@ozura/elements 1.2.0-next.29 → 1.2.0-next.31

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 (35) hide show
  1. package/dist/frame/element-frame.js +7 -3
  2. package/dist/frame/element-frame.js.map +1 -1
  3. package/dist/frame/tokenizer-frame.js +24 -10
  4. package/dist/frame/tokenizer-frame.js.map +1 -1
  5. package/dist/oz-elements.esm.js +55 -16
  6. package/dist/oz-elements.esm.js.map +1 -1
  7. package/dist/oz-elements.umd.js +55 -16
  8. package/dist/oz-elements.umd.js.map +1 -1
  9. package/dist/react/frame/elementFrame.d.ts +2 -0
  10. package/dist/react/frame/tokenizerFrame.d.ts +9 -0
  11. package/dist/react/index.cjs.js +55 -16
  12. package/dist/react/index.cjs.js.map +1 -1
  13. package/dist/react/index.esm.js +55 -16
  14. package/dist/react/index.esm.js.map +1 -1
  15. package/dist/react/sdk/OzElement.d.ts +2 -1
  16. package/dist/react/server/index.d.ts +15 -0
  17. package/dist/react/types/index.d.ts +1 -1
  18. package/dist/react/utils/billingUtils.d.ts +2 -1
  19. package/dist/server/frame/elementFrame.d.ts +2 -0
  20. package/dist/server/frame/tokenizerFrame.d.ts +9 -0
  21. package/dist/server/index.cjs.js +51 -13
  22. package/dist/server/index.cjs.js.map +1 -1
  23. package/dist/server/index.esm.js +51 -13
  24. package/dist/server/index.esm.js.map +1 -1
  25. package/dist/server/sdk/OzElement.d.ts +2 -1
  26. package/dist/server/server/index.d.ts +15 -0
  27. package/dist/server/types/index.d.ts +1 -1
  28. package/dist/server/utils/billingUtils.d.ts +2 -1
  29. package/dist/types/frame/elementFrame.d.ts +2 -0
  30. package/dist/types/frame/tokenizerFrame.d.ts +9 -0
  31. package/dist/types/sdk/OzElement.d.ts +2 -1
  32. package/dist/types/server/index.d.ts +15 -0
  33. package/dist/types/types/index.d.ts +1 -1
  34. package/dist/types/utils/billingUtils.d.ts +2 -1
  35. package/package.json +1 -1
