@sekyro/web 0.1.0-rc.1 → 0.1.0-rc.2

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.
@@ -1,7 +1,7 @@
1
1
  import { n as DeviceClass, h as CaptureState, b as CaptureArtifacts, c as CaptureErrorKind } from '../capture-session-v3-CAoWM8iT.cjs';
2
2
  export { C as CENTERED_FACTOR, a as CIRCLE_RADIUS_FACTOR, I as IN_CIRCLE_FACTOR } from '../capture-constraints-BujkZcfb.cjs';
3
- import { k as VerificationResult } from '../create-verification--ldwakXV.cjs';
4
- export { A as AttestationError, o as CLIP_MIME_ALLOWLIST, p as CaptureEngine, H as HostedClientLike, q as LivenessCaptureInternalHandle, r as LivenessCaptureInternals, s as LivenessFlowDeps, t as LivenessFlowOutcome, P as PROCESSING_POLL_DELAY_MS, u as PROCESSING_POLL_MAX, v as REGISTRY_RETRY_DELAY_MS, w as SubmitExecutor, x as SubmitRuntime, T as TRANSPORT_REPLAY_ATTEMPTS, y as TRANSPORT_REPLAY_DELAY_MS, z as VerificationInternals, B as createLivenessCaptureInternal, E as createVerificationInternal, F as mapEngineState, I as mapErrorKind, J as mapGuidanceHint, K as randomUuid, M as runLivenessFlow, N as runSubmission } from '../create-verification--ldwakXV.cjs';
3
+ import { k as VerificationResult } from '../create-verification-EnZ13uY4.cjs';
4
+ export { A as AttestationError, o as CLIP_MIME_ALLOWLIST, p as CaptureEngine, H as HostedClientLike, q as LivenessCaptureInternalHandle, r as LivenessCaptureInternals, s as LivenessFlowDeps, t as LivenessFlowOutcome, P as PROCESSING_POLL_DELAY_MS, u as PROCESSING_POLL_MAX, v as REGISTRY_RETRY_DELAY_MS, w as SubmitExecutor, x as SubmitRuntime, T as TRANSPORT_REPLAY_ATTEMPTS, y as TRANSPORT_REPLAY_DELAY_MS, z as VerificationInternals, B as createLivenessCaptureInternal, E as createVerificationInternal, F as mapEngineState, I as mapErrorKind, J as mapGuidanceHint, K as randomUuid, M as runLivenessFlow, N as runSubmission } from '../create-verification-EnZ13uY4.cjs';
5
5
  import { C as CheckReason, c as HostedSessionView, d as HostedStepView, h as SessionView, b as CheckType } from '../hosted-client-BpvBqu9f.cjs';
6
6
  import '../detect-worker-CKXHlXx9.cjs';
7
7
 
@@ -1,7 +1,7 @@
1
1
  import { n as DeviceClass, h as CaptureState, b as CaptureArtifacts, c as CaptureErrorKind } from '../capture-session-v3-BJ8ciaWl.js';
2
2
  export { C as CENTERED_FACTOR, a as CIRCLE_RADIUS_FACTOR, I as IN_CIRCLE_FACTOR } from '../capture-constraints-BujkZcfb.js';
3
- import { k as VerificationResult } from '../create-verification-BlAPWeW5.js';
4
- export { A as AttestationError, o as CLIP_MIME_ALLOWLIST, p as CaptureEngine, H as HostedClientLike, q as LivenessCaptureInternalHandle, r as LivenessCaptureInternals, s as LivenessFlowDeps, t as LivenessFlowOutcome, P as PROCESSING_POLL_DELAY_MS, u as PROCESSING_POLL_MAX, v as REGISTRY_RETRY_DELAY_MS, w as SubmitExecutor, x as SubmitRuntime, T as TRANSPORT_REPLAY_ATTEMPTS, y as TRANSPORT_REPLAY_DELAY_MS, z as VerificationInternals, B as createLivenessCaptureInternal, E as createVerificationInternal, F as mapEngineState, I as mapErrorKind, J as mapGuidanceHint, K as randomUuid, M as runLivenessFlow, N as runSubmission } from '../create-verification-BlAPWeW5.js';
3
+ import { k as VerificationResult } from '../create-verification-CjLnJ0w6.js';
4
+ export { A as AttestationError, o as CLIP_MIME_ALLOWLIST, p as CaptureEngine, H as HostedClientLike, q as LivenessCaptureInternalHandle, r as LivenessCaptureInternals, s as LivenessFlowDeps, t as LivenessFlowOutcome, P as PROCESSING_POLL_DELAY_MS, u as PROCESSING_POLL_MAX, v as REGISTRY_RETRY_DELAY_MS, w as SubmitExecutor, x as SubmitRuntime, T as TRANSPORT_REPLAY_ATTEMPTS, y as TRANSPORT_REPLAY_DELAY_MS, z as VerificationInternals, B as createLivenessCaptureInternal, E as createVerificationInternal, F as mapEngineState, I as mapErrorKind, J as mapGuidanceHint, K as randomUuid, M as runLivenessFlow, N as runSubmission } from '../create-verification-CjLnJ0w6.js';
5
5
  import { C as CheckReason, c as HostedSessionView, d as HostedStepView, h as SessionView, b as CheckType } from '../hosted-client-BpvBqu9f.js';
6
6
  import '../detect-worker-CKXHlXx9.js';
7
7
 
