@ozura/elements 1.0.2 → 1.1.0-next.22

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 (42) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +234 -86
  3. package/dist/frame/element-frame.js +92 -20
  4. package/dist/frame/element-frame.js.map +1 -1
  5. package/dist/frame/tokenizer-frame.html +1 -1
  6. package/dist/frame/tokenizer-frame.js +20 -4
  7. package/dist/frame/tokenizer-frame.js.map +1 -1
  8. package/dist/oz-elements.esm.js +477 -251
  9. package/dist/oz-elements.esm.js.map +1 -1
  10. package/dist/oz-elements.umd.js +478 -251
  11. package/dist/oz-elements.umd.js.map +1 -1
  12. package/dist/react/frame/elementFrame.d.ts +70 -1
  13. package/dist/react/frame/protocol.d.ts +12 -0
  14. package/dist/react/index.cjs.js +447 -225
  15. package/dist/react/index.cjs.js.map +1 -1
  16. package/dist/react/index.esm.js +448 -226
  17. package/dist/react/index.esm.js.map +1 -1
  18. package/dist/react/react/index.d.ts +70 -26
  19. package/dist/react/sdk/OzVault.d.ts +55 -5
  20. package/dist/react/sdk/createSessionFetcher.d.ts +29 -0
  21. package/dist/react/sdk/index.d.ts +6 -26
  22. package/dist/react/server/index.d.ts +126 -74
  23. package/dist/react/types/index.d.ts +72 -31
  24. package/dist/server/frame/elementFrame.d.ts +70 -1
  25. package/dist/server/frame/protocol.d.ts +12 -0
  26. package/dist/server/index.cjs.js +167 -78
  27. package/dist/server/index.cjs.js.map +1 -1
  28. package/dist/server/index.esm.js +166 -79
  29. package/dist/server/index.esm.js.map +1 -1
  30. package/dist/server/sdk/OzVault.d.ts +55 -5
  31. package/dist/server/sdk/createSessionFetcher.d.ts +29 -0
  32. package/dist/server/sdk/index.d.ts +6 -26
  33. package/dist/server/server/index.d.ts +126 -74
  34. package/dist/server/types/index.d.ts +72 -31
  35. package/dist/types/frame/elementFrame.d.ts +70 -1
  36. package/dist/types/frame/protocol.d.ts +12 -0
  37. package/dist/types/sdk/OzVault.d.ts +55 -5
  38. package/dist/types/sdk/createSessionFetcher.d.ts +29 -0
  39. package/dist/types/sdk/index.d.ts +6 -26
  40. package/dist/types/server/index.d.ts +126 -74
  41. package/dist/types/types/index.d.ts +72 -31
  42. package/package.json +1 -1
