@ozura/elements 0.1.0-beta.6 → 1.0.0
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.
- package/README.md +1121 -720
- package/dist/frame/element-frame.js +77 -57
- package/dist/frame/element-frame.js.map +1 -1
- package/dist/frame/tokenizer-frame.html +1 -1
- package/dist/frame/tokenizer-frame.js +221 -74
- package/dist/frame/tokenizer-frame.js.map +1 -1
- package/dist/oz-elements.esm.js +870 -231
- package/dist/oz-elements.esm.js.map +1 -1
- package/dist/oz-elements.umd.js +870 -230
- package/dist/oz-elements.umd.js.map +1 -1
- package/dist/react/frame/tokenizerFrame.d.ts +32 -0
- package/dist/react/index.cjs.js +1045 -220
- package/dist/react/index.cjs.js.map +1 -1
- package/dist/react/index.esm.js +1042 -221
- package/dist/react/index.esm.js.map +1 -1
- package/dist/react/react/index.d.ts +165 -8
- package/dist/react/sdk/OzElement.d.ts +34 -3
- package/dist/react/sdk/OzVault.d.ts +104 -4
- package/dist/react/sdk/errors.d.ts +9 -0
- package/dist/react/sdk/index.d.ts +29 -0
- package/dist/react/server/index.d.ts +266 -2
- package/dist/react/types/index.d.ts +94 -16
- package/dist/react/utils/appearance.d.ts +9 -0
- package/dist/react/utils/cardUtils.d.ts +14 -0
- package/dist/react/utils/uuid.d.ts +12 -0
- package/dist/server/frame/tokenizerFrame.d.ts +32 -0
- package/dist/server/index.cjs.js +761 -30
- package/dist/server/index.cjs.js.map +1 -1
- package/dist/server/index.esm.js +757 -31
- package/dist/server/index.esm.js.map +1 -1
- package/dist/server/sdk/OzElement.d.ts +34 -3
- package/dist/server/sdk/OzVault.d.ts +104 -4
- package/dist/server/sdk/errors.d.ts +9 -0
- package/dist/server/sdk/index.d.ts +29 -0
- package/dist/server/server/index.d.ts +266 -2
- package/dist/server/types/index.d.ts +94 -16
- package/dist/server/utils/appearance.d.ts +9 -0
- package/dist/server/utils/cardUtils.d.ts +14 -0
- package/dist/server/utils/uuid.d.ts +12 -0
- package/dist/types/frame/tokenizerFrame.d.ts +32 -0
- package/dist/types/sdk/OzElement.d.ts +34 -3
- package/dist/types/sdk/OzVault.d.ts +104 -4
- package/dist/types/sdk/errors.d.ts +9 -0
- package/dist/types/sdk/index.d.ts +29 -0
- package/dist/types/server/index.d.ts +266 -2
- package/dist/types/types/index.d.ts +94 -16
- package/dist/types/utils/appearance.d.ts +9 -0
- package/dist/types/utils/cardUtils.d.ts +14 -0
- package/dist/types/utils/uuid.d.ts +12 -0
- package/package.json +7 -4
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @example
|
|
8
8
|
* ```ts
|
|
9
|
-
* import { Ozura } from '
|
|
9
|
+
* import { Ozura } from '@ozura/elements/server';
|
|
10
10
|
*
|
|
11
11
|
* const ozura = new Ozura({
|
|
12
12
|
* merchantId: process.env.MERCHANT_ID!,
|
|
@@ -36,6 +36,11 @@ export interface OzuraConfig {
|
|
|
36
36
|
vaultKey: string;
|
|
37
37
|
/** Ozura Pay API base URL. Defaults to staging. */
|
|
38
38
|
apiUrl?: string;
|
|
39
|
+
/**
|
|
40
|
+
* Ozura Vault base URL. Used for `mintWaxKey` and `revokeWaxKey`.
|
|
41
|
+
* Defaults to the build-time vault URL (staging or production).
|
|
42
|
+
*/
|
|
43
|
+
vaultUrl?: string;
|
|
39
44
|
/** Request timeout in milliseconds. Default: 30000. */
|
|
40
45
|
timeoutMs?: number;
|
|
41
46
|
/** Max retry attempts for 5xx / network errors. Default: 2 (up to 3 total attempts). Set 0 to disable. */
|
|
@@ -47,6 +52,43 @@ export declare class OzuraError extends Error {
|
|
|
47
52
|
readonly retryAfter?: number;
|
|
48
53
|
constructor(message: string, statusCode: number, raw?: string, retryAfter?: number);
|
|
49
54
|
}
|
|
55
|
+
export interface MintWaxKeyResult {
|
|
56
|
+
/** Wax key UUID — pass as the `X-Wax-Key` header on vault tokenize calls. */
|
|
57
|
+
waxKey: string;
|
|
58
|
+
/** Seconds until the wax key expires. Typically 1800 (30 min). */
|
|
59
|
+
expiresInSeconds: number;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Options for {@link Ozura.mintWaxKey}.
|
|
63
|
+
*/
|
|
64
|
+
export interface MintWaxKeyOptions {
|
|
65
|
+
/**
|
|
66
|
+
* SDK-generated session UUID forwarded from the `fetchWaxKey` callback.
|
|
67
|
+
* Stored by the vault for correlation and audit — not used for authentication.
|
|
68
|
+
*/
|
|
69
|
+
tokenizationSessionId?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Maximum number of tokenize calls this wax key will accept before the vault
|
|
72
|
+
* marks it as consumed. Once consumed, further tokenize attempts return an
|
|
73
|
+
* auth/validation error and the client SDK automatically re-mints a fresh key.
|
|
74
|
+
*
|
|
75
|
+
* Keep this value small (3–5) to limit the blast radius if a key is intercepted.
|
|
76
|
+
* Set the same value in `VaultOptions.maxTokenizeCalls` so the client SDK can
|
|
77
|
+
* proactively refresh before hitting the wall, avoiding a user-visible delay.
|
|
78
|
+
*
|
|
79
|
+
* @default 3
|
|
80
|
+
*/
|
|
81
|
+
maxTokenizeCalls?: number;
|
|
82
|
+
/**
|
|
83
|
+
* Maximum number of proxy calls this wax key will accept.
|
|
84
|
+
* Proxy calls are distinct from tokenize calls — they cover non-tokenize vault
|
|
85
|
+
* operations. Leave `undefined` to use the vault's built-in default.
|
|
86
|
+
*
|
|
87
|
+
* In most integrations you only need `maxTokenizeCalls`; set this only if you
|
|
88
|
+
* are explicitly using vault proxy endpoints.
|
|
89
|
+
*/
|
|
90
|
+
maxProxyCalls?: number;
|
|
91
|
+
}
|
|
50
92
|
export interface CardSaleInput {
|
|
51
93
|
/** From TokenResponse.token (frontend SDK). */
|
|
52
94
|
token: string;
|
|
@@ -89,6 +131,7 @@ export declare class Ozura {
|
|
|
89
131
|
private apiKey;
|
|
90
132
|
private vaultKey;
|
|
91
133
|
private apiUrl;
|
|
134
|
+
private vaultUrl;
|
|
92
135
|
private timeoutMs;
|
|
93
136
|
private retries;
|
|
94
137
|
constructor(config: OzuraConfig);
|
|
@@ -105,6 +148,51 @@ export declare class Ozura {
|
|
|
105
148
|
* Rate limit: 200 requests/minute per merchant.
|
|
106
149
|
*/
|
|
107
150
|
listTransactions(input?: ListTransactionsInput): Promise<ListTransactionsResult>;
|
|
151
|
+
/**
|
|
152
|
+
* Mint a short-lived, use-limited wax key from the vault.
|
|
153
|
+
*
|
|
154
|
+
* Call this server-side to implement the `fetchWaxKey` callback required by
|
|
155
|
+
* `OzVault.create()` on the frontend. The wax key replaces the vault secret
|
|
156
|
+
* on every browser tokenize call — the secret never leaves your server.
|
|
157
|
+
*
|
|
158
|
+
* **Use limits:** by default each wax key accepts up to 3 tokenize calls
|
|
159
|
+
* (`maxTokenizeCalls: 3`). After that the vault marks the key as consumed and
|
|
160
|
+
* the client SDK transparently re-mints. Keep `maxTokenizeCalls` in sync with
|
|
161
|
+
* `VaultOptions.maxTokenizeCalls` so the SDK can proactively refresh before
|
|
162
|
+
* hitting the limit rather than waiting for a rejection.
|
|
163
|
+
*
|
|
164
|
+
* **Session correlation:** the `tokenizationSessionId` forwarded from the SDK's
|
|
165
|
+
* `fetchWaxKey` callback should be passed here so the vault can correlate the
|
|
166
|
+
* key with the checkout session in its audit log.
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* // Next.js API route
|
|
170
|
+
* export async function POST(req: Request) {
|
|
171
|
+
* const { sessionId } = await req.json();
|
|
172
|
+
* const { waxKey } = await ozura.mintWaxKey({
|
|
173
|
+
* tokenizationSessionId: sessionId,
|
|
174
|
+
* maxTokenizeCalls: 3,
|
|
175
|
+
* });
|
|
176
|
+
* return Response.json({ waxKey });
|
|
177
|
+
* }
|
|
178
|
+
*/
|
|
179
|
+
mintWaxKey(options?: MintWaxKeyOptions): Promise<MintWaxKeyResult>;
|
|
180
|
+
/**
|
|
181
|
+
* Revoke a previously minted wax key.
|
|
182
|
+
*
|
|
183
|
+
* Best-effort: never throws. Call this when the user's session ends (payment
|
|
184
|
+
* complete, cancelled, or expired) to close the exposure window before the
|
|
185
|
+
* vault TTL (30 min) elapses.
|
|
186
|
+
*
|
|
187
|
+
* - 200 = revoked successfully.
|
|
188
|
+
* - 404 = key already expired or not found — treated as success.
|
|
189
|
+
* - 503 = Redis error; the wax may still be valid. Retry if needed.
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* // After a successful card sale:
|
|
193
|
+
* await ozura.revokeWaxKey(waxKey);
|
|
194
|
+
*/
|
|
195
|
+
revokeWaxKey(waxKey: string): Promise<void>;
|
|
108
196
|
/**
|
|
109
197
|
* Execute a fetch with retry on 5xx / network errors.
|
|
110
198
|
* 4xx errors (including 429) are never retried — they require caller action.
|
|
@@ -113,7 +201,72 @@ export declare class Ozura {
|
|
|
113
201
|
private post;
|
|
114
202
|
private getRaw;
|
|
115
203
|
private handleResponse;
|
|
204
|
+
/**
|
|
205
|
+
* Parses a Pay API response JSON and throws `OzuraError` on HTTP errors or
|
|
206
|
+
* `success: false` payloads. Used by both `getRaw` and `handleResponse` to
|
|
207
|
+
* avoid duplicating the error-mapping logic.
|
|
208
|
+
*/
|
|
209
|
+
private parseApiJson;
|
|
210
|
+
}
|
|
211
|
+
/** Minimal response shape required by {@link createMintWaxMiddleware}. */
|
|
212
|
+
interface NodeLikeResponse {
|
|
213
|
+
json(data: unknown): void;
|
|
214
|
+
status(code: number): NodeLikeResponse;
|
|
215
|
+
/** Present on Node/Express `ServerResponse` — used for 429 `Retry-After`. */
|
|
216
|
+
setHeader?(name: string, value: string | number): void;
|
|
116
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* Creates a ready-to-use Fetch API route handler for minting wax keys.
|
|
220
|
+
*
|
|
221
|
+
* Drop-in for Next.js App Router, Cloudflare Workers, Vercel Edge, and any
|
|
222
|
+
* runtime built on the standard Web API `Request` / `Response`.
|
|
223
|
+
*
|
|
224
|
+
* The handler reads `sessionId` (or `tokenizationSessionId`) from the JSON
|
|
225
|
+
* request body, calls `ozura.mintWaxKey()`, and returns `{ waxKey }`.
|
|
226
|
+
* On error it returns `{ error }` with an appropriate HTTP status.
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* // app/api/mint-wax/route.ts (Next.js App Router)
|
|
230
|
+
* import { Ozura, createMintWaxHandler } from '@ozura/elements/server';
|
|
231
|
+
*
|
|
232
|
+
* const ozura = new Ozura({
|
|
233
|
+
* merchantId: process.env.MERCHANT_ID!,
|
|
234
|
+
* apiKey: process.env.MERCHANT_API_KEY!,
|
|
235
|
+
* vaultKey: process.env.VAULT_API_KEY!,
|
|
236
|
+
* });
|
|
237
|
+
*
|
|
238
|
+
* export const POST = createMintWaxHandler(ozura);
|
|
239
|
+
*/
|
|
240
|
+
export declare function createMintWaxHandler(ozura: Ozura): (req: Request) => Promise<Response>;
|
|
241
|
+
/**
|
|
242
|
+
* Creates a ready-to-use Express / Connect middleware for minting wax keys.
|
|
243
|
+
*
|
|
244
|
+
* Requires `express.json()` (or equivalent body-parser) to be registered
|
|
245
|
+
* before this middleware so `req.body` is available.
|
|
246
|
+
*
|
|
247
|
+
* The middleware reads `sessionId` (or `tokenizationSessionId`) from
|
|
248
|
+
* `req.body`, calls `ozura.mintWaxKey()`, and sends `{ waxKey }`.
|
|
249
|
+
* On error it sends `{ error }` with an appropriate HTTP status.
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* // Express
|
|
253
|
+
* import express from 'express';
|
|
254
|
+
* import { Ozura, createMintWaxMiddleware } from '@ozura/elements/server';
|
|
255
|
+
*
|
|
256
|
+
* const ozura = new Ozura({
|
|
257
|
+
* merchantId: process.env.MERCHANT_ID!,
|
|
258
|
+
* apiKey: process.env.MERCHANT_API_KEY!,
|
|
259
|
+
* vaultKey: process.env.VAULT_API_KEY!,
|
|
260
|
+
* });
|
|
261
|
+
*
|
|
262
|
+
* const app = express();
|
|
263
|
+
* app.use(express.json());
|
|
264
|
+
* app.post('/api/mint-wax', createMintWaxMiddleware(ozura));
|
|
265
|
+
*/
|
|
266
|
+
export declare function createMintWaxMiddleware(ozura: Ozura): (req: {
|
|
267
|
+
body?: unknown;
|
|
268
|
+
headers?: unknown;
|
|
269
|
+
}, res: NodeLikeResponse) => Promise<void>;
|
|
117
270
|
/**
|
|
118
271
|
* Extract the client IP address from a server request object.
|
|
119
272
|
* Works with Express (`req.ip`), Fastify (`request.ip`), Next.js App Router
|
|
@@ -123,12 +276,123 @@ export declare class Ozura {
|
|
|
123
276
|
* (Cloudflare) → `x-forwarded-for` (reverse proxy) → `x-real-ip` →
|
|
124
277
|
* `socket.remoteAddress` → `"0.0.0.0"`.
|
|
125
278
|
*
|
|
279
|
+
* **Proxy trust requirements — read before deploying:**
|
|
280
|
+
*
|
|
281
|
+
* - **`x-forwarded-for` / `x-real-ip`** are HTTP headers that any client can
|
|
282
|
+
* set arbitrarily. They are only trustworthy when your server sits behind a
|
|
283
|
+
* reverse proxy (nginx, AWS ALB, Cloudflare, etc.) that strips and rewrites
|
|
284
|
+
* those headers. If your Node.js process is directly internet-accessible,
|
|
285
|
+
* an attacker can spoof any IP value and bypass payment-processor
|
|
286
|
+
* IP-based fraud checks.
|
|
287
|
+
* - **Express `req.ip`** resolves through `X-Forwarded-For` only when
|
|
288
|
+
* `app.set('trust proxy', true)` (or a specific proxy count/subnet) is
|
|
289
|
+
* configured. Without `trust proxy`, `req.ip` returns the direct socket
|
|
290
|
+
* address (your load-balancer's IP, not the client's).
|
|
291
|
+
* - **`cf-connecting-ip`** is only trustworthy when Cloudflare is genuinely
|
|
292
|
+
* in front of your server. Without Cloudflare, any client can send this
|
|
293
|
+
* header with a fabricated value.
|
|
294
|
+
*
|
|
295
|
+
* In all cases, ensure your infrastructure strips untrusted forwarding headers
|
|
296
|
+
* before they reach your application.
|
|
297
|
+
*
|
|
126
298
|
* @example
|
|
127
|
-
* // Express
|
|
299
|
+
* // Express — requires app.set('trust proxy', true) behind a proxy
|
|
128
300
|
* clientIpAddress: getClientIp(req)
|
|
129
301
|
*
|
|
130
302
|
* // Next.js App Router
|
|
131
303
|
* clientIpAddress: getClientIp(req)
|
|
132
304
|
*/
|
|
133
305
|
export declare function getClientIp(req: Record<string, unknown>): string;
|
|
306
|
+
/**
|
|
307
|
+
* Options for {@link createCardSaleHandler} and {@link createCardSaleMiddleware}.
|
|
308
|
+
*
|
|
309
|
+
* The only required option is `getAmount` — it must return the authoritative
|
|
310
|
+
* transaction amount from **your own** database or session. Never read the
|
|
311
|
+
* amount from the request body without validating it against your records;
|
|
312
|
+
* a malicious client could otherwise send an arbitrarily low amount.
|
|
313
|
+
*/
|
|
314
|
+
export interface CardSaleHandlerOptions {
|
|
315
|
+
/**
|
|
316
|
+
* Return the authoritative amount for this transaction as a decimal string
|
|
317
|
+
* (e.g. `"49.00"`). Source this from your own database or session — never
|
|
318
|
+
* trust the value the client sends in the request body.
|
|
319
|
+
*
|
|
320
|
+
* Receives the parsed request body so you can forward an `orderId` or
|
|
321
|
+
* similar identifier to look up the correct amount.
|
|
322
|
+
*
|
|
323
|
+
* @example
|
|
324
|
+
* getAmount: async (body) => {
|
|
325
|
+
* const order = await db.orders.findById(body.orderId as string);
|
|
326
|
+
* return order.total;
|
|
327
|
+
* }
|
|
328
|
+
*/
|
|
329
|
+
getAmount: (body: Record<string, unknown>) => string | Promise<string>;
|
|
330
|
+
/**
|
|
331
|
+
* Return the ISO 4217 currency code for this transaction. Default: `"USD"`.
|
|
332
|
+
*/
|
|
333
|
+
getCurrency?: (body: Record<string, unknown>) => string | Promise<string>;
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Creates a ready-to-use Fetch API route handler for charging a tokenized card.
|
|
337
|
+
*
|
|
338
|
+
* Drop-in for Next.js App Router, Cloudflare Workers, Vercel Edge, and any
|
|
339
|
+
* runtime built on the standard Web API `Request` / `Response`.
|
|
340
|
+
*
|
|
341
|
+
* The handler reads `{ token, cvcSession, billing }` from the JSON request body,
|
|
342
|
+
* resolves the amount via `options.getAmount()`, calls `ozura.cardSale()`, and
|
|
343
|
+
* returns `{ transactionId, amount, cardLastFour, cardBrand }` on success.
|
|
344
|
+
* On error it returns `{ error }` with a normalized, user-facing message and
|
|
345
|
+
* an appropriate HTTP status.
|
|
346
|
+
*
|
|
347
|
+
* `clientIpAddress` is extracted automatically from the request headers.
|
|
348
|
+
*
|
|
349
|
+
* @example
|
|
350
|
+
* // app/api/charge/route.ts (Next.js App Router)
|
|
351
|
+
* import { Ozura, createCardSaleHandler } from '@ozura/elements/server';
|
|
352
|
+
*
|
|
353
|
+
* const ozura = new Ozura({ merchantId: '...', apiKey: '...', vaultKey: '...' });
|
|
354
|
+
*
|
|
355
|
+
* export const POST = createCardSaleHandler(ozura, {
|
|
356
|
+
* getAmount: async (body) => {
|
|
357
|
+
* const order = await db.orders.findById(body.orderId as string);
|
|
358
|
+
* return order.total;
|
|
359
|
+
* },
|
|
360
|
+
* });
|
|
361
|
+
*/
|
|
362
|
+
export declare function createCardSaleHandler(ozura: Ozura, options: CardSaleHandlerOptions): (req: Request) => Promise<Response>;
|
|
363
|
+
/**
|
|
364
|
+
* Creates a ready-to-use Express / Connect middleware for charging a tokenized card.
|
|
365
|
+
*
|
|
366
|
+
* Requires `express.json()` (or equivalent body-parser) to be registered before
|
|
367
|
+
* this middleware so `req.body` is available.
|
|
368
|
+
*
|
|
369
|
+
* The middleware reads `{ token, cvcSession, billing }` from `req.body`, resolves
|
|
370
|
+
* the amount via `options.getAmount()`, calls `ozura.cardSale()`, and sends
|
|
371
|
+
* `{ transactionId, amount, cardLastFour, cardBrand }` on success.
|
|
372
|
+
* On error it sends `{ error }` with a normalized, user-facing message and an
|
|
373
|
+
* appropriate HTTP status.
|
|
374
|
+
*
|
|
375
|
+
* `clientIpAddress` is extracted automatically from the request object.
|
|
376
|
+
*
|
|
377
|
+
* @example
|
|
378
|
+
* // Express
|
|
379
|
+
* import express from 'express';
|
|
380
|
+
* import { Ozura, createCardSaleMiddleware } from '@ozura/elements/server';
|
|
381
|
+
*
|
|
382
|
+
* const app = express();
|
|
383
|
+
* const ozura = new Ozura({ merchantId: '...', apiKey: '...', vaultKey: '...' });
|
|
384
|
+
*
|
|
385
|
+
* app.use(express.json());
|
|
386
|
+
* app.post('/api/charge', createCardSaleMiddleware(ozura, {
|
|
387
|
+
* getAmount: async (body) => {
|
|
388
|
+
* const order = await db.orders.findById(body.orderId as string);
|
|
389
|
+
* return order.total;
|
|
390
|
+
* },
|
|
391
|
+
* }));
|
|
392
|
+
*/
|
|
393
|
+
export declare function createCardSaleMiddleware(ozura: Ozura, options: CardSaleHandlerOptions): (req: {
|
|
394
|
+
body?: unknown;
|
|
395
|
+
headers?: unknown;
|
|
396
|
+
}, res: NodeLikeResponse) => Promise<void>;
|
|
134
397
|
export type { BillingDetails, CardSaleResponseData, TransactionQueryPagination, TransactionType, TransactionBase, CardTransactionData, AchTransactionData, CryptoTransactionData, TransactionData, } from '../types';
|
|
398
|
+
export { normalizeCardSaleError } from '../sdk/errors';
|
|
@@ -5,6 +5,9 @@ export interface ElementStyle {
|
|
|
5
5
|
fontWeight?: string;
|
|
6
6
|
fontStyle?: string;
|
|
7
7
|
fontVariant?: string;
|
|
8
|
+
fontSmoothing?: string;
|
|
9
|
+
webkitFontSmoothing?: string;
|
|
10
|
+
mozOsxFontSmoothing?: string;
|
|
8
11
|
letterSpacing?: string;
|
|
9
12
|
lineHeight?: string;
|
|
10
13
|
textAlign?: string;
|
|
@@ -55,8 +58,6 @@ export interface ElementStyle {
|
|
|
55
58
|
minHeight?: string;
|
|
56
59
|
maxHeight?: string;
|
|
57
60
|
transition?: string;
|
|
58
|
-
/** Index signature for forward-compatibility with future CSS properties. */
|
|
59
|
-
[key: string]: string | undefined;
|
|
60
61
|
}
|
|
61
62
|
export interface ElementStyleConfig {
|
|
62
63
|
/** Default styles applied to the input. */
|
|
@@ -74,7 +75,8 @@ export interface ElementOptions {
|
|
|
74
75
|
style?: ElementStyleConfig;
|
|
75
76
|
placeholder?: string;
|
|
76
77
|
disabled?: boolean;
|
|
77
|
-
/** How long to wait (ms) for the iframe to load before emitting `loaderror`. Default: 10 000.
|
|
78
|
+
/** How long to wait (ms) for the iframe to load before emitting `loaderror`. Default: 10 000.
|
|
79
|
+
* Only takes effect when this element's `onLoadError` option is provided or when `VaultOptions.onLoadError` is set. */
|
|
78
80
|
loadTimeoutMs?: number;
|
|
79
81
|
}
|
|
80
82
|
export interface ElementChangeEvent {
|
|
@@ -118,7 +120,7 @@ export interface AppearanceVariables {
|
|
|
118
120
|
colorText?: string;
|
|
119
121
|
/** Input background color. Maps to `base.backgroundColor`. */
|
|
120
122
|
colorBackground?: string;
|
|
121
|
-
/** Primary accent color. Maps to `focus.caretColor` and `
|
|
123
|
+
/** Primary accent color. Maps to `focus.caretColor` and `base.caretColor`. */
|
|
122
124
|
colorPrimary?: string;
|
|
123
125
|
/** Error/invalid state text color. Maps to `invalid.color`. */
|
|
124
126
|
colorDanger?: string;
|
|
@@ -153,6 +155,36 @@ export interface VaultOptions {
|
|
|
153
155
|
/** System pub key required for tokenization. Obtain from Ozura admin.
|
|
154
156
|
* Sent as the `X-Pub-Key` header on tokenize requests. */
|
|
155
157
|
pubKey: string;
|
|
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.
|
|
162
|
+
*
|
|
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.
|
|
166
|
+
*
|
|
167
|
+
* **Server-side (recommended):** Use `ozura.mintWaxKey()` from `@ozura/elements/server`:
|
|
168
|
+
* @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 });
|
|
174
|
+
*
|
|
175
|
+
* **Client-side (fetchWaxKey callback):**
|
|
176
|
+
* @example
|
|
177
|
+
* fetchWaxKey: async (sessionId) => {
|
|
178
|
+
* const res = await fetch('/api/mint-wax', {
|
|
179
|
+
* method: 'POST',
|
|
180
|
+
* headers: { 'Content-Type': 'application/json' },
|
|
181
|
+
* body: JSON.stringify({ sessionId }),
|
|
182
|
+
* });
|
|
183
|
+
* const { waxKey } = await res.json();
|
|
184
|
+
* return waxKey;
|
|
185
|
+
* }
|
|
186
|
+
*/
|
|
187
|
+
fetchWaxKey: (tokenizationSessionId: string) => Promise<string>;
|
|
156
188
|
/** Base URL where the Ozura frame HTML/JS assets are served from.
|
|
157
189
|
* Defaults to the production CDN. Override for local development. */
|
|
158
190
|
frameBaseUrl?: string;
|
|
@@ -175,8 +207,40 @@ export interface VaultOptions {
|
|
|
175
207
|
* Use this to show a fallback UI (e.g. "Unable to load payment fields").
|
|
176
208
|
*/
|
|
177
209
|
onLoadError?: () => void;
|
|
178
|
-
/** How long to wait (ms) for the tokenizer iframe before calling `onLoadError`. Default: 10 000.
|
|
210
|
+
/** How long to wait (ms) for the tokenizer iframe before calling `onLoadError`. Default: 10 000.
|
|
211
|
+
* Only takes effect when `onLoadError` is also provided — setting this without `onLoadError` has no effect. */
|
|
179
212
|
loadTimeoutMs?: number;
|
|
213
|
+
/**
|
|
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.
|
|
218
|
+
*/
|
|
219
|
+
onWaxRefresh?: () => void;
|
|
220
|
+
/**
|
|
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`).
|
|
224
|
+
*
|
|
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.
|
|
230
|
+
*
|
|
231
|
+
* @default 3
|
|
232
|
+
*/
|
|
233
|
+
maxTokenizeCalls?: number;
|
|
234
|
+
/**
|
|
235
|
+
* Called once when the tokenizer iframe has loaded and is ready to accept
|
|
236
|
+
* tokenization requests. Useful in vanilla JS to re-evaluate submit-button
|
|
237
|
+
* readiness when the tokenizer becomes ready after all element iframes have
|
|
238
|
+
* already loaded.
|
|
239
|
+
*
|
|
240
|
+
* In React, use `useOzElements().ready` instead — it combines both tokenizer
|
|
241
|
+
* and element readiness automatically.
|
|
242
|
+
*/
|
|
243
|
+
onReady?: () => void;
|
|
180
244
|
/**
|
|
181
245
|
* Global appearance configuration. Applies preset themes and/or variable
|
|
182
246
|
* overrides to all elements created by this vault. Per-element `style`
|
|
@@ -248,8 +312,8 @@ export interface BankTokenizeOptions {
|
|
|
248
312
|
export interface BankAccountMetadata {
|
|
249
313
|
/** Last 4 digits of the account number. */
|
|
250
314
|
last4: string;
|
|
251
|
-
/**
|
|
252
|
-
|
|
315
|
+
/** Last 4 digits of the routing number — sufficient for display and reconciliation. */
|
|
316
|
+
routingNumberLast4: string;
|
|
253
317
|
}
|
|
254
318
|
/** Non-sensitive card metadata returned alongside the token. */
|
|
255
319
|
export interface CardMetadata {
|
|
@@ -264,6 +328,16 @@ export interface CardMetadata {
|
|
|
264
328
|
}
|
|
265
329
|
export interface TokenResponse {
|
|
266
330
|
token: string;
|
|
331
|
+
/**
|
|
332
|
+
* CVC session token returned by the vault alongside the card token.
|
|
333
|
+
*
|
|
334
|
+
* Required by the Ozura Pay API `cardSale` endpoint. If this is absent it
|
|
335
|
+
* means the vault is not configured to return CVC sessions — `createToken()`
|
|
336
|
+
* will reject with an `OZ_TOKEN_ERROR` before this response is ever returned
|
|
337
|
+
* to the caller. In practice, this field is always present on successful
|
|
338
|
+
* tokenization; the optional type reflects only that the field is not part
|
|
339
|
+
* of the tokenized card data itself.
|
|
340
|
+
*/
|
|
267
341
|
cvcSession?: string;
|
|
268
342
|
/** Non-sensitive card metadata — available immediately without a cardSale call. */
|
|
269
343
|
card?: CardMetadata;
|
|
@@ -290,7 +364,6 @@ export interface BankTokenResponse {
|
|
|
290
364
|
*
|
|
291
365
|
* Headers required:
|
|
292
366
|
* x-api-key: <merchantApiKey>
|
|
293
|
-
* vault-api-key: <vaultApiKey> (same key passed to OzVault)
|
|
294
367
|
*/
|
|
295
368
|
export interface CardSaleRequest {
|
|
296
369
|
/** Processor to use. If omitted, the Pay API auto-selects (Elavon → Nuvei → Worldpay). */
|
|
@@ -339,12 +412,12 @@ export interface CardSaleResponseData {
|
|
|
339
412
|
amount: string;
|
|
340
413
|
/** ISO 4217 currency code, e.g. "USD". */
|
|
341
414
|
currency: string;
|
|
342
|
-
/** Surcharge amount applied, e.g. "
|
|
343
|
-
surchargeAmount
|
|
415
|
+
/** Surcharge amount applied, e.g. "1.50". Absent when no surcharge was configured. */
|
|
416
|
+
surchargeAmount?: string;
|
|
344
417
|
/** Sales tax calculated by the Pay API based on billing address. */
|
|
345
418
|
salesTaxAmount?: string;
|
|
346
|
-
/** Tip amount applied, e.g. "
|
|
347
|
-
tipAmount
|
|
419
|
+
/** Tip amount applied, e.g. "5.00". Absent when no tip was included in the request. */
|
|
420
|
+
tipAmount?: string;
|
|
348
421
|
/** Last four digits of the card number. */
|
|
349
422
|
cardLastFour: string;
|
|
350
423
|
/** First six digits of the card number (BIN). */
|
|
@@ -379,12 +452,17 @@ export interface CardSaleResponseData {
|
|
|
379
452
|
* Full response envelope from the Ozura Pay API cardSale endpoint.
|
|
380
453
|
*
|
|
381
454
|
* On success: `{ success: true, data: CardSaleResponseData }`
|
|
382
|
-
* On failure: HTTP 4xx/5xx with `{ error: string }` — pass
|
|
383
|
-
* `normalizeCardSaleError()` to get a user-facing message.
|
|
455
|
+
* On failure: HTTP 4xx/5xx with `{ success: false, error: string }` — pass
|
|
456
|
+
* `error` to `normalizeCardSaleError()` to get a user-facing message.
|
|
457
|
+
*
|
|
458
|
+
* Note: the server SDK `Ozura.cardSale()` throws `OzuraError` on failure rather
|
|
459
|
+
* than returning this shape. This type is only needed when calling the Pay API
|
|
460
|
+
* directly via `fetch`.
|
|
384
461
|
*/
|
|
385
462
|
export interface CardSaleApiResponse {
|
|
386
463
|
success: boolean;
|
|
387
|
-
data
|
|
464
|
+
data?: CardSaleResponseData;
|
|
465
|
+
error?: string;
|
|
388
466
|
}
|
|
389
467
|
/**
|
|
390
468
|
* Transaction types returned by the Pay API transQuery endpoint.
|
|
@@ -510,7 +588,7 @@ export interface TransactionQueryResponse {
|
|
|
510
588
|
data: TransactionData[];
|
|
511
589
|
pagination: TransactionQueryPagination;
|
|
512
590
|
}
|
|
513
|
-
export type OzMessageType = 'OZ_FRAME_READY' | 'OZ_INIT' | 'OZ_UPDATE' | 'OZ_CLEAR' | 'OZ_CHANGE' | 'OZ_FOCUS' | 'OZ_BLUR' | 'OZ_RESIZE' | '
|
|
591
|
+
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';
|
|
514
592
|
export interface OzMessage {
|
|
515
593
|
__oz: true;
|
|
516
594
|
vaultId: string;
|
|
@@ -4,6 +4,15 @@ import type { Appearance, ElementStyleConfig } from '../types';
|
|
|
4
4
|
* Resolution order: theme defaults → variable overrides.
|
|
5
5
|
* The returned config is then used as the "base appearance" that
|
|
6
6
|
* per-element `style` overrides merge on top of.
|
|
7
|
+
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* - `appearance: undefined` → no styles injected (element iframes use their
|
|
10
|
+
* own minimal built-in defaults).
|
|
11
|
+
* - `appearance: {}` or `appearance: { variables: {...} }` without an explicit
|
|
12
|
+
* `theme` → the `'default'` theme is used as the base. Omitting `theme`
|
|
13
|
+
* does NOT mean "no theme" — it means `theme: 'default'`. To opt out of
|
|
14
|
+
* the preset themes entirely, use per-element `style` overrides without
|
|
15
|
+
* passing an `appearance` prop at all.
|
|
7
16
|
*/
|
|
8
17
|
export declare function resolveAppearance(appearance?: Appearance): ElementStyleConfig | undefined;
|
|
9
18
|
/**
|
|
@@ -21,6 +21,20 @@ export interface CardValidationResult {
|
|
|
21
21
|
valid: boolean;
|
|
22
22
|
error?: string;
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Canonical card number validation: length check then Luhn.
|
|
26
|
+
*
|
|
27
|
+
* **Not called by `elementFrame.ts` at runtime.** The frame needs `complete`
|
|
28
|
+
* and `valid` as separate signals for field UX (show completion indicator
|
|
29
|
+
* before running Luhn), so it implements both checks inline via `isComplete()`
|
|
30
|
+
* and `isValid()`. Those methods MUST stay logically in sync with this
|
|
31
|
+
* function — any change to length bounds or error text here must be mirrored
|
|
32
|
+
* there, and vice-versa.
|
|
33
|
+
*
|
|
34
|
+
* Used by the unit test suite as the authoritative spec for the algorithm.
|
|
35
|
+
*
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
24
38
|
export declare function validateCardNumber(digits: string, brand: CardBrand | string): CardValidationResult;
|
|
25
39
|
export interface ExpiryValidationResult {
|
|
26
40
|
complete: boolean;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates a RFC 4122 v4 UUID.
|
|
3
|
+
*
|
|
4
|
+
* Uses `crypto.randomUUID()` when available (Chrome 92+, Firefox 95+,
|
|
5
|
+
* Safari 15.4+, Node 14.17+) and falls back to `crypto.getRandomValues()`
|
|
6
|
+
* for older environments (Safari 14, some embedded WebViews, older Node).
|
|
7
|
+
*
|
|
8
|
+
* Both paths use the same CSPRNG — the difference is only in API surface.
|
|
9
|
+
*
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export declare function uuid(): string;
|
|
@@ -19,3 +19,35 @@
|
|
|
19
19
|
* Exported for unit testing only — not part of the public SDK API.
|
|
20
20
|
*/
|
|
21
21
|
export declare function isAllowedVaultOrigin(apiUrl: string): boolean;
|
|
22
|
+
/** Exported for unit testing only — not part of the public SDK API. */
|
|
23
|
+
export declare class TokenizerFrame {
|
|
24
|
+
private vaultId;
|
|
25
|
+
private hostOrigin;
|
|
26
|
+
/** Wax key delivered once via OZ_INIT. Used for all tokenize calls. */
|
|
27
|
+
private waxKey;
|
|
28
|
+
private pending;
|
|
29
|
+
private pendingBank;
|
|
30
|
+
constructor();
|
|
31
|
+
private onMessage;
|
|
32
|
+
/**
|
|
33
|
+
* Shared vault POST helper. Handles origin guard, header construction,
|
|
34
|
+
* the fetchWithRetry call, token extraction, empty-token error, and catch.
|
|
35
|
+
*
|
|
36
|
+
* Returns the raw response data augmented with a guaranteed non-empty
|
|
37
|
+
* `token` string, or `null` if an error was already reported via
|
|
38
|
+
* postMessage to `target`.
|
|
39
|
+
*/
|
|
40
|
+
private postToVault;
|
|
41
|
+
private tokenize;
|
|
42
|
+
private tokenizeBank;
|
|
43
|
+
private static classifyHttpStatus;
|
|
44
|
+
/**
|
|
45
|
+
* Fetches with a 30s timeout and a single automatic retry for network
|
|
46
|
+
* errors only. 4xx and 5xx responses are not retried — 4xx inputs won't
|
|
47
|
+
* succeed on a second attempt, and 5xx may have already been processed
|
|
48
|
+
* server-side (idempotency cannot be guaranteed for the vault tokenize POST).
|
|
49
|
+
*
|
|
50
|
+
* Throws an Error with an `errorCode` property for downstream classification.
|
|
51
|
+
*/
|
|
52
|
+
private fetchWithRetry;
|
|
53
|
+
}
|
|
@@ -33,10 +33,29 @@ export declare class OzElement {
|
|
|
33
33
|
* (useful when integrating with React refs).
|
|
34
34
|
*/
|
|
35
35
|
mount(target: string | HTMLElement): void;
|
|
36
|
+
/**
|
|
37
|
+
* Subscribe to an element event. Returns `this` for chaining.
|
|
38
|
+
* @param event - Event name: `'change'`, `'focus'`, `'blur'`, `'ready'`, or `'loaderror'`.
|
|
39
|
+
* @param callback - Handler invoked with the event payload.
|
|
40
|
+
*/
|
|
36
41
|
on(event: ElementEvent, callback: ElementCallback): this;
|
|
42
|
+
/**
|
|
43
|
+
* Remove a previously registered event handler.
|
|
44
|
+
* Has no effect if the handler is not registered.
|
|
45
|
+
*/
|
|
37
46
|
off(event: ElementEvent, callback: ElementCallback): this;
|
|
47
|
+
/**
|
|
48
|
+
* Subscribe to an event for a single invocation. The handler is automatically
|
|
49
|
+
* removed after it fires once.
|
|
50
|
+
*/
|
|
38
51
|
once(event: ElementEvent, callback: ElementCallback): this;
|
|
52
|
+
/**
|
|
53
|
+
* Dynamically update element options (placeholder, style, etc.) without
|
|
54
|
+
* re-mounting the iframe. Only the provided keys are merged; omitted keys
|
|
55
|
+
* retain their current values.
|
|
56
|
+
*/
|
|
39
57
|
update(options: Partial<ElementOptions>): void;
|
|
58
|
+
/** Clear the current field value without removing the element from the DOM. */
|
|
40
59
|
clear(): void;
|
|
41
60
|
/**
|
|
42
61
|
* Removes the iframe from the DOM and resets internal state.
|
|
@@ -53,13 +72,25 @@ export declare class OzElement {
|
|
|
53
72
|
* and prevents future use. Distinct from `unmount()` which allows re-mounting.
|
|
54
73
|
*/
|
|
55
74
|
destroy(): void;
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Sends OZ_BEGIN_COLLECT to the element iframe, transferring `port` so the
|
|
77
|
+
* iframe can post its field value directly to the tokenizer without going
|
|
78
|
+
* through the merchant page (no named-window lookup required).
|
|
79
|
+
* @internal
|
|
80
|
+
*/
|
|
81
|
+
beginCollect(requestId: string, port: MessagePort): void;
|
|
82
|
+
/**
|
|
83
|
+
* Tell a CVV element how many digits to expect. Called automatically when card brand changes.
|
|
84
|
+
* @internal
|
|
85
|
+
*/
|
|
59
86
|
setCvvLength(length: number): void;
|
|
87
|
+
/** @internal */
|
|
60
88
|
handleMessage(msg: OzMessage): void;
|
|
61
89
|
private emit;
|
|
62
90
|
private post;
|
|
63
91
|
private send;
|
|
92
|
+
/** Posts a message with transferable objects (e.g. MessagePort). Bypasses the
|
|
93
|
+
* pending-message queue — only call when the frame is already ready. */
|
|
94
|
+
private sendWithTransfer;
|
|
64
95
|
}
|
|
65
96
|
export {};
|