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.mjs
CHANGED
|
@@ -488,6 +488,27 @@ function appendSupportedIssueReportScope(q, scope) {
|
|
|
488
488
|
}
|
|
489
489
|
q.append("scope", scope);
|
|
490
490
|
}
|
|
491
|
+
var ISSUE_REPORT_ATTACHMENT_ALLOWED_MIME_TYPES = [
|
|
492
|
+
"image/png",
|
|
493
|
+
"image/jpeg",
|
|
494
|
+
"image/webp"
|
|
495
|
+
];
|
|
496
|
+
var ISSUE_REPORT_ATTACHMENT_MAX_BYTES = 10 * 1024 * 1024;
|
|
497
|
+
var ISSUE_REPORT_ATTACHMENT_MAX_RETAINED = 5;
|
|
498
|
+
var ISSUE_REPORT_ATTACHMENT_ALLOWED_MIME_TYPE_SET = new Set(
|
|
499
|
+
ISSUE_REPORT_ATTACHMENT_ALLOWED_MIME_TYPES
|
|
500
|
+
);
|
|
501
|
+
function assertSupportedIssueReportAttachment(file) {
|
|
502
|
+
const mimeType = (file.type || "").trim().toLowerCase();
|
|
503
|
+
if (!ISSUE_REPORT_ATTACHMENT_ALLOWED_MIME_TYPE_SET.has(mimeType)) {
|
|
504
|
+
throw new Error(
|
|
505
|
+
"SPAPS issue report attachments must be PNG, JPEG, or WebP screenshots"
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
if (file.size > ISSUE_REPORT_ATTACHMENT_MAX_BYTES) {
|
|
509
|
+
throw new Error("SPAPS issue report attachments must be 10 MiB or smaller");
|
|
510
|
+
}
|
|
511
|
+
}
|
|
491
512
|
var X402PaymentRequiredSDKError = class extends Error {
|
|
492
513
|
paymentRequiredHeader;
|
|
493
514
|
response;
|
|
@@ -498,6 +519,148 @@ var X402PaymentRequiredSDKError = class extends Error {
|
|
|
498
519
|
this.response = response;
|
|
499
520
|
}
|
|
500
521
|
};
|
|
522
|
+
var SPAPSSDKError = class extends Error {
|
|
523
|
+
code;
|
|
524
|
+
status;
|
|
525
|
+
statusCode;
|
|
526
|
+
details;
|
|
527
|
+
requestId;
|
|
528
|
+
request_id;
|
|
529
|
+
diagnostics;
|
|
530
|
+
remediations;
|
|
531
|
+
constructor(options) {
|
|
532
|
+
super(options.message);
|
|
533
|
+
this.name = "SPAPSSDKError";
|
|
534
|
+
this.code = options.code;
|
|
535
|
+
this.status = options.status;
|
|
536
|
+
this.statusCode = options.status;
|
|
537
|
+
this.details = options.details;
|
|
538
|
+
this.requestId = options.requestId;
|
|
539
|
+
this.request_id = options.requestId;
|
|
540
|
+
this.diagnostics = options.diagnostics || [];
|
|
541
|
+
this.remediations = options.remediations || [];
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
function isObjectRecord(value) {
|
|
545
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
546
|
+
}
|
|
547
|
+
function toOptionalString(value) {
|
|
548
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
549
|
+
}
|
|
550
|
+
function toOptionalNumber(value) {
|
|
551
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
552
|
+
if (typeof value === "string" && value.trim()) {
|
|
553
|
+
const parsed = Number(value);
|
|
554
|
+
if (Number.isFinite(parsed)) return parsed;
|
|
555
|
+
}
|
|
556
|
+
return void 0;
|
|
557
|
+
}
|
|
558
|
+
function extractResponseHeader(headers, name) {
|
|
559
|
+
if (!headers || typeof headers !== "object") return void 0;
|
|
560
|
+
const getter = headers.get;
|
|
561
|
+
if (typeof getter === "function") {
|
|
562
|
+
return toOptionalString(getter.call(headers, name));
|
|
563
|
+
}
|
|
564
|
+
const normalized = name.toLowerCase();
|
|
565
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
566
|
+
if (key.toLowerCase() === normalized) {
|
|
567
|
+
return Array.isArray(value) ? toOptionalString(value[0]) : toOptionalString(value);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
return void 0;
|
|
571
|
+
}
|
|
572
|
+
function extractRequestId(payload, fallback) {
|
|
573
|
+
if (!isObjectRecord(payload)) return fallback;
|
|
574
|
+
const metadata = isObjectRecord(payload.metadata) ? payload.metadata : {};
|
|
575
|
+
return toOptionalString(payload.request_id) || toOptionalString(metadata.request_id) || fallback;
|
|
576
|
+
}
|
|
577
|
+
function normalizeDiagnostics(payload, fallbackCode, fallbackMessage, status) {
|
|
578
|
+
const raw = isObjectRecord(payload) ? payload.diagnostics : void 0;
|
|
579
|
+
const diagnostics = [];
|
|
580
|
+
if (Array.isArray(raw)) {
|
|
581
|
+
for (const item of raw) {
|
|
582
|
+
if (!isObjectRecord(item)) continue;
|
|
583
|
+
const code = toOptionalString(item.code) || fallbackCode || "request_failed";
|
|
584
|
+
const message = toOptionalString(item.message) || fallbackMessage;
|
|
585
|
+
diagnostics.push({
|
|
586
|
+
code,
|
|
587
|
+
message,
|
|
588
|
+
status: toOptionalNumber(item.status) ?? status ?? null,
|
|
589
|
+
...item.details !== void 0 ? { details: item.details } : {}
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
if (diagnostics.length > 0) {
|
|
594
|
+
return diagnostics;
|
|
595
|
+
}
|
|
596
|
+
if (fallbackCode || status !== void 0) {
|
|
597
|
+
return [
|
|
598
|
+
{
|
|
599
|
+
code: fallbackCode || `http_${status}`,
|
|
600
|
+
message: fallbackMessage,
|
|
601
|
+
status: status ?? null
|
|
602
|
+
}
|
|
603
|
+
];
|
|
604
|
+
}
|
|
605
|
+
return [];
|
|
606
|
+
}
|
|
607
|
+
function normalizeRemediations(payload) {
|
|
608
|
+
const raw = isObjectRecord(payload) ? payload.remediations : void 0;
|
|
609
|
+
if (!Array.isArray(raw)) return [];
|
|
610
|
+
const remediations = [];
|
|
611
|
+
for (const item of raw) {
|
|
612
|
+
if (!isObjectRecord(item)) continue;
|
|
613
|
+
const kind = toOptionalString(item.kind);
|
|
614
|
+
if (!kind) continue;
|
|
615
|
+
remediations.push({
|
|
616
|
+
kind,
|
|
617
|
+
...item.label === null || typeof item.label === "string" ? { label: item.label } : {},
|
|
618
|
+
...item.method === null || typeof item.method === "string" ? { method: item.method } : {},
|
|
619
|
+
...item.path === null || typeof item.path === "string" ? { path: item.path } : {},
|
|
620
|
+
...item.cli === null || typeof item.cli === "string" ? { cli: item.cli } : {},
|
|
621
|
+
...Array.isArray(item.requires) ? { requires: item.requires.filter((value) => typeof value === "string") } : {},
|
|
622
|
+
...item.details !== void 0 ? { details: item.details } : {},
|
|
623
|
+
...item.command_template === null || typeof item.command_template === "string" ? { command_template: item.command_template } : {},
|
|
624
|
+
...item.safe_to_execute === null || typeof item.safe_to_execute === "boolean" ? { safe_to_execute: item.safe_to_execute } : {},
|
|
625
|
+
...item.operator_gate_required === null || typeof item.operator_gate_required === "boolean" ? { operator_gate_required: item.operator_gate_required } : {}
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
return remediations;
|
|
629
|
+
}
|
|
630
|
+
function buildSPAPSSDKError(payload, fallback, status, requestId) {
|
|
631
|
+
const record = isObjectRecord(payload) ? payload : {};
|
|
632
|
+
const error = isObjectRecord(record.error) ? record.error : {};
|
|
633
|
+
const code = toOptionalString(error.code);
|
|
634
|
+
const message = toOptionalString(error.message) || fallback || "SPAPS request failed";
|
|
635
|
+
return new SPAPSSDKError({
|
|
636
|
+
message,
|
|
637
|
+
code,
|
|
638
|
+
status,
|
|
639
|
+
details: error.details,
|
|
640
|
+
requestId: extractRequestId(record, requestId),
|
|
641
|
+
diagnostics: normalizeDiagnostics(record, code, message, status),
|
|
642
|
+
remediations: normalizeRemediations(record)
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
function buildSPAPSSDKErrorFromAxios(error) {
|
|
646
|
+
const status = error.response?.status;
|
|
647
|
+
const requestId = extractResponseHeader(error.response?.headers, "x-request-id");
|
|
648
|
+
if (error.response) {
|
|
649
|
+
return buildSPAPSSDKError(
|
|
650
|
+
error.response.data,
|
|
651
|
+
error.message || "SPAPS request failed",
|
|
652
|
+
status,
|
|
653
|
+
requestId
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
return new SPAPSSDKError({
|
|
657
|
+
message: error.message || "SPAPS request failed",
|
|
658
|
+
code: error.code,
|
|
659
|
+
status,
|
|
660
|
+
requestId,
|
|
661
|
+
diagnostics: normalizeDiagnostics(void 0, error.code, error.message, status)
|
|
662
|
+
});
|
|
663
|
+
}
|
|
501
664
|
var SPAPSClient = class _SPAPSClient {
|
|
502
665
|
client;
|
|
503
666
|
apiKey;
|
|
@@ -509,10 +672,19 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
509
672
|
if (!response) {
|
|
510
673
|
throw new Error(fallback);
|
|
511
674
|
}
|
|
512
|
-
const
|
|
675
|
+
const axiosResponse = this.isAxiosResponse(response) ? response : void 0;
|
|
676
|
+
if (axiosResponse?.status === 204) {
|
|
677
|
+
return void 0;
|
|
678
|
+
}
|
|
679
|
+
const payload = axiosResponse ? axiosResponse.data : this.isResponseLikeWithData(response) ? response.data : response;
|
|
513
680
|
if (this.isApiResponse(payload)) {
|
|
514
681
|
if (payload.success === false) {
|
|
515
|
-
throw
|
|
682
|
+
throw buildSPAPSSDKError(
|
|
683
|
+
payload,
|
|
684
|
+
fallback,
|
|
685
|
+
axiosResponse?.status,
|
|
686
|
+
extractResponseHeader(axiosResponse?.headers, "x-request-id")
|
|
687
|
+
);
|
|
516
688
|
}
|
|
517
689
|
if (payload.data !== void 0) {
|
|
518
690
|
return payload.data;
|
|
@@ -539,6 +711,19 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
539
711
|
}
|
|
540
712
|
return userId;
|
|
541
713
|
}
|
|
714
|
+
requireAccessToken(message = "Authentication required. Please authenticate first.") {
|
|
715
|
+
if (!this.accessToken) {
|
|
716
|
+
throw new Error(message);
|
|
717
|
+
}
|
|
718
|
+
return this.accessToken;
|
|
719
|
+
}
|
|
720
|
+
authConfig(message) {
|
|
721
|
+
return {
|
|
722
|
+
headers: {
|
|
723
|
+
Authorization: `Bearer ${this.requireAccessToken(message)}`
|
|
724
|
+
}
|
|
725
|
+
};
|
|
726
|
+
}
|
|
542
727
|
isAxiosResponse(value) {
|
|
543
728
|
if (!value || typeof value !== "object") {
|
|
544
729
|
return false;
|
|
@@ -558,6 +743,41 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
558
743
|
const record = value;
|
|
559
744
|
return "success" in record && typeof record.success === "boolean";
|
|
560
745
|
}
|
|
746
|
+
static isMfaRequiredAuthResponse(value) {
|
|
747
|
+
return Boolean(value && typeof value === "object" && value.mfa_required === true);
|
|
748
|
+
}
|
|
749
|
+
normalizeAuthPayload(payload) {
|
|
750
|
+
if (_SPAPSClient.isMfaRequiredAuthResponse(payload)) {
|
|
751
|
+
return payload;
|
|
752
|
+
}
|
|
753
|
+
if (payload?.tokens && payload?.user) {
|
|
754
|
+
return {
|
|
755
|
+
access_token: payload.tokens.access_token,
|
|
756
|
+
refresh_token: payload.tokens.refresh_token,
|
|
757
|
+
expires_in: payload.tokens.expires_in,
|
|
758
|
+
token_type: payload.token_type || "Bearer",
|
|
759
|
+
user: payload.user
|
|
760
|
+
};
|
|
761
|
+
}
|
|
762
|
+
return payload;
|
|
763
|
+
}
|
|
764
|
+
storeAuthTokens(result) {
|
|
765
|
+
if (_SPAPSClient.isMfaRequiredAuthResponse(result)) {
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
if (result.access_token) {
|
|
769
|
+
this.accessToken = result.access_token;
|
|
770
|
+
}
|
|
771
|
+
if (result.refresh_token) {
|
|
772
|
+
this.refreshToken = result.refresh_token;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
unwrapAuthMethodResponse(response, fallback) {
|
|
776
|
+
const payload = this.unwrapApiResponse(response, fallback);
|
|
777
|
+
const result = this.normalizeAuthPayload(payload);
|
|
778
|
+
this.storeAuthTokens(result);
|
|
779
|
+
return result;
|
|
780
|
+
}
|
|
561
781
|
static isSdkManagedHeader(name) {
|
|
562
782
|
const normalized = name.toLowerCase();
|
|
563
783
|
return normalized === "authorization" || normalized === "x-api-key";
|
|
@@ -780,6 +1000,7 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
780
1000
|
if (typeof FormData === "undefined") {
|
|
781
1001
|
throw new Error("FormData is required to upload issue report attachments");
|
|
782
1002
|
}
|
|
1003
|
+
assertSupportedIssueReportAttachment(file);
|
|
783
1004
|
const formData = new FormData();
|
|
784
1005
|
const fileWithOptionalName = file;
|
|
785
1006
|
const inferredFilename = typeof fileWithOptionalName.name === "string" ? fileWithOptionalName.name : void 0;
|
|
@@ -986,6 +1207,203 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
986
1207
|
return this.unwrapApiResponse(res, "Failed to get app link");
|
|
987
1208
|
}
|
|
988
1209
|
};
|
|
1210
|
+
/**
|
|
1211
|
+
* Application email whitelist helpers.
|
|
1212
|
+
*
|
|
1213
|
+
* `check` is API-key scoped. Mutations and admin reads require an
|
|
1214
|
+
* authenticated admin JWT plus the configured API key.
|
|
1215
|
+
*/
|
|
1216
|
+
whitelist = {
|
|
1217
|
+
check: async (email) => {
|
|
1218
|
+
const q = new URLSearchParams({ email });
|
|
1219
|
+
const res = await this.client.get(`/api/v1/whitelist/check?${q.toString()}`);
|
|
1220
|
+
return this.unwrapApiResponse(res, "Failed to check whitelist");
|
|
1221
|
+
},
|
|
1222
|
+
add: async (payload) => {
|
|
1223
|
+
const res = await this.client.post(
|
|
1224
|
+
"/api/v1/whitelist",
|
|
1225
|
+
payload,
|
|
1226
|
+
this.authConfig("Access token is required for whitelist admin operations")
|
|
1227
|
+
);
|
|
1228
|
+
return this.unwrapApiResponse(res, "Failed to add whitelist entry");
|
|
1229
|
+
},
|
|
1230
|
+
bulkAdd: async (payload) => {
|
|
1231
|
+
const res = await this.client.post(
|
|
1232
|
+
"/api/v1/whitelist/bulk",
|
|
1233
|
+
payload,
|
|
1234
|
+
this.authConfig("Access token is required for whitelist admin operations")
|
|
1235
|
+
);
|
|
1236
|
+
return this.unwrapApiResponse(res, "Failed to bulk add whitelist entries");
|
|
1237
|
+
},
|
|
1238
|
+
list: async (params = {}) => {
|
|
1239
|
+
const q = new URLSearchParams();
|
|
1240
|
+
if (params.limit !== void 0) q.set("limit", String(params.limit));
|
|
1241
|
+
if (params.offset !== void 0) q.set("offset", String(params.offset));
|
|
1242
|
+
if (params.tier) q.set("tier", params.tier);
|
|
1243
|
+
const qs = q.toString();
|
|
1244
|
+
const res = await this.client.get(
|
|
1245
|
+
`/api/v1/whitelist${qs ? `?${qs}` : ""}`,
|
|
1246
|
+
this.authConfig("Access token is required for whitelist admin operations")
|
|
1247
|
+
);
|
|
1248
|
+
return this.unwrapApiResponse(res, "Failed to list whitelist entries");
|
|
1249
|
+
},
|
|
1250
|
+
update: async (email, payload) => {
|
|
1251
|
+
const res = await this.client.put(
|
|
1252
|
+
`/api/v1/whitelist/${encodeURIComponent(email)}`,
|
|
1253
|
+
payload,
|
|
1254
|
+
this.authConfig("Access token is required for whitelist admin operations")
|
|
1255
|
+
);
|
|
1256
|
+
return this.unwrapApiResponse(res, "Failed to update whitelist entry");
|
|
1257
|
+
},
|
|
1258
|
+
stats: async () => {
|
|
1259
|
+
const res = await this.client.get(
|
|
1260
|
+
"/api/v1/whitelist/stats",
|
|
1261
|
+
this.authConfig("Access token is required for whitelist admin operations")
|
|
1262
|
+
);
|
|
1263
|
+
return this.unwrapApiResponse(res, "Failed to get whitelist stats");
|
|
1264
|
+
},
|
|
1265
|
+
clear: async () => {
|
|
1266
|
+
const res = await this.client.delete(
|
|
1267
|
+
"/api/v1/whitelist/all",
|
|
1268
|
+
this.authConfig("Access token is required for whitelist admin operations")
|
|
1269
|
+
);
|
|
1270
|
+
return this.unwrapApiResponse(res, "Failed to clear whitelist");
|
|
1271
|
+
},
|
|
1272
|
+
remove: async (email) => {
|
|
1273
|
+
const res = await this.client.delete(
|
|
1274
|
+
`/api/v1/whitelist/${encodeURIComponent(email)}`,
|
|
1275
|
+
this.authConfig("Access token is required for whitelist admin operations")
|
|
1276
|
+
);
|
|
1277
|
+
return this.unwrapApiResponse(res, "Failed to remove whitelist entry");
|
|
1278
|
+
}
|
|
1279
|
+
};
|
|
1280
|
+
/**
|
|
1281
|
+
* User lookup and app membership administration helpers.
|
|
1282
|
+
*/
|
|
1283
|
+
users = {
|
|
1284
|
+
getEmailsBatch: async (userIds) => {
|
|
1285
|
+
const res = await this.client.post("/api/users/emails", { user_ids: userIds });
|
|
1286
|
+
return this.unwrapApiResponse(res, "Failed to get user emails");
|
|
1287
|
+
},
|
|
1288
|
+
getUsersBatch: async (userIds) => {
|
|
1289
|
+
const res = await this.client.post("/api/users/batch", { user_ids: userIds });
|
|
1290
|
+
return this.unwrapApiResponse(res, "Failed to get users");
|
|
1291
|
+
},
|
|
1292
|
+
memberships: {
|
|
1293
|
+
list: async (params = {}) => {
|
|
1294
|
+
const q = new URLSearchParams();
|
|
1295
|
+
if (params.status) q.set("status", params.status);
|
|
1296
|
+
if (params.limit !== void 0) q.set("limit", String(params.limit));
|
|
1297
|
+
if (params.offset !== void 0) q.set("offset", String(params.offset));
|
|
1298
|
+
if (params.cursor) q.set("cursor", params.cursor);
|
|
1299
|
+
const qs = q.toString();
|
|
1300
|
+
const res = await this.client.get(
|
|
1301
|
+
`/api/users/memberships${qs ? `?${qs}` : ""}`,
|
|
1302
|
+
this.authConfig("Access token is required for membership admin operations")
|
|
1303
|
+
);
|
|
1304
|
+
return this.unwrapApiResponse(res, "Failed to list memberships");
|
|
1305
|
+
},
|
|
1306
|
+
add: async (payload) => {
|
|
1307
|
+
if (!payload.user_id && !payload.email) {
|
|
1308
|
+
throw new Error("Either user_id or email is required");
|
|
1309
|
+
}
|
|
1310
|
+
const res = await this.client.post(
|
|
1311
|
+
"/api/users/memberships",
|
|
1312
|
+
payload,
|
|
1313
|
+
this.authConfig("Access token is required for membership admin operations")
|
|
1314
|
+
);
|
|
1315
|
+
return this.unwrapApiResponse(res, "Failed to add membership");
|
|
1316
|
+
},
|
|
1317
|
+
remove: async (userId) => {
|
|
1318
|
+
const res = await this.client.delete(
|
|
1319
|
+
`/api/users/memberships/${encodeURIComponent(userId)}`,
|
|
1320
|
+
this.authConfig("Access token is required for membership admin operations")
|
|
1321
|
+
);
|
|
1322
|
+
return this.unwrapApiResponse(res, "Failed to remove membership");
|
|
1323
|
+
},
|
|
1324
|
+
deleteAccount: async (userId, params = {}) => {
|
|
1325
|
+
const config = {
|
|
1326
|
+
...this.authConfig("Access token is required for user account deletion"),
|
|
1327
|
+
params
|
|
1328
|
+
};
|
|
1329
|
+
const res = await this.client.delete(
|
|
1330
|
+
`/api/users/${encodeURIComponent(userId)}`,
|
|
1331
|
+
config
|
|
1332
|
+
);
|
|
1333
|
+
return this.unwrapApiResponse(
|
|
1334
|
+
res,
|
|
1335
|
+
"Failed to delete user account"
|
|
1336
|
+
);
|
|
1337
|
+
}
|
|
1338
|
+
}
|
|
1339
|
+
};
|
|
1340
|
+
/**
|
|
1341
|
+
* Trusted-service support telemetry helpers.
|
|
1342
|
+
*
|
|
1343
|
+
* These endpoints require a secret API key. Case lifecycle patching also
|
|
1344
|
+
* requires a super-admin JWT.
|
|
1345
|
+
*/
|
|
1346
|
+
supportTelemetry = {
|
|
1347
|
+
ingestEvent: async (payload) => {
|
|
1348
|
+
const res = await this.client.post("/api/v1/support-telemetry/events", payload);
|
|
1349
|
+
return this.unwrapApiResponse(
|
|
1350
|
+
res,
|
|
1351
|
+
"Failed to ingest support telemetry event"
|
|
1352
|
+
);
|
|
1353
|
+
},
|
|
1354
|
+
listCases: async (params = {}) => {
|
|
1355
|
+
const q = new URLSearchParams();
|
|
1356
|
+
if (params.application_id) q.set("application_id", params.application_id);
|
|
1357
|
+
if (params.status) q.set("status", params.status);
|
|
1358
|
+
if (params.priority) q.set("priority", params.priority);
|
|
1359
|
+
if (params.severity_gte) q.set("severity_gte", params.severity_gte);
|
|
1360
|
+
if (params.assigned_to_user_id) q.set("assigned_to_user_id", params.assigned_to_user_id);
|
|
1361
|
+
if (params.limit !== void 0) q.set("limit", String(params.limit));
|
|
1362
|
+
if (params.offset !== void 0) q.set("offset", String(params.offset));
|
|
1363
|
+
const qs = q.toString();
|
|
1364
|
+
const res = await this.client.get(`/api/v1/support-telemetry/cases${qs ? `?${qs}` : ""}`);
|
|
1365
|
+
return this.unwrapApiResponse(
|
|
1366
|
+
res,
|
|
1367
|
+
"Failed to list support telemetry cases"
|
|
1368
|
+
);
|
|
1369
|
+
},
|
|
1370
|
+
getCase: async (caseId, params = {}) => {
|
|
1371
|
+
const q = new URLSearchParams();
|
|
1372
|
+
if (params.event_limit !== void 0) q.set("event_limit", String(params.event_limit));
|
|
1373
|
+
if (params.event_offset !== void 0) q.set("event_offset", String(params.event_offset));
|
|
1374
|
+
const qs = q.toString();
|
|
1375
|
+
const res = await this.client.get(
|
|
1376
|
+
`/api/v1/support-telemetry/cases/${encodeURIComponent(caseId)}${qs ? `?${qs}` : ""}`
|
|
1377
|
+
);
|
|
1378
|
+
return this.unwrapApiResponse(
|
|
1379
|
+
res,
|
|
1380
|
+
"Failed to get support telemetry case"
|
|
1381
|
+
);
|
|
1382
|
+
},
|
|
1383
|
+
patchCase: async (caseId, payload) => {
|
|
1384
|
+
const res = await this.client.patch(
|
|
1385
|
+
`/api/v1/support-telemetry/cases/${encodeURIComponent(caseId)}`,
|
|
1386
|
+
payload,
|
|
1387
|
+
this.authConfig("Access token is required for support telemetry case updates")
|
|
1388
|
+
);
|
|
1389
|
+
return this.unwrapApiResponse(
|
|
1390
|
+
res,
|
|
1391
|
+
"Failed to patch support telemetry case"
|
|
1392
|
+
);
|
|
1393
|
+
},
|
|
1394
|
+
getCaseByExternalRef: async (externalCaseRef, params = {}) => {
|
|
1395
|
+
const q = new URLSearchParams();
|
|
1396
|
+
if (params.application_id) q.set("application_id", params.application_id);
|
|
1397
|
+
const qs = q.toString();
|
|
1398
|
+
const res = await this.client.get(
|
|
1399
|
+
`/api/v1/support-telemetry/cases/by-external/${encodeURIComponent(externalCaseRef)}${qs ? `?${qs}` : ""}`
|
|
1400
|
+
);
|
|
1401
|
+
return this.unwrapApiResponse(
|
|
1402
|
+
res,
|
|
1403
|
+
"Failed to get support telemetry case by external ref"
|
|
1404
|
+
);
|
|
1405
|
+
}
|
|
1406
|
+
};
|
|
989
1407
|
/**
|
|
990
1408
|
* Marketing events and experiment results.
|
|
991
1409
|
*
|
|
@@ -1104,7 +1522,7 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1104
1522
|
this.refreshToken = void 0;
|
|
1105
1523
|
}
|
|
1106
1524
|
}
|
|
1107
|
-
return Promise.reject(error);
|
|
1525
|
+
return Promise.reject(buildSPAPSSDKErrorFromAxios(error));
|
|
1108
1526
|
}
|
|
1109
1527
|
);
|
|
1110
1528
|
}
|
|
@@ -1119,6 +1537,9 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1119
1537
|
const res = await this.client.request(config);
|
|
1120
1538
|
return { success: true, data: res.data };
|
|
1121
1539
|
} catch (err) {
|
|
1540
|
+
if (err instanceof SPAPSSDKError) {
|
|
1541
|
+
return Promise.reject(err);
|
|
1542
|
+
}
|
|
1122
1543
|
const message = err?.response?.data?.error?.message || err?.message || "Request failed";
|
|
1123
1544
|
return Promise.reject(new Error(message));
|
|
1124
1545
|
}
|
|
@@ -1178,8 +1599,20 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1178
1599
|
async getUser() {
|
|
1179
1600
|
return this.client.get("/api/auth/user");
|
|
1180
1601
|
}
|
|
1602
|
+
async getSessionContext() {
|
|
1603
|
+
const res = await this.client.get("/api/auth/session-context", this.authConfig());
|
|
1604
|
+
return this.unwrapApiResponse(res, "Failed to get session context");
|
|
1605
|
+
}
|
|
1181
1606
|
// -------- Facade namespaces (compat with previous SDK shape) --------
|
|
1182
1607
|
auth = {
|
|
1608
|
+
getMethods: async () => {
|
|
1609
|
+
const res = await this.client.get("/api/auth/methods");
|
|
1610
|
+
return this.unwrapApiResponse(res, "Auth method discovery failed");
|
|
1611
|
+
},
|
|
1612
|
+
getSessionContext: async () => {
|
|
1613
|
+
const res = await this.client.get("/api/auth/session-context", this.authConfig());
|
|
1614
|
+
return this.unwrapApiResponse(res, "Failed to get session context");
|
|
1615
|
+
},
|
|
1183
1616
|
/**
|
|
1184
1617
|
* Verify magic link token without mutating token state.
|
|
1185
1618
|
* Returns a simple success object from the API.
|
|
@@ -1192,12 +1625,7 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1192
1625
|
},
|
|
1193
1626
|
signInWithWallet: async (req) => {
|
|
1194
1627
|
const res = await this.client.post("/api/auth/wallet-sign-in", req);
|
|
1195
|
-
|
|
1196
|
-
if (body?.success === false) throw new Error(body?.error?.message || "Wallet sign-in failed");
|
|
1197
|
-
const data = body?.data ?? body;
|
|
1198
|
-
this.accessToken = data.access_token;
|
|
1199
|
-
this.refreshToken = data.refresh_token;
|
|
1200
|
-
return data;
|
|
1628
|
+
return this.unwrapAuthMethodResponse(res, "Wallet sign-in failed");
|
|
1201
1629
|
},
|
|
1202
1630
|
authenticateWallet: async (walletAddress, signFn, chainType, username) => {
|
|
1203
1631
|
const nonce = await this.auth.getNonce(walletAddress);
|
|
@@ -1206,12 +1634,11 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1206
1634
|
},
|
|
1207
1635
|
signInWithPassword: async (payload) => {
|
|
1208
1636
|
const res = await this.client.post("/api/auth/login", payload);
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
this.
|
|
1214
|
-
return data;
|
|
1637
|
+
return this.unwrapAuthMethodResponse(res, "Login failed");
|
|
1638
|
+
},
|
|
1639
|
+
login: async (payload) => {
|
|
1640
|
+
const res = await this.client.post("/api/auth/login", payload);
|
|
1641
|
+
return this.unwrapAuthMethodResponse(res, "Login failed");
|
|
1215
1642
|
},
|
|
1216
1643
|
requestMagicLink: async (payload) => {
|
|
1217
1644
|
await this.client.post("/api/auth/magic-link", payload);
|
|
@@ -1233,6 +1660,20 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1233
1660
|
if (body?.success === false) throw new Error(body?.error?.message || "Set password failed");
|
|
1234
1661
|
return { message: body?.message || "Password updated successfully" };
|
|
1235
1662
|
},
|
|
1663
|
+
deleteCurrentAccount: async (payload) => {
|
|
1664
|
+
const config = {
|
|
1665
|
+
...this.authConfig("Access token is required to delete the current account"),
|
|
1666
|
+
data: payload
|
|
1667
|
+
};
|
|
1668
|
+
const res = await this.client.delete("/api/auth/me", config);
|
|
1669
|
+
const result = this.unwrapApiResponse(
|
|
1670
|
+
res,
|
|
1671
|
+
"Failed to delete current account"
|
|
1672
|
+
);
|
|
1673
|
+
this.accessToken = void 0;
|
|
1674
|
+
this.refreshToken = void 0;
|
|
1675
|
+
return result;
|
|
1676
|
+
},
|
|
1236
1677
|
register: async (payload) => {
|
|
1237
1678
|
const res = await this.client.post("/api/auth/register", payload);
|
|
1238
1679
|
const body = res.data;
|
|
@@ -1249,18 +1690,71 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1249
1690
|
verifyMagicLink: async (payload) => {
|
|
1250
1691
|
const res = await this.client.post("/api/auth/verify-magic-link", {
|
|
1251
1692
|
token: payload.token,
|
|
1252
|
-
type: payload.type || "magiclink"
|
|
1693
|
+
type: payload.type || "magiclink",
|
|
1694
|
+
...payload.state ? { state: payload.state } : {}
|
|
1253
1695
|
});
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1696
|
+
return this.unwrapAuthMethodResponse(res, "Magic link verification failed");
|
|
1697
|
+
},
|
|
1698
|
+
oidc: {
|
|
1699
|
+
getNonce: async () => {
|
|
1700
|
+
const res = await this.client.post("/api/auth/oidc/nonce");
|
|
1701
|
+
return this.unwrapApiResponse(res, "OIDC nonce request failed");
|
|
1702
|
+
},
|
|
1703
|
+
signIn: async (payload) => {
|
|
1704
|
+
const res = await this.client.post("/api/auth/oidc/sign-in", payload);
|
|
1705
|
+
return this.unwrapAuthMethodResponse(res, "OIDC sign-in failed");
|
|
1706
|
+
}
|
|
1707
|
+
},
|
|
1708
|
+
webauthn: {
|
|
1709
|
+
registerOptions: async () => {
|
|
1710
|
+
const res = await this.client.post("/api/auth/webauthn/register/options");
|
|
1711
|
+
return this.unwrapApiResponse(res, "WebAuthn registration options failed");
|
|
1712
|
+
},
|
|
1713
|
+
registerVerify: async (payload) => {
|
|
1714
|
+
const res = await this.client.post("/api/auth/webauthn/register/verify", payload);
|
|
1715
|
+
return this.unwrapApiResponse(
|
|
1716
|
+
res,
|
|
1717
|
+
"WebAuthn registration verification failed"
|
|
1718
|
+
);
|
|
1719
|
+
},
|
|
1720
|
+
assertionOptions: async (payload) => {
|
|
1721
|
+
const res = await this.client.post("/api/auth/webauthn/assertion/options", payload ?? {});
|
|
1722
|
+
return this.unwrapApiResponse(res, "WebAuthn assertion options failed");
|
|
1723
|
+
},
|
|
1724
|
+
assertionVerify: async (payload) => {
|
|
1725
|
+
const res = await this.client.post("/api/auth/webauthn/assertion/verify", payload);
|
|
1726
|
+
return this.unwrapAuthMethodResponse(res, "WebAuthn assertion verification failed");
|
|
1727
|
+
}
|
|
1728
|
+
},
|
|
1729
|
+
mfa: {
|
|
1730
|
+
totp: {
|
|
1731
|
+
enroll: async () => {
|
|
1732
|
+
const res = await this.client.post("/api/auth/mfa/totp/enroll");
|
|
1733
|
+
return this.unwrapApiResponse(res, "MFA TOTP enrollment failed");
|
|
1734
|
+
},
|
|
1735
|
+
activate: async (payload) => {
|
|
1736
|
+
const res = await this.client.post("/api/auth/mfa/totp/activate", payload);
|
|
1737
|
+
return this.unwrapApiResponse(res, "MFA TOTP activation failed");
|
|
1738
|
+
},
|
|
1739
|
+
disable: async (payload) => {
|
|
1740
|
+
const res = await this.client.post("/api/auth/mfa/totp/disable", payload);
|
|
1741
|
+
return this.unwrapApiResponse(res, "MFA TOTP disable failed");
|
|
1742
|
+
}
|
|
1743
|
+
},
|
|
1744
|
+
verify: async (payload) => {
|
|
1745
|
+
const res = await this.client.post("/api/auth/mfa/verify", payload);
|
|
1746
|
+
return this.unwrapAuthMethodResponse(res, "MFA verification failed");
|
|
1747
|
+
}
|
|
1748
|
+
},
|
|
1749
|
+
sms: {
|
|
1750
|
+
request: async (payload) => {
|
|
1751
|
+
const res = await this.client.post("/api/auth/sms/request", payload);
|
|
1752
|
+
return this.unwrapApiResponse(res, "SMS OTP request failed");
|
|
1753
|
+
},
|
|
1754
|
+
verify: async (payload) => {
|
|
1755
|
+
const res = await this.client.post("/api/auth/sms/verify", payload);
|
|
1756
|
+
return this.unwrapAuthMethodResponse(res, "SMS OTP verification failed");
|
|
1757
|
+
}
|
|
1264
1758
|
},
|
|
1265
1759
|
solana: {
|
|
1266
1760
|
linkWallet: async (payload) => {
|
|
@@ -1892,6 +2386,92 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
1892
2386
|
return this.unwrapApiResponse(res, "Failed to list usage history");
|
|
1893
2387
|
}
|
|
1894
2388
|
};
|
|
2389
|
+
/**
|
|
2390
|
+
* Agent-oriented access decisions and action preparation.
|
|
2391
|
+
*
|
|
2392
|
+
* `check` intentionally resolves for denied decisions; inspect
|
|
2393
|
+
* `allowed`, `outcome`, and `next_actions` to decide what to do next.
|
|
2394
|
+
*/
|
|
2395
|
+
access = {
|
|
2396
|
+
check: async (payload) => {
|
|
2397
|
+
const res = await this.client.post("/api/access/decide", payload);
|
|
2398
|
+
return this.unwrapApiResponse(res, "Failed to check access");
|
|
2399
|
+
},
|
|
2400
|
+
decide: async (payload) => {
|
|
2401
|
+
const res = await this.client.post("/api/access/decide", payload);
|
|
2402
|
+
return this.unwrapApiResponse(res, "Failed to decide access");
|
|
2403
|
+
},
|
|
2404
|
+
prepareAction: async (payload) => {
|
|
2405
|
+
const res = await this.client.post("/api/actions/prepare", payload);
|
|
2406
|
+
return this.unwrapApiResponse(res, "Failed to prepare action");
|
|
2407
|
+
},
|
|
2408
|
+
getDecision: async (decisionTraceId) => {
|
|
2409
|
+
const res = await this.client.get(`/api/access/decisions/${encodeURIComponent(decisionTraceId)}`);
|
|
2410
|
+
return this.unwrapApiResponse(res, "Failed to get access decision");
|
|
2411
|
+
},
|
|
2412
|
+
explain: async (decisionTraceId) => {
|
|
2413
|
+
const res = await this.client.get(`/api/graph/explain/${encodeURIComponent(decisionTraceId)}`);
|
|
2414
|
+
return this.unwrapApiResponse(res, "Failed to explain access decision");
|
|
2415
|
+
}
|
|
2416
|
+
};
|
|
2417
|
+
/**
|
|
2418
|
+
* Capability graph inspection helpers. These require a secret key.
|
|
2419
|
+
*/
|
|
2420
|
+
graph = {
|
|
2421
|
+
listNodes: async (query = {}) => {
|
|
2422
|
+
const params = new URLSearchParams();
|
|
2423
|
+
if (query.node_type) params.set("node_type", query.node_type);
|
|
2424
|
+
if (query.status) params.set("status", query.status);
|
|
2425
|
+
if (query.q) params.set("q", query.q);
|
|
2426
|
+
if (query.cursor) params.set("cursor", query.cursor);
|
|
2427
|
+
if (query.limit !== void 0) params.set("limit", String(query.limit));
|
|
2428
|
+
if (query.application_id) params.set("application_id", query.application_id);
|
|
2429
|
+
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
2430
|
+
const res = await this.client.get(`/api/graph/nodes${suffix}`);
|
|
2431
|
+
return this.unwrapApiResponse(res, "Failed to list capability graph nodes");
|
|
2432
|
+
},
|
|
2433
|
+
getPaths: async (query) => {
|
|
2434
|
+
const params = new URLSearchParams();
|
|
2435
|
+
params.set("from_node_key", query.from_node_key);
|
|
2436
|
+
params.set("to_node_key", query.to_node_key);
|
|
2437
|
+
if (query.max_depth !== void 0) params.set("max_depth", String(query.max_depth));
|
|
2438
|
+
if (query.limit !== void 0) params.set("limit", String(query.limit));
|
|
2439
|
+
if (query.include_stale !== void 0) params.set("include_stale", String(query.include_stale));
|
|
2440
|
+
if (query.application_id) params.set("application_id", query.application_id);
|
|
2441
|
+
const res = await this.client.get(`/api/graph/paths?${params.toString()}`);
|
|
2442
|
+
return this.unwrapApiResponse(res, "Failed to get capability graph paths");
|
|
2443
|
+
},
|
|
2444
|
+
getImpact: async (query) => {
|
|
2445
|
+
const params = new URLSearchParams();
|
|
2446
|
+
params.set("node_key", query.node_key);
|
|
2447
|
+
if (query.max_depth !== void 0) params.set("max_depth", String(query.max_depth));
|
|
2448
|
+
if (query.limit !== void 0) params.set("limit", String(query.limit));
|
|
2449
|
+
if (query.include_stale !== void 0) params.set("include_stale", String(query.include_stale));
|
|
2450
|
+
if (query.application_id) params.set("application_id", query.application_id);
|
|
2451
|
+
const res = await this.client.get(`/api/graph/impact?${params.toString()}`);
|
|
2452
|
+
return this.unwrapApiResponse(res, "Failed to get capability graph impact");
|
|
2453
|
+
},
|
|
2454
|
+
explain: async (decisionTraceId) => {
|
|
2455
|
+
return this.access.explain(decisionTraceId);
|
|
2456
|
+
},
|
|
2457
|
+
refresh: async (correlationId, applicationId) => {
|
|
2458
|
+
const params = new URLSearchParams();
|
|
2459
|
+
if (correlationId) params.set("correlation_id", correlationId);
|
|
2460
|
+
if (applicationId) params.set("application_id", applicationId);
|
|
2461
|
+
const suffix = params.toString() ? `?${params.toString()}` : "";
|
|
2462
|
+
const res = await this.client.post(`/api/graph/refresh${suffix}`);
|
|
2463
|
+
return this.unwrapApiResponse(res, "Failed to refresh capability graph");
|
|
2464
|
+
}
|
|
2465
|
+
};
|
|
2466
|
+
/**
|
|
2467
|
+
* Machine-readable capability graph contract for agents and SDK adapters.
|
|
2468
|
+
*/
|
|
2469
|
+
contract = {
|
|
2470
|
+
get: async () => {
|
|
2471
|
+
const res = await this.client.get("/api/contract");
|
|
2472
|
+
return this.unwrapApiResponse(res, "Failed to get capability graph contract");
|
|
2473
|
+
}
|
|
2474
|
+
};
|
|
1895
2475
|
// Stripe Methods
|
|
1896
2476
|
async createCheckoutSession(priceId, successUrl, cancelUrl) {
|
|
1897
2477
|
return this.client.post("/api/stripe/checkout-sessions", {
|
|
@@ -2028,11 +2608,12 @@ var SPAPSClient = class _SPAPSClient {
|
|
|
2028
2608
|
if (!this.accessToken) {
|
|
2029
2609
|
throw new Error("Authentication required. Please authenticate first.");
|
|
2030
2610
|
}
|
|
2031
|
-
|
|
2611
|
+
const res = await this.client.delete(`/api/stripe/products/${productId}`, {
|
|
2032
2612
|
headers: {
|
|
2033
2613
|
"Authorization": `Bearer ${this.accessToken}`
|
|
2034
2614
|
}
|
|
2035
2615
|
});
|
|
2616
|
+
return this.unwrapApiResponse(res, "Failed to archive product");
|
|
2036
2617
|
}
|
|
2037
2618
|
/**
|
|
2038
2619
|
* Create a new price for a product (Admin required)
|
|
@@ -2344,8 +2925,7 @@ function isErrorEnvelope(value) {
|
|
|
2344
2925
|
function unwrapEnvelope(value, fallbackMessage) {
|
|
2345
2926
|
if (!isEnvelope(value)) return value;
|
|
2346
2927
|
if (value.success === false) {
|
|
2347
|
-
|
|
2348
|
-
throw new Error(message || fallbackMessage || "SPAPS request failed");
|
|
2928
|
+
throw buildSPAPSSDKError(value, fallbackMessage || "SPAPS request failed");
|
|
2349
2929
|
}
|
|
2350
2930
|
return value.data;
|
|
2351
2931
|
}
|
|
@@ -2385,10 +2965,14 @@ function detectKeyType(key) {
|
|
|
2385
2965
|
export {
|
|
2386
2966
|
DEFAULT_ADMIN_ACCOUNTS,
|
|
2387
2967
|
FeatureEvaluator,
|
|
2968
|
+
ISSUE_REPORT_ATTACHMENT_ALLOWED_MIME_TYPES,
|
|
2969
|
+
ISSUE_REPORT_ATTACHMENT_MAX_BYTES,
|
|
2970
|
+
ISSUE_REPORT_ATTACHMENT_MAX_RETAINED,
|
|
2388
2971
|
PermissionChecker,
|
|
2389
2972
|
RoleHierarchy,
|
|
2390
2973
|
SPAPSClient as SPAPS,
|
|
2391
2974
|
SPAPSClient,
|
|
2975
|
+
SPAPSSDKError,
|
|
2392
2976
|
TokenManager,
|
|
2393
2977
|
WalletUtils,
|
|
2394
2978
|
WebSocketAuthHelper,
|