@arkyc/widget 1.1.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/LICENSE +21 -0
- package/dist/_virtual/_virtual_arkyc-theme-css.mjs +1 -1
- package/dist/arkyc-widget.iife.global.js +57 -3
- package/dist/arkyc-widget.iife.global.js.map +1 -1
- package/dist/client.d.mts +27 -0
- package/dist/client.d.mts.map +1 -1
- package/dist/client.mjs +24 -0
- package/dist/client.mjs.map +1 -1
- package/dist/controller.d.mts +63 -6
- package/dist/controller.d.mts.map +1 -1
- package/dist/controller.mjs +107 -8
- package/dist/controller.mjs.map +1 -1
- package/dist/flow.d.mts.map +1 -1
- package/dist/flow.mjs +1 -0
- package/dist/flow.mjs.map +1 -1
- package/dist/h.mjs +64 -0
- package/dist/h.mjs.map +1 -0
- package/dist/index.d.mts +3 -3
- package/dist/types.d.mts +26 -2
- package/dist/types.d.mts.map +1 -1
- package/dist/ui.d.mts +19 -0
- package/dist/ui.d.mts.map +1 -0
- package/dist/ui.mjs +257 -183
- package/dist/ui.mjs.map +1 -1
- package/package.json +2 -2
package/dist/flow.mjs
CHANGED
package/dist/flow.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flow.mjs","names":[],"sources":["../src/flow.ts"],"sourcesContent":["import {\n type DocumentType,\n type LivenessMode,\n type VerificationDecision,\n type VerificationStatus,\n type WidgetStep,\n type WorkflowConfig,\n type WorkflowStepKey,\n workflowEnabledSteps,\n workflowRunsOcr,\n} from '@arkyc/types'\n\n/** Context that influences flow branching. */\nexport interface FlowContext {\n documentType?: DocumentType | null\n /** Which liveness flow this session runs (resolved from the capture model). */\n livenessMode?: LivenessMode\n /** The applied workflow (orders/toggles the coarse stages), or null for the default flow. */\n workflow?: WorkflowConfig | null\n}\n\n/** The widget screens that make up each coarse verification stage, in stage-local order. */\nconst STAGE_STEPS: Record<WorkflowStepKey, WidgetStep[]> = {\n document: ['document_selection', 'front_capture', 'back_capture', 'ocr_processing'],\n liveness: ['active_liveness', 'selfie_capture', 'passive_liveness'],\n face_match: ['face_match'],\n}\n\n/**\n * The verification flow's step machine. Stateless — exposed as static members so\n * the single \"flow\" concern lives in one class rather than as floating helpers.\n */\nexport class Flow {\n /**\n * The flow screens, in the order the widget walks them. The `back_capture`\n * screen is skipped for single-sided documents (passports).\n */\n static readonly STEP_ORDER: WidgetStep[] = [\n 'welcome',\n 'document_selection',\n 'front_capture',\n 'back_capture',\n 'ocr_processing',\n 'active_liveness',\n 'selfie_capture',\n 'passive_liveness',\n 'face_match',\n 'processing',\n 'result',\n ]\n\n /**\n * Statuses from which a session can no longer progress.\n */\n static readonly TERMINAL_STATUSES: VerificationStatus[] = [\n 'approved',\n 'rejected',\n 'requires_review',\n 'expired',\n 'cancelled',\n ]\n\n /**\n * Whether a document type has a second (back) side to capture.\n *\n * @param type\n * @returns\n */\n static documentHasBack(type: DocumentType | null | undefined): boolean {\n return type != null && type !== 'passport'\n }\n\n /**\n * The screens to walk for this session, in order. With no workflow this is the\n * default {@link STEP_ORDER}; a workflow reorders the coarse stages and drops\n * disabled ones (their screens are excluded entirely), always bracketed by\n * `welcome` and `processing`/`result`.\n */\n static stepOrder(ctx: FlowContext = {}): WidgetStep[] {\n const stages = workflowEnabledSteps(ctx.workflow) as WorkflowStepKey[]\n const middle = stages.flatMap((stage) => STAGE_STEPS[stage])\n\n return ['welcome', ...middle, 'processing', 'result']\n }\n\n /**\n * Whether a step runs for the given context. `back_capture` is skipped for\n * single-sided documents; `ocr_processing` is skipped when the workflow skips\n * OCR; the liveness steps branch on the resolved mode — `active_liveness` only\n * in active mode, `selfie_capture`/`passive_liveness` only in passive mode.\n * Stage-level disabling is handled by {@link stepOrder} (disabled stages are\n * absent from the order), so this only covers within-stage branching.\n */\n static isStepEnabled(step: WidgetStep, ctx: FlowContext = {}): boolean {\n if (step === 'back_capture') return Flow.documentHasBack(ctx.documentType)\n if (step === 'ocr_processing') return workflowRunsOcr(ctx.workflow)\n if (step === 'active_liveness') return ctx.livenessMode === 'active'\n if (step === 'selfie_capture' || step === 'passive_liveness') {\n return ctx.livenessMode !== 'active'\n }\n return true\n }\n\n /**\n * The next enabled screen after `current`, honouring the workflow order and the\n * branch rules. Returns `current` when already at the end.\n *\n * @param current\n * @param ctx\n * @returns\n */\n static nextStep(current: WidgetStep, ctx: FlowContext = {}): WidgetStep {\n const order = Flow.stepOrder(ctx)\n const idx = order.indexOf(current)\n if (idx < 0) return current\n for (let i = idx + 1; i < order.length; i += 1) {\n const step = order[i]!\n if (Flow.isStepEnabled(step, ctx)) return step\n }\n return current\n }\n\n /**\n * Whether a session status is terminal (the flow is done).\n *\n * @param status\n * @returns\n */\n static isTerminal(status: VerificationStatus): boolean {\n return Flow.TERMINAL_STATUSES.includes(status)\n }\n\n /**\n * Map a terminal session status to the decision the integrator cares about.\n * Non-decision terminals (`expired`/`cancelled`) and in-flight statuses map to\n * `null`.\n */\n static statusToDecision(status: VerificationStatus): VerificationDecision | null {\n switch (status) {\n case 'approved':\n return 'approved'\n case 'rejected':\n return 'rejected'\n case 'requires_review':\n return 'requires_review'\n default:\n return null\n }\n }\n}\n"],"mappings":";;;AAsBA,MAAM,cAAqD;CACzD,UAAU;EAAC;EAAsB;EAAiB;EAAgB;CAAgB;CAClF,UAAU;EAAC;EAAmB;EAAkB;CAAkB;CAClE,YAAY,CAAC,YAAY;AAC3B;;;;;AAMA,IAAa,OAAb,MAAa,KAAK;;;;;CAKhB,OAAgB,aAA2B;EACzC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;;;;CAKA,OAAgB,oBAA0C;EACxD;EACA;EACA;EACA;EACA;CACF;;;;;;;CAQA,OAAO,gBAAgB,MAAgD;EACrE,OAAO,QAAQ,QAAQ,SAAS;CAClC;;;;;;;CAQA,OAAO,UAAU,MAAmB,CAAC,GAAiB;EAIpD,OAAO;GAAC;GAAW,GAHJ,qBAAqB,IAAI,QACpB,CAAC,CAAC,SAAS,UAAU,YAAY,MAE1B;GAAG;GAAc;EAAQ;CACtD;;;;;;;;;CAUA,OAAO,cAAc,MAAkB,MAAmB,CAAC,GAAY;EACrE,IAAI,SAAS,gBAAgB,OAAO,KAAK,gBAAgB,IAAI,YAAY;EACzE,IAAI,SAAS,kBAAkB,OAAO,gBAAgB,IAAI,QAAQ;EAClE,IAAI,SAAS,mBAAmB,OAAO,IAAI,iBAAiB;EAC5D,IAAI,SAAS,oBAAoB,SAAS,oBACxC,OAAO,IAAI,iBAAiB;EAE9B,OAAO;CACT;;;;;;;;;CAUA,OAAO,SAAS,SAAqB,MAAmB,CAAC,GAAe;EACtE,MAAM,QAAQ,KAAK,UAAU,GAAG;EAChC,MAAM,MAAM,MAAM,QAAQ,OAAO;EACjC,IAAI,MAAM,GAAG,OAAO;EACpB,KAAK,IAAI,IAAI,MAAM,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;GAC9C,MAAM,OAAO,MAAM;GACnB,IAAI,KAAK,cAAc,MAAM,GAAG,GAAG,OAAO;EAC5C;EACA,OAAO;CACT;;;;;;;CAQA,OAAO,WAAW,QAAqC;EACrD,OAAO,KAAK,kBAAkB,SAAS,MAAM;CAC/C;;;;;;CAOA,OAAO,iBAAiB,QAAyD;EAC/E,QAAQ,QAAR;GACE,KAAK,YACH,OAAO;GACT,KAAK,YACH,OAAO;GACT,KAAK,mBACH,OAAO;GACT,SACE,OAAO;EACX;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"flow.mjs","names":[],"sources":["../src/flow.ts"],"sourcesContent":["import {\n type DocumentType,\n type LivenessMode,\n type VerificationDecision,\n type VerificationStatus,\n type WidgetStep,\n type WorkflowConfig,\n type WorkflowStepKey,\n workflowEnabledSteps,\n workflowRunsOcr,\n} from '@arkyc/types'\n\n/** Context that influences flow branching. */\nexport interface FlowContext {\n documentType?: DocumentType | null\n /** Which liveness flow this session runs (resolved from the capture model). */\n livenessMode?: LivenessMode\n /** The applied workflow (orders/toggles the coarse stages), or null for the default flow. */\n workflow?: WorkflowConfig | null\n}\n\n/** The widget screens that make up each coarse verification stage, in stage-local order. */\nconst STAGE_STEPS: Record<WorkflowStepKey, WidgetStep[]> = {\n document: ['document_selection', 'front_capture', 'back_capture', 'ocr_processing'],\n address: ['address_entry', 'address_processing'],\n liveness: ['active_liveness', 'selfie_capture', 'passive_liveness'],\n face_match: ['face_match'],\n}\n\n/**\n * The verification flow's step machine. Stateless — exposed as static members so\n * the single \"flow\" concern lives in one class rather than as floating helpers.\n */\nexport class Flow {\n /**\n * The flow screens, in the order the widget walks them. The `back_capture`\n * screen is skipped for single-sided documents (passports).\n */\n static readonly STEP_ORDER: WidgetStep[] = [\n 'welcome',\n 'document_selection',\n 'front_capture',\n 'back_capture',\n 'ocr_processing',\n 'active_liveness',\n 'selfie_capture',\n 'passive_liveness',\n 'face_match',\n 'processing',\n 'result',\n ]\n\n /**\n * Statuses from which a session can no longer progress.\n */\n static readonly TERMINAL_STATUSES: VerificationStatus[] = [\n 'approved',\n 'rejected',\n 'requires_review',\n 'expired',\n 'cancelled',\n ]\n\n /**\n * Whether a document type has a second (back) side to capture.\n *\n * @param type\n * @returns\n */\n static documentHasBack(type: DocumentType | null | undefined): boolean {\n return type != null && type !== 'passport'\n }\n\n /**\n * The screens to walk for this session, in order. With no workflow this is the\n * default {@link STEP_ORDER}; a workflow reorders the coarse stages and drops\n * disabled ones (their screens are excluded entirely), always bracketed by\n * `welcome` and `processing`/`result`.\n */\n static stepOrder(ctx: FlowContext = {}): WidgetStep[] {\n const stages = workflowEnabledSteps(ctx.workflow) as WorkflowStepKey[]\n const middle = stages.flatMap((stage) => STAGE_STEPS[stage])\n\n return ['welcome', ...middle, 'processing', 'result']\n }\n\n /**\n * Whether a step runs for the given context. `back_capture` is skipped for\n * single-sided documents; `ocr_processing` is skipped when the workflow skips\n * OCR; the liveness steps branch on the resolved mode — `active_liveness` only\n * in active mode, `selfie_capture`/`passive_liveness` only in passive mode.\n * Stage-level disabling is handled by {@link stepOrder} (disabled stages are\n * absent from the order), so this only covers within-stage branching.\n */\n static isStepEnabled(step: WidgetStep, ctx: FlowContext = {}): boolean {\n if (step === 'back_capture') return Flow.documentHasBack(ctx.documentType)\n if (step === 'ocr_processing') return workflowRunsOcr(ctx.workflow)\n if (step === 'active_liveness') return ctx.livenessMode === 'active'\n if (step === 'selfie_capture' || step === 'passive_liveness') {\n return ctx.livenessMode !== 'active'\n }\n return true\n }\n\n /**\n * The next enabled screen after `current`, honouring the workflow order and the\n * branch rules. Returns `current` when already at the end.\n *\n * @param current\n * @param ctx\n * @returns\n */\n static nextStep(current: WidgetStep, ctx: FlowContext = {}): WidgetStep {\n const order = Flow.stepOrder(ctx)\n const idx = order.indexOf(current)\n if (idx < 0) return current\n for (let i = idx + 1; i < order.length; i += 1) {\n const step = order[i]!\n if (Flow.isStepEnabled(step, ctx)) return step\n }\n return current\n }\n\n /**\n * Whether a session status is terminal (the flow is done).\n *\n * @param status\n * @returns\n */\n static isTerminal(status: VerificationStatus): boolean {\n return Flow.TERMINAL_STATUSES.includes(status)\n }\n\n /**\n * Map a terminal session status to the decision the integrator cares about.\n * Non-decision terminals (`expired`/`cancelled`) and in-flight statuses map to\n * `null`.\n */\n static statusToDecision(status: VerificationStatus): VerificationDecision | null {\n switch (status) {\n case 'approved':\n return 'approved'\n case 'rejected':\n return 'rejected'\n case 'requires_review':\n return 'requires_review'\n default:\n return null\n }\n }\n}\n"],"mappings":";;;AAsBA,MAAM,cAAqD;CACzD,UAAU;EAAC;EAAsB;EAAiB;EAAgB;CAAgB;CAClF,SAAS,CAAC,iBAAiB,oBAAoB;CAC/C,UAAU;EAAC;EAAmB;EAAkB;CAAkB;CAClE,YAAY,CAAC,YAAY;AAC3B;;;;;AAMA,IAAa,OAAb,MAAa,KAAK;;;;;CAKhB,OAAgB,aAA2B;EACzC;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;;;;CAKA,OAAgB,oBAA0C;EACxD;EACA;EACA;EACA;EACA;CACF;;;;;;;CAQA,OAAO,gBAAgB,MAAgD;EACrE,OAAO,QAAQ,QAAQ,SAAS;CAClC;;;;;;;CAQA,OAAO,UAAU,MAAmB,CAAC,GAAiB;EAIpD,OAAO;GAAC;GAAW,GAHJ,qBAAqB,IAAI,QACpB,CAAC,CAAC,SAAS,UAAU,YAAY,MAE1B;GAAG;GAAc;EAAQ;CACtD;;;;;;;;;CAUA,OAAO,cAAc,MAAkB,MAAmB,CAAC,GAAY;EACrE,IAAI,SAAS,gBAAgB,OAAO,KAAK,gBAAgB,IAAI,YAAY;EACzE,IAAI,SAAS,kBAAkB,OAAO,gBAAgB,IAAI,QAAQ;EAClE,IAAI,SAAS,mBAAmB,OAAO,IAAI,iBAAiB;EAC5D,IAAI,SAAS,oBAAoB,SAAS,oBACxC,OAAO,IAAI,iBAAiB;EAE9B,OAAO;CACT;;;;;;;;;CAUA,OAAO,SAAS,SAAqB,MAAmB,CAAC,GAAe;EACtE,MAAM,QAAQ,KAAK,UAAU,GAAG;EAChC,MAAM,MAAM,MAAM,QAAQ,OAAO;EACjC,IAAI,MAAM,GAAG,OAAO;EACpB,KAAK,IAAI,IAAI,MAAM,GAAG,IAAI,MAAM,QAAQ,KAAK,GAAG;GAC9C,MAAM,OAAO,MAAM;GACnB,IAAI,KAAK,cAAc,MAAM,GAAG,GAAG,OAAO;EAC5C;EACA,OAAO;CACT;;;;;;;CAQA,OAAO,WAAW,QAAqC;EACrD,OAAO,KAAK,kBAAkB,SAAS,MAAM;CAC/C;;;;;;CAOA,OAAO,iBAAiB,QAAyD;EAC/E,QAAQ,QAAR;GACE,KAAK,YACH,OAAO;GACT,KAAK,YACH,OAAO;GACT,KAAK,mBACH,OAAO;GACT,SACE,OAAO;EACX;CACF;AACF"}
|
package/dist/h.mjs
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
//#region src/h.ts
|
|
2
|
+
/**
|
|
3
|
+
* Bind the hyperscript helpers to a specific `Document`. Pass the real
|
|
4
|
+
* `document` in the browser, or an injected fake in tests.
|
|
5
|
+
*
|
|
6
|
+
* @param doc
|
|
7
|
+
* @returns
|
|
8
|
+
*/
|
|
9
|
+
function createDom(doc) {
|
|
10
|
+
function append(parent, children) {
|
|
11
|
+
for (const child of Array.isArray(children) ? children : [children]) {
|
|
12
|
+
if (child == null || child === false) continue;
|
|
13
|
+
parent.appendChild(typeof child === "string" ? doc.createTextNode(child) : child);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function h(tag, props = {}, children) {
|
|
17
|
+
const node = doc.createElement(tag);
|
|
18
|
+
for (const [key, value] of Object.entries(props)) {
|
|
19
|
+
if (value == null) continue;
|
|
20
|
+
if (key === "on") for (const [event, handler] of Object.entries(value)) node.addEventListener(event, handler);
|
|
21
|
+
else if (key === "class") node.className = value;
|
|
22
|
+
else if (key === "text") node.textContent = value;
|
|
23
|
+
else if (key === "html") node.innerHTML = value;
|
|
24
|
+
else if (key === "value" || key === "src" || key === "type" || key === "accept" || key === "placeholder") node[key] = value;
|
|
25
|
+
else node.setAttribute(key, value);
|
|
26
|
+
}
|
|
27
|
+
append(node, children);
|
|
28
|
+
return node;
|
|
29
|
+
}
|
|
30
|
+
function field(placeholder, opts = {}) {
|
|
31
|
+
const cls = opts.class ?? "arkyc-addr-input";
|
|
32
|
+
if (opts.choices) return h("select", {
|
|
33
|
+
class: cls,
|
|
34
|
+
name: opts.name,
|
|
35
|
+
autocomplete: opts.autocomplete,
|
|
36
|
+
"aria-label": opts.name ?? placeholder
|
|
37
|
+
}, [h("option", {
|
|
38
|
+
value: "",
|
|
39
|
+
text: placeholder
|
|
40
|
+
}), ...opts.choices.map((choice) => {
|
|
41
|
+
return h("option", {
|
|
42
|
+
value: typeof choice === "string" ? choice : choice.value,
|
|
43
|
+
text: typeof choice === "string" ? choice : choice.label ?? choice.value
|
|
44
|
+
});
|
|
45
|
+
})]);
|
|
46
|
+
return h("input", {
|
|
47
|
+
class: cls,
|
|
48
|
+
type: opts.type ?? "text",
|
|
49
|
+
placeholder,
|
|
50
|
+
name: opts.name,
|
|
51
|
+
autocomplete: opts.autocomplete,
|
|
52
|
+
value: opts.value
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
h,
|
|
57
|
+
append,
|
|
58
|
+
field
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
export { createDom };
|
|
63
|
+
|
|
64
|
+
//# sourceMappingURL=h.mjs.map
|
package/dist/h.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"h.mjs","names":[],"sources":["../src/h.ts"],"sourcesContent":["/**\n * Tiny dependency-free DOM hyperscript — the widget's deliberate alternative to\n * a virtual-DOM library (the widget is a lightweight, framework-agnostic embed,\n * so it ships no UI framework).\n *\n * `h(tag, props, children)` builds an element in one expression; `append` adds\n * children to an existing node. Both are bound to a `Document` so they work\n * against the real DOM in the browser and against an injected fake in tests.\n *\n * ```ts\n * const { h } = createDom(document)\n * const card = h('div', { class: 'card', on: { click: onClick } }, [\n * h('h2', { text: 'Title' }),\n * subtitle && h('p', { text: subtitle }), // falsy children are skipped\n * ])\n * ```\n */\n\n/** A child accepted by {@link Dom.h}: a node, text, or a falsy value to skip. */\nexport type ElChild = Node | string | false | null | undefined\n\n/** Props for {@link Dom.h}: class/text/html, known DOM properties, attributes, and `on` listeners. */\nexport interface ElProps {\n class?: string\n text?: string\n html?: string\n type?: string\n src?: string\n accept?: string\n placeholder?: string\n value?: string\n /** Event listeners keyed by event name, e.g. `{ click: () => … }`. */\n on?: Record<string, EventListener>\n [attr: string]: string | Record<string, EventListener> | undefined\n}\n\n/** A `<select>` choice: a bare value, or a value with a distinct display label. */\nexport type FieldChoice = string | { value: string; label?: string }\n\n/** Options for {@link Dom.field}. With `choices`, a `<select>` is built; otherwise a text `<input>`. */\nexport interface FieldOptions {\n /** CSS class (defaults to `arkyc-addr-input`). */\n class?: string\n name?: string\n /** Input type (text inputs only; ignored for selects). */\n type?: string\n autocomplete?: string\n value?: string\n /** When present, render a `<select>` with `placeholder` as the leading empty option, then these. */\n choices?: FieldChoice[]\n}\n\n/** The hyperscript helpers bound to a {@link Document}. */\nexport interface Dom {\n h<T extends HTMLElement = HTMLElement>(tag: string, props?: ElProps, children?: ElChild | ElChild[]): T\n append(parent: HTMLElement, children?: ElChild | ElChild[]): void\n /**\n * Build a form control: a text `<input>`, or a `<select>` when `opts.choices`\n * is given (with `placeholder` as the leading empty option). Returns the\n * element — the caller appends it.\n *\n * @param placeholder\n * @param opts\n */\n field(placeholder: string, opts?: FieldOptions): HTMLInputElement | HTMLSelectElement\n}\n\n/**\n * Bind the hyperscript helpers to a specific `Document`. Pass the real\n * `document` in the browser, or an injected fake in tests.\n *\n * @param doc\n * @returns\n */\nexport function createDom(doc: Document): Dom {\n function append(parent: HTMLElement, children?: ElChild | ElChild[]): void {\n for (const child of Array.isArray(children) ? children : [children]) {\n if (child == null || child === false) continue\n parent.appendChild(typeof child === 'string' ? doc.createTextNode(child) : child)\n }\n }\n\n function h<T extends HTMLElement = HTMLElement>(tag: string, props: ElProps = {}, children?: ElChild | ElChild[]): T {\n const node = doc.createElement(tag) as T\n for (const [key, value] of Object.entries(props)) {\n if (value == null) continue\n if (key === 'on') {\n for (const [event, handler] of Object.entries(value as Record<string, EventListener>)) {\n node.addEventListener(event, handler)\n }\n } else if (key === 'class') node.className = value as string\n else if (key === 'text') node.textContent = value as string\n else if (key === 'html') node.innerHTML = value as string\n else if (key === 'value' || key === 'src' || key === 'type' || key === 'accept' || key === 'placeholder') {\n ;(node as unknown as Record<string, string>)[key] = value as string\n } else node.setAttribute(key, value as string)\n }\n append(node, children)\n return node\n }\n\n function field(placeholder: string, opts: FieldOptions = {}): HTMLInputElement | HTMLSelectElement {\n const cls = opts.class ?? 'arkyc-addr-input'\n if (opts.choices) {\n return h<HTMLSelectElement>(\n 'select',\n { class: cls, name: opts.name, autocomplete: opts.autocomplete, 'aria-label': opts.name ?? placeholder },\n [\n h('option', { value: '', text: placeholder }),\n ...opts.choices.map((choice) => {\n const value = typeof choice === 'string' ? choice : choice.value\n const label = typeof choice === 'string' ? choice : (choice.label ?? choice.value)\n return h('option', { value, text: label })\n }),\n ],\n )\n }\n return h<HTMLInputElement>('input', {\n class: cls,\n type: opts.type ?? 'text',\n placeholder,\n name: opts.name,\n autocomplete: opts.autocomplete,\n value: opts.value,\n })\n }\n\n return { h, append, field }\n}\n\n/**\n * Browser-default helpers, bound lazily to `globalThis.document` for\n * non-test call sites.\n */\nlet browser: Dom | undefined\nconst lazy = (): Dom => (browser ??= createDom(globalThis.document))\n\n/**\n * {@link Dom.h} bound to the browser `document`.\n * Import this from any browser-only module.\n *\n * @param tag\n * @param props\n * @param children\n * @returns\n */\nexport const h = <T extends HTMLElement = HTMLElement>(\n tag: string,\n props?: ElProps,\n children?: ElChild | ElChild[],\n): T => lazy().h<T>(tag, props, children)\n\n/**\n * {@link Dom.append} bound to the browser `document`.\n *\n * @param parent\n * @param children\n * @returns\n */\nexport const append = (parent: HTMLElement, children?: ElChild | ElChild[]): void => lazy().append(parent, children)\n\n/**\n * {@link Dom.field} bound to the browser `document`.\n *\n * @param placeholder\n * @param opts\n * @returns\n */\nexport const field = (placeholder: string, opts?: FieldOptions): HTMLInputElement | HTMLSelectElement =>\n lazy().field(placeholder, opts)\n"],"mappings":";;;;;;;;AA0EA,SAAgB,UAAU,KAAoB;CAC5C,SAAS,OAAO,QAAqB,UAAsC;EACzE,KAAK,MAAM,SAAS,MAAM,QAAQ,QAAQ,IAAI,WAAW,CAAC,QAAQ,GAAG;GACnE,IAAI,SAAS,QAAQ,UAAU,OAAO;GACtC,OAAO,YAAY,OAAO,UAAU,WAAW,IAAI,eAAe,KAAK,IAAI,KAAK;EAClF;CACF;CAEA,SAAS,EAAuC,KAAa,QAAiB,CAAC,GAAG,UAAmC;EACnH,MAAM,OAAO,IAAI,cAAc,GAAG;EAClC,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAAG;GAChD,IAAI,SAAS,MAAM;GACnB,IAAI,QAAQ,MACV,KAAK,MAAM,CAAC,OAAO,YAAY,OAAO,QAAQ,KAAsC,GAClF,KAAK,iBAAiB,OAAO,OAAO;QAEjC,IAAI,QAAQ,SAAS,KAAK,YAAY;QACxC,IAAI,QAAQ,QAAQ,KAAK,cAAc;QACvC,IAAI,QAAQ,QAAQ,KAAK,YAAY;QACrC,IAAI,QAAQ,WAAW,QAAQ,SAAS,QAAQ,UAAU,QAAQ,YAAY,QAAQ,eACxF,KAA4C,OAAO;QAC/C,KAAK,aAAa,KAAK,KAAe;EAC/C;EACA,OAAO,MAAM,QAAQ;EACrB,OAAO;CACT;CAEA,SAAS,MAAM,aAAqB,OAAqB,CAAC,GAAyC;EACjG,MAAM,MAAM,KAAK,SAAS;EAC1B,IAAI,KAAK,SACP,OAAO,EACL,UACA;GAAE,OAAO;GAAK,MAAM,KAAK;GAAM,cAAc,KAAK;GAAc,cAAc,KAAK,QAAQ;EAAY,GACvG,CACE,EAAE,UAAU;GAAE,OAAO;GAAI,MAAM;EAAY,CAAC,GAC5C,GAAG,KAAK,QAAQ,KAAK,WAAW;GAG9B,OAAO,EAAE,UAAU;IAAE,OAFP,OAAO,WAAW,WAAW,SAAS,OAAO;IAE/B,MADd,OAAO,WAAW,WAAW,SAAU,OAAO,SAAS,OAAO;GACpC,CAAC;EAC3C,CAAC,CACH,CACF;EAEF,OAAO,EAAoB,SAAS;GAClC,OAAO;GACP,MAAM,KAAK,QAAQ;GACnB;GACA,MAAM,KAAK;GACX,cAAc,KAAK;GACnB,OAAO,KAAK;EACd,CAAC;CACH;CAEA,OAAO;EAAE;EAAG;EAAQ;CAAM;AAC5B"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { DEFAULT_DOCUMENT_TUNING, DocRect, DocumentAnalyzer, DocumentSample, DocumentTuning, analyzeDocumentGray, createDefaultDocumentAnalyzer, documentGuidance, isDocumentReady } from "./document.mjs";
|
|
2
2
|
import { ChallengeDetector, DEFAULT_TUNING, FaceAnalyzer, FaceSample, FaceTuning, createDefaultFaceAnalyzer, isSelfieReady, makeChallengeDetector } from "./face.mjs";
|
|
3
|
+
import { Theme } from "./theme.mjs";
|
|
3
4
|
import { ArkycClient, ArkycClientOptions, ClientRealtime, ClientSession, ProviderSignalHints, WidgetApiError } from "./client.mjs";
|
|
4
5
|
import { WidgetRealtimeClient, WidgetRealtimeFactory, WidgetRealtimeHandler, createWidgetRealtimeClient } from "./realtime.mjs";
|
|
5
|
-
import { BaseWidgetOptions, MountWidgetOptions, WidgetControllerConfig, WidgetEvent, WidgetEventListener, WidgetHandle } from "./types.mjs";
|
|
6
|
+
import { BaseWidgetOptions, MountWidgetOptions, ViewHandlers, WidgetControllerConfig, WidgetEvent, WidgetEventListener, WidgetHandle } from "./types.mjs";
|
|
6
7
|
import { WidgetController } from "./controller.mjs";
|
|
7
|
-
import { Theme } from "./theme.mjs";
|
|
8
8
|
import { Camera, Facing } from "./capture.mjs";
|
|
9
9
|
import { Flow, FlowContext } from "./flow.mjs";
|
|
10
10
|
import { ArkycWidget } from "./ArkycWidget.mjs";
|
|
@@ -15,5 +15,5 @@ import { WidgetResult } from "@arkyc/types";
|
|
|
15
15
|
declare const PACKAGE_NAME = "@arkyc/widget";
|
|
16
16
|
declare const VERSION = "0.1.0";
|
|
17
17
|
//#endregion
|
|
18
|
-
export { ArkycClient, type ArkycClientOptions, ArkycWidget, BaseWidgetOptions, Camera, type ChallengeDetector, type ClientRealtime, type ClientSession, DEFAULT_DOCUMENT_TUNING, DEFAULT_TUNING, type DocRect, type DocumentAnalyzer, type DocumentSample, type DocumentTuning, type FaceAnalyzer, type FaceSample, type FaceTuning, type Facing, Flow, type FlowContext, MountWidgetOptions, PACKAGE_NAME, type ProviderSignalHints, Theme, VERSION, WidgetApiError, type WidgetController, WidgetControllerConfig, WidgetEvent, WidgetEventListener, WidgetHandle, WidgetHandler, type WidgetRealtimeClient, type WidgetRealtimeFactory, type WidgetRealtimeHandler, type WidgetResult, analyzeDocumentGray, createDefaultDocumentAnalyzer, createDefaultFaceAnalyzer, createWidgetRealtimeClient, documentGuidance, isDocumentReady, isSelfieReady, makeChallengeDetector };
|
|
18
|
+
export { ArkycClient, type ArkycClientOptions, ArkycWidget, BaseWidgetOptions, Camera, type ChallengeDetector, type ClientRealtime, type ClientSession, DEFAULT_DOCUMENT_TUNING, DEFAULT_TUNING, type DocRect, type DocumentAnalyzer, type DocumentSample, type DocumentTuning, type FaceAnalyzer, type FaceSample, type FaceTuning, type Facing, Flow, type FlowContext, MountWidgetOptions, PACKAGE_NAME, type ProviderSignalHints, Theme, VERSION, ViewHandlers, WidgetApiError, type WidgetController, WidgetControllerConfig, WidgetEvent, WidgetEventListener, WidgetHandle, WidgetHandler, type WidgetRealtimeClient, type WidgetRealtimeFactory, type WidgetRealtimeHandler, type WidgetResult, analyzeDocumentGray, createDefaultDocumentAnalyzer, createDefaultFaceAnalyzer, createWidgetRealtimeClient, documentGuidance, isDocumentReady, isSelfieReady, makeChallengeDetector };
|
|
19
19
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/types.d.mts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { DocumentAnalyzer, DocumentTuning } from "./document.mjs";
|
|
2
2
|
import { FaceAnalyzer, FaceTuning } from "./face.mjs";
|
|
3
|
+
import { AddressFormData } from "./ui.mjs";
|
|
3
4
|
import { ProviderSignalHints } from "./client.mjs";
|
|
4
5
|
import { WidgetRealtimeFactory } from "./realtime.mjs";
|
|
5
|
-
import { ProjectBranding, WidgetResult } from "@arkyc/types";
|
|
6
|
+
import { DocumentType, LivenessChallenge, ProjectBranding, WidgetResult } from "@arkyc/types";
|
|
6
7
|
|
|
7
8
|
//#region src/types.d.ts
|
|
8
9
|
/**
|
|
@@ -148,6 +149,29 @@ interface WidgetHandle {
|
|
|
148
149
|
*/
|
|
149
150
|
on: (event: string, listener: WidgetEventListener) => () => void;
|
|
150
151
|
}
|
|
152
|
+
/** High-level events the view raises back to the controller. */
|
|
153
|
+
interface ViewHandlers {
|
|
154
|
+
onClose(): void;
|
|
155
|
+
onStart(): void;
|
|
156
|
+
onDocumentSelected(type: DocumentType, country: string): void;
|
|
157
|
+
/** A capture screen produced an image (or `null` when skipped in demo mode). */
|
|
158
|
+
onImage(blob: Blob | null): void;
|
|
159
|
+
/**
|
|
160
|
+
* Active liveness finished: the recorded video (or `null`), the performed
|
|
161
|
+
* sequence, and a still selfie frame grabbed from the live video (or `null`).
|
|
162
|
+
*/
|
|
163
|
+
onActiveLiveness(video: Blob | null, performed: LivenessChallenge[], selfie?: Blob | null): void;
|
|
164
|
+
/** The result screen was acknowledged ("Done"). */
|
|
165
|
+
onAcknowledge(): void;
|
|
166
|
+
/** The user chose to continue the verification on another device (handoff). */
|
|
167
|
+
onUsePhone(): void;
|
|
168
|
+
/** The user chose to keep verifying on this (desktop) device instead of handing off. */
|
|
169
|
+
onContinueHere(): void;
|
|
170
|
+
/** The address-entry form was submitted (opt-in address stage). */
|
|
171
|
+
onAddress(data: AddressFormData): void;
|
|
172
|
+
/** Request the device's location (address stage); resolves true when shared. */
|
|
173
|
+
onShareLocation(): boolean | Promise<boolean>;
|
|
174
|
+
}
|
|
151
175
|
//#endregion
|
|
152
|
-
export { BaseWidgetOptions, MountWidgetOptions, WidgetControllerConfig, WidgetEvent, WidgetEventListener, WidgetHandle };
|
|
176
|
+
export { BaseWidgetOptions, MountWidgetOptions, ViewHandlers, WidgetControllerConfig, WidgetEvent, WidgetEventListener, WidgetHandle };
|
|
153
177
|
//# sourceMappingURL=types.d.mts.map
|
package/dist/types.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;;;;;;AAaA;;;UAAiB,WAAA;EAIX;EAFJ,IAAA;EAM6B;EAJ7B,IAAI;AAAA;AAI0C;AAAA,KAApC,mBAAA,IAAuB,IAAa;;UAG/B,sBAAA;EASJ;EAPX,KAAA;EAasB;EAXtB,OAAA;EAmBkB;EAjBlB,OAAA;EAyBM;EAvBN,UAAA;EACA,QAAA,GAAW,eAAA;EA8BI;;;;EAzBf,OAAA,GAAU,mBAAA;EACV,UAAA,IAAc,MAAA,EAAQ,YAAA;EACtB,OAAA,IAAW,KAAA,EAAO,KAAA;EAClB,OAAA;EAbA;;;;;EAmBA,OAAA,IAAW,KAAA,EAAO,WAAA;EATR;EAWV,QAAA;EAVsB;EAYtB,YAAA;EAGA,KAAA,UAAe,KAAA;EACf,GAAA,GAAM,QAAA;EACN,GAAA,GAAM,MAAA;EACN,GAAA,GAAM,SAAA;EAVN;;;;;EAgBA,YAAA,GAAe,YAAA;EATA;EAWf,UAAA,GAAa,UAAA;EAVP;;;;;EAgBN,gBAAA,GAAmB,gBAAA;EARJ;EAUf,cAAA,GAAiB,cAAA;EARJ;;;;EAab,eAAA,GAAkB,qBAAA;EAAlB;EAEA,SAAA,IAAa,EAAA,cAAgB,EAAA;EAA7B;EAEA,WAAA;EAF6B;EAI7B,MAAA;EAAA;EAEA,QAAA;EAEA;EAAA,eAAA;AAAA;AAIF;AAAA,UAAiB,iBAAA;;EAEf,KAAA;EAsBU;EApBV,OAAA;EAsBkB;;;;;EAhBlB,OAAA;EAgCe;;;;EA3Bf,UAAA;EAiC+B;EA/B/B,QAAA,GAAW,eAAA;EAbX;;;;EAkBA,UAAA;EAAA;EAEA,OAAA,GAAU,mBAAA;EACV,UAAA,IAAc,MAAA,EAAQ,YAAA;EACtB,OAAA,IAAW,KAAA,EAAO,KAAA;EAClB,OAAA;EAFc;;;;;;EASd,OAAA,IAAW,KAAA,EAAO,WAAA;EAGlB,KAAA,UAAe,KAAA;EACf,GAAA,GAAM,QAAA;EACN,GAAA,GAAM,MAAA;EACN,GAAA,GAAM,SAAA;EAFA;EAIN,YAAA,GAAe,YAAA;EAHT;EAKN,UAAA,GAAa,UAAA;EAJP;EAMN,gBAAA,GAAmB,gBAAA;EAJJ;EAMf,cAAA,GAAiB,cAAA;AAAA;;UAIF,kBAAA,SAA2B,iBAAiB;EAJ3D;EAMA,SAAA,WAAoB,WAAA;AAAA;AANW;AAAA,UAUhB,YAAA;EANmB;EAQlC,KAAA;EAR2D;;;;;EAc3D,EAAA,GAAK,KAAA,UAAe,QAAA,EAAU,mBAAmB;AAAA;;UAIlC,YAAA;EACf,OAAA;EACA,OAAA;EACA,kBAAA,CAAmB,IAAA,EAAM,YAAA,EAAc,OAAA;EAPlC;EASL,OAAA,CAAQ,IAAA,EAAM,IAAA;EATM;;AAA6B;AAInD;EAUE,gBAAA,CAAiB,KAAA,EAAO,IAAA,SAAa,SAAA,EAAW,iBAAA,IAAqB,MAAA,GAAS,IAAA;;EAE9E,aAAA;EAPc;EASd,UAAA;EAJgD;EAMhD,cAAA;EAEgB;EAAhB,SAAA,CAAU,IAAA,EAAM,eAAA;EAEoB;EAApC,eAAA,cAA6B,OAAA;AAAA"}
|
package/dist/ui.d.mts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { DocumentType, LivenessChallenge, ProjectBranding, VerificationDecision, VerificationStatus, WidgetStep } from "@arkyc/types";
|
|
2
|
+
|
|
3
|
+
//#region src/ui.d.ts
|
|
4
|
+
/** The data the address-entry screen collects before submission. */
|
|
5
|
+
interface AddressFormData {
|
|
6
|
+
line1: string | null;
|
|
7
|
+
line2: string | null;
|
|
8
|
+
city: string | null;
|
|
9
|
+
region: string | null;
|
|
10
|
+
postalCode: string | null;
|
|
11
|
+
country: string | null;
|
|
12
|
+
/** Proof-of-address image, when the `poa_document` method is configured. */
|
|
13
|
+
poa: Blob | null;
|
|
14
|
+
/** Whether the user opted to share device location (`device_location` method). */
|
|
15
|
+
useLocation: boolean;
|
|
16
|
+
}
|
|
17
|
+
//#endregion
|
|
18
|
+
export { AddressFormData };
|
|
19
|
+
//# sourceMappingURL=ui.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.d.mts","names":[],"sources":["../src/ui.ts"],"mappings":";;;;UAWiB,eAAA;EACf,KAAA;EACA,KAAA;EACA,IAAA;EACA,MAAA;EACA,UAAA;EACA,OAAA;EAES;EAAT,GAAA,EAAK,IAAI;EANT;EAQA,WAAA;AAAA"}
|