@invonetwork/web-sdk 1.0.0 → 1.2.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 +26 -0
- package/README.md +11 -3
- package/dist/{chunk-D3XBTH4C.js → chunk-P65XQ6VF.js} +54 -3
- package/dist/index.cjs +52 -39
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -41
- package/dist/server.cjs +342 -1
- package/dist/server.d.cts +68 -3
- package/dist/server.d.ts +68 -3
- package/dist/server.js +293 -3
- package/dist/{types-DLSCxpoT.d.cts → types-DTAmriOB.d.cts} +135 -1
- package/dist/{types-DLSCxpoT.d.ts → types-DTAmriOB.d.ts} +135 -1
- package/package.json +1 -1
package/dist/server.cjs
CHANGED
|
@@ -40,6 +40,14 @@ var InvoError = class _InvoError extends Error {
|
|
|
40
40
|
const b = this.bodyObject();
|
|
41
41
|
return this.code === "INSUFFICIENT_BALANCE" || "required_amount" in b || /insufficient[_ ]balance/i.test(this.message);
|
|
42
42
|
}
|
|
43
|
+
/** True if a claim needs phone-share approval before it can complete (claim → 409). */
|
|
44
|
+
get isPhoneShareApprovalRequired() {
|
|
45
|
+
return this.code === "PHONE_SHARE_APPROVAL_REQUIRED";
|
|
46
|
+
}
|
|
47
|
+
/** True if the phone-share (phone, requesting_email) pair was already approved. */
|
|
48
|
+
get isPhoneShareAlreadyApproved() {
|
|
49
|
+
return this.code === "PHONE_SHARE_ALREADY_APPROVED";
|
|
50
|
+
}
|
|
43
51
|
/** True if an idempotency-keyed request was a duplicate (item purchase → 409). */
|
|
44
52
|
get isDuplicateRequest() {
|
|
45
53
|
return this.code === "DUPLICATE_REQUEST" || this.status === 409 && /duplicate/i.test(this.message);
|
|
@@ -259,6 +267,49 @@ function retryAfterMs(parsed, headers) {
|
|
|
259
267
|
}
|
|
260
268
|
return void 0;
|
|
261
269
|
}
|
|
270
|
+
|
|
271
|
+
// src/shared/destinations.ts
|
|
272
|
+
function toDestinationGame(row) {
|
|
273
|
+
const s = (k) => row[k] === void 0 || row[k] === null ? void 0 : String(row[k]);
|
|
274
|
+
return {
|
|
275
|
+
gameId: row["game_id"] ?? "",
|
|
276
|
+
gameName: String(row["game_name"] ?? ""),
|
|
277
|
+
tenantType: s("tenant_type"),
|
|
278
|
+
developerName: s("developer_name"),
|
|
279
|
+
publisherName: s("publisher_name"),
|
|
280
|
+
genre: s("genre"),
|
|
281
|
+
platform: s("platform"),
|
|
282
|
+
gameStatus: s("game_status"),
|
|
283
|
+
gameIcon: s("game_icon"),
|
|
284
|
+
gamePoster: s("game_poster"),
|
|
285
|
+
gameUrl: s("game_url"),
|
|
286
|
+
gameDescription: s("game_description"),
|
|
287
|
+
currencyName: String(row["currency_name"] ?? ""),
|
|
288
|
+
currencySymbol: String(row["currency_symbol"] ?? ""),
|
|
289
|
+
currencySymbolUrl: s("currency_symbol_url"),
|
|
290
|
+
minimumTransfer: String(row["minimum_transfer"] ?? ""),
|
|
291
|
+
maximumTransfer: String(row["maximum_transfer"] ?? ""),
|
|
292
|
+
raw: row
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
function toDestinationsResult(raw, direction) {
|
|
296
|
+
const games = Array.isArray(raw["available_games"]) ? raw["available_games"] : [];
|
|
297
|
+
return {
|
|
298
|
+
status: String(raw["status"] ?? ""),
|
|
299
|
+
sourceGameId: raw["source_game_id"] ?? "",
|
|
300
|
+
sourceGameName: String(raw["source_game_name"] ?? ""),
|
|
301
|
+
sourceGameIcon: raw["source_game_icon"],
|
|
302
|
+
sourceCurrencyName: String(raw["source_currency_name"] ?? ""),
|
|
303
|
+
sourceCurrencyIcon: raw["source_currency_icon"],
|
|
304
|
+
universalTransfers: raw["universal_transfers"] === true,
|
|
305
|
+
transferMode: String(raw["transfer_mode"] ?? ""),
|
|
306
|
+
availableGames: games.map(toDestinationGame),
|
|
307
|
+
totalDestinations: Number(raw["total_destinations"] ?? games.length),
|
|
308
|
+
direction: String(raw["direction"] ?? direction),
|
|
309
|
+
linkedGameIds: Array.isArray(raw["linked_game_ids"]) ? raw["linked_game_ids"] : void 0,
|
|
310
|
+
raw
|
|
311
|
+
};
|
|
312
|
+
}
|
|
262
313
|
var DEFAULT_TOLERANCE_SEC = 300;
|
|
263
314
|
var ENCODER = new TextEncoder();
|
|
264
315
|
function toBytes(body) {
|
|
@@ -418,7 +469,7 @@ async function hmacHexSubtle(secret, message) {
|
|
|
418
469
|
}
|
|
419
470
|
|
|
420
471
|
// src/server.ts
|
|
421
|
-
var DEFAULT_UA = "invonetwork-web-sdk/1.
|
|
472
|
+
var DEFAULT_UA = "invonetwork-web-sdk/1.2.0 (+https://invo.network)";
|
|
422
473
|
var MAX_USD_AMOUNT = 999.99;
|
|
423
474
|
var MAX_ITEM_PRICE = 999999.99;
|
|
424
475
|
function invalidInput(label, value, why) {
|
|
@@ -480,6 +531,75 @@ function toInboundPendingItem(row) {
|
|
|
480
531
|
raw: row
|
|
481
532
|
};
|
|
482
533
|
}
|
|
534
|
+
function toSmsVerifyResult(raw) {
|
|
535
|
+
return {
|
|
536
|
+
status: String(raw["status"] ?? ""),
|
|
537
|
+
transactionId: String(raw["transaction_id"] ?? ""),
|
|
538
|
+
claimCode: raw["claim_code"],
|
|
539
|
+
newBalance: raw["new_balance"] ?? null,
|
|
540
|
+
orderId: raw["order_id"],
|
|
541
|
+
raw
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
function toClaimResult(raw) {
|
|
545
|
+
const status = String(raw["status"] ?? "");
|
|
546
|
+
return {
|
|
547
|
+
status,
|
|
548
|
+
transactionId: raw["transaction_id"],
|
|
549
|
+
newBalance: raw["new_balance"] ?? null,
|
|
550
|
+
currencyName: raw["currency_name"],
|
|
551
|
+
orderId: raw["order_id"],
|
|
552
|
+
needsAccountSelection: status === "needs_account_selection",
|
|
553
|
+
candidates: Array.isArray(raw["candidates"]) ? raw["candidates"] : void 0,
|
|
554
|
+
raw
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
function toTransactionStatus(raw) {
|
|
558
|
+
return {
|
|
559
|
+
transactionId: String(raw["transaction_id"] ?? ""),
|
|
560
|
+
transactionType: String(raw["transaction_type"] ?? ""),
|
|
561
|
+
transactionStatus: String(raw["transaction_status"] ?? ""),
|
|
562
|
+
verificationState: String(raw["verification_state"] ?? ""),
|
|
563
|
+
amount: raw["amount"] ?? null,
|
|
564
|
+
netAmount: raw["net_amount"] ?? null,
|
|
565
|
+
currencyId: raw["currency_id"] ?? "",
|
|
566
|
+
orderId: raw["order_id"],
|
|
567
|
+
toPhone: raw["to_phone"],
|
|
568
|
+
toIdentityId: raw["to_identity_id"] ?? null,
|
|
569
|
+
raw
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
function toGuardianApprovalStatus(raw) {
|
|
573
|
+
const approval = raw["approval"] ?? {};
|
|
574
|
+
return {
|
|
575
|
+
state: String(approval["state"] ?? ""),
|
|
576
|
+
approvalId: approval["approval_id"],
|
|
577
|
+
transactionId: approval["transaction_id"],
|
|
578
|
+
expiresAt: approval["expires_at"],
|
|
579
|
+
decidedAt: approval["decided_at"],
|
|
580
|
+
decisionSource: approval["decision_source"],
|
|
581
|
+
actionDescription: approval["action_description"],
|
|
582
|
+
raw
|
|
583
|
+
};
|
|
584
|
+
}
|
|
585
|
+
function toPhoneShareInitiateResult(raw) {
|
|
586
|
+
return {
|
|
587
|
+
approvalId: raw["approval_id"],
|
|
588
|
+
codeSent: typeof raw["code_sent"] === "boolean" ? raw["code_sent"] : void 0,
|
|
589
|
+
expiresAt: raw["expires_at"],
|
|
590
|
+
alreadyApproved: typeof raw["already_approved"] === "boolean" ? raw["already_approved"] : void 0,
|
|
591
|
+
raw
|
|
592
|
+
};
|
|
593
|
+
}
|
|
594
|
+
function toPhoneShareApproveResult(raw) {
|
|
595
|
+
return {
|
|
596
|
+
approvalId: raw["approval_id"],
|
|
597
|
+
approved: typeof raw["approved"] === "boolean" ? raw["approved"] : void 0,
|
|
598
|
+
alreadyApproved: typeof raw["already_approved"] === "boolean" ? raw["already_approved"] : void 0,
|
|
599
|
+
expiresAt: raw["expires_at"],
|
|
600
|
+
raw
|
|
601
|
+
};
|
|
602
|
+
}
|
|
483
603
|
function toCurrencyBalance(row) {
|
|
484
604
|
return {
|
|
485
605
|
currencyId: row["currency_id"] ?? "",
|
|
@@ -926,6 +1046,227 @@ var InvoServer = class {
|
|
|
926
1046
|
raw
|
|
927
1047
|
};
|
|
928
1048
|
}
|
|
1049
|
+
/**
|
|
1050
|
+
* Complete a TRANSFER's SMS-PIN step (un-enrolled fallback). NOT idempotent —
|
|
1051
|
+
* each attempt is counted server-side, so this is never auto-retried. A bad PIN
|
|
1052
|
+
* throws a 400 InvoError carrying `attempts_remaining` on `err.body`; a blocked
|
|
1053
|
+
* recipient throws 429 (`sms_verification_blocked`).
|
|
1054
|
+
*/
|
|
1055
|
+
async verifySmsTransfer(transactionId, smsPin, opts) {
|
|
1056
|
+
if (typeof transactionId !== "string" || !transactionId.trim()) {
|
|
1057
|
+
throw invalidInput("transactionId", transactionId, "is required");
|
|
1058
|
+
}
|
|
1059
|
+
if (typeof smsPin !== "string" || !smsPin.trim()) {
|
|
1060
|
+
throw invalidInput("smsPin", smsPin, "is required");
|
|
1061
|
+
}
|
|
1062
|
+
const raw = await this.http.post(
|
|
1063
|
+
"/api/transfers/verify-sms",
|
|
1064
|
+
{ transaction_id: transactionId, sms_pin: smsPin },
|
|
1065
|
+
this.auth,
|
|
1066
|
+
{ signal: opts?.signal }
|
|
1067
|
+
// NOT idempotent — attempts are counted; never auto-retried
|
|
1068
|
+
);
|
|
1069
|
+
return toSmsVerifyResult(raw);
|
|
1070
|
+
}
|
|
1071
|
+
/** Complete a SEND's SMS-PIN step (un-enrolled fallback). See verifySmsTransfer. */
|
|
1072
|
+
async verifySmsSend(transactionId, smsPin, opts) {
|
|
1073
|
+
if (typeof transactionId !== "string" || !transactionId.trim()) {
|
|
1074
|
+
throw invalidInput("transactionId", transactionId, "is required");
|
|
1075
|
+
}
|
|
1076
|
+
if (typeof smsPin !== "string" || !smsPin.trim()) {
|
|
1077
|
+
throw invalidInput("smsPin", smsPin, "is required");
|
|
1078
|
+
}
|
|
1079
|
+
const raw = await this.http.post(
|
|
1080
|
+
"/api/currency-sends/verify-sms",
|
|
1081
|
+
{ transaction_id: transactionId, sms_pin: smsPin },
|
|
1082
|
+
this.auth,
|
|
1083
|
+
{ signal: opts?.signal }
|
|
1084
|
+
// NOT idempotent — attempts are counted; never auto-retried
|
|
1085
|
+
);
|
|
1086
|
+
return toSmsVerifyResult(raw);
|
|
1087
|
+
}
|
|
1088
|
+
/**
|
|
1089
|
+
* Claim an inbound TRANSFER by its claim code, crediting one of this game's currencies.
|
|
1090
|
+
* NOT idempotent. A 200 may come back as `needsAccountSelection` (the recipient phone
|
|
1091
|
+
* maps to >1 of your players) — inspect `result.candidates` and re-submit with
|
|
1092
|
+
* `targetPlayerId`. Errors surface via InvoError (404 unknown code, 403 phone mismatch,
|
|
1093
|
+
* 400 not-claimable/expired/wrong-value, 409 `err.isPhoneShareApprovalRequired`, …).
|
|
1094
|
+
*/
|
|
1095
|
+
async claimTransfer(input, opts) {
|
|
1096
|
+
const body = {
|
|
1097
|
+
claim_code: input.claimCode,
|
|
1098
|
+
target_player_name: input.targetPlayerName,
|
|
1099
|
+
target_player_email: input.targetPlayerEmail,
|
|
1100
|
+
target_player_phone: input.targetPlayerPhone,
|
|
1101
|
+
target_currency_id: input.targetCurrencyId
|
|
1102
|
+
};
|
|
1103
|
+
if (input.targetPlayerId != null) body["target_player_id"] = input.targetPlayerId;
|
|
1104
|
+
const raw = await this.http.post(
|
|
1105
|
+
"/api/transfers/claim-transfer",
|
|
1106
|
+
body,
|
|
1107
|
+
this.auth,
|
|
1108
|
+
{ signal: opts?.signal }
|
|
1109
|
+
// NOT idempotent — never auto-retried
|
|
1110
|
+
);
|
|
1111
|
+
return toClaimResult(raw);
|
|
1112
|
+
}
|
|
1113
|
+
/**
|
|
1114
|
+
* Claim an inbound SEND by its claim code. NOT idempotent. May return
|
|
1115
|
+
* `needsAccountSelection` (multi-account phone) — re-submit with `receiverPlayerId`.
|
|
1116
|
+
* See claimTransfer for the error surface.
|
|
1117
|
+
*/
|
|
1118
|
+
async claimCurrency(input, opts) {
|
|
1119
|
+
const body = {
|
|
1120
|
+
claim_code: input.claimCode,
|
|
1121
|
+
receiver_player_name: input.receiverPlayerName,
|
|
1122
|
+
receiver_player_email: input.receiverPlayerEmail,
|
|
1123
|
+
receiver_player_phone: input.receiverPlayerPhone
|
|
1124
|
+
};
|
|
1125
|
+
if (input.receiverPlayerId != null) body["receiver_player_id"] = input.receiverPlayerId;
|
|
1126
|
+
const raw = await this.http.post(
|
|
1127
|
+
"/api/currency-sends/claim-currency",
|
|
1128
|
+
body,
|
|
1129
|
+
this.auth,
|
|
1130
|
+
{ signal: opts?.signal }
|
|
1131
|
+
// NOT idempotent — never auto-retried
|
|
1132
|
+
);
|
|
1133
|
+
return toClaimResult(raw);
|
|
1134
|
+
}
|
|
1135
|
+
/** Read a TRANSFER's status (verification_state + amounts + destination). */
|
|
1136
|
+
async getTransferStatus(transactionId, opts) {
|
|
1137
|
+
if (typeof transactionId !== "string" || !transactionId.trim()) {
|
|
1138
|
+
throw invalidInput("transactionId", transactionId, "is required");
|
|
1139
|
+
}
|
|
1140
|
+
const raw = await this.http.get(
|
|
1141
|
+
`/api/transfers/${encodeURIComponent(transactionId)}/status`,
|
|
1142
|
+
this.auth,
|
|
1143
|
+
{ signal: opts?.signal }
|
|
1144
|
+
);
|
|
1145
|
+
return toTransactionStatus(raw);
|
|
1146
|
+
}
|
|
1147
|
+
/** Read a SEND's status (adds fees, game names, claim_info, … on `raw`). */
|
|
1148
|
+
async getSendStatus(transactionId, opts) {
|
|
1149
|
+
if (typeof transactionId !== "string" || !transactionId.trim()) {
|
|
1150
|
+
throw invalidInput("transactionId", transactionId, "is required");
|
|
1151
|
+
}
|
|
1152
|
+
const raw = await this.http.get(
|
|
1153
|
+
`/api/currency-sends/${encodeURIComponent(transactionId)}/status`,
|
|
1154
|
+
this.auth,
|
|
1155
|
+
{ signal: opts?.signal }
|
|
1156
|
+
);
|
|
1157
|
+
return toTransactionStatus(raw);
|
|
1158
|
+
}
|
|
1159
|
+
/**
|
|
1160
|
+
* Poll a transaction's guardian approval status (minor/guardian flow). The retry
|
|
1161
|
+
* layer already retries the 503 (`{status:"unavailable"}`) for this idempotent GET;
|
|
1162
|
+
* a missing approval throws a 404 InvoError (`{status:"not_found"}`).
|
|
1163
|
+
*/
|
|
1164
|
+
async getGuardianApprovalStatus(transactionId, opts) {
|
|
1165
|
+
if (typeof transactionId !== "string" || !transactionId.trim()) {
|
|
1166
|
+
throw invalidInput("transactionId", transactionId, "is required");
|
|
1167
|
+
}
|
|
1168
|
+
const raw = await this.http.get(
|
|
1169
|
+
`/api/transactions/${encodeURIComponent(transactionId)}/approval-status`,
|
|
1170
|
+
this.auth,
|
|
1171
|
+
{ signal: opts?.signal }
|
|
1172
|
+
);
|
|
1173
|
+
return toGuardianApprovalStatus(raw);
|
|
1174
|
+
}
|
|
1175
|
+
/**
|
|
1176
|
+
* List the games/tenants a player can send/transfer to FROM `sourceGameId`, with
|
|
1177
|
+
* display metadata inline (name, icon, currency, min/max limits) — one call, no
|
|
1178
|
+
* per-game lookup. SERVER variant (game-secret) of the browser `InvoClient.getDestinations`;
|
|
1179
|
+
* the source game is passed explicitly rather than inferred from a player token. Rows
|
|
1180
|
+
* share the browser shape. Idempotent (a POST read — safe to retry).
|
|
1181
|
+
*/
|
|
1182
|
+
async getDestinations(query, opts) {
|
|
1183
|
+
if (query.sourceGameId == null || String(query.sourceGameId).trim() === "") {
|
|
1184
|
+
throw invalidInput("sourceGameId", query.sourceGameId, "is required");
|
|
1185
|
+
}
|
|
1186
|
+
const direction = query.direction ?? "transfer";
|
|
1187
|
+
const path = direction === "send" ? "/api/currency-sends/available-destinations" : "/api/transfers/available-destinations";
|
|
1188
|
+
const raw = await this.http.post(
|
|
1189
|
+
path,
|
|
1190
|
+
{ source_game_id: query.sourceGameId },
|
|
1191
|
+
this.auth,
|
|
1192
|
+
{ idempotent: true, signal: opts?.signal }
|
|
1193
|
+
// a POST read — no side effect, safe to retry
|
|
1194
|
+
);
|
|
1195
|
+
return toDestinationsResult(raw, direction);
|
|
1196
|
+
}
|
|
1197
|
+
/**
|
|
1198
|
+
* Phone-share OTP handshake — resolves a 409 `PHONE_SHARE_APPROVAL_REQUIRED`.
|
|
1199
|
+
*
|
|
1200
|
+
* These three endpoints are UNAUTHENTICATED (phone-owner-driven: no game secret,
|
|
1201
|
+
* no player token) — a partner backend relays the handshake. The triggering 409
|
|
1202
|
+
* carries `approval_id, expires_at, code_sent, existing_account_hints[], next_endpoint`.
|
|
1203
|
+
*
|
|
1204
|
+
* `phoneShareInitiate` is the fallback OTP send (use when the 409 didn't already
|
|
1205
|
+
* dispatch a code). NOT idempotent — never auto-retried. OTP TTL ~10 min.
|
|
1206
|
+
*/
|
|
1207
|
+
async phoneShareInitiate(input, opts) {
|
|
1208
|
+
if (typeof input.phone !== "string" || !input.phone.trim()) {
|
|
1209
|
+
throw invalidInput("phone", input.phone, "is required");
|
|
1210
|
+
}
|
|
1211
|
+
if (typeof input.email !== "string" || !input.email.trim()) {
|
|
1212
|
+
throw invalidInput("email", input.email, "is required");
|
|
1213
|
+
}
|
|
1214
|
+
const raw = await this.http.post(
|
|
1215
|
+
"/api/wallet/phone-share/initiate",
|
|
1216
|
+
{ phone: input.phone, email: input.email },
|
|
1217
|
+
{ kind: "none" },
|
|
1218
|
+
// UNAUTHENTICATED — phone-owner-driven; send no auth header
|
|
1219
|
+
{ signal: opts?.signal }
|
|
1220
|
+
// NOT idempotent — sends an OTP; never auto-retried
|
|
1221
|
+
);
|
|
1222
|
+
return toPhoneShareInitiateResult(raw);
|
|
1223
|
+
}
|
|
1224
|
+
/**
|
|
1225
|
+
* Approve a phone-share with the OTP the phone owner received. On success the grant
|
|
1226
|
+
* is stored server-side, keyed by (phone, requesting_email) and auto-consumed — the
|
|
1227
|
+
* caller simply RE-ISSUES the identical original request. UNAUTHENTICATED. NOT
|
|
1228
|
+
* idempotent (attempts are counted) — never auto-retried.
|
|
1229
|
+
*/
|
|
1230
|
+
async phoneShareApprove(input, opts) {
|
|
1231
|
+
if (typeof input.approvalId !== "string" || !input.approvalId.trim()) {
|
|
1232
|
+
throw invalidInput("approvalId", input.approvalId, "is required");
|
|
1233
|
+
}
|
|
1234
|
+
if (typeof input.otp !== "string" || !input.otp.trim()) {
|
|
1235
|
+
throw invalidInput("otp", input.otp, "is required");
|
|
1236
|
+
}
|
|
1237
|
+
const raw = await this.http.post(
|
|
1238
|
+
"/api/wallet/phone-share/approve",
|
|
1239
|
+
{ approval_id: input.approvalId, otp: input.otp },
|
|
1240
|
+
{ kind: "none" },
|
|
1241
|
+
// UNAUTHENTICATED — phone-owner-driven; send no auth header
|
|
1242
|
+
{ signal: opts?.signal }
|
|
1243
|
+
// NOT idempotent — OTP attempts are counted; never auto-retried
|
|
1244
|
+
);
|
|
1245
|
+
return toPhoneShareApproveResult(raw);
|
|
1246
|
+
}
|
|
1247
|
+
/**
|
|
1248
|
+
* Poll whether a phone-share (phone, requesting_email) pair is approved yet.
|
|
1249
|
+
* UNAUTHENTICATED, idempotent GET. `approved:true` means the original request can
|
|
1250
|
+
* be re-issued.
|
|
1251
|
+
*/
|
|
1252
|
+
async phoneShareStatus(input, opts) {
|
|
1253
|
+
if (typeof input.phone !== "string" || !input.phone.trim()) {
|
|
1254
|
+
throw invalidInput("phone", input.phone, "is required");
|
|
1255
|
+
}
|
|
1256
|
+
if (typeof input.email !== "string" || !input.email.trim()) {
|
|
1257
|
+
throw invalidInput("email", input.email, "is required");
|
|
1258
|
+
}
|
|
1259
|
+
const q = new URLSearchParams();
|
|
1260
|
+
q.set("phone", input.phone);
|
|
1261
|
+
q.set("email", input.email);
|
|
1262
|
+
const raw = await this.http.get(
|
|
1263
|
+
`/api/wallet/phone-share/status?${q.toString()}`,
|
|
1264
|
+
{ kind: "none" },
|
|
1265
|
+
// UNAUTHENTICATED — phone-owner-driven; send no auth header
|
|
1266
|
+
{ signal: opts?.signal }
|
|
1267
|
+
);
|
|
1268
|
+
return { approved: raw["approved"] === true, raw };
|
|
1269
|
+
}
|
|
929
1270
|
toInitiateResult(raw) {
|
|
930
1271
|
const vm = raw["verification_method"];
|
|
931
1272
|
const guardian = raw["guardian_approval"];
|
package/dist/server.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as InvoError, S as ServerConfig, a as CallOptions, l as PlayerToken, m as InitiateSendInput, n as InitiateResult, o as InitiateTransferInput, p as CreateCheckoutInput, q as CreateCheckoutResult, r as PurchaseInput, s as PurchaseResult, t as ConfirmPaymentResult, O as OrderDetailsResult, u as PurchaseItemInput, v as PurchaseItemResult, w as ItemHistoryQuery, x as ItemHistoryResult, y as ItemOrderQuery, z as PlayerBalanceQuery, F as PlayerBalanceResult, G as InboundPendingQuery, H as InboundPendingResult, J as LinkedIdentitiesQuery, K as LinkedIdentitiesResult } from './types-
|
|
2
|
-
export {
|
|
1
|
+
import { I as InvoError, S as ServerConfig, a as CallOptions, l as PlayerToken, m as InitiateSendInput, n as InitiateResult, o as InitiateTransferInput, p as CreateCheckoutInput, q as CreateCheckoutResult, r as PurchaseInput, s as PurchaseResult, t as ConfirmPaymentResult, O as OrderDetailsResult, u as PurchaseItemInput, v as PurchaseItemResult, w as ItemHistoryQuery, x as ItemHistoryResult, y as ItemOrderQuery, z as PlayerBalanceQuery, F as PlayerBalanceResult, G as InboundPendingQuery, H as InboundPendingResult, J as LinkedIdentitiesQuery, K as LinkedIdentitiesResult, M as SmsVerifyResult, N as ClaimTransferInput, Q as ClaimResult, T as ClaimCurrencyInput, U as TransactionStatusResult, W as GuardianApprovalStatusResult, X as ServerDestinationsQuery, c as DestinationsResult, Y as PhoneShareContact, Z as PhoneShareInitiateResult, _ as PhoneShareApproveInput, $ as PhoneShareApproveResult, a0 as PhoneShareStatusResult } from './types-DTAmriOB.cjs';
|
|
2
|
+
export { a1 as CurrencyBalance, f as DestinationGame, a2 as InboundPendingItem, g as InvoErrorInfo, h as InvoHooks, i as InvoRequestInfo, j as InvoResponseInfo, a3 as LinkedIdentityEmail, R as Rail, V as VerificationMethod } from './types-DTAmriOB.cjs';
|
|
3
3
|
|
|
4
4
|
interface VerifyWebhookOptions {
|
|
5
5
|
/** Max age of the signed timestamp, in seconds. Default 300 (5 min). */
|
|
@@ -225,7 +225,72 @@ declare class InvoServer {
|
|
|
225
225
|
* ⚠️ Returns first-party PII (emails/phones) — never expose this to the browser.
|
|
226
226
|
*/
|
|
227
227
|
getLinkedIdentities(query: LinkedIdentitiesQuery, opts?: CallOptions): Promise<LinkedIdentitiesResult>;
|
|
228
|
+
/**
|
|
229
|
+
* Complete a TRANSFER's SMS-PIN step (un-enrolled fallback). NOT idempotent —
|
|
230
|
+
* each attempt is counted server-side, so this is never auto-retried. A bad PIN
|
|
231
|
+
* throws a 400 InvoError carrying `attempts_remaining` on `err.body`; a blocked
|
|
232
|
+
* recipient throws 429 (`sms_verification_blocked`).
|
|
233
|
+
*/
|
|
234
|
+
verifySmsTransfer(transactionId: string, smsPin: string, opts?: CallOptions): Promise<SmsVerifyResult>;
|
|
235
|
+
/** Complete a SEND's SMS-PIN step (un-enrolled fallback). See verifySmsTransfer. */
|
|
236
|
+
verifySmsSend(transactionId: string, smsPin: string, opts?: CallOptions): Promise<SmsVerifyResult>;
|
|
237
|
+
/**
|
|
238
|
+
* Claim an inbound TRANSFER by its claim code, crediting one of this game's currencies.
|
|
239
|
+
* NOT idempotent. A 200 may come back as `needsAccountSelection` (the recipient phone
|
|
240
|
+
* maps to >1 of your players) — inspect `result.candidates` and re-submit with
|
|
241
|
+
* `targetPlayerId`. Errors surface via InvoError (404 unknown code, 403 phone mismatch,
|
|
242
|
+
* 400 not-claimable/expired/wrong-value, 409 `err.isPhoneShareApprovalRequired`, …).
|
|
243
|
+
*/
|
|
244
|
+
claimTransfer(input: ClaimTransferInput, opts?: CallOptions): Promise<ClaimResult>;
|
|
245
|
+
/**
|
|
246
|
+
* Claim an inbound SEND by its claim code. NOT idempotent. May return
|
|
247
|
+
* `needsAccountSelection` (multi-account phone) — re-submit with `receiverPlayerId`.
|
|
248
|
+
* See claimTransfer for the error surface.
|
|
249
|
+
*/
|
|
250
|
+
claimCurrency(input: ClaimCurrencyInput, opts?: CallOptions): Promise<ClaimResult>;
|
|
251
|
+
/** Read a TRANSFER's status (verification_state + amounts + destination). */
|
|
252
|
+
getTransferStatus(transactionId: string, opts?: CallOptions): Promise<TransactionStatusResult>;
|
|
253
|
+
/** Read a SEND's status (adds fees, game names, claim_info, … on `raw`). */
|
|
254
|
+
getSendStatus(transactionId: string, opts?: CallOptions): Promise<TransactionStatusResult>;
|
|
255
|
+
/**
|
|
256
|
+
* Poll a transaction's guardian approval status (minor/guardian flow). The retry
|
|
257
|
+
* layer already retries the 503 (`{status:"unavailable"}`) for this idempotent GET;
|
|
258
|
+
* a missing approval throws a 404 InvoError (`{status:"not_found"}`).
|
|
259
|
+
*/
|
|
260
|
+
getGuardianApprovalStatus(transactionId: string, opts?: CallOptions): Promise<GuardianApprovalStatusResult>;
|
|
261
|
+
/**
|
|
262
|
+
* List the games/tenants a player can send/transfer to FROM `sourceGameId`, with
|
|
263
|
+
* display metadata inline (name, icon, currency, min/max limits) — one call, no
|
|
264
|
+
* per-game lookup. SERVER variant (game-secret) of the browser `InvoClient.getDestinations`;
|
|
265
|
+
* the source game is passed explicitly rather than inferred from a player token. Rows
|
|
266
|
+
* share the browser shape. Idempotent (a POST read — safe to retry).
|
|
267
|
+
*/
|
|
268
|
+
getDestinations(query: ServerDestinationsQuery, opts?: CallOptions): Promise<DestinationsResult>;
|
|
269
|
+
/**
|
|
270
|
+
* Phone-share OTP handshake — resolves a 409 `PHONE_SHARE_APPROVAL_REQUIRED`.
|
|
271
|
+
*
|
|
272
|
+
* These three endpoints are UNAUTHENTICATED (phone-owner-driven: no game secret,
|
|
273
|
+
* no player token) — a partner backend relays the handshake. The triggering 409
|
|
274
|
+
* carries `approval_id, expires_at, code_sent, existing_account_hints[], next_endpoint`.
|
|
275
|
+
*
|
|
276
|
+
* `phoneShareInitiate` is the fallback OTP send (use when the 409 didn't already
|
|
277
|
+
* dispatch a code). NOT idempotent — never auto-retried. OTP TTL ~10 min.
|
|
278
|
+
*/
|
|
279
|
+
phoneShareInitiate(input: PhoneShareContact, opts?: CallOptions): Promise<PhoneShareInitiateResult>;
|
|
280
|
+
/**
|
|
281
|
+
* Approve a phone-share with the OTP the phone owner received. On success the grant
|
|
282
|
+
* is stored server-side, keyed by (phone, requesting_email) and auto-consumed — the
|
|
283
|
+
* caller simply RE-ISSUES the identical original request. UNAUTHENTICATED. NOT
|
|
284
|
+
* idempotent (attempts are counted) — never auto-retried.
|
|
285
|
+
*/
|
|
286
|
+
phoneShareApprove(input: PhoneShareApproveInput, opts?: CallOptions): Promise<PhoneShareApproveResult>;
|
|
287
|
+
/**
|
|
288
|
+
* Poll whether a phone-share (phone, requesting_email) pair is approved yet.
|
|
289
|
+
* UNAUTHENTICATED, idempotent GET. `approved:true` means the original request can
|
|
290
|
+
* be re-issued.
|
|
291
|
+
*/
|
|
292
|
+
phoneShareStatus(input: PhoneShareContact, opts?: CallOptions): Promise<PhoneShareStatusResult>;
|
|
228
293
|
private toInitiateResult;
|
|
229
294
|
}
|
|
230
295
|
|
|
231
|
-
export { CallOptions, ConfirmPaymentResult, CreateCheckoutInput, CreateCheckoutResult, InboundPendingQuery, InboundPendingResult, InitiateResult, InitiateSendInput, InitiateTransferInput, InvoError, InvoServer, type InvoWebhookEvent, ItemHistoryQuery, ItemHistoryResult, ItemOrderQuery, type ItemPurchasedData, LinkedIdentitiesQuery, LinkedIdentitiesResult, OrderDetailsResult, PlayerBalanceQuery, PlayerBalanceResult, PlayerToken, type PurchaseCompletedData, type PurchaseEventData, PurchaseInput, PurchaseItemInput, PurchaseItemResult, PurchaseResult, ServerConfig, type TransferEventData, type VerifyWebhookOptions, type WebhookHandlerOptions, createWebhookHandler, verifyWebhook, verifyWebhookAsync };
|
|
296
|
+
export { CallOptions, ClaimCurrencyInput, ClaimResult, ClaimTransferInput, ConfirmPaymentResult, CreateCheckoutInput, CreateCheckoutResult, DestinationsResult, GuardianApprovalStatusResult, InboundPendingQuery, InboundPendingResult, InitiateResult, InitiateSendInput, InitiateTransferInput, InvoError, InvoServer, type InvoWebhookEvent, ItemHistoryQuery, ItemHistoryResult, ItemOrderQuery, type ItemPurchasedData, LinkedIdentitiesQuery, LinkedIdentitiesResult, OrderDetailsResult, PhoneShareApproveInput, PhoneShareApproveResult, PhoneShareContact, PhoneShareInitiateResult, PhoneShareStatusResult, PlayerBalanceQuery, PlayerBalanceResult, PlayerToken, type PurchaseCompletedData, type PurchaseEventData, PurchaseInput, PurchaseItemInput, PurchaseItemResult, PurchaseResult, ServerConfig, ServerDestinationsQuery, SmsVerifyResult, TransactionStatusResult, type TransferEventData, type VerifyWebhookOptions, type WebhookHandlerOptions, createWebhookHandler, verifyWebhook, verifyWebhookAsync };
|
package/dist/server.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as InvoError, S as ServerConfig, a as CallOptions, l as PlayerToken, m as InitiateSendInput, n as InitiateResult, o as InitiateTransferInput, p as CreateCheckoutInput, q as CreateCheckoutResult, r as PurchaseInput, s as PurchaseResult, t as ConfirmPaymentResult, O as OrderDetailsResult, u as PurchaseItemInput, v as PurchaseItemResult, w as ItemHistoryQuery, x as ItemHistoryResult, y as ItemOrderQuery, z as PlayerBalanceQuery, F as PlayerBalanceResult, G as InboundPendingQuery, H as InboundPendingResult, J as LinkedIdentitiesQuery, K as LinkedIdentitiesResult } from './types-
|
|
2
|
-
export {
|
|
1
|
+
import { I as InvoError, S as ServerConfig, a as CallOptions, l as PlayerToken, m as InitiateSendInput, n as InitiateResult, o as InitiateTransferInput, p as CreateCheckoutInput, q as CreateCheckoutResult, r as PurchaseInput, s as PurchaseResult, t as ConfirmPaymentResult, O as OrderDetailsResult, u as PurchaseItemInput, v as PurchaseItemResult, w as ItemHistoryQuery, x as ItemHistoryResult, y as ItemOrderQuery, z as PlayerBalanceQuery, F as PlayerBalanceResult, G as InboundPendingQuery, H as InboundPendingResult, J as LinkedIdentitiesQuery, K as LinkedIdentitiesResult, M as SmsVerifyResult, N as ClaimTransferInput, Q as ClaimResult, T as ClaimCurrencyInput, U as TransactionStatusResult, W as GuardianApprovalStatusResult, X as ServerDestinationsQuery, c as DestinationsResult, Y as PhoneShareContact, Z as PhoneShareInitiateResult, _ as PhoneShareApproveInput, $ as PhoneShareApproveResult, a0 as PhoneShareStatusResult } from './types-DTAmriOB.js';
|
|
2
|
+
export { a1 as CurrencyBalance, f as DestinationGame, a2 as InboundPendingItem, g as InvoErrorInfo, h as InvoHooks, i as InvoRequestInfo, j as InvoResponseInfo, a3 as LinkedIdentityEmail, R as Rail, V as VerificationMethod } from './types-DTAmriOB.js';
|
|
3
3
|
|
|
4
4
|
interface VerifyWebhookOptions {
|
|
5
5
|
/** Max age of the signed timestamp, in seconds. Default 300 (5 min). */
|
|
@@ -225,7 +225,72 @@ declare class InvoServer {
|
|
|
225
225
|
* ⚠️ Returns first-party PII (emails/phones) — never expose this to the browser.
|
|
226
226
|
*/
|
|
227
227
|
getLinkedIdentities(query: LinkedIdentitiesQuery, opts?: CallOptions): Promise<LinkedIdentitiesResult>;
|
|
228
|
+
/**
|
|
229
|
+
* Complete a TRANSFER's SMS-PIN step (un-enrolled fallback). NOT idempotent —
|
|
230
|
+
* each attempt is counted server-side, so this is never auto-retried. A bad PIN
|
|
231
|
+
* throws a 400 InvoError carrying `attempts_remaining` on `err.body`; a blocked
|
|
232
|
+
* recipient throws 429 (`sms_verification_blocked`).
|
|
233
|
+
*/
|
|
234
|
+
verifySmsTransfer(transactionId: string, smsPin: string, opts?: CallOptions): Promise<SmsVerifyResult>;
|
|
235
|
+
/** Complete a SEND's SMS-PIN step (un-enrolled fallback). See verifySmsTransfer. */
|
|
236
|
+
verifySmsSend(transactionId: string, smsPin: string, opts?: CallOptions): Promise<SmsVerifyResult>;
|
|
237
|
+
/**
|
|
238
|
+
* Claim an inbound TRANSFER by its claim code, crediting one of this game's currencies.
|
|
239
|
+
* NOT idempotent. A 200 may come back as `needsAccountSelection` (the recipient phone
|
|
240
|
+
* maps to >1 of your players) — inspect `result.candidates` and re-submit with
|
|
241
|
+
* `targetPlayerId`. Errors surface via InvoError (404 unknown code, 403 phone mismatch,
|
|
242
|
+
* 400 not-claimable/expired/wrong-value, 409 `err.isPhoneShareApprovalRequired`, …).
|
|
243
|
+
*/
|
|
244
|
+
claimTransfer(input: ClaimTransferInput, opts?: CallOptions): Promise<ClaimResult>;
|
|
245
|
+
/**
|
|
246
|
+
* Claim an inbound SEND by its claim code. NOT idempotent. May return
|
|
247
|
+
* `needsAccountSelection` (multi-account phone) — re-submit with `receiverPlayerId`.
|
|
248
|
+
* See claimTransfer for the error surface.
|
|
249
|
+
*/
|
|
250
|
+
claimCurrency(input: ClaimCurrencyInput, opts?: CallOptions): Promise<ClaimResult>;
|
|
251
|
+
/** Read a TRANSFER's status (verification_state + amounts + destination). */
|
|
252
|
+
getTransferStatus(transactionId: string, opts?: CallOptions): Promise<TransactionStatusResult>;
|
|
253
|
+
/** Read a SEND's status (adds fees, game names, claim_info, … on `raw`). */
|
|
254
|
+
getSendStatus(transactionId: string, opts?: CallOptions): Promise<TransactionStatusResult>;
|
|
255
|
+
/**
|
|
256
|
+
* Poll a transaction's guardian approval status (minor/guardian flow). The retry
|
|
257
|
+
* layer already retries the 503 (`{status:"unavailable"}`) for this idempotent GET;
|
|
258
|
+
* a missing approval throws a 404 InvoError (`{status:"not_found"}`).
|
|
259
|
+
*/
|
|
260
|
+
getGuardianApprovalStatus(transactionId: string, opts?: CallOptions): Promise<GuardianApprovalStatusResult>;
|
|
261
|
+
/**
|
|
262
|
+
* List the games/tenants a player can send/transfer to FROM `sourceGameId`, with
|
|
263
|
+
* display metadata inline (name, icon, currency, min/max limits) — one call, no
|
|
264
|
+
* per-game lookup. SERVER variant (game-secret) of the browser `InvoClient.getDestinations`;
|
|
265
|
+
* the source game is passed explicitly rather than inferred from a player token. Rows
|
|
266
|
+
* share the browser shape. Idempotent (a POST read — safe to retry).
|
|
267
|
+
*/
|
|
268
|
+
getDestinations(query: ServerDestinationsQuery, opts?: CallOptions): Promise<DestinationsResult>;
|
|
269
|
+
/**
|
|
270
|
+
* Phone-share OTP handshake — resolves a 409 `PHONE_SHARE_APPROVAL_REQUIRED`.
|
|
271
|
+
*
|
|
272
|
+
* These three endpoints are UNAUTHENTICATED (phone-owner-driven: no game secret,
|
|
273
|
+
* no player token) — a partner backend relays the handshake. The triggering 409
|
|
274
|
+
* carries `approval_id, expires_at, code_sent, existing_account_hints[], next_endpoint`.
|
|
275
|
+
*
|
|
276
|
+
* `phoneShareInitiate` is the fallback OTP send (use when the 409 didn't already
|
|
277
|
+
* dispatch a code). NOT idempotent — never auto-retried. OTP TTL ~10 min.
|
|
278
|
+
*/
|
|
279
|
+
phoneShareInitiate(input: PhoneShareContact, opts?: CallOptions): Promise<PhoneShareInitiateResult>;
|
|
280
|
+
/**
|
|
281
|
+
* Approve a phone-share with the OTP the phone owner received. On success the grant
|
|
282
|
+
* is stored server-side, keyed by (phone, requesting_email) and auto-consumed — the
|
|
283
|
+
* caller simply RE-ISSUES the identical original request. UNAUTHENTICATED. NOT
|
|
284
|
+
* idempotent (attempts are counted) — never auto-retried.
|
|
285
|
+
*/
|
|
286
|
+
phoneShareApprove(input: PhoneShareApproveInput, opts?: CallOptions): Promise<PhoneShareApproveResult>;
|
|
287
|
+
/**
|
|
288
|
+
* Poll whether a phone-share (phone, requesting_email) pair is approved yet.
|
|
289
|
+
* UNAUTHENTICATED, idempotent GET. `approved:true` means the original request can
|
|
290
|
+
* be re-issued.
|
|
291
|
+
*/
|
|
292
|
+
phoneShareStatus(input: PhoneShareContact, opts?: CallOptions): Promise<PhoneShareStatusResult>;
|
|
228
293
|
private toInitiateResult;
|
|
229
294
|
}
|
|
230
295
|
|
|
231
|
-
export { CallOptions, ConfirmPaymentResult, CreateCheckoutInput, CreateCheckoutResult, InboundPendingQuery, InboundPendingResult, InitiateResult, InitiateSendInput, InitiateTransferInput, InvoError, InvoServer, type InvoWebhookEvent, ItemHistoryQuery, ItemHistoryResult, ItemOrderQuery, type ItemPurchasedData, LinkedIdentitiesQuery, LinkedIdentitiesResult, OrderDetailsResult, PlayerBalanceQuery, PlayerBalanceResult, PlayerToken, type PurchaseCompletedData, type PurchaseEventData, PurchaseInput, PurchaseItemInput, PurchaseItemResult, PurchaseResult, ServerConfig, type TransferEventData, type VerifyWebhookOptions, type WebhookHandlerOptions, createWebhookHandler, verifyWebhook, verifyWebhookAsync };
|
|
296
|
+
export { CallOptions, ClaimCurrencyInput, ClaimResult, ClaimTransferInput, ConfirmPaymentResult, CreateCheckoutInput, CreateCheckoutResult, DestinationsResult, GuardianApprovalStatusResult, InboundPendingQuery, InboundPendingResult, InitiateResult, InitiateSendInput, InitiateTransferInput, InvoError, InvoServer, type InvoWebhookEvent, ItemHistoryQuery, ItemHistoryResult, ItemOrderQuery, type ItemPurchasedData, LinkedIdentitiesQuery, LinkedIdentitiesResult, OrderDetailsResult, PhoneShareApproveInput, PhoneShareApproveResult, PhoneShareContact, PhoneShareInitiateResult, PhoneShareStatusResult, PlayerBalanceQuery, PlayerBalanceResult, PlayerToken, type PurchaseCompletedData, type PurchaseEventData, PurchaseInput, PurchaseItemInput, PurchaseItemResult, PurchaseResult, ServerConfig, ServerDestinationsQuery, SmsVerifyResult, TransactionStatusResult, type TransferEventData, type VerifyWebhookOptions, type WebhookHandlerOptions, createWebhookHandler, verifyWebhook, verifyWebhookAsync };
|