diff --git a/dist/autofill-debug.js b/dist/autofill-debug.js index fbb94e217..d8cfb14ec 100644 --- a/dist/autofill-debug.js +++ b/dist/autofill-debug.js @@ -6240,6 +6240,9 @@ Source: "${matchedFrom}"`; * @returns {boolean} */ get shouldAutoprompt() { + if (this.device.globalConfig.isMobileApp && this.device.credentialsImport.isAvailable()) { + return false; + } return Date.now() - this.initTimeStamp <= 1500; } /** @@ -10759,6 +10762,38 @@ Source: "${matchedFrom}"`; phone: external_exports.string().optional(), emailAddress: external_exports.string().optional() }); + var availableInputTypesSchema = external_exports.object({ + credentials: external_exports.object({ + username: external_exports.boolean().optional(), + password: external_exports.boolean().optional() + }).optional(), + identities: external_exports.object({ + firstName: external_exports.boolean().optional(), + middleName: external_exports.boolean().optional(), + lastName: external_exports.boolean().optional(), + birthdayDay: external_exports.boolean().optional(), + birthdayMonth: external_exports.boolean().optional(), + birthdayYear: external_exports.boolean().optional(), + addressStreet: external_exports.boolean().optional(), + addressStreet2: external_exports.boolean().optional(), + addressCity: external_exports.boolean().optional(), + addressProvince: external_exports.boolean().optional(), + addressPostalCode: external_exports.boolean().optional(), + addressCountryCode: external_exports.boolean().optional(), + phone: external_exports.boolean().optional(), + emailAddress: external_exports.boolean().optional() + }).optional(), + creditCards: external_exports.object({ + cardName: external_exports.boolean().optional(), + cardSecurityCode: external_exports.boolean().optional(), + expirationMonth: external_exports.boolean().optional(), + expirationYear: external_exports.boolean().optional(), + cardNumber: external_exports.boolean().optional() + }).optional(), + email: external_exports.boolean().optional(), + credentialsProviderStatus: external_exports.union([external_exports.literal("locked"), external_exports.literal("unlocked")]).optional(), + credentialsImport: external_exports.boolean().optional() + }); var genericErrorSchema = external_exports.object({ message: external_exports.string() }); @@ -10786,7 +10821,7 @@ Source: "${matchedFrom}"`; username: external_exports.string().optional(), password: external_exports.string().optional() }); - var availableInputTypesSchema = external_exports.object({ + var availableInputTypes1Schema = external_exports.object({ credentials: external_exports.object({ username: external_exports.boolean().optional(), password: external_exports.boolean().optional() @@ -10838,42 +10873,15 @@ Source: "${matchedFrom}"`; }).optional(), error: genericErrorSchema.optional() }); - var availableInputTypes1Schema = external_exports.object({ - credentials: external_exports.object({ - username: external_exports.boolean().optional(), - password: external_exports.boolean().optional() - }).optional(), - identities: external_exports.object({ - firstName: external_exports.boolean().optional(), - middleName: external_exports.boolean().optional(), - lastName: external_exports.boolean().optional(), - birthdayDay: external_exports.boolean().optional(), - birthdayMonth: external_exports.boolean().optional(), - birthdayYear: external_exports.boolean().optional(), - addressStreet: external_exports.boolean().optional(), - addressStreet2: external_exports.boolean().optional(), - addressCity: external_exports.boolean().optional(), - addressProvince: external_exports.boolean().optional(), - addressPostalCode: external_exports.boolean().optional(), - addressCountryCode: external_exports.boolean().optional(), - phone: external_exports.boolean().optional(), - emailAddress: external_exports.boolean().optional() - }).optional(), - creditCards: external_exports.object({ - cardName: external_exports.boolean().optional(), - cardSecurityCode: external_exports.boolean().optional(), - expirationMonth: external_exports.boolean().optional(), - expirationYear: external_exports.boolean().optional(), - cardNumber: external_exports.boolean().optional() - }).optional(), - email: external_exports.boolean().optional(), - credentialsProviderStatus: external_exports.union([external_exports.literal("locked"), external_exports.literal("unlocked")]).optional(), - credentialsImport: external_exports.boolean().optional() - }); var providerStatusUpdatedSchema = external_exports.object({ status: external_exports.union([external_exports.literal("locked"), external_exports.literal("unlocked")]), credentials: external_exports.array(credentialsSchema), - availableInputTypes: availableInputTypes1Schema + availableInputTypes: availableInputTypesSchema + }); + var checkCredentialsProviderStatusResultSchema = external_exports.object({ + type: external_exports.literal("checkCredentialsProviderStatusResponse").optional(), + success: providerStatusUpdatedSchema, + error: genericErrorSchema.optional() }); var autofillFeatureTogglesSchema = external_exports.object({ autocomplete_attribute_support: external_exports.boolean().optional(), @@ -10936,7 +10944,7 @@ Source: "${matchedFrom}"`; inputType: external_exports.string(), mainType: external_exports.union([external_exports.literal("credentials"), external_exports.literal("identities"), external_exports.literal("creditCards")]), subType: external_exports.string(), - trigger: external_exports.union([external_exports.literal("userInitiated"), external_exports.literal("autoprompt"), external_exports.literal("postSignup")]).optional(), + trigger: external_exports.union([external_exports.literal("userInitiated"), external_exports.literal("autoprompt"), external_exports.literal("postSignup"), external_exports.literal("credentialsImport")]).optional(), serializedInputContext: external_exports.string().optional(), triggerContext: triggerContextSchema.optional() }); @@ -10946,6 +10954,7 @@ Source: "${matchedFrom}"`; credentials: credentialsSchema.optional(), creditCards: creditCardObjectSchema.optional(), identities: identityObjectSchema.optional(), + availableInputTypes: availableInputTypesSchema.optional(), action: external_exports.union([external_exports.literal("fill"), external_exports.literal("focus"), external_exports.literal("none"), external_exports.literal("refreshAvailableInputTypes"), external_exports.literal("acceptGeneratedPassword"), external_exports.literal("rejectGeneratedPassword")]) }).optional(), error: genericErrorSchema.optional() @@ -10956,7 +10965,7 @@ Source: "${matchedFrom}"`; }); var getAvailableInputTypesResultSchema = external_exports.object({ type: external_exports.literal("getAvailableInputTypesResponse").optional(), - success: availableInputTypesSchema, + success: availableInputTypes1Schema, error: genericErrorSchema.optional() }); var askToUnlockProviderResultSchema = external_exports.object({ @@ -10964,11 +10973,6 @@ Source: "${matchedFrom}"`; success: providerStatusUpdatedSchema, error: genericErrorSchema.optional() }); - var checkCredentialsProviderStatusResultSchema = external_exports.object({ - type: external_exports.literal("checkCredentialsProviderStatusResponse").optional(), - success: providerStatusUpdatedSchema, - error: genericErrorSchema.optional() - }); var autofillSettingsSchema = external_exports.object({ featureToggles: autofillFeatureTogglesSchema }); @@ -11631,6 +11635,10 @@ Source: "${matchedFrom}"`; form.activeInput?.focus(); break; } + case "refreshAvailableInputTypes": { + device.credentialsImport.refresh(resp.availableInputTypes); + break; + } case "acceptGeneratedPassword": { form.autofillData( { @@ -16254,13 +16262,29 @@ Source: "${matchedFrom}"`; } catch (e) { } } - async refresh() { - await this.device.settings.refresh(); - this.device.activeForm?.redecorateAllInputs(); + /** + * @param {import("./deviceApiCalls/__generated__/validators-ts").AvailableInputTypes} [availableInputTypes] + */ + async refresh(availableInputTypes) { + const inputTypes = availableInputTypes || await this.device.settings.getAvailableInputTypes(); + this.device.settings.setAvailableInputTypes(inputTypes); + this.device.scanner.forms.forEach((form) => form.redecorateAllInputs()); this.device.uiController?.removeTooltip("interface"); - const activeInput = this.device.activeForm?.activeInput; - activeInput?.blur(); - activeInput?.focus(); + const activeForm = this.device.activeForm; + if (!activeForm) return; + const { activeInput } = activeForm; + const { username, password } = this.device.settings.availableInputTypes.credentials || {}; + if (activeInput && (username || password)) { + this.device.attachTooltip({ + form: activeForm, + input: activeInput, + click: null, + trigger: "credentialsImport", + triggerMetaData: { + type: "transactional" + } + }); + } } async started() { this.device.deviceApi.notify(new StartCredentialsImportFlowCall({})); diff --git a/dist/autofill.js b/dist/autofill.js index 0e6fda439..69fe5df73 100644 --- a/dist/autofill.js +++ b/dist/autofill.js @@ -6236,6 +6236,9 @@ Source: "${matchedFrom}"`; * @returns {boolean} */ get shouldAutoprompt() { + if (this.device.globalConfig.isMobileApp && this.device.credentialsImport.isAvailable()) { + return false; + } return Date.now() - this.initTimeStamp <= 1500; } /** @@ -6607,6 +6610,7 @@ Source: "${matchedFrom}"`; var getAutofillDataFocusResponseSchema = null; var getAutofillInitDataResponseSchema = null; var getAutofillCredentialsResultSchema = null; + var checkCredentialsProviderStatusResultSchema = null; var getIdentityResultSchema = null; var getCreditCardResultSchema = null; var emailProtectionGetIsLoggedInResultSchema = null; @@ -6619,7 +6623,6 @@ Source: "${matchedFrom}"`; var storeFormDataSchema = null; var getAvailableInputTypesResultSchema = null; var askToUnlockProviderResultSchema = null; - var checkCredentialsProviderStatusResultSchema = null; var getRuntimeConfigurationResponseSchema = null; // packages/device-api/lib/device-api-call.js @@ -7155,6 +7158,10 @@ Source: "${matchedFrom}"`; form.activeInput?.focus(); break; } + case "refreshAvailableInputTypes": { + device.credentialsImport.refresh(resp.availableInputTypes); + break; + } case "acceptGeneratedPassword": { form.autofillData( { @@ -11782,13 +11789,29 @@ Source: "${matchedFrom}"`; } catch (e) { } } - async refresh() { - await this.device.settings.refresh(); - this.device.activeForm?.redecorateAllInputs(); + /** + * @param {import("./deviceApiCalls/__generated__/validators-ts").AvailableInputTypes} [availableInputTypes] + */ + async refresh(availableInputTypes) { + const inputTypes = availableInputTypes || await this.device.settings.getAvailableInputTypes(); + this.device.settings.setAvailableInputTypes(inputTypes); + this.device.scanner.forms.forEach((form) => form.redecorateAllInputs()); this.device.uiController?.removeTooltip("interface"); - const activeInput = this.device.activeForm?.activeInput; - activeInput?.blur(); - activeInput?.focus(); + const activeForm = this.device.activeForm; + if (!activeForm) return; + const { activeInput } = activeForm; + const { username, password } = this.device.settings.availableInputTypes.credentials || {}; + if (activeInput && (username || password)) { + this.device.attachTooltip({ + form: activeForm, + input: activeInput, + click: null, + trigger: "credentialsImport", + triggerMetaData: { + type: "transactional" + } + }); + } } async started() { this.device.deviceApi.notify(new StartCredentialsImportFlowCall({})); diff --git a/src/CredentialsImport.js b/src/CredentialsImport.js index c2100a534..e35630df8 100644 --- a/src/CredentialsImport.js +++ b/src/CredentialsImport.js @@ -40,22 +40,40 @@ class CredentialsImport { } } - async refresh() { - // Refresh all settings (e.g availableInputTypes) - await this.device.settings.refresh(); + /** + * @param {import("./deviceApiCalls/__generated__/validators-ts").AvailableInputTypes} [availableInputTypes] + */ + async refresh(availableInputTypes) { + const inputTypes = availableInputTypes || (await this.device.settings.getAvailableInputTypes()); + this.device.settings.setAvailableInputTypes(inputTypes); // Re-decorate all inputs to show the input decorations - this.device.activeForm?.redecorateAllInputs(); + // Include other forms too, as credentials might now be available in other forms. + this.device.scanner.forms.forEach((form) => form.redecorateAllInputs()); // Make sure the tooltip is closed before we try to open it this.device.uiController?.removeTooltip('interface'); - const activeInput = this.device.activeForm?.activeInput; - // First blur to make sure we're not already in focus - activeInput?.blur(); + const activeForm = this.device.activeForm; + // If no active form, we can't show the prompt + if (!activeForm) return; + + const { activeInput } = activeForm; - // Then focus to open the tooltip - activeInput?.focus(); + const { username, password } = this.device.settings.availableInputTypes.credentials || {}; + if (activeInput && (username || password)) { + // Attach tooltip again to force prompt the credentials prompt, + // if username or password become available. + this.device.attachTooltip({ + form: activeForm, + input: activeInput, + click: null, + trigger: 'credentialsImport', + triggerMetaData: { + type: 'transactional', + }, + }); + } } async started() { diff --git a/src/CredentialsImport.test.js b/src/CredentialsImport.test.js new file mode 100644 index 000000000..fc728d438 --- /dev/null +++ b/src/CredentialsImport.test.js @@ -0,0 +1,85 @@ +import { DeviceApi } from '../packages/device-api/index.js'; +import { createGlobalConfig } from './config.js'; +import { AndroidTransport } from './deviceApiCalls/transports/android.transport.js'; +import { AndroidInterface } from './DeviceInterface/AndroidInterface.js'; +import { Settings } from './Settings.js'; +import { CredentialsImport } from './CredentialsImport.js'; +import { attachAndReturnGenericForm } from './test-utils.js'; +import { Form } from './Form/Form.js'; + +function createDeviceApi() { + const transport = new AndroidTransport(createGlobalConfig()); + return new DeviceApi(transport); +} + +function createDevice() { + const deviceApi = createDeviceApi(); + const settings = Settings.default(createGlobalConfig(), deviceApi); + return new AndroidInterface(createGlobalConfig(), deviceApi, settings); +} + +function createLoginForm(device) { + const formEl = attachAndReturnGenericForm(` +
+ `); + const input = formEl.querySelector('input'); + if (!input) throw new Error('unreachable'); + const form = new Form(formEl, input, device); + device.activeForm = form; + form.activeInput = input; + return form; +} + +describe('CredentialsImport', () => { + /** @type {CredentialsImport} */ + let credentialsImport; + + /** @type {AndroidInterface} */ + let device; + + /** @type {Form} */ + let form; + + const newAvailableInputTypes = { + credentialsImport: false, + credentials: { + username: true, + password: false, + }, + }; + + beforeEach(() => { + device = createDevice(); + form = createLoginForm(device); + credentialsImport = new CredentialsImport(device); + }); + + describe('refresh()', () => { + it('correctly updates the available input types', async () => { + await credentialsImport.refresh(newAvailableInputTypes); + expect(credentialsImport.isAvailable()).toBe(false); + expect(device.settings.availableInputTypes.credentials).toEqual(newAvailableInputTypes.credentials); + }); + + it('should attach tooltip with credentialsImport trigger when credentials are available', async () => { + // Set up a form and active input + // Mock attachTooltip + jest.spyOn(device, 'attachTooltip'); + + await credentialsImport.refresh(newAvailableInputTypes); + expect(device.attachTooltip).toHaveBeenCalledWith({ + form, + input: form.activeInput, + click: null, + trigger: 'credentialsImport', + triggerMetaData: { + type: 'transactional', + }, + }); + }); + }); +}); diff --git a/src/Form/Form.js b/src/Form/Form.js index 80c3301e9..97513d2c3 100644 --- a/src/Form/Form.js +++ b/src/Form/Form.js @@ -646,7 +646,6 @@ class Form { const config = getInputConfig(input); const shouldDecorate = await config.shouldDecorate(input, this); - if (!shouldDecorate) return this; input.setAttribute(ATTR_AUTOFILL, 'true'); diff --git a/src/Scanner.js b/src/Scanner.js index e9638774e..9e5a0056d 100644 --- a/src/Scanner.js +++ b/src/Scanner.js @@ -96,6 +96,12 @@ class DefaultScanner { * @returns {boolean} */ get shouldAutoprompt() { + // On mobile, if credentials import is available, we don't need an autoprompt + // We wait for the user to click on the input to show the prompt, for better UX. + if (this.device.globalConfig.isMobileApp && this.device.credentialsImport.isAvailable()) { + return false; + } + return Date.now() - this.initTimeStamp <= 1500; } diff --git a/src/UI/controllers/NativeUIController.js b/src/UI/controllers/NativeUIController.js index 5d9709d93..782ec1684 100644 --- a/src/UI/controllers/NativeUIController.js +++ b/src/UI/controllers/NativeUIController.js @@ -76,6 +76,11 @@ export class NativeUIController extends UIController { break; } + case 'refreshAvailableInputTypes': { + device.credentialsImport.refresh(resp.availableInputTypes); + break; + } + case 'acceptGeneratedPassword': { form.autofillData( { diff --git a/src/deviceApiCalls/__generated__/validators-ts.ts b/src/deviceApiCalls/__generated__/validators-ts.ts index bf51adf15..cc6095bb6 100644 --- a/src/deviceApiCalls/__generated__/validators-ts.ts +++ b/src/deviceApiCalls/__generated__/validators-ts.ts @@ -299,7 +299,7 @@ export interface GetAutofillDataRequest { /** * Signals that the prompt was triggered automatically rather than by user action */ - trigger?: "userInitiated" | "autoprompt" | "postSignup"; + trigger?: "userInitiated" | "autoprompt" | "postSignup" | "credentialsImport"; /** * Serialized JSON that will be picked up once the 'parent' requests its initial data */ @@ -332,6 +332,7 @@ export interface GetAutofillDataResponse { credentials?: Credentials; creditCards?: CreditCardObject; identities?: IdentityObject; + availableInputTypes?: AvailableInputTypes; action: | "fill" | "focus" @@ -462,6 +463,53 @@ export interface IdentityObject { */ emailAddress?: string; } +/** + * For each main autofill types, it maps specific fields to their availability + */ +export interface AvailableInputTypes { + /** + * maps field types and the availability of data for the current site + */ + credentials?: { + username?: boolean; + password?: boolean; + }; + /** + * maps field types and the availability of data saved by the user + */ + identities?: { + firstName?: boolean; + middleName?: boolean; + lastName?: boolean; + birthdayDay?: boolean; + birthdayMonth?: boolean; + birthdayYear?: boolean; + addressStreet?: boolean; + addressStreet2?: boolean; + addressCity?: boolean; + addressProvince?: boolean; + addressPostalCode?: boolean; + addressCountryCode?: boolean; + phone?: boolean; + emailAddress?: boolean; + }; + /** + * maps field types and the availability of data saved by the user + */ + creditCards?: { + cardName?: boolean; + cardSecurityCode?: boolean; + expirationMonth?: boolean; + expirationYear?: boolean; + cardNumber?: boolean; + }; + /** + * true if signed in for Email Protection + */ + email?: boolean; + credentialsProviderStatus?: "locked" | "unlocked"; + credentialsImport?: boolean; +} export interface GenericError { message: string; } @@ -553,13 +601,13 @@ export interface GetAvailableInputTypesResult { * A string used to identify this result. It's optional */ type?: "getAvailableInputTypesResponse"; - success: AvailableInputTypes; + success: AvailableInputTypes1; error?: GenericError; } /** * For each main autofill types, it maps specific fields to their availability */ -export interface AvailableInputTypes { +export interface AvailableInputTypes1 { /** * maps field types and the availability of data for the current site */ @@ -674,54 +722,7 @@ export interface AskToUnlockProviderResult { export interface ProviderStatusUpdated { status: "locked" | "unlocked"; credentials: Credentials[]; - availableInputTypes: AvailableInputTypes1; -} -/** - * For each main autofill types, it maps specific fields to their availability - */ -export interface AvailableInputTypes1 { - /** - * maps field types and the availability of data for the current site - */ - credentials?: { - username?: boolean; - password?: boolean; - }; - /** - * maps field types and the availability of data saved by the user - */ - identities?: { - firstName?: boolean; - middleName?: boolean; - lastName?: boolean; - birthdayDay?: boolean; - birthdayMonth?: boolean; - birthdayYear?: boolean; - addressStreet?: boolean; - addressStreet2?: boolean; - addressCity?: boolean; - addressProvince?: boolean; - addressPostalCode?: boolean; - addressCountryCode?: boolean; - phone?: boolean; - emailAddress?: boolean; - }; - /** - * maps field types and the availability of data saved by the user - */ - creditCards?: { - cardName?: boolean; - cardSecurityCode?: boolean; - expirationMonth?: boolean; - expirationYear?: boolean; - cardNumber?: boolean; - }; - /** - * true if signed in for Email Protection - */ - email?: boolean; - credentialsProviderStatus?: "locked" | "unlocked"; - credentialsImport?: boolean; + availableInputTypes: AvailableInputTypes; } /** * This is only used in macOS 10.15 Catalina diff --git a/src/deviceApiCalls/__generated__/validators.zod.js b/src/deviceApiCalls/__generated__/validators.zod.js index 9aae1e3f9..44c944a42 100644 --- a/src/deviceApiCalls/__generated__/validators.zod.js +++ b/src/deviceApiCalls/__generated__/validators.zod.js @@ -146,6 +146,39 @@ export const identityObjectSchema = z.object({ emailAddress: z.string().optional() }); +export const availableInputTypesSchema = z.object({ + credentials: z.object({ + username: z.boolean().optional(), + password: z.boolean().optional() + }).optional(), + identities: z.object({ + firstName: z.boolean().optional(), + middleName: z.boolean().optional(), + lastName: z.boolean().optional(), + birthdayDay: z.boolean().optional(), + birthdayMonth: z.boolean().optional(), + birthdayYear: z.boolean().optional(), + addressStreet: z.boolean().optional(), + addressStreet2: z.boolean().optional(), + addressCity: z.boolean().optional(), + addressProvince: z.boolean().optional(), + addressPostalCode: z.boolean().optional(), + addressCountryCode: z.boolean().optional(), + phone: z.boolean().optional(), + emailAddress: z.boolean().optional() + }).optional(), + creditCards: z.object({ + cardName: z.boolean().optional(), + cardSecurityCode: z.boolean().optional(), + expirationMonth: z.boolean().optional(), + expirationYear: z.boolean().optional(), + cardNumber: z.boolean().optional() + }).optional(), + email: z.boolean().optional(), + credentialsProviderStatus: z.union([z.literal("locked"), z.literal("unlocked")]).optional(), + credentialsImport: z.boolean().optional() +}); + export const genericErrorSchema = z.object({ message: z.string() }); @@ -177,7 +210,7 @@ export const outgoingCredentialsSchema = z.object({ password: z.string().optional() }); -export const availableInputTypesSchema = z.object({ +export const availableInputTypes1Schema = z.object({ credentials: z.object({ username: z.boolean().optional(), password: z.boolean().optional() @@ -232,43 +265,16 @@ export const getAutofillCredentialsResultSchema = z.object({ error: genericErrorSchema.optional() }); -export const availableInputTypes1Schema = z.object({ - credentials: z.object({ - username: z.boolean().optional(), - password: z.boolean().optional() - }).optional(), - identities: z.object({ - firstName: z.boolean().optional(), - middleName: z.boolean().optional(), - lastName: z.boolean().optional(), - birthdayDay: z.boolean().optional(), - birthdayMonth: z.boolean().optional(), - birthdayYear: z.boolean().optional(), - addressStreet: z.boolean().optional(), - addressStreet2: z.boolean().optional(), - addressCity: z.boolean().optional(), - addressProvince: z.boolean().optional(), - addressPostalCode: z.boolean().optional(), - addressCountryCode: z.boolean().optional(), - phone: z.boolean().optional(), - emailAddress: z.boolean().optional() - }).optional(), - creditCards: z.object({ - cardName: z.boolean().optional(), - cardSecurityCode: z.boolean().optional(), - expirationMonth: z.boolean().optional(), - expirationYear: z.boolean().optional(), - cardNumber: z.boolean().optional() - }).optional(), - email: z.boolean().optional(), - credentialsProviderStatus: z.union([z.literal("locked"), z.literal("unlocked")]).optional(), - credentialsImport: z.boolean().optional() -}); - export const providerStatusUpdatedSchema = z.object({ status: z.union([z.literal("locked"), z.literal("unlocked")]), credentials: z.array(credentialsSchema), - availableInputTypes: availableInputTypes1Schema + availableInputTypes: availableInputTypesSchema +}); + +export const checkCredentialsProviderStatusResultSchema = z.object({ + type: z.literal("checkCredentialsProviderStatusResponse").optional(), + success: providerStatusUpdatedSchema, + error: genericErrorSchema.optional() }); export const autofillFeatureTogglesSchema = z.object({ @@ -340,7 +346,7 @@ export const getAutofillDataRequestSchema = z.object({ inputType: z.string(), mainType: z.union([z.literal("credentials"), z.literal("identities"), z.literal("creditCards")]), subType: z.string(), - trigger: z.union([z.literal("userInitiated"), z.literal("autoprompt"), z.literal("postSignup")]).optional(), + trigger: z.union([z.literal("userInitiated"), z.literal("autoprompt"), z.literal("postSignup"), z.literal("credentialsImport")]).optional(), serializedInputContext: z.string().optional(), triggerContext: triggerContextSchema.optional() }); @@ -351,6 +357,7 @@ export const getAutofillDataResponseSchema = z.object({ credentials: credentialsSchema.optional(), creditCards: creditCardObjectSchema.optional(), identities: identityObjectSchema.optional(), + availableInputTypes: availableInputTypesSchema.optional(), action: z.union([z.literal("fill"), z.literal("focus"), z.literal("none"), z.literal("refreshAvailableInputTypes"), z.literal("acceptGeneratedPassword"), z.literal("rejectGeneratedPassword")]) }).optional(), error: genericErrorSchema.optional() @@ -363,7 +370,7 @@ export const storeFormDataSchema = z.object({ export const getAvailableInputTypesResultSchema = z.object({ type: z.literal("getAvailableInputTypesResponse").optional(), - success: availableInputTypesSchema, + success: availableInputTypes1Schema, error: genericErrorSchema.optional() }); @@ -373,12 +380,6 @@ export const askToUnlockProviderResultSchema = z.object({ error: genericErrorSchema.optional() }); -export const checkCredentialsProviderStatusResultSchema = z.object({ - type: z.literal("checkCredentialsProviderStatusResponse").optional(), - success: providerStatusUpdatedSchema, - error: genericErrorSchema.optional() -}); - export const autofillSettingsSchema = z.object({ featureToggles: autofillFeatureTogglesSchema }); diff --git a/src/deviceApiCalls/schemas/getAutofillData.params.json b/src/deviceApiCalls/schemas/getAutofillData.params.json index 683eced19..68f6af7da 100644 --- a/src/deviceApiCalls/schemas/getAutofillData.params.json +++ b/src/deviceApiCalls/schemas/getAutofillData.params.json @@ -42,7 +42,7 @@ "trigger": { "description": "Signals that the prompt was triggered automatically rather than by user action", "type": "string", - "enum": ["userInitiated", "autoprompt", "postSignup"] + "enum": ["userInitiated", "autoprompt", "postSignup", "credentialsImport"] }, "serializedInputContext": { "description": "Serialized JSON that will be picked up once the 'parent' requests its initial data", diff --git a/src/deviceApiCalls/schemas/getAutofillData.result.json b/src/deviceApiCalls/schemas/getAutofillData.result.json index b319dc0b4..395a7021f 100644 --- a/src/deviceApiCalls/schemas/getAutofillData.result.json +++ b/src/deviceApiCalls/schemas/getAutofillData.result.json @@ -17,6 +17,7 @@ "credentials": { "$ref": "./credentials.json" }, "creditCards": { "$ref": "./creditCard.json" }, "identities": { "$ref": "./identity.json" }, + "availableInputTypes": { "$ref": "./availableInputTypes.json" }, "action": { "type": "string", "enum": ["fill", "focus", "none", "refreshAvailableInputTypes", "acceptGeneratedPassword", "rejectGeneratedPassword"]