@checktiv/sdk-web 1.0.0 → 1.2.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.
Files changed (50) hide show
  1. package/README.md +172 -96
  2. package/dist/agents/AGENTS.md +20 -25
  3. package/dist/agents/manifest.json +15 -4
  4. package/dist/{types-CnlkFS7V.d.ts → api-DyExBfAQ.d.ts} +161 -97
  5. package/dist/capture-ui.css +1 -1
  6. package/dist/capture-ui.d.ts +5 -4
  7. package/dist/capture-ui.js +4 -2
  8. package/dist/capture.d.ts +3 -3
  9. package/dist/capture.js +3 -1
  10. package/dist/challenge.d.ts +18 -0
  11. package/dist/challenge.js +9 -0
  12. package/dist/chunk-5AQCMTZV.js +6 -0
  13. package/dist/chunk-5MNNRYD5.js +7 -0
  14. package/dist/{chunk-TRTAZKYV.js → chunk-6U53T32A.js} +4 -3
  15. package/dist/chunk-BEZGAQ74.js +8 -0
  16. package/dist/chunk-GFHNOZVO.js +3 -0
  17. package/dist/chunk-IQKHRPJR.js +3 -0
  18. package/dist/chunk-ITLSDZHK.js +5 -0
  19. package/dist/chunk-LTMLIUPC.js +5 -0
  20. package/dist/chunk-QVDWM4KK.js +6 -0
  21. package/dist/chunk-UBQTPS5J.js +3 -0
  22. package/dist/{controller-C4vJ47JI.d.ts → controller-CFL3mA5e.d.ts} +2 -2
  23. package/dist/copy-DCeQ4JKx.d.ts +19 -0
  24. package/dist/{copy-DeUly5vr.d.ts → copy-Dfmk11S_.d.ts} +2 -2
  25. package/dist/cross-device.d.ts +19 -1
  26. package/dist/custom-form.css +1 -1
  27. package/dist/custom-form.d.ts +4 -3
  28. package/dist/custom-form.js +6 -3
  29. package/dist/fraud.d.ts +4 -3
  30. package/dist/fraud.js +6 -4
  31. package/dist/idv/cross-device.d.ts +41 -6
  32. package/dist/idv/cross-device.js +7 -3
  33. package/dist/idv.css +1 -1
  34. package/dist/idv.d.ts +4 -3
  35. package/dist/idv.js +10 -6
  36. package/dist/index.d.ts +19 -6
  37. package/dist/index.js +9 -7
  38. package/dist/{machine--zVZIM4F.d.ts → machine-CuZalPFX.d.ts} +15 -3
  39. package/dist/react.d.ts +6 -4
  40. package/dist/react.js +7 -5
  41. package/dist/workspace.d.ts +60 -0
  42. package/dist/workspace.js +7 -0
  43. package/package.json +15 -5
  44. package/dist/chunk-BYTKOKAD.js +0 -7
  45. package/dist/chunk-C7H2ZVQT.js +0 -7
  46. package/dist/chunk-CXNPD67Z.js +0 -5
  47. package/dist/chunk-FGWZZNAN.js +0 -5
  48. package/dist/chunk-WQCYRLWP.js +0 -3
  49. package/dist/fp.esm.min-QD5CJD52.js +0 -5
  50. package/dist/index-BtJbU9MC.d.ts +0 -43
@@ -1,34 +1,13 @@
1
- import { a as CoachingKind, C as CaptureBehaviorMessage, S as SelfiePromptMap } from './machine--zVZIM4F.js';
2
- import { M as MountCopy } from './copy-DeUly5vr.js';
1
+ import { C as CaptureLayout, a as CaptureBehaviorMessage, S as SelfiePromptMap, h as SelfieChromeCopy, b as CoachingKind } from './machine-CuZalPFX.js';
2
+ import { M as MountCopy } from './copy-Dfmk11S_.js';
3
+ import { C as CrossDeviceCopy } from './copy-DCeQ4JKx.js';
3
4
 
4
5
  declare const SystemModes: readonly ["live", "test"];
5
6
  type SystemMode = (typeof SystemModes)[number];
6
7
  declare const DataRegions: readonly ["us", "eu"];
7
8
  type DataRegion = (typeof DataRegions)[number];
8
9
 
