@arkyc/widget 1.0.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 +85 -0
- package/dist/ArkycWidget.d.mts +50 -0
- package/dist/ArkycWidget.d.mts.map +1 -0
- package/dist/ArkycWidget.mjs +80 -0
- package/dist/ArkycWidget.mjs.map +1 -0
- package/dist/WidgetHandler.d.mts +24 -0
- package/dist/WidgetHandler.d.mts.map +1 -0
- package/dist/WidgetHandler.mjs +28 -0
- package/dist/WidgetHandler.mjs.map +1 -0
- package/dist/_virtual/_virtual_arkyc-theme-css.mjs +4 -0
- package/dist/arkyc-widget.iife.global.js +670 -0
- package/dist/arkyc-widget.iife.global.js.map +1 -0
- package/dist/capture.d.mts +73 -0
- package/dist/capture.d.mts.map +1 -0
- package/dist/capture.mjs +126 -0
- package/dist/capture.mjs.map +1 -0
- package/dist/client.d.mts +152 -0
- package/dist/client.d.mts.map +1 -0
- package/dist/client.mjs +120 -0
- package/dist/client.mjs.map +1 -0
- package/dist/controller.d.mts +126 -0
- package/dist/controller.d.mts.map +1 -0
- package/dist/controller.mjs +582 -0
- package/dist/controller.mjs.map +1 -0
- package/dist/countries.mjs +967 -0
- package/dist/countries.mjs.map +1 -0
- package/dist/device.mjs +17 -0
- package/dist/device.mjs.map +1 -0
- package/dist/document.d.mts +108 -0
- package/dist/document.d.mts.map +1 -0
- package/dist/document.mjs +227 -0
- package/dist/document.mjs.map +1 -0
- package/dist/face.d.mts +82 -0
- package/dist/face.d.mts.map +1 -0
- package/dist/face.mjs +230 -0
- package/dist/face.mjs.map +1 -0
- package/dist/flow.d.mts +74 -0
- package/dist/flow.d.mts.map +1 -0
- package/dist/flow.mjs +132 -0
- package/dist/flow.mjs.map +1 -0
- package/dist/index.d.mts +19 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +16 -0
- package/dist/index.mjs.map +1 -0
- package/dist/qr.mjs +22 -0
- package/dist/qr.mjs.map +1 -0
- package/dist/realtime.d.mts +29 -0
- package/dist/realtime.d.mts.map +1 -0
- package/dist/realtime.mjs +107 -0
- package/dist/realtime.mjs.map +1 -0
- package/dist/theme.d.mts +42 -0
- package/dist/theme.d.mts.map +1 -0
- package/dist/theme.mjs +77 -0
- package/dist/theme.mjs.map +1 -0
- package/dist/types.d.mts +153 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/ui.mjs +931 -0
- package/dist/ui.mjs.map +1 -0
- package/package.json +43 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
//#region src/realtime.ts
|
|
2
|
+
/** CDN that serves any npm package as ESM (`…/pkg@ver/+esm`). */
|
|
3
|
+
const CDN = "https://cdn.jsdelivr.net/npm/";
|
|
4
|
+
/**
|
|
5
|
+
* Import an optional transport SDK. Tries the bare package specifier first (a
|
|
6
|
+
* bundler, import map, or Node resolves it), then falls back to the jsdelivr CDN
|
|
7
|
+
* so a plain browser embed still loads it — a bare specifier like `pusher-js`
|
|
8
|
+
* isn't resolvable at runtime in the browser, which would otherwise leave the
|
|
9
|
+
* widget silently polling. Non-literal specifiers also keep the bundler from
|
|
10
|
+
* trying to resolve these (they aren't hard dependencies) and avoid needing their
|
|
11
|
+
* type declarations.
|
|
12
|
+
*/
|
|
13
|
+
async function loadOptional(pkg, cdnPath) {
|
|
14
|
+
try {
|
|
15
|
+
return await import(
|
|
16
|
+
/* @vite-ignore */
|
|
17
|
+
/* webpackIgnore: true */
|
|
18
|
+
pkg
|
|
19
|
+
);
|
|
20
|
+
} catch {
|
|
21
|
+
return await import(
|
|
22
|
+
/* @vite-ignore */
|
|
23
|
+
/* webpackIgnore: true */
|
|
24
|
+
`${CDN}${cdnPath}`
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Connect to whichever push transport the API reported for this session. Returns
|
|
30
|
+
* null for `polling`/`off`/`memory` (no push — the widget polls instead) and also
|
|
31
|
+
* when the transport SDK can't be loaded (e.g. a plain `<script>` standalone embed
|
|
32
|
+
* with no bundler), so realtime degrades gracefully to polling. The SDK is
|
|
33
|
+
* dynamically imported so only the active transport is ever pulled in.
|
|
34
|
+
*/
|
|
35
|
+
async function createWidgetRealtimeClient(config, options) {
|
|
36
|
+
try {
|
|
37
|
+
if (config.transport === "pusher") return await createPusherClient(config, options);
|
|
38
|
+
if (config.transport === "firebase") return await createFirebaseClient(config);
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
async function createPusherClient(config, options) {
|
|
45
|
+
const Pusher = (await loadOptional("pusher-js", "pusher-js@8/+esm")).default;
|
|
46
|
+
const pusher = new Pusher(String(config.key ?? ""), {
|
|
47
|
+
cluster: String(config.cluster ?? "mt1"),
|
|
48
|
+
forceTLS: Boolean(config.forceTLS ?? false),
|
|
49
|
+
...config.wsHost ? {
|
|
50
|
+
wsHost: String(config.wsHost),
|
|
51
|
+
wsPort: Number(config.wsPort),
|
|
52
|
+
wssPort: Number(config.wssPort ?? config.wsPort),
|
|
53
|
+
enabledTransports: config.enabledTransports ?? ["ws", "wss"]
|
|
54
|
+
} : {},
|
|
55
|
+
channelAuthorization: {
|
|
56
|
+
transport: "ajax",
|
|
57
|
+
endpoint: options.authEndpoint,
|
|
58
|
+
headers: { "X-Client-Token": options.token }
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
return {
|
|
62
|
+
subscribe(channel, handler) {
|
|
63
|
+
const ch = pusher.subscribe(channel);
|
|
64
|
+
const cb = (event, data) => handler(event, data);
|
|
65
|
+
ch.bind_global(cb);
|
|
66
|
+
return () => {
|
|
67
|
+
ch.unbind_global(cb);
|
|
68
|
+
pusher.unsubscribe(channel);
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
disconnect() {
|
|
72
|
+
pusher.disconnect();
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
async function createFirebaseClient(config) {
|
|
77
|
+
const [app, auth, database] = await Promise.all([
|
|
78
|
+
loadOptional("firebase/app", "firebase@11/app/+esm"),
|
|
79
|
+
loadOptional("firebase/auth", "firebase@11/auth/+esm"),
|
|
80
|
+
loadOptional("firebase/database", "firebase@11/database/+esm")
|
|
81
|
+
]);
|
|
82
|
+
const name = "arkyc-widget-realtime";
|
|
83
|
+
const fbApp = app.getApps().some((a) => a.name === name) ? app.getApp(name) : app.initializeApp({
|
|
84
|
+
apiKey: String(config.apiKey ?? ""),
|
|
85
|
+
authDomain: String(config.authDomain ?? ""),
|
|
86
|
+
projectId: String(config.projectId ?? ""),
|
|
87
|
+
databaseURL: String(config.databaseURL ?? "")
|
|
88
|
+
}, name);
|
|
89
|
+
if (config.token) await auth.signInWithCustomToken(auth.getAuth(fbApp), config.token);
|
|
90
|
+
const db = database.getDatabase(fbApp);
|
|
91
|
+
const since = Date.now();
|
|
92
|
+
return {
|
|
93
|
+
subscribe(channel, handler) {
|
|
94
|
+
const q = database.query(database.ref(db, `realtime/${channel}`), database.orderByChild("at"), database.startAt(since));
|
|
95
|
+
const unsubscribe = database.onChildAdded(q, (snap) => {
|
|
96
|
+
const value = snap.val();
|
|
97
|
+
if (value) handler(value.event, value.payload);
|
|
98
|
+
});
|
|
99
|
+
return () => unsubscribe();
|
|
100
|
+
},
|
|
101
|
+
disconnect() {}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//#endregion
|
|
105
|
+
export { createWidgetRealtimeClient };
|
|
106
|
+
|
|
107
|
+
//# sourceMappingURL=realtime.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"realtime.mjs","names":[],"sources":["../src/realtime.ts"],"sourcesContent":["import type { ClientRealtime } from './client'\n\n/** Fires for every event received on a subscribed channel. */\nexport type WidgetRealtimeHandler = (event: string, data: unknown) => void\n\n/** A connected push transport. `subscribe` returns an unsubscribe function. */\nexport interface WidgetRealtimeClient {\n subscribe(channel: string, handler: WidgetRealtimeHandler): () => void\n disconnect(): void\n}\n\n/** A factory that builds a push client from the session's realtime config. */\nexport type WidgetRealtimeFactory = (\n config: ClientRealtime,\n options: WidgetRealtimeOptions,\n) => Promise<WidgetRealtimeClient | null>\n\nexport interface WidgetRealtimeOptions {\n /** The client-token channel-auth endpoint (pusher). */\n authEndpoint: string\n /** The session's client token (sent as `X-Client-Token` to the authorizer). */\n token: string\n}\n\n/** CDN that serves any npm package as ESM (`…/pkg@ver/+esm`). */\nconst CDN = 'https://cdn.jsdelivr.net/npm/'\n\n/**\n * Import an optional transport SDK. Tries the bare package specifier first (a\n * bundler, import map, or Node resolves it), then falls back to the jsdelivr CDN\n * so a plain browser embed still loads it — a bare specifier like `pusher-js`\n * isn't resolvable at runtime in the browser, which would otherwise leave the\n * widget silently polling. Non-literal specifiers also keep the bundler from\n * trying to resolve these (they aren't hard dependencies) and avoid needing their\n * type declarations.\n */\nasync function loadOptional(pkg: string, cdnPath: string): Promise<unknown> {\n try {\n return await import(/* @vite-ignore */ /* webpackIgnore: true */ pkg)\n } catch {\n return await import(/* @vite-ignore */ /* webpackIgnore: true */ `${CDN}${cdnPath}`)\n }\n}\n\n/**\n * Connect to whichever push transport the API reported for this session. Returns\n * null for `polling`/`off`/`memory` (no push — the widget polls instead) and also\n * when the transport SDK can't be loaded (e.g. a plain `<script>` standalone embed\n * with no bundler), so realtime degrades gracefully to polling. The SDK is\n * dynamically imported so only the active transport is ever pulled in.\n */\nexport async function createWidgetRealtimeClient(\n config: ClientRealtime,\n options: WidgetRealtimeOptions,\n): Promise<WidgetRealtimeClient | null> {\n try {\n if (config.transport === 'pusher') return await createPusherClient(config, options)\n if (config.transport === 'firebase') return await createFirebaseClient(config)\n } catch {\n // Transport SDK unavailable / failed to connect — fall back to polling.\n return null\n }\n\n return null\n}\n\n// --- pusher-js (minimal surface we depend on) ---\n\ninterface PusherChannel {\n bind_global(cb: (event: string, data: unknown) => void): void\n unbind_global(cb: (event: string, data: unknown) => void): void\n}\ninterface PusherInstance {\n subscribe(channel: string): PusherChannel\n unsubscribe(channel: string): void\n disconnect(): void\n}\ntype PusherCtor = new (key: string, options: Record<string, unknown>) => PusherInstance\n\nasync function createPusherClient(\n config: ClientRealtime,\n options: WidgetRealtimeOptions,\n): Promise<WidgetRealtimeClient> {\n const mod = (await loadOptional('pusher-js', 'pusher-js@8/+esm')) as { default: PusherCtor }\n const Pusher = mod.default\n const pusher = new Pusher(String(config.key ?? ''), {\n cluster: String(config.cluster ?? 'mt1'),\n forceTLS: Boolean(config.forceTLS ?? false),\n ...(config.wsHost\n ? {\n wsHost: String(config.wsHost),\n wsPort: Number(config.wsPort),\n wssPort: Number(config.wssPort ?? config.wsPort),\n enabledTransports: (config.enabledTransports as string[]) ?? ['ws', 'wss'],\n }\n : {}),\n // The widget authorizes private channels with its short-lived client token,\n // which the API scopes to this session's own channel only.\n channelAuthorization: {\n transport: 'ajax',\n endpoint: options.authEndpoint,\n headers: { 'X-Client-Token': options.token },\n },\n })\n\n return {\n subscribe(channel, handler) {\n const ch = pusher.subscribe(channel)\n const cb = (event: string, data: unknown) => handler(event, data)\n ch.bind_global(cb)\n\n return () => {\n ch.unbind_global(cb)\n pusher.unsubscribe(channel)\n }\n },\n disconnect() {\n pusher.disconnect()\n },\n }\n}\n\n// --- firebase (minimal surface we depend on) ---\n\ninterface FirebaseApp {\n name: string\n}\ninterface FirebaseAppModule {\n initializeApp(options: Record<string, unknown>, name: string): FirebaseApp\n getApps(): FirebaseApp[]\n getApp(name: string): FirebaseApp\n}\ninterface FirebaseAuthModule {\n getAuth(app: FirebaseApp): unknown\n signInWithCustomToken(auth: unknown, token: string): Promise<unknown>\n}\ninterface FirebaseSnapshot {\n val(): { event: string; payload: unknown } | null\n}\ninterface FirebaseDatabaseModule {\n getDatabase(app: FirebaseApp): unknown\n ref(db: unknown, path: string): unknown\n query(ref: unknown, ...constraints: unknown[]): unknown\n orderByChild(path: string): unknown\n startAt(value: number): unknown\n onChildAdded(query: unknown, cb: (snap: FirebaseSnapshot) => void): () => void\n}\n\nasync function createFirebaseClient(config: ClientRealtime): Promise<WidgetRealtimeClient> {\n const [app, auth, database] = (await Promise.all([\n loadOptional('firebase/app', 'firebase@11/app/+esm'),\n loadOptional('firebase/auth', 'firebase@11/auth/+esm'),\n loadOptional('firebase/database', 'firebase@11/database/+esm'),\n ])) as [FirebaseAppModule, FirebaseAuthModule, FirebaseDatabaseModule]\n\n const name = 'arkyc-widget-realtime'\n const fbApp = app.getApps().some((a) => a.name === name)\n ? app.getApp(name)\n : app.initializeApp(\n {\n apiKey: String(config.apiKey ?? ''),\n authDomain: String(config.authDomain ?? ''),\n projectId: String(config.projectId ?? ''),\n databaseURL: String(config.databaseURL ?? ''),\n },\n name,\n )\n\n // The per-session custom token authorizes reads of this session's channel only.\n if (config.token) await auth.signInWithCustomToken(auth.getAuth(fbApp), config.token)\n\n const db = database.getDatabase(fbApp)\n const since = Date.now()\n\n return {\n subscribe(channel, handler) {\n const q = database.query(\n database.ref(db, `realtime/${channel}`),\n database.orderByChild('at'),\n database.startAt(since),\n )\n const unsubscribe = database.onChildAdded(q, (snap) => {\n const value = snap.val()\n if (value) handler(value.event, value.payload)\n })\n\n return () => unsubscribe()\n },\n disconnect() {\n // Firebase listeners are torn down per-subscription via the returned unsub.\n },\n }\n}\n"],"mappings":";;AAyBA,MAAM,MAAM;;;;;;;;;;AAWZ,eAAe,aAAa,KAAa,SAAmC;CAC1E,IAAI;EACF,OAAO,MAAM;;;GAAoD;;CACnE,QAAQ;EACN,OAAO,MAAM;;;GAAoD,GAAG,MAAM;;CAC5E;AACF;;;;;;;;AASA,eAAsB,2BACpB,QACA,SACsC;CACtC,IAAI;EACF,IAAI,OAAO,cAAc,UAAU,OAAO,MAAM,mBAAmB,QAAQ,OAAO;EAClF,IAAI,OAAO,cAAc,YAAY,OAAO,MAAM,qBAAqB,MAAM;CAC/E,QAAQ;EAEN,OAAO;CACT;CAEA,OAAO;AACT;AAeA,eAAe,mBACb,QACA,SAC+B;CAE/B,MAAM,UAAS,MADI,aAAa,aAAa,kBAAkB,EAAA,CAC5C;CACnB,MAAM,SAAS,IAAI,OAAO,OAAO,OAAO,OAAO,EAAE,GAAG;EAClD,SAAS,OAAO,OAAO,WAAW,KAAK;EACvC,UAAU,QAAQ,OAAO,YAAY,KAAK;EAC1C,GAAI,OAAO,SACP;GACE,QAAQ,OAAO,OAAO,MAAM;GAC5B,QAAQ,OAAO,OAAO,MAAM;GAC5B,SAAS,OAAO,OAAO,WAAW,OAAO,MAAM;GAC/C,mBAAoB,OAAO,qBAAkC,CAAC,MAAM,KAAK;EAC3E,IACA,CAAC;EAGL,sBAAsB;GACpB,WAAW;GACX,UAAU,QAAQ;GAClB,SAAS,EAAE,kBAAkB,QAAQ,MAAM;EAC7C;CACF,CAAC;CAED,OAAO;EACL,UAAU,SAAS,SAAS;GAC1B,MAAM,KAAK,OAAO,UAAU,OAAO;GACnC,MAAM,MAAM,OAAe,SAAkB,QAAQ,OAAO,IAAI;GAChE,GAAG,YAAY,EAAE;GAEjB,aAAa;IACX,GAAG,cAAc,EAAE;IACnB,OAAO,YAAY,OAAO;GAC5B;EACF;EACA,aAAa;GACX,OAAO,WAAW;EACpB;CACF;AACF;AA4BA,eAAe,qBAAqB,QAAuD;CACzF,MAAM,CAAC,KAAK,MAAM,YAAa,MAAM,QAAQ,IAAI;EAC/C,aAAa,gBAAgB,sBAAsB;EACnD,aAAa,iBAAiB,uBAAuB;EACrD,aAAa,qBAAqB,2BAA2B;CAC/D,CAAC;CAED,MAAM,OAAO;CACb,MAAM,QAAQ,IAAI,QAAQ,CAAC,CAAC,MAAM,MAAM,EAAE,SAAS,IAAI,IACnD,IAAI,OAAO,IAAI,IACf,IAAI,cACF;EACE,QAAQ,OAAO,OAAO,UAAU,EAAE;EAClC,YAAY,OAAO,OAAO,cAAc,EAAE;EAC1C,WAAW,OAAO,OAAO,aAAa,EAAE;EACxC,aAAa,OAAO,OAAO,eAAe,EAAE;CAC9C,GACA,IACF;CAGJ,IAAI,OAAO,OAAO,MAAM,KAAK,sBAAsB,KAAK,QAAQ,KAAK,GAAG,OAAO,KAAK;CAEpF,MAAM,KAAK,SAAS,YAAY,KAAK;CACrC,MAAM,QAAQ,KAAK,IAAI;CAEvB,OAAO;EACL,UAAU,SAAS,SAAS;GAC1B,MAAM,IAAI,SAAS,MACjB,SAAS,IAAI,IAAI,YAAY,SAAS,GACtC,SAAS,aAAa,IAAI,GAC1B,SAAS,QAAQ,KAAK,CACxB;GACA,MAAM,cAAc,SAAS,aAAa,IAAI,SAAS;IACrD,MAAM,QAAQ,KAAK,IAAI;IACvB,IAAI,OAAO,QAAQ,MAAM,OAAO,MAAM,OAAO;GAC/C,CAAC;GAED,aAAa,YAAY;EAC3B;EACA,aAAa,CAEb;CACF;AACF"}
|
package/dist/theme.d.mts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ProjectBranding } from "@arkyc/types";
|
|
2
|
+
|
|
3
|
+
//#region src/theme.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Resolves project branding into a concrete theme and renders its CSS. One class
|
|
6
|
+
* owns the whole "theme" concern: defaulted colour/logo/radius values plus the
|
|
7
|
+
* CSS-variable block and stylesheet derived from them.
|
|
8
|
+
*/
|
|
9
|
+
declare class Theme {
|
|
10
|
+
readonly primaryColor: string;
|
|
11
|
+
readonly borderRadius: number;
|
|
12
|
+
readonly mode: 'light' | 'dark';
|
|
13
|
+
readonly logoUrl: string | null;
|
|
14
|
+
/** Project/company display name shown in the header (when branding is shown). */
|
|
15
|
+
readonly name: string | null;
|
|
16
|
+
/** Whether to show the project name/logo in the header (white-label off → false). */
|
|
17
|
+
readonly showBranding: boolean;
|
|
18
|
+
/** Surface (card) background. */
|
|
19
|
+
readonly background: string;
|
|
20
|
+
/** Primary text colour. */
|
|
21
|
+
readonly foreground: string;
|
|
22
|
+
/** Muted text colour. */
|
|
23
|
+
readonly muted: string;
|
|
24
|
+
/** Subtle border colour. */
|
|
25
|
+
readonly border: string;
|
|
26
|
+
constructor(branding?: ProjectBranding | null);
|
|
27
|
+
/**
|
|
28
|
+
* The CSS-variable declaration block for this theme.
|
|
29
|
+
*
|
|
30
|
+
* @returns
|
|
31
|
+
*/
|
|
32
|
+
variables(): string;
|
|
33
|
+
/**
|
|
34
|
+
* The widget stylesheet, parameterised by this theme's variables.
|
|
35
|
+
*
|
|
36
|
+
* @returns
|
|
37
|
+
*/
|
|
38
|
+
stylesheet(): string;
|
|
39
|
+
}
|
|
40
|
+
//#endregion
|
|
41
|
+
export { Theme };
|
|
42
|
+
//# sourceMappingURL=theme.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.mts","names":[],"sources":["../src/theme.ts"],"mappings":";;;;;AAsBA;;;cAAa,KAAA;EAAA,SACF,YAAA;EAAA,SACA,YAAA;EAAA,SACA,IAAA;EAAA,SACA,OAAA;EAEA;EAAA,SAAA,IAAA;EAIA;EAAA,SAFA,YAAA;EAMA;EAAA,SAJA,UAAA;;WAEA,UAAA;EAMG;EAAA,SAJH,KAAA;EAuCT;EAAA,SArCS,MAAA;cAEG,QAAA,GAAW,eAAe;;;;;;EAmBtC,SAAA;;;;;;EAgBA,UAAA;AAAA"}
|
package/dist/theme.mjs
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import _virtual_arkyc_theme_css_default from "./_virtual/_virtual_arkyc-theme-css.mjs";
|
|
2
|
+
//#region src/theme.ts
|
|
3
|
+
const LIGHT = {
|
|
4
|
+
background: "#ffffff",
|
|
5
|
+
foreground: "#0f172a",
|
|
6
|
+
muted: "#64748b",
|
|
7
|
+
border: "#e2e8f0"
|
|
8
|
+
};
|
|
9
|
+
const DARK = {
|
|
10
|
+
background: "#0f172a",
|
|
11
|
+
foreground: "#f8fafc",
|
|
12
|
+
muted: "#94a3b8",
|
|
13
|
+
border: "#1e293b"
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Resolves project branding into a concrete theme and renders its CSS. One class
|
|
17
|
+
* owns the whole "theme" concern: defaulted colour/logo/radius values plus the
|
|
18
|
+
* CSS-variable block and stylesheet derived from them.
|
|
19
|
+
*/
|
|
20
|
+
var Theme = class {
|
|
21
|
+
primaryColor;
|
|
22
|
+
borderRadius;
|
|
23
|
+
mode;
|
|
24
|
+
logoUrl;
|
|
25
|
+
/** Project/company display name shown in the header (when branding is shown). */
|
|
26
|
+
name;
|
|
27
|
+
/** Whether to show the project name/logo in the header (white-label off → false). */
|
|
28
|
+
showBranding;
|
|
29
|
+
/** Surface (card) background. */
|
|
30
|
+
background;
|
|
31
|
+
/** Primary text colour. */
|
|
32
|
+
foreground;
|
|
33
|
+
/** Muted text colour. */
|
|
34
|
+
muted;
|
|
35
|
+
/** Subtle border colour. */
|
|
36
|
+
border;
|
|
37
|
+
constructor(branding) {
|
|
38
|
+
this.mode = branding?.theme === "dark" ? "dark" : "light";
|
|
39
|
+
const palette = this.mode === "dark" ? DARK : LIGHT;
|
|
40
|
+
this.primaryColor = branding?.primary_color ?? "#b8860b";
|
|
41
|
+
this.borderRadius = branding?.border_radius ?? 12;
|
|
42
|
+
this.logoUrl = branding?.logo_url ?? null;
|
|
43
|
+
this.name = branding?.name ?? null;
|
|
44
|
+
this.showBranding = branding?.show_branding !== false;
|
|
45
|
+
this.background = palette.background;
|
|
46
|
+
this.foreground = palette.foreground;
|
|
47
|
+
this.muted = palette.muted;
|
|
48
|
+
this.border = palette.border;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The CSS-variable declaration block for this theme.
|
|
52
|
+
*
|
|
53
|
+
* @returns
|
|
54
|
+
*/
|
|
55
|
+
variables() {
|
|
56
|
+
return [
|
|
57
|
+
`--arkyc-primary:${this.primaryColor}`,
|
|
58
|
+
`--arkyc-radius:${this.borderRadius}px`,
|
|
59
|
+
`--arkyc-bg:${this.background}`,
|
|
60
|
+
`--arkyc-fg:${this.foreground}`,
|
|
61
|
+
`--arkyc-muted:${this.muted}`,
|
|
62
|
+
`--arkyc-border:${this.border}`
|
|
63
|
+
].join(";");
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The widget stylesheet, parameterised by this theme's variables.
|
|
67
|
+
*
|
|
68
|
+
* @returns
|
|
69
|
+
*/
|
|
70
|
+
stylesheet() {
|
|
71
|
+
return _virtual_arkyc_theme_css_default.replace("/* {variables} */", `${this.variables()};`).trim();
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
//#endregion
|
|
75
|
+
export { Theme };
|
|
76
|
+
|
|
77
|
+
//# sourceMappingURL=theme.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.mjs","names":["themeCss"],"sources":["../src/theme.ts"],"sourcesContent":["import type { ProjectBranding } from '@arkyc/types'\nimport themeCss from 'virtual:arkyc-theme-css'\n\nconst LIGHT = {\n background: '#ffffff',\n foreground: '#0f172a',\n muted: '#64748b',\n border: '#e2e8f0',\n}\n\nconst DARK = {\n background: '#0f172a',\n foreground: '#f8fafc',\n muted: '#94a3b8',\n border: '#1e293b',\n}\n\n/**\n * Resolves project branding into a concrete theme and renders its CSS. One class\n * owns the whole \"theme\" concern: defaulted colour/logo/radius values plus the\n * CSS-variable block and stylesheet derived from them.\n */\nexport class Theme {\n readonly primaryColor: string\n readonly borderRadius: number\n readonly mode: 'light' | 'dark'\n readonly logoUrl: string | null\n /** Project/company display name shown in the header (when branding is shown). */\n readonly name: string | null\n /** Whether to show the project name/logo in the header (white-label off → false). */\n readonly showBranding: boolean\n /** Surface (card) background. */\n readonly background: string\n /** Primary text colour. */\n readonly foreground: string\n /** Muted text colour. */\n readonly muted: string\n /** Subtle border colour. */\n readonly border: string\n\n constructor(branding?: ProjectBranding | null) {\n this.mode = branding?.theme === 'dark' ? 'dark' : 'light'\n const palette = this.mode === 'dark' ? DARK : LIGHT\n this.primaryColor = branding?.primary_color ?? '#b8860b'\n this.borderRadius = branding?.border_radius ?? 12\n this.logoUrl = branding?.logo_url ?? null\n this.name = branding?.name ?? null\n this.showBranding = branding?.show_branding !== false\n this.background = palette.background\n this.foreground = palette.foreground\n this.muted = palette.muted\n this.border = palette.border\n }\n\n /**\n * The CSS-variable declaration block for this theme.\n *\n * @returns\n */\n variables(): string {\n return [\n `--arkyc-primary:${this.primaryColor}`,\n `--arkyc-radius:${this.borderRadius}px`,\n `--arkyc-bg:${this.background}`,\n `--arkyc-fg:${this.foreground}`,\n `--arkyc-muted:${this.muted}`,\n `--arkyc-border:${this.border}`,\n ].join(';')\n }\n\n /**\n * The widget stylesheet, parameterised by this theme's variables.\n *\n * @returns\n */\n stylesheet(): string {\n return themeCss.replace('/* {variables} */', `${this.variables()};`).trim()\n }\n}\n"],"mappings":";;AAGA,MAAM,QAAQ;CACZ,YAAY;CACZ,YAAY;CACZ,OAAO;CACP,QAAQ;AACV;AAEA,MAAM,OAAO;CACX,YAAY;CACZ,YAAY;CACZ,OAAO;CACP,QAAQ;AACV;;;;;;AAOA,IAAa,QAAb,MAAmB;CACjB;CACA;CACA;CACA;;CAEA;;CAEA;;CAEA;;CAEA;;CAEA;;CAEA;CAEA,YAAY,UAAmC;EAC7C,KAAK,OAAO,UAAU,UAAU,SAAS,SAAS;EAClD,MAAM,UAAU,KAAK,SAAS,SAAS,OAAO;EAC9C,KAAK,eAAe,UAAU,iBAAiB;EAC/C,KAAK,eAAe,UAAU,iBAAiB;EAC/C,KAAK,UAAU,UAAU,YAAY;EACrC,KAAK,OAAO,UAAU,QAAQ;EAC9B,KAAK,eAAe,UAAU,kBAAkB;EAChD,KAAK,aAAa,QAAQ;EAC1B,KAAK,aAAa,QAAQ;EAC1B,KAAK,QAAQ,QAAQ;EACrB,KAAK,SAAS,QAAQ;CACxB;;;;;;CAOA,YAAoB;EAClB,OAAO;GACL,mBAAmB,KAAK;GACxB,kBAAkB,KAAK,aAAa;GACpC,cAAc,KAAK;GACnB,cAAc,KAAK;GACnB,iBAAiB,KAAK;GACtB,kBAAkB,KAAK;EACzB,CAAC,CAAC,KAAK,GAAG;CACZ;;;;;;CAOA,aAAqB;EACnB,OAAOA,iCAAS,QAAQ,qBAAqB,GAAG,KAAK,UAAU,EAAE,EAAE,CAAC,CAAC,KAAK;CAC5E;AACF"}
|
package/dist/types.d.mts
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { DocumentAnalyzer, DocumentTuning } from "./document.mjs";
|
|
2
|
+
import { FaceAnalyzer, FaceTuning } from "./face.mjs";
|
|
3
|
+
import { ProviderSignalHints } from "./client.mjs";
|
|
4
|
+
import { WidgetRealtimeFactory } from "./realtime.mjs";
|
|
5
|
+
import { ProjectBranding, WidgetResult } from "@arkyc/types";
|
|
6
|
+
|
|
7
|
+
//#region src/types.d.ts
|
|
8
|
+
/**
|
|
9
|
+
* An event surfaced to consumers through `onEvent` / `handle.on(name, cb)`. The
|
|
10
|
+
* stream is a firehose: `session.transition` (live status changes, from the
|
|
11
|
+
* configured transport) plus the lifecycle events `complete` / `error` / `close`.
|
|
12
|
+
*/
|
|
13
|
+
interface WidgetEvent {
|
|
14
|
+
/** Event name, e.g. `session.transition`, `complete`, `error`, `close`. */
|
|
15
|
+
name: string;
|
|
16
|
+
/** Event payload (shape depends on `name`). */
|
|
17
|
+
data?: unknown;
|
|
18
|
+
}
|
|
19
|
+
/** Subscribe to a named widget event; returns an unsubscribe function. */
|
|
20
|
+
type WidgetEventListener = (data: unknown) => void;
|
|
21
|
+
/** Configuration for a {@link WidgetController}. */
|
|
22
|
+
interface WidgetControllerConfig {
|
|
23
|
+
/** Short-lived client token for this session. */
|
|
24
|
+
token: string;
|
|
25
|
+
/** API origin (defaults to the widget's own origin). */
|
|
26
|
+
baseUrl?: string;
|
|
27
|
+
/** Disable cross-device handoff entirely (set on the hosted page to avoid recursion). */
|
|
28
|
+
handoff?: boolean;
|
|
29
|
+
/** Override the server-provided handoff page URL. */
|
|
30
|
+
handoffUrl?: string;
|
|
31
|
+
branding?: ProjectBranding | null;
|
|
32
|
+
/**
|
|
33
|
+
* Mock-driver signal hints. When present, capture screens also offer a
|
|
34
|
+
* "Skip" affordance (the `mock` drivers can decide without a real image).
|
|
35
|
+
*/
|
|
36
|
+
signals?: ProviderSignalHints;
|
|
37
|
+
onComplete?: (result: WidgetResult) => void;
|
|
38
|
+
onError?: (error: Error) => void;
|
|
39
|
+
onClose?: () => void;
|
|
40
|
+
/**
|
|
41
|
+
* Firehose for every widget event (`session.transition`, `complete`, `error`,
|
|
42
|
+
* `close`). Nothing is emitted unless this or a `handle.on(...)` listener is
|
|
43
|
+
* active. The same stream is filterable per-name via {@link WidgetHandle.on}.
|
|
44
|
+
*/
|
|
45
|
+
onEvent?: (event: WidgetEvent) => void;
|
|
46
|
+
/** Fired once the flow settles (complete/error/close); used to remove the host. */
|
|
47
|
+
onSettle?: () => void;
|
|
48
|
+
/** Force (or disable) posting `arkyc:*` messages to `window.parent`. */
|
|
49
|
+
postToParent?: boolean;
|
|
50
|
+
fetch?: typeof fetch;
|
|
51
|
+
doc?: Document;
|
|
52
|
+
win?: Window;
|
|
53
|
+
nav?: Navigator;
|
|
54
|
+
/**
|
|
55
|
+
* Face analyzer powering selfie auto-capture + active-liveness detection.
|
|
56
|
+
* Defaults to the real MediaPipe-backed analyzer (loaded lazily from a CDN);
|
|
57
|
+
* pass `null` to disable detection and use the manual capture flow.
|
|
58
|
+
*/
|
|
59
|
+
faceAnalyzer?: FaceAnalyzer | null;
|
|
60
|
+
/** Override face-detection thresholds (tune against a real camera). */
|
|
61
|
+
faceTuning?: FaceTuning;
|
|
62
|
+
/**
|
|
63
|
+
* Document analyzer powering document auto-capture (real edge-projection
|
|
64
|
+
* detection). Defaults to the built-in canvas detector; pass `null` to disable
|
|
65
|
+
* it and fall back to the brightness/glare heuristic.
|
|
66
|
+
*/
|
|
67
|
+
documentAnalyzer?: DocumentAnalyzer | null;
|
|
68
|
+
/** Override document-detection thresholds (tune against a real camera). */
|
|
69
|
+
documentTuning?: DocumentTuning;
|
|
70
|
+
/**
|
|
71
|
+
* Builds the realtime push client from the session's realtime config. Defaults
|
|
72
|
+
* to the bundled pusher/firebase factory; injectable for tests.
|
|
73
|
+
*/
|
|
74
|
+
realtimeFactory?: WidgetRealtimeFactory;
|
|
75
|
+
/** Schedules a callback after `ms` (defaults to `setTimeout`). */
|
|
76
|
+
scheduler?: (fn: () => void, ms: number) => void;
|
|
77
|
+
/** Cosmetic OCR-processing screen duration (ms). */
|
|
78
|
+
transientMs?: number;
|
|
79
|
+
/** Delay between session polls while finalising (ms). */
|
|
80
|
+
pollMs?: number;
|
|
81
|
+
/** Maximum number of polls before giving up and showing the last status. */
|
|
82
|
+
maxPolls?: number;
|
|
83
|
+
/** Maximum number of polls while waiting on a handed-off device (bounded by session TTL). */
|
|
84
|
+
maxHandoffPolls?: number;
|
|
85
|
+
}
|
|
86
|
+
/** Common options shared by every launch mode. */
|
|
87
|
+
interface BaseWidgetOptions {
|
|
88
|
+
/** Short-lived client token minted by the integrator's backend. */
|
|
89
|
+
token: string;
|
|
90
|
+
/** API origin (defaults to the page's own origin). */
|
|
91
|
+
baseUrl?: string;
|
|
92
|
+
/**
|
|
93
|
+
* Cross-device handoff (desktop → phone via QR) is on by default and uses a
|
|
94
|
+
* first-party hosted page the API points to — integrators host nothing. Set
|
|
95
|
+
* `false` to disable it (the hosted page itself does, to avoid recursion).
|
|
96
|
+
*/
|
|
97
|
+
handoff?: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Override the hosted handoff page URL. By default the widget uses the URL the
|
|
100
|
+
* API returns (the dashboard's `/verify` page); only set this for custom hosting.
|
|
101
|
+
*/
|
|
102
|
+
handoffUrl?: string;
|
|
103
|
+
/** Branding (colors, logo, radius, theme, name). Usually sourced from project config. */
|
|
104
|
+
branding?: ProjectBranding | null;
|
|
105
|
+
/**
|
|
106
|
+
* Open the widget edge-to-edge (no surrounding padding/backdrop gap, no card
|
|
107
|
+
* max-size or border radius). Applies to {@link ArkycWidget.open} only.
|
|
108
|
+
*/
|
|
109
|
+
fullscreen?: boolean;
|
|
110
|
+
/** Mock-driver signal hints; enables a "Skip" affordance on capture screens. */
|
|
111
|
+
signals?: ProviderSignalHints;
|
|
112
|
+
onComplete?: (result: WidgetResult) => void;
|
|
113
|
+
onError?: (error: Error) => void;
|
|
114
|
+
onClose?: () => void;
|
|
115
|
+
/**
|
|
116
|
+
* Firehose for live session events (`session.transition`) and lifecycle events
|
|
117
|
+
* (`complete` / `error` / `close`). Whether updates arrive via pusher, firebase
|
|
118
|
+
* or polling is decided by the platform's configured transport — the widget
|
|
119
|
+
* handles it. Nothing is emitted unless this (or a `handle.on(...)`) is active.
|
|
120
|
+
*/
|
|
121
|
+
onEvent?: (event: WidgetEvent) => void;
|
|
122
|
+
fetch?: typeof fetch;
|
|
123
|
+
doc?: Document;
|
|
124
|
+
win?: Window;
|
|
125
|
+
nav?: Navigator;
|
|
126
|
+
/** Pass `null` to disable face detection (selfie auto-capture + active liveness). */
|
|
127
|
+
faceAnalyzer?: FaceAnalyzer | null;
|
|
128
|
+
/** Override face-detection thresholds (tune against a real camera). */
|
|
129
|
+
faceTuning?: FaceTuning;
|
|
130
|
+
/** Pass `null` to disable document detection (falls back to the brightness heuristic). */
|
|
131
|
+
documentAnalyzer?: DocumentAnalyzer | null;
|
|
132
|
+
/** Override document-detection thresholds (tune against a real camera). */
|
|
133
|
+
documentTuning?: DocumentTuning;
|
|
134
|
+
}
|
|
135
|
+
/** Options for {@link ArkycWidget.mount} (inline mode). */
|
|
136
|
+
interface MountWidgetOptions extends BaseWidgetOptions {
|
|
137
|
+
/** Element (or selector) to mount the widget into. */
|
|
138
|
+
container: string | HTMLElement;
|
|
139
|
+
}
|
|
140
|
+
/** A handle to an open/mounted widget. */
|
|
141
|
+
interface WidgetHandle {
|
|
142
|
+
/** Close the widget and release the camera (fires `onClose`). */
|
|
143
|
+
close: () => void;
|
|
144
|
+
/**
|
|
145
|
+
* Subscribe to a named widget event (e.g. `session.transition`, `complete`).
|
|
146
|
+
* Returns an unsubscribe function. Registering a listener activates the event
|
|
147
|
+
* stream (events are only delivered while at least one listener is active).
|
|
148
|
+
*/
|
|
149
|
+
on: (event: string, listener: WidgetEventListener) => () => void;
|
|
150
|
+
}
|
|
151
|
+
//#endregion
|
|
152
|
+
export { BaseWidgetOptions, MountWidgetOptions, WidgetControllerConfig, WidgetEvent, WidgetEventListener, WidgetHandle };
|
|
153
|
+
//# sourceMappingURL=types.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../src/types.ts"],"mappings":";;;;;;;;;AAYA;;;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"}
|