@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.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { InvoError, assertSecureBaseUrl, Http } from './chunk-
|
|
2
|
-
export { InvoError } from './chunk-
|
|
1
|
+
import { InvoError, assertSecureBaseUrl, Http, toDestinationsResult } from './chunk-P65XQ6VF.js';
|
|
2
|
+
export { InvoError } from './chunk-P65XQ6VF.js';
|
|
3
3
|
import { createHmac } from 'crypto';
|
|
4
4
|
|
|
5
5
|
var DEFAULT_TOLERANCE_SEC = 300;
|
|
@@ -161,7 +161,7 @@ async function hmacHexSubtle(secret, message) {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
// src/server.ts
|
|
164
|
-
var DEFAULT_UA = "invonetwork-web-sdk/1.
|
|
164
|
+
var DEFAULT_UA = "invonetwork-web-sdk/1.2.0 (+https://invo.network)";
|
|
165
165
|
var MAX_USD_AMOUNT = 999.99;
|
|
166
166
|
var MAX_ITEM_PRICE = 999999.99;
|
|
167
167
|
function invalidInput(label, value, why) {
|
|
@@ -223,6 +223,75 @@ function toInboundPendingItem(row) {
|
|
|
223
223
|
raw: row
|
|
224
224
|
};
|
|
225
225
|
}
|
|
226
|
+
function toSmsVerifyResult(raw) {
|
|
227
|
+
return {
|
|
228
|
+
status: String(raw["status"] ?? ""),
|
|
229
|
+
transactionId: String(raw["transaction_id"] ?? ""),
|
|
230
|
+
claimCode: raw["claim_code"],
|
|
231
|
+
newBalance: raw["new_balance"] ?? null,
|
|
232
|
+
orderId: raw["order_id"],
|
|
233
|
+
raw
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
function toClaimResult(raw) {
|
|
237
|
+
const status = String(raw["status"] ?? "");
|
|
238
|
+
return {
|
|
239
|
+
status,
|
|
240
|
+
transactionId: raw["transaction_id"],
|
|
241
|
+
newBalance: raw["new_balance"] ?? null,
|
|
242
|
+
currencyName: raw["currency_name"],
|
|
243
|
+
orderId: raw["order_id"],
|
|
244
|
+
needsAccountSelection: status === "needs_account_selection",
|
|
245
|
+
candidates: Array.isArray(raw["candidates"]) ? raw["candidates"] : void 0,
|
|
246
|
+
raw
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function toTransactionStatus(raw) {
|
|
250
|
+
return {
|
|
251
|
+
transactionId: String(raw["transaction_id"] ?? ""),
|
|
252
|
+
transactionType: String(raw["transaction_type"] ?? ""),
|
|
253
|
+
transactionStatus: String(raw["transaction_status"] ?? ""),
|
|
254
|
+
verificationState: String(raw["verification_state"] ?? ""),
|
|
255
|
+
amount: raw["amount"] ?? null,
|
|
256
|
+
netAmount: raw["net_amount"] ?? null,
|
|
257
|
+
currencyId: raw["currency_id"] ?? "",
|
|
258
|
+
orderId: raw["order_id"],
|
|
259
|
+
toPhone: raw["to_phone"],
|
|
260
|
+
toIdentityId: raw["to_identity_id"] ?? null,
|
|
261
|
+
raw
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function toGuardianApprovalStatus(raw) {
|
|
265
|
+
const approval = raw["approval"] ?? {};
|
|
266
|
+
return {
|
|
267
|
+
state: String(approval["state"] ?? ""),
|
|
268
|
+
approvalId: approval["approval_id"],
|
|
269
|
+
transactionId: approval["transaction_id"],
|
|
270
|
+
expiresAt: approval["expires_at"],
|
|
271
|
+
decidedAt: approval["decided_at"],
|
|
272
|
+
decisionSource: approval["decision_source"],
|
|
273
|
+
actionDescription: approval["action_description"],
|
|
274
|
+
raw
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
function toPhoneShareInitiateResult(raw) {
|
|
278
|
+
return {
|
|
279
|
+
approvalId: raw["approval_id"],
|
|
280
|
+
codeSent: typeof raw["code_sent"] === "boolean" ? raw["code_sent"] : void 0,
|
|
281
|
+
expiresAt: raw["expires_at"],
|
|
282
|
+
alreadyApproved: typeof raw["already_approved"] === "boolean" ? raw["already_approved"] : void 0,
|
|
283
|
+
raw
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
function toPhoneShareApproveResult(raw) {
|
|
287
|
+
return {
|
|
288
|
+
approvalId: raw["approval_id"],
|
|
289
|
+
approved: typeof raw["approved"] === "boolean" ? raw["approved"] : void 0,
|
|
290
|
+
alreadyApproved: typeof raw["already_approved"] === "boolean" ? raw["already_approved"] : void 0,
|
|
291
|
+
expiresAt: raw["expires_at"],
|
|
292
|
+
raw
|
|
293
|
+
};
|
|
294
|
+
}
|
|
226
295
|
function toCurrencyBalance(row) {
|
|
227
296
|
return {
|
|
228
297
|
currencyId: row["currency_id"] ?? "",
|
|
@@ -669,6 +738,227 @@ var InvoServer = class {
|
|
|
669
738
|
raw
|
|
670
739
|
};
|
|
671
740
|
}
|
|
741
|
+
/**
|
|
742
|
+
* Complete a TRANSFER's SMS-PIN step (un-enrolled fallback). NOT idempotent —
|
|
743
|
+
* each attempt is counted server-side, so this is never auto-retried. A bad PIN
|
|
744
|
+
* throws a 400 InvoError carrying `attempts_remaining` on `err.body`; a blocked
|
|
745
|
+
* recipient throws 429 (`sms_verification_blocked`).
|
|
746
|
+
*/
|
|
747
|
+
async verifySmsTransfer(transactionId, smsPin, opts) {
|
|
748
|
+
if (typeof transactionId !== "string" || !transactionId.trim()) {
|
|
749
|
+
throw invalidInput("transactionId", transactionId, "is required");
|
|
750
|
+
}
|
|
751
|
+
if (typeof smsPin !== "string" || !smsPin.trim()) {
|
|
752
|
+
throw invalidInput("smsPin", smsPin, "is required");
|
|
753
|
+
}
|
|
754
|
+
const raw = await this.http.post(
|
|
755
|
+
"/api/transfers/verify-sms",
|
|
756
|
+
{ transaction_id: transactionId, sms_pin: smsPin },
|
|
757
|
+
this.auth,
|
|
758
|
+
{ signal: opts?.signal }
|
|
759
|
+
// NOT idempotent — attempts are counted; never auto-retried
|
|
760
|
+
);
|
|
761
|
+
return toSmsVerifyResult(raw);
|
|
762
|
+
}
|
|
763
|
+
/** Complete a SEND's SMS-PIN step (un-enrolled fallback). See verifySmsTransfer. */
|
|
764
|
+
async verifySmsSend(transactionId, smsPin, opts) {
|
|
765
|
+
if (typeof transactionId !== "string" || !transactionId.trim()) {
|
|
766
|
+
throw invalidInput("transactionId", transactionId, "is required");
|
|
767
|
+
}
|
|
768
|
+
if (typeof smsPin !== "string" || !smsPin.trim()) {
|
|
769
|
+
throw invalidInput("smsPin", smsPin, "is required");
|
|
770
|
+
}
|
|
771
|
+
const raw = await this.http.post(
|
|
772
|
+
"/api/currency-sends/verify-sms",
|
|
773
|
+
{ transaction_id: transactionId, sms_pin: smsPin },
|
|
774
|
+
this.auth,
|
|
775
|
+
{ signal: opts?.signal }
|
|
776
|
+
// NOT idempotent — attempts are counted; never auto-retried
|
|
777
|
+
);
|
|
778
|
+
return toSmsVerifyResult(raw);
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Claim an inbound TRANSFER by its claim code, crediting one of this game's currencies.
|
|
782
|
+
* NOT idempotent. A 200 may come back as `needsAccountSelection` (the recipient phone
|
|
783
|
+
* maps to >1 of your players) — inspect `result.candidates` and re-submit with
|
|
784
|
+
* `targetPlayerId`. Errors surface via InvoError (404 unknown code, 403 phone mismatch,
|
|
785
|
+
* 400 not-claimable/expired/wrong-value, 409 `err.isPhoneShareApprovalRequired`, …).
|
|
786
|
+
*/
|
|
787
|
+
async claimTransfer(input, opts) {
|
|
788
|
+
const body = {
|
|
789
|
+
claim_code: input.claimCode,
|
|
790
|
+
target_player_name: input.targetPlayerName,
|
|
791
|
+
target_player_email: input.targetPlayerEmail,
|
|
792
|
+
target_player_phone: input.targetPlayerPhone,
|
|
793
|
+
target_currency_id: input.targetCurrencyId
|
|
794
|
+
};
|
|
795
|
+
if (input.targetPlayerId != null) body["target_player_id"] = input.targetPlayerId;
|
|
796
|
+
const raw = await this.http.post(
|
|
797
|
+
"/api/transfers/claim-transfer",
|
|
798
|
+
body,
|
|
799
|
+
this.auth,
|
|
800
|
+
{ signal: opts?.signal }
|
|
801
|
+
// NOT idempotent — never auto-retried
|
|
802
|
+
);
|
|
803
|
+
return toClaimResult(raw);
|
|
804
|
+
}
|
|
805
|
+
/**
|
|
806
|
+
* Claim an inbound SEND by its claim code. NOT idempotent. May return
|
|
807
|
+
* `needsAccountSelection` (multi-account phone) — re-submit with `receiverPlayerId`.
|
|
808
|
+
* See claimTransfer for the error surface.
|
|
809
|
+
*/
|
|
810
|
+
async claimCurrency(input, opts) {
|
|
811
|
+
const body = {
|
|
812
|
+
claim_code: input.claimCode,
|
|
813
|
+
receiver_player_name: input.receiverPlayerName,
|
|
814
|
+
receiver_player_email: input.receiverPlayerEmail,
|
|
815
|
+
receiver_player_phone: input.receiverPlayerPhone
|
|
816
|
+
};
|
|
817
|
+
if (input.receiverPlayerId != null) body["receiver_player_id"] = input.receiverPlayerId;
|
|
818
|
+
const raw = await this.http.post(
|
|
819
|
+
"/api/currency-sends/claim-currency",
|
|
820
|
+
body,
|
|
821
|
+
this.auth,
|
|
822
|
+
{ signal: opts?.signal }
|
|
823
|
+
// NOT idempotent — never auto-retried
|
|
824
|
+
);
|
|
825
|
+
return toClaimResult(raw);
|
|
826
|
+
}
|
|
827
|
+
/** Read a TRANSFER's status (verification_state + amounts + destination). */
|
|
828
|
+
async getTransferStatus(transactionId, opts) {
|
|
829
|
+
if (typeof transactionId !== "string" || !transactionId.trim()) {
|
|
830
|
+
throw invalidInput("transactionId", transactionId, "is required");
|
|
831
|
+
}
|
|
832
|
+
const raw = await this.http.get(
|
|
833
|
+
`/api/transfers/${encodeURIComponent(transactionId)}/status`,
|
|
834
|
+
this.auth,
|
|
835
|
+
{ signal: opts?.signal }
|
|
836
|
+
);
|
|
837
|
+
return toTransactionStatus(raw);
|
|
838
|
+
}
|
|
839
|
+
/** Read a SEND's status (adds fees, game names, claim_info, … on `raw`). */
|
|
840
|
+
async getSendStatus(transactionId, opts) {
|
|
841
|
+
if (typeof transactionId !== "string" || !transactionId.trim()) {
|
|
842
|
+
throw invalidInput("transactionId", transactionId, "is required");
|
|
843
|
+
}
|
|
844
|
+
const raw = await this.http.get(
|
|
845
|
+
`/api/currency-sends/${encodeURIComponent(transactionId)}/status`,
|
|
846
|
+
this.auth,
|
|
847
|
+
{ signal: opts?.signal }
|
|
848
|
+
);
|
|
849
|
+
return toTransactionStatus(raw);
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Poll a transaction's guardian approval status (minor/guardian flow). The retry
|
|
853
|
+
* layer already retries the 503 (`{status:"unavailable"}`) for this idempotent GET;
|
|
854
|
+
* a missing approval throws a 404 InvoError (`{status:"not_found"}`).
|
|
855
|
+
*/
|
|
856
|
+
async getGuardianApprovalStatus(transactionId, opts) {
|
|
857
|
+
if (typeof transactionId !== "string" || !transactionId.trim()) {
|
|
858
|
+
throw invalidInput("transactionId", transactionId, "is required");
|
|
859
|
+
}
|
|
860
|
+
const raw = await this.http.get(
|
|
861
|
+
`/api/transactions/${encodeURIComponent(transactionId)}/approval-status`,
|
|
862
|
+
this.auth,
|
|
863
|
+
{ signal: opts?.signal }
|
|
864
|
+
);
|
|
865
|
+
return toGuardianApprovalStatus(raw);
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* List the games/tenants a player can send/transfer to FROM `sourceGameId`, with
|
|
869
|
+
* display metadata inline (name, icon, currency, min/max limits) — one call, no
|
|
870
|
+
* per-game lookup. SERVER variant (game-secret) of the browser `InvoClient.getDestinations`;
|
|
871
|
+
* the source game is passed explicitly rather than inferred from a player token. Rows
|
|
872
|
+
* share the browser shape. Idempotent (a POST read — safe to retry).
|
|
873
|
+
*/
|
|
874
|
+
async getDestinations(query, opts) {
|
|
875
|
+
if (query.sourceGameId == null || String(query.sourceGameId).trim() === "") {
|
|
876
|
+
throw invalidInput("sourceGameId", query.sourceGameId, "is required");
|
|
877
|
+
}
|
|
878
|
+
const direction = query.direction ?? "transfer";
|
|
879
|
+
const path = direction === "send" ? "/api/currency-sends/available-destinations" : "/api/transfers/available-destinations";
|
|
880
|
+
const raw = await this.http.post(
|
|
881
|
+
path,
|
|
882
|
+
{ source_game_id: query.sourceGameId },
|
|
883
|
+
this.auth,
|
|
884
|
+
{ idempotent: true, signal: opts?.signal }
|
|
885
|
+
// a POST read — no side effect, safe to retry
|
|
886
|
+
);
|
|
887
|
+
return toDestinationsResult(raw, direction);
|
|
888
|
+
}
|
|
889
|
+
/**
|
|
890
|
+
* Phone-share OTP handshake — resolves a 409 `PHONE_SHARE_APPROVAL_REQUIRED`.
|
|
891
|
+
*
|
|
892
|
+
* These three endpoints are UNAUTHENTICATED (phone-owner-driven: no game secret,
|
|
893
|
+
* no player token) — a partner backend relays the handshake. The triggering 409
|
|
894
|
+
* carries `approval_id, expires_at, code_sent, existing_account_hints[], next_endpoint`.
|
|
895
|
+
*
|
|
896
|
+
* `phoneShareInitiate` is the fallback OTP send (use when the 409 didn't already
|
|
897
|
+
* dispatch a code). NOT idempotent — never auto-retried. OTP TTL ~10 min.
|
|
898
|
+
*/
|
|
899
|
+
async phoneShareInitiate(input, opts) {
|
|
900
|
+
if (typeof input.phone !== "string" || !input.phone.trim()) {
|
|
901
|
+
throw invalidInput("phone", input.phone, "is required");
|
|
902
|
+
}
|
|
903
|
+
if (typeof input.email !== "string" || !input.email.trim()) {
|
|
904
|
+
throw invalidInput("email", input.email, "is required");
|
|
905
|
+
}
|
|
906
|
+
const raw = await this.http.post(
|
|
907
|
+
"/api/wallet/phone-share/initiate",
|
|
908
|
+
{ phone: input.phone, email: input.email },
|
|
909
|
+
{ kind: "none" },
|
|
910
|
+
// UNAUTHENTICATED — phone-owner-driven; send no auth header
|
|
911
|
+
{ signal: opts?.signal }
|
|
912
|
+
// NOT idempotent — sends an OTP; never auto-retried
|
|
913
|
+
);
|
|
914
|
+
return toPhoneShareInitiateResult(raw);
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* Approve a phone-share with the OTP the phone owner received. On success the grant
|
|
918
|
+
* is stored server-side, keyed by (phone, requesting_email) and auto-consumed — the
|
|
919
|
+
* caller simply RE-ISSUES the identical original request. UNAUTHENTICATED. NOT
|
|
920
|
+
* idempotent (attempts are counted) — never auto-retried.
|
|
921
|
+
*/
|
|
922
|
+
async phoneShareApprove(input, opts) {
|
|
923
|
+
if (typeof input.approvalId !== "string" || !input.approvalId.trim()) {
|
|
924
|
+
throw invalidInput("approvalId", input.approvalId, "is required");
|
|
925
|
+
}
|
|
926
|
+
if (typeof input.otp !== "string" || !input.otp.trim()) {
|
|
927
|
+
throw invalidInput("otp", input.otp, "is required");
|
|
928
|
+
}
|
|
929
|
+
const raw = await this.http.post(
|
|
930
|
+
"/api/wallet/phone-share/approve",
|
|
931
|
+
{ approval_id: input.approvalId, otp: input.otp },
|
|
932
|
+
{ kind: "none" },
|
|
933
|
+
// UNAUTHENTICATED — phone-owner-driven; send no auth header
|
|
934
|
+
{ signal: opts?.signal }
|
|
935
|
+
// NOT idempotent — OTP attempts are counted; never auto-retried
|
|
936
|
+
);
|
|
937
|
+
return toPhoneShareApproveResult(raw);
|
|
938
|
+
}
|
|
939
|
+
/**
|
|
940
|
+
* Poll whether a phone-share (phone, requesting_email) pair is approved yet.
|
|
941
|
+
* UNAUTHENTICATED, idempotent GET. `approved:true` means the original request can
|
|
942
|
+
* be re-issued.
|
|
943
|
+
*/
|
|
944
|
+
async phoneShareStatus(input, opts) {
|
|
945
|
+
if (typeof input.phone !== "string" || !input.phone.trim()) {
|
|
946
|
+
throw invalidInput("phone", input.phone, "is required");
|
|
947
|
+
}
|
|
948
|
+
if (typeof input.email !== "string" || !input.email.trim()) {
|
|
949
|
+
throw invalidInput("email", input.email, "is required");
|
|
950
|
+
}
|
|
951
|
+
const q = new URLSearchParams();
|
|
952
|
+
q.set("phone", input.phone);
|
|
953
|
+
q.set("email", input.email);
|
|
954
|
+
const raw = await this.http.get(
|
|
955
|
+
`/api/wallet/phone-share/status?${q.toString()}`,
|
|
956
|
+
{ kind: "none" },
|
|
957
|
+
// UNAUTHENTICATED — phone-owner-driven; send no auth header
|
|
958
|
+
{ signal: opts?.signal }
|
|
959
|
+
);
|
|
960
|
+
return { approved: raw["approved"] === true, raw };
|
|
961
|
+
}
|
|
672
962
|
toInitiateResult(raw) {
|
|
673
963
|
const vm = raw["verification_method"];
|
|
674
964
|
const guardian = raw["guardian_approval"];
|
|
@@ -37,6 +37,10 @@ declare class InvoError extends Error {
|
|
|
37
37
|
* is a rate-limit, not a top-up condition) is NOT misclassified as this.
|
|
38
38
|
*/
|
|
39
39
|
get isInsufficientBalance(): boolean;
|
|
40
|
+
/** True if a claim needs phone-share approval before it can complete (claim → 409). */
|
|
41
|
+
get isPhoneShareApprovalRequired(): boolean;
|
|
42
|
+
/** True if the phone-share (phone, requesting_email) pair was already approved. */
|
|
43
|
+
get isPhoneShareAlreadyApproved(): boolean;
|
|
40
44
|
/** True if an idempotency-keyed request was a duplicate (item purchase → 409). */
|
|
41
45
|
get isDuplicateRequest(): boolean;
|
|
42
46
|
/** Seconds to wait before retrying, when the backend throttled the call (429 `retry_after`). */
|
|
@@ -405,6 +409,14 @@ interface DestinationsQuery {
|
|
|
405
409
|
/** "transfer" | "send". Defaults "transfer" (the set is identical for both today). */
|
|
406
410
|
direction?: "transfer" | "send";
|
|
407
411
|
}
|
|
412
|
+
/** Server-side (game-secret) destinations query. Unlike the browser variant, the
|
|
413
|
+
* source game isn't inferred from a player token — pass it explicitly. */
|
|
414
|
+
interface ServerDestinationsQuery {
|
|
415
|
+
/** The game the player is sending/transferring FROM. */
|
|
416
|
+
sourceGameId: string | number;
|
|
417
|
+
/** "transfer" | "send". Defaults "transfer" (the set is identical for both today). */
|
|
418
|
+
direction?: "transfer" | "send";
|
|
419
|
+
}
|
|
408
420
|
/** A game/tenant this player can send/transfer to, with display metadata inline. */
|
|
409
421
|
interface DestinationGame {
|
|
410
422
|
gameId: string | number;
|
|
@@ -459,5 +471,127 @@ interface LinkDeviceResult {
|
|
|
459
471
|
status: string;
|
|
460
472
|
raw: Record<string, unknown>;
|
|
461
473
|
}
|
|
474
|
+
interface SmsVerifyResult {
|
|
475
|
+
/** "success" on a completed verification. */
|
|
476
|
+
status: string;
|
|
477
|
+
transactionId: string;
|
|
478
|
+
/** The recipient claim code, when the completion issued one. */
|
|
479
|
+
claimCode?: string;
|
|
480
|
+
/** Canonical balance AFTER completion, when the backend returned it. */
|
|
481
|
+
newBalance?: string | number | null;
|
|
482
|
+
orderId?: string;
|
|
483
|
+
raw: Record<string, unknown>;
|
|
484
|
+
}
|
|
485
|
+
interface ClaimTransferInput {
|
|
486
|
+
claimCode: string;
|
|
487
|
+
targetPlayerName: string;
|
|
488
|
+
targetPlayerEmail: string;
|
|
489
|
+
targetPlayerPhone: string;
|
|
490
|
+
/** Which of this game's currencies to credit. */
|
|
491
|
+
targetCurrencyId: string | number;
|
|
492
|
+
/** Re-submit with this after a `needsAccountSelection` result to disambiguate a
|
|
493
|
+
* phone that maps to more than one of your players. */
|
|
494
|
+
targetPlayerId?: string | number;
|
|
495
|
+
}
|
|
496
|
+
interface ClaimCurrencyInput {
|
|
497
|
+
claimCode: string;
|
|
498
|
+
receiverPlayerName: string;
|
|
499
|
+
receiverPlayerEmail: string;
|
|
500
|
+
receiverPlayerPhone: string;
|
|
501
|
+
/** Re-submit with this after a `needsAccountSelection` result (multi-account phone). */
|
|
502
|
+
receiverPlayerId?: string | number;
|
|
503
|
+
}
|
|
504
|
+
interface ClaimResult {
|
|
505
|
+
/** "success" on completion, or "needs_account_selection" (see `needsAccountSelection`). */
|
|
506
|
+
status: string;
|
|
507
|
+
transactionId?: string;
|
|
508
|
+
newBalance?: string | number | null;
|
|
509
|
+
currencyName?: string;
|
|
510
|
+
orderId?: string;
|
|
511
|
+
/**
|
|
512
|
+
* true when a 200 came back as `status:"needs_account_selection"` (the recipient
|
|
513
|
+
* phone maps to more than one of your players). NOT an error — re-submit the claim
|
|
514
|
+
* with `targetPlayerId` (transfer) / `receiverPlayerId` (send) from `candidates`.
|
|
515
|
+
*/
|
|
516
|
+
needsAccountSelection: boolean;
|
|
517
|
+
/** Candidate accounts to disambiguate, present on a `needsAccountSelection` result. */
|
|
518
|
+
candidates?: Record<string, unknown>[];
|
|
519
|
+
raw: Record<string, unknown>;
|
|
520
|
+
}
|
|
521
|
+
/** `verification_state` ∈ awaiting | approved | completed | expired | failed | unknown. */
|
|
522
|
+
interface TransactionStatusResult {
|
|
523
|
+
transactionId: string;
|
|
524
|
+
/** "transfer" | "send". */
|
|
525
|
+
transactionType: string;
|
|
526
|
+
transactionStatus: string;
|
|
527
|
+
verificationState: string;
|
|
528
|
+
amount: string | number | null;
|
|
529
|
+
netAmount: string | number | null;
|
|
530
|
+
currencyId: string | number;
|
|
531
|
+
orderId?: string;
|
|
532
|
+
toPhone?: string;
|
|
533
|
+
toIdentityId?: string | null;
|
|
534
|
+
/** Everything else (send fees, game names, claim_info, failure_reason, sender claim_code, …). */
|
|
535
|
+
raw: Record<string, unknown>;
|
|
536
|
+
}
|
|
537
|
+
/** `state` ∈ pending | approved | rejected | expired. */
|
|
538
|
+
interface GuardianApprovalStatusResult {
|
|
539
|
+
state: string;
|
|
540
|
+
approvalId?: string;
|
|
541
|
+
transactionId?: string;
|
|
542
|
+
expiresAt?: string;
|
|
543
|
+
decidedAt?: string;
|
|
544
|
+
decisionSource?: string;
|
|
545
|
+
actionDescription?: string;
|
|
546
|
+
raw: Record<string, unknown>;
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* A phone + requesting-email pair identifying a phone-share approval. Used to send
|
|
550
|
+
* the fallback OTP and to poll status. The server-side grant is keyed by this pair.
|
|
551
|
+
*/
|
|
552
|
+
interface PhoneShareContact {
|
|
553
|
+
/** The phone number whose owner must approve the share. */
|
|
554
|
+
phone: string;
|
|
555
|
+
/** The email of the account requesting to use that phone (requesting_email). */
|
|
556
|
+
email: string;
|
|
557
|
+
}
|
|
558
|
+
/** Result of `phoneShareInitiate` (fallback OTP send). Known fields are surfaced;
|
|
559
|
+
* everything else stays on `raw`. */
|
|
560
|
+
interface PhoneShareInitiateResult {
|
|
561
|
+
/** The approval id to pass back to `phoneShareApprove`. */
|
|
562
|
+
approvalId?: string;
|
|
563
|
+
/** Whether the backend actually dispatched an OTP. */
|
|
564
|
+
codeSent?: boolean;
|
|
565
|
+
/** When the OTP / approval expires (ISO). OTP TTL is ~10 min. */
|
|
566
|
+
expiresAt?: string;
|
|
567
|
+
/** true when the (phone, email) pair was already approved — no OTP needed. */
|
|
568
|
+
alreadyApproved?: boolean;
|
|
569
|
+
raw: Record<string, unknown>;
|
|
570
|
+
}
|
|
571
|
+
/** Input for `phoneShareApprove`. */
|
|
572
|
+
interface PhoneShareApproveInput {
|
|
573
|
+
/** The `approval_id` from the 409 body or from `phoneShareInitiate`. */
|
|
574
|
+
approvalId: string;
|
|
575
|
+
/** The one-time code the phone owner received. */
|
|
576
|
+
otp: string;
|
|
577
|
+
}
|
|
578
|
+
/** Result of `phoneShareApprove`. Known fields are surfaced; the rest stays on `raw`.
|
|
579
|
+
* On success the grant is stored server-side, so the caller simply re-issues the
|
|
580
|
+
* identical original request (the grant is auto-consumed). */
|
|
581
|
+
interface PhoneShareApproveResult {
|
|
582
|
+
approvalId?: string;
|
|
583
|
+
/** true once the share is approved. */
|
|
584
|
+
approved?: boolean;
|
|
585
|
+
/** true when the pair was already approved before this call. */
|
|
586
|
+
alreadyApproved?: boolean;
|
|
587
|
+
expiresAt?: string;
|
|
588
|
+
raw: Record<string, unknown>;
|
|
589
|
+
}
|
|
590
|
+
/** Result of `phoneShareStatus` (idempotent GET). */
|
|
591
|
+
interface PhoneShareStatusResult {
|
|
592
|
+
/** true when the (phone, email) pair is approved and the original request can be re-issued. */
|
|
593
|
+
approved: boolean;
|
|
594
|
+
raw: Record<string, unknown>;
|
|
595
|
+
}
|
|
462
596
|
|
|
463
|
-
export { type ApproveResult as A, type BalanceResult as B, type ClientConfig as C, type DestinationsQuery as D, type EnrollmentBeginResult as E, type PlayerBalanceResult as F, type InboundPendingQuery as G, type InboundPendingResult as H, InvoError as I, type LinkedIdentitiesQuery as J, type LinkedIdentitiesResult as K, type LinkDeviceResult as L, type
|
|
597
|
+
export { type PhoneShareApproveResult as $, type ApproveResult as A, type BalanceResult as B, type ClientConfig as C, type DestinationsQuery as D, type EnrollmentBeginResult as E, type PlayerBalanceResult as F, type InboundPendingQuery as G, type InboundPendingResult as H, InvoError as I, type LinkedIdentitiesQuery as J, type LinkedIdentitiesResult as K, type LinkDeviceResult as L, type SmsVerifyResult as M, type ClaimTransferInput as N, type OrderDetailsResult as O, type PendingCollectResult as P, type ClaimResult as Q, type Rail as R, type ServerConfig as S, type ClaimCurrencyInput as T, type TransactionStatusResult as U, type VerificationMethod as V, type GuardianApprovalStatusResult as W, type ServerDestinationsQuery as X, type PhoneShareContact as Y, type PhoneShareInitiateResult as Z, type PhoneShareApproveInput as _, type CallOptions as a, type PhoneShareStatusResult as a0, type CurrencyBalance as a1, type InboundPendingItem as a2, type LinkedIdentityEmail as a3, type ConfirmReceiptResult as b, type DestinationsResult as c, type EnrollmentVerifyResult as d, type BalanceRow as e, type DestinationGame as f, type InvoErrorInfo as g, type InvoHooks as h, type InvoRequestInfo as i, type InvoResponseInfo as j, type PendingCollectItem as k, type PlayerToken as l, type InitiateSendInput as m, type InitiateResult as n, type InitiateTransferInput as o, type CreateCheckoutInput as p, type CreateCheckoutResult as q, type PurchaseInput as r, type PurchaseResult as s, type ConfirmPaymentResult as t, type PurchaseItemInput as u, type PurchaseItemResult as v, type ItemHistoryQuery as w, type ItemHistoryResult as x, type ItemOrderQuery as y, type PlayerBalanceQuery as z };
|
|
@@ -37,6 +37,10 @@ declare class InvoError extends Error {
|
|
|
37
37
|
* is a rate-limit, not a top-up condition) is NOT misclassified as this.
|
|
38
38
|
*/
|
|
39
39
|
get isInsufficientBalance(): boolean;
|
|
40
|
+
/** True if a claim needs phone-share approval before it can complete (claim → 409). */
|
|
41
|
+
get isPhoneShareApprovalRequired(): boolean;
|
|
42
|
+
/** True if the phone-share (phone, requesting_email) pair was already approved. */
|
|
43
|
+
get isPhoneShareAlreadyApproved(): boolean;
|
|
40
44
|
/** True if an idempotency-keyed request was a duplicate (item purchase → 409). */
|
|
41
45
|
get isDuplicateRequest(): boolean;
|
|
42
46
|
/** Seconds to wait before retrying, when the backend throttled the call (429 `retry_after`). */
|
|
@@ -405,6 +409,14 @@ interface DestinationsQuery {
|
|
|
405
409
|
/** "transfer" | "send". Defaults "transfer" (the set is identical for both today). */
|
|
406
410
|
direction?: "transfer" | "send";
|
|
407
411
|
}
|
|
412
|
+
/** Server-side (game-secret) destinations query. Unlike the browser variant, the
|
|
413
|
+
* source game isn't inferred from a player token — pass it explicitly. */
|
|
414
|
+
interface ServerDestinationsQuery {
|
|
415
|
+
/** The game the player is sending/transferring FROM. */
|
|
416
|
+
sourceGameId: string | number;
|
|
417
|
+
/** "transfer" | "send". Defaults "transfer" (the set is identical for both today). */
|
|
418
|
+
direction?: "transfer" | "send";
|
|
419
|
+
}
|
|
408
420
|
/** A game/tenant this player can send/transfer to, with display metadata inline. */
|
|
409
421
|
interface DestinationGame {
|
|
410
422
|
gameId: string | number;
|
|
@@ -459,5 +471,127 @@ interface LinkDeviceResult {
|
|
|
459
471
|
status: string;
|
|
460
472
|
raw: Record<string, unknown>;
|
|
461
473
|
}
|
|
474
|
+
interface SmsVerifyResult {
|
|
475
|
+
/** "success" on a completed verification. */
|
|
476
|
+
status: string;
|
|
477
|
+
transactionId: string;
|
|
478
|
+
/** The recipient claim code, when the completion issued one. */
|
|
479
|
+
claimCode?: string;
|
|
480
|
+
/** Canonical balance AFTER completion, when the backend returned it. */
|
|
481
|
+
newBalance?: string | number | null;
|
|
482
|
+
orderId?: string;
|
|
483
|
+
raw: Record<string, unknown>;
|
|
484
|
+
}
|
|
485
|
+
interface ClaimTransferInput {
|
|
486
|
+
claimCode: string;
|
|
487
|
+
targetPlayerName: string;
|
|
488
|
+
targetPlayerEmail: string;
|
|
489
|
+
targetPlayerPhone: string;
|
|
490
|
+
/** Which of this game's currencies to credit. */
|
|
491
|
+
targetCurrencyId: string | number;
|
|
492
|
+
/** Re-submit with this after a `needsAccountSelection` result to disambiguate a
|
|
493
|
+
* phone that maps to more than one of your players. */
|
|
494
|
+
targetPlayerId?: string | number;
|
|
495
|
+
}
|
|
496
|
+
interface ClaimCurrencyInput {
|
|
497
|
+
claimCode: string;
|
|
498
|
+
receiverPlayerName: string;
|
|
499
|
+
receiverPlayerEmail: string;
|
|
500
|
+
receiverPlayerPhone: string;
|
|
501
|
+
/** Re-submit with this after a `needsAccountSelection` result (multi-account phone). */
|
|
502
|
+
receiverPlayerId?: string | number;
|
|
503
|
+
}
|
|
504
|
+
interface ClaimResult {
|
|
505
|
+
/** "success" on completion, or "needs_account_selection" (see `needsAccountSelection`). */
|
|
506
|
+
status: string;
|
|
507
|
+
transactionId?: string;
|
|
508
|
+
newBalance?: string | number | null;
|
|
509
|
+
currencyName?: string;
|
|
510
|
+
orderId?: string;
|
|
511
|
+
/**
|
|
512
|
+
* true when a 200 came back as `status:"needs_account_selection"` (the recipient
|
|
513
|
+
* phone maps to more than one of your players). NOT an error — re-submit the claim
|
|
514
|
+
* with `targetPlayerId` (transfer) / `receiverPlayerId` (send) from `candidates`.
|
|
515
|
+
*/
|
|
516
|
+
needsAccountSelection: boolean;
|
|
517
|
+
/** Candidate accounts to disambiguate, present on a `needsAccountSelection` result. */
|
|
518
|
+
candidates?: Record<string, unknown>[];
|
|
519
|
+
raw: Record<string, unknown>;
|
|
520
|
+
}
|
|
521
|
+
/** `verification_state` ∈ awaiting | approved | completed | expired | failed | unknown. */
|
|
522
|
+
interface TransactionStatusResult {
|
|
523
|
+
transactionId: string;
|
|
524
|
+
/** "transfer" | "send". */
|
|
525
|
+
transactionType: string;
|
|
526
|
+
transactionStatus: string;
|
|
527
|
+
verificationState: string;
|
|
528
|
+
amount: string | number | null;
|
|
529
|
+
netAmount: string | number | null;
|
|
530
|
+
currencyId: string | number;
|
|
531
|
+
orderId?: string;
|
|
532
|
+
toPhone?: string;
|
|
533
|
+
toIdentityId?: string | null;
|
|
534
|
+
/** Everything else (send fees, game names, claim_info, failure_reason, sender claim_code, …). */
|
|
535
|
+
raw: Record<string, unknown>;
|
|
536
|
+
}
|
|
537
|
+
/** `state` ∈ pending | approved | rejected | expired. */
|
|
538
|
+
interface GuardianApprovalStatusResult {
|
|
539
|
+
state: string;
|
|
540
|
+
approvalId?: string;
|
|
541
|
+
transactionId?: string;
|
|
542
|
+
expiresAt?: string;
|
|
543
|
+
decidedAt?: string;
|
|
544
|
+
decisionSource?: string;
|
|
545
|
+
actionDescription?: string;
|
|
546
|
+
raw: Record<string, unknown>;
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* A phone + requesting-email pair identifying a phone-share approval. Used to send
|
|
550
|
+
* the fallback OTP and to poll status. The server-side grant is keyed by this pair.
|
|
551
|
+
*/
|
|
552
|
+
interface PhoneShareContact {
|
|
553
|
+
/** The phone number whose owner must approve the share. */
|
|
554
|
+
phone: string;
|
|
555
|
+
/** The email of the account requesting to use that phone (requesting_email). */
|
|
556
|
+
email: string;
|
|
557
|
+
}
|
|
558
|
+
/** Result of `phoneShareInitiate` (fallback OTP send). Known fields are surfaced;
|
|
559
|
+
* everything else stays on `raw`. */
|
|
560
|
+
interface PhoneShareInitiateResult {
|
|
561
|
+
/** The approval id to pass back to `phoneShareApprove`. */
|
|
562
|
+
approvalId?: string;
|
|
563
|
+
/** Whether the backend actually dispatched an OTP. */
|
|
564
|
+
codeSent?: boolean;
|
|
565
|
+
/** When the OTP / approval expires (ISO). OTP TTL is ~10 min. */
|
|
566
|
+
expiresAt?: string;
|
|
567
|
+
/** true when the (phone, email) pair was already approved — no OTP needed. */
|
|
568
|
+
alreadyApproved?: boolean;
|
|
569
|
+
raw: Record<string, unknown>;
|
|
570
|
+
}
|
|
571
|
+
/** Input for `phoneShareApprove`. */
|
|
572
|
+
interface PhoneShareApproveInput {
|
|
573
|
+
/** The `approval_id` from the 409 body or from `phoneShareInitiate`. */
|
|
574
|
+
approvalId: string;
|
|
575
|
+
/** The one-time code the phone owner received. */
|
|
576
|
+
otp: string;
|
|
577
|
+
}
|
|
578
|
+
/** Result of `phoneShareApprove`. Known fields are surfaced; the rest stays on `raw`.
|
|
579
|
+
* On success the grant is stored server-side, so the caller simply re-issues the
|
|
580
|
+
* identical original request (the grant is auto-consumed). */
|
|
581
|
+
interface PhoneShareApproveResult {
|
|
582
|
+
approvalId?: string;
|
|
583
|
+
/** true once the share is approved. */
|
|
584
|
+
approved?: boolean;
|
|
585
|
+
/** true when the pair was already approved before this call. */
|
|
586
|
+
alreadyApproved?: boolean;
|
|
587
|
+
expiresAt?: string;
|
|
588
|
+
raw: Record<string, unknown>;
|
|
589
|
+
}
|
|
590
|
+
/** Result of `phoneShareStatus` (idempotent GET). */
|
|
591
|
+
interface PhoneShareStatusResult {
|
|
592
|
+
/** true when the (phone, email) pair is approved and the original request can be re-issued. */
|
|
593
|
+
approved: boolean;
|
|
594
|
+
raw: Record<string, unknown>;
|
|
595
|
+
}
|
|
462
596
|
|
|
463
|
-
export { type ApproveResult as A, type BalanceResult as B, type ClientConfig as C, type DestinationsQuery as D, type EnrollmentBeginResult as E, type PlayerBalanceResult as F, type InboundPendingQuery as G, type InboundPendingResult as H, InvoError as I, type LinkedIdentitiesQuery as J, type LinkedIdentitiesResult as K, type LinkDeviceResult as L, type
|
|
597
|
+
export { type PhoneShareApproveResult as $, type ApproveResult as A, type BalanceResult as B, type ClientConfig as C, type DestinationsQuery as D, type EnrollmentBeginResult as E, type PlayerBalanceResult as F, type InboundPendingQuery as G, type InboundPendingResult as H, InvoError as I, type LinkedIdentitiesQuery as J, type LinkedIdentitiesResult as K, type LinkDeviceResult as L, type SmsVerifyResult as M, type ClaimTransferInput as N, type OrderDetailsResult as O, type PendingCollectResult as P, type ClaimResult as Q, type Rail as R, type ServerConfig as S, type ClaimCurrencyInput as T, type TransactionStatusResult as U, type VerificationMethod as V, type GuardianApprovalStatusResult as W, type ServerDestinationsQuery as X, type PhoneShareContact as Y, type PhoneShareInitiateResult as Z, type PhoneShareApproveInput as _, type CallOptions as a, type PhoneShareStatusResult as a0, type CurrencyBalance as a1, type InboundPendingItem as a2, type LinkedIdentityEmail as a3, type ConfirmReceiptResult as b, type DestinationsResult as c, type EnrollmentVerifyResult as d, type BalanceRow as e, type DestinationGame as f, type InvoErrorInfo as g, type InvoHooks as h, type InvoRequestInfo as i, type InvoResponseInfo as j, type PendingCollectItem as k, type PlayerToken as l, type InitiateSendInput as m, type InitiateResult as n, type InitiateTransferInput as o, type CreateCheckoutInput as p, type CreateCheckoutResult as q, type PurchaseInput as r, type PurchaseResult as s, type ConfirmPaymentResult as t, type PurchaseItemInput as u, type PurchaseItemResult as v, type ItemHistoryQuery as w, type ItemHistoryResult as x, type ItemOrderQuery as y, type PlayerBalanceQuery as z };
|
package/package.json
CHANGED