@ozura/elements 1.3.1 → 1.4.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/dist/frame/element-frame.html +1 -1
- package/dist/frame/element-frame.js +7 -4
- package/dist/frame/tokenizer-frame.html +1 -1
- package/dist/frame/tokenizer-frame.js +5 -6
- package/dist/oz-elements.esm.js +70 -22
- package/dist/oz-elements.umd.js +70 -22
- package/dist/react/index.cjs.js +114 -38
- package/dist/react/index.esm.js +114 -38
- package/dist/react/react/index.d.ts +29 -1
- package/dist/react/sdk/OzVault.d.ts +33 -0
- package/dist/react/types/index.d.ts +30 -5
- package/dist/react/vue/index.d.ts +56 -1
- package/dist/server/sdk/OzVault.d.ts +33 -0
- package/dist/server/types/index.d.ts +30 -5
- package/dist/server/vue/index.d.ts +56 -1
- package/dist/types/sdk/OzVault.d.ts +33 -0
- package/dist/types/types/index.d.ts +30 -5
- package/dist/types/vue/index.d.ts +56 -1
- package/dist/vue/index.cjs.js +135 -35
- package/dist/vue/index.esm.js +135 -35
- package/dist/vue/sdk/OzVault.d.ts +33 -0
- package/dist/vue/types/index.d.ts +30 -5
- package/dist/vue/vue/index.d.ts +56 -1
- package/package.json +1 -1
- package/dist/react/index.cjs.js.map +0 -1
- package/dist/react/index.esm.js.map +0 -1
- package/dist/vue/index.cjs.js.map +0 -1
- package/dist/vue/index.esm.js.map +0 -1
package/dist/vue/index.esm.js
CHANGED
|
@@ -1114,7 +1114,7 @@ class OzVault {
|
|
|
1114
1114
|
this.loadErrorTimeoutId = setTimeout(() => {
|
|
1115
1115
|
this.loadErrorTimeoutId = null;
|
|
1116
1116
|
if (!this._destroyed && !this.tokenizerReady) {
|
|
1117
|
-
options.onLoadError();
|
|
1117
|
+
options.onLoadError({ source: 'tokenizer' });
|
|
1118
1118
|
}
|
|
1119
1119
|
}, timeout);
|
|
1120
1120
|
}
|
|
@@ -1247,6 +1247,49 @@ class OzVault {
|
|
|
1247
1247
|
get tokenizeCount() {
|
|
1248
1248
|
return this._tokenizeSuccessCount;
|
|
1249
1249
|
}
|
|
1250
|
+
/**
|
|
1251
|
+
* `true` when every mounted field has reported `complete && valid` via its
|
|
1252
|
+
* last `change` event. `false` if no fields have been created, or if any
|
|
1253
|
+
* field is incomplete or invalid.
|
|
1254
|
+
*
|
|
1255
|
+
* Use this to gate the pay button in vanilla JS integrations without having
|
|
1256
|
+
* to wire up individual `change` event listeners:
|
|
1257
|
+
*
|
|
1258
|
+
* @example
|
|
1259
|
+
* vault.getElement('cardNumber')!.on('change', () => {
|
|
1260
|
+
* payBtn.disabled = !vault.isComplete;
|
|
1261
|
+
* });
|
|
1262
|
+
*/
|
|
1263
|
+
get isComplete() {
|
|
1264
|
+
return this.allComplete([...this.elementsByType.values()]);
|
|
1265
|
+
}
|
|
1266
|
+
/**
|
|
1267
|
+
* Like {@link isComplete}, but for bank-account elements created via
|
|
1268
|
+
* {@link createBankElement}. Card and bank fields are tracked separately so a
|
|
1269
|
+
* card-only checkout is never gated on bank fields (and vice versa), matching
|
|
1270
|
+
* the `createToken()` / `createBankToken()` split. A vault with both card and
|
|
1271
|
+
* bank elements exposes each completion state independently.
|
|
1272
|
+
*/
|
|
1273
|
+
get isBankComplete() {
|
|
1274
|
+
return this.allComplete([...this.bankElementsByType.values()]);
|
|
1275
|
+
}
|
|
1276
|
+
/** True iff the set is non-empty and every element has reported complete-and-valid. */
|
|
1277
|
+
allComplete(els) {
|
|
1278
|
+
if (els.length === 0)
|
|
1279
|
+
return false;
|
|
1280
|
+
return els.every(el => this.completionState.get(el.frameId) === true);
|
|
1281
|
+
}
|
|
1282
|
+
/**
|
|
1283
|
+
* `true` while a `createToken()` or `createBankToken()` call is in progress
|
|
1284
|
+
* (including the transparent wax-key refresh phase). Use this to keep the pay
|
|
1285
|
+
* button disabled during tokenization to prevent double-submission.
|
|
1286
|
+
*
|
|
1287
|
+
* @example
|
|
1288
|
+
* payBtn.disabled = vault.isTokenizing;
|
|
1289
|
+
*/
|
|
1290
|
+
get isTokenizing() {
|
|
1291
|
+
return this._tokenizing !== null;
|
|
1292
|
+
}
|
|
1250
1293
|
/**
|
|
1251
1294
|
* Creates a new OzElement of the given type. Call `.mount(selector)` on the
|
|
1252
1295
|
* returned element to attach it to the DOM.
|
|
@@ -1329,17 +1372,29 @@ class OzVault {
|
|
|
1329
1372
|
? 'A card tokenization is already in progress. Wait for it to complete before calling createBankToken().'
|
|
1330
1373
|
: 'A bank tokenization is already in progress. Wait for it to complete before calling createBankToken() again.');
|
|
1331
1374
|
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1375
|
+
// Validate billing details if provided — billing.firstName/lastName take
|
|
1376
|
+
// precedence over the top-level params (mirrors createToken() behaviour).
|
|
1377
|
+
let normalizedBankBilling;
|
|
1378
|
+
let bankFirstName = ((_a = options.firstName) !== null && _a !== void 0 ? _a : '').trim();
|
|
1379
|
+
let bankLastName = ((_b = options.lastName) !== null && _b !== void 0 ? _b : '').trim();
|
|
1380
|
+
if (options.billing) {
|
|
1381
|
+
const result = validateBilling(options.billing);
|
|
1382
|
+
if (!result.valid) {
|
|
1383
|
+
throw new OzError(`Invalid billing details: ${result.errors.join('; ')}`);
|
|
1384
|
+
}
|
|
1385
|
+
normalizedBankBilling = result.normalized;
|
|
1386
|
+
bankFirstName = normalizedBankBilling.firstName;
|
|
1387
|
+
bankLastName = normalizedBankBilling.lastName;
|
|
1340
1388
|
}
|
|
1341
|
-
|
|
1342
|
-
|
|
1389
|
+
else {
|
|
1390
|
+
if (!bankFirstName)
|
|
1391
|
+
throw new OzError('firstName is required for bank account tokenization.');
|
|
1392
|
+
if (!bankLastName)
|
|
1393
|
+
throw new OzError('lastName is required for bank account tokenization.');
|
|
1394
|
+
if (bankFirstName.length > 50)
|
|
1395
|
+
throw new OzError('firstName must be 50 characters or fewer.');
|
|
1396
|
+
if (bankLastName.length > 50)
|
|
1397
|
+
throw new OzError('lastName must be 50 characters or fewer.');
|
|
1343
1398
|
}
|
|
1344
1399
|
const accountEl = this.bankElementsByType.get('accountNumber');
|
|
1345
1400
|
const routingEl = this.bankElementsByType.get('routingNumber');
|
|
@@ -1365,14 +1420,7 @@ class OzVault {
|
|
|
1365
1420
|
if (this._resetCount === resetCountAtStart)
|
|
1366
1421
|
this._tokenizing = null;
|
|
1367
1422
|
};
|
|
1368
|
-
this.bankTokenizeResolvers.set(requestId, {
|
|
1369
|
-
resolve: (v) => { cleanup(); resolve(v); },
|
|
1370
|
-
reject: (e) => { cleanup(); reject(e); },
|
|
1371
|
-
firstName: options.firstName.trim(),
|
|
1372
|
-
lastName: options.lastName.trim(),
|
|
1373
|
-
readyElements: readyBankElements,
|
|
1374
|
-
fieldCount: readyBankElements.length,
|
|
1375
|
-
});
|
|
1423
|
+
this.bankTokenizeResolvers.set(requestId, Object.assign(Object.assign({ resolve: (v) => { cleanup(); resolve(v); }, reject: (e) => { cleanup(); reject(e); }, firstName: bankFirstName, lastName: bankLastName }, (normalizedBankBilling ? { billing: normalizedBankBilling } : {})), { readyElements: readyBankElements, fieldCount: readyBankElements.length }));
|
|
1376
1424
|
try {
|
|
1377
1425
|
const bankChannels = readyBankElements.map(() => new MessageChannel());
|
|
1378
1426
|
const bankTokenizeStartMs = Date.now();
|
|
@@ -1381,8 +1429,8 @@ class OzVault {
|
|
|
1381
1429
|
requestId,
|
|
1382
1430
|
tokenizationSessionId: this.tokenizationSessionId,
|
|
1383
1431
|
pubKey: (_a = this.pubKey) !== null && _a !== void 0 ? _a : '',
|
|
1384
|
-
firstName:
|
|
1385
|
-
lastName:
|
|
1432
|
+
firstName: bankFirstName,
|
|
1433
|
+
lastName: bankLastName,
|
|
1386
1434
|
fieldCount: readyBankElements.length,
|
|
1387
1435
|
}, bankChannels.map(ch => ch.port1));
|
|
1388
1436
|
this.log('OZ_BANK_TOKENIZE sent', { requestIdPrefix: `${requestId.slice(0, 12)}...`, fieldCount: readyBankElements.length });
|
|
@@ -2104,7 +2152,7 @@ class OzVault {
|
|
|
2104
2152
|
break;
|
|
2105
2153
|
}
|
|
2106
2154
|
const bank = isBankAccountMetadata(msg.bank) ? msg.bank : undefined;
|
|
2107
|
-
pending.resolve(Object.assign({ token }, (bank ? { bank } : {})));
|
|
2155
|
+
pending.resolve(Object.assign(Object.assign({ token }, (bank ? { bank } : {})), (pending.billing ? { billing: pending.billing } : {})));
|
|
2108
2156
|
this.log('bank token received', {
|
|
2109
2157
|
elapsedMs: pending.tokenizeStartMs != null ? Date.now() - pending.tokenizeStartMs : null,
|
|
2110
2158
|
tokenPresent: true,
|
|
@@ -2271,6 +2319,7 @@ const OzElements = defineComponent({
|
|
|
2271
2319
|
debug: { type: Boolean, default: undefined },
|
|
2272
2320
|
onSessionRefresh: { type: Function, default: undefined },
|
|
2273
2321
|
onReady: { type: Function, default: undefined },
|
|
2322
|
+
onLoadError: { type: Function, default: undefined },
|
|
2274
2323
|
sessionLimit: { type: Number, default: undefined },
|
|
2275
2324
|
maxTokenizeCalls: { type: Number, default: undefined },
|
|
2276
2325
|
},
|
|
@@ -2281,6 +2330,8 @@ const OzElements = defineComponent({
|
|
|
2281
2330
|
const mountedCount = ref(0);
|
|
2282
2331
|
const readyCount = ref(0);
|
|
2283
2332
|
const tokenizeCount = ref(0);
|
|
2333
|
+
const changeTick = ref(0);
|
|
2334
|
+
const notifyChange = () => { changeTick.value++; };
|
|
2284
2335
|
const notifyMount = () => { mountedCount.value++; };
|
|
2285
2336
|
let readyEmitted = false;
|
|
2286
2337
|
const notifyReady = () => {
|
|
@@ -2306,17 +2357,32 @@ const OzElements = defineComponent({
|
|
|
2306
2357
|
mountedCount,
|
|
2307
2358
|
readyCount,
|
|
2308
2359
|
tokenizeCount,
|
|
2360
|
+
changeTick,
|
|
2309
2361
|
notifyMount,
|
|
2310
2362
|
notifyReady,
|
|
2311
2363
|
notifyUnmount,
|
|
2312
2364
|
notifyTokenize,
|
|
2365
|
+
notifyChange,
|
|
2313
2366
|
});
|
|
2314
2367
|
let createdVault = null;
|
|
2315
2368
|
let abortController = null;
|
|
2316
2369
|
onMounted(() => {
|
|
2317
2370
|
const ac = new AbortController();
|
|
2318
2371
|
abortController = ac;
|
|
2319
|
-
|
|
2372
|
+
// Guard: onLoadError must fire at most once per mount cycle. It can be
|
|
2373
|
+
// triggered by two independent paths — the vault's iframe load timeout
|
|
2374
|
+
// (inside OzVault constructor) and the .catch below when create() rejects
|
|
2375
|
+
// after the timeout has already fired. Without this flag both paths would
|
|
2376
|
+
// call the callback, mirroring the same guard used in the React provider.
|
|
2377
|
+
let loadErrorFired = false;
|
|
2378
|
+
const fireLoadError = () => {
|
|
2379
|
+
var _a;
|
|
2380
|
+
if (loadErrorFired)
|
|
2381
|
+
return;
|
|
2382
|
+
loadErrorFired = true;
|
|
2383
|
+
(_a = props.onLoadError) === null || _a === void 0 ? void 0 : _a.call(props, { source: 'tokenizer' });
|
|
2384
|
+
};
|
|
2385
|
+
OzVault.create(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({ pubKey: props.pubKey }, (props.sessionUrl ? { sessionUrl: props.sessionUrl } : {})), (props.getSessionKey ? { getSessionKey: props.getSessionKey } : {})), (props.frameBaseUrl ? { frameBaseUrl: props.frameBaseUrl } : {})), (props.fonts ? { fonts: props.fonts } : {})), (props.appearance ? { appearance: props.appearance } : {})), (props.loadTimeoutMs !== undefined ? { loadTimeoutMs: props.loadTimeoutMs } : {})), (props.onLoadError ? { onLoadError: fireLoadError } : {})), (props.debug ? { debug: props.debug } : {})), {
|
|
2320
2386
|
// Session lifecycle — wire refresh callback and reset tokenizeCount so the
|
|
2321
2387
|
// counter stays accurate across proactive key refreshes (mirrors React provider).
|
|
2322
2388
|
// Deferred by one microtask for the same reason as React: notifyTokenize fires
|
|
@@ -2338,6 +2404,12 @@ const OzElements = defineComponent({
|
|
|
2338
2404
|
if (ac.signal.aborted)
|
|
2339
2405
|
return;
|
|
2340
2406
|
initError.value = err instanceof Error ? err : new Error('OzVault.create() failed.');
|
|
2407
|
+
if (props.onLoadError) {
|
|
2408
|
+
fireLoadError();
|
|
2409
|
+
}
|
|
2410
|
+
else {
|
|
2411
|
+
console.error('[OzElements] OzVault.create() failed. Provide an `onLoadError` prop to handle this gracefully.', err);
|
|
2412
|
+
}
|
|
2341
2413
|
});
|
|
2342
2414
|
});
|
|
2343
2415
|
onUnmounted(() => {
|
|
@@ -2359,7 +2431,7 @@ function useOzElements() {
|
|
|
2359
2431
|
if (!ctx) {
|
|
2360
2432
|
throw new Error('[OzVault] useOzElements() must be called inside <OzElements>');
|
|
2361
2433
|
}
|
|
2362
|
-
const { vault, initError, mountedCount, readyCount, tokenizeCount, notifyTokenize } = ctx;
|
|
2434
|
+
const { vault, initError, mountedCount, readyCount, tokenizeCount, changeTick, notifyTokenize, notifyChange } = ctx;
|
|
2363
2435
|
const ready = computed(() => vault.value !== null &&
|
|
2364
2436
|
vault.value.isReady &&
|
|
2365
2437
|
mountedCount.value > 0 &&
|
|
@@ -2368,20 +2440,49 @@ function useOzElements() {
|
|
|
2368
2440
|
if (!vault.value) {
|
|
2369
2441
|
throw new Error('[OzVault] vault is not ready — wait for ready before calling createToken()');
|
|
2370
2442
|
}
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2443
|
+
// Start the call so vault._tokenizing flips synchronously, then bump changeTick
|
|
2444
|
+
// so `isTokenizing` recomputes as `true`; bump again on settle. (vault.isTokenizing
|
|
2445
|
+
// is a plain getter — nothing else would recompute the computed while in flight.)
|
|
2446
|
+
const promise = vault.value.createToken(options);
|
|
2447
|
+
notifyChange();
|
|
2448
|
+
try {
|
|
2449
|
+
const result = await promise;
|
|
2450
|
+
notifyTokenize();
|
|
2451
|
+
return result;
|
|
2452
|
+
}
|
|
2453
|
+
finally {
|
|
2454
|
+
notifyChange();
|
|
2455
|
+
}
|
|
2374
2456
|
};
|
|
2375
2457
|
const createBankToken = async (options) => {
|
|
2376
2458
|
if (!vault.value) {
|
|
2377
2459
|
throw new Error('[OzVault] vault is not ready — wait for ready before calling createBankToken()');
|
|
2378
2460
|
}
|
|
2379
|
-
const
|
|
2380
|
-
|
|
2381
|
-
|
|
2461
|
+
const promise = vault.value.createBankToken(options);
|
|
2462
|
+
notifyChange();
|
|
2463
|
+
try {
|
|
2464
|
+
const result = await promise;
|
|
2465
|
+
notifyTokenize();
|
|
2466
|
+
return result;
|
|
2467
|
+
}
|
|
2468
|
+
finally {
|
|
2469
|
+
notifyChange();
|
|
2470
|
+
}
|
|
2471
|
+
};
|
|
2472
|
+
const reset = () => {
|
|
2473
|
+
var _a;
|
|
2474
|
+
(_a = vault.value) === null || _a === void 0 ? void 0 : _a.reset();
|
|
2475
|
+
// reset() clears completion state and cancels any in-flight tokenization;
|
|
2476
|
+
// bump changeTick so the derived computeds below recompute.
|
|
2477
|
+
notifyChange();
|
|
2382
2478
|
};
|
|
2383
|
-
|
|
2384
|
-
|
|
2479
|
+
// `void changeTick.value` registers a reactive dependency so these recompute when
|
|
2480
|
+
// notifyChange() fires (field change / tokenize start-stop). vault.isComplete and
|
|
2481
|
+
// vault.isTokenizing read non-reactive internal Maps/flags that Vue cannot track.
|
|
2482
|
+
const isComplete = computed(() => { var _a, _b; void changeTick.value; return (_b = (_a = vault.value) === null || _a === void 0 ? void 0 : _a.isComplete) !== null && _b !== void 0 ? _b : false; });
|
|
2483
|
+
const isBankComplete = computed(() => { var _a, _b; void changeTick.value; return (_b = (_a = vault.value) === null || _a === void 0 ? void 0 : _a.isBankComplete) !== null && _b !== void 0 ? _b : false; });
|
|
2484
|
+
const isTokenizing = computed(() => { var _a, _b; void changeTick.value; return (_b = (_a = vault.value) === null || _a === void 0 ? void 0 : _a.isTokenizing) !== null && _b !== void 0 ? _b : false; });
|
|
2485
|
+
return { createToken, createBankToken, ready, initError, tokenizeCount, reset, isComplete, isBankComplete, isTokenizing };
|
|
2385
2486
|
}
|
|
2386
2487
|
function createFieldComponent(displayName, mountElement) {
|
|
2387
2488
|
return defineComponent({
|
|
@@ -2397,7 +2498,7 @@ function createFieldComponent(displayName, mountElement) {
|
|
|
2397
2498
|
if (!ctx) {
|
|
2398
2499
|
throw new Error('[OzVault] useOzElements() must be called inside <OzElements>');
|
|
2399
2500
|
}
|
|
2400
|
-
const { vault, notifyMount, notifyReady, notifyUnmount } = ctx;
|
|
2501
|
+
const { vault, notifyMount, notifyReady, notifyUnmount, notifyChange } = ctx;
|
|
2401
2502
|
const containerRef = ref(null);
|
|
2402
2503
|
let element = null;
|
|
2403
2504
|
let notifyMountCalled = false;
|
|
@@ -2412,7 +2513,7 @@ function createFieldComponent(displayName, mountElement) {
|
|
|
2412
2513
|
notifyMountCalled = true;
|
|
2413
2514
|
notifyMount();
|
|
2414
2515
|
element.on('ready', () => notifyReady());
|
|
2415
|
-
element.on('change', (e) => emit('change', e));
|
|
2516
|
+
element.on('change', (e) => { emit('change', e); notifyChange(); });
|
|
2416
2517
|
element.on('focus', () => emit('focus'));
|
|
2417
2518
|
element.on('blur', () => emit('blur'));
|
|
2418
2519
|
element.mount(containerRef.value);
|
|
@@ -2444,4 +2545,3 @@ const OzBankAccountNumber = createFieldComponent('OzBankAccountNumber', (v, opts
|
|
|
2444
2545
|
const OzBankRoutingNumber = createFieldComponent('OzBankRoutingNumber', (v, opts) => v.createBankElement('routingNumber', opts));
|
|
2445
2546
|
|
|
2446
2547
|
export { OzBankAccountNumber, OzBankRoutingNumber, OzCardNumber, OzCvv, OzElements, OzExpiry, useOzElements };
|
|
2447
|
-
//# sourceMappingURL=index.esm.js.map
|
|
@@ -107,6 +107,39 @@ export declare class OzVault {
|
|
|
107
107
|
* payButton.textContent = remaining > 0 ? `Pay (${remaining} attempts left)` : 'Pay';
|
|
108
108
|
*/
|
|
109
109
|
get tokenizeCount(): number;
|
|
110
|
+
/**
|
|
111
|
+
* `true` when every mounted field has reported `complete && valid` via its
|
|
112
|
+
* last `change` event. `false` if no fields have been created, or if any
|
|
113
|
+
* field is incomplete or invalid.
|
|
114
|
+
*
|
|
115
|
+
* Use this to gate the pay button in vanilla JS integrations without having
|
|
116
|
+
* to wire up individual `change` event listeners:
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* vault.getElement('cardNumber')!.on('change', () => {
|
|
120
|
+
* payBtn.disabled = !vault.isComplete;
|
|
121
|
+
* });
|
|
122
|
+
*/
|
|
123
|
+
get isComplete(): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Like {@link isComplete}, but for bank-account elements created via
|
|
126
|
+
* {@link createBankElement}. Card and bank fields are tracked separately so a
|
|
127
|
+
* card-only checkout is never gated on bank fields (and vice versa), matching
|
|
128
|
+
* the `createToken()` / `createBankToken()` split. A vault with both card and
|
|
129
|
+
* bank elements exposes each completion state independently.
|
|
130
|
+
*/
|
|
131
|
+
get isBankComplete(): boolean;
|
|
132
|
+
/** True iff the set is non-empty and every element has reported complete-and-valid. */
|
|
133
|
+
private allComplete;
|
|
134
|
+
/**
|
|
135
|
+
* `true` while a `createToken()` or `createBankToken()` call is in progress
|
|
136
|
+
* (including the transparent wax-key refresh phase). Use this to keep the pay
|
|
137
|
+
* button disabled during tokenization to prevent double-submission.
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* payBtn.disabled = vault.isTokenizing;
|
|
141
|
+
*/
|
|
142
|
+
get isTokenizing(): boolean;
|
|
110
143
|
/**
|
|
111
144
|
* Creates a new OzElement of the given type. Call `.mount(selector)` on the
|
|
112
145
|
* returned element to attach it to the DOM.
|
|
@@ -223,8 +223,14 @@ export interface VaultOptions {
|
|
|
223
223
|
/**
|
|
224
224
|
* Called if the tokenizer iframe fails to signal ready within `loadTimeoutMs`.
|
|
225
225
|
* Use this to show a fallback UI (e.g. "Unable to load payment fields").
|
|
226
|
+
*
|
|
227
|
+
* Receives an optional `info` object with a `source` field identifying which
|
|
228
|
+
* iframe timed out. Currently always `'tokenizer'` — element-level load errors
|
|
229
|
+
* fire the `loaderror` event on the individual element instead.
|
|
226
230
|
*/
|
|
227
|
-
onLoadError?: (
|
|
231
|
+
onLoadError?: (info?: {
|
|
232
|
+
source: 'tokenizer';
|
|
233
|
+
}) => void;
|
|
228
234
|
/** How long to wait (ms) for the tokenizer iframe before calling `onLoadError`. Default: 10 000.
|
|
229
235
|
* Only takes effect when `onLoadError` is also provided — setting this without `onLoadError` has no effect. */
|
|
230
236
|
loadTimeoutMs?: number;
|
|
@@ -350,10 +356,24 @@ export interface TokenizeOptions {
|
|
|
350
356
|
}
|
|
351
357
|
/** Options for `vault.createBankToken()`. */
|
|
352
358
|
export interface BankTokenizeOptions {
|
|
353
|
-
/**
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
359
|
+
/**
|
|
360
|
+
* Account holder first name.
|
|
361
|
+
* Required when `billing` is not provided.
|
|
362
|
+
* @deprecated Pass firstName inside `billing` instead.
|
|
363
|
+
*/
|
|
364
|
+
firstName?: string;
|
|
365
|
+
/**
|
|
366
|
+
* Account holder last name.
|
|
367
|
+
* Required when `billing` is not provided.
|
|
368
|
+
* @deprecated Pass lastName inside `billing` instead.
|
|
369
|
+
*/
|
|
370
|
+
lastName?: string;
|
|
371
|
+
/**
|
|
372
|
+
* Billing details for the account holder. When provided, `billing.firstName`
|
|
373
|
+
* and `billing.lastName` take precedence over the top-level fields.
|
|
374
|
+
* The normalized details are echoed back in `BankTokenResponse.billing`.
|
|
375
|
+
*/
|
|
376
|
+
billing?: BillingDetails;
|
|
357
377
|
}
|
|
358
378
|
/** Non-sensitive bank account metadata returned alongside the token. */
|
|
359
379
|
export interface BankAccountMetadata {
|
|
@@ -406,6 +426,11 @@ export interface BankTokenResponse {
|
|
|
406
426
|
token: string;
|
|
407
427
|
/** Non-sensitive bank account metadata. */
|
|
408
428
|
bank?: BankAccountMetadata;
|
|
429
|
+
/**
|
|
430
|
+
* Validated, normalized billing details — echoed back when billing was
|
|
431
|
+
* passed to createBankToken(). Ready to spread into your ACH processor request.
|
|
432
|
+
*/
|
|
433
|
+
billing?: BillingDetails;
|
|
409
434
|
}
|
|
410
435
|
/**
|
|
411
436
|
* Full request body for the Ozura Pay API cardSale endpoint.
|
package/dist/vue/vue/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* ```
|
|
25
25
|
*/
|
|
26
26
|
import { type Ref, type PropType, type ComputedRef } from 'vue';
|
|
27
|
-
import type { TokenizeOptions, TokenResponse, BankTokenizeOptions, BankTokenResponse, FontSource, Appearance } from '../types';
|
|
27
|
+
import type { ElementOptions, TokenizeOptions, TokenResponse, BankTokenizeOptions, BankTokenResponse, FontSource, Appearance } from '../types';
|
|
28
28
|
export interface OzElementsProps {
|
|
29
29
|
/** Omit when using a test vault key from a Test project at ozuravault.com.
|
|
30
30
|
* Required for production vault keys. */
|
|
@@ -40,6 +40,14 @@ export interface OzElementsProps {
|
|
|
40
40
|
onSessionRefresh?: () => void;
|
|
41
41
|
/** Called once when the vault tokenizer and all mounted field iframes are ready. */
|
|
42
42
|
onReady?: () => void;
|
|
43
|
+
/**
|
|
44
|
+
* Called if the tokenizer iframe fails to signal ready within `loadTimeoutMs`.
|
|
45
|
+
* Use this to show a fallback UI (e.g. "Payment fields failed to load").
|
|
46
|
+
* Receives an optional info object with `source: 'tokenizer'`.
|
|
47
|
+
*/
|
|
48
|
+
onLoadError?: (info?: {
|
|
49
|
+
source: 'tokenizer';
|
|
50
|
+
}) => void;
|
|
43
51
|
/**
|
|
44
52
|
* Maximum number of tokenize calls before the vault proactively refreshes the session.
|
|
45
53
|
* Must match the `sessionLimit` passed to `createSession()` on your server.
|
|
@@ -94,6 +102,12 @@ export declare const OzElements: import("vue").DefineComponent<import("vue").Ext
|
|
|
94
102
|
type: PropType<() => void>;
|
|
95
103
|
default: undefined;
|
|
96
104
|
};
|
|
105
|
+
onLoadError: {
|
|
106
|
+
type: PropType<(info?: {
|
|
107
|
+
source: "tokenizer";
|
|
108
|
+
}) => void>;
|
|
109
|
+
default: undefined;
|
|
110
|
+
};
|
|
97
111
|
sessionLimit: {
|
|
98
112
|
type: PropType<number | null>;
|
|
99
113
|
default: undefined;
|
|
@@ -145,6 +159,12 @@ export declare const OzElements: import("vue").DefineComponent<import("vue").Ext
|
|
|
145
159
|
type: PropType<() => void>;
|
|
146
160
|
default: undefined;
|
|
147
161
|
};
|
|
162
|
+
onLoadError: {
|
|
163
|
+
type: PropType<(info?: {
|
|
164
|
+
source: "tokenizer";
|
|
165
|
+
}) => void>;
|
|
166
|
+
default: undefined;
|
|
167
|
+
};
|
|
148
168
|
sessionLimit: {
|
|
149
169
|
type: PropType<number | null>;
|
|
150
170
|
default: undefined;
|
|
@@ -167,6 +187,9 @@ export declare const OzElements: import("vue").DefineComponent<import("vue").Ext
|
|
|
167
187
|
appearance: Appearance;
|
|
168
188
|
onSessionRefresh: () => void;
|
|
169
189
|
onReady: () => void;
|
|
190
|
+
onLoadError: (info?: {
|
|
191
|
+
source: "tokenizer";
|
|
192
|
+
}) => void;
|
|
170
193
|
sessionLimit: number | null;
|
|
171
194
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
172
195
|
export interface UseOzElementsReturn {
|
|
@@ -196,6 +219,32 @@ export interface UseOzElementsReturn {
|
|
|
196
219
|
* Clears all mounted element fields without destroying the vault.
|
|
197
220
|
*/
|
|
198
221
|
reset: () => void;
|
|
222
|
+
/**
|
|
223
|
+
* `true` when every mounted field has reported `complete && valid`.
|
|
224
|
+
* Use this to gate the pay button without wiring individual `@change`
|
|
225
|
+
* listeners — reacts in real time as the customer fills in fields.
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* const { ready, isComplete, createToken } = useOzElements();
|
|
229
|
+
* // <button :disabled="!ready || !isComplete" @click="createToken()">Pay</button>
|
|
230
|
+
*/
|
|
231
|
+
isComplete: ComputedRef<boolean>;
|
|
232
|
+
/**
|
|
233
|
+
* Like `isComplete`, but for bank-account fields (`createBankElement`). Card
|
|
234
|
+
* and bank completion are tracked independently, so a card-only form isn't
|
|
235
|
+
* gated on bank fields and vice versa.
|
|
236
|
+
*/
|
|
237
|
+
isBankComplete: ComputedRef<boolean>;
|
|
238
|
+
/**
|
|
239
|
+
* `true` while `createToken()` or `createBankToken()` is in progress,
|
|
240
|
+
* including the transparent wax-key refresh phase. Use this to keep the
|
|
241
|
+
* pay button disabled and prevent double-submission.
|
|
242
|
+
*
|
|
243
|
+
* @example
|
|
244
|
+
* const { isTokenizing, createToken } = useOzElements();
|
|
245
|
+
* // <button :disabled="isTokenizing" @click="createToken()">Pay</button>
|
|
246
|
+
*/
|
|
247
|
+
isTokenizing: ComputedRef<boolean>;
|
|
199
248
|
}
|
|
200
249
|
/**
|
|
201
250
|
* Returns createToken, createBankToken, ready, initError, tokenizeCount, and reset.
|
|
@@ -204,6 +253,12 @@ export interface UseOzElementsReturn {
|
|
|
204
253
|
* @throws {Error} if called outside an <OzElements> provider
|
|
205
254
|
*/
|
|
206
255
|
export declare function useOzElements(): UseOzElementsReturn;
|
|
256
|
+
/** Props accepted by all individual field components (OzCardNumber, OzExpiry, OzCvv, etc.). */
|
|
257
|
+
export interface OzFieldProps {
|
|
258
|
+
placeholder?: string;
|
|
259
|
+
disabled?: boolean;
|
|
260
|
+
style?: ElementOptions['style'];
|
|
261
|
+
}
|
|
207
262
|
/** Card number field. Emits `change` (ElementChangeEvent), `focus`, `blur`. */
|
|
208
263
|
export declare const OzCardNumber: import("vue").DefineComponent<{
|
|
209
264
|
placeholder?: string | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ozura/elements",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "PCI-compliant card tokenization SDK for the Ozura Vault — collect card data in iframe-isolated fields and tokenize without PCI scope",
|
|
5
5
|
"main": "dist/oz-elements.umd.js",
|
|
6
6
|
"module": "dist/oz-elements.esm.js",
|