@incodetech/core 0.0.0-dev-20260512-e44bacb → 0.0.0-dev-20260512-cffbe28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/{BaseWasmProvider-C2cw9STp.esm.js → BaseWasmProvider-IiHnsP8E.esm.js} +17 -17
  2. package/dist/{WasmUtilProvider-B8VtGgvF.esm.js → WasmUtilProvider-BrEYcdhY.esm.js} +1 -1
  3. package/dist/ae-signature.d.ts +1 -1
  4. package/dist/authentication.esm.js +6 -6
  5. package/dist/{authenticationManager-D0Yv5R02.esm.js → authenticationManager-CKDxnLtG.esm.js} +2 -2
  6. package/dist/{authenticationStateMachine-CFiP6P_V.esm.js → authenticationStateMachine-BNs4VCxh.esm.js} +2 -2
  7. package/dist/consent.d.ts +50 -50
  8. package/dist/cpf-ocr.d.ts +17 -17
  9. package/dist/{deepsightLoader-CFNSfs2N.esm.js → deepsightLoader-BMeAmiNh.esm.js} +2 -2
  10. package/dist/document-capture.d.ts +76 -76
  11. package/dist/document-upload.d.ts +49 -49
  12. package/dist/ekyb.esm.js +3 -3
  13. package/dist/{ekybStateMachine-Cq7M50sN.esm.js → ekybStateMachine-tZ1_L9vE.esm.js} +1 -1
  14. package/dist/electronic-signature.d.ts +1 -1
  15. package/dist/extensibility.d.ts +1 -1
  16. package/dist/extensibility.esm.js +11 -11
  17. package/dist/{faceCaptureSetup-zLRBv0-5.esm.js → faceCaptureSetup-CUzqUwkP.esm.js} +1 -1
  18. package/dist/flow.esm.js +2 -2
  19. package/dist/{flowServices-CLnM71N7.esm.js → flowServices-CLo2qihS.esm.js} +1 -1
  20. package/dist/home.d.ts +10 -10
  21. package/dist/id-ocr.d.ts +55 -55
  22. package/dist/id.d.ts +1 -1
  23. package/dist/id.esm.js +5 -5
  24. package/dist/{idCaptureManager-C4xBRJNt.d.ts → idCaptureManager-DiFBYm7h.d.ts} +43 -1
  25. package/dist/{idCaptureManager-vkJ6QLuk.esm.js → idCaptureManager-ZtfBOR6V.esm.js} +64 -1
  26. package/dist/{idCaptureStateMachine-C94NHeR2.esm.js → idCaptureStateMachine-BuX1-VlB.esm.js} +358 -14
  27. package/dist/identity-reuse.d.ts +40 -40
  28. package/dist/{index-CNrrk1gH.d.ts → index-BRdxM5zm.d.ts} +119 -119
  29. package/dist/index.d.ts +1 -1
  30. package/dist/index.esm.js +4 -4
  31. package/dist/mandatory-consent.d.ts +50 -50
  32. package/dist/qe-signature.d.ts +1 -1
  33. package/dist/{recordingService-BsYjkILQ.esm.js → recordingService-DMaVUhWY.esm.js} +2 -2
  34. package/dist/selfie.esm.js +6 -6
  35. package/dist/{selfieManager-ByCKxpZC.esm.js → selfieManager-DC9hKgt7.esm.js} +2 -2
  36. package/dist/{selfieStateMachine-ecwZ7tWK.esm.js → selfieStateMachine-DvOTE42w.esm.js} +2 -2
  37. package/dist/{session-DWFMKdX6.esm.js → session-DAspZUCj.esm.js} +1 -1
  38. package/dist/session.esm.js +1 -1
  39. package/dist/{setup-D3rE3N3K.d.ts → setup-DM301Lyz.d.ts} +39 -5
  40. package/dist/{setup-h75-vL1d.esm.js → setup-DyspWyTY.esm.js} +326 -169
  41. package/dist/wasm.d.ts +1 -1
  42. package/dist/wasm.esm.js +4 -4
  43. package/dist/workflow.d.ts +84 -84
  44. package/dist/workflow.esm.js +9 -9
  45. package/package.json +3 -3
@@ -1,11 +1,137 @@
1
- import { c as SemaphoreProvider, n as warmupWasm, o as wasmCallWrapper, s as loadWasmModule } from "./BaseWasmProvider-C2cw9STp.esm.js";
2
- import { t as WasmUtilProvider } from "./WasmUtilProvider-B8VtGgvF.esm.js";
1
+ import { c as SemaphoreProvider, i as wasmCallWrapper, n as warmupWasm, s as loadWasmModule } from "./BaseWasmProvider-IiHnsP8E.esm.js";
2
+ import { t as WasmUtilProvider } from "./WasmUtilProvider-BrEYcdhY.esm.js";
3
3
  import { t as BrowserTimerProvider } from "./BrowserTimerProvider-BZGH3sYJ.esm.js";