@@ -26,7 +26,7 @@ import {
26
26
  runLivenessFlow,
27
27
  runSubmission,
28
28
  stepOf
29
- } from "../chunk-NU4YOLCN.js";
29
+ } from "../chunk-BPYVZUJA.js";
30
30
  import {
31
31
  CENTERED_FACTOR,
32
32
  CIRCLE_RADIUS_FACTOR,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sekyro/web",
3
- "version": "0.1.0-rc.1",
3
+ "version": "0.1.0-rc.2",
4
4
  "description": "Sekyro web SDK — browser liveness capture, hosted-verification client and popup embed for Sekyro identity verification",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/verification/emitter.ts","../src/capture/create-liveness-capture.ts","../src/verification/result.ts","../src/verification/liveness-flow.ts","../src/verification/turnstile.ts","../src/verification/create-verification.ts"],"sourcesContent":["// Tiny typed emitter (zero deps). Handlers are snapshotted before dispatch so an\n// unsubscribe from inside a handler never skips a sibling.\n\nexport interface Emitter<Events extends object> {\n on<K extends keyof Events>(event: K, handler: (payload: Events[K]) => void): () => void;\n emit<K extends keyof Events>(event: K, payload: Events[K]): void;\n clear(): void;\n}\n\nexport function createEmitter<Events extends object>(): Emitter<Events> {\n const handlers = new Map<keyof Events, Set<(payload: never) => void>>();\n return {\n on(event, handler) {\n let set = handlers.get(event);\n if (set === undefined) {\n set = new Set();\n handlers.set(event, set);\n }\n const h = handler as (payload: never) => void;\n set.add(h);\n return () => {\n set?.delete(h);\n };\n },\n emit(event, payload) {\n const set = handlers.get(event);\n if (set === undefined) return;\n for (const handler of [...set]) {\n (handler as (p: Events[typeof event]) => void)(payload);\n }\n },\n clear() {\n handlers.clear();\n },\n };\n}\n","// createLivenessCapture — the public, framework-free capture handle (spec\n// §3.1) over the calibration-pinned CaptureSessionV3 engine. It MAPS the\n// engine's event surface (statechange / checks / guidance / artifacts / error /\n// frozen) onto the partner contract (state / gate / captured / error) and owns\n// the NO_RECORDER degrade (photo mode → keyframe-only `captured`). Pinned\n// capture constants stay inside the engine — nothing here is configurable.\nimport { detectIsMobile } from \"../core/capture-constraints\";\nimport { isMediaRecorderSupported } from \"../core/media\";\nimport type { CaptureErrorKind as EngineErrorKind, CaptureState as EngineState } from \"../core/types\";\nimport {\n CaptureSessionV3,\n type CaptureSessionV3Events,\n type CaptureSessionV3Options,\n} from \"../core/v3/capture-session-v3\";\nimport { createEmitter } from \"../verification/emitter\";\nimport type {\n CaptureErrorKind,\n CaptureState,\n GateHint,\n LivenessCaptureEvents,\n LivenessCaptureHandle,\n LivenessCaptureOptions,\n} from \"../verification/types\";\n\n/** The engine surface the handle binds — CaptureSessionV3 or a test double. */\nexport interface CaptureEngine {\n readonly state: EngineState;\n on<K extends keyof CaptureSessionV3Events>(\n event: K,\n handler: (payload: CaptureSessionV3Events[K]) => void,\n ): () => void;\n start(): Promise<void>;\n retry(): void;\n switchCamera(): void;\n destroy(): void;\n /** Device-profile chrome hint (LOW class → `'reduced'`); absent on doubles. */\n readonly animations?: \"full\" | \"reduced\";\n}\n\n/** Internal construction seams (tests; Sekyro's own hosted page). */\nexport interface LivenessCaptureInternals {\n /** Replace the engine constructor (default: `new CaptureSessionV3(options)`). */\n createEngine?: (options: CaptureSessionV3Options) => CaptureEngine;\n /** Extra engine options merged in (worker offload, warmed detector, telemetry). */\n engineOptions?: Partial<\n Pick<CaptureSessionV3Options, \"createDetector\" | \"createWorker\" | \"telemetry\" | \"deviceClass\">\n >;\n /** Clock (default `performance.now`). */\n now?: () => number;\n}\n\n/** fcv3.* guidance key → public gate hint code. */\nexport function mapGuidanceHint(key: string): GateHint | null {\n switch (key) {\n case \"fcv3.no_face\":\n case \"fcv3.center_face\":\n case \"fcv3.straighten\":\n return \"center\";\n case \"fcv3.come_closer\":\n return \"closer\";\n case \"fcv3.move_back\":\n return \"farther\";\n case \"fcv3.more_light\":\n case \"fcv3.too_bright\":\n return \"light\";\n case \"fcv3.hold_still\":\n case \"fcv3.steady_camera\":\n return \"still\";\n default:\n return null;\n }\n}\n\n/** Engine state → public state (`preflight|acquiring → starting`, `positioning → gating`). */\nexport function mapEngineState(state: EngineState): CaptureState {\n switch (state) {\n case \"preflight\":\n case \"acquiring\":\n return \"starting\";\n case \"positioning\":\n return \"gating\";\n case \"idle\":\n case \"recording\":\n case \"captured\":\n case \"error\":\n return state;\n default: {\n const unhandled: never = state;\n throw new Error(`mapEngineState: unhandled state ${unhandled as string}`);\n }\n }\n}\n\n/** Engine error kinds → the public six (`models|cliptoolarge|recorder|overconstrained → generic`). */\nexport function mapErrorKind(kind: EngineErrorKind): CaptureErrorKind {\n switch (kind) {\n case \"permission\":\n case \"notfound\":\n case \"inuse\":\n case \"insecure\":\n case \"unsupported\":\n return kind;\n case \"overconstrained\":\n case \"generic\":\n case \"models\":\n case \"cliptoolarge\":\n case \"recorder\":\n return \"generic\";\n default: {\n const unhandled: never = kind;\n throw new Error(`mapErrorKind: unhandled kind ${unhandled as string}`);\n }\n }\n}\n\n/** Handle + the hooks the verification layer uses to drive the flow states. */\nexport interface LivenessCaptureInternalHandle {\n handle: LivenessCaptureHandle;\n /** Push a post-capture state (`uploading | checking | done`). */\n setFlowState(state: Extract<CaptureState, \"uploading\" | \"checking\" | \"done\">): void;\n}\n\nexport function createLivenessCaptureInternal(\n options: LivenessCaptureOptions,\n internals: LivenessCaptureInternals = {},\n): LivenessCaptureInternalHandle {\n const now = internals.now ?? (() => performance.now());\n const emitter = createEmitter<LivenessCaptureEvents>();\n // NO_RECORDER degrade: no MediaRecorder → photo mode (keyframe only). Decided\n // ONCE at construction; the artifacts carry the flag.\n const degraded = !isMediaRecorderSupported();\n const engineOptions: CaptureSessionV3Options = {\n video: options.video,\n mode: degraded ? \"photo\" : \"clip\",\n ...(options.facing !== undefined ? { facingMode: options.facing } : {}),\n ...(options.assetBaseUrl !== undefined ? { v3AssetBaseUrl: options.assetBaseUrl } : {}),\n ...(internals.engineOptions ?? {}),\n };\n const engine: CaptureEngine =\n internals.createEngine?.(engineOptions) ?? new CaptureSessionV3(engineOptions);\n\n let state: CaptureState = \"idle\";\n let hint: GateHint | null = null;\n let progress = 0;\n let faceDetected = false;\n let animations: \"full\" | \"reduced\" = \"full\";\n let recordingStartedAt: number | null = null;\n let frozenAt: number | null = null;\n\n const setState = (next: CaptureState): void => {\n state = next;\n emitter.emit(\"state\", next);\n };\n const emitGate = (): void => emitter.emit(\"gate\", { progress, hint, faceDetected });\n // The LOW-profile hint settles once the engine probes (statechange) and may\n // flip mid-positioning on a dynamic demotion (per checks tick) — emit on change.\n const syncProfile = (): void => {\n const next = engine.animations ?? \"full\";\n if (next === animations) return;\n animations = next;\n emitter.emit(\"profile\", { animations });\n };\n\n const unsubscribes = [\n engine.on(\"statechange\", ({ state: engineState }) => {\n const next = mapEngineState(engineState);\n if (next === \"starting\" && state !== \"starting\") {\n // Fresh attempt: gate chrome resets.\n hint = null;\n progress = 0;\n faceDetected = false;\n recordingStartedAt = null;\n frozenAt = null;\n }\n setState(next);\n syncProfile();\n if (next === \"recording\") {\n recordingStartedAt = now();\n hint = \"hold\";\n progress = 1;\n emitGate();\n }\n }),\n engine.on(\"checks\", (payload) => {\n progress = payload.progress;\n faceDetected = payload.factors.presence > 0;\n emitGate();\n syncProfile();\n }),\n engine.on(\"guidance\", ({ key }) => {\n hint = mapGuidanceHint(key);\n emitGate();\n }),\n engine.on(\"frozen\", ({ previewDataUrl }) => {\n frozenAt = now();\n emitter.emit(\"frozen\", { previewDataUrl });\n }),\n engine.on(\"artifacts\", (artifacts) => {\n const clipMs =\n recordingStartedAt !== null && frozenAt !== null\n ? Math.max(0, Math.round(frozenAt - recordingStartedAt))\n : undefined;\n emitter.emit(\"captured\", {\n keyframe: artifacts.keyframe,\n ...(artifacts.clip !== undefined ? { clip: artifacts.clip } : {}),\n ...(artifacts.clipMimeType !== undefined ? { clipMime: artifacts.clipMimeType } : {}),\n width: options.video.videoWidth,\n height: options.video.videoHeight,\n ...(clipMs !== undefined ? { clipMs } : {}),\n captureChannel: detectIsMobile() ? \"mobile\" : \"desktop\",\n ...(degraded ? { degraded: \"NO_RECORDER\" as const } : {}),\n });\n }),\n engine.on(\"error\", ({ kind, retryable }) => {\n emitter.emit(\"error\", { kind: mapErrorKind(kind), retryable });\n }),\n ];\n\n const handle: LivenessCaptureHandle = {\n get state() {\n return state;\n },\n on: (event, handler) => emitter.on(event, handler),\n start: () => engine.start(),\n retry: () => engine.retry(),\n switchCamera: () => engine.switchCamera(),\n destroy: () => {\n for (const unsubscribe of unsubscribes) unsubscribe();\n engine.destroy();\n emitter.clear();\n },\n };\n\n return {\n handle,\n setFlowState: (next) => {\n if (state !== next) setState(next);\n },\n };\n}\n\n/**\n * Create a standalone liveness capture (no upload — pair it with your own\n * submission, or use {@link Verification.liveness} for the full flow).\n */\nexport function createLivenessCapture(options: LivenessCaptureOptions): LivenessCaptureHandle {\n return createLivenessCaptureInternal(options).handle;\n}\n","// Result mapping: server view → the public VerificationResult (spec §3.1) plus\n// the view helpers the flow needs (frontier, terminal, view merge).\nimport type {\n CheckReason,\n CheckType,\n HostedSessionView,\n HostedStepView,\n SessionView,\n} from \"../client/types\";\nimport type { ReasonCode, VerificationResult } from \"./types\";\n\n/**\n * Reasons the backend parks at `input_required` while attempts remain\n * (identity-backend/src/checks/check-reasons.ts isRetryable tables — the single\n * source of truth; identity-hosted/lib/reason-copy.ts mirrors the same rows).\n */\nexport const RETRYABLE_REASONS: ReadonlySet<CheckReason> = new Set<CheckReason>([\n \"no_face\",\n \"media_unreadable\",\n \"clip_too_short\",\n \"no_face_source\",\n \"side_missing\",\n \"unreadable\",\n \"registry_unavailable\",\n \"otp_mismatch\",\n \"otp_expired\",\n \"otp_send_failed\",\n]);\n\n/** The two checks one biometric capture feeds. */\nconst BIOMETRIC_CHECKS: ReadonlySet<CheckType> = new Set<CheckType>([\"liveness\", \"face_match\"]);\n\n/** A check the browser may still submit. */\nexport function isExecutable(step: HostedStepView | undefined): boolean {\n return step !== undefined && (step.state === \"pending\" || step.state === \"input_required\");\n}\n\n/** The session accepts no further submissions. */\nexport function isTerminalView(view: Pick<HostedSessionView, \"status\">): boolean {\n return view.status !== \"created\" && view.status !== \"in_progress\";\n}\n\n/** First step in `steps[]` order with state `pending | input_required` (the backend's frontier). */\nexport function frontierStep(view: HostedSessionView): HostedStepView | undefined {\n return view.steps.find((step) => isExecutable(step));\n}\n\nexport function stepOf(view: HostedSessionView, checkType: CheckType): HostedStepView | undefined {\n return view.steps.find((step) => step.checkType === checkType);\n}\n\n/**\n * Fold a submit response (partner `SessionView`: no attemptsRemaining) into the\n * hosted view: status/outcome/step states+reasons come from the response; the\n * submitted check's `attemptsRemaining` is decremented locally (every accepted\n * submit consumes exactly one attempt server-side — `max(0, cap - attempts)`).\n * This keeps the happy path free of extra `GET /hosted/session` round-trips.\n */\nexport function mergeSessionView(\n prev: HostedSessionView,\n next: SessionView,\n submitted: CheckType,\n): HostedSessionView {\n const byType = new Map(prev.steps.map((step) => [step.checkType, step] as const));\n const steps: HostedStepView[] = next.steps.map((step) => {\n const before = byType.get(step.checkType);\n const attemptsBefore = before?.attemptsRemaining ?? 0;\n const merged: HostedStepView = {\n ...(before ?? {}),\n checkType: step.checkType,\n state: step.state,\n attemptsRemaining:\n step.checkType === submitted ? Math.max(0, attemptsBefore - 1) : attemptsBefore,\n };\n if (step.reason !== undefined) merged.reason = step.reason;\n else delete merged.reason;\n return merged;\n });\n return { ...prev, status: next.status, outcome: next.outcome, steps, expiresAt: next.expiresAt };\n}\n\nexport function unavailable(sessionId: string, reason?: ReasonCode): VerificationResult {\n return reason === undefined\n ? { sessionId, status: \"unavailable\" }\n : { sessionId, status: \"unavailable\", reason };\n}\n\nfunction withReason(\n sessionId: string,\n status: VerificationResult[\"status\"],\n reason: CheckReason | undefined,\n): VerificationResult {\n return reason === undefined ? { sessionId, status } : { sessionId, status, reason };\n}\n\n/**\n * Map the session view to the public result:\n * - `completed/approved → approved`, `completed/review` or `review_pending → review`,\n * `failed` or `completed/rejected → rejected` (reason = the deciding step's);\n * - `expired → unavailable` (no reason);\n * - in flight: a biometric step parked at `input_required` with a retryable\n * reason → `retry` when `autoRetry` and attempts remain, else `rejected`\n * (the partner opted out of retries — this capture was refused); a step in\n * `review` with nothing executable left → `review`; otherwise `unavailable`\n * (a non-biometric frontier the SDK cannot drive, or still processing).\n */\nexport function mapSessionResult(\n view: HostedSessionView,\n opts: { autoRetry: boolean },\n): VerificationResult {\n const { sessionId } = view;\n switch (view.status) {\n case \"completed\":\n if (view.outcome === \"approved\") return { sessionId, status: \"approved\" };\n if (view.outcome === \"review\") return withReason(sessionId, \"review\", reasonIn(view, \"review\"));\n return withReason(sessionId, \"rejected\", reasonIn(view, \"failed\"));\n case \"failed\":\n return withReason(sessionId, \"rejected\", reasonIn(view, \"failed\"));\n case \"review_pending\":\n return withReason(sessionId, \"review\", reasonIn(view, \"review\"));\n case \"expired\":\n return unavailable(sessionId);\n case \"created\":\n case \"in_progress\":\n break;\n default: {\n const unhandled: never = view.status;\n throw new Error(`mapSessionResult: unhandled status ${unhandled as string}`);\n }\n }\n\n const parked = view.steps.find(\n (step) =>\n BIOMETRIC_CHECKS.has(step.checkType) &&\n step.state === \"input_required\" &&\n step.reason !== undefined,\n );\n if (parked?.reason !== undefined) {\n const canRetry =\n opts.autoRetry && RETRYABLE_REASONS.has(parked.reason) && parked.attemptsRemaining > 0;\n return {\n sessionId,\n status: canRetry ? \"retry\" : \"rejected\",\n reason: parked.reason,\n attemptsRemaining: parked.attemptsRemaining,\n };\n }\n if (frontierStep(view) === undefined && view.steps.some((step) => step.state === \"review\")) {\n return withReason(sessionId, \"review\", reasonIn(view, \"review\"));\n }\n return unavailable(sessionId);\n}\n\n/** Reason of the first step in the given state (the deciding check). */\nfunction reasonIn(view: HostedSessionView, state: HostedStepView[\"state\"]): CheckReason | undefined {\n return view.steps.find((step) => step.state === state && step.reason !== undefined)?.reason;\n}\n","// The post-capture flow: upload the clip → attestation → submit `liveness` →\n// upload the keyframe → submit `face_match`. Logic ported (not the React) from\n// identity-hosted/lib/use-submit.ts (idempotency-key lifecycle, same-key\n// transport replay, one-shot consent_required recovery) and\n// lib/use-capture-submission.ts + components/steps/liveness-step.tsx (the\n// `buildSubmit` executor closures and the face_match chain).\n//\n// Per-submission caches (promoted media key, attestation) are CLOSURE LOCALS of\n// each executor: a same-key replay re-runs the executor with the caches intact\n// (byte-identical body — a re-presign or a fresh token under the same key would\n// be an idempotency_key_collision); fresh artifacts build fresh closures.\nimport { HostedApiError } from \"../client/errors\";\nimport { type HostedClient, stripMimeParams } from \"../client/hosted-client\";\nimport type {\n AttestationInput,\n CheckType,\n HostedSessionView,\n SessionView,\n} from \"../client/types\";\nimport { isExecutable, isTerminalView, stepOf } from \"./result\";\nimport type { CapturedArtifacts, SdkFailureReason } from \"./types\";\n\n/** The client surface the flow needs — `HostedClient` or a test fake. */\nexport type HostedClientLike = Pick<\n HostedClient,\n \"getSession\" | \"recordConsent\" | \"presign\" | \"uploadToSpaces\" | \"completeMedia\" | \"submitCheck\"\n>;\n\n/** The presign policy allowlist for `kind: 'clip'` (media.policy.ts mirror). */\nexport const CLIP_MIME_ALLOWLIST: readonly string[] = [\"video/webm\", \"video/mp4\"];\n\n/** The engine's keyframe encode (captureMirroredKeyframe → canvas JPEG). */\nconst KEYFRAME_MIME = \"image/jpeg\";\n\n/** Same-key transport replays AFTER the first try, and the pause between them. */\nexport const TRANSPORT_REPLAY_ATTEMPTS = 2;\nexport const TRANSPORT_REPLAY_DELAY_MS = 1_000;\n/** Cap on honouring a 429's Retry-After before giving up on this capture. */\nconst MAX_RETRY_AFTER_MS = 10_000;\n\n/** No (usable) response arrived — a same-key replay can succeed. */\nconst TRANSPORT_CODES: ReadonlySet<string> = new Set([\n \"network_error\",\n \"timeout\",\n \"upload_failed\",\n \"unknown_error\",\n \"rate_limit_exceeded\",\n]);\n\n/** The server moved past what we hold — re-GET and map from truth. */\nconst RESYNC_CODES: ReadonlySet<string> = new Set([\n \"session_not_active\",\n \"check_not_found\",\n \"check_already_finalized\",\n \"check_out_of_order\",\n]);\n\n/** A Turnstile challenge failed client-side (load / render / error-callback / timeout). */\nexport class AttestationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AttestationError\";\n }\n}\n\n/** One logical submission: receives the client and ITS idempotency key. */\nexport type SubmitExecutor = (\n client: HostedClientLike,\n idempotencyKey: string,\n) => Promise<SessionView>;\n\nexport interface SubmitRuntime {\n client: HostedClientLike;\n /** Force-record consent (the server just said it is missing). */\n ensureConsent(opts: { force: true }): Promise<void>;\n sleep(ms: number): Promise<void>;\n uuid(): string;\n}\n\n/**\n * Run one logical submission (ported use-submit semantics):\n * - a fresh `crypto.randomUUID()` key per logical submission;\n * - a transport-class failure replays the SAME executor under the SAME key\n * (bounded) — the backend's IdempotencyInterceptor returns the first\n * response instead of burning another attempt;\n * - ONE `consent_required` recovery: force-record consent and re-run under a\n * FRESH key (the 409 envelope is idempotency-cached under the old one);\n * - ONE attestation retry (client-side Turnstile failure or a server\n * `attestation_invalid`): `onAttestationInvalid` drops the cached token and\n * the executor re-runs under a fresh key.\n * Throws the final error otherwise.\n */\nexport async function runSubmission(\n rt: SubmitRuntime,\n executor: SubmitExecutor,\n hooks: { onAttestationInvalid?: () => void } = {},\n): Promise<SessionView> {\n let key = rt.uuid();\n let consentRecovered = false;\n let attestationRetried = false;\n let transportReplays = 0;\n for (;;) {\n try {\n return await executor(rt.client, key);\n } catch (err) {\n if (err instanceof AttestationError) {\n if (attestationRetried) throw err;\n attestationRetried = true;\n hooks.onAttestationInvalid?.();\n key = rt.uuid();\n continue;\n }\n if (!(err instanceof HostedApiError)) throw err;\n if (err.code === \"consent_required\" && !consentRecovered) {\n consentRecovered = true;\n await rt.ensureConsent({ force: true });\n key = rt.uuid();\n continue;\n }\n if (err.code === \"attestation_invalid\" && !attestationRetried) {\n attestationRetried = true;\n hooks.onAttestationInvalid?.();\n key = rt.uuid();\n continue;\n }\n if (TRANSPORT_CODES.has(err.code) && transportReplays < TRANSPORT_REPLAY_ATTEMPTS) {\n transportReplays += 1;\n const retryAfterMs =\n err.retryAfterSeconds !== undefined ? err.retryAfterSeconds * 1000 : undefined;\n await rt.sleep(\n retryAfterMs !== undefined\n ? Math.min(retryAfterMs, MAX_RETRY_AFTER_MS)\n : TRANSPORT_REPLAY_DELAY_MS,\n );\n continue;\n }\n throw err;\n }\n }\n}\n\nexport interface LivenessFlowDeps extends SubmitRuntime {\n artifacts: CapturedArtifacts;\n /** Fresh attestation per call (Turnstile execute, or `{sandbox: true}`). */\n getAttestation(): Promise<AttestationInput>;\n /** Latest hosted view (frontier decisions). */\n getView(): HostedSessionView;\n /** Fold a submit response into the view. */\n applySubmit(view: SessionView, submitted: CheckType): void;\n /** Flow-state hook for the capture handle. */\n onPhase(phase: \"uploading\" | \"checking\"): void;\n /** A newer capture / destroy superseded this flow. */\n isCancelled(): boolean;\n}\n\nexport type LivenessFlowOutcome =\n | { kind: \"settled\" }\n | { kind: \"resync\" }\n | { kind: \"unavailable\"; reason: SdkFailureReason }\n | { kind: \"cancelled\" };\n\n/**\n * Run the biometric submissions that are still executable: `liveness` when its\n * step is `pending | input_required`, then `face_match` when face_match is\n * executable and liveness either was NOT part of this capture (it had already\n * settled — any state, incl. `failed`: the selfie-fallback case, where this\n * capture only feeds face_match) or settled not-failed from this capture\n * (passed / review / processing / skipped — or absent). Returns `settled` for\n * the caller to map the view.\n */\nexport async function runLivenessFlow(deps: LivenessFlowDeps): Promise<LivenessFlowOutcome> {\n const { artifacts } = deps;\n const clip = artifacts.clip;\n const bareMime = stripMimeParams(artifacts.clipMime ?? \"\");\n if (\n artifacts.degraded === \"NO_RECORDER\" ||\n clip === undefined ||\n !CLIP_MIME_ALLOWLIST.includes(bareMime)\n ) {\n // No clip, or a container outside the presign allowlist (never sign an\n // off-allowlist type): v2 cannot run THIS capture.\n return { kind: \"unavailable\", reason: \"no_recorder\" };\n }\n\n try {\n const livenessWasExecutable = isExecutable(stepOf(deps.getView(), \"liveness\"));\n if (livenessWasExecutable) {\n let clipKey: string | null = null;\n let attestation: AttestationInput | null = null;\n const response = await runSubmission(\n deps,\n async (client, idempotencyKey) => {\n if (clipKey === null) {\n deps.onPhase(\"uploading\");\n const presigned = await client.presign(\"clip\", bareMime, clip.size);\n await client.uploadToSpaces(presigned.uploadUrl, clip, bareMime);\n clipKey = (await client.completeMedia(presigned.key)).key;\n }\n // Attestation AFTER the upload settles (token stays fresh), cached\n // for the same-key replay.\n if (attestation === null) {\n try {\n attestation = await deps.getAttestation();\n } catch (err) {\n throw new AttestationError(err instanceof Error ? err.message : String(err));\n }\n }\n deps.onPhase(\"checking\");\n return client.submitCheck(\n \"liveness\",\n { clipKey, attestation, captureChannel: artifacts.captureChannel },\n { idempotencyKey },\n );\n },\n {\n onAttestationInvalid: () => {\n attestation = null;\n },\n },\n );\n if (deps.isCancelled()) return { kind: \"cancelled\" };\n deps.applySubmit(response, \"liveness\");\n }\n\n const view = deps.getView();\n const liveness = stepOf(view, \"liveness\");\n const livenessOk =\n !livenessWasExecutable ||\n liveness === undefined ||\n liveness.state === \"passed\" ||\n liveness.state === \"review\" ||\n liveness.state === \"processing\" ||\n liveness.state === \"skipped\";\n if (!isTerminalView(view) && livenessOk && isExecutable(stepOf(view, \"face_match\"))) {\n const keyframe = artifacts.keyframe;\n let imageKey: string | null = null;\n const response = await runSubmission(deps, async (client, idempotencyKey) => {\n if (imageKey === null) {\n deps.onPhase(\"uploading\");\n const presigned = await client.presign(\"image\", KEYFRAME_MIME, keyframe.size);\n await client.uploadToSpaces(presigned.uploadUrl, keyframe, KEYFRAME_MIME);\n imageKey = (await client.completeMedia(presigned.key)).key;\n }\n deps.onPhase(\"checking\");\n return client.submitCheck(\"face_match\", { imageKey }, { idempotencyKey });\n });\n if (deps.isCancelled()) return { kind: \"cancelled\" };\n deps.applySubmit(response, \"face_match\");\n }\n return { kind: \"settled\" };\n } catch (err) {\n if (deps.isCancelled()) return { kind: \"cancelled\" };\n return classifyFailure(err);\n }\n}\n\nfunction classifyFailure(err: unknown): LivenessFlowOutcome {\n if (err instanceof AttestationError) return { kind: \"unavailable\", reason: \"attestation\" };\n if (err instanceof HostedApiError) {\n if (err.code === \"attestation_invalid\") return { kind: \"unavailable\", reason: \"attestation\" };\n if (RESYNC_CODES.has(err.code)) return { kind: \"resync\" };\n }\n return { kind: \"unavailable\", reason: \"network\" };\n}\n","// Cloudflare Turnstile: lazy script loader + execute-mode invisible challenge.\n// Ported from identity-hosted/lib/turnstile.ts (Plan 6 Task 10 AC4) — same\n// behaviour: the script loads ONCE, lazily, only when a liveness submit first\n// needs a token; each token request renders a fresh execute-mode widget,\n// resolves the callback token, and removes the widget. Hosts' CSP must allow\n// challenges.cloudflare.com.\n//\n// The site key is RUNTIME data (`HostedSessionView.turnstileSiteKey`); when it\n// is null the verification sends `{sandbox: true}` instead of calling this.\n\nexport const TURNSTILE_SCRIPT_SRC = \"https://challenges.cloudflare.com/turnstile/v0/api.js\";\n\n/** Bound on a single execute round-trip (challenge fetch + solve). */\nexport const TURNSTILE_EXECUTE_TIMEOUT_MS = 30_000;\n\nexport interface TurnstileRenderParams {\n sitekey: string;\n callback: (token: string) => void;\n \"error-callback\"?: (code?: string) => void;\n execution?: \"render\" | \"execute\";\n appearance?: \"always\" | \"execute\" | \"interaction-only\";\n}\n\n/** The subset of the Turnstile JS API this module uses. */\nexport interface TurnstileApi {\n render(container: HTMLElement, params: TurnstileRenderParams): string | undefined;\n execute(widgetId: string): void;\n remove(widgetId: string): void;\n}\n\n/** `window.turnstile` without augmenting the global Window type for consumers. */\nfunction installedApi(): TurnstileApi | undefined {\n return (window as unknown as { turnstile?: TurnstileApi }).turnstile;\n}\n\nlet loaderPromise: Promise<TurnstileApi> | null = null;\n\n/** Test-only: reset the module singleton between cases. */\nexport function resetTurnstileForTests(): void {\n loaderPromise = null;\n}\n\n/** Load the Turnstile script once (singleton; a load failure resets it so a\n * retry can re-attempt). */\nexport function loadTurnstile(): Promise<TurnstileApi> {\n loaderPromise ??= new Promise<TurnstileApi>((resolve, reject) => {\n const present = installedApi();\n if (present) {\n resolve(present);\n return;\n }\n const script = document.createElement(\"script\");\n script.src = TURNSTILE_SCRIPT_SRC;\n script.async = true;\n script.onload = () => {\n const api = installedApi();\n if (api) {\n resolve(api);\n } else {\n loaderPromise = null;\n reject(new Error(\"Turnstile script loaded but exposed no API\"));\n }\n };\n script.onerror = () => {\n loaderPromise = null;\n script.remove(); // a retry appends a fresh tag\n reject(new Error(\"Turnstile script failed to load\"));\n };\n document.head.appendChild(script);\n });\n return loaderPromise;\n}\n\n/** Options of {@link executeTurnstile}. */\nexport interface ExecuteTurnstileOptions {\n /** Bound on the challenge round-trip; default {@link TURNSTILE_EXECUTE_TIMEOUT_MS}. */\n timeoutMs?: number;\n /**\n * Aborts the challenge: the promise rejects and the widget, its container and\n * the timeout are cleaned up at once. `createVerification().destroy()` passes\n * its own signal so a torn-down verification never leaves a widget behind.\n */\n signal?: AbortSignal;\n}\n\nfunction abortError(): Error {\n return new Error(\"Turnstile challenge aborted\");\n}\n\n/**\n * Run one invisible execute-mode challenge and resolve its token. Rejects on\n * challenge error, on `signal` abort, or after {@link TURNSTILE_EXECUTE_TIMEOUT_MS}\n * — the verification maps a failure to `result {status:'unavailable',\n * reason:'attestation'}` after one retry.\n */\nexport async function executeTurnstile(\n siteKey: string,\n opts: ExecuteTurnstileOptions = {},\n): Promise<string> {\n const timeoutMs = opts.timeoutMs ?? TURNSTILE_EXECUTE_TIMEOUT_MS;\n const signal = opts.signal;\n if (signal?.aborted) throw abortError();\n const api = await loadTurnstile();\n if (signal?.aborted) throw abortError();\n const container = document.createElement(\"div\");\n document.body.appendChild(container);\n let widgetId: string | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let onAbort: (() => void) | undefined;\n try {\n return await new Promise<string>((resolve, reject) => {\n timer = setTimeout(\n () => reject(new Error(`Turnstile challenge timed out (${timeoutMs} ms)`)),\n timeoutMs,\n );\n if (signal !== undefined) {\n onAbort = () => reject(abortError());\n signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n widgetId = api.render(container, {\n sitekey: siteKey,\n execution: \"execute\",\n appearance: \"execute\",\n callback: resolve,\n \"error-callback\": (code) => {\n reject(new Error(`Turnstile challenge failed${code ? ` (${code})` : \"\"}`));\n },\n });\n if (widgetId === undefined) {\n reject(new Error(\"Turnstile render returned no widget id\"));\n return;\n }\n api.execute(widgetId);\n });\n } finally {\n // ONE cleanup path for every outcome (token / challenge error / timeout /\n // abort / render failure): the challenge timer and the abort listener must\n // never leak past settlement.\n clearTimeout(timer);\n if (signal !== undefined && onAbort !== undefined) signal.removeEventListener(\"abort\", onAbort);\n if (widgetId !== undefined) {\n try {\n api.remove(widgetId);\n } catch {\n // widget already gone — nothing to clean\n }\n }\n container.remove();\n }\n}\n","// createVerification — composes the hosted client, consent, the early registry\n// submit, the capture handle and the post-capture flow behind the public\n// contract (spec §3.1). Framework-free; the only state is the latest hosted\n// view (re-emitted on every update via `on('view')`).\nimport { HostedClient } from \"../client/hosted-client\";\nimport type { AttestationInput, CheckType, HostedSessionView, SessionView } from \"../client/types\";\nimport {\n createLivenessCaptureInternal,\n type LivenessCaptureInternalHandle,\n type LivenessCaptureInternals,\n} from \"../capture/create-liveness-capture\";\nimport { createEmitter } from \"./emitter\";\nimport {\n type HostedClientLike,\n runLivenessFlow,\n runSubmission,\n type SubmitRuntime,\n} from \"./liveness-flow\";\nimport {\n frontierStep,\n isTerminalView,\n mapSessionResult,\n mergeSessionView,\n stepOf,\n unavailable,\n} from \"./result\";\nimport { executeTurnstile } from \"./turnstile\";\nimport type {\n CapturedArtifacts,\n LivenessCaptureHandle,\n LivenessCaptureOptions,\n Verification,\n VerificationEvents,\n VerificationOptions,\n VerificationResult,\n} from \"./types\";\n\n/** Production API origin — the `apiOrigin` default. */\nexport const DEFAULT_API_ORIGIN = \"https://api.sekyro.ai\";\n\n/** Pause before the single `registry_unavailable` re-submit. */\nexport const REGISTRY_RETRY_DELAY_MS = 5_000;\n\n/** Bounded poll while a biometric verdict is still `processing` after the submits. */\nexport const PROCESSING_POLL_DELAY_MS = 1_500;\nexport const PROCESSING_POLL_MAX = 10;\n\n/**\n * Construction seams — tests and Sekyro's own hosted page (`@sekyro/web/internal`).\n * Not part of the partner contract.\n */\nexport interface VerificationInternals {\n /** Replace the HTTP client (default: `new HostedClient({...})`). */\n client?: HostedClientLike;\n /**\n * Replace the Turnstile challenge (default: {@link executeTurnstile}). The\n * `signal` aborts when the verification is destroyed (M1).\n */\n getTurnstileToken?: (siteKey: string, opts: { signal: AbortSignal }) => Promise<string>;\n /** Capture-engine seams forwarded to {@link createLivenessCaptureInternal}. */\n capture?: LivenessCaptureInternals;\n sleep?: (ms: number) => Promise<void>;\n uuid?: () => string;\n}\n\nfunction defaultSleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/** `crypto.randomUUID()` with a v4 fallback for hosts that lack it. */\nexport function randomUuid(): string {\n const c = (globalThis as { crypto?: Crypto }).crypto;\n if (c !== undefined && typeof c.randomUUID === \"function\") return c.randomUUID();\n const bytes = new Uint8Array(16);\n if (c !== undefined && typeof c.getRandomValues === \"function\") c.getRandomValues(bytes);\n else for (let i = 0; i < 16; i += 1) bytes[i] = Math.floor(Math.random() * 256);\n bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x40;\n bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80;\n const hex = [...bytes].map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n\n/**\n * Create a verification bound to one session (spec §3.1):\n * `consent()` → `startRegistry()` → `liveness({video})` → `on('result')`.\n */\nexport function createVerification(options: VerificationOptions): Verification {\n return createVerificationInternal(options, {});\n}\n\n/** {@link createVerification} with construction seams (tests / Sekyro-internal hosts). */\nexport function createVerificationInternal(\n options: VerificationOptions,\n internals: VerificationInternals,\n): Verification {\n const apiOrigin = options.apiOrigin ?? DEFAULT_API_ORIGIN;\n const autoRetry = options.autoRetry ?? true;\n const rearm = options.rearm ?? \"auto\";\n const client: HostedClientLike =\n internals.client ??\n new HostedClient({\n apiOrigin,\n sessionToken: options.clientToken,\n ...(options.fetch !== undefined ? { fetch: options.fetch } : {}),\n });\n const sleep = internals.sleep ?? defaultSleep;\n const uuid = internals.uuid ?? randomUuid;\n const getTurnstileToken = internals.getTurnstileToken ?? executeTurnstile;\n const emitter = createEmitter<VerificationEvents>();\n\n let destroyed = false;\n // Aborts an in-flight Turnstile challenge on destroy() (widget + timer clean up).\n const lifetime = new AbortController();\n\n // ── view ───────────────────────────────────────────────────────────────────\n let view: HostedSessionView | null = null;\n let bootstrap: Promise<HostedSessionView> | null = null;\n const setView = (next: HostedSessionView): void => {\n view = next;\n emitter.emit(\"view\", next);\n };\n const ensureView = (): Promise<HostedSessionView> => {\n if (view !== null) return Promise.resolve(view);\n bootstrap ??= client\n .getSession()\n .then((next) => {\n setView(next);\n return next;\n })\n .finally(() => {\n bootstrap = null;\n });\n return bootstrap;\n };\n const refreshView = async (): Promise<HostedSessionView> => {\n const next = await client.getSession();\n setView(next);\n return next;\n };\n const applySubmit = (response: SessionView, submitted: CheckType): void => {\n if (view !== null) setView(mergeSessionView(view, response, submitted));\n };\n\n // ── consent (idempotent; `force` after a server consent_required) ──────────\n let consentInFlight: Promise<void> | null = null;\n const recordConsent = async (force: boolean): Promise<void> => {\n const current = await ensureView();\n if (!force && current.consentRecorded) return;\n await client.recordConsent(options.locale);\n if (view !== null) setView({ ...view, consentRecorded: true });\n };\n const ensureConsent = (opts?: { force?: boolean }): Promise<void> => {\n if (opts?.force === true) return recordConsent(true);\n consentInFlight ??= recordConsent(false).finally(() => {\n consentInFlight = null;\n });\n return consentInFlight;\n };\n\n const runtime: SubmitRuntime = {\n client,\n ensureConsent: (opts) => ensureConsent(opts),\n sleep,\n uuid,\n };\n\n // ── result emission ────────────────────────────────────────────────────────\n // A session verdict is emitted ONCE (the registry may settle it before any\n // capture); `retry` / `unavailable` are per capture.\n let terminalEmitted = false;\n const emitResult = (result: VerificationResult): void => {\n if (result.status === \"approved\" || result.status === \"rejected\" || result.status === \"review\") {\n if (terminalEmitted) return;\n terminalEmitted = true;\n }\n emitter.emit(\"result\", result);\n };\n\n // ── early registry ─────────────────────────────────────────────────────────\n let registry: Promise<void> | null = null;\n let registryFailed = false;\n // The frontier is population_registry on a session minted WITHOUT a bound\n // NNI: the SDK has nothing to submit (and must never guess one).\n let registryUnbound = false;\n const submitRegistry = (): Promise<SessionView> =>\n runSubmission(runtime, (c, idempotencyKey) =>\n // `{}` input: the session is bound to a SERVER-provided NNI (Plan A Task 2).\n c.submitCheck(\"population_registry\", {}, { idempotencyKey }),\n );\n const runRegistry = async (): Promise<void> => {\n try {\n const current = await ensureView();\n if (isTerminalView(current) || frontierStep(current)?.checkType !== \"population_registry\") {\n return;\n }\n if (current.nniBound !== true) {\n registryUnbound = true;\n return;\n }\n await ensureConsent();\n applySubmit(await submitRegistry(), \"population_registry\");\n const step = view === null ? undefined : stepOf(view, \"population_registry\");\n if (\n step?.state === \"input_required\" &&\n step.reason === \"registry_unavailable\" &&\n step.attemptsRemaining > 0\n ) {\n await sleep(REGISTRY_RETRY_DELAY_MS);\n if (destroyed) return;\n applySubmit(await submitRegistry(), \"population_registry\");\n }\n } catch {\n // Never throws (incl. 409 nni_locked / transport failures): the flow\n // surfaces it through result mapping.\n registryFailed = true;\n return;\n }\n if (view !== null && isTerminalView(view)) emitResult(mapSessionResult(view, { autoRetry }));\n };\n const startRegistry = (): Promise<void> => {\n registry ??= runRegistry();\n return registry;\n };\n\n // ── attestation ────────────────────────────────────────────────────────────\n // The SDK echoes the site key it rendered (`siteKey`) so the backend selects\n // the matching widget secret deterministically — Turnstile tokens are\n // single-use, so the verifier never retries with another secret (C1).\n const getAttestation = async (): Promise<AttestationInput> => {\n const current = await ensureView();\n const siteKey = current.turnstileSiteKey;\n if (siteKey === null) return { sandbox: true };\n return {\n channel: \"hosted_web\",\n siteKey,\n turnstileToken: await getTurnstileToken(siteKey, { signal: lifetime.signal }),\n };\n };\n\n // ── capture + flow ─────────────────────────────────────────────────────────\n let active: LivenessCaptureInternalHandle | null = null;\n let flowToken = 0;\n\n const settleProcessing = async (): Promise<HostedSessionView> => {\n let current = await ensureView();\n for (\n let i = 0;\n i < PROCESSING_POLL_MAX &&\n !destroyed &&\n !isTerminalView(current) &&\n frontierStep(current) === undefined &&\n current.steps.some((step) => step.state === \"processing\");\n i += 1\n ) {\n await sleep(PROCESSING_POLL_DELAY_MS);\n if (destroyed) break;\n current = await refreshView();\n }\n return current;\n };\n\n const runFlow = async (\n capture: LivenessCaptureInternalHandle,\n artifacts: CapturedArtifacts,\n token: number,\n ): Promise<void> => {\n const isCancelled = (): boolean => destroyed || token !== flowToken || active !== capture;\n const finish = (result: VerificationResult): void => {\n if (isCancelled()) return;\n emitResult(result);\n if (result.status === \"retry\" && rearm === \"auto\") {\n // Re-arm: the engine restarts and the next `captured` runs a new flow.\n capture.handle.retry();\n return;\n }\n // `done` (incl. a manual-rearm `retry`): the host calls `retry()` on the\n // handle when the user is ready — the engine restarts from there.\n capture.setFlowState(\"done\");\n };\n\n if (artifacts.degraded === \"NO_RECORDER\") {\n // No MediaRecorder: nothing is submitted (no liveness, no face_match).\n const sessionId = view?.sessionId ?? (await ensureView().catch(() => null))?.sessionId ?? \"\";\n finish(unavailable(sessionId, \"no_recorder\"));\n return;\n }\n\n capture.setFlowState(\"uploading\");\n try {\n // Registry first: it records consent itself only when it actually\n // submits — an unbound / failed registry frontier ends the flow below\n // without recording a consent nothing was submitted under.\n await startRegistry();\n if (isCancelled()) return;\n let current = await ensureView();\n if (!isTerminalView(current)) {\n if (frontierStep(current)?.checkType === \"population_registry\") {\n // The registry never passed (outage after the retry, or a request-\n // level failure): the biometric checks cannot be submitted.\n finish(\n unavailable(\n current.sessionId,\n registryUnbound ? \"nni_unbound\" : registryFailed ? \"network\" : \"registry_unavailable\",\n ),\n );\n return;\n }\n await ensureConsent();\n if (isCancelled()) return;\n const outcome = await runLivenessFlow({\n ...runtime,\n artifacts,\n getAttestation,\n getView: () => view ?? current,\n applySubmit,\n onPhase: (phase) => {\n if (!isCancelled()) capture.setFlowState(phase);\n },\n isCancelled,\n });\n if (isCancelled()) return;\n if (outcome.kind === \"unavailable\") {\n finish(unavailable(current.sessionId, outcome.reason));\n return;\n }\n if (outcome.kind === \"resync\") await refreshView();\n current = await settleProcessing();\n }\n finish(mapSessionResult(current, { autoRetry }));\n } catch {\n if (isCancelled()) return;\n finish(unavailable(view?.sessionId ?? \"\", \"network\"));\n }\n };\n\n const liveness = (captureOptions: LivenessCaptureOptions): LivenessCaptureHandle => {\n active?.handle.destroy();\n const capture = createLivenessCaptureInternal(captureOptions, internals.capture);\n active = capture;\n capture.handle.on(\"state\", (state) => {\n // A fresh engine attempt supersedes any in-flight flow for the old artifacts.\n if (state === \"starting\") flowToken += 1;\n });\n capture.handle.on(\"captured\", (artifacts) => {\n const token = ++flowToken;\n // Partners' own `captured` handlers run first (the event fires BEFORE\n // any upload); the flow starts on the next microtask.\n void Promise.resolve().then(() => runFlow(capture, artifacts, token));\n });\n return capture.handle;\n };\n\n return {\n consent: () => ensureConsent(),\n startRegistry,\n liveness,\n on: (event, handler) => emitter.on(event, handler),\n destroy: () => {\n destroyed = true;\n lifetime.abort();\n active?.handle.destroy();\n active = null;\n emitter.clear();\n },\n };\n}\n"],"mappings":"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","names":[]}