@basis-theory/web-elements 3.0.0-beta.4 → 3.0.0-beta.6

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 (108) hide show
  1. package/dist/.vite/manifest.json +22 -11
  2. package/dist/basis-theory-sdk.es.js +2 -2
  3. package/dist/basis-theory-sdk.umd.js +1 -1
  4. package/dist/basis-theory-sdk.umd.js.map +1 -1
  5. package/dist/{create-card-B5zEHyRg.js → create-card-C0MwL3Ou.js} +21 -14
  6. package/dist/create-card-C0MwL3Ou.js.map +1 -0
  7. package/dist/create-card-display-DscvxIs4.js +291 -0
  8. package/dist/create-card-display-DscvxIs4.js.map +1 -0
  9. package/dist/{create-copy-button-DrAz8g0m.js → create-copy-button-DlJ3VvAn.js} +40 -12
  10. package/dist/create-copy-button-DlJ3VvAn.js.map +1 -0
  11. package/dist/{index-BOedIhUN.js → index-DPhSs28B.js} +432 -121
  12. package/dist/index-DPhSs28B.js.map +1 -0
  13. package/dist/index.d.ts +1133 -0
  14. package/dist/loader/basis-theory.min.js +1 -1
  15. package/dist/sri.json +9 -9
  16. package/dist/stats.html +1 -1
  17. package/package.json +12 -12
  18. package/dist/api-client/src/api-client.d.ts +0 -11
  19. package/dist/api-client/src/api-client.d.ts.map +0 -1
  20. package/dist/api-client/src/bin-lookup-transform.d.ts +0 -35
  21. package/dist/api-client/src/bin-lookup-transform.d.ts.map +0 -1
  22. package/dist/api-client/src/http-client.d.ts +0 -24
  23. package/dist/api-client/src/http-client.d.ts.map +0 -1
  24. package/dist/api-client/src/index.d.ts +0 -9
  25. package/dist/api-client/src/index.d.ts.map +0 -1
  26. package/dist/api-client/src/services/sessions.d.ts +0 -19
  27. package/dist/api-client/src/services/sessions.d.ts.map +0 -1
  28. package/dist/api-client/src/services/token-intents.d.ts +0 -17
  29. package/dist/api-client/src/services/token-intents.d.ts.map +0 -1
  30. package/dist/api-client/src/services/tokens.d.ts +0 -19
  31. package/dist/api-client/src/services/tokens.d.ts.map +0 -1
  32. package/dist/api-client/src/types.d.ts +0 -421
  33. package/dist/api-client/src/types.d.ts.map +0 -1
  34. package/dist/create-card-B5zEHyRg.js.map +0 -1
  35. package/dist/create-copy-button-DrAz8g0m.js.map +0 -1
  36. package/dist/index-BOedIhUN.js.map +0 -1
  37. package/dist/postmessage/src/client.d.ts +0 -7
  38. package/dist/postmessage/src/client.d.ts.map +0 -1
  39. package/dist/postmessage/src/event-map.d.ts +0 -139
  40. package/dist/postmessage/src/event-map.d.ts.map +0 -1
  41. package/dist/postmessage/src/index.d.ts +0 -9
  42. package/dist/postmessage/src/index.d.ts.map +0 -1
  43. package/dist/postmessage/src/server.d.ts +0 -11
  44. package/dist/postmessage/src/server.d.ts.map +0 -1
  45. package/dist/postmessage/src/types.d.ts +0 -75
  46. package/dist/postmessage/src/types.d.ts.map +0 -1
  47. package/dist/shared/src/api-url-resolver.d.ts +0 -22
  48. package/dist/shared/src/api-url-resolver.d.ts.map +0 -1
  49. package/dist/shared/src/debug-logger.d.ts +0 -16
  50. package/dist/shared/src/debug-logger.d.ts.map +0 -1
  51. package/dist/shared/src/deep-sanitization.d.ts +0 -24
  52. package/dist/shared/src/deep-sanitization.d.ts.map +0 -1
  53. package/dist/shared/src/errors.d.ts +0 -93
  54. package/dist/shared/src/errors.d.ts.map +0 -1
  55. package/dist/shared/src/generate-id.d.ts +0 -13
  56. package/dist/shared/src/generate-id.d.ts.map +0 -1
  57. package/dist/shared/src/index.d.ts +0 -14
  58. package/dist/shared/src/index.d.ts.map +0 -1
  59. package/dist/shared/src/logger-context.d.ts +0 -25
  60. package/dist/shared/src/logger-context.d.ts.map +0 -1
  61. package/dist/shared/src/proxy-validation.d.ts +0 -93
  62. package/dist/shared/src/proxy-validation.d.ts.map +0 -1
  63. package/dist/web-elements/src/BasisTheory.d.ts +0 -47
  64. package/dist/web-elements/src/BasisTheory.d.ts.map +0 -1
  65. package/dist/web-elements/src/basis-theory.d.ts +0 -85
  66. package/dist/web-elements/src/basis-theory.d.ts.map +0 -1
  67. package/dist/web-elements/src/elements/create-card-number.d.ts +0 -15
  68. package/dist/web-elements/src/elements/create-card-number.d.ts.map +0 -1
  69. package/dist/web-elements/src/elements/create-card.d.ts +0 -50
  70. package/dist/web-elements/src/elements/create-card.d.ts.map +0 -1
  71. package/dist/web-elements/src/elements/create-copy-button.d.ts +0 -19
  72. package/dist/web-elements/src/elements/create-copy-button.d.ts.map +0 -1
  73. package/dist/web-elements/src/elements/create-cvv.d.ts +0 -11
  74. package/dist/web-elements/src/elements/create-cvv.d.ts.map +0 -1
  75. package/dist/web-elements/src/elements/create-expiry.d.ts +0 -11
  76. package/dist/web-elements/src/elements/create-expiry.d.ts.map +0 -1
  77. package/dist/web-elements/src/elements/create-text.d.ts +0 -14
  78. package/dist/web-elements/src/elements/create-text.d.ts.map +0 -1
  79. package/dist/web-elements/src/index.d.ts +0 -27
  80. package/dist/web-elements/src/index.d.ts.map +0 -1
  81. package/dist/web-elements/src/mounter/create-mounter.d.ts +0 -11
  82. package/dist/web-elements/src/mounter/create-mounter.d.ts.map +0 -1
  83. package/dist/web-elements/src/theme/default-theme.d.ts +0 -22
  84. package/dist/web-elements/src/theme/default-theme.d.ts.map +0 -1
  85. package/dist/web-elements/src/theme/inject-theme-dark.d.ts +0 -13
  86. package/dist/web-elements/src/theme/inject-theme-dark.d.ts.map +0 -1
  87. package/dist/web-elements/src/theme/inject-theme.d.ts +0 -20
  88. package/dist/web-elements/src/theme/inject-theme.d.ts.map +0 -1
  89. package/dist/web-elements/src/types/events.d.ts +0 -165
  90. package/dist/web-elements/src/types/events.d.ts.map +0 -1
  91. package/dist/web-elements/src/types/theme.d.ts +0 -91
  92. package/dist/web-elements/src/types/theme.d.ts.map +0 -1
  93. package/dist/web-elements/src/types.d.ts +0 -667
  94. package/dist/web-elements/src/types.d.ts.map +0 -1
  95. package/dist/web-elements/src/utils/create-event-dispatcher.d.ts +0 -47
  96. package/dist/web-elements/src/utils/create-event-dispatcher.d.ts.map +0 -1
  97. package/dist/web-elements/src/utils/create-iframe.d.ts +0 -10
  98. package/dist/web-elements/src/utils/create-iframe.d.ts.map +0 -1
  99. package/dist/web-elements/src/utils/resolve-element-references.d.ts +0 -20
  100. package/dist/web-elements/src/utils/resolve-element-references.d.ts.map +0 -1
  101. package/dist/web-elements/src/utils/validate-element-options.d.ts +0 -11
  102. package/dist/web-elements/src/utils/validate-element-options.d.ts.map +0 -1
  103. package/dist/web-elements/src/utils/validate-sdk-config.d.ts +0 -15
  104. package/dist/web-elements/src/utils/validate-sdk-config.d.ts.map +0 -1
  105. package/dist/web-elements/src/utils/warn-unknown-keys.d.ts +0 -15
  106. package/dist/web-elements/src/utils/warn-unknown-keys.d.ts.map +0 -1
  107. package/dist/web-elements/src/version.d.ts +0 -25
  108. package/dist/web-elements/src/version.d.ts.map +0 -1