4
4
  import { a as resetApi, i as isApiConfigured, n as getApi, o as setClient, r as getToken, s as setToken, t as api } from "./api-eqRXuVG-.esm.js";
5
5
  import { _ as resetAnalyticsBatcher, g as getAnalyticsBatcher, m as createAnalyticsBatchingService, v as setAnalyticsBatcher } from "./events-Bt1azl2B.esm.js";
6
6
  import { t as endpoints } from "./endpoints-B3V1U9Dg.esm.js";
7
- import { i as resetSessionInit, r as initializeSession } from "./session-DWFMKdX6.esm.js";
7
+ import { i as resetSessionInit, r as initializeSession } from "./session-DAspZUCj.esm.js";
8
8
 
9
+ //#region ../infra/src/wasm/wasmDefaults.ts
10
+ const WASM_CDN_BASE_URL = "https://cdn.incodesmile.com/ml-wasm-kit-release";
11
+ /** The WASM version bundled and tested with this SDK release. */
12
+ const DEFAULT_WASM_VERSION = "v2.13.14";
13
+ const PATH_KEYS = [
14
+ "wasmPath",
15
+ "wasmSimdPath",
16
+ "glueCodePath",
17
+ "modelsBasePath"
18
+ ];
19
+ function isBlank(value) {
20
+ return value.trim() === "";
21
+ }
22
+ function hasDisallowedControlChars(value) {
23
+ for (let i = 0; i < value.length; i += 1) {
24
+ const code = value.charCodeAt(i);
25
+ if (code < 32 || code === 127) return true;
26
+ }
27
+ return false;
28
+ }
29
+ function isMalformedPath(value) {
30
+ const trimmed = value.trim();
31
+ if (trimmed === "") return false;
32
+ if (hasDisallowedControlChars(trimmed)) return true;
33
+ if (/^https?:\/\//i.test(trimmed)) try {
34
+ new URL(trimmed);
35
+ return false;
36
+ } catch {
37
+ return true;
38
+ }
39
+ return false;
40
+ }
41
+ function warnInvalidWasmPath(field, reason) {
42
+ if (reason === "empty") {
43
+ console.warn(`[Incode SDK] wasm.${field} is empty. Falling back to CDN default.`);
44
+ return;
45
+ }
46
+ console.warn(`[Incode SDK] wasm.${field} appears malformed. Falling back to CDN default.`);
47
+ }
48
+ function warnMalformedWasmPath(field) {
49
+ console.warn(`[Incode SDK] wasm.${field} appears malformed. Check the URL or path.`);
50
+ }
51
+ /**
52
+ * Validates merged WASM path strings. When overrides contained blank path
53
+ * values, callers should have already fallen back to defaults before this runs.
54
+ */
55
+ function validateWasmPaths(config) {
56
+ for (const key of PATH_KEYS) {
57
+ const value = config[key];
58
+ if (typeof value === "string" && isMalformedPath(value)) warnMalformedWasmPath(key);
59
+ }
60
+ }
61
+ function pickPath(key, overrides, defaultValue) {
62
+ if (!overrides || !(key in overrides)) return defaultValue;
63
+ const raw = overrides[key];
64
+ if (raw === void 0) return defaultValue;
65
+ if (typeof raw !== "string") return defaultValue;
66
+ if (isBlank(raw)) {
67
+ warnInvalidWasmPath(key, "empty");
68
+ return defaultValue;
69
+ }
70
+ if (isMalformedPath(raw)) {
71
+ warnInvalidWasmPath(key, "malformed");
72
+ return defaultValue;
73
+ }
74
+ return raw.trim();
75
+ }
76
+ /** Builds the standard WarmupConfig from the Incode CDN. */
77
+ function buildDefaultWasmConfig() {
78
+ const base = `${WASM_CDN_BASE_URL}/${DEFAULT_WASM_VERSION}`;
79
+ return {
80
+ wasmPath: `${base}/webLib.wasm`,
81
+ wasmSimdPath: `${base}/webLibSimd.wasm`,
82
+ glueCodePath: `${base}/webLib.js`,
83
+ modelsBasePath: `${base}/models`
84
+ };
85
+ }
86
+ /**
87
+ * Merges optional WASM path overrides with CDN defaults. Explicit non-blank
88
+ * paths take precedence. Blank override strings log a warning and fall back to defaults.
89
+ */
90
+ function resolveWasmConfig(overrides) {
91
+ const defaults = buildDefaultWasmConfig();
92
+ if (!overrides) return defaults;
93
+ const simdDefault = defaults.wasmSimdPath ?? defaults.wasmPath;
94
+ const modelsDefault = defaults.modelsBasePath ?? (() => {
95
+ const lastSlash = defaults.wasmPath.lastIndexOf("/");
96
+ return lastSlash === -1 ? "models" : `${defaults.wasmPath.substring(0, lastSlash)}/models`;
97
+ })();
98
+ const merged = {
99
+ wasmPath: pickPath("wasmPath", overrides, defaults.wasmPath),
100
+ wasmSimdPath: pickPath("wasmSimdPath", overrides, simdDefault),
101
+ glueCodePath: pickPath("glueCodePath", overrides, defaults.glueCodePath),
102
+ modelsBasePath: pickPath("modelsBasePath", overrides, modelsDefault),
103
+ useSimd: overrides.useSimd,
104
+ pipelines: overrides.pipelines,
105
+ pipelineModels: overrides.pipelineModels
106
+ };
107
+ validateWasmPaths(merged);
108
+ return merged;
109
+ }
110
+
111
+ //#endregion
112
+ //#region ../infra/src/providers/browser/BrowserPageLifecycleProvider.ts
113
+ var BrowserPageLifecycleProvider = class {
114
+ sendBeacon(url, body, contentType = "application/json") {
115
+ if (typeof navigator === "undefined" || typeof navigator.sendBeacon !== "function") return false;
116
+ const blob = new Blob([body], { type: contentType });
117
+ return navigator.sendBeacon(url, blob);
118
+ }
119
+ onPageHide(listener) {
120
+ const onVisibilityChange = () => {
121
+ if (document.visibilityState === "hidden") listener();
122
+ };
123
+ document.addEventListener("visibilitychange", onVisibilityChange);
124
+ window.addEventListener("pagehide", listener);
125
+ window.addEventListener("beforeunload", listener);
126
+ return () => {
127
+ document.removeEventListener("visibilitychange", onVisibilityChange);
128
+ window.removeEventListener("pagehide", listener);
129
+ window.removeEventListener("beforeunload", listener);
130
+ };
131
+ }
132
+ };
133
+
134
+ //#endregion
9
135
  //#region ../infra/src/http/createApi.ts
