spaps-sdk 1.6.8 → 1.8.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 +9 -1
- package/README.md +153 -3
- package/dist/index.d.mts +348 -3
- package/dist/index.d.ts +348 -3
- package/dist/index.js +358 -11
- package/dist/index.mjs +350 -8
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -203,10 +203,11 @@ __export(index_exports, {
|
|
|
203
203
|
TokenManager: () => TokenManager,
|
|
204
204
|
WalletUtils: () => WalletUtils,
|
|
205
205
|
WebSocketAuthHelper: () => WebSocketAuthHelper,
|
|
206
|
+
X402PaymentRequiredSDKError: () => X402PaymentRequiredSDKError,
|
|
206
207
|
canAccessAdmin: () => canAccessAdmin,
|
|
207
208
|
createBrowserClient: () => createBrowserClient,
|
|
208
209
|
createPermissionChecker: () => createPermissionChecker,
|
|
209
|
-
createSecureMessageRequestSchema: () =>
|
|
210
|
+
createSecureMessageRequestSchema: () => import_spaps_types2.createSecureMessageRequestSchema,
|
|
210
211
|
createServerClient: () => createServerClient,
|
|
211
212
|
default: () => index_default,
|
|
212
213
|
defaultPermissionChecker: () => defaultPermissionChecker,
|
|
@@ -216,14 +217,22 @@ __export(index_exports, {
|
|
|
216
217
|
getUserRole: () => getUserRole,
|
|
217
218
|
hasPermission: () => hasPermission,
|
|
218
219
|
isAdminAccount: () => isAdminAccount,
|
|
219
|
-
|
|
220
|
-
|
|
220
|
+
isEnvelope: () => isEnvelope,
|
|
221
|
+
isErrorEnvelope: () => isErrorEnvelope,
|
|
222
|
+
isSuccessEnvelope: () => isSuccessEnvelope,
|
|
223
|
+
isX402PaymentRequired: () => import_spaps_types.isX402PaymentRequired,
|
|
224
|
+
isX402ResourceStatus: () => import_spaps_types.isX402ResourceStatus,
|
|
225
|
+
secureMessageMetadataSchema: () => import_spaps_types2.secureMessageMetadataSchema,
|
|
226
|
+
secureMessageSchema: () => import_spaps_types2.secureMessageSchema,
|
|
227
|
+
unwrapEnvelope: () => unwrapEnvelope,
|
|
228
|
+
unwrapNestedData: () => unwrapNestedData,
|
|
221
229
|
verifyCryptoWebhookSignature: () => verifyCryptoWebhookSignature
|
|
222
230
|
});
|
|
223
231
|
module.exports = __toCommonJS(index_exports);
|
|
224
232
|
var import_crypto = __toESM(require("crypto"));
|
|
225
233
|
var import_axios = __toESM(require("axios"));
|
|
226
234
|
var import_spaps_types = require("spaps-types");
|
|
235
|
+
var import_spaps_types2 = require("spaps-types");
|
|
227
236
|
init_permissions();
|
|
228
237
|
|
|
229
238
|
// src/role-hierarchy.ts
|
|
@@ -510,12 +519,23 @@ function appendSupportedIssueReportScope(q, scope) {
|
|
|
510
519
|
}
|
|
511
520
|
q.append("scope", scope);
|
|
512
521
|
}
|
|
513
|
-
var
|
|
522
|
+
var X402PaymentRequiredSDKError = class extends Error {
|
|
523
|
+
paymentRequiredHeader;
|
|
524
|
+
response;
|
|
525
|
+
constructor(paymentRequiredHeader, response) {
|
|
526
|
+
super("x402 payment required");
|
|
527
|
+
this.name = "X402PaymentRequiredSDKError";
|
|
528
|
+
this.paymentRequiredHeader = paymentRequiredHeader;
|
|
529
|
+
this.response = response;
|
|
530
|
+
}
|
|
531
|
+
};
|
|
532
|
+
var SPAPSClient = class _SPAPSClient {
|
|
514
533
|
client;
|
|
515
534
|
apiKey;
|
|
516
535
|
accessToken;
|
|
517
536
|
refreshToken;
|
|
518
537
|
_isLocalMode = false;
|
|
538
|
+
headerProvider;
|
|
519
539
|
unwrapApiResponse(response, fallback) {
|
|
520
540
|
if (!response) {
|
|
521
541
|
throw new Error(fallback);
|
|
@@ -532,6 +552,13 @@ var SPAPSClient = class {
|
|
|
532
552
|
}
|
|
533
553
|
return payload;
|
|
534
554
|
}
|
|
555
|
+
skillEvalMutationConfig(options) {
|
|
556
|
+
const ifMatch = options?.ifMatch ?? options?.caseVersion;
|
|
557
|
+
if (ifMatch === void 0 || ifMatch === null || ifMatch === "") {
|
|
558
|
+
return void 0;
|
|
559
|
+
}
|
|
560
|
+
return { headers: { "If-Match": String(ifMatch) } };
|
|
561
|
+
}
|
|
535
562
|
isAxiosResponse(value) {
|
|
536
563
|
if (!value || typeof value !== "object") {
|
|
537
564
|
return false;
|
|
@@ -551,6 +578,41 @@ var SPAPSClient = class {
|
|
|
551
578
|
const record = value;
|
|
552
579
|
return "success" in record && typeof record.success === "boolean";
|
|
553
580
|
}
|
|
581
|
+
static isSdkManagedHeader(name) {
|
|
582
|
+
const normalized = name.toLowerCase();
|
|
583
|
+
return normalized === "authorization" || normalized === "x-api-key";
|
|
584
|
+
}
|
|
585
|
+
static hasHeader(headers, name) {
|
|
586
|
+
if (!headers) return false;
|
|
587
|
+
if (typeof headers.has === "function") {
|
|
588
|
+
return headers.has(name);
|
|
589
|
+
}
|
|
590
|
+
const normalized = name.toLowerCase();
|
|
591
|
+
return Object.keys(headers).some((key) => key.toLowerCase() === normalized);
|
|
592
|
+
}
|
|
593
|
+
static setHeader(headers, name, value) {
|
|
594
|
+
if (typeof headers.set === "function") {
|
|
595
|
+
headers.set(name, value);
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
headers[name] = value;
|
|
599
|
+
}
|
|
600
|
+
static assertSafeHeaderValue(name, value) {
|
|
601
|
+
if (typeof value === "string" && /[\r\n]/.test(value)) {
|
|
602
|
+
throw new Error(`Invalid header value for ${name}: control characters not allowed`);
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
applyCustomHeaders(headers) {
|
|
606
|
+
const customHeaders = this.headerProvider?.();
|
|
607
|
+
if (!customHeaders) return;
|
|
608
|
+
for (const [key, value] of Object.entries(customHeaders)) {
|
|
609
|
+
if (_SPAPSClient.isSdkManagedHeader(key) || _SPAPSClient.hasHeader(headers, key)) {
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
612
|
+
_SPAPSClient.assertSafeHeaderValue(key, value);
|
|
613
|
+
_SPAPSClient.setHeader(headers, key, value);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
554
616
|
// Admin namespace for cleaner API
|
|
555
617
|
admin = {
|
|
556
618
|
createProduct: (productData) => this.createProduct(productData),
|
|
@@ -725,8 +787,43 @@ var SPAPSClient = class {
|
|
|
725
787
|
return this.unwrapApiResponse(res, "Failed to reply to issue report");
|
|
726
788
|
}
|
|
727
789
|
};
|
|
790
|
+
/**
|
|
791
|
+
* Application-scoped short links for browser apps that need stable public URLs.
|
|
792
|
+
*/
|
|
793
|
+
appLinks = {
|
|
794
|
+
/**
|
|
795
|
+
* Create a short link owned by the authenticated user.
|
|
796
|
+
*/
|
|
797
|
+
create: async (payload) => {
|
|
798
|
+
const res = await this.client.post(
|
|
799
|
+
"/api/v1/app-links",
|
|
800
|
+
payload,
|
|
801
|
+
this.accessToken ? { headers: { Authorization: `Bearer ${this.accessToken}` } } : void 0
|
|
802
|
+
);
|
|
803
|
+
return this.unwrapApiResponse(res, "Failed to create app link");
|
|
804
|
+
},
|
|
805
|
+
/**
|
|
806
|
+
* Resolve a public short link for the active application.
|
|
807
|
+
*/
|
|
808
|
+
get: async (username, slug, options) => {
|
|
809
|
+
const q = new URLSearchParams();
|
|
810
|
+
if (options?.track) q.set("track", "true");
|
|
811
|
+
const qs = q.toString();
|
|
812
|
+
const res = await this.client.get(
|
|
813
|
+
`/api/v1/app-links/${encodeURIComponent(username)}/${encodeURIComponent(slug)}${qs ? `?${qs}` : ""}`,
|
|
814
|
+
this.accessToken ? { headers: { Authorization: `Bearer ${this.accessToken}` } } : void 0
|
|
815
|
+
);
|
|
816
|
+
return this.unwrapApiResponse(res, "Failed to get app link");
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
static envVar(name) {
|
|
820
|
+
if (typeof process !== "undefined" && process.env) {
|
|
821
|
+
return process.env[name];
|
|
822
|
+
}
|
|
823
|
+
return void 0;
|
|
824
|
+
}
|
|
728
825
|
constructor(config = {}) {
|
|
729
|
-
const apiUrl = config.apiUrl ||
|
|
826
|
+
const apiUrl = config.apiUrl || _SPAPSClient.envVar("SPAPS_API_URL") || _SPAPSClient.envVar("NEXT_PUBLIC_SPAPS_API_URL");
|
|
730
827
|
const isBrowser = typeof window !== "undefined";
|
|
731
828
|
let effectiveApiKey;
|
|
732
829
|
if (config.publishableKey) {
|
|
@@ -739,7 +836,7 @@ var SPAPSClient = class {
|
|
|
739
836
|
} else if (config.apiKey) {
|
|
740
837
|
effectiveApiKey = config.apiKey;
|
|
741
838
|
} else {
|
|
742
|
-
effectiveApiKey =
|
|
839
|
+
effectiveApiKey = _SPAPSClient.envVar("SPAPS_API_KEY") || _SPAPSClient.envVar("NEXT_PUBLIC_SPAPS_API_KEY");
|
|
743
840
|
}
|
|
744
841
|
if (!apiUrl || apiUrl.includes("localhost") || apiUrl.includes("127.0.0.1")) {
|
|
745
842
|
this._isLocalMode = true;
|
|
@@ -748,6 +845,7 @@ var SPAPSClient = class {
|
|
|
748
845
|
if (!this.apiKey && !this._isLocalMode) {
|
|
749
846
|
console.warn("\u26A0\uFE0F SPAPS: No API key provided. Some features may not work.");
|
|
750
847
|
}
|
|
848
|
+
this.headerProvider = config.headerProvider;
|
|
751
849
|
this.client = import_axios.default.create({
|
|
752
850
|
baseURL: apiUrl || "http://localhost:3301",
|
|
753
851
|
timeout: config.timeout || 1e4,
|
|
@@ -757,11 +855,13 @@ var SPAPSClient = class {
|
|
|
757
855
|
}
|
|
758
856
|
});
|
|
759
857
|
this.client.interceptors.request.use((config2) => {
|
|
760
|
-
|
|
761
|
-
|
|
858
|
+
config2.headers = config2.headers || {};
|
|
859
|
+
this.applyCustomHeaders(config2.headers);
|
|
860
|
+
if (this.apiKey && !_SPAPSClient.hasHeader(config2.headers, "X-API-Key")) {
|
|
861
|
+
_SPAPSClient.setHeader(config2.headers, "X-API-Key", this.apiKey);
|
|
762
862
|
}
|
|
763
|
-
if (this.accessToken && !config2.headers
|
|
764
|
-
config2.headers
|
|
863
|
+
if (this.accessToken && !_SPAPSClient.hasHeader(config2.headers, "Authorization")) {
|
|
864
|
+
_SPAPSClient.setHeader(config2.headers, "Authorization", `Bearer ${this.accessToken}`);
|
|
765
865
|
}
|
|
766
866
|
return config2;
|
|
767
867
|
});
|
|
@@ -1063,6 +1163,7 @@ var SPAPSClient = class {
|
|
|
1063
1163
|
reconcile: async (options = {}) => {
|
|
1064
1164
|
const headers = {};
|
|
1065
1165
|
if (options.reconToken) {
|
|
1166
|
+
_SPAPSClient.assertSafeHeaderValue("X-Recon-Token", options.reconToken);
|
|
1066
1167
|
headers["X-Recon-Token"] = options.reconToken;
|
|
1067
1168
|
}
|
|
1068
1169
|
const payload = {};
|
|
@@ -1288,6 +1389,185 @@ var SPAPSClient = class {
|
|
|
1288
1389
|
return this.unwrapApiResponse(res, "Failed to disconnect");
|
|
1289
1390
|
}
|
|
1290
1391
|
};
|
|
1392
|
+
/**
|
|
1393
|
+
* x402 paid-resource namespace.
|
|
1394
|
+
* Handles resource status checks, payment-gated actions, receipts, and handoff authorization.
|
|
1395
|
+
*/
|
|
1396
|
+
x402 = {
|
|
1397
|
+
getResourceStatus: async (resourceKey) => {
|
|
1398
|
+
const res = await this.client.get(
|
|
1399
|
+
`/api/x402/resources/${encodeURIComponent(resourceKey)}/status`
|
|
1400
|
+
);
|
|
1401
|
+
return this.unwrapApiResponse(res, "Failed to get x402 resource status");
|
|
1402
|
+
},
|
|
1403
|
+
executeAction: async (resourceKey, actionKey, options) => {
|
|
1404
|
+
const headers = {};
|
|
1405
|
+
if (this.accessToken) {
|
|
1406
|
+
headers["Authorization"] = `Bearer ${this.accessToken}`;
|
|
1407
|
+
}
|
|
1408
|
+
if (options?.paymentSignature) {
|
|
1409
|
+
headers["PAYMENT-SIGNATURE"] = options.paymentSignature;
|
|
1410
|
+
}
|
|
1411
|
+
const body = {};
|
|
1412
|
+
if (options?.target) body.target = options.target;
|
|
1413
|
+
const bridgeToken = options?.bridgeToken ?? options?.bridge_token;
|
|
1414
|
+
if (bridgeToken !== void 0) body.bridge_token = bridgeToken;
|
|
1415
|
+
const res = await this.client.post(
|
|
1416
|
+
`/api/x402/resources/${encodeURIComponent(resourceKey)}/actions/${encodeURIComponent(actionKey)}`,
|
|
1417
|
+
body,
|
|
1418
|
+
{ headers, validateStatus: (s) => s < 500 }
|
|
1419
|
+
);
|
|
1420
|
+
const paymentRequiredHeader = res.headers?.["payment-required"] || res.headers?.["PAYMENT-REQUIRED"] || "";
|
|
1421
|
+
if (res.status === 402 && paymentRequiredHeader) {
|
|
1422
|
+
throw new X402PaymentRequiredSDKError(
|
|
1423
|
+
paymentRequiredHeader,
|
|
1424
|
+
res.data
|
|
1425
|
+
);
|
|
1426
|
+
}
|
|
1427
|
+
return this.unwrapApiResponse(res, "Failed to execute x402 action");
|
|
1428
|
+
},
|
|
1429
|
+
getReceipt: async (receiptId) => {
|
|
1430
|
+
const res = await this.client.get(`/api/x402/receipts/${encodeURIComponent(receiptId)}`);
|
|
1431
|
+
return this.unwrapApiResponse(res, "Failed to get x402 receipt");
|
|
1432
|
+
},
|
|
1433
|
+
listReceipts: async (params) => {
|
|
1434
|
+
const q = new URLSearchParams();
|
|
1435
|
+
if (params?.resourceKey) q.append("resource_key", params.resourceKey);
|
|
1436
|
+
if (params?.limit !== void 0) q.append("limit", String(params.limit));
|
|
1437
|
+
if (params?.offset !== void 0) q.append("offset", String(params.offset));
|
|
1438
|
+
const qs = q.toString();
|
|
1439
|
+
const res = await this.client.get(`/api/x402/receipts${qs ? `?${qs}` : ""}`);
|
|
1440
|
+
return this.unwrapApiResponse(res, "Failed to list x402 receipts");
|
|
1441
|
+
},
|
|
1442
|
+
verifyHandoff: async (token, target, bridgeToken, options) => {
|
|
1443
|
+
const body = {
|
|
1444
|
+
token,
|
|
1445
|
+
resource_key: options.resourceKey,
|
|
1446
|
+
action_key: options.actionKey,
|
|
1447
|
+
target,
|
|
1448
|
+
bridge_token: bridgeToken
|
|
1449
|
+
};
|
|
1450
|
+
const res = await this.client.post("/api/x402/handoff/verify", body);
|
|
1451
|
+
return this.unwrapApiResponse(res, "Failed to verify x402 handoff");
|
|
1452
|
+
}
|
|
1453
|
+
};
|
|
1454
|
+
/**
|
|
1455
|
+
* Blind comparative skill-eval namespace.
|
|
1456
|
+
*/
|
|
1457
|
+
skillEvals = {
|
|
1458
|
+
createCase: async (payload, options) => {
|
|
1459
|
+
const headers = {};
|
|
1460
|
+
if (this.accessToken) {
|
|
1461
|
+
headers["Authorization"] = `Bearer ${this.accessToken}`;
|
|
1462
|
+
}
|
|
1463
|
+
if (options?.paymentSignature) {
|
|
1464
|
+
headers["PAYMENT-SIGNATURE"] = options.paymentSignature;
|
|
1465
|
+
}
|
|
1466
|
+
const res = await this.client.post("/api/skill-evals/cases", payload, {
|
|
1467
|
+
headers,
|
|
1468
|
+
validateStatus: (s) => s < 500
|
|
1469
|
+
});
|
|
1470
|
+
const paymentRequiredHeader = res.headers?.["payment-required"] || res.headers?.["PAYMENT-REQUIRED"] || "";
|
|
1471
|
+
if (res.status === 402 && paymentRequiredHeader) {
|
|
1472
|
+
throw new X402PaymentRequiredSDKError(paymentRequiredHeader, res.data);
|
|
1473
|
+
}
|
|
1474
|
+
return this.unwrapApiResponse(
|
|
1475
|
+
res,
|
|
1476
|
+
"Failed to create skill eval case"
|
|
1477
|
+
);
|
|
1478
|
+
},
|
|
1479
|
+
getCase: async (caseId) => {
|
|
1480
|
+
const res = await this.client.get(
|
|
1481
|
+
`/api/skill-evals/cases/${encodeURIComponent(caseId)}`
|
|
1482
|
+
);
|
|
1483
|
+
return this.unwrapApiResponse(res, "Failed to get skill eval case");
|
|
1484
|
+
},
|
|
1485
|
+
getReviewRoom: async (caseId) => {
|
|
1486
|
+
const res = await this.client.get(
|
|
1487
|
+
`/api/skill-evals/cases/${encodeURIComponent(caseId)}/room`
|
|
1488
|
+
);
|
|
1489
|
+
return this.unwrapApiResponse(res, "Failed to get skill eval room");
|
|
1490
|
+
},
|
|
1491
|
+
getInsights: async (caseId) => {
|
|
1492
|
+
const res = await this.client.get(
|
|
1493
|
+
`/api/skill-evals/cases/${encodeURIComponent(caseId)}/insights`
|
|
1494
|
+
);
|
|
1495
|
+
return this.unwrapApiResponse(
|
|
1496
|
+
res,
|
|
1497
|
+
"Failed to get skill eval insights"
|
|
1498
|
+
);
|
|
1499
|
+
},
|
|
1500
|
+
submitReview: async (caseId, payload, options) => {
|
|
1501
|
+
const config = this.skillEvalMutationConfig(options);
|
|
1502
|
+
const res = await this.client.post(
|
|
1503
|
+
`/api/skill-evals/cases/${encodeURIComponent(caseId)}/reviews`,
|
|
1504
|
+
payload,
|
|
1505
|
+
...config ? [config] : []
|
|
1506
|
+
);
|
|
1507
|
+
return this.unwrapApiResponse(
|
|
1508
|
+
res,
|
|
1509
|
+
"Failed to submit skill eval review"
|
|
1510
|
+
);
|
|
1511
|
+
},
|
|
1512
|
+
respondToReview: async (caseId, reviewId, payload, options) => {
|
|
1513
|
+
const config = this.skillEvalMutationConfig(options);
|
|
1514
|
+
const res = await this.client.post(
|
|
1515
|
+
`/api/skill-evals/cases/${encodeURIComponent(caseId)}/reviews/${encodeURIComponent(reviewId)}/response`,
|
|
1516
|
+
payload,
|
|
1517
|
+
...config ? [config] : []
|
|
1518
|
+
);
|
|
1519
|
+
return this.unwrapApiResponse(
|
|
1520
|
+
res,
|
|
1521
|
+
"Failed to respond to skill eval review"
|
|
1522
|
+
);
|
|
1523
|
+
},
|
|
1524
|
+
lockReviews: async (caseId, options) => {
|
|
1525
|
+
const config = this.skillEvalMutationConfig(options);
|
|
1526
|
+
const res = await this.client.post(
|
|
1527
|
+
`/api/skill-evals/cases/${encodeURIComponent(caseId)}/lock`,
|
|
1528
|
+
{},
|
|
1529
|
+
...config ? [config] : []
|
|
1530
|
+
);
|
|
1531
|
+
return this.unwrapApiResponse(
|
|
1532
|
+
res,
|
|
1533
|
+
"Failed to lock skill eval reviews"
|
|
1534
|
+
);
|
|
1535
|
+
},
|
|
1536
|
+
revealEvidence: async (caseId, payload, options) => {
|
|
1537
|
+
const config = this.skillEvalMutationConfig(options);
|
|
1538
|
+
const res = await this.client.post(
|
|
1539
|
+
`/api/skill-evals/cases/${encodeURIComponent(caseId)}/reveal`,
|
|
1540
|
+
payload,
|
|
1541
|
+
...config ? [config] : []
|
|
1542
|
+
);
|
|
1543
|
+
return this.unwrapApiResponse(
|
|
1544
|
+
res,
|
|
1545
|
+
"Failed to reveal skill eval evidence"
|
|
1546
|
+
);
|
|
1547
|
+
},
|
|
1548
|
+
createGovernanceSnapshot: async (caseId, payload, options) => {
|
|
1549
|
+
const config = this.skillEvalMutationConfig(options);
|
|
1550
|
+
const res = await this.client.post(
|
|
1551
|
+
`/api/skill-evals/cases/${encodeURIComponent(caseId)}/governance-snapshots`,
|
|
1552
|
+
payload,
|
|
1553
|
+
...config ? [config] : []
|
|
1554
|
+
);
|
|
1555
|
+
return this.unwrapApiResponse(
|
|
1556
|
+
res,
|
|
1557
|
+
"Failed to create skill eval governance snapshot"
|
|
1558
|
+
);
|
|
1559
|
+
},
|
|
1560
|
+
importGovernanceOutcome: async (snapshotId, payload) => {
|
|
1561
|
+
const res = await this.client.post(
|
|
1562
|
+
`/api/skill-evals/governance-snapshots/${encodeURIComponent(snapshotId)}/outcome`,
|
|
1563
|
+
payload
|
|
1564
|
+
);
|
|
1565
|
+
return this.unwrapApiResponse(
|
|
1566
|
+
res,
|
|
1567
|
+
"Failed to import skill eval governance outcome"
|
|
1568
|
+
);
|
|
1569
|
+
}
|
|
1570
|
+
};
|
|
1291
1571
|
/**
|
|
1292
1572
|
* DayRate (Dynamic Scheduling) namespace
|
|
1293
1573
|
* For booking half-day sessions with dynamic pricing
|
|
@@ -1316,6 +1596,21 @@ var SPAPSClient = class {
|
|
|
1316
1596
|
createMultiBooking: async (payload) => {
|
|
1317
1597
|
const res = await this.client.post("/api/dayrate/book-multi", payload);
|
|
1318
1598
|
return this.unwrapApiResponse(res, "Failed to create multi-booking");
|
|
1599
|
+
},
|
|
1600
|
+
/**
|
|
1601
|
+
* Create a single-slot booking hold backed by an x402 paid-resource action.
|
|
1602
|
+
*/
|
|
1603
|
+
createX402Booking: async (payload) => {
|
|
1604
|
+
const res = await this.client.post("/api/dayrate/book-x402", payload);
|
|
1605
|
+
return this.unwrapApiResponse(res, "Failed to create x402 booking");
|
|
1606
|
+
},
|
|
1607
|
+
/**
|
|
1608
|
+
* Get guest-safe checkout confirmation state for a Stripe session.
|
|
1609
|
+
*/
|
|
1610
|
+
getCheckoutStatus: async (sessionId) => {
|
|
1611
|
+
const query = new URLSearchParams({ sessionId }).toString();
|
|
1612
|
+
const res = await this.client.get(`/api/dayrate/checkout-status?${query}`);
|
|
1613
|
+
return this.unwrapApiResponse(res, "Failed to get checkout status");
|
|
1319
1614
|
}
|
|
1320
1615
|
};
|
|
1321
1616
|
// Stripe Methods
|
|
@@ -1604,13 +1899,24 @@ var TokenManager = class _TokenManager {
|
|
|
1604
1899
|
s.removeItem(_TokenManager.USER_KEY);
|
|
1605
1900
|
}
|
|
1606
1901
|
}
|
|
1902
|
+
static decodePayload(token) {
|
|
1903
|
+
try {
|
|
1904
|
+
const parts = token.split(".");
|
|
1905
|
+
if (parts.length !== 3 || !parts[1]) return null;
|
|
1906
|
+
const decoded = JSON.parse(_TokenManager.base64Decode(parts[1]));
|
|
1907
|
+
if (!decoded || typeof decoded !== "object" || Array.isArray(decoded)) return null;
|
|
1908
|
+
return decoded;
|
|
1909
|
+
} catch {
|
|
1910
|
+
return null;
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1607
1913
|
static isTokenExpired(token) {
|
|
1608
1914
|
try {
|
|
1609
1915
|
const parts = token.split(".");
|
|
1610
1916
|
if (parts.length !== 3 || !parts[1]) return true;
|
|
1611
1917
|
const payload = JSON.parse(_TokenManager.base64Decode(parts[1]));
|
|
1612
1918
|
const now = Math.floor(Date.now() / 1e3);
|
|
1613
|
-
return payload.exp < now;
|
|
1919
|
+
return typeof payload?.exp !== "number" || payload.exp < now;
|
|
1614
1920
|
} catch {
|
|
1615
1921
|
return true;
|
|
1616
1922
|
}
|
|
@@ -1725,6 +2031,39 @@ var WalletUtils = class _WalletUtils {
|
|
|
1725
2031
|
}
|
|
1726
2032
|
}
|
|
1727
2033
|
};
|
|
2034
|
+
function isEnvelope(value) {
|
|
2035
|
+
if (!value || typeof value !== "object") return false;
|
|
2036
|
+
const r = value;
|
|
2037
|
+
return "success" in r && typeof r.success === "boolean";
|
|
2038
|
+
}
|
|
2039
|
+
function isSuccessEnvelope(value) {
|
|
2040
|
+
return isEnvelope(value) && value.success === true;
|
|
2041
|
+
}
|
|
2042
|
+
function isErrorEnvelope(value) {
|
|
2043
|
+
if (!isEnvelope(value) || value.success !== false) return false;
|
|
2044
|
+
const error = value.error;
|
|
2045
|
+
if (!error || typeof error !== "object") return false;
|
|
2046
|
+
const r = error;
|
|
2047
|
+
return typeof r.code === "string" && typeof r.message === "string";
|
|
2048
|
+
}
|
|
2049
|
+
function unwrapEnvelope(value, fallbackMessage) {
|
|
2050
|
+
if (!isEnvelope(value)) return value;
|
|
2051
|
+
if (value.success === false) {
|
|
2052
|
+
const message = isErrorEnvelope(value) ? value.error.message : void 0;
|
|
2053
|
+
throw new Error(message || fallbackMessage || "SPAPS request failed");
|
|
2054
|
+
}
|
|
2055
|
+
return value.data;
|
|
2056
|
+
}
|
|
2057
|
+
function unwrapNestedData(value) {
|
|
2058
|
+
if (isEnvelope(value) && value.success !== false) {
|
|
2059
|
+
const inner = value.data;
|
|
2060
|
+
if (inner && typeof inner === "object" && "data" in inner) {
|
|
2061
|
+
return inner.data;
|
|
2062
|
+
}
|
|
2063
|
+
return inner;
|
|
2064
|
+
}
|
|
2065
|
+
return value;
|
|
2066
|
+
}
|
|
1728
2067
|
function createBrowserClient(publishableKey, options) {
|
|
1729
2068
|
if (!publishableKey.startsWith("spaps_pub_")) {
|
|
1730
2069
|
console.warn("\u26A0\uFE0F SPAPS: Expected a publishable key (spaps_pub_xxx). Using a secret key in browser is not recommended.");
|
|
@@ -1759,6 +2098,7 @@ function detectKeyType(key) {
|
|
|
1759
2098
|
TokenManager,
|
|
1760
2099
|
WalletUtils,
|
|
1761
2100
|
WebSocketAuthHelper,
|
|
2101
|
+
X402PaymentRequiredSDKError,
|
|
1762
2102
|
canAccessAdmin,
|
|
1763
2103
|
createBrowserClient,
|
|
1764
2104
|
createPermissionChecker,
|
|
@@ -1771,7 +2111,14 @@ function detectKeyType(key) {
|
|
|
1771
2111
|
getUserRole,
|
|
1772
2112
|
hasPermission,
|
|
1773
2113
|
isAdminAccount,
|
|
2114
|
+
isEnvelope,
|
|
2115
|
+
isErrorEnvelope,
|
|
2116
|
+
isSuccessEnvelope,
|
|
2117
|
+
isX402PaymentRequired,
|
|
2118
|
+
isX402ResourceStatus,
|
|
1774
2119
|
secureMessageMetadataSchema,
|
|
1775
2120
|
secureMessageSchema,
|
|
2121
|
+
unwrapEnvelope,
|
|
2122
|
+
unwrapNestedData,
|
|
1776
2123
|
verifyCryptoWebhookSignature
|
|
1777
2124
|
});
|