@@ -201,7 +201,7 @@ function normalizeCommonVaultError(msg) {
201
201
  if (msg.includes('timeout') || msg.includes('timed out')) {
202
202
  return 'The request timed out. Please try again.';
203
203
  }
204
- if (msg.includes('http 5') || msg.includes('500') || msg.includes('502') || msg.includes('503')) {
204
+ if (msg.includes('http 5') || /\b5\d{2}\b/.test(msg)) {
205
205
  return 'A server error occurred. Please try again shortly.';
206
206
  }
207
207
  return null;
@@ -221,7 +221,7 @@ function normalizeVaultError(raw) {
221
221
  if (msg.includes('cvv') || msg.includes('cvc') || msg.includes('security code')) {
222
222
  return 'The CVV code is invalid. Please check and try again.';
223
223
  }
224
- if (msg.includes('insufficient') || msg.includes('funds')) {
224
+ if (msg.includes('insufficient funds')) {
225
225
  return 'Your card has insufficient funds. Please use a different card.';
226
226
  }
227
227
  if (msg.includes('declined') || msg.includes('do not honor')) {
@@ -324,7 +324,7 @@ function sanitizeOptions(options) {
324
324
  * it never holds raw card data — all sensitive values live in the iframe.
325
325
  */
326
326
  class OzElement {
327
- constructor(elementType, options, vaultId, frameBaseUrl, fonts = [], appearanceStyle, onDestroy) {
327
+ constructor(elementType, options, vaultId, frameBaseUrl, fonts = [], appearanceStyle, onDestroy, debug = false) {
328
328
  this.iframe = null;
329
329
  this._frameWindow = null;
330
330
  this._ready = false;
@@ -332,6 +332,7 @@ class OzElement {
332
332
  this._loadTimer = null;
333
333
  this.pendingMessages = [];
334
334
  this.handlers = new Map();
335
+ this.debug = false;
335
336
  this.elementType = elementType;
336
337
  this.options = sanitizeOptions(options);
337
338
  this.vaultId = vaultId;
@@ -341,6 +342,7 @@ class OzElement {
341
342
  this.appearanceStyle = appearanceStyle;
342
343
  this.frameId = `oz-${elementType}-${uuid()}`;
343
344
  this._onDestroy = onDestroy;
345
+ this.debug = debug;
344
346
  }
345
347
  /** The element type this proxy represents. */
346
348
  get type() {
@@ -540,7 +542,7 @@ class OzElement {
540
542
  }
541
543
  this._frameWindow = (_b = (_a = this.iframe) === null || _a === void 0 ? void 0 : _a.contentWindow) !== null && _b !== void 0 ? _b : null;
542
544
  const mergedOptions = Object.assign(Object.assign({}, this.options), { style: mergeAppearanceWithElementStyle(this.appearanceStyle, this.options.style) });
543
- this.post(Object.assign({ type: 'OZ_INIT', elementType: this.elementType, options: sanitizeOptions(mergedOptions), frameId: this.frameId }, (this.fonts.length > 0 ? { fonts: this.fonts } : {})));
545
+ this.post(Object.assign({ type: 'OZ_INIT', elementType: this.elementType, options: sanitizeOptions(mergedOptions), frameId: this.frameId, debug: this.debug }, (this.fonts.length > 0 ? { fonts: this.fonts } : {})));
544
546
  this.pendingMessages.forEach(m => this.send(m));
545
547
  this.pendingMessages = [];
546
548
  this.emit('ready', undefined);
@@ -654,13 +656,14 @@ function validateEmail(email) {
654
656
  // ─── Phone ───────────────────────────────────────────────────────────────────
655
657
  /**
656
658
  * Validates E.164 phone format: starts with +, 1–3 digit country code,
657
- * followed by 7–12 digits, total ≤50 characters.
659
+ * followed by 7–12 digits, max 15 digits total (E.164 spec cap = 16 chars
660
+ * including the leading +).
658
661
  *
659
662
  * Matches the output of checkout's formatPhoneForAPI() function.
660
663
  * Examples: "+15551234567", "+447911123456", "+61412345678"
661
664
  */
662
665
  function validateE164Phone(phone) {
663
- return /^\+[1-9]\d{6,49}$/.test(phone) && phone.length <= 50;
666
+ return /^\+[1-9]\d{6,14}$/.test(phone);
664
667
  }
665
668
  // ─── Field length ─────────────────────────────────────────────────────────────
666
669
  /** Returns true when the string is non-empty and ≤50 characters (cardSale schema). */
@@ -1118,7 +1121,7 @@ class OzVault {
1118
1121
  // the OZ_INIT sent at that point had an empty waxKey. Send a follow-up now
1119
1122
  // so the tokenizer has the key stored before any createToken() call.
1120
1123
  if (vault.tokenizerReady) {
1121
- vault.sendToTokenizer({ type: 'OZ_INIT', frameId: '__tokenizer__', waxKey });
1124
+ vault.sendToTokenizer({ type: 'OZ_INIT', frameId: '__tokenizer__', waxKey, debug: vault._debug });
1122
1125
  }
1123
1126
  vault.log('wax key received — vault ready');
1124
1127
  return vault;
@@ -1205,7 +1208,7 @@ class OzVault {
1205
1208
  // don't grow unboundedly in SPA scenarios with repeated mount/unmount cycles.
1206
1209
  this.elements.delete(el.frameId);
1207
1210
  this.completionState.delete(el.frameId);
1208
- });
1211
+ }, this._debug);
1209
1212
  this.elements.set(el.frameId, el);
1210
1213
  typeMap.set(type, el);
1211
1214
  return el;
@@ -1380,7 +1383,11 @@ class OzVault {
1380
1383
  }
1381
1384
  this._tokenizing = 'card';
1382
1385
  const requestId = `req-${uuid()}`;
1383
- this.log('createToken() called');
1386
+ this.log('createToken() called', {
1387
+ requestIdPrefix: requestId.slice(0, 12),
1388
+ fields: readyElements.map(el => el.type),
1389
+ billingPresent: Boolean(options.billing),
1390
+ });
1384
1391
  return new Promise((resolve, reject) => {
1385
1392
  // Capture the reset generation so cleanup() only zeros _tokenizing when it
1386
1393
  // still belongs to this invocation — not a newer one that started after a reset.
@@ -1652,7 +1659,7 @@ class OzVault {
1652
1659
  }
1653
1660
  }
1654
1661
  handleMessage(event) {
1655
- var _a;
1662
+ var _a, _b;
1656
1663
  if (this._destroyed)
1657
1664
  return;
1658
1665
  // Only accept messages from our frame origin (defense in depth; prevents
@@ -1684,6 +1691,20 @@ class OzVault {
1684
1691
  }
1685
1692
  this.log('element iframe ready', { type: el.type, frameIdPrefix: frameId.slice(0, 8) });
1686
1693
  }
1694
+ // Relay debug/warning messages from element iframes into the parent
1695
+ // DevTools console. Element frames run in cross-origin iframes whose
1696
+ // console context is invisible to developers without a frame selector switch.
1697
+ if (msg.type === 'OZ_DEBUG_LOG') {
1698
+ const level = typeof msg.level === 'string' ? msg.level : 'warn';
1699
+ const message = typeof msg.message === 'string' ? msg.message : String((_b = msg.message) !== null && _b !== void 0 ? _b : '');
1700
+ if (level === 'error') {
1701
+ console.error(`[OzVault:${el.type}] ${message}`);
1702
+ }
1703
+ else {
1704
+ console.warn(`[OzVault:${el.type}] ${message}`);
1705
+ }
1706
+ return;
1707
+ }
1687
1708
  // Intercept OZ_CHANGE before forwarding — handle auto-advance and CVV sync
1688
1709
  if (msg.type === 'OZ_CHANGE') {
1689
1710
  this.handleElementChange(msg, el);
@@ -1728,7 +1749,7 @@ class OzVault {
1728
1749
  }
1729
1750
  }
1730
1751
  handleTokenizerMessage(msg) {
1731
- var _a, _b, _c, _d;
1752
+ var _a, _b, _c, _d, _e;
1732
1753
  switch (msg.type) {
1733
1754
  case 'OZ_FRAME_READY':
1734
1755
  if (msg.__ozVersion !== PROTOCOL_VERSION) {
@@ -1746,9 +1767,10 @@ class OzVault {
1746
1767
  // Deliver the wax key via OZ_INIT so the tokenizer stores it internally.
1747
1768
  // If waxKey is still empty (fetchWaxKey hasn't resolved yet), it will be
1748
1769
  // sent again from create() once the key is available.
1749
- this.sendToTokenizer(Object.assign({ type: 'OZ_INIT', frameId: '__tokenizer__' }, (this.waxKey ? { waxKey: this.waxKey } : {})));
1770
+ this.sendToTokenizer(Object.assign(Object.assign({ type: 'OZ_INIT', frameId: '__tokenizer__' }, (this.waxKey ? { waxKey: this.waxKey } : {})), { debug: this._debug }));
1750
1771
  (_c = this._onReady) === null || _c === void 0 ? void 0 : _c.call(this);
1751
1772
  this.log('tokenizer iframe ready', { protocolVersion: (_d = msg.__ozVersion) !== null && _d !== void 0 ? _d : null });
1773
+ this.log('vault state', this.debugState());
1752
1774
  break;
1753
1775
  case 'OZ_TOKEN_RESULT': {
1754
1776
  if (typeof msg.requestId !== 'string' || !msg.requestId) {
@@ -1774,6 +1796,7 @@ class OzVault {
1774
1796
  pending.resolve(Object.assign(Object.assign({ token,
1775
1797
  cvcSession }, (card ? { card } : {})), (pending.billing ? { billing: pending.billing } : {})));
1776
1798
  this.log('token received', {
1799
+ requestIdPrefix: msg.requestId.slice(0, 12),
1777
1800
  elapsedMs: pending.tokenizeStartMs != null ? Date.now() - pending.tokenizeStartMs : null,
1778
1801
  tokenPresent: true,
1779
1802
  cvcSessionPresent: true,
@@ -1805,7 +1828,7 @@ class OzVault {
1805
1828
  if (pending.timeoutId != null)
1806
1829
  clearTimeout(pending.timeoutId);
1807
1830
  const willRefresh = this.isRefreshableAuthError(errorCode, raw) && !pending.retried && Boolean(this._storedFetchWaxKey);
1808
- this.log('token error', { errorCode, willRefresh });
1831
+ this.log('token error', { requestIdPrefix: msg.requestId.slice(0, 12), errorCode, willRefresh });
1809
1832
  // Auto-refresh: if the wax key expired or was consumed and we haven't
1810
1833
  // already retried for this request, transparently re-mint and retry.
1811
1834
  if (willRefresh) {
@@ -1956,6 +1979,21 @@ class OzVault {
1956
1979
  }
1957
1980
  break;
1958
1981
  }
1982
+ case 'OZ_DEBUG_LOG': {
1983
+ // Relay warnings/errors from the tokenizer iframe into the parent page's
1984
+ // DevTools console. The tokenizer runs in a cross-origin iframe whose
1985
+ // console context is invisible to most developers unless they manually
1986
+ // switch the DevTools frame selector.
1987
+ const level = typeof msg.level === 'string' ? msg.level : 'warn';
1988
+ const message = typeof msg.message === 'string' ? msg.message : String((_e = msg.message) !== null && _e !== void 0 ? _e : '');
1989
+ if (level === 'error') {
1990
+ console.error(`[OzVault:tokenizer] ${message}`);
1991
+ }
1992
+ else {
1993
+ console.warn(`[OzVault:tokenizer] ${message}`);
1994
+ }
1995
+ break;
1996
+ }
1959
1997
  }
1960
1998
  }
1961
1999
  /**
@@ -2004,6 +2042,7 @@ class OzVault {
2004
2042
  }
2005
2043
  const newSessionId = uuid();
2006
2044
  (_a = this._onWaxRefresh) === null || _a === void 0 ? void 0 : _a.call(this);
2045
+ const refreshStartMs = Date.now();
2007
2046
  this.log('wax key refresh started');
2008
2047
  this._waxRefreshing = this._storedFetchWaxKey(newSessionId)
2009
2048
  .then(newWaxKey => {
@@ -2016,12 +2055,12 @@ class OzVault {
2016
2055
  this._tokenizeSuccessCount = 0;
2017
2056
  }
2018
2057
  if (!this._destroyed && this.tokenizerReady) {
2019
- this.sendToTokenizer({ type: 'OZ_INIT', frameId: '__tokenizer__', waxKey: newWaxKey });
2058
+ this.sendToTokenizer({ type: 'OZ_INIT', frameId: '__tokenizer__', waxKey: newWaxKey, debug: this._debug });
2020
2059
  }
2021
- this.log('wax key refresh succeeded');
2060
+ this.log('wax key refresh succeeded', { durationMs: Date.now() - refreshStartMs });
2022
2061
  })
2023
2062
  .catch((err) => {
2024
- this.log('wax key refresh failed', { error: err instanceof Error ? err.message : String(err) });
2063
+ this.log('wax key refresh failed', { error: err instanceof Error ? err.message : String(err), durationMs: Date.now() - refreshStartMs });
2025
2064
  throw err;
2026
2065
  })
2027
2066
  .finally(() => {