From 0b2a6544504196b8f71ee6ba2121dbe631b8a29f Mon Sep 17 00:00:00 2001 From: Ryan Bas Date: Mon, 11 May 2026 10:47:32 -0600 Subject: [PATCH 1/2] feat(oidc-client): add PAR (Pushed Authorization Request) support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements RFC 9126 PAR flow: client POSTs authorization parameters to the server's pushed_authorization_request_endpoint, receives a request_uri, and uses only that in the redirect — keeping sensitive parameters out of browser history and server logs. - New parAuthorizeµ pipeline: builds PAR body, dispatches POST, validates response, stores PKCE state, builds slim authorize URL - authorizeµ selects PAR vs standard flow via config.par or wellknown.require_pushed_authorization_requests - New par.types.ts, authorize.request.micros.ts, authorize.request.effects.ts layer split - PAR endpoint added to oidc.api.ts (RTK Query mutation) - e2e suite and app added (e2e/oidc-app/src/par/, oidc-suites/par.spec.ts) --- .changeset/some-shirts-joke.md | 9 + e2e/am-mock-api/src/app/constants.js | 1 + e2e/am-mock-api/src/app/responses.js | 5 + e2e/am-mock-api/src/app/routes.auth.js | 5 + e2e/oidc-app/src/index.html | 1 + e2e/oidc-app/src/par/index.html | 61 + e2e/oidc-app/src/par/main.ts | 82 + e2e/oidc-app/src/utils/oidc-app.ts | 5 +- e2e/oidc-app/vite.config.ts | 2 +- e2e/oidc-suites/src/login.spec.ts | 2 +- e2e/oidc-suites/src/par.spec.ts | 87 + .../api-report/davinci-client.api.md | 4599 ++++++++--------- .../api-report/davinci-client.types.api.md | 4593 ++++++++-------- .../oidc-client/api-report/oidc-client.api.md | 18 + .../api-report/oidc-client.types.api.md | 18 + packages/oidc-client/package.json | 1 + .../src/lib/authorize.request.effects.ts | 61 + .../src/lib/authorize.request.micros.test.ts | 410 ++ .../src/lib/authorize.request.micros.ts | 110 + .../oidc-client/src/lib/authorize.request.ts | 282 +- .../src/lib/authorize.request.utils.test.ts | 436 +- .../src/lib/authorize.request.utils.ts | 301 +- .../oidc-client/src/lib/client.store.test.ts | 324 +- packages/oidc-client/src/lib/client.store.ts | 88 +- packages/oidc-client/src/lib/config.types.ts | 1 + packages/oidc-client/src/lib/oidc.api.ts | 66 + packages/oidc-client/src/lib/par.types.ts | 11 + packages/oidc-client/src/types.ts | 1 + packages/oidc-client/tsconfig.lib.json | 3 + packages/sdk-effects/oidc/src/index.ts | 1 + .../oidc/src/lib/authorize.effects.ts | 14 +- .../oidc/src/lib/authorize.test.ts | 50 + .../oidc/src/lib/authorize.utils.ts | 34 + .../src/lib/request-mware.derived.ts | 1 + pnpm-lock.yaml | 3 + 35 files changed, 6223 insertions(+), 5463 deletions(-) create mode 100644 .changeset/some-shirts-joke.md create mode 100644 e2e/oidc-app/src/par/index.html create mode 100644 e2e/oidc-app/src/par/main.ts create mode 100644 e2e/oidc-suites/src/par.spec.ts create mode 100644 packages/oidc-client/src/lib/authorize.request.effects.ts create mode 100644 packages/oidc-client/src/lib/authorize.request.micros.test.ts create mode 100644 packages/oidc-client/src/lib/authorize.request.micros.ts create mode 100644 packages/oidc-client/src/lib/par.types.ts create mode 100644 packages/sdk-effects/oidc/src/lib/authorize.utils.ts diff --git a/.changeset/some-shirts-joke.md b/.changeset/some-shirts-joke.md new file mode 100644 index 0000000000..f9c2399f3f --- /dev/null +++ b/.changeset/some-shirts-joke.md @@ -0,0 +1,9 @@ +--- +'@forgerock/sdk-request-middleware': minor +'@forgerock/sdk-oidc': minor +'@forgerock/davinci-client': minor +'@forgerock/oidc-client': minor +'am-mock-api': patch +--- + +Add support for PAR in oidc-client requests for redirect flows diff --git a/e2e/am-mock-api/src/app/constants.js b/e2e/am-mock-api/src/app/constants.js index 6e7b8240a8..cdd6edc5a5 100644 --- a/e2e/am-mock-api/src/app/constants.js +++ b/e2e/am-mock-api/src/app/constants.js @@ -9,6 +9,7 @@ */ export const authPaths = { + par: ['/am/oauth2/realms/root/par'], tokenExchange: [ '/am/auth/tokenExchange', '/am/oauth2/realms/root/access_token', diff --git a/e2e/am-mock-api/src/app/responses.js b/e2e/am-mock-api/src/app/responses.js index d7c9e7af41..6127ea6e3d 100644 --- a/e2e/am-mock-api/src/app/responses.js +++ b/e2e/am-mock-api/src/app/responses.js @@ -1348,6 +1348,11 @@ export const recaptchaEnterpriseCallback = { ], }; +export const parResponse = { + request_uri: 'urn:ietf:params:oauth:request_uri:mock-par-request-uri', + expires_in: 60, +}; + export const qrCodeCallbacksResponse = { authId: 'qrcode-journey-confirmation', callbacks: [ diff --git a/e2e/am-mock-api/src/app/routes.auth.js b/e2e/am-mock-api/src/app/routes.auth.js index bcf0e7c2e9..38e75a426d 100644 --- a/e2e/am-mock-api/src/app/routes.auth.js +++ b/e2e/am-mock-api/src/app/routes.auth.js @@ -49,6 +49,7 @@ import { MetadataMarketPlacePingOneEvaluation, newPiWellKnown, qrCodeCallbacksResponse, + parResponse, } from './responses.js'; import initialRegResponse from './response.registration.js'; import { @@ -664,6 +665,10 @@ export default function (app) { app.get('/callback', (req, res) => res.status(200).send('ok')); + app.post(authPaths.par, (req, res) => { + res.status(201).json(parResponse); + }); + app.get('/am/.well-known/oidc-configuration', (req, res) => { res.send(wellKnownForgeRock); }); diff --git a/e2e/oidc-app/src/index.html b/e2e/oidc-app/src/index.html index 862f53f9d6..dcc720ee3b 100644 --- a/e2e/oidc-app/src/index.html +++ b/e2e/oidc-app/src/index.html @@ -12,6 +12,7 @@

OIDC Client E2E Test Index | Ping Identity JavaScript SDK

diff --git a/e2e/oidc-app/src/par/index.html b/e2e/oidc-app/src/par/index.html new file mode 100644 index 0000000000..86f24176a5 --- /dev/null +++ b/e2e/oidc-app/src/par/index.html @@ -0,0 +1,61 @@ + + + + E2E Test | Ping Identity JavaScript SDK + + + + +
+ Home +

OIDC App | PAR Login (Pushed Authorization Request)

+

+ Client: ParClient — PAR enabled. Authorize params are sent via + back-channel POST to /par first, then a slim URL (client_id + request_uri + only) is used for the authorize redirect. +

+ +

Step 1: Establish AM Session (Journey: Login)

+

+ Background PAR auth requires an existing AM session. Log in via the Login journey first. +

+
+
+ + + + + +
+
+

+ +

Step 2: PAR OAuth

