@ozura/elements 1.2.1 → 1.2.4-next.47

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 (63) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +1445 -1340
  3. package/dist/frame/element-frame.html +22 -22
  4. package/dist/frame/element-frame.js +49 -4
  5. package/dist/frame/element-frame.js.map +1 -1
  6. package/dist/frame/tokenizer-frame.html +11 -11
  7. package/dist/frame/tokenizer-frame.js +147 -63
  8. package/dist/frame/tokenizer-frame.js.map +1 -1
  9. package/dist/oz-elements.esm.js +222 -98
  10. package/dist/oz-elements.esm.js.map +1 -1
  11. package/dist/oz-elements.umd.js +222 -98
  12. package/dist/oz-elements.umd.js.map +1 -1
  13. package/dist/react/frame/elementFrame.d.ts +9 -0
  14. package/dist/react/frame/tokenizerFrame.d.ts +17 -1
  15. package/dist/react/index.cjs.js +222 -98
  16. package/dist/react/index.cjs.js.map +1 -1
  17. package/dist/react/index.esm.js +222 -98
  18. package/dist/react/index.esm.js.map +1 -1
  19. package/dist/react/sdk/OzElement.d.ts +4 -1
  20. package/dist/react/sdk/OzVault.d.ts +3 -9
  21. package/dist/react/sdk/createSessionFetcher.d.ts +2 -2
  22. package/dist/react/server/index.d.ts +26 -0
  23. package/dist/react/types/index.d.ts +30 -11
  24. package/dist/react/utils/billingUtils.d.ts +2 -1
  25. package/dist/react/vue/index.d.ts +256 -0
  26. package/dist/server/frame/elementFrame.d.ts +9 -0
  27. package/dist/server/frame/tokenizerFrame.d.ts +17 -1
  28. package/dist/server/index.cjs.js +67 -26
  29. package/dist/server/index.cjs.js.map +1 -1
  30. package/dist/server/index.esm.js +67 -26
  31. package/dist/server/index.esm.js.map +1 -1
  32. package/dist/server/sdk/OzElement.d.ts +4 -1
  33. package/dist/server/sdk/OzVault.d.ts +3 -9
  34. package/dist/server/sdk/createSessionFetcher.d.ts +2 -2
  35. package/dist/server/server/index.d.ts +26 -0
  36. package/dist/server/types/index.d.ts +30 -11
  37. package/dist/server/utils/billingUtils.d.ts +2 -1
  38. package/dist/server/vue/index.d.ts +256 -0
  39. package/dist/types/frame/elementFrame.d.ts +9 -0
  40. package/dist/types/frame/tokenizerFrame.d.ts +17 -1
  41. package/dist/types/sdk/OzElement.d.ts +4 -1
  42. package/dist/types/sdk/OzVault.d.ts +3 -9
  43. package/dist/types/sdk/createSessionFetcher.d.ts +2 -2
  44. package/dist/types/server/index.d.ts +26 -0
  45. package/dist/types/types/index.d.ts +30 -11
  46. package/dist/types/utils/billingUtils.d.ts +2 -1
  47. package/dist/types/vue/index.d.ts +256 -0
  48. package/dist/vue/frame/protocol.d.ts +12 -0
  49. package/dist/vue/index.cjs.js +2335 -0
  50. package/dist/vue/index.cjs.js.map +1 -0
  51. package/dist/vue/index.esm.js +2327 -0
  52. package/dist/vue/index.esm.js.map +1 -0
  53. package/dist/vue/sdk/OzElement.d.ts +99 -0
  54. package/dist/vue/sdk/OzVault.d.ts +250 -0
  55. package/dist/vue/sdk/createSessionFetcher.d.ts +29 -0
  56. package/dist/vue/sdk/errors.d.ts +65 -0
  57. package/dist/vue/sdk/index.d.ts +14 -0
  58. package/dist/vue/types/index.d.ts +667 -0
  59. package/dist/vue/utils/appearance.d.ts +22 -0
  60. package/dist/vue/utils/billingUtils.d.ts +61 -0
  61. package/dist/vue/utils/uuid.d.ts +12 -0
  62. package/dist/vue/vue/index.d.ts +256 -0
  63. package/package.json +15 -3