@@ -44,6 +44,8 @@ export declare class OzVault {
44
44
  private tokenizerReady;
45
45
  private _tokenizing;
46
46
  private _destroyed;
47
+ private _resetCount;
48
+ private _debug;
47
49
  private _tokenizeSuccessCount;
48
50
  private _maxTokenizeCalls;
49
51
  private boundHandleMessage;
@@ -66,18 +68,19 @@ export declare class OzVault {
66
68
  * Creates and returns a ready `OzVault` instance.
67
69
  *
68
70
  * Internally this:
69
- * 1. Generates a `tokenizationSessionId` (UUID).
71
+ * 1. Generates a session UUID.
70
72
  * 2. Starts loading the hidden tokenizer iframe immediately.
71
- * 3. Calls `options.fetchWaxKey(tokenizationSessionId)` concurrently — your
72
- * backend mints a session-bound wax key from the vault and returns it.
73
- * 4. Resolves with the vault instance once the wax key is stored. The iframe
73
+ * 3. Fetches a session key from your backend concurrently — either via
74
+ * `sessionUrl` (simplest), `getSessionKey` (custom headers/auth), or the
75
+ * deprecated `fetchWaxKey` callback.
76
+ * 4. Resolves with the vault instance once the session key is stored. The iframe
74
77
  * has been loading the whole time, so `isReady` may already be true or
75
78
  * will fire shortly after.
76
79
  *
77
80
  * The returned vault is ready to create elements immediately. `createToken()`
78
81
  * additionally requires `vault.isReady` (tokenizer iframe loaded).
79
82
  *
80
- * @throws {OzError} if `fetchWaxKey` throws, returns a non-string value, or returns an empty/whitespace-only string.
83
+ * @throws {OzError} if the session fetch fails, times out, or returns an empty string.
81
84
  */
82
85
  static create(options: VaultOptions, signal?: AbortSignal): Promise<OzVault>;
83
86
  /**
@@ -155,6 +158,29 @@ export declare class OzVault {
155
158
  * Returns a token and cvcSession that can be passed to the Ozura Pay API.
156
159
  */
157
160
  createToken(options?: TokenizeOptions): Promise<TokenResponse>;
161
+ /**
162
+ * Clears all mounted element fields without tearing down the vault.
163
+ *
164
+ * Call this after a failed payment (e.g. card declined) to let the customer
165
+ * re-enter their details. The vault instance, tokenizer iframe, wax key, and
166
+ * tokenization budget counter are all preserved — no network calls are made.
167
+ *
168
+ * **Wax key session model:** by design, one wax key covers the full checkout
169
+ * session. The default `max_tokenize_calls: 3` supports two declined attempts
170
+ * and one final attempt on the same key. Do not call `vault.destroy()` and
171
+ * recreate the vault between declines — that unnecessarily re-mints the key
172
+ * and discards the remaining budget.
173
+ *
174
+ * @example
175
+ * try {
176
+ * const { token, cvcSession } = await vault.createToken({ billing });
177
+ * await chargeCard(token, cvcSession);
178
+ * } catch (err) {
179
+ * vault.reset(); // clear fields; let customer re-enter
180
+ * showError(err.message);
181
+ * }
182
+ */
183
+ reset(): void;
158
184
  /**
159
185
  * Tears down the vault: removes all element iframes, the tokenizer iframe,
160
186
  * and the global message listener. Call this when the checkout component
@@ -172,6 +198,30 @@ export declare class OzVault {
172
198
  * while avoiding spurious refreshes for brief tab-switches.
173
199
  */
174
200
  private handleVisibilityChange;
201
+ /**
202
+ * Emits a `[OzVault]`-prefixed entry to `console.log`. No-op when `debug` is
203
+ * not set. Never called with sensitive values — callers use presence flags only.
204
+ */
205
+ private log;
206
+ /**
207
+ * Returns a plain-object snapshot of the vault's current internal state.
208
+ * Safe to attach to bug reports — no wax keys, tokens, or billing data included.
209
+ *
210
+ * Available on all vault instances regardless of whether `debug` was enabled.
211
+ *
212
+ * @example
213
+ * console.log(vault.debugState());
214
+ * // {
215
+ * // vaultId: 'vault-abc123',
216
+ * // isReady: true,
217
+ * // tokenizing: null,
218
+ * // destroyed: false,
219
+ * // waxKeyPresent: true,
220
+ * // elements: ['cardNumber', 'expirationDate', 'cvv'],
221
+ * // ...
222
+ * // }
223
+ */
224
+ debugState(): Record<string, unknown>;
175
225
  private mountTokenizerFrame;
176
226
  private handleMessage;
177
227
  /**
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Creates a `getSessionKey` callback for `OzVault.create()` and `<OzElements>`.
3
+ *
4
+ * This is the recommended way to wire the SDK to your backend session endpoint.
5
+ * If you don't need custom headers or auth logic, pass `sessionUrl` directly to
6
+ * `OzVault.create()` or `<OzElements>` — it calls this helper internally.
7
+ *
8
+ * The callback POSTs `{ sessionId }` to `url` and reads `sessionKey` (or the
9
+ * legacy `waxKey`) from the JSON response, so it is compatible with both the
10
+ * new `createSessionMiddleware` and the old `createMintWaxMiddleware` backends.
11
+ *
12
+ * Each call enforces a **10-second timeout**. On pure network failures
13
+ * (offline, DNS, connection refused) the request is retried **once after 750ms**.
14
+ * HTTP 4xx/5xx errors are never retried — they indicate misconfiguration.
15
+ *
16
+ * @param url - Absolute or relative URL of your session endpoint, e.g. `'/api/oz-session'`.
17
+ *
18
+ * @example
19
+ * // Simplest — just pass sessionUrl, no need to call this directly
20
+ * const vault = await OzVault.create({ pubKey: 'pk_live_...', sessionUrl: '/api/oz-session' });
21
+ *
22
+ * @example
23
+ * // Manual — use when you need custom headers
24
+ * const vault = await OzVault.create({
25
+ * pubKey: 'pk_live_...',
26
+ * getSessionKey: createSessionFetcher('/api/oz-session'),
27
+ * });
28
+ */
29
+ export declare function createSessionFetcher(url: string): (sessionId: string) => Promise<string>;
@@ -1,34 +1,14 @@
1
1
  export { OzVault } from './OzVault';
2
2
  export { OzElement } from './OzElement';
3
3
  export { OzError, normalizeVaultError, normalizeBankVaultError, normalizeCardSaleError } from './errors';
4
+ export { createSessionFetcher } from './createSessionFetcher';
4
5
  /**
5
- * Creates a ready-to-use `fetchWaxKey` callback for `OzVault.create()` and `<OzElements>`.
6
+ * @deprecated Use `sessionUrl` on `VaultOptions` / `OzElementsProps` instead
7
+ * it calls `createSessionFetcher` internally and requires no extra code.
6
8
  *
7
- * Calls your backend mint endpoint with `{ sessionId }` and returns the wax key string.
8
- * Throws on non-OK responses or a missing `waxKey` field so the vault can surface the
9
- * error through its normal error path.
10
- *
11
- * Each call enforces a 10-second per-attempt timeout. On a pure network-level
12
- * failure (connection refused, DNS failure, etc.) the call is retried once after
13
- * 750ms before throwing. HTTP errors (4xx/5xx) are never retried — they indicate
14
- * an endpoint misconfiguration or an invalid key, not a transient failure.
15
- *
16
- * The mint endpoint is typically the one-line `createMintWaxHandler` / `createMintWaxMiddleware`
17
- * from `@ozura/elements/server`.
18
- *
19
- * @param mintUrl - Absolute or relative URL of your wax-key mint endpoint, e.g. `'/api/mint-wax'`.
20
- *
21
- * @example
22
- * // Vanilla JS
23
- * const vault = await OzVault.create({
24
- * pubKey: 'pk_live_...',
25
- * fetchWaxKey: createFetchWaxKey('/api/mint-wax'),
26
- * });
27
- *
28
- * @example
29
- * // React
30
- * <OzElements pubKey="pk_live_..." fetchWaxKey={createFetchWaxKey('/api/mint-wax')}>
9
+ * For custom request logic (auth headers etc.), use `createSessionFetcher` or
10
+ * write a `getSessionKey` callback inline.
31
11
  */
32
- export declare function createFetchWaxKey(mintUrl: string): (sessionId: string) => Promise<string>;
12
+ export { createSessionFetcher as createFetchWaxKey } from './createSessionFetcher';
33
13
  export type { OzErrorCode } from './errors';
34
14
  export type { ElementType, BankElementType, ElementOptions, ElementStyleConfig, ElementStyle, ElementChangeEvent, VaultOptions, TokenizeOptions, BankTokenizeOptions, TokenResponse, BankTokenResponse, CardMetadata, BankAccountMetadata, FontSource, CssFontSource, CustomFontSource, BillingDetails, BillingAddress, CardSaleRequest, CardSaleResponseData, CardSaleApiResponse, Appearance, AppearanceVariables, OzTheme, TransactionQueryParams, TransactionQueryPagination, TransactionQueryResponse, TransactionType, CardTransactionType, AchTransactionType, CryptoTransactionType, TransactionBase, CardTransactionData, AchTransactionData, CryptoTransactionData, TransactionData, } from '../types';
@@ -38,12 +38,12 @@ export interface OzuraConfig {
38
38
  * Required for `cardSale()`. Tokenize-only integrations can omit this.
39
39
  */
40
40
  apiKey?: string;
41
- /** Vault API key — used for `mintWaxKey()` and `revokeWaxKey()`. Always required. */
41
+ /** Vault API key — used for `createSession()` and `revokeSession()`. Always required. */
42
42
  vaultKey: string;
43
43
  /** Ozura Pay API base URL. Defaults to staging. */
44
44
  apiUrl?: string;
45
45
  /**
46
- * Ozura Vault base URL. Used for `mintWaxKey` and `revokeWaxKey`.
46
+ * Ozura Vault base URL. Used for `createSession` and `revokeSession`.
47
47
  * Defaults to the build-time vault URL (staging or production).
48
48
  */
49
49
  vaultUrl?: string;
@@ -58,41 +58,81 @@ export declare class OzuraError extends Error {
58
58
  readonly retryAfter?: number;
59
59
  constructor(message: string, statusCode: number, raw?: string, retryAfter?: number);
60
60
  }
61
- export interface MintWaxKeyResult {
62
- /** Wax key UUID pass as the `X-Wax-Key` header on vault tokenize calls. */
63
- waxKey: string;
64
- /** Seconds until the wax key expires. Typically 1800 (30 min). */
61
+ /**
62
+ * Result of {@link Ozura.createSession} / {@link Ozura.mintWaxKey}.
63
+ */
64
+ export interface CreateSessionResult {
65
+ /** Session key — the SDK transmits this on every tokenize call. */
66
+ sessionKey: string;
67
+ /** Seconds until the session expires. Typically 1800 (30 min). */
65
68
  expiresInSeconds: number;
66
69
  }
67
70
  /**
68
- * Options for {@link Ozura.mintWaxKey}.
71
+ * Options for {@link Ozura.createSession} / {@link Ozura.mintWaxKey}.
69
72
  */
70
- export interface MintWaxKeyOptions {
73
+ export interface CreateSessionOptions {
71
74
  /**
72
- * SDK-generated session UUID forwarded from the `fetchWaxKey` callback.
73
- * Stored by the vault for correlation and audit — not used for authentication.
75
+ * SDK-generated session UUID forwarded from the `getSessionKey` /
76
+ * `fetchWaxKey` callback. Stored by the vault for correlation and audit.
74
77
  */
75
- tokenizationSessionId?: string;
78
+ sessionId?: string;
76
79
  /**
77
- * Maximum number of tokenize calls this wax key will accept before the vault
78
- * marks it as consumed. Once consumed, further tokenize attempts return an
79
- * auth/validation error and the client SDK automatically re-mints a fresh key.
80
+ * Maximum number of card submissions this session accepts before the SDK
81
+ * automatically refreshes it. Keep this in sync with `sessionLimit` in
82
+ * `VaultOptions` so the client can proactively refresh without a user-
83
+ * visible delay.
80
84
  *
81
- * Keep this value small (3–5) to limit the blast radius if a key is intercepted.
82
- * Set the same value in `VaultOptions.maxTokenizeCalls` so the client SDK can
83
- * proactively refresh before hitting the wall, avoiding a user-visible delay.
85
+ * Pass `null` to remove the cap entirely (the vault will accept unlimited
86
+ * tokenize calls until the session TTL elapses). Only do this for flows
87
+ * where the same session genuinely needs more than 3 submissions.
84
88
  *
85
89
  * @default 3
86
90
  */
87
- maxTokenizeCalls?: number;
91
+ sessionLimit?: number | null;
88
92
  /**
89
- * Maximum number of proxy calls this wax key will accept.
90
- * Proxy calls are distinct from tokenize calls they cover non-tokenize vault
91
- * operations. Leave `undefined` to use the vault's built-in default.
92
- *
93
- * In most integrations you only need `maxTokenizeCalls`; set this only if you
94
- * are explicitly using vault proxy endpoints.
93
+ * Maximum number of proxy calls this session accepts.
94
+ * Only relevant if you use vault proxy endpoints directly.
95
+ * Pass `null` to remove the proxy cap.
96
+ */
97
+ maxProxyCalls?: number | null;
98
+ /**
99
+ * Your internal order or checkout ID. Stored alongside the session in the
100
+ * vault audit log so you can correlate vault events with your own records.
101
+ */
102
+ orderId?: string;
103
+ /**
104
+ * Your internal customer ID. Stored in the vault audit log for correlation.
105
+ */
106
+ customerId?: string;
107
+ /**
108
+ * Your internal cart or basket ID. Stored in the vault audit log for correlation.
95
109
  */
110
+ cartId?: string;
111
+ /**
112
+ * Arbitrary key/value metadata (string values only) stored with the session
113
+ * in the vault audit log. Max 16 keys, 64-char keys, 256-char values.
114
+ */
115
+ metadata?: Record<string, string>;
116
+ /**
117
+ * Session lifetime in seconds (60–1800). Defaults to 1800 (30 minutes).
118
+ * Only set this if your checkout flow is shorter than 30 minutes and you want
119
+ * the session to expire sooner as a defense-in-depth measure.
120
+ */
121
+ ttlSeconds?: number;
122
+ }
123
+ /** @deprecated Use {@link CreateSessionResult} instead. */
124
+ export interface MintWaxKeyResult {
125
+ /** @deprecated Use `sessionKey` from {@link CreateSessionResult} instead. */
126
+ waxKey: string;
127
+ /** Seconds until the session expires. Typically 1800 (30 min). */
128
+ expiresInSeconds: number;
129
+ }
130
+ /** @deprecated Use {@link CreateSessionOptions} instead. */
131
+ export interface MintWaxKeyOptions {
132
+ /** @deprecated Use `sessionId` from {@link CreateSessionOptions} instead. */
133
+ tokenizationSessionId?: string;
134
+ /** @deprecated Use `sessionLimit` from {@link CreateSessionOptions} instead. */
135
+ maxTokenizeCalls?: number;
96
136
  maxProxyCalls?: number;
97
137
  }
98
138
  export interface CardSaleInput {
@@ -155,48 +195,52 @@ export declare class Ozura {
155
195
  */
156
196
  listTransactions(input?: ListTransactionsInput): Promise<ListTransactionsResult>;
157
197
  /**
158
- * Mint a short-lived, use-limited wax key from the vault.
159
- *
160
- * Call this server-side to implement the `fetchWaxKey` callback required by
161
- * `OzVault.create()` on the frontend. The wax key replaces the vault secret
162
- * on every browser tokenize call — the secret never leaves your server.
198
+ * Creates a short-lived payment session key from the vault.
163
199
  *
164
- * **Use limits:** by default each wax key accepts up to 3 tokenize calls
165
- * (`maxTokenizeCalls: 3`). After that the vault marks the key as consumed and
166
- * the client SDK transparently re-mints. Keep `maxTokenizeCalls` in sync with
167
- * `VaultOptions.maxTokenizeCalls` so the SDK can proactively refresh before
168
- * hitting the limit rather than waiting for a rejection.
200
+ * Call this from your session endpoint (created with `createSessionMiddleware`
201
+ * or `createSessionHandler`) to issue a key that the frontend SDK will use for
202
+ * tokenization. The vault secret never leaves your server.
169
203
  *
170
- * **Session correlation:** the `tokenizationSessionId` forwarded from the SDK's
171
- * `fetchWaxKey` callback should be passed here so the vault can correlate the
172
- * key with the checkout session in its audit log.
204
+ * **Use limits:** each session key accepts up to `sessionLimit` (default 3)
205
+ * card submissions. After that the SDK automatically fetches a new session.
206
+ * Set `sessionLimit` to the same value in `VaultOptions` / `OzElementsProps`
207
+ * so the client can refresh proactively before hitting the limit.
173
208
  *
174
209
  * @example
175
- * // Next.js API route
210
+ * // Manual route (Next.js App Router)
176
211
  * export async function POST(req: Request) {
177
212
  * const { sessionId } = await req.json();
178
- * const { waxKey } = await ozura.mintWaxKey({
179
- * tokenizationSessionId: sessionId,
180
- * maxTokenizeCalls: 3,
181
- * });
182
- * return Response.json({ waxKey });
213
+ * const { sessionKey } = await ozura.createSession({ sessionId });
214
+ * return Response.json({ sessionKey });
183
215
  * }
216
+ *
217
+ * @example
218
+ * // One-liner with createSessionMiddleware (Express)
219
+ * app.post('/api/oz-session', createSessionMiddleware(ozura));
184
220
  */
185
- mintWaxKey(options?: MintWaxKeyOptions): Promise<MintWaxKeyResult>;
221
+ createSession(options?: CreateSessionOptions): Promise<CreateSessionResult>;
186
222
  /**
187
- * Revoke a previously minted wax key.
223
+ * Revokes a payment session key.
188
224
  *
189
- * Best-effort: never throws. Call this when the user's session ends (payment
190
- * complete, cancelled, or expired) to close the exposure window before the
191
- * vault TTL (30 min) elapses.
225
+ * Best-effort: never throws. Call this when the user's checkout ends (payment
226
+ * complete, cancelled, or abandoned) to close the key's exposure window before
227
+ * the vault TTL (30 min) elapses.
192
228
  *
193
229
  * - 200 = revoked successfully.
194
230
  * - 404 = key already expired or not found — treated as success.
195
- * - 503 = Redis error; the wax may still be valid. Retry if needed.
231
+ * - 503 = Redis error; the key may still be valid. Retry if needed.
196
232
  *
197
233
  * @example
198
234
  * // After a successful card sale:
199
- * await ozura.revokeWaxKey(waxKey);
235
+ * await ozura.revokeSession(sessionKey);
236
+ */
237
+ revokeSession(sessionKey: string): Promise<void>;
238
+ /**
239
+ * @deprecated Use {@link createSession} instead.
240
+ */
241
+ mintWaxKey(options?: MintWaxKeyOptions): Promise<MintWaxKeyResult>;
242
+ /**
243
+ * @deprecated Use {@link revokeSession} instead.
200
244
  */
201
245
  revokeWaxKey(waxKey: string): Promise<void>;
202
246
  /**
@@ -214,7 +258,7 @@ export declare class Ozura {
214
258
  */
215
259
  private parseApiJson;
216
260
  }
217
- /** Minimal response shape required by {@link createMintWaxMiddleware}. */
261
+ /** Minimal response shape required by {@link createSessionMiddleware}. */
218
262
  interface NodeLikeResponse {
219
263
  json(data: unknown): void;
220
264
  status(code: number): NodeLikeResponse;
@@ -222,52 +266,60 @@ interface NodeLikeResponse {
222
266
  setHeader?(name: string, value: string | number): void;
223
267
  }
224
268
  /**
225
- * Creates a ready-to-use Fetch API route handler for minting wax keys.
269
+ * Creates a ready-to-use Fetch API route handler for payment session creation.
226
270
  *
227
271
  * Drop-in for Next.js App Router, Cloudflare Workers, Vercel Edge, and any
228
272
  * runtime built on the standard Web API `Request` / `Response`.
229
273
  *
230
- * The handler reads `sessionId` (or `tokenizationSessionId`) from the JSON
231
- * request body, calls `ozura.mintWaxKey()`, and returns `{ waxKey }`.
274
+ * The handler reads `sessionId` from the JSON request body, calls
275
+ * `ozura.createSession()`, and returns `{ sessionKey }`.
232
276
  * On error it returns `{ error }` with an appropriate HTTP status.
233
277
  *
234
- * @example
235
- * // app/api/mint-wax/route.ts (Next.js App Router)
236
- * import { Ozura, createMintWaxHandler } from '@ozura/elements/server';
278
+ * Pair with `sessionUrl` on the frontend — no other configuration needed.
237
279
  *
238
- * const ozura = new Ozura({
239
- * merchantId: process.env.MERCHANT_ID!,
240
- * apiKey: process.env.MERCHANT_API_KEY!,
241
- * vaultKey: process.env.VAULT_API_KEY!,
242
- * });
280
+ * @example
281
+ * // app/api/oz-session/route.ts (Next.js App Router)
282
+ * import { Ozura, createSessionHandler } from '@ozura/elements/server';
243
283
  *
244
- * export const POST = createMintWaxHandler(ozura);
284
+ * const ozura = new Ozura({ vaultKey: process.env.VAULT_API_KEY! });
285
+ * export const POST = createSessionHandler(ozura);
245
286
  */
246
- export declare function createMintWaxHandler(ozura: Ozura): (req: Request) => Promise<Response>;
287
+ export declare function createSessionHandler(ozura: Ozura): (req: Request) => Promise<Response>;
247
288
  /**
248
- * Creates a ready-to-use Express / Connect middleware for minting wax keys.
289
+ * Creates a ready-to-use Express / Connect middleware for payment session creation.
249
290
  *
250
291
  * Requires `express.json()` (or equivalent body-parser) to be registered
251
292
  * before this middleware so `req.body` is available.
252
293
  *
253
- * The middleware reads `sessionId` (or `tokenizationSessionId`) from
254
- * `req.body`, calls `ozura.mintWaxKey()`, and sends `{ waxKey }`.
294
+ * The middleware reads `sessionId` from `req.body`, calls
295
+ * `ozura.createSession()`, and sends `{ sessionKey }`.
255
296
  * On error it sends `{ error }` with an appropriate HTTP status.
256
297
  *
298
+ * Pair with `sessionUrl` on the frontend — no other configuration needed.
299
+ *
257
300
  * @example
258
301
  * // Express
259
302
  * import express from 'express';
260
- * import { Ozura, createMintWaxMiddleware } from '@ozura/elements/server';
303
+ * import { Ozura, createSessionMiddleware } from '@ozura/elements/server';
261
304
  *
262
- * const ozura = new Ozura({
263
- * merchantId: process.env.MERCHANT_ID!,
264
- * apiKey: process.env.MERCHANT_API_KEY!,
265
- * vaultKey: process.env.VAULT_API_KEY!,
266
- * });
305
+ * const ozura = new Ozura({ vaultKey: process.env.VAULT_API_KEY! });
267
306
  *
268
307
  * const app = express();
269
308
  * app.use(express.json());
270
- * app.post('/api/mint-wax', createMintWaxMiddleware(ozura));
309
+ * app.post('/api/oz-session', createSessionMiddleware(ozura));
310
+ */
311
+ export declare function createSessionMiddleware(ozura: Ozura): (req: {
312
+ body?: unknown;
313
+ headers?: unknown;
314
+ }, res: NodeLikeResponse) => Promise<void>;
315
+ /**
316
+ * @deprecated Use {@link createSessionHandler} instead.
317
+ * Returns `{ waxKey }` for backward compatibility with old `createFetchWaxKey` backends.
318
+ */
319
+ export declare function createMintWaxHandler(ozura: Ozura): (req: Request) => Promise<Response>;
320
+ /**
321
+ * @deprecated Use {@link createSessionMiddleware} instead.
322
+ * Sends `{ waxKey }` for backward compatibility with old `createFetchWaxKey` clients.
271
323
  */
272
324
  export declare function createMintWaxMiddleware(ozura: Ozura): (req: {
273
325
  body?: unknown;
@@ -156,35 +156,49 @@ export interface VaultOptions {
156
156
  * Sent as the `X-Pub-Key` header on tokenize requests. */
157
157
  pubKey: string;
158
158
  /**
159
- * Called by the SDK with a SDK-generated `tokenizationSessionId` UUID during
160
- * `OzVault.create()`. Implement this to call your backend, which should mint a
161
- * wax key from the vault using your vault secret and return it here.
159
+ * URL of your backend session endpoint. The simplest way to connect the SDK
160
+ * to your server just pass the path and the SDK handles everything else.
162
161
  *
163
- * The wax key is a short-lived, session-scoped credential (TTL ~30 min).
164
- * It replaces the vault secret on every browser tokenize call — the secret
165
- * never leaves your server.
162
+ * The endpoint should be created with `createSessionMiddleware` or
163
+ * `createSessionHandler` from `@ozura/elements/server`.
166
164
  *
167
- * **Server-side (recommended):** Use `ozura.mintWaxKey()` from `@ozura/elements/server`:
168
165
  * @example
169
- * // Your API route (e.g. Next.js App Router):
170
- * // POST /api/mint-wax
171
- * // const { sessionId } = await req.json();
172
- * // const { waxKey } = await ozura.mintWaxKey({ tokenizationSessionId: sessionId });
173
- * // return Response.json({ waxKey });
166
+ * // Backend (Express)
167
+ * app.post('/api/oz-session', createSessionMiddleware(ozura));
168
+ *
169
+ * // Frontend
170
+ * OzVault.create({ pubKey: 'pk_live_...', sessionUrl: '/api/oz-session' })
171
+ */
172
+ sessionUrl?: string;
173
+ /**
174
+ * Custom async function to obtain a session key from your backend.
175
+ * Use this when you need custom headers, auth tokens, or request logic that
176
+ * `sessionUrl` cannot provide.
177
+ *
178
+ * Receives an SDK-generated session UUID; your implementation passes it to
179
+ * your backend, which calls `ozura.createSession()` and returns the key.
180
+ *
181
+ * For the common case, prefer `sessionUrl` — it wraps this automatically.
174
182
  *
175
- * **Client-side (fetchWaxKey callback):**
176
183
  * @example
177
- * fetchWaxKey: async (sessionId) => {
178
- * const res = await fetch('/api/mint-wax', {
184
+ * getSessionKey: async (sessionId) => {
185
+ * const res = await fetch('/api/oz-session', {
179
186
  * method: 'POST',
180
- * headers: { 'Content-Type': 'application/json' },
187
+ * headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
181
188
  * body: JSON.stringify({ sessionId }),
182
189
  * });
183
- * const { waxKey } = await res.json();
184
- * return waxKey;
190
+ * const { sessionKey } = await res.json();
191
+ * return sessionKey;
185
192
  * }
186
193
  */
187
- fetchWaxKey: (tokenizationSessionId: string) => Promise<string>;
194
+ getSessionKey?: (sessionId: string) => Promise<string>;
195
+ /**
196
+ * @deprecated Use `sessionUrl` or `getSessionKey` instead.
197
+ *
198
+ * Legacy callback name. Equivalent to `getSessionKey` — both are supported
199
+ * and work identically. `fetchWaxKey` will be removed in a future major version.
200
+ */
201
+ fetchWaxKey?: (tokenizationSessionId: string) => Promise<string>;
188
202
  /** Base URL where the Ozura frame HTML/JS assets are served from.
189
203
  * Defaults to the production CDN. Override for local development. */
190
204
  frameBaseUrl?: string;
@@ -211,25 +225,32 @@ export interface VaultOptions {
211
225
  * Only takes effect when `onLoadError` is also provided — setting this without `onLoadError` has no effect. */
212
226
  loadTimeoutMs?: number;
213
227
  /**
214
- * Called when the SDK silently re-mints the wax key during a tokenization
215
- * attempt (expiry or consumption). The `createToken()` / `createBankToken()`
216
- * promise stays pending until the refresh completes and the retry resolves.
217
- * Use this to show a loading indicator while the re-mint round trip is in flight.
228
+ * Called when the SDK silently refreshes the payment session mid-checkout
229
+ * (e.g. after the session is consumed or expires). The `createToken()` /
230
+ * `createBankToken()` promise stays pending until the refresh completes.
231
+ * Use this to show a loading indicator while the refresh is in progress.
232
+ */
233
+ onSessionRefresh?: () => void;
234
+ /**
235
+ * @deprecated Use `onSessionRefresh` instead.
218
236
  */
219
237
  onWaxRefresh?: () => void;
220
238
  /**
221
- * Maximum number of tokenize calls each minted wax key accepts before the
222
- * vault marks it as consumed. Should match the `maxTokenizeCalls` passed to
223
- * `ozura.mintWaxKey()` on your server (both default to `3`).
239
+ * Maximum number of card submissions allowed per session before the SDK
240
+ * automatically refreshes the session in the background. Defaults to `3`.
224
241
  *
225
- * The SDK uses this value to proactively refresh the wax key after it has been
226
- * fully consumed before the next `createToken()` call is made — so users
227
- * never experience a delay from a reactive re-mint. If the values are out of
228
- * sync the reactive refresh path still catches consumption errors; this is
229
- * purely an optimisation.
242
+ * Must match the `sessionLimit` (or `maxTokenizeCalls`) passed to
243
+ * `ozura.createSession()` on your server. Both default to `3` so you only
244
+ * need this if you override the server-side value.
230
245
  *
231
246
  * @default 3
232
247
  */
248
+ sessionLimit?: number;
249
+ /**
250
+ * @deprecated Use `sessionLimit` instead.
251
+ * Maximum number of tokenize calls per session. Equivalent to `sessionLimit`.
252
+ * @default 3
253
+ */
233
254
  maxTokenizeCalls?: number;
234
255
  /**
235
256
  * Called once when the tokenizer iframe has loaded and is ready to accept
@@ -256,6 +277,24 @@ export interface VaultOptions {
256
277
  * }
257
278
  */
258
279
  appearance?: Appearance;
280
+ /**
281
+ * Enables structured debug logging to the browser console.
282
+ *
283
+ * When `true`, the vault emits a `[OzVault]`-prefixed `console.log` entry at
284
+ * every meaningful lifecycle event: vault creation, tokenizer readiness, element
285
+ * readiness, field changes, tokenization start/result/error, wax key refresh,
286
+ * tab-visibility refreshes, `reset()`, and `destroy()`.
287
+ *
288
+ * **No sensitive data is ever logged.** Wax keys, tokens, CVC sessions, and
289
+ * billing fields are represented only as boolean presence flags. Frame IDs and
290
+ * request IDs are truncated. Output is safe to paste directly into bug reports.
291
+ *
292
+ * Use `vault.debugState()` to capture a full snapshot of internal state at any
293
+ * point, regardless of whether `debug` is enabled.
294
+ *
295
+ * @default false
296
+ */
297
+ debug?: boolean;
259
298
  }
260
299
  /** Billing address. All string fields are validated to 1–50 characters. */
261
300
  export interface BillingAddress {
@@ -593,6 +632,8 @@ export interface TransactionQueryResponse {
593
632
  export type OzMessageType = 'OZ_FRAME_READY' | 'OZ_INIT' | 'OZ_UPDATE' | 'OZ_CLEAR' | 'OZ_CHANGE' | 'OZ_FOCUS' | 'OZ_BLUR' | 'OZ_RESIZE' | 'OZ_BEGIN_COLLECT' | 'OZ_FIELD_VALUE' | 'OZ_TOKENIZE' | 'OZ_TOKEN_RESULT' | 'OZ_TOKEN_ERROR' | 'OZ_FOCUS_REQUEST' | 'OZ_BLUR_REQUEST' | 'OZ_SET_CVV_LENGTH' | 'OZ_BANK_TOKENIZE' | 'OZ_BANK_TOKEN_RESULT' | 'OZ_TOKENIZE_CANCEL';
594
633
  export interface OzMessage {
595
634
  __oz: true;
635
+ /** Protocol version stamped by the frame on OZ_FRAME_READY. Read by the SDK to detect stale CDN frames. */
636
+ __ozVersion?: number;
596
637
  vaultId: string;
597
638
  type: OzMessageType;
598
639
  [key: string]: unknown;