10
136
  var FetchHttpError = class extends Error {
11
137
  constructor(status, statusText, url, method, headers, data) {
@@ -244,9 +370,12 @@ var createApi_default = createApi;
244
370
  * busy-poll via {@link wasmCallWrapper}.
245
371
  * - Result extraction (`getRequestResult`) is per-thread.
246
372
  *
247
- * Encryption is wired through the `encryptionEnabled` flag but defaults to
248
- * `false`. End-to-end encryption (Phase 2) will re-call `setupConnection` with
249
- * a real token + `encryptionEnabled = true`; that helper is a follow-up.
373
+ * Encryption support: `setupConnection` accepts an `encryptionEnabled` flag
374
+ * that triggers the in-binary RSA/AES handshake (always using SHA-256 OAEP).
375
+ * {@link enableWasmEncryption} is a stateless helper that re-runs the
376
+ * handshake with the caller-supplied connection params. State lives in the
377
+ * C++ binary and (for SDK config) in `@incodetech/core`'s `setup.ts` — this
378
+ * module caches nothing.
250
379
  */
251
380
  const HTTP_CONCURRENCY = 4;
252
381
  var WasmWebClientError = class extends Error {
@@ -304,12 +433,30 @@ async function initializeWasmWebClient(wasmPath, wasmSimdPath, glueCodePath, use
304
433
  /**
305
434
  * Configures the C++ WebClient connection. Safe to call multiple times — each
306
435
  * call resets the underlying session and re-applies default headers.
436
+ *
437
+ * `defaultHeaders` are applied **before** `createApi`, so the in-binary RSA
438
+ * handshake (`GET /e2ee/key/v2` + `POST /e2ee/key`) sees the same headers as
439
+ * data requests. Without this ordering, environments that require auth/version
440
+ * headers on the handshake (e.g. `x-api-key`, `api-version`) would 401/4xx
441
+ * before any encrypted traffic ever flowed.
442
+ *
443
+ * OAEP padding is hardcoded to SHA-256 (we always pass `useSha256 = true` into
444
+ * the C++ binary).
307
445
  */
308
- async function setupWasmConnection(apiURL, token, useSha256, encryptionEnabled, defaultHeaders) {
446
+ async function setupWasmConnection(apiURL, token, encryptionEnabled, defaultHeaders) {
309
447
  const api$1 = ensureReady();
310
448
  api$1.resetSessionState?.();
311
- api$1.createApi(apiURL, token, useSha256, encryptionEnabled);
312
449
  api$1.setDefaultHeaders?.(defaultHeaders);
450
+ api$1.createApi(apiURL, token, true, encryptionEnabled);
451
+ }
452
+ /**
453
+ * Re-runs the connection handshake with `encryptionEnabled = true`. Stateless:
454
+ * callers (currently `@incodetech/core`'s `setup()`) own the connection params
455
+ * and supply them on every call. Use this to upgrade an existing non-encrypted
456
+ * WASM connection to encrypted at runtime.
457
+ */
458
+ async function enableWasmEncryption(params) {
459
+ await setupWasmConnection(params.apiURL, params.token ?? "", true, params.defaultHeaders);
313
460
  }
314
461
  /**
315
462
  * Executes a single HTTP request through the WASM WebClient.
@@ -364,6 +511,22 @@ function ensureReady() {
364
511
 
365
512
  //#endregion
366
513
  //#region ../infra/src/http/createWasmApi.ts
514
+ const RSA_OAEP_SHA256_SCHEME = "RSA/NONE/OAEPWITHSHA-256ANDMGF1PADDING";
515
+ /**
516
+ * Builds the base set of HTTP headers that the WASM WebClient sends on every
517
+ * request (including the internal `/e2ee/key/v2` and `/e2ee/key` handshake
518
+ * calls). Exported so callers that drive `setupWasmConnection` /
519
+ * `enableWasmEncryption` directly (e.g. core's runtime encryption upgrade
520
+ * path) can build the same headers without duplicating constants.
521
+ */
522
+ function buildWasmDefaultHeaders(customHeaders) {
523
+ return {
524
+ "Content-Type": "application/json",
525
+ Accept: "application/json",
526
+ "api-version": "1.0",
527
+ ...customHeaders ?? {}
528
+ };
529
+ }
367
530
  var WasmHttpError = class extends Error {
368
531
  constructor(status, statusText, url, method, headers, data) {
369
532
  super(`HTTP ${status} ${statusText}`);
@@ -439,14 +602,10 @@ const withAbortSignal = async (promise, signal, error) => {
439
602
  });
440
603
  };
441
604
  const createWasmApi = async (config) => {
442
- const headers = {
443
- "Content-Type": "application/json",
444
- Accept: "application/json",
445
- "api-version": "1.0",
446
- ...config.customHeaders ?? {}
447
- };
605
+ const headers = buildWasmDefaultHeaders(config.customHeaders);
606
+ const isEncryptionEnabled = config.isEncryptionEnabled ?? (() => false);
448
607
  await initializeWasmWebClient(config.wasm.wasmPath, config.wasm.wasmSimdPath ?? config.wasm.wasmPath, config.wasm.glueCodePath, config.wasm.useSimd ?? true);
449
- await setupWasmConnection(config.apiURL, "", config.useSha256 ?? false, config.encryptionEnabled ?? false, headers);
608
+ await setupWasmConnection(config.apiURL, "", config.encryptionEnabled ?? false, headers);
450
609
  const defaults = {
451
610
  baseURL: config.apiURL,
452
611
  headers
@@ -460,6 +619,7 @@ const createWasmApi = async (config) => {
460
619
  const fullUrl = buildUrl(defaults.baseURL, url, requestParams);
461
620
  const mergedHeaders = {
462
621
  ...defaults.headers,
622
+ ...isEncryptionEnabled() ? { "X-RSA-Encryption-Scheme": RSA_OAEP_SHA256_SCHEME } : {},
463
623
  ...requestHeaders
464
624
  };
465
625
  const requestBody = prepareBody(body);
@@ -537,135 +697,153 @@ const createWasmApi = async (config) => {
537
697
  var createWasmApi_default = createWasmApi;
538
698
 
539
699
  //#endregion
540
- //#region ../infra/src/wasm/wasmDefaults.ts
541
- const WASM_CDN_BASE_URL = "https://cdn.incodesmile.com/ml-wasm-kit-release";
542
- /** The WASM version bundled and tested with this SDK release. */
543
- const DEFAULT_WASM_VERSION = "v2.13.14";
544
- const PATH_KEYS = [
545
- "wasmPath",
546
- "wasmSimdPath",
547
- "glueCodePath",
548
- "modelsBasePath"
549
- ];
550
- function isBlank(value) {
551
- return value.trim() === "";
552
- }
553
- function hasDisallowedControlChars(value) {
554
- for (let i = 0; i < value.length; i += 1) {
555
- const code = value.charCodeAt(i);
556
- if (code < 32 || code === 127) return true;
557
- }
558
- return false;
700
+ //#region src/internal/http/clientLifecycle.ts
701
+ /**
702
+ * HTTP client lifecycle for the SDK.
703
+ *
704
+ * Owns the active `StoredHttpConfig` and the procedures that mutate it:
705
+ *
706
+ * - {@link installFreshHttpClient} — first-time setup, or full reconfigure
707
+ * when a new `apiURL` is provided to `setup()`.
708
+ * - {@link enableEncryptionOnExistingClient} — runtime upgrade from a plain
709
+ * or non-encrypted WASM client to an encrypted WASM client.
710
+ * - {@link upgradeToWasmHttpClient} — lazy XHR→WASM swap used by
711
+ * `<incode-flow>` / `<incode-workflow>` when WASM finishes warming up.
712
+ *
713
+ * Everything that touches the encrypted-transport handshake is wrapped in
714
+ * {@link withHandshakeFailureContext} so callers see a single descriptive
715
+ * error instead of an opaque infra exception.
716
+ *
717
+ * Module-scoped state intentional: there is one HTTP client per SDK
718
+ * instance.
719
+ */
720
+ let storedHttpConfig;
721
+ /** Reads the current HTTP-client config (or `undefined` if none installed). */
722
+ function getStoredHttpConfig() {
723
+ return storedHttpConfig;
559
724
  }
560
- function isMalformedPath(value) {
561
- const trimmed = value.trim();
562
- if (trimmed === "") return false;
563
- if (hasDisallowedControlChars(trimmed)) return true;
564
- if (/^https?:\/\//i.test(trimmed)) try {
565
- new URL(trimmed);
566
- return false;
567
- } catch {
568
- return true;
569
- }
570
- return false;
725
+ /** Whether encryption is currently active on the installed HTTP client. */
726
+ function isHttpEncrypted() {
727
+ return storedHttpConfig?.encryption ?? false;
571
728
  }
572
- function warnInvalidWasmPath(field, reason) {
573
- if (reason === "empty") {
574
- console.warn(`[Incode SDK] wasm.${field} is empty. Falling back to CDN default.`);
575
- return;
576
- }
577
- console.warn(`[Incode SDK] wasm.${field} appears malformed. Falling back to CDN default.`);
729
+ /** Clears all HTTP-client state. Called by `reset()`. */
730
+ function resetHttpClientState() {
731
+ storedHttpConfig = void 0;
578
732
  }
579
- function warnMalformedWasmPath(field) {
580
- console.warn(`[Incode SDK] wasm.${field} appears malformed. Check the URL or path.`);
733
+ /**
734
+ * Builds (or replaces) the HTTP client when `setup()` receives an `apiURL`.
735
+ * Picks `createWasmApi` when `effectiveWasm` is set, otherwise plain
736
+ * `createApi`. Wraps the call in handshake-failure context when encryption
737
+ * is requested.
738
+ */
739
+ async function installFreshHttpClient(apiURL, options, effectiveWasm, wantsEncryption) {
740
+ setClient(effectiveWasm ? await withHandshakeFailureContext(wantsEncryption, () => createWasmApi_default({
741
+ apiURL,
742
+ customHeaders: options.customHeaders,
743
+ timeout: options.timeout,
744
+ wasm: effectiveWasm,
745
+ encryptionEnabled: wantsEncryption,
746
+ isEncryptionEnabled: isHttpEncrypted
747
+ })) : createApi_default({
748
+ apiURL,
749
+ customHeaders: options.customHeaders,
750
+ timeout: options.timeout
751
+ }));
752
+ storedHttpConfig = {
753
+ apiURL,
754
+ customHeaders: options.customHeaders,
755
+ timeout: options.timeout,
756
+ isWasm: Boolean(effectiveWasm),
757
+ encryption: wantsEncryption
758
+ };
581
759
  }
582
760
  /**
583
- * Validates merged WASM path strings. When overrides contained blank path
584
- * values, callers should have already fallen back to defaults before this runs.
761
+ * Upgrades an existing non-encrypted connection to encrypted. Merges new
762
+ * `customHeaders` / `timeout` over the stored ones (new values win). If the
763
+ * existing client was plain fetch/XHR, swaps it for a WASM client; if it
764
+ * was already a non-encrypted WASM client, flips encryption on in place.
765
+ *
766
+ * No-op if no HTTP client was previously installed.
585
767
  */
586
- function validateWasmPaths(config) {
587
- for (const key of PATH_KEYS) {
588
- const value = config[key];
589
- if (typeof value === "string" && isMalformedPath(value)) warnMalformedWasmPath(key);
590
- }
768
+ async function enableEncryptionOnExistingClient(options, effectiveWasm) {
769
+ const stored = storedHttpConfig;
770
+ if (!stored) return;
771
+ const customHeaders = mergeHeaders(stored.customHeaders, options.customHeaders);
772
+ const timeout = options.timeout ?? stored.timeout;
773
+ if (!stored.isWasm) setClient(await withHandshakeFailureContext(true, () => createWasmApi_default({
774
+ apiURL: stored.apiURL,
775
+ customHeaders,
776
+ timeout,
777
+ wasm: effectiveWasm,
778
+ encryptionEnabled: true,
779
+ isEncryptionEnabled: isHttpEncrypted
780
+ })));
781
+ else if (!stored.encryption) await withHandshakeFailureContext(true, () => enableWasmEncryption({
782
+ apiURL: stored.apiURL,
783
+ defaultHeaders: buildWasmDefaultHeaders(customHeaders),
784
+ token: options.token
785
+ }));
786
+ storedHttpConfig = {
787
+ ...stored,
788
+ customHeaders,
789
+ timeout,
790
+ isWasm: true,
791
+ encryption: true
792
+ };
591
793
  }
592
- function pickPath(key, overrides, defaultValue) {
593
- if (!overrides || !(key in overrides)) return defaultValue;
594
- const raw = overrides[key];
595
- if (raw === void 0) return defaultValue;
596
- if (typeof raw !== "string") return defaultValue;
597
- if (isBlank(raw)) {
598
- warnInvalidWasmPath(key, "empty");
599
- return defaultValue;
600
- }
601
- if (isMalformedPath(raw)) {
602
- warnInvalidWasmPath(key, "malformed");
603
- return defaultValue;
604
- }
605
- return raw.trim();
794
+ /**
795
+ * Replaces the active HTTP client with the WASM-backed one. Used internally
796
+ * by lazy-loading UI components (`<incode-flow>`, `<incode-workflow>`) when
797
+ * WASM finishes warming up.
798
+ *
799
+ * No-op when no apiURL was previously configured, or when the active client
800
+ * is already WASM-backed.
801
+ *
802
+ * @internal NOT a public API. Application code should use
803
+ * `setup({ wasm: {...} })` instead.
804
+ */
805
+ async function upgradeToWasmHttpClient(resolved) {
806
+ const stored = storedHttpConfig;
807
+ if (!stored || stored.isWasm) return;
808
+ setClient(await createWasmApi_default({
809
+ apiURL: stored.apiURL,
810
+ customHeaders: stored.customHeaders,
811
+ timeout: stored.timeout,
812
+ wasm: resolved,
813
+ encryptionEnabled: stored.encryption,
814
+ isEncryptionEnabled: isHttpEncrypted
815
+ }));
816
+ storedHttpConfig = {
817
+ ...stored,
818
+ isWasm: true
819
+ };
606
820
  }
607
- /** Builds the standard WarmupConfig from the Incode CDN. */
608
- function buildDefaultWasmConfig() {
609
- const base = `${WASM_CDN_BASE_URL}/${DEFAULT_WASM_VERSION}`;
821
+ function mergeHeaders(base, override) {
822
+ if (!base && !override) return void 0;
610
823
  return {
611
- wasmPath: `${base}/webLib.wasm`,
612
- wasmSimdPath: `${base}/webLibSimd.wasm`,
613
- glueCodePath: `${base}/webLib.js`,
614
- modelsBasePath: `${base}/models`
824
+ ...base ?? {},
825
+ ...override ?? {}
615
826
  };
616
827
  }
617
828
  /**
618
- * Merges optional WASM path overrides with CDN defaults. Explicit non-blank
619
- * paths take precedence. Blank override strings log a warning and fall back to defaults.
829
+ * When `wantsEncryption` is true, wraps a call that triggers the in-binary
830
+ * RSA/AES handshake so its rejection surfaces as a single, descriptive error
831
+ * with the original error preserved as `cause`. Pass-through otherwise.
620
832
  */
621
- function resolveWasmConfig(overrides) {
622
- const defaults = buildDefaultWasmConfig();
623
- if (!overrides) return defaults;
624
- const simdDefault = defaults.wasmSimdPath ?? defaults.wasmPath;
625
- const modelsDefault = defaults.modelsBasePath ?? (() => {
626
- const lastSlash = defaults.wasmPath.lastIndexOf("/");
627
- return lastSlash === -1 ? "models" : `${defaults.wasmPath.substring(0, lastSlash)}/models`;
628
- })();
629
- const merged = {
630
- wasmPath: pickPath("wasmPath", overrides, defaults.wasmPath),
631
- wasmSimdPath: pickPath("wasmSimdPath", overrides, simdDefault),
632
- glueCodePath: pickPath("glueCodePath", overrides, defaults.glueCodePath),
633
- modelsBasePath: pickPath("modelsBasePath", overrides, modelsDefault),
634
- useSimd: overrides.useSimd,
635
- pipelines: overrides.pipelines,
636
- pipelineModels: overrides.pipelineModels
637
- };
638
- validateWasmPaths(merged);
639
- return merged;
640
- }
641
-
642
- //#endregion
643
- //#region ../infra/src/providers/browser/BrowserPageLifecycleProvider.ts
644
- var BrowserPageLifecycleProvider = class {
645
- sendBeacon(url, body, contentType = "application/json") {
646
- if (typeof navigator === "undefined" || typeof navigator.sendBeacon !== "function") return false;
647
- const blob = new Blob([body], { type: contentType });
648
- return navigator.sendBeacon(url, blob);
833
+ async function withHandshakeFailureContext(wantsEncryption, fn) {
834
+ if (!wantsEncryption) return fn();
835
+ try {
836
+ return await fn();
837
+ } catch (cause) {
838
+ const error = /* @__PURE__ */ new Error("Failed to establish encrypted transport. The /e2ee/key handshake did not complete. Verify the apiURL is reachable and that the environment supports E2EE.");
839
+ error.cause = cause;
840
+ throw error;
649
841
  }
650
- onPageHide(listener) {
651
- const onVisibilityChange = () => {
652
- if (document.visibilityState === "hidden") listener();
653
- };
654
- document.addEventListener("visibilitychange", onVisibilityChange);
655
- window.addEventListener("pagehide", listener);
656
- window.addEventListener("beforeunload", listener);
657
- return () => {
658
- document.removeEventListener("visibilitychange", onVisibilityChange);
659
- window.removeEventListener("pagehide", listener);
660
- window.removeEventListener("beforeunload", listener);
661
- };
662
- }
663
- };
842
+ }
664
843
 
665
844
  //#endregion
666
845
  //#region src/setup.ts
667
846
  let wasmConfig;
668
- let storedHttpConfig;
669
847
  let configured = false;
670
848
  /**
671
849
  * Initializes the SDK with the provided configuration.
@@ -717,7 +895,9 @@ let configured = false;
717
895
  * pipelines: ['selfie'],
718
896
  * },
719
897
  * });
720
- * ```
898
+ *
899
+ * // Enable end-to-end encryption at boot
900
+ * await setup({ apiURL: 'https://api.incode.com', encryption: true });
721
901
  */
722
902
  async function setup(options) {
723
903
  const batcher = getAnalyticsBatcher() ?? setAnalyticsBatcher(createAnalyticsBatchingService({
@@ -728,26 +908,12 @@ async function setup(options) {
728
908
  pageLifecycle: new BrowserPageLifecycleProvider(),
729
909
  timer: BrowserTimerProvider.getInstance()
730
910
  }));
731
- const effectiveWasm = options.wasm ? resolveWasmConfig(options.wasm) : void 0;
732
- if (options.apiURL) {
733
- const client = effectiveWasm ? await createWasmApi_default({
734
- apiURL: options.apiURL,
735
- customHeaders: options.customHeaders,
736
- timeout: options.timeout,
737
- wasm: effectiveWasm
738
- }) : createApi_default({
739
- apiURL: options.apiURL,
740
- customHeaders: options.customHeaders,
741
- timeout: options.timeout
742
- });
743
- storedHttpConfig = {
744
- apiURL: options.apiURL,
745
- customHeaders: options.customHeaders,
746
- timeout: options.timeout,
747
- isWasm: Boolean(effectiveWasm)
748
- };
749
- setClient(client);
750
- }
911
+ const wantsEncryption = options.encryption === true;
912
+ if (wantsEncryption && options.wasm === false) throw new Error("Encryption is incompatible with `wasm: false`. Either remove `wasm: false` or omit `encryption`.");
913
+ if (options.encryption === false && getStoredHttpConfig()?.encryption === true) throw new Error("Encryption cannot be disabled once enabled. Call reset() to fully reinitialize the SDK if you need a non-encrypted client.");
914
+ const effectiveWasm = options.wasm || wantsEncryption ? resolveWasmConfig(options.wasm || {}) : void 0;
915
+ if (options.apiURL) await installFreshHttpClient(options.apiURL, options, effectiveWasm, wantsEncryption);
916
+ else if (wantsEncryption && getStoredHttpConfig() && effectiveWasm) await enableEncryptionOnExistingClient(options, effectiveWasm);
751
917
  if (options.token && isApiConfigured()) {
752
918
  setToken(options.token);
753
919
  resetSessionInit();
@@ -793,32 +959,23 @@ async function initializeWasmUtil(config) {
793
959
  });
794
960
  }
795
961
  /**
796
- * Replaces the active HTTP client with the WASM-backed one. Used when WASM is
797
- * loaded lazily (e.g. by the flow component) — `setup()` originally wired the
798
- * fetch/XHR client because no `wasm` was provided, and this swap upgrades to
799
- * `createWasmApi` once the WASM module is ready.
962
+ * Replaces the active HTTP client with the WASM-backed one. Used internally
963
+ * by lazy-loading UI components (`<incode-flow>`, `<incode-workflow>`) when
964
+ * WASM finishes warming up.
800
965
  *
801
966
  * No-op when no apiURL was originally configured, or when the active client is
802
967
  * already the WASM one.
803
968
  *
969
+ * @internal NOT a public API. Application code should use
970
+ * `setup({ wasm: {...} })` instead — that path is the supported way to opt
971
+ * into the WASM HTTP client.
972
+ *
804
973
  * @param config - Optional WASM configuration. Defaults to the config stored via `setWasmConfig`.
805
974
  */
806
- async function upgradeToWasmHttpClient(config) {
807
- if (!storedHttpConfig) return;
808
- if (storedHttpConfig.isWasm) return;
809
- const wasmConfigToUse = config ?? wasmConfig;
810
- if (!wasmConfigToUse) return;
811
- const resolved = resolveWasmConfig(wasmConfigToUse);
812
- setClient(await createWasmApi_default({
813
- apiURL: storedHttpConfig.apiURL,
814
- customHeaders: storedHttpConfig.customHeaders,
815
- timeout: storedHttpConfig.timeout,
816
- wasm: resolved
817
- }));
818
- storedHttpConfig = {
819
- ...storedHttpConfig,
820
- isWasm: true
821
- };
975
+ async function upgradeToWasmHttpClient$1(config) {
976
+ const configToUse = config ?? wasmConfig;
977
+ if (!configToUse) return;
978
+ await upgradeToWasmHttpClient(resolveWasmConfig(configToUse));
822
979
  }
823
980
  /**
824
981
  * Checks if the SDK has been configured.
@@ -835,11 +992,11 @@ function reset() {
835
992
  resetApi();
836
993
  resetSessionInit();
837
994
  resetAnalyticsBatcher();
995
+ resetHttpClientState();
838
996
  configured = false;
839
997
  wasmConfig = void 0;
840
- storedHttpConfig = void 0;
841
998
  WasmUtilProvider.resetInstance();
842
999
  }
843
1000
 
844
1001
  //#endregion
845
- export { setup as a, buildDefaultWasmConfig as c, setWasmConfig as i, resolveWasmConfig as l, isConfigured as n, upgradeToWasmHttpClient as o, reset as r, DEFAULT_WASM_VERSION as s, initializeWasmUtil as t };
1002
+ export { setup as a, buildDefaultWasmConfig as c, setWasmConfig as i, resolveWasmConfig as l, isConfigured as n, upgradeToWasmHttpClient$1 as o, reset as r, DEFAULT_WASM_VERSION as s, initializeWasmUtil as t };
package/dist/wasm.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { n as WasmPipeline, r as warmupWasm, t as WarmupConfig } from "./warmup-DHGg8wQZ.js";
2
- import { c as upgradeToWasmHttpClient, n as WasmConfig, o as setWasmConfig, r as initializeWasmUtil } from "./setup-D3rE3N3K.js";
2
+ import { c as upgradeToWasmHttpClient, n as WasmConfig, o as setWasmConfig, r as initializeWasmUtil } from "./setup-DM301Lyz.js";
3
3
 
4
4
  //#region ../infra/src/wasm/wasmDefaults.d.ts
5
5
  /** The WASM version bundled and tested with this SDK release. */
package/dist/wasm.esm.js CHANGED
@@ -1,11 +1,11 @@
1
- import { c as buildDefaultWasmConfig, i as setWasmConfig, l as resolveWasmConfig, o as upgradeToWasmHttpClient, s as DEFAULT_WASM_VERSION, t as initializeWasmUtil } from "./setup-h75-vL1d.esm.js";
2
- import { n as warmupWasm } from "./BaseWasmProvider-C2cw9STp.esm.js";
3
- import "./WasmUtilProvider-B8VtGgvF.esm.js";
1
+ import { c as buildDefaultWasmConfig, i as setWasmConfig, l as resolveWasmConfig, o as upgradeToWasmHttpClient, s as DEFAULT_WASM_VERSION, t as initializeWasmUtil } from "./setup-DyspWyTY.esm.js";
2
+ import { n as warmupWasm } from "./BaseWasmProvider-IiHnsP8E.esm.js";
3
+ import "./WasmUtilProvider-BrEYcdhY.esm.js";
4
4
  import "./BrowserTimerProvider-BZGH3sYJ.esm.js";
5
5
  import "./api-eqRXuVG-.esm.js";
6
6
  import "./events-Bt1azl2B.esm.js";
7
7
  import "./endpoints-B3V1U9Dg.esm.js";
8
- import "./session-DWFMKdX6.esm.js";
8
+ import "./session-DAspZUCj.esm.js";
9
9
  import "./IpifyProvider-ByL6JYxg.esm.js";
10
10
  import "./browserSimulation-CAH-V_iE.esm.js";
11
11