@checktiv/sdk-web 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +180 -77
- package/dist/agents/AGENTS.md +1 -1
- package/dist/agents/manifest.json +1 -1
- package/dist/{api-DyExBfAQ.d.ts → api-CkHzWaTo.d.ts} +9 -0
- package/dist/chunk-2ZXL5RVX.js +10 -0
- package/dist/{chunk-QVDWM4KK.js → chunk-7NIKMJFJ.js} +1 -1
- package/dist/chunk-ACQKQLL2.js +5 -0
- package/dist/{chunk-LTMLIUPC.js → chunk-ZXE45FN5.js} +1 -1
- package/dist/custom-form.d.ts +1 -1
- package/dist/custom-form.js +2 -2
- package/dist/fraud.d.ts +1 -1
- package/dist/fraud.js +2 -2
- package/dist/idv/cross-device.d.ts +1 -1
- package/dist/idv/cross-device.js +3 -3
- package/dist/idv.d.ts +1 -1
- package/dist/idv.js +4 -4
- package/dist/index-Ch6p6GHo.d.ts +35 -0
- package/dist/index.d.ts +7 -9
- package/dist/index.js +5 -10
- package/dist/react.d.ts +5 -24
- package/dist/react.js +7 -6
- package/dist/workspace.d.ts +1 -1
- package/dist/workspace.js +2 -2
- package/package.json +5 -4
- package/dist/chunk-BEZGAQ74.js +0 -8
- package/dist/chunk-ITLSDZHK.js +0 -5
package/README.md
CHANGED
|
@@ -23,6 +23,93 @@ npm install @checktiv/sdk-web
|
|
|
23
23
|
`react` and `react-dom` are **optional peer dependencies**. Install them only if you
|
|
24
24
|
use the `./react` subpath. Everything else works without React.
|
|
25
25
|
|
|
26
|
+
## Quickstart
|
|
27
|
+
|
|
28
|
+
The recommended integration is the zero-lifecycle `mount()`. Your backend mints one
|
|
29
|
+
durable, low-privilege `clientToken` per applicant; the SDK exchanges it for
|
|
30
|
+
short-lived working tokens and refreshes them internally, so you write no
|
|
31
|
+
token-lifecycle code.
|
|
32
|
+
|
|
33
|
+
**Backend** - your server holds the secret key and returns a `clientToken`:
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
import { sessions } from '@checktiv/sdk-web';
|
|
37
|
+
|
|
38
|
+
// POST /kyc/session (your backend)
|
|
39
|
+
const { clientToken } = await sessions.create(
|
|
40
|
+
{ templateId: 'wt_...', applicant: { externalId: user.id } },
|
|
41
|
+
{
|
|
42
|
+
apiBase: 'https://api.us.checktiv.com',
|
|
43
|
+
secretKey: process.env.CHECKTIV_SECRET_KEY, // ah_sk_* - never in the browser
|
|
44
|
+
idempotencyKey: user.id, // retries and new-device re-entry never double-mint
|
|
45
|
+
},
|
|
46
|
+
);
|
|
47
|
+
// Return ONLY the clientToken to the browser.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`sessions.create` throws if it runs in a browser: it needs your secret key, so call
|
|
51
|
+
it only from your server. The `clientToken` it returns can resume the applicant's own
|
|
52
|
+
session; it never reads verification results or applicant data.
|
|
53
|
+
|
|
54
|
+
**Frontend** - mount and forget:
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
import { mount } from '@checktiv/sdk-web';
|
|
58
|
+
import '@checktiv/sdk-web/idv'; // self-registers the managed IDV module
|
|
59
|
+
import '@checktiv/sdk-web/fraud'; // omit if the workflow never declares fraud
|
|
60
|
+
import '@checktiv/sdk-web/capture-ui/style.css'; // REQUIRED: styles the capture surface
|
|
61
|
+
|
|
62
|
+
const handle = mount(document.getElementById('checktiv-container'), {
|
|
63
|
+
publishableKey: 'ah_pk_us_test_...', // safe to expose - origin-pinned, no scopes
|
|
64
|
+
// Called ONCE for the cold start (or a new device), never on every expiry.
|
|
65
|
+
fetchToken: () =>
|
|
66
|
+
fetch('/kyc/session', { method: 'POST' })
|
|
67
|
+
.then((res) => res.json())
|
|
68
|
+
.then((data) => data.clientToken),
|
|
69
|
+
onConsent: () => showConsentPrompt(), // required only if the session declares fraud
|
|
70
|
+
onEvent: (event) => console.log(event),
|
|
71
|
+
onComplete: ({ sessionId }) => {
|
|
72
|
+
// Capture is complete. Wait for the webhook verdict before acting.
|
|
73
|
+
showMessage('Verification submitted. You will hear from us shortly.');
|
|
74
|
+
},
|
|
75
|
+
layout: 'immersive', // optional: full-screen capture on phones
|
|
76
|
+
theme: { primaryColor: '#0b5fff' }, // optional: match your brand
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Later, when navigating away:
|
|
80
|
+
// handle.destroy();
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Key properties of this design:
|
|
84
|
+
|
|
85
|
+
- **No token-refresh code.** `fetchToken` fires once; the SDK mints and refreshes the
|
|
86
|
+
short-lived working token internally, so mid-flow expiry never surfaces to you.
|
|
87
|
+
- **Your secret key never touches client code.** Only `sessions.create` (server-side)
|
|
88
|
+
uses it; the browser holds just the low-privilege `clientToken`.
|
|
89
|
+
- **The server drives composition.** `mount()` renders whatever modules the session
|
|
90
|
+
declares (identity verification, the consent-gated fraud module, custom forms), so
|
|
91
|
+
you change the journey server-side without shipping new client code.
|
|
92
|
+
- **Import `@checktiv/sdk-web/capture-ui/style.css`.** The managed capture surface
|
|
93
|
+
ships its styles as a separate stylesheet; without this import the capture screen
|
|
94
|
+
renders unstyled and collapses to a small box.
|
|
95
|
+
|
|
96
|
+
`onComplete` (and `checktiv.idv.submitted`) means capture finished, not that
|
|
97
|
+
verification passed. The authoritative verdict arrives on your server as a signed
|
|
98
|
+
webhook.
|
|
99
|
+
|
|
100
|
+
### Cross-device handoff
|
|
101
|
+
|
|
102
|
+
The handle returned by `mount()` exposes `openCrossDevice()` so a desktop applicant
|
|
103
|
+
can continue on their phone. Pass a `crossDeviceCopy` map, render your own "Continue
|
|
104
|
+
on your phone" trigger, and call `handle.openCrossDevice()` from it: the SDK mints the
|
|
105
|
+
one-time link, opens the QR overlay, runs the completion poll, and fires `onComplete`
|
|
106
|
+
when the phone finishes. The trigger is desktop only (it warn-no-ops on a touch
|
|
107
|
+
device, where capture runs on the phone directly), so gate your control to a
|
|
108
|
+
fine-pointer device. Pass an optional `onOpenCrossDevice` mint hook to mint the link
|
|
109
|
+
on your own backend instead of the SDK-owned default. Import
|
|
110
|
+
`@checktiv/sdk-web/idv/cross-device` once to enable the overlay (the CDN bundle
|
|
111
|
+
registers it for you). See the developer docs for the full contract.
|
|
112
|
+
|
|
26
113
|
## CDN usage
|
|
27
114
|
|
|
28
115
|
Load the moving pointer for the latest release:
|
|
@@ -46,19 +133,25 @@ release notes, so the exact bytes your page loads are locked and verified:
|
|
|
46
133
|
```
|
|
47
134
|
|
|
48
135
|
Use the region host that matches your account (for example `sdk.us.checktiv.com` or
|
|
49
|
-
`sdk.eu.checktiv.com`). The CDN bundle exposes the same API
|
|
50
|
-
|
|
136
|
+
`sdk.eu.checktiv.com`). The CDN bundle exposes the same API on the `window.Checktiv`
|
|
137
|
+
global and includes every module, so no per-module import is needed.
|
|
51
138
|
|
|
52
|
-
##
|
|
139
|
+
## Alternative: the per-request browser-token path (`init()`)
|
|
140
|
+
|
|
141
|
+
If your integration mints a fresh browser token on every page load instead of holding
|
|
142
|
+
a durable `clientToken`, use `init()` with a `getSessionToken` callback. `init()`
|
|
143
|
+
makes no network call; it sets up the client and the token callback, and
|
|
144
|
+
`mountProvisioned()` renders the server-declared modules.
|
|
53
145
|
|
|
54
146
|
```js
|
|
55
147
|
import { init } from '@checktiv/sdk-web';
|
|
56
|
-
import '@checktiv/sdk-web/idv';
|
|
148
|
+
import '@checktiv/sdk-web/idv';
|
|
149
|
+
import '@checktiv/sdk-web/capture-ui/style.css'; // REQUIRED for the managed capture surface
|
|
57
150
|
|
|
58
151
|
const client = init({
|
|
59
152
|
publishableKey: 'ah_pk_us_test_...',
|
|
60
153
|
getSessionToken: async (ctx) => {
|
|
61
|
-
// Your server
|
|
154
|
+
// Your server mints a short-lived browser token from its secret key.
|
|
62
155
|
const res = await fetch('/api/checktiv/token', {
|
|
63
156
|
method: 'POST',
|
|
64
157
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -66,96 +159,67 @@ const client = init({
|
|
|
66
159
|
});
|
|
67
160
|
return (await res.json()).token;
|
|
68
161
|
},
|
|
162
|
+
theme: { primaryColor: '#0b5fff' }, // optional
|
|
69
163
|
});
|
|
70
164
|
|
|
71
|
-
// Server-driven: renders whatever modules the session declares.
|
|
72
165
|
const handle = client.mountProvisioned({
|
|
73
166
|
target: document.getElementById('checktiv-container'),
|
|
74
167
|
onEvent: (event) => console.log(event),
|
|
75
168
|
});
|
|
76
|
-
|
|
77
|
-
// Later, when navigating away:
|
|
78
|
-
// handle.destroy();
|
|
169
|
+
// handle.destroy() when navigating away.
|
|
79
170
|
```
|
|
80
171
|
|
|
81
|
-
Key properties of this design:
|
|
82
|
-
|
|
83
|
-
- `init()` makes **no network call**. It only sets up the client and the token
|
|
84
|
-
callback.
|
|
85
|
-
- Your **secret key never touches client code**. `getSessionToken` returns a
|
|
86
|
-
short-lived browser token that your server mints; the SDK only ever holds that
|
|
87
|
-
token.
|
|
88
|
-
- **The server drives composition.** `mountProvisioned()` reads the modules the
|
|
89
|
-
session declares and renders each one, so you can change the journey server-side
|
|
90
|
-
without shipping new client code.
|
|
91
|
-
|
|
92
172
|
## Published subpaths
|
|
93
173
|
|
|
94
174
|
Every entry below is part of the published API. Import a module subpath (like
|
|
95
175
|
`./idv`) once anywhere in your app: importing it runs a one-time self-registration
|
|
96
|
-
side effect so `mountProvisioned()`
|
|
97
|
-
session needs a module you did not import, the SDK throws a clear,
|
|
98
|
-
telling you which subpath to add, instead of failing silently.
|
|
99
|
-
|
|
100
|
-
| Subpath | Purpose
|
|
101
|
-
| ------------------------- |
|
|
102
|
-
| `.` / `@checktiv/sdk-web` | Core entry: `
|
|
103
|
-
| `./idv` | Managed identity-verification module. Import for its self-registration side effect so `
|
|
104
|
-
| `./fraud` | Consent-gated fraud-signal collection. Import for its self-registration side effect.
|
|
105
|
-
| `./custom-form` | Custom intake-form module (server-authored field definitions). Import for its self-registration side effect.
|
|
106
|
-
| `./custom-form/style.css` | Stylesheet for the custom-form module. `<link>` or `import` this into the host page.
|
|
107
|
-
| `./
|
|
108
|
-
| `./
|
|
109
|
-
| `./capture
|
|
110
|
-
| `./
|
|
111
|
-
| `./
|
|
112
|
-
| `./
|
|
176
|
+
side effect so `mount()` / `mountProvisioned()` / `mount('idv')` can resolve that
|
|
177
|
+
module. If a session needs a module you did not import, the SDK throws a clear,
|
|
178
|
+
actionable error telling you which subpath to add, instead of failing silently.
|
|
179
|
+
|
|
180
|
+
| Subpath | Purpose |
|
|
181
|
+
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
182
|
+
| `.` / `@checktiv/sdk-web` | Core entry: the zero-lifecycle `mount(target, opts)` + `sessions.create`, plus the `init(opts)` client. Tree-shakeable and lightweight. |
|
|
183
|
+
| `./idv` | Managed identity-verification module. Import for its self-registration side effect so `mount()` / `mount('idv')` resolve it. |
|
|
184
|
+
| `./fraud` | Consent-gated fraud-signal collection. Import for its self-registration side effect. |
|
|
185
|
+
| `./custom-form` | Custom intake-form module (server-authored field definitions). Import for its self-registration side effect. |
|
|
186
|
+
| `./custom-form/style.css` | Stylesheet for the custom-form module. `<link>` or `import` this into the host page. |
|
|
187
|
+
| `./capture-ui/style.css` | Stylesheet for the managed IDV capture surface. Import it (the managed module renders through it) or the capture screen is unstyled. |
|
|
188
|
+
| `./react` | React wrappers: `ChecktivJourney` (zero-lifecycle `mount`), plus `ChecktivProvider` / `useChecktiv()` / `ChecktivIdv` (the `init()` path). |
|
|
189
|
+
| `./capture` | Advanced: headless host-side capture controller (`createCaptureController`). No default UI. |
|
|
190
|
+
| `./capture-ui` | Advanced: batteries-included capture renderer (`mount()`), built on `./capture`. |
|
|
191
|
+
| `./cross-device` | Cross-device QR / copy-link handoff overlay (`mountCrossDevice`). |
|
|
192
|
+
| `./idv/cross-device` | Cross-device wiring for the managed IDV module. |
|
|
193
|
+
| `./agents` | Machine-readable steering manifest (JSON) for coding-agent tooling. |
|
|
113
194
|
|
|
114
195
|
## Managed IDV module (`./idv`)
|
|
115
196
|
|
|
116
197
|
The managed IDV module renders the full identity-verification capture experience for
|
|
117
|
-
you. Import it for its registration side effect, then let
|
|
118
|
-
render it, or mount it explicitly:
|
|
198
|
+
you. Import it for its registration side effect and the capture stylesheet, then let
|
|
199
|
+
the provisioned session render it, or mount it explicitly on an `init()` client:
|
|
119
200
|
|
|
120
201
|
```js
|
|
121
|
-
import { init } from '@checktiv/sdk-web';
|
|
122
202
|
import '@checktiv/sdk-web/idv';
|
|
123
|
-
|
|
124
|
-
const client = init({ publishableKey: 'ah_pk_us_live_...', getSessionToken });
|
|
125
|
-
|
|
126
|
-
const idv = client.mount('idv', {
|
|
127
|
-
target: '#checktiv-container',
|
|
128
|
-
onEvent: (event) => {
|
|
129
|
-
// Events are named `checktiv.idv.*`, for example `checktiv.idv.ready`.
|
|
130
|
-
console.log(event.type);
|
|
131
|
-
},
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
// idv.destroy() when you are done.
|
|
203
|
+
import '@checktiv/sdk-web/capture-ui/style.css';
|
|
135
204
|
```
|
|
136
205
|
|
|
137
|
-
Events are `checktiv.<module>.<name
|
|
138
|
-
types can appear over time, so handle the ones you
|
|
139
|
-
do not write an exhaustive switch that assumes a
|
|
206
|
+
Events are `checktiv.<module>.<name>`, for example `checktiv.idv.ready`. The event
|
|
207
|
+
stream is forward-open: new event types can appear over time, so handle the ones you
|
|
208
|
+
care about and ignore the rest - do not write an exhaustive switch that assumes a
|
|
209
|
+
fixed set.
|
|
140
210
|
|
|
141
211
|
## Fraud module (`./fraud`)
|
|
142
212
|
|
|
143
213
|
Fraud-signal collection is **consent-gated and default-deny**: it collects nothing
|
|
144
|
-
until your `onConsent` callback resolves truthy.
|
|
214
|
+
until your `onConsent` callback resolves truthy. Pass `onConsent` to `mount()` (or to
|
|
215
|
+
`mount('fraud')` on an `init()` client) whenever the session declares the fraud
|
|
216
|
+
module.
|
|
145
217
|
|
|
146
218
|
```js
|
|
147
|
-
import { init } from '@checktiv/sdk-web';
|
|
148
219
|
import '@checktiv/sdk-web/fraud';
|
|
149
220
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const fraud = client.mount('fraud', {
|
|
153
|
-
target: '#checktiv-container',
|
|
154
|
-
onConsent: () => userHasConsented(), // boolean or Promise<boolean>
|
|
155
|
-
onEvent: (event) => console.log(event), // `checktiv.fraud.*`
|
|
156
|
-
});
|
|
157
|
-
|
|
158
|
-
// fraud.destroy() when you are done.
|
|
221
|
+
// With mount(): pass onConsent in the mount options.
|
|
222
|
+
// onConsent: () => userHasConsented(), // boolean or Promise<boolean>
|
|
159
223
|
```
|
|
160
224
|
|
|
161
225
|
## Custom-form module (`./custom-form`)
|
|
@@ -171,19 +235,53 @@ import '@checktiv/sdk-web/custom-form/style.css';
|
|
|
171
235
|
|
|
172
236
|
The module always renders a continue control (even for a content-only screen) so the
|
|
173
237
|
journey can advance, and emits `checktiv.custom_form.submitted` when the applicant
|
|
174
|
-
completes it.
|
|
175
|
-
`customFormCopy` alongside `target`.
|
|
238
|
+
completes it. Pass `customFormConfig` and `customFormCopy` alongside `target`.
|
|
176
239
|
|
|
177
240
|
## React integration (`./react`)
|
|
178
241
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
242
|
+
`react` / `react-dom` are supplied by your app as optional peers, so there is a single
|
|
243
|
+
React instance. Both wrappers are SSR-safe (they render `null` on the server and only
|
|
244
|
+
initialize in the browser). Import the capture stylesheet alongside the modules.
|
|
245
|
+
|
|
246
|
+
### Recommended: `<ChecktivJourney>` (zero-lifecycle)
|
|
247
|
+
|
|
248
|
+
`<ChecktivJourney>` is the React wrapper for `mount()`. It needs no provider or
|
|
249
|
+
context: it manages the mount and teardown lifecycle for you (SSR-safe,
|
|
250
|
+
StrictMode-safe), and forwards every `mount()` option as a prop.
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
import { ChecktivJourney } from '@checktiv/sdk-web/react';
|
|
254
|
+
import '@checktiv/sdk-web/idv';
|
|
255
|
+
import '@checktiv/sdk-web/fraud';
|
|
256
|
+
import '@checktiv/sdk-web/capture-ui/style.css';
|
|
257
|
+
|
|
258
|
+
export function CheckIn() {
|
|
259
|
+
return (
|
|
260
|
+
<ChecktivJourney
|
|
261
|
+
publishableKey="ah_pk_us_test_..."
|
|
262
|
+
fetchToken={() => fetchClientToken()} // returns your durable clientToken
|
|
263
|
+
onConsent={() => showConsent()} // required only if the session declares fraud
|
|
264
|
+
onEvent={(e) => console.log(e)}
|
|
265
|
+
onComplete={({ sessionId }) => showDone(sessionId)}
|
|
266
|
+
layout="immersive" // optional: full-screen capture on phones
|
|
267
|
+
theme={{ primaryColor: '#0b5fff' }} // optional
|
|
268
|
+
/>
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
Pass a `ref` to reach the in-SDK self-service resend (`ref.current.requestResend(email)`).
|
|
274
|
+
|
|
275
|
+
### The `init()` path: `<ChecktivProvider>` + `<ChecktivIdv>`
|
|
276
|
+
|
|
277
|
+
If you use the per-request browser-token flow (`init()` + `getSessionToken`), wrap
|
|
278
|
+
your tree in `<ChecktivProvider>` and render `<ChecktivIdv>`; `useChecktiv()` returns
|
|
279
|
+
the client from context.
|
|
183
280
|
|
|
184
281
|
```tsx
|
|
185
282
|
import { ChecktivProvider, ChecktivIdv } from '@checktiv/sdk-web/react';
|
|
186
|
-
import '@checktiv/sdk-web/idv';
|
|
283
|
+
import '@checktiv/sdk-web/idv';
|
|
284
|
+
import '@checktiv/sdk-web/capture-ui/style.css';
|
|
187
285
|
|
|
188
286
|
export function App() {
|
|
189
287
|
return (
|
|
@@ -197,8 +295,7 @@ export function App() {
|
|
|
197
295
|
}
|
|
198
296
|
```
|
|
199
297
|
|
|
200
|
-
`ChecktivIdv` mounts the managed IDV module and tears it down on unmount.
|
|
201
|
-
hosted developer docs for the full SSR-safe integration pattern.
|
|
298
|
+
`ChecktivIdv` mounts the managed IDV module and tears it down on unmount.
|
|
202
299
|
|
|
203
300
|
## Advanced: host-side capture (`./capture`, `./capture-ui`)
|
|
204
301
|
|
|
@@ -210,7 +307,8 @@ level escape hatches for hosts that need to own the capture surface themselves:
|
|
|
210
307
|
capture controller with no default UI. You inject token and submit functions and
|
|
211
308
|
drive the state machine yourself.
|
|
212
309
|
- `./capture-ui` exports `mount(element, options)`, a batteries-included default
|
|
213
|
-
renderer built on `./capture` that returns a `{ destroy }` handle.
|
|
310
|
+
renderer built on `./capture` that returns a `{ destroy }` handle. Import
|
|
311
|
+
`@checktiv/sdk-web/capture-ui/style.css` for its styles.
|
|
214
312
|
|
|
215
313
|
## Cross-device handoff (`./cross-device`)
|
|
216
314
|
|
|
@@ -234,7 +332,12 @@ migrating an older snippet:
|
|
|
234
332
|
The package ships self-contained type declarations. Import types from the root:
|
|
235
333
|
|
|
236
334
|
```ts
|
|
237
|
-
import type {
|
|
335
|
+
import type {
|
|
336
|
+
ChecktivClient,
|
|
337
|
+
ChecktivEvent,
|
|
338
|
+
ChecktivIdvEvent,
|
|
339
|
+
MountOptions,
|
|
340
|
+
} from '@checktiv/sdk-web';
|
|
238
341
|
```
|
|
239
342
|
|
|
240
343
|
The `ChecktivEvent` union is forward-open, so a handler typed against it keeps
|
package/dist/agents/AGENTS.md
CHANGED
|
@@ -25,7 +25,7 @@ runnable recipes. Read both.
|
|
|
25
25
|
|
|
26
26
|
9. **The SDK adds X-Publishable-Key itself on the customer path.** Pass `publishableKey` to `Checktiv.init(...)` and stop there. On the customer (pk-present) path the managed transport attaches the `X-Publishable-Key` header to its own `bt_*` data-plane calls internally. Do NOT also hand-add an `X-Publishable-Key` header yourself; double-adding it is wrong. (The first-party hosted path used internally by the verify app carries no publishable key and sends none.)
|
|
27
27
|
|
|
28
|
-
10. **Cross-device QR handoff is built into the managed IDV module.** Cross-device handoff (a desktop applicant finishes on their phone via a QR + copy-link overlay) is OWNED BY THE MANAGED IDV MODULE. Render it with `client.mount('idv', { crossDeviceCopy, onEvent })` and the returned handle exposes `openCrossDevice()`: calling it opens the overlay OVER the still-live capture frame, runs the completion poll, and emits `checktiv.idv.submitted` when the phone finishes so your host reloads. You MUST `import '@checktiv/sdk-web/idv/cross-device';` to enable the overlay (the CDN script-tag bundle already includes it); without that import `openCrossDevice()` is a graceful, actionable no-op, as it also is before the applicant verification resolves or when no `crossDeviceCopy` was supplied. `IdvMountOptions` carries `crossDeviceCopy` (host-injected strings; the `unavailableMessage` key is required so no arm renders blank) and the OPTIONAL `onOpenCrossDevice` mint override; `IdvHandle` exposes `openCrossDevice?()`, so call it as `handle.openCrossDevice?.()`.
|
|
28
|
+
10. **Cross-device QR handoff is built into the managed IDV module.** Cross-device handoff (a desktop applicant finishes on their phone via a QR + copy-link overlay) is OWNED BY THE MANAGED IDV MODULE. Render it with `client.mount('idv', { crossDeviceCopy, onEvent })` and the returned handle exposes `openCrossDevice()`: calling it opens the overlay OVER the still-live capture frame, runs the completion poll, and emits `checktiv.idv.submitted` when the phone finishes so your host reloads. You MUST `import '@checktiv/sdk-web/idv/cross-device';` to enable the overlay (the CDN script-tag bundle already includes it); without that import `openCrossDevice()` is a graceful, actionable no-op, as it also is before the applicant verification resolves or when no `crossDeviceCopy` was supplied. `IdvMountOptions` carries `crossDeviceCopy` (host-injected strings; the `unavailableMessage` key is required so no arm renders blank) and the OPTIONAL `onOpenCrossDevice` mint override; `IdvHandle` exposes `openCrossDevice?()`, so call it as `handle.openCrossDevice?.()`. The zero-lifecycle `Checktiv.mount(...)` and its React wrapper `<ChecktivJourney>` ALSO expose `openCrossDevice()` on their handle (reach the React handle via a `ref`), carrying the same `crossDeviceCopy` / optional `onOpenCrossDevice` options; on that path the SDK self-mints the handoff on the working-token plane by default (see below), and the CDN script-tag bundle registers the opener too. The trigger is a DESKTOP affordance: `openCrossDevice()` is a graceful warn-no-op on a coarse-pointer (touch) device, because immersive phone capture and the desktop cross-device overlay are mutually exclusive per device, so gate your trigger to desktop.
|
|
29
29
|
|
|
30
30
|
Who mints the one-time handoff link depends on the token plane:
|
|
31
31
|
• Working-token plane: the module mints the link ITSELF (it calls its own handoff endpoint `POST /sdk/v1/sessions/me/handoff`, authenticated by the applicant's short-lived working token, and caps the per-overlay "refresh link" re-mints). Supply `onOpenCrossDevice` ONLY to point the mint at your own backend instead.
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
{
|
|
75
75
|
"id": "cross-device-handoff-hook",
|
|
76
76
|
"title": "Cross-device QR handoff is built into the managed IDV module",
|
|
77
|
-
"body": "Cross-device handoff (a desktop applicant finishes on their phone via a QR + copy-link overlay) is OWNED BY THE MANAGED IDV MODULE. Render it with `client.mount('idv', { crossDeviceCopy, onEvent })` and the returned handle exposes `openCrossDevice()`: calling it opens the overlay OVER the still-live capture frame, runs the completion poll, and emits `checktiv.idv.submitted` when the phone finishes so your host reloads. You MUST `import '@checktiv/sdk-web/idv/cross-device';` to enable the overlay (the CDN script-tag bundle already includes it); without that import `openCrossDevice()` is a graceful, actionable no-op, as it also is before the applicant verification resolves or when no `crossDeviceCopy` was supplied. `IdvMountOptions` carries `crossDeviceCopy` (host-injected strings; the `unavailableMessage` key is required so no arm renders blank) and the OPTIONAL `onOpenCrossDevice` mint override; `IdvHandle` exposes `openCrossDevice?()`, so call it as `handle.openCrossDevice?.()`.
|
|
77
|
+
"body": "Cross-device handoff (a desktop applicant finishes on their phone via a QR + copy-link overlay) is OWNED BY THE MANAGED IDV MODULE. Render it with `client.mount('idv', { crossDeviceCopy, onEvent })` and the returned handle exposes `openCrossDevice()`: calling it opens the overlay OVER the still-live capture frame, runs the completion poll, and emits `checktiv.idv.submitted` when the phone finishes so your host reloads. You MUST `import '@checktiv/sdk-web/idv/cross-device';` to enable the overlay (the CDN script-tag bundle already includes it); without that import `openCrossDevice()` is a graceful, actionable no-op, as it also is before the applicant verification resolves or when no `crossDeviceCopy` was supplied. `IdvMountOptions` carries `crossDeviceCopy` (host-injected strings; the `unavailableMessage` key is required so no arm renders blank) and the OPTIONAL `onOpenCrossDevice` mint override; `IdvHandle` exposes `openCrossDevice?()`, so call it as `handle.openCrossDevice?.()`. The zero-lifecycle `Checktiv.mount(...)` and its React wrapper `<ChecktivJourney>` ALSO expose `openCrossDevice()` on their handle (reach the React handle via a `ref`), carrying the same `crossDeviceCopy` / optional `onOpenCrossDevice` options; on that path the SDK self-mints the handoff on the working-token plane by default (see below), and the CDN script-tag bundle registers the opener too. The trigger is a DESKTOP affordance: `openCrossDevice()` is a graceful warn-no-op on a coarse-pointer (touch) device, because immersive phone capture and the desktop cross-device overlay are mutually exclusive per device, so gate your trigger to desktop.\n\nWho mints the one-time handoff link depends on the token plane:\n • Working-token plane: the module mints the link ITSELF (it calls its own handoff endpoint `POST /sdk/v1/sessions/me/handoff`, authenticated by the applicant's short-lived working token, and caps the per-overlay \"refresh link\" re-mints). Supply `onOpenCrossDevice` ONLY to point the mint at your own backend instead.\n • Browser-token (`bt_*`) plane: the SDK CANNOT self-mint (the handoff route rejects a `bt_*` bearer), so you MUST supply `onOpenCrossDevice` backed by a server-held credential.\n\n`onOpenCrossDevice: CrossDeviceHandoffHook` is `() => Promise<{ kind: 'ok'; url: string } | { kind: 'unavailable' }>`. Return `{ kind: 'ok', url }` with the journey URL (which MUST be `https:`: the SDK collapses `javascript:`, `http:`, and `data:` schemes to `'unavailable'`) or `{ kind: 'unavailable' }` when the mint fails. The hook is re-callable for the overlay's \"refresh link\" affordance; the SDK caps re-mints per overlay.\n\nFor a FULLY CUSTOM IDV renderer built on `@checktiv/sdk-web/capture` (NOT the managed module), the STANDALONE exports drive the overlay yourself and you always supply the mint hook: `@checktiv/sdk-web/idv/cross-device` (`openCrossDeviceOverlay(opts)` opens the overlay, `preloadCrossDeviceChunk()` warms the lazy chunk) and `@checktiv/sdk-web/cross-device` (`mountCrossDevice(target, props)` renders the bare panel on a screen you fully control). `openCrossDeviceOverlay` takes `{ target, onOpenCrossDevice, copy, isMobile, emit, onClose }` plus an optional `poll` config, and returns a handle with `setCompleting()` (keep the QR mounted with a waiting label while your page reloads) and `destroy()` (idempotent). Set `isMobile: true` to suppress the QR on a phone (a same-device scan is circular). The SDK NEVER writes `window.location`; navigation is always the host's, off the emitted event.\n\nThree token-free overlay events (NONE carries the url / OTL / short-code / expiry hint):\n • `checktiv.idv.cross_device_opened`: the mint returned `ok` and the overlay is shown.\n • `checktiv.idv.cross_device_unavailable`: the mint returned `unavailable` or URL validation failed.\n • `checktiv.idv.cross_device_capped`: the completion poll hit its total time cap without the phone finishing. NOT an error and NOT a verdict: the QR panel stays mounted so the applicant can still finish on their phone."
|
|
78
78
|
}
|
|
79
79
|
],
|
|
80
80
|
"recipes": [
|
|
@@ -133,6 +133,7 @@ declare function createCustomForm(ctx: SubstrateContext, opts: CustomFormMountOp
|
|
|
133
133
|
|
|
134
134
|
interface ProvisionedHandle {
|
|
135
135
|
destroy(): void;
|
|
136
|
+
openCrossDevice?(): void;
|
|
136
137
|
}
|
|
137
138
|
interface MountProvisionedOptions {
|
|
138
139
|
target: HTMLElement | string;
|
|
@@ -146,6 +147,8 @@ interface MountProvisionedOptions {
|
|
|
146
147
|
synthetic?: IdvMountOptions['synthetic'];
|
|
147
148
|
customFormConfig?: CustomFormApplicantConfig;
|
|
148
149
|
customFormCopy?: CustomFormCopy;
|
|
150
|
+
crossDeviceCopy?: CrossDeviceCopy;
|
|
151
|
+
onOpenCrossDevice?: CrossDeviceHandoffHook;
|
|
149
152
|
}
|
|
150
153
|
|
|
151
154
|
interface GetSessionTokenContext {
|
|
@@ -270,6 +273,12 @@ type MountOptions = MountScope & {
|
|
|
270
273
|
readonly fetchImpl?: typeof fetch;
|
|
271
274
|
readonly resumeKey?: string;
|
|
272
275
|
readonly shortCode?: string;
|
|
276
|
+
readonly layout?: CaptureLayout;
|
|
277
|
+
readonly theme?: {
|
|
278
|
+
readonly primaryColor?: string;
|
|
279
|
+
};
|
|
280
|
+
readonly crossDeviceCopy?: CrossDeviceCopy;
|
|
281
|
+
readonly onOpenCrossDevice?: CrossDeviceHandoffHook;
|
|
273
282
|
};
|
|
274
283
|
interface SessionsCreateApplicant {
|
|
275
284
|
readonly externalId?: string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { getModule } from './chunk-GFHNOZVO.js';
|
|
2
|
+
import { assertNever } from './chunk-UBQTPS5J.js';
|
|
3
|
+
import { createTokenManager, resolveSession, warnWrongTokenPlane, createChecktivError } from './chunk-7NIKMJFJ.js';
|
|
4
|
+
import { R, k } from './chunk-XOGHMNBX.js';
|
|
5
|
+
import { resolveApiBaseOrigin, sdkPublicSettings, shortCodeRefreshPath, PUBLISHABLE_KEY_HEADER, SESSIONS_ME_REFRESH_LINK_PATH, WORKING_TOKEN_MINT_PATH } from './chunk-ACQKQLL2.js';
|
|
6
|
+
import { getServiceOrigin } from './chunk-QFA3K5ZV.js';
|
|
7
|
+
|
|
8
|
+
var PUBLISHABLE_KEY_REGEX=/^ah_pk_(us|eu)_(live|test)_[A-Za-z0-9_-]{8,}$/;var InvalidPublishableKeyError=class extends Error{constructor(message){super(message);this.name="InvalidPublishableKeyError";}};function parsePublishableKey(key){const match=PUBLISHABLE_KEY_REGEX.exec(key);if(!match){throw new InvalidPublishableKeyError(`Invalid publishable key format. Expected ah_pk_<us|eu>_<live|test>_<token>, got: ${maskKey(key)}`)}const region=match[1];const mode=match[2];if(region!=="us"&®ion!=="eu"){throw new InvalidPublishableKeyError(`Invalid region in publishable key: ${maskKey(key)}`)}if(mode!=="test"&&mode!=="live"){throw new InvalidPublishableKeyError(`Invalid mode in publishable key: ${maskKey(key)}`)}return {region,mode}}function maskKey(key){if(key.length<=8)return "***";return `${key.slice(0,6)}...${key.slice(-2)}`}var HOST_TAG="checktiv-root";var MOUNTED_FLAG="__checktivMounted";var LEGACY_HOST_ATTR="data-autohost-kyc-host";var HOST_ATTR="data-checktiv-host";var shadowCache=new WeakMap;function mountShadowHost(target){const existing=findExistingHost(target);if(existing){const cached=shadowCache.get(existing);if(cached)return cached}const host=document.createElement("div");host.setAttribute(HOST_ATTR,HOST_TAG);host.setAttribute(LEGACY_HOST_ATTR,HOST_TAG);host[MOUNTED_FLAG]=true;target.appendChild(host);const shadow=host.attachShadow({mode:"closed"});shadowCache.set(host,shadow);return shadow}function findExistingHost(target){for(const child of Array.from(target.children)){if(!(child instanceof HTMLElement))continue;const candidate=child;if(candidate[MOUNTED_FLAG]===true)return candidate}return null}function moduleErrorEvent(name,error){switch(name){case "idv":return {type:"checktiv.idv.error",error};case "fraud":return {type:"checktiv.fraud.error",error};case "custom_form":return {type:"checktiv.custom_form.error",error}}}function missingModuleMessage(name){return `This session requires the '${name}' module. Import '@checktiv/sdk-web/${name}' in your app.`}function missingModuleError(name){const base=createChecktivError("sdk_load_failed");return moduleErrorEvent(name,{...base,message:missingModuleMessage(name)})}function consentGateRequiredError(){const base=createChecktivError("sdk_load_failed");return moduleErrorEvent("fraud",{...base,message:"This session includes the 'fraud' module, which needs a consent gate. Pass onConsent to mountProvisioned() to enable it."})}function customFormConfigRequiredError(){const base=createChecktivError("sdk_load_failed");return moduleErrorEvent("custom_form",{...base,message:"This session includes the 'custom_form' module, which needs its form config. Pass customFormConfig to mountProvisioned() to enable it."})}function unmappedStepTypeError(stepType){const base=createChecktivError("sdk_load_failed");return moduleErrorEvent("idv",{...base,message:`This session's current step ('${stepType}') has no matching visual module in this SDK build. Upgrade '@checktiv/sdk-web' to a version that renders this step.`})}var MODULE_IS_VISUAL={idv:true,fraud:false,custom_form:true};var STEP_TYPE_TO_VISUAL_MODULE={id_verification:"idv",custom_form:"custom_form"};var stepTypeToVisualModuleView=STEP_TYPE_TO_VISUAL_MODULE;function resolveCurrentStepVisualModule(stepType){return stepTypeToVisualModuleView[stepType]}function defaultLoadModule(name){if(name==="idv"){const factory2=getModule("idv");if(factory2===void 0)return Promise.resolve(null);return Promise.resolve({mount:(ctx,opts)=>factory2(ctx,{target:opts.target,onEvent:opts.onEvent,copy:opts.copy,layout:opts.layout,onBeforeSubmit:opts.onBeforeSubmit,onBehaviorSegment:opts.onBehaviorSegment,synthetic:opts.synthetic,crossDeviceCopy:opts.crossDeviceCopy,onOpenCrossDevice:opts.onOpenCrossDevice})})}if(name==="custom_form"){const factory2=getModule("custom_form");if(factory2===void 0)return Promise.resolve(null);return Promise.resolve({mount:(ctx,opts)=>{if(opts.customFormConfig===void 0){opts.onEvent?.(customFormConfigRequiredError());return {destroy:()=>void 0}}return factory2(ctx,{target:opts.target,config:opts.customFormConfig,copy:opts.customFormCopy,onEvent:opts.onEvent,session:opts.session})}})}const factory=getModule("fraud");if(factory===void 0)return Promise.resolve(null);return Promise.resolve({mount:(ctx,opts)=>{const onConsent=opts.onConsent;if(onConsent===void 0){opts.onEvent?.(consentGateRequiredError());return {destroy:()=>void 0}}return factory(ctx,{onConsent,onEvent:opts.onEvent})}})}function moduleErrorFor(name,code){return moduleErrorEvent(name,createChecktivError(code))}function createMountProvisioned(ctx,opts,deps={}){const emit=e=>opts.onEvent?.(e);const fetchImpl=opts.fetchImpl??fetch;const resolveSession2=deps.resolveSession??(()=>resolveSession(ctx,fetchImpl));const loadModule=deps.loadModule??defaultLoadModule;const handles=[];let destroyed=false;let idvOpenCrossDevice=null;void(async()=>{try{await composeModules();}catch(err){if(destroyed)return;console.warn("[Checktiv] mountProvisioned composition failed.",err);emit(moduleErrorFor("idv","sdk_load_failed"));}})();async function composeModules(){const resolution=await resolveSession2();if(destroyed)return;let session;switch(resolution.kind){case "ok":session=resolution.session;break;case "wrong_token":warnWrongTokenPlane();emit(moduleErrorFor("idv","wrong_token_type"));return;case "unresolved":emit(moduleErrorFor("idv","session_expired"));return;default:return assertNever(resolution)}const currentStepVisualModule=resolveCurrentStepVisualModule(session.stepType);if(currentStepVisualModule===void 0&&session.modules.some(m=>MODULE_IS_VISUAL[m])){emit(unmappedStepTypeError(session.stepType));return}for(const name of session.modules){if(destroyed)return;if(MODULE_IS_VISUAL[name]&&name!==currentStepVisualModule){continue}if(name==="fraud"&&opts.onConsent===void 0){emit(consentGateRequiredError());continue}const mod=await loadModule(name);if(destroyed)return;if(mod===null){emit(missingModuleError(name));continue}let moduleTarget;let containerToRemove=null;if(MODULE_IS_VISUAL[name]){const resolvedParent=typeof opts.target==="string"?typeof document!=="undefined"?document.querySelector(opts.target):null:opts.target;if(resolvedParent!==null){const container=document.createElement("div");resolvedParent.appendChild(container);containerToRemove=container;moduleTarget=container;}else {moduleTarget=opts.target;}}else {moduleTarget=opts.target;}let innerHandle;try{innerHandle=mod.mount(ctx,{target:moduleTarget,onEvent:opts.onEvent,onConsent:opts.onConsent,copy:opts.copy,layout:opts.layout,onBeforeSubmit:opts.onBeforeSubmit,onBehaviorSegment:opts.onBehaviorSegment,synthetic:opts.synthetic,crossDeviceCopy:opts.crossDeviceCopy,onOpenCrossDevice:opts.onOpenCrossDevice,customFormConfig:opts.customFormConfig,customFormCopy:opts.customFormCopy,session:{sessionId:session.sessionId,stepId:session.stepId}});}catch(err){containerToRemove?.remove();throw err}if(name==="idv"){idvOpenCrossDevice=innerHandle.openCrossDevice??null;}const capturedContainer=containerToRemove;const handle={destroy(){try{innerHandle.destroy();}finally{capturedContainer?.remove();}}};if(destroyed){handle.destroy();return}handles.push(handle);}}return {destroy(){destroyed=true;while(handles.length>0){const handle=handles.pop();handle?.destroy();}},openCrossDevice(){idvOpenCrossDevice?.();}}}function init(opts,deps={}){const scope="publishableKey"in opts?{...parsePublishableKey(opts.publishableKey),publishableKey:opts.publishableKey}:{region:opts.region,mode:opts.mode,publishableKey:void 0};let sessionId="";const apiBaseOrigin=resolveApiBaseOrigin(opts.apiBase,scope.region,scope.mode);const ctx={region:scope.region,mode:scope.mode,publishableKey:scope.publishableKey,apiBaseOrigin,theme:opts.theme,locale:opts.locale??"en",betas:opts.betas??[],...opts.selfiePromptMap!==void 0?{selfiePromptMap:opts.selfiePromptMap}:{},...opts.selfieChromeCopy!==void 0?{selfieChromeCopy:opts.selfieChromeCopy}:{},tokens:deps.tokens??createTokenManager(opts.getSessionToken,()=>sessionId),getSessionId:()=>sessionId,setSessionId:id=>{sessionId=id;}};function mount2(...args){if(args[0]==="idv"){const factory2=getModule("idv");if(factory2===void 0)return missingIdvHandle(args[1]);return factory2(ctx,args[1])}if(args[0]==="custom_form"){const factory2=getModule("custom_form");if(factory2===void 0)return missingCustomFormHandle(args[1]);return factory2(ctx,args[1])}const factory=getModule("fraud");if(factory===void 0)return missingFraudHandle(args[1]);return factory(ctx,args[1])}return {mountProvisioned:provOpts=>createMountProvisioned(ctx,provOpts),mount:mount2}}function missingIdvHandle(opts){const base=createChecktivError("sdk_load_failed");opts.onEvent?.({type:"checktiv.idv.error",error:{...base,message:missingModuleMessage("idv")}});return {destroy:()=>void 0,unmount:()=>void 0}}function missingFraudHandle(opts){const base=createChecktivError("sdk_load_failed");opts.onEvent?.({type:"checktiv.fraud.error",error:{...base,message:missingModuleMessage("fraud")}});return {destroy:()=>void 0}}function missingCustomFormHandle(opts){const base=createChecktivError("sdk_load_failed");const error={type:"checktiv.custom_form.error",error:{...base,message:missingModuleMessage("custom_form")}};opts.onEvent?.(error);return {destroy:()=>void 0}}var DEFAULT_REFRESH_MARGIN_MS=6e4;function createWorkingTokenManager(source,deps={}){const now=deps.now??(()=>Date.now());const setTimer=deps.setTimer??((fn,ms)=>setTimeout(fn,ms));const clearTimer=deps.clearTimer??(handle=>clearTimeout(handle));const marginMs=deps.marginMs??DEFAULT_REFRESH_MARGIN_MS;const onProactiveError=deps.onProactiveError;let cached=null;let pending=null;let timer=null;let stopped=false;const clearScheduled=()=>{if(timer!==null){clearTimer(timer);timer=null;}};const scheduleProactive=expiresAt=>{clearScheduled();if(stopped)return;const expiryMs=Date.parse(expiresAt);if(Number.isNaN(expiryMs))return;const delay=expiryMs-now()-marginMs;if(delay<=0)return;timer=setTimer(()=>{timer=null;void doRefresh("expired").catch(err=>onProactiveError?.(err));},delay);};const mintOnce=reason=>source(reason).then(minted=>{scheduleProactive(minted.expiresAt);return minted.token});const doRefresh=reason=>{if(pending!==null)return pending;const p=mintOnce(reason);pending=p;cached=p;void p.then(()=>{if(pending===p)pending=null;},()=>{if(pending===p)pending=null;if(cached===p)cached=null;});return p};return {get(){if(cached!==null)return cached;const p=mintOnce("initial");cached=p;void p.catch(()=>{if(cached===p)cached=null;});return p},refresh(reason){return doRefresh(reason)},stop(){stopped=true;clearScheduled();}}}var RESUME_CLIENT_TOKEN_KEY_PREFIX="checktiv.rct.";function safeLocalStorage(){try{return globalThis.localStorage??null}catch{return null}}function createClientTokenStore(resumeKey,storage=safeLocalStorage()){const key=RESUME_CLIENT_TOKEN_KEY_PREFIX+resumeKey;return {read(){if(storage===null)return null;try{const raw=storage.getItem(key);return raw!==null&&raw.length>0?raw:null}catch{return null}},write(token){if(storage===null)return;try{storage.setItem(key,token);}catch{}},clear(){if(storage===null)return;try{storage.removeItem(key);}catch{}}}}async function requestSelfServiceResend(params){const fetchImpl=params.fetchImpl??fetch;const body=JSON.stringify({confirmEmail:params.confirmEmail});try{let res;if(params.mode==="short_code"){res=await fetchImpl(params.origin+shortCodeRefreshPath(params.shortCode),{method:"POST",headers:{"content-type":"application/json"},body});}return {requested:res.ok}}catch{return {requested:false}}}var version="1.4.0";var initialised=new WeakSet;function resolveVerifyOrigin(parsed){return getServiceOrigin(sdkPublicSettings.apps.verify.subdomain,"prod",parsed.region,sdkPublicSettings)}function buildPopupUrl(parsed,opts){const origin=resolveVerifyOrigin(parsed);if(opts.applicantLinkToken){return `${origin}/start?lt=${encodeURIComponent(opts.applicantLinkToken)}`}return `${origin}/`}function launchPopup(url){const w=460;const h=760;const left=Math.max(0,Math.floor((window.screen.width-w)/2));const top=Math.max(0,Math.floor((window.screen.height-h)/2));const features=`popup=yes,width=${w},height=${h},left=${left},top=${top}`;const popup=window.open(url,"checktiv",features);if(!popup){window.location.href=url;return null}return popup}var COMPLETE_EVENT_TYPE="autohost.kyc.complete";function isCompletionMessage(data){if(typeof data!=="object"||data===null)return false;if(!("type"in data))return false;return data.type===COMPLETE_EVENT_TYPE}function listenForCompletion(expectedOrigin,onComplete){if(!onComplete)return;const handler=event=>{if(event.origin!==expectedOrigin)return;const data=event.data;if(!isCompletionMessage(data))return;onComplete(data);};window.addEventListener("message",handler);}function buildButton(onClick){const children="Start verification";return k("button",{type:"button",onClick,style:'display: inline-flex; align-items: center; justify-content: center; padding: 10px 20px; font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif; font-size: 14px; font-weight: 600; color: #fff; background: #0b5fff; border: none; border-radius: 6px; cursor: pointer;'},children)}function resolveTarget(opts){if(opts.target)return opts.target;return document.querySelector("[data-checktiv]")??document.querySelector("[data-autohost-kyc]")}function mountButton(opts){const parsed=parsePublishableKey(opts.publishableKey);const target=resolveTarget(opts);if(!target){console.warn("[Checktiv] No mount target found. Either pass `target` explicitly or add `<div data-checktiv>` to your page.");return}if(initialised.has(target))return;initialised.add(target);const shadow=mountShadowHost(target);const verifyOrigin=resolveVerifyOrigin(parsed);listenForCompletion(verifyOrigin,opts.onComplete);const onClick=()=>{const popupUrl=buildPopupUrl(parsed,opts);launchPopup(popupUrl);};R(buildButton(onClick),shadow);}function parseWorkingTokenMintResponse(body){if(typeof body!=="object"||body===null)return null;if(!("workingToken"in body)||!("expiresAt"in body))return null;const workingToken=body.workingToken;const expiresAt=body.expiresAt;if(typeof workingToken!=="string"||workingToken.length===0)return null;if(typeof expiresAt!=="string"||expiresAt.length===0)return null;return {workingToken,expiresAt}}async function mintWorkingTokenFacet(origin,clientToken,publishableKey,fetchImpl){const headers={Authorization:`Bearer ${clientToken}`};if(publishableKey!==void 0)headers[PUBLISHABLE_KEY_HEADER]=publishableKey;const res=await fetchImpl(origin+WORKING_TOKEN_MINT_PATH,{method:"POST",headers});if(!res.ok){throw new Error(`Checktiv working-token mint failed (status ${res.status}).`)}let body;try{body=await res.json();}catch{throw new Error("Checktiv working-token mint returned a non-JSON body.")}const parsed=parseWorkingTokenMintResponse(body);if(parsed===null)throw new Error("Checktiv working-token mint returned a malformed body.");return parsed}function completionSessionId(e){if(e.type!=="checktiv.idv.submitted"&&e.type!=="checktiv.custom_form.submitted"){return null}const sid="sessionId"in e?e.sessionId:void 0;return typeof sid==="string"&&sid.length>0?sid:null}function isSessionExpiredEvent(e){if(!e.type.endsWith(".error")||!("error"in e))return false;const err=e.error;if(typeof err!=="object"||err===null||!("code"in err))return false;return err.code==="session_expired"}function mount(target,opts){const fetchImpl=opts.fetchImpl??fetch;const scope="publishableKey"in opts?{...parsePublishableKey(opts.publishableKey),publishableKey:opts.publishableKey}:{region:opts.region,mode:opts.mode,publishableKey:void 0};const mintOrigin=resolveApiBaseOrigin(opts.apiBase,scope.region,scope.mode);const store=opts.resumeKey!==void 0?createClientTokenStore(opts.resumeKey):null;let clientTokenPromise=null;const getClientToken=()=>{if(clientTokenPromise!==null)return clientTokenPromise;const persisted=store?.read()??null;if(persisted!==null){clientTokenPromise=Promise.resolve(persisted);return clientTokenPromise}const p=opts.fetchToken();clientTokenPromise=p;void p.then(tok=>store?.write(tok),()=>{if(clientTokenPromise===p)clientTokenPromise=null;});return p};const mintWorkingToken=async()=>{const clientToken=await getClientToken();const minted=await mintWorkingTokenFacet(mintOrigin,clientToken,scope.publishableKey,fetchImpl);return {token:minted.workingToken,expiresAt:minted.expiresAt}};const tokens=createWorkingTokenManager(mintWorkingToken);const base={getSessionToken:()=>tokens.get(),...opts.apiBase!==void 0?{apiBase:opts.apiBase}:{},...opts.theme!==void 0?{theme:opts.theme}:{}};const initOptions=scope.publishableKey!==void 0?{...base,publishableKey:scope.publishableKey}:{...base,region:scope.region,mode:scope.mode};const needsChannel=opts.onEvent!==void 0||opts.onComplete!==void 0||store!==null;const onEvent=needsChannel?e=>{opts.onEvent?.(e);const sessionId=completionSessionId(e);if(sessionId!==null){store?.clear();opts.onComplete?.({sessionId});}else if(isSessionExpiredEvent(e)){store?.clear();}}:void 0;const client=init(initOptions,{tokens});const handle=client.mountProvisioned({target,fetchImpl,onEvent,onConsent:opts.onConsent,...opts.layout!==void 0?{layout:opts.layout}:{},...opts.crossDeviceCopy!==void 0?{crossDeviceCopy:opts.crossDeviceCopy}:{},...opts.onOpenCrossDevice!==void 0?{onOpenCrossDevice:opts.onOpenCrossDevice}:{}});const requestResend=confirmEmail=>{if(opts.shortCode===void 0)return Promise.resolve({requested:false});return requestSelfServiceResend({mode:"short_code",origin:mintOrigin,shortCode:opts.shortCode,confirmEmail,fetchImpl})};return {destroy(){handle.destroy();tokens.stop();},openCrossDevice:()=>handle.openCrossDevice?.(),requestResend}}function applicantToWire(a){const wire={};if(a.externalId!==void 0)wire.external_id=a.externalId;if(a.email!==void 0)wire.email=a.email;if(a.phone!==void 0)wire.phone=a.phone;if(a.firstName!==void 0)wire.first_name=a.firstName;if(a.lastName!==void 0)wire.last_name=a.lastName;if(a.dateOfBirth!==void 0)wire.date_of_birth=a.dateOfBirth;if(a.referenceName!==void 0)wire.reference_name=a.referenceName;return wire}function readCreatedClientToken(body){if(typeof body!=="object"||body===null||!("data"in body))return null;const data=body.data;if(typeof data!=="object"||data===null||!("client_token"in data))return null;const clientToken=data.client_token;return typeof clientToken==="string"&&clientToken.length>0?clientToken:null}var sessions={async create(input,options){if(typeof window!=="undefined"||typeof document!=="undefined"){throw new Error("checktiv.sessions.create must run on your server: it needs your secret key. Never call it in the browser.")}const fetchImpl=options.fetchImpl??fetch;const headers={Authorization:`Bearer ${options.secretKey}`,"content-type":"application/json"};if(options.idempotencyKey!==void 0)headers["Idempotency-Key"]=options.idempotencyKey;const body=JSON.stringify({workflow_template_id:input.templateId,applicant:applicantToWire(input.applicant)});const res=await fetchImpl(`${options.apiBase}/v1/sessions`,{method:"POST",headers,body});if(!res.ok){throw new Error(`Checktiv sessions.create failed (status ${res.status}). Verify the apiBase origin and secret key.`)}let parsed;try{parsed=await res.json();}catch{throw new Error("Checktiv sessions.create returned a non-JSON response.")}const clientToken=readCreatedClientToken(parsed);if(clientToken===null){throw new Error("Checktiv sessions.create response carried no client token. Enable the working-token capability for this environment, then retry.")}return {clientToken}}};
|
|
9
|
+
|
|
10
|
+
export { InvalidPublishableKeyError, init, mount, mountButton, parsePublishableKey, sessions, version };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IDV_DOCUMENT_TYPES } from './chunk-IQKHRPJR.js';
|
|
2
|
-
import { sdkPublicSettings, SESSIONS_ME_PATH, dataPlaneHeaders } from './chunk-
|
|
2
|
+
import { sdkPublicSettings, SESSIONS_ME_PATH, dataPlaneHeaders } from './chunk-ACQKQLL2.js';
|
|
3
3
|
|
|
4
4
|
function createTokenManager(source,sessionId){const mint=reason=>typeof source==="string"?Promise.resolve(source):source({sessionId:sessionId(),reason});let cached=null;let pending=null;return {get(){if(cached!==null)return cached;const p=mint("initial");cached=p;void p.catch(()=>{if(cached===p)cached=null;});return p},refresh(reason){if(pending!==null)return pending;const p=mint(reason);pending=p;cached=p;void p.then(()=>{if(pending===p)pending=null;},()=>{if(pending===p)pending=null;if(cached===p)cached=null;});return p}}}async function withTokenRetry(tokens,fn,isUnauthorized){const first=await tokens.get();let result;let error;try{result=await fn(first);}catch(err){error=err;}if(error===void 0&&result!==void 0&&!isUnauthorized(result,void 0)){return result}if(error!==void 0&&!isUnauthorized(void 0,error)){throw error}const fresh=await tokens.refresh("401");return fn(fresh)}var SDK_MODULES=["idv","fraud","custom_form"];var BIOMETRIC_MODES=["none","selfie","liveness"];var DOCUMENT_TYPES=IDV_DOCUMENT_TYPES;var SDK_MODES=["live","test"];var DATA_REGIONS=Object.keys(sdkPublicSettings.regions);function isRecord(v){return typeof v==="object"&&v!==null}function isNonEmptyString(v){return typeof v==="string"&&v.length>0}function isSdkModule(v){return typeof v==="string"&&SDK_MODULES.includes(v)}function isBiometricMode(v){return typeof v==="string"&&BIOMETRIC_MODES.includes(v)}function isSdkMode(v){return typeof v==="string"&&SDK_MODES.includes(v)}function isSdkRegion(v){return typeof v==="string"&&DATA_REGIONS.includes(v)}function isDocumentType(v){return typeof v==="string"&&DOCUMENT_TYPES.includes(v)}function parseIdvConfig(value){if(!isRecord(value))return null;const documentTypes=value.document_types;const biometricMode=value.biometric_mode;const minAge=value.min_age;if(!Array.isArray(documentTypes)||documentTypes.length<1)return null;const types=[];for(const t of documentTypes){if(!isDocumentType(t))return null;types.push(t);}if(!isBiometricMode(biometricMode))return null;if(minAge!==void 0&&typeof minAge!=="number")return null;const config={documentTypes:types,biometricMode};if(typeof minAge==="number")config.minAge=minAge;return config}function parseSessionData(body){if(!isRecord(body)||!isRecord(body.data))return null;const d=body.data;const sessionId=d.session_id;const stepId=d.step_id;const stepType=d.step_type;if(!isNonEmptyString(sessionId)||!isNonEmptyString(stepId)||!isNonEmptyString(stepType)||!isSdkMode(d.mode)||!isSdkRegion(d.region)){return null}if(!Array.isArray(d.modules)||!d.modules.every(isSdkModule))return null;const modules=d.modules;const wantsIdv=stepType==="id_verification";let config=null;if(wantsIdv){config=parseIdvConfig(d.config);if(config===null)return null}return {sessionId,stepId,stepType,config,mode:d.mode,region:d.region,modules}}function isJourneyPlaneBody(body){if(!isRecord(body)||!isRecord(body.data))return false;const d=body.data;if("session_id"in d)return false;return isRecord(d.session)||isRecord(d.snapshot)}function warnWrongTokenPlane(){console.warn("[Checktiv] getSessionToken returned a non-browser token. Pass a browser token (bt_*) to getSessionToken, or use Checktiv.mount() with a client token.");}async function resolveSession(ctx,fetchImpl){const origin=ctx.apiBaseOrigin;let res;try{res=await withTokenRetry(ctx.tokens,token=>fetchImpl(origin+SESSIONS_ME_PATH,{method:"GET",headers:dataPlaneHeaders(ctx,token)}),result=>result?.status===401);}catch{return {kind:"unresolved"}}if(!res.ok)return {kind:"unresolved"};let body;try{body=await res.json();}catch{return {kind:"unresolved"}}const data=parseSessionData(body);if(data!==null){ctx.setSessionId(data.sessionId);return {kind:"ok",session:data}}if(isJourneyPlaneBody(body))return {kind:"wrong_token"};return {kind:"unresolved"}}var ERROR_TABLE={origin_not_allowed:{recoverable:false,recovery:"contact_operator",message:"This origin is not allowed for the publishable key. Add it to the allowed origins list in the Checktiv console."},token_expired:{recoverable:true,recovery:"retry",message:"The session token expired. The SDK is refreshing it; if this persists, mint a new token from your backend."},session_expired:{recoverable:false,recovery:"refresh_session",message:"The verification session is no longer valid. Start a new verification from your backend."},wrong_token_type:{recoverable:false,recovery:"contact_operator",message:"This verification could not start. Contact the site operator."},protocol_mismatch:{recoverable:false,recovery:"contact_operator",message:"The SDK version is out of date. Update to the latest published version."},camera_denied:{recoverable:true,recovery:"cross_device",message:"Camera access was blocked. Allow camera access, or continue on another device."},camera_unsupported:{recoverable:true,recovery:"cross_device",message:"Your camera does not meet the minimum resolution needed for capture. Try another device, or continue on your phone."},cv_gate_failed:{recoverable:true,recovery:"retry",message:"We could not read the image clearly. Try again with better lighting and a steady hand."},upload_failed:{recoverable:true,recovery:"retry",message:"The upload did not complete. Check the connection and try again."},sdk_load_failed:{recoverable:true,recovery:"cross_device",message:"Verification could not start on this device. Try again, or continue on another device."},biometric_unsupported:{recoverable:false,recovery:"contact_operator",message:"This capture is not supported on this page. Contact the site operator."},isolation_required:{recoverable:false,recovery:"contact_operator",message:"This page configuration is not supported. Contact the site operator."}};Object.keys(ERROR_TABLE).filter(key=>key in ERROR_TABLE);function createChecktivError(code){const entry=ERROR_TABLE[code];return {code,...entry}}function mapHttpStatusToError(status){if(status===401)return "token_expired";if(status===403)return "origin_not_allowed";if(status===429)return "upload_failed";if(status>=500)return "upload_failed";return "session_expired"}
|
|
5
5
|
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { getServiceOrigin } from './chunk-QFA3K5ZV.js';
|
|
2
|
+
|
|
3
|
+
var sdkPublicSettings={"project":{"marketingApex":"checktiv.com"},"apps":{"verify":{"subdomain":"verify"},"workspace-embed":{"subdomain":"workspace"}},"services":{"sdk-api":{"subdomain":"sdk-api"},"sdk-cdn":{"subdomain":"sdk"}},"regions":{"us":{"apex":"us.checktiv.com"},"eu":{"apex":"eu.checktiv.com"}}};var PUBLISHABLE_KEY_HEADER="X-Publishable-Key";function dataPlaneHeaders(ctx,token,opts={}){const headers={Authorization:`Bearer ${token}`};if(ctx.publishableKey!==void 0){headers[PUBLISHABLE_KEY_HEADER]=ctx.publishableKey;}if(opts.withJsonBody)headers["content-type"]="application/json";return headers}function resolveSdkApiOrigin(region,_mode,_hostname){return getServiceOrigin(sdkPublicSettings.services["sdk-api"].subdomain,"prod",region,sdkPublicSettings)}function isCanonicalOrigin(value){if(typeof value!=="string"||value.length===0)return false;try{return new URL(value).origin===value}catch{return false}}function resolveApiBaseOrigin(apiBase,region,mode,hostname){if(isCanonicalOrigin(apiBase))return apiBase;return resolveSdkApiOrigin(region)}var SESSIONS_ME_PATH="/sdk/v1/sessions/me";var WORKING_TOKEN_MINT_PATH="/sdk/v1/working-token";var CAPTURE_TOKEN_MINT_PATH="/sdk/v1/idv/capture-token";function stepSubmitPath(_sessionId,stepId){return `${SESSIONS_ME_PATH}/steps/${encodeURIComponent(stepId)}/submit`}var TELEMETRY_PATH="/sdk/v1/telemetry";var SESSIONS_ME_REFRESH_LINK_PATH="/sdk/v1/sessions/me/refresh-link";function shortCodeRefreshPath(code){return `/sdk/v1/short-codes/${encodeURIComponent(code)}/refresh`}function formUploadUrlPath(stepId){return `${SESSIONS_ME_PATH}/steps/${encodeURIComponent(stepId)}/form-upload-url`}
|
|
4
|
+
|
|
5
|
+
export { CAPTURE_TOKEN_MINT_PATH, PUBLISHABLE_KEY_HEADER, SESSIONS_ME_PATH, SESSIONS_ME_REFRESH_LINK_PATH, TELEMETRY_PATH, WORKING_TOKEN_MINT_PATH, dataPlaneHeaders, formUploadUrlPath, isCanonicalOrigin, resolveApiBaseOrigin, sdkPublicSettings, shortCodeRefreshPath, stepSubmitPath };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createChecktivError } from './chunk-
|
|
1
|
+
import { createChecktivError } from './chunk-7NIKMJFJ.js';
|
|
2
2
|
|
|
3
3
|
function createChecktivErrorEvent(code){return {type:"checktiv.idv.error",error:createChecktivError(code)}}var CAPTURE_ERROR_CODE={cv_gate_failed:"cv_gate_failed",upload_failed:"upload_failed",sdk_load_failed:"sdk_load_failed",biometric_unsupported:"biometric_unsupported",camera_unsupported:"camera_unsupported",selfie_camera_denied:"camera_denied",liveness_camera_denied:"camera_denied",liveness_runtime_error:"sdk_load_failed",liveness_timeout:"sdk_load_failed",liveness_server_error:"sdk_load_failed",liveness_cancelled:"sdk_load_failed",protocol_mismatch:"protocol_mismatch"};function mapStateToEvent(state,ctx){switch(state.kind){case "minting":case "waiting_for_init":case "submitting":return null;case "ready":return {type:"checktiv.idv.ready",config:ctx.config};case "capturing":if(state.phase==="coaching"&&state.coaching!==null){return {type:"checktiv.idv.coaching",hint:state.coaching}}return {type:"checktiv.idv.phase",phase:state.phase};case "mint_error":return createChecktivErrorEvent("session_expired");case "submit_error":return createChecktivErrorEvent("upload_failed");case "submit_pending":return {type:"checktiv.idv.processing"};case "capture_superseded":return {type:"checktiv.idv.capture_superseded"};case "token_expired":return createChecktivErrorEvent("token_expired");case "capture_error":return createChecktivErrorEvent(CAPTURE_ERROR_CODE[state.errorKind]);default:return null}}var opener=null;function registerCrossDeviceOpener(fn){opener=fn;}function getCrossDeviceOpener(){return opener}
|
|
4
4
|
|
package/dist/custom-form.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { E as ChecktivCustomFormEvent, H as CustomFormCopy, J as CustomFormFieldCopy, K as CustomFormHandle, L as CustomFormMountOptions, N as createCustomForm } from './api-
|
|
1
|
+
export { E as ChecktivCustomFormEvent, H as CustomFormCopy, J as CustomFormFieldCopy, K as CustomFormHandle, L as CustomFormMountOptions, N as createCustomForm } from './api-CkHzWaTo.js';
|
|
2
2
|
import './machine-CuZalPFX.js';
|
|
3
3
|
import './copy-Dfmk11S_.js';
|
|
4
4
|
import './copy-DCeQ4JKx.js';
|
package/dist/custom-form.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { registerModule } from './chunk-GFHNOZVO.js';
|
|
2
2
|
import { assertNever } from './chunk-UBQTPS5J.js';
|
|
3
|
-
import { warnWrongTokenPlane, withTokenRetry, isRecord, isJourneyPlaneBody, createChecktivError, mapHttpStatusToError } from './chunk-
|
|
3
|
+
import { warnWrongTokenPlane, withTokenRetry, isRecord, isJourneyPlaneBody, createChecktivError, mapHttpStatusToError } from './chunk-7NIKMJFJ.js';
|
|
4
4
|
import { u } from './chunk-HV2QKVJX.js';
|
|
5
5
|
import { R, k, S } from './chunk-XOGHMNBX.js';
|
|
6
6
|
import './chunk-IQKHRPJR.js';
|
|
7
|
-
import { SESSIONS_ME_PATH, dataPlaneHeaders, stepSubmitPath, formUploadUrlPath } from './chunk-
|
|
7
|
+
import { SESSIONS_ME_PATH, dataPlaneHeaders, stepSubmitPath, formUploadUrlPath } from './chunk-ACQKQLL2.js';
|
|
8
8
|
import './chunk-QFA3K5ZV.js';
|
|
9
9
|
import './chunk-AIK7CDV6.js';
|
|
10
10
|
|
package/dist/fraud.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { f as ChecktivFraudEvent, F as FraudHandle, i as FraudMountOptions, O as createFraud } from './api-
|
|
1
|
+
export { f as ChecktivFraudEvent, F as FraudHandle, i as FraudMountOptions, O as createFraud } from './api-CkHzWaTo.js';
|
|
2
2
|
import './machine-CuZalPFX.js';
|
|
3
3
|
import './copy-Dfmk11S_.js';
|
|
4
4
|
import './copy-DCeQ4JKx.js';
|
package/dist/fraud.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { registerModule } from './chunk-GFHNOZVO.js';
|
|
2
2
|
import { assertNever } from './chunk-UBQTPS5J.js';
|
|
3
|
-
import { resolveSession, createChecktivError, warnWrongTokenPlane, withTokenRetry } from './chunk-
|
|
3
|
+
import { resolveSession, createChecktivError, warnWrongTokenPlane, withTokenRetry } from './chunk-7NIKMJFJ.js';
|
|
4
4
|
import './chunk-IQKHRPJR.js';
|
|
5
|
-
import { TELEMETRY_PATH, dataPlaneHeaders } from './chunk-
|
|
5
|
+
import { TELEMETRY_PATH, dataPlaneHeaders } from './chunk-ACQKQLL2.js';
|
|
6
6
|
import './chunk-QFA3K5ZV.js';
|
|
7
7
|
import { __publicField } from './chunk-AIK7CDV6.js';
|
|
8
8
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as SubstrateContext, h as CrossDeviceHandoffHook, g as ChecktivIdvEvent } from '../api-
|
|
1
|
+
import { A as SubstrateContext, h as CrossDeviceHandoffHook, g as ChecktivIdvEvent } from '../api-CkHzWaTo.js';
|
|
2
2
|
import { C as CrossDeviceCopy } from '../copy-DCeQ4JKx.js';
|
|
3
3
|
import { CrossDevicePanelProps, CrossDeviceHandle } from '../cross-device.js';
|
|
4
4
|
import '../machine-CuZalPFX.js';
|
package/dist/idv/cross-device.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { registerCrossDeviceOpener, createChecktivErrorEvent } from '../chunk-
|
|
2
|
-
import { withTokenRetry, createChecktivError, parseSessionData } from '../chunk-
|
|
1
|
+
import { registerCrossDeviceOpener, createChecktivErrorEvent } from '../chunk-ZXE45FN5.js';
|
|
2
|
+
import { withTokenRetry, createChecktivError, parseSessionData } from '../chunk-7NIKMJFJ.js';
|
|
3
3
|
import '../chunk-IQKHRPJR.js';
|
|
4
|
-
import { SESSIONS_ME_PATH, dataPlaneHeaders } from '../chunk-
|
|
4
|
+
import { SESSIONS_ME_PATH, dataPlaneHeaders } from '../chunk-ACQKQLL2.js';
|
|
5
5
|
import '../chunk-QFA3K5ZV.js';
|
|
6
6
|
import '../chunk-AIK7CDV6.js';
|
|
7
7
|
|
package/dist/idv.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import './machine-CuZalPFX.js';
|
|
2
2
|
import './copy-Dfmk11S_.js';
|
|
3
|
-
export { h as CrossDeviceHandoffHook, l as IdvHandle, m as IdvMountOptions, B as REMINT_READY_TIMEOUT_MS, D as createIdv } from './api-
|
|
3
|
+
export { h as CrossDeviceHandoffHook, l as IdvHandle, m as IdvMountOptions, B as REMINT_READY_TIMEOUT_MS, D as createIdv } from './api-CkHzWaTo.js';
|
|
4
4
|
import './copy-DCeQ4JKx.js';
|
package/dist/idv.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { createChecktivErrorEvent, mapStateToEvent, getCrossDeviceOpener } from './chunk-
|
|
1
|
+
import { createChecktivErrorEvent, mapStateToEvent, getCrossDeviceOpener } from './chunk-ZXE45FN5.js';
|
|
2
2
|
import { registerModule } from './chunk-GFHNOZVO.js';
|
|
3
3
|
import { assertNever } from './chunk-UBQTPS5J.js';
|
|
4
|
-
import { resolveSession, warnWrongTokenPlane, createChecktivError, withTokenRetry, mapHttpStatusToError } from './chunk-
|
|
4
|
+
import { resolveSession, warnWrongTokenPlane, createChecktivError, withTokenRetry, mapHttpStatusToError } from './chunk-7NIKMJFJ.js';
|
|
5
5
|
import { mount } from './chunk-5MNNRYD5.js';
|
|
6
6
|
import './chunk-HV2QKVJX.js';
|
|
7
7
|
import './chunk-XOGHMNBX.js';
|
|
8
8
|
import './chunk-5AQCMTZV.js';
|
|
9
9
|
import { CURRENT_PROTOCOL_VERSION } from './chunk-6U53T32A.js';
|
|
10
10
|
import './chunk-IQKHRPJR.js';
|
|
11
|
-
import { stepSubmitPath, dataPlaneHeaders, CAPTURE_TOKEN_MINT_PATH, isCanonicalOrigin } from './chunk-
|
|
11
|
+
import { stepSubmitPath, dataPlaneHeaders, CAPTURE_TOKEN_MINT_PATH, isCanonicalOrigin } from './chunk-ACQKQLL2.js';
|
|
12
12
|
import './chunk-QFA3K5ZV.js';
|
|
13
13
|
import './chunk-AIK7CDV6.js';
|
|
14
14
|
|
|
15
|
-
var PLATFORM_BRAND_DEFAULT={primaryColor:"#2563eb",secondaryColor:"#ff5e4d",colorMode:"auto"};var SURFACE={light:{bg:"#fafaf7",surface1:"#ffffff"},dark:{bg:"#0b0c0f",surface1:"#15171c"}};var WHITE="#ffffff";var NEAR_BLACK="#0b0c0f";var ACCENT_TARGET=3;var ADAPT_STEP=.04;var ADAPT_MAX_ITERS=24;var HOVER_DELTA=.08;var SECONDARY_HUE_SHIFT=150;var HEX_RE=/^#[0-9a-fA-F]{6}$/;function toHex(r,g,b){const ch=v=>Math.max(0,Math.min(255,Math.round(v))).toString(16).padStart(2,"0");return `#${ch(r)}${ch(g)}${ch(b)}`}function parseHex(hex){if(typeof hex!=="string"||!HEX_RE.test(hex))return null;const n=Number.parseInt(hex.slice(1),16);return {r:n>>16&255,g:n>>8&255,b:n&255}}function linearize(channel){const s=channel/255;return s<=.03928?s/12.92:Math.pow((s+.055)/1.055,2.4)}function relativeLuminance(rgb){return .2126*linearize(rgb.r)+.7152*linearize(rgb.g)+.0722*linearize(rgb.b)}function assessContrast(fg,bg){const f=parseHex(fg);const b=parseHex(bg);if(!f||!b)return 1;const l1=relativeLuminance(f);const l2=relativeLuminance(b);const hi=Math.max(l1,l2);const lo=Math.min(l1,l2);return (hi+.05)/(lo+.05)}function rgbToHsl({r,g,b}){const rn=r/255;const gn=g/255;const bn=b/255;const max=Math.max(rn,gn,bn);const min=Math.min(rn,gn,bn);const l=(max+min)/2;let h=0;let s=0;if(max!==min){const d=max-min;s=l>.5?d/(2-max-min):d/(max+min);switch(max){case rn:h=(gn-bn)/d+(gn<bn?6:0);break;case gn:h=(bn-rn)/d+2;break;default:h=(rn-gn)/d+4;break}h/=6;}return {h:h*360,s,l}}function hueToRgb(p,q,tRaw){let t=tRaw;if(t<0)t+=1;if(t>1)t-=1;if(t<1/6)return p+(q-p)*6*t;if(t<1/2)return q;if(t<2/3)return p+(q-p)*(2/3-t)*6;return p}function hslToRgb({h,s,l}){const hn=(h%360+360)%360/360;let r;let g;let b;if(s===0){r=g=b=l;}else {const q=l<.5?l*(1+s):l+s-l*s;const p=2*l-q;r=hueToRgb(p,q,hn+1/3);g=hueToRgb(p,q,hn);b=hueToRgb(p,q,hn-1/3);}return {r:Math.round(r*255),g:Math.round(g*255),b:Math.round(b*255)}}function deriveSecondaryHue(hex){const rgb=parseHex(hex);if(!rgb)return PLATFORM_BRAND_DEFAULT.secondaryColor;const hsl=rgbToHsl(rgb);const out=hslToRgb({...hsl,h:(hsl.h+SECONDARY_HUE_SHIFT)%360});return toHex(out.r,out.g,out.b)}function shiftLightness(hex,delta){const rgb=parseHex(hex);if(!rgb)return toHex(0,0,0);const hsl=rgbToHsl(rgb);const out=hslToRgb({...hsl,l:Math.max(0,Math.min(1,hsl.l+delta))});return toHex(out.r,out.g,out.b)}function onColorFor(bg){const white=assessContrast(WHITE,bg);const dark=assessContrast(NEAR_BLACK,bg);return white>=dark?WHITE:NEAR_BLACK}function adaptAccent(hex,surface,target,warnings,field,mode){const rgb=parseHex(hex);if(!rgb){return toHex(0,0,0)}const hsl=rgbToHsl(rgb);const lighten=relativeLuminance(parseHex(surface)??{r:255,g:255,b:255})<.5;const rawRatio=assessContrast(hex,surface);let l=hsl.l;let out=toHex(rgb.r,rgb.g,rgb.b);for(let i=0;i<ADAPT_MAX_ITERS;i+=1){if(assessContrast(out,surface)>=target)break;l=Math.max(0,Math.min(1,l+(lighten?ADAPT_STEP:-ADAPT_STEP)));const o=hslToRgb({h:hsl.h,s:hsl.s,l});out=toHex(o.r,o.g,o.b);}const finalRatio=assessContrast(out,surface);if(rawRatio<target||finalRatio<target){warnings.push({field,mode,ratio:Number(rawRatio.toFixed(2))});}return out}function deriveMode(input,mode,warnings){const surf=SURFACE[mode];const primary=adaptAccent(input.primaryColor,surf.bg,ACCENT_TARGET,warnings,"primary",mode);const rawSecondary=input.secondaryColor??deriveSecondaryHue(input.primaryColor);const secondary=adaptAccent(rawSecondary,surf.bg,ACCENT_TARGET,warnings,"secondary",mode);const primaryHover=shiftLightness(primary,mode==="light"?-HOVER_DELTA:HOVER_DELTA);const onPrimary=onColorFor(primary);const onSecondary=onColorFor(secondary);const ring=primary;return {primary,primaryHover,onPrimary,secondary,onSecondary,ring}}function toSafeBrandColors(input){if(!input||parseHex(input.primaryColor)===null){return {primaryColor:PLATFORM_BRAND_DEFAULT.primaryColor,secondaryColor:PLATFORM_BRAND_DEFAULT.secondaryColor,colorMode:PLATFORM_BRAND_DEFAULT.colorMode}}const secondaryColor=typeof input.secondaryColor==="string"&&parseHex(input.secondaryColor)!==null?input.secondaryColor:null;const colorMode="auto";return {primaryColor:input.primaryColor,secondaryColor,colorMode}}function deriveBrandTokens(input){const safe=toSafeBrandColors(input);const warnings=[];return {light:deriveMode(safe,"light",warnings),dark:deriveMode(safe,"dark",warnings),warnings}}function defaultPrefersDark(){if(typeof window==="undefined"||typeof window.matchMedia!=="function"){return false}try{return window.matchMedia("(prefers-color-scheme: dark)").matches}catch{return false}}function defaultForcedMode(){if(typeof document==="undefined")return null;const dataTheme=document.documentElement.dataset.theme;return dataTheme==="light"||dataTheme==="dark"?dataTheme:null}function brandColorsFrom(primaryColor){return {primaryColor,secondaryColor:PLATFORM_BRAND_DEFAULT.secondaryColor,colorMode:"auto"}}function resolveCaptureTheme(ctxTheme,opts={}){const prefersDark=opts.prefersDark??defaultPrefersDark;const forcedMode=opts.forcedMode??defaultForcedMode;const colorMode=forcedMode()??(prefersDark()?"dark":"light");const primaryColor=ctxTheme?.primaryColor;if(typeof primaryColor!=="string"||primaryColor.length===0){return {colorMode,brandTokens:null}}const brandTokens=deriveBrandTokens(brandColorsFrom(primaryColor))[colorMode];return {colorMode,brandTokens}}var LEASE_STORAGE_KEY_PREFIX="checktiv.idv.lease.";function isRecord(v){return typeof v==="object"&&v!==null}function storageKey(sessionId){return LEASE_STORAGE_KEY_PREFIX+sessionId}function safeLocalStorage(){try{return globalThis.localStorage??null}catch{return null}}function generateHolderDeviceId(){const c=globalThis.crypto;if(c&&typeof c.randomUUID==="function"){return c.randomUUID()}const bytes=new Uint8Array(16);c.getRandomValues(bytes);let hex="";for(const b of bytes)hex+=b.toString(16).padStart(2,"0");return hex}function loadPersistedLease(sessionId){const ls=safeLocalStorage();if(ls===null)return null;let raw;try{raw=ls.getItem(storageKey(sessionId));}catch{return null}if(raw===null)return null;let parsed;try{parsed=JSON.parse(raw);}catch{return null}if(!isRecord(parsed))return null;const{holderDeviceId,leaseGeneration}=parsed;if(typeof holderDeviceId!=="string"||holderDeviceId.length===0)return null;const gen=typeof leaseGeneration==="number"&&Number.isInteger(leaseGeneration)&&leaseGeneration>=0?leaseGeneration:void 0;return gen===void 0?{holderDeviceId}:{holderDeviceId,leaseGeneration:gen}}function persistLease(sessionId,record){const ls=safeLocalStorage();if(ls===null)return;try{ls.setItem(storageKey(sessionId),JSON.stringify(record));}catch{}}function loadOrCreatePersistedLease(sessionId){const persisted=loadPersistedLease(sessionId);if(persisted!==null)return persisted;const record={holderDeviceId:generateHolderDeviceId()};persistLease(sessionId,record);return record}var MAX_REMINTS=3;function isRecord2(v){return typeof v==="object"&&v!==null}function asMode(value){return value==="live"||value==="test"?value:null}function asTestHint(value){return value==="pass"||value==="review"||value==="fail"?value:null}function parseMintBody(body){if(!isRecord2(body)||!isRecord2(body.data))return null;const d=body.data;const captureToken=d.capture_token;const embedOrigin=d.embed_origin;const runIndex=d.run_index;const embedContextToken=d.embed_context_token;if(typeof captureToken!=="string"||captureToken.length===0)return null;if(!isCanonicalOrigin(embedOrigin))return null;if(typeof runIndex!=="number"||!Number.isInteger(runIndex)||runIndex<0)return null;if(typeof embedContextToken!=="string"||embedContextToken.length===0)return null;const mode=asMode(d.mode);const testHint=asTestHint(d.test_hint);return {captureToken,embedOrigin,runIndex,embedContextToken,...mode!==null?{mode}:{},...testHint!==null?{testHint}:{}}}function buildCaptureSubmitBody(input){return {runIndex:input.runIndex,r2Keys:input.r2Keys,holderDeviceId:input.holderDeviceId,...input.leaseGeneration!==void 0?{leaseGeneration:input.leaseGeneration}:{}}}function createIdvTransport(ctx,opts){const fetchImpl=opts.fetchImpl??fetch;const origin=ctx.apiBaseOrigin;let embedContextToken=null;let mintMode;let mintTestHint;let remintCount=0;const persistedLease=loadOrCreatePersistedLease(opts.sessionId);const holderDeviceId=persistedLease.holderDeviceId;const leaseGeneration=persistedLease.leaseGeneration;async function mintToken(){const res=await withTokenRetry(ctx.tokens,token=>fetchImpl(origin+CAPTURE_TOKEN_MINT_PATH,{method:"POST",headers:dataPlaneHeaders(ctx,token,{withJsonBody:true}),body:JSON.stringify({stepId:opts.stepId})}),result=>result?.status===401);if(!res.ok){throw createChecktivError(mapHttpStatusToError(res.status))}let body;try{body=await res.json();}catch{opts.onError?.(createChecktivErrorEvent("sdk_load_failed"));throw createChecktivError("sdk_load_failed")}const parsed=parseMintBody(body);if(parsed===null){opts.onError?.(createChecktivErrorEvent("sdk_load_failed"));throw createChecktivError("sdk_load_failed")}embedContextToken=parsed.embedContextToken;mintMode=parsed.mode;mintTestHint=parsed.testHint;return {captureToken:parsed.captureToken,embedOrigin:parsed.embedOrigin,runIndex:parsed.runIndex}}function getEmbedSrc(embedOrigin){if(embedContextToken===null){opts.onError?.(createChecktivErrorEvent("sdk_load_failed"));throw createChecktivError("sdk_load_failed")}return `${embedOrigin}/idv/capture?ctx=${encodeURIComponent(embedContextToken)}`}async function submit(runIndex,r2Keys){let res;try{res=await withTokenRetry(ctx.tokens,token=>fetchImpl(origin+stepSubmitPath(opts.sessionId,opts.stepId??""),{method:"POST",headers:dataPlaneHeaders(ctx,token,{withJsonBody:true}),body:JSON.stringify(buildCaptureSubmitBody({runIndex,r2Keys,holderDeviceId,leaseGeneration}))}),result=>result?.status===401);}catch{return {ok:false,reason:"failed"}}if(res.ok)return {ok:true};if(res.status===401)return {ok:false,reason:"token_expired"};if(res.status===409)return {ok:false,reason:"capture_superseded"};if(res.status===503&&res.headers.has("Retry-After")){return {ok:false,reason:"signal_pending"}}return {ok:false,reason:"failed"}}function initPayload(){return {config:opts.config(),locale:ctx.locale,theme:resolveCaptureTheme(ctx.theme),protocolVersion:CURRENT_PROTOCOL_VERSION,...mintMode!==void 0?{mode:mintMode}:{},...mintTestHint!==void 0?{testHint:mintTestHint}:{},...ctx.selfiePromptMap!==void 0?{selfiePromptMap:ctx.selfiePromptMap}:{},...ctx.selfieChromeCopy!==void 0?{selfieChromeCopy:ctx.selfieChromeCopy}:{}}}async function remint(){if(remintCount>=MAX_REMINTS){opts.onError?.(createChecktivErrorEvent("session_expired"));return null}remintCount+=1;try{return await mintToken()}catch{return null}}function failProtocolMismatch(){opts.onError?.(createChecktivErrorEvent("protocol_mismatch"));}return {mintToken,submit,getEmbedSrc,initPayload,remint,failProtocolMismatch}}function after(delayMs,fn){return setTimeout(fn,delayMs)}function createSyntheticIdv(opts,config,sessionId,script){const emit=e=>opts.onEvent?.(e);const delayMs=script?.stepDelayMs??0;const timers=[];let destroyed=false;function step(offsetMs,fn){timers.push(after(offsetMs,()=>{if(!destroyed)fn();}));}step(delayMs*0,()=>{emit({type:"checktiv.idv.ready",config});});if(script?.injectError!==void 0){const code=script.injectError;step(delayMs*1,()=>{emit(createChecktivErrorEvent(code));});}else {step(delayMs*1,()=>{emit({type:"checktiv.idv.phase",phase:"document_front"});});step(delayMs*2,()=>{emit({type:"checktiv.idv.submitted",sessionId});});}const destroy=()=>{if(destroyed)return;destroyed=true;for(const id of timers)clearTimeout(id);};return {destroy,unmount:destroy}}function resolveTarget(target){if(typeof target!=="string")return target;if(typeof document==="undefined")return null;return document.querySelector(target)}function toCaptureConfig(config){return {documentTypes:config.documentTypes,biometricMode:config.biometricMode,requireMrzMatch:false,requireExpiryValid:false,requireNameMatch:false,documentAuthenticity:false,...config.minAge!==void 0?{minAge:config.minAge}:{}}}var REMINT_READY_TIMEOUT_MS=15e3;function noopHandle(){return {destroy(){},unmount(){},openCrossDevice(){}}}function isCoarsePointerViewport(){return typeof window!=="undefined"&&typeof window.matchMedia==="function"&&window.matchMedia("(pointer: coarse)").matches}function createIdv(ctx,opts){const element=resolveTarget(opts.target);if(element===null){console.warn('[Checktiv] mount("idv"): no target element found. Pass an element or a selector that resolves.');return noopHandle()}const emit=e=>opts.onEvent?.(e);const fetchImpl=opts.fetchImpl??fetch;let teardown=null;let cancelled=false;let crossDeviceSession=null;let crossDeviceOverlay=null;const closeCrossDevice=()=>{if(crossDeviceOverlay!==null){crossDeviceOverlay.destroy();crossDeviceOverlay=null;}};const openCrossDevice=()=>{if(cancelled)return;if(crossDeviceOverlay!==null)return;const sess=crossDeviceSession;if(sess===null){console.warn('[Checktiv] mount("idv"): openCrossDevice() called before the session resolved.');return}const copy=opts.crossDeviceCopy;if(copy===void 0){console.warn('[Checktiv] mount("idv"): openCrossDevice() requires `crossDeviceCopy` (with `unavailableMessage`).');return}const openOverlay=getCrossDeviceOpener();if(openOverlay===null){console.warn(`[Checktiv] mount("idv"): cross-device is not enabled. Import '@checktiv/sdk-web/idv/cross-device' in your app.`);return}crossDeviceOverlay=openOverlay({ctx,fetchImpl,target:sess.element,stepId:sess.stepId,sessionId:sess.sessionId,copy,isMobile:isCoarsePointerViewport(),onOpenCrossDevice:opts.onOpenCrossDevice,emit,onClose:closeCrossDevice});};void(async()=>{try{await setupCapture(element);}catch(err){if(cancelled)return;console.warn('[Checktiv] mount("idv") setup failed.',err);emit(createChecktivErrorEvent("sdk_load_failed"));}})();async function setupCapture(element2){const resolution=await resolveSession(ctx,fetchImpl);if(cancelled)return;let session;switch(resolution.kind){case "ok":session=resolution.session;break;case "wrong_token":warnWrongTokenPlane();emit(createChecktivErrorEvent("wrong_token_type"));return;case "unresolved":emit(createChecktivErrorEvent("session_expired"));return;default:return assertNever(resolution)}const idvConfig=session.config;if(idvConfig===null){emit(createChecktivErrorEvent("session_expired"));return}const readyConfig={documentTypes:idvConfig.documentTypes,biometricMode:idvConfig.biometricMode};if(ctx.mode==="test"&&opts.synthetic!==void 0){const synthHandle=createSyntheticIdv(opts,readyConfig,session.sessionId,opts.synthetic);teardown=()=>synthHandle.destroy();return}const captureConfig=toCaptureConfig(idvConfig);crossDeviceSession={sessionId:session.sessionId,stepId:session.stepId,element:element2};const transport=createIdvTransport(ctx,{fetchImpl,sessionId:session.sessionId,stepId:session.stepId,config:()=>captureConfig,onError:emit});let pinnedOrigin=null;let everReady=false;const onState=state=>{if(state.kind==="ready"){pinnedOrigin=state.embedOrigin;everReady=true;}if(state.kind==="capture_error"&&state.errorKind==="protocol_mismatch"){transport.failProtocolMismatch();return}const event=mapStateToEvent(state,{config:readyConfig,sessionId:session.sessionId});if(event!==null)emit(event);};const onControllerEvent=event=>{if(event.type==="all-complete"){emit({type:"checktiv.idv.submitted",sessionId:session.sessionId});}};const handle=mount(element2,{mintToken:transport.mintToken,submit:transport.submit,getEmbedSrc:transport.getEmbedSrc,initPayload:transport.initPayload,copy:opts.copy??{},layout:opts.layout,onBeforeSubmit:opts.onBeforeSubmit,onBehaviorSegment:opts.onBehaviorSegment,onState,onControllerEvent});let reminting=false;let awaitingRemintReady=false;let remintReadyTimeoutHandle=null;const clearRemintReadyTimeout=()=>{if(remintReadyTimeoutHandle!==null){clearTimeout(remintReadyTimeoutHandle);remintReadyTimeoutHandle=null;}};const armRemintReadyTimeout=()=>{clearRemintReadyTimeout();remintReadyTimeoutHandle=setTimeout(()=>{remintReadyTimeoutHandle=null;if(!awaitingRemintReady)return;if(cancelled)return;void(async()=>{const minted=await transport.remint();if(cancelled||minted===null){awaitingRemintReady=false;reminting=false;return}if(!awaitingRemintReady){reminting=false;return}const frame=element2.querySelector("iframe.idv-capture-frame");if(frame===null){awaitingRemintReady=false;reminting=false;return}armRemintReadyTimeout();frame.src=transport.getEmbedSrc(minted.embedOrigin);})();},REMINT_READY_TIMEOUT_MS);};const isCaptureReady=data=>typeof data==="object"&&data!==null&&"type"in data&&data.type==="capture:ready";const onReloadMessage=mev=>{if(pinnedOrigin===null||mev.origin!==pinnedOrigin)return;if(!everReady)return;if(!isCaptureReady(mev.data))return;const pinnedFrame=element2.querySelector("iframe.idv-capture-frame");if(pinnedFrame===null)return;if(mev.source!==null&&mev.source!==pinnedFrame.contentWindow)return;if(reminting){if(awaitingRemintReady){clearRemintReadyTimeout();awaitingRemintReady=false;reminting=false;}return}reminting=true;void(async()=>{const minted=await transport.remint();if(cancelled||minted===null){reminting=false;return}const frame=element2.querySelector("iframe.idv-capture-frame");if(frame===null){reminting=false;return}awaitingRemintReady=true;armRemintReadyTimeout();frame.src=transport.getEmbedSrc(minted.embedOrigin);})();};if(typeof window!=="undefined"){window.addEventListener("message",onReloadMessage);}teardown=()=>{clearRemintReadyTimeout();if(typeof window!=="undefined"){window.removeEventListener("message",onReloadMessage);}handle.destroy();};}const destroy=()=>{cancelled=true;closeCrossDevice();if(teardown!==null){teardown();teardown=null;}};return {destroy,unmount:destroy,openCrossDevice}}registerModule("idv",createIdv);
|
|
15
|
+
var PLATFORM_BRAND_DEFAULT={primaryColor:"#2563eb",secondaryColor:"#ff5e4d",colorMode:"auto"};var SURFACE={light:{bg:"#fafaf7",surface1:"#ffffff"},dark:{bg:"#0b0c0f",surface1:"#15171c"}};var WHITE="#ffffff";var NEAR_BLACK="#0b0c0f";var ACCENT_TARGET=3;var ADAPT_STEP=.04;var ADAPT_MAX_ITERS=24;var HOVER_DELTA=.08;var SECONDARY_HUE_SHIFT=150;var HEX_RE=/^#[0-9a-fA-F]{6}$/;function toHex(r,g,b){const ch=v=>Math.max(0,Math.min(255,Math.round(v))).toString(16).padStart(2,"0");return `#${ch(r)}${ch(g)}${ch(b)}`}function parseHex(hex){if(typeof hex!=="string"||!HEX_RE.test(hex))return null;const n=Number.parseInt(hex.slice(1),16);return {r:n>>16&255,g:n>>8&255,b:n&255}}function linearize(channel){const s=channel/255;return s<=.03928?s/12.92:Math.pow((s+.055)/1.055,2.4)}function relativeLuminance(rgb){return .2126*linearize(rgb.r)+.7152*linearize(rgb.g)+.0722*linearize(rgb.b)}function assessContrast(fg,bg){const f=parseHex(fg);const b=parseHex(bg);if(!f||!b)return 1;const l1=relativeLuminance(f);const l2=relativeLuminance(b);const hi=Math.max(l1,l2);const lo=Math.min(l1,l2);return (hi+.05)/(lo+.05)}function rgbToHsl({r,g,b}){const rn=r/255;const gn=g/255;const bn=b/255;const max=Math.max(rn,gn,bn);const min=Math.min(rn,gn,bn);const l=(max+min)/2;let h=0;let s=0;if(max!==min){const d=max-min;s=l>.5?d/(2-max-min):d/(max+min);switch(max){case rn:h=(gn-bn)/d+(gn<bn?6:0);break;case gn:h=(bn-rn)/d+2;break;default:h=(rn-gn)/d+4;break}h/=6;}return {h:h*360,s,l}}function hueToRgb(p,q,tRaw){let t=tRaw;if(t<0)t+=1;if(t>1)t-=1;if(t<1/6)return p+(q-p)*6*t;if(t<1/2)return q;if(t<2/3)return p+(q-p)*(2/3-t)*6;return p}function hslToRgb({h,s,l}){const hn=(h%360+360)%360/360;let r;let g;let b;if(s===0){r=g=b=l;}else {const q=l<.5?l*(1+s):l+s-l*s;const p=2*l-q;r=hueToRgb(p,q,hn+1/3);g=hueToRgb(p,q,hn);b=hueToRgb(p,q,hn-1/3);}return {r:Math.round(r*255),g:Math.round(g*255),b:Math.round(b*255)}}function deriveSecondaryHue(hex){const rgb=parseHex(hex);if(!rgb)return PLATFORM_BRAND_DEFAULT.secondaryColor;const hsl=rgbToHsl(rgb);const out=hslToRgb({...hsl,h:(hsl.h+SECONDARY_HUE_SHIFT)%360});return toHex(out.r,out.g,out.b)}function shiftLightness(hex,delta){const rgb=parseHex(hex);if(!rgb)return toHex(0,0,0);const hsl=rgbToHsl(rgb);const out=hslToRgb({...hsl,l:Math.max(0,Math.min(1,hsl.l+delta))});return toHex(out.r,out.g,out.b)}function onColorFor(bg){const white=assessContrast(WHITE,bg);const dark=assessContrast(NEAR_BLACK,bg);return white>=dark?WHITE:NEAR_BLACK}function adaptAccent(hex,surface,target,warnings,field,mode){const rgb=parseHex(hex);if(!rgb){return toHex(0,0,0)}const hsl=rgbToHsl(rgb);const lighten=relativeLuminance(parseHex(surface)??{r:255,g:255,b:255})<.5;const rawRatio=assessContrast(hex,surface);let l=hsl.l;let out=toHex(rgb.r,rgb.g,rgb.b);for(let i=0;i<ADAPT_MAX_ITERS;i+=1){if(assessContrast(out,surface)>=target)break;l=Math.max(0,Math.min(1,l+(lighten?ADAPT_STEP:-ADAPT_STEP)));const o=hslToRgb({h:hsl.h,s:hsl.s,l});out=toHex(o.r,o.g,o.b);}const finalRatio=assessContrast(out,surface);if(rawRatio<target||finalRatio<target){warnings.push({field,mode,ratio:Number(rawRatio.toFixed(2))});}return out}function deriveMode(input,mode,warnings){const surf=SURFACE[mode];const primary=adaptAccent(input.primaryColor,surf.bg,ACCENT_TARGET,warnings,"primary",mode);const rawSecondary=input.secondaryColor??deriveSecondaryHue(input.primaryColor);const secondary=adaptAccent(rawSecondary,surf.bg,ACCENT_TARGET,warnings,"secondary",mode);const primaryHover=shiftLightness(primary,mode==="light"?-HOVER_DELTA:HOVER_DELTA);const onPrimary=onColorFor(primary);const onSecondary=onColorFor(secondary);const ring=primary;return {primary,primaryHover,onPrimary,secondary,onSecondary,ring}}function toSafeBrandColors(input){if(!input||parseHex(input.primaryColor)===null){return {primaryColor:PLATFORM_BRAND_DEFAULT.primaryColor,secondaryColor:PLATFORM_BRAND_DEFAULT.secondaryColor,colorMode:PLATFORM_BRAND_DEFAULT.colorMode}}const secondaryColor=typeof input.secondaryColor==="string"&&parseHex(input.secondaryColor)!==null?input.secondaryColor:null;const colorMode="auto";return {primaryColor:input.primaryColor,secondaryColor,colorMode}}function deriveBrandTokens(input){const safe=toSafeBrandColors(input);const warnings=[];return {light:deriveMode(safe,"light",warnings),dark:deriveMode(safe,"dark",warnings),warnings}}function defaultPrefersDark(){if(typeof window==="undefined"||typeof window.matchMedia!=="function"){return false}try{return window.matchMedia("(prefers-color-scheme: dark)").matches}catch{return false}}function defaultForcedMode(){if(typeof document==="undefined")return null;const dataTheme=document.documentElement.dataset.theme;return dataTheme==="light"||dataTheme==="dark"?dataTheme:null}function brandColorsFrom(primaryColor){return {primaryColor,secondaryColor:PLATFORM_BRAND_DEFAULT.secondaryColor,colorMode:"auto"}}function resolveCaptureTheme(ctxTheme,opts={}){const prefersDark=opts.prefersDark??defaultPrefersDark;const forcedMode=opts.forcedMode??defaultForcedMode;const colorMode=forcedMode()??(prefersDark()?"dark":"light");const primaryColor=ctxTheme?.primaryColor;if(typeof primaryColor!=="string"||primaryColor.length===0){return {colorMode,brandTokens:null}}const brandTokens=deriveBrandTokens(brandColorsFrom(primaryColor))[colorMode];return {colorMode,brandTokens}}var LEASE_STORAGE_KEY_PREFIX="checktiv.idv.lease.";function isRecord(v){return typeof v==="object"&&v!==null}function storageKey(sessionId){return LEASE_STORAGE_KEY_PREFIX+sessionId}function safeLocalStorage(){try{return globalThis.localStorage??null}catch{return null}}function generateHolderDeviceId(){const c=globalThis.crypto;if(c&&typeof c.randomUUID==="function"){return c.randomUUID()}const bytes=new Uint8Array(16);c.getRandomValues(bytes);let hex="";for(const b of bytes)hex+=b.toString(16).padStart(2,"0");return hex}function loadPersistedLease(sessionId){const ls=safeLocalStorage();if(ls===null)return null;let raw;try{raw=ls.getItem(storageKey(sessionId));}catch{return null}if(raw===null)return null;let parsed;try{parsed=JSON.parse(raw);}catch{return null}if(!isRecord(parsed))return null;const{holderDeviceId,leaseGeneration}=parsed;if(typeof holderDeviceId!=="string"||holderDeviceId.length===0)return null;const gen=typeof leaseGeneration==="number"&&Number.isInteger(leaseGeneration)&&leaseGeneration>=0?leaseGeneration:void 0;return gen===void 0?{holderDeviceId}:{holderDeviceId,leaseGeneration:gen}}function persistLease(sessionId,record){const ls=safeLocalStorage();if(ls===null)return;try{ls.setItem(storageKey(sessionId),JSON.stringify(record));}catch{}}function loadOrCreatePersistedLease(sessionId){const persisted=loadPersistedLease(sessionId);if(persisted!==null)return persisted;const record={holderDeviceId:generateHolderDeviceId()};persistLease(sessionId,record);return record}var MAX_REMINTS=3;function isRecord2(v){return typeof v==="object"&&v!==null}function asMode(value){return value==="live"||value==="test"?value:null}function asTestHint(value){return value==="pass"||value==="review"||value==="fail"?value:null}function parseMintBody(body){if(!isRecord2(body)||!isRecord2(body.data))return null;const d=body.data;const captureToken=d.capture_token;const embedOrigin=d.embed_origin;const runIndex=d.run_index;const embedContextToken=d.embed_context_token;if(typeof captureToken!=="string"||captureToken.length===0)return null;if(!isCanonicalOrigin(embedOrigin))return null;if(typeof runIndex!=="number"||!Number.isInteger(runIndex)||runIndex<0)return null;if(typeof embedContextToken!=="string"||embedContextToken.length===0)return null;const mode=asMode(d.mode);const testHint=asTestHint(d.test_hint);return {captureToken,embedOrigin,runIndex,embedContextToken,...mode!==null?{mode}:{},...testHint!==null?{testHint}:{}}}function buildCaptureSubmitBody(input){return {runIndex:input.runIndex,r2Keys:input.r2Keys,holderDeviceId:input.holderDeviceId,...input.leaseGeneration!==void 0?{leaseGeneration:input.leaseGeneration}:{}}}function createIdvTransport(ctx,opts){const fetchImpl=opts.fetchImpl??fetch;const origin=ctx.apiBaseOrigin;let embedContextToken=null;let mintMode;let mintTestHint;let remintCount=0;const persistedLease=loadOrCreatePersistedLease(opts.sessionId);const holderDeviceId=persistedLease.holderDeviceId;const leaseGeneration=persistedLease.leaseGeneration;async function mintToken(){const res=await withTokenRetry(ctx.tokens,token=>fetchImpl(origin+CAPTURE_TOKEN_MINT_PATH,{method:"POST",headers:dataPlaneHeaders(ctx,token,{withJsonBody:true}),body:JSON.stringify({stepId:opts.stepId})}),result=>result?.status===401);if(!res.ok){throw createChecktivError(mapHttpStatusToError(res.status))}let body;try{body=await res.json();}catch{opts.onError?.(createChecktivErrorEvent("sdk_load_failed"));throw createChecktivError("sdk_load_failed")}const parsed=parseMintBody(body);if(parsed===null){opts.onError?.(createChecktivErrorEvent("sdk_load_failed"));throw createChecktivError("sdk_load_failed")}embedContextToken=parsed.embedContextToken;mintMode=parsed.mode;mintTestHint=parsed.testHint;return {captureToken:parsed.captureToken,embedOrigin:parsed.embedOrigin,runIndex:parsed.runIndex}}function getEmbedSrc(embedOrigin){if(embedContextToken===null){opts.onError?.(createChecktivErrorEvent("sdk_load_failed"));throw createChecktivError("sdk_load_failed")}return `${embedOrigin}/idv/capture?ctx=${encodeURIComponent(embedContextToken)}`}async function submit(runIndex,r2Keys){let res;try{res=await withTokenRetry(ctx.tokens,token=>fetchImpl(origin+stepSubmitPath(opts.sessionId,opts.stepId??""),{method:"POST",headers:dataPlaneHeaders(ctx,token,{withJsonBody:true}),body:JSON.stringify(buildCaptureSubmitBody({runIndex,r2Keys,holderDeviceId,leaseGeneration}))}),result=>result?.status===401);}catch{return {ok:false,reason:"failed"}}if(res.ok)return {ok:true};if(res.status===401)return {ok:false,reason:"token_expired"};if(res.status===409)return {ok:false,reason:"capture_superseded"};if(res.status===503&&res.headers.has("Retry-After")){return {ok:false,reason:"signal_pending"}}return {ok:false,reason:"failed"}}function initPayload(){return {config:opts.config(),locale:ctx.locale,theme:resolveCaptureTheme(ctx.theme),protocolVersion:CURRENT_PROTOCOL_VERSION,...mintMode!==void 0?{mode:mintMode}:{},...mintTestHint!==void 0?{testHint:mintTestHint}:{},...ctx.selfiePromptMap!==void 0?{selfiePromptMap:ctx.selfiePromptMap}:{},...ctx.selfieChromeCopy!==void 0?{selfieChromeCopy:ctx.selfieChromeCopy}:{}}}async function remint(){if(remintCount>=MAX_REMINTS){opts.onError?.(createChecktivErrorEvent("session_expired"));return null}remintCount+=1;try{return await mintToken()}catch{return null}}function failProtocolMismatch(){opts.onError?.(createChecktivErrorEvent("protocol_mismatch"));}return {mintToken,submit,getEmbedSrc,initPayload,remint,failProtocolMismatch}}function after(delayMs,fn){return setTimeout(fn,delayMs)}function createSyntheticIdv(opts,config,sessionId,script){const emit=e=>opts.onEvent?.(e);const delayMs=script?.stepDelayMs??0;const timers=[];let destroyed=false;function step(offsetMs,fn){timers.push(after(offsetMs,()=>{if(!destroyed)fn();}));}step(delayMs*0,()=>{emit({type:"checktiv.idv.ready",config});});if(script?.injectError!==void 0){const code=script.injectError;step(delayMs*1,()=>{emit(createChecktivErrorEvent(code));});}else {step(delayMs*1,()=>{emit({type:"checktiv.idv.phase",phase:"document_front"});});step(delayMs*2,()=>{emit({type:"checktiv.idv.submitted",sessionId});});}const destroy=()=>{if(destroyed)return;destroyed=true;for(const id of timers)clearTimeout(id);};return {destroy,unmount:destroy}}function resolveTarget(target){if(typeof target!=="string")return target;if(typeof document==="undefined")return null;return document.querySelector(target)}function toCaptureConfig(config){return {documentTypes:config.documentTypes,biometricMode:config.biometricMode,requireMrzMatch:false,requireExpiryValid:false,requireNameMatch:false,documentAuthenticity:false,...config.minAge!==void 0?{minAge:config.minAge}:{}}}var REMINT_READY_TIMEOUT_MS=15e3;function noopHandle(){return {destroy(){},unmount(){},openCrossDevice(){}}}function isCoarsePointerViewport(){return typeof window!=="undefined"&&typeof window.matchMedia==="function"&&window.matchMedia("(pointer: coarse)").matches}function createIdv(ctx,opts){const element=resolveTarget(opts.target);if(element===null){console.warn('[Checktiv] mount("idv"): no target element found. Pass an element or a selector that resolves.');return noopHandle()}const emit=e=>opts.onEvent?.(e);const fetchImpl=opts.fetchImpl??fetch;let teardown=null;let cancelled=false;let crossDeviceSession=null;let crossDeviceOverlay=null;const closeCrossDevice=()=>{if(crossDeviceOverlay!==null){crossDeviceOverlay.destroy();crossDeviceOverlay=null;}};const openCrossDevice=()=>{if(cancelled)return;if(crossDeviceOverlay!==null)return;if(isCoarsePointerViewport()){console.warn('[Checktiv] mount("idv"): openCrossDevice() is a desktop affordance; ignoring the call on a touch device (the immersive capture layout already owns the phone).');return}const sess=crossDeviceSession;if(sess===null){console.warn('[Checktiv] mount("idv"): openCrossDevice() called before the session resolved.');return}const copy=opts.crossDeviceCopy;if(copy===void 0){console.warn('[Checktiv] mount("idv"): openCrossDevice() requires `crossDeviceCopy` (with `unavailableMessage`).');return}const openOverlay=getCrossDeviceOpener();if(openOverlay===null){console.warn(`[Checktiv] mount("idv"): cross-device is not enabled. Import '@checktiv/sdk-web/idv/cross-device' in your app.`);return}crossDeviceOverlay=openOverlay({ctx,fetchImpl,target:sess.element,stepId:sess.stepId,sessionId:sess.sessionId,copy,isMobile:isCoarsePointerViewport(),onOpenCrossDevice:opts.onOpenCrossDevice,emit,onClose:closeCrossDevice});};void(async()=>{try{await setupCapture(element);}catch(err){if(cancelled)return;console.warn('[Checktiv] mount("idv") setup failed.',err);emit(createChecktivErrorEvent("sdk_load_failed"));}})();async function setupCapture(element2){const resolution=await resolveSession(ctx,fetchImpl);if(cancelled)return;let session;switch(resolution.kind){case "ok":session=resolution.session;break;case "wrong_token":warnWrongTokenPlane();emit(createChecktivErrorEvent("wrong_token_type"));return;case "unresolved":emit(createChecktivErrorEvent("session_expired"));return;default:return assertNever(resolution)}const idvConfig=session.config;if(idvConfig===null){emit(createChecktivErrorEvent("session_expired"));return}const readyConfig={documentTypes:idvConfig.documentTypes,biometricMode:idvConfig.biometricMode};if(ctx.mode==="test"&&opts.synthetic!==void 0){const synthHandle=createSyntheticIdv(opts,readyConfig,session.sessionId,opts.synthetic);teardown=()=>synthHandle.destroy();return}const captureConfig=toCaptureConfig(idvConfig);crossDeviceSession={sessionId:session.sessionId,stepId:session.stepId,element:element2};const transport=createIdvTransport(ctx,{fetchImpl,sessionId:session.sessionId,stepId:session.stepId,config:()=>captureConfig,onError:emit});let pinnedOrigin=null;let everReady=false;const onState=state=>{if(state.kind==="ready"){pinnedOrigin=state.embedOrigin;everReady=true;}if(state.kind==="capture_error"&&state.errorKind==="protocol_mismatch"){transport.failProtocolMismatch();return}const event=mapStateToEvent(state,{config:readyConfig,sessionId:session.sessionId});if(event!==null)emit(event);};const onControllerEvent=event=>{if(event.type==="all-complete"){emit({type:"checktiv.idv.submitted",sessionId:session.sessionId});}};const handle=mount(element2,{mintToken:transport.mintToken,submit:transport.submit,getEmbedSrc:transport.getEmbedSrc,initPayload:transport.initPayload,copy:opts.copy??{},layout:opts.layout,onBeforeSubmit:opts.onBeforeSubmit,onBehaviorSegment:opts.onBehaviorSegment,onState,onControllerEvent});let reminting=false;let awaitingRemintReady=false;let remintReadyTimeoutHandle=null;const clearRemintReadyTimeout=()=>{if(remintReadyTimeoutHandle!==null){clearTimeout(remintReadyTimeoutHandle);remintReadyTimeoutHandle=null;}};const armRemintReadyTimeout=()=>{clearRemintReadyTimeout();remintReadyTimeoutHandle=setTimeout(()=>{remintReadyTimeoutHandle=null;if(!awaitingRemintReady)return;if(cancelled)return;void(async()=>{const minted=await transport.remint();if(cancelled||minted===null){awaitingRemintReady=false;reminting=false;return}if(!awaitingRemintReady){reminting=false;return}const frame=element2.querySelector("iframe.idv-capture-frame");if(frame===null){awaitingRemintReady=false;reminting=false;return}armRemintReadyTimeout();frame.src=transport.getEmbedSrc(minted.embedOrigin);})();},REMINT_READY_TIMEOUT_MS);};const isCaptureReady=data=>typeof data==="object"&&data!==null&&"type"in data&&data.type==="capture:ready";const onReloadMessage=mev=>{if(pinnedOrigin===null||mev.origin!==pinnedOrigin)return;if(!everReady)return;if(!isCaptureReady(mev.data))return;const pinnedFrame=element2.querySelector("iframe.idv-capture-frame");if(pinnedFrame===null)return;if(mev.source!==null&&mev.source!==pinnedFrame.contentWindow)return;if(reminting){if(awaitingRemintReady){clearRemintReadyTimeout();awaitingRemintReady=false;reminting=false;}return}reminting=true;void(async()=>{const minted=await transport.remint();if(cancelled||minted===null){reminting=false;return}const frame=element2.querySelector("iframe.idv-capture-frame");if(frame===null){reminting=false;return}awaitingRemintReady=true;armRemintReadyTimeout();frame.src=transport.getEmbedSrc(minted.embedOrigin);})();};if(typeof window!=="undefined"){window.addEventListener("message",onReloadMessage);}teardown=()=>{clearRemintReadyTimeout();if(typeof window!=="undefined"){window.removeEventListener("message",onReloadMessage);}handle.destroy();};}const destroy=()=>{cancelled=true;closeCrossDevice();if(teardown!==null){teardown();teardown=null;}};return {destroy,unmount:destroy,openCrossDevice}}registerModule("idv",createIdv);
|
|
16
16
|
|
|
17
17
|
export { REMINT_READY_TIMEOUT_MS, createIdv };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode, ReactElement } from 'react';
|
|
3
|
+
import { g as ChecktivIdvEvent, M as MountOptions, C as ChecktivInitOptions, z as ChecktivInitScope, a as ChecktivClient } from './api-CkHzWaTo.js';
|
|
4
|
+
import { C as CaptureLayout, a as CaptureBehaviorMessage } from './machine-CuZalPFX.js';
|
|
5
|
+
import { M as MountCopy } from './copy-Dfmk11S_.js';
|
|
6
|
+
|
|
7
|
+
interface SelfServiceResendResult {
|
|
8
|
+
readonly requested: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface ChecktivProviderPropsBase {
|
|
12
|
+
getSessionToken: ChecktivInitOptions['getSessionToken'];
|
|
13
|
+
theme?: ChecktivInitOptions['theme'];
|
|
14
|
+
locale?: string;
|
|
15
|
+
children: ReactNode;
|
|
16
|
+
}
|
|
17
|
+
type ChecktivProviderProps = ChecktivProviderPropsBase & ChecktivInitScope;
|
|
18
|
+
declare function ChecktivProvider(props: ChecktivProviderProps): ReactElement | null;
|
|
19
|
+
declare function useChecktiv(): ChecktivClient;
|
|
20
|
+
interface ChecktivIdvProps {
|
|
21
|
+
onEvent: (e: ChecktivIdvEvent) => void;
|
|
22
|
+
copy?: MountCopy;
|
|
23
|
+
layout?: CaptureLayout;
|
|
24
|
+
onBeforeSubmit?: () => Promise<void>;
|
|
25
|
+
onBehaviorSegment?: (segment: Pick<CaptureBehaviorMessage, 'steps' | 'traits'>) => void;
|
|
26
|
+
}
|
|
27
|
+
declare function ChecktivIdv({ onEvent, copy, layout, onBeforeSubmit, onBehaviorSegment, }: ChecktivIdvProps): ReactElement | null;
|
|
28
|
+
type ChecktivJourneyProps = MountOptions;
|
|
29
|
+
interface ChecktivJourneyHandle {
|
|
30
|
+
requestResend(confirmEmail: string): Promise<SelfServiceResendResult>;
|
|
31
|
+
openCrossDevice(): void;
|
|
32
|
+
}
|
|
33
|
+
declare const ChecktivJourney: react.ForwardRefExoticComponent<MountOptions & react.RefAttributes<ChecktivJourneyHandle>>;
|
|
34
|
+
|
|
35
|
+
export { type ChecktivIdvProps as C, type SelfServiceResendResult as S, type ChecktivJourneyHandle as a, type ChecktivJourneyProps as b, type ChecktivProviderProps as c, ChecktivIdv as d, ChecktivJourney as e, ChecktivProvider as f, type ChecktivProviderPropsBase as g, useChecktiv as u };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { C as ChecktivInitOptions, T as TokenManager, a as ChecktivClient, P as ProvisionedHandle, M as MountOptions, I as InitOptions, b as ChecktivSessions } from './api-
|
|
2
|
-
export { c as ChecktivError, d as ChecktivErrorCode, e as ChecktivEvent, f as ChecktivFraudEvent, g as ChecktivIdvEvent, h as CrossDeviceHandoffHook, F as FraudHandle, i as FraudMountOptions, G as GetSessionToken, j as GetSessionTokenContext, k as IdvCoachingHint, l as IdvHandle, m as IdvMountOptions, n as InvalidPublishableKeyError, o as MountCompleteResult, p as MountProvisionedOptions, q as MountScope, r as ParsedPublishableKey, R as ResolvedIdvConfig, S as SdkMode, s as SdkRegion, t as SessionsCreateApplicant, u as SessionsCreateInput, v as SessionsCreateOptions, w as SessionsCreateResult, x as SyntheticIdvScript, y as parsePublishableKey } from './api-
|
|
3
|
-
|
|
1
|
+
import { C as ChecktivInitOptions, T as TokenManager, a as ChecktivClient, P as ProvisionedHandle, M as MountOptions, I as InitOptions, b as ChecktivSessions } from './api-CkHzWaTo.js';
|
|
2
|
+
export { c as ChecktivError, d as ChecktivErrorCode, e as ChecktivEvent, f as ChecktivFraudEvent, g as ChecktivIdvEvent, h as CrossDeviceHandoffHook, F as FraudHandle, i as FraudMountOptions, G as GetSessionToken, j as GetSessionTokenContext, k as IdvCoachingHint, l as IdvHandle, m as IdvMountOptions, n as InvalidPublishableKeyError, o as MountCompleteResult, p as MountProvisionedOptions, q as MountScope, r as ParsedPublishableKey, R as ResolvedIdvConfig, S as SdkMode, s as SdkRegion, t as SessionsCreateApplicant, u as SessionsCreateInput, v as SessionsCreateOptions, w as SessionsCreateResult, x as SyntheticIdvScript, y as parsePublishableKey } from './api-CkHzWaTo.js';
|
|
3
|
+
import { S as SelfServiceResendResult } from './index-Ch6p6GHo.js';
|
|
4
|
+
export { C as ChecktivIdvProps, a as ChecktivJourneyHandle, b as ChecktivJourneyProps, c as ChecktivProviderProps } from './index-Ch6p6GHo.js';
|
|
5
|
+
export { C as CrossDeviceCopy } from './copy-DCeQ4JKx.js';
|
|
4
6
|
import './machine-CuZalPFX.js';
|
|
5
7
|
import './copy-Dfmk11S_.js';
|
|
6
|
-
import './copy-DCeQ4JKx.js';
|
|
7
8
|
import 'react';
|
|
8
9
|
|
|
9
10
|
interface InitDeps {
|
|
@@ -11,16 +12,13 @@ interface InitDeps {
|
|
|
11
12
|
}
|
|
12
13
|
declare function init(opts: ChecktivInitOptions, deps?: InitDeps): ChecktivClient;
|
|
13
14
|
|
|
14
|
-
interface SelfServiceResendResult {
|
|
15
|
-
readonly requested: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
15
|
declare const version: string;
|
|
19
16
|
declare function mountButton(opts: InitOptions): void;
|
|
20
17
|
interface MountHandle extends ProvisionedHandle {
|
|
21
18
|
requestResend(confirmEmail: string): Promise<SelfServiceResendResult>;
|
|
19
|
+
openCrossDevice?(): void;
|
|
22
20
|
}
|
|
23
21
|
declare function mount(target: HTMLElement | string, opts: MountOptions): MountHandle;
|
|
24
22
|
declare const sessions: ChecktivSessions;
|
|
25
23
|
|
|
26
|
-
export { ChecktivClient, ChecktivInitOptions, ChecktivSessions, InitOptions, type MountHandle, MountOptions, ProvisionedHandle,
|
|
24
|
+
export { ChecktivClient, ChecktivInitOptions, ChecktivSessions, InitOptions, type MountHandle, MountOptions, ProvisionedHandle, SelfServiceResendResult, init, mount, mountButton, sessions, version };
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
export { InvalidPublishableKeyError, init, parsePublishableKey } from './chunk-BEZGAQ74.js';
|
|
1
|
+
export { InvalidPublishableKeyError, init, mount, mountButton, parsePublishableKey, sessions, version } from './chunk-2ZXL5RVX.js';
|
|
3
2
|
import './chunk-GFHNOZVO.js';
|
|
4
3
|
import './chunk-UBQTPS5J.js';
|
|
5
|
-
import './chunk-
|
|
6
|
-
import
|
|
4
|
+
import './chunk-7NIKMJFJ.js';
|
|
5
|
+
import './chunk-XOGHMNBX.js';
|
|
7
6
|
import './chunk-IQKHRPJR.js';
|
|
8
|
-
import
|
|
9
|
-
import
|
|
7
|
+
import './chunk-ACQKQLL2.js';
|
|
8
|
+
import './chunk-QFA3K5ZV.js';
|
|
10
9
|
import './chunk-AIK7CDV6.js';
|
|
11
|
-
|
|
12
|
-
var HOST_TAG="checktiv-root";var MOUNTED_FLAG="__checktivMounted";var LEGACY_HOST_ATTR="data-autohost-kyc-host";var HOST_ATTR="data-checktiv-host";var shadowCache=new WeakMap;function mountShadowHost(target){const existing=findExistingHost(target);if(existing){const cached=shadowCache.get(existing);if(cached)return cached}const host=document.createElement("div");host.setAttribute(HOST_ATTR,HOST_TAG);host.setAttribute(LEGACY_HOST_ATTR,HOST_TAG);host[MOUNTED_FLAG]=true;target.appendChild(host);const shadow=host.attachShadow({mode:"closed"});shadowCache.set(host,shadow);return shadow}function findExistingHost(target){for(const child of Array.from(target.children)){if(!(child instanceof HTMLElement))continue;const candidate=child;if(candidate[MOUNTED_FLAG]===true)return candidate}return null}var DEFAULT_REFRESH_MARGIN_MS=6e4;function createWorkingTokenManager(source,deps={}){const now=deps.now??(()=>Date.now());const setTimer=deps.setTimer??((fn,ms)=>setTimeout(fn,ms));const clearTimer=deps.clearTimer??(handle=>clearTimeout(handle));const marginMs=deps.marginMs??DEFAULT_REFRESH_MARGIN_MS;const onProactiveError=deps.onProactiveError;let cached=null;let pending=null;let timer=null;let stopped=false;const clearScheduled=()=>{if(timer!==null){clearTimer(timer);timer=null;}};const scheduleProactive=expiresAt=>{clearScheduled();if(stopped)return;const expiryMs=Date.parse(expiresAt);if(Number.isNaN(expiryMs))return;const delay=expiryMs-now()-marginMs;if(delay<=0)return;timer=setTimer(()=>{timer=null;void doRefresh("expired").catch(err=>onProactiveError?.(err));},delay);};const mintOnce=reason=>source(reason).then(minted=>{scheduleProactive(minted.expiresAt);return minted.token});const doRefresh=reason=>{if(pending!==null)return pending;const p=mintOnce(reason);pending=p;cached=p;void p.then(()=>{if(pending===p)pending=null;},()=>{if(pending===p)pending=null;if(cached===p)cached=null;});return p};return {get(){if(cached!==null)return cached;const p=mintOnce("initial");cached=p;void p.catch(()=>{if(cached===p)cached=null;});return p},refresh(reason){return doRefresh(reason)},stop(){stopped=true;clearScheduled();}}}var RESUME_CLIENT_TOKEN_KEY_PREFIX="checktiv.rct.";function safeLocalStorage(){try{return globalThis.localStorage??null}catch{return null}}function createClientTokenStore(resumeKey,storage=safeLocalStorage()){const key=RESUME_CLIENT_TOKEN_KEY_PREFIX+resumeKey;return {read(){if(storage===null)return null;try{const raw=storage.getItem(key);return raw!==null&&raw.length>0?raw:null}catch{return null}},write(token){if(storage===null)return;try{storage.setItem(key,token);}catch{}},clear(){if(storage===null)return;try{storage.removeItem(key);}catch{}}}}async function requestSelfServiceResend(params){const fetchImpl=params.fetchImpl??fetch;const body=JSON.stringify({confirmEmail:params.confirmEmail});try{let res;if(params.mode==="short_code"){res=await fetchImpl(params.origin+shortCodeRefreshPath(params.shortCode),{method:"POST",headers:{"content-type":"application/json"},body});}return {requested:res.ok}}catch{return {requested:false}}}var version="1.2.0";var initialised=new WeakSet;function resolveVerifyOrigin(parsed){return getServiceOrigin(sdkPublicSettings.apps.verify.subdomain,"prod",parsed.region,sdkPublicSettings)}function buildPopupUrl(parsed,opts){const origin=resolveVerifyOrigin(parsed);if(opts.applicantLinkToken){return `${origin}/start?lt=${encodeURIComponent(opts.applicantLinkToken)}`}return `${origin}/`}function launchPopup(url){const w=460;const h=760;const left=Math.max(0,Math.floor((window.screen.width-w)/2));const top=Math.max(0,Math.floor((window.screen.height-h)/2));const features=`popup=yes,width=${w},height=${h},left=${left},top=${top}`;const popup=window.open(url,"checktiv",features);if(!popup){window.location.href=url;return null}return popup}var COMPLETE_EVENT_TYPE="autohost.kyc.complete";function isCompletionMessage(data){if(typeof data!=="object"||data===null)return false;if(!("type"in data))return false;return data.type===COMPLETE_EVENT_TYPE}function listenForCompletion(expectedOrigin,onComplete){if(!onComplete)return;const handler=event=>{if(event.origin!==expectedOrigin)return;const data=event.data;if(!isCompletionMessage(data))return;onComplete(data);};window.addEventListener("message",handler);}function buildButton(onClick){const children="Start verification";return k("button",{type:"button",onClick,style:'display: inline-flex; align-items: center; justify-content: center; padding: 10px 20px; font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif; font-size: 14px; font-weight: 600; color: #fff; background: #0b5fff; border: none; border-radius: 6px; cursor: pointer;'},children)}function resolveTarget(opts){if(opts.target)return opts.target;return document.querySelector("[data-checktiv]")??document.querySelector("[data-autohost-kyc]")}function mountButton(opts){const parsed=parsePublishableKey(opts.publishableKey);const target=resolveTarget(opts);if(!target){console.warn("[Checktiv] No mount target found. Either pass `target` explicitly or add `<div data-checktiv>` to your page.");return}if(initialised.has(target))return;initialised.add(target);const shadow=mountShadowHost(target);const verifyOrigin=resolveVerifyOrigin(parsed);listenForCompletion(verifyOrigin,opts.onComplete);const onClick=()=>{const popupUrl=buildPopupUrl(parsed,opts);launchPopup(popupUrl);};R(buildButton(onClick),shadow);}function parseWorkingTokenMintResponse(body){if(typeof body!=="object"||body===null)return null;if(!("workingToken"in body)||!("expiresAt"in body))return null;const workingToken=body.workingToken;const expiresAt=body.expiresAt;if(typeof workingToken!=="string"||workingToken.length===0)return null;if(typeof expiresAt!=="string"||expiresAt.length===0)return null;return {workingToken,expiresAt}}async function mintWorkingTokenFacet(origin,clientToken,publishableKey,fetchImpl){const headers={Authorization:`Bearer ${clientToken}`};if(publishableKey!==void 0)headers[PUBLISHABLE_KEY_HEADER]=publishableKey;const res=await fetchImpl(origin+WORKING_TOKEN_MINT_PATH,{method:"POST",headers});if(!res.ok){throw new Error(`Checktiv working-token mint failed (status ${res.status}).`)}let body;try{body=await res.json();}catch{throw new Error("Checktiv working-token mint returned a non-JSON body.")}const parsed=parseWorkingTokenMintResponse(body);if(parsed===null)throw new Error("Checktiv working-token mint returned a malformed body.");return parsed}function completionSessionId(e){if(e.type!=="checktiv.idv.submitted"&&e.type!=="checktiv.custom_form.submitted"){return null}const sid="sessionId"in e?e.sessionId:void 0;return typeof sid==="string"&&sid.length>0?sid:null}function isSessionExpiredEvent(e){if(!e.type.endsWith(".error")||!("error"in e))return false;const err=e.error;if(typeof err!=="object"||err===null||!("code"in err))return false;return err.code==="session_expired"}function mount(target,opts){const fetchImpl=opts.fetchImpl??fetch;const scope="publishableKey"in opts?{...parsePublishableKey(opts.publishableKey),publishableKey:opts.publishableKey}:{region:opts.region,mode:opts.mode,publishableKey:void 0};const mintOrigin=resolveApiBaseOrigin(opts.apiBase,scope.region,scope.mode);const store=opts.resumeKey!==void 0?createClientTokenStore(opts.resumeKey):null;let clientTokenPromise=null;const getClientToken=()=>{if(clientTokenPromise!==null)return clientTokenPromise;const persisted=store?.read()??null;if(persisted!==null){clientTokenPromise=Promise.resolve(persisted);return clientTokenPromise}const p=opts.fetchToken();clientTokenPromise=p;void p.then(tok=>store?.write(tok),()=>{if(clientTokenPromise===p)clientTokenPromise=null;});return p};const mintWorkingToken=async()=>{const clientToken=await getClientToken();const minted=await mintWorkingTokenFacet(mintOrigin,clientToken,scope.publishableKey,fetchImpl);return {token:minted.workingToken,expiresAt:minted.expiresAt}};const tokens=createWorkingTokenManager(mintWorkingToken);const base={getSessionToken:()=>tokens.get(),...opts.apiBase!==void 0?{apiBase:opts.apiBase}:{}};const initOptions=scope.publishableKey!==void 0?{...base,publishableKey:scope.publishableKey}:{...base,region:scope.region,mode:scope.mode};const needsChannel=opts.onEvent!==void 0||opts.onComplete!==void 0||store!==null;const onEvent=needsChannel?e=>{opts.onEvent?.(e);const sessionId=completionSessionId(e);if(sessionId!==null){store?.clear();opts.onComplete?.({sessionId});}else if(isSessionExpiredEvent(e)){store?.clear();}}:void 0;const client=init(initOptions,{tokens});const handle=client.mountProvisioned({target,fetchImpl,onEvent,onConsent:opts.onConsent});const requestResend=confirmEmail=>{if(opts.shortCode===void 0)return Promise.resolve({requested:false});return requestSelfServiceResend({mode:"short_code",origin:mintOrigin,shortCode:opts.shortCode,confirmEmail,fetchImpl})};return {destroy(){handle.destroy();tokens.stop();},requestResend}}function applicantToWire(a){const wire={};if(a.externalId!==void 0)wire.external_id=a.externalId;if(a.email!==void 0)wire.email=a.email;if(a.phone!==void 0)wire.phone=a.phone;if(a.firstName!==void 0)wire.first_name=a.firstName;if(a.lastName!==void 0)wire.last_name=a.lastName;if(a.dateOfBirth!==void 0)wire.date_of_birth=a.dateOfBirth;if(a.referenceName!==void 0)wire.reference_name=a.referenceName;return wire}function readCreatedClientToken(body){if(typeof body!=="object"||body===null||!("data"in body))return null;const data=body.data;if(typeof data!=="object"||data===null||!("client_token"in data))return null;const clientToken=data.client_token;return typeof clientToken==="string"&&clientToken.length>0?clientToken:null}var sessions={async create(input,options){if(typeof window!=="undefined"||typeof document!=="undefined"){throw new Error("checktiv.sessions.create must run on your server: it needs your secret key. Never call it in the browser.")}const fetchImpl=options.fetchImpl??fetch;const headers={Authorization:`Bearer ${options.secretKey}`,"content-type":"application/json"};if(options.idempotencyKey!==void 0)headers["Idempotency-Key"]=options.idempotencyKey;const body=JSON.stringify({workflow_template_id:input.templateId,applicant:applicantToWire(input.applicant)});const res=await fetchImpl(`${options.apiBase}/v1/sessions`,{method:"POST",headers,body});if(!res.ok){throw new Error(`Checktiv sessions.create failed (status ${res.status}). Verify the apiBase origin and secret key.`)}let parsed;try{parsed=await res.json();}catch{throw new Error("Checktiv sessions.create returned a non-JSON response.")}const clientToken=readCreatedClientToken(parsed);if(clientToken===null){throw new Error("Checktiv sessions.create response carried no client token. Enable the working-token capability for this environment, then retry.")}return {clientToken}}};
|
|
13
|
-
|
|
14
|
-
export { mount, mountButton, sessions, version };
|
package/dist/react.d.ts
CHANGED
|
@@ -1,25 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
import 'react';
|
|
2
|
+
import './api-CkHzWaTo.js';
|
|
3
|
+
import './machine-CuZalPFX.js';
|
|
4
|
+
import './copy-Dfmk11S_.js';
|
|
5
|
+
export { d as ChecktivIdv, C as ChecktivIdvProps, e as ChecktivJourney, a as ChecktivJourneyHandle, b as ChecktivJourneyProps, f as ChecktivProvider, c as ChecktivProviderProps, g as ChecktivProviderPropsBase, u as useChecktiv } from './index-Ch6p6GHo.js';
|
|
5
6
|
import './copy-DCeQ4JKx.js';
|
|
6
|
-
|
|
7
|
-
interface ChecktivProviderPropsBase {
|
|
8
|
-
getSessionToken: ChecktivInitOptions['getSessionToken'];
|
|
9
|
-
theme?: ChecktivInitOptions['theme'];
|
|
10
|
-
locale?: string;
|
|
11
|
-
children: ReactNode;
|
|
12
|
-
}
|
|
13
|
-
type ChecktivProviderProps = ChecktivProviderPropsBase & ChecktivInitScope;
|
|
14
|
-
declare function ChecktivProvider(props: ChecktivProviderProps): ReactElement | null;
|
|
15
|
-
declare function useChecktiv(): ChecktivClient;
|
|
16
|
-
interface ChecktivIdvProps {
|
|
17
|
-
onEvent: (e: ChecktivIdvEvent) => void;
|
|
18
|
-
copy?: MountCopy;
|
|
19
|
-
layout?: CaptureLayout;
|
|
20
|
-
onBeforeSubmit?: () => Promise<void>;
|
|
21
|
-
onBehaviorSegment?: (segment: Pick<CaptureBehaviorMessage, 'steps' | 'traits'>) => void;
|
|
22
|
-
}
|
|
23
|
-
declare function ChecktivIdv({ onEvent, copy, layout, onBeforeSubmit, onBehaviorSegment, }: ChecktivIdvProps): ReactElement | null;
|
|
24
|
-
|
|
25
|
-
export { ChecktivIdv, type ChecktivIdvProps, ChecktivProvider, type ChecktivProviderProps, type ChecktivProviderPropsBase, useChecktiv };
|
package/dist/react.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { init } from './chunk-
|
|
1
|
+
import { mount, init } from './chunk-2ZXL5RVX.js';
|
|
2
2
|
import './chunk-GFHNOZVO.js';
|
|
3
3
|
import './chunk-UBQTPS5J.js';
|
|
4
|
-
import './chunk-
|
|
4
|
+
import './chunk-7NIKMJFJ.js';
|
|
5
|
+
import './chunk-XOGHMNBX.js';
|
|
5
6
|
import './chunk-IQKHRPJR.js';
|
|
6
|
-
import './chunk-
|
|
7
|
+
import './chunk-ACQKQLL2.js';
|
|
7
8
|
import './chunk-QFA3K5ZV.js';
|
|
8
9
|
import './chunk-AIK7CDV6.js';
|
|
9
|
-
import { createContext,
|
|
10
|
+
import { createContext, forwardRef, useRef, useImperativeHandle, useEffect, useMemo, useContext } from 'react';
|
|
10
11
|
import { jsx } from 'react/jsx-runtime';
|
|
11
12
|
|
|
12
|
-
var ChecktivContext=createContext(null);function ChecktivProvider(props){if(typeof window==="undefined")return null;return jsx(ProviderImpl,{...props})}function ProviderImpl(props){const{getSessionToken,theme,locale,children}=props;const scope="publishableKey"in props?{publishableKey:props.publishableKey}:{region:props.region,mode:props.mode};const pk="publishableKey"in props?props.publishableKey:void 0;const region="publishableKey"in props?void 0:props.region;const mode="publishableKey"in props?void 0:props.mode;const themeKey=JSON.stringify(theme??null);const client=useMemo(()=>init({...scope,getSessionToken,theme,locale}),[pk,region,mode,getSessionToken,themeKey,locale]);return jsx(ChecktivContext.Provider,{value:client,children})}function useChecktiv(){const client=useContext(ChecktivContext);if(client===null){throw new Error("useChecktiv must be used within a <ChecktivProvider>. Wrap the component tree that needs the Checktiv client with <ChecktivProvider>.")}return client}function ChecktivIdv({onEvent,copy,layout,onBeforeSubmit,onBehaviorSegment}){const client=useChecktiv();const containerRef=useRef(null);const handleRef=useRef(null);const mountConfigRef=useRef({copy,layout,onBeforeSubmit,onBehaviorSegment});const onEventRef=useRef(onEvent);onEventRef.current=onEvent;useEffect(()=>{if(typeof window==="undefined")return;if(containerRef.current===null)return;if(handleRef.current!==null)return;const mountConfig=mountConfigRef.current;handleRef.current=client.mount("idv",{target:containerRef.current,onEvent:e=>onEventRef.current(e),...mountConfig.copy!==void 0?{copy:mountConfig.copy}:{},...mountConfig.layout!==void 0?{layout:mountConfig.layout}:{},...mountConfig.onBeforeSubmit!==void 0?{onBeforeSubmit:mountConfig.onBeforeSubmit}:{},...mountConfig.onBehaviorSegment!==void 0?{onBehaviorSegment:mountConfig.onBehaviorSegment}:{}});return ()=>{handleRef.current?.destroy();handleRef.current=null;}},[client]);if(typeof window==="undefined")return null;return jsx("div",{ref:containerRef})}
|
|
13
|
+
var ChecktivContext=createContext(null);function ChecktivProvider(props){if(typeof window==="undefined")return null;return jsx(ProviderImpl,{...props})}function ProviderImpl(props){const{getSessionToken,theme,locale,children}=props;const scope="publishableKey"in props?{publishableKey:props.publishableKey}:{region:props.region,mode:props.mode};const pk="publishableKey"in props?props.publishableKey:void 0;const region="publishableKey"in props?void 0:props.region;const mode="publishableKey"in props?void 0:props.mode;const themeKey=JSON.stringify(theme??null);const client=useMemo(()=>init({...scope,getSessionToken,theme,locale}),[pk,region,mode,getSessionToken,themeKey,locale]);return jsx(ChecktivContext.Provider,{value:client,children})}function useChecktiv(){const client=useContext(ChecktivContext);if(client===null){throw new Error("useChecktiv must be used within a <ChecktivProvider>. Wrap the component tree that needs the Checktiv client with <ChecktivProvider>.")}return client}function ChecktivIdv({onEvent,copy,layout,onBeforeSubmit,onBehaviorSegment}){const client=useChecktiv();const containerRef=useRef(null);const handleRef=useRef(null);const mountConfigRef=useRef({copy,layout,onBeforeSubmit,onBehaviorSegment});const onEventRef=useRef(onEvent);onEventRef.current=onEvent;useEffect(()=>{if(typeof window==="undefined")return;if(containerRef.current===null)return;if(handleRef.current!==null)return;const mountConfig=mountConfigRef.current;handleRef.current=client.mount("idv",{target:containerRef.current,onEvent:e=>onEventRef.current(e),...mountConfig.copy!==void 0?{copy:mountConfig.copy}:{},...mountConfig.layout!==void 0?{layout:mountConfig.layout}:{},...mountConfig.onBeforeSubmit!==void 0?{onBeforeSubmit:mountConfig.onBeforeSubmit}:{},...mountConfig.onBehaviorSegment!==void 0?{onBehaviorSegment:mountConfig.onBehaviorSegment}:{}});return ()=>{handleRef.current?.destroy();handleRef.current=null;}},[client]);if(typeof window==="undefined")return null;return jsx("div",{ref:containerRef})}var ChecktivJourneyImpl=(props,ref)=>{const containerRef=useRef(null);const handleRef=useRef(null);const scope="publishableKey"in props?{publishableKey:props.publishableKey}:{region:props.region,mode:props.mode};const pk="publishableKey"in props?props.publishableKey:void 0;const region="publishableKey"in props?void 0:props.region;const mode="publishableKey"in props?void 0:props.mode;const journeyConfig={fetchToken:props.fetchToken,onConsent:props.onConsent,layout:props.layout,theme:props.theme,resumeKey:props.resumeKey,shortCode:props.shortCode,apiBase:props.apiBase,fetchImpl:props.fetchImpl,crossDeviceCopy:props.crossDeviceCopy,onOpenCrossDevice:props.onOpenCrossDevice};const mountConfigRef=useRef(journeyConfig);mountConfigRef.current=journeyConfig;const onEventRef=useRef(props.onEvent);onEventRef.current=props.onEvent;const onCompleteRef=useRef(props.onComplete);onCompleteRef.current=props.onComplete;useImperativeHandle(ref,()=>({requestResend:confirmEmail=>handleRef.current?.requestResend(confirmEmail)??Promise.resolve({requested:false}),openCrossDevice:()=>handleRef.current?.openCrossDevice?.()}),[]);useEffect(()=>{if(typeof window==="undefined")return;if(containerRef.current===null)return;if(handleRef.current!==null)return;const cfg=mountConfigRef.current;const opts={...scope,fetchToken:cfg.fetchToken,onEvent:e=>onEventRef.current?.(e),onComplete:r=>onCompleteRef.current?.(r),...cfg.onConsent!==void 0?{onConsent:cfg.onConsent}:{},...cfg.layout!==void 0?{layout:cfg.layout}:{},...cfg.theme!==void 0?{theme:cfg.theme}:{},...cfg.resumeKey!==void 0?{resumeKey:cfg.resumeKey}:{},...cfg.shortCode!==void 0?{shortCode:cfg.shortCode}:{},...cfg.apiBase!==void 0?{apiBase:cfg.apiBase}:{},...cfg.fetchImpl!==void 0?{fetchImpl:cfg.fetchImpl}:{},...cfg.crossDeviceCopy!==void 0?{crossDeviceCopy:cfg.crossDeviceCopy}:{},...cfg.onOpenCrossDevice!==void 0?{onOpenCrossDevice:cfg.onOpenCrossDevice}:{}};handleRef.current=mount(containerRef.current,opts);return ()=>{handleRef.current?.destroy();handleRef.current=null;}},[pk,region,mode]);if(typeof window==="undefined")return null;return jsx("div",{ref:containerRef})};var ChecktivJourney=forwardRef(ChecktivJourneyImpl);
|
|
13
14
|
|
|
14
|
-
export { ChecktivIdv, ChecktivProvider, useChecktiv };
|
|
15
|
+
export { ChecktivIdv, ChecktivJourney, ChecktivProvider, useChecktiv };
|
package/dist/workspace.d.ts
CHANGED
package/dist/workspace.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { isCanonicalOrigin, sdkPublicSettings } from './chunk-
|
|
1
|
+
import { isCanonicalOrigin, sdkPublicSettings } from './chunk-ACQKQLL2.js';
|
|
2
2
|
import { getServiceOrigin } from './chunk-QFA3K5ZV.js';
|
|
3
3
|
import './chunk-AIK7CDV6.js';
|
|
4
4
|
|
|
5
|
-
function isOriginTargetedPoster(value){return typeof value==="object"&&value!==null&&"postMessage"in value}function initTransport(options,announce){const{win,allowedOrigins,parse,onMessage,accept,reAnnounce}=options;if(!Array.isArray(allowedOrigins)||allowedOrigins.length===0){return {teardown:()=>{}}}const allowlist=new Set(allowedOrigins);const onMessageListener=event=>{if(!allowlist.has(event.origin))return;const parsed=parse(event.data);if(parsed===null)return;if(accept&&!accept(parsed,event.origin))return;const source=event.source;if(!isOriginTargetedPoster(source))return;const post=message=>source.postMessage(message,event.origin);onMessage(parsed,post,event.origin);};win.addEventListener("message",onMessageListener);const broadcast=message=>{for(const origin of allowlist){win.parent.postMessage(message,origin);}};let timer=null;if(reAnnounce!==void 0&&reAnnounce.maxAttempts>0){const scheduler=reAnnounce.schedule??{set:(cb,ms)=>setTimeout(cb,ms),clear:handle=>clearTimeout(handle)};let attemptsLeft=reAnnounce.maxAttempts;const tick=()=>{if(attemptsLeft<=0){timer=null;return}attemptsLeft-=1;broadcast(reAnnounce.message);timer=attemptsLeft>0?scheduler.set(tick,reAnnounce.intervalMs):null;};timer=scheduler.set(tick,reAnnounce.intervalMs);return {teardown:()=>{win.removeEventListener("message",onMessageListener);if(timer!==null){scheduler.clear(timer);timer=null;}}}}return {teardown:()=>{win.removeEventListener("message",onMessageListener);}}}var REVIEWER_COMPONENT="reviewer";var LOADER_PROTOCOL_VERSION=1;var NAVIGATION_EVENTS=new Set(["session_complete","navigate_away"]);function parseWorkspaceInbound(data){if(typeof data!=="object"||data===null)return null;const record=data;const type=record.type;if(type==="wk:ready"){if(record.component!==REVIEWER_COMPONENT)return null;if(typeof record.sessionId!=="string"||record.sessionId.length===0)return null;if(typeof record.nonce!=="string"||record.nonce.length===0)return null;return {type:"wk:ready",component:REVIEWER_COMPONENT,sessionId:record.sessionId,nonce:record.nonce,...typeof record.protocolVersion==="number"?{protocolVersion:record.protocolVersion}:{}}}if(type==="wk:token_refresh"){return {type:"wk:token_refresh",...typeof record.protocolVersion==="number"?{protocolVersion:record.protocolVersion}:{}}}if(type==="wk:event"){if(record.component!==REVIEWER_COMPONENT)return null;const event=record.event;if(typeof event!=="string"||!NAVIGATION_EVENTS.has(event)){return null}return {type:"wk:event",component:REVIEWER_COMPONENT,event,...typeof record.protocolVersion==="number"?{protocolVersion:record.protocolVersion}:{}}}if(type==="wk:error"){const code=record.code;if(code!=="session_expired"&&code!=="protocol_mismatch"&&code!=="origin_rejected"&&code!=="nonce_mismatch"){return null}return {type:"wk:error",code,...typeof record.protocolVersion==="number"?{protocolVersion:record.protocolVersion}:{}}}return null}function makeNonce(){const c=globalThis.crypto;if(c&&typeof c.randomUUID==="function")return c.randomUUID();return `wkn_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`}function buildInitMessage(dataToken,nonce){return {type:"wk:init",component:REVIEWER_COMPONENT,dataToken,nonce,protocolVersion:LOADER_PROTOCOL_VERSION}}function buildErrorMessage(code){return {type:"wk:error",code,protocolVersion:LOADER_PROTOCOL_VERSION}}function wireWorkspaceTransport(options){const{win,workspaceOrigin,currentNonce,handlers}=options;return initTransport({win,allowedOrigins:[workspaceOrigin],parse:parseWorkspaceInbound,accept:message=>{if(message.type!=="wk:ready")return true;const current=currentNonce();if(current===null)return true;return message.nonce===current},onMessage:(message,post,origin)=>{switch(message.type){case "wk:ready":handlers.onReady(message,post,origin);return;case "wk:token_refresh":handlers.onTokenRefresh(post,origin);return;case "wk:event":handlers.onNavigation(message.event,origin);return;case "wk:error":handlers.onError(message,origin);return;default:return assertNeverInbound(message)}}})}function assertNeverInbound(message){throw new Error(`Unhandled workspace inbound message: ${JSON.stringify(message)}`)}function createWorkspaceTokenPair(getToken,sessionId){let cached=null;let pending=null;let liveDataToken=null;const mint=reason=>{const p=getToken({sessionId:sessionId(),reason});void p.then(bundle=>{liveDataToken=bundle.dataToken;},()=>{});return p};const initialBundle=()=>{if(cached!==null)return cached;const p=mint("initial");cached=p;void p.catch(()=>{if(cached===p)cached=null;});return p};return {framingToken(){return initialBundle().then(b=>b.framingToken)},currentDataToken(){return liveDataToken},dataToken(){return initialBundle().then(b=>b.dataToken)},refreshDataToken(){if(pending!==null)return pending.then(b=>b.dataToken);const p=mint("refresh");pending=p;cached=p;void p.then(()=>{if(pending===p)pending=null;},()=>{if(pending===p)pending=null;if(cached===p)cached=null;});return p.then(b=>b.dataToken)}}}function resolveWorkspaceOrigin(region){return getServiceOrigin(sdkPublicSettings.apps["workspace-embed"].subdomain,"prod",region,sdkPublicSettings)}function resolveWorkspaceBaseOrigin(workspaceBaseUrl,region){if(isCanonicalOrigin(workspaceBaseUrl))return workspaceBaseUrl;return resolveWorkspaceOrigin(region)}var REVIEWER_PATH_PREFIX="/reviewer";function buildReviewerSrc(origin,sessionId,framingToken,theme){const path=`${REVIEWER_PATH_PREFIX}/${encodeURIComponent(sessionId)}`;const url=new URL(path,`${origin}/`);url.searchParams.set("ctx",framingToken);if(theme?.primaryColor!==void 0&&theme.primaryColor.length>0){url.searchParams.set("primary",theme.primaryColor);}if(theme?.colorMode!==void 0){url.searchParams.set("mode",theme.colorMode);}if(theme?.logoUrl!==void 0&&theme.logoUrl.length>0){url.searchParams.set("logo",theme.logoUrl);}if(theme?.brandName!==void 0&&theme.brandName.length>0){url.searchParams.set("brand",theme.brandName);}return url.toString()}var IFRAME_SANDBOX="allow-scripts allow-same-origin allow-downloads";function createReviewerController(deps){return {mount(options){return mountReviewer(deps,options)}}}function mountReviewer(deps,options){const doc=deps.doc??deps.win.document;const{sessionId,target,onEvent}=options;const tokens=createWorkspaceTokenPair(deps.getToken,()=>sessionId);const workspaceOrigin=resolveWorkspaceBaseOrigin(deps.workspaceBaseUrl,deps.region);let currentNonce=null;let consecutiveRefreshRejects=0;const container=doc.createElement("div");target.appendChild(container);const iframe=doc.createElement("iframe");iframe.setAttribute("title","Identity review");iframe.setAttribute("sandbox",IFRAME_SANDBOX);iframe.setAttribute("referrerpolicy","no-referrer");container.appendChild(iframe);let destroyed=false;let transport=null;const emit=event=>{if(destroyed)return;try{onEvent?.(event);}catch{}};const deliverInit=(dataToken,post)=>{if(destroyed)return;currentNonce=makeNonce();post(buildInitMessage(dataToken,currentNonce));};transport=wireWorkspaceTransport({win:deps.win,workspaceOrigin,currentNonce:()=>currentNonce,handlers:{onReady:(_message,post)=>{consecutiveRefreshRejects=0;if(currentNonce!==null)return;void tokens.dataToken().then(dataToken=>{if(destroyed)return;deliverInit(dataToken,post);}).catch(()=>{emit({type:"checktiv.workspace.error",code:"session_expired",recoverable:true,recovery:"retry_review"});});},onTokenRefresh:post=>{void tokens.refreshDataToken().then(fresh=>{consecutiveRefreshRejects=0;deliverInit(fresh,post);}).catch(()=>{if(destroyed)return;consecutiveRefreshRejects+=1;if(consecutiveRefreshRejects>=2){post(buildErrorMessage("session_expired"));emit({type:"checktiv.workspace.error",code:"session_expired",recoverable:true,recovery:"retry_review"});}});},onNavigation:intent=>{emit({type:"checktiv.workspace.navigate",intent});},onError:message=>{const recoverable=message.code==="session_expired";emit({type:"checktiv.workspace.error",code:message.code,recoverable,recovery:recoverable?"retry_review":"reload_host"});}}});void tokens.framingToken().then(framingToken=>{if(destroyed)return;iframe.src=buildReviewerSrc(workspaceOrigin,sessionId,framingToken,deps.theme);}).catch(()=>{emit({type:"checktiv.workspace.error",code:"session_expired",recoverable:true,recovery:"retry_review"});});return {destroy(){if(destroyed)return;destroyed=true;transport?.teardown();transport=null;container.remove();}}}function workspace(config){const controller=createReviewerController({getToken:config.getToken,region:config.region,workspaceBaseUrl:config.workspaceBaseUrl,theme:config.theme,win:window});return {mount(_component,options){return controller.mount(options)}}}
|
|
5
|
+
function isOriginTargetedPoster(value){return typeof value==="object"&&value!==null&&"postMessage"in value}function initTransport(options,announce){const{win,allowedOrigins,parse,onMessage,accept,reAnnounce}=options;if(!Array.isArray(allowedOrigins)||allowedOrigins.length===0){return {teardown:()=>{}}}const allowlist=new Set(allowedOrigins);const onMessageListener=event=>{if(!allowlist.has(event.origin))return;const parsed=parse(event.data);if(parsed===null)return;if(accept&&!accept(parsed,event.origin))return;const source=event.source;if(!isOriginTargetedPoster(source))return;const post=message=>source.postMessage(message,event.origin);onMessage(parsed,post,event.origin);};win.addEventListener("message",onMessageListener);const broadcast=message=>{for(const origin of allowlist){win.parent.postMessage(message,origin);}};let timer=null;if(reAnnounce!==void 0&&reAnnounce.maxAttempts>0){const scheduler=reAnnounce.schedule??{set:(cb,ms)=>setTimeout(cb,ms),clear:handle=>clearTimeout(handle)};let attemptsLeft=reAnnounce.maxAttempts;const tick=()=>{if(attemptsLeft<=0){timer=null;return}attemptsLeft-=1;broadcast(reAnnounce.message);timer=attemptsLeft>0?scheduler.set(tick,reAnnounce.intervalMs):null;};timer=scheduler.set(tick,reAnnounce.intervalMs);return {teardown:()=>{win.removeEventListener("message",onMessageListener);if(timer!==null){scheduler.clear(timer);timer=null;}}}}return {teardown:()=>{win.removeEventListener("message",onMessageListener);}}}var REVIEWER_COMPONENT="reviewer";var LOADER_PROTOCOL_VERSION=1;var NAVIGATION_EVENTS=new Set(["session_complete","navigate_away"]);function parseWorkspaceInbound(data){if(typeof data!=="object"||data===null)return null;const record=data;const type=record.type;if(type==="wk:ready"){if(record.component!==REVIEWER_COMPONENT)return null;if(typeof record.sessionId!=="string"||record.sessionId.length===0)return null;if(typeof record.nonce!=="string"||record.nonce.length===0)return null;return {type:"wk:ready",component:REVIEWER_COMPONENT,sessionId:record.sessionId,nonce:record.nonce,...typeof record.protocolVersion==="number"?{protocolVersion:record.protocolVersion}:{}}}if(type==="wk:token_refresh"){return {type:"wk:token_refresh",...typeof record.protocolVersion==="number"?{protocolVersion:record.protocolVersion}:{}}}if(type==="wk:event"){if(record.component!==REVIEWER_COMPONENT)return null;const event=record.event;if(typeof event!=="string"||!NAVIGATION_EVENTS.has(event)){return null}return {type:"wk:event",component:REVIEWER_COMPONENT,event,...typeof record.protocolVersion==="number"?{protocolVersion:record.protocolVersion}:{}}}if(type==="wk:error"){const code=record.code;if(code!=="session_expired"&&code!=="protocol_mismatch"&&code!=="origin_rejected"&&code!=="nonce_mismatch"){return null}return {type:"wk:error",code,...typeof record.protocolVersion==="number"?{protocolVersion:record.protocolVersion}:{}}}return null}function makeNonce(){const c=globalThis.crypto;if(c&&typeof c.randomUUID==="function")return c.randomUUID();return `wkn_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`}function buildInitMessage(dataToken,nonce){return {type:"wk:init",component:REVIEWER_COMPONENT,dataToken,nonce,protocolVersion:LOADER_PROTOCOL_VERSION}}function buildErrorMessage(code){return {type:"wk:error",code,protocolVersion:LOADER_PROTOCOL_VERSION}}function wireWorkspaceTransport(options){const{win,workspaceOrigin,currentNonce,handlers}=options;return initTransport({win,allowedOrigins:[workspaceOrigin],parse:parseWorkspaceInbound,accept:message=>{if(message.type!=="wk:ready")return true;const current=currentNonce();if(current===null)return true;return message.nonce===current},onMessage:(message,post,origin)=>{switch(message.type){case "wk:ready":handlers.onReady(message,post,origin);return;case "wk:token_refresh":handlers.onTokenRefresh(post,origin);return;case "wk:event":handlers.onNavigation(message.event,origin);return;case "wk:error":handlers.onError(message,origin);return;default:return assertNeverInbound(message)}}})}function assertNeverInbound(message){throw new Error(`Unhandled workspace inbound message: ${JSON.stringify(message)}`)}function createWorkspaceTokenPair(getToken,sessionId){let cached=null;let pending=null;let liveDataToken=null;const mint=reason=>{const p=getToken({sessionId:sessionId(),reason});void p.then(bundle=>{liveDataToken=bundle.dataToken;},()=>{});return p};const initialBundle=()=>{if(cached!==null)return cached;const p=mint("initial");cached=p;void p.catch(()=>{if(cached===p)cached=null;});return p};return {framingToken(){return initialBundle().then(b=>b.framingToken)},currentDataToken(){return liveDataToken},dataToken(){return initialBundle().then(b=>b.dataToken)},refreshDataToken(){if(pending!==null)return pending.then(b=>b.dataToken);const p=mint("refresh");pending=p;cached=p;void p.then(()=>{if(pending===p)pending=null;},()=>{if(pending===p)pending=null;if(cached===p)cached=null;});return p.then(b=>b.dataToken)}}}function resolveWorkspaceOrigin(region){return getServiceOrigin(sdkPublicSettings.apps["workspace-embed"].subdomain,"prod",region,sdkPublicSettings)}function resolveWorkspaceBaseOrigin(workspaceBaseUrl,region){if(isCanonicalOrigin(workspaceBaseUrl))return workspaceBaseUrl;return resolveWorkspaceOrigin(region)}var REVIEWER_PATH_PREFIX="/reviewer";function buildReviewerSrc(origin,sessionId,framingToken,theme){const path=`${REVIEWER_PATH_PREFIX}/${encodeURIComponent(sessionId)}`;const url=new URL(path,`${origin}/`);url.searchParams.set("ctx",framingToken);if(theme?.primaryColor!==void 0&&theme.primaryColor.length>0){url.searchParams.set("primary",theme.primaryColor);}if(theme?.colorMode!==void 0){url.searchParams.set("mode",theme.colorMode);}if(theme?.logoUrl!==void 0&&theme.logoUrl.length>0){url.searchParams.set("logo",theme.logoUrl);}if(theme?.brandName!==void 0&&theme.brandName.length>0){url.searchParams.set("brand",theme.brandName);}return url.toString()}var IFRAME_SANDBOX="allow-scripts allow-same-origin allow-downloads";function createReviewerController(deps){return {mount(options){return mountReviewer(deps,options)}}}function mountReviewer(deps,options){const doc=deps.doc??deps.win.document;const{sessionId,target,onEvent}=options;const tokens=createWorkspaceTokenPair(deps.getToken,()=>sessionId);const workspaceOrigin=resolveWorkspaceBaseOrigin(deps.workspaceBaseUrl,deps.region);let currentNonce=null;let consecutiveRefreshRejects=0;const container=doc.createElement("div");container.style.width="100%";container.style.height="100%";target.appendChild(container);const iframe=doc.createElement("iframe");iframe.setAttribute("title","Identity review");iframe.setAttribute("sandbox",IFRAME_SANDBOX);iframe.setAttribute("referrerpolicy","no-referrer");Object.assign(iframe.style,{width:"100%",height:"100%",border:"0",display:"block"});container.appendChild(iframe);let destroyed=false;let transport=null;const emit=event=>{if(destroyed)return;try{onEvent?.(event);}catch{}};const deliverInit=(dataToken,post)=>{if(destroyed)return;currentNonce=makeNonce();post(buildInitMessage(dataToken,currentNonce));};transport=wireWorkspaceTransport({win:deps.win,workspaceOrigin,currentNonce:()=>currentNonce,handlers:{onReady:(_message,post)=>{consecutiveRefreshRejects=0;if(currentNonce!==null)return;void tokens.dataToken().then(dataToken=>{if(destroyed)return;deliverInit(dataToken,post);}).catch(()=>{emit({type:"checktiv.workspace.error",code:"session_expired",recoverable:true,recovery:"retry_review"});});},onTokenRefresh:post=>{void tokens.refreshDataToken().then(fresh=>{consecutiveRefreshRejects=0;deliverInit(fresh,post);}).catch(()=>{if(destroyed)return;consecutiveRefreshRejects+=1;if(consecutiveRefreshRejects>=2){post(buildErrorMessage("session_expired"));emit({type:"checktiv.workspace.error",code:"session_expired",recoverable:true,recovery:"retry_review"});}});},onNavigation:intent=>{emit({type:"checktiv.workspace.navigate",intent});},onError:message=>{const recoverable=message.code==="session_expired";emit({type:"checktiv.workspace.error",code:message.code,recoverable,recovery:recoverable?"retry_review":"reload_host"});}}});void tokens.framingToken().then(framingToken=>{if(destroyed)return;iframe.src=buildReviewerSrc(workspaceOrigin,sessionId,framingToken,deps.theme);}).catch(()=>{emit({type:"checktiv.workspace.error",code:"session_expired",recoverable:true,recovery:"retry_review"});});return {destroy(){if(destroyed)return;destroyed=true;transport?.teardown();transport=null;container.remove();}}}function workspace(config){const controller=createReviewerController({getToken:config.getToken,region:config.region,workspaceBaseUrl:config.workspaceBaseUrl,theme:config.theme,win:window});return {mount(_component,options){return controller.mount(options)}}}
|
|
6
6
|
|
|
7
7
|
export { workspace };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@checktiv/sdk-web",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"//publishConfigNameNote": "pnpm does NOT apply `publishConfig.name` (the publishConfig override list at https://pnpm.io/package_json#publishconfig excludes `name`; `pnpm pack` leaves the tarball `name` as the workspace name). The published `name` rewrite to `@checktiv/sdk-web` happens in the root `.pnpmfile.cjs` `beforePacking` hook (pnpm >= 10.28) instead — see that file's header. This field is retained ONLY as documentation of intent; the hook deletes it from the packed manifest. The packed-name gate in __tests__/dist-shape.test.ts reads the REAL extracted tarball, not this field.",
|
|
@@ -60,10 +60,11 @@
|
|
|
60
60
|
"./package.json": "./package.json"
|
|
61
61
|
},
|
|
62
62
|
"//challengeExportNote": "The `./challenge` subpath (top-level `exports` only, ABSENT from `publishConfig.exports`) is the generic parent-side challenge relay kernel consumed by `apps/verify` (ChallengeIframe). It stays OFF the npm-publish boundary (no schema-mirror / dist-shape / bundle-budget / CDN build), like `./agent`. tsup emits `dist/challenge.js` from the entry map for the in-repo `import` condition.",
|
|
63
|
-
"//sideEffectsNote": "The module-load seam (src/substrate/module-registry.ts) makes the `./idv`, `./fraud`, and `./custom-form` entries SIDE-EFFECTFUL: each calls registerModule(...) at import-eval time so the substrate's mount('idv'|'fraud'|'custom_form')/mountProvisioned can resolve it. `./idv/cross-device` is ALSO side-effectful: it calls registerCrossDeviceOpener(...) (src/idv/cross-device-registry.ts) so createIdv().openCrossDevice() (S13/B2) resolves the overlay WITHOUT idv/index.ts importing the heavy orchestrator (keeps the CDN sdk.js flat). A blanket `sideEffects: false` would let a consumer's bundler tree-shake those registrations away (breaking the seams), so this lists ONLY the side-effectful entry files (src + published dist forms). Everything else still tree-shakes, so the `.` and `./react` entries stay Zod-free and per-subpath tree-shaking holds. When plan-C rewrites this manifest, KEEP this array (do NOT replace it with `false`).",
|
|
63
|
+
"//sideEffectsNote": "The module-load seam (src/substrate/module-registry.ts) makes the `./idv`, `./fraud`, and `./custom-form` entries SIDE-EFFECTFUL: each calls registerModule(...) at import-eval time so the substrate's mount('idv'|'fraud'|'custom_form')/mountProvisioned can resolve it. `./idv/cross-device` is ALSO side-effectful: it calls registerCrossDeviceOpener(...) (src/idv/cross-device-registry.ts) so createIdv().openCrossDevice() (S13/B2) resolves the overlay WITHOUT idv/index.ts importing the heavy orchestrator (keeps the CDN sdk.js flat). `src/idv/cross-device-cdn.ts` is the CDN-ONLY counterpart (imported for its side effect by src/cdn.ts, NOT a published subpath so it has no dist form): it registers a wrapper opener that injects a runtime chunk-URL importer so the CDN IIFE (window.Checktiv.mount) resolves the overlay by loading the pre-built /v1/cross-device.js chunk by URL instead of inlining the QR panel into sdk.js. Its registration side effect MUST be listed here or esbuild tree-shakes the side-effect-only `import './idv/cross-device-cdn.js'` in src/cdn.ts, leaving getCrossDeviceOpener() null in the IIFE. A blanket `sideEffects: false` would let a consumer's bundler tree-shake those registrations away (breaking the seams), so this lists ONLY the side-effectful entry files (src + published dist forms). Everything else still tree-shakes, so the `.` and `./react` entries stay Zod-free and per-subpath tree-shaking holds. When plan-C rewrites this manifest, KEEP this array (do NOT replace it with `false`).",
|
|
64
64
|
"sideEffects": [
|
|
65
65
|
"./src/idv/index.ts",
|
|
66
66
|
"./src/idv/cross-device.ts",
|
|
67
|
+
"./src/idv/cross-device-cdn.ts",
|
|
67
68
|
"./src/fraud/index.ts",
|
|
68
69
|
"./src/custom-form/index.ts",
|
|
69
70
|
"./src/cdn.ts",
|
|
@@ -112,10 +113,10 @@
|
|
|
112
113
|
"tsup": "^8.5.0",
|
|
113
114
|
"typescript": "5.9.3",
|
|
114
115
|
"vitest": "^4.1.9",
|
|
116
|
+
"@rf/config": "0.0.0",
|
|
115
117
|
"@rf/iam-core": "0.0.1",
|
|
116
118
|
"@rf/schemas": "0.1.0",
|
|
117
|
-
"@rf/theme": "0.1.0"
|
|
118
|
-
"@rf/config": "0.0.0"
|
|
119
|
+
"@rf/theme": "0.1.0"
|
|
119
120
|
},
|
|
120
121
|
"scripts": {
|
|
121
122
|
"build": "tsup && node scripts/generate-agent-steering.mjs && pnpm run build:embed-capture && pnpm run build:embed-challenge && pnpm run build:host-capture && pnpm run build:cross-device",
|
package/dist/chunk-BEZGAQ74.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { getModule } from './chunk-GFHNOZVO.js';
|
|
2
|
-
import { assertNever } from './chunk-UBQTPS5J.js';
|
|
3
|
-
import { createTokenManager, resolveSession, warnWrongTokenPlane, createChecktivError } from './chunk-QVDWM4KK.js';
|
|
4
|
-
import { resolveApiBaseOrigin } from './chunk-ITLSDZHK.js';
|
|
5
|
-
|
|
6
|
-
var PUBLISHABLE_KEY_REGEX=/^ah_pk_(us|eu)_(live|test)_[A-Za-z0-9_-]{8,}$/;var InvalidPublishableKeyError=class extends Error{constructor(message){super(message);this.name="InvalidPublishableKeyError";}};function parsePublishableKey(key){const match=PUBLISHABLE_KEY_REGEX.exec(key);if(!match){throw new InvalidPublishableKeyError(`Invalid publishable key format. Expected ah_pk_<us|eu>_<live|test>_<token>, got: ${maskKey(key)}`)}const region=match[1];const mode=match[2];if(region!=="us"&®ion!=="eu"){throw new InvalidPublishableKeyError(`Invalid region in publishable key: ${maskKey(key)}`)}if(mode!=="test"&&mode!=="live"){throw new InvalidPublishableKeyError(`Invalid mode in publishable key: ${maskKey(key)}`)}return {region,mode}}function maskKey(key){if(key.length<=8)return "***";return `${key.slice(0,6)}...${key.slice(-2)}`}function moduleErrorEvent(name,error){switch(name){case "idv":return {type:"checktiv.idv.error",error};case "fraud":return {type:"checktiv.fraud.error",error};case "custom_form":return {type:"checktiv.custom_form.error",error}}}function missingModuleMessage(name){return `This session requires the '${name}' module. Import '@checktiv/sdk-web/${name}' in your app.`}function missingModuleError(name){const base=createChecktivError("sdk_load_failed");return moduleErrorEvent(name,{...base,message:missingModuleMessage(name)})}function consentGateRequiredError(){const base=createChecktivError("sdk_load_failed");return moduleErrorEvent("fraud",{...base,message:"This session includes the 'fraud' module, which needs a consent gate. Pass onConsent to mountProvisioned() to enable it."})}function customFormConfigRequiredError(){const base=createChecktivError("sdk_load_failed");return moduleErrorEvent("custom_form",{...base,message:"This session includes the 'custom_form' module, which needs its form config. Pass customFormConfig to mountProvisioned() to enable it."})}function unmappedStepTypeError(stepType){const base=createChecktivError("sdk_load_failed");return moduleErrorEvent("idv",{...base,message:`This session's current step ('${stepType}') has no matching visual module in this SDK build. Upgrade '@checktiv/sdk-web' to a version that renders this step.`})}var MODULE_IS_VISUAL={idv:true,fraud:false,custom_form:true};var STEP_TYPE_TO_VISUAL_MODULE={id_verification:"idv",custom_form:"custom_form"};var stepTypeToVisualModuleView=STEP_TYPE_TO_VISUAL_MODULE;function resolveCurrentStepVisualModule(stepType){return stepTypeToVisualModuleView[stepType]}function defaultLoadModule(name){if(name==="idv"){const factory2=getModule("idv");if(factory2===void 0)return Promise.resolve(null);return Promise.resolve({mount:(ctx,opts)=>factory2(ctx,{target:opts.target,onEvent:opts.onEvent,copy:opts.copy,layout:opts.layout,onBeforeSubmit:opts.onBeforeSubmit,onBehaviorSegment:opts.onBehaviorSegment,synthetic:opts.synthetic})})}if(name==="custom_form"){const factory2=getModule("custom_form");if(factory2===void 0)return Promise.resolve(null);return Promise.resolve({mount:(ctx,opts)=>{if(opts.customFormConfig===void 0){opts.onEvent?.(customFormConfigRequiredError());return {destroy:()=>void 0}}return factory2(ctx,{target:opts.target,config:opts.customFormConfig,copy:opts.customFormCopy,onEvent:opts.onEvent,session:opts.session})}})}const factory=getModule("fraud");if(factory===void 0)return Promise.resolve(null);return Promise.resolve({mount:(ctx,opts)=>{const onConsent=opts.onConsent;if(onConsent===void 0){opts.onEvent?.(consentGateRequiredError());return {destroy:()=>void 0}}return factory(ctx,{onConsent,onEvent:opts.onEvent})}})}function moduleErrorFor(name,code){return moduleErrorEvent(name,createChecktivError(code))}function createMountProvisioned(ctx,opts,deps={}){const emit=e=>opts.onEvent?.(e);const fetchImpl=opts.fetchImpl??fetch;const resolveSession2=deps.resolveSession??(()=>resolveSession(ctx,fetchImpl));const loadModule=deps.loadModule??defaultLoadModule;const handles=[];let destroyed=false;void(async()=>{try{await composeModules();}catch(err){if(destroyed)return;console.warn("[Checktiv] mountProvisioned composition failed.",err);emit(moduleErrorFor("idv","sdk_load_failed"));}})();async function composeModules(){const resolution=await resolveSession2();if(destroyed)return;let session;switch(resolution.kind){case "ok":session=resolution.session;break;case "wrong_token":warnWrongTokenPlane();emit(moduleErrorFor("idv","wrong_token_type"));return;case "unresolved":emit(moduleErrorFor("idv","session_expired"));return;default:return assertNever(resolution)}const currentStepVisualModule=resolveCurrentStepVisualModule(session.stepType);if(currentStepVisualModule===void 0&&session.modules.some(m=>MODULE_IS_VISUAL[m])){emit(unmappedStepTypeError(session.stepType));return}for(const name of session.modules){if(destroyed)return;if(MODULE_IS_VISUAL[name]&&name!==currentStepVisualModule){continue}if(name==="fraud"&&opts.onConsent===void 0){emit(consentGateRequiredError());continue}const mod=await loadModule(name);if(destroyed)return;if(mod===null){emit(missingModuleError(name));continue}let moduleTarget;let containerToRemove=null;if(MODULE_IS_VISUAL[name]){const resolvedParent=typeof opts.target==="string"?typeof document!=="undefined"?document.querySelector(opts.target):null:opts.target;if(resolvedParent!==null){const container=document.createElement("div");resolvedParent.appendChild(container);containerToRemove=container;moduleTarget=container;}else {moduleTarget=opts.target;}}else {moduleTarget=opts.target;}let innerHandle;try{innerHandle=mod.mount(ctx,{target:moduleTarget,onEvent:opts.onEvent,onConsent:opts.onConsent,copy:opts.copy,layout:opts.layout,onBeforeSubmit:opts.onBeforeSubmit,onBehaviorSegment:opts.onBehaviorSegment,synthetic:opts.synthetic,customFormConfig:opts.customFormConfig,customFormCopy:opts.customFormCopy,session:{sessionId:session.sessionId,stepId:session.stepId}});}catch(err){containerToRemove?.remove();throw err}const capturedContainer=containerToRemove;const handle={destroy(){try{innerHandle.destroy();}finally{capturedContainer?.remove();}}};if(destroyed){handle.destroy();return}handles.push(handle);}}return {destroy(){destroyed=true;while(handles.length>0){const handle=handles.pop();handle?.destroy();}}}}function init(opts,deps={}){const scope="publishableKey"in opts?{...parsePublishableKey(opts.publishableKey),publishableKey:opts.publishableKey}:{region:opts.region,mode:opts.mode,publishableKey:void 0};let sessionId="";const apiBaseOrigin=resolveApiBaseOrigin(opts.apiBase,scope.region,scope.mode);const ctx={region:scope.region,mode:scope.mode,publishableKey:scope.publishableKey,apiBaseOrigin,theme:opts.theme,locale:opts.locale??"en",betas:opts.betas??[],...opts.selfiePromptMap!==void 0?{selfiePromptMap:opts.selfiePromptMap}:{},...opts.selfieChromeCopy!==void 0?{selfieChromeCopy:opts.selfieChromeCopy}:{},tokens:deps.tokens??createTokenManager(opts.getSessionToken,()=>sessionId),getSessionId:()=>sessionId,setSessionId:id=>{sessionId=id;}};function mount(...args){if(args[0]==="idv"){const factory2=getModule("idv");if(factory2===void 0)return missingIdvHandle(args[1]);return factory2(ctx,args[1])}if(args[0]==="custom_form"){const factory2=getModule("custom_form");if(factory2===void 0)return missingCustomFormHandle(args[1]);return factory2(ctx,args[1])}const factory=getModule("fraud");if(factory===void 0)return missingFraudHandle(args[1]);return factory(ctx,args[1])}return {mountProvisioned:provOpts=>createMountProvisioned(ctx,provOpts),mount}}function missingIdvHandle(opts){const base=createChecktivError("sdk_load_failed");opts.onEvent?.({type:"checktiv.idv.error",error:{...base,message:missingModuleMessage("idv")}});return {destroy:()=>void 0,unmount:()=>void 0}}function missingFraudHandle(opts){const base=createChecktivError("sdk_load_failed");opts.onEvent?.({type:"checktiv.fraud.error",error:{...base,message:missingModuleMessage("fraud")}});return {destroy:()=>void 0}}function missingCustomFormHandle(opts){const base=createChecktivError("sdk_load_failed");const error={type:"checktiv.custom_form.error",error:{...base,message:missingModuleMessage("custom_form")}};opts.onEvent?.(error);return {destroy:()=>void 0}}
|
|
7
|
-
|
|
8
|
-
export { InvalidPublishableKeyError, init, parsePublishableKey };
|
package/dist/chunk-ITLSDZHK.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { getServiceOrigin } from './chunk-QFA3K5ZV.js';
|
|
2
|
-
|
|
3
|
-
var sdkPublicSettings={"project":{"marketingApex":"checktiv.com"},"apps":{"verify":{"subdomain":"verify"},"workspace-embed":{"subdomain":"workspace"}},"services":{"sdk-api":{"subdomain":"sdk-api"}},"regions":{"us":{"apex":"us.checktiv.com"},"eu":{"apex":"eu.checktiv.com"}}};var PUBLISHABLE_KEY_HEADER="X-Publishable-Key";function dataPlaneHeaders(ctx,token,opts={}){const headers={Authorization:`Bearer ${token}`};if(ctx.publishableKey!==void 0){headers[PUBLISHABLE_KEY_HEADER]=ctx.publishableKey;}if(opts.withJsonBody)headers["content-type"]="application/json";return headers}function resolveSdkApiOrigin(region,_mode,_hostname){return getServiceOrigin(sdkPublicSettings.services["sdk-api"].subdomain,"prod",region,sdkPublicSettings)}function isCanonicalOrigin(value){if(typeof value!=="string"||value.length===0)return false;try{return new URL(value).origin===value}catch{return false}}function resolveApiBaseOrigin(apiBase,region,mode,hostname){if(isCanonicalOrigin(apiBase))return apiBase;return resolveSdkApiOrigin(region)}var SESSIONS_ME_PATH="/sdk/v1/sessions/me";var WORKING_TOKEN_MINT_PATH="/sdk/v1/working-token";var CAPTURE_TOKEN_MINT_PATH="/sdk/v1/idv/capture-token";function stepSubmitPath(_sessionId,stepId){return `${SESSIONS_ME_PATH}/steps/${encodeURIComponent(stepId)}/submit`}var TELEMETRY_PATH="/sdk/v1/telemetry";var SESSIONS_ME_REFRESH_LINK_PATH="/sdk/v1/sessions/me/refresh-link";function shortCodeRefreshPath(code){return `/sdk/v1/short-codes/${encodeURIComponent(code)}/refresh`}function formUploadUrlPath(stepId){return `${SESSIONS_ME_PATH}/steps/${encodeURIComponent(stepId)}/form-upload-url`}
|
|
4
|
-
|
|
5
|
-
export { CAPTURE_TOKEN_MINT_PATH, PUBLISHABLE_KEY_HEADER, SESSIONS_ME_PATH, SESSIONS_ME_REFRESH_LINK_PATH, TELEMETRY_PATH, WORKING_TOKEN_MINT_PATH, dataPlaneHeaders, formUploadUrlPath, isCanonicalOrigin, resolveApiBaseOrigin, sdkPublicSettings, shortCodeRefreshPath, stepSubmitPath };
|