@@ -15,7 +15,9 @@ const REDACT_PATTERNS = [
15
15
  /secret/i,
16
16
  /token/i,
17
17
  /ssn/i,
18
- /track/i
18
+ /track/i,
19
+ /session_key/i,
20
+ /^apikey$/i
19
21
  ];
20
22
  const isPANField = (key) => {
21
23
  return PAN_PATTERNS.some((pattern) => pattern.test(key));
@@ -140,6 +142,16 @@ const createDebugLogger = (packageName, enabled) => {
140
142
  console.log(`🔍 [${timestamp}] [${packageName}] ${action}`, sanitized);
141
143
  };
142
144
  };
145
+ const generateId = () => {
146
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
147
+ return crypto.randomUUID();
148
+ }
149
+ const random = () => Math.random().toString(36).substring(2);
150
+ const randomPart = (random() + random() + random() + random()).substring(0, 32);
151
+ return `${randomPart.substring(0, 8)}-${randomPart.substring(8, 12)}-${randomPart.substring(12, 16)}-${randomPart.substring(16, 20)}-${randomPart.substring(20, 32)}`;
152
+ };
153
+ const log = (action, metadata) => {
154
+ };
143
155
  const createBasisTheoryError = (code, message, details) => {
144
156
  const error = new Error(message);
145
157
  error.name = "BasisTheoryError";
@@ -183,8 +195,6 @@ const ConfigurationError = (message, details) => {
183
195
  error.name = "ConfigurationError";
184
196
  return error;
185
197
  };
186
- const log = (action, metadata) => {
187
- };
188
198
  const ALLOWED_PROXY_SCHEMES = /* @__PURE__ */ new Set(["https:"]);
189
199
  const ALLOWED_METHODS = /* @__PURE__ */ new Set([
190
200
  "GET",
@@ -463,9 +473,10 @@ const createPostMessageClient = (iframe, config) => {
463
473
  try {
464
474
  callback(payload);
465
475
  } catch (err) {
466
- if (config.debug) {
467
- console.error(`[PostMessage Client] Error in event subscriber for ${type}:`, err);
468
- }
476
+ log2("Error in event subscriber", {
477
+ type,
478
+ error: err.message
479
+ });
469
480
  }
470
481
  });
471
482
  } else if (!nonce) {
@@ -477,9 +488,9 @@ const createPostMessageClient = (iframe, config) => {
477
488
  };
478
489
  window.addEventListener("message", handleMessage);
479
490
  const retryConfig = typeof config.retries === "number" ? { ...DEFAULT_RETRY_CONFIG, maxRetries: config.retries } : typeof config.retries === "object" ? config.retries : DEFAULT_RETRY_CONFIG;
480
- const sendRequestOnce = (type, payload) => {
491
+ const sendRequestOnce = (type, payload, transfer) => {
481
492
  return new Promise((resolve, reject) => {
482
- const nonce = crypto.randomUUID();
493
+ const nonce = generateId();
483
494
  const timestamp = Date.now();
484
495
  if (!iframe.contentWindow) {
485
496
  reject(BasisTheoryError("IFRAME_NOT_READY", "Iframe not ready"));
@@ -491,15 +502,21 @@ const createPostMessageClient = (iframe, config) => {
491
502
  }, config.timeout || 5e3);
492
503
  pendingRequests.set(nonce, { resolve, reject, timeout, timestamp });
493
504
  log2("Sending request", { type, nonce });
494
- iframe.contentWindow.postMessage({ type, nonce, timestamp, payload }, config.targetOrigin);
505
+ const message = { type, nonce, timestamp, payload };
506
+ if (transfer == null ? void 0 : transfer.length) {
507
+ iframe.contentWindow.postMessage(message, config.targetOrigin, transfer);
508
+ } else {
509
+ iframe.contentWindow.postMessage(message, config.targetOrigin);
510
+ }
495
511
  });
496
512
  };
497
513
  const sendRequest = async (type, payload, options) => {
498
- const maxRetries = (options == null ? void 0 : options.retries) !== void 0 ? options.retries : retryConfig.maxRetries;
514
+ var _a;
515
+ const maxRetries = ((_a = options == null ? void 0 : options.transfer) == null ? void 0 : _a.length) ? 0 : (options == null ? void 0 : options.retries) !== void 0 ? options.retries : retryConfig.maxRetries;
499
516
  let lastError = null;
500
517
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
501
518
  try {
502
- return await sendRequestOnce(type, payload);
519
+ return await sendRequestOnce(type, payload, options == null ? void 0 : options.transfer);
503
520
  } catch (error) {
504
521
  lastError = error;
505
522
  const errorMessage = error.message;
@@ -597,6 +614,54 @@ const createMounter = () => {
597
614
  }
598
615
  };
599
616
  };
617
+ const CMD_REGISTER_ELEMENT = "CMD_REGISTER_ELEMENT";
618
+ const CMD_BIND_ELEMENT_PORT = "CMD_BIND_ELEMENT_PORT";
619
+ const CMD_BIND_COORDINATOR_PORT = "CMD_BIND_COORDINATOR_PORT";
620
+ const bindCoordinatorPort = async ({
621
+ elementId,
622
+ elementType,
623
+ client,
624
+ coordinatorRequest
625
+ }) => {
626
+ await coordinatorRequest(CMD_REGISTER_ELEMENT, {
627
+ elementId,
628
+ type: elementType
629
+ });
630
+ const channel = new MessageChannel();
631
+ const coordinatorBind = await coordinatorRequest(
632
+ CMD_BIND_ELEMENT_PORT,
633
+ { elementId },
634
+ { retries: 0, transfer: [channel.port2] }
635
+ );
636
+ if (!(coordinatorBind == null ? void 0 : coordinatorBind.success)) {
637
+ channel.port1.close();
638
+ throw ElementError(
639
+ `Coordinator rejected the element port (${(coordinatorBind == null ? void 0 : coordinatorBind.error) ?? "UNKNOWN"})`,
640
+ elementId,
641
+ { elementType }
642
+ );
643
+ }
644
+ const elementBind = await client.sendRequest(
645
+ CMD_BIND_COORDINATOR_PORT,
646
+ { elementId },
647
+ { retries: 0, transfer: [channel.port1] }
648
+ ).catch((error) => {
649
+ log("Failed to hand coordinator port to element", {
650
+ error: error.message
651
+ });
652
+ return { success: false, error: error.message };
653
+ });
654
+ if (!(elementBind == null ? void 0 : elementBind.success)) {
655
+ await coordinatorRequest("CMD_BROADCAST_ELEMENT_UNMOUNT", {
656
+ elementId
657
+ }).catch(() => void 0);
658
+ throw ElementError(
659
+ `Element rejected the coordinator port (${(elementBind == null ? void 0 : elementBind.error) ?? "UNKNOWN"})`,
660
+ elementId,
661
+ { elementType }
662
+ );
663
+ }
664
+ };
600
665
  const createIframe = (config) => {
601
666
  const iframe = document.createElement("iframe");
602
667
  iframe.src = config.src;
@@ -709,7 +774,7 @@ const createEventDispatcher = (config) => {
709
774
  dispatchError
710
775
  };
711
776
  };
712
- const createCardNumberElement = (apiKey, sdkConfig, options = {}, coordinatorElementId, ensureCoordinatorReady, notifyCoordinatorElementUnmount) => {
777
+ const createCardNumberElement = (apiKey, sdkConfig, options = {}, coordinatorElementId, ensureCoordinatorReady, notifyCoordinatorElementUnmount, coordinatorRequest) => {
713
778
  let iframe = null;
714
779
  let client = null;
715
780
  let mounter = null;
@@ -743,6 +808,9 @@ const createCardNumberElement = (apiKey, sdkConfig, options = {}, coordinatorEle
743
808
  get mounted() {
744
809
  return isMounted;
745
810
  },
811
+ get loaded() {
812
+ return isMounted;
813
+ },
746
814
  mount: async (selector) => {
747
815
  if (isMounted) {
748
816
  throw ElementError("Element is already mounted");
@@ -800,6 +868,12 @@ const createCardNumberElement = (apiKey, sdkConfig, options = {}, coordinatorEle
800
868
  try {
801
869
  await ensureCoordinatorReady();
802
870
  await readyPromise;
871
+ await bindCoordinatorPort({
872
+ elementId: id,
873
+ elementType: type,
874
+ client,
875
+ coordinatorRequest
876
+ });
803
877
  await client.sendRequest("CMD_SET_CONFIG", {
804
878
  elementId: id,
805
879
  // Include element ID for validation
@@ -928,7 +1002,7 @@ const createCardNumberElement = (apiKey, sdkConfig, options = {}, coordinatorEle
928
1002
  }
929
1003
  };
930
1004
  };
931
- const createCVVElement = (apiKey, sdkConfig, options = {}, coordinatorElementId, ensureCoordinatorReady, notifyCoordinatorElementUnmount) => {
1005
+ const createCVVElement = (apiKey, sdkConfig, options = {}, coordinatorElementId, ensureCoordinatorReady, notifyCoordinatorElementUnmount, coordinatorRequest) => {
932
1006
  let iframe = null;
933
1007
  let client = null;
934
1008
  let mounter = null;
@@ -954,6 +1028,9 @@ const createCVVElement = (apiKey, sdkConfig, options = {}, coordinatorElementId,
954
1028
  get mounted() {
955
1029
  return isMounted;
956
1030
  },
1031
+ get loaded() {
1032
+ return isMounted;
1033
+ },
957
1034
  mount: async (selector) => {
958
1035
  if (isMounted) {
959
1036
  throw ElementError("Element is already mounted", id);
@@ -1008,6 +1085,12 @@ const createCVVElement = (apiKey, sdkConfig, options = {}, coordinatorElementId,
1008
1085
  try {
1009
1086
  await ensureCoordinatorReady();
1010
1087
  await readyPromise;
1088
+ await bindCoordinatorPort({
1089
+ elementId: id,
1090
+ elementType: type,
1091
+ client,
1092
+ coordinatorRequest
1093
+ });
1011
1094
  await client.sendRequest("CMD_SET_CONFIG", {
1012
1095
  elementId: id,
1013
1096
  // Include element ID for validation
@@ -1118,7 +1201,7 @@ const createCVVElement = (apiKey, sdkConfig, options = {}, coordinatorElementId,
1118
1201
  }
1119
1202
  };
1120
1203
  };
1121
- const createExpiryElement = (apiKey, sdkConfig, options = {}, coordinatorElementId, ensureCoordinatorReady, notifyCoordinatorElementUnmount) => {
1204
+ const createExpiryElement = (apiKey, sdkConfig, options = {}, coordinatorElementId, ensureCoordinatorReady, notifyCoordinatorElementUnmount, coordinatorRequest) => {
1122
1205
  let iframe = null;
1123
1206
  let client = null;
1124
1207
  let mounter = null;
@@ -1144,6 +1227,9 @@ const createExpiryElement = (apiKey, sdkConfig, options = {}, coordinatorElement
1144
1227
  get mounted() {
1145
1228
  return isMounted;
1146
1229
  },
1230
+ get loaded() {
1231
+ return isMounted;
1232
+ },
1147
1233
  mount: async (selector) => {
1148
1234
  if (isMounted) {
1149
1235
  throw ElementError("Element is already mounted", id);
@@ -1198,6 +1284,12 @@ const createExpiryElement = (apiKey, sdkConfig, options = {}, coordinatorElement
1198
1284
  try {
1199
1285
  await ensureCoordinatorReady();
1200
1286
  await readyPromise;
1287
+ await bindCoordinatorPort({
1288
+ elementId: id,
1289
+ elementType: type,
1290
+ client,
1291
+ coordinatorRequest
1292
+ });
1201
1293
  await client.sendRequest("CMD_SET_CONFIG", {
1202
1294
  elementId: id,
1203
1295
  // Include element ID for validation
@@ -1304,7 +1396,7 @@ const createExpiryElement = (apiKey, sdkConfig, options = {}, coordinatorElement
1304
1396
  }
1305
1397
  };
1306
1398
  };
1307
- const createTextElement = (apiKey, sdkConfig, options = {}, coordinatorElementId, ensureCoordinatorReady, notifyCoordinatorElementUnmount) => {
1399
+ const createTextElement = (apiKey, sdkConfig, options = {}, coordinatorElementId, ensureCoordinatorReady, notifyCoordinatorElementUnmount, coordinatorRequest) => {
1308
1400
  let iframe = null;
1309
1401
  let client = null;
1310
1402
  let mounter = null;
@@ -1337,6 +1429,9 @@ const createTextElement = (apiKey, sdkConfig, options = {}, coordinatorElementId
1337
1429
  get mounted() {
1338
1430
  return isMounted;
1339
1431
  },
1432
+ get loaded() {
1433
+ return isMounted;
1434
+ },
1340
1435
  mount: async (selector) => {
1341
1436
  if (isMounted) {
1342
1437
  throw ElementError("Element is already mounted", id);
@@ -1391,6 +1486,12 @@ const createTextElement = (apiKey, sdkConfig, options = {}, coordinatorElementId
1391
1486
  try {
1392
1487
  await ensureCoordinatorReady();
1393
1488
  await readyPromise;
1489
+ await bindCoordinatorPort({
1490
+ elementId: id,
1491
+ elementType: type,
1492
+ client,
1493
+ coordinatorRequest
1494
+ });
1394
1495
  const serializedTransform = options.transform ? {
1395
1496
  pattern: options.transform[0].source,
1396
1497
  flags: options.transform[0].flags,
@@ -1712,14 +1813,17 @@ const warnUnknownKeys = (label, obj, knownKeys, deprecatedKeys) => {
1712
1813
  };
1713
1814
  const KNOWN_SDK_KEYS = /* @__PURE__ */ new Set([
1714
1815
  "elementsBaseUrl",
1816
+ "whitelabelDomain",
1715
1817
  "apiBaseUrl",
1716
1818
  "debug",
1819
+ "allowClipboard",
1717
1820
  "measurePerformance",
1718
1821
  "timeoutMs",
1719
1822
  "retryConfig",
1720
1823
  "themeMode",
1721
1824
  "theme",
1722
- "darkTheme"
1825
+ "darkTheme",
1826
+ "sessionAuthorizationUrl"
1723
1827
  ]);
1724
1828
  const DEPRECATED_SDK_KEYS = /* @__PURE__ */ new Map([
1725
1829
  ["iframeOrigin", 'Use "elementsBaseUrl" instead.']
@@ -1761,6 +1865,9 @@ const validateSDKConfig = (options = {}) => {
1761
1865
  if (options.debug !== void 0 && typeof options.debug !== "boolean") {
1762
1866
  throw ConfigurationError("debug must be a boolean");
1763
1867
  }
1868
+ if (options.allowClipboard !== void 0 && typeof options.allowClipboard !== "boolean") {
1869
+ throw ConfigurationError("allowClipboard must be a boolean");
1870
+ }
1764
1871
  if (options.measurePerformance !== void 0 && typeof options.measurePerformance !== "boolean") {
1765
1872
  throw ConfigurationError("measurePerformance must be a boolean");
1766
1873
  }
@@ -1787,7 +1894,44 @@ const validateSDKConfig = (options = {}) => {
1787
1894
  if (!["light", "dark", "auto"].includes(themeMode)) {
1788
1895
  throw ConfigurationError('themeMode must be "light", "dark", or "auto"');
1789
1896
  }
1790
- const finalBaseUrl = baseUrl || "https://js.basistheory.com/3.0.0-beta.4/elements";
1897
+ if (options.sessionAuthorizationUrl !== void 0) {
1898
+ if (typeof options.sessionAuthorizationUrl !== "string" || options.sessionAuthorizationUrl.trim() === "") {
1899
+ throw ConfigurationError("sessionAuthorizationUrl must be a non-empty string");
1900
+ }
1901
+ try {
1902
+ const parsed = new URL(options.sessionAuthorizationUrl, window.location.origin);
1903
+ if (parsed.protocol === "http:" && parsed.hostname !== "localhost" && parsed.hostname !== "127.0.0.1") {
1904
+ throw ConfigurationError("sessionAuthorizationUrl must use https://.");
1905
+ }
1906
+ } catch (error) {
1907
+ if (error instanceof Error && error.name === "ConfigurationError") {
1908
+ throw error;
1909
+ }
1910
+ }
1911
+ }
1912
+ let resolvedBaseUrl = baseUrl;
1913
+ if (resolvedBaseUrl === void 0 && options.whitelabelDomain !== void 0) {
1914
+ const { whitelabelDomain } = options;
1915
+ if (typeof whitelabelDomain !== "string" || whitelabelDomain.trim().length === 0) {
1916
+ throw ConfigurationError("whitelabelDomain must be a non-empty string");
1917
+ }
1918
+ let domainOrigin;
1919
+ try {
1920
+ const parsed = new URL(whitelabelDomain);
1921
+ if (parsed.protocol !== "https:") {
1922
+ throw ConfigurationError("whitelabelDomain must use https://");
1923
+ }
1924
+ domainOrigin = parsed.origin;
1925
+ } catch (error) {
1926
+ if (error instanceof Error && error.name === "ConfigurationError") {
1927
+ throw error;
1928
+ }
1929
+ throw ConfigurationError("whitelabelDomain must be a valid URL");
1930
+ }
1931
+ const { pathname } = new URL("https://js.basistheory.com/3.0.0-beta.6/elements");
1932
+ resolvedBaseUrl = `${domainOrigin}${pathname}`;
1933
+ }
1934
+ const finalBaseUrl = resolvedBaseUrl || "https://js.basistheory.com/3.0.0-beta.6/elements";
1791
1935
  const iframeOrigin = new URL(finalBaseUrl).origin;
1792
1936
  return {
1793
1937
  iframeOrigin,
@@ -1795,6 +1939,7 @@ const validateSDKConfig = (options = {}) => {
1795
1939
  apiBaseUrl: options.apiBaseUrl,
1796
1940
  // Optional - auto-detects if not provided
1797
1941
  debug: options.debug ?? false,
1942
+ allowClipboard: options.allowClipboard ?? false,
1798
1943
  measurePerformance: options.measurePerformance ?? false,
1799
1944
  timeoutMs: options.timeoutMs || 3e4,
1800
1945
  // 30s default for slow 3G connections
@@ -1803,7 +1948,9 @@ const validateSDKConfig = (options = {}) => {
1803
1948
  // Light theme or only theme
1804
1949
  darkTheme: options.darkTheme ? mergeWithDefaultTheme(options.darkTheme) : void 0,
1805
1950
  // Optional dark theme
1806
- retryConfig
1951
+ retryConfig,
1952
+ sessionAuthorizationUrl: options.sessionAuthorizationUrl
1953
+ // Optional - required for cardDisplay
1807
1954
  };
1808
1955
  };
1809
1956
  const COMMON_ELEMENT_KEYS = /* @__PURE__ */ new Set([
@@ -1841,6 +1988,12 @@ const ELEMENT_TYPE_KEYS = {
1841
1988
  "value",
1842
1989
  "text",
1843
1990
  "disabled"
1991
+ ]),
1992
+ cardDisplay: /* @__PURE__ */ new Set([
1993
+ "tokenId",
1994
+ "number",
1995
+ "cvc",
1996
+ "expiration"
1844
1997
  ])
1845
1998
  };
1846
1999
  const validateElementOptions = (type, options = {}) => {
@@ -1941,7 +2094,109 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
1941
2094
  let coordinatorClient = null;
1942
2095
  let coordinatorReadyPromise = null;
1943
2096
  let coordinatorInitStarted = false;
2097
+ let coordinatorLoadTimeout = null;
2098
+ let rejectCoordinatorLoad = null;
2099
+ let destroyed = false;
2100
+ const assertNotDestroyed = () => {
2101
+ if (destroyed) {
2102
+ throw ConfigurationError(
2103
+ "SDK instance has been destroyed. Create a new instance with BasisTheory()"
2104
+ );
2105
+ }
2106
+ };
2107
+ const guardSync = (fn) => (...args) => {
2108
+ assertNotDestroyed();
2109
+ return fn(...args);
2110
+ };
2111
+ const guardAsync = (fn) => async (...args) => {
2112
+ assertNotDestroyed();
2113
+ return fn(...args);
2114
+ };
1944
2115
  let currentThemeMode = options.themeMode || "auto";
2116
+ const createLazyElementWrapper = (lazyFactory, elementType, elementId, elementApiKey, elementConfig, elementOptions, ensureCoordinator, notifyUnmount, coordinatorRequest) => {
2117
+ let realElement = null;
2118
+ let loadPromise = null;
2119
+ const loadRealElement = async () => {
2120
+ if (!loadPromise) {
2121
+ loadPromise = (async () => {
2122
+ const factory = await lazyFactory();
2123
+ realElement = factory(
2124
+ elementApiKey,
2125
+ elementConfig,
2126
+ elementOptions,
2127
+ elementId,
2128
+ ensureCoordinator,
2129
+ notifyUnmount,
2130
+ coordinatorRequest
2131
+ );
2132
+ })();
2133
+ }
2134
+ await loadPromise;
2135
+ };
2136
+ const ensureLoaded = () => {
2137
+ if (!realElement) throw ElementError("Element not initialized");
2138
+ return realElement;
2139
+ };
2140
+ const wrapper = {
2141
+ id: elementId,
2142
+ type: elementType,
2143
+ get mounted() {
2144
+ return (realElement == null ? void 0 : realElement.mounted) ?? false;
2145
+ },
2146
+ get loaded() {
2147
+ return (realElement == null ? void 0 : realElement.loaded) ?? false;
2148
+ },
2149
+ mount: async (selector) => {
2150
+ await loadRealElement();
2151
+ return realElement.mount(selector);
2152
+ },
2153
+ unmount: () => ensureLoaded().unmount(),
2154
+ update: async (opts) => ensureLoaded().update(opts),
2155
+ focus: () => ensureLoaded().focus(),
2156
+ blur: () => ensureLoaded().blur(),
2157
+ clear: () => ensureLoaded().clear(),
2158
+ on: (eventType, listener) => {
2159
+ if (!realElement) {
2160
+ let unsubscribe = null;
2161
+ let cancelled = false;
2162
+ loadRealElement().then(() => {
2163
+ if (!cancelled) unsubscribe = realElement.on(eventType, listener);
2164
+ });
2165
+ return () => {
2166
+ cancelled = true;
2167
+ unsubscribe == null ? void 0 : unsubscribe();
2168
+ };
2169
+ }
2170
+ return realElement.on(eventType, listener);
2171
+ },
2172
+ setValueRef: async (refElement) => {
2173
+ if (!realElement) {
2174
+ await loadRealElement();
2175
+ }
2176
+ if (realElement && "setValueRef" in realElement && typeof realElement.setValueRef === "function") {
2177
+ return realElement.setValueRef(refElement);
2178
+ }
2179
+ throw ElementError("setValueRef not available on this element type");
2180
+ }
2181
+ };
2182
+ if (elementType === "card") {
2183
+ Object.defineProperties(wrapper, {
2184
+ number: {
2185
+ get: () => realElement == null ? void 0 : realElement.number,
2186
+ enumerable: true
2187
+ },
2188
+ expiryDate: {
2189
+ get: () => realElement == null ? void 0 : realElement.expiryDate,
2190
+ enumerable: true
2191
+ },
2192
+ cvc: {
2193
+ get: () => realElement == null ? void 0 : realElement.cvc,
2194
+ enumerable: true
2195
+ }
2196
+ });
2197
+ }
2198
+ return wrapper;
2199
+ };
1945
2200
  const notifyCoordinatorElementUnmount = async (elementId) => {
1946
2201
  if (!coordinatorClient) {
1947
2202
  log2("Cannot notify coordinator of unmount - coordinator not initialized", {
@@ -1961,22 +2216,36 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
1961
2216
  });
1962
2217
  }
1963
2218
  };
2219
+ const sendCoordinatorRequest = async (command, payload, options2) => {
2220
+ if (!coordinatorClient) {
2221
+ throw CoordinatorError("Coordinator not initialized");
2222
+ }
2223
+ return coordinatorClient.sendRequest(command, payload, options2);
2224
+ };
1964
2225
  let cardElementFactory = null;
1965
2226
  let copyButtonElementFactory = null;
2227
+ let cardDisplayElementFactory = null;
1966
2228
  const lazyCardElement = async () => {
1967
2229
  if (!cardElementFactory) {
1968
- const module = await import("./create-card-B5zEHyRg.js");
2230
+ const module = await import("./create-card-C0MwL3Ou.js");
1969
2231
  cardElementFactory = module.createCardElement;
1970
2232
  }
1971
2233
  return cardElementFactory;
1972
2234
  };
1973
2235
  const lazyCopyButtonElement = async () => {
1974
2236
  if (!copyButtonElementFactory) {
1975
- const module = await import("./create-copy-button-DrAz8g0m.js");
2237
+ const module = await import("./create-copy-button-DlJ3VvAn.js");
1976
2238
  copyButtonElementFactory = module.createCopyButtonElement;
1977
2239
  }
1978
2240
  return copyButtonElementFactory;
1979
2241
  };
2242
+ const lazyCardDisplayElement = async () => {
2243
+ if (!cardDisplayElementFactory) {
2244
+ const module = await import("./create-card-display-DscvxIs4.js");
2245
+ cardDisplayElementFactory = module.createCardDisplayElement;
2246
+ }
2247
+ return cardDisplayElementFactory;
2248
+ };
1980
2249
  const syncFactories = {
1981
2250
  cardNumber: createCardNumberElement,
1982
2251
  cvv: createCVVElement,
@@ -1985,7 +2254,8 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
1985
2254
  };
1986
2255
  const lazyFactories = {
1987
2256
  card: lazyCardElement,
1988
- copyButton: lazyCopyButtonElement
2257
+ copyButton: lazyCopyButtonElement,
2258
+ cardDisplay: lazyCardDisplayElement
1989
2259
  };
1990
2260
  const ensureCoordinatorInitialized = () => {
1991
2261
  if (coordinatorReadyPromise) {
@@ -2027,7 +2297,10 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2027
2297
  url: coordinatorIframe.src
2028
2298
  });
2029
2299
  await new Promise((resolve, reject) => {
2030
- const timeout = setTimeout(() => {
2300
+ rejectCoordinatorLoad = reject;
2301
+ coordinatorLoadTimeout = setTimeout(() => {
2302
+ coordinatorLoadTimeout = null;
2303
+ rejectCoordinatorLoad = null;
2031
2304
  reject(
2032
2305
  new Error(
2033
2306
  `Coordinator load timeout (${config.timeoutMs}ms). Try increasing timeoutMs for slow connections.`
@@ -2037,13 +2310,21 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2037
2310
  coordinatorIframe.addEventListener(
2038
2311
  "load",
2039
2312
  () => {
2040
- clearTimeout(timeout);
2313
+ if (coordinatorLoadTimeout !== null) {
2314
+ clearTimeout(coordinatorLoadTimeout);
2315
+ }
2316
+ coordinatorLoadTimeout = null;
2317
+ rejectCoordinatorLoad = null;
2041
2318
  log2("Coordinator iframe loaded");
2042
2319
  resolve();
2043
2320
  },
2044
2321
  { once: true }
2045
2322
  );
2046
2323
  });
2324
+ if (destroyed) {
2325
+ log2("Coordinator load resolved after destroy — aborting init");
2326
+ return;
2327
+ }
2047
2328
  coordinatorClient = createPostMessageClient(coordinatorIframe, {
2048
2329
  targetOrigin: new URL(config.elementsBaseUrl).origin,
2049
2330
  timeout: 3e4,
@@ -2057,10 +2338,16 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2057
2338
  // Optional - auto-detects if not provided
2058
2339
  apiTimeout: 3e4,
2059
2340
  apiRetries: 3,
2341
+ // Frozen by the coordinator on this first config; copy references are
2342
+ // refused unless it's enabled here.
2343
+ allowClipboard: config.allowClipboard,
2060
2344
  debug: config.debug || false,
2061
2345
  theme: config.theme,
2062
2346
  darkTheme: config.darkTheme,
2063
2347
  themeMode: config.themeMode
2348
+ // sessionAuthorizationUrl is intentionally NOT sent to the coordinator:
2349
+ // the merchant-authorization fetch now runs in the parent page (see
2350
+ // create-card-display.ts), so the coordinator never needs the URL.
2064
2351
  });
2065
2352
  log2("Coordinator initialized successfully");
2066
2353
  };
@@ -2070,7 +2357,7 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2070
2357
  * createElement is now SYNCHRONOUS - returns Element instantly
2071
2358
  * Coordinator initialization starts on first element (but doesn't block)
2072
2359
  */
2073
- createElement: (type, elementOptions) => {
2360
+ createElement: guardSync((type, elementOptions) => {
2074
2361
  const syncFactory = syncFactories[type];
2075
2362
  const lazyFactory = lazyFactories[type];
2076
2363
  if (!syncFactory && !lazyFactory) {
@@ -2079,6 +2366,12 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2079
2366
  if (elementOptions) {
2080
2367
  validateElementOptions(type, elementOptions);
2081
2368
  }
2369
+ if (type === "copyButton" && !config.allowClipboard) {
2370
+ throw ConfigurationError(
2371
+ "copyButton requires allowClipboard: true on BasisTheory() initialization. Clipboard access for raw card data may not be PCI compliant and must be enabled explicitly.",
2372
+ { received: config.allowClipboard, expected: true, elementType: type }
2373
+ );
2374
+ }
2082
2375
  const localElementId = `${type}-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
2083
2376
  log2("Creating element (sync)", {
2084
2377
  type,
@@ -2094,79 +2387,21 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2094
2387
  elementOptions,
2095
2388
  localElementId,
2096
2389
  ensureCoordinatorInitialized,
2097
- notifyCoordinatorElementUnmount
2390
+ notifyCoordinatorElementUnmount,
2391
+ sendCoordinatorRequest
2098
2392
  );
2099
2393
  } else {
2100
- let realElement = null;
2101
- let loadPromise = null;
2102
- const loadRealElement = async () => {
2103
- if (!loadPromise) {
2104
- loadPromise = (async () => {
2105
- const factory = await lazyFactory();
2106
- realElement = factory(
2107
- apiKey,
2108
- config,
2109
- elementOptions,
2110
- localElementId,
2111
- ensureCoordinatorInitialized,
2112
- notifyCoordinatorElementUnmount
2113
- );
2114
- })();
2115
- }
2116
- await loadPromise;
2117
- };
2118
- element = {
2119
- id: localElementId,
2394
+ element = createLazyElementWrapper(
2395
+ lazyFactory,
2120
2396
  type,
2121
- get mounted() {
2122
- return (realElement == null ? void 0 : realElement.mounted) ?? false;
2123
- },
2124
- get fields() {
2125
- return realElement == null ? void 0 : realElement.fields;
2126
- },
2127
- mount: async (selector) => {
2128
- await loadRealElement();
2129
- return realElement.mount(selector);
2130
- },
2131
- unmount: () => {
2132
- if (!realElement) throw ElementError("Element not initialized");
2133
- return realElement.unmount();
2134
- },
2135
- update: async (opts) => {
2136
- if (!realElement) throw ElementError("Element not initialized");
2137
- return realElement.update(opts);
2138
- },
2139
- focus: () => {
2140
- if (!realElement) throw ElementError("Element not initialized");
2141
- return realElement.focus();
2142
- },
2143
- blur: () => {
2144
- if (!realElement) throw ElementError("Element not initialized");
2145
- return realElement.blur();
2146
- },
2147
- clear: () => {
2148
- if (!realElement) throw ElementError("Element not initialized");
2149
- return realElement.clear();
2150
- },
2151
- on: (eventType, listener) => {
2152
- if (!realElement) {
2153
- loadRealElement().then(() => realElement.on(eventType, listener));
2154
- return () => {
2155
- };
2156
- }
2157
- return realElement.on(eventType, listener);
2158
- },
2159
- // Forward setValueRef for CopyButtonElement
2160
- setValueRef: async (refElement) => {
2161
- if (!realElement) {
2162
- await loadRealElement();
2163
- }
2164
- if (realElement && "setValueRef" in realElement && typeof realElement.setValueRef === "function") {
2165
- return realElement.setValueRef(refElement);
2166
- }
2167
- throw ElementError("setValueRef not available on this element type");
2168
- }
2169
- };
2397
+ localElementId,
2398
+ apiKey,
2399
+ config,
2400
+ elementOptions,
2401
+ ensureCoordinatorInitialized,
2402
+ notifyCoordinatorElementUnmount,
2403
+ sendCoordinatorRequest
2404
+ );
2170
2405
  }
2171
2406
  elements.set(element.id, element);
2172
2407
  if (type === "cardNumber") {
@@ -2205,8 +2440,8 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2205
2440
  });
2206
2441
  }
2207
2442
  return element;
2208
- },
2209
- tokenize: async (payload, options2) => {
2443
+ }),
2444
+ tokenize: guardAsync(async (payload, options2) => {
2210
2445
  log2("tokenize called", {
2211
2446
  hasPayload: !!payload,
2212
2447
  hasOptions: !!options2,
@@ -2243,7 +2478,7 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2243
2478
  });
2244
2479
  throw error;
2245
2480
  }
2246
- },
2481
+ }),
2247
2482
  /**
2248
2483
  * Token CRUD operations
2249
2484
  * Supports Element references - automatically resolves to secure values
@@ -2253,7 +2488,7 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2253
2488
  * Create a new token
2254
2489
  * Supports Element references in data (same as tokenize)
2255
2490
  */
2256
- create: async (request) => {
2491
+ create: guardAsync(async (request) => {
2257
2492
  if (!request || typeof request !== "object" || Array.isArray(request)) {
2258
2493
  throw ValidationError("Token data must be a non-null object");
2259
2494
  }
@@ -2288,7 +2523,7 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2288
2523
  });
2289
2524
  throw error;
2290
2525
  }
2291
- },
2526
+ }),
2292
2527
  /**
2293
2528
  * Retrieve a token by ID
2294
2529
  *
@@ -2296,7 +2531,7 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2296
2531
  * @param options - Optional configuration
2297
2532
  * @param options.apiKey - Optional session key for authorized access (from sessions.create + authorize)
2298
2533
  */
2299
- retrieve: async (id, options2) => {
2534
+ retrieve: guardAsync(async (id, options2) => {
2300
2535
  log2("tokens.retrieve called", {
2301
2536
  tokenId: id,
2302
2537
  hasSessionKey: !!(options2 == null ? void 0 : options2.apiKey)
@@ -2326,12 +2561,12 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2326
2561
  });
2327
2562
  throw error;
2328
2563
  }
2329
- },
2564
+ }),
2330
2565
  /**
2331
2566
  * Update a token
2332
2567
  * Supports Element references in data
2333
2568
  */
2334
- update: async (id, request) => {
2569
+ update: guardAsync(async (id, request) => {
2335
2570
  log2("tokens.update called", { tokenId: id });
2336
2571
  if (!coordinatorClient) {
2337
2572
  await initializeCoordinator();
@@ -2353,7 +2588,7 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2353
2588
  });
2354
2589
  throw error;
2355
2590
  }
2356
- },
2591
+ }),
2357
2592
  /**
2358
2593
  * Encrypt token data with client-side JWE
2359
2594
  * Uses ECDH-ES key agreement and A256GCM authenticated encryption
@@ -2364,7 +2599,7 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2364
2599
  * @param keyId - Key identifier for decryption lookup
2365
2600
  * @returns Encrypted JWE token(s)
2366
2601
  */
2367
- encrypt: async (tokenData, publicKeyPEM, keyId) => {
2602
+ encrypt: guardAsync(async (tokenData, publicKeyPEM, keyId) => {
2368
2603
  log2("tokens.encrypt called", {
2369
2604
  isSingleToken: "type" in tokenData && "data" in tokenData,
2370
2605
  keyId
@@ -2405,14 +2640,14 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2405
2640
  });
2406
2641
  throw error;
2407
2642
  }
2408
- }
2643
+ })
2409
2644
  },
2410
2645
  sessions: {
2411
2646
  /**
2412
2647
  * Create a new session for temporary elevated access
2413
2648
  * Note: Session must be authorized by a Private Application on your backend
2414
2649
  */
2415
- create: async () => {
2650
+ create: guardAsync(async () => {
2416
2651
  log2("sessions.create called");
2417
2652
  if (!coordinatorClient) {
2418
2653
  await initializeCoordinator();
@@ -2436,13 +2671,13 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2436
2671
  });
2437
2672
  throw error;
2438
2673
  }
2439
- }
2674
+ })
2440
2675
  },
2441
2676
  tokenIntents: {
2442
2677
  /**
2443
2678
  * Create a token intent with element reference support
2444
2679
  */
2445
- create: async (data, options2) => {
2680
+ create: guardAsync(async (data, options2) => {
2446
2681
  log2("tokenIntents.create called", {
2447
2682
  type: data.type,
2448
2683
  hasData: !!data.data,
@@ -2475,11 +2710,11 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2475
2710
  });
2476
2711
  throw error;
2477
2712
  }
2478
- },
2713
+ }),
2479
2714
  /**
2480
2715
  * Get a token intent by ID
2481
2716
  */
2482
- get: async (id, options2) => {
2717
+ get: guardAsync(async (id, options2) => {
2483
2718
  log2("tokenIntents.get called", {
2484
2719
  intentId: id
2485
2720
  });
@@ -2507,15 +2742,16 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2507
2742
  });
2508
2743
  throw error;
2509
2744
  }
2510
- }
2745
+ })
2511
2746
  },
2512
2747
  proxy: (() => {
2513
- const invokeProxy = async (method, options2 = {}) => {
2748
+ const invokeProxy = guardAsync(async (method, options2 = {}) => {
2514
2749
  validateProxyOptions({ ...options2, method });
2515
2750
  log2("proxy invoked", {
2516
2751
  method,
2517
2752
  hasUrl: !!options2.url,
2518
- hasProxyKey: !!options2.proxyKey
2753
+ hasProxyKey: !!options2.proxyKey,
2754
+ hasApiKey: !!options2.apiKey
2519
2755
  });
2520
2756
  if (!coordinatorClient) {
2521
2757
  log2("Waiting for coordinator initialization");
@@ -2534,7 +2770,8 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2534
2770
  proxyKey: options2.proxyKey,
2535
2771
  headers: options2.headers,
2536
2772
  body: resolvedBody,
2537
- includeResponseHeaders: options2.includeResponseHeaders
2773
+ includeResponseHeaders: options2.includeResponseHeaders,
2774
+ apiKey: options2.apiKey
2538
2775
  },
2539
2776
  { retries: 0 }
2540
2777
  );
@@ -2547,7 +2784,7 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2547
2784
  });
2548
2785
  throw error;
2549
2786
  }
2550
- };
2787
+ });
2551
2788
  const proxyVerb = (method) => (options2) => invokeProxy(method, options2 ?? {});
2552
2789
  return {
2553
2790
  get: proxyVerb("GET"),
@@ -2557,7 +2794,7 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2557
2794
  delete: proxyVerb("DELETE")
2558
2795
  };
2559
2796
  })(),
2560
- updateThemeMode: async (mode) => {
2797
+ updateThemeMode: guardAsync(async (mode) => {
2561
2798
  log2("updateThemeMode called", {
2562
2799
  oldMode: currentThemeMode,
2563
2800
  newMode: mode,
@@ -2596,6 +2833,79 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2596
2833
  mode,
2597
2834
  updatedCount: Array.from(elements.values()).filter((el) => el.mounted).length
2598
2835
  });
2836
+ }),
2837
+ /**
2838
+ * Destroys this instance and removes its elements from the page. Once
2839
+ * destroyed, its other methods throw; create a new instance with
2840
+ * BasisTheory() to recover. Safe to call more than once.
2841
+ */
2842
+ destroy: async () => {
2843
+ if (destroyed) {
2844
+ return;
2845
+ }
2846
+ destroyed = true;
2847
+ log2("Destroying SDK instance", {
2848
+ elementCount: elements.size,
2849
+ hasCoordinator: coordinatorIframe !== null
2850
+ });
2851
+ for (const [id, element] of elements) {
2852
+ if (!element.mounted) {
2853
+ continue;
2854
+ }
2855
+ try {
2856
+ element.unmount();
2857
+ } catch (error) {
2858
+ log2("Failed to unmount element during destroy", {
2859
+ elementId: id,
2860
+ error: error.message
2861
+ });
2862
+ }
2863
+ }
2864
+ elements.clear();
2865
+ if (coordinatorLoadTimeout !== null) {
2866
+ clearTimeout(coordinatorLoadTimeout);
2867
+ coordinatorLoadTimeout = null;
2868
+ }
2869
+ if (rejectCoordinatorLoad) {
2870
+ rejectCoordinatorLoad(
2871
+ ConfigurationError(
2872
+ "SDK instance has been destroyed. Create a new instance with BasisTheory()"
2873
+ )
2874
+ );
2875
+ rejectCoordinatorLoad = null;
2876
+ }
2877
+ if (coordinatorClient) {
2878
+ const CACHE_CLEAR_TIMEOUT_MS = 2e3;
2879
+ const cacheCleared = coordinatorClient.sendRequest("CMD_CLEAR_ALL_CACHE", {}, { retries: 0 }).catch((error) => {
2880
+ log2("Failed to clear coordinator cache during destroy", {
2881
+ error: error.message
2882
+ });
2883
+ });
2884
+ let capTimeout;
2885
+ const cap = new Promise((resolve) => {
2886
+ capTimeout = setTimeout(() => {
2887
+ log2("Coordinator cache-clear timed out during destroy", {
2888
+ timeoutMs: CACHE_CLEAR_TIMEOUT_MS
2889
+ });
2890
+ resolve();
2891
+ }, CACHE_CLEAR_TIMEOUT_MS);
2892
+ });
2893
+ await Promise.race([cacheCleared, cap]);
2894
+ if (capTimeout !== void 0) {
2895
+ clearTimeout(capTimeout);
2896
+ }
2897
+ }
2898
+ if (coordinatorClient) {
2899
+ coordinatorClient.destroy();
2900
+ coordinatorClient = null;
2901
+ }
2902
+ if (coordinatorIframe) {
2903
+ coordinatorIframe.remove();
2904
+ coordinatorIframe = null;
2905
+ }
2906
+ coordinatorReadyPromise = null;
2907
+ coordinatorInitStarted = false;
2908
+ log2("SDK instance destroyed");
2599
2909
  }
2600
2910
  };
2601
2911
  if (queuedCommands && queuedCommands.length > 0) {
@@ -2650,8 +2960,8 @@ const BasisTheory = (apiKey, options = {}, queuedCommands) => {
2650
2960
  if (typeof window !== "undefined" && typeof document !== "undefined" && document.currentScript && !window.BasisTheory) {
2651
2961
  window.BasisTheory = BasisTheory;
2652
2962
  }
2653
- const version = "3.0.0-beta.4";
2654
- const buildDate = "2026-06-09T15:35:24.276Z";
2963
+ const version = "3.0.0-beta.6";
2964
+ const buildDate = "2026-08-05T15:06:02.574Z";
2655
2965
  if (typeof window !== "undefined") {
2656
2966
  window.__BasisTheorySDK__ = BasisTheory;
2657
2967
  }
@@ -2660,10 +2970,11 @@ export {
2660
2970
  ConfigurationError as C,
2661
2971
  ElementError as E,
2662
2972
  createPostMessageClient as a,
2663
- createEventDispatcher as b,
2973
+ bindCoordinatorPort as b,
2664
2974
  createIframe as c,
2665
- createMounter as d,
2666
- buildDate as e,
2975
+ createEventDispatcher as d,
2976
+ createMounter as e,
2977
+ buildDate as f,
2667
2978
  log as l,
2668
2979
  version as v
2669
2980
  };