+ + + + + + + + + Start Over +
+ + + diff --git a/e2e/oidc-app/src/par/main.ts b/e2e/oidc-app/src/par/main.ts new file mode 100644 index 0000000000..a94da7fadd --- /dev/null +++ b/e2e/oidc-app/src/par/main.ts @@ -0,0 +1,82 @@ +/* + * + * Copyright © 2025 Ping Identity Corporation. All right reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + */ +import { oidcApp } from '../utils/oidc-app.js'; + +const AM_BASE = 'https://openam-sdks.forgeblocks.com/am'; +const REALM = 'alpha'; + +const urlParams = new URLSearchParams(window.location.search); +const wellknown = urlParams.get('wellknown'); + +const config = { + clientId: 'ParClient', + redirectUri: 'http://localhost:8443/par/', + scope: 'openid profile email', + par: true, + serverConfig: { + wellknown: + wellknown || + 'https://openam-sdks.forgeblocks.com/am/oauth2/alpha/.well-known/openid-configuration', + }, +}; + +// Run journey Login to establish an AM session before background PAR auth +async function runLoginJourney(username: string, password: string): Promise { + const authenticateUrl = `${AM_BASE}/json/realms/root/realms/${REALM}/authenticate?authIndexType=service&authIndexValue=Login`; + + // Step 1: start the journey + const initRes = await fetch(authenticateUrl, { + method: 'POST', + credentials: 'include', + headers: { 'Content-Type': 'application/json', 'Accept-API-Version': 'resource=2.1' }, + body: '{}', + }); + const initJson = await initRes.json(); + + if (initJson.successUrl) return; // already authenticated + + // Fill NameCallback + PasswordCallback + for (const cb of initJson.callbacks ?? []) { + if (cb.type === 'NameCallback') cb.input[0].value = username; + if (cb.type === 'PasswordCallback') cb.input[0].value = password; + } + + // Step 2: submit credentials + const submitRes = await fetch(authenticateUrl, { + method: 'POST', + credentials: 'include', + headers: { 'Content-Type': 'application/json', 'Accept-API-Version': 'resource=2.1' }, + body: JSON.stringify(initJson), + }); + const submitJson = await submitRes.json(); + + if (!submitJson.tokenId && !submitJson.successUrl) { + throw new Error(submitJson.message || 'Login failed'); + } +} + +const journeyForm = document.getElementById('journey-form') as HTMLFormElement; +const journeyStatus = document.getElementById('journey-status') as HTMLParagraphElement; +const backgroundBtn = document.getElementById('login-background') as HTMLButtonElement; + +journeyForm.addEventListener('submit', async (e) => { + e.preventDefault(); + const username = (document.getElementById('username') as HTMLInputElement).value; + const password = (document.getElementById('password') as HTMLInputElement).value; + journeyStatus.textContent = 'Logging in…'; + try { + await runLoginJourney(username, password); + journeyStatus.textContent = '✓ Session established — background login now available.'; + backgroundBtn.disabled = false; + } catch (err) { + journeyStatus.textContent = `✗ ${err instanceof Error ? err.message : 'Login failed'}`; + } +}); + +oidcApp({ config, urlParams }); diff --git a/e2e/oidc-app/src/utils/oidc-app.ts b/e2e/oidc-app/src/utils/oidc-app.ts index 69289580a0..f8565a10c7 100644 --- a/e2e/oidc-app/src/utils/oidc-app.ts +++ b/e2e/oidc-app/src/utils/oidc-app.ts @@ -49,8 +49,11 @@ export async function oidcApp({ config, urlParams }) { const code = urlParams.get('code'); const state = urlParams.get('state'); const piflow = urlParams.get('piflow'); + const par = urlParams.get('par') === 'true'; - const oidcClient: OidcClient = await oidc({ config }); + const oidcClient: OidcClient = await oidc({ + config: { ...config, ...(par && { par: true }) }, + }); if ('error' in oidcClient) { displayError(oidcClient); } diff --git a/e2e/oidc-app/vite.config.ts b/e2e/oidc-app/vite.config.ts index d2a956b1a9..c40a554f9f 100644 --- a/e2e/oidc-app/vite.config.ts +++ b/e2e/oidc-app/vite.config.ts @@ -4,7 +4,7 @@ import { dirname, resolve } from 'path'; import { fileURLToPath } from 'url'; const __dirname = dirname(fileURLToPath(import.meta.url)); -const pages = ['ping-am', 'ping-one']; +const pages = ['ping-am', 'ping-one', 'par']; export default defineConfig(() => ({ root: __dirname + '/src', cacheDir: '../../node_modules/.vite/e2e/oidc-app', diff --git a/e2e/oidc-suites/src/login.spec.ts b/e2e/oidc-suites/src/login.spec.ts index 1d1523bc13..5934f94cb5 100644 --- a/e2e/oidc-suites/src/login.spec.ts +++ b/e2e/oidc-suites/src/login.spec.ts @@ -152,7 +152,7 @@ test('oidc client fails to initialize with bad wellknown', async ({ page }) => { await page.getByRole('button', { name: 'Login (Background)' }).click(); await expect(page.locator('.error')).toContainText( - 'Authorization endpoint not found in wellknown configuration', + 'Failed to fetch well-known configuration from:', ); await expect(page.locator('.error')).toContainText('wellknown_error'); }); diff --git a/e2e/oidc-suites/src/par.spec.ts b/e2e/oidc-suites/src/par.spec.ts new file mode 100644 index 0000000000..de224ffba2 --- /dev/null +++ b/e2e/oidc-suites/src/par.spec.ts @@ -0,0 +1,87 @@ +/* + * + * Copyright © 2025 Ping Identity Corporation. All right reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + * + */ +import { test, expect } from '@playwright/test'; +import { pingAmUsername, pingAmPassword } from './utils/demo-users.js'; +import { asyncEvents } from './utils/async-events.js'; + +async function loginJourney(page, username: string, password: string) { + await page.getByLabel('User Name').fill(username); + await page.getByLabel('Password').fill(password); + await page.getByRole('button', { name: 'Login (Journey)' }).click(); + await expect(page.locator('#journey-status')).toContainText('Session established'); +} + +test.describe('PAR (Pushed Authorization Request) login tests', () => { + test('background login with PAR enabled (ParClient) obtains access token', async ({ page }) => { + const { navigate } = asyncEvents(page); + + const parRequests: string[] = []; + page.on('request', (request) => { + if (request.method() === 'POST' && request.url().includes('/par')) { + parRequests.push(request.url()); + } + }); + + await navigate('/par/'); + + // Establish AM session via the Login journey before attempting background PAR auth + await loginJourney(page, pingAmUsername, pingAmPassword); + + // Background button is now enabled — click and wait for the iframe to return a code + await page.getByRole('button', { name: /Login \(Background/ }).click(); + await expect(page.locator('#accessToken-0')).not.toBeEmpty(); + + // PAR POST was made for the background request + expect(parRequests.length).toBeGreaterThan(0); + }); + + test('redirect login with PAR enabled (ParClient) obtains access token and uses slim authorize URL', async ({ + page, + }) => { + const { clickWithRedirect, navigate } = asyncEvents(page); + + const parRequests: string[] = []; + const parAuthorizeUrls: string[] = []; + + page.on('request', (request) => { + if (request.method() === 'POST' && request.url().includes('/par')) { + parRequests.push(request.url()); + } + // Capture the slim PAR authorize redirect — has request_uri, not scope + if (request.url().includes('/authorize') && request.url().includes('request_uri=')) { + parAuthorizeUrls.push(request.url()); + } + }); + + await navigate('/par/'); + + await clickWithRedirect('Login (Redirect', '**/am/XUI/**'); + + await page.getByLabel('User Name').fill(pingAmUsername); + await page.getByRole('textbox', { name: 'Password' }).fill(pingAmPassword); + await clickWithRedirect('Next', 'http://localhost:8443/par/**'); + + expect(page.url()).toContain('code'); + expect(page.url()).toContain('state'); + + await expect(page.locator('#accessToken-0')).not.toBeEmpty(); + + // PAR POST was made + expect(parRequests.length).toBeGreaterThan(0); + + // Slim authorize URL contains only client_id + request_uri (not scope/code_challenge) + expect(parAuthorizeUrls.length).toBeGreaterThan(0); + const authorizeUrl = new URL(parAuthorizeUrls[0]); + expect(authorizeUrl.searchParams.has('client_id')).toBe(true); + expect(authorizeUrl.searchParams.has('request_uri')).toBe(true); + expect(authorizeUrl.searchParams.has('scope')).toBe(false); + expect(authorizeUrl.searchParams.has('code_challenge')).toBe(false); + expect(authorizeUrl.searchParams.has('redirect_uri')).toBe(false); + }); +}); diff --git a/packages/davinci-client/api-report/davinci-client.api.md b/packages/davinci-client/api-report/davinci-client.api.md index e937b32655..1f0898b63a 100644 --- a/packages/davinci-client/api-report/davinci-client.api.md +++ b/packages/davinci-client/api-report/davinci-client.api.md @@ -1,2578 +1,2021 @@ -## API Report File for "@forgerock/davinci-client" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts -import { ActionCreatorWithPayload } from '@reduxjs/toolkit'; -import { ActionTypes } from '@forgerock/sdk-request-middleware'; -import type { AsyncLegacyConfigOptions } from '@forgerock/sdk-types'; -import { BaseQueryFn } from '@reduxjs/toolkit/query'; -import { CustomLogger } from '@forgerock/sdk-logger'; -import { FetchArgs } from '@reduxjs/toolkit/query'; -import { FetchBaseQueryError } from '@reduxjs/toolkit/query'; -import { FetchBaseQueryMeta } from '@reduxjs/toolkit/query'; -import { GenericError } from '@forgerock/sdk-types'; -import { LogLevel } from '@forgerock/sdk-logger'; -import { MutationDefinition } from '@reduxjs/toolkit/query'; -import type { MutationResultSelectorResult } from '@reduxjs/toolkit/query'; -import { QueryDefinition } from '@reduxjs/toolkit/query'; -import { QueryStatus } from '@reduxjs/toolkit/query'; -import { Reducer } from '@reduxjs/toolkit'; -import { RequestMiddleware } from '@forgerock/sdk-request-middleware'; -import { RootState } from '@reduxjs/toolkit/query'; -import { SerializedError } from '@reduxjs/toolkit'; -import { Unsubscribe } from '@reduxjs/toolkit'; - -// @public (undocumented) -export type ActionCollector = - | ActionCollectorNoUrl - | ActionCollectorWithUrl; - -// @public (undocumented) -export interface ActionCollectorNoUrl { - // (undocumented) - category: 'ActionCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type ActionCollectors = - | ActionCollectorWithUrl<'IdpCollector'> - | ActionCollectorNoUrl<'ActionCollector'> - | ActionCollectorNoUrl<'FlowCollector'> - | ActionCollectorNoUrl<'SubmitCollector'>; - -// @public -export type ActionCollectorTypes = - | 'FlowCollector' - | 'SubmitCollector' - | 'IdpCollector' - | 'ActionCollector'; - -// @public (undocumented) -export interface ActionCollectorWithUrl { - // (undocumented) - category: 'ActionCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - url?: string | null; - }; - // (undocumented) - type: T; -} - -export { ActionTypes }; - -// @public (undocumented) -export interface AgreementCollector extends NoValueCollectorBase<'AgreementCollector'> { - // (undocumented) - output: { - key: string; - label: string; - type: string; - titleEnabled: boolean; - title: string; - agreement: { - id: string; - useDynamicAgreement: boolean; - }; - enabled: boolean; - }; -} - -// @public (undocumented) -export type AgreementField = { - type: 'AGREEMENT'; - key: string; - content: string; - titleEnabled: boolean; - title: string; - agreement: { - id: string; - useDynamicAgreement: boolean; - }; - enabled: boolean; -}; - -// @public (undocumented) -export interface AssertionValue extends Omit< - PublicKeyCredential, - 'rawId' | 'response' | 'getClientExtensionResults' | 'toJSON' -> { - // (undocumented) - rawId: string; - // (undocumented) - response: { - clientDataJSON: string; - authenticatorData: string; - signature: string; - userHandle: string | null; - }; -} - -// @public (undocumented) -export interface AttestationValue extends Omit< - PublicKeyCredential, - 'rawId' | 'response' | 'getClientExtensionResults' | 'toJSON' -> { - // (undocumented) - rawId: string; - // (undocumented) - response: { - clientDataJSON: string; - attestationObject: string; - }; -} - -// @public (undocumented) -export interface AutoCollector< - C extends AutoCollectorCategories, - T extends AutoCollectorTypes, - IV = string, - OV = Record, -> { - // (undocumented) - category: C; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: IV; - type: string; - validation?: ValidationRequired[] | null; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - type: string; - config: OV; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type AutoCollectorCategories = 'SingleValueAutoCollector' | 'ObjectValueAutoCollector'; - -// @public (undocumented) -export type AutoCollectors = - | ProtectCollector - | FidoRegistrationCollector - | FidoAuthenticationCollector - | PollingCollector - | SingleValueAutoCollector - | ObjectValueAutoCollector; - -// @public (undocumented) -export type AutoCollectorTypes = SingleValueAutoCollectorTypes | ObjectValueAutoCollectorTypes; - -// @public (undocumented) -export interface CollectorErrors { - // (undocumented) - code: string; - // (undocumented) - message: string; - // (undocumented) - target: string; -} - -// @public -export interface CollectorRichContent { - // (undocumented) - content: string; - // (undocumented) - replacements: RichContentLink[]; -} - -// @public (undocumented) -export type Collectors = - | FlowCollector - | PasswordCollector - | ValidatedPasswordCollector - | TextCollector - | SingleSelectCollector - | IdpCollector - | SubmitCollector - | ActionCollector<'ActionCollector'> - | SingleValueCollector<'SingleValueCollector'> - | MultiSelectCollector - | DeviceAuthenticationCollector - | DeviceRegistrationCollector - | PhoneNumberCollector - | PhoneNumberExtensionCollector - | ReadOnlyCollector - | RichTextCollector - | ValidatedTextCollector - | ProtectCollector - | PollingCollector - | FidoRegistrationCollector - | FidoAuthenticationCollector - | QrCodeCollector - | AgreementCollector - | UnknownCollector; - -// @public -export type CollectorValueType = T extends { - type: 'PasswordCollector'; -} - ? string - : T extends { - type: 'ValidatedPasswordCollector'; - } - ? string - : T extends { - type: 'TextCollector'; - category: 'SingleValueCollector'; - } - ? string - : T extends { - type: 'TextCollector'; - category: 'ValidatedSingleValueCollector'; - } - ? string - : T extends { - type: 'SingleSelectCollector'; - } - ? string - : T extends { - type: 'MultiSelectCollector'; - } - ? string[] - : T extends { - type: 'DeviceRegistrationCollector'; - } - ? string - : T extends { - type: 'DeviceAuthenticationCollector'; - } - ? string - : T extends { - type: 'PhoneNumberCollector'; - } - ? PhoneNumberInputValue - : T extends { - type: 'FidoRegistrationCollector'; - } - ? FidoRegistrationInputValue - : T extends { - type: 'FidoAuthenticationCollector'; - } - ? FidoAuthenticationInputValue - : T extends { - category: 'SingleValueCollector'; - } - ? string - : T extends { - category: 'ValidatedSingleValueCollector'; - } - ? string - : T extends { - category: 'MultiValueCollector'; - } - ? string[] - : - | string - | string[] - | PhoneNumberInputValue - | FidoRegistrationInputValue - | FidoAuthenticationInputValue; - -// @public (undocumented) -export type ComplexValueFields = - | DeviceAuthenticationField - | DeviceRegistrationField - | PhoneNumberField - | PhoneNumberExtensionField - | FidoRegistrationField - | FidoAuthenticationField - | PollingField; - -// @public (undocumented) -export interface ContinueNode { - // (undocumented) - cache: { - key: string; - }; - // (undocumented) - client: { - action: string; - collectors: Collectors[]; - description?: string; - name?: string; - status: 'continue'; - }; - // (undocumented) - error: null; - // (undocumented) - httpStatus: number; - // (undocumented) - server: { - _links?: Links; - id?: string; - interactionId?: string; - interactionToken?: string; - href?: string; - eventName?: string; - status: 'continue'; - }; - // (undocumented) - status: 'continue'; -} - -export { CustomLogger }; - -// @public -export type CustomPollingStatus = string & {}; - -// @public -export function davinci(input: { - config: DaVinciConfig; - requestMiddleware?: RequestMiddleware[]; - logger?: { - level: LogLevel; - custom?: CustomLogger; - }; -}): Promise<{ - subscribe: (listener: () => void) => Unsubscribe; - externalIdp: () => () => Promise; - flow: (action: DaVinciAction) => InitFlow; - next: (args?: DaVinciRequest) => Promise; - resume: (input: { continueToken: string }) => Promise; - start: ( - options?: StartOptions | undefined, - ) => Promise; - update: < - T extends SingleValueCollectors | MultiSelectCollector | ObjectValueCollectors | AutoCollectors, - >( - collector: T, - ) => Updater; - validate: ( - collector: - | SingleValueCollectors - | ObjectValueCollectors - | MultiValueCollectors - | AutoCollectors, - ) => Validator; - pollStatus: (collector: PollingCollector) => Poller; - getClient: () => - | { - action: string; - collectors: Collectors[]; - description?: string; - name?: string; - status: 'continue'; - } - | { - action: string; - collectors: Collectors[]; - description?: string; - name?: string; - status: 'error'; - } - | { - status: 'failure'; - } - | { - status: 'start'; - } - | { - authorization?: { - code?: string; - state?: string; - }; - status: 'success'; - } - | null; - getCollectors: () => Collectors[]; - getError: () => DaVinciError | null; - getErrorCollectors: () => CollectorErrors[]; - getNode: () => ContinueNode | ErrorNode | FailureNode | StartNode | SuccessNode; - getServer: () => - | { - _links?: Links; - id?: string; - interactionId?: string; - interactionToken?: string; - href?: string; - eventName?: string; - status: 'continue'; - } - | { - _links?: Links; - eventName?: string; - id?: string; - interactionId?: string; - interactionToken?: string; - status: 'error'; - } - | { - _links?: Links; - eventName?: string; - href?: string; - id?: string; - interactionId?: string; - interactionToken?: string; - status: 'failure'; - } - | { - status: 'start'; - } - | { - _links?: Links; - eventName?: string; - id?: string; - interactionId?: string; - interactionToken?: string; - href?: string; - session?: string; - status: 'success'; - } - | null; - cache: { - getLatestResponse: () => - | (( - state: RootState< - { - flow: MutationDefinition< - any, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - any - >; - next: MutationDefinition< - any, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - any - >; - start: MutationDefinition< - StartOptions | undefined, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - unknown - >; - resume: QueryDefinition< - { - serverInfo: ContinueNode['server']; - continueToken: string; - }, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - unknown - >; - poll: MutationDefinition< - { - endpoint: string; - interactionId: string; - }, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - unknown - >; - }, - never, - 'davinci' - >, - ) => - | ({ - requestId?: undefined; - status: QueryStatus.uninitialized; - data?: undefined; - error?: undefined; - endpointName?: string; - startedTimeStamp?: undefined; - fulfilledTimeStamp?: undefined; - } & { - status: QueryStatus.uninitialized; - isUninitialized: true; - isLoading: false; - isSuccess: false; - isError: false; - }) - | ({ - status: QueryStatus.fulfilled; - } & Omit< - { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - }, - 'data' | 'fulfilledTimeStamp' - > & - Required< - Pick< - { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - }, - 'data' | 'fulfilledTimeStamp' - > - > & { - error: undefined; - } & { - status: QueryStatus.fulfilled; - isUninitialized: false; - isLoading: false; - isSuccess: true; - isError: false; - }) - | ({ - status: QueryStatus.pending; - } & { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - } & { - data?: undefined; - } & { - status: QueryStatus.pending; - isUninitialized: false; - isLoading: true; - isSuccess: false; - isError: false; - }) - | ({ - status: QueryStatus.rejected; - } & Omit< - { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - }, - 'error' - > & - Required< - Pick< - { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - }, - 'error' - > - > & { - status: QueryStatus.rejected; - isUninitialized: false; - isLoading: false; - isSuccess: false; - isError: true; - })) - | { - error: { - message: string; - type: string; - }; - }; - getResponseWithId: (requestId: string) => - | (( - state: RootState< - { - flow: MutationDefinition< - any, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - any - >; - next: MutationDefinition< - any, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - any - >; - start: MutationDefinition< - StartOptions | undefined, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - unknown - >; - resume: QueryDefinition< - { - serverInfo: ContinueNode['server']; - continueToken: string; - }, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - unknown - >; - poll: MutationDefinition< - { - endpoint: string; - interactionId: string; - }, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - unknown - >; - }, - never, - 'davinci' - >, - ) => - | ({ - requestId?: undefined; - status: QueryStatus.uninitialized; - data?: undefined; - error?: undefined; - endpointName?: string; - startedTimeStamp?: undefined; - fulfilledTimeStamp?: undefined; - } & { - status: QueryStatus.uninitialized; - isUninitialized: true; - isLoading: false; - isSuccess: false; - isError: false; - }) - | ({ - status: QueryStatus.fulfilled; - } & Omit< - { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - }, - 'data' | 'fulfilledTimeStamp' - > & - Required< - Pick< - { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - }, - 'data' | 'fulfilledTimeStamp' - > - > & { - error: undefined; - } & { - status: QueryStatus.fulfilled; - isUninitialized: false; - isLoading: false; - isSuccess: true; - isError: false; - }) - | ({ - status: QueryStatus.pending; - } & { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - } & { - data?: undefined; - } & { - status: QueryStatus.pending; - isUninitialized: false; - isLoading: true; - isSuccess: false; - isError: false; - }) - | ({ - status: QueryStatus.rejected; - } & Omit< - { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - }, - 'error' - > & - Required< - Pick< - { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - }, - 'error' - > - > & { - status: QueryStatus.rejected; - isUninitialized: false; - isLoading: false; - isSuccess: false; - isError: true; - })) - | { - error: { - message: string; - type: string; - }; - }; - }; -}>; - -// @public -export interface DaVinciAction { - // (undocumented) - action: string; -} - -// @public -export interface DaVinciBaseResponse { - // (undocumented) - capabilityName?: string; - // (undocumented) - companyId?: string; - // (undocumented) - connectionId?: string; - // (undocumented) - connectorId?: string; - // (undocumented) - id?: string; - // (undocumented) - interactionId?: string; - // (undocumented) - interactionToken?: string; - // (undocumented) - isResponseCompatibleWithMobileAndWebSdks?: boolean; - // (undocumented) - status?: string; -} - -// @public -export type DaVinciCacheEntry = { - data?: DaVinciBaseResponse; - error?: { - data: DaVinciBaseResponse; - status: number; - }; -} & { - data?: any; - error?: any; -} & MutationResultSelectorResult; - -// @public (undocumented) -export type DavinciClient = Awaited>; - -// @public (undocumented) -export interface DaVinciConfig extends AsyncLegacyConfigOptions { - // (undocumented) - responseType?: string; -} - -// @public (undocumented) -export interface DaVinciError extends Omit { - // (undocumented) - collectors?: CollectorErrors[]; - // (undocumented) - internalHttpStatus?: number; - // (undocumented) - message: string; - // (undocumented) - status: 'error' | 'failure' | 'unknown'; -} - -// @public (undocumented) -export interface DaVinciErrorCacheEntry { - // (undocumented) - endpointName: 'next' | 'flow' | 'start'; - // (undocumented) - error: { - data: T; - }; - // (undocumented) - fulfilledTimeStamp: number; - // (undocumented) - isError: boolean; - // (undocumented) - isLoading: boolean; - // (undocumented) - isSuccess: boolean; - // (undocumented) - isUninitialized: boolean; - // (undocumented) - requestId: string; - // (undocumented) - startedTimeStamp: number; - // (undocumented) - status: 'fulfilled' | 'pending' | 'rejected'; -} - -// @public (undocumented) -export interface DavinciErrorResponse extends DaVinciBaseResponse { - // (undocumented) - cause?: string | null; - // (undocumented) - code: string | number; - // (undocumented) - details?: ErrorDetail[]; - // (undocumented) - doNotSendToOE?: boolean; - // (undocumented) - error?: { - code?: string; - message?: string; - }; - // (undocumented) - errorCategory?: string; - // (undocumented) - errorMessage?: string; - // (undocumented) - expected?: boolean; - // (undocumented) - httpResponseCode: number; - // (undocumented) - isErrorCustomized?: boolean; - // (undocumented) - message: string; - // (undocumented) - metricAttributes?: { - [key: string]: unknown; - }; -} - -// @public (undocumented) -export interface DaVinciFailureResponse extends DaVinciBaseResponse { - // (undocumented) - error?: { - code?: string; - message?: string; - [key: string]: unknown; - }; -} - -// @public (undocumented) -export type DaVinciField = - | ComplexValueFields - | MultiValueFields - | ReadOnlyFields - | RedirectFields - | SingleValueFields; - -// @public -export interface DaVinciNextResponse extends DaVinciBaseResponse { - // (undocumented) - eventName?: string; - // (undocumented) - form?: { - name?: string; - description?: string; - components?: { - fields?: DaVinciField[]; - }; - }; - // (undocumented) - formData?: { - value?: { - [key: string]: string; - }; - }; - // (undocumented) - _links?: Links; -} - -// @public -export interface DaVinciPollResponse extends DaVinciBaseResponse { - // (undocumented) - eventName?: string; - // (undocumented) - _links?: Links; - // (undocumented) - success?: boolean; -} - -// @public (undocumented) -export interface DaVinciRequest { - // (undocumented) - eventName: string; - // (undocumented) - id: string; - // (undocumented) - interactionId: string; - // (undocumented) - parameters: { - eventType: 'submit' | 'action' | 'polling'; - data: { - actionKey: string; - formData?: Record; - }; - }; -} - -// @public (undocumented) -export interface DaVinciSuccessResponse extends DaVinciBaseResponse { - // (undocumented) - authorizeResponse?: OAuthDetails; - // (undocumented) - environment: { - id: string; - [key: string]: unknown; - }; - // (undocumented) - _links?: Links; - // (undocumented) - resetCookie?: boolean; - // (undocumented) - session?: { - id?: string; - [key: string]: unknown; - }; - // (undocumented) - sessionToken?: string; - // (undocumented) - sessionTokenMaxAge?: number; - // (undocumented) - status: string; - // (undocumented) - subFlowSettings?: { - cssLinks?: unknown[]; - cssUrl?: unknown; - jsLinks?: unknown[]; - loadingScreenSettings?: unknown; - reactSkUrl?: unknown; - }; - // (undocumented) - success: true; -} - -// @public (undocumented) -export type DeviceAuthenticationCollector = ObjectOptionsCollectorWithObjectValue< - 'DeviceAuthenticationCollector', - DeviceValue ->; - -// @public (undocumented) -export type DeviceAuthenticationField = { - type: 'DEVICE_AUTHENTICATION'; - key: string; - label: string; - options: { - type: string; - iconSrc: string; - title: string; - id: string; - default: boolean; - description: string; - }[]; - required: boolean; -}; - -// @public (undocumented) -export interface DeviceOptionNoDefault { - // (undocumented) - content: string; - // (undocumented) - key: string; - // (undocumented) - label: string; - // (undocumented) - type: string; - // (undocumented) - value: string; -} - -// @public (undocumented) -export interface DeviceOptionWithDefault { - // (undocumented) - content: string; - // (undocumented) - default: boolean; - // (undocumented) - key: string; - // (undocumented) - label: string; - // (undocumented) - type: string; - // (undocumented) - value: string; -} - -// @public (undocumented) -export type DeviceRegistrationCollector = ObjectOptionsCollectorWithStringValue< - 'DeviceRegistrationCollector', - string ->; - -// @public (undocumented) -export type DeviceRegistrationField = { - type: 'DEVICE_REGISTRATION'; - key: string; - label: string; - options: { - type: string; - iconSrc: string; - title: string; - description: string; - }[]; - required: boolean; -}; - -// @public (undocumented) -export interface DeviceValue { - // (undocumented) - id: string; - // (undocumented) - type: string; - // (undocumented) - value: string; -} - -// @public (undocumented) -export interface ErrorDetail { - // (undocumented) - message?: string; - // (undocumented) - rawResponse?: { - _embedded?: { - users?: Array; - }; - code?: string; - count?: number; - details?: NestedErrorDetails[]; - id?: string; - message?: string; - size?: number; - userFilter?: string; - [key: string]: unknown; - }; - // (undocumented) - statusCode?: number; -} - -// @public (undocumented) -export interface ErrorNode { - // (undocumented) - cache: { - key: string; - }; - // (undocumented) - client: { - action: string; - collectors: Collectors[]; - description?: string; - name?: string; - status: 'error'; - }; - // (undocumented) - error: DaVinciError; - // (undocumented) - httpStatus: number; - // (undocumented) - server: { - _links?: Links; - eventName?: string; - id?: string; - interactionId?: string; - interactionToken?: string; - status: 'error'; - } | null; - // (undocumented) - status: 'error'; -} - -// @public (undocumented) -export interface FailureNode { - // (undocumented) - cache: { - key: string; - }; - // (undocumented) - client: { - status: 'failure'; - }; - // (undocumented) - error: DaVinciError; - // (undocumented) - httpStatus: number; - // (undocumented) - server: { - _links?: Links; - eventName?: string; - href?: string; - id?: string; - interactionId?: string; - interactionToken?: string; - status: 'failure'; - } | null; - // (undocumented) - status: 'failure'; -} - -// @public -export function fido(): FidoClient; - -// @public (undocumented) -export type FidoAuthenticationCollector = AutoCollector< - 'ObjectValueAutoCollector', - 'FidoAuthenticationCollector', - FidoAuthenticationInputValue, - FidoAuthenticationOutputValue ->; - -// @public (undocumented) -export type FidoAuthenticationField = { - type: 'FIDO2'; - key: string; - label: string; - publicKeyCredentialRequestOptions: FidoAuthenticationOptions; - action: 'AUTHENTICATE'; - trigger: string; - required: boolean; -}; - -// @public (undocumented) -export interface FidoAuthenticationInputValue { - // (undocumented) - assertionValue?: AssertionValue; -} - -// @public (undocumented) -export interface FidoAuthenticationOptions extends Omit< - PublicKeyCredentialRequestOptions, - 'challenge' | 'allowCredentials' -> { - // (undocumented) - allowCredentials?: { - id: number[]; - transports?: AuthenticatorTransport[]; - type: PublicKeyCredentialType; - }[]; - // (undocumented) - challenge: number[]; -} - -// @public (undocumented) -export interface FidoAuthenticationOutputValue { - // (undocumented) - action: 'AUTHENTICATE'; - // (undocumented) - publicKeyCredentialRequestOptions: FidoAuthenticationOptions; - // (undocumented) - trigger: string; -} - -// @public (undocumented) -export interface FidoClient { - authenticate: ( - options: FidoAuthenticationOptions, - ) => Promise; - register: ( - options: FidoRegistrationOptions, - ) => Promise; -} - -// @public (undocumented) -export type FidoRegistrationCollector = AutoCollector< - 'ObjectValueAutoCollector', - 'FidoRegistrationCollector', - FidoRegistrationInputValue, - FidoRegistrationOutputValue ->; - -// @public (undocumented) -export type FidoRegistrationField = { - type: 'FIDO2'; - key: string; - label: string; - publicKeyCredentialCreationOptions: FidoRegistrationOptions; - action: 'REGISTER'; - trigger: string; - required: boolean; -}; - -// @public (undocumented) -export interface FidoRegistrationInputValue { - // (undocumented) - attestationValue?: AttestationValue; -} - -// @public (undocumented) -export interface FidoRegistrationOptions extends Omit< - PublicKeyCredentialCreationOptions, - 'challenge' | 'user' | 'pubKeyCredParams' | 'excludeCredentials' -> { - // (undocumented) - challenge: number[]; - // (undocumented) - excludeCredentials?: { - id: number[]; - transports?: AuthenticatorTransport[]; - type: PublicKeyCredentialType; - }[]; - // (undocumented) - pubKeyCredParams: { - alg: string | number; - type: PublicKeyCredentialType; - }[]; - // (undocumented) - user: { - id: number[]; - name: string; - displayName: string; - }; -} - -// @public (undocumented) -export interface FidoRegistrationOutputValue { - // (undocumented) - action: 'REGISTER'; - // (undocumented) - publicKeyCredentialCreationOptions: FidoRegistrationOptions; - // (undocumented) - trigger: string; -} - -// @public (undocumented) -export type FlowCollector = ActionCollectorNoUrl<'FlowCollector'>; - -// @public (undocumented) -export type FlowNode = ContinueNode | ErrorNode | StartNode | SuccessNode | FailureNode; - -// @public -export type GetClient = - | StartNode['client'] - | ContinueNode['client'] - | ErrorNode['client'] - | SuccessNode['client'] - | FailureNode['client']; - -// @public (undocumented) -export type IdpCollector = ActionCollectorWithUrl<'IdpCollector'>; - -// @public (undocumented) -export type InferActionCollectorType = T extends 'IdpCollector' - ? IdpCollector - : T extends 'SubmitCollector' - ? SubmitCollector - : T extends 'FlowCollector' - ? FlowCollector - : ActionCollectorWithUrl<'ActionCollector'> | ActionCollectorNoUrl<'ActionCollector'>; - -// @public -export type InferAutoCollectorType = T extends 'ProtectCollector' - ? ProtectCollector - : T extends 'PollingCollector' - ? PollingCollector - : T extends 'FidoRegistrationCollector' - ? FidoRegistrationCollector - : T extends 'FidoAuthenticationCollector' - ? FidoAuthenticationCollector - : T extends 'ObjectValueAutoCollector' - ? ObjectValueAutoCollector - : SingleValueAutoCollector; - -// @public -export type InferMultiValueCollectorType = - T extends 'MultiSelectCollector' - ? MultiValueCollectorWithValue<'MultiSelectCollector'> - : - | MultiValueCollectorWithValue<'MultiValueCollector'> - | MultiValueCollectorNoValue<'MultiValueCollector'>; - -// @public -export type InferNoValueCollectorType = - T extends 'ReadOnlyCollector' - ? ReadOnlyCollector - : T extends 'RichTextCollector' - ? RichTextCollector - : T extends 'QrCodeCollector' - ? QrCodeCollector - : T extends 'AgreementCollector' - ? AgreementCollector - : NoValueCollectorBase<'NoValueCollector'>; - -// @public -export type InferSingleValueCollectorType = - T extends 'TextCollector' - ? TextCollector - : T extends 'SingleSelectCollector' - ? SingleSelectCollector - : T extends 'ValidatedTextCollector' - ? ValidatedTextCollector - : T extends 'PasswordCollector' - ? PasswordCollector - : T extends 'ValidatedPasswordCollector' - ? ValidatedPasswordCollector - : - | SingleValueCollectorWithValue<'SingleValueCollector'> - | SingleValueCollectorNoValue<'SingleValueCollector'>; - -// @public (undocumented) -export type InferValueObjectCollectorType = - T extends 'DeviceAuthenticationCollector' - ? DeviceAuthenticationCollector - : T extends 'DeviceRegistrationCollector' - ? DeviceRegistrationCollector - : T extends 'PhoneNumberCollector' - ? PhoneNumberCollector - : T extends 'PhoneNumberExtensionCollector' - ? PhoneNumberExtensionCollector - : - | ObjectOptionsCollectorWithObjectValue<'ObjectValueCollector'> - | ObjectOptionsCollectorWithStringValue<'ObjectValueCollector'>; - -// @public (undocumented) -export type InitFlow = () => Promise; - -// @public (undocumented) -export interface InternalErrorResponse { - // (undocumented) - error: Omit & { - message: string; - }; - // (undocumented) - type: 'internal_error'; -} - -// @public (undocumented) -export interface Links { - // (undocumented) - [key: string]: { - href?: string; - }; -} - -export { LogLevel }; - -// @public (undocumented) -export type MultiSelectCollector = MultiValueCollectorWithValue<'MultiSelectCollector'>; - -// @public (undocumented) -export type MultiSelectField = { - inputType: 'MULTI_SELECT'; - key: string; - label: string; - options: { - label: string; - value: string; - }[]; - required?: boolean; - type: 'CHECKBOX' | 'COMBOBOX'; -}; - -// @public (undocumented) -export type MultiValueCollector = - | MultiValueCollectorWithValue - | MultiValueCollectorNoValue; - -// @public (undocumented) -export interface MultiValueCollectorNoValue { - // (undocumented) - category: 'MultiValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string[]; - type: string; - validation: ValidationRequired[] | null; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - options: SelectorOption[]; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type MultiValueCollectors = - | MultiValueCollectorWithValue<'MultiValueCollector'> - | MultiValueCollectorWithValue<'MultiSelectCollector'>; - -// @public -export type MultiValueCollectorTypes = 'MultiSelectCollector' | 'MultiValueCollector'; - -// @public (undocumented) -export interface MultiValueCollectorWithValue { - // (undocumented) - category: 'MultiValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string[]; - type: string; - validation: ValidationRequired[] | null; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - value: string[]; - options: SelectorOption[]; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type MultiValueFields = MultiSelectField; - -// @public -export interface NestedErrorDetails { - // (undocumented) - code?: string; - // (undocumented) - innerError?: { - history?: string; - unsatisfiedRequirements?: string[]; - failuresRemaining?: number; - }; - // (undocumented) - message?: string; - // (undocumented) - target?: string; -} - -// @public -export const nextCollectorValues: ActionCreatorWithPayload< - { - fields: DaVinciField[]; - formData: { - value: Record; - }; - }, - string ->; - -// @public -export const nodeCollectorReducer: Reducer< - ( - | TextCollector - | SingleSelectCollector - | ValidatedTextCollector - | PasswordCollector - | ValidatedPasswordCollector - | MultiSelectCollector - | PhoneNumberExtensionCollector - | DeviceAuthenticationCollector - | DeviceRegistrationCollector - | PhoneNumberCollector - | IdpCollector - | SubmitCollector - | FlowCollector - | QrCodeCollector - | ReadOnlyCollector - | RichTextCollector - | AgreementCollector - | UnknownCollector - | ProtectCollector - | FidoRegistrationCollector - | FidoAuthenticationCollector - | PollingCollector - | ActionCollector<'ActionCollector'> - | SingleValueCollector<'SingleValueCollector'> - )[] -> & { - getInitialState: () => ( - | TextCollector - | SingleSelectCollector - | ValidatedTextCollector - | PasswordCollector - | ValidatedPasswordCollector - | MultiSelectCollector - | PhoneNumberExtensionCollector - | DeviceAuthenticationCollector - | DeviceRegistrationCollector - | PhoneNumberCollector - | IdpCollector - | SubmitCollector - | FlowCollector - | QrCodeCollector - | ReadOnlyCollector - | RichTextCollector - | AgreementCollector - | UnknownCollector - | ProtectCollector - | FidoRegistrationCollector - | FidoAuthenticationCollector - | PollingCollector - | ActionCollector<'ActionCollector'> - | SingleValueCollector<'SingleValueCollector'> - )[]; -}; - -// @public (undocumented) -export type NodeStates = StartNode | ContinueNode | ErrorNode | SuccessNode | FailureNode; - -// @public (undocumented) -export type NoValueCollector = InferNoValueCollectorType; - -// @public (undocumented) -export interface NoValueCollectorBase { - // (undocumented) - category: 'NoValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type NoValueCollectors = - | NoValueCollectorBase<'NoValueCollector'> - | ReadOnlyCollector - | RichTextCollector - | QrCodeCollector - | AgreementCollector; - -// @public -export type NoValueCollectorTypes = - | 'ReadOnlyCollector' - | 'RichTextCollector' - | 'NoValueCollector' - | 'QrCodeCollector' - | 'AgreementCollector'; - -// @public -export interface OAuthDetails { - // (undocumented) - [key: string]: unknown; - // (undocumented) - code?: string; - // (undocumented) - state?: string; -} - -// @public (undocumented) -export interface ObjectOptionsCollectorWithObjectValue< - T extends ObjectValueCollectorTypes, - V = Record, - D = Record, -> { - // (undocumented) - category: 'ObjectValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: V; - type: string; - validation: ValidationRequired[] | null; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - options: DeviceOptionWithDefault[]; - value?: D | null; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export interface ObjectOptionsCollectorWithStringValue< - T extends ObjectValueCollectorTypes, - V = string, -> { - // (undocumented) - category: 'ObjectValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: V; - type: string; - validation: ValidationRequired[] | null; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - options: DeviceOptionNoDefault[]; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type ObjectValueAutoCollector = AutoCollector< - 'ObjectValueAutoCollector', - 'ObjectValueAutoCollector', - Record ->; - -// @public (undocumented) -export type ObjectValueAutoCollectorTypes = - | 'ObjectValueAutoCollector' - | 'FidoRegistrationCollector' - | 'FidoAuthenticationCollector'; - -// @public (undocumented) -export type ObjectValueCollector = - | ObjectOptionsCollectorWithObjectValue - | ObjectOptionsCollectorWithStringValue - | ObjectValueCollectorWithObjectValue; - -// @public (undocumented) -export type ObjectValueCollectors = - | DeviceAuthenticationCollector - | DeviceRegistrationCollector - | PhoneNumberCollector - | PhoneNumberExtensionCollector - | ObjectOptionsCollectorWithObjectValue<'ObjectSelectCollector'> - | ObjectOptionsCollectorWithStringValue<'ObjectSelectCollector'>; - -// @public -export type ObjectValueCollectorTypes = - | 'DeviceAuthenticationCollector' - | 'DeviceRegistrationCollector' - | 'PhoneNumberCollector' - | 'PhoneNumberExtensionCollector' - | 'ObjectOptionsCollector' - | 'ObjectValueCollector' - | 'ObjectSelectCollector'; - -// @public (undocumented) -export interface ObjectValueCollectorWithObjectValue< - T extends ObjectValueCollectorTypes, - IV = Record, - OV = Record, -> { - // (undocumented) - category: 'ObjectValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: IV; - type: string; - validation: (ValidationRequired | ValidationPhoneNumber)[] | null; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - value?: OV | null; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export interface OutgoingQueryParams { - // (undocumented) - [key: string]: string | string[]; -} - -// @public (undocumented) -export interface PasswordCollector { - // (undocumented) - category: 'SingleValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string | number | boolean; - type: string; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - verify: boolean; - }; - // (undocumented) - type: 'PasswordCollector'; -} - -// @public -export type PasswordField = { - type: 'PASSWORD' | 'PASSWORD_VERIFY'; - key: string; - label: string; - required?: boolean; - verify?: boolean; - passwordPolicy?: PasswordPolicy; -}; - -// @public (undocumented) -export interface PasswordPolicy { - // (undocumented) - createdAt?: string; - // (undocumented) - default?: boolean; - // (undocumented) - description?: string; - // (undocumented) - excludesCommonlyUsed?: boolean; - // (undocumented) - excludesProfileData?: boolean; - // (undocumented) - history?: { - count?: number; - retentionDays?: number; - }; - // (undocumented) - id?: string; - // (undocumented) - length?: { - min?: number; - max?: number; - }; - // (undocumented) - lockout?: { - failureCount?: number; - durationSeconds?: number; - }; - // (undocumented) - maxAgeDays?: number; - // (undocumented) - maxRepeatedCharacters?: number; - // (undocumented) - minAgeDays?: number; - // (undocumented) - minCharacters?: Record; - // (undocumented) - minUniqueCharacters?: number; - // (undocumented) - name?: string; - // (undocumented) - notSimilarToCurrent?: boolean; - // (undocumented) - populationCount?: number; - // (undocumented) - updatedAt?: string; -} - -// @public (undocumented) -export type PhoneNumberCollector = ObjectValueCollectorWithObjectValue< - 'PhoneNumberCollector', - PhoneNumberInputValue, - PhoneNumberOutputValue ->; - -// @public (undocumented) -export interface PhoneNumberExtensionCollector { - // (undocumented) - category: 'ObjectValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: PhoneNumberExtensionInputValue; - type: string; - validation: (ValidationRequired | ValidationPhoneNumber)[] | null; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - extensionLabel: string; - value: PhoneNumberExtensionOutputValue; - }; - // (undocumented) - type: 'PhoneNumberExtensionCollector'; -} - -// @public (undocumented) -export type PhoneNumberExtensionField = PhoneNumberField & { - showExtension: boolean; - extensionLabel: string; -}; - -// @public (undocumented) -export interface PhoneNumberExtensionInputValue { - // (undocumented) - countryCode: string; - // (undocumented) - extension: string; - // (undocumented) - phoneNumber: string; -} - -// @public (undocumented) -export interface PhoneNumberExtensionOutputValue { - // (undocumented) - countryCode?: string; - // (undocumented) - extension?: string; - // (undocumented) - phoneNumber?: string; -} - -// @public (undocumented) -export type PhoneNumberField = { - type: 'PHONE_NUMBER'; - key: string; - label: string; - required: boolean; - defaultCountryCode: string | null; - validatePhoneNumber: boolean; -}; - -// @public (undocumented) -export interface PhoneNumberInputValue { - // (undocumented) - countryCode: string; - // (undocumented) - phoneNumber: string; -} - -// @public (undocumented) -export interface PhoneNumberOutputValue { - // (undocumented) - countryCode?: string; - // (undocumented) - phoneNumber?: string; -} - -// @public (undocumented) -export type Poller = () => Promise; - -// @public (undocumented) -export type PollingCollector = AutoCollector< - 'SingleValueAutoCollector', - 'PollingCollector', - string, - PollingOutputValue ->; - -// @public (undocumented) -export type PollingField = { - type: 'POLLING'; - key: string; - pollInterval: number; - pollRetries: number; - pollChallengeStatus?: boolean; - challenge?: string; -}; - -// @public (undocumented) -export interface PollingOutputValue { - // (undocumented) - challenge?: string; - // (undocumented) - pollChallengeStatus?: boolean; - // (undocumented) - pollInterval: number; - // (undocumented) - pollRetries: number; - // (undocumented) - retriesRemaining?: number; -} - -// @public (undocumented) -export type PollingStatus = PollingStatusContinue | PollingStatusChallenge; - -// @public (undocumented) -export type PollingStatusChallenge = - | PollingStatusChallengeComplete - | 'expired' - | 'timedOut' - | 'error'; - -// @public (undocumented) -export type PollingStatusChallengeComplete = - | 'approved' - | 'denied' - | 'continue' - | CustomPollingStatus; - -// @public (undocumented) -export type PollingStatusContinue = 'continue' | 'timedOut'; - -// @public (undocumented) -export type ProtectCollector = AutoCollector< - 'SingleValueAutoCollector', - 'ProtectCollector', - string, - ProtectOutputValue ->; - -// @public (undocumented) -export type ProtectField = { - type: 'PROTECT'; - key: string; - behavioralDataCollection: boolean; - universalDeviceIdentification: boolean; -}; - -// @public -export interface ProtectOutputValue { - // (undocumented) - behavioralDataCollection: boolean; - // (undocumented) - universalDeviceIdentification: boolean; -} - -// @public -export interface QrCodeCollector extends NoValueCollectorBase<'QrCodeCollector'> { - // (undocumented) - output: NoValueCollectorBase<'QrCodeCollector'>['output'] & { - src: string; - }; -} - -// @public (undocumented) -export type QrCodeField = { - type: 'QR_CODE'; - key: string; - content: string; - fallbackText?: string; -}; - -// @public -export interface ReadOnlyCollector extends NoValueCollectorBase<'ReadOnlyCollector'> { - // (undocumented) - output: NoValueCollectorBase<'ReadOnlyCollector'>['output'] & { - content: string; - }; -} - -// @public -export type ReadOnlyField = { - type: 'LABEL'; - content: string; - richContent?: RichContent; - key?: string; -}; - -// @public (undocumented) -export type ReadOnlyFields = ReadOnlyField | QrCodeField | AgreementField; - -// @public (undocumented) -export type RedirectField = { - type: 'SOCIAL_LOGIN_BUTTON'; - key: string; - label: string; - links: Links; -}; - -// @public (undocumented) -export type RedirectFields = RedirectField; - -export { RequestMiddleware }; - -// @public -export type RichContent = { - content: string; - replacements?: Record; -}; - -// @public -export interface RichContentLink { - // (undocumented) - href: string; - // (undocumented) - key: string; - // (undocumented) - target?: '_self' | '_blank'; - // (undocumented) - type: 'link'; - // (undocumented) - value: string; -} - -// @public -export type RichContentReplacement = { - type: 'link'; - value: string; - href: string; - target?: '_self' | '_blank'; -}; - -// @public -export interface RichTextCollector extends NoValueCollectorBase<'RichTextCollector'> { - // (undocumented) - output: NoValueCollectorBase<'RichTextCollector'>['output'] & { - content: string; - richContent: CollectorRichContent; - }; -} - -// @public (undocumented) -export interface SelectorOption { - // (undocumented) - label: string; - // (undocumented) - value: string; -} - -// @public (undocumented) -export type SingleSelectCollector = SingleSelectCollectorWithValue<'SingleSelectCollector'>; - -// @public (undocumented) -export interface SingleSelectCollectorNoValue { - // (undocumented) - category: 'SingleValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string | number | boolean; - type: string; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - options: SelectorOption[]; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export interface SingleSelectCollectorWithValue { - // (undocumented) - category: 'SingleValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string | number | boolean; - type: string; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - value: string | number | boolean; - options: SelectorOption[]; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type SingleSelectField = { - inputType: 'SINGLE_SELECT'; - key: string; - label: string; - options: { - label: string; - value: string; - }[]; - required?: boolean; - type: 'RADIO' | 'DROPDOWN'; -}; - -// @public (undocumented) -export type SingleValueAutoCollector = AutoCollector< - 'SingleValueAutoCollector', - 'SingleValueAutoCollector', - string ->; - -// @public (undocumented) -export type SingleValueAutoCollectorTypes = - | 'SingleValueAutoCollector' - | 'ProtectCollector' - | 'PollingCollector'; - -// @public -export type SingleValueCollector = - | SingleValueCollectorWithValue - | SingleValueCollectorNoValue; - -// @public (undocumented) -export interface SingleValueCollectorNoValue { - // (undocumented) - category: 'SingleValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string | number | boolean; - type: string; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type SingleValueCollectors = - | PasswordCollector - | ValidatedPasswordCollector - | SingleSelectCollectorWithValue<'SingleSelectCollector'> - | SingleValueCollectorWithValue<'SingleValueCollector'> - | SingleValueCollectorWithValue<'TextCollector'> - | ValidatedSingleValueCollectorWithValue<'TextCollector'>; - -// @public -export type SingleValueCollectorTypes = - | 'PasswordCollector' - | 'ValidatedPasswordCollector' - | 'SingleValueCollector' - | 'SingleSelectCollector' - | 'SingleSelectObjectCollector' - | 'TextCollector' - | 'ValidatedTextCollector'; - -// @public (undocumented) -export interface SingleValueCollectorWithValue { - // (undocumented) - category: 'SingleValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string | number | boolean; - type: string; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - value: string | number | boolean; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type SingleValueFields = - | StandardField - | PasswordField - | ValidatedField - | SingleSelectField - | ProtectField; - -// @public (undocumented) -export type StandardField = { - type: 'TEXT' | 'SUBMIT_BUTTON' | 'FLOW_BUTTON' | 'FLOW_LINK' | 'BUTTON'; - key: string; - label: string; - required?: boolean; -}; - -// @public (undocumented) -export interface StartNode { - // (undocumented) - cache: null; - // (undocumented) - client: { - status: 'start'; - }; - // (undocumented) - error: DaVinciError | null; - // (undocumented) - server: { - status: 'start'; - }; - // (undocumented) - status: 'start'; -} - -// @public (undocumented) -export interface StartOptions { - // (undocumented) - query: Query; -} - -// @public (undocumented) -export type SubmitCollector = ActionCollectorNoUrl<'SubmitCollector'>; - -// @public (undocumented) -export interface SuccessNode { - // (undocumented) - cache: { - key: string; - }; - // (undocumented) - client: { - authorization?: { - code?: string; - state?: string; - }; - status: 'success'; - } | null; - // (undocumented) - error: null; - // (undocumented) - httpStatus: number; - // (undocumented) - server: { - _links?: Links; - eventName?: string; - id?: string; - interactionId?: string; - interactionToken?: string; - href?: string; - session?: string; - status: 'success'; - }; - // (undocumented) - status: 'success'; -} - -// @public (undocumented) -export type TextCollector = SingleValueCollectorWithValue<'TextCollector'>; - -// @public (undocumented) -export interface ThrownQueryError { - // (undocumented) - error: FetchBaseQueryError; - // (undocumented) - isHandledError: boolean; - // (undocumented) - meta: FetchBaseQueryMeta; -} - -// @public -export type UnknownCollector = { - category: 'UnknownCollector'; - error: string | null; - type: 'UnknownCollector'; - id: string; - name: string; - output: { - key: string; - label: string; - type: string; - }; -}; - -// @public (undocumented) -export type UnknownField = Record; - -// @public (undocumented) -export const updateCollectorValues: ActionCreatorWithPayload< - { - id: string; - value: - | string - | string[] - | PhoneNumberInputValue - | PhoneNumberExtensionInputValue - | FidoRegistrationInputValue - | FidoAuthenticationInputValue; - index?: number; - }, - string ->; - -// @public -export type Updater = ( - value: CollectorValueType, - index?: number, -) => InternalErrorResponse | null; - -// @public (undocumented) -export type ValidatedField = { - type: 'TEXT'; - key: string; - label: string; - required: boolean; - validation: { - regex: string; - errorMessage: string; - }; -}; - -// @public (undocumented) -export interface ValidatedPasswordCollector { - // (undocumented) - category: 'SingleValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string | number | boolean; - type: string; - validation: PasswordPolicy; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - verify: boolean; - }; - // (undocumented) - type: 'ValidatedPasswordCollector'; -} - -// @public (undocumented) -export interface ValidatedSingleValueCollectorWithValue { - // (undocumented) - category: 'ValidatedSingleValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string | number | boolean; - type: string; - validation: (ValidationRequired | ValidationRegex)[]; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - value: string | number | boolean; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type ValidatedTextCollector = ValidatedSingleValueCollectorWithValue<'TextCollector'>; - -// @public (undocumented) -export interface ValidationPhoneNumber { - // (undocumented) - message: string; - // (undocumented) - rule: boolean; - // (undocumented) - type: 'validatePhoneNumber'; -} - -// @public (undocumented) -export interface ValidationRegex { - // (undocumented) - message: string; - // (undocumented) - rule: string; - // (undocumented) - type: 'regex'; -} - -// @public (undocumented) -export interface ValidationRequired { - // (undocumented) - message: string; - // (undocumented) - rule: boolean; - // (undocumented) - type: 'required'; -} - -// @public (undocumented) -export type Validator = (value: string) => - | string[] - | { - error: { - message: string; - type: string; - }; - type: string; - }; - -// (No @packageDocumentation comment for this package) -``` +## API Report File for "@forgerock/davinci-client" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { ActionCreatorWithPayload } from '@reduxjs/toolkit'; +import { ActionTypes } from '@forgerock/sdk-request-middleware'; +import type { AsyncLegacyConfigOptions } from '@forgerock/sdk-types'; +import { BaseQueryFn } from '@reduxjs/toolkit/query'; +import { CustomLogger } from '@forgerock/sdk-logger'; +import { FetchArgs } from '@reduxjs/toolkit/query'; +import { FetchBaseQueryError } from '@reduxjs/toolkit/query'; +import { FetchBaseQueryMeta } from '@reduxjs/toolkit/query'; +import { GenericError } from '@forgerock/sdk-types'; +import { LogLevel } from '@forgerock/sdk-logger'; +import { MutationDefinition } from '@reduxjs/toolkit/query'; +import type { MutationResultSelectorResult } from '@reduxjs/toolkit/query'; +import { QueryDefinition } from '@reduxjs/toolkit/query'; +import { QueryStatus } from '@reduxjs/toolkit/query'; +import { Reducer } from '@reduxjs/toolkit'; +import { RequestMiddleware } from '@forgerock/sdk-request-middleware'; +import { RootState } from '@reduxjs/toolkit/query'; +import { SerializedError } from '@reduxjs/toolkit'; +import { Unsubscribe } from '@reduxjs/toolkit'; + +// @public (undocumented) +export type ActionCollector = ActionCollectorNoUrl | ActionCollectorWithUrl; + +// @public (undocumented) +export interface ActionCollectorNoUrl { + // (undocumented) + category: 'ActionCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type ActionCollectors = ActionCollectorWithUrl<'IdpCollector'> | ActionCollectorNoUrl<'ActionCollector'> | ActionCollectorNoUrl<'FlowCollector'> | ActionCollectorNoUrl<'SubmitCollector'>; + +// @public +export type ActionCollectorTypes = 'FlowCollector' | 'SubmitCollector' | 'IdpCollector' | 'ActionCollector'; + +// @public (undocumented) +export interface ActionCollectorWithUrl { + // (undocumented) + category: 'ActionCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + url?: string | null; + }; + // (undocumented) + type: T; +} + +export { ActionTypes } + +// @public (undocumented) +export interface AgreementCollector extends NoValueCollectorBase<'AgreementCollector'> { + // (undocumented) + output: { + key: string; + label: string; + type: string; + titleEnabled: boolean; + title: string; + agreement: { + id: string; + useDynamicAgreement: boolean; + }; + enabled: boolean; + }; +} + +// @public (undocumented) +export type AgreementField = { + type: 'AGREEMENT'; + key: string; + content: string; + titleEnabled: boolean; + title: string; + agreement: { + id: string; + useDynamicAgreement: boolean; + }; + enabled: boolean; +}; + +// @public (undocumented) +export interface AssertionValue extends Omit { + // (undocumented) + rawId: string; + // (undocumented) + response: { + clientDataJSON: string; + authenticatorData: string; + signature: string; + userHandle: string | null; + }; +} + +// @public (undocumented) +export interface AttestationValue extends Omit { + // (undocumented) + rawId: string; + // (undocumented) + response: { + clientDataJSON: string; + attestationObject: string; + }; +} + +// @public (undocumented) +export interface AutoCollector> { + // (undocumented) + category: C; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: IV; + type: string; + validation?: ValidationRequired[] | null; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + type: string; + config: OV; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type AutoCollectorCategories = 'SingleValueAutoCollector' | 'ObjectValueAutoCollector'; + +// @public (undocumented) +export type AutoCollectors = ProtectCollector | FidoRegistrationCollector | FidoAuthenticationCollector | PollingCollector | SingleValueAutoCollector | ObjectValueAutoCollector; + +// @public (undocumented) +export type AutoCollectorTypes = SingleValueAutoCollectorTypes | ObjectValueAutoCollectorTypes; + +// @public (undocumented) +export interface CollectorErrors { + // (undocumented) + code: string; + // (undocumented) + message: string; + // (undocumented) + target: string; +} + +// @public +export interface CollectorRichContent { + // (undocumented) + content: string; + // (undocumented) + replacements: RichContentLink[]; +} + +// @public (undocumented) +export type Collectors = FlowCollector | PasswordCollector | ValidatedPasswordCollector | TextCollector | SingleSelectCollector | IdpCollector | SubmitCollector | ActionCollector<'ActionCollector'> | SingleValueCollector<'SingleValueCollector'> | MultiSelectCollector | DeviceAuthenticationCollector | DeviceRegistrationCollector | PhoneNumberCollector | PhoneNumberExtensionCollector | ReadOnlyCollector | RichTextCollector | ValidatedTextCollector | ProtectCollector | PollingCollector | FidoRegistrationCollector | FidoAuthenticationCollector | QrCodeCollector | AgreementCollector | UnknownCollector; + +// @public +export type CollectorValueType = T extends { + type: 'PasswordCollector'; +} ? string : T extends { + type: 'ValidatedPasswordCollector'; +} ? string : T extends { + type: 'TextCollector'; + category: 'SingleValueCollector'; +} ? string : T extends { + type: 'TextCollector'; + category: 'ValidatedSingleValueCollector'; +} ? string : T extends { + type: 'SingleSelectCollector'; +} ? string : T extends { + type: 'MultiSelectCollector'; +} ? string[] : T extends { + type: 'DeviceRegistrationCollector'; +} ? string : T extends { + type: 'DeviceAuthenticationCollector'; +} ? string : T extends { + type: 'PhoneNumberCollector'; +} ? PhoneNumberInputValue : T extends { + type: 'FidoRegistrationCollector'; +} ? FidoRegistrationInputValue : T extends { + type: 'FidoAuthenticationCollector'; +} ? FidoAuthenticationInputValue : T extends { + category: 'SingleValueCollector'; +} ? string : T extends { + category: 'ValidatedSingleValueCollector'; +} ? string : T extends { + category: 'MultiValueCollector'; +} ? string[] : string | string[] | PhoneNumberInputValue | FidoRegistrationInputValue | FidoAuthenticationInputValue; + +// @public (undocumented) +export type ComplexValueFields = DeviceAuthenticationField | DeviceRegistrationField | PhoneNumberField | PhoneNumberExtensionField | FidoRegistrationField | FidoAuthenticationField | PollingField; + +// @public (undocumented) +export interface ContinueNode { + // (undocumented) + cache: { + key: string; + }; + // (undocumented) + client: { + action: string; + collectors: Collectors[]; + description?: string; + name?: string; + status: 'continue'; + }; + // (undocumented) + error: null; + // (undocumented) + httpStatus: number; + // (undocumented) + server: { + _links?: Links; + id?: string; + interactionId?: string; + interactionToken?: string; + href?: string; + eventName?: string; + status: 'continue'; + }; + // (undocumented) + status: 'continue'; +} + +export { CustomLogger } + +// @public +export type CustomPollingStatus = string & {}; + +// @public +export function davinci(input: { + config: DaVinciConfig; + requestMiddleware?: RequestMiddleware[]; + logger?: { + level: LogLevel; + custom?: CustomLogger; + }; +}): Promise<{ + subscribe: (listener: () => void) => Unsubscribe; + externalIdp: () => (() => Promise); + flow: (action: DaVinciAction) => InitFlow; + next: (args?: DaVinciRequest) => Promise; + resume: (input: { + continueToken: string; + }) => Promise; + start: (options?: StartOptions | undefined) => Promise; + update: (collector: T) => Updater; + validate: (collector: SingleValueCollectors | ObjectValueCollectors | MultiValueCollectors | AutoCollectors) => Validator; + pollStatus: (collector: PollingCollector) => Poller; + getClient: () => { + status: "start"; + } | { + action: string; + collectors: Collectors[]; + description?: string; + name?: string; + status: "continue"; + } | { + action: string; + collectors: Collectors[]; + description?: string; + name?: string; + status: "error"; + } | { + authorization?: { + code?: string; + state?: string; + }; + status: "success"; + } | { + status: "failure"; + } | null; + getCollectors: () => Collectors[]; + getError: () => DaVinciError | null; + getErrorCollectors: () => CollectorErrors[]; + getNode: () => ContinueNode | ErrorNode | StartNode | SuccessNode | FailureNode; + getServer: () => { + _links?: Links; + id?: string; + interactionId?: string; + interactionToken?: string; + href?: string; + eventName?: string; + status: "continue"; + } | { + status: "start"; + } | { + _links?: Links; + eventName?: string; + id?: string; + interactionId?: string; + interactionToken?: string; + status: "error"; + } | { + _links?: Links; + eventName?: string; + id?: string; + interactionId?: string; + interactionToken?: string; + href?: string; + session?: string; + status: "success"; + } | { + _links?: Links; + eventName?: string; + href?: string; + id?: string; + interactionId?: string; + interactionToken?: string; + status: "failure"; + } | null; + cache: { + getLatestResponse: () => ((state: RootState< { + flow: MutationDefinition, never, unknown, "davinci", any>; + next: MutationDefinition, never, unknown, "davinci", any>; + start: MutationDefinition | undefined, BaseQueryFn, never, unknown, "davinci", unknown>; + resume: QueryDefinition< { + serverInfo: ContinueNode["server"]; + continueToken: string; + }, BaseQueryFn, never, unknown, "davinci", unknown>; + poll: MutationDefinition< { + endpoint: string; + interactionId: string; + }, BaseQueryFn, never, unknown, "davinci", unknown>; + }, never, "davinci">) => ({ + requestId?: undefined; + status: QueryStatus.uninitialized; + data?: undefined; + error?: undefined; + endpointName?: string; + startedTimeStamp?: undefined; + fulfilledTimeStamp?: undefined; + } & { + status: QueryStatus.uninitialized; + isUninitialized: true; + isLoading: false; + isSuccess: false; + isError: false; + }) | ({ + status: QueryStatus.fulfilled; + } & Omit<{ + requestId: string; + data?: unknown; + error?: FetchBaseQueryError | SerializedError | undefined; + endpointName: string; + startedTimeStamp: number; + fulfilledTimeStamp?: number; + }, "data" | "fulfilledTimeStamp"> & Required> & { + error: undefined; + } & { + status: QueryStatus.fulfilled; + isUninitialized: false; + isLoading: false; + isSuccess: true; + isError: false; + }) | ({ + status: QueryStatus.pending; + } & { + requestId: string; + data?: unknown; + error?: FetchBaseQueryError | SerializedError | undefined; + endpointName: string; + startedTimeStamp: number; + fulfilledTimeStamp?: number; + } & { + data?: undefined; + } & { + status: QueryStatus.pending; + isUninitialized: false; + isLoading: true; + isSuccess: false; + isError: false; + }) | ({ + status: QueryStatus.rejected; + } & Omit<{ + requestId: string; + data?: unknown; + error?: FetchBaseQueryError | SerializedError | undefined; + endpointName: string; + startedTimeStamp: number; + fulfilledTimeStamp?: number; + }, "error"> & Required> & { + status: QueryStatus.rejected; + isUninitialized: false; + isLoading: false; + isSuccess: false; + isError: true; + })) | { + error: { + message: string; + type: string; + }; + }; + getResponseWithId: (requestId: string) => ((state: RootState< { + flow: MutationDefinition, never, unknown, "davinci", any>; + next: MutationDefinition, never, unknown, "davinci", any>; + start: MutationDefinition | undefined, BaseQueryFn, never, unknown, "davinci", unknown>; + resume: QueryDefinition< { + serverInfo: ContinueNode["server"]; + continueToken: string; + }, BaseQueryFn, never, unknown, "davinci", unknown>; + poll: MutationDefinition< { + endpoint: string; + interactionId: string; + }, BaseQueryFn, never, unknown, "davinci", unknown>; + }, never, "davinci">) => ({ + requestId?: undefined; + status: QueryStatus.uninitialized; + data?: undefined; + error?: undefined; + endpointName?: string; + startedTimeStamp?: undefined; + fulfilledTimeStamp?: undefined; + } & { + status: QueryStatus.uninitialized; + isUninitialized: true; + isLoading: false; + isSuccess: false; + isError: false; + }) | ({ + status: QueryStatus.fulfilled; + } & Omit<{ + requestId: string; + data?: unknown; + error?: FetchBaseQueryError | SerializedError | undefined; + endpointName: string; + startedTimeStamp: number; + fulfilledTimeStamp?: number; + }, "data" | "fulfilledTimeStamp"> & Required> & { + error: undefined; + } & { + status: QueryStatus.fulfilled; + isUninitialized: false; + isLoading: false; + isSuccess: true; + isError: false; + }) | ({ + status: QueryStatus.pending; + } & { + requestId: string; + data?: unknown; + error?: FetchBaseQueryError | SerializedError | undefined; + endpointName: string; + startedTimeStamp: number; + fulfilledTimeStamp?: number; + } & { + data?: undefined; + } & { + status: QueryStatus.pending; + isUninitialized: false; + isLoading: true; + isSuccess: false; + isError: false; + }) | ({ + status: QueryStatus.rejected; + } & Omit<{ + requestId: string; + data?: unknown; + error?: FetchBaseQueryError | SerializedError | undefined; + endpointName: string; + startedTimeStamp: number; + fulfilledTimeStamp?: number; + }, "error"> & Required> & { + status: QueryStatus.rejected; + isUninitialized: false; + isLoading: false; + isSuccess: false; + isError: true; + })) | { + error: { + message: string; + type: string; + }; + }; + }; +}>; + +// @public +export interface DaVinciAction { + // (undocumented) + action: string; +} + +// @public +export interface DaVinciBaseResponse { + // (undocumented) + capabilityName?: string; + // (undocumented) + companyId?: string; + // (undocumented) + connectionId?: string; + // (undocumented) + connectorId?: string; + // (undocumented) + id?: string; + // (undocumented) + interactionId?: string; + // (undocumented) + interactionToken?: string; + // (undocumented) + isResponseCompatibleWithMobileAndWebSdks?: boolean; + // (undocumented) + status?: string; +} + +// @public +export type DaVinciCacheEntry = { + data?: DaVinciBaseResponse; + error?: { + data: DaVinciBaseResponse; + status: number; + }; +} & { + data?: any; + error?: any; +} & MutationResultSelectorResult; + +// @public (undocumented) +export type DavinciClient = Awaited>; + +// @public (undocumented) +export interface DaVinciConfig extends AsyncLegacyConfigOptions { + // (undocumented) + responseType?: string; +} + +// @public (undocumented) +export interface DaVinciError extends Omit { + // (undocumented) + collectors?: CollectorErrors[]; + // (undocumented) + internalHttpStatus?: number; + // (undocumented) + message: string; + // (undocumented) + status: 'error' | 'failure' | 'unknown'; +} + +// @public (undocumented) +export interface DaVinciErrorCacheEntry { + // (undocumented) + endpointName: 'next' | 'flow' | 'start'; + // (undocumented) + error: { + data: T; + }; + // (undocumented) + fulfilledTimeStamp: number; + // (undocumented) + isError: boolean; + // (undocumented) + isLoading: boolean; + // (undocumented) + isSuccess: boolean; + // (undocumented) + isUninitialized: boolean; + // (undocumented) + requestId: string; + // (undocumented) + startedTimeStamp: number; + // (undocumented) + status: 'fulfilled' | 'pending' | 'rejected'; +} + +// @public (undocumented) +export interface DavinciErrorResponse extends DaVinciBaseResponse { + // (undocumented) + cause?: string | null; + // (undocumented) + code: string | number; + // (undocumented) + details?: ErrorDetail[]; + // (undocumented) + doNotSendToOE?: boolean; + // (undocumented) + error?: { + code?: string; + message?: string; + }; + // (undocumented) + errorCategory?: string; + // (undocumented) + errorMessage?: string; + // (undocumented) + expected?: boolean; + // (undocumented) + httpResponseCode: number; + // (undocumented) + isErrorCustomized?: boolean; + // (undocumented) + message: string; + // (undocumented) + metricAttributes?: { + [key: string]: unknown; + }; +} + +// @public (undocumented) +export interface DaVinciFailureResponse extends DaVinciBaseResponse { + // (undocumented) + error?: { + code?: string; + message?: string; + [key: string]: unknown; + }; +} + +// @public (undocumented) +export type DaVinciField = ComplexValueFields | MultiValueFields | ReadOnlyFields | RedirectFields | SingleValueFields; + +// @public +export interface DaVinciNextResponse extends DaVinciBaseResponse { + // (undocumented) + eventName?: string; + // (undocumented) + form?: { + name?: string; + description?: string; + components?: { + fields?: DaVinciField[]; + }; + }; + // (undocumented) + formData?: { + value?: { + [key: string]: string; + }; + }; + // (undocumented) + _links?: Links; +} + +// @public +export interface DaVinciPollResponse extends DaVinciBaseResponse { + // (undocumented) + eventName?: string; + // (undocumented) + _links?: Links; + // (undocumented) + success?: boolean; +} + +// @public (undocumented) +export interface DaVinciRequest { + // (undocumented) + eventName: string; + // (undocumented) + id: string; + // (undocumented) + interactionId: string; + // (undocumented) + parameters: { + eventType: 'submit' | 'action' | 'polling'; + data: { + actionKey: string; + formData?: Record; + }; + }; +} + +// @public (undocumented) +export interface DaVinciSuccessResponse extends DaVinciBaseResponse { + // (undocumented) + authorizeResponse?: OAuthDetails; + // (undocumented) + environment: { + id: string; + [key: string]: unknown; + }; + // (undocumented) + _links?: Links; + // (undocumented) + resetCookie?: boolean; + // (undocumented) + session?: { + id?: string; + [key: string]: unknown; + }; + // (undocumented) + sessionToken?: string; + // (undocumented) + sessionTokenMaxAge?: number; + // (undocumented) + status: string; + // (undocumented) + subFlowSettings?: { + cssLinks?: unknown[]; + cssUrl?: unknown; + jsLinks?: unknown[]; + loadingScreenSettings?: unknown; + reactSkUrl?: unknown; + }; + // (undocumented) + success: true; +} + +// @public (undocumented) +export type DeviceAuthenticationCollector = ObjectOptionsCollectorWithObjectValue<'DeviceAuthenticationCollector', DeviceValue>; + +// @public (undocumented) +export type DeviceAuthenticationField = { + type: 'DEVICE_AUTHENTICATION'; + key: string; + label: string; + options: { + type: string; + iconSrc: string; + title: string; + id: string; + default: boolean; + description: string; + }[]; + required: boolean; +}; + +// @public (undocumented) +export interface DeviceOptionNoDefault { + // (undocumented) + content: string; + // (undocumented) + key: string; + // (undocumented) + label: string; + // (undocumented) + type: string; + // (undocumented) + value: string; +} + +// @public (undocumented) +export interface DeviceOptionWithDefault { + // (undocumented) + content: string; + // (undocumented) + default: boolean; + // (undocumented) + key: string; + // (undocumented) + label: string; + // (undocumented) + type: string; + // (undocumented) + value: string; +} + +// @public (undocumented) +export type DeviceRegistrationCollector = ObjectOptionsCollectorWithStringValue<'DeviceRegistrationCollector', string>; + +// @public (undocumented) +export type DeviceRegistrationField = { + type: 'DEVICE_REGISTRATION'; + key: string; + label: string; + options: { + type: string; + iconSrc: string; + title: string; + description: string; + }[]; + required: boolean; +}; + +// @public (undocumented) +export interface DeviceValue { + // (undocumented) + id: string; + // (undocumented) + type: string; + // (undocumented) + value: string; +} + +// @public (undocumented) +export interface ErrorDetail { + // (undocumented) + message?: string; + // (undocumented) + rawResponse?: { + _embedded?: { + users?: Array; + }; + code?: string; + count?: number; + details?: NestedErrorDetails[]; + id?: string; + message?: string; + size?: number; + userFilter?: string; + [key: string]: unknown; + }; + // (undocumented) + statusCode?: number; +} + +// @public (undocumented) +export interface ErrorNode { + // (undocumented) + cache: { + key: string; + }; + // (undocumented) + client: { + action: string; + collectors: Collectors[]; + description?: string; + name?: string; + status: 'error'; + }; + // (undocumented) + error: DaVinciError; + // (undocumented) + httpStatus: number; + // (undocumented) + server: { + _links?: Links; + eventName?: string; + id?: string; + interactionId?: string; + interactionToken?: string; + status: 'error'; + } | null; + // (undocumented) + status: 'error'; +} + +// @public (undocumented) +export interface FailureNode { + // (undocumented) + cache: { + key: string; + }; + // (undocumented) + client: { + status: 'failure'; + }; + // (undocumented) + error: DaVinciError; + // (undocumented) + httpStatus: number; + // (undocumented) + server: { + _links?: Links; + eventName?: string; + href?: string; + id?: string; + interactionId?: string; + interactionToken?: string; + status: 'failure'; + } | null; + // (undocumented) + status: 'failure'; +} + +// @public +export function fido(): FidoClient; + +// @public (undocumented) +export type FidoAuthenticationCollector = AutoCollector<'ObjectValueAutoCollector', 'FidoAuthenticationCollector', FidoAuthenticationInputValue, FidoAuthenticationOutputValue>; + +// @public (undocumented) +export type FidoAuthenticationField = { + type: 'FIDO2'; + key: string; + label: string; + publicKeyCredentialRequestOptions: FidoAuthenticationOptions; + action: 'AUTHENTICATE'; + trigger: string; + required: boolean; +}; + +// @public (undocumented) +export interface FidoAuthenticationInputValue { + // (undocumented) + assertionValue?: AssertionValue; +} + +// @public (undocumented) +export interface FidoAuthenticationOptions extends Omit { + // (undocumented) + allowCredentials?: { + id: number[]; + transports?: AuthenticatorTransport[]; + type: PublicKeyCredentialType; + }[]; + // (undocumented) + challenge: number[]; +} + +// @public (undocumented) +export interface FidoAuthenticationOutputValue { + // (undocumented) + action: 'AUTHENTICATE'; + // (undocumented) + publicKeyCredentialRequestOptions: FidoAuthenticationOptions; + // (undocumented) + trigger: string; +} + +// @public (undocumented) +export interface FidoClient { + authenticate: (options: FidoAuthenticationOptions) => Promise; + register: (options: FidoRegistrationOptions) => Promise; +} + +// @public (undocumented) +export type FidoRegistrationCollector = AutoCollector<'ObjectValueAutoCollector', 'FidoRegistrationCollector', FidoRegistrationInputValue, FidoRegistrationOutputValue>; + +// @public (undocumented) +export type FidoRegistrationField = { + type: 'FIDO2'; + key: string; + label: string; + publicKeyCredentialCreationOptions: FidoRegistrationOptions; + action: 'REGISTER'; + trigger: string; + required: boolean; +}; + +// @public (undocumented) +export interface FidoRegistrationInputValue { + // (undocumented) + attestationValue?: AttestationValue; +} + +// @public (undocumented) +export interface FidoRegistrationOptions extends Omit { + // (undocumented) + challenge: number[]; + // (undocumented) + excludeCredentials?: { + id: number[]; + transports?: AuthenticatorTransport[]; + type: PublicKeyCredentialType; + }[]; + // (undocumented) + pubKeyCredParams: { + alg: string | number; + type: PublicKeyCredentialType; + }[]; + // (undocumented) + user: { + id: number[]; + name: string; + displayName: string; + }; +} + +// @public (undocumented) +export interface FidoRegistrationOutputValue { + // (undocumented) + action: 'REGISTER'; + // (undocumented) + publicKeyCredentialCreationOptions: FidoRegistrationOptions; + // (undocumented) + trigger: string; +} + +// @public (undocumented) +export type FlowCollector = ActionCollectorNoUrl<'FlowCollector'>; + +// @public (undocumented) +export type FlowNode = ContinueNode | ErrorNode | StartNode | SuccessNode | FailureNode; + +// @public +export type GetClient = StartNode['client'] | ContinueNode['client'] | ErrorNode['client'] | SuccessNode['client'] | FailureNode['client']; + +// @public (undocumented) +export type IdpCollector = ActionCollectorWithUrl<'IdpCollector'>; + +// @public (undocumented) +export type InferActionCollectorType = T extends 'IdpCollector' ? IdpCollector : T extends 'SubmitCollector' ? SubmitCollector : T extends 'FlowCollector' ? FlowCollector : ActionCollectorWithUrl<'ActionCollector'> | ActionCollectorNoUrl<'ActionCollector'>; + +// @public +export type InferAutoCollectorType = T extends 'ProtectCollector' ? ProtectCollector : T extends 'PollingCollector' ? PollingCollector : T extends 'FidoRegistrationCollector' ? FidoRegistrationCollector : T extends 'FidoAuthenticationCollector' ? FidoAuthenticationCollector : T extends 'ObjectValueAutoCollector' ? ObjectValueAutoCollector : SingleValueAutoCollector; + +// @public +export type InferMultiValueCollectorType = T extends 'MultiSelectCollector' ? MultiValueCollectorWithValue<'MultiSelectCollector'> : MultiValueCollectorWithValue<'MultiValueCollector'> | MultiValueCollectorNoValue<'MultiValueCollector'>; + +// @public +export type InferNoValueCollectorType = T extends 'ReadOnlyCollector' ? ReadOnlyCollector : T extends 'RichTextCollector' ? RichTextCollector : T extends 'QrCodeCollector' ? QrCodeCollector : T extends 'AgreementCollector' ? AgreementCollector : NoValueCollectorBase<'NoValueCollector'>; + +// @public +export type InferSingleValueCollectorType = T extends 'TextCollector' ? TextCollector : T extends 'SingleSelectCollector' ? SingleSelectCollector : T extends 'ValidatedTextCollector' ? ValidatedTextCollector : T extends 'PasswordCollector' ? PasswordCollector : T extends 'ValidatedPasswordCollector' ? ValidatedPasswordCollector : SingleValueCollectorWithValue<'SingleValueCollector'> | SingleValueCollectorNoValue<'SingleValueCollector'>; + +// @public (undocumented) +export type InferValueObjectCollectorType = T extends 'DeviceAuthenticationCollector' ? DeviceAuthenticationCollector : T extends 'DeviceRegistrationCollector' ? DeviceRegistrationCollector : T extends 'PhoneNumberCollector' ? PhoneNumberCollector : T extends 'PhoneNumberExtensionCollector' ? PhoneNumberExtensionCollector : ObjectOptionsCollectorWithObjectValue<'ObjectValueCollector'> | ObjectOptionsCollectorWithStringValue<'ObjectValueCollector'>; + +// @public (undocumented) +export type InitFlow = () => Promise; + +// @public (undocumented) +export interface InternalErrorResponse { + // (undocumented) + error: Omit & { + message: string; + }; + // (undocumented) + type: 'internal_error'; +} + +// @public (undocumented) +export interface Links { + // (undocumented) + [key: string]: { + href?: string; + }; +} + +export { LogLevel } + +// @public (undocumented) +export type MultiSelectCollector = MultiValueCollectorWithValue<'MultiSelectCollector'>; + +// @public (undocumented) +export type MultiSelectField = { + inputType: 'MULTI_SELECT'; + key: string; + label: string; + options: { + label: string; + value: string; + }[]; + required?: boolean; + type: 'CHECKBOX' | 'COMBOBOX'; +}; + +// @public (undocumented) +export type MultiValueCollector = MultiValueCollectorWithValue | MultiValueCollectorNoValue; + +// @public (undocumented) +export interface MultiValueCollectorNoValue { + // (undocumented) + category: 'MultiValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string[]; + type: string; + validation: ValidationRequired[] | null; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + options: SelectorOption[]; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type MultiValueCollectors = MultiValueCollectorWithValue<'MultiValueCollector'> | MultiValueCollectorWithValue<'MultiSelectCollector'>; + +// @public +export type MultiValueCollectorTypes = 'MultiSelectCollector' | 'MultiValueCollector'; + +// @public (undocumented) +export interface MultiValueCollectorWithValue { + // (undocumented) + category: 'MultiValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string[]; + type: string; + validation: ValidationRequired[] | null; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + value: string[]; + options: SelectorOption[]; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type MultiValueFields = MultiSelectField; + +// @public +export interface NestedErrorDetails { + // (undocumented) + code?: string; + // (undocumented) + innerError?: { + history?: string; + unsatisfiedRequirements?: string[]; + failuresRemaining?: number; + }; + // (undocumented) + message?: string; + // (undocumented) + target?: string; +} + +// @public +export const nextCollectorValues: ActionCreatorWithPayload< { +fields: DaVinciField[]; +formData: { +value: Record; +}; +}, string>; + +// @public +export const nodeCollectorReducer: Reducer<(TextCollector | SingleSelectCollector | ValidatedTextCollector | PasswordCollector | ValidatedPasswordCollector | MultiSelectCollector | PhoneNumberExtensionCollector | DeviceAuthenticationCollector | DeviceRegistrationCollector | PhoneNumberCollector | IdpCollector | SubmitCollector | FlowCollector | QrCodeCollector | ReadOnlyCollector | RichTextCollector | AgreementCollector | UnknownCollector | ProtectCollector | FidoRegistrationCollector | FidoAuthenticationCollector | PollingCollector | ActionCollector<"ActionCollector"> | SingleValueCollector<"SingleValueCollector">)[]> & { + getInitialState: () => (TextCollector | SingleSelectCollector | ValidatedTextCollector | PasswordCollector | ValidatedPasswordCollector | MultiSelectCollector | PhoneNumberExtensionCollector | DeviceAuthenticationCollector | DeviceRegistrationCollector | PhoneNumberCollector | IdpCollector | SubmitCollector | FlowCollector | QrCodeCollector | ReadOnlyCollector | RichTextCollector | AgreementCollector | UnknownCollector | ProtectCollector | FidoRegistrationCollector | FidoAuthenticationCollector | PollingCollector | ActionCollector<"ActionCollector"> | SingleValueCollector<"SingleValueCollector">)[]; +}; + +// @public (undocumented) +export type NodeStates = StartNode | ContinueNode | ErrorNode | SuccessNode | FailureNode; + +// @public (undocumented) +export type NoValueCollector = InferNoValueCollectorType; + +// @public (undocumented) +export interface NoValueCollectorBase { + // (undocumented) + category: 'NoValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type NoValueCollectors = NoValueCollectorBase<'NoValueCollector'> | ReadOnlyCollector | RichTextCollector | QrCodeCollector | AgreementCollector; + +// @public +export type NoValueCollectorTypes = 'ReadOnlyCollector' | 'RichTextCollector' | 'NoValueCollector' | 'QrCodeCollector' | 'AgreementCollector'; + +// @public +export interface OAuthDetails { + // (undocumented) + [key: string]: unknown; + // (undocumented) + code?: string; + // (undocumented) + state?: string; +} + +// @public (undocumented) +export interface ObjectOptionsCollectorWithObjectValue, D = Record> { + // (undocumented) + category: 'ObjectValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: V; + type: string; + validation: ValidationRequired[] | null; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + options: DeviceOptionWithDefault[]; + value?: D | null; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export interface ObjectOptionsCollectorWithStringValue { + // (undocumented) + category: 'ObjectValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: V; + type: string; + validation: ValidationRequired[] | null; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + options: DeviceOptionNoDefault[]; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type ObjectValueAutoCollector = AutoCollector<'ObjectValueAutoCollector', 'ObjectValueAutoCollector', Record>; + +// @public (undocumented) +export type ObjectValueAutoCollectorTypes = 'ObjectValueAutoCollector' | 'FidoRegistrationCollector' | 'FidoAuthenticationCollector'; + +// @public (undocumented) +export type ObjectValueCollector = ObjectOptionsCollectorWithObjectValue | ObjectOptionsCollectorWithStringValue | ObjectValueCollectorWithObjectValue; + +// @public (undocumented) +export type ObjectValueCollectors = DeviceAuthenticationCollector | DeviceRegistrationCollector | PhoneNumberCollector | PhoneNumberExtensionCollector | ObjectOptionsCollectorWithObjectValue<'ObjectSelectCollector'> | ObjectOptionsCollectorWithStringValue<'ObjectSelectCollector'>; + +// @public +export type ObjectValueCollectorTypes = 'DeviceAuthenticationCollector' | 'DeviceRegistrationCollector' | 'PhoneNumberCollector' | 'PhoneNumberExtensionCollector' | 'ObjectOptionsCollector' | 'ObjectValueCollector' | 'ObjectSelectCollector'; + +// @public (undocumented) +export interface ObjectValueCollectorWithObjectValue, OV = Record> { + // (undocumented) + category: 'ObjectValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: IV; + type: string; + validation: (ValidationRequired | ValidationPhoneNumber)[] | null; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + value?: OV | null; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export interface OutgoingQueryParams { + // (undocumented) + [key: string]: string | string[]; +} + +// @public (undocumented) +export interface PasswordCollector { + // (undocumented) + category: 'SingleValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string | number | boolean; + type: string; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + verify: boolean; + }; + // (undocumented) + type: 'PasswordCollector'; +} + +// @public +export type PasswordField = { + type: 'PASSWORD' | 'PASSWORD_VERIFY'; + key: string; + label: string; + required?: boolean; + verify?: boolean; + passwordPolicy?: PasswordPolicy; +}; + +// @public +export interface PasswordPolicy { + // (undocumented) + createdAt?: string; + // (undocumented) + default?: boolean; + // (undocumented) + description?: string; + // (undocumented) + excludesCommonlyUsed?: boolean; + // (undocumented) + excludesProfileData?: boolean; + // (undocumented) + history?: { + count?: number; + retentionDays?: number; + }; + // (undocumented) + id?: string; + // (undocumented) + length?: { + min?: number; + max?: number; + }; + // (undocumented) + lockout?: { + failureCount?: number; + durationSeconds?: number; + }; + // (undocumented) + maxAgeDays?: number; + // (undocumented) + maxRepeatedCharacters?: number; + // (undocumented) + minAgeDays?: number; + // (undocumented) + minCharacters?: Record; + // (undocumented) + minUniqueCharacters?: number; + // (undocumented) + name?: string; + // (undocumented) + notSimilarToCurrent?: boolean; + // (undocumented) + populationCount?: number; + // (undocumented) + updatedAt?: string; +} + +// @public (undocumented) +export type PhoneNumberCollector = ObjectValueCollectorWithObjectValue<'PhoneNumberCollector', PhoneNumberInputValue, PhoneNumberOutputValue>; + +// @public (undocumented) +export interface PhoneNumberExtensionCollector { + // (undocumented) + category: 'ObjectValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: PhoneNumberExtensionInputValue; + type: string; + validation: (ValidationRequired | ValidationPhoneNumber)[] | null; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + extensionLabel: string; + value: PhoneNumberExtensionOutputValue; + }; + // (undocumented) + type: 'PhoneNumberExtensionCollector'; +} + +// @public (undocumented) +export type PhoneNumberExtensionField = PhoneNumberField & { + showExtension: boolean; + extensionLabel: string; +}; + +// @public (undocumented) +export interface PhoneNumberExtensionInputValue { + // (undocumented) + countryCode: string; + // (undocumented) + extension: string; + // (undocumented) + phoneNumber: string; +} + +// @public (undocumented) +export interface PhoneNumberExtensionOutputValue { + // (undocumented) + countryCode?: string; + // (undocumented) + extension?: string; + // (undocumented) + phoneNumber?: string; +} + +// @public (undocumented) +export type PhoneNumberField = { + type: 'PHONE_NUMBER'; + key: string; + label: string; + required: boolean; + defaultCountryCode: string | null; + validatePhoneNumber: boolean; +}; + +// @public (undocumented) +export interface PhoneNumberInputValue { + // (undocumented) + countryCode: string; + // (undocumented) + phoneNumber: string; +} + +// @public (undocumented) +export interface PhoneNumberOutputValue { + // (undocumented) + countryCode?: string; + // (undocumented) + phoneNumber?: string; +} + +// @public (undocumented) +export type Poller = () => Promise; + +// @public (undocumented) +export type PollingCollector = AutoCollector<'SingleValueAutoCollector', 'PollingCollector', string, PollingOutputValue>; + +// @public (undocumented) +export type PollingField = { + type: 'POLLING'; + key: string; + pollInterval: number; + pollRetries: number; + pollChallengeStatus?: boolean; + challenge?: string; +}; + +// @public (undocumented) +export interface PollingOutputValue { + // (undocumented) + challenge?: string; + // (undocumented) + pollChallengeStatus?: boolean; + // (undocumented) + pollInterval: number; + // (undocumented) + pollRetries: number; + // (undocumented) + retriesRemaining?: number; +} + +// @public (undocumented) +export type PollingStatus = PollingStatusContinue | PollingStatusChallenge; + +// @public (undocumented) +export type PollingStatusChallenge = PollingStatusChallengeComplete | 'expired' | 'timedOut' | 'error'; + +// @public (undocumented) +export type PollingStatusChallengeComplete = 'approved' | 'denied' | 'continue' | CustomPollingStatus; + +// @public (undocumented) +export type PollingStatusContinue = 'continue' | 'timedOut'; + +// @public (undocumented) +export type ProtectCollector = AutoCollector<'SingleValueAutoCollector', 'ProtectCollector', string, ProtectOutputValue>; + +// @public (undocumented) +export type ProtectField = { + type: 'PROTECT'; + key: string; + behavioralDataCollection: boolean; + universalDeviceIdentification: boolean; +}; + +// @public +export interface ProtectOutputValue { + // (undocumented) + behavioralDataCollection: boolean; + // (undocumented) + universalDeviceIdentification: boolean; +} + +// @public +export interface QrCodeCollector extends NoValueCollectorBase<'QrCodeCollector'> { + // (undocumented) + output: NoValueCollectorBase<'QrCodeCollector'>['output'] & { + src: string; + }; +} + +// @public (undocumented) +export type QrCodeField = { + type: 'QR_CODE'; + key: string; + content: string; + fallbackText?: string; +}; + +// @public +export interface ReadOnlyCollector extends NoValueCollectorBase<'ReadOnlyCollector'> { + // (undocumented) + output: NoValueCollectorBase<'ReadOnlyCollector'>['output'] & { + content: string; + }; +} + +// @public (undocumented) +export type ReadOnlyField = { + type: 'LABEL'; + content: string; + richContent?: RichContent; + key?: string; +}; + +// @public (undocumented) +export type ReadOnlyFields = ReadOnlyField | QrCodeField | AgreementField; + +// @public (undocumented) +export type RedirectField = { + type: 'SOCIAL_LOGIN_BUTTON'; + key: string; + label: string; + links: Links; +}; + +// @public (undocumented) +export type RedirectFields = RedirectField; + +export { RequestMiddleware } + +// @public +export type RichContent = { + content: string; + replacements?: Record; +}; + +// @public +export interface RichContentLink { + // (undocumented) + href: string; + // (undocumented) + key: string; + // (undocumented) + target?: '_self' | '_blank'; + // (undocumented) + type: 'link'; + // (undocumented) + value: string; +} + +// @public +export type RichContentReplacement = { + type: 'link'; + value: string; + href: string; + target?: '_self' | '_blank'; +}; + +// @public +export interface RichTextCollector extends NoValueCollectorBase<'RichTextCollector'> { + // (undocumented) + output: NoValueCollectorBase<'RichTextCollector'>['output'] & { + content: string; + richContent: CollectorRichContent; + }; +} + +// @public (undocumented) +export interface SelectorOption { + // (undocumented) + label: string; + // (undocumented) + value: string; +} + +// @public (undocumented) +export type SingleSelectCollector = SingleSelectCollectorWithValue<'SingleSelectCollector'>; + +// @public (undocumented) +export interface SingleSelectCollectorNoValue { + // (undocumented) + category: 'SingleValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string | number | boolean; + type: string; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + options: SelectorOption[]; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export interface SingleSelectCollectorWithValue { + // (undocumented) + category: 'SingleValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string | number | boolean; + type: string; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + value: string | number | boolean; + options: SelectorOption[]; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type SingleSelectField = { + inputType: 'SINGLE_SELECT'; + key: string; + label: string; + options: { + label: string; + value: string; + }[]; + required?: boolean; + type: 'RADIO' | 'DROPDOWN'; +}; + +// @public (undocumented) +export type SingleValueAutoCollector = AutoCollector<'SingleValueAutoCollector', 'SingleValueAutoCollector', string>; + +// @public (undocumented) +export type SingleValueAutoCollectorTypes = 'SingleValueAutoCollector' | 'ProtectCollector' | 'PollingCollector'; + +// @public +export type SingleValueCollector = SingleValueCollectorWithValue | SingleValueCollectorNoValue; + +// @public (undocumented) +export interface SingleValueCollectorNoValue { + // (undocumented) + category: 'SingleValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string | number | boolean; + type: string; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type SingleValueCollectors = PasswordCollector | ValidatedPasswordCollector | SingleSelectCollectorWithValue<'SingleSelectCollector'> | SingleValueCollectorWithValue<'SingleValueCollector'> | SingleValueCollectorWithValue<'TextCollector'> | ValidatedSingleValueCollectorWithValue<'TextCollector'>; + +// @public +export type SingleValueCollectorTypes = 'PasswordCollector' | 'ValidatedPasswordCollector' | 'SingleValueCollector' | 'SingleSelectCollector' | 'SingleSelectObjectCollector' | 'TextCollector' | 'ValidatedTextCollector'; + +// @public (undocumented) +export interface SingleValueCollectorWithValue { + // (undocumented) + category: 'SingleValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string | number | boolean; + type: string; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + value: string | number | boolean; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type SingleValueFields = StandardField | PasswordField | ValidatedField | SingleSelectField | ProtectField; + +// @public (undocumented) +export type StandardField = { + type: 'TEXT' | 'SUBMIT_BUTTON' | 'FLOW_BUTTON' | 'FLOW_LINK' | 'BUTTON'; + key: string; + label: string; + required?: boolean; +}; + +// @public (undocumented) +export interface StartNode { + // (undocumented) + cache: null; + // (undocumented) + client: { + status: 'start'; + }; + // (undocumented) + error: DaVinciError | null; + // (undocumented) + server: { + status: 'start'; + }; + // (undocumented) + status: 'start'; +} + +// @public (undocumented) +export interface StartOptions { + // (undocumented) + query: Query; +} + +// @public (undocumented) +export type SubmitCollector = ActionCollectorNoUrl<'SubmitCollector'>; + +// @public (undocumented) +export interface SuccessNode { + // (undocumented) + cache: { + key: string; + }; + // (undocumented) + client: { + authorization?: { + code?: string; + state?: string; + }; + status: 'success'; + } | null; + // (undocumented) + error: null; + // (undocumented) + httpStatus: number; + // (undocumented) + server: { + _links?: Links; + eventName?: string; + id?: string; + interactionId?: string; + interactionToken?: string; + href?: string; + session?: string; + status: 'success'; + }; + // (undocumented) + status: 'success'; +} + +// @public (undocumented) +export type TextCollector = SingleValueCollectorWithValue<'TextCollector'>; + +// @public (undocumented) +export interface ThrownQueryError { + // (undocumented) + error: FetchBaseQueryError; + // (undocumented) + isHandledError: boolean; + // (undocumented) + meta: FetchBaseQueryMeta; +} + +// @public +export type UnknownCollector = { + category: 'UnknownCollector'; + error: string | null; + type: 'UnknownCollector'; + id: string; + name: string; + output: { + key: string; + label: string; + type: string; + }; +}; + +// @public (undocumented) +export type UnknownField = Record; + +// @public (undocumented) +export const updateCollectorValues: ActionCreatorWithPayload< { +id: string; +value: string | string[] | PhoneNumberInputValue | PhoneNumberExtensionInputValue | FidoRegistrationInputValue | FidoAuthenticationInputValue; +index?: number; +}, string>; + +// @public +export type Updater = (value: CollectorValueType, index?: number) => InternalErrorResponse | null; + +// @public (undocumented) +export type ValidatedField = { + type: 'TEXT'; + key: string; + label: string; + required: boolean; + validation: { + regex: string; + errorMessage: string; + }; +}; + +// @public (undocumented) +export interface ValidatedPasswordCollector { + // (undocumented) + category: 'SingleValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string | number | boolean; + type: string; + validation: PasswordPolicy; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + verify: boolean; + }; + // (undocumented) + type: 'ValidatedPasswordCollector'; +} + +// @public (undocumented) +export interface ValidatedSingleValueCollectorWithValue { + // (undocumented) + category: 'ValidatedSingleValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string | number | boolean; + type: string; + validation: (ValidationRequired | ValidationRegex)[]; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + value: string | number | boolean; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type ValidatedTextCollector = ValidatedSingleValueCollectorWithValue<'TextCollector'>; + +// @public (undocumented) +export interface ValidationPhoneNumber { + // (undocumented) + message: string; + // (undocumented) + rule: boolean; + // (undocumented) + type: 'validatePhoneNumber'; +} + +// @public (undocumented) +export interface ValidationRegex { + // (undocumented) + message: string; + // (undocumented) + rule: string; + // (undocumented) + type: 'regex'; +} + +// @public (undocumented) +export interface ValidationRequired { + // (undocumented) + message: string; + // (undocumented) + rule: boolean; + // (undocumented) + type: 'required'; +} + +// @public (undocumented) +export type Validator = (value: string) => string[] | { + error: { + message: string; + type: string; + }; + type: string; +}; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/packages/davinci-client/api-report/davinci-client.types.api.md b/packages/davinci-client/api-report/davinci-client.types.api.md index 1ef11fb121..1de28378db 100644 --- a/packages/davinci-client/api-report/davinci-client.types.api.md +++ b/packages/davinci-client/api-report/davinci-client.types.api.md @@ -1,2575 +1,2018 @@ -## API Report File for "@forgerock/davinci-client" - -> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). - -```ts -import { ActionCreatorWithPayload } from '@reduxjs/toolkit'; -import { ActionTypes } from '@forgerock/sdk-request-middleware'; -import type { AsyncLegacyConfigOptions } from '@forgerock/sdk-types'; -import { BaseQueryFn } from '@reduxjs/toolkit/query'; -import { CustomLogger } from '@forgerock/sdk-logger'; -import { FetchArgs } from '@reduxjs/toolkit/query'; -import { FetchBaseQueryError } from '@reduxjs/toolkit/query'; -import { FetchBaseQueryMeta } from '@reduxjs/toolkit/query'; -import { GenericError } from '@forgerock/sdk-types'; -import { LogLevel } from '@forgerock/sdk-logger'; -import { MutationDefinition } from '@reduxjs/toolkit/query'; -import type { MutationResultSelectorResult } from '@reduxjs/toolkit/query'; -import { QueryDefinition } from '@reduxjs/toolkit/query'; -import { QueryStatus } from '@reduxjs/toolkit/query'; -import { Reducer } from '@reduxjs/toolkit'; -import { RequestMiddleware } from '@forgerock/sdk-request-middleware'; -import { RootState } from '@reduxjs/toolkit/query'; -import { SerializedError } from '@reduxjs/toolkit'; -import { Unsubscribe } from '@reduxjs/toolkit'; - -// @public (undocumented) -export type ActionCollector = - | ActionCollectorNoUrl - | ActionCollectorWithUrl; - -// @public (undocumented) -export interface ActionCollectorNoUrl { - // (undocumented) - category: 'ActionCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type ActionCollectors = - | ActionCollectorWithUrl<'IdpCollector'> - | ActionCollectorNoUrl<'ActionCollector'> - | ActionCollectorNoUrl<'FlowCollector'> - | ActionCollectorNoUrl<'SubmitCollector'>; - -// @public -export type ActionCollectorTypes = - | 'FlowCollector' - | 'SubmitCollector' - | 'IdpCollector' - | 'ActionCollector'; - -// @public (undocumented) -export interface ActionCollectorWithUrl { - // (undocumented) - category: 'ActionCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - url?: string | null; - }; - // (undocumented) - type: T; -} - -export { ActionTypes }; - -// @public (undocumented) -export interface AgreementCollector extends NoValueCollectorBase<'AgreementCollector'> { - // (undocumented) - output: { - key: string; - label: string; - type: string; - titleEnabled: boolean; - title: string; - agreement: { - id: string; - useDynamicAgreement: boolean; - }; - enabled: boolean; - }; -} - -// @public (undocumented) -export type AgreementField = { - type: 'AGREEMENT'; - key: string; - content: string; - titleEnabled: boolean; - title: string; - agreement: { - id: string; - useDynamicAgreement: boolean; - }; - enabled: boolean; -}; - -// @public (undocumented) -export interface AssertionValue extends Omit< - PublicKeyCredential, - 'rawId' | 'response' | 'getClientExtensionResults' | 'toJSON' -> { - // (undocumented) - rawId: string; - // (undocumented) - response: { - clientDataJSON: string; - authenticatorData: string; - signature: string; - userHandle: string | null; - }; -} - -// @public (undocumented) -export interface AttestationValue extends Omit< - PublicKeyCredential, - 'rawId' | 'response' | 'getClientExtensionResults' | 'toJSON' -> { - // (undocumented) - rawId: string; - // (undocumented) - response: { - clientDataJSON: string; - attestationObject: string; - }; -} - -// @public (undocumented) -export interface AutoCollector< - C extends AutoCollectorCategories, - T extends AutoCollectorTypes, - IV = string, - OV = Record, -> { - // (undocumented) - category: C; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: IV; - type: string; - validation?: ValidationRequired[] | null; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - type: string; - config: OV; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type AutoCollectorCategories = 'SingleValueAutoCollector' | 'ObjectValueAutoCollector'; - -// @public (undocumented) -export type AutoCollectors = - | ProtectCollector - | FidoRegistrationCollector - | FidoAuthenticationCollector - | PollingCollector - | SingleValueAutoCollector - | ObjectValueAutoCollector; - -// @public (undocumented) -export type AutoCollectorTypes = SingleValueAutoCollectorTypes | ObjectValueAutoCollectorTypes; - -// @public (undocumented) -export interface CollectorErrors { - // (undocumented) - code: string; - // (undocumented) - message: string; - // (undocumented) - target: string; -} - -// @public -export interface CollectorRichContent { - // (undocumented) - content: string; - // (undocumented) - replacements: RichContentLink[]; -} - -// @public (undocumented) -export type Collectors = - | FlowCollector - | PasswordCollector - | ValidatedPasswordCollector - | TextCollector - | SingleSelectCollector - | IdpCollector - | SubmitCollector - | ActionCollector<'ActionCollector'> - | SingleValueCollector<'SingleValueCollector'> - | MultiSelectCollector - | DeviceAuthenticationCollector - | DeviceRegistrationCollector - | PhoneNumberCollector - | PhoneNumberExtensionCollector - | ReadOnlyCollector - | RichTextCollector - | ValidatedTextCollector - | ProtectCollector - | PollingCollector - | FidoRegistrationCollector - | FidoAuthenticationCollector - | QrCodeCollector - | AgreementCollector - | UnknownCollector; - -// @public -export type CollectorValueType = T extends { - type: 'PasswordCollector'; -} - ? string - : T extends { - type: 'ValidatedPasswordCollector'; - } - ? string - : T extends { - type: 'TextCollector'; - category: 'SingleValueCollector'; - } - ? string - : T extends { - type: 'TextCollector'; - category: 'ValidatedSingleValueCollector'; - } - ? string - : T extends { - type: 'SingleSelectCollector'; - } - ? string - : T extends { - type: 'MultiSelectCollector'; - } - ? string[] - : T extends { - type: 'DeviceRegistrationCollector'; - } - ? string - : T extends { - type: 'DeviceAuthenticationCollector'; - } - ? string - : T extends { - type: 'PhoneNumberCollector'; - } - ? PhoneNumberInputValue - : T extends { - type: 'FidoRegistrationCollector'; - } - ? FidoRegistrationInputValue - : T extends { - type: 'FidoAuthenticationCollector'; - } - ? FidoAuthenticationInputValue - : T extends { - category: 'SingleValueCollector'; - } - ? string - : T extends { - category: 'ValidatedSingleValueCollector'; - } - ? string - : T extends { - category: 'MultiValueCollector'; - } - ? string[] - : - | string - | string[] - | PhoneNumberInputValue - | FidoRegistrationInputValue - | FidoAuthenticationInputValue; - -// @public (undocumented) -export type ComplexValueFields = - | DeviceAuthenticationField - | DeviceRegistrationField - | PhoneNumberField - | PhoneNumberExtensionField - | FidoRegistrationField - | FidoAuthenticationField - | PollingField; - -// @public (undocumented) -export interface ContinueNode { - // (undocumented) - cache: { - key: string; - }; - // (undocumented) - client: { - action: string; - collectors: Collectors[]; - description?: string; - name?: string; - status: 'continue'; - }; - // (undocumented) - error: null; - // (undocumented) - httpStatus: number; - // (undocumented) - server: { - _links?: Links; - id?: string; - interactionId?: string; - interactionToken?: string; - href?: string; - eventName?: string; - status: 'continue'; - }; - // (undocumented) - status: 'continue'; -} - -export { CustomLogger }; - -// @public -export type CustomPollingStatus = string & {}; - -// @public -export function davinci(input: { - config: DaVinciConfig; - requestMiddleware?: RequestMiddleware[]; - logger?: { - level: LogLevel; - custom?: CustomLogger; - }; -}): Promise<{ - subscribe: (listener: () => void) => Unsubscribe; - externalIdp: () => () => Promise; - flow: (action: DaVinciAction) => InitFlow; - next: (args?: DaVinciRequest) => Promise; - resume: (input: { continueToken: string }) => Promise; - start: ( - options?: StartOptions | undefined, - ) => Promise; - update: < - T extends SingleValueCollectors | MultiSelectCollector | ObjectValueCollectors | AutoCollectors, - >( - collector: T, - ) => Updater; - validate: ( - collector: - | SingleValueCollectors - | ObjectValueCollectors - | MultiValueCollectors - | AutoCollectors, - ) => Validator; - pollStatus: (collector: PollingCollector) => Poller; - getClient: () => - | { - action: string; - collectors: Collectors[]; - description?: string; - name?: string; - status: 'continue'; - } - | { - action: string; - collectors: Collectors[]; - description?: string; - name?: string; - status: 'error'; - } - | { - status: 'failure'; - } - | { - status: 'start'; - } - | { - authorization?: { - code?: string; - state?: string; - }; - status: 'success'; - } - | null; - getCollectors: () => Collectors[]; - getError: () => DaVinciError | null; - getErrorCollectors: () => CollectorErrors[]; - getNode: () => ContinueNode | ErrorNode | FailureNode | StartNode | SuccessNode; - getServer: () => - | { - _links?: Links; - id?: string; - interactionId?: string; - interactionToken?: string; - href?: string; - eventName?: string; - status: 'continue'; - } - | { - _links?: Links; - eventName?: string; - id?: string; - interactionId?: string; - interactionToken?: string; - status: 'error'; - } - | { - _links?: Links; - eventName?: string; - href?: string; - id?: string; - interactionId?: string; - interactionToken?: string; - status: 'failure'; - } - | { - status: 'start'; - } - | { - _links?: Links; - eventName?: string; - id?: string; - interactionId?: string; - interactionToken?: string; - href?: string; - session?: string; - status: 'success'; - } - | null; - cache: { - getLatestResponse: () => - | (( - state: RootState< - { - flow: MutationDefinition< - any, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - any - >; - next: MutationDefinition< - any, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - any - >; - start: MutationDefinition< - StartOptions | undefined, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - unknown - >; - resume: QueryDefinition< - { - serverInfo: ContinueNode['server']; - continueToken: string; - }, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - unknown - >; - poll: MutationDefinition< - { - endpoint: string; - interactionId: string; - }, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - unknown - >; - }, - never, - 'davinci' - >, - ) => - | ({ - requestId?: undefined; - status: QueryStatus.uninitialized; - data?: undefined; - error?: undefined; - endpointName?: string; - startedTimeStamp?: undefined; - fulfilledTimeStamp?: undefined; - } & { - status: QueryStatus.uninitialized; - isUninitialized: true; - isLoading: false; - isSuccess: false; - isError: false; - }) - | ({ - status: QueryStatus.fulfilled; - } & Omit< - { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - }, - 'data' | 'fulfilledTimeStamp' - > & - Required< - Pick< - { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - }, - 'data' | 'fulfilledTimeStamp' - > - > & { - error: undefined; - } & { - status: QueryStatus.fulfilled; - isUninitialized: false; - isLoading: false; - isSuccess: true; - isError: false; - }) - | ({ - status: QueryStatus.pending; - } & { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - } & { - data?: undefined; - } & { - status: QueryStatus.pending; - isUninitialized: false; - isLoading: true; - isSuccess: false; - isError: false; - }) - | ({ - status: QueryStatus.rejected; - } & Omit< - { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - }, - 'error' - > & - Required< - Pick< - { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - }, - 'error' - > - > & { - status: QueryStatus.rejected; - isUninitialized: false; - isLoading: false; - isSuccess: false; - isError: true; - })) - | { - error: { - message: string; - type: string; - }; - }; - getResponseWithId: (requestId: string) => - | (( - state: RootState< - { - flow: MutationDefinition< - any, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - any - >; - next: MutationDefinition< - any, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - any - >; - start: MutationDefinition< - StartOptions | undefined, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - unknown - >; - resume: QueryDefinition< - { - serverInfo: ContinueNode['server']; - continueToken: string; - }, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - unknown - >; - poll: MutationDefinition< - { - endpoint: string; - interactionId: string; - }, - BaseQueryFn< - string | FetchArgs, - unknown, - FetchBaseQueryError, - {}, - FetchBaseQueryMeta - >, - never, - unknown, - 'davinci', - unknown - >; - }, - never, - 'davinci' - >, - ) => - | ({ - requestId?: undefined; - status: QueryStatus.uninitialized; - data?: undefined; - error?: undefined; - endpointName?: string; - startedTimeStamp?: undefined; - fulfilledTimeStamp?: undefined; - } & { - status: QueryStatus.uninitialized; - isUninitialized: true; - isLoading: false; - isSuccess: false; - isError: false; - }) - | ({ - status: QueryStatus.fulfilled; - } & Omit< - { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - }, - 'data' | 'fulfilledTimeStamp' - > & - Required< - Pick< - { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - }, - 'data' | 'fulfilledTimeStamp' - > - > & { - error: undefined; - } & { - status: QueryStatus.fulfilled; - isUninitialized: false; - isLoading: false; - isSuccess: true; - isError: false; - }) - | ({ - status: QueryStatus.pending; - } & { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - } & { - data?: undefined; - } & { - status: QueryStatus.pending; - isUninitialized: false; - isLoading: true; - isSuccess: false; - isError: false; - }) - | ({ - status: QueryStatus.rejected; - } & Omit< - { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - }, - 'error' - > & - Required< - Pick< - { - requestId: string; - data?: unknown; - error?: FetchBaseQueryError | SerializedError | undefined; - endpointName: string; - startedTimeStamp: number; - fulfilledTimeStamp?: number; - }, - 'error' - > - > & { - status: QueryStatus.rejected; - isUninitialized: false; - isLoading: false; - isSuccess: false; - isError: true; - })) - | { - error: { - message: string; - type: string; - }; - }; - }; -}>; - -// @public -export interface DaVinciAction { - // (undocumented) - action: string; -} - -// @public -export interface DaVinciBaseResponse { - // (undocumented) - capabilityName?: string; - // (undocumented) - companyId?: string; - // (undocumented) - connectionId?: string; - // (undocumented) - connectorId?: string; - // (undocumented) - id?: string; - // (undocumented) - interactionId?: string; - // (undocumented) - interactionToken?: string; - // (undocumented) - isResponseCompatibleWithMobileAndWebSdks?: boolean; - // (undocumented) - status?: string; -} - -// @public -export type DaVinciCacheEntry = { - data?: DaVinciBaseResponse; - error?: { - data: DaVinciBaseResponse; - status: number; - }; -} & { - data?: any; - error?: any; -} & MutationResultSelectorResult; - -// @public (undocumented) -export type DavinciClient = Awaited>; - -// @public (undocumented) -export interface DaVinciConfig extends AsyncLegacyConfigOptions { - // (undocumented) - responseType?: string; -} - -// @public (undocumented) -export interface DaVinciError extends Omit { - // (undocumented) - collectors?: CollectorErrors[]; - // (undocumented) - internalHttpStatus?: number; - // (undocumented) - message: string; - // (undocumented) - status: 'error' | 'failure' | 'unknown'; -} - -// @public (undocumented) -export interface DaVinciErrorCacheEntry { - // (undocumented) - endpointName: 'next' | 'flow' | 'start'; - // (undocumented) - error: { - data: T; - }; - // (undocumented) - fulfilledTimeStamp: number; - // (undocumented) - isError: boolean; - // (undocumented) - isLoading: boolean; - // (undocumented) - isSuccess: boolean; - // (undocumented) - isUninitialized: boolean; - // (undocumented) - requestId: string; - // (undocumented) - startedTimeStamp: number; - // (undocumented) - status: 'fulfilled' | 'pending' | 'rejected'; -} - -// @public (undocumented) -export interface DavinciErrorResponse extends DaVinciBaseResponse { - // (undocumented) - cause?: string | null; - // (undocumented) - code: string | number; - // (undocumented) - details?: ErrorDetail[]; - // (undocumented) - doNotSendToOE?: boolean; - // (undocumented) - error?: { - code?: string; - message?: string; - }; - // (undocumented) - errorCategory?: string; - // (undocumented) - errorMessage?: string; - // (undocumented) - expected?: boolean; - // (undocumented) - httpResponseCode: number; - // (undocumented) - isErrorCustomized?: boolean; - // (undocumented) - message: string; - // (undocumented) - metricAttributes?: { - [key: string]: unknown; - }; -} - -// @public (undocumented) -export interface DaVinciFailureResponse extends DaVinciBaseResponse { - // (undocumented) - error?: { - code?: string; - message?: string; - [key: string]: unknown; - }; -} - -// @public (undocumented) -export type DaVinciField = - | ComplexValueFields - | MultiValueFields - | ReadOnlyFields - | RedirectFields - | SingleValueFields; - -// @public -export interface DaVinciNextResponse extends DaVinciBaseResponse { - // (undocumented) - eventName?: string; - // (undocumented) - form?: { - name?: string; - description?: string; - components?: { - fields?: DaVinciField[]; - }; - }; - // (undocumented) - formData?: { - value?: { - [key: string]: string; - }; - }; - // (undocumented) - _links?: Links; -} - -// @public -export interface DaVinciPollResponse extends DaVinciBaseResponse { - // (undocumented) - eventName?: string; - // (undocumented) - _links?: Links; - // (undocumented) - success?: boolean; -} - -// @public (undocumented) -export interface DaVinciRequest { - // (undocumented) - eventName: string; - // (undocumented) - id: string; - // (undocumented) - interactionId: string; - // (undocumented) - parameters: { - eventType: 'submit' | 'action' | 'polling'; - data: { - actionKey: string; - formData?: Record; - }; - }; -} - -// @public (undocumented) -export interface DaVinciSuccessResponse extends DaVinciBaseResponse { - // (undocumented) - authorizeResponse?: OAuthDetails; - // (undocumented) - environment: { - id: string; - [key: string]: unknown; - }; - // (undocumented) - _links?: Links; - // (undocumented) - resetCookie?: boolean; - // (undocumented) - session?: { - id?: string; - [key: string]: unknown; - }; - // (undocumented) - sessionToken?: string; - // (undocumented) - sessionTokenMaxAge?: number; - // (undocumented) - status: string; - // (undocumented) - subFlowSettings?: { - cssLinks?: unknown[]; - cssUrl?: unknown; - jsLinks?: unknown[]; - loadingScreenSettings?: unknown; - reactSkUrl?: unknown; - }; - // (undocumented) - success: true; -} - -// @public (undocumented) -export type DeviceAuthenticationCollector = ObjectOptionsCollectorWithObjectValue< - 'DeviceAuthenticationCollector', - DeviceValue ->; - -// @public (undocumented) -export type DeviceAuthenticationField = { - type: 'DEVICE_AUTHENTICATION'; - key: string; - label: string; - options: { - type: string; - iconSrc: string; - title: string; - id: string; - default: boolean; - description: string; - }[]; - required: boolean; -}; - -// @public (undocumented) -export interface DeviceOptionNoDefault { - // (undocumented) - content: string; - // (undocumented) - key: string; - // (undocumented) - label: string; - // (undocumented) - type: string; - // (undocumented) - value: string; -} - -// @public (undocumented) -export interface DeviceOptionWithDefault { - // (undocumented) - content: string; - // (undocumented) - default: boolean; - // (undocumented) - key: string; - // (undocumented) - label: string; - // (undocumented) - type: string; - // (undocumented) - value: string; -} - -// @public (undocumented) -export type DeviceRegistrationCollector = ObjectOptionsCollectorWithStringValue< - 'DeviceRegistrationCollector', - string ->; - -// @public (undocumented) -export type DeviceRegistrationField = { - type: 'DEVICE_REGISTRATION'; - key: string; - label: string; - options: { - type: string; - iconSrc: string; - title: string; - description: string; - }[]; - required: boolean; -}; - -// @public (undocumented) -export interface DeviceValue { - // (undocumented) - id: string; - // (undocumented) - type: string; - // (undocumented) - value: string; -} - -// @public (undocumented) -export interface ErrorDetail { - // (undocumented) - message?: string; - // (undocumented) - rawResponse?: { - _embedded?: { - users?: Array; - }; - code?: string; - count?: number; - details?: NestedErrorDetails[]; - id?: string; - message?: string; - size?: number; - userFilter?: string; - [key: string]: unknown; - }; - // (undocumented) - statusCode?: number; -} - -// @public (undocumented) -export interface ErrorNode { - // (undocumented) - cache: { - key: string; - }; - // (undocumented) - client: { - action: string; - collectors: Collectors[]; - description?: string; - name?: string; - status: 'error'; - }; - // (undocumented) - error: DaVinciError; - // (undocumented) - httpStatus: number; - // (undocumented) - server: { - _links?: Links; - eventName?: string; - id?: string; - interactionId?: string; - interactionToken?: string; - status: 'error'; - } | null; - // (undocumented) - status: 'error'; -} - -// @public (undocumented) -export interface FailureNode { - // (undocumented) - cache: { - key: string; - }; - // (undocumented) - client: { - status: 'failure'; - }; - // (undocumented) - error: DaVinciError; - // (undocumented) - httpStatus: number; - // (undocumented) - server: { - _links?: Links; - eventName?: string; - href?: string; - id?: string; - interactionId?: string; - interactionToken?: string; - status: 'failure'; - } | null; - // (undocumented) - status: 'failure'; -} - -// @public (undocumented) -export type FidoAuthenticationCollector = AutoCollector< - 'ObjectValueAutoCollector', - 'FidoAuthenticationCollector', - FidoAuthenticationInputValue, - FidoAuthenticationOutputValue ->; - -// @public (undocumented) -export type FidoAuthenticationField = { - type: 'FIDO2'; - key: string; - label: string; - publicKeyCredentialRequestOptions: FidoAuthenticationOptions; - action: 'AUTHENTICATE'; - trigger: string; - required: boolean; -}; - -// @public (undocumented) -export interface FidoAuthenticationInputValue { - // (undocumented) - assertionValue?: AssertionValue; -} - -// @public (undocumented) -export interface FidoAuthenticationOptions extends Omit< - PublicKeyCredentialRequestOptions, - 'challenge' | 'allowCredentials' -> { - // (undocumented) - allowCredentials?: { - id: number[]; - transports?: AuthenticatorTransport[]; - type: PublicKeyCredentialType; - }[]; - // (undocumented) - challenge: number[]; -} - -// @public (undocumented) -export interface FidoAuthenticationOutputValue { - // (undocumented) - action: 'AUTHENTICATE'; - // (undocumented) - publicKeyCredentialRequestOptions: FidoAuthenticationOptions; - // (undocumented) - trigger: string; -} - -// @public (undocumented) -export interface FidoClient { - authenticate: ( - options: FidoAuthenticationOptions, - ) => Promise; - register: ( - options: FidoRegistrationOptions, - ) => Promise; -} - -// @public (undocumented) -export type FidoRegistrationCollector = AutoCollector< - 'ObjectValueAutoCollector', - 'FidoRegistrationCollector', - FidoRegistrationInputValue, - FidoRegistrationOutputValue ->; - -// @public (undocumented) -export type FidoRegistrationField = { - type: 'FIDO2'; - key: string; - label: string; - publicKeyCredentialCreationOptions: FidoRegistrationOptions; - action: 'REGISTER'; - trigger: string; - required: boolean; -}; - -// @public (undocumented) -export interface FidoRegistrationInputValue { - // (undocumented) - attestationValue?: AttestationValue; -} - -// @public (undocumented) -export interface FidoRegistrationOptions extends Omit< - PublicKeyCredentialCreationOptions, - 'challenge' | 'user' | 'pubKeyCredParams' | 'excludeCredentials' -> { - // (undocumented) - challenge: number[]; - // (undocumented) - excludeCredentials?: { - id: number[]; - transports?: AuthenticatorTransport[]; - type: PublicKeyCredentialType; - }[]; - // (undocumented) - pubKeyCredParams: { - alg: string | number; - type: PublicKeyCredentialType; - }[]; - // (undocumented) - user: { - id: number[]; - name: string; - displayName: string; - }; -} - -// @public (undocumented) -export interface FidoRegistrationOutputValue { - // (undocumented) - action: 'REGISTER'; - // (undocumented) - publicKeyCredentialCreationOptions: FidoRegistrationOptions; - // (undocumented) - trigger: string; -} - -// @public (undocumented) -export type FlowCollector = ActionCollectorNoUrl<'FlowCollector'>; - -// @public (undocumented) -export type FlowNode = ContinueNode | ErrorNode | StartNode | SuccessNode | FailureNode; - -// @public -export type GetClient = - | StartNode['client'] - | ContinueNode['client'] - | ErrorNode['client'] - | SuccessNode['client'] - | FailureNode['client']; - -// @public (undocumented) -export type IdpCollector = ActionCollectorWithUrl<'IdpCollector'>; - -// @public (undocumented) -export type InferActionCollectorType = T extends 'IdpCollector' - ? IdpCollector - : T extends 'SubmitCollector' - ? SubmitCollector - : T extends 'FlowCollector' - ? FlowCollector - : ActionCollectorWithUrl<'ActionCollector'> | ActionCollectorNoUrl<'ActionCollector'>; - -// @public -export type InferAutoCollectorType = T extends 'ProtectCollector' - ? ProtectCollector - : T extends 'PollingCollector' - ? PollingCollector - : T extends 'FidoRegistrationCollector' - ? FidoRegistrationCollector - : T extends 'FidoAuthenticationCollector' - ? FidoAuthenticationCollector - : T extends 'ObjectValueAutoCollector' - ? ObjectValueAutoCollector - : SingleValueAutoCollector; - -// @public -export type InferMultiValueCollectorType = - T extends 'MultiSelectCollector' - ? MultiValueCollectorWithValue<'MultiSelectCollector'> - : - | MultiValueCollectorWithValue<'MultiValueCollector'> - | MultiValueCollectorNoValue<'MultiValueCollector'>; - -// @public -export type InferNoValueCollectorType = - T extends 'ReadOnlyCollector' - ? ReadOnlyCollector - : T extends 'RichTextCollector' - ? RichTextCollector - : T extends 'QrCodeCollector' - ? QrCodeCollector - : T extends 'AgreementCollector' - ? AgreementCollector - : NoValueCollectorBase<'NoValueCollector'>; - -// @public -export type InferSingleValueCollectorType = - T extends 'TextCollector' - ? TextCollector - : T extends 'SingleSelectCollector' - ? SingleSelectCollector - : T extends 'ValidatedTextCollector' - ? ValidatedTextCollector - : T extends 'PasswordCollector' - ? PasswordCollector - : T extends 'ValidatedPasswordCollector' - ? ValidatedPasswordCollector - : - | SingleValueCollectorWithValue<'SingleValueCollector'> - | SingleValueCollectorNoValue<'SingleValueCollector'>; - -// @public (undocumented) -export type InferValueObjectCollectorType = - T extends 'DeviceAuthenticationCollector' - ? DeviceAuthenticationCollector - : T extends 'DeviceRegistrationCollector' - ? DeviceRegistrationCollector - : T extends 'PhoneNumberCollector' - ? PhoneNumberCollector - : T extends 'PhoneNumberExtensionCollector' - ? PhoneNumberExtensionCollector - : - | ObjectOptionsCollectorWithObjectValue<'ObjectValueCollector'> - | ObjectOptionsCollectorWithStringValue<'ObjectValueCollector'>; - -// @public (undocumented) -export type InitFlow = () => Promise; - -// @public (undocumented) -export interface InternalErrorResponse { - // (undocumented) - error: Omit & { - message: string; - }; - // (undocumented) - type: 'internal_error'; -} - -// @public (undocumented) -export interface Links { - // (undocumented) - [key: string]: { - href?: string; - }; -} - -export { LogLevel }; - -// @public (undocumented) -export type MultiSelectCollector = MultiValueCollectorWithValue<'MultiSelectCollector'>; - -// @public (undocumented) -export type MultiSelectField = { - inputType: 'MULTI_SELECT'; - key: string; - label: string; - options: { - label: string; - value: string; - }[]; - required?: boolean; - type: 'CHECKBOX' | 'COMBOBOX'; -}; - -// @public (undocumented) -export type MultiValueCollector = - | MultiValueCollectorWithValue - | MultiValueCollectorNoValue; - -// @public (undocumented) -export interface MultiValueCollectorNoValue { - // (undocumented) - category: 'MultiValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string[]; - type: string; - validation: ValidationRequired[] | null; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - options: SelectorOption[]; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type MultiValueCollectors = - | MultiValueCollectorWithValue<'MultiValueCollector'> - | MultiValueCollectorWithValue<'MultiSelectCollector'>; - -// @public -export type MultiValueCollectorTypes = 'MultiSelectCollector' | 'MultiValueCollector'; - -// @public (undocumented) -export interface MultiValueCollectorWithValue { - // (undocumented) - category: 'MultiValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string[]; - type: string; - validation: ValidationRequired[] | null; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - value: string[]; - options: SelectorOption[]; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type MultiValueFields = MultiSelectField; - -// @public -export interface NestedErrorDetails { - // (undocumented) - code?: string; - // (undocumented) - innerError?: { - history?: string; - unsatisfiedRequirements?: string[]; - failuresRemaining?: number; - }; - // (undocumented) - message?: string; - // (undocumented) - target?: string; -} - -// @public -export const nextCollectorValues: ActionCreatorWithPayload< - { - fields: DaVinciField[]; - formData: { - value: Record; - }; - }, - string ->; - -// @public -export const nodeCollectorReducer: Reducer< - ( - | TextCollector - | SingleSelectCollector - | ValidatedTextCollector - | PasswordCollector - | ValidatedPasswordCollector - | MultiSelectCollector - | PhoneNumberExtensionCollector - | DeviceAuthenticationCollector - | DeviceRegistrationCollector - | PhoneNumberCollector - | IdpCollector - | SubmitCollector - | FlowCollector - | QrCodeCollector - | ReadOnlyCollector - | RichTextCollector - | AgreementCollector - | UnknownCollector - | ProtectCollector - | FidoRegistrationCollector - | FidoAuthenticationCollector - | PollingCollector - | ActionCollector<'ActionCollector'> - | SingleValueCollector<'SingleValueCollector'> - )[] -> & { - getInitialState: () => ( - | TextCollector - | SingleSelectCollector - | ValidatedTextCollector - | PasswordCollector - | ValidatedPasswordCollector - | MultiSelectCollector - | PhoneNumberExtensionCollector - | DeviceAuthenticationCollector - | DeviceRegistrationCollector - | PhoneNumberCollector - | IdpCollector - | SubmitCollector - | FlowCollector - | QrCodeCollector - | ReadOnlyCollector - | RichTextCollector - | AgreementCollector - | UnknownCollector - | ProtectCollector - | FidoRegistrationCollector - | FidoAuthenticationCollector - | PollingCollector - | ActionCollector<'ActionCollector'> - | SingleValueCollector<'SingleValueCollector'> - )[]; -}; - -// @public (undocumented) -export type NodeStates = StartNode | ContinueNode | ErrorNode | SuccessNode | FailureNode; - -// @public (undocumented) -export type NoValueCollector = InferNoValueCollectorType; - -// @public (undocumented) -export interface NoValueCollectorBase { - // (undocumented) - category: 'NoValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type NoValueCollectors = - | NoValueCollectorBase<'NoValueCollector'> - | ReadOnlyCollector - | RichTextCollector - | QrCodeCollector - | AgreementCollector; - -// @public -export type NoValueCollectorTypes = - | 'ReadOnlyCollector' - | 'RichTextCollector' - | 'NoValueCollector' - | 'QrCodeCollector' - | 'AgreementCollector'; - -// @public -export interface OAuthDetails { - // (undocumented) - [key: string]: unknown; - // (undocumented) - code?: string; - // (undocumented) - state?: string; -} - -// @public (undocumented) -export interface ObjectOptionsCollectorWithObjectValue< - T extends ObjectValueCollectorTypes, - V = Record, - D = Record, -> { - // (undocumented) - category: 'ObjectValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: V; - type: string; - validation: ValidationRequired[] | null; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - options: DeviceOptionWithDefault[]; - value?: D | null; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export interface ObjectOptionsCollectorWithStringValue< - T extends ObjectValueCollectorTypes, - V = string, -> { - // (undocumented) - category: 'ObjectValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: V; - type: string; - validation: ValidationRequired[] | null; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - options: DeviceOptionNoDefault[]; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type ObjectValueAutoCollector = AutoCollector< - 'ObjectValueAutoCollector', - 'ObjectValueAutoCollector', - Record ->; - -// @public (undocumented) -export type ObjectValueAutoCollectorTypes = - | 'ObjectValueAutoCollector' - | 'FidoRegistrationCollector' - | 'FidoAuthenticationCollector'; - -// @public (undocumented) -export type ObjectValueCollector = - | ObjectOptionsCollectorWithObjectValue - | ObjectOptionsCollectorWithStringValue - | ObjectValueCollectorWithObjectValue; - -// @public (undocumented) -export type ObjectValueCollectors = - | DeviceAuthenticationCollector - | DeviceRegistrationCollector - | PhoneNumberCollector - | PhoneNumberExtensionCollector - | ObjectOptionsCollectorWithObjectValue<'ObjectSelectCollector'> - | ObjectOptionsCollectorWithStringValue<'ObjectSelectCollector'>; - -// @public -export type ObjectValueCollectorTypes = - | 'DeviceAuthenticationCollector' - | 'DeviceRegistrationCollector' - | 'PhoneNumberCollector' - | 'PhoneNumberExtensionCollector' - | 'ObjectOptionsCollector' - | 'ObjectValueCollector' - | 'ObjectSelectCollector'; - -// @public (undocumented) -export interface ObjectValueCollectorWithObjectValue< - T extends ObjectValueCollectorTypes, - IV = Record, - OV = Record, -> { - // (undocumented) - category: 'ObjectValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: IV; - type: string; - validation: (ValidationRequired | ValidationPhoneNumber)[] | null; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - value?: OV | null; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export interface OutgoingQueryParams { - // (undocumented) - [key: string]: string | string[]; -} - -// @public (undocumented) -export interface PasswordCollector { - // (undocumented) - category: 'SingleValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string | number | boolean; - type: string; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - verify: boolean; - }; - // (undocumented) - type: 'PasswordCollector'; -} - -// @public -export type PasswordField = { - type: 'PASSWORD' | 'PASSWORD_VERIFY'; - key: string; - label: string; - required?: boolean; - verify?: boolean; - passwordPolicy?: PasswordPolicy; -}; - -// @public (undocumented) -export interface PasswordPolicy { - // (undocumented) - createdAt?: string; - // (undocumented) - default?: boolean; - // (undocumented) - description?: string; - // (undocumented) - excludesCommonlyUsed?: boolean; - // (undocumented) - excludesProfileData?: boolean; - // (undocumented) - history?: { - count?: number; - retentionDays?: number; - }; - // (undocumented) - id?: string; - // (undocumented) - length?: { - min?: number; - max?: number; - }; - // (undocumented) - lockout?: { - failureCount?: number; - durationSeconds?: number; - }; - // (undocumented) - maxAgeDays?: number; - // (undocumented) - maxRepeatedCharacters?: number; - // (undocumented) - minAgeDays?: number; - // (undocumented) - minCharacters?: Record; - // (undocumented) - minUniqueCharacters?: number; - // (undocumented) - name?: string; - // (undocumented) - notSimilarToCurrent?: boolean; - // (undocumented) - populationCount?: number; - // (undocumented) - updatedAt?: string; -} - -// @public (undocumented) -export type PhoneNumberCollector = ObjectValueCollectorWithObjectValue< - 'PhoneNumberCollector', - PhoneNumberInputValue, - PhoneNumberOutputValue ->; - -// @public (undocumented) -export interface PhoneNumberExtensionCollector { - // (undocumented) - category: 'ObjectValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: PhoneNumberExtensionInputValue; - type: string; - validation: (ValidationRequired | ValidationPhoneNumber)[] | null; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - extensionLabel: string; - value: PhoneNumberExtensionOutputValue; - }; - // (undocumented) - type: 'PhoneNumberExtensionCollector'; -} - -// @public (undocumented) -export type PhoneNumberExtensionField = PhoneNumberField & { - showExtension: boolean; - extensionLabel: string; -}; - -// @public (undocumented) -export interface PhoneNumberExtensionInputValue { - // (undocumented) - countryCode: string; - // (undocumented) - extension: string; - // (undocumented) - phoneNumber: string; -} - -// @public (undocumented) -export interface PhoneNumberExtensionOutputValue { - // (undocumented) - countryCode?: string; - // (undocumented) - extension?: string; - // (undocumented) - phoneNumber?: string; -} - -// @public (undocumented) -export type PhoneNumberField = { - type: 'PHONE_NUMBER'; - key: string; - label: string; - required: boolean; - defaultCountryCode: string | null; - validatePhoneNumber: boolean; -}; - -// @public (undocumented) -export interface PhoneNumberInputValue { - // (undocumented) - countryCode: string; - // (undocumented) - phoneNumber: string; -} - -// @public (undocumented) -export interface PhoneNumberOutputValue { - // (undocumented) - countryCode?: string; - // (undocumented) - phoneNumber?: string; -} - -// @public (undocumented) -export type Poller = () => Promise; - -// @public (undocumented) -export type PollingCollector = AutoCollector< - 'SingleValueAutoCollector', - 'PollingCollector', - string, - PollingOutputValue ->; - -// @public (undocumented) -export type PollingField = { - type: 'POLLING'; - key: string; - pollInterval: number; - pollRetries: number; - pollChallengeStatus?: boolean; - challenge?: string; -}; - -// @public (undocumented) -export interface PollingOutputValue { - // (undocumented) - challenge?: string; - // (undocumented) - pollChallengeStatus?: boolean; - // (undocumented) - pollInterval: number; - // (undocumented) - pollRetries: number; - // (undocumented) - retriesRemaining?: number; -} - -// @public (undocumented) -export type PollingStatus = PollingStatusContinue | PollingStatusChallenge; - -// @public (undocumented) -export type PollingStatusChallenge = - | PollingStatusChallengeComplete - | 'expired' - | 'timedOut' - | 'error'; - -// @public (undocumented) -export type PollingStatusChallengeComplete = - | 'approved' - | 'denied' - | 'continue' - | CustomPollingStatus; - -// @public (undocumented) -export type PollingStatusContinue = 'continue' | 'timedOut'; - -// @public (undocumented) -export type ProtectCollector = AutoCollector< - 'SingleValueAutoCollector', - 'ProtectCollector', - string, - ProtectOutputValue ->; - -// @public (undocumented) -export type ProtectField = { - type: 'PROTECT'; - key: string; - behavioralDataCollection: boolean; - universalDeviceIdentification: boolean; -}; - -// @public -export interface ProtectOutputValue { - // (undocumented) - behavioralDataCollection: boolean; - // (undocumented) - universalDeviceIdentification: boolean; -} - -// @public -export interface QrCodeCollector extends NoValueCollectorBase<'QrCodeCollector'> { - // (undocumented) - output: NoValueCollectorBase<'QrCodeCollector'>['output'] & { - src: string; - }; -} - -// @public (undocumented) -export type QrCodeField = { - type: 'QR_CODE'; - key: string; - content: string; - fallbackText?: string; -}; - -// @public -export interface ReadOnlyCollector extends NoValueCollectorBase<'ReadOnlyCollector'> { - // (undocumented) - output: NoValueCollectorBase<'ReadOnlyCollector'>['output'] & { - content: string; - }; -} - -// @public -export type ReadOnlyField = { - type: 'LABEL'; - content: string; - richContent?: RichContent; - key?: string; -}; - -// @public (undocumented) -export type ReadOnlyFields = ReadOnlyField | QrCodeField | AgreementField; - -// @public (undocumented) -export type RedirectField = { - type: 'SOCIAL_LOGIN_BUTTON'; - key: string; - label: string; - links: Links; -}; - -// @public (undocumented) -export type RedirectFields = RedirectField; - -export { RequestMiddleware }; - -// @public -export type RichContent = { - content: string; - replacements?: Record; -}; - -// @public -export interface RichContentLink { - // (undocumented) - href: string; - // (undocumented) - key: string; - // (undocumented) - target?: '_self' | '_blank'; - // (undocumented) - type: 'link'; - // (undocumented) - value: string; -} - -// @public -export type RichContentReplacement = { - type: 'link'; - value: string; - href: string; - target?: '_self' | '_blank'; -}; - -// @public -export interface RichTextCollector extends NoValueCollectorBase<'RichTextCollector'> { - // (undocumented) - output: NoValueCollectorBase<'RichTextCollector'>['output'] & { - content: string; - richContent: CollectorRichContent; - }; -} - -// @public (undocumented) -export interface SelectorOption { - // (undocumented) - label: string; - // (undocumented) - value: string; -} - -// @public (undocumented) -export type SingleSelectCollector = SingleSelectCollectorWithValue<'SingleSelectCollector'>; - -// @public (undocumented) -export interface SingleSelectCollectorNoValue { - // (undocumented) - category: 'SingleValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string | number | boolean; - type: string; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - options: SelectorOption[]; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export interface SingleSelectCollectorWithValue { - // (undocumented) - category: 'SingleValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string | number | boolean; - type: string; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - value: string | number | boolean; - options: SelectorOption[]; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type SingleSelectField = { - inputType: 'SINGLE_SELECT'; - key: string; - label: string; - options: { - label: string; - value: string; - }[]; - required?: boolean; - type: 'RADIO' | 'DROPDOWN'; -}; - -// @public (undocumented) -export type SingleValueAutoCollector = AutoCollector< - 'SingleValueAutoCollector', - 'SingleValueAutoCollector', - string ->; - -// @public (undocumented) -export type SingleValueAutoCollectorTypes = - | 'SingleValueAutoCollector' - | 'ProtectCollector' - | 'PollingCollector'; - -// @public -export type SingleValueCollector = - | SingleValueCollectorWithValue - | SingleValueCollectorNoValue; - -// @public (undocumented) -export interface SingleValueCollectorNoValue { - // (undocumented) - category: 'SingleValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string | number | boolean; - type: string; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type SingleValueCollectors = - | PasswordCollector - | ValidatedPasswordCollector - | SingleSelectCollectorWithValue<'SingleSelectCollector'> - | SingleValueCollectorWithValue<'SingleValueCollector'> - | SingleValueCollectorWithValue<'TextCollector'> - | ValidatedSingleValueCollectorWithValue<'TextCollector'>; - -// @public -export type SingleValueCollectorTypes = - | 'PasswordCollector' - | 'ValidatedPasswordCollector' - | 'SingleValueCollector' - | 'SingleSelectCollector' - | 'SingleSelectObjectCollector' - | 'TextCollector' - | 'ValidatedTextCollector'; - -// @public (undocumented) -export interface SingleValueCollectorWithValue { - // (undocumented) - category: 'SingleValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string | number | boolean; - type: string; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - value: string | number | boolean; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type SingleValueFields = - | StandardField - | PasswordField - | ValidatedField - | SingleSelectField - | ProtectField; - -// @public (undocumented) -export type StandardField = { - type: 'TEXT' | 'SUBMIT_BUTTON' | 'FLOW_BUTTON' | 'FLOW_LINK' | 'BUTTON'; - key: string; - label: string; - required?: boolean; -}; - -// @public (undocumented) -export interface StartNode { - // (undocumented) - cache: null; - // (undocumented) - client: { - status: 'start'; - }; - // (undocumented) - error: DaVinciError | null; - // (undocumented) - server: { - status: 'start'; - }; - // (undocumented) - status: 'start'; -} - -// @public (undocumented) -export interface StartOptions { - // (undocumented) - query: Query; -} - -// @public (undocumented) -export type SubmitCollector = ActionCollectorNoUrl<'SubmitCollector'>; - -// @public (undocumented) -export interface SuccessNode { - // (undocumented) - cache: { - key: string; - }; - // (undocumented) - client: { - authorization?: { - code?: string; - state?: string; - }; - status: 'success'; - } | null; - // (undocumented) - error: null; - // (undocumented) - httpStatus: number; - // (undocumented) - server: { - _links?: Links; - eventName?: string; - id?: string; - interactionId?: string; - interactionToken?: string; - href?: string; - session?: string; - status: 'success'; - }; - // (undocumented) - status: 'success'; -} - -// @public (undocumented) -export type TextCollector = SingleValueCollectorWithValue<'TextCollector'>; - -// @public (undocumented) -export interface ThrownQueryError { - // (undocumented) - error: FetchBaseQueryError; - // (undocumented) - isHandledError: boolean; - // (undocumented) - meta: FetchBaseQueryMeta; -} - -// @public -export type UnknownCollector = { - category: 'UnknownCollector'; - error: string | null; - type: 'UnknownCollector'; - id: string; - name: string; - output: { - key: string; - label: string; - type: string; - }; -}; - -// @public (undocumented) -export type UnknownField = Record; - -// @public (undocumented) -export const updateCollectorValues: ActionCreatorWithPayload< - { - id: string; - value: - | string - | string[] - | PhoneNumberInputValue - | PhoneNumberExtensionInputValue - | FidoRegistrationInputValue - | FidoAuthenticationInputValue; - index?: number; - }, - string ->; - -// @public -export type Updater = ( - value: CollectorValueType, - index?: number, -) => InternalErrorResponse | null; - -// @public (undocumented) -export type ValidatedField = { - type: 'TEXT'; - key: string; - label: string; - required: boolean; - validation: { - regex: string; - errorMessage: string; - }; -}; - -// @public (undocumented) -export interface ValidatedPasswordCollector { - // (undocumented) - category: 'SingleValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string | number | boolean; - type: string; - validation: PasswordPolicy; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - verify: boolean; - }; - // (undocumented) - type: 'ValidatedPasswordCollector'; -} - -// @public (undocumented) -export interface ValidatedSingleValueCollectorWithValue { - // (undocumented) - category: 'ValidatedSingleValueCollector'; - // (undocumented) - error: string | null; - // (undocumented) - id: string; - // (undocumented) - input: { - key: string; - value: string | number | boolean; - type: string; - validation: (ValidationRequired | ValidationRegex)[]; - }; - // (undocumented) - name: string; - // (undocumented) - output: { - key: string; - label: string; - type: string; - value: string | number | boolean; - }; - // (undocumented) - type: T; -} - -// @public (undocumented) -export type ValidatedTextCollector = ValidatedSingleValueCollectorWithValue<'TextCollector'>; - -// @public (undocumented) -export interface ValidationPhoneNumber { - // (undocumented) - message: string; - // (undocumented) - rule: boolean; - // (undocumented) - type: 'validatePhoneNumber'; -} - -// @public (undocumented) -export interface ValidationRegex { - // (undocumented) - message: string; - // (undocumented) - rule: string; - // (undocumented) - type: 'regex'; -} - -// @public (undocumented) -export interface ValidationRequired { - // (undocumented) - message: string; - // (undocumented) - rule: boolean; - // (undocumented) - type: 'required'; -} - -// @public (undocumented) -export type Validator = (value: string) => - | string[] - | { - error: { - message: string; - type: string; - }; - type: string; - }; - -// (No @packageDocumentation comment for this package) -``` +## API Report File for "@forgerock/davinci-client" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { ActionCreatorWithPayload } from '@reduxjs/toolkit'; +import { ActionTypes } from '@forgerock/sdk-request-middleware'; +import type { AsyncLegacyConfigOptions } from '@forgerock/sdk-types'; +import { BaseQueryFn } from '@reduxjs/toolkit/query'; +import { CustomLogger } from '@forgerock/sdk-logger'; +import { FetchArgs } from '@reduxjs/toolkit/query'; +import { FetchBaseQueryError } from '@reduxjs/toolkit/query'; +import { FetchBaseQueryMeta } from '@reduxjs/toolkit/query'; +import { GenericError } from '@forgerock/sdk-types'; +import { LogLevel } from '@forgerock/sdk-logger'; +import { MutationDefinition } from '@reduxjs/toolkit/query'; +import type { MutationResultSelectorResult } from '@reduxjs/toolkit/query'; +import { QueryDefinition } from '@reduxjs/toolkit/query'; +import { QueryStatus } from '@reduxjs/toolkit/query'; +import { Reducer } from '@reduxjs/toolkit'; +import { RequestMiddleware } from '@forgerock/sdk-request-middleware'; +import { RootState } from '@reduxjs/toolkit/query'; +import { SerializedError } from '@reduxjs/toolkit'; +import { Unsubscribe } from '@reduxjs/toolkit'; + +// @public (undocumented) +export type ActionCollector = ActionCollectorNoUrl | ActionCollectorWithUrl; + +// @public (undocumented) +export interface ActionCollectorNoUrl { + // (undocumented) + category: 'ActionCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type ActionCollectors = ActionCollectorWithUrl<'IdpCollector'> | ActionCollectorNoUrl<'ActionCollector'> | ActionCollectorNoUrl<'FlowCollector'> | ActionCollectorNoUrl<'SubmitCollector'>; + +// @public +export type ActionCollectorTypes = 'FlowCollector' | 'SubmitCollector' | 'IdpCollector' | 'ActionCollector'; + +// @public (undocumented) +export interface ActionCollectorWithUrl { + // (undocumented) + category: 'ActionCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + url?: string | null; + }; + // (undocumented) + type: T; +} + +export { ActionTypes } + +// @public (undocumented) +export interface AgreementCollector extends NoValueCollectorBase<'AgreementCollector'> { + // (undocumented) + output: { + key: string; + label: string; + type: string; + titleEnabled: boolean; + title: string; + agreement: { + id: string; + useDynamicAgreement: boolean; + }; + enabled: boolean; + }; +} + +// @public (undocumented) +export type AgreementField = { + type: 'AGREEMENT'; + key: string; + content: string; + titleEnabled: boolean; + title: string; + agreement: { + id: string; + useDynamicAgreement: boolean; + }; + enabled: boolean; +}; + +// @public (undocumented) +export interface AssertionValue extends Omit { + // (undocumented) + rawId: string; + // (undocumented) + response: { + clientDataJSON: string; + authenticatorData: string; + signature: string; + userHandle: string | null; + }; +} + +// @public (undocumented) +export interface AttestationValue extends Omit { + // (undocumented) + rawId: string; + // (undocumented) + response: { + clientDataJSON: string; + attestationObject: string; + }; +} + +// @public (undocumented) +export interface AutoCollector> { + // (undocumented) + category: C; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: IV; + type: string; + validation?: ValidationRequired[] | null; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + type: string; + config: OV; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type AutoCollectorCategories = 'SingleValueAutoCollector' | 'ObjectValueAutoCollector'; + +// @public (undocumented) +export type AutoCollectors = ProtectCollector | FidoRegistrationCollector | FidoAuthenticationCollector | PollingCollector | SingleValueAutoCollector | ObjectValueAutoCollector; + +// @public (undocumented) +export type AutoCollectorTypes = SingleValueAutoCollectorTypes | ObjectValueAutoCollectorTypes; + +// @public (undocumented) +export interface CollectorErrors { + // (undocumented) + code: string; + // (undocumented) + message: string; + // (undocumented) + target: string; +} + +// @public +export interface CollectorRichContent { + // (undocumented) + content: string; + // (undocumented) + replacements: RichContentLink[]; +} + +// @public (undocumented) +export type Collectors = FlowCollector | PasswordCollector | ValidatedPasswordCollector | TextCollector | SingleSelectCollector | IdpCollector | SubmitCollector | ActionCollector<'ActionCollector'> | SingleValueCollector<'SingleValueCollector'> | MultiSelectCollector | DeviceAuthenticationCollector | DeviceRegistrationCollector | PhoneNumberCollector | PhoneNumberExtensionCollector | ReadOnlyCollector | RichTextCollector | ValidatedTextCollector | ProtectCollector | PollingCollector | FidoRegistrationCollector | FidoAuthenticationCollector | QrCodeCollector | AgreementCollector | UnknownCollector; + +// @public +export type CollectorValueType = T extends { + type: 'PasswordCollector'; +} ? string : T extends { + type: 'ValidatedPasswordCollector'; +} ? string : T extends { + type: 'TextCollector'; + category: 'SingleValueCollector'; +} ? string : T extends { + type: 'TextCollector'; + category: 'ValidatedSingleValueCollector'; +} ? string : T extends { + type: 'SingleSelectCollector'; +} ? string : T extends { + type: 'MultiSelectCollector'; +} ? string[] : T extends { + type: 'DeviceRegistrationCollector'; +} ? string : T extends { + type: 'DeviceAuthenticationCollector'; +} ? string : T extends { + type: 'PhoneNumberCollector'; +} ? PhoneNumberInputValue : T extends { + type: 'FidoRegistrationCollector'; +} ? FidoRegistrationInputValue : T extends { + type: 'FidoAuthenticationCollector'; +} ? FidoAuthenticationInputValue : T extends { + category: 'SingleValueCollector'; +} ? string : T extends { + category: 'ValidatedSingleValueCollector'; +} ? string : T extends { + category: 'MultiValueCollector'; +} ? string[] : string | string[] | PhoneNumberInputValue | FidoRegistrationInputValue | FidoAuthenticationInputValue; + +// @public (undocumented) +export type ComplexValueFields = DeviceAuthenticationField | DeviceRegistrationField | PhoneNumberField | PhoneNumberExtensionField | FidoRegistrationField | FidoAuthenticationField | PollingField; + +// @public (undocumented) +export interface ContinueNode { + // (undocumented) + cache: { + key: string; + }; + // (undocumented) + client: { + action: string; + collectors: Collectors[]; + description?: string; + name?: string; + status: 'continue'; + }; + // (undocumented) + error: null; + // (undocumented) + httpStatus: number; + // (undocumented) + server: { + _links?: Links; + id?: string; + interactionId?: string; + interactionToken?: string; + href?: string; + eventName?: string; + status: 'continue'; + }; + // (undocumented) + status: 'continue'; +} + +export { CustomLogger } + +// @public +export type CustomPollingStatus = string & {}; + +// @public +export function davinci(input: { + config: DaVinciConfig; + requestMiddleware?: RequestMiddleware[]; + logger?: { + level: LogLevel; + custom?: CustomLogger; + }; +}): Promise<{ + subscribe: (listener: () => void) => Unsubscribe; + externalIdp: () => (() => Promise); + flow: (action: DaVinciAction) => InitFlow; + next: (args?: DaVinciRequest) => Promise; + resume: (input: { + continueToken: string; + }) => Promise; + start: (options?: StartOptions | undefined) => Promise; + update: (collector: T) => Updater; + validate: (collector: SingleValueCollectors | ObjectValueCollectors | MultiValueCollectors | AutoCollectors) => Validator; + pollStatus: (collector: PollingCollector) => Poller; + getClient: () => { + status: "start"; + } | { + action: string; + collectors: Collectors[]; + description?: string; + name?: string; + status: "continue"; + } | { + action: string; + collectors: Collectors[]; + description?: string; + name?: string; + status: "error"; + } | { + authorization?: { + code?: string; + state?: string; + }; + status: "success"; + } | { + status: "failure"; + } | null; + getCollectors: () => Collectors[]; + getError: () => DaVinciError | null; + getErrorCollectors: () => CollectorErrors[]; + getNode: () => ContinueNode | ErrorNode | StartNode | SuccessNode | FailureNode; + getServer: () => { + _links?: Links; + id?: string; + interactionId?: string; + interactionToken?: string; + href?: string; + eventName?: string; + status: "continue"; + } | { + status: "start"; + } | { + _links?: Links; + eventName?: string; + id?: string; + interactionId?: string; + interactionToken?: string; + status: "error"; + } | { + _links?: Links; + eventName?: string; + id?: string; + interactionId?: string; + interactionToken?: string; + href?: string; + session?: string; + status: "success"; + } | { + _links?: Links; + eventName?: string; + href?: string; + id?: string; + interactionId?: string; + interactionToken?: string; + status: "failure"; + } | null; + cache: { + getLatestResponse: () => ((state: RootState< { + flow: MutationDefinition, never, unknown, "davinci", any>; + next: MutationDefinition, never, unknown, "davinci", any>; + start: MutationDefinition | undefined, BaseQueryFn, never, unknown, "davinci", unknown>; + resume: QueryDefinition< { + serverInfo: ContinueNode["server"]; + continueToken: string; + }, BaseQueryFn, never, unknown, "davinci", unknown>; + poll: MutationDefinition< { + endpoint: string; + interactionId: string; + }, BaseQueryFn, never, unknown, "davinci", unknown>; + }, never, "davinci">) => ({ + requestId?: undefined; + status: QueryStatus.uninitialized; + data?: undefined; + error?: undefined; + endpointName?: string; + startedTimeStamp?: undefined; + fulfilledTimeStamp?: undefined; + } & { + status: QueryStatus.uninitialized; + isUninitialized: true; + isLoading: false; + isSuccess: false; + isError: false; + }) | ({ + status: QueryStatus.fulfilled; + } & Omit<{ + requestId: string; + data?: unknown; + error?: FetchBaseQueryError | SerializedError | undefined; + endpointName: string; + startedTimeStamp: number; + fulfilledTimeStamp?: number; + }, "data" | "fulfilledTimeStamp"> & Required> & { + error: undefined; + } & { + status: QueryStatus.fulfilled; + isUninitialized: false; + isLoading: false; + isSuccess: true; + isError: false; + }) | ({ + status: QueryStatus.pending; + } & { + requestId: string; + data?: unknown; + error?: FetchBaseQueryError | SerializedError | undefined; + endpointName: string; + startedTimeStamp: number; + fulfilledTimeStamp?: number; + } & { + data?: undefined; + } & { + status: QueryStatus.pending; + isUninitialized: false; + isLoading: true; + isSuccess: false; + isError: false; + }) | ({ + status: QueryStatus.rejected; + } & Omit<{ + requestId: string; + data?: unknown; + error?: FetchBaseQueryError | SerializedError | undefined; + endpointName: string; + startedTimeStamp: number; + fulfilledTimeStamp?: number; + }, "error"> & Required> & { + status: QueryStatus.rejected; + isUninitialized: false; + isLoading: false; + isSuccess: false; + isError: true; + })) | { + error: { + message: string; + type: string; + }; + }; + getResponseWithId: (requestId: string) => ((state: RootState< { + flow: MutationDefinition, never, unknown, "davinci", any>; + next: MutationDefinition, never, unknown, "davinci", any>; + start: MutationDefinition | undefined, BaseQueryFn, never, unknown, "davinci", unknown>; + resume: QueryDefinition< { + serverInfo: ContinueNode["server"]; + continueToken: string; + }, BaseQueryFn, never, unknown, "davinci", unknown>; + poll: MutationDefinition< { + endpoint: string; + interactionId: string; + }, BaseQueryFn, never, unknown, "davinci", unknown>; + }, never, "davinci">) => ({ + requestId?: undefined; + status: QueryStatus.uninitialized; + data?: undefined; + error?: undefined; + endpointName?: string; + startedTimeStamp?: undefined; + fulfilledTimeStamp?: undefined; + } & { + status: QueryStatus.uninitialized; + isUninitialized: true; + isLoading: false; + isSuccess: false; + isError: false; + }) | ({ + status: QueryStatus.fulfilled; + } & Omit<{ + requestId: string; + data?: unknown; + error?: FetchBaseQueryError | SerializedError | undefined; + endpointName: string; + startedTimeStamp: number; + fulfilledTimeStamp?: number; + }, "data" | "fulfilledTimeStamp"> & Required> & { + error: undefined; + } & { + status: QueryStatus.fulfilled; + isUninitialized: false; + isLoading: false; + isSuccess: true; + isError: false; + }) | ({ + status: QueryStatus.pending; + } & { + requestId: string; + data?: unknown; + error?: FetchBaseQueryError | SerializedError | undefined; + endpointName: string; + startedTimeStamp: number; + fulfilledTimeStamp?: number; + } & { + data?: undefined; + } & { + status: QueryStatus.pending; + isUninitialized: false; + isLoading: true; + isSuccess: false; + isError: false; + }) | ({ + status: QueryStatus.rejected; + } & Omit<{ + requestId: string; + data?: unknown; + error?: FetchBaseQueryError | SerializedError | undefined; + endpointName: string; + startedTimeStamp: number; + fulfilledTimeStamp?: number; + }, "error"> & Required> & { + status: QueryStatus.rejected; + isUninitialized: false; + isLoading: false; + isSuccess: false; + isError: true; + })) | { + error: { + message: string; + type: string; + }; + }; + }; +}>; + +// @public +export interface DaVinciAction { + // (undocumented) + action: string; +} + +// @public +export interface DaVinciBaseResponse { + // (undocumented) + capabilityName?: string; + // (undocumented) + companyId?: string; + // (undocumented) + connectionId?: string; + // (undocumented) + connectorId?: string; + // (undocumented) + id?: string; + // (undocumented) + interactionId?: string; + // (undocumented) + interactionToken?: string; + // (undocumented) + isResponseCompatibleWithMobileAndWebSdks?: boolean; + // (undocumented) + status?: string; +} + +// @public +export type DaVinciCacheEntry = { + data?: DaVinciBaseResponse; + error?: { + data: DaVinciBaseResponse; + status: number; + }; +} & { + data?: any; + error?: any; +} & MutationResultSelectorResult; + +// @public (undocumented) +export type DavinciClient = Awaited>; + +// @public (undocumented) +export interface DaVinciConfig extends AsyncLegacyConfigOptions { + // (undocumented) + responseType?: string; +} + +// @public (undocumented) +export interface DaVinciError extends Omit { + // (undocumented) + collectors?: CollectorErrors[]; + // (undocumented) + internalHttpStatus?: number; + // (undocumented) + message: string; + // (undocumented) + status: 'error' | 'failure' | 'unknown'; +} + +// @public (undocumented) +export interface DaVinciErrorCacheEntry { + // (undocumented) + endpointName: 'next' | 'flow' | 'start'; + // (undocumented) + error: { + data: T; + }; + // (undocumented) + fulfilledTimeStamp: number; + // (undocumented) + isError: boolean; + // (undocumented) + isLoading: boolean; + // (undocumented) + isSuccess: boolean; + // (undocumented) + isUninitialized: boolean; + // (undocumented) + requestId: string; + // (undocumented) + startedTimeStamp: number; + // (undocumented) + status: 'fulfilled' | 'pending' | 'rejected'; +} + +// @public (undocumented) +export interface DavinciErrorResponse extends DaVinciBaseResponse { + // (undocumented) + cause?: string | null; + // (undocumented) + code: string | number; + // (undocumented) + details?: ErrorDetail[]; + // (undocumented) + doNotSendToOE?: boolean; + // (undocumented) + error?: { + code?: string; + message?: string; + }; + // (undocumented) + errorCategory?: string; + // (undocumented) + errorMessage?: string; + // (undocumented) + expected?: boolean; + // (undocumented) + httpResponseCode: number; + // (undocumented) + isErrorCustomized?: boolean; + // (undocumented) + message: string; + // (undocumented) + metricAttributes?: { + [key: string]: unknown; + }; +} + +// @public (undocumented) +export interface DaVinciFailureResponse extends DaVinciBaseResponse { + // (undocumented) + error?: { + code?: string; + message?: string; + [key: string]: unknown; + }; +} + +// @public (undocumented) +export type DaVinciField = ComplexValueFields | MultiValueFields | ReadOnlyFields | RedirectFields | SingleValueFields; + +// @public +export interface DaVinciNextResponse extends DaVinciBaseResponse { + // (undocumented) + eventName?: string; + // (undocumented) + form?: { + name?: string; + description?: string; + components?: { + fields?: DaVinciField[]; + }; + }; + // (undocumented) + formData?: { + value?: { + [key: string]: string; + }; + }; + // (undocumented) + _links?: Links; +} + +// @public +export interface DaVinciPollResponse extends DaVinciBaseResponse { + // (undocumented) + eventName?: string; + // (undocumented) + _links?: Links; + // (undocumented) + success?: boolean; +} + +// @public (undocumented) +export interface DaVinciRequest { + // (undocumented) + eventName: string; + // (undocumented) + id: string; + // (undocumented) + interactionId: string; + // (undocumented) + parameters: { + eventType: 'submit' | 'action' | 'polling'; + data: { + actionKey: string; + formData?: Record; + }; + }; +} + +// @public (undocumented) +export interface DaVinciSuccessResponse extends DaVinciBaseResponse { + // (undocumented) + authorizeResponse?: OAuthDetails; + // (undocumented) + environment: { + id: string; + [key: string]: unknown; + }; + // (undocumented) + _links?: Links; + // (undocumented) + resetCookie?: boolean; + // (undocumented) + session?: { + id?: string; + [key: string]: unknown; + }; + // (undocumented) + sessionToken?: string; + // (undocumented) + sessionTokenMaxAge?: number; + // (undocumented) + status: string; + // (undocumented) + subFlowSettings?: { + cssLinks?: unknown[]; + cssUrl?: unknown; + jsLinks?: unknown[]; + loadingScreenSettings?: unknown; + reactSkUrl?: unknown; + }; + // (undocumented) + success: true; +} + +// @public (undocumented) +export type DeviceAuthenticationCollector = ObjectOptionsCollectorWithObjectValue<'DeviceAuthenticationCollector', DeviceValue>; + +// @public (undocumented) +export type DeviceAuthenticationField = { + type: 'DEVICE_AUTHENTICATION'; + key: string; + label: string; + options: { + type: string; + iconSrc: string; + title: string; + id: string; + default: boolean; + description: string; + }[]; + required: boolean; +}; + +// @public (undocumented) +export interface DeviceOptionNoDefault { + // (undocumented) + content: string; + // (undocumented) + key: string; + // (undocumented) + label: string; + // (undocumented) + type: string; + // (undocumented) + value: string; +} + +// @public (undocumented) +export interface DeviceOptionWithDefault { + // (undocumented) + content: string; + // (undocumented) + default: boolean; + // (undocumented) + key: string; + // (undocumented) + label: string; + // (undocumented) + type: string; + // (undocumented) + value: string; +} + +// @public (undocumented) +export type DeviceRegistrationCollector = ObjectOptionsCollectorWithStringValue<'DeviceRegistrationCollector', string>; + +// @public (undocumented) +export type DeviceRegistrationField = { + type: 'DEVICE_REGISTRATION'; + key: string; + label: string; + options: { + type: string; + iconSrc: string; + title: string; + description: string; + }[]; + required: boolean; +}; + +// @public (undocumented) +export interface DeviceValue { + // (undocumented) + id: string; + // (undocumented) + type: string; + // (undocumented) + value: string; +} + +// @public (undocumented) +export interface ErrorDetail { + // (undocumented) + message?: string; + // (undocumented) + rawResponse?: { + _embedded?: { + users?: Array; + }; + code?: string; + count?: number; + details?: NestedErrorDetails[]; + id?: string; + message?: string; + size?: number; + userFilter?: string; + [key: string]: unknown; + }; + // (undocumented) + statusCode?: number; +} + +// @public (undocumented) +export interface ErrorNode { + // (undocumented) + cache: { + key: string; + }; + // (undocumented) + client: { + action: string; + collectors: Collectors[]; + description?: string; + name?: string; + status: 'error'; + }; + // (undocumented) + error: DaVinciError; + // (undocumented) + httpStatus: number; + // (undocumented) + server: { + _links?: Links; + eventName?: string; + id?: string; + interactionId?: string; + interactionToken?: string; + status: 'error'; + } | null; + // (undocumented) + status: 'error'; +} + +// @public (undocumented) +export interface FailureNode { + // (undocumented) + cache: { + key: string; + }; + // (undocumented) + client: { + status: 'failure'; + }; + // (undocumented) + error: DaVinciError; + // (undocumented) + httpStatus: number; + // (undocumented) + server: { + _links?: Links; + eventName?: string; + href?: string; + id?: string; + interactionId?: string; + interactionToken?: string; + status: 'failure'; + } | null; + // (undocumented) + status: 'failure'; +} + +// @public (undocumented) +export type FidoAuthenticationCollector = AutoCollector<'ObjectValueAutoCollector', 'FidoAuthenticationCollector', FidoAuthenticationInputValue, FidoAuthenticationOutputValue>; + +// @public (undocumented) +export type FidoAuthenticationField = { + type: 'FIDO2'; + key: string; + label: string; + publicKeyCredentialRequestOptions: FidoAuthenticationOptions; + action: 'AUTHENTICATE'; + trigger: string; + required: boolean; +}; + +// @public (undocumented) +export interface FidoAuthenticationInputValue { + // (undocumented) + assertionValue?: AssertionValue; +} + +// @public (undocumented) +export interface FidoAuthenticationOptions extends Omit { + // (undocumented) + allowCredentials?: { + id: number[]; + transports?: AuthenticatorTransport[]; + type: PublicKeyCredentialType; + }[]; + // (undocumented) + challenge: number[]; +} + +// @public (undocumented) +export interface FidoAuthenticationOutputValue { + // (undocumented) + action: 'AUTHENTICATE'; + // (undocumented) + publicKeyCredentialRequestOptions: FidoAuthenticationOptions; + // (undocumented) + trigger: string; +} + +// @public (undocumented) +export interface FidoClient { + authenticate: (options: FidoAuthenticationOptions) => Promise; + register: (options: FidoRegistrationOptions) => Promise; +} + +// @public (undocumented) +export type FidoRegistrationCollector = AutoCollector<'ObjectValueAutoCollector', 'FidoRegistrationCollector', FidoRegistrationInputValue, FidoRegistrationOutputValue>; + +// @public (undocumented) +export type FidoRegistrationField = { + type: 'FIDO2'; + key: string; + label: string; + publicKeyCredentialCreationOptions: FidoRegistrationOptions; + action: 'REGISTER'; + trigger: string; + required: boolean; +}; + +// @public (undocumented) +export interface FidoRegistrationInputValue { + // (undocumented) + attestationValue?: AttestationValue; +} + +// @public (undocumented) +export interface FidoRegistrationOptions extends Omit { + // (undocumented) + challenge: number[]; + // (undocumented) + excludeCredentials?: { + id: number[]; + transports?: AuthenticatorTransport[]; + type: PublicKeyCredentialType; + }[]; + // (undocumented) + pubKeyCredParams: { + alg: string | number; + type: PublicKeyCredentialType; + }[]; + // (undocumented) + user: { + id: number[]; + name: string; + displayName: string; + }; +} + +// @public (undocumented) +export interface FidoRegistrationOutputValue { + // (undocumented) + action: 'REGISTER'; + // (undocumented) + publicKeyCredentialCreationOptions: FidoRegistrationOptions; + // (undocumented) + trigger: string; +} + +// @public (undocumented) +export type FlowCollector = ActionCollectorNoUrl<'FlowCollector'>; + +// @public (undocumented) +export type FlowNode = ContinueNode | ErrorNode | StartNode | SuccessNode | FailureNode; + +// @public +export type GetClient = StartNode['client'] | ContinueNode['client'] | ErrorNode['client'] | SuccessNode['client'] | FailureNode['client']; + +// @public (undocumented) +export type IdpCollector = ActionCollectorWithUrl<'IdpCollector'>; + +// @public (undocumented) +export type InferActionCollectorType = T extends 'IdpCollector' ? IdpCollector : T extends 'SubmitCollector' ? SubmitCollector : T extends 'FlowCollector' ? FlowCollector : ActionCollectorWithUrl<'ActionCollector'> | ActionCollectorNoUrl<'ActionCollector'>; + +// @public +export type InferAutoCollectorType = T extends 'ProtectCollector' ? ProtectCollector : T extends 'PollingCollector' ? PollingCollector : T extends 'FidoRegistrationCollector' ? FidoRegistrationCollector : T extends 'FidoAuthenticationCollector' ? FidoAuthenticationCollector : T extends 'ObjectValueAutoCollector' ? ObjectValueAutoCollector : SingleValueAutoCollector; + +// @public +export type InferMultiValueCollectorType = T extends 'MultiSelectCollector' ? MultiValueCollectorWithValue<'MultiSelectCollector'> : MultiValueCollectorWithValue<'MultiValueCollector'> | MultiValueCollectorNoValue<'MultiValueCollector'>; + +// @public +export type InferNoValueCollectorType = T extends 'ReadOnlyCollector' ? ReadOnlyCollector : T extends 'RichTextCollector' ? RichTextCollector : T extends 'QrCodeCollector' ? QrCodeCollector : T extends 'AgreementCollector' ? AgreementCollector : NoValueCollectorBase<'NoValueCollector'>; + +// @public +export type InferSingleValueCollectorType = T extends 'TextCollector' ? TextCollector : T extends 'SingleSelectCollector' ? SingleSelectCollector : T extends 'ValidatedTextCollector' ? ValidatedTextCollector : T extends 'PasswordCollector' ? PasswordCollector : T extends 'ValidatedPasswordCollector' ? ValidatedPasswordCollector : SingleValueCollectorWithValue<'SingleValueCollector'> | SingleValueCollectorNoValue<'SingleValueCollector'>; + +// @public (undocumented) +export type InferValueObjectCollectorType = T extends 'DeviceAuthenticationCollector' ? DeviceAuthenticationCollector : T extends 'DeviceRegistrationCollector' ? DeviceRegistrationCollector : T extends 'PhoneNumberCollector' ? PhoneNumberCollector : T extends 'PhoneNumberExtensionCollector' ? PhoneNumberExtensionCollector : ObjectOptionsCollectorWithObjectValue<'ObjectValueCollector'> | ObjectOptionsCollectorWithStringValue<'ObjectValueCollector'>; + +// @public (undocumented) +export type InitFlow = () => Promise; + +// @public (undocumented) +export interface InternalErrorResponse { + // (undocumented) + error: Omit & { + message: string; + }; + // (undocumented) + type: 'internal_error'; +} + +// @public (undocumented) +export interface Links { + // (undocumented) + [key: string]: { + href?: string; + }; +} + +export { LogLevel } + +// @public (undocumented) +export type MultiSelectCollector = MultiValueCollectorWithValue<'MultiSelectCollector'>; + +// @public (undocumented) +export type MultiSelectField = { + inputType: 'MULTI_SELECT'; + key: string; + label: string; + options: { + label: string; + value: string; + }[]; + required?: boolean; + type: 'CHECKBOX' | 'COMBOBOX'; +}; + +// @public (undocumented) +export type MultiValueCollector = MultiValueCollectorWithValue | MultiValueCollectorNoValue; + +// @public (undocumented) +export interface MultiValueCollectorNoValue { + // (undocumented) + category: 'MultiValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string[]; + type: string; + validation: ValidationRequired[] | null; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + options: SelectorOption[]; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type MultiValueCollectors = MultiValueCollectorWithValue<'MultiValueCollector'> | MultiValueCollectorWithValue<'MultiSelectCollector'>; + +// @public +export type MultiValueCollectorTypes = 'MultiSelectCollector' | 'MultiValueCollector'; + +// @public (undocumented) +export interface MultiValueCollectorWithValue { + // (undocumented) + category: 'MultiValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string[]; + type: string; + validation: ValidationRequired[] | null; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + value: string[]; + options: SelectorOption[]; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type MultiValueFields = MultiSelectField; + +// @public +export interface NestedErrorDetails { + // (undocumented) + code?: string; + // (undocumented) + innerError?: { + history?: string; + unsatisfiedRequirements?: string[]; + failuresRemaining?: number; + }; + // (undocumented) + message?: string; + // (undocumented) + target?: string; +} + +// @public +export const nextCollectorValues: ActionCreatorWithPayload< { +fields: DaVinciField[]; +formData: { +value: Record; +}; +}, string>; + +// @public +export const nodeCollectorReducer: Reducer<(TextCollector | SingleSelectCollector | ValidatedTextCollector | PasswordCollector | ValidatedPasswordCollector | MultiSelectCollector | PhoneNumberExtensionCollector | DeviceAuthenticationCollector | DeviceRegistrationCollector | PhoneNumberCollector | IdpCollector | SubmitCollector | FlowCollector | QrCodeCollector | ReadOnlyCollector | RichTextCollector | AgreementCollector | UnknownCollector | ProtectCollector | FidoRegistrationCollector | FidoAuthenticationCollector | PollingCollector | ActionCollector<"ActionCollector"> | SingleValueCollector<"SingleValueCollector">)[]> & { + getInitialState: () => (TextCollector | SingleSelectCollector | ValidatedTextCollector | PasswordCollector | ValidatedPasswordCollector | MultiSelectCollector | PhoneNumberExtensionCollector | DeviceAuthenticationCollector | DeviceRegistrationCollector | PhoneNumberCollector | IdpCollector | SubmitCollector | FlowCollector | QrCodeCollector | ReadOnlyCollector | RichTextCollector | AgreementCollector | UnknownCollector | ProtectCollector | FidoRegistrationCollector | FidoAuthenticationCollector | PollingCollector | ActionCollector<"ActionCollector"> | SingleValueCollector<"SingleValueCollector">)[]; +}; + +// @public (undocumented) +export type NodeStates = StartNode | ContinueNode | ErrorNode | SuccessNode | FailureNode; + +// @public (undocumented) +export type NoValueCollector = InferNoValueCollectorType; + +// @public (undocumented) +export interface NoValueCollectorBase { + // (undocumented) + category: 'NoValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type NoValueCollectors = NoValueCollectorBase<'NoValueCollector'> | ReadOnlyCollector | RichTextCollector | QrCodeCollector | AgreementCollector; + +// @public +export type NoValueCollectorTypes = 'ReadOnlyCollector' | 'RichTextCollector' | 'NoValueCollector' | 'QrCodeCollector' | 'AgreementCollector'; + +// @public +export interface OAuthDetails { + // (undocumented) + [key: string]: unknown; + // (undocumented) + code?: string; + // (undocumented) + state?: string; +} + +// @public (undocumented) +export interface ObjectOptionsCollectorWithObjectValue, D = Record> { + // (undocumented) + category: 'ObjectValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: V; + type: string; + validation: ValidationRequired[] | null; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + options: DeviceOptionWithDefault[]; + value?: D | null; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export interface ObjectOptionsCollectorWithStringValue { + // (undocumented) + category: 'ObjectValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: V; + type: string; + validation: ValidationRequired[] | null; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + options: DeviceOptionNoDefault[]; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type ObjectValueAutoCollector = AutoCollector<'ObjectValueAutoCollector', 'ObjectValueAutoCollector', Record>; + +// @public (undocumented) +export type ObjectValueAutoCollectorTypes = 'ObjectValueAutoCollector' | 'FidoRegistrationCollector' | 'FidoAuthenticationCollector'; + +// @public (undocumented) +export type ObjectValueCollector = ObjectOptionsCollectorWithObjectValue | ObjectOptionsCollectorWithStringValue | ObjectValueCollectorWithObjectValue; + +// @public (undocumented) +export type ObjectValueCollectors = DeviceAuthenticationCollector | DeviceRegistrationCollector | PhoneNumberCollector | PhoneNumberExtensionCollector | ObjectOptionsCollectorWithObjectValue<'ObjectSelectCollector'> | ObjectOptionsCollectorWithStringValue<'ObjectSelectCollector'>; + +// @public +export type ObjectValueCollectorTypes = 'DeviceAuthenticationCollector' | 'DeviceRegistrationCollector' | 'PhoneNumberCollector' | 'PhoneNumberExtensionCollector' | 'ObjectOptionsCollector' | 'ObjectValueCollector' | 'ObjectSelectCollector'; + +// @public (undocumented) +export interface ObjectValueCollectorWithObjectValue, OV = Record> { + // (undocumented) + category: 'ObjectValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: IV; + type: string; + validation: (ValidationRequired | ValidationPhoneNumber)[] | null; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + value?: OV | null; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export interface OutgoingQueryParams { + // (undocumented) + [key: string]: string | string[]; +} + +// @public (undocumented) +export interface PasswordCollector { + // (undocumented) + category: 'SingleValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string | number | boolean; + type: string; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + verify: boolean; + }; + // (undocumented) + type: 'PasswordCollector'; +} + +// @public +export type PasswordField = { + type: 'PASSWORD' | 'PASSWORD_VERIFY'; + key: string; + label: string; + required?: boolean; + verify?: boolean; + passwordPolicy?: PasswordPolicy; +}; + +// @public +export interface PasswordPolicy { + // (undocumented) + createdAt?: string; + // (undocumented) + default?: boolean; + // (undocumented) + description?: string; + // (undocumented) + excludesCommonlyUsed?: boolean; + // (undocumented) + excludesProfileData?: boolean; + // (undocumented) + history?: { + count?: number; + retentionDays?: number; + }; + // (undocumented) + id?: string; + // (undocumented) + length?: { + min?: number; + max?: number; + }; + // (undocumented) + lockout?: { + failureCount?: number; + durationSeconds?: number; + }; + // (undocumented) + maxAgeDays?: number; + // (undocumented) + maxRepeatedCharacters?: number; + // (undocumented) + minAgeDays?: number; + // (undocumented) + minCharacters?: Record; + // (undocumented) + minUniqueCharacters?: number; + // (undocumented) + name?: string; + // (undocumented) + notSimilarToCurrent?: boolean; + // (undocumented) + populationCount?: number; + // (undocumented) + updatedAt?: string; +} + +// @public (undocumented) +export type PhoneNumberCollector = ObjectValueCollectorWithObjectValue<'PhoneNumberCollector', PhoneNumberInputValue, PhoneNumberOutputValue>; + +// @public (undocumented) +export interface PhoneNumberExtensionCollector { + // (undocumented) + category: 'ObjectValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: PhoneNumberExtensionInputValue; + type: string; + validation: (ValidationRequired | ValidationPhoneNumber)[] | null; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + extensionLabel: string; + value: PhoneNumberExtensionOutputValue; + }; + // (undocumented) + type: 'PhoneNumberExtensionCollector'; +} + +// @public (undocumented) +export type PhoneNumberExtensionField = PhoneNumberField & { + showExtension: boolean; + extensionLabel: string; +}; + +// @public (undocumented) +export interface PhoneNumberExtensionInputValue { + // (undocumented) + countryCode: string; + // (undocumented) + extension: string; + // (undocumented) + phoneNumber: string; +} + +// @public (undocumented) +export interface PhoneNumberExtensionOutputValue { + // (undocumented) + countryCode?: string; + // (undocumented) + extension?: string; + // (undocumented) + phoneNumber?: string; +} + +// @public (undocumented) +export type PhoneNumberField = { + type: 'PHONE_NUMBER'; + key: string; + label: string; + required: boolean; + defaultCountryCode: string | null; + validatePhoneNumber: boolean; +}; + +// @public (undocumented) +export interface PhoneNumberInputValue { + // (undocumented) + countryCode: string; + // (undocumented) + phoneNumber: string; +} + +// @public (undocumented) +export interface PhoneNumberOutputValue { + // (undocumented) + countryCode?: string; + // (undocumented) + phoneNumber?: string; +} + +// @public (undocumented) +export type Poller = () => Promise; + +// @public (undocumented) +export type PollingCollector = AutoCollector<'SingleValueAutoCollector', 'PollingCollector', string, PollingOutputValue>; + +// @public (undocumented) +export type PollingField = { + type: 'POLLING'; + key: string; + pollInterval: number; + pollRetries: number; + pollChallengeStatus?: boolean; + challenge?: string; +}; + +// @public (undocumented) +export interface PollingOutputValue { + // (undocumented) + challenge?: string; + // (undocumented) + pollChallengeStatus?: boolean; + // (undocumented) + pollInterval: number; + // (undocumented) + pollRetries: number; + // (undocumented) + retriesRemaining?: number; +} + +// @public (undocumented) +export type PollingStatus = PollingStatusContinue | PollingStatusChallenge; + +// @public (undocumented) +export type PollingStatusChallenge = PollingStatusChallengeComplete | 'expired' | 'timedOut' | 'error'; + +// @public (undocumented) +export type PollingStatusChallengeComplete = 'approved' | 'denied' | 'continue' | CustomPollingStatus; + +// @public (undocumented) +export type PollingStatusContinue = 'continue' | 'timedOut'; + +// @public (undocumented) +export type ProtectCollector = AutoCollector<'SingleValueAutoCollector', 'ProtectCollector', string, ProtectOutputValue>; + +// @public (undocumented) +export type ProtectField = { + type: 'PROTECT'; + key: string; + behavioralDataCollection: boolean; + universalDeviceIdentification: boolean; +}; + +// @public +export interface ProtectOutputValue { + // (undocumented) + behavioralDataCollection: boolean; + // (undocumented) + universalDeviceIdentification: boolean; +} + +// @public +export interface QrCodeCollector extends NoValueCollectorBase<'QrCodeCollector'> { + // (undocumented) + output: NoValueCollectorBase<'QrCodeCollector'>['output'] & { + src: string; + }; +} + +// @public (undocumented) +export type QrCodeField = { + type: 'QR_CODE'; + key: string; + content: string; + fallbackText?: string; +}; + +// @public +export interface ReadOnlyCollector extends NoValueCollectorBase<'ReadOnlyCollector'> { + // (undocumented) + output: NoValueCollectorBase<'ReadOnlyCollector'>['output'] & { + content: string; + }; +} + +// @public (undocumented) +export type ReadOnlyField = { + type: 'LABEL'; + content: string; + richContent?: RichContent; + key?: string; +}; + +// @public (undocumented) +export type ReadOnlyFields = ReadOnlyField | QrCodeField | AgreementField; + +// @public (undocumented) +export type RedirectField = { + type: 'SOCIAL_LOGIN_BUTTON'; + key: string; + label: string; + links: Links; +}; + +// @public (undocumented) +export type RedirectFields = RedirectField; + +export { RequestMiddleware } + +// @public +export type RichContent = { + content: string; + replacements?: Record; +}; + +// @public +export interface RichContentLink { + // (undocumented) + href: string; + // (undocumented) + key: string; + // (undocumented) + target?: '_self' | '_blank'; + // (undocumented) + type: 'link'; + // (undocumented) + value: string; +} + +// @public +export type RichContentReplacement = { + type: 'link'; + value: string; + href: string; + target?: '_self' | '_blank'; +}; + +// @public +export interface RichTextCollector extends NoValueCollectorBase<'RichTextCollector'> { + // (undocumented) + output: NoValueCollectorBase<'RichTextCollector'>['output'] & { + content: string; + richContent: CollectorRichContent; + }; +} + +// @public (undocumented) +export interface SelectorOption { + // (undocumented) + label: string; + // (undocumented) + value: string; +} + +// @public (undocumented) +export type SingleSelectCollector = SingleSelectCollectorWithValue<'SingleSelectCollector'>; + +// @public (undocumented) +export interface SingleSelectCollectorNoValue { + // (undocumented) + category: 'SingleValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string | number | boolean; + type: string; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + options: SelectorOption[]; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export interface SingleSelectCollectorWithValue { + // (undocumented) + category: 'SingleValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string | number | boolean; + type: string; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + value: string | number | boolean; + options: SelectorOption[]; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type SingleSelectField = { + inputType: 'SINGLE_SELECT'; + key: string; + label: string; + options: { + label: string; + value: string; + }[]; + required?: boolean; + type: 'RADIO' | 'DROPDOWN'; +}; + +// @public (undocumented) +export type SingleValueAutoCollector = AutoCollector<'SingleValueAutoCollector', 'SingleValueAutoCollector', string>; + +// @public (undocumented) +export type SingleValueAutoCollectorTypes = 'SingleValueAutoCollector' | 'ProtectCollector' | 'PollingCollector'; + +// @public +export type SingleValueCollector = SingleValueCollectorWithValue | SingleValueCollectorNoValue; + +// @public (undocumented) +export interface SingleValueCollectorNoValue { + // (undocumented) + category: 'SingleValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string | number | boolean; + type: string; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type SingleValueCollectors = PasswordCollector | ValidatedPasswordCollector | SingleSelectCollectorWithValue<'SingleSelectCollector'> | SingleValueCollectorWithValue<'SingleValueCollector'> | SingleValueCollectorWithValue<'TextCollector'> | ValidatedSingleValueCollectorWithValue<'TextCollector'>; + +// @public +export type SingleValueCollectorTypes = 'PasswordCollector' | 'ValidatedPasswordCollector' | 'SingleValueCollector' | 'SingleSelectCollector' | 'SingleSelectObjectCollector' | 'TextCollector' | 'ValidatedTextCollector'; + +// @public (undocumented) +export interface SingleValueCollectorWithValue { + // (undocumented) + category: 'SingleValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string | number | boolean; + type: string; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + value: string | number | boolean; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type SingleValueFields = StandardField | PasswordField | ValidatedField | SingleSelectField | ProtectField; + +// @public (undocumented) +export type StandardField = { + type: 'TEXT' | 'SUBMIT_BUTTON' | 'FLOW_BUTTON' | 'FLOW_LINK' | 'BUTTON'; + key: string; + label: string; + required?: boolean; +}; + +// @public (undocumented) +export interface StartNode { + // (undocumented) + cache: null; + // (undocumented) + client: { + status: 'start'; + }; + // (undocumented) + error: DaVinciError | null; + // (undocumented) + server: { + status: 'start'; + }; + // (undocumented) + status: 'start'; +} + +// @public (undocumented) +export interface StartOptions { + // (undocumented) + query: Query; +} + +// @public (undocumented) +export type SubmitCollector = ActionCollectorNoUrl<'SubmitCollector'>; + +// @public (undocumented) +export interface SuccessNode { + // (undocumented) + cache: { + key: string; + }; + // (undocumented) + client: { + authorization?: { + code?: string; + state?: string; + }; + status: 'success'; + } | null; + // (undocumented) + error: null; + // (undocumented) + httpStatus: number; + // (undocumented) + server: { + _links?: Links; + eventName?: string; + id?: string; + interactionId?: string; + interactionToken?: string; + href?: string; + session?: string; + status: 'success'; + }; + // (undocumented) + status: 'success'; +} + +// @public (undocumented) +export type TextCollector = SingleValueCollectorWithValue<'TextCollector'>; + +// @public (undocumented) +export interface ThrownQueryError { + // (undocumented) + error: FetchBaseQueryError; + // (undocumented) + isHandledError: boolean; + // (undocumented) + meta: FetchBaseQueryMeta; +} + +// @public +export type UnknownCollector = { + category: 'UnknownCollector'; + error: string | null; + type: 'UnknownCollector'; + id: string; + name: string; + output: { + key: string; + label: string; + type: string; + }; +}; + +// @public (undocumented) +export type UnknownField = Record; + +// @public (undocumented) +export const updateCollectorValues: ActionCreatorWithPayload< { +id: string; +value: string | string[] | PhoneNumberInputValue | PhoneNumberExtensionInputValue | FidoRegistrationInputValue | FidoAuthenticationInputValue; +index?: number; +}, string>; + +// @public +export type Updater = (value: CollectorValueType, index?: number) => InternalErrorResponse | null; + +// @public (undocumented) +export type ValidatedField = { + type: 'TEXT'; + key: string; + label: string; + required: boolean; + validation: { + regex: string; + errorMessage: string; + }; +}; + +// @public (undocumented) +export interface ValidatedPasswordCollector { + // (undocumented) + category: 'SingleValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string | number | boolean; + type: string; + validation: PasswordPolicy; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + verify: boolean; + }; + // (undocumented) + type: 'ValidatedPasswordCollector'; +} + +// @public (undocumented) +export interface ValidatedSingleValueCollectorWithValue { + // (undocumented) + category: 'ValidatedSingleValueCollector'; + // (undocumented) + error: string | null; + // (undocumented) + id: string; + // (undocumented) + input: { + key: string; + value: string | number | boolean; + type: string; + validation: (ValidationRequired | ValidationRegex)[]; + }; + // (undocumented) + name: string; + // (undocumented) + output: { + key: string; + label: string; + type: string; + value: string | number | boolean; + }; + // (undocumented) + type: T; +} + +// @public (undocumented) +export type ValidatedTextCollector = ValidatedSingleValueCollectorWithValue<'TextCollector'>; + +// @public (undocumented) +export interface ValidationPhoneNumber { + // (undocumented) + message: string; + // (undocumented) + rule: boolean; + // (undocumented) + type: 'validatePhoneNumber'; +} + +// @public (undocumented) +export interface ValidationRegex { + // (undocumented) + message: string; + // (undocumented) + rule: string; + // (undocumented) + type: 'regex'; +} + +// @public (undocumented) +export interface ValidationRequired { + // (undocumented) + message: string; + // (undocumented) + rule: boolean; + // (undocumented) + type: 'required'; +} + +// @public (undocumented) +export type Validator = (value: string) => string[] | { + error: { + message: string; + type: string; + }; + type: string; +}; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/packages/oidc-client/api-report/oidc-client.api.md b/packages/oidc-client/api-report/oidc-client.api.md index 283d363dc9..ab5c1d0fbe 100644 --- a/packages/oidc-client/api-report/oidc-client.api.md +++ b/packages/oidc-client/api-report/oidc-client.api.md @@ -123,6 +123,10 @@ oidc: CombinedState< { authorizeFetch: MutationDefinition< { url: string; }, BaseQueryFn, never, AuthorizeSuccessResponse, "oidc", unknown>; +par: MutationDefinition< { +endpoint: string; +body: URLSearchParams; +}, BaseQueryFn, never, PushAuthorizationResponse, "oidc", unknown>; authorizeIframe: MutationDefinition< { url: string; }, BaseQueryFn, never, AuthorizationSuccess, "oidc", unknown>; @@ -155,6 +159,10 @@ oidc: CombinedState< { authorizeFetch: MutationDefinition< { url: string; }, BaseQueryFn, never, AuthorizeSuccessResponse, "oidc", unknown>; +par: MutationDefinition< { +endpoint: string; +body: URLSearchParams; +}, BaseQueryFn, never, PushAuthorizationResponse, "oidc", unknown>; authorizeIframe: MutationDefinition< { url: string; }, BaseQueryFn, never, AuthorizationSuccess, "oidc", unknown>; @@ -281,6 +289,8 @@ export interface OidcConfig extends AsyncLegacyConfigOptions { // (undocumented) clientId: string; // (undocumented) + par?: boolean; + // (undocumented) redirectUri: string; // (undocumented) responseType?: ResponseType_2; @@ -296,6 +306,14 @@ export interface OidcConfig extends AsyncLegacyConfigOptions { // @public (undocumented) export type OptionalAuthorizeOptions = Partial; +// @public (undocumented) +export interface PushAuthorizationResponse { + // (undocumented) + expires_in: number; + // (undocumented) + request_uri: string; +} + export { RequestMiddleware } export { ResponseType_2 as ResponseType } diff --git a/packages/oidc-client/api-report/oidc-client.types.api.md b/packages/oidc-client/api-report/oidc-client.types.api.md index 283d363dc9..ab5c1d0fbe 100644 --- a/packages/oidc-client/api-report/oidc-client.types.api.md +++ b/packages/oidc-client/api-report/oidc-client.types.api.md @@ -123,6 +123,10 @@ oidc: CombinedState< { authorizeFetch: MutationDefinition< { url: string; }, BaseQueryFn, never, AuthorizeSuccessResponse, "oidc", unknown>; +par: MutationDefinition< { +endpoint: string; +body: URLSearchParams; +}, BaseQueryFn, never, PushAuthorizationResponse, "oidc", unknown>; authorizeIframe: MutationDefinition< { url: string; }, BaseQueryFn, never, AuthorizationSuccess, "oidc", unknown>; @@ -155,6 +159,10 @@ oidc: CombinedState< { authorizeFetch: MutationDefinition< { url: string; }, BaseQueryFn, never, AuthorizeSuccessResponse, "oidc", unknown>; +par: MutationDefinition< { +endpoint: string; +body: URLSearchParams; +}, BaseQueryFn, never, PushAuthorizationResponse, "oidc", unknown>; authorizeIframe: MutationDefinition< { url: string; }, BaseQueryFn, never, AuthorizationSuccess, "oidc", unknown>; @@ -281,6 +289,8 @@ export interface OidcConfig extends AsyncLegacyConfigOptions { // (undocumented) clientId: string; // (undocumented) + par?: boolean; + // (undocumented) redirectUri: string; // (undocumented) responseType?: ResponseType_2; @@ -296,6 +306,14 @@ export interface OidcConfig extends AsyncLegacyConfigOptions { // @public (undocumented) export type OptionalAuthorizeOptions = Partial; +// @public (undocumented) +export interface PushAuthorizationResponse { + // (undocumented) + expires_in: number; + // (undocumented) + request_uri: string; +} + export { RequestMiddleware } export { ResponseType_2 as ResponseType } diff --git a/packages/oidc-client/package.json b/packages/oidc-client/package.json index 6a71dd61ad..4d69dc10c5 100644 --- a/packages/oidc-client/package.json +++ b/packages/oidc-client/package.json @@ -32,6 +32,7 @@ "@forgerock/sdk-oidc": "workspace:*", "@forgerock/sdk-request-middleware": "workspace:*", "@forgerock/sdk-types": "workspace:*", + "@forgerock/sdk-utilities": "workspace:*", "@forgerock/storage": "workspace:*", "@reduxjs/toolkit": "catalog:", "effect": "catalog:effect" diff --git a/packages/oidc-client/src/lib/authorize.request.effects.ts b/packages/oidc-client/src/lib/authorize.request.effects.ts new file mode 100644 index 0000000000..f2c52d3205 --- /dev/null +++ b/packages/oidc-client/src/lib/authorize.request.effects.ts @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2025 Ping Identity Corporation. All rights reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ +import { generateAndStoreAuthUrlValues } from '@forgerock/sdk-oidc'; +import { createChallenge } from '@forgerock/sdk-utilities'; +import { Micro } from 'effect'; + +import type { WellknownResponse } from '@forgerock/sdk-types'; +import type { AuthorizationError, OptionalAuthorizeOptions } from './authorize.request.types.js'; +import type { OidcConfig } from './config.types.js'; + +// ─── Crypto / sessionStorage side effects ──────────────────────────────────── + +export const generateAuthValues = ( + config: OidcConfig, + wellknown: WellknownResponse, + options?: OptionalAuthorizeOptions, +): Micro.Micro, AuthorizationError, never> => + Micro.try({ + try: () => + generateAndStoreAuthUrlValues({ + clientId: config.clientId, + serverConfig: { baseUrl: new URL(wellknown.authorization_endpoint).origin }, + responseType: config.responseType || 'code', + redirectUri: config.redirectUri, + scope: config.scope || 'openid', + ...options, + }), + catch: (err): AuthorizationError => ({ + error: 'PAR_PARAM_BUILD_ERROR', + error_description: err instanceof Error ? err.message : 'Failed to generate auth URL values', + type: 'auth_error', + }), + }); + +export const generatePkceChallenge = ( + verifier: string, +): Micro.Micro => + Micro.tryPromise({ + try: () => createChallenge(verifier), + catch: (err): AuthorizationError => ({ + error: 'PAR_CHALLENGE_ERROR', + error_description: err instanceof Error ? err.message : 'Failed to generate PKCE challenge', + type: 'auth_error', + }), + }); + +export const storeAuthOptions = ( + storeOptions: () => void, +): Micro.Micro => + Micro.try({ + try: () => storeOptions(), + catch: (err): AuthorizationError => ({ + error: 'PAR_STORAGE_ERROR', + error_description: err instanceof Error ? err.message : 'Failed to store PAR session options', + type: 'unknown_error', + }), + }); diff --git a/packages/oidc-client/src/lib/authorize.request.micros.test.ts b/packages/oidc-client/src/lib/authorize.request.micros.test.ts new file mode 100644 index 0000000000..773515efc2 --- /dev/null +++ b/packages/oidc-client/src/lib/authorize.request.micros.test.ts @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2025 Ping Identity Corporation. All rights reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ +import { it, expect } from '@effect/vitest'; +import { Micro } from 'effect'; +import { vi, afterEach } from 'vitest'; +import * as sdkOidc from '@forgerock/sdk-oidc'; +import * as sdkUtilities from '@forgerock/sdk-utilities'; + +import { + generateAuthValues, + generatePkceChallenge, + storeAuthOptions, +} from './authorize.request.effects.js'; +import { + buildParBody, + validateParResponse, + handleDispatchError, + createAuthorizeUrlMicro, +} from './authorize.request.utils.js'; +import { + buildParSlimUrl, + dispatchAuthorizeFetch, + dispatchAuthorizeIframe, +} from './authorize.request.micros.js'; + +import type { OidcConfig } from './config.types.js'; +import type { WellknownResponse } from '@forgerock/sdk-types'; +import type { ClientStore } from './client.types.js'; +import type { FetchBaseQueryError } from '@reduxjs/toolkit/query'; + +// ─── Fixtures ──────────────────────────────────────────────────────────────── + +const clientId = 'test-client-id'; +const redirectUri = 'https://example.com/callback.html'; +const scope = 'openid profile'; +const responseType = 'code'; +const config: OidcConfig = { + clientId, + redirectUri, + scope, + responseType, + serverConfig: { wellknown: 'https://example.com/.well-known/openid-configuration' }, +}; +const wellknown: WellknownResponse = { + issuer: 'https://example.com', + authorization_endpoint: 'https://example.com/authorize', + token_endpoint: 'https://example.com/token', + userinfo_endpoint: 'https://example.com/userinfo', + end_session_endpoint: 'https://example.com/logout', + introspection_endpoint: 'https://example.com/introspect', + revocation_endpoint: 'https://example.com/revoke', +}; +const mockStore = { dispatch: vi.fn() } as unknown as ClientStore; +const sessionStorageStub = { getItem: vi.fn(), setItem: vi.fn(), removeItem: vi.fn() }; + +afterEach(() => { + vi.unstubAllGlobals(); + vi.resetAllMocks(); +}); + +// ─── generateAuthValues ─────────────────────────────────────────────────────── + +it.effect('generateAuthValues returns auth URL options and store function', () => + Micro.gen(function* () { + vi.stubGlobal('sessionStorage', sessionStorageStub); + const result = yield* generateAuthValues(config, wellknown); + const [opts, storeFn] = result; + expect(opts.clientId).toBe(clientId); + expect(typeof opts.state).toBe('string'); + expect(typeof opts.verifier).toBe('string'); + expect(typeof storeFn).toBe('function'); + }), +); + +it.effect('generateAuthValues fails with auth_error when sessionStorage throws', () => + Micro.gen(function* () { + vi.spyOn(sdkOidc, 'generateAndStoreAuthUrlValues').mockImplementation(() => { + throw new Error('storage unavailable'); + }); + const exit = yield* Micro.exit(generateAuthValues(config, wellknown)); + expect(Micro.exitIsFailure(exit)).toBe(true); + if (!Micro.exitIsFailure(exit) || !Micro.causeIsFail(exit.cause)) return; + expect(exit.cause.error.type).toBe('auth_error'); + expect(exit.cause.error.error).toBe('PAR_PARAM_BUILD_ERROR'); + }), +); + +// ─── generatePkceChallenge ──────────────────────────────────────────────────── + +it.effect('generatePkceChallenge returns a non-empty challenge string', () => + Micro.gen(function* () { + vi.stubGlobal('crypto', { + subtle: { + digest: vi.fn().mockResolvedValue(new ArrayBuffer(32)), + }, + getRandomValues: vi.fn((arr: Uint8Array) => arr.fill(1)), + }); + const challenge = yield* generatePkceChallenge('test-verifier'); + expect(typeof challenge).toBe('string'); + expect(challenge.length).toBeGreaterThan(0); + }), +); + +it.effect('generatePkceChallenge fails with auth_error when createChallenge throws', () => + Micro.gen(function* () { + vi.spyOn(sdkUtilities, 'createChallenge').mockRejectedValue(new Error('crypto unavailable')); + const exit = yield* Micro.exit(generatePkceChallenge('bad-verifier')); + expect(Micro.exitIsFailure(exit)).toBe(true); + if (!Micro.exitIsFailure(exit) || !Micro.causeIsFail(exit.cause)) return; + expect(exit.cause.error.type).toBe('auth_error'); + expect(exit.cause.error.error).toBe('PAR_CHALLENGE_ERROR'); + }), +); + +// ─── buildParBody ───────────────────────────────────────────────────────────── + +it.effect('buildParBody returns URLSearchParams with expected fields', () => + Micro.gen(function* () { + const params = yield* buildParBody(config, {}, 'challenge-abc', 'state-xyz'); + expect(params.get('client_id')).toBe(clientId); + expect(params.get('code_challenge')).toBe('challenge-abc'); + expect(params.get('state')).toBe('state-xyz'); + expect(params.get('scope')).toBe(scope); + expect(params.has('prompt')).toBe(false); + }), +); + +it.effect('buildParBody includes prompt when provided', () => + Micro.gen(function* () { + const params = yield* buildParBody(config, {}, 'challenge-abc', 'state-xyz', 'login'); + expect(params.get('prompt')).toBe('login'); + }), +); + +it.effect('buildParBody fails with auth_error when buildAuthorizeParams throws', () => + Micro.gen(function* () { + vi.spyOn(sdkOidc, 'buildAuthorizeParams').mockImplementation(() => { + throw new Error('build failed'); + }); + const exit = yield* Micro.exit(buildParBody(config, {}, 'ch', 'st')); + expect(Micro.exitIsFailure(exit)).toBe(true); + if (!Micro.exitIsFailure(exit) || !Micro.causeIsFail(exit.cause)) return; + expect(exit.cause.error.type).toBe('auth_error'); + expect(exit.cause.error.error).toBe('PAR_PARAM_BUILD_ERROR'); + }), +); + +// ─── buildParSlimUrl ────────────────────────────────────────────────────────── + +it.effect('buildParSlimUrl returns URL with only client_id and request_uri', () => + Micro.gen(function* () { + const url = yield* buildParSlimUrl( + wellknown.authorization_endpoint, + clientId, + 'urn:ietf:params:oauth:request_uri:abc123', + ); + const parsed = new URL(url); + expect(parsed.searchParams.get('client_id')).toBe(clientId); + expect(parsed.searchParams.get('request_uri')).toBe('urn:ietf:params:oauth:request_uri:abc123'); + expect(parsed.searchParams.has('scope')).toBe(false); + }), +); + +it.effect('buildParSlimUrl includes prompt when provided', () => + Micro.gen(function* () { + const url = yield* buildParSlimUrl( + wellknown.authorization_endpoint, + clientId, + 'urn:ietf:params:oauth:request_uri:abc123', + 'none', + ); + expect(new URL(url).searchParams.get('prompt')).toBe('none'); + }), +); + +// ─── storeAuthOptions ───────────────────────────────────────────────────────── + +it.effect('storeAuthOptions calls the provided store function', () => + Micro.gen(function* () { + const storeFn = vi.fn(); + yield* storeAuthOptions(storeFn); + expect(storeFn).toHaveBeenCalledOnce(); + }), +); + +it.effect('storeAuthOptions fails with unknown_error when store function throws', () => + Micro.gen(function* () { + const exit = yield* Micro.exit( + storeAuthOptions(() => { + throw new Error('storage write failed'); + }), + ); + expect(Micro.exitIsFailure(exit)).toBe(true); + if (!Micro.exitIsFailure(exit) || !Micro.causeIsFail(exit.cause)) return; + expect(exit.cause.error.type).toBe('unknown_error'); + expect(exit.cause.error.error).toBe('PAR_STORAGE_ERROR'); + }), +); + +// ─── validateParResponse ────────────────────────────────────────────────────── + +it.effect('validateParResponse succeeds when request_uri is present', () => + Micro.gen(function* () { + const result = yield* validateParResponse({ + data: { request_uri: 'urn:ietf:params:oauth:request_uri:xyz', expires_in: 60 }, + }); + expect(result.request_uri).toBe('urn:ietf:params:oauth:request_uri:xyz'); + }), +); + +it.effect('validateParResponse fails with network_error on RTK error', () => + Micro.gen(function* () { + const exit = yield* Micro.exit( + validateParResponse({ + error: { + status: 400, + data: { error: 'invalid_client', error_description: 'bad creds', type: 'auth_error' }, + }, + }), + ); + expect(Micro.exitIsFailure(exit)).toBe(true); + if (!Micro.exitIsFailure(exit) || !Micro.causeIsFail(exit.cause)) return; + expect(exit.cause.error.error).toBe('invalid_client'); + }), +); + +it.effect('validateParResponse fails with network_error when request_uri is absent', () => + Micro.gen(function* () { + const exit = yield* Micro.exit(validateParResponse({ data: { expires_in: 60 } })); + expect(Micro.exitIsFailure(exit)).toBe(true); + if (!Micro.exitIsFailure(exit) || !Micro.causeIsFail(exit.cause)) return; + expect(exit.cause.error.type).toBe('network_error'); + expect(exit.cause.error.error_description).toContain('request_uri'); + }), +); + +// ─── createAuthorizeUrlMicro ────────────────────────────────────────────────── + +it.effect('createAuthorizeUrlMicro returns [url, options] tuple', () => + Micro.gen(function* () { + vi.stubGlobal('sessionStorage', sessionStorageStub); + const opts = { + clientId, + redirectUri, + scope, + responseType: 'code' as const, + state: 'test-state', + verifier: 'test-verifier', + }; + vi.spyOn(sdkOidc, 'createAuthorizeUrl').mockResolvedValue( + 'https://example.com/authorize?foo=bar', + ); + const [url, returnedOpts] = yield* createAuthorizeUrlMicro( + wellknown.authorization_endpoint, + opts, + ); + expect(url).toBe('https://example.com/authorize?foo=bar'); + expect(returnedOpts).toBe(opts); + }), +); + +it.effect('createAuthorizeUrlMicro fails with auth_error when createAuthorizeUrl rejects', () => + Micro.gen(function* () { + vi.spyOn(sdkOidc, 'createAuthorizeUrl').mockRejectedValue(new Error('url build failed')); + const exit = yield* Micro.exit( + createAuthorizeUrlMicro(wellknown.authorization_endpoint, { + clientId, + redirectUri, + scope, + responseType, + }), + ); + expect(Micro.exitIsFailure(exit)).toBe(true); + if (!Micro.exitIsFailure(exit) || !Micro.causeIsFail(exit.cause)) return; + expect(exit.cause.error.type).toBe('auth_error'); + expect(exit.cause.error.error).toBe('AuthorizationUrlError'); + }), +); + +// ─── handleDispatchError ────────────────────────────────────────────────────── + +it.effect('handleDispatchError fails immediately for CONFIGURATION_ERROR', () => + Micro.gen(function* () { + const exit = yield* Micro.exit( + handleDispatchError( + { + status: 'CUSTOM_ERROR', + statusText: 'CONFIGURATION_ERROR', + error: 'config error', + data: undefined, + } as FetchBaseQueryError, + wellknown, + { clientId, redirectUri, scope, responseType }, + ), + ); + expect(Micro.exitIsFailure(exit)).toBe(true); + if (!Micro.exitIsFailure(exit) || !Micro.causeIsFail(exit.cause)) return; + expect(exit.cause.error.type).toBe('unknown_error'); + }), +); + +it.effect('handleDispatchError builds redirect URL for non-config errors', () => + Micro.gen(function* () { + vi.spyOn(sdkOidc, 'createAuthorizeUrl').mockResolvedValue( + 'https://example.com/authorize?error=login_required', + ); + const exit = yield* Micro.exit( + handleDispatchError( + { + status: 400, + data: { + error: 'login_required', + error_description: 'User must authenticate', + type: 'auth_error', + }, + }, + wellknown, + { clientId, redirectUri, scope, responseType }, + ), + ); + expect(Micro.exitIsFailure(exit)).toBe(true); + if (!Micro.exitIsFailure(exit) || !Micro.causeIsFail(exit.cause)) return; + expect(exit.cause.error.error).toBe('login_required'); + expect(exit.cause.error).toHaveProperty('redirectUrl'); + }), +); + +// ─── dispatchAuthorizeFetch ─────────────────────────────────────────────────── + +it.effect('dispatchAuthorizeFetch succeeds with authorizeResponse', () => + Micro.gen(function* () { + const authorizeResponse = { code: 'auth-code-abc', state: 'state-xyz' }; + vi.mocked(mockStore.dispatch).mockResolvedValueOnce({ + data: { authorizeResponse }, + } as unknown as ReturnType); + + const result = yield* dispatchAuthorizeFetch( + mockStore, + 'https://example.com/authorize?request_uri=...', + wellknown, + { clientId, redirectUri, scope, responseType }, + ); + expect(result).toStrictEqual(authorizeResponse); + }), +); + +it.effect( + 'dispatchAuthorizeFetch fails with unknown_error when data has no authorizeResponse', + () => + Micro.gen(function* () { + vi.mocked(mockStore.dispatch).mockResolvedValueOnce({ + data: {}, + } as unknown as ReturnType); + + const exit = yield* Micro.exit( + dispatchAuthorizeFetch(mockStore, 'https://example.com/authorize', wellknown, { + clientId, + redirectUri, + scope, + responseType, + }), + ); + expect(Micro.exitIsFailure(exit)).toBe(true); + if (!Micro.exitIsFailure(exit) || !Micro.causeIsFail(exit.cause)) return; + expect(exit.cause.error.type).toBe('unknown_error'); + }), +); + +// ─── dispatchAuthorizeIframe ────────────────────────────────────────────────── + +it.effect('dispatchAuthorizeIframe succeeds with iframe data', () => + Micro.gen(function* () { + const iframeData = { code: 'iframe-code', state: 'state-abc' }; + vi.mocked(mockStore.dispatch).mockResolvedValueOnce({ + data: iframeData, + } as unknown as ReturnType); + + const result = yield* dispatchAuthorizeIframe( + mockStore, + 'https://example.com/authorize', + wellknown, + { clientId, redirectUri, scope, responseType }, + ); + expect(result).toStrictEqual(iframeData); + }), +); + +it.effect('dispatchAuthorizeIframe fails with unknown_error when data is undefined', () => + Micro.gen(function* () { + vi.mocked(mockStore.dispatch).mockResolvedValueOnce({ + data: undefined, + } as unknown as ReturnType); + + const exit = yield* Micro.exit( + dispatchAuthorizeIframe(mockStore, 'https://example.com/authorize', wellknown, { + clientId, + redirectUri, + scope, + responseType, + }), + ); + expect(Micro.exitIsFailure(exit)).toBe(true); + if (!Micro.exitIsFailure(exit) || !Micro.causeIsFail(exit.cause)) return; + expect(exit.cause.error.type).toBe('unknown_error'); + }), +); diff --git a/packages/oidc-client/src/lib/authorize.request.micros.ts b/packages/oidc-client/src/lib/authorize.request.micros.ts new file mode 100644 index 0000000000..4380eb4893 --- /dev/null +++ b/packages/oidc-client/src/lib/authorize.request.micros.ts @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025 Ping Identity Corporation. All rights reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ +import { Micro } from 'effect'; + +import { + buildParAuthorizeUrl, + handleDispatchError, + type PromptValue, +} from './authorize.request.utils.js'; + +import { oidcApi } from './oidc.api.js'; + +import type { SerializedError } from '@reduxjs/toolkit'; +import type { FetchBaseQueryError } from '@reduxjs/toolkit/query'; +import type { GetAuthorizationUrlOptions, WellknownResponse } from '@forgerock/sdk-types'; +import type { AuthorizationError, AuthorizationSuccess } from './authorize.request.types.js'; +import type { ClientStore } from './client.types.js'; + +// ─── PAR POST ──────────────────────────────────────────────────────────────── + +export const dispatchParRequest = ( + store: ClientStore, + parEndpoint: string, + body: URLSearchParams, +): Micro.Micro< + { error?: FetchBaseQueryError | SerializedError; data?: unknown }, + AuthorizationError, + never +> => + Micro.tryPromise({ + try: () => store.dispatch(oidcApi.endpoints.par.initiate({ endpoint: parEndpoint, body })), + catch: (error): AuthorizationError => ({ + error: 'PAR_DISPATCH_ERROR', + error_description: error instanceof Error ? error.message : 'Failed to dispatch PAR request', + type: 'network_error', + }), + }); + +export const buildParSlimUrl = ( + authorizationEndpoint: string, + clientId: string, + requestUri: string, + prompt?: PromptValue, +): Micro.Micro => + Micro.try({ + try: () => buildParAuthorizeUrl({ authorizationEndpoint, clientId, requestUri, prompt }), + catch: (err): AuthorizationError => ({ + error: 'PAR_URL_BUILD_ERROR', + error_description: err instanceof Error ? err.message : 'Failed to build PAR authorize URL', + type: 'unknown_error', + }), + }); + +// ─── Authorize dispatch ─────────────────────────────────────────────────────── + +export const dispatchAuthorizeFetch = ( + store: ClientStore, + url: string, + wellknown: WellknownResponse, + options: GetAuthorizationUrlOptions, +): Micro.Micro => + Micro.tryPromise({ + try: () => store.dispatch(oidcApi.endpoints.authorizeFetch.initiate({ url })), + catch: (error): AuthorizationError => ({ + error: 'AUTHORIZE_DISPATCH_ERROR', + error_description: + error instanceof Error ? error.message : 'Failed to dispatch authorize request', + type: 'network_error', + }), + }).pipe( + Micro.flatMap(({ error, data }) => { + if (error) return handleDispatchError(error, wellknown, options); + if (data?.authorizeResponse) return Micro.succeed(data.authorizeResponse); + return Micro.fail({ + error: 'Unknown_Error', + error_description: 'Response schema was not recognized', + type: 'unknown_error', + } as const); + }), + ); + +export const dispatchAuthorizeIframe = ( + store: ClientStore, + url: string, + wellknown: WellknownResponse, + options: GetAuthorizationUrlOptions, +): Micro.Micro => + Micro.tryPromise({ + try: () => store.dispatch(oidcApi.endpoints.authorizeIframe.initiate({ url })), + catch: (error): AuthorizationError => ({ + error: 'AUTHORIZE_DISPATCH_ERROR', + error_description: + error instanceof Error ? error.message : 'Failed to dispatch authorize request', + type: 'network_error', + }), + }).pipe( + Micro.flatMap(({ error, data }) => { + if (error) return handleDispatchError(error, wellknown, options); + if (data !== undefined) return Micro.succeed(data); + return Micro.fail({ + error: 'Unknown_Error', + error_description: 'Response data was empty', + type: 'unknown_error', + } as const); + }), + ); diff --git a/packages/oidc-client/src/lib/authorize.request.ts b/packages/oidc-client/src/lib/authorize.request.ts index 96af6a9fc0..303f566b72 100644 --- a/packages/oidc-client/src/lib/authorize.request.ts +++ b/packages/oidc-client/src/lib/authorize.request.ts @@ -8,172 +8,150 @@ import { CustomLogger } from '@forgerock/sdk-logger'; import { Micro } from 'effect'; import { - createAuthorizeUrlµ, - buildAuthorizeOptionsµ, - createAuthorizeErrorµ, + buildAuthorizeOptions, + buildParBody, + createAuthorizeUrlMicro, + validateParResponse, } from './authorize.request.utils.js'; -import { oidcApi } from './oidc.api.js'; +import { + generateAuthValues, + generatePkceChallenge, + storeAuthOptions, +} from './authorize.request.effects.js'; +import { + buildParSlimUrl, + dispatchAuthorizeFetch, + dispatchAuthorizeIframe, + dispatchParRequest, +} from './authorize.request.micros.js'; -import type { ClientStore } from './client.types.js'; import type { GetAuthorizationUrlOptions, WellknownResponse } from '@forgerock/sdk-types'; -import type { AuthorizationError, AuthorizationSuccess } from './authorize.request.types.js'; +import type { + AuthorizationError, + AuthorizationSuccess, + OptionalAuthorizeOptions, +} from './authorize.request.types.js'; +import type { ClientStore } from './client.types.js'; import type { OidcConfig } from './config.types.js'; +// ─── Dispatch routing ───────────────────────────────────────────────────────── + /** - * @function authorizeµ - * @description Creates an authorization URL for the OIDC client. - * @param {WellKnownResponse} wellknown - The well-known configuration for the OIDC server. - * @param {OidcConfig} config - The OIDC client configuration. - * @param {CustomLogger} log - The logger instance for logging debug information. - * @param {ClientStore} store - The Redux store instance for managing OIDC state. - * @param {GetAuthorizationUrlOptions} options - Optional parameters for the authorization request. - * @returns {Micro.Micro} - A micro effect that resolves to the authorization response. + * Routes the authorize URL to the appropriate transport: a direct fetch for + * pi.flow (PingOne servers reject iframes via X-Frame-Options: DENY), or an + * iframe for all other response modes. */ -export function authorizeµ( +function dispatchAuthorizeµ( + url: string, + options: GetAuthorizationUrlOptions, wellknown: WellknownResponse, - config: OidcConfig, - log: CustomLogger, store: ClientStore, - options?: GetAuthorizationUrlOptions, -) { - return buildAuthorizeOptionsµ(wellknown, config, options).pipe( - Micro.flatMap(([url, options]) => createAuthorizeUrlµ(url, options)), - Micro.tap((url) => log.debug('Authorize URL created', url)), - Micro.tapError((url) => Micro.sync(() => log.error('Error creating authorize URL', url))), - Micro.flatMap( - ([url, options]): Micro.Micro => { - if (options.responseMode === 'pi.flow') { - /** - * If we support the pi.flow field, this means we are using a PingOne server. - * PingOne servers do not support redirection through iframes because they - * set iframe's to DENY. - * - * We do not use RTK Query for this because we don't want caching, or store - * updates, and want the request to be made similar to the iframe method below. - * - * This returns a Micro that resolves to the parsed response JSON. - */ - return Micro.promise(() => - store.dispatch(oidcApi.endpoints.authorizeFetch.initiate({ url })), - ).pipe( - Micro.flatMap( - ({ error, data }): Micro.Micro => { - if (error) { - // Check for serialized error - if (!('status' in error)) { - // This is a network or fetch error, so return it as-is - return Micro.fail({ - error: error.code || 'Unknown_Error', - error_description: - error.message || 'An unknown error occurred during authorization', - type: 'unknown_error', - }); - } - - // If there is no data, this is an unknown error - if (!('data' in error)) { - return Micro.fail({ - error: 'Unknown_Error', - error_description: 'An unknown error occurred during authorization', - type: 'unknown_error', - }); - } - - const errorDetails = error.data as AuthorizationError; - - // If the error is a configuration issue, return it as-is - if ('statusText' in error && error.statusText === 'CONFIGURATION_ERROR') { - return Micro.fail(errorDetails); - } - - // If the error is not a configuration issue, we build a new Authorize URL - // For redirection, we need to remove `pi.flow` from the options - const redirectOptions = options; - delete redirectOptions.responseMode; - - // Create an error with a new Authorize URL - return createAuthorizeErrorµ(errorDetails, wellknown, options); - } - - log.debug('Received success response', data); - - if (data.authorizeResponse) { - // Authorization was successful - return Micro.succeed(data.authorizeResponse); - } else { - // This should never be reached, but just in case - return Micro.fail({ - error: 'Unknown_Error', - error_description: 'Response schema was not recognized', - type: 'unknown_error', - }); - } - }, - ), - ); - } else { - /** - * If the response mode is not pi.flow, then we are likely using a traditional - * redirect based server supporting iframes. An example would be PingAM. - * - * This returns a Micro that's either the success URL parameters or error URL - * parameters. - */ - return Micro.promise(() => - store.dispatch(oidcApi.endpoints.authorizeIframe.initiate({ url })), - ).pipe( - Micro.flatMap( - ({ error, data }): Micro.Micro => { - if (error) { - // Check for serialized error - if (!('status' in error)) { - // This is a network or fetch error, so return it as-is - return Micro.fail({ - error: error.code || 'Unknown_Error', - error_description: - error.message || 'An unknown error occurred during authorization', - type: 'unknown_error', - }); - } - - // If there is no data, this is an unknown error - if (!('data' in error)) { - return Micro.fail({ - error: 'Unknown_Error', - error_description: 'An unknown error occurred during authorization', - type: 'unknown_error', - }); - } + log: CustomLogger, +): Micro.Micro { + if (options.responseMode === 'pi.flow') { + const { responseMode: _, ...redirectOptions } = options; + return dispatchAuthorizeFetch(store, url, wellknown, redirectOptions).pipe( + Micro.tap((result) => log.debug('Received success response', result)), + ); + } + + return dispatchAuthorizeIframe(store, url, wellknown, options).pipe( + Micro.tap((result) => log.debug('Received success response', result)), + ); +} - const errorDetails = error.data as AuthorizationError; +// ─── PAR flow ───────────────────────────────────────────────────────────────── - // If the error is a configuration issue, return it as-is - if ('statusText' in error && error.statusText === 'CONFIGURATION_ERROR') { - return Micro.fail(errorDetails); - } +/** + * Pushed Authorization Request (RFC 9126): POSTs all authorize parameters to + * the PAR endpoint, then returns a slim URL containing only `client_id` and + * `request_uri` — keeping sensitive params out of the browser address bar. + */ +export function parAuthorizeµ( + wellknown: WellknownResponse, + config: OidcConfig, + store: ClientStore, + options?: OptionalAuthorizeOptions, +): Micro.Micro { + const parEndpoint = wellknown.pushed_authorization_request_endpoint; + + if (!parEndpoint) { + return Micro.fail({ + error: 'PAR endpoint not configured', + error_description: 'PAR endpoint not found in server configuration', + type: 'wellknown_error', + } as const); + } + + const { prompt, ...parBodyOptions } = options ?? {}; + + return Micro.gen(function* () { + const [authUrlOptions, storeOptions] = yield* generateAuthValues(config, wellknown, options); + const challenge = yield* generatePkceChallenge(authUrlOptions.verifier); + const body = yield* buildParBody( + config, + parBodyOptions, + challenge, + authUrlOptions.state, + prompt, + ); + const parResult = yield* dispatchParRequest(store, parEndpoint, body); + const { request_uri } = yield* validateParResponse(parResult); + yield* storeAuthOptions(storeOptions); + return yield* buildParSlimUrl( + wellknown.authorization_endpoint, + config.clientId, + request_uri, + prompt, + ); + }); +} - // This is an expected error, so combine error with a new Authorize URL - return createAuthorizeErrorµ(errorDetails, wellknown, options); - } +// ─── Standard + PAR authorize ───────────────────────────────────────────────── - log.debug('Received success response', data); +/** + * Background authorization flow. Uses PAR when the server mandates it + * (`require_pushed_authorization_requests`) or `config.par` is set; otherwise + * builds a full authorize URL and dispatches via iframe or pi.flow fetch. + */ +export function authorizeµ( + wellknown: WellknownResponse, + config: OidcConfig, + log: CustomLogger, + store: ClientStore, + options?: GetAuthorizationUrlOptions, + useParFlow = config.par ?? wellknown.require_pushed_authorization_requests === true, +): Micro.Micro { + const parDispatchOptions: GetAuthorizationUrlOptions = { + clientId: config.clientId, + redirectUri: config.redirectUri, + scope: config.scope || 'openid', + responseType: config.responseType || 'code', + ...options, + }; + + const parFlow = parAuthorizeµ(wellknown, config, store, options).pipe( + Micro.tap((url) => log.debug('PAR authorize URL created', url)), + Micro.tapError((err) => + Micro.sync(() => log.error(`PAR authorize failed [${err.type}]: ${err.error}`, err)), + ), + Micro.flatMap((url) => dispatchAuthorizeµ(url, parDispatchOptions, wellknown, store, log)), + Micro.tapError((err) => + Micro.sync(() => log.error('Error dispatching PAR authorize request', err)), + ), + ); - if (data) { - // Authorization was successful - return Micro.succeed(data); - } else { - // This should never be reached, but just in case - return Micro.fail({ - error: 'Unknown_Error', - error_description: 'Redirect parameters was not recognized', - type: 'unknown_error', - }); - } - }, - ), - ); - } - }, + const [path, opts] = buildAuthorizeOptions(wellknown, config, options); + const standardFlow = createAuthorizeUrlMicro(path, opts).pipe( + Micro.tap(([url]) => log.debug('Authorize URL created', url)), + Micro.tapError((err) => Micro.sync(() => log.error('Error creating authorize URL', err))), + Micro.flatMap(([url, dispatchOpts]) => + dispatchAuthorizeµ(url, dispatchOpts, wellknown, store, log), + ), + Micro.tapError((err) => + Micro.sync(() => log.error('Error dispatching authorize request', err)), ), ); + + return useParFlow ? parFlow : standardFlow; } diff --git a/packages/oidc-client/src/lib/authorize.request.utils.test.ts b/packages/oidc-client/src/lib/authorize.request.utils.test.ts index 0a00278a7b..b6eac42f6e 100644 --- a/packages/oidc-client/src/lib/authorize.request.utils.test.ts +++ b/packages/oidc-client/src/lib/authorize.request.utils.test.ts @@ -6,9 +6,21 @@ */ import { it, expect } from '@effect/vitest'; import { Micro } from 'effect'; -import { buildAuthorizeOptionsµ } from './authorize.request.utils.js'; -import { OidcConfig } from './config.types.js'; -import { WellknownResponse } from '@forgerock/sdk-types'; +import { vi, afterEach } from 'vitest'; +import * as sdkOidc from '@forgerock/sdk-oidc'; +import { parAuthorizeµ, authorizeµ } from './authorize.request.js'; +import { + toAuthorizationError, + isFetchBaseQueryError, + toDispatchError, + isStringRecord, + hasPushRequestUri, + buildAuthorizeOptions, + buildParAuthorizeUrl, +} from './authorize.request.utils.js'; +import type { OidcConfig } from './config.types.js'; +import type { WellknownResponse } from '@forgerock/sdk-types'; +import type { ClientStore } from './client.types.js'; const clientId = '123456789'; const redirectUri = 'https://example.com/callback.html'; @@ -33,35 +45,405 @@ const wellknown: WellknownResponse = { revocation_endpoint: 'https://example.com/revoke', }; -it.effect('buildAuthorizeOptionsµ succeeds with BuildAuthorizationData', () => +const parEndpoint = 'https://example.com/par'; +const wellknownWithPar: WellknownResponse = { + ...wellknown, + pushed_authorization_request_endpoint: parEndpoint, +}; + +const mockStore = { + dispatch: vi.fn(), +} as unknown as ClientStore; + +const sessionStorageStub = { getItem: vi.fn(), setItem: vi.fn(), removeItem: vi.fn() }; + +afterEach(() => { + vi.unstubAllGlobals(); + vi.resetAllMocks(); +}); + +// ─── toAuthorizationError ──────────────────────────────────────────────────── + +it('toAuthorizationError returns error shape from valid object', () => { + const result = toAuthorizationError({ + error: 'access_denied', + error_description: 'denied', + type: 'auth_error', + }); + expect(result).toStrictEqual({ + error: 'access_denied', + error_description: 'denied', + type: 'auth_error', + }); +}); + +it('toAuthorizationError returns Unknown_Error for missing error field', () => { + const result = toAuthorizationError({ error_description: 'no error key' }); + expect(result.error).toBe('Unknown_Error'); + expect(result.type).toBe('unknown_error'); +}); + +it('toAuthorizationError returns Unknown_Error for non-object input', () => { + const result = toAuthorizationError(null); + expect(result.error).toBe('Unknown_Error'); +}); + +// ─── isFetchBaseQueryError ─────────────────────────────────────────────────── + +it('isFetchBaseQueryError returns true for FetchBaseQueryError', () => { + expect(isFetchBaseQueryError({ status: 400, data: {} })).toBe(true); +}); + +it('isFetchBaseQueryError returns false for SerializedError', () => { + expect(isFetchBaseQueryError({ message: 'oops', code: 'ERR' })).toBe(false); +}); + +// ─── toDispatchError ───────────────────────────────────────────────────────── + +it('toDispatchError uses code/message for SerializedError', () => { + const result = toDispatchError({ code: 'NETWORK_ERR', message: 'fetch failed' }); + expect(result).toStrictEqual({ + error: 'NETWORK_ERR', + error_description: 'fetch failed', + type: 'unknown_error', + }); +}); + +it('toDispatchError delegates to toAuthorizationError for FetchBaseQueryError', () => { + const result = toDispatchError({ + status: 400, + data: { error: 'invalid_client', error_description: 'bad creds', type: 'auth_error' }, + }); + expect(result).toStrictEqual({ + error: 'invalid_client', + error_description: 'bad creds', + type: 'auth_error', + }); +}); + +// ─── parAuthorizeµ ─────────────────────────────────────────────────────────── + +it.effect('parAuthorizeµ fails with wellknown_error when par endpoint is missing', () => Micro.gen(function* () { - const result = yield* buildAuthorizeOptionsµ(wellknown, config); - - expect(result).toStrictEqual([ - wellknown.authorization_endpoint, - { - clientId, - redirectUri, - scope, - responseType, - }, - ]); + const configWithPar: OidcConfig = { ...config, par: true }; + const result = yield* Micro.exit(parAuthorizeµ(wellknown, configWithPar, mockStore)); + expect(Micro.exitIsFailure(result)).toBe(true); + if (!Micro.exitIsFailure(result)) return; + expect(Micro.causeIsFail(result.cause)).toBe(true); + if (Micro.causeIsFail(result.cause)) { + expect(result.cause.error.type).toBe('wellknown_error'); + expect(result.cause.error.error_description).toBe( + 'PAR endpoint not found in server configuration', + ); + } + }), +); + +it.effect('parAuthorizeµ succeeds and returns slim authorize URL', () => + Micro.gen(function* () { + const configWithPar: OidcConfig = { ...config, par: true }; + const requestUri = 'urn:ietf:params:oauth:request_uri:abc123'; + + vi.stubGlobal('sessionStorage', sessionStorageStub); + vi.mocked(mockStore.dispatch).mockResolvedValueOnce({ + data: { request_uri: requestUri, expires_in: 60 }, + } as unknown as ReturnType); + + const url = yield* parAuthorizeµ(wellknownWithPar, configWithPar, mockStore); + + expect(url).toContain('client_id=123456789'); + expect(url).toContain(`request_uri=${encodeURIComponent(requestUri)}`); + expect(url).not.toContain('scope='); + expect(url).not.toContain('code_challenge='); + expect(sessionStorageStub.setItem).toHaveBeenCalled(); }), ); -it.effect('buildAuthorizeOptionsµ with pi.flow succeeds with BuildAuthorizationData', () => +it.effect('parAuthorizeµ fails with network_error when PAR POST returns error', () => Micro.gen(function* () { - const result = yield* buildAuthorizeOptionsµ(wellknown, config, { responseMode: 'pi.flow' }); - - expect(result).toStrictEqual([ - wellknown.authorization_endpoint, - { - clientId, - redirectUri, - scope, - responseType, - responseMode: 'pi.flow', + const configWithPar: OidcConfig = { ...config, par: true }; + + vi.stubGlobal('sessionStorage', sessionStorageStub); + vi.mocked(mockStore.dispatch).mockResolvedValueOnce({ + error: { + status: 400, + statusText: 'PAR_ERROR', + data: { error: 'PAR_ERROR', error_description: 'invalid_client', type: 'network_error' }, }, - ]); + } as unknown as ReturnType); + + const result = yield* Micro.exit(parAuthorizeµ(wellknownWithPar, configWithPar, mockStore)); + + expect(Micro.exitIsFailure(result)).toBe(true); + if (!Micro.exitIsFailure(result)) return; + expect(Micro.causeIsFail(result.cause)).toBe(true); + if (Micro.causeIsFail(result.cause)) { + expect(result.cause.error.type).toBe('network_error'); + } + expect(sessionStorageStub.setItem).not.toHaveBeenCalled(); + }), +); + +it.effect('parAuthorizeµ fails with network_error when PAR response is missing request_uri', () => + Micro.gen(function* () { + const configWithPar: OidcConfig = { ...config, par: true }; + + vi.stubGlobal('sessionStorage', sessionStorageStub); + vi.mocked(mockStore.dispatch).mockResolvedValueOnce({ + data: {}, + } as unknown as ReturnType); + + const result = yield* Micro.exit(parAuthorizeµ(wellknownWithPar, configWithPar, mockStore)); + + expect(Micro.exitIsFailure(result)).toBe(true); + if (!Micro.exitIsFailure(result)) return; + expect(Micro.causeIsFail(result.cause)).toBe(true); + if (Micro.causeIsFail(result.cause)) { + expect(result.cause.error.type).toBe('network_error'); + expect(result.cause.error.error_description).toBe( + "PAR response missing required 'request_uri' field", + ); + } + expect(sessionStorageStub.setItem).not.toHaveBeenCalled(); + }), +); + +it.effect( + 'parAuthorizeµ with prompt=none includes prompt on slim authorize URL and in PAR body', + () => + Micro.gen(function* () { + const configWithPar: OidcConfig = { ...config, par: true }; + const requestUri = 'urn:ietf:params:oauth:request_uri:prompt-none-test'; + + vi.stubGlobal('sessionStorage', sessionStorageStub); + + const buildParamsSpy = vi.spyOn(sdkOidc, 'buildAuthorizeParams'); + + vi.mocked(mockStore.dispatch).mockResolvedValueOnce({ + data: { request_uri: requestUri, expires_in: 60 }, + } as unknown as ReturnType); + + const url = yield* parAuthorizeµ(wellknownWithPar, configWithPar, mockStore, { + prompt: 'none', + }); + + expect(url).toContain('prompt=none'); + const parBodyArg = buildParamsSpy.mock.calls[0][0] as unknown as Record; + expect(parBodyArg.prompt).toBe('none'); + }), +); + +// ─── isStringRecord ────────────────────────────────────────────────────────── + +it('isStringRecord returns true for plain objects', () => { + expect(isStringRecord({ a: 1 })).toBe(true); + expect(isStringRecord({})).toBe(true); +}); + +it('isStringRecord returns false for non-objects', () => { + expect(isStringRecord(null)).toBe(false); + expect(isStringRecord('string')).toBe(false); + expect(isStringRecord(42)).toBe(false); + expect(isStringRecord(undefined)).toBe(false); + expect(isStringRecord([])).toBe(true); // arrays are objects — intentional +}); + +// ─── hasPushRequestUri ─────────────────────────────────────────────────────── + +it('hasPushRequestUri returns true when request_uri is a string', () => { + expect(hasPushRequestUri({ request_uri: 'urn:ietf:params:oauth:request_uri:abc' })).toBe(true); +}); + +it('hasPushRequestUri returns false when request_uri is missing', () => { + expect(hasPushRequestUri({})).toBe(false); + expect(hasPushRequestUri({ request_uri: 123 })).toBe(false); + expect(hasPushRequestUri(null)).toBe(false); + expect(hasPushRequestUri('string')).toBe(false); +}); + +// ─── buildParAuthorizeUrl ──────────────────────────────────────────────────── + +it('buildParAuthorizeUrl produces slim URL with client_id and request_uri', () => { + const url = buildParAuthorizeUrl({ + authorizationEndpoint: 'https://example.com/authorize', + clientId: 'my-client', + requestUri: 'urn:ietf:params:oauth:request_uri:xyz', + }); + + const parsed = new URL(url); + expect(parsed.searchParams.get('client_id')).toBe('my-client'); + expect(parsed.searchParams.get('request_uri')).toBe('urn:ietf:params:oauth:request_uri:xyz'); + expect(parsed.searchParams.has('scope')).toBe(false); + expect(parsed.searchParams.has('code_challenge')).toBe(false); +}); + +it('buildParAuthorizeUrl includes prompt when provided', () => { + const url = buildParAuthorizeUrl({ + authorizationEndpoint: 'https://example.com/authorize', + clientId: 'my-client', + requestUri: 'urn:ietf:params:oauth:request_uri:xyz', + prompt: 'login', + }); + + expect(new URL(url).searchParams.get('prompt')).toBe('login'); +}); + +it('buildParAuthorizeUrl omits prompt when not provided', () => { + const url = buildParAuthorizeUrl({ + authorizationEndpoint: 'https://example.com/authorize', + clientId: 'my-client', + requestUri: 'urn:ietf:params:oauth:request_uri:xyz', + }); + + expect(new URL(url).searchParams.has('prompt')).toBe(false); +}); + +// ─── buildAuthorizeOptions ──────────────────────────────────────────────────── + +it('buildAuthorizeOptions returns path and merged options from config', () => { + const wk: WellknownResponse = { ...wellknown }; + const [path, opts] = buildAuthorizeOptions(wk, config); + + expect(path).toBe(wk.authorization_endpoint); + expect(opts.clientId).toBe(config.clientId); + expect(opts.redirectUri).toBe(config.redirectUri); + expect(opts.scope).toBe(config.scope); + expect(opts.responseType).toBe(config.responseType); + // pi.flow should NOT be set when response_modes_supported is absent + expect(opts.responseMode).toBeUndefined(); +}); + +it('buildAuthorizeOptions adds pi.flow responseMode when server supports it', () => { + const wkWithPiFlow: WellknownResponse = { + ...wellknown, + response_modes_supported: ['query', 'pi.flow'], + }; + const [, opts] = buildAuthorizeOptions(wkWithPiFlow, config); + expect(opts.responseMode).toBe('pi.flow'); +}); + +it('buildAuthorizeOptions merges caller options and lets them override defaults', () => { + const [, opts] = buildAuthorizeOptions(wellknown, config, { scope: 'openid email' }); + expect(opts.scope).toBe('openid email'); +}); + +it('buildAuthorizeOptions falls back to "openid" scope and "code" responseType when config omits them', () => { + const minimal = { + clientId, + redirectUri, + serverConfig: config.serverConfig, + } as unknown as OidcConfig; + const [, opts] = buildAuthorizeOptions(wellknown, minimal); + expect(opts.scope).toBe('openid'); + expect(opts.responseType).toBe('code'); +}); + +// ─── authorizeµ flow routing ────────────────────────────────────────────────── + +const mockLog = { + debug: vi.fn(), + error: vi.fn(), + info: vi.fn(), + warn: vi.fn(), +} as unknown as import('@forgerock/sdk-logger').CustomLogger; + +it.effect('authorizeµ uses PAR flow when useParFlow=true', () => + Micro.gen(function* () { + const requestUri = 'urn:ietf:params:oauth:request_uri:par-routing-test'; + const authorizeResponse = { code: 'par-code', state: 'par-state' }; + + vi.stubGlobal('sessionStorage', sessionStorageStub); + // First dispatch: PAR POST → returns request_uri + vi.mocked(mockStore.dispatch) + .mockResolvedValueOnce({ + data: { request_uri: requestUri, expires_in: 60 }, + } as unknown as ReturnType) + // Second dispatch: authorize iframe/fetch → returns code+state + .mockResolvedValueOnce({ + data: authorizeResponse, + } as unknown as ReturnType); + + const result = yield* authorizeµ(wellknownWithPar, config, mockLog, mockStore, undefined, true); + expect(result).toStrictEqual(authorizeResponse); + // PAR POST + authorize dispatch = 2 calls + expect(mockStore.dispatch).toHaveBeenCalledTimes(2); + }), +); + +it.effect('authorizeµ uses standard flow when useParFlow=false', () => + Micro.gen(function* () { + const authorizeResponse = { code: 'std-code', state: 'std-state' }; + + vi.stubGlobal('sessionStorage', sessionStorageStub); + vi.spyOn(sdkOidc, 'createAuthorizeUrl').mockResolvedValue( + 'https://example.com/authorize?code_challenge=xxx', + ); + vi.mocked(mockStore.dispatch).mockResolvedValueOnce({ + data: authorizeResponse, + } as unknown as ReturnType); + + const result = yield* authorizeµ(wellknown, config, mockLog, mockStore, undefined, false); + expect(result).toStrictEqual(authorizeResponse); + // Only one dispatch: the iframe/fetch call (no PAR POST) + expect(mockStore.dispatch).toHaveBeenCalledTimes(1); }), ); + +it.effect('authorizeµ defaults to PAR when wellknown requires it and useParFlow not passed', () => + Micro.gen(function* () { + const requestUri = 'urn:ietf:params:oauth:request_uri:required-par-test'; + const authorizeResponse = { code: 'req-par-code', state: 'req-par-state' }; + const wkRequiresPar: WellknownResponse = { + ...wellknownWithPar, + require_pushed_authorization_requests: true, + }; + + vi.stubGlobal('sessionStorage', sessionStorageStub); + vi.mocked(mockStore.dispatch) + .mockResolvedValueOnce({ + data: { request_uri: requestUri, expires_in: 60 }, + } as unknown as ReturnType) + .mockResolvedValueOnce({ + data: authorizeResponse, + } as unknown as ReturnType); + + const result = yield* authorizeµ(wkRequiresPar, config, mockLog, mockStore); + expect(result).toStrictEqual(authorizeResponse); + expect(mockStore.dispatch).toHaveBeenCalledTimes(2); + }), +); + +it.effect( + 'authorizeµ routes to pi.flow fetch when options.responseMode is pi.flow (unwraps authorizeResponse)', + () => + Micro.gen(function* () { + // pi.flow dispatch goes through dispatchAuthorizeFetch which unwraps { authorizeResponse } + const requestUri = 'urn:ietf:params:oauth:request_uri:pi-flow-test'; + const authorizeResponse = { code: 'pi-code', state: 'pi-state' }; + + vi.stubGlobal('sessionStorage', sessionStorageStub); + vi.mocked(mockStore.dispatch) + .mockResolvedValueOnce({ + data: { request_uri: requestUri, expires_in: 60 }, + } as unknown as ReturnType) + .mockResolvedValueOnce({ + data: { authorizeResponse }, + } as unknown as ReturnType); + + const result = yield* authorizeµ( + wellknownWithPar, + config, + mockLog, + mockStore, + { + clientId, + redirectUri, + scope, + responseType: 'code' as const, + responseMode: 'pi.flow' as const, + }, + true, + ); + expect(result).toStrictEqual(authorizeResponse); + }), +); diff --git a/packages/oidc-client/src/lib/authorize.request.utils.ts b/packages/oidc-client/src/lib/authorize.request.utils.ts index 96557e22ed..d8b4829540 100644 --- a/packages/oidc-client/src/lib/authorize.request.utils.ts +++ b/packages/oidc-client/src/lib/authorize.request.utils.ts @@ -4,129 +4,230 @@ * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. */ -import { createAuthorizeUrl } from '@forgerock/sdk-oidc'; import { Micro } from 'effect'; - +import { buildAuthorizeParams, createAuthorizeUrl } from '@forgerock/sdk-oidc'; +import type { SerializedError } from '@reduxjs/toolkit'; +import type { FetchBaseQueryError } from '@reduxjs/toolkit/query'; import type { WellknownResponse, GetAuthorizationUrlOptions } from '@forgerock/sdk-types'; -import type { - AuthorizationError, - AuthorizationSuccess, - BuildAuthorizationData, - OptionalAuthorizeOptions, -} from './authorize.request.types.js'; +import type { AuthorizationError, OptionalAuthorizeOptions } from './authorize.request.types.js'; import type { OidcConfig } from './config.types.js'; -/** - * @function buildAuthorizeOptionsµ - * @description Builds the authorization options for the OIDC client. - * @param {WellknownResponse} wellknown - The well-known configuration for the OIDC server. - * @param {OptionalAuthorizeOptions} options - Optional parameters for the authorization request. - * @returns {Micro.Micro} - */ -export function buildAuthorizeOptionsµ( +export type PromptValue = 'none' | 'login' | 'consent'; + +export type ParUrlParams = { + authorizationEndpoint: string; + clientId: string; + requestUri: string; + prompt?: PromptValue; +}; + +export function isStringRecord(value: unknown): value is Record { + return typeof value === 'object' && value !== null; +} + +export function hasPushRequestUri(data: unknown): data is { request_uri: string } { + return isStringRecord(data) && typeof data['request_uri'] === 'string'; +} + +export function buildAuthorizeOptions( wellknown: WellknownResponse, config: OidcConfig, options?: OptionalAuthorizeOptions, -): Micro.Micro { +): [string, GetAuthorizationUrlOptions] { const isPiFlow = wellknown.response_modes_supported?.includes('pi.flow'); - return Micro.sync( - (): BuildAuthorizationData => [ - wellknown.authorization_endpoint, - { + return [ + wellknown.authorization_endpoint, + { + clientId: config.clientId, + redirectUri: config.redirectUri, + scope: config.scope || 'openid', + responseType: config.responseType || 'code', + ...(isPiFlow && { responseMode: 'pi.flow' as const }), + ...options, + }, + ]; +} + +/** + * Type guard for RTK FetchBaseQueryError vs SerializedError. + * FetchBaseQueryError always carries a `status` field; SerializedError does not. + */ +export function isFetchBaseQueryError( + error: FetchBaseQueryError | SerializedError, +): error is FetchBaseQueryError { + return 'status' in error; +} + +const KNOWN_ERROR_TYPES = new Set([ + 'auth_error', + 'argument_error', + 'network_error', + 'unknown_error', + 'wellknown_error', +] as const); + +function isKnownErrorType(value: unknown): value is AuthorizationError['type'] { + return typeof value === 'string' && KNOWN_ERROR_TYPES.has(value as AuthorizationError['type']); +} + +/** + * Safely narrows an unknown value to AuthorizationError shape. + * Validates that the data has the required 'error' string field, otherwise returns + * a default unknown error response. + */ +export function toAuthorizationError(data: unknown): AuthorizationError { + if (isStringRecord(data)) { + if (typeof data['error'] === 'string') { + return { + error: data['error'], + error_description: + typeof data['error_description'] === 'string' ? data['error_description'] : '', + type: isKnownErrorType(data['type']) ? data['type'] : 'unknown_error', + ...(typeof data['redirectUrl'] === 'string' && { redirectUrl: data['redirectUrl'] }), + }; + } + } + return { + error: 'Unknown_Error', + error_description: 'Unexpected error response shape', + type: 'unknown_error', + }; +} + +/** + * Constructs the slim PAR authorize URL containing only client_id and request_uri + * (and optionally prompt). Keeping sensitive params out of the browser address bar + * is the core security value of PAR (RFC 9126). + */ +export function buildParAuthorizeUrl({ + authorizationEndpoint, + clientId, + requestUri, + prompt, +}: ParUrlParams): string { + const url = new URL(authorizationEndpoint); + url.searchParams.set('client_id', clientId); + url.searchParams.set('request_uri', requestUri); + if (prompt) url.searchParams.set('prompt', prompt); + return url.toString(); +} + +/** + * Converts an RTK Query dispatch error to a typed AuthorizationError. + * oidc.api.ts normalizes all FetchBaseQueryErrors so that error.data always + * contains { error, error_description, type }. SerializedErrors fall back to + * their code/message fields. + */ +export function toDispatchError(error: FetchBaseQueryError | SerializedError): AuthorizationError { + if (!isFetchBaseQueryError(error)) { + return { + error: error.code ?? 'Unknown_Error', + error_description: error.message ?? 'An unknown error occurred during authorization', + type: 'unknown_error', + }; + } + return toAuthorizationError(error.data); +} + +export const buildParBody = ( + config: OidcConfig, + parBodyOptions: OptionalAuthorizeOptions, + challenge: string, + state: string, + prompt?: PromptValue, +): Micro.Micro => + Micro.try({ + try: () => + buildAuthorizeParams({ clientId: config.clientId, redirectUri: config.redirectUri, scope: config.scope || 'openid', responseType: config.responseType || 'code', - ...(isPiFlow && { responseMode: 'pi.flow' }), - ...options, - }, - ], - ); -} + ...parBodyOptions, + challenge, + state, + ...(prompt && { prompt }), + }), + catch: (err): AuthorizationError => ({ + error: 'PAR_PARAM_BUILD_ERROR', + error_description: err instanceof Error ? err.message : 'Failed to build PAR parameters', + type: 'auth_error', + }), + }); -/** - * @function createAuthorizeErrorµ - * @description Creates an error response with new Authorize URL for the authorization request. - * @param { error: string; error_description: string } res - The error response from the authorization request. - * @param {WellknownResponse} wellknown- The well-known configuration for the OIDC server. - * @param { OidcConfig } config- The OIDC client configuration. - * @param { GetAuthorizationUrlOptions } options- Optional parameters for the authorization request. - * @returns { Micro.Micro } - */ -export function createAuthorizeErrorµ( +export const createAuthorizeUrlMicro = ( + path: string, + options: GetAuthorizationUrlOptions, +): Micro.Micro<[string, GetAuthorizationUrlOptions], AuthorizationError, never> => + Micro.tryPromise({ + try: async () => + [await createAuthorizeUrl(path, { ...options, prompt: 'none' }), options] as [ + string, + GetAuthorizationUrlOptions, + ], + catch: (error): AuthorizationError => ({ + error: 'AuthorizationUrlError', + error_description: + error instanceof Error ? error.message : 'Error creating authorization URL', + type: 'auth_error', + }), + }); + +export const buildAuthorizeRedirectUrl = ( res: { error: string; error_description: string }, wellknown: WellknownResponse, options: GetAuthorizationUrlOptions, -): Micro.Micro { - return Micro.tryPromise({ - try: () => - createAuthorizeUrl(wellknown.authorization_endpoint, { - ...options, - }), - catch: (error) => { - let message = 'Error creating authorization URL'; - if (error instanceof Error) { - message = error.message; - } - return { - error: 'AuthorizationUrlError', - error_description: message, - type: 'auth_error', - } as const; - }, +): Micro.Micro => + Micro.tryPromise({ + try: () => createAuthorizeUrl(wellknown.authorization_endpoint, { ...options }), + catch: (error): AuthorizationError => ({ + error: 'AuthorizationUrlError', + error_description: + error instanceof Error ? error.message : 'Error creating authorization URL', + type: 'auth_error', + }), }).pipe( - Micro.flatMap((url) => { - return Micro.fail({ + Micro.flatMap((url) => + Micro.fail({ error: res.error, error_description: res.error_description, type: 'auth_error', redirectUrl: url, - } as const); - }), + } as const), + ), ); -} -/** - * @function createAuthorizeUrlµ - * @description Creates an authorization URL and related options/config for the Authorize request. - * @param {string} path - The path to the authorization endpoint. - * @param { GetAuthorizationUrlOptions } options - Optional parameters for the authorization request. - * @returns { Micro.Micro<[string, GetAuthorizationUrlOptions], AuthorizationError, never> } - */ -export function createAuthorizeUrlµ( - path: string, - options: GetAuthorizationUrlOptions, -): Micro.Micro<[string, GetAuthorizationUrlOptions], AuthorizationError, never> { - return Micro.tryPromise({ - try: async () => [ - await createAuthorizeUrl(path, { - ...options, - prompt: 'none', - }), - options, - ], - catch: (error) => { - let message = 'Error creating authorization URL'; - if (error instanceof Error) { - message = error.message; - } - return { - error: 'AuthorizationUrlError', - error_description: message, - type: 'auth_error', - } as const; - }, - }); -} +export const validateParResponse = (result: { + error?: FetchBaseQueryError | SerializedError; + data?: unknown; +}): Micro.Micro<{ request_uri: string }, AuthorizationError, never> => { + if (result.error) { + return Micro.fail( + toAuthorizationError(isFetchBaseQueryError(result.error) ? result.error.data : undefined), + ); + } + if (!hasPushRequestUri(result.data)) { + return Micro.fail({ + error: 'PAR_ERROR', + error_description: "PAR response missing required 'request_uri' field", + type: 'network_error', + } as const); + } + return Micro.succeed(result.data); +}; -export function handleResponseµ( - response: AuthorizationSuccess | AuthorizationError, +export const handleDispatchError = ( + error: FetchBaseQueryError | SerializedError, wellknown: WellknownResponse, options: GetAuthorizationUrlOptions, -): Micro.Micro { - if ('code' in response) { - return Micro.sync(() => response); - } else { - return createAuthorizeErrorµ(response, wellknown, options); - } -} +): Micro.Micro => { + const errorDetails = toDispatchError(error); + const isConfigError = + isFetchBaseQueryError(error) && + 'statusText' in error && + error.statusText === 'CONFIGURATION_ERROR'; + + return isConfigError + ? Micro.fail(errorDetails) + : buildAuthorizeRedirectUrl(errorDetails, wellknown, options); +}; diff --git a/packages/oidc-client/src/lib/client.store.test.ts b/packages/oidc-client/src/lib/client.store.test.ts index 87703d308a..40ebb64ec4 100644 --- a/packages/oidc-client/src/lib/client.store.test.ts +++ b/packages/oidc-client/src/lib/client.store.test.ts @@ -7,7 +7,7 @@ import { http, HttpResponse } from 'msw'; import { setupServer } from 'msw/node'; -import { it, expect, describe, vi } from 'vitest'; +import { it, expect, describe, vi, beforeEach, afterEach, afterAll, beforeAll } from 'vitest'; import { oidc } from './client.store.js'; @@ -39,6 +39,8 @@ vi.stubGlobal( })(), ); +const parRequestUri = 'urn:ietf:params:oauth:request_uri:test-par-request-uri'; + const server = setupServer( // P1 Revoke http.post('*/as/authorize', async () => { @@ -57,6 +59,9 @@ const server = setupServer( }), ), http.post('*/as/revoke', async () => HttpResponse.json(null, { status: 204 })), + http.post('*/as/par', async () => + HttpResponse.json({ request_uri: parRequestUri, expires_in: 60 }, { status: 201 }), + ), http.get('*/wellknown', async () => HttpResponse.json({ issuer: 'https://api.example.com/as/issuer', @@ -65,6 +70,7 @@ const server = setupServer( userinfo_endpoint: 'https://api.example.com/as/userinfo', introspection_endpoint: 'https://api.example.com/as/introspect', revocation_endpoint: 'https://api.example.com/as/revoke', + pushed_authorization_request_endpoint: 'https://api.example.com/as/par', response_types_supported: ['code', 'token', 'id_token', 'code id_token'], response_modes_supported: ['query', 'fragment', 'form_post', 'pi.flow'], }), @@ -279,3 +285,319 @@ describe('PingOne token get method', async () => { expect(tokens.accessToken).toBe('abcdefghijklmnop'); }); }); + +describe('authorize.url() with PAR enabled', async () => { + const configWithPar: OidcConfig = { + clientId: '123456789', + redirectUri: 'https://example.com/callback.html', + scope: 'openid profile', + serverConfig: { + wellknown: 'https://api.example.com/wellknown', + }, + responseType: 'code', + par: true, + }; + + beforeEach(() => { + customStorage.remove(storageKey); + }); + + it('returns a slim authorize URL with client_id and request_uri only', async () => { + const oidcClient = await oidc({ config: configWithPar, storage: customStorageConfig }); + + if ('error' in oidcClient) { + throw new Error('Error creating OIDC Client'); + } + + const url = await oidcClient.authorize.url(); + + if (typeof url !== 'string') { + expect.fail(`Expected string URL, got: ${JSON.stringify(url)}`); + } + + const parsed = new URL(url); + expect(parsed.searchParams.get('client_id')).toBe('123456789'); + expect(parsed.searchParams.get('request_uri')).toBe(parRequestUri); + expect(parsed.searchParams.has('scope')).toBe(false); + expect(parsed.searchParams.has('code_challenge')).toBe(false); + expect(parsed.searchParams.has('redirect_uri')).toBe(false); + }); + + it('returns wellknown_error when PAR endpoint is missing from wellknown', async () => { + server.use( + http.get('*/wellknown', async () => + HttpResponse.json({ + issuer: 'https://api.example.com/as/issuer', + authorization_endpoint: 'https://api.example.com/as/authorize', + token_endpoint: 'https://api.example.com/as/token', + userinfo_endpoint: 'https://api.example.com/as/userinfo', + introspection_endpoint: 'https://api.example.com/as/introspect', + revocation_endpoint: 'https://api.example.com/as/revoke', + }), + ), + ); + + const oidcClient = await oidc({ config: configWithPar, storage: customStorageConfig }); + + if ('error' in oidcClient) { + throw new Error('Error creating OIDC Client'); + } + + const result = await oidcClient.authorize.url(); + + if (typeof result === 'string') { + expect.fail('Expected error, got URL string'); + } + expect(result.type).toBe('wellknown_error'); + }); + + it('returns network_error when PAR endpoint returns an error', async () => { + server.use( + http.post('*/as/par', async () => + HttpResponse.json( + { error: 'invalid_client', error_description: 'Client authentication failed' }, + { status: 400 }, + ), + ), + ); + + const oidcClient = await oidc({ config: configWithPar, storage: customStorageConfig }); + + if ('error' in oidcClient) { + throw new Error('Error creating OIDC Client'); + } + + const result = await oidcClient.authorize.url(); + + if (typeof result === 'string') { + expect.fail('Expected error, got URL string'); + } + expect(result.type).toBe('network_error'); + }); +}); + +describe('PAR factory validation', async () => { + it('returns argument_error when wellknown requires PAR but config.par is explicitly false', async () => { + server.use( + http.get('*/wellknown', async () => + HttpResponse.json({ + issuer: 'https://api.example.com/as/issuer', + authorization_endpoint: 'https://api.example.com/as/authorize', + token_endpoint: 'https://api.example.com/as/token', + userinfo_endpoint: 'https://api.example.com/as/userinfo', + introspection_endpoint: 'https://api.example.com/as/introspect', + revocation_endpoint: 'https://api.example.com/as/revoke', + pushed_authorization_request_endpoint: 'https://api.example.com/as/par', + require_pushed_authorization_requests: true, + }), + ), + ); + + const configParFalse: OidcConfig = { + clientId: '123456789', + redirectUri: 'https://example.com/callback.html', + scope: 'openid profile', + serverConfig: { wellknown: 'https://api.example.com/wellknown' }, + responseType: 'code', + par: false, + }; + + const result = await oidc({ config: configParFalse, storage: customStorageConfig }); + + if (!('error' in result)) { + expect.fail('Expected error, got client'); + } + expect(result.type).toBe('argument_error'); + }); + + it('succeeds when wellknown requires PAR and config.par is true', async () => { + server.use( + http.get('*/wellknown', async () => + HttpResponse.json({ + issuer: 'https://api.example.com/as/issuer', + authorization_endpoint: 'https://api.example.com/as/authorize', + token_endpoint: 'https://api.example.com/as/token', + userinfo_endpoint: 'https://api.example.com/as/userinfo', + introspection_endpoint: 'https://api.example.com/as/introspect', + revocation_endpoint: 'https://api.example.com/as/revoke', + pushed_authorization_request_endpoint: 'https://api.example.com/as/par', + require_pushed_authorization_requests: true, + }), + ), + ); + + const configParTrue: OidcConfig = { + clientId: '123456789', + redirectUri: 'https://example.com/callback.html', + scope: 'openid profile', + serverConfig: { wellknown: 'https://api.example.com/wellknown' }, + responseType: 'code', + par: true, + }; + + const result = await oidc({ config: configParTrue, storage: customStorageConfig }); + expect('error' in result).toBe(false); + }); + + it('succeeds when wellknown requires PAR and config.par is unset (implicit opt-in)', async () => { + server.use( + http.get('*/wellknown', async () => + HttpResponse.json({ + issuer: 'https://api.example.com/as/issuer', + authorization_endpoint: 'https://api.example.com/as/authorize', + token_endpoint: 'https://api.example.com/as/token', + userinfo_endpoint: 'https://api.example.com/as/userinfo', + introspection_endpoint: 'https://api.example.com/as/introspect', + revocation_endpoint: 'https://api.example.com/as/revoke', + pushed_authorization_request_endpoint: 'https://api.example.com/as/par', + require_pushed_authorization_requests: true, + }), + ), + ); + + const configParUnset: OidcConfig = { + clientId: '123456789', + redirectUri: 'https://example.com/callback.html', + scope: 'openid profile', + serverConfig: { wellknown: 'https://api.example.com/wellknown' }, + responseType: 'code', + }; + + const result = await oidc({ config: configParUnset, storage: customStorageConfig }); + expect('error' in result).toBe(false); + }); + + it('uses PAR when wellknown requires it and config.par is unset', async () => { + server.use( + http.get('*/wellknown', async () => + HttpResponse.json({ + issuer: 'https://api.example.com/as/issuer', + authorization_endpoint: 'https://api.example.com/as/authorize', + token_endpoint: 'https://api.example.com/as/token', + userinfo_endpoint: 'https://api.example.com/as/userinfo', + introspection_endpoint: 'https://api.example.com/as/introspect', + revocation_endpoint: 'https://api.example.com/as/revoke', + pushed_authorization_request_endpoint: 'https://api.example.com/as/par', + require_pushed_authorization_requests: true, + }), + ), + ); + + const configParUnset: OidcConfig = { + clientId: '123456789', + redirectUri: 'https://example.com/callback.html', + scope: 'openid profile', + serverConfig: { wellknown: 'https://api.example.com/wellknown' }, + responseType: 'code', + // par deliberately omitted + }; + + const result = await oidc({ config: configParUnset, storage: customStorageConfig }); + + if ('error' in result) { + expect.fail('Expected client, got error'); + } + + const url = await result.authorize.url(); + + if (typeof url !== 'string') { + expect.fail(`Expected string URL, got: ${JSON.stringify(url)}`); + } + + const parsed = new URL(url); + expect(parsed.searchParams.has('request_uri')).toBe(true); + expect(parsed.searchParams.has('client_id')).toBe(true); + expect(parsed.searchParams.has('scope')).toBe(false); + expect(parsed.searchParams.has('code_challenge')).toBe(false); + }); +}); + +describe('authorize.background() with PAR enabled', async () => { + const configWithPar: OidcConfig = { + clientId: '123456789', + redirectUri: 'https://example.com/callback.html', + scope: 'openid profile', + serverConfig: { wellknown: 'https://api.example.com/wellknown' }, + responseType: 'code', + par: true, + }; + + beforeEach(() => { + customStorage.remove(storageKey); + }); + + it('uses slim PAR authorize URL for pi.flow background request', async () => { + const result = await oidc({ config: configWithPar, storage: customStorageConfig }); + + if ('error' in result) { + expect.fail('Expected client, got error'); + } + + const response = await result.authorize.background({ + clientId: configWithPar.clientId, + redirectUri: configWithPar.redirectUri, + scope: configWithPar.scope, + responseType: 'code', + responseMode: 'pi.flow', + }); + + if ('error' in response) { + expect.fail(`Expected success, got error: ${JSON.stringify(response)}`); + } + + expect(response.code).toBeDefined(); + expect(response.state).toBeDefined(); + }); +}); + +describe('authorize.url() with PAR enabled on non-pi.flow server', async () => { + beforeEach(() => { + customStorage.remove(storageKey); + }); + + it('returns slim PAR authorize URL for iframe-based server', async () => { + server.use( + http.get('*/wellknown', async () => + HttpResponse.json({ + issuer: 'https://api.example.com/as/issuer', + authorization_endpoint: 'https://api.example.com/as/authorize', + token_endpoint: 'https://api.example.com/as/token', + userinfo_endpoint: 'https://api.example.com/as/userinfo', + introspection_endpoint: 'https://api.example.com/as/introspect', + revocation_endpoint: 'https://api.example.com/as/revoke', + pushed_authorization_request_endpoint: 'https://api.example.com/as/par', + response_types_supported: ['code', 'token', 'id_token', 'code id_token'], + response_modes_supported: ['query', 'fragment', 'form_post'], + }), + ), + ); + + const configWithPar: OidcConfig = { + clientId: '123456789', + redirectUri: 'https://example.com/callback.html', + scope: 'openid profile', + serverConfig: { wellknown: 'https://api.example.com/wellknown' }, + responseType: 'code', + par: true, + }; + + const oidcClient = await oidc({ config: configWithPar, storage: customStorageConfig }); + + if ('error' in oidcClient) { + throw new Error('Error creating OIDC Client'); + } + + const url = await oidcClient.authorize.url(); + + if (typeof url !== 'string') { + expect.fail(`Expected string URL, got: ${JSON.stringify(url)}`); + } + + const parsed = new URL(url); + expect(parsed.searchParams.get('client_id')).toBe('123456789'); + expect(parsed.searchParams.get('request_uri')).toBe(parRequestUri); + expect(parsed.searchParams.has('scope')).toBe(false); + expect(parsed.searchParams.has('code_challenge')).toBe(false); + expect(parsed.searchParams.has('redirect_uri')).toBe(false); + }); +}); diff --git a/packages/oidc-client/src/lib/client.store.ts b/packages/oidc-client/src/lib/client.store.ts index da6c3de99c..f86795e8cc 100644 --- a/packages/oidc-client/src/lib/client.store.ts +++ b/packages/oidc-client/src/lib/client.store.ts @@ -8,9 +8,9 @@ import { logger as loggerFn } from '@forgerock/sdk-logger'; import { createAuthorizeUrl } from '@forgerock/sdk-oidc'; import { createStorage } from '@forgerock/storage'; import { Micro } from 'effect'; -import { exitIsFail, exitIsSuccess } from 'effect/Micro'; +import { causeIsDie, exitIsFail, exitIsSuccess } from 'effect/Micro'; -import { authorizeµ } from './authorize.request.js'; +import { authorizeµ, parAuthorizeµ } from './authorize.request.js'; import { buildTokenExchangeµ } from './exchange.request.js'; import { createClientStore, createTokenError } from './client.store.utils.js'; import { oidcApi } from './oidc.api.js'; @@ -92,8 +92,22 @@ export async function oidc({ if (error || !data) { log.error(`Error fetching wellknown config. Please check the URL: ${wellknownUrl}`); + return { + error: `Failed to fetch well-known configuration from: ${wellknownUrl}`, + type: 'wellknown_error', + }; + } + + if (data?.require_pushed_authorization_requests && config.par === false) { + return { + error: + 'The authorization server requires Pushed Authorization Requests (PAR). Set config.par to true or omit it.', + type: 'argument_error', + }; } + const useParFlow = config.par ?? data?.require_pushed_authorization_requests === true; + return { /** * An object containing methods for the creation, and background use, of the authorization URL @@ -106,14 +120,6 @@ export async function oidc({ * @returns {Promise} - Returns a promise that resolves to the authorization URL or an error. */ url: async (options?: GetAuthorizationUrlOptions): Promise => { - const optionsWithDefaults = { - clientId: config.clientId, - redirectUri: config.redirectUri, - scope: config.scope || 'openid', - responseType: config.responseType || 'code', - ...options, - }; - const state = store.getState(); const wellknown = wellknownSelector(wellknownUrl, state); @@ -124,6 +130,45 @@ export async function oidc({ }; } + if (useParFlow) { + const result = await Micro.runPromiseExit( + parAuthorizeµ(wellknown, config, store, options).pipe( + Micro.tapError((err) => + Micro.sync(() => + log.error(`PAR authorize.url() failed [${err.type}]: ${err.error}`, err), + ), + ), + ), + ); + + if (exitIsSuccess(result)) { + return result.value; + } else if (exitIsFail(result)) { + const authErr = result.cause.error; + return { + error: authErr.error, + message: authErr.error_description, + type: authErr.type, + }; + } else { + const defect = causeIsDie(result.cause) ? result.cause.defect : undefined; + return { + error: 'PAR authorization failure', + message: + defect instanceof Error ? defect.message : String(defect ?? 'Unknown defect'), + type: 'auth_error', + }; + } + } + + const optionsWithDefaults = { + clientId: config.clientId, + redirectUri: config.redirectUri, + scope: config.scope || 'openid', + responseType: config.responseType || 'code', + ...options, + }; + return createAuthorizeUrl(wellknown.authorization_endpoint, optionsWithDefaults); }, @@ -147,7 +192,7 @@ export async function oidc({ } const result = await Micro.runPromiseExit( - await authorizeµ(wellknown, config, log, store, options), + await authorizeµ(wellknown, config, log, store, options, useParFlow), ); if (exitIsSuccess(result)) { @@ -155,9 +200,11 @@ export async function oidc({ } else if (exitIsFail(result)) { return result.cause.error; } else { + const defect = causeIsDie(result.cause) ? result.cause.defect : undefined; return { error: 'Authorization failure', - error_description: result.cause.message, + error_description: + defect instanceof Error ? defect.message : String(defect ?? 'Unknown defect'), type: 'auth_error', }; } @@ -212,9 +259,10 @@ export async function oidc({ } else if (exitIsFail(result)) { return result.cause.error; } else { + const defect = causeIsDie(result.cause) ? result.cause.defect : undefined; return { error: 'Token Exchange failure', - message: result.cause.message, + message: defect instanceof Error ? defect.message : String(defect ?? 'Unknown defect'), type: 'exchange_error', }; } @@ -277,6 +325,7 @@ export async function oidc({ log, store, authorizeOptions, + useParFlow, ).pipe( Micro.flatMap((response): Micro.Micro => { return buildTokenExchangeµ({ @@ -311,9 +360,11 @@ export async function oidc({ } else if (exitIsFail(result)) { return result.cause.error; } else { + const defect = causeIsDie(result.cause) ? result.cause.defect : undefined; return { error: 'Background token renewal failed', - error_description: result.cause.message, + error_description: + defect instanceof Error ? defect.message : String(defect ?? 'Unknown defect'), type: 'auth_error', }; } @@ -407,9 +458,10 @@ export async function oidc({ } else if (exitIsFail(result)) { return result.cause.error; } else { + const defect = causeIsDie(result.cause) ? result.cause.defect : undefined; return { error: 'Token revocation failure', - message: result.cause.message, + message: defect instanceof Error ? defect.message : String(defect ?? 'Unknown defect'), type: 'auth_error', }; } @@ -482,9 +534,10 @@ export async function oidc({ } else if (exitIsFail(result)) { return result.cause.error; } else { + const defect = causeIsDie(result.cause) ? result.cause.defect : undefined; return { error: 'User Info retrieval failure', - message: result.cause.message, + message: defect instanceof Error ? defect.message : String(defect ?? 'Unknown defect'), type: 'auth_error', }; } @@ -537,9 +590,10 @@ export async function oidc({ } else if (exitIsFail(result)) { return result.cause.error; } else { + const defect = causeIsDie(result.cause) ? result.cause.defect : undefined; return { error: 'Logout_Failure', - message: result.cause.message, + message: defect instanceof Error ? defect.message : String(defect ?? 'Unknown defect'), type: 'auth_error', }; } diff --git a/packages/oidc-client/src/lib/config.types.ts b/packages/oidc-client/src/lib/config.types.ts index d560edc9fb..3f25a8fa39 100644 --- a/packages/oidc-client/src/lib/config.types.ts +++ b/packages/oidc-client/src/lib/config.types.ts @@ -16,6 +16,7 @@ export interface OidcConfig extends AsyncLegacyConfigOptions { timeout?: number; }; responseType?: ResponseType; + par?: boolean; } export interface OauthTokens { diff --git a/packages/oidc-client/src/lib/oidc.api.ts b/packages/oidc-client/src/lib/oidc.api.ts index 86f6408d6c..12f7fa0a95 100644 --- a/packages/oidc-client/src/lib/oidc.api.ts +++ b/packages/oidc-client/src/lib/oidc.api.ts @@ -23,6 +23,7 @@ import type { logger as loggerFn } from '@forgerock/sdk-logger'; import type { TokenExchangeResponse } from './exchange.types.js'; import type { AuthorizationSuccess, AuthorizeSuccessResponse } from './authorize.request.types.js'; import type { UserInfoResponse } from './client.types.js'; +import type { PushAuthorizationResponse } from './par.types.js'; interface Extras { requestMiddleware: RequestMiddleware[]; @@ -102,6 +103,71 @@ export const oidcApi = createApi({ return response as { data: AuthorizeSuccessResponse }; }, }), + par: builder.mutation({ + queryFn: async ({ endpoint, body }, api, _, baseQuery) => { + const { requestMiddleware, logger } = api.extra as Extras; + + const request: FetchArgs = { + url: endpoint, + method: 'POST', + headers: { + Accept: 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body, + }; + + logger.debug('OIDC PAR API request', request); + + const response = await initQuery(request, 'par') + .applyMiddleware(requestMiddleware) + .applyQuery(async (req: FetchArgs) => await baseQuery(req)); + + if (response.error) { + const responseError = response.error; + let message: string; + + if ( + responseError.data && + typeof responseError.data === 'object' && + 'error_description' in responseError.data && + typeof responseError.data.error_description === 'string' + ) { + message = responseError.data.error_description; + } else { + message = `Failed to push authorization request: ${responseError.status}`; + } + + logger.error('PAR API error', message); + + response.error.data = { + error: 'PAR_ERROR', + error_description: message, + type: 'network_error', + }; + + return response; + } + + if (!response.data || !('request_uri' in response.data)) { + return { + error: { + status: 'CUSTOM_ERROR', + error: 'PAR_ERROR', + data: { + error: 'PAR_ERROR', + error_description: "PAR response missing required 'request_uri' field", + type: 'network_error', + }, + } as FetchBaseQueryError, + }; + } + + logger.debug('OIDC PAR API response', response); + + return response as { data: PushAuthorizationResponse }; + }, + }), authorizeIframe: builder.mutation({ queryFn: async ({ url }, api) => { const { requestMiddleware, logger } = api.extra as Extras; diff --git a/packages/oidc-client/src/lib/par.types.ts b/packages/oidc-client/src/lib/par.types.ts new file mode 100644 index 0000000000..ae0cf25985 --- /dev/null +++ b/packages/oidc-client/src/lib/par.types.ts @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2025 Ping Identity Corporation. All rights reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +export interface PushAuthorizationResponse { + request_uri: string; + expires_in: number; +} diff --git a/packages/oidc-client/src/types.ts b/packages/oidc-client/src/types.ts index 8e6750b0a8..c1e5c71b95 100644 --- a/packages/oidc-client/src/types.ts +++ b/packages/oidc-client/src/types.ts @@ -7,6 +7,7 @@ export * from './lib/client.types.js'; export * from './lib/config.types.js'; export * from './lib/authorize.request.types.js'; export * from './lib/exchange.types.js'; +export type { PushAuthorizationResponse } from './lib/par.types.js'; export type { GenericError, diff --git a/packages/oidc-client/tsconfig.lib.json b/packages/oidc-client/tsconfig.lib.json index d4b07d31d8..d689866941 100644 --- a/packages/oidc-client/tsconfig.lib.json +++ b/packages/oidc-client/tsconfig.lib.json @@ -19,6 +19,9 @@ }, "include": ["src/**/*.ts"], "references": [ + { + "path": "../sdk-utilities/tsconfig.lib.json" + }, { "path": "../sdk-effects/storage/tsconfig.lib.json" }, diff --git a/packages/sdk-effects/oidc/src/index.ts b/packages/sdk-effects/oidc/src/index.ts index daef741c30..6ed59d5aa9 100644 --- a/packages/sdk-effects/oidc/src/index.ts +++ b/packages/sdk-effects/oidc/src/index.ts @@ -6,5 +6,6 @@ */ export * from './lib/authorize.effects.js'; +export * from './lib/authorize.utils.js'; export * from './lib/state-pkce.effects.js'; export * from './lib/wellknown.effects.js'; diff --git a/packages/sdk-effects/oidc/src/lib/authorize.effects.ts b/packages/sdk-effects/oidc/src/lib/authorize.effects.ts index 4881f2dd34..f196238674 100644 --- a/packages/sdk-effects/oidc/src/lib/authorize.effects.ts +++ b/packages/sdk-effects/oidc/src/lib/authorize.effects.ts @@ -11,6 +11,7 @@ import { createChallenge } from '@forgerock/sdk-utilities'; import { generateAndStoreAuthUrlValues } from './state-pkce.effects.js'; +import { buildAuthorizeParams } from './authorize.utils.js'; import type { GetAuthorizationUrlOptions } from '@forgerock/sdk-types'; @@ -39,16 +40,9 @@ export async function createAuthorizeUrl( const challenge = await createChallenge(authorizeUrlOptions.verifier); - const requestParams = new URLSearchParams({ - ...options.query, - code_challenge: challenge, - code_challenge_method: 'S256', - client_id: options.clientId, - prompt: options.prompt || '', - redirect_uri: options.redirectUri, - response_mode: options.responseMode || '', - response_type: options.responseType, - scope: options.scope, + const requestParams = buildAuthorizeParams({ + ...options, + challenge, state: authorizeUrlOptions.state, }); diff --git a/packages/sdk-effects/oidc/src/lib/authorize.test.ts b/packages/sdk-effects/oidc/src/lib/authorize.test.ts index 6dc03c43a7..484e8bed25 100644 --- a/packages/sdk-effects/oidc/src/lib/authorize.test.ts +++ b/packages/sdk-effects/oidc/src/lib/authorize.test.ts @@ -8,6 +8,7 @@ import type { GenerateAndStoreAuthUrlValues } from '@forgerock/sdk-types'; import { describe, expect, it, beforeEach } from 'vitest'; import { createAuthorizeUrl } from './authorize.effects.js'; +import { buildAuthorizeParams } from './authorize.utils.js'; import { getStorageKey } from './state-pkce.effects.js'; const mockSessionStorage = (() => { @@ -136,3 +137,52 @@ describe('createAuthorizeUrl', () => { expect(parsedOptions).toHaveProperty('verifier'); }); }); + +describe('buildAuthorizeParams', () => { + it('returns URLSearchParams with required OAuth fields', () => { + const params = buildAuthorizeParams({ + clientId: 'test-client', + redirectUri: 'https://example.com/cb', + scope: 'openid profile', + responseType: 'code', + challenge: 'abc123challenge', + state: 'randomstate', + }); + + expect(params.get('client_id')).toBe('test-client'); + expect(params.get('redirect_uri')).toBe('https://example.com/cb'); + expect(params.get('scope')).toBe('openid profile'); + expect(params.get('response_type')).toBe('code'); + expect(params.get('code_challenge')).toBe('abc123challenge'); + expect(params.get('code_challenge_method')).toBe('S256'); + expect(params.get('state')).toBe('randomstate'); + }); + + it('includes response_mode when provided', () => { + const params = buildAuthorizeParams({ + clientId: 'test-client', + redirectUri: 'https://example.com/cb', + scope: 'openid', + responseType: 'code', + challenge: 'abc123', + state: 'state1', + responseMode: 'pi.flow', + }); + + expect(params.get('response_mode')).toBe('pi.flow'); + }); + + it('omits optional fields when not provided', () => { + const params = buildAuthorizeParams({ + clientId: 'test-client', + redirectUri: 'https://example.com/cb', + scope: 'openid', + responseType: 'code', + challenge: 'abc123', + state: 'state1', + }); + + expect(params.has('response_mode')).toBe(false); + expect(params.has('prompt')).toBe(false); + }); +}); diff --git a/packages/sdk-effects/oidc/src/lib/authorize.utils.ts b/packages/sdk-effects/oidc/src/lib/authorize.utils.ts new file mode 100644 index 0000000000..27e41bf14d --- /dev/null +++ b/packages/sdk-effects/oidc/src/lib/authorize.utils.ts @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Ping Identity Corporation. All rights reserved. + * + * This software may be modified and distributed under the terms + * of the MIT license. See the LICENSE file for details. + */ + +import type { GetAuthorizationUrlOptions } from '@forgerock/sdk-types'; + +/** + * Builds URLSearchParams for an OAuth2/OIDC authorization request. + * Used for both direct authorize URL construction and PAR body. + * + * Standard OAuth fields always take precedence over any conflicting `query` + * entries — `query` is applied first and then overwritten by the known params. + */ +export function buildAuthorizeParams( + options: GetAuthorizationUrlOptions & { challenge: string; state: string }, +): URLSearchParams { + const params = new URLSearchParams(options.query); + + params.set('client_id', options.clientId); + params.set('response_type', options.responseType); + params.set('scope', options.scope); + params.set('redirect_uri', options.redirectUri); + params.set('code_challenge', options.challenge); + params.set('code_challenge_method', 'S256'); + params.set('state', options.state); + + if (options.responseMode) params.set('response_mode', options.responseMode); + if (options.prompt) params.set('prompt', options.prompt); + + return params; +} diff --git a/packages/sdk-effects/sdk-request-middleware/src/lib/request-mware.derived.ts b/packages/sdk-effects/sdk-request-middleware/src/lib/request-mware.derived.ts index 8de893dfe9..a05fb52a4d 100644 --- a/packages/sdk-effects/sdk-request-middleware/src/lib/request-mware.derived.ts +++ b/packages/sdk-effects/sdk-request-middleware/src/lib/request-mware.derived.ts @@ -23,6 +23,7 @@ export const actionTypes = { // OIDC authorize: 'AUTHORIZE', + par: 'PAR', tokenExchange: 'TOKEN_EXCHANGE', revoke: 'REVOKE', userInfo: 'USER_INFO', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b0fdeec512..2ed394efe0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -517,6 +517,9 @@ importers: '@forgerock/sdk-types': specifier: workspace:* version: link:../sdk-types + '@forgerock/sdk-utilities': + specifier: workspace:* + version: link:../sdk-utilities '@forgerock/storage': specifier: workspace:* version: link:../sdk-effects/storage From a3bcb7affc9fa69813d51df27e0055d6c2105e2f Mon Sep 17 00:00:00 2001 From: Ryan Bas Date: Thu, 14 May 2026 14:55:38 -0600 Subject: [PATCH 2/2] =?UTF-8?q?fix(oidc-client):=20address=20PAR=20code=20?= =?UTF-8?q?review=20=E2=80=94=20correctness,=20security,=20error=20handlin?= =?UTF-8?q?g?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix: spurious await on Micro value in client.store authorize path - Fix: validateParResponse uses toDispatchError for SerializedError, preserving diagnostic info instead of silently dropping it - Fix: optional chaining on wellknown?.require_pushed_authorization_requests in authorizeµ default param (prevents synchronous throw outside Micro) - Fix: scope PAR dispatch tapError inside flatMap to prevent double-logging with misleading "Error dispatching PAR authorize request" message - Fix: dispatchAuthorizeIframe validates code+state shape before succeeding - Fix: add credentials: include to PAR endpoint FetchArgs for SSO support - Fix: correct misleading log in authorizeIframe error path - Feat: surface expires_in from PAR response; warn when TTL < 30s - Test: add PAR 400 error e2e scenario to mock server and par.spec.ts - Chore: remove console.log debug artifacts from client.store.test.ts --- e2e/am-mock-api/src/app/routes.auth.js | 6 +++ e2e/oidc-suites/src/par.spec.ts | 47 +++++++++++++++++++ .../src/lib/authorize.request.micros.test.ts | 21 +++++++++ .../src/lib/authorize.request.micros.ts | 7 ++- .../oidc-client/src/lib/authorize.request.ts | 23 ++++++--- .../src/lib/authorize.request.utils.test.ts | 43 ++++++++++++----- .../src/lib/authorize.request.utils.ts | 9 ++-- .../oidc-client/src/lib/client.store.test.ts | 14 ++---- packages/oidc-client/src/lib/client.store.ts | 4 +- packages/oidc-client/src/lib/oidc.api.ts | 3 +- 10 files changed, 139 insertions(+), 38 deletions(-) diff --git a/e2e/am-mock-api/src/app/routes.auth.js b/e2e/am-mock-api/src/app/routes.auth.js index 38e75a426d..52a2fd143d 100644 --- a/e2e/am-mock-api/src/app/routes.auth.js +++ b/e2e/am-mock-api/src/app/routes.auth.js @@ -666,6 +666,12 @@ export default function (app) { app.get('/callback', (req, res) => res.status(200).send('ok')); app.post(authPaths.par, (req, res) => { + if (req.query.scenario === 'error') { + return res.status(400).json({ + error: 'invalid_request', + error_description: 'Missing required PAR parameter', + }); + } res.status(201).json(parResponse); }); diff --git a/e2e/oidc-suites/src/par.spec.ts b/e2e/oidc-suites/src/par.spec.ts index de224ffba2..a1089dc223 100644 --- a/e2e/oidc-suites/src/par.spec.ts +++ b/e2e/oidc-suites/src/par.spec.ts @@ -17,7 +17,54 @@ async function loginJourney(page, username: string, password: string) { await expect(page.locator('#journey-status')).toContainText('Session established'); } +// Synthetic PAR error endpoint — intercepted by Playwright before any real network call +const SYNTHETIC_PAR_ERROR_URL = 'http://localhost:8443/synthetic-par-error-endpoint'; +// The real wellknown used by the PAR app (intercepted to inject the synthetic PAR endpoint) +const DEFAULT_WELLKNOWN_PATTERN = + '**/openam-sdks.forgeblocks.com/am/oauth2/alpha/.well-known/openid-configuration*'; + test.describe('PAR (Pushed Authorization Request) login tests', () => { + test('PAR authorize returns 400 error — SDK surfaces error to the UI without redirecting', async ({ + page, + }) => { + const { navigate } = asyncEvents(page); + + // Intercept the wellknown to inject our synthetic PAR endpoint URL + await page.route(DEFAULT_WELLKNOWN_PATTERN, async (route) => { + const response = await route.fetch(); + const json = await response.json(); + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ + ...json, + pushed_authorization_request_endpoint: SYNTHETIC_PAR_ERROR_URL, + }), + }); + }); + + // Intercept the synthetic PAR endpoint and return a 400 error + await page.route(SYNTHETIC_PAR_ERROR_URL, (route) => { + route.fulfill({ + status: 400, + contentType: 'application/json', + body: JSON.stringify({ + error: 'invalid_request', + error_description: 'Missing required PAR parameter', + }), + }); + }); + + await navigate('/par/'); + + // Clicking redirect login triggers PAR → receives 400 → SDK should surface an error + await page.getByRole('button', { name: 'Login (Redirect' }).click(); + + // The SDK should surface an error in the UI instead of redirecting away + await expect(page.locator('.error')).toBeVisible({ timeout: 10000 }); + await expect(page.locator('.error')).toContainText('PAR_ERROR'); + }); + test('background login with PAR enabled (ParClient) obtains access token', async ({ page }) => { const { navigate } = asyncEvents(page); diff --git a/packages/oidc-client/src/lib/authorize.request.micros.test.ts b/packages/oidc-client/src/lib/authorize.request.micros.test.ts index 773515efc2..626c31aaa8 100644 --- a/packages/oidc-client/src/lib/authorize.request.micros.test.ts +++ b/packages/oidc-client/src/lib/authorize.request.micros.test.ts @@ -408,3 +408,24 @@ it.effect('dispatchAuthorizeIframe fails with unknown_error when data is undefin expect(exit.cause.error.type).toBe('unknown_error'); }), ); + +it.effect('dispatchAuthorizeIframe fails with unknown_error when data has no code or state', () => + Micro.gen(function* () { + vi.mocked(mockStore.dispatch).mockResolvedValueOnce({ + data: { unexpected: 'shape' }, + } as unknown as ReturnType); + + const exit = yield* Micro.exit( + dispatchAuthorizeIframe( + mockStore, + 'https://example.com/authorize?foo=bar', + wellknown, + {} as import('@forgerock/sdk-types').GetAuthorizationUrlOptions, + ), + ); + expect(Micro.exitIsFailure(exit)).toBe(true); + if (!Micro.exitIsFailure(exit) || !Micro.causeIsFail(exit.cause)) return; + expect(exit.cause.error.type).toBe('unknown_error'); + expect(exit.cause.error.error).toBe('Unknown_Error'); + }), +); diff --git a/packages/oidc-client/src/lib/authorize.request.micros.ts b/packages/oidc-client/src/lib/authorize.request.micros.ts index 4380eb4893..c269298e49 100644 --- a/packages/oidc-client/src/lib/authorize.request.micros.ts +++ b/packages/oidc-client/src/lib/authorize.request.micros.ts @@ -100,10 +100,13 @@ export const dispatchAuthorizeIframe = ( }).pipe( Micro.flatMap(({ error, data }) => { if (error) return handleDispatchError(error, wellknown, options); - if (data !== undefined) return Micro.succeed(data); + const d = data as { code?: unknown; state?: unknown } | undefined; + if (d !== undefined && typeof d.code === 'string' && typeof d.state === 'string') { + return Micro.succeed(d as AuthorizationSuccess); + } return Micro.fail({ error: 'Unknown_Error', - error_description: 'Response data was empty', + error_description: 'Response data did not contain expected code and state fields', type: 'unknown_error', } as const); }), diff --git a/packages/oidc-client/src/lib/authorize.request.ts b/packages/oidc-client/src/lib/authorize.request.ts index 303f566b72..e7b177a102 100644 --- a/packages/oidc-client/src/lib/authorize.request.ts +++ b/packages/oidc-client/src/lib/authorize.request.ts @@ -70,6 +70,7 @@ function dispatchAuthorizeµ( export function parAuthorizeµ( wellknown: WellknownResponse, config: OidcConfig, + log: CustomLogger, store: ClientStore, options?: OptionalAuthorizeOptions, ): Micro.Micro { @@ -96,7 +97,14 @@ export function parAuthorizeµ( prompt, ); const parResult = yield* dispatchParRequest(store, parEndpoint, body); - const { request_uri } = yield* validateParResponse(parResult); + const { request_uri, expires_in } = yield* validateParResponse(parResult); + if (expires_in < 30) { + yield* Micro.sync(() => + log.warn( + `PAR request_uri expires in ${expires_in}s — authorize must complete before expiry`, + ), + ); + } yield* storeAuthOptions(storeOptions); return yield* buildParSlimUrl( wellknown.authorization_endpoint, @@ -120,7 +128,7 @@ export function authorizeµ( log: CustomLogger, store: ClientStore, options?: GetAuthorizationUrlOptions, - useParFlow = config.par ?? wellknown.require_pushed_authorization_requests === true, + useParFlow = config.par ?? wellknown?.require_pushed_authorization_requests === true, ): Micro.Micro { const parDispatchOptions: GetAuthorizationUrlOptions = { clientId: config.clientId, @@ -130,14 +138,17 @@ export function authorizeµ( ...options, }; - const parFlow = parAuthorizeµ(wellknown, config, store, options).pipe( + const parFlow = parAuthorizeµ(wellknown, config, log, store, options).pipe( Micro.tap((url) => log.debug('PAR authorize URL created', url)), Micro.tapError((err) => Micro.sync(() => log.error(`PAR authorize failed [${err.type}]: ${err.error}`, err)), ), - Micro.flatMap((url) => dispatchAuthorizeµ(url, parDispatchOptions, wellknown, store, log)), - Micro.tapError((err) => - Micro.sync(() => log.error('Error dispatching PAR authorize request', err)), + Micro.flatMap((url) => + dispatchAuthorizeµ(url, parDispatchOptions, wellknown, store, log).pipe( + Micro.tapError((err) => + Micro.sync(() => log.error('Error dispatching PAR authorize request', err)), + ), + ), ), ); diff --git a/packages/oidc-client/src/lib/authorize.request.utils.test.ts b/packages/oidc-client/src/lib/authorize.request.utils.test.ts index b6eac42f6e..60c098207e 100644 --- a/packages/oidc-client/src/lib/authorize.request.utils.test.ts +++ b/packages/oidc-client/src/lib/authorize.request.utils.test.ts @@ -55,6 +55,13 @@ const mockStore = { dispatch: vi.fn(), } as unknown as ClientStore; +const mockLog = { + debug: vi.fn(), + error: vi.fn(), + info: vi.fn(), + warn: vi.fn(), +} as unknown as import('@forgerock/sdk-logger').CustomLogger; + const sessionStorageStub = { getItem: vi.fn(), setItem: vi.fn(), removeItem: vi.fn() }; afterEach(() => { @@ -126,7 +133,7 @@ it('toDispatchError delegates to toAuthorizationError for FetchBaseQueryError', it.effect('parAuthorizeµ fails with wellknown_error when par endpoint is missing', () => Micro.gen(function* () { const configWithPar: OidcConfig = { ...config, par: true }; - const result = yield* Micro.exit(parAuthorizeµ(wellknown, configWithPar, mockStore)); + const result = yield* Micro.exit(parAuthorizeµ(wellknown, configWithPar, mockLog, mockStore)); expect(Micro.exitIsFailure(result)).toBe(true); if (!Micro.exitIsFailure(result)) return; expect(Micro.causeIsFail(result.cause)).toBe(true); @@ -149,7 +156,7 @@ it.effect('parAuthorizeµ succeeds and returns slim authorize URL', () => data: { request_uri: requestUri, expires_in: 60 }, } as unknown as ReturnType); - const url = yield* parAuthorizeµ(wellknownWithPar, configWithPar, mockStore); + const url = yield* parAuthorizeµ(wellknownWithPar, configWithPar, mockLog, mockStore); expect(url).toContain('client_id=123456789'); expect(url).toContain(`request_uri=${encodeURIComponent(requestUri)}`); @@ -172,7 +179,9 @@ it.effect('parAuthorizeµ fails with network_error when PAR POST returns error', }, } as unknown as ReturnType); - const result = yield* Micro.exit(parAuthorizeµ(wellknownWithPar, configWithPar, mockStore)); + const result = yield* Micro.exit( + parAuthorizeµ(wellknownWithPar, configWithPar, mockLog, mockStore), + ); expect(Micro.exitIsFailure(result)).toBe(true); if (!Micro.exitIsFailure(result)) return; @@ -193,7 +202,9 @@ it.effect('parAuthorizeµ fails with network_error when PAR response is missing data: {}, } as unknown as ReturnType); - const result = yield* Micro.exit(parAuthorizeµ(wellknownWithPar, configWithPar, mockStore)); + const result = yield* Micro.exit( + parAuthorizeµ(wellknownWithPar, configWithPar, mockLog, mockStore), + ); expect(Micro.exitIsFailure(result)).toBe(true); if (!Micro.exitIsFailure(result)) return; @@ -223,7 +234,7 @@ it.effect( data: { request_uri: requestUri, expires_in: 60 }, } as unknown as ReturnType); - const url = yield* parAuthorizeµ(wellknownWithPar, configWithPar, mockStore, { + const url = yield* parAuthorizeµ(wellknownWithPar, configWithPar, mockLog, mockStore, { prompt: 'none', }); @@ -261,6 +272,21 @@ it('hasPushRequestUri returns false when request_uri is missing', () => { expect(hasPushRequestUri('string')).toBe(false); }); +// ─── validateParResponse ───────────────────────────────────────────────────── + +import { validateParResponse } from './authorize.request.utils.js'; + +it.effect('validateParResponse with SerializedError preserves error message', () => + Micro.gen(function* () { + const serializedError = { name: 'Error', message: 'network timeout', code: 'FETCH_ERROR' }; + const exit = yield* Micro.exit(validateParResponse({ error: serializedError })); + expect(Micro.exitIsFailure(exit)).toBe(true); + if (!Micro.exitIsFailure(exit) || !Micro.causeIsFail(exit.cause)) return; + // Should surface the actual message, not generic "Unknown_Error" + expect(exit.cause.error.error_description).toContain('network timeout'); + }), +); + // ─── buildParAuthorizeUrl ──────────────────────────────────────────────────── it('buildParAuthorizeUrl produces slim URL with client_id and request_uri', () => { @@ -340,13 +366,6 @@ it('buildAuthorizeOptions falls back to "openid" scope and "code" responseType w // ─── authorizeµ flow routing ────────────────────────────────────────────────── -const mockLog = { - debug: vi.fn(), - error: vi.fn(), - info: vi.fn(), - warn: vi.fn(), -} as unknown as import('@forgerock/sdk-logger').CustomLogger; - it.effect('authorizeµ uses PAR flow when useParFlow=true', () => Micro.gen(function* () { const requestUri = 'urn:ietf:params:oauth:request_uri:par-routing-test'; diff --git a/packages/oidc-client/src/lib/authorize.request.utils.ts b/packages/oidc-client/src/lib/authorize.request.utils.ts index d8b4829540..3eca94a686 100644 --- a/packages/oidc-client/src/lib/authorize.request.utils.ts +++ b/packages/oidc-client/src/lib/authorize.request.utils.ts @@ -200,11 +200,9 @@ export const buildAuthorizeRedirectUrl = ( export const validateParResponse = (result: { error?: FetchBaseQueryError | SerializedError; data?: unknown; -}): Micro.Micro<{ request_uri: string }, AuthorizationError, never> => { +}): Micro.Micro<{ request_uri: string; expires_in: number }, AuthorizationError, never> => { if (result.error) { - return Micro.fail( - toAuthorizationError(isFetchBaseQueryError(result.error) ? result.error.data : undefined), - ); + return Micro.fail(toDispatchError(result.error)); } if (!hasPushRequestUri(result.data)) { return Micro.fail({ @@ -213,7 +211,8 @@ export const validateParResponse = (result: { type: 'network_error', } as const); } - return Micro.succeed(result.data); + const d = result.data as { request_uri: string; expires_in?: number }; + return Micro.succeed({ request_uri: d.request_uri, expires_in: d.expires_in ?? 60 }); }; export const handleDispatchError = ( diff --git a/packages/oidc-client/src/lib/client.store.test.ts b/packages/oidc-client/src/lib/client.store.test.ts index 40ebb64ec4..9ce2c478e8 100644 --- a/packages/oidc-client/src/lib/client.store.test.ts +++ b/packages/oidc-client/src/lib/client.store.test.ts @@ -22,7 +22,6 @@ vi.stubGlobal( return { getItem(key: string) { - console.log('getItem', key); return store[key] || null; }, setItem(key: string) { @@ -43,15 +42,14 @@ const parRequestUri = 'urn:ietf:params:oauth:request_uri:test-par-request-uri'; const server = setupServer( // P1 Revoke - http.post('*/as/authorize', async () => { - console.log('authorize request received'); - return HttpResponse.json({ + http.post('*/as/authorize', async () => + HttpResponse.json({ authorizeResponse: { code: 123, state: 'NzUyNDUyMDAxOTMyNDUxNzI1NjkxNDc2MjEyMzUwMjQzMzQyMjE4OQ', }, - }); - }), + }), + ), http.post('*/as/token', async () => HttpResponse.json({ access_token: 'abcdefghijklmnop', @@ -204,7 +202,6 @@ describe('PingOne token get method', async () => { } const tokens = await oidcClient.token.get({ backgroundRenew: true }); if ('error' in tokens) { - console.log('tokens error', tokens); expect.fail(); } expect(tokens.accessToken).toBe('1234567890'); @@ -229,7 +226,6 @@ describe('PingOne token get method', async () => { } const tokens = await oidcClient.token.get({ backgroundRenew: true }); if ('error' in tokens) { - console.log('tokens error', tokens); expect.fail(); } expect(tokens.accessToken).toBe('abcdefghijklmnop'); @@ -254,7 +250,6 @@ describe('PingOne token get method', async () => { } const tokens = await oidcClient.token.get({ backgroundRenew: true }); if ('error' in tokens) { - console.log('tokens error', tokens); expect.fail(); } expect(tokens.accessToken).toBe('abcdefghijklmnop'); @@ -279,7 +274,6 @@ describe('PingOne token get method', async () => { } const tokens = await oidcClient.token.get({ backgroundRenew: true, forceRenew: true }); if ('error' in tokens) { - console.log('tokens error', tokens); expect.fail(); } expect(tokens.accessToken).toBe('abcdefghijklmnop'); diff --git a/packages/oidc-client/src/lib/client.store.ts b/packages/oidc-client/src/lib/client.store.ts index f86795e8cc..6fc88ddebf 100644 --- a/packages/oidc-client/src/lib/client.store.ts +++ b/packages/oidc-client/src/lib/client.store.ts @@ -132,7 +132,7 @@ export async function oidc({ if (useParFlow) { const result = await Micro.runPromiseExit( - parAuthorizeµ(wellknown, config, store, options).pipe( + parAuthorizeµ(wellknown, config, log, store, options).pipe( Micro.tapError((err) => Micro.sync(() => log.error(`PAR authorize.url() failed [${err.type}]: ${err.error}`, err), @@ -192,7 +192,7 @@ export async function oidc({ } const result = await Micro.runPromiseExit( - await authorizeµ(wellknown, config, log, store, options, useParFlow), + authorizeµ(wellknown, config, log, store, options, useParFlow), ); if (exitIsSuccess(result)) { diff --git a/packages/oidc-client/src/lib/oidc.api.ts b/packages/oidc-client/src/lib/oidc.api.ts index 12f7fa0a95..b9b8743781 100644 --- a/packages/oidc-client/src/lib/oidc.api.ts +++ b/packages/oidc-client/src/lib/oidc.api.ts @@ -114,6 +114,7 @@ export const oidcApi = createApi({ Accept: 'application/json', 'Content-Type': 'application/x-www-form-urlencoded', }, + credentials: 'include', body, }; @@ -210,7 +211,7 @@ export const oidcApi = createApi({ }); if ('error' in response) { - logger.error('Received authorization code', response); + logger.error('Error in authorizeIframe response', response); return { error: { status: 400,