@@ -0,0 +1,256 @@
1
+ /**
2
+ * @ozura/elements/vue — Vue 3 wrapper for OzElements.
3
+ *
4
+ * Provides a context-based provider that creates and manages an OzVault instance,
5
+ * five individual field components, and a composable to access createToken +
6
+ * readiness state from anywhere inside the provider tree.
7
+ *
8
+ * Quick start:
9
+ * @example
10
+ * ```vue
11
+ * <script setup lang="ts">
12
+ * import { OzElements, OzCardNumber, OzExpiry, OzCvv, useOzElements } from '@ozura/elements/vue';
13
+ * const { createToken, ready } = useOzElements();
14
+ * </script>
15
+ *
16
+ * <template>
17
+ * <OzElements pub-key="pk_live_..." session-url="/api/oz-session">
18
+ * <OzCardNumber />
19
+ * <OzExpiry />
20
+ * <OzCvv />
21
+ * <button :disabled="!ready" @click="createToken()">Pay</button>
22
+ * </OzElements>
23
+ * </template>
24
+ * ```
25
+ */
26
+ import { type Ref, type PropType, type ComputedRef } from 'vue';
27
+ import type { TokenizeOptions, TokenResponse, BankTokenizeOptions, BankTokenResponse, FontSource, Appearance } from '../types';
28
+ export interface OzElementsProps {
29
+ pubKey: string;
30
+ sessionUrl?: string;
31
+ getSessionKey?: (sessionId: string) => Promise<string>;
32
+ frameBaseUrl?: string;
33
+ fonts?: FontSource[];
34
+ appearance?: Appearance;
35
+ loadTimeoutMs?: number;
36
+ debug?: boolean;
37
+ }
38
+ /**
39
+ * Creates and owns an OzVault instance for the lifetime of this component.
40
+ * All field components must be rendered inside this provider.
41
+ */
42
+ export declare const OzElements: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
43
+ pubKey: {
44
+ type: StringConstructor;
45
+ required: true;
46
+ };
47
+ sessionUrl: {
48
+ type: StringConstructor;
49
+ default: undefined;
50
+ };
51
+ getSessionKey: {
52
+ type: PropType<(sessionId: string) => Promise<string>>;
53
+ default: undefined;
54
+ };
55
+ frameBaseUrl: {
56
+ type: StringConstructor;
57
+ default: undefined;
58
+ };
59
+ fonts: {
60
+ type: PropType<FontSource[]>;
61
+ default: undefined;
62
+ };
63
+ appearance: {
64
+ type: PropType<Appearance>;
65
+ default: undefined;
66
+ };
67
+ loadTimeoutMs: {
68
+ type: NumberConstructor;
69
+ default: undefined;
70
+ };
71
+ debug: {
72
+ type: BooleanConstructor;
73
+ default: undefined;
74
+ };
75
+ }>, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
76
+ [key: string]: any;
77
+ }>[] | undefined, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "ready"[], "ready", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
78
+ pubKey: {
79
+ type: StringConstructor;
80
+ required: true;
81
+ };
82
+ sessionUrl: {
83
+ type: StringConstructor;
84
+ default: undefined;
85
+ };
86
+ getSessionKey: {
87
+ type: PropType<(sessionId: string) => Promise<string>>;
88
+ default: undefined;
89
+ };
90
+ frameBaseUrl: {
91
+ type: StringConstructor;
92
+ default: undefined;
93
+ };
94
+ fonts: {
95
+ type: PropType<FontSource[]>;
96
+ default: undefined;
97
+ };
98
+ appearance: {
99
+ type: PropType<Appearance>;
100
+ default: undefined;
101
+ };
102
+ loadTimeoutMs: {
103
+ type: NumberConstructor;
104
+ default: undefined;
105
+ };
106
+ debug: {
107
+ type: BooleanConstructor;
108
+ default: undefined;
109
+ };
110
+ }>> & Readonly<{
111
+ onReady?: ((...args: any[]) => any) | undefined;
112
+ }>, {
113
+ debug: boolean;
114
+ fonts: FontSource[];
115
+ loadTimeoutMs: number;
116
+ frameBaseUrl: string;
117
+ sessionUrl: string;
118
+ getSessionKey: (sessionId: string) => Promise<string>;
119
+ appearance: Appearance;
120
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
121
+ export interface UseOzElementsReturn {
122
+ /**
123
+ * Tokenizes all mounted card fields. Resolves with a token and cvcSession
124
+ * that can be passed to the Ozura Pay API endpoint.
125
+ */
126
+ createToken: (options?: TokenizeOptions) => Promise<TokenResponse>;
127
+ /**
128
+ * Tokenizes mounted bank account fields (accountNumber + routingNumber).
129
+ */
130
+ createBankToken: (options: BankTokenizeOptions) => Promise<BankTokenResponse>;
131
+ /**
132
+ * True when the vault tokenizer and all mounted field iframes are ready.
133
+ * Gate your submit button on this.
134
+ */
135
+ ready: ComputedRef<boolean>;
136
+ /**
137
+ * Non-null when OzVault.create() rejected during initialization.
138
+ */
139
+ initError: Ref<Error | null>;
140
+ /**
141
+ * Number of successful tokenizations since the last session refresh.
142
+ */
143
+ tokenizeCount: Ref<number>;
144
+ /**
145
+ * Clears all mounted element fields without destroying the vault.
146
+ */
147
+ reset: () => void;
148
+ }
149
+ /**
150
+ * Returns createToken, createBankToken, ready, initError, tokenizeCount, and reset.
151
+ * Must be called from inside an <OzElements> provider tree.
152
+ *
153
+ * @throws {Error} if called outside an <OzElements> provider
154
+ */
155
+ export declare function useOzElements(): UseOzElementsReturn;
156
+ /** Card number field. Emits `change` (ElementChangeEvent), `focus`, `blur`. */
157
+ export declare const OzCardNumber: import("vue").DefineComponent<{
158
+ placeholder?: string | undefined;
159
+ disabled?: boolean | undefined;
160
+ style?: import("../types").ElementStyleConfig | undefined;
161
+ }, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
162
+ [key: string]: any;
163
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("blur" | "change" | "focus")[], "blur" | "change" | "focus", import("vue").PublicProps, Readonly<{
164
+ placeholder?: string | undefined;
165
+ disabled?: boolean | undefined;
166
+ style?: import("../types").ElementStyleConfig | undefined;
167
+ }> & Readonly<{
168
+ onChange?: ((...args: any[]) => any) | undefined;
169
+ onFocus?: ((...args: any[]) => any) | undefined;
170
+ onBlur?: ((...args: any[]) => any) | undefined;
171
+ }>, {
172
+ style: import("../types").ElementStyleConfig | undefined;
173
+ placeholder: string;
174
+ disabled: boolean;
175
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
176
+ /** Expiry date field. Emits `change` (ElementChangeEvent), `focus`, `blur`. */
177
+ export declare const OzExpiry: import("vue").DefineComponent<{
178
+ placeholder?: string | undefined;
179
+ disabled?: boolean | undefined;
180
+ style?: import("../types").ElementStyleConfig | undefined;
181
+ }, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
182
+ [key: string]: any;
183
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("blur" | "change" | "focus")[], "blur" | "change" | "focus", import("vue").PublicProps, Readonly<{
184
+ placeholder?: string | undefined;
185
+ disabled?: boolean | undefined;
186
+ style?: import("../types").ElementStyleConfig | undefined;
187
+ }> & Readonly<{
188
+ onChange?: ((...args: any[]) => any) | undefined;
189
+ onFocus?: ((...args: any[]) => any) | undefined;
190
+ onBlur?: ((...args: any[]) => any) | undefined;
191
+ }>, {
192
+ style: import("../types").ElementStyleConfig | undefined;
193
+ placeholder: string;
194
+ disabled: boolean;
195
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
196
+ /** CVV / CVC field. Emits `change` (ElementChangeEvent), `focus`, `blur`. */
197
+ export declare const OzCvv: import("vue").DefineComponent<{
198
+ placeholder?: string | undefined;
199
+ disabled?: boolean | undefined;
200
+ style?: import("../types").ElementStyleConfig | undefined;
201
+ }, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
202
+ [key: string]: any;
203
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("blur" | "change" | "focus")[], "blur" | "change" | "focus", import("vue").PublicProps, Readonly<{
204
+ placeholder?: string | undefined;
205
+ disabled?: boolean | undefined;
206
+ style?: import("../types").ElementStyleConfig | undefined;
207
+ }> & Readonly<{
208
+ onChange?: ((...args: any[]) => any) | undefined;
209
+ onFocus?: ((...args: any[]) => any) | undefined;
210
+ onBlur?: ((...args: any[]) => any) | undefined;
211
+ }>, {
212
+ style: import("../types").ElementStyleConfig | undefined;
213
+ placeholder: string;
214
+ disabled: boolean;
215
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
216
+ /** Bank account number field. Emits `change` (ElementChangeEvent), `focus`, `blur`. */
217
+ export declare const OzBankAccountNumber: import("vue").DefineComponent<{
218
+ placeholder?: string | undefined;
219
+ disabled?: boolean | undefined;
220
+ style?: import("../types").ElementStyleConfig | undefined;
221
+ }, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
222
+ [key: string]: any;
223
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("blur" | "change" | "focus")[], "blur" | "change" | "focus", import("vue").PublicProps, Readonly<{
224
+ placeholder?: string | undefined;
225
+ disabled?: boolean | undefined;
226
+ style?: import("../types").ElementStyleConfig | undefined;
227
+ }> & Readonly<{
228
+ onChange?: ((...args: any[]) => any) | undefined;
229
+ onFocus?: ((...args: any[]) => any) | undefined;
230
+ onBlur?: ((...args: any[]) => any) | undefined;
231
+ }>, {
232
+ style: import("../types").ElementStyleConfig | undefined;
233
+ placeholder: string;
234
+ disabled: boolean;
235
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
236
+ /** Bank routing number field. Emits `change` (ElementChangeEvent), `focus`, `blur`. */
237
+ export declare const OzBankRoutingNumber: import("vue").DefineComponent<{
238
+ placeholder?: string | undefined;
239
+ disabled?: boolean | undefined;
240
+ style?: import("../types").ElementStyleConfig | undefined;
241
+ }, () => import("vue").VNode<import("vue").RendererNode, import("vue").RendererElement, {
242
+ [key: string]: any;
243
+ }>, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("blur" | "change" | "focus")[], "blur" | "change" | "focus", import("vue").PublicProps, Readonly<{
244
+ placeholder?: string | undefined;
245
+ disabled?: boolean | undefined;
246
+ style?: import("../types").ElementStyleConfig | undefined;
247
+ }> & Readonly<{
248
+ onChange?: ((...args: any[]) => any) | undefined;
249
+ onFocus?: ((...args: any[]) => any) | undefined;
250
+ onBlur?: ((...args: any[]) => any) | undefined;
251
+ }>, {
252
+ style: import("../types").ElementStyleConfig | undefined;
253
+ placeholder: string;
254
+ disabled: boolean;
255
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
256
+ export type { ElementChangeEvent, TokenizeOptions, TokenResponse, BankTokenizeOptions, BankTokenResponse, Appearance, FontSource, } from '../types';
@@ -22,6 +22,8 @@ export declare class ElementFrame {
22
22
  private vaultId;
23
23
  private frameId;
24
24
  private hostOrigin;
25
+ /** Mirrors the parent vault's debug flag — set via OZ_INIT. */
26
+ private debug;
25
27
  private rawValue;
26
28
  private cardBrand;
27
29
  private cvvMaxLength;
@@ -64,6 +66,13 @@ export declare class ElementFrame {
64
66
  private reapplyStateStyles;
65
67
  private applyPlaceholderStyles;
66
68
  private fontsInjected;
69
+ /**
70
+ * Allowed hostnames for cssSrc font stylesheets. Restricting to known font
71
+ * CDNs prevents a merchant from loading arbitrary third-party stylesheets
72
+ * inside the PCI-isolated iframe, which could otherwise be used to load
73
+ * tracking scripts via @import or attempt CSS-based data extraction.
74
+ */
75
+ private static readonly ALLOWED_FONT_HOSTS;
67
76
  private injectFonts;
68
77
  /**
69
78
  * Delivers this field's raw value to the tokenizer iframe via the MessagePort
@@ -23,11 +23,27 @@ export declare function isAllowedVaultOrigin(apiUrl: string): boolean;
23
23
  export declare class TokenizerFrame {
24
24
  private vaultId;
25
25
  private hostOrigin;
26
- /** Wax key delivered once via OZ_INIT. Used for all tokenize calls. */
26
+ /**
27
+ * Session key — delivered via OZ_INIT on first ready and again after each
28
+ * auto-refresh. The latest value is always used for tokenize calls.
29
+ */
27
30
  private waxKey;
28
31
  private pending;
29
32
  private pendingBank;
33
+ /** Mirrors the parent vault's debug flag — set via OZ_INIT. When true, the frame relays debug-level info in addition to errors/warnings. */
34
+ private debug;
30
35
  constructor();
36
+ /**
37
+ * Relays a message to the parent window as OZ_DEBUG_LOG so it surfaces in
38
+ * the merchant page's DevTools console rather than the hidden tokenizer-frame
39
+ * context.
40
+ *
41
+ * Level semantics:
42
+ * 'error' — always relayed (genuine failure)
43
+ * 'warn' — always relayed (developer misconfiguration)
44
+ * 'log' — only relayed when debug mode is enabled (lifecycle / timing info)
45
+ */
46
+ private postDebugLog;
31
47
  private onMessage;
32
48
  /**
33
49
  * Shared vault POST helper. Handles origin guard, header construction,
@@ -87,13 +87,14 @@ function validateEmail(email) {
87
87
  // ─── Phone ───────────────────────────────────────────────────────────────────
88
88
  /**
89
89
  * Validates E.164 phone format: starts with +, 1–3 digit country code,
90
- * followed by 7–12 digits, total ≤50 characters.
90
+ * followed by 7–12 digits, max 15 digits total (E.164 spec cap = 16 chars
91
+ * including the leading +).
91
92
  *
92
93
  * Matches the output of checkout's formatPhoneForAPI() function.
93
94
  * Examples: "+15551234567", "+447911123456", "+61412345678"
94
95
  */
95
96
  function validateE164Phone(phone) {
96
- return /^\+[1-9]\d{6,49}$/.test(phone) && phone.length <= 50;
97
+ return /^\+[1-9]\d{6,14}$/.test(phone);
97
98
  }
98
99
  // ─── Field length ─────────────────────────────────────────────────────────────
99
100
  /** Returns true when the string is non-empty and ≤50 characters (cardSale schema). */
@@ -293,8 +294,8 @@ function validateBilling(billing) {
293
294
  * ```
294
295
  */
295
296
  // ─── Configuration ───────────────────────────────────────────────────────────
296
- const DEFAULT_API_URL = "https://payapi.v2.ozurapay.com";
297
- const DEFAULT_VAULT_URL = "https://api.ozuravault.com";
297
+ const DEFAULT_API_URL = "https://ozurapay-pay-api-v2-staging-c8abbdfhfbd3c5em.eastus-01.azurewebsites.net";
298
+ const DEFAULT_VAULT_URL = "https://pci-vault-staging-drc0duhcakf4g4fr.eastus-01.azurewebsites.net";
298
299
  const DEFAULT_TIMEOUT = 30000;
299
300
  // ─── Error ───────────────────────────────────────────────────────────────────
300
301
  class OzuraError extends Error {
@@ -334,7 +335,7 @@ function timeoutSignal(ms) {
334
335
  // ─── Main class ──────────────────────────────────────────────────────────────
335
336
  class Ozura {
336
337
  constructor(config) {
337
- var _a, _b;
338
+ var _a, _b, _c;
338
339
  if (!config.vaultKey)
339
340
  throw new OzuraError('vaultKey is required', 0);
340
341
  this.merchantId = config.merchantId;
@@ -344,6 +345,30 @@ class Ozura {
344
345
  this.vaultUrl = config.vaultUrl || DEFAULT_VAULT_URL;
345
346
  this.timeoutMs = (_a = config.timeoutMs) !== null && _a !== void 0 ? _a : DEFAULT_TIMEOUT;
346
347
  this.retries = (_b = config.retries) !== null && _b !== void 0 ? _b : DEFAULT_RETRIES;
348
+ this.debug = (_c = config.debug) !== null && _c !== void 0 ? _c : false;
349
+ }
350
+ /** Emits a `[Ozura]`-prefixed entry to `console.log`. No-op when `debug` is not set. */
351
+ log(message, data) {
352
+ if (!this.debug)
353
+ return;
354
+ if (data !== undefined) {
355
+ console.log(`[Ozura] ${message}`, data);
356
+ }
357
+ else {
358
+ console.log(`[Ozura] ${message}`);
359
+ }
360
+ }
361
+ /**
362
+ * Returns a copy of `body` with known-sensitive fields replaced by `'[REDACTED]'`.
363
+ * Used to make debug logs safe to emit without leaking vault tokens or session keys.
364
+ */
365
+ static redactBody(body) {
366
+ const SENSITIVE = new Set(['ozuraVaultToken', 'ozuraCvcSession', 'wax_key', 'waxKey']);
367
+ const result = {};
368
+ for (const [k, v] of Object.entries(body)) {
369
+ result[k] = SENSITIVE.has(k) ? '[REDACTED]' : v;
370
+ }
371
+ return result;
347
372
  }
348
373
  /**
349
374
  * Charge a tokenized card. Maps the friendly `CardSaleInput` shape to the
@@ -352,11 +377,12 @@ class Ozura {
352
377
  * Rate limit: 100 requests/minute per merchant.
353
378
  */
354
379
  async cardSale(input) {
355
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
380
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
356
381
  if (!this.merchantId)
357
382
  throw new OzuraError('merchantId is required for cardSale(). Add it to the Ozura constructor config.', 0);
358
383
  if (!this.apiKey)
359
384
  throw new OzuraError('apiKey is required for cardSale(). Add it to the Ozura constructor config.', 0);
385
+ this.log('cardSale', { merchantId: this.merchantId, amount: input.amount, currency: input.currency || 'USD' });
360
386
  const billing = input.billing;
361
387
  // Build body with required fields, then conditionally add optional billing
362
388
  // fields only when non-empty. The Pay API enforces minLength:1 on these
@@ -366,30 +392,33 @@ class Ozura {
366
392
  merchantId: this.merchantId,
367
393
  amount: input.amount,
368
394
  currency: input.currency || 'USD',
369
- ozuraCardToken: input.token,
395
+ // Pay API requires these two fields. Default to standard web-checkout values.
396
+ transactionInitiationType: (_a = input.transactionInitiationType) !== null && _a !== void 0 ? _a : 'cit',
397
+ transactionChannel: (_b = input.transactionChannel) !== null && _b !== void 0 ? _b : 'ecommerce',
398
+ ozuraVaultToken: input.token,
370
399
  ozuraCvcSession: input.cvcSession,
371
400
  billingFirstName: billing.firstName,
372
401
  billingLastName: billing.lastName,
373
402
  clientIpAddress: input.clientIpAddress,
374
- salesTaxExempt: (_a = input.salesTaxExempt) !== null && _a !== void 0 ? _a : false,
375
- surchargePercent: (_b = input.surchargePercent) !== null && _b !== void 0 ? _b : '0.00',
376
- tipAmount: (_c = input.tipAmount) !== null && _c !== void 0 ? _c : '0.00',
403
+ salesTaxExempt: (_c = input.salesTaxExempt) !== null && _c !== void 0 ? _c : false,
404
+ surchargePercent: (_d = input.surchargePercent) !== null && _d !== void 0 ? _d : '0.00',
405
+ tipAmount: (_e = input.tipAmount) !== null && _e !== void 0 ? _e : '0.00',
377
406
  };
378
407
  if (billing.email)
379
408
  body.billingEmail = billing.email;
380
409
  if (billing.phone)
381
410
  body.billingPhone = billing.phone;
382
- if ((_d = billing.address) === null || _d === void 0 ? void 0 : _d.line1)
411
+ if ((_f = billing.address) === null || _f === void 0 ? void 0 : _f.line1)
383
412
  body.billingAddress1 = billing.address.line1;
384
- if ((_e = billing.address) === null || _e === void 0 ? void 0 : _e.line2)
413
+ if ((_g = billing.address) === null || _g === void 0 ? void 0 : _g.line2)
385
414
  body.billingAddress2 = billing.address.line2;
386
- if ((_f = billing.address) === null || _f === void 0 ? void 0 : _f.city)
415
+ if ((_h = billing.address) === null || _h === void 0 ? void 0 : _h.city)
387
416
  body.billingCity = billing.address.city;
388
- if ((_g = billing.address) === null || _g === void 0 ? void 0 : _g.state)
417
+ if ((_j = billing.address) === null || _j === void 0 ? void 0 : _j.state)
389
418
  body.billingState = billing.address.state;
390
- if ((_h = billing.address) === null || _h === void 0 ? void 0 : _h.zip)
419
+ if ((_k = billing.address) === null || _k === void 0 ? void 0 : _k.zip)
391
420
  body.billingZipcode = billing.address.zip;
392
- body.billingCountry = ((_j = billing.address) === null || _j === void 0 ? void 0 : _j.country) || 'US';
421
+ body.billingCountry = ((_l = billing.address) === null || _l === void 0 ? void 0 : _l.country) || 'US';
393
422
  if (input.processor) {
394
423
  body.processor = input.processor;
395
424
  }
@@ -457,7 +486,8 @@ class Ozura {
457
486
  * app.post('/api/oz-session', createSessionMiddleware(ozura));
458
487
  */
459
488
  async createSession(options) {
460
- var _a, _b, _c;
489
+ var _a, _b, _c, _d;
490
+ this.log('createSession', { sessionId: options === null || options === void 0 ? void 0 : options.sessionId, sessionLimit: (_a = options === null || options === void 0 ? void 0 : options.sessionLimit) !== null && _a !== void 0 ? _a : 3 });
461
491
  const body = {};
462
492
  if (options === null || options === void 0 ? void 0 : options.sessionId) {
463
493
  body.checkout_session_id = options.sessionId;
@@ -467,7 +497,7 @@ class Ozura {
467
497
  // sessionLimit: number → use that value.
468
498
  if ((options === null || options === void 0 ? void 0 : options.sessionLimit) === null) ;
469
499
  else {
470
- body.max_tokenize_calls = (_a = options === null || options === void 0 ? void 0 : options.sessionLimit) !== null && _a !== void 0 ? _a : 3;
500
+ body.max_tokenize_calls = (_b = options === null || options === void 0 ? void 0 : options.sessionLimit) !== null && _b !== void 0 ? _b : 3;
471
501
  }
472
502
  // maxProxyCalls: null → omit (unlimited). undefined → omit (vault default).
473
503
  if ((options === null || options === void 0 ? void 0 : options.maxProxyCalls) != null) {
@@ -483,6 +513,7 @@ class Ozura {
483
513
  body.metadata = options.metadata;
484
514
  if ((options === null || options === void 0 ? void 0 : options.ttlSeconds) != null)
485
515
  body.ttl_seconds = options.ttlSeconds;
516
+ const sessionStartMs = Date.now();
486
517
  const res = await this.fetchWithRetry(`${this.vaultUrl}/internal/wax-session`, {
487
518
  method: 'POST',
488
519
  headers: {
@@ -492,15 +523,16 @@ class Ozura {
492
523
  body: JSON.stringify(body),
493
524
  });
494
525
  const json = await res.json().catch(() => ({}));
495
- if (res.status === 201) {
526
+ this.log(`createSession → ${res.status} (${Date.now() - sessionStartMs}ms)`);
527
+ if (res.ok) {
496
528
  const data = json.data;
497
- const sessionKey = String((_b = data === null || data === void 0 ? void 0 : data.wax_key) !== null && _b !== void 0 ? _b : '');
529
+ const sessionKey = String((_c = data === null || data === void 0 ? void 0 : data.wax_key) !== null && _c !== void 0 ? _c : '');
498
530
  if (!sessionKey) {
499
531
  throw new OzuraError('Vault session response missing data.wax_key', res.status, JSON.stringify(json));
500
532
  }
501
533
  return {
502
534
  sessionKey,
503
- expiresInSeconds: Number((_c = data === null || data === void 0 ? void 0 : data.expires_in_seconds) !== null && _c !== void 0 ? _c : 1800),
535
+ expiresInSeconds: Number((_d = data === null || data === void 0 ? void 0 : data.expires_in_seconds) !== null && _d !== void 0 ? _d : 1800),
504
536
  };
505
537
  }
506
538
  const errorCode = json.error_code || '';
@@ -622,11 +654,20 @@ class Ozura {
622
654
  if (includeVaultKey) {
623
655
  headers['vault-api-key'] = this.vaultKey;
624
656
  }
625
- const res = await this.fetchWithRetry(`${this.apiUrl}${path}`, {
626
- method: 'POST',
627
- headers,
628
- body: JSON.stringify(body),
629
- }, maxRetries);
657
+ const postStartMs = Date.now();
658
+ let res;
659
+ try {
660
+ res = await this.fetchWithRetry(`${this.apiUrl}${path}`, {
661
+ method: 'POST',
662
+ headers,
663
+ body: JSON.stringify(body),
664
+ }, maxRetries);
665
+ }
666
+ catch (err) {
667
+ this.log(`POST ${path} ERROR (${Date.now() - postStartMs}ms)`, { error: err instanceof Error ? err.message : String(err) });
668
+ throw err;
669
+ }
670
+ this.log(`POST ${path} → ${res.status} (${Date.now() - postStartMs}ms)`, Ozura.redactBody(body));
630
671
  return this.handleResponse(res);
631
672
  }
632
673
  async getRaw(path) {