9
- type SdkRegion = DataRegion;
10
- type SdkMode = SystemMode;
11
- interface InitOptions {
12
- readonly publishableKey: string;
13
- readonly applicantLinkToken?: string;
14
- readonly target?: HTMLElement;
15
- readonly onComplete?: (payload: unknown) => void;
16
- }
17
- interface ParsedPublishableKey {
18
- readonly region: SdkRegion;
19
- readonly mode: SdkMode;
20
- }
21
- declare class InvalidPublishableKeyError extends Error {
22
- constructor(message: string);
23
- }
24
- declare function parsePublishableKey(key: string): ParsedPublishableKey;
25
-
26
- interface TokenManager {
27
- get(): Promise<string>;
28
- refresh(reason: 'expired' | '401'): Promise<string>;
29
- }
30
-
31
- type ChecktivErrorCode = 'origin_not_allowed' | 'token_expired' | 'session_expired' | 'protocol_mismatch' | 'camera_denied' | 'cv_gate_failed' | 'upload_failed' | 'sdk_load_failed' | 'biometric_unsupported' | 'isolation_required';
10
+ type ChecktivErrorCode = 'origin_not_allowed' | 'token_expired' | 'session_expired' | 'wrong_token_type' | 'protocol_mismatch' | 'camera_denied' | 'camera_unsupported' | 'cv_gate_failed' | 'upload_failed' | 'sdk_load_failed' | 'biometric_unsupported' | 'isolation_required';
32
11
  interface ChecktivError {
33
12
  code: ChecktivErrorCode;
34
13
  recoverable: boolean;
@@ -36,53 +15,10 @@ interface ChecktivError {
36
15
  message: string;
37
16
  }
38
17
 
39
- type ChecktivFraudEvent = {
40
- type: 'checktiv.fraud.started';
41
- } | {
42
- type: 'checktiv.fraud.error';
43
- error: ChecktivError;
44
- };
45
- interface FraudMountOptions {
46
- onConsent: () => boolean | Promise<boolean>;
47
- onEvent?: (e: ChecktivFraudEvent) => void;
48
- fetchImpl?: typeof fetch;
49
- }
50
- interface FraudHandle {
51
- destroy(): void;
52
- }
53
- declare function createFraud(ctx: SubstrateContext, opts: FraudMountOptions): FraudHandle;
54
-
55
- type IdvCoachingHint = CoachingKind;
56
- interface ResolvedIdvConfig {
57
- documentTypes: readonly string[];
58
- biometricMode: 'selfie' | 'liveness' | 'none';
18
+ interface TokenManager {
19
+ get(): Promise<string>;
20
+ refresh(reason: 'expired' | '401'): Promise<string>;
59
21
  }
60
- type ChecktivIdvEvent = {
61
- type: 'checktiv.idv.ready';
62
- config: ResolvedIdvConfig;
63
- } | {
64
- type: 'checktiv.idv.phase';
65
- phase: string;
66
- } | {
67
- type: 'checktiv.idv.coaching';
68
- hint: IdvCoachingHint;
69
- } | {
70
- type: 'checktiv.idv.submitted';
71
- sessionId: string;
72
- } | {
73
- type: 'checktiv.idv.processing';
74
- } | {
75
- type: 'checktiv.idv.error';
76
- error: ChecktivError;
77
- } | {
78
- type: 'checktiv.idv.cross_device_opened';
79
- } | {
80
- type: 'checktiv.idv.cross_device_unavailable';
81
- };
82
- type ChecktivEvent = ChecktivIdvEvent | ChecktivFraudEvent | {
83
- type: `checktiv.${string}`;
84
- [k: string]: unknown;
85
- };
86
22
 
87
23
  interface SyntheticIdvScript {
88
24
  injectError?: ChecktivErrorCode;
@@ -99,43 +35,22 @@ interface IdvMountOptions {
99
35
  target: HTMLElement | string;
100
36
  onEvent?: (e: ChecktivIdvEvent) => void;
101
37
  copy?: MountCopy;
38
+ layout?: CaptureLayout;
102
39
  onBeforeSubmit?: () => Promise<void>;
103
40
  onBehaviorSegment?: (segment: Pick<CaptureBehaviorMessage, 'steps' | 'traits'>) => void;
104
41
  fetchImpl?: typeof fetch;
105
42
  synthetic?: SyntheticIdvScript;
43
+ onOpenCrossDevice?: CrossDeviceHandoffHook;
44
+ crossDeviceCopy?: CrossDeviceCopy;
106
45
  }
107
46
  interface IdvHandle {
108
47
  destroy(): void;
109
48
  unmount(): void;
49
+ openCrossDevice?(): void;
110
50
  }
111
51
  declare const REMINT_READY_TIMEOUT_MS = 15000;
112
52
  declare function createIdv(ctx: SubstrateContext, opts: IdvMountOptions): IdvHandle;
113
53
 
114
- interface CustomFormFieldCopy {
115
- readonly label?: string;
116
- readonly helpText?: string;
117
- readonly options?: Readonly<Record<string, string>>;
118
- }
119
- interface CustomFormCopy {
120
- readonly fields?: Readonly<Record<string, CustomFormFieldCopy>>;
121
- readonly submit?: string;
122
- readonly requiredError?: string;
123
- readonly uploadError?: string;
124
- readonly submitError?: string;
125
- readonly booleanYes?: string;
126
- readonly booleanNo?: string;
127
- }
128
-
129
- type ChecktivCustomFormEvent = {
130
- type: 'checktiv.custom_form.ready';
131
- } | {
132
- type: 'checktiv.custom_form.submitted';
133
- sessionId: string;
134
- } | {
135
- type: 'checktiv.custom_form.error';
136
- error: ChecktivError;
137
- };
138
-
139
54
  declare const FORM_FIELD_TYPES: readonly ["short_text", "long_text", "number", "email", "phone", "date", "single_select", "multi_select", "boolean", "file_upload", "content_heading", "content_paragraph"];
140
55
  type FormFieldType = (typeof FORM_FIELD_TYPES)[number];
141
56
 
@@ -166,6 +81,39 @@ type CustomFormApplicantConfig = {
166
81
  fields: CustomFormApplicantField[];
167
82
  };
168
83
 
84
+ interface CustomFormFieldCopy {
85
+ readonly label?: string;
86
+ readonly helpText?: string;
87
+ readonly options?: Readonly<Record<string, string>>;
88
+ }
89
+ interface CustomFormCopy {
90
+ readonly fields?: Readonly<Record<string, CustomFormFieldCopy>>;
91
+ readonly submit?: string;
92
+ readonly requiredError?: string;
93
+ readonly invalidPhoneError?: string;
94
+ readonly invalidEmailError?: string;
95
+ readonly invalidDateError?: string;
96
+ readonly invalidOptionError?: string;
97
+ readonly outOfRangeError?: string;
98
+ readonly invalidFormatError?: string;
99
+ readonly invalidError?: string;
100
+ readonly validationError?: string;
101
+ readonly uploadError?: string;
102
+ readonly submitError?: string;
103
+ readonly booleanYes?: string;
104
+ readonly booleanNo?: string;
105
+ }
106
+
107
+ type ChecktivCustomFormEvent = {
108
+ type: 'checktiv.custom_form.ready';
109
+ } | {
110
+ type: 'checktiv.custom_form.submitted';
111
+ sessionId: string;
112
+ } | {
113
+ type: 'checktiv.custom_form.error';
114
+ error: ChecktivError;
115
+ };
116
+
169
117
  interface CustomFormMountOptions {
170
118
  target: HTMLElement | string;
171
119
  config: CustomFormApplicantConfig;
@@ -191,6 +139,7 @@ interface MountProvisionedOptions {
191
139
  onEvent?: (e: ChecktivEvent) => void;
192
140
  onConsent?: () => boolean | Promise<boolean>;
193
141
  copy?: MountCopy;
142
+ layout?: CaptureLayout;
194
143
  onBeforeSubmit?: () => Promise<void>;
195
144
  onBehaviorSegment?: (segment: Pick<CaptureBehaviorMessage, 'steps' | 'traits'>) => void;
196
145
  fetchImpl?: typeof fetch;
@@ -213,6 +162,7 @@ interface ChecktivInitOptionsBase {
213
162
  apiBase?: string;
214
163
  betas?: string[];
215
164
  selfiePromptMap?: SelfiePromptMap;
165
+ selfieChromeCopy?: SelfieChromeCopy;
216
166
  }
217
167
  type ChecktivInitScope = {
218
168
  publishableKey: string;
@@ -236,9 +186,123 @@ interface SubstrateContext {
236
186
  readonly locale: string;
237
187
  readonly betas: readonly string[];
238
188
  readonly selfiePromptMap?: SelfiePromptMap;
189
+ readonly selfieChromeCopy?: SelfieChromeCopy;
239
190
  readonly tokens: TokenManager;
240
191
  getSessionId(): string;
241
192
  setSessionId(id: string): void;
242
193
  }
243
194
 
244
- export { createCustomForm as A, type ChecktivInitOptions as C, type FraudHandle as F, type GetSessionToken as G, type InitOptions as I, type MountProvisionedOptions as M, type ParsedPublishableKey as P, type ResolvedIdvConfig as R, type SdkMode as S, type ChecktivClient as a, type ChecktivError as b, type ChecktivErrorCode as c, type ChecktivEvent as d, type ChecktivFraudEvent as e, type ChecktivIdvEvent as f, type CrossDeviceHandoffHook as g, type FraudMountOptions as h, type GetSessionTokenContext as i, type IdvCoachingHint as j, type IdvHandle as k, type IdvMountOptions as l, InvalidPublishableKeyError as m, type ProvisionedHandle as n, type SdkRegion as o, type SyntheticIdvScript as p, parsePublishableKey as q, type ChecktivInitScope as r, createFraud as s, REMINT_READY_TIMEOUT_MS as t, createIdv as u, type ChecktivCustomFormEvent as v, type CustomFormCopy as w, type CustomFormFieldCopy as x, type CustomFormHandle as y, type CustomFormMountOptions as z };
195
+ type ChecktivFraudEvent = {
196
+ type: 'checktiv.fraud.started';
197
+ } | {
198
+ type: 'checktiv.fraud.error';
199
+ error: ChecktivError;
200
+ };
201
+ interface FraudMountOptions {
202
+ onConsent: () => boolean | Promise<boolean>;
203
+ onEvent?: (e: ChecktivFraudEvent) => void;
204
+ fetchImpl?: typeof fetch;
205
+ }
206
+ interface FraudHandle {
207
+ destroy(): void;
208
+ }
209
+ declare function createFraud(ctx: SubstrateContext, opts: FraudMountOptions): FraudHandle;
210
+
211
+ type IdvCoachingHint = CoachingKind;
212
+ interface ResolvedIdvConfig {
213
+ documentTypes: readonly string[];
214
+ biometricMode: 'selfie' | 'liveness' | 'none';
215
+ }
216
+ type ChecktivIdvEvent = {
217
+ type: 'checktiv.idv.ready';
218
+ config: ResolvedIdvConfig;
219
+ } | {
220
+ type: 'checktiv.idv.phase';
221
+ phase: string;
222
+ } | {
223
+ type: 'checktiv.idv.coaching';
224
+ hint: IdvCoachingHint;
225
+ } | {
226
+ type: 'checktiv.idv.submitted';
227
+ sessionId: string;
228
+ } | {
229
+ type: 'checktiv.idv.processing';
230
+ } | {
231
+ type: 'checktiv.idv.capture_superseded';
232
+ } | {
233
+ type: 'checktiv.idv.error';
234
+ error: ChecktivError;
235
+ } | {
236
+ type: 'checktiv.idv.cross_device_opened';
237
+ } | {
238
+ type: 'checktiv.idv.cross_device_unavailable';
239
+ } | {
240
+ type: 'checktiv.idv.cross_device_capped';
241
+ };
242
+ type ChecktivEvent = ChecktivIdvEvent | ChecktivFraudEvent | {
243
+ type: `checktiv.${string}`;
244
+ [k: string]: unknown;
245
+ };
246
+
247
+ type SdkRegion = DataRegion;
248
+ type SdkMode = SystemMode;
249
+ interface InitOptions {
250
+ readonly publishableKey: string;
251
+ readonly applicantLinkToken?: string;
252
+ readonly target?: HTMLElement;
253
+ readonly onComplete?: (payload: unknown) => void;
254
+ }
255
+ interface MountCompleteResult {
256
+ readonly sessionId: string;
257
+ }
258
+ type MountScope = {
259
+ readonly publishableKey: string;
260
+ } | {
261
+ readonly region: SdkRegion;
262
+ readonly mode: SdkMode;
263
+ };
264
+ type MountOptions = MountScope & {
265
+ readonly fetchToken: () => Promise<string>;
266
+ readonly onComplete?: (result: MountCompleteResult) => void;
267
+ readonly onEvent?: (e: ChecktivEvent) => void;
268
+ readonly onConsent?: () => boolean | Promise<boolean>;
269
+ readonly apiBase?: string;
270
+ readonly fetchImpl?: typeof fetch;
271
+ readonly resumeKey?: string;
272
+ readonly shortCode?: string;
273
+ };
274
+ interface SessionsCreateApplicant {
275
+ readonly externalId?: string;
276
+ readonly email?: string;
277
+ readonly phone?: string;
278
+ readonly firstName?: string;
279
+ readonly lastName?: string;
280
+ readonly dateOfBirth?: string;
281
+ readonly referenceName?: string;
282
+ }
283
+ interface SessionsCreateInput {
284
+ readonly templateId: string;
285
+ readonly applicant: SessionsCreateApplicant;
286
+ }
287
+ interface SessionsCreateOptions {
288
+ readonly apiBase: string;
289
+ readonly secretKey: string;
290
+ readonly idempotencyKey?: string;
291
+ readonly fetchImpl?: typeof fetch;
292
+ }
293
+ interface SessionsCreateResult {
294
+ readonly clientToken: string;
295
+ }
296
+ interface ChecktivSessions {
297
+ create(input: SessionsCreateInput, options: SessionsCreateOptions): Promise<SessionsCreateResult>;
298
+ }
299
+ interface ParsedPublishableKey {
300
+ readonly region: SdkRegion;
301
+ readonly mode: SdkMode;
302
+ }
303
+ declare class InvalidPublishableKeyError extends Error {
304
+ constructor(message: string);
305
+ }
306
+ declare function parsePublishableKey(key: string): ParsedPublishableKey;
307
+
308
+ export { type SubstrateContext as A, REMINT_READY_TIMEOUT_MS as B, type ChecktivInitOptions as C, createIdv as D, type ChecktivCustomFormEvent as E, type FraudHandle as F, type GetSessionToken as G, type CustomFormCopy as H, type InitOptions as I, type CustomFormFieldCopy as J, type CustomFormHandle as K, type CustomFormMountOptions as L, type MountOptions as M, createCustomForm as N, createFraud as O, type ProvisionedHandle as P, type ResolvedIdvConfig as R, type SdkMode as S, type TokenManager as T, type ChecktivClient as a, type ChecktivSessions as b, type ChecktivError as c, type ChecktivErrorCode as d, type ChecktivEvent as e, type ChecktivFraudEvent as f, type ChecktivIdvEvent as g, type CrossDeviceHandoffHook as h, type FraudMountOptions as i, type GetSessionTokenContext as j, type IdvCoachingHint as k, type IdvHandle as l, type IdvMountOptions as m, InvalidPublishableKeyError as n, type MountCompleteResult as o, type MountProvisionedOptions as p, type MountScope as q, type ParsedPublishableKey as r, type SdkRegion as s, type SessionsCreateApplicant as t, type SessionsCreateInput as u, type SessionsCreateOptions as v, type SessionsCreateResult as w, type SyntheticIdvScript as x, parsePublishableKey as y, type ChecktivInitScope as z };
@@ -1 +1 @@
1
- .idv-capture-frame{display:block;width:100%;max-width:28rem;aspect-ratio:3 / 4;margin:0 auto;border:0;border-radius:0.5rem;background:transparent}.idv-capture-frame--biometric{aspect-ratio:auto;height:min(70dvh,520px)}@media(orientation:landscape){.idv-capture-frame,.idv-capture-frame--biometric{aspect-ratio:auto;height:min(55dvh,380px);width:auto}}.idv-capture-active{position:relative}.idv-capture-skeleton{position:absolute;top:0;left:50%;transform:translateX(-50%);z-index:1;width:100%;max-width:28rem;height:min(70dvh,520px);border-radius:0.5rem;overflow:hidden;background:#e5e7eb}.idv-capture-skeleton[data-color-mode=dark]{background:#1f2937}.idv-capture-skeleton::before{content:"";position:absolute;inset:0;background:linear-gradient(100deg,transparent 30%,rgba(255,255,255,0.22) 50%,transparent 70%);background-size:200% 100%;animation:idv-capture-skeleton-sweep 1.4s ease-in-out infinite}@keyframes idv-capture-skeleton-sweep{from{background-position:200% 0}to{background-position:-200% 0}}@media(prefers-reduced-motion:reduce){.idv-capture-skeleton::before{animation:none}}@media(orientation:landscape){.idv-capture-skeleton{height:min(55dvh,380px)}}
1
+ .idv-capture-frame{display:block;width:100%;max-width:28rem;aspect-ratio:3 / 4;margin:0 auto;border:0;border-radius:0.5rem;background:transparent}.idv-capture-frame--biometric{aspect-ratio:auto;height:min(70dvh,var(--idv-capture-max-height, 520px))}@media(orientation:landscape){.idv-capture-frame,.idv-capture-frame--biometric{aspect-ratio:auto;height:min(55dvh,var(--idv-capture-landscape-max-height, 380px));width:auto}}.idv-capture-active{position:relative}.idv-capture-skeleton{position:absolute;top:0;left:50%;transform:translateX(-50%);z-index:1;width:100%;max-width:28rem;height:min(70dvh,var(--idv-capture-max-height, 520px));border-radius:0.5rem;overflow:hidden;background:#e5e7eb}.idv-capture-skeleton[data-color-mode=dark]{background:#1f2937}.idv-capture-skeleton::before{content:"";position:absolute;inset:0;background:linear-gradient(100deg,transparent 30%,rgba(255,255,255,0.22) 50%,transparent 70%);background-size:200% 100%;animation:idv-capture-skeleton-sweep 1.4s ease-in-out infinite}@keyframes idv-capture-skeleton-sweep{from{background-position:200% 0}to{background-position:-200% 0}}@media(prefers-reduced-motion:reduce){.idv-capture-skeleton::before{animation:none}}@media(orientation:landscape){.idv-capture-skeleton{height:min(55dvh,var(--idv-capture-landscape-max-height, 380px))}}:root{--idv-capture-max-height: 520px;--idv-capture-landscape-max-height: 380px}@media(pointer:coarse)and (max-width:640px),(pointer:coarse)and (max-height:640px){.idv-capture-immersive{position:fixed;inset:0;z-index:2147483000;display:flex;flex-direction:column;height:100dvh;overflow:hidden;box-sizing:border-box;background:#111827}.idv-capture-immersive .idv-capture-frame,.idv-capture-immersive .idv-capture-frame--biometric{flex:1 1 auto;min-height:0;width:100%;height:auto;max-width:none;aspect-ratio:auto;border-radius:0}.idv-capture-immersive .idv-capture-cv-reject,.idv-capture-immersive .idv-capture-status{flex:0 0 auto}.idv-capture-immersive .idv-capture-status{margin:0;text-align:center;color:#f3f4f6;line-height:1.4;padding:0.75rem 1rem calc(0.75rem + env(safe-area-inset-bottom))}.idv-capture-immersive .idv-capture-skeleton{position:absolute;inset:0;transform:none;width:100%;max-width:none;height:auto;background:#1f2937}.idv-capture-immersive .idv-capture-sentinel{position:absolute;width:0;height:0;overflow:hidden}}
@@ -1,10 +1,11 @@
1
- import { a as CaptureControllerDeps, b as CaptureEvent } from './controller-C4vJ47JI.js';
2
- import { e as CaptureState } from './machine--zVZIM4F.js';
3
- import { M as MountCopy } from './copy-DeUly5vr.js';
4
- export { T as TerminalKind, f as fallbackCopy } from './copy-DeUly5vr.js';
1
+ import { a as CaptureControllerDeps, b as CaptureEvent } from './controller-CFL3mA5e.js';
2
+ import { C as CaptureLayout, f as CaptureState } from './machine-CuZalPFX.js';
3
+ import { M as MountCopy } from './copy-Dfmk11S_.js';
4
+ export { T as TerminalKind, f as fallbackCopy } from './copy-Dfmk11S_.js';
5
5
 
6
6
  interface MountCaptureOptions extends Omit<CaptureControllerDeps, 'getIframe'> {
7
7
  copy: MountCopy;
8
+ layout?: CaptureLayout;
8
9
  onState?: (state: CaptureState) => void;
9
10
  onControllerEvent?: (event: CaptureEvent) => void;
10
11
  }
@@ -1,6 +1,8 @@
1
- export { fallbackCopy, mount } from './chunk-C7H2ZVQT.js';
1
+ export { fallbackCopy, mount } from './chunk-5MNNRYD5.js';
2
2
  import './chunk-HV2QKVJX.js';
3
3
  import './chunk-XOGHMNBX.js';
4
- import './chunk-TRTAZKYV.js';
4
+ import './chunk-5AQCMTZV.js';
5
+ import './chunk-6U53T32A.js';
6
+ import './chunk-IQKHRPJR.js';
5
7
  import './chunk-QFA3K5ZV.js';
6
8
  import './chunk-AIK7CDV6.js';
package/dist/capture.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { C as CaptureController, a as CaptureControllerDeps, b as CaptureEvent, c as CaptureEventType, S as SubmitResult, d as createCaptureController } from './controller-C4vJ47JI.js';
2
- import { a as CoachingKind } from './machine--zVZIM4F.js';
3
- export { b as CaptureAction, c as CaptureErrorKind, d as CapturePhase, e as CaptureState, i as isBiometricPhase, n as nextCapturePhaseAfterDocument, r as reducer } from './machine--zVZIM4F.js';
1
+ export { C as CaptureController, a as CaptureControllerDeps, b as CaptureEvent, c as CaptureEventType, S as SubmitResult, d as createCaptureController } from './controller-CFL3mA5e.js';
2
+ import { b as CoachingKind } from './machine-CuZalPFX.js';
3
+ export { c as CaptureAction, d as CaptureErrorKind, e as CapturePhase, f as CaptureState, i as isBiometricPhase, n as nextCapturePhaseAfterDocument, r as reducer } from './machine-CuZalPFX.js';
4
4
 
5
5
  declare function coachingKindForState(state: string): CoachingKind;
6
6
 
package/dist/capture.js CHANGED
@@ -1,3 +1,5 @@
1
- export { coachingKindForState, createCaptureController, isBiometricPhase, nextCapturePhaseAfterDocument, reducer } from './chunk-TRTAZKYV.js';
1
+ export { coachingKindForState, createCaptureController, isBiometricPhase, nextCapturePhaseAfterDocument, reducer } from './chunk-5AQCMTZV.js';
2
+ import './chunk-6U53T32A.js';
3
+ import './chunk-IQKHRPJR.js';
2
4
  import './chunk-QFA3K5ZV.js';
3
5
  import './chunk-AIK7CDV6.js';
@@ -0,0 +1,18 @@
1
+ type ChallengeErrorCode = 'challenge_failed' | 'load_failed' | 'expired' | 'config_error';
2
+
3
+ interface ChallengeControllerDeps {
4
+ getIframe: () => HTMLIFrameElement | null;
5
+ embedOrigin: string;
6
+ onToken: (token: string) => void;
7
+ onError: (code: ChallengeErrorCode) => void;
8
+ theme?: 'light' | 'dark';
9
+ locale?: string;
10
+ }
11
+ interface ChallengeController {
12
+ start(): void;
13
+ reset(): void;
14
+ destroy(): void;
15
+ }
16
+ declare function createChallengeController(deps: ChallengeControllerDeps): ChallengeController;
17
+
18
+ export { type ChallengeController, type ChallengeControllerDeps, type ChallengeErrorCode, createChallengeController };
@@ -0,0 +1,9 @@
1
+ import { assertNever } from './chunk-UBQTPS5J.js';
2
+ import { challengeFromIframeMessageSchema } from './chunk-6U53T32A.js';
3
+ import './chunk-IQKHRPJR.js';
4
+ import './chunk-QFA3K5ZV.js';
5
+ import './chunk-AIK7CDV6.js';
6
+
7
+ function createChallengeController(deps){let started=false;let destroyed=false;let resetInFlight=false;let messageListener=null;function postInit(){const iframe=deps.getIframe();if(iframe===null||iframe.contentWindow===null)return;const init={type:"challenge:init",...deps.theme!==void 0?{theme:deps.theme}:{},...deps.locale!==void 0?{locale:deps.locale}:{}};iframe.contentWindow.postMessage(init,deps.embedOrigin);}function postReset(){const iframe=deps.getIframe();if(iframe===null||iframe.contentWindow===null)return;const reset={type:"challenge:reset"};iframe.contentWindow.postMessage(reset,deps.embedOrigin);}function handleMessage(msg){switch(msg.type){case "challenge:ready":{resetInFlight=false;return}case "challenge:token":{resetInFlight=false;deps.onToken(msg.token);return}case "challenge:error":{resetInFlight=false;deps.onError(msg.code);return}default:{return assertNever(msg)}}}function onWindowMessage(event){if(destroyed)return;if(event.origin!==deps.embedOrigin)return;if(event.source!==null&&event.source!==deps.getIframe()?.contentWindow)return;const parsed=challengeFromIframeMessageSchema.safeParse(event.data);if(!parsed.success)return;handleMessage(parsed.data);}return {start(){if(destroyed||started)return;started=true;messageListener=onWindowMessage;window.addEventListener("message",messageListener);postInit();},reset(){if(destroyed||!started)return;if(resetInFlight)return;resetInFlight=true;postReset();},destroy(){if(destroyed)return;destroyed=true;if(messageListener!==null){window.removeEventListener("message",messageListener);messageListener=null;}}}}
8
+
9
+ export { createChallengeController };
@@ -0,0 +1,6 @@
1
+ import { idvCvGateRetryReasonEnum, captureFromIframeMessageSchema } from './chunk-6U53T32A.js';
2
+ import { isTwoSidedDocumentType } from './chunk-IQKHRPJR.js';
3
+
4
+ function reducer(state,action){switch(action.type){case "mint_ok":return {kind:"waiting_for_init",captureToken:action.captureToken,embedOrigin:action.embedOrigin,runIndex:action.runIndex};case "mint_failed":return {kind:"mint_error"};case "iframe_ready":if(state.kind==="waiting_for_init"){return {kind:"ready",embedOrigin:state.embedOrigin,runIndex:state.runIndex}}return state;case "phase":if(state.kind==="ready"||state.kind==="capturing"){return {kind:"capturing",embedOrigin:state.embedOrigin,runIndex:state.runIndex,phase:action.phase,coaching:null,lastCvRejectReason:action.phase==="selfie"&&state.kind==="capturing"?state.lastCvRejectReason:null,biometricLoading:isBiometricPhase(action.phase)}}return state;case "coaching":if(state.kind==="ready"||state.kind==="capturing"){return {kind:"capturing",embedOrigin:state.embedOrigin,runIndex:state.runIndex,phase:"coaching",coaching:action.coaching,lastCvRejectReason:state.kind==="capturing"?state.lastCvRejectReason:null,biometricLoading:state.kind==="capturing"?state.biometricLoading:false}}return state;case "selfie_cv_reject":if(state.kind==="ready"||state.kind==="capturing"){return {kind:"capturing",embedOrigin:state.embedOrigin,runIndex:state.runIndex,phase:state.kind==="capturing"?state.phase:"selfie",coaching:state.kind==="capturing"?state.coaching:null,lastCvRejectReason:action.reason,biometricLoading:false}}return state;case "biometric_camera_live":if(state.kind==="capturing"){return {...state,biometricLoading:false}}return state;case "submitting":return {kind:"submitting"};case "submit_failed":return {kind:"submit_error"};case "submit_pending":return {kind:"submit_pending"};case "capture_superseded":return {kind:"capture_superseded"};case "token_expired":return {kind:"token_expired"};case "capture_error":return {kind:"capture_error",errorKind:action.errorKind};default:return state}}function nextCapturePhaseAfterDocument(side,documentTypes,biometricMode){if(side==="front"&&documentTypes.some(isTwoSidedDocumentType))return "document_back";if(biometricMode==="liveness")return "liveness";if(biometricMode==="selfie")return "selfie";return "uploading"}function isBiometricPhase(phase){return phase==="selfie"||phase==="liveness"}var RETRY_REASON_COACHING={no_face_detected:"hold_steady",multiple_faces:"hold_steady",low_confidence:"move_closer",no_id_document:"hold_steady",image_read_failed:"hold_steady"};function coachingKindForState(state){const retryParsed=idvCvGateRetryReasonEnum.safeParse(state);if(retryParsed.success)return RETRY_REASON_COACHING[retryParsed.data];switch(state){case "camera-too-far":return "move_closer";case "camera-too-close":case "document-too-close-to-frame-edge":return "move_farther";case "glare-detected":return "reduce_glare";case "too-dark":case "lighting-too-dark":return "too_dark";case "wrong-side":return "wrong_side";case "selfie_move_closer":return "move_closer";case "selfie_too_dark":return "too_dark";case "selfie_no_face":case "selfie_multiple_faces":case "selfie_not_centered":return "hold_steady";default:return "hold_steady"}}function createCaptureController(deps){let state={kind:"minting"};const stateListeners=new Set;const eventListeners=new Map;let captureToken=null;let pinnedOrigin=null;let runIndex=null;let started=false;let destroyed=false;let cancelled=false;let submitStarted=false;let messageListener=null;function setState(next){state=next;for(const listener of stateListeners)listener(state);}function dispatch(action){setState(reducer(state,action));}function emit(event){const listeners=eventListeners.get(event.type);if(listeners===void 0)return;for(const listener of listeners)listener(event);}function postInit(){if(destroyed||captureToken===null||pinnedOrigin===null)return false;const iframe=deps.getIframe();if(iframe===null||iframe.contentWindow===null)return false;const init={type:"capture:init",captureToken,...deps.initPayload()};iframe.contentWindow.postMessage(init,pinnedOrigin);return true}function handleMessage(msg){switch(msg.type){case "capture:ready":{const posted=postInit();if(posted&&state.kind==="waiting_for_init"){dispatch({type:"iframe_ready"});}return}case "capture:coaching":{dispatch({type:"coaching",coaching:coachingKindForState(msg.state)});deps.onCoaching?.(msg.state,msg.attemptIndex);return}case "capture:selfie-cv-reject":{const reason=msg.retryReason??null;dispatch({type:"selfie_cv_reject",reason});emit({type:"selfie-cv-reject",attemptIndex:msg.attemptIndex,reason});return}case "capture:document-complete":{const{config}=deps.initPayload();dispatch({type:"phase",phase:nextCapturePhaseAfterDocument(msg.side,config.documentTypes,config.biometricMode)});return}case "capture:selfie-complete":{dispatch({type:"phase",phase:"uploading"});return}case "capture:error":{if(msg.code==="token_expired"){dispatch({type:"token_expired"});return}dispatch({type:"capture_error",errorKind:msg.code});return}case "capture:all-complete":{void submitCapture(msg.r2Keys);return}case "capture:behavior":{deps.onBehaviorSegment?.({steps:msg.steps,traits:msg.traits});return}case "capture:biometric_camera_live":{dispatch({type:"biometric_camera_live"});return}default:{const _exhaustive=msg;return _exhaustive}}}async function submitCapture(r2Keys){if(submitStarted)return;submitStarted=true;if(runIndex===null){dispatch({type:"submit_failed"});return}if(deps.onBeforeSubmit){try{await deps.onBeforeSubmit();}catch{if(!destroyed)dispatch({type:"submit_failed"});return}if(destroyed)return}dispatch({type:"submitting"});let result;try{result=await deps.submit(runIndex,r2Keys);}catch{if(!destroyed)dispatch({type:"submit_failed"});return}if(destroyed)return;if(result.ok){emit({type:"all-complete",runIndex});return}if(result.reason==="token_expired"){dispatch({type:"token_expired"});return}if(result.reason==="signal_pending"){dispatch({type:"submit_pending"});return}if(result.reason==="capture_superseded"){dispatch({type:"capture_superseded"});return}dispatch({type:"submit_failed"});}function onWindowMessage(event){if(destroyed||pinnedOrigin===null)return;if(event.origin!==pinnedOrigin)return;if(event.source!==null&&event.source!==deps.getIframe()?.contentWindow)return;const parsed=captureFromIframeMessageSchema.safeParse(event.data);if(!parsed.success)return;handleMessage(parsed.data);}return {start(){if(destroyed||started)return;started=true;void(async()=>{try{const minted=await deps.mintToken();if(cancelled||destroyed)return;captureToken=minted.captureToken;pinnedOrigin=minted.embedOrigin;runIndex=minted.runIndex;messageListener=onWindowMessage;window.addEventListener("message",messageListener);dispatch({type:"mint_ok",...minted});}catch{if(cancelled||destroyed)return;dispatch({type:"mint_failed"});}})();},on(type,cb){let listeners=eventListeners.get(type);if(listeners===void 0){listeners=new Set;eventListeners.set(type,listeners);}listeners.add(cb);return ()=>{listeners?.delete(cb);}},subscribe(cb){stateListeners.add(cb);cb(state);return ()=>{stateListeners.delete(cb);}},handleReady(){if(destroyed)return;postInit();},destroy(){if(destroyed)return;destroyed=true;cancelled=true;if(messageListener!==null){window.removeEventListener("message",messageListener);messageListener=null;}}}}
5
+
6
+ export { coachingKindForState, createCaptureController, isBiometricPhase, nextCapturePhaseAfterDocument, reducer };
@@ -0,0 +1,7 @@
1
+ import { u } from './chunk-HV2QKVJX.js';
2
+ import { R, k } from './chunk-XOGHMNBX.js';
3
+ import { createCaptureController, isBiometricPhase, coachingKindForState } from './chunk-5AQCMTZV.js';
4
+
5
+ function coachingFallback(kind){switch(kind){case "move_closer":return "Move a little closer.";case "move_farther":return "Move a little farther away.";case "reduce_glare":return "Reduce glare: tilt away from bright light.";case "too_dark":return "Find a brighter, well-lit spot.";case "wrong_side":return "Show the other side of your document.";case "hold_steady":return "Hold steady and keep everything in frame."}}function statusFallback(phase){switch(phase){case "ready":return "Getting the camera ready.";case "document_front":return "Position the front of your document in the frame.";case "document_back":return "Now show the back of your document.";case "selfie":return "Center your face in the frame.";case "liveness":return "Follow the on-screen prompts to confirm it is you.";case "uploading":return "Uploading. This takes a few seconds.";case "coaching":return "Hold steady and keep everything in frame."}}function errorFallback(kind){switch(kind){case "cv_gate_failed":return "We could not read that capture. Please try again in good lighting.";case "upload_failed":return "The upload did not finish. Check your connection and try again.";case "sdk_load_failed":return "The capture tools could not load. Refresh, or continue on your phone.";case "biometric_unsupported":return "This device cannot run the selfie check. Please continue on your phone.";case "camera_unsupported":return "Your camera does not meet the minimum resolution for capture. Please continue on your phone.";case "selfie_camera_denied":return "Camera access was blocked. Allow the camera, or continue on your phone.";case "liveness_camera_denied":return "Camera access was blocked. Allow the camera, or continue on your phone.";case "liveness_timeout":return "The check timed out. Please try again.";case "liveness_server_error":return "Something went wrong on our side. Please try again.";case "liveness_runtime_error":return "The check could not run. Refresh and try again.";case "liveness_cancelled":return "The check was canceled. Please try again when you are ready.";case "protocol_mismatch":return "This version of the verification tool is no longer supported. Please contact the operator to continue.";default:{const _exhaustive=kind;return _exhaustive}}}function terminalFallback(kind){switch(kind){case "mint_error":return "We could not start verification. Please try again.";case "submit_error":return "We could not submit your capture. Please try again.";case "token_expired":return "This step expired for your security. Please refresh to start again.";case "capture_superseded":return "Verification is active on another device. Finish there, or select Try again to continue here.";default:{const _exhaustive=kind;return _exhaustive}}}var fallbackCopy={cvReject:(_attemptIndex,kind)=>`We could not use that photo. ${coachingFallback(kind)}`,error:errorFallback,status:statusFallback,coaching:coachingFallback,terminal:terminalFallback,tryAgain:()=>"Try again",frameTitle:()=>"Identity verification capture"};var IFRAME_SANDBOX="allow-scripts allow-same-origin";function phaseOf(state){if(state.kind==="capturing")return state.phase;return "ready"}function statusLine(state,copy){if(state.kind==="capturing"&&state.phase==="coaching"&&state.coaching!==null){return (copy.coaching??fallbackCopy.coaching)(state.coaching)}return (copy.status??fallbackCopy.status)(phaseOf(state))}function CvRejectAlert({reason,attemptIndex,copy}){const kind=coachingKindForState(reason);const text=(copy.cvReject??fallbackCopy.cvReject)(attemptIndex,kind);return u("div",{role:"status","data-testid":"idv-cv-reject-alert",className:"idv-capture-cv-reject",style:"margin-bottom: 0.75rem;",children:text})}function CaptureFrame({state,attemptIndex,getEmbedSrc,onTryAgain,copy,layout="inline",immersiveActive=false,colorMode="light"}){switch(state.kind){case "minting":return u("p",{className:"idv-capture-status",children:(copy.status??fallbackCopy.status)("ready")});case "mint_error":case "submit_error":case "token_expired":case "capture_superseded":return u("div",{className:"idv-capture-error",role:"alert",children:[u("p",{children:(copy.terminal??fallbackCopy.terminal)(state.kind)}),u("button",{type:"button",onClick:onTryAgain,className:"idv-capture-retry",children:copy.tryAgain??fallbackCopy.tryAgain()})]});case "capture_error":{const errorKind=state.errorKind;const terminal=errorKind==="protocol_mismatch";return u("div",{className:"idv-capture-error",role:"alert",children:[u("p",{children:(copy.error??fallbackCopy.error)(errorKind)}),!terminal&&u("button",{type:"button",onClick:onTryAgain,className:"idv-capture-retry",children:copy.tryAgain??fallbackCopy.tryAgain()})]})}case "submitting":case "submit_pending":return u("p",{className:"idv-capture-status",children:(copy.status??fallbackCopy.status)("uploading")});case "waiting_for_init":case "ready":case "capturing":{const phase=phaseOf(state);const biometric=isBiometricPhase(phase);const frameClass=biometric?"idv-capture-frame idv-capture-frame--biometric":"idv-capture-frame";const reason=state.kind==="capturing"?state.lastCvRejectReason:null;const biometricLoading=biometric&&state.kind==="capturing"&&state.biometricLoading;const embedSrc=getEmbedSrc(state.embedOrigin);const immersive=layout==="immersive";const wrapperClass=immersive?"idv-capture-active idv-capture-immersive":"idv-capture-active";const frameTitle=copy.frameTitle??fallbackCopy.frameTitle();let iframeEl=null;const focusFrame=()=>iframeEl?.focus();return u("div",{className:wrapperClass,"data-color-mode":colorMode,role:immersiveActive?"dialog":void 0,"aria-modal":immersiveActive?"true":void 0,"aria-label":immersiveActive?frameTitle:void 0,children:[reason!==null&&u(CvRejectAlert,{reason,attemptIndex,copy}),biometricLoading&&u("div",{"data-testid":"idv-capture-skeleton","data-color-mode":colorMode,className:"idv-capture-skeleton","aria-hidden":"true"}),immersiveActive&&u("div",{className:"idv-capture-sentinel",tabIndex:0,onFocus:focusFrame}),u("iframe",{ref:el=>{iframeEl=el;},className:frameClass,title:frameTitle,src:embedSrc,allow:"camera",sandbox:IFRAME_SANDBOX}),immersiveActive&&u("div",{className:"idv-capture-sentinel",tabIndex:0,onFocus:focusFrame}),u("p",{className:"idv-capture-status","aria-live":"polite",children:statusLine(state,copy)})]})}default:{const _exhaustive=state;return _exhaustive}}}var IMMERSIVE_MEDIA="(pointer: coarse) and (max-width: 640px), (pointer: coarse) and (max-height: 640px)";function matchesImmersive(){return typeof window!=="undefined"&&typeof window.matchMedia==="function"&&window.matchMedia(IMMERSIVE_MEDIA).matches}function subscribeImmersive(cb){if(typeof window==="undefined"||typeof window.matchMedia!=="function"){return ()=>{}}const mql=window.matchMedia(IMMERSIVE_MEDIA);mql.addEventListener("change",cb);return ()=>{mql.removeEventListener("change",cb);}}function mount(element,options){const{copy,layout,onState,onControllerEvent,...deps}=options;const resolvedInitPayload=deps.initPayload();const controller=createCaptureController({...deps,initPayload:()=>resolvedInitPayload,getIframe:()=>element.querySelector("iframe.idv-capture-frame")});let destroyed=false;let state={kind:"minting"};let attemptIndex=0;const computeImmersiveActive=()=>layout==="immersive"&&matchesImmersive();let immersiveActive=computeImmersiveActive();let prevFocusable=false;let prevStateKind=state.kind;const IMMERSIVE_FILL_TOLERANCE_PX=2;let selfCheckRaf;let selfCheckWarned=false;const scheduleImmersiveSelfCheck=()=>{if(typeof requestAnimationFrame!=="function")return;if(selfCheckRaf!==void 0&&typeof cancelAnimationFrame==="function"){cancelAnimationFrame(selfCheckRaf);}selfCheckRaf=requestAnimationFrame(()=>{selfCheckRaf=void 0;if(destroyed||selfCheckWarned||typeof window==="undefined")return;const overlay=element.querySelector(".idv-capture-immersive");if(overlay===null)return;const rect=overlay.getBoundingClientRect();const vw=window.innerWidth;const vh=window.innerHeight;if(Math.abs(rect.width-vw)>IMMERSIVE_FILL_TOLERANCE_PX||Math.abs(rect.height-vh)>IMMERSIVE_FILL_TOLERANCE_PX){selfCheckWarned=true;console.warn("[Checktiv] immersive capture overlay does not fill the viewport",rect.width,rect.height,vw,vh);}});};const ERROR_ARM_KINDS={minting:false,mint_error:true,waiting_for_init:false,ready:false,capturing:false,submitting:false,submit_error:true,submit_pending:false,capture_superseded:true,token_expired:true,capture_error:true};const isErrorArm=kind=>ERROR_ARM_KINDS[kind];const onTryAgain=()=>{if(typeof window!=="undefined")window.location.reload();};const paint=()=>{if(destroyed)return;R(k(CaptureFrame,{state,attemptIndex,getEmbedSrc:deps.getEmbedSrc,onTryAgain,copy,layout,immersiveActive,colorMode:resolvedInitPayload.theme.colorMode}),element);const iframeEl=element.querySelector("iframe.idv-capture-frame");const iframePresent=iframeEl!==null;const focusable=immersiveActive&&iframePresent;if(focusable&&!prevFocusable&&!destroyed){iframeEl?.focus();scheduleImmersiveSelfCheck();}if(isErrorArm(state.kind)&&state.kind!==prevStateKind){element.querySelector(".idv-capture-retry")?.focus();}prevFocusable=focusable;prevStateKind=state.kind;};const rerender=()=>{if(destroyed)return;immersiveActive=computeImmersiveActive();paint();};const unsubImmersive=layout==="immersive"?subscribeImmersive(rerender):void 0;const safeObserve=(fn,arg)=>{if(fn===void 0)return;try{fn(arg);}catch(err){console.warn("[Checktiv] capture observer threw; ignoring (observational only).",err);}};const unsubState=controller.subscribe(next=>{state=next;paint();safeObserve(onState,next);});const offReject=controller.on("selfie-cv-reject",event=>{if(event.type==="selfie-cv-reject"){attemptIndex=event.attemptIndex;paint();}safeObserve(onControllerEvent,event);});const offComplete=controller.on("all-complete",event=>{safeObserve(onControllerEvent,event);});controller.start();return {destroy(){if(destroyed)return;destroyed=true;unsubState();offReject();offComplete();if(unsubImmersive!==void 0)unsubImmersive();if(selfCheckRaf!==void 0&&typeof cancelAnimationFrame==="function"){cancelAnimationFrame(selfCheckRaf);}R(null,element);controller.destroy();}}}
6
+
7
+ export { fallbackCopy, mount };