@invonetwork/web-sdk 0.4.1 → 0.5.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/CHANGELOG.md +28 -0
- package/README.md +5 -3
- package/dist/{chunk-EEWOAUXO.js → chunk-JOVATUDY.js} +6 -2
- package/dist/index.cjs +12 -2
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +10 -4
- package/dist/server.cjs +6 -1
- package/dist/server.d.cts +4 -2
- package/dist/server.d.ts +4 -2
- package/dist/server.js +4 -3
- package/dist/{types-CBMLNwbe.d.cts → types-CZdmipNK.d.cts} +2 -0
- package/dist/{types-CBMLNwbe.d.ts → types-CZdmipNK.d.ts} +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,34 @@ All notable changes to `@invonetwork/web-sdk` are documented here. This project
|
|
|
4
4
|
[Semantic Versioning](https://semver.org/). Releases are managed with
|
|
5
5
|
[changesets](https://github.com/changesets/changesets).
|
|
6
6
|
|
|
7
|
+
## [0.5.0] — 2026-07-01
|
|
8
|
+
|
|
9
|
+
Support partner `metadata` end-to-end on the purchase flow (additive, backward-compatible).
|
|
10
|
+
|
|
11
|
+
- **`PurchaseCompletedData.metadata?`** — the `purchase.completed` webhook now echoes your
|
|
12
|
+
metadata back (all rails); `event.data.metadata` is typed.
|
|
13
|
+
- **`purchaseCurrency`** now accepts and forwards `metadata` (the direct `/purchase-currency`
|
|
14
|
+
endpoint accepts it too, matching `createCheckout`).
|
|
15
|
+
|
|
16
|
+
## [0.4.2] — 2026-06-30
|
|
17
|
+
|
|
18
|
+
Fixes from an independent line-by-line audit against the live backend.
|
|
19
|
+
|
|
20
|
+
- **`linkDevice` now works.** `device/link/webauthn/begin` returns a wrapped
|
|
21
|
+
`{ link_id, options }` body (challenge nested under `options`) and binds the
|
|
22
|
+
challenge to a server-generated `link_id`. The client now unwraps `options` and
|
|
23
|
+
echoes the server's `link_id` to `/complete` (it previously threw on an undefined
|
|
24
|
+
challenge and sent the wrong id).
|
|
25
|
+
- **`InvoError.code` is now populated for the direct purchase rail + guardian flows.**
|
|
26
|
+
`errorFromResponse` reads `error_code` (SecureErrorHandler + `/purchase-currency`)
|
|
27
|
+
in addition to `code`, and promotes known no-code tokens (`flow_paused`,
|
|
28
|
+
`spending_limit_exceeded`, `receiver_not_enrolled_use_claim_code`) to `.code`. Fixes
|
|
29
|
+
`isDuplicateRequest` on the direct rail.
|
|
30
|
+
- **Guardian/minor routing.** The 202 guardian body also carries
|
|
31
|
+
`verification_method:"sms"`; the SDK now suppresses it (reports
|
|
32
|
+
`verificationMethod: undefined`) so a guardian-pending minor isn't routed into the
|
|
33
|
+
SMS-PIN UI. README example reordered to branch on `guardianApproval` first.
|
|
34
|
+
|
|
7
35
|
## [0.4.1] — 2026-06-30
|
|
8
36
|
|
|
9
37
|
Docs only — replaced the README's internal-leaking "Deployment prerequisites"
|
package/README.md
CHANGED
|
@@ -183,6 +183,7 @@ const purchase = await server.purchaseCurrency({
|
|
|
183
183
|
purchaseReference: crypto.randomUUID(), // idempotency key, required
|
|
184
184
|
rail: "platform",
|
|
185
185
|
paymentMethodId: "pm_...", // a tokenized payment method
|
|
186
|
+
metadata: { yourOrderId: "ord_42" }, // echoed back on the purchase.completed webhook
|
|
186
187
|
});
|
|
187
188
|
// purchase.status:
|
|
188
189
|
// "success" → captured, purchase.newBalance updated
|
|
@@ -260,10 +261,11 @@ const t = await server.initiateTransfer({
|
|
|
260
261
|
});
|
|
261
262
|
// (initiateSend uses sender*/receiver* + receivingGameId instead)
|
|
262
263
|
|
|
264
|
+
// Check guardianApproval FIRST — the guardian path takes precedence.
|
|
263
265
|
switch (true) {
|
|
266
|
+
case !!t.guardianApproval: // minor/guardian path (HTTP 202) → pending approval, no PIN UI
|
|
264
267
|
case t.verificationMethod === "in_app": // sender is passkey-enrolled → approve in the browser
|
|
265
268
|
case t.verificationMethod === "sms": // not enrolled, a PIN was sent → show a PIN-entry fallback
|
|
266
|
-
case !!t.guardianApproval: // minor/guardian path (HTTP 202) → do NOT show the PIN UI
|
|
267
269
|
}
|
|
268
270
|
|
|
269
271
|
// 2. BROWSER — the sender approves with their passkey (give them t.transactionId + the player token)
|
|
@@ -280,7 +282,7 @@ try {
|
|
|
280
282
|
}
|
|
281
283
|
```
|
|
282
284
|
|
|
283
|
-
- **`verificationMethod`** (from initiate): `"in_app"` → passkey approve; `"sms"` → un-enrolled, PIN sent; `undefined` + `guardianApproval` → minor/guardian (HTTP 202), do **not** show the PIN UI.
|
|
285
|
+
- **`verificationMethod`** (from initiate): `"in_app"` → passkey approve; `"sms"` → un-enrolled, PIN sent; `undefined` + `guardianApproval` → minor/guardian (HTTP 202), do **not** show the PIN UI. On the guardian path the SDK reports `verificationMethod: undefined` (even though the raw 202 body also carries `"sms"`) so `guardianApproval` wins — but branch on it first to be safe.
|
|
284
286
|
- **Claim codes** are returned only by `approveTransfer`; they're the out-of-band fallback when the recipient isn't enrolled.
|
|
285
287
|
- **`err.isReceiverNotEnrolled`** on `confirmReceipt*` is the explicit signal to switch to claim-code entry.
|
|
286
288
|
- Transfer self-claim may be disabled for your tenant; if it is, surface the claim-code path instead.
|
|
@@ -368,7 +370,7 @@ export const POST = createWebhookHandler({
|
|
|
368
370
|
|
|
369
371
|
| Event | Fires for | Use it to |
|
|
370
372
|
|---|---|---|
|
|
371
|
-
| `purchase.completed` | every currency-purchase rail | grant currency (payload: `transaction_id, order_id, player_email, identity_id, usd_amount, currency_amount, currency_name, new_balance, rail`) |
|
|
373
|
+
| `purchase.completed` | every currency-purchase rail | grant currency (payload: `transaction_id, order_id, player_email, identity_id, usd_amount, currency_amount, currency_name, new_balance, rail, metadata`) — `metadata` echoes what you passed to `createCheckout`/`purchaseCurrency` |
|
|
372
374
|
| `purchase.failed` / `purchase.disputed` | `platform` rail only | handle failures/disputes |
|
|
373
375
|
| `purchase.refunded` | `game` / `steam` rails | handle refunds |
|
|
374
376
|
| `item.purchased` | every item purchase | **grant the in-game item** (payload includes `transaction_id, order_id, player_email, identity_id, item_id, item_name, item_quantity, unit_price, total_price, currency_name, new_balance, fee_breakdown`) |
|
|
@@ -50,8 +50,12 @@ function errorFromResponse(status, body, requestId) {
|
|
|
50
50
|
if (body && typeof body === "object") {
|
|
51
51
|
const b = body;
|
|
52
52
|
if (typeof b["code"] === "string") code = b["code"];
|
|
53
|
+
else if (typeof b["error_code"] === "string") code = b["error_code"];
|
|
53
54
|
if (typeof b["error"] === "string") message = b["error"];
|
|
54
55
|
else if (typeof b["message"] === "string") message = b["message"];
|
|
56
|
+
if (!code && typeof b["error"] === "string" && /^(flow_paused|spending_limit_exceeded|receiver_not_enrolled_use_claim_code)$/.test(b["error"])) {
|
|
57
|
+
code = b["error"];
|
|
58
|
+
}
|
|
55
59
|
} else if (typeof body === "string" && body.trim()) {
|
|
56
60
|
message = body;
|
|
57
61
|
}
|
|
@@ -245,5 +249,5 @@ function retryAfterMs(parsed, headers) {
|
|
|
245
249
|
}
|
|
246
250
|
|
|
247
251
|
export { Http, InvoError, assertSecureBaseUrl };
|
|
248
|
-
//# sourceMappingURL=chunk-
|
|
249
|
-
//# sourceMappingURL=chunk-
|
|
252
|
+
//# sourceMappingURL=chunk-JOVATUDY.js.map
|
|
253
|
+
//# sourceMappingURL=chunk-JOVATUDY.js.map
|
package/dist/index.cjs
CHANGED
|
@@ -52,8 +52,12 @@ function errorFromResponse(status, body, requestId) {
|
|
|
52
52
|
if (body && typeof body === "object") {
|
|
53
53
|
const b = body;
|
|
54
54
|
if (typeof b["code"] === "string") code = b["code"];
|
|
55
|
+
else if (typeof b["error_code"] === "string") code = b["error_code"];
|
|
55
56
|
if (typeof b["error"] === "string") message = b["error"];
|
|
56
57
|
else if (typeof b["message"] === "string") message = b["message"];
|
|
58
|
+
if (!code && typeof b["error"] === "string" && /^(flow_paused|spending_limit_exceeded|receiver_not_enrolled_use_claim_code)$/.test(b["error"])) {
|
|
59
|
+
code = b["error"];
|
|
60
|
+
}
|
|
57
61
|
} else if (typeof body === "string" && body.trim()) {
|
|
58
62
|
message = body;
|
|
59
63
|
}
|
|
@@ -399,16 +403,22 @@ var InvoClient = class {
|
|
|
399
403
|
*/
|
|
400
404
|
async linkDevice(linkId, opts) {
|
|
401
405
|
if (!linkId) throw new Error("linkDevice requires a `linkId`.");
|
|
406
|
+
this.assertWebAuthn();
|
|
402
407
|
const signal = opts?.signal;
|
|
403
408
|
return this.withTokenRetry(async () => {
|
|
404
|
-
const
|
|
409
|
+
const begin = await this.post(
|
|
405
410
|
"/api/sdk/device/link/webauthn/begin",
|
|
406
411
|
{ link_id: linkId },
|
|
407
412
|
signal
|
|
408
413
|
);
|
|
414
|
+
const cred = await navigator.credentials.get({
|
|
415
|
+
publicKey: toRequestOptions(begin.options),
|
|
416
|
+
signal
|
|
417
|
+
});
|
|
418
|
+
if (!cred) throw new Error("Passkey assertion was cancelled or returned no credential.");
|
|
409
419
|
const raw = await this.post(
|
|
410
420
|
"/api/sdk/device/link/webauthn/complete",
|
|
411
|
-
{ link_id:
|
|
421
|
+
{ link_id: begin.link_id, webauthn_assertion: assertionToJSON(cred) },
|
|
412
422
|
signal
|
|
413
423
|
);
|
|
414
424
|
return { status: String(raw["status"] ?? ""), raw };
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as ClientConfig, a as CallOptions, A as ApproveResult, b as ConfirmReceiptResult, L as LinkDeviceResult } from './types-
|
|
2
|
-
export { I as InvoError, c as InvoErrorInfo, d as InvoHooks, e as InvoRequestInfo, f as InvoResponseInfo, R as Rail, V as VerificationMethod } from './types-
|
|
1
|
+
import { C as ClientConfig, a as CallOptions, A as ApproveResult, b as ConfirmReceiptResult, L as LinkDeviceResult } from './types-CZdmipNK.cjs';
|
|
2
|
+
export { I as InvoError, c as InvoErrorInfo, d as InvoHooks, e as InvoRequestInfo, f as InvoResponseInfo, R as Rail, V as VerificationMethod } from './types-CZdmipNK.cjs';
|
|
3
3
|
|
|
4
4
|
declare class InvoClient {
|
|
5
5
|
private readonly http;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as ClientConfig, a as CallOptions, A as ApproveResult, b as ConfirmReceiptResult, L as LinkDeviceResult } from './types-
|
|
2
|
-
export { I as InvoError, c as InvoErrorInfo, d as InvoHooks, e as InvoRequestInfo, f as InvoResponseInfo, R as Rail, V as VerificationMethod } from './types-
|
|
1
|
+
import { C as ClientConfig, a as CallOptions, A as ApproveResult, b as ConfirmReceiptResult, L as LinkDeviceResult } from './types-CZdmipNK.js';
|
|
2
|
+
export { I as InvoError, c as InvoErrorInfo, d as InvoHooks, e as InvoRequestInfo, f as InvoResponseInfo, R as Rail, V as VerificationMethod } from './types-CZdmipNK.js';
|
|
3
3
|
|
|
4
4
|
declare class InvoClient {
|
|
5
5
|
private readonly http;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { assertSecureBaseUrl, Http, InvoError } from './chunk-
|
|
2
|
-
export { InvoError } from './chunk-
|
|
1
|
+
import { assertSecureBaseUrl, Http, InvoError } from './chunk-JOVATUDY.js';
|
|
2
|
+
export { InvoError } from './chunk-JOVATUDY.js';
|
|
3
3
|
|
|
4
4
|
// src/shared/webauthn.ts
|
|
5
5
|
function b64urlToBuffer(value) {
|
|
@@ -154,16 +154,22 @@ var InvoClient = class {
|
|
|
154
154
|
*/
|
|
155
155
|
async linkDevice(linkId, opts) {
|
|
156
156
|
if (!linkId) throw new Error("linkDevice requires a `linkId`.");
|
|
157
|
+
this.assertWebAuthn();
|
|
157
158
|
const signal = opts?.signal;
|
|
158
159
|
return this.withTokenRetry(async () => {
|
|
159
|
-
const
|
|
160
|
+
const begin = await this.post(
|
|
160
161
|
"/api/sdk/device/link/webauthn/begin",
|
|
161
162
|
{ link_id: linkId },
|
|
162
163
|
signal
|
|
163
164
|
);
|
|
165
|
+
const cred = await navigator.credentials.get({
|
|
166
|
+
publicKey: toRequestOptions(begin.options),
|
|
167
|
+
signal
|
|
168
|
+
});
|
|
169
|
+
if (!cred) throw new Error("Passkey assertion was cancelled or returned no credential.");
|
|
164
170
|
const raw = await this.post(
|
|
165
171
|
"/api/sdk/device/link/webauthn/complete",
|
|
166
|
-
{ link_id:
|
|
172
|
+
{ link_id: begin.link_id, webauthn_assertion: assertionToJSON(cred) },
|
|
167
173
|
signal
|
|
168
174
|
);
|
|
169
175
|
return { status: String(raw["status"] ?? ""), raw };
|
package/dist/server.cjs
CHANGED
|
@@ -54,8 +54,12 @@ function errorFromResponse(status, body, requestId) {
|
|
|
54
54
|
if (body && typeof body === "object") {
|
|
55
55
|
const b = body;
|
|
56
56
|
if (typeof b["code"] === "string") code = b["code"];
|
|
57
|
+
else if (typeof b["error_code"] === "string") code = b["error_code"];
|
|
57
58
|
if (typeof b["error"] === "string") message = b["error"];
|
|
58
59
|
else if (typeof b["message"] === "string") message = b["message"];
|
|
60
|
+
if (!code && typeof b["error"] === "string" && /^(flow_paused|spending_limit_exceeded|receiver_not_enrolled_use_claim_code)$/.test(b["error"])) {
|
|
61
|
+
code = b["error"];
|
|
62
|
+
}
|
|
59
63
|
} else if (typeof body === "string" && body.trim()) {
|
|
60
64
|
message = body;
|
|
61
65
|
}
|
|
@@ -627,6 +631,7 @@ var InvoServer = class {
|
|
|
627
631
|
if (input.savedCardId) body["saved_card_id"] = input.savedCardId;
|
|
628
632
|
if (input.playerName) body["player_name"] = input.playerName;
|
|
629
633
|
if (input.playerPhone) body["player_phone"] = input.playerPhone;
|
|
634
|
+
if (input.metadata) body["metadata"] = input.metadata;
|
|
630
635
|
const raw = await this.http.post(
|
|
631
636
|
"/api/currency-purchases/purchase-currency",
|
|
632
637
|
body,
|
|
@@ -869,7 +874,7 @@ var InvoServer = class {
|
|
|
869
874
|
const guardian = raw["guardian_approval"];
|
|
870
875
|
return {
|
|
871
876
|
transactionId: String(raw["transaction_id"] ?? ""),
|
|
872
|
-
verificationMethod: vm === "in_app" || vm === "sms" ? vm : void 0,
|
|
877
|
+
verificationMethod: guardian ? void 0 : vm === "in_app" || vm === "sms" ? vm : void 0,
|
|
873
878
|
guardianApproval: guardian ?? void 0,
|
|
874
879
|
raw
|
|
875
880
|
};
|
package/dist/server.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as InvoError, S as ServerConfig, a as CallOptions, P as PlayerToken, g as InitiateSendInput, h as InitiateResult, i as InitiateTransferInput, j as CreateCheckoutInput, k as CreateCheckoutResult, l as PurchaseInput, m as PurchaseResult, n as ConfirmPaymentResult, O as OrderDetailsResult, o as PurchaseItemInput, p as PurchaseItemResult, q as ItemHistoryQuery, r as ItemHistoryResult, s as ItemOrderQuery, t as PlayerBalanceQuery, u as PlayerBalanceResult, v as InboundPendingQuery, w as InboundPendingResult } from './types-
|
|
2
|
-
export { x as CurrencyBalance, y as InboundPendingItem, c as InvoErrorInfo, d as InvoHooks, e as InvoRequestInfo, f as InvoResponseInfo, R as Rail, V as VerificationMethod } from './types-
|
|
1
|
+
import { I as InvoError, S as ServerConfig, a as CallOptions, P as PlayerToken, g as InitiateSendInput, h as InitiateResult, i as InitiateTransferInput, j as CreateCheckoutInput, k as CreateCheckoutResult, l as PurchaseInput, m as PurchaseResult, n as ConfirmPaymentResult, O as OrderDetailsResult, o as PurchaseItemInput, p as PurchaseItemResult, q as ItemHistoryQuery, r as ItemHistoryResult, s as ItemOrderQuery, t as PlayerBalanceQuery, u as PlayerBalanceResult, v as InboundPendingQuery, w as InboundPendingResult } from './types-CZdmipNK.cjs';
|
|
2
|
+
export { x as CurrencyBalance, y as InboundPendingItem, c as InvoErrorInfo, d as InvoHooks, e as InvoRequestInfo, f as InvoResponseInfo, R as Rail, V as VerificationMethod } from './types-CZdmipNK.cjs';
|
|
3
3
|
|
|
4
4
|
interface VerifyWebhookOptions {
|
|
5
5
|
/** Max age of the signed timestamp, in seconds. Default 300 (5 min). */
|
|
@@ -25,6 +25,8 @@ interface PurchaseCompletedData {
|
|
|
25
25
|
currency_name: string;
|
|
26
26
|
new_balance: string;
|
|
27
27
|
rail: string;
|
|
28
|
+
/** The metadata you passed to createCheckout/purchaseCurrency, echoed back (all rails). */
|
|
29
|
+
metadata?: Record<string, unknown>;
|
|
28
30
|
[key: string]: unknown;
|
|
29
31
|
}
|
|
30
32
|
interface PurchaseEventData {
|
package/dist/server.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as InvoError, S as ServerConfig, a as CallOptions, P as PlayerToken, g as InitiateSendInput, h as InitiateResult, i as InitiateTransferInput, j as CreateCheckoutInput, k as CreateCheckoutResult, l as PurchaseInput, m as PurchaseResult, n as ConfirmPaymentResult, O as OrderDetailsResult, o as PurchaseItemInput, p as PurchaseItemResult, q as ItemHistoryQuery, r as ItemHistoryResult, s as ItemOrderQuery, t as PlayerBalanceQuery, u as PlayerBalanceResult, v as InboundPendingQuery, w as InboundPendingResult } from './types-
|
|
2
|
-
export { x as CurrencyBalance, y as InboundPendingItem, c as InvoErrorInfo, d as InvoHooks, e as InvoRequestInfo, f as InvoResponseInfo, R as Rail, V as VerificationMethod } from './types-
|
|
1
|
+
import { I as InvoError, S as ServerConfig, a as CallOptions, P as PlayerToken, g as InitiateSendInput, h as InitiateResult, i as InitiateTransferInput, j as CreateCheckoutInput, k as CreateCheckoutResult, l as PurchaseInput, m as PurchaseResult, n as ConfirmPaymentResult, O as OrderDetailsResult, o as PurchaseItemInput, p as PurchaseItemResult, q as ItemHistoryQuery, r as ItemHistoryResult, s as ItemOrderQuery, t as PlayerBalanceQuery, u as PlayerBalanceResult, v as InboundPendingQuery, w as InboundPendingResult } from './types-CZdmipNK.js';
|
|
2
|
+
export { x as CurrencyBalance, y as InboundPendingItem, c as InvoErrorInfo, d as InvoHooks, e as InvoRequestInfo, f as InvoResponseInfo, R as Rail, V as VerificationMethod } from './types-CZdmipNK.js';
|
|
3
3
|
|
|
4
4
|
interface VerifyWebhookOptions {
|
|
5
5
|
/** Max age of the signed timestamp, in seconds. Default 300 (5 min). */
|
|
@@ -25,6 +25,8 @@ interface PurchaseCompletedData {
|
|
|
25
25
|
currency_name: string;
|
|
26
26
|
new_balance: string;
|
|
27
27
|
rail: string;
|
|
28
|
+
/** The metadata you passed to createCheckout/purchaseCurrency, echoed back (all rails). */
|
|
29
|
+
metadata?: Record<string, unknown>;
|
|
28
30
|
[key: string]: unknown;
|
|
29
31
|
}
|
|
30
32
|
interface PurchaseEventData {
|
package/dist/server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { InvoError, assertSecureBaseUrl, Http } from './chunk-
|
|
2
|
-
export { InvoError } from './chunk-
|
|
1
|
+
import { InvoError, assertSecureBaseUrl, Http } from './chunk-JOVATUDY.js';
|
|
2
|
+
export { InvoError } from './chunk-JOVATUDY.js';
|
|
3
3
|
import { createHmac } from 'crypto';
|
|
4
4
|
|
|
5
5
|
var DEFAULT_TOLERANCE_SEC = 300;
|
|
@@ -382,6 +382,7 @@ var InvoServer = class {
|
|
|
382
382
|
if (input.savedCardId) body["saved_card_id"] = input.savedCardId;
|
|
383
383
|
if (input.playerName) body["player_name"] = input.playerName;
|
|
384
384
|
if (input.playerPhone) body["player_phone"] = input.playerPhone;
|
|
385
|
+
if (input.metadata) body["metadata"] = input.metadata;
|
|
385
386
|
const raw = await this.http.post(
|
|
386
387
|
"/api/currency-purchases/purchase-currency",
|
|
387
388
|
body,
|
|
@@ -624,7 +625,7 @@ var InvoServer = class {
|
|
|
624
625
|
const guardian = raw["guardian_approval"];
|
|
625
626
|
return {
|
|
626
627
|
transactionId: String(raw["transaction_id"] ?? ""),
|
|
627
|
-
verificationMethod: vm === "in_app" || vm === "sms" ? vm : void 0,
|
|
628
|
+
verificationMethod: guardian ? void 0 : vm === "in_app" || vm === "sms" ? vm : void 0,
|
|
628
629
|
guardianApproval: guardian ?? void 0,
|
|
629
630
|
raw
|
|
630
631
|
};
|
|
@@ -176,6 +176,8 @@ interface PurchaseInput {
|
|
|
176
176
|
savedCardId?: string;
|
|
177
177
|
playerName?: string;
|
|
178
178
|
playerPhone?: string;
|
|
179
|
+
/** Arbitrary metadata echoed back on the purchase.completed webhook (data.metadata). */
|
|
180
|
+
metadata?: Record<string, unknown>;
|
|
179
181
|
}
|
|
180
182
|
type PurchaseStatus = "success" | "requires_action" | "pending_payment";
|
|
181
183
|
interface PurchaseResult {
|
|
@@ -176,6 +176,8 @@ interface PurchaseInput {
|
|
|
176
176
|
savedCardId?: string;
|
|
177
177
|
playerName?: string;
|
|
178
178
|
playerPhone?: string;
|
|
179
|
+
/** Arbitrary metadata echoed back on the purchase.completed webhook (data.metadata). */
|
|
180
|
+
metadata?: Record<string, unknown>;
|
|
179
181
|
}
|
|
180
182
|
type PurchaseStatus = "success" | "requires_action" | "pending_payment";
|
|
181
183
|
interface PurchaseResult {
|
package/package.json
CHANGED