@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.
- package/README.md +172 -96
- package/dist/agents/AGENTS.md +20 -25
- package/dist/agents/manifest.json +15 -4
- package/dist/{types-CnlkFS7V.d.ts → api-DyExBfAQ.d.ts} +161 -97
- package/dist/capture-ui.css +1 -1
- package/dist/capture-ui.d.ts +5 -4
- package/dist/capture-ui.js +4 -2
- package/dist/capture.d.ts +3 -3
- package/dist/capture.js +3 -1
- package/dist/challenge.d.ts +18 -0
- package/dist/challenge.js +9 -0
- package/dist/chunk-5AQCMTZV.js +6 -0
- package/dist/chunk-5MNNRYD5.js +7 -0
- package/dist/{chunk-TRTAZKYV.js → chunk-6U53T32A.js} +4 -3
- package/dist/chunk-BEZGAQ74.js +8 -0
- package/dist/chunk-GFHNOZVO.js +3 -0
- package/dist/chunk-IQKHRPJR.js +3 -0
- package/dist/chunk-ITLSDZHK.js +5 -0
- package/dist/chunk-LTMLIUPC.js +5 -0
- package/dist/chunk-QVDWM4KK.js +6 -0
- package/dist/chunk-UBQTPS5J.js +3 -0
- package/dist/{controller-C4vJ47JI.d.ts → controller-CFL3mA5e.d.ts} +2 -2
- package/dist/copy-DCeQ4JKx.d.ts +19 -0
- package/dist/{copy-DeUly5vr.d.ts → copy-Dfmk11S_.d.ts} +2 -2
- package/dist/cross-device.d.ts +19 -1
- package/dist/custom-form.css +1 -1
- package/dist/custom-form.d.ts +4 -3
- package/dist/custom-form.js +6 -3
- package/dist/fraud.d.ts +4 -3
- package/dist/fraud.js +6 -4
- package/dist/idv/cross-device.d.ts +41 -6
- package/dist/idv/cross-device.js +7 -3
- package/dist/idv.css +1 -1
- package/dist/idv.d.ts +4 -3
- package/dist/idv.js +10 -6
- package/dist/index.d.ts +19 -6
- package/dist/index.js +9 -7
- package/dist/{machine--zVZIM4F.d.ts → machine-CuZalPFX.d.ts} +15 -3
- package/dist/react.d.ts +6 -4
- package/dist/react.js +7 -5
- package/dist/workspace.d.ts +60 -0
- package/dist/workspace.js +7 -0
- package/package.json +15 -5
- package/dist/chunk-BYTKOKAD.js +0 -7
- package/dist/chunk-C7H2ZVQT.js +0 -7
- package/dist/chunk-CXNPD67Z.js +0 -5
- package/dist/chunk-FGWZZNAN.js +0 -5
- package/dist/chunk-WQCYRLWP.js +0 -3
- package/dist/fp.esm.min-QD5CJD52.js +0 -5
- package/dist/index-BtJbU9MC.d.ts +0 -43
|
@@ -0,0 +1,8 @@
|
|
|
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 };
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var IDV_DOCUMENT_TYPES=["passport","drivers_license","id_card","residence_permit","visa","work_permit"];var TWO_SIDED_DOCUMENT_TYPES=new Set(["drivers_license","id_card","residence_permit","work_permit"]);function isTwoSidedDocumentType(t){return TWO_SIDED_DOCUMENT_TYPES.has(t)}
|
|
2
|
+
|
|
3
|
+
export { IDV_DOCUMENT_TYPES, isTwoSidedDocumentType };
|
|
@@ -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"}},"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 };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { createChecktivError } from './chunk-QVDWM4KK.js';
|
|
2
|
+
|
|
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
|
+
|
|
5
|
+
export { createChecktivErrorEvent, getCrossDeviceOpener, mapStateToEvent, registerCrossDeviceOpener };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { IDV_DOCUMENT_TYPES } from './chunk-IQKHRPJR.js';
|
|
2
|
+
import { sdkPublicSettings, SESSIONS_ME_PATH, dataPlaneHeaders } from './chunk-ITLSDZHK.js';
|
|
3
|
+
|
|
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
|
+
|
|
6
|
+
export { createChecktivError, createTokenManager, isJourneyPlaneBody, isRecord, mapHttpStatusToError, parseSessionData, resolveSession, warnWrongTokenPlane, withTokenRetry };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { f as CaptureState, I as IdvR2Keys, g as CaptureInitMessage, a as CaptureBehaviorMessage } from './machine-CuZalPFX.js';
|
|
2
2
|
|
|
3
3
|
type CaptureEvent = {
|
|
4
4
|
type: 'selfie-cv-reject';
|
|
@@ -14,7 +14,7 @@ type SubmitResult = {
|
|
|
14
14
|
ok: true;
|
|
15
15
|
} | {
|
|
16
16
|
ok: false;
|
|
17
|
-
reason: 'token_expired' | 'failed' | 'signal_pending' | (string & {});
|
|
17
|
+
reason: 'token_expired' | 'failed' | 'signal_pending' | 'capture_superseded' | (string & {});
|
|
18
18
|
};
|
|
19
19
|
interface CaptureControllerDeps {
|
|
20
20
|
getIframe: () => HTMLIFrameElement | null;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
interface CrossDeviceCopy {
|
|
2
|
+
readonly desktopPrompt?: string;
|
|
3
|
+
readonly desktopSubtext?: string;
|
|
4
|
+
readonly waitingLabel?: string;
|
|
5
|
+
readonly copyLinkLabel?: string;
|
|
6
|
+
readonly linkCopiedLabel?: string;
|
|
7
|
+
readonly backLabel?: string;
|
|
8
|
+
readonly refreshLinkLabel?: string;
|
|
9
|
+
readonly qrAlt?: string;
|
|
10
|
+
readonly mobilePrompt?: string;
|
|
11
|
+
readonly mobileOpenBrowserHint?: string;
|
|
12
|
+
readonly mobileCopyLinkLabel?: string;
|
|
13
|
+
readonly mobileLinkCopiedLabel?: string;
|
|
14
|
+
readonly mobileTryAgainLabel?: string;
|
|
15
|
+
readonly mobileCameraSettingsNote?: string;
|
|
16
|
+
readonly unavailableMessage: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export type { CrossDeviceCopy as C };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b as CoachingKind, d as CaptureErrorKind, e as CapturePhase } from './machine-CuZalPFX.js';
|
|
2
2
|
|
|
3
|
-
type TerminalKind = 'mint_error' | 'submit_error' | 'token_expired';
|
|
3
|
+
type TerminalKind = 'mint_error' | 'submit_error' | 'token_expired' | 'capture_superseded';
|
|
4
4
|
interface MountCopy {
|
|
5
5
|
cvReject?: (attemptIndex: number, kind: CoachingKind) => string;
|
|
6
6
|
error?: (kind: CaptureErrorKind) => string;
|
package/dist/cross-device.d.ts
CHANGED
|
@@ -1 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
import { C as CrossDeviceCopy } from './copy-DCeQ4JKx.js';
|
|
2
|
+
|
|
3
|
+
interface CrossDevicePanelProps {
|
|
4
|
+
url: string;
|
|
5
|
+
copy: CrossDeviceCopy;
|
|
6
|
+
isMobile: boolean;
|
|
7
|
+
completing?: boolean;
|
|
8
|
+
onBack?: () => void;
|
|
9
|
+
onRefreshLink?: () => void;
|
|
10
|
+
onRetry?: () => void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface CrossDeviceHandle {
|
|
14
|
+
update(next: CrossDevicePanelProps): void;
|
|
15
|
+
destroy(): void;
|
|
16
|
+
}
|
|
17
|
+
declare function mountCrossDevice(target: HTMLElement, props: CrossDevicePanelProps): CrossDeviceHandle;
|
|
18
|
+
|
|
19
|
+
export { CrossDeviceCopy, type CrossDeviceHandle, type CrossDevicePanelProps, mountCrossDevice };
|
package/dist/custom-form.css
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.checktiv-cf-field{display:flex;flex-direction:column;gap:0.375rem;margin-bottom:1rem}.checktiv-cf-label{font-size:0.875rem;font-weight:500;color:var(--theme-on-surface-1, #16181d)}.checktiv-cf-help{margin:0;font-size:0.8125rem;color:var(--theme-on-surface-1-muted, rgba(22, 24, 29, 0.62))}.checktiv-cf-input,.checktiv-cf-select{width:100%;box-sizing:border-box;padding:0.5rem 0.75rem;font-size:0.9375rem;font-family:inherit;line-height:1.5;color:var(--theme-on-surface-1, #16181d);background-color:var(--theme-surface-1, #ffffff);border:1px solid var(--theme-border-strong, rgba(22, 24, 29, 0.18));border-radius:var(--theme-button-border-radius, 0.4rem);outline:none;transition:border-color 0.15s ease,box-shadow 0.15s ease}.checktiv-cf-input::placeholder{color:var(--theme-on-surface-1-muted, rgba(22, 24, 29, 0.62))}textarea.checktiv-cf-input{min-height:6rem;resize:vertical}.checktiv-cf-input:focus,.checktiv-cf-select:focus{border-color:var(--theme-primary, #2563eb);box-shadow:0 0 0 3px var(--theme-ring, rgba(37, 99, 235, 0.35))}.checktiv-cf-multiselect input[type=checkbox],.checktiv-cf-radio{width:1rem;height:1rem;accent-color:var(--theme-primary, #2563eb)}.checktiv-cf-radiogroup{display:flex;flex-direction:row;gap:1.25rem;margin:0;padding:0;border:0}.checktiv-cf-radio-option{display:inline-flex;align-items:center;gap:0.5rem;font-size:0.9375rem;color:var(--theme-on-surface-1, #16181d);cursor:pointer}.checktiv-cf-multiselect{display:flex;flex-direction:column;gap:0.375rem}.checktiv-cf-option{display:flex;align-items:center;gap:0.5rem;font-size:0.9375rem;color:var(--theme-on-surface-1, #16181d)}.checktiv-cf-file{width:100%;box-sizing:border-box;padding:0.5rem 0.75rem;font-size:0.9375rem;font-family:inherit;color:var(--theme-on-surface-1, #16181d);background-color:var(--theme-surface-1, #ffffff);border:1px dashed var(--theme-border-strong, rgba(22, 24, 29, 0.18));border-radius:var(--theme-button-border-radius, 0.4rem)}.checktiv-cf-heading{margin:1rem 0 0.5rem;font-size:1.125rem;font-weight:600;color:var(--theme-on-surface-1, #16181d)}.checktiv-cf-paragraph{margin:0 0 1rem;font-size:0.9375rem;line-height:1.6;color:var(--theme-on-surface-1-muted, rgba(22, 24, 29, 0.62))}.checktiv-cf-submit{display:inline-flex;align-items:center;justify-content:center;padding:0.5rem 1.25rem;font-size:0.9375rem;font-weight:600;font-family:inherit;color:var(--theme-on-primary, #ffffff);background-color:var(--theme-primary, #2563eb);border:none;border-radius:var(--theme-button-border-radius, 0.4rem);cursor:pointer;transition:background-color 0.15s ease}.checktiv-cf-submit:hover:not(:disabled){background-color:var(--theme-primary-hover, #1d4ed8)}.checktiv-cf-submit:disabled{opacity:0.55;cursor:not-allowed}
|
|
1
|
+
.checktiv-cf-field{display:flex;flex-direction:column;gap:0.375rem;margin-bottom:1rem}.checktiv-cf-label{font-size:0.875rem;font-weight:500;color:var(--theme-on-surface-1, #16181d)}.checktiv-cf-help{margin:0;font-size:0.8125rem;color:var(--theme-on-surface-1-muted, rgba(22, 24, 29, 0.62))}.checktiv-cf-input,.checktiv-cf-select{width:100%;box-sizing:border-box;padding:0.5rem 0.75rem;font-size:0.9375rem;font-family:inherit;line-height:1.5;color:var(--theme-on-surface-1, #16181d);background-color:var(--theme-surface-1, #ffffff);border:1px solid var(--theme-border-strong, rgba(22, 24, 29, 0.18));border-radius:var(--theme-button-border-radius, 0.4rem);outline:none;transition:border-color 0.15s ease,box-shadow 0.15s ease}.checktiv-cf-input::placeholder{color:var(--theme-on-surface-1-muted, rgba(22, 24, 29, 0.62))}textarea.checktiv-cf-input{min-height:6rem;resize:vertical}.checktiv-cf-input:focus,.checktiv-cf-select:focus{border-color:var(--theme-primary, #2563eb);box-shadow:0 0 0 3px var(--theme-ring, rgba(37, 99, 235, 0.35))}.checktiv-cf-multiselect input[type=checkbox],.checktiv-cf-radio{width:1rem;height:1rem;accent-color:var(--theme-primary, #2563eb)}.checktiv-cf-radiogroup{display:flex;flex-direction:row;gap:1.25rem;margin:0;padding:0;border:0}.checktiv-cf-radio-option{display:inline-flex;align-items:center;gap:0.5rem;font-size:0.9375rem;color:var(--theme-on-surface-1, #16181d);cursor:pointer}.checktiv-cf-multiselect{display:flex;flex-direction:column;gap:0.375rem}.checktiv-cf-option{display:flex;align-items:center;gap:0.5rem;font-size:0.9375rem;color:var(--theme-on-surface-1, #16181d)}.checktiv-cf-file{width:100%;box-sizing:border-box;padding:0.5rem 0.75rem;font-size:0.9375rem;font-family:inherit;color:var(--theme-on-surface-1, #16181d);background-color:var(--theme-surface-1, #ffffff);border:1px dashed var(--theme-border-strong, rgba(22, 24, 29, 0.18));border-radius:var(--theme-button-border-radius, 0.4rem)}.checktiv-cf-error{margin:0.125rem 0 0;font-size:0.8125rem;line-height:1.4;color:var(--theme-danger, #dc2626)}.checktiv-cf-input[aria-invalid=true],.checktiv-cf-select[aria-invalid=true],.checktiv-cf-file[aria-invalid=true]{border-color:var(--theme-danger, #dc2626)}.checktiv-cf-input[aria-invalid=true]:focus,.checktiv-cf-select[aria-invalid=true]:focus{border-color:var(--theme-danger, #dc2626);box-shadow:0 0 0 3px var(--theme-danger, #dc2626)}.checktiv-cf-heading{margin:1rem 0 0.5rem;font-size:1.125rem;font-weight:600;color:var(--theme-on-surface-1, #16181d)}.checktiv-cf-paragraph{margin:0 0 1rem;font-size:0.9375rem;line-height:1.6;color:var(--theme-on-surface-1-muted, rgba(22, 24, 29, 0.62))}.checktiv-cf-submit{display:inline-flex;align-items:center;justify-content:center;padding:0.5rem 1.25rem;font-size:0.9375rem;font-weight:600;font-family:inherit;color:var(--theme-on-primary, #ffffff);background-color:var(--theme-primary, #2563eb);border:none;border-radius:var(--theme-button-border-radius, 0.4rem);cursor:pointer;transition:background-color 0.15s ease}.checktiv-cf-submit:hover:not(:disabled){background-color:var(--theme-primary-hover, #1d4ed8)}.checktiv-cf-submit:disabled{opacity:0.55;cursor:not-allowed}
|
package/dist/custom-form.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export {
|
|
2
|
-
import './machine
|
|
3
|
-
import './copy-
|
|
1
|
+
export { E as ChecktivCustomFormEvent, H as CustomFormCopy, J as CustomFormFieldCopy, K as CustomFormHandle, L as CustomFormMountOptions, N as createCustomForm } from './api-DyExBfAQ.js';
|
|
2
|
+
import './machine-CuZalPFX.js';
|
|
3
|
+
import './copy-Dfmk11S_.js';
|
|
4
|
+
import './copy-DCeQ4JKx.js';
|
package/dist/custom-form.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import { registerModule
|
|
1
|
+
import { registerModule } from './chunk-GFHNOZVO.js';
|
|
2
|
+
import { assertNever } from './chunk-UBQTPS5J.js';
|
|
3
|
+
import { warnWrongTokenPlane, withTokenRetry, isRecord, isJourneyPlaneBody, createChecktivError, mapHttpStatusToError } from './chunk-QVDWM4KK.js';
|
|
2
4
|
import { u } from './chunk-HV2QKVJX.js';
|
|
3
5
|
import { R, k, S } from './chunk-XOGHMNBX.js';
|
|
6
|
+
import './chunk-IQKHRPJR.js';
|
|
7
|
+
import { SESSIONS_ME_PATH, dataPlaneHeaders, stepSubmitPath, formUploadUrlPath } from './chunk-ITLSDZHK.js';
|
|
4
8
|
import './chunk-QFA3K5ZV.js';
|
|
5
|
-
import { createChecktivError, mapHttpStatusToError } from './chunk-WQCYRLWP.js';
|
|
6
9
|
import './chunk-AIK7CDV6.js';
|
|
7
10
|
|
|
8
|
-
function labelText(props){return props.copy?.label??props.field.id}function labelIdFor(controlId){return `${controlId}-label`}function FieldShell(props,control){const help=props.copy?.helpText;return u("div",{class:"checktiv-cf-field",children:[u("label",{id:labelIdFor(props.id),for:props.id,class:"checktiv-cf-label",children:labelText(props)}),help!==void 0?u("p",{id:`${props.id}-help`,class:"checktiv-cf-help",children:help}):null,control]})}function asText(value){return typeof value==="string"?value:""}function asInputValue(value){return typeof value==="number"?String(value):asText(value)}function inputTypeFor(type){switch(type){case "email":return "email";case "phone":return "tel";case "date":return "date";case "number":return "number";default:return "text"}}function renderTextLike(props){const{field}=props;const onInput=e=>{const target=e.target;if(field.type==="number"){const input=target;props.onChange(input.value===""||Number.isNaN(input.valueAsNumber)?void 0:input.valueAsNumber);return}props.onChange(target.value);};if(field.type==="long_text"){return FieldShell(props,u("textarea",{id:props.id,name:field.id,required:field.required,class:"checktiv-cf-input",value:asInputValue(props.value),onInput}))}return FieldShell(props,u("input",{id:props.id,name:field.id,type:inputTypeFor(field.type),required:field.required,class:"checktiv-cf-input",value:asInputValue(props.value),onInput}))}function renderBoolean(props){const yesId=`${props.id}-yes`;const noId=`${props.id}-no`;return FieldShell(props,u("fieldset",{class:"checktiv-cf-radiogroup",role:"radiogroup","aria-labelledby":labelIdFor(props.id),"aria-required":props.field.required?"true":void 0,children:[u("label",{for:yesId,class:"checktiv-cf-radio-option",children:[u("input",{id:yesId,name:props.field.id,type:"radio",class:"checktiv-cf-radio",checked:props.value===true,onChange:e=>{if(e.target.checked)props.onChange(true);}}),props.booleanYes]}),u("label",{for:noId,class:"checktiv-cf-radio-option",children:[u("input",{id:noId,name:props.field.id,type:"radio",class:"checktiv-cf-radio",checked:props.value===false,onChange:e=>{if(e.target.checked)props.onChange(false);}}),props.booleanNo]})]}))}function optionLabel(props,value){return props.copy?.options?.[value]??value}function renderSingleSelect(props){const options=props.field.options??[];return FieldShell(props,u("select",{id:props.id,name:props.field.id,required:props.field.required,class:"checktiv-cf-select",value:asText(props.value),onChange:e=>props.onChange(e.target.value),children:[u("option",{value:"",children:""}),options.map(o=>u("option",{value:o.value,children:optionLabel(props,o.value)}))]}))}function renderMultiSelect(props){const options=props.field.options??[];const selected=Array.isArray(props.value)?props.value:[];const toggle=(value,checked)=>{const next=checked?[...selected,value]:selected.filter(v=>v!==value);props.onChange(next);};return FieldShell(props,u("div",{class:"checktiv-cf-multiselect",role:"group","aria-labelledby":labelIdFor(props.id),children:options.map(o=>u("label",{class:"checktiv-cf-option",children:[u("input",{type:"checkbox",name:props.field.id,value:o.value,checked:selected.includes(o.value),onChange:e=>toggle(o.value,e.target.checked)}),optionLabel(props,o.value)]}))}))}function renderFileUpload(props){return FieldShell(props,u("input",{id:props.id,name:props.field.id,type:"file",class:"checktiv-cf-file",required:props.field.required,onChange:e=>{const files=e.target.files;props.onFile(files&&files.length>0?files[0]:null);}}))}function renderContent(props){const text=props.copy?.label??props.field.id;return props.field.type==="content_heading"?u("h2",{class:"checktiv-cf-heading",children:text}):u("p",{class:"checktiv-cf-paragraph",children:text})}function renderField(props){switch(props.field.type){case "short_text":case "long_text":case "email":case "phone":case "date":case "number":return renderTextLike(props);case "boolean":return renderBoolean(props);case "single_select":return renderSingleSelect(props);case "multi_select":return renderMultiSelect(props);case "file_upload":return renderFileUpload(props);case "content_heading":case "content_paragraph":return renderContent(props);default:{const _exhaustive=props.field.type;return _exhaustive}}}function collectAnswers(answers){const blob={};for(const[fieldId,value]of answers){if(value===void 0)continue;if(typeof value==="string"&&value.length===0)continue;blob[fieldId]=value;}return blob}function isRecord(v){return typeof v==="object"&&v!==null}function parseUploadTarget(body){if(!isRecord(body)||!isRecord(body.data))return null;const d=body.data;const uploadUrl=d.upload_url;const r2Key=d.r2_key;if(typeof uploadUrl!=="string"||uploadUrl.length===0)return null;if(typeof r2Key!=="string"||r2Key.length===0)return null;return {uploadUrl,r2Key}}function extensionOf(fileName){const dot=fileName.lastIndexOf(".");if(dot<0||dot===fileName.length-1)return "";return fileName.slice(dot+1).toLowerCase()}async function uploadFormFile(ctx,fetchImpl,stepId,fieldId,file){const origin=ctx.apiBaseOrigin;let res;try{res=await withTokenRetry(ctx.tokens,token=>fetchImpl(origin+formUploadUrlPath(stepId),{method:"POST",headers:dataPlaneHeaders(ctx,token,{withJsonBody:true}),body:JSON.stringify({fieldId,ext:extensionOf(file.name),contentLength:file.size})}),result=>result?.status===401);}catch{return null}if(!res.ok)return null;let body;try{body=await res.json();}catch{return null}const target=parseUploadTarget(body);if(target===null)return null;let putRes;try{putRes=await fetchImpl(target.uploadUrl,{method:"PUT",headers:{"content-type":file.type||"application/octet-stream"},body:file});}catch{return null}if(!putRes.ok)return null;return target.r2Key}var FALLBACK={submit:"Continue",requiredError:"This field is required.",uploadError:"That file could not be uploaded. Choose the file and try again.",submitError:"Something went wrong submitting the form. Please try again.",booleanYes:"Yes",booleanNo:"No"};function resolveCopy(copy){return {submit:copy?.submit??FALLBACK.submit,requiredError:copy?.requiredError??FALLBACK.requiredError,uploadError:copy?.uploadError??FALLBACK.uploadError,submitError:copy?.submitError??FALLBACK.submitError,booleanYes:copy?.booleanYes??FALLBACK.booleanYes,booleanNo:copy?.booleanNo??FALLBACK.booleanNo}}function createCustomFormErrorEvent(code){return {type:"checktiv.custom_form.error",error:createChecktivError(code)}}function resolveTarget(target){if(typeof target!=="string")return target;if(typeof document==="undefined")return null;return document.querySelector(target)}async function resolveSessionIdentity(ctx,fetchImpl){let res;try{res=await withTokenRetry(ctx.tokens,token=>fetchImpl(ctx.apiBaseOrigin+SESSIONS_ME_PATH,{method:"GET",headers:dataPlaneHeaders(ctx,token)}),result=>result?.status===401);}catch{return null}if(!res.ok)return null;let body;try{body=await res.json();}catch{return null}if(typeof body!=="object"||body===null)return null;const data=body.data;if(typeof data!=="object"||data===null)return null;const record=data;const sessionId=record.session_id;const stepId=record.step_id;if(typeof sessionId!=="string"||sessionId.length===0)return null;if(typeof stepId!=="string"||stepId.length===0)return null;ctx.setSessionId(sessionId);return {sessionId,stepId}}function noopHandle(){return {destroy:()=>void 0}}function createCustomForm(ctx,opts){const element=resolveTarget(opts.target);if(element===null){console.warn('[Checktiv] mount("custom_form"): 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;const chrome=resolveCopy(opts.copy);const answers=new Map;const pendingFiles=new Map;let identity=null;let submitting=false;let cancelled=false;const paint=()=>{if(cancelled)return;R(k(S,null,[...opts.config.fields.map(field=>renderField({field,copy:opts.copy?.fields?.[field.id],value:answers.get(field.id),id:`checktiv-cf-${field.id}`,booleanYes:chrome.booleanYes,booleanNo:chrome.booleanNo,onChange:next=>{answers.set(field.id,next);if(field.type==="multi_select")paint();},onFile:file=>{if(file===null){pendingFiles.delete(field.id);answers.delete(field.id);}else {pendingFiles.set(field.id,file);}}})),k("button",{type:"submit",class:"checktiv-cf-submit",disabled:opts.preview===true,onClick:e=>{e.preventDefault();if(opts.preview===true)return;void onSubmit();}},chrome.submit)]),element);};async function onSubmit(){if(submitting||cancelled)return;if(identity===null){emit(createCustomFormErrorEvent("session_expired"));return}const session=identity;submitting=true;for(const[fieldId,file]of pendingFiles){const key=await uploadFormFile(ctx,fetchImpl,session.stepId,fieldId,file);if(cancelled)return;if(key===null){emit(createCustomFormErrorEvent("upload_failed"));submitting=false;return}answers.set(fieldId,key);}pendingFiles.clear();const blob=collectAnswers(answers);let res;try{res=await withTokenRetry(ctx.tokens,token=>fetchImpl(ctx.apiBaseOrigin+stepSubmitPath(session.sessionId,session.stepId),{method:"POST",headers:dataPlaneHeaders(ctx,token,{withJsonBody:true}),body:JSON.stringify(blob)}),result=>result?.status===401);}catch(err){console.warn("[Checktiv] custom_form submit request failed.",err);submitting=false;return}if(cancelled)return;if(!res.ok){emit(createCustomFormErrorEvent(mapHttpStatusToError(res.status)));submitting=false;return}emit({type:"checktiv.custom_form.submitted",sessionId:session.sessionId});}if(opts.preview===true){paint();emit({type:"checktiv.custom_form.ready"});return {destroy(){if(cancelled)return;cancelled=true;R(null,element);}}}void(async()=>{try{const resolved=opts.session??await resolveSessionIdentity(ctx,fetchImpl);if(cancelled)return;if(resolved===null){emit(createCustomFormErrorEvent("session_expired"));return}identity=resolved;paint();emit({type:"checktiv.custom_form.ready"});}catch(err){if(cancelled)return;console.warn('[Checktiv] mount("custom_form") setup failed.',err);emit(createCustomFormErrorEvent("sdk_load_failed"));}})();return {destroy(){if(cancelled)return;cancelled=true;R(null,element);}}}registerModule("custom_form",createCustomForm);
|
|
11
|
+
function describedBy(props){const ids=[];if(props.copy?.helpText!==void 0)ids.push(`${props.id}-help`);if(props.error!==void 0)ids.push(`${props.id}-error`);return ids.length>0?ids.join(" "):void 0}function ariaInvalid(props){return props.error!==void 0?"true":void 0}function labelText(props){return props.copy?.label??props.field.id}function labelIdFor(controlId){return `${controlId}-label`}function FieldShell(props,control){const help=props.copy?.helpText;return u("div",{class:"checktiv-cf-field",children:[u("label",{id:labelIdFor(props.id),for:props.id,class:"checktiv-cf-label",children:labelText(props)}),help!==void 0?u("p",{id:`${props.id}-help`,class:"checktiv-cf-help",children:help}):null,control,props.error!==void 0?u("p",{id:`${props.id}-error`,class:"checktiv-cf-error",role:"alert",children:props.error}):null]})}function asText(value){return typeof value==="string"?value:""}function asInputValue(value){return typeof value==="number"?String(value):asText(value)}function inputTypeFor(type){switch(type){case "email":return "email";case "phone":return "tel";case "date":return "date";case "number":return "number";default:return "text"}}function renderTextLike(props){const{field}=props;const onInput=e=>{const target=e.target;if(field.type==="number"){const input=target;props.onChange(input.value===""||Number.isNaN(input.valueAsNumber)?void 0:input.valueAsNumber);return}props.onChange(target.value);};if(field.type==="long_text"){return FieldShell(props,u("textarea",{id:props.id,name:field.id,required:field.required,class:"checktiv-cf-input",value:asInputValue(props.value),"aria-invalid":ariaInvalid(props),"aria-describedby":describedBy(props),onInput,onBlur:props.onBlur}))}return FieldShell(props,u("input",{id:props.id,name:field.id,type:inputTypeFor(field.type),required:field.required,class:"checktiv-cf-input",value:asInputValue(props.value),"aria-invalid":ariaInvalid(props),"aria-describedby":describedBy(props),onInput,onBlur:props.onBlur}))}function renderBoolean(props){const yesId=`${props.id}-yes`;const noId=`${props.id}-no`;return FieldShell(props,u("fieldset",{class:"checktiv-cf-radiogroup",role:"radiogroup","aria-labelledby":labelIdFor(props.id),"aria-required":props.field.required?"true":void 0,"aria-invalid":ariaInvalid(props),"aria-describedby":describedBy(props),children:[u("label",{for:yesId,class:"checktiv-cf-radio-option",children:[u("input",{id:yesId,name:props.field.id,type:"radio",class:"checktiv-cf-radio",checked:props.value===true,onChange:e=>{if(e.target.checked)props.onChange(true);}}),props.booleanYes]}),u("label",{for:noId,class:"checktiv-cf-radio-option",children:[u("input",{id:noId,name:props.field.id,type:"radio",class:"checktiv-cf-radio",checked:props.value===false,onChange:e=>{if(e.target.checked)props.onChange(false);}}),props.booleanNo]})]}))}function optionLabel(props,value){return props.copy?.options?.[value]??value}function renderSingleSelect(props){const options=props.field.options??[];return FieldShell(props,u("select",{id:props.id,name:props.field.id,required:props.field.required,class:"checktiv-cf-select",value:asText(props.value),"aria-invalid":ariaInvalid(props),"aria-describedby":describedBy(props),onChange:e=>props.onChange(e.target.value),children:[u("option",{value:"",children:""}),options.map(o=>u("option",{value:o.value,children:optionLabel(props,o.value)}))]}))}function renderMultiSelect(props){const options=props.field.options??[];const selected=Array.isArray(props.value)?props.value:[];const toggle=(value,checked)=>{const next=checked?[...selected,value]:selected.filter(v=>v!==value);props.onChange(next);};return FieldShell(props,u("div",{class:"checktiv-cf-multiselect",role:"group","aria-labelledby":labelIdFor(props.id),"aria-invalid":ariaInvalid(props),"aria-describedby":describedBy(props),children:options.map(o=>u("label",{class:"checktiv-cf-option",children:[u("input",{type:"checkbox",name:props.field.id,value:o.value,checked:selected.includes(o.value),onChange:e=>toggle(o.value,e.target.checked)}),optionLabel(props,o.value)]}))}))}function renderFileUpload(props){return FieldShell(props,u("input",{id:props.id,name:props.field.id,type:"file",class:"checktiv-cf-file",required:props.field.required,"aria-invalid":ariaInvalid(props),"aria-describedby":describedBy(props),onChange:e=>{const files=e.target.files;props.onFile(files&&files.length>0?files[0]:null);}}))}function renderContent(props){const text=props.copy?.label??props.field.id;return props.field.type==="content_heading"?u("h2",{class:"checktiv-cf-heading",children:text}):u("p",{class:"checktiv-cf-paragraph",children:text})}function renderField(props){switch(props.field.type){case "short_text":case "long_text":case "email":case "phone":case "date":case "number":return renderTextLike(props);case "boolean":return renderBoolean(props);case "single_select":return renderSingleSelect(props);case "multi_select":return renderMultiSelect(props);case "file_upload":return renderFileUpload(props);case "content_heading":case "content_paragraph":return renderContent(props);default:{const _exhaustive=props.field.type;return _exhaustive}}}var CLIENT_PHONE_RE=/^\+?[0-9 ().-]{6,24}$/;var CLIENT_EMAIL_RE=/^[^\s@]+@[^\s@]+\.[^\s@]+$/;function isEmptyAnswer(answer){if(answer===void 0)return true;if(typeof answer==="string")return answer.length===0;if(Array.isArray(answer))return answer.length===0;return false}function validateField(field,answer){const requiredIfEmpty=()=>isEmptyAnswer(answer)?field.required?"required":void 0:void 0;switch(field.type){case "short_text":case "long_text":case "date":case "file_upload":return requiredIfEmpty();case "boolean":return field.required&&answer===void 0?"required":void 0;case "email":{if(isEmptyAnswer(answer))return field.required?"required":void 0;return typeof answer==="string"&&!CLIENT_EMAIL_RE.test(answer)?"invalid_email":void 0}case "phone":{if(isEmptyAnswer(answer))return field.required?"required":void 0;return typeof answer==="string"&&!CLIENT_PHONE_RE.test(answer)?"invalid_phone":void 0}case "number":{if(isEmptyAnswer(answer))return field.required?"required":void 0;if(typeof answer!=="number")return void 0;const min=field.validation?.min;const max=field.validation?.max;if(min!==void 0&&answer<min)return "out_of_range";if(max!==void 0&&answer>max)return "out_of_range";return void 0}case "single_select":{if(isEmptyAnswer(answer))return field.required?"required":void 0;const options=field.options??[];if(typeof answer==="string"&&options.length>0){return options.some(o=>o.value===answer)?void 0:"invalid_option"}return void 0}case "multi_select":{const selected=Array.isArray(answer)?answer:[];if(selected.length===0)return field.required?"required":void 0;const min=field.validation?.minSelections;const max=field.validation?.maxSelections;if(min!==void 0&&selected.length<min)return "out_of_range";if(max!==void 0&&selected.length>max)return "out_of_range";return void 0}case "content_heading":case "content_paragraph":return void 0;default:return assertNever(field.type)}}function collectAnswers(answers){const blob={};for(const[fieldId,value]of answers){if(value===void 0)continue;if(typeof value==="string"&&value.length===0)continue;blob[fieldId]=value;}return blob}function isRecord2(v){return typeof v==="object"&&v!==null}function parseUploadTarget(body){if(!isRecord2(body)||!isRecord2(body.data))return null;const d=body.data;const uploadUrl=d.upload_url;const r2Key=d.r2_key;if(typeof uploadUrl!=="string"||uploadUrl.length===0)return null;if(typeof r2Key!=="string"||r2Key.length===0)return null;return {uploadUrl,r2Key}}function extensionOf(fileName){const dot=fileName.lastIndexOf(".");if(dot<0||dot===fileName.length-1)return "";return fileName.slice(dot+1).toLowerCase()}async function uploadFormFile(ctx,fetchImpl,stepId,fieldId,file){const origin=ctx.apiBaseOrigin;let res;try{res=await withTokenRetry(ctx.tokens,token=>fetchImpl(origin+formUploadUrlPath(stepId),{method:"POST",headers:dataPlaneHeaders(ctx,token,{withJsonBody:true}),body:JSON.stringify({fieldId,ext:extensionOf(file.name),contentLength:file.size})}),result=>result?.status===401);}catch{return null}if(!res.ok)return null;let body;try{body=await res.json();}catch{return null}const target=parseUploadTarget(body);if(target===null)return null;let putRes;try{putRes=await fetchImpl(target.uploadUrl,{method:"PUT",headers:{"content-type":file.type||"application/octet-stream"},body:file});}catch{return null}if(!putRes.ok)return null;return target.r2Key}var FALLBACK={submit:"Continue",requiredError:"This field is required.",invalidPhoneError:"Enter a valid phone number.",invalidEmailError:"Enter a valid email address.",invalidDateError:"Enter a valid date.",invalidOptionError:"Choose one of the available options.",outOfRangeError:"That value is outside the allowed range.",invalidFormatError:"That value is not in the expected format.",invalidError:"That value is not valid.",validationError:"Some answers could not be accepted. Review your entries and try again.",uploadError:"That file could not be uploaded. Choose the file and try again.",submitError:"Something went wrong submitting the form. Please try again.",booleanYes:"Yes",booleanNo:"No"};function resolveCopy(copy){return {submit:copy?.submit??FALLBACK.submit,requiredError:copy?.requiredError??FALLBACK.requiredError,invalidPhoneError:copy?.invalidPhoneError??FALLBACK.invalidPhoneError,invalidEmailError:copy?.invalidEmailError??FALLBACK.invalidEmailError,invalidDateError:copy?.invalidDateError??FALLBACK.invalidDateError,invalidOptionError:copy?.invalidOptionError??FALLBACK.invalidOptionError,outOfRangeError:copy?.outOfRangeError??FALLBACK.outOfRangeError,invalidFormatError:copy?.invalidFormatError??FALLBACK.invalidFormatError,invalidError:copy?.invalidError??FALLBACK.invalidError,validationError:copy?.validationError??FALLBACK.validationError,uploadError:copy?.uploadError??FALLBACK.uploadError,submitError:copy?.submitError??FALLBACK.submitError,booleanYes:copy?.booleanYes??FALLBACK.booleanYes,booleanNo:copy?.booleanNo??FALLBACK.booleanNo}}function messageForReason(chrome,reason){const byReason={required:chrome.requiredError,invalid_phone:chrome.invalidPhoneError,invalid_email:chrome.invalidEmailError,invalid_date:chrome.invalidDateError,invalid_option:chrome.invalidOptionError,out_of_range:chrome.outOfRangeError,invalid_format:chrome.invalidFormatError,invalid:chrome.invalidError};return byReason[reason]}var CUSTOM_FORM_FIELD_ERROR_REASONS=["required","invalid_phone","invalid_email","invalid_date","invalid_option","out_of_range","invalid_format","invalid"];var REASON_SET=new Set(CUSTOM_FORM_FIELD_ERROR_REASONS);function isCustomFormFieldErrorReason(value){return REASON_SET.has(value)}function createCustomFormErrorEvent(code){return {type:"checktiv.custom_form.error",error:createChecktivError(code)}}function resolveTarget(target){if(typeof target!=="string")return target;if(typeof document==="undefined")return null;return document.querySelector(target)}async function resolveSessionIdentity(ctx,fetchImpl){let res;try{res=await withTokenRetry(ctx.tokens,token=>fetchImpl(ctx.apiBaseOrigin+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"}}if(!isRecord(body))return {kind:"unresolved"};const data=body.data;if(isRecord(data)){const sessionId=data.session_id;const stepId=data.step_id;if(typeof sessionId==="string"&&sessionId.length>0&&typeof stepId==="string"&&stepId.length>0){ctx.setSessionId(sessionId);return {kind:"ok",identity:{sessionId,stepId}}}}return isJourneyPlaneBody(body)?{kind:"wrong_token"}:{kind:"unresolved"}}async function parseFieldErrors(res){let body;try{body=await res.json();}catch{return null}if(typeof body!=="object"||body===null)return null;const fieldErrors=body.fieldErrors;if(typeof fieldErrors!=="object"||fieldErrors===null)return null;const out=new Map;for(const[fieldId,reason]of Object.entries(fieldErrors)){if(typeof reason==="string"&&isCustomFormFieldErrorReason(reason)){out.set(fieldId,reason);}}return out}function noopHandle(){return {destroy:()=>void 0}}function createCustomForm(ctx,opts){const element=resolveTarget(opts.target);if(element===null){console.warn('[Checktiv] mount("custom_form"): 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;const chrome=resolveCopy(opts.copy);const answers=new Map;const pendingFiles=new Map;const errors=new Map;let formError=null;let identity=null;let submitting=false;let cancelled=false;const PENDING_FILE_SENTINEL="\0pending-file";const clearFieldError=fieldId=>{const clearedField=errors.delete(fieldId);const clearedForm=formError!==null;formError=null;if(clearedField||clearedForm)paint();};const focusField=fieldId=>{element.querySelector(`[name="${fieldId}"]`)?.focus();};const validateAll=()=>{errors.clear();let firstInvalid=null;for(const field of opts.config.fields){const answer=pendingFiles.has(field.id)?PENDING_FILE_SENTINEL:answers.get(field.id);const reason=validateField(field,answer);if(reason!==void 0){errors.set(field.id,reason);if(firstInvalid===null)firstInvalid=field.id;}}return firstInvalid};const applyServerFieldErrors=fieldErrors=>{errors.clear();formError=null;const knownFieldIds=new Set(opts.config.fields.map(f=>f.id));for(const[fieldId,reason]of fieldErrors){if(knownFieldIds.has(fieldId))errors.set(fieldId,reason);}if(errors.size===0)formError=chrome.validationError;paint();const first=opts.config.fields.find(f=>errors.has(f.id));if(first!==void 0)focusField(first.id);};const paint=()=>{if(cancelled)return;R(k(S,null,[...opts.config.fields.map(field=>{const reason=errors.get(field.id);return renderField({field,copy:opts.copy?.fields?.[field.id],value:answers.get(field.id),id:`checktiv-cf-${field.id}`,error:reason!==void 0?messageForReason(chrome,reason):void 0,booleanYes:chrome.booleanYes,booleanNo:chrome.booleanNo,onChange:next=>{answers.set(field.id,next);if(field.type==="multi_select"||field.type==="boolean"||field.type==="single_select"){const clearedField=errors.delete(field.id);const clearedForm=formError!==null;formError=null;if(field.type==="multi_select"||clearedField||clearedForm)paint();}},onBlur:()=>clearFieldError(field.id),onFile:file=>{if(file===null){pendingFiles.delete(field.id);answers.delete(field.id);}else {pendingFiles.set(field.id,file);}clearFieldError(field.id);}})}),formError!==null?k("p",{class:"checktiv-cf-error",role:"alert",id:"checktiv-cf-form-error"},formError):null,k("button",{type:"submit",class:"checktiv-cf-submit",disabled:opts.preview===true,onClick:e=>{e.preventDefault();if(opts.preview===true)return;void onSubmit();}},chrome.submit)]),element);};async function onSubmit(){if(submitting||cancelled)return;formError=null;const firstInvalid=validateAll();if(firstInvalid!==null){paint();focusField(firstInvalid);return}if(identity===null){emit(createCustomFormErrorEvent("session_expired"));return}const session=identity;submitting=true;for(const[fieldId,file]of pendingFiles){const key=await uploadFormFile(ctx,fetchImpl,session.stepId,fieldId,file);if(cancelled)return;if(key===null){emit(createCustomFormErrorEvent("upload_failed"));submitting=false;return}answers.set(fieldId,key);}pendingFiles.clear();const blob=collectAnswers(answers);let res;try{res=await withTokenRetry(ctx.tokens,token=>fetchImpl(ctx.apiBaseOrigin+stepSubmitPath(session.sessionId,session.stepId),{method:"POST",headers:dataPlaneHeaders(ctx,token,{withJsonBody:true}),body:JSON.stringify(blob)}),result=>result?.status===401);}catch(err){console.warn("[Checktiv] custom_form submit request failed.",err);submitting=false;return}if(cancelled)return;if(!res.ok){if(res.status===422){const fieldErrors=await parseFieldErrors(res);if(cancelled)return;if(fieldErrors!==null&&fieldErrors.size>0){applyServerFieldErrors(fieldErrors);}else {formError=chrome.validationError;paint();}submitting=false;return}if(res.status===400){formError=chrome.validationError;paint();submitting=false;return}emit(createCustomFormErrorEvent(mapHttpStatusToError(res.status)));submitting=false;return}emit({type:"checktiv.custom_form.submitted",sessionId:session.sessionId});}if(opts.preview===true){paint();emit({type:"checktiv.custom_form.ready"});return {destroy(){if(cancelled)return;cancelled=true;R(null,element);}}}void(async()=>{try{if(opts.session!==void 0){identity=opts.session;}else {const resolution=await resolveSessionIdentity(ctx,fetchImpl);if(cancelled)return;switch(resolution.kind){case "ok":identity=resolution.identity;break;case "wrong_token":warnWrongTokenPlane();emit(createCustomFormErrorEvent("wrong_token_type"));return;case "unresolved":emit(createCustomFormErrorEvent("session_expired"));return;default:return assertNever(resolution)}}if(cancelled)return;paint();emit({type:"checktiv.custom_form.ready"});}catch(err){if(cancelled)return;console.warn('[Checktiv] mount("custom_form") setup failed.',err);emit(createCustomFormErrorEvent("sdk_load_failed"));}})();return {destroy(){if(cancelled)return;cancelled=true;R(null,element);}}}registerModule("custom_form",createCustomForm);
|
|
9
12
|
|
|
10
13
|
export { createCustomForm };
|
package/dist/fraud.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export {
|
|
2
|
-
import './machine
|
|
3
|
-
import './copy-
|
|
1
|
+
export { f as ChecktivFraudEvent, F as FraudHandle, i as FraudMountOptions, O as createFraud } from './api-DyExBfAQ.js';
|
|
2
|
+
import './machine-CuZalPFX.js';
|
|
3
|
+
import './copy-Dfmk11S_.js';
|
|
4
|
+
import './copy-DCeQ4JKx.js';
|
package/dist/fraud.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { registerModule } from './chunk-GFHNOZVO.js';
|
|
2
|
+
import { assertNever } from './chunk-UBQTPS5J.js';
|
|
3
|
+
import { resolveSession, createChecktivError, warnWrongTokenPlane, withTokenRetry } from './chunk-QVDWM4KK.js';
|
|
4
|
+
import './chunk-IQKHRPJR.js';
|
|
5
|
+
import { TELEMETRY_PATH, dataPlaneHeaders } from './chunk-ITLSDZHK.js';
|
|
3
6
|
import './chunk-QFA3K5ZV.js';
|
|
4
|
-
import { createChecktivError } from './chunk-WQCYRLWP.js';
|
|
5
7
|
import { __publicField } from './chunk-AIK7CDV6.js';
|
|
6
8
|
|
|
7
|
-
var MAX_STEPS=50;var MAX_STEP_SECONDS=86400;var MAX_STEP_PASTE_COUNT=1e4;var MAX_STEP_ID_LEN=80;function defaultNow(){return typeof performance!=="undefined"&&typeof performance.now==="function"?performance.now():Date.now()}var BehavioralTracker=class{constructor(now=defaultNow){__publicField(this,"steps",new Map);__publicField(this,"activeStepId",null);__publicField(this,"now");this.now=now;}get currentStepId(){return this.activeStepId}enter(rawStepId){const stepId=this.boundStepId(rawStepId);if(stepId===null)return;this.closeActiveInterval();const existing=this.steps.get(stepId);if(existing){existing.enteredAtMs=this.now();}else {this.steps.set(stepId,{stepId,enteredAtMs:this.now(),accumulatedMs:0,pasteCount:0});}this.activeStepId=stepId;}recordPaste(rawStepId){const target=rawStepId===void 0?this.activeStepId:this.boundStepId(rawStepId);if(target===null)return;const existing=this.steps.get(target);if(existing){if(existing.pasteCount<MAX_STEP_PASTE_COUNT)existing.pasteCount+=1;return}this.steps.set(target,{stepId:target,enteredAtMs:null,accumulatedMs:0,pasteCount:1});}snapshot(){this.closeActiveInterval();if(this.activeStepId!==null){const active=this.steps.get(this.activeStepId);if(active)active.enteredAtMs=this.now();}const out=[];for(const acc of this.steps.values()){if(out.length>=MAX_STEPS)break;out.push({stepId:acc.stepId,seconds:this.boundSeconds(acc.accumulatedMs),pasteCount:acc.pasteCount});}return out}closeActiveInterval(){if(this.activeStepId===null)return;const active=this.steps.get(this.activeStepId);if(!active||active.enteredAtMs===null)return;const delta=this.now()-active.enteredAtMs;if(delta>0)active.accumulatedMs+=delta;active.enteredAtMs=null;}boundStepId(rawStepId){if(typeof rawStepId!=="string")return null;const trimmed=rawStepId.trim();if(trimmed.length===0)return null;return trimmed.length>MAX_STEP_ID_LEN?trimmed.slice(0,MAX_STEP_ID_LEN):trimmed}boundSeconds(ms){const seconds=ms/1e3;if(!Number.isFinite(seconds)||seconds<0)return 0;return seconds>MAX_STEP_SECONDS?MAX_STEP_SECONDS:seconds}};var DEVICE_MODEL_HINT_MAX=120;function readBoundedString(value,max){if(typeof value!=="string")return null;const trimmed=value.trim();if(trimmed.length===0)return null;return trimmed.length>max?trimmed.slice(0,max):trimmed}function readTimezone(){try{const tz=Intl.DateTimeFormat().resolvedOptions().timeZone;return readBoundedString(tz,64)}catch{return null}}function readMaxTouchPoints(nav){const raw=nav.maxTouchPoints;if(typeof raw!=="number"||!Number.isFinite(raw))return 0;const floored=Math.floor(raw);if(floored<0)return 0;return floored>512?512:floored}function readPluginCount(nav){const plugins=nav.plugins;const len=plugins&&typeof plugins.length==="number"?plugins.length:0;if(!Number.isFinite(len)||len<0)return 0;return len>256?256:Math.floor(len)}function readDeviceModelHint(nav){const uaData=nav.userAgentData;if(typeof uaData!=="object"||uaData===null)return null;return readBoundedString(uaData.platform,DEVICE_MODEL_HINT_MAX)}function readBehaviorTraits(nav=navigator){return {webdriver:nav.webdriver===true,maxTouchPoints:readMaxTouchPoints(nav),timezone:readTimezone(),pluginCount:readPluginCount(nav),deviceModelHint:readDeviceModelHint(nav)}}var BEHAVIOR_CAPTURED_EVENT="kyc.fraud.behavior_captured";var MAX_SEGMENTS=4;var MAX_SEGMENT_STEPS=50;var DEFAULT_SUBMIT_TIMEOUT_MS=2500;function defaultSleep(ms){return new Promise(resolve=>setTimeout(resolve,ms))}function createGatedTransport(inner,opts){const sleep=opts.sleep??defaultSleep;return {async postTelemetry(events){for(let attempt=0;attempt<=opts.maxRetries;attempt+=1){if(attempt>0)await sleep(opts.retryDelayMs).catch(()=>{});try{const res=await inner.postTelemetry(events);if(res.ok)return}catch{}}console.warn("[fraud-agent] flush failed");}}}function withTimeout(promise,ms){return new Promise(resolve=>{let settled=false;const done=()=>{if(settled)return;settled=true;resolve();};const timer=setTimeout(done,ms);void promise.finally(()=>{clearTimeout(timer);done();});})}function boundSegmentSteps(steps){return steps.length>MAX_SEGMENT_STEPS?steps.slice(0,MAX_SEGMENT_STEPS):steps}function createFraudAgent(options){const{transport,sessionId,pasteListenerTarget,now,submitTimeoutMs=DEFAULT_SUBMIT_TIMEOUT_MS}=options;const tracker=new BehavioralTracker(now);let parentTraits=null;const traits=()=>parentTraits??(parentTraits=readBehaviorTraits());const embedSegments=[];const pasteTarget=pasteListenerTarget===void 0?typeof document!=="undefined"?document:null:pasteListenerTarget;const onPasteEvent=()=>{tracker.recordPaste();};if(pasteTarget){pasteTarget.addEventListener("paste",onPasteEvent,{capture:true,passive:true});}function buildPayload(){const steps=tracker.snapshot();const parentTraitsValue=traits();const payload={steps,traits:parentTraitsValue};if(embedSegments.length>0){payload.segments=[{surface:"parent",steps,traits:parentTraitsValue},...embedSegments.slice(0,MAX_SEGMENTS-1).map(seg=>({surface:"embed",steps:boundSegmentSteps(seg.steps),traits:seg.traits}))];}return payload}return {onStepEnter(stepId){tracker.enter(stepId);},onPaste(stepId){tracker.recordPaste(stepId);},mergeEmbedSegment(segment){if(embedSegments.length>=MAX_SEGMENTS-1)return;embedSegments.push({steps:boundSegmentSteps(segment.steps),traits:segment.traits});},async onSubmit(){if(sessionId===void 0)return;const payload=buildPayload();const activeStepId=tracker.currentStepId;const post=(async()=>{try{await transport.postTelemetry([{event:BEHAVIOR_CAPTURED_EVENT,sessionId,...activeStepId!==null?{stepId:activeStepId}:{},ts:Date.now(),payload}]);}catch{}})();await withTimeout(post,submitTimeoutMs);},dispose(){if(pasteTarget){pasteTarget.removeEventListener("paste",onPasteEvent,{capture:true});}}}}var TELEMETRY_FLUSH_MAX_RETRIES=1;var TELEMETRY_FLUSH_RETRY_DELAY_MS=400;function createTelemetryTransport(ctx,fetchImpl){const url=ctx.apiBaseOrigin+TELEMETRY_PATH;return {postTelemetry(events){return withTokenRetry(ctx.tokens,token=>fetchImpl(url,{method:"POST",headers:dataPlaneHeaders(ctx,token,{withJsonBody:true}),body:JSON.stringify({events})}),result=>result?.status===401)}}}function createFraud(ctx,opts){const fetchImpl=opts.fetchImpl??fetch;const transport=createGatedTransport(createTelemetryTransport(ctx,fetchImpl),{maxRetries:TELEMETRY_FLUSH_MAX_RETRIES,retryDelayMs:TELEMETRY_FLUSH_RETRY_DELAY_MS});let destroyed=false;let agent=null;void Promise.resolve().then(async()=>{const granted=await opts.onConsent();if(destroyed||!granted)return;const
|
|
9
|
+
var MAX_STEPS=50;var MAX_STEP_SECONDS=86400;var MAX_STEP_PASTE_COUNT=1e4;var MAX_STEP_ID_LEN=80;function defaultNow(){return typeof performance!=="undefined"&&typeof performance.now==="function"?performance.now():Date.now()}var BehavioralTracker=class{constructor(now=defaultNow){__publicField(this,"steps",new Map);__publicField(this,"activeStepId",null);__publicField(this,"now");this.now=now;}get currentStepId(){return this.activeStepId}enter(rawStepId){const stepId=this.boundStepId(rawStepId);if(stepId===null)return;this.closeActiveInterval();const existing=this.steps.get(stepId);if(existing){existing.enteredAtMs=this.now();}else {this.steps.set(stepId,{stepId,enteredAtMs:this.now(),accumulatedMs:0,pasteCount:0});}this.activeStepId=stepId;}recordPaste(rawStepId){const target=rawStepId===void 0?this.activeStepId:this.boundStepId(rawStepId);if(target===null)return;const existing=this.steps.get(target);if(existing){if(existing.pasteCount<MAX_STEP_PASTE_COUNT)existing.pasteCount+=1;return}this.steps.set(target,{stepId:target,enteredAtMs:null,accumulatedMs:0,pasteCount:1});}snapshot(){this.closeActiveInterval();if(this.activeStepId!==null){const active=this.steps.get(this.activeStepId);if(active)active.enteredAtMs=this.now();}const out=[];for(const acc of this.steps.values()){if(out.length>=MAX_STEPS)break;out.push({stepId:acc.stepId,seconds:this.boundSeconds(acc.accumulatedMs),pasteCount:acc.pasteCount});}return out}closeActiveInterval(){if(this.activeStepId===null)return;const active=this.steps.get(this.activeStepId);if(!active||active.enteredAtMs===null)return;const delta=this.now()-active.enteredAtMs;if(delta>0)active.accumulatedMs+=delta;active.enteredAtMs=null;}boundStepId(rawStepId){if(typeof rawStepId!=="string")return null;const trimmed=rawStepId.trim();if(trimmed.length===0)return null;return trimmed.length>MAX_STEP_ID_LEN?trimmed.slice(0,MAX_STEP_ID_LEN):trimmed}boundSeconds(ms){const seconds=ms/1e3;if(!Number.isFinite(seconds)||seconds<0)return 0;return seconds>MAX_STEP_SECONDS?MAX_STEP_SECONDS:seconds}};var DEVICE_MODEL_HINT_MAX=120;function readBoundedString(value,max){if(typeof value!=="string")return null;const trimmed=value.trim();if(trimmed.length===0)return null;return trimmed.length>max?trimmed.slice(0,max):trimmed}function readTimezone(){try{const tz=Intl.DateTimeFormat().resolvedOptions().timeZone;return readBoundedString(tz,64)}catch{return null}}function readMaxTouchPoints(nav){const raw=nav.maxTouchPoints;if(typeof raw!=="number"||!Number.isFinite(raw))return 0;const floored=Math.floor(raw);if(floored<0)return 0;return floored>512?512:floored}function readPluginCount(nav){const plugins=nav.plugins;const len=plugins&&typeof plugins.length==="number"?plugins.length:0;if(!Number.isFinite(len)||len<0)return 0;return len>256?256:Math.floor(len)}function readDeviceModelHint(nav){const uaData=nav.userAgentData;if(typeof uaData!=="object"||uaData===null)return null;return readBoundedString(uaData.platform,DEVICE_MODEL_HINT_MAX)}function readBehaviorTraits(nav=navigator){return {webdriver:nav.webdriver===true,maxTouchPoints:readMaxTouchPoints(nav),timezone:readTimezone(),pluginCount:readPluginCount(nav),deviceModelHint:readDeviceModelHint(nav)}}var BEHAVIOR_CAPTURED_EVENT="kyc.fraud.behavior_captured";var MAX_SEGMENTS=4;var MAX_SEGMENT_STEPS=50;var DEFAULT_SUBMIT_TIMEOUT_MS=2500;function defaultSleep(ms){return new Promise(resolve=>setTimeout(resolve,ms))}function createGatedTransport(inner,opts){const sleep=opts.sleep??defaultSleep;return {async postTelemetry(events){for(let attempt=0;attempt<=opts.maxRetries;attempt+=1){if(attempt>0)await sleep(opts.retryDelayMs).catch(()=>{});try{const res=await inner.postTelemetry(events);if(res.ok)return}catch{}}console.warn("[fraud-agent] flush failed");}}}function withTimeout(promise,ms){return new Promise(resolve=>{let settled=false;const done=()=>{if(settled)return;settled=true;resolve();};const timer=setTimeout(done,ms);void promise.finally(()=>{clearTimeout(timer);done();});})}function boundSegmentSteps(steps){return steps.length>MAX_SEGMENT_STEPS?steps.slice(0,MAX_SEGMENT_STEPS):steps}function createFraudAgent(options){const{transport,sessionId,pasteListenerTarget,now,submitTimeoutMs=DEFAULT_SUBMIT_TIMEOUT_MS}=options;const tracker=new BehavioralTracker(now);let parentTraits=null;const traits=()=>parentTraits??(parentTraits=readBehaviorTraits());const embedSegments=[];const pasteTarget=pasteListenerTarget===void 0?typeof document!=="undefined"?document:null:pasteListenerTarget;const onPasteEvent=()=>{tracker.recordPaste();};if(pasteTarget){pasteTarget.addEventListener("paste",onPasteEvent,{capture:true,passive:true});}function buildPayload(){const steps=tracker.snapshot();const parentTraitsValue=traits();const payload={steps,traits:parentTraitsValue};if(embedSegments.length>0){payload.segments=[{surface:"parent",steps,traits:parentTraitsValue},...embedSegments.slice(0,MAX_SEGMENTS-1).map(seg=>({surface:"embed",steps:boundSegmentSteps(seg.steps),traits:seg.traits}))];}return payload}return {onStepEnter(stepId){tracker.enter(stepId);},onPaste(stepId){tracker.recordPaste(stepId);},mergeEmbedSegment(segment){if(embedSegments.length>=MAX_SEGMENTS-1)return;embedSegments.push({steps:boundSegmentSteps(segment.steps),traits:segment.traits});},async onSubmit(){if(sessionId===void 0)return;const payload=buildPayload();const activeStepId=tracker.currentStepId;const post=(async()=>{try{await transport.postTelemetry([{event:BEHAVIOR_CAPTURED_EVENT,sessionId,...activeStepId!==null?{stepId:activeStepId}:{},ts:Date.now(),payload}]);}catch{}})();await withTimeout(post,submitTimeoutMs);},dispose(){if(pasteTarget){pasteTarget.removeEventListener("paste",onPasteEvent,{capture:true});}}}}var TELEMETRY_FLUSH_MAX_RETRIES=1;var TELEMETRY_FLUSH_RETRY_DELAY_MS=400;function createTelemetryTransport(ctx,fetchImpl){const url=ctx.apiBaseOrigin+TELEMETRY_PATH;return {postTelemetry(events){return withTokenRetry(ctx.tokens,token=>fetchImpl(url,{method:"POST",headers:dataPlaneHeaders(ctx,token,{withJsonBody:true}),body:JSON.stringify({events})}),result=>result?.status===401)}}}function createFraud(ctx,opts){const fetchImpl=opts.fetchImpl??fetch;const transport=createGatedTransport(createTelemetryTransport(ctx,fetchImpl),{maxRetries:TELEMETRY_FLUSH_MAX_RETRIES,retryDelayMs:TELEMETRY_FLUSH_RETRY_DELAY_MS});let destroyed=false;let agent=null;void Promise.resolve().then(async()=>{const granted=await opts.onConsent();if(destroyed||!granted)return;const resolution=await resolveSession(ctx,fetchImpl);if(destroyed)return;let session;switch(resolution.kind){case "ok":session=resolution.session;break;case "wrong_token":warnWrongTokenPlane();opts.onEvent?.({type:"checktiv.fraud.error",error:createChecktivError("wrong_token_type")});return;case "unresolved":opts.onEvent?.({type:"checktiv.fraud.error",error:createChecktivError("session_expired")});return;default:return assertNever(resolution)}agent=createFraudAgent({transport,sessionId:session.sessionId});opts.onEvent?.({type:"checktiv.fraud.started"});}).catch(()=>{});return {destroy(){destroyed=true;agent?.dispose();agent=null;}}}registerModule("fraud",createFraud);
|
|
8
10
|
|
|
9
11
|
export { createFraud };
|
|
@@ -1,10 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import '../
|
|
4
|
-
import '../
|
|
1
|
+
import { A as SubstrateContext, h as CrossDeviceHandoffHook, g as ChecktivIdvEvent } from '../api-DyExBfAQ.js';
|
|
2
|
+
import { C as CrossDeviceCopy } from '../copy-DCeQ4JKx.js';
|
|
3
|
+
import { CrossDevicePanelProps, CrossDeviceHandle } from '../cross-device.js';
|
|
4
|
+
import '../machine-CuZalPFX.js';
|
|
5
|
+
import '../copy-Dfmk11S_.js';
|
|
5
6
|
|
|
7
|
+
interface ManagedCrossDeviceParams {
|
|
8
|
+
ctx: SubstrateContext;
|
|
9
|
+
fetchImpl: typeof fetch;
|
|
10
|
+
target: HTMLElement;
|
|
11
|
+
stepId: string;
|
|
12
|
+
sessionId: string;
|
|
13
|
+
copy: CrossDeviceCopy;
|
|
14
|
+
isMobile: boolean;
|
|
15
|
+
onOpenCrossDevice?: CrossDeviceHandoffHook;
|
|
16
|
+
emit: (e: ChecktivIdvEvent) => void;
|
|
17
|
+
onClose: () => void;
|
|
18
|
+
chunkImporter?: CrossDeviceChunkImporter;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
declare const CROSS_DEVICE_POLL_INTERVAL_MS = 2500;
|
|
22
|
+
declare const CROSS_DEVICE_POLL_TOTAL_CAP_MS: number;
|
|
23
|
+
type CrossDeviceCompletion = 'advanced' | 'pending' | 'terminal';
|
|
24
|
+
interface CrossDevicePollConfig {
|
|
25
|
+
checkCompletion: (signal: AbortSignal) => Promise<CrossDeviceCompletion>;
|
|
26
|
+
onComplete: () => void;
|
|
27
|
+
onCapped?: () => void;
|
|
28
|
+
onTerminal?: () => void;
|
|
29
|
+
intervalMs?: number;
|
|
30
|
+
totalCapMs?: number;
|
|
31
|
+
}
|
|
6
32
|
declare const CROSS_DEVICE_REMINT_CAP = 3;
|
|
7
|
-
|
|
33
|
+
interface CrossDeviceChunkModule {
|
|
34
|
+
mountCrossDevice(target: HTMLElement, props: CrossDevicePanelProps): CrossDeviceHandle;
|
|
35
|
+
}
|
|
36
|
+
type CrossDeviceChunkImporter = () => Promise<CrossDeviceChunkModule>;
|
|
8
37
|
declare function preloadCrossDeviceChunk(importer?: CrossDeviceChunkImporter): void;
|
|
9
38
|
interface CrossDeviceOverlayOptions {
|
|
10
39
|
target: HTMLElement;
|
|
@@ -14,11 +43,17 @@ interface CrossDeviceOverlayOptions {
|
|
|
14
43
|
emit: (e: ChecktivIdvEvent) => void;
|
|
15
44
|
onClose?: () => void;
|
|
16
45
|
chunkImporter?: CrossDeviceChunkImporter;
|
|
46
|
+
poll?: CrossDevicePollConfig;
|
|
17
47
|
}
|
|
18
48
|
interface CrossDeviceOverlayHandle {
|
|
19
49
|
setCompleting(): void;
|
|
20
50
|
destroy(): void;
|
|
21
51
|
}
|
|
22
52
|
declare function openCrossDeviceOverlay(opts: CrossDeviceOverlayOptions): CrossDeviceOverlayHandle;
|
|
53
|
+
declare function parseHandoffMintUrl(body: unknown): string | null;
|
|
54
|
+
declare function createHandoffMintHook(ctx: SubstrateContext, fetchImpl: typeof fetch): CrossDeviceHandoffHook;
|
|
55
|
+
declare function classifyCrossDeviceCompletion(body: unknown, originalStepId: string): CrossDeviceCompletion;
|
|
56
|
+
declare function checkSessionCompletion(ctx: SubstrateContext, fetchImpl: typeof fetch, originalStepId: string, signal: AbortSignal): Promise<CrossDeviceCompletion>;
|
|
57
|
+
declare function openManagedCrossDevice(params: ManagedCrossDeviceParams): CrossDeviceOverlayHandle;
|
|
23
58
|
|
|
24
|
-
export { CROSS_DEVICE_REMINT_CAP, type CrossDeviceChunkImporter, type CrossDeviceOverlayHandle, type CrossDeviceOverlayOptions, openCrossDeviceOverlay, preloadCrossDeviceChunk };
|
|
59
|
+
export { CROSS_DEVICE_POLL_INTERVAL_MS, CROSS_DEVICE_POLL_TOTAL_CAP_MS, CROSS_DEVICE_REMINT_CAP, type CrossDeviceChunkImporter, type CrossDeviceChunkModule, type CrossDeviceCompletion, type CrossDeviceOverlayHandle, type CrossDeviceOverlayOptions, type CrossDevicePollConfig, checkSessionCompletion, classifyCrossDeviceCompletion, createHandoffMintHook, openCrossDeviceOverlay, openManagedCrossDevice, parseHandoffMintUrl, preloadCrossDeviceChunk };
|
package/dist/idv/cross-device.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { registerCrossDeviceOpener, createChecktivErrorEvent } from '../chunk-LTMLIUPC.js';
|
|
2
|
+
import { withTokenRetry, createChecktivError, parseSessionData } from '../chunk-QVDWM4KK.js';
|
|
3
|
+
import '../chunk-IQKHRPJR.js';
|
|
4
|
+
import { SESSIONS_ME_PATH, dataPlaneHeaders } from '../chunk-ITLSDZHK.js';
|
|
5
|
+
import '../chunk-QFA3K5ZV.js';
|
|
2
6
|
import '../chunk-AIK7CDV6.js';
|
|
3
7
|
|
|
4
|
-
var CROSS_DEVICE_REMINT_CAP=3;var defaultChunkImporter=()=>import('../cross-device.js');function preloadCrossDeviceChunk(importer=defaultChunkImporter){try{void importer().catch(()=>{});}catch{}}function openCrossDeviceOverlay(opts){const{target,onOpenCrossDevice,copy,isMobile,emit,onClose,chunkImporter=defaultChunkImporter}=opts;const childContainer=document.createElement("div");target.appendChild(childContainer);let destroyed=false;let remintCount=0;let onCloseFired=false;const invokeOnClose=()=>{if(onCloseFired)return;onCloseFired=true;onClose?.();};const panelOnClose=onClose?invokeOnClose:void 0;let chunkHandle=null;let isCompleting=false;let currentUrl=null;const renderUnavailable=()=>{emit({type:"checktiv.idv.cross_device_unavailable"});chunkHandle?.update({url:"",copy,isMobile,completing:false,onBack:panelOnClose,onRetry:panelOnClose});};const rerender=url=>{if(typeof url!=="string"||url.length===0){renderUnavailable();return}currentUrl=url;chunkHandle?.update({url,copy,isMobile,completing:isCompleting,onBack:panelOnClose,onRefreshLink:makeRefreshHandler(),onRetry:panelOnClose});};function makeRefreshHandler(currentUrl2){if(remintCount>=CROSS_DEVICE_REMINT_CAP){return void 0}return ()=>{if(destroyed)return;if(remintCount>=CROSS_DEVICE_REMINT_CAP)return;void(async()=>{remintCount+=1;let result;try{result=await onOpenCrossDevice();}catch(err){console.warn("[Checktiv] cross-device: refresh hook rejected unexpectedly.",err);if(destroyed)return;renderUnavailable();return}if(destroyed)return;if(result.kind==="unavailable"){renderUnavailable();return}rerender(result.url);})();}}function mountPanel(chunkModule,mintResult){if(destroyed)return;const okUrl=mintResult.kind==="ok"?mintResult.url:void 0;if(mintResult.kind==="unavailable"||typeof okUrl!=="string"||okUrl.length===0){emit({type:"checktiv.idv.cross_device_unavailable"});chunkHandle=chunkModule.mountCrossDevice(childContainer,{url:"",copy,isMobile,completing:false,onBack:panelOnClose,onRetry:panelOnClose});return}emit({type:"checktiv.idv.cross_device_opened"});currentUrl=okUrl;chunkHandle=chunkModule.mountCrossDevice(childContainer,{url:okUrl,copy,isMobile,completing:isCompleting,onBack:panelOnClose,onRefreshLink:makeRefreshHandler(),onRetry:panelOnClose});}function renderDoubleFaultFallback(){if(destroyed)return;childContainer.textContent="";const msg=document.createElement("div");msg.setAttribute("data-testid","cross-device-double-fault");const text=copy.unavailableMessage;if(text){const p=document.createElement("p");p.textContent=text;msg.appendChild(p);}if(onClose){const btn=document.createElement("button");btn.type="button";btn.setAttribute("data-testid","cross-device-double-fault-retry");const retryLabel=copy.mobileTryAgainLabel??"Try again";btn.textContent=retryLabel;btn.addEventListener("click",invokeOnClose);msg.appendChild(btn);}childContainer.appendChild(msg);}void(async()=>{let chunkResult;try{chunkResult=await chunkImporter();}catch(err){console.warn("[Checktiv] cross-device: failed to load the cross-device chunk.",err);emit(createErrorEvent("sdk_load_failed"));renderDoubleFaultFallback();return}if(destroyed)return;const mintResult=await onOpenCrossDevice().catch(err=>{console.warn("[Checktiv] cross-device: onOpenCrossDevice hook threw unexpectedly.",err);return {kind:"unavailable"}});if(destroyed)return;try{mountPanel(chunkResult,mintResult);}catch(err){console.warn("[Checktiv] cross-device: failed to mount the cross-device panel.",err);emit(createErrorEvent("sdk_load_failed"));renderDoubleFaultFallback();}})();return {setCompleting(){if(destroyed)return;
|
|
8
|
+
var SESSIONS_HANDOFF_MINT_PATH=`${SESSIONS_ME_PATH}/handoff`;var CROSS_DEVICE_POLL_INTERVAL_MS=2500;var CROSS_DEVICE_POLL_TOTAL_CAP_MS=5*60*1e3;var CROSS_DEVICE_REMINT_CAP=3;var defaultChunkImporter=()=>import('../cross-device.js');function preloadCrossDeviceChunk(importer=defaultChunkImporter){try{void importer().catch(()=>{});}catch{}}function openCrossDeviceOverlay(opts){const{target,onOpenCrossDevice,copy,isMobile,emit,onClose,chunkImporter=defaultChunkImporter,poll}=opts;const childContainer=document.createElement("div");target.appendChild(childContainer);let destroyed=false;let remintCount=0;let onCloseFired=false;const invokeOnClose=()=>{if(onCloseFired)return;onCloseFired=true;onClose?.();};const panelOnClose=onClose?invokeOnClose:void 0;let chunkHandle=null;let isCompleting=false;let currentUrl=null;let pollGen=0;let pollTimeout=null;let pollAbort=null;let pollStart=0;const markCompleting=()=>{isCompleting=true;if(chunkHandle!==null&¤tUrl!==null){chunkHandle.update({url:currentUrl,copy,isMobile,completing:true,onBack:panelOnClose,onRefreshLink:void 0,onRetry:panelOnClose});}};const stopPoll=()=>{pollGen+=1;if(pollTimeout!==null){clearTimeout(pollTimeout);pollTimeout=null;}if(pollAbort!==null){pollAbort.abort();pollAbort=null;}};const startPoll=()=>{if(poll===void 0)return;const intervalMs=poll.intervalMs??CROSS_DEVICE_POLL_INTERVAL_MS;const totalCapMs=poll.totalCapMs??CROSS_DEVICE_POLL_TOTAL_CAP_MS;stopPoll();const gen=pollGen;pollStart=Date.now();const scheduleNext=()=>{if(gen!==pollGen||destroyed)return;pollTimeout=setTimeout(runTick,intervalMs);};const runTick=()=>{if(Date.now()-pollStart>=totalCapMs){stopPoll();poll.onCapped?.();return}void(async()=>{const controller=new AbortController;pollAbort=controller;let outcome;try{outcome=await poll.checkCompletion(controller.signal);}catch{scheduleNext();return}if(gen!==pollGen||destroyed)return;if(outcome==="advanced"){stopPoll();markCompleting();poll.onComplete();return}if(outcome==="terminal"){stopPoll();poll.onTerminal?.();return}scheduleNext();})();};pollTimeout=setTimeout(runTick,intervalMs);};const renderUnavailable=()=>{emit({type:"checktiv.idv.cross_device_unavailable"});chunkHandle?.update({url:"",copy,isMobile,completing:false,onBack:panelOnClose,onRetry:panelOnClose});};const rerender=url=>{if(typeof url!=="string"||url.length===0){renderUnavailable();return}currentUrl=url;chunkHandle?.update({url,copy,isMobile,completing:isCompleting,onBack:panelOnClose,onRefreshLink:makeRefreshHandler(),onRetry:panelOnClose});};function makeRefreshHandler(currentUrl2){if(remintCount>=CROSS_DEVICE_REMINT_CAP){return void 0}return ()=>{if(destroyed)return;if(remintCount>=CROSS_DEVICE_REMINT_CAP)return;void(async()=>{remintCount+=1;let result;try{result=await onOpenCrossDevice();}catch(err){console.warn("[Checktiv] cross-device: refresh hook rejected unexpectedly.",err);if(destroyed)return;renderUnavailable();return}if(destroyed)return;if(result.kind==="unavailable"){renderUnavailable();return}rerender(result.url);})();}}function mountPanel(chunkModule,mintResult){if(destroyed)return;const okUrl=mintResult.kind==="ok"?mintResult.url:void 0;if(mintResult.kind==="unavailable"||typeof okUrl!=="string"||okUrl.length===0){emit({type:"checktiv.idv.cross_device_unavailable"});chunkHandle=chunkModule.mountCrossDevice(childContainer,{url:"",copy,isMobile,completing:false,onBack:panelOnClose,onRetry:panelOnClose});return}emit({type:"checktiv.idv.cross_device_opened"});currentUrl=okUrl;chunkHandle=chunkModule.mountCrossDevice(childContainer,{url:okUrl,copy,isMobile,completing:isCompleting,onBack:panelOnClose,onRefreshLink:makeRefreshHandler(),onRetry:panelOnClose});}function renderDoubleFaultFallback(){if(destroyed)return;childContainer.textContent="";const msg=document.createElement("div");msg.setAttribute("data-testid","cross-device-double-fault");const text=copy.unavailableMessage;if(text){const p=document.createElement("p");p.textContent=text;msg.appendChild(p);}if(onClose){const btn=document.createElement("button");btn.type="button";btn.setAttribute("data-testid","cross-device-double-fault-retry");const retryLabel=copy.mobileTryAgainLabel??"Try again";btn.textContent=retryLabel;btn.addEventListener("click",invokeOnClose);msg.appendChild(btn);}childContainer.appendChild(msg);}startPoll();void(async()=>{let chunkResult;try{chunkResult=await chunkImporter();}catch(err){console.warn("[Checktiv] cross-device: failed to load the cross-device chunk.",err);emit(createErrorEvent("sdk_load_failed"));renderDoubleFaultFallback();return}if(destroyed)return;const mintResult=await onOpenCrossDevice().catch(err=>{console.warn("[Checktiv] cross-device: onOpenCrossDevice hook threw unexpectedly.",err);return {kind:"unavailable"}});if(destroyed)return;try{mountPanel(chunkResult,mintResult);}catch(err){console.warn("[Checktiv] cross-device: failed to mount the cross-device panel.",err);emit(createErrorEvent("sdk_load_failed"));renderDoubleFaultFallback();}})();return {setCompleting(){if(destroyed)return;markCompleting();},destroy(){if(destroyed)return;destroyed=true;stopPoll();invokeOnClose();if(chunkHandle!==null){chunkHandle.destroy();chunkHandle=null;}childContainer.remove();}}}function isRecord(v){return typeof v==="object"&&v!==null}function isHttpsUrl(value){if(typeof value!=="string"||value.length===0)return false;try{return new URL(value).protocol==="https:"}catch{return false}}function parseHandoffMintUrl(body){if(!isRecord(body))return null;const handoffUrl=body.handoffUrl;return isHttpsUrl(handoffUrl)?handoffUrl:null}function createHandoffMintHook(ctx,fetchImpl){const origin=ctx.apiBaseOrigin;return async()=>{let res;try{res=await withTokenRetry(ctx.tokens,token=>fetchImpl(origin+SESSIONS_HANDOFF_MINT_PATH,{method:"POST",headers:dataPlaneHeaders(ctx,token,{withJsonBody:true}),body:"{}"}),result=>result?.status===401);}catch{return {kind:"unavailable"}}if(!res.ok)return {kind:"unavailable"};let body;try{body=await res.json();}catch{return {kind:"unavailable"}}const url=parseHandoffMintUrl(body);return url===null?{kind:"unavailable"}:{kind:"ok",url}}}function classifyCrossDeviceCompletion(body,originalStepId){const data=parseSessionData(body);if(data===null)return "terminal";return data.stepId!==originalStepId?"advanced":"pending"}async function checkSessionCompletion(ctx,fetchImpl,originalStepId,signal){const origin=ctx.apiBaseOrigin;let res;try{res=await withTokenRetry(ctx.tokens,token=>fetchImpl(origin+SESSIONS_ME_PATH,{method:"GET",headers:dataPlaneHeaders(ctx,token),signal}),result=>result?.status===401);}catch{return "pending"}if(res.status===401)return "terminal";if(!res.ok)return "pending";let body;try{body=await res.json();}catch{return "pending"}return classifyCrossDeviceCompletion(body,originalStepId)}function openManagedCrossDevice(params){const{ctx,fetchImpl,target,stepId,sessionId,copy,isMobile,emit,onClose,chunkImporter}=params;const onOpenCrossDevice=params.onOpenCrossDevice??createHandoffMintHook(ctx,fetchImpl);return openCrossDeviceOverlay({target,onOpenCrossDevice,copy,isMobile,emit,onClose,...chunkImporter!==void 0?{chunkImporter}:{},poll:{checkCompletion:signal=>checkSessionCompletion(ctx,fetchImpl,stepId,signal),onComplete:()=>emit({type:"checktiv.idv.submitted",sessionId}),onCapped:()=>emit({type:"checktiv.idv.cross_device_capped"}),onTerminal:()=>emit(createChecktivErrorEvent("session_expired"))}})}registerCrossDeviceOpener(openManagedCrossDevice);function createErrorEvent(code){return {type:"checktiv.idv.error",error:createChecktivError(code)}}
|
|
5
9
|
|
|
6
|
-
export { CROSS_DEVICE_REMINT_CAP, openCrossDeviceOverlay, preloadCrossDeviceChunk };
|
|
10
|
+
export { CROSS_DEVICE_POLL_INTERVAL_MS, CROSS_DEVICE_POLL_TOTAL_CAP_MS, CROSS_DEVICE_REMINT_CAP, checkSessionCompletion, classifyCrossDeviceCompletion, createHandoffMintHook, openCrossDeviceOverlay, openManagedCrossDevice, parseHandoffMintUrl, preloadCrossDeviceChunk };
|
package/dist/idv.css
CHANGED
|
@@ -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}}
|
package/dist/idv.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import './machine
|
|
2
|
-
import './copy-
|
|
3
|
-
export {
|
|
1
|
+
import './machine-CuZalPFX.js';
|
|
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-DyExBfAQ.js';
|
|
4
|
+
import './copy-DCeQ4JKx.js';
|
package/dist/idv.js
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { registerModule
|
|
3
|
-
import {
|
|
1
|
+
import { createChecktivErrorEvent, mapStateToEvent, getCrossDeviceOpener } from './chunk-LTMLIUPC.js';
|
|
2
|
+
import { registerModule } from './chunk-GFHNOZVO.js';
|
|
3
|
+
import { assertNever } from './chunk-UBQTPS5J.js';
|
|
4
|
+
import { resolveSession, warnWrongTokenPlane, createChecktivError, withTokenRetry, mapHttpStatusToError } from './chunk-QVDWM4KK.js';
|
|
5
|
+
import { mount } from './chunk-5MNNRYD5.js';
|
|
4
6
|
import './chunk-HV2QKVJX.js';
|
|
5
7
|
import './chunk-XOGHMNBX.js';
|
|
6
|
-
import
|
|
8
|
+
import './chunk-5AQCMTZV.js';
|
|
9
|
+
import { CURRENT_PROTOCOL_VERSION } from './chunk-6U53T32A.js';
|
|
10
|
+
import './chunk-IQKHRPJR.js';
|
|
11
|
+
import { stepSubmitPath, dataPlaneHeaders, CAPTURE_TOKEN_MINT_PATH, isCanonicalOrigin } from './chunk-ITLSDZHK.js';
|
|
7
12
|
import './chunk-QFA3K5ZV.js';
|
|
8
|
-
import { createChecktivError, mapHttpStatusToError } from './chunk-WQCYRLWP.js';
|
|
9
13
|
import './chunk-AIK7CDV6.js';
|
|
10
14
|
|
|
11
|
-
var PLATFORM_BRAND_DEFAULT={primaryColor:"#2563eb",secondaryColor:"#ff5e4d",colorMode:"auto"};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",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 "token_expired":return createChecktivErrorEvent("token_expired");case "capture_error":return createChecktivErrorEvent(CAPTURE_ERROR_CODE[state.errorKind]);default:return null}}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 MAX_REMINTS=3;function isRecord(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(!isRecord(body)||!isRecord(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 createIdvTransport(ctx,opts){const fetchImpl=opts.fetchImpl??fetch;const origin=ctx.apiBaseOrigin;let embedContextToken=null;let mintMode;let mintTestHint;let remintCount=0;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({runIndex,r2Keys})}),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===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}:{}}}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(){}}}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;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 session=await resolveSession(ctx,fetchImpl);if(cancelled)return;if(session===null){emit(createChecktivErrorEvent("session_expired"));return}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);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??{},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;if(teardown!==null){teardown();teardown=null;}};return {destroy,unmount:destroy}}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;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);
|
|
12
16
|
|
|
13
17
|
export { REMINT_READY_TIMEOUT_MS, createIdv };
|