spaps-sdk 1.11.0 → 1.13.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 +20 -0
- package/README.md +177 -9
- package/dist/index.d.mts +808 -35
- package/dist/index.d.ts +808 -35
- package/dist/index.js +617 -29
- package/dist/index.mjs +613 -29
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -196,10 +196,14 @@ var index_exports = {};
|
|
|
196
196
|
__export(index_exports, {
|
|
197
197
|
DEFAULT_ADMIN_ACCOUNTS: () => DEFAULT_ADMIN_ACCOUNTS,
|
|
198
198
|
FeatureEvaluator: () => FeatureEvaluator,
|
|
199
|
+
ISSUE_REPORT_ATTACHMENT_ALLOWED_MIME_TYPES: () => ISSUE_REPORT_ATTACHMENT_ALLOWED_MIME_TYPES,
|
|
200
|
+
ISSUE_REPORT_ATTACHMENT_MAX_BYTES: () => ISSUE_REPORT_ATTACHMENT_MAX_BYTES,
|
|
201
|
+
ISSUE_REPORT_ATTACHMENT_MAX_RETAINED: () => ISSUE_REPORT_ATTACHMENT_MAX_RETAINED,
|
|
199
202
|
PermissionChecker: () => PermissionChecker,
|
|
200
203
|
RoleHierarchy: () => RoleHierarchy,
|
|
201
204
|
SPAPS: () => SPAPSClient,
|
|
202
205
|
SPAPSClient: () => SPAPSClient,
|
|
206
|
+
SPAPSSDKError: () => SPAPSSDKError,
|
|
203
207
|
TokenManager: () => TokenManager,
|
|
204
208
|
WalletUtils: () => WalletUtils,
|
|
205
209
|
WebSocketAuthHelper: () => WebSocketAuthHelper,
|
|
@@ -523,6 +527,27 @@ function appendSupportedIssueReportScope(q, scope) {
|
|
|
523
527
|
}
|
|
524
528
|
q.append("scope", scope);
|
|
525
529
|
}
|
|
530
|
+
var ISSUE_REPORT_ATTACHMENT_ALLOWED_MIME_TYPES = [
|
|
531
|
+
"image/png",
|
|
532
|
+
"image/jpeg",
|
|
533
|
+
"image/webp"
|
|
534
|
+
];
|
|
535
|
+
var ISSUE_REPORT_ATTACHMENT_MAX_BYTES = 10 * 1024 * 1024;
|
|
536
|
+
var ISSUE_REPORT_ATTACHMENT_MAX_RETAINED = 5;
|
|
537
|
+
var ISSUE_REPORT_ATTACHMENT_ALLOWED_MIME_TYPE_SET = new Set(
|
|
538
|
+
ISSUE_REPORT_ATTACHMENT_ALLOWED_MIME_TYPES
|
|
539
|
+
);
|
|
540
|
+
function assertSupportedIssueReportAttachment(file) {
|
|
541
|
+
const mimeType = (file.type || "").trim().toLowerCase();
|
|
542
|
+
if (!ISSUE_REPORT_ATTACHMENT_ALLOWED_MIME_TYPE_SET.has(mimeType)) {
|
|
543
|
+
throw new Error(
|
|
544
|
+
"SPAPS issue report attachments must be PNG, JPEG, or WebP screenshots"
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
if (file.size > ISSUE_REPORT_ATTACHMENT_MAX_BYTES) {
|
|
548
|
+
throw new Error("SPAPS issue report attachments must be 10 MiB or smaller");
|
|
549
|
+
}
|
|
550
|
+
}
|
|
526
551
|
var X402PaymentRequiredSDKError = class extends Error {
|
|
527
552
|
paymentRequiredHeader;
|
|
528
553
|
response;
|
|
@@ -533,6 +558,148 @@ var X402PaymentRequiredSDKError = class extends Error {
|
|
|
533
558
|
this.response = response;
|
|
534
559
|
}
|
|
535
560
|
};
|
|
561
|
+
var SPAPSSDKError = class extends Error {
|
|
562
|
+
code;
|
|
563
|
+
status;
|
|
564
|
+
statusCode;
|
|
565
|
+
details;
|
|
566
|
+
requestId;
|
|
567
|
+
request_id;
|
|
568
|
+
diagnostics;
|
|
569
|
+
remediations;
|
|
570
|
+
constructor(options) {
|
|
571
|
+
super(options.message);
|
|
572
|
+
this.name = "SPAPSSDKError";
|
|
573
|
+
this.code = options.code;
|
|
574
|
+
this.status = options.status;
|
|
575
|
+
this.statusCode = options.status;
|
|
576
|
+
this.details = options.details;
|
|
577
|
+
this.requestId = options.requestId;
|
|
578
|
+
this.request_id = options.requestId;
|
|
579
|
+
this.diagnostics = options.diagnostics || [];
|
|
580
|
+
this.remediations = options.remediations || [];
|
|
581
|
+
}
|
|
582
|
+
};
|
|
583
|
+
function isObjectRecord(value) {
|
|
584
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
585
|
+
}
|
|
586
|
+
function toOptionalString(value) {
|
|
587
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
588
|
+
}
|
|
589
|
+
function toOptionalNumber(value) {
|
|
590
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
591
|
+
if (typeof value === "string" && value.trim()) {
|
|
592
|
+
const parsed = Number(value);
|
|
593
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
594
|
+
}
|
|
595
|
+
return void 0;
|
|
596
|
+
}
|
|
597
|
+
function extractResponseHeader(headers, name) {
|
|
598
|
+
if (!headers || typeof headers !== "object") return void 0;
|
|
599
|
+
const getter = headers.get;
|
|
600
|
+
if (typeof getter === "function") {
|
|
601
|
+
return toOptionalString(getter.call(headers, name));
|
|
602
|
+
}
|
|
603
|
+
const normalized = name.toLowerCase();
|
|
604
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
605
|
+
if (key.toLowerCase() === normalized) {
|
|
606
|
+
return Array.isArray(value) ? toOptionalString(value[0]) : toOptionalString(value);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
return void 0;
|
|
610
|
+
}
|
|
611
|
+
function extractRequestId(payload, fallback) {
|
|
612
|
+
if (!isObjectRecord(payload)) return fallback;
|
|
613
|
+
const metadata = isObjectRecord(payload.metadata) ? payload.metadata : {};
|
|
614
|
+
return toOptionalString(payload.request_id) || toOptionalString(metadata.request_id) || fallback;
|
|
615
|
+
}
|
|
616
|
+
function normalizeDiagnostics(payload, fallbackCode, fallbackMessage, status) {
|
|
617
|
+
const raw = isObjectRecord(payload) ? payload.diagnostics : void 0;
|
|
618
|
+
const diagnostics = [];
|
|
619
|
+
if (Array.isArray(raw)) {
|
|
620
|
+
for (const item of raw) {
|
|
621
|
+
if (!isObjectRecord(item)) continue;
|
|
622
|
+
const code = toOptionalString(item.code) || fallbackCode || "request_failed";
|
|
623
|
+
const message = toOptionalString(item.message) || fallbackMessage;
|
|
624
|
+
diagnostics.push({
|
|
625
|
+
code,
|
|
626
|
+
message,
|
|
627
|
+
status: toOptionalNumber(item.status) ?? status ?? null,
|
|
628
|
+
...item.details !== void 0 ? { details: item.details } : {}
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
if (diagnostics.length > 0) {
|
|
633
|
+
return diagnostics;
|
|
634
|
+
}
|
|
635
|
+
if (fallbackCode || status !== void 0) {
|
|
636
|
+
return [
|
|
637
|
+
{
|
|
638
|
+
code: fallbackCode || `http_${status}`,
|
|
639
|
+
message: fallbackMessage,
|
|
640
|
+
status: status ?? null
|
|
641
|
+
}
|
|
642
|
+
];
|
|
643
|
+
}
|
|
644
|
+
return [];
|
|
645
|
+
}
|
|
646
|
+
function normalizeRemediations(payload) {
|
|
647
|
+
const raw = isObjectRecord(payload) ? payload.remediations : void 0;
|
|
648
|
+
if (!Array.isArray(raw)) return [];
|
|
649
|
+
const remediations = [];
|
|
650
|
+
for (const item of raw) {
|
|
651
|
+
if (!isObjectRecord(item)) continue;
|
|
652
|
+
const kind = toOptionalString(item.kind);
|
|
653
|
+
if (!kind) continue;
|
|
654
|
+
remediations.push({
|
|
655
|
+
kind,
|
|
656
|
+
...item.label === null || typeof item.label === "string" ? { label: item.label } : {},
|
|
657
|
+
...item.method === null || typeof item.method === "string" ? { method: item.method } : {},
|
|
658
|
+
...item.path === null || typeof item.path === "string" ? { path: item.path } : {},
|
|
659
|
+
...item.cli === null || typeof item.cli === "string" ? { cli: item.cli } : {},
|
|
660
|
+
...Array.isArray(item.requires) ? { requires: item.requires.filter((value) => typeof value === "string") } : {},
|
|
661
|
+
...item.details !== void 0 ? { details: item.details } : {},
|
|
662
|
+
...item.command_template === null || typeof item.command_template === "string" ? { command_template: item.command_template } : {},
|
|
663
|
+
...item.safe_to_execute === null || typeof item.safe_to_execute === "boolean" ? { safe_to_execute: item.safe_to_execute } : {},
|
|
664
|
+
...item.operator_gate_required === null || typeof item.operator_gate_required === "boolean" ? { operator_gate_required: item.operator_gate_required } : {}
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
return remediations;
|
|
668
|
+
}
|
|
669
|
+
function buildSPAPSSDKError(payload, fallback, status, requestId) {
|
|
670
|
+
const record = isObjectRecord(payload) ? payload : {};
|
|
671
|
+
const error = isObjectRecord(record.error) ? record.error : {};
|
|
672
|
+
const code = toOptionalString(error.code);
|
|
673
|
+
const message = toOptionalString(error.message) || fallback || "SPAPS request failed";
|
|
674
|
+
return new SPAPSSDKError({
|
|
675
|
+
message,
|
|
676
|
+
code,
|
|
677
|
+
status,
|
|
678
|
+
details: error.details,
|
|
679
|
+
requestId: extractRequestId(record, requestId),
|
|
680
|
+
diagnostics: normalizeDiagnostics(record, code, message, status),
|
|
681
|
+
remediations: normalizeRemediations(record)
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
function buildSPAPSSDKErrorFromAxios(error) {
|
|
685
|
+
const status = error.response?.status;
|
|
686
|
+
const requestId = extractResponseHeader(error.response?.headers, "x-request-id");
|
|
687
|
+
if (error.response) {
|
|
688
|
+
return buildSPAPSSDKError(
|
|
689
|
+
error.response.data,
|
|
690
|
+
error.message || "SPAPS request failed",
|
|
691
|
+
status,
|
|
692
|
+
requestId
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
return new SPAPSSDKError({
|
|
696
|
+
message: error.message || "SPAPS request failed",
|
|
697
|
+
code: error.code,
|
|
698
|
+
status,
|
|
699
|
+
requestId,
|
|
700
|
+
diagnostics: normalizeDiagnostics(void 0, error.code, error.message, status)
|
|
701
|
+
});
|
|
702
|
+
}
|
|
536
703
|
var SPAPSClient = class _SPAPSClient {
|
|
537
704
|
client;
|
|
538
705
|
apiKey;
|
|
@@ -544,10 +711,19 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
544
711
|
if (!response) {
|
|
545
712
|
throw new Error(fallback);
|
|
546
713
|
}
|
|
547
|
-
const
|
|
714
|
+
const axiosResponse = this.isAxiosResponse(response) ? response : void 0;
|
|
715
|
+
if (axiosResponse?.status === 204) {
|
|
716
|
+
return void 0;
|
|
717
|
+
}
|
|
718
|
+
const payload = axiosResponse ? axiosResponse.data : this.isResponseLikeWithData(response) ? response.data : response;
|
|
548
719
|
if (this.isApiResponse(payload)) {
|
|
549
720
|
if (payload.success === false) {
|
|
550
|
-
throw
|
|
721
|
+
throw buildSPAPSSDKError(
|
|
722
|
+
payload,
|
|
723
|
+
fallback,
|
|
724
|
+
axiosResponse?.status,
|
|
725
|
+
extractResponseHeader(axiosResponse?.headers, "x-request-id")
|
|
726
|
+
);
|
|
551
727
|
}
|
|
552
728
|
if (payload.data !== void 0) {
|
|
553
729
|
return payload.data;
|
|
@@ -574,6 +750,19 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
574
750
|
}
|
|
575
751
|
return userId;
|
|
576
752
|
}
|
|
753
|
+
requireAccessToken(message = "Authentication required. Please authenticate first.") {
|
|
754
|
+
if (!this.accessToken) {
|
|
755
|
+
throw new Error(message);
|
|
756
|
+
}
|
|
757
|
+
return this.accessToken;
|
|
758
|
+
}
|
|
759
|
+
authConfig(message) {
|
|
760
|
+
return {
|
|
761
|
+
headers: {
|
|
762
|
+
Authorization: `Bearer ${this.requireAccessToken(message)}`
|
|
763
|
+
}
|
|
764
|
+
};
|
|
765
|
+
}
|
|
577
766
|
isAxiosResponse(value) {
|
|
578
767
|
if (!value || typeof value !== "object") {
|
|
579
768
|
return false;
|
|
@@ -593,6 +782,41 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
593
782
|
const record = value;
|
|
594
783
|
return "success" in record && typeof record.success === "boolean";
|
|
595
784
|
}
|
|
785
|
+
static isMfaRequiredAuthResponse(value) {
|
|
786
|
+
return Boolean(value && typeof value === "object" && value.mfa_required === true);
|
|
787
|
+
}
|
|
788
|
+
normalizeAuthPayload(payload) {
|
|
789
|
+
if (_SPAPSClient.isMfaRequiredAuthResponse(payload)) {
|
|
790
|
+
return payload;
|
|
791
|
+
}
|
|
792
|
+
if (payload?.tokens && payload?.user) {
|
|
793
|
+
return {
|
|
794
|
+
access_token: payload.tokens.access_token,
|
|
795
|
+
refresh_token: payload.tokens.refresh_token,
|
|
796
|
+
expires_in: payload.tokens.expires_in,
|
|
797
|
+
token_type: payload.token_type || "Bearer",
|
|
798
|
+
user: payload.user
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
return payload;
|
|
802
|
+
}
|
|
803
|
+
storeAuthTokens(result) {
|
|
804
|
+
if (_SPAPSClient.isMfaRequiredAuthResponse(result)) {
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
if (result.access_token) {
|
|
808
|
+
this.accessToken = result.access_token;
|
|
809
|
+
}
|
|
810
|
+
if (result.refresh_token) {
|
|
811
|
+
this.refreshToken = result.refresh_token;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
unwrapAuthMethodResponse(response, fallback) {
|
|
815
|
+
const payload = this.unwrapApiResponse(response, fallback);
|
|
816
|
+
const result = this.normalizeAuthPayload(payload);
|
|
817
|
+
this.storeAuthTokens(result);
|
|
818
|
+
return result;
|
|
819
|
+
}
|
|
596
820
|
static isSdkManagedHeader(name) {
|
|
597
821
|
const normalized = name.toLowerCase();
|
|
598
822
|
return normalized === "authorization" || normalized === "x-api-key";
|
|
@@ -815,6 +1039,7 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
815
1039
|
if (typeof FormData === "undefined") {
|
|
816
1040
|
throw new Error("FormData is required to upload issue report attachments");
|
|
817
1041
|
}
|
|
1042
|
+
assertSupportedIssueReportAttachment(file);
|
|
818
1043
|
const formData = new FormData();
|
|
819
1044
|
const fileWithOptionalName = file;
|
|
820
1045
|
const inferredFilename = typeof fileWithOptionalName.name === "string" ? fileWithOptionalName.name : void 0;
|
|
@@ -1021,6 +1246,203 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1021
1246
|
return this.unwrapApiResponse(res, "Failed to get app link");
|
|
1022
1247
|
}
|
|
1023
1248
|
};
|
|
1249
|
+
/**
|
|
1250
|
+
* Application email whitelist helpers.
|
|
1251
|
+
*
|
|
1252
|
+
* `check` is API-key scoped. Mutations and admin reads require an
|
|
1253
|
+
* authenticated admin JWT plus the configured API key.
|
|
1254
|
+
*/
|
|
1255
|
+
whitelist = {
|
|
1256
|
+
check: async (email) => {
|
|
1257
|
+
const q = new URLSearchParams({ email });
|
|
1258
|
+
const res = await this.client.get(`/api/v1/whitelist/check?${q.toString()}`);
|
|
1259
|
+
return this.unwrapApiResponse(res, "Failed to check whitelist");
|
|
1260
|
+
},
|
|
1261
|
+
add: async (payload) => {
|
|
1262
|
+
const res = await this.client.post(
|
|
1263
|
+
"/api/v1/whitelist",
|
|
1264
|
+
payload,
|
|
1265
|
+
this.authConfig("Access token is required for whitelist admin operations")
|
|
1266
|
+
);
|
|
1267
|
+
return this.unwrapApiResponse(res, "Failed to add whitelist entry");
|
|
1268
|
+
},
|
|
1269
|
+
bulkAdd: async (payload) => {
|
|
1270
|
+
const res = await this.client.post(
|
|
1271
|
+
"/api/v1/whitelist/bulk",
|
|
1272
|
+
payload,
|
|
1273
|
+
this.authConfig("Access token is required for whitelist admin operations")
|
|
1274
|
+
);
|
|
1275
|
+
return this.unwrapApiResponse(res, "Failed to bulk add whitelist entries");
|
|
1276
|
+
},
|
|
1277
|
+
list: async (params = {}) => {
|
|
1278
|
+
const q = new URLSearchParams();
|
|
1279
|
+
if (params.limit !== void 0) q.set("limit", String(params.limit));
|
|
1280
|
+
if (params.offset !== void 0) q.set("offset", String(params.offset));
|
|
1281
|
+
if (params.tier) q.set("tier", params.tier);
|
|
1282
|
+
const qs = q.toString();
|
|
1283
|
+
const res = await this.client.get(
|
|
1284
|
+
`/api/v1/whitelist${qs ? `?${qs}` : ""}`,
|
|
1285
|
+
this.authConfig("Access token is required for whitelist admin operations")
|
|
1286
|
+
);
|
|
1287
|
+
return this.unwrapApiResponse(res, "Failed to list whitelist entries");
|
|
1288
|
+
},
|
|
1289
|
+
update: async (email, payload) => {
|
|
1290
|
+
const res = await this.client.put(
|
|
1291
|
+
`/api/v1/whitelist/${encodeURIComponent(email)}`,
|
|
1292
|
+
payload,
|
|
1293
|
+
this.authConfig("Access token is required for whitelist admin operations")
|
|
1294
|
+
);
|
|
1295
|
+
return this.unwrapApiResponse(res, "Failed to update whitelist entry");
|
|
1296
|
+
},
|
|
1297
|
+
stats: async () => {
|
|
1298
|
+
const res = await this.client.get(
|
|
1299
|
+
"/api/v1/whitelist/stats",
|
|
1300
|
+
this.authConfig("Access token is required for whitelist admin operations")
|
|
1301
|
+
);
|
|
1302
|
+
return this.unwrapApiResponse(res, "Failed to get whitelist stats");
|
|
1303
|
+
},
|
|
1304
|
+
clear: async () => {
|
|
1305
|
+
const res = await this.client.delete(
|
|
1306
|
+
"/api/v1/whitelist/all",
|
|
1307
|
+
this.authConfig("Access token is required for whitelist admin operations")
|
|
1308
|
+
);
|
|
1309
|
+
return this.unwrapApiResponse(res, "Failed to clear whitelist");
|
|
1310
|
+
},
|
|
1311
|
+
remove: async (email) => {
|
|
1312
|
+
const res = await this.client.delete(
|
|
1313
|
+
`/api/v1/whitelist/${encodeURIComponent(email)}`,
|
|
1314
|
+
this.authConfig("Access token is required for whitelist admin operations")
|
|
1315
|
+
);
|
|
1316
|
+
return this.unwrapApiResponse(res, "Failed to remove whitelist entry");
|
|
1317
|
+
}
|
|
1318
|
+
};
|
|
1319
|
+
/**
|
|
1320
|
+
* User lookup and app membership administration helpers.
|
|
1321
|
+
*/
|
|
1322
|
+
users = {
|
|
1323
|
+
getEmailsBatch: async (userIds) => {
|
|
1324
|
+
const res = await this.client.post("/api/users/emails", { user_ids: userIds });
|
|
1325
|
+
return this.unwrapApiResponse(res, "Failed to get user emails");
|
|
1326
|
+
},
|
|
1327
|
+
getUsersBatch: async (userIds) => {
|
|
1328
|
+
const res = await this.client.post("/api/users/batch", { user_ids: userIds });
|
|
1329
|
+
return this.unwrapApiResponse(res, "Failed to get users");
|
|
1330
|
+
},
|
|
1331
|
+
memberships: {
|
|
1332
|
+
list: async (params = {}) => {
|
|
1333
|
+
const q = new URLSearchParams();
|
|
1334
|
+
if (params.status) q.set("status", params.status);
|
|
1335
|
+
if (params.limit !== void 0) q.set("limit", String(params.limit));
|
|
1336
|
+
if (params.offset !== void 0) q.set("offset", String(params.offset));
|
|
1337
|
+
if (params.cursor) q.set("cursor", params.cursor);
|
|
1338
|
+
const qs = q.toString();
|
|
1339
|
+
const res = await this.client.get(
|
|
1340
|
+
`/api/users/memberships${qs ? `?${qs}` : ""}`,
|
|
1341
|
+
this.authConfig("Access token is required for membership admin operations")
|
|
1342
|
+
);
|
|
1343
|
+
return this.unwrapApiResponse(res, "Failed to list memberships");
|
|
1344
|
+
},
|
|
1345
|
+
add: async (payload) => {
|
|
1346
|
+
if (!payload.user_id && !payload.email) {
|
|
1347
|
+
throw new Error("Either user_id or email is required");
|
|
1348
|
+
}
|
|
1349
|
+
const res = await this.client.post(
|
|
1350
|
+
"/api/users/memberships",
|
|
1351
|
+
payload,
|
|
1352
|
+
this.authConfig("Access token is required for membership admin operations")
|
|
1353
|
+
);
|
|
1354
|
+
return this.unwrapApiResponse(res, "Failed to add membership");
|
|
1355
|
+
},
|
|
1356
|
+
remove: async (userId) => {
|
|
1357
|
+
const res = await this.client.delete(
|
|
1358
|
+
`/api/users/memberships/${encodeURIComponent(userId)}`,
|
|
1359
|
+
this.authConfig("Access token is required for membership admin operations")
|
|
1360
|
+
);
|
|
1361
|
+
return this.unwrapApiResponse(res, "Failed to remove membership");
|
|
1362
|
+
},
|
|
1363
|
+
deleteAccount: async (userId, params = {}) => {
|
|
1364
|
+
const config = {
|
|
1365
|
+
...this.authConfig("Access token is required for user account deletion"),
|
|
1366
|
+
params
|
|
1367
|
+
};
|
|
1368
|
+
const res = await this.client.delete(
|
|
1369
|
+
`/api/users/${encodeURIComponent(userId)}`,
|
|
1370
|
+
config
|
|
1371
|
+
);
|
|
1372
|
+
return this.unwrapApiResponse(
|
|
1373
|
+
res,
|
|
1374
|
+
"Failed to delete user account"
|
|
1375
|
+
);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
};
|
|
1379
|
+
/**
|
|
1380
|
+
* Trusted-service support telemetry helpers.
|
|
1381
|
+
*
|
|
1382
|
+
* These endpoints require a secret API key. Case lifecycle patching also
|
|
1383
|
+
* requires a super-admin JWT.
|
|
1384
|
+
*/
|
|
1385
|
+
supportTelemetry = {
|
|
1386
|
+
ingestEvent: async (payload) => {
|
|
1387
|
+
const res = await this.client.post("/api/v1/support-telemetry/events", payload);
|
|
1388
|
+
return this.unwrapApiResponse(
|
|
1389
|
+
res,
|
|
1390
|
+
"Failed to ingest support telemetry event"
|
|
1391
|
+
);
|
|
1392
|
+
},
|
|
1393
|
+
listCases: async (params = {}) => {
|
|
1394
|
+
const q = new URLSearchParams();
|
|
1395
|
+
if (params.application_id) q.set("application_id", params.application_id);
|
|
1396
|
+
if (params.status) q.set("status", params.status);
|
|
1397
|
+
if (params.priority) q.set("priority", params.priority);
|
|
1398
|
+
if (params.severity_gte) q.set("severity_gte", params.severity_gte);
|
|
1399
|
+
if (params.assigned_to_user_id) q.set("assigned_to_user_id", params.assigned_to_user_id);
|
|
1400
|
+
if (params.limit !== void 0) q.set("limit", String(params.limit));
|
|
1401
|
+
if (params.offset !== void 0) q.set("offset", String(params.offset));
|
|
1402
|
+
const qs = q.toString();
|
|
1403
|
+
const res = await this.client.get(`/api/v1/support-telemetry/cases${qs ? `?${qs}` : ""}`);
|
|
1404
|
+
return this.unwrapApiResponse(
|
|
1405
|
+
res,
|
|
1406
|
+
"Failed to list support telemetry cases"
|
|
1407
|
+
);
|
|
1408
|
+
},
|
|
1409
|
+
getCase: async (caseId, params = {}) => {
|
|
1410
|
+
const q = new URLSearchParams();
|
|
1411
|
+
if (params.event_limit !== void 0) q.set("event_limit", String(params.event_limit));
|
|
1412
|
+
if (params.event_offset !== void 0) q.set("event_offset", String(params.event_offset));
|
|
1413
|
+
const qs = q.toString();
|
|
1414
|
+
const res = await this.client.get(
|
|
1415
|
+
`/api/v1/support-telemetry/cases/${encodeURIComponent(caseId)}${qs ? `?${qs}` : ""}`
|
|
1416
|
+
);
|
|
1417
|
+
return this.unwrapApiResponse(
|
|
1418
|
+
res,
|
|
1419
|
+
"Failed to get support telemetry case"
|
|
1420
|
+
);
|
|
1421
|
+
},
|
|
1422
|
+
patchCase: async (caseId, payload) => {
|
|
1423
|
+
const res = await this.client.patch(
|
|
1424
|
+
`/api/v1/support-telemetry/cases/${encodeURIComponent(caseId)}`,
|
|
1425
|
+
payload,
|
|
1426
|
+
this.authConfig("Access token is required for support telemetry case updates")
|
|
1427
|
+
);
|
|
1428
|
+
return this.unwrapApiResponse(
|
|
1429
|
+
res,
|
|
1430
|
+
"Failed to patch support telemetry case"
|
|
1431
|
+
);
|
|
1432
|
+
},
|
|
1433
|
+
getCaseByExternalRef: async (externalCaseRef, params = {}) => {
|
|
1434
|
+
const q = new URLSearchParams();
|
|
1435
|
+
if (params.application_id) q.set("application_id", params.application_id);
|
|
1436
|
+
const qs = q.toString();
|
|
1437
|
+
const res = await this.client.get(
|
|
1438
|
+
`/api/v1/support-telemetry/cases/by-external/${encodeURIComponent(externalCaseRef)}${qs ? `?${qs}` : ""}`
|
|
1439
|
+
);
|
|
1440
|
+
return this.unwrapApiResponse(
|
|
1441
|
+
res,
|
|
1442
|
+
"Failed to get support telemetry case by external ref"
|
|
1443
|
+
);
|
|
1444
|
+
}
|
|
1445
|
+
};
|
|
1024
1446
|
/**
|
|
1025
1447
|
* Marketing events and experiment results.
|
|
1026
1448
|
*
|
|
@@ -1139,7 +1561,7 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1139
1561
|
this.refreshToken = void 0;
|
|
1140
1562
|
}
|
|
1141
1563
|
}
|
|
1142
|
-
return Promise.reject(error);
|
|
1564
|
+
return Promise.reject(buildSPAPSSDKErrorFromAxios(error));
|
|
1143
1565
|
}
|
|
1144
1566
|
);
|
|
1145
1567
|
}
|
|
@@ -1154,6 +1576,9 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1154
1576
|
const res = await this.client.request(config);
|
|
1155
1577
|
return { success: true, data: res.data };
|
|
1156
1578
|
} catch (err) {
|
|
1579
|
+
if (err instanceof SPAPSSDKError) {
|
|
1580
|
+
return Promise.reject(err);
|
|
1581
|
+
}
|
|
1157
1582
|
const message = err?.response?.data?.error?.message || err?.message || "Request failed";
|
|
1158
1583
|
return Promise.reject(new Error(message));
|
|
1159
1584
|
}
|
|
@@ -1213,8 +1638,20 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1213
1638
|
async getUser() {
|
|
1214
1639
|
return this.client.get("/api/auth/user");
|
|
1215
1640
|
}
|
|
1641
|
+
async getSessionContext() {
|
|
1642
|
+
const res = await this.client.get("/api/auth/session-context", this.authConfig());
|
|
1643
|
+
return this.unwrapApiResponse(res, "Failed to get session context");
|
|
1644
|
+
}
|
|
1216
1645
|
// -------- Facade namespaces (compat with previous SDK shape) --------
|
|
1217
1646
|
auth = {
|
|
1647
|
+
getMethods: async () => {
|
|
1648
|
+
const res = await this.client.get("/api/auth/methods");
|
|
1649
|
+
return this.unwrapApiResponse(res, "Auth method discovery failed");
|
|
1650
|
+
},
|
|
1651
|
+
getSessionContext: async () => {
|
|
1652
|
+
const res = await this.client.get("/api/auth/session-context", this.authConfig());
|
|
1653
|
+
return this.unwrapApiResponse(res, "Failed to get session context");
|
|
1654
|
+
},
|
|
1218
1655
|
/**
|
|
1219
1656
|
* Verify magic link token without mutating token state.
|
|
1220
1657
|
* Returns a simple success object from the API.
|
|
@@ -1227,12 +1664,7 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1227
1664
|
},
|
|
1228
1665
|
signInWithWallet: async (req) => {
|
|
1229
1666
|
const res = await this.client.post("/api/auth/wallet-sign-in", req);
|
|
1230
|
-
|
|
1231
|
-
if (body?.success === false) throw new Error(body?.error?.message || "Wallet sign-in failed");
|
|
1232
|
-
const data = body?.data ?? body;
|
|
1233
|
-
this.accessToken = data.access_token;
|
|
1234
|
-
this.refreshToken = data.refresh_token;
|
|
1235
|
-
return data;
|
|
1667
|
+
return this.unwrapAuthMethodResponse(res, "Wallet sign-in failed");
|
|
1236
1668
|
},
|
|
1237
1669
|
authenticateWallet: async (walletAddress, signFn, chainType, username) => {
|
|
1238
1670
|
const nonce = await this.auth.getNonce(walletAddress);
|
|
@@ -1241,12 +1673,11 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1241
1673
|
},
|
|
1242
1674
|
signInWithPassword: async (payload) => {
|
|
1243
1675
|
const res = await this.client.post("/api/auth/login", payload);
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
this.
|
|
1249
|
-
return data;
|
|
1676
|
+
return this.unwrapAuthMethodResponse(res, "Login failed");
|
|
1677
|
+
},
|
|
1678
|
+
login: async (payload) => {
|
|
1679
|
+
const res = await this.client.post("/api/auth/login", payload);
|
|
1680
|
+
return this.unwrapAuthMethodResponse(res, "Login failed");
|
|
1250
1681
|
},
|
|
1251
1682
|
requestMagicLink: async (payload) => {
|
|
1252
1683
|
await this.client.post("/api/auth/magic-link", payload);
|
|
@@ -1268,6 +1699,20 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1268
1699
|
if (body?.success === false) throw new Error(body?.error?.message || "Set password failed");
|
|
1269
1700
|
return { message: body?.message || "Password updated successfully" };
|
|
1270
1701
|
},
|
|
1702
|
+
deleteCurrentAccount: async (payload) => {
|
|
1703
|
+
const config = {
|
|
1704
|
+
...this.authConfig("Access token is required to delete the current account"),
|
|
1705
|
+
data: payload
|
|
1706
|
+
};
|
|
1707
|
+
const res = await this.client.delete("/api/auth/me", config);
|
|
1708
|
+
const result = this.unwrapApiResponse(
|
|
1709
|
+
res,
|
|
1710
|
+
"Failed to delete current account"
|
|
1711
|
+
);
|
|
1712
|
+
this.accessToken = void 0;
|
|
1713
|
+
this.refreshToken = void 0;
|
|
1714
|
+
return result;
|
|
1715
|
+
},
|
|
1271
1716
|
register: async (payload) => {
|
|
1272
1717
|
const res = await this.client.post("/api/auth/register", payload);
|
|
1273
1718
|
const body = res.data;
|
|
@@ -1284,18 +1729,71 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1284
1729
|
verifyMagicLink: async (payload) => {
|
|
1285
1730
|
const res = await this.client.post("/api/auth/verify-magic-link", {
|
|
1286
1731
|
token: payload.token,
|
|
1287
|
-
type: payload.type || "magiclink"
|
|
1732
|
+
type: payload.type || "magiclink",
|
|
1733
|
+
...payload.state ? { state: payload.state } : {}
|
|
1288
1734
|
});
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1735
|
+
return this.unwrapAuthMethodResponse(res, "Magic link verification failed");
|
|
1736
|
+
},
|
|
1737
|
+
oidc: {
|
|
1738
|
+
getNonce: async () => {
|
|
1739
|
+
const res = await this.client.post("/api/auth/oidc/nonce");
|
|
1740
|
+
return this.unwrapApiResponse(res, "OIDC nonce request failed");
|
|
1741
|
+
},
|
|
1742
|
+
signIn: async (payload) => {
|
|
1743
|
+
const res = await this.client.post("/api/auth/oidc/sign-in", payload);
|
|
1744
|
+
return this.unwrapAuthMethodResponse(res, "OIDC sign-in failed");
|
|
1745
|
+
}
|
|
1746
|
+
},
|
|
1747
|
+
webauthn: {
|
|
1748
|
+
registerOptions: async () => {
|
|
1749
|
+
const res = await this.client.post("/api/auth/webauthn/register/options");
|
|
1750
|
+
return this.unwrapApiResponse(res, "WebAuthn registration options failed");
|
|
1751
|
+
},
|
|
1752
|
+
registerVerify: async (payload) => {
|
|
1753
|
+
const res = await this.client.post("/api/auth/webauthn/register/verify", payload);
|
|
1754
|
+
return this.unwrapApiResponse(
|
|
1755
|
+
res,
|
|
1756
|
+
"WebAuthn registration verification failed"
|
|
1757
|
+
);
|
|
1758
|
+
},
|
|
1759
|
+
assertionOptions: async (payload) => {
|
|
1760
|
+
const res = await this.client.post("/api/auth/webauthn/assertion/options", payload ?? {});
|
|
1761
|
+
return this.unwrapApiResponse(res, "WebAuthn assertion options failed");
|
|
1762
|
+
},
|
|
1763
|
+
assertionVerify: async (payload) => {
|
|
1764
|
+
const res = await this.client.post("/api/auth/webauthn/assertion/verify", payload);
|
|
1765
|
+
return this.unwrapAuthMethodResponse(res, "WebAuthn assertion verification failed");
|
|
1766
|
+
}
|
|
1767
|
+
},
|
|
1768
|
+
mfa: {
|
|
1769
|
+
totp: {
|
|
1770
|
+
enroll: async () => {
|
|
1771
|
+
const res = await this.client.post("/api/auth/mfa/totp/enroll");
|
|
1772
|
+
return this.unwrapApiResponse(res, "MFA TOTP enrollment failed");
|
|
1773
|
+
},
|
|
1774
|
+
activate: async (payload) => {
|
|
1775
|
+
const res = await this.client.post("/api/auth/mfa/totp/activate", payload);
|
|
1776
|
+
return this.unwrapApiResponse(res, "MFA TOTP activation failed");
|
|
1777
|
+
},
|
|
1778
|
+
disable: async (payload) => {
|
|
1779
|
+
const res = await this.client.post("/api/auth/mfa/totp/disable", payload);
|
|
1780
|
+
return this.unwrapApiResponse(res, "MFA TOTP disable failed");
|
|
1781
|
+
}
|
|
1782
|
+
},
|
|
1783
|
+
verify: async (payload) => {
|
|
1784
|
+
const res = await this.client.post("/api/auth/mfa/verify", payload);
|
|
1785
|
+
return this.unwrapAuthMethodResponse(res, "MFA verification failed");
|
|
1786
|
+
}
|
|
1787
|
+
},
|
|
1788
|
+
sms: {
|
|
1789
|
+
request: async (payload) => {
|
|
1790
|
+
const res = await this.client.post("/api/auth/sms/request", payload);
|
|
1791
|
+
return this.unwrapApiResponse(res, "SMS OTP request failed");
|
|
1792
|
+
},
|
|
1793
|
+
verify: async (payload) => {
|
|
1794
|
+
const res = await this.client.post("/api/auth/sms/verify", payload);
|
|
1795
|
+
return this.unwrapAuthMethodResponse(res, "SMS OTP verification failed");
|
|
1796
|
+
}
|
|
1299
1797
|
},
|
|
1300
1798
|
solana: {
|
|
1301
1799
|
linkWallet: async (payload) => {
|
|
@@ -1927,6 +2425,92 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1927
2425
|
return this.unwrapApiResponse(res, "Failed to list usage history");
|
|
1928
2426
|
}
|
|
1929
2427
|
};
|
|
2428
|
+
/**
|
|
2429
|
+
* Agent-oriented access decisions and action preparation.
|
|
2430
|
+
*
|
|
2431
|
+
* `check` intentionally resolves for denied decisions; inspect
|
|
2432
|
+
* `allowed`, `outcome`, and `next_actions` to decide what to do next.
|
|
2433
|
+
*/
|
|
2434
|
+
access = {
|
|
2435
|
+
check: async (payload) => {
|
|
2436
|
+
const res = await this.client.post("/api/access/decide", payload);
|
|
2437
|
+
return this.unwrapApiResponse(res, "Failed to check access");
|
|
2438
|
+
},
|
|
2439
|
+
decide: async (payload) => {
|
|
2440
|
+
const res = await this.client.post("/api/access/decide", payload);
|
|
2441
|
+
return this.unwrapApiResponse(res, "Failed to decide access");
|
|
2442
|
+
},
|
|
2443
|
+
prepareAction: async (payload) => {
|
|
2444
|
+
const res = await this.client.post("/api/actions/prepare", payload);
|
|
2445
|
+
return this.unwrapApiResponse(res, "Failed to prepare action");
|
|
2446
|
+
},
|
|
2447
|
+
getDecision: async (decisionTraceId) => {
|
|
2448
|
+
const res = await this.client.get(`/api/access/decisions/${encodeURIComponent(decisionTraceId)}`);
|
|
2449
|
+
return this.unwrapApiResponse(res, "Failed to get access decision");
|
|
2450
|
+
},
|
|
2451
|
+
explain: async (decisionTraceId) => {
|
|
2452
|
+
const res = await this.client.get(`/api/graph/explain/${encodeURIComponent(decisionTraceId)}`);
|
|
2453
|
+
return this.unwrapApiResponse(res, "Failed to explain access decision");
|
|
2454
|
+
}
|
|
2455
|
+
};
|
|
2456
|
+
/**
|
|
2457
|
+
* Capability graph inspection helpers. These require a secret key.
|
|
2458
|
+
*/
|
|
2459
|
+
graph = {
|
|
2460
|
+
listNodes: async (query = {}) => {
|
|
2461
|
+
const params = new URLSearchParams();
|
|
2462
|
+
if (query.node_type) params.set("node_type", query.node_type);
|
|
2463
|
+
if (query.status) params.set("status", query.status);
|
|
2464
|
+
if (query.q) params.set("q", query.q);
|
|
2465
|
+
if (query.cursor) params.set("cursor", query.cursor);
|
|
2466
|
+
if (query.limit !== void 0) params.set("limit", String(query.limit));
|
|
2467
|
+
if (query.application_id) params.set("application_id", query.application_id);
|
|
2468
|
+
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
2469
|
+
const res = await this.client.get(`/api/graph/nodes${suffix}`);
|
|
2470
|
+
return this.unwrapApiResponse(res, "Failed to list capability graph nodes");
|
|
2471
|
+
},
|
|
2472
|
+
getPaths: async (query) => {
|
|
2473
|
+
const params = new URLSearchParams();
|
|
2474
|
+
params.set("from_node_key", query.from_node_key);
|
|
2475
|
+
params.set("to_node_key", query.to_node_key);
|
|
2476
|
+
if (query.max_depth !== void 0) params.set("max_depth", String(query.max_depth));
|
|
2477
|
+
if (query.limit !== void 0) params.set("limit", String(query.limit));
|
|
2478
|
+
if (query.include_stale !== void 0) params.set("include_stale", String(query.include_stale));
|
|
2479
|
+
if (query.application_id) params.set("application_id", query.application_id);
|
|
2480
|
+
const res = await this.client.get(`/api/graph/paths?${params.toString()}`);
|
|
2481
|
+
return this.unwrapApiResponse(res, "Failed to get capability graph paths");
|
|
2482
|
+
},
|
|
2483
|
+
getImpact: async (query) => {
|
|
2484
|
+
const params = new URLSearchParams();
|
|
2485
|
+
params.set("node_key", query.node_key);
|
|
2486
|
+
if (query.max_depth !== void 0) params.set("max_depth", String(query.max_depth));
|
|
2487
|
+
if (query.limit !== void 0) params.set("limit", String(query.limit));
|
|
2488
|
+
if (query.include_stale !== void 0) params.set("include_stale", String(query.include_stale));
|
|
2489
|
+
if (query.application_id) params.set("application_id", query.application_id);
|
|
2490
|
+
const res = await this.client.get(`/api/graph/impact?${params.toString()}`);
|
|
2491
|
+
return this.unwrapApiResponse(res, "Failed to get capability graph impact");
|
|
2492
|
+
},
|
|
2493
|
+
explain: async (decisionTraceId) => {
|
|
2494
|
+
return this.access.explain(decisionTraceId);
|
|
2495
|
+
},
|
|
2496
|
+
refresh: async (correlationId, applicationId) => {
|
|
2497
|
+
const params = new URLSearchParams();
|
|
2498
|
+
if (correlationId) params.set("correlation_id", correlationId);
|
|
2499
|
+
if (applicationId) params.set("application_id", applicationId);
|
|
2500
|
+
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
2501
|
+
const res = await this.client.post(`/api/graph/refresh${suffix}`);
|
|
2502
|
+
return this.unwrapApiResponse(res, "Failed to refresh capability graph");
|
|
2503
|
+
}
|
|
2504
|
+
};
|
|
2505
|
+
/**
|
|
2506
|
+
* Machine-readable capability graph contract for agents and SDK adapters.
|
|
2507
|
+
*/
|
|
2508
|
+
contract = {
|
|
2509
|
+
get: async () => {
|
|
2510
|
+
const res = await this.client.get("/api/contract");
|
|
2511
|
+
return this.unwrapApiResponse(res, "Failed to get capability graph contract");
|
|
2512
|
+
}
|
|
2513
|
+
};
|
|
1930
2514
|
// Stripe Methods
|
|
1931
2515
|
async createCheckoutSession(priceId, successUrl, cancelUrl) {
|
|
1932
2516
|
return this.client.post("/api/stripe/checkout-sessions", {
|
|
@@ -2063,11 +2647,12 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
2063
2647
|
if (!this.accessToken) {
|
|
2064
2648
|
throw new Error("Authentication required. Please authenticate first.");
|
|
2065
2649
|
}
|
|
2066
|
-
|
|
2650
|
+
const res = await this.client.delete(`/api/stripe/products/${productId}`, {
|
|
2067
2651
|
headers: {
|
|
2068
2652
|
"Authorization": `Bearer ${this.accessToken}`
|
|
2069
2653
|
}
|
|
2070
2654
|
});
|
|
2655
|
+
return this.unwrapApiResponse(res, "Failed to archive product");
|
|
2071
2656
|
}
|
|
2072
2657
|
/**
|
|
2073
2658
|
* Create a new price for a product (Admin required)
|
|
@@ -2379,8 +2964,7 @@ function isErrorEnvelope(value) {
|
|
|
2379
2964
|
function unwrapEnvelope(value, fallbackMessage) {
|
|
2380
2965
|
if (!isEnvelope(value)) return value;
|
|
2381
2966
|
if (value.success === false) {
|
|
2382
|
-
|
|
2383
|
-
throw new Error(message || fallbackMessage || "SPAPS request failed");
|
|
2967
|
+
throw buildSPAPSSDKError(value, fallbackMessage || "SPAPS request failed");
|
|
2384
2968
|
}
|
|
2385
2969
|
return value.data;
|
|
2386
2970
|
}
|
|
@@ -2421,10 +3005,14 @@ function detectKeyType(key) {
|
|
|
2421
3005
|
0 && (module.exports = {
|
|
2422
3006
|
DEFAULT_ADMIN_ACCOUNTS,
|
|
2423
3007
|
FeatureEvaluator,
|
|
3008
|
+
ISSUE_REPORT_ATTACHMENT_ALLOWED_MIME_TYPES,
|
|
3009
|
+
ISSUE_REPORT_ATTACHMENT_MAX_BYTES,
|
|
3010
|
+
ISSUE_REPORT_ATTACHMENT_MAX_RETAINED,
|
|
2424
3011
|
PermissionChecker,
|
|
2425
3012
|
RoleHierarchy,
|
|
2426
3013
|
SPAPS,
|
|
2427
3014
|
SPAPSClient,
|
|
3015
|
+
SPAPSSDKError,
|
|
2428
3016
|
TokenManager,
|
|
2429
3017
|
WalletUtils,
|
|
2430
3018
|
WebSocketAuthHelper,
|