spaps-sdk 1.12.0 → 1.13.1

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/dist/index.js CHANGED
@@ -203,6 +203,7 @@ __export(index_exports, {
203
203
  RoleHierarchy: () => RoleHierarchy,
204
204
  SPAPS: () => SPAPSClient,
205
205
  SPAPSClient: () => SPAPSClient,
206
+ SPAPSSDKError: () => SPAPSSDKError,
206
207
  TokenManager: () => TokenManager,
207
208
  WalletUtils: () => WalletUtils,
208
209
  WebSocketAuthHelper: () => WebSocketAuthHelper,
@@ -557,6 +558,148 @@ var X402PaymentRequiredSDKError = class extends Error {
557
558
  this.response = response;
558
559
  }
559
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
+ }
560
703
  var SPAPSClient = class _SPAPSClient {
561
704
  client;
562
705
  apiKey;
@@ -568,10 +711,19 @@ var SPAPSClient = class _SPAPSClient {
568
711
  if (!response) {
569
712
  throw new Error(fallback);
570
713
  }
571
- const payload = this.isAxiosResponse(response) ? response.data : this.isResponseLikeWithData(response) ? response.data : response;
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;
572
719
  if (this.isApiResponse(payload)) {
573
720
  if (payload.success === false) {
574
- throw new Error(payload.error?.message || fallback);
721
+ throw buildSPAPSSDKError(
722
+ payload,
723
+ fallback,
724
+ axiosResponse?.status,
725
+ extractResponseHeader(axiosResponse?.headers, "x-request-id")
726
+ );
575
727
  }
576
728
  if (payload.data !== void 0) {
577
729
  return payload.data;
@@ -598,6 +750,19 @@ var SPAPSClient = class _SPAPSClient {
598
750
  }
599
751
  return userId;
600
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
+ }
601
766
  isAxiosResponse(value) {
602
767
  if (!value || typeof value !== "object") {
603
768
  return false;
@@ -617,6 +782,41 @@ var SPAPSClient = class _SPAPSClient {
617
782
  const record = value;
618
783
  return "success" in record && typeof record.success === "boolean";
619
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
+ }
620
820
  static isSdkManagedHeader(name) {
621
821
  const normalized = name.toLowerCase();
622
822
  return normalized === "authorization" || normalized === "x-api-key";
@@ -1046,6 +1246,203 @@ var SPAPSClient = class _SPAPSClient {
1046
1246
  return this.unwrapApiResponse(res, "Failed to get app link");
1047
1247
  }
1048
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
+ };
1049
1446
  /**
1050
1447
  * Marketing events and experiment results.
1051
1448
  *
@@ -1164,7 +1561,7 @@ var SPAPSClient = class _SPAPSClient {
1164
1561
  this.refreshToken = void 0;
1165
1562
  }
1166
1563
  }
1167
- return Promise.reject(error);
1564
+ return Promise.reject(buildSPAPSSDKErrorFromAxios(error));
1168
1565
  }
1169
1566
  );
1170
1567
  }
@@ -1179,6 +1576,9 @@ var SPAPSClient = class _SPAPSClient {
1179
1576
  const res = await this.client.request(config);
1180
1577
  return { success: true, data: res.data };
1181
1578
  } catch (err) {
1579
+ if (err instanceof SPAPSSDKError) {
1580
+ return Promise.reject(err);
1581
+ }
1182
1582
  const message = err?.response?.data?.error?.message || err?.message || "Request failed";
1183
1583
  return Promise.reject(new Error(message));
1184
1584
  }
@@ -1238,8 +1638,20 @@ var SPAPSClient = class _SPAPSClient {
1238
1638
  async getUser() {
1239
1639
  return this.client.get("/api/auth/user");
1240
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
+ }
1241
1645
  // -------- Facade namespaces (compat with previous SDK shape) --------
1242
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
+ },
1243
1655
  /**
1244
1656
  * Verify magic link token without mutating token state.
1245
1657
  * Returns a simple success object from the API.
@@ -1252,12 +1664,7 @@ var SPAPSClient = class _SPAPSClient {
1252
1664
  },
1253
1665
  signInWithWallet: async (req) => {
1254
1666
  const res = await this.client.post("/api/auth/wallet-sign-in", req);
1255
- const body = res.data;
1256
- if (body?.success === false) throw new Error(body?.error?.message || "Wallet sign-in failed");
1257
- const data = body?.data ?? body;
1258
- this.accessToken = data.access_token;
1259
- this.refreshToken = data.refresh_token;
1260
- return data;
1667
+ return this.unwrapAuthMethodResponse(res, "Wallet sign-in failed");
1261
1668
  },
1262
1669
  authenticateWallet: async (walletAddress, signFn, chainType, username) => {
1263
1670
  const nonce = await this.auth.getNonce(walletAddress);
@@ -1266,12 +1673,11 @@ var SPAPSClient = class _SPAPSClient {
1266
1673
  },
1267
1674
  signInWithPassword: async (payload) => {
1268
1675
  const res = await this.client.post("/api/auth/login", payload);
1269
- const body = res.data;
1270
- if (body?.success === false) throw new Error(body?.error?.message || "Login failed");
1271
- const data = body?.data ?? body;
1272
- this.accessToken = data.access_token;
1273
- this.refreshToken = data.refresh_token;
1274
- 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");
1275
1681
  },
1276
1682
  requestMagicLink: async (payload) => {
1277
1683
  await this.client.post("/api/auth/magic-link", payload);
@@ -1293,6 +1699,20 @@ var SPAPSClient = class _SPAPSClient {
1293
1699
  if (body?.success === false) throw new Error(body?.error?.message || "Set password failed");
1294
1700
  return { message: body?.message || "Password updated successfully" };
1295
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
+ },
1296
1716
  register: async (payload) => {
1297
1717
  const res = await this.client.post("/api/auth/register", payload);
1298
1718
  const body = res.data;
@@ -1309,18 +1729,71 @@ var SPAPSClient = class _SPAPSClient {
1309
1729
  verifyMagicLink: async (payload) => {
1310
1730
  const res = await this.client.post("/api/auth/verify-magic-link", {
1311
1731
  token: payload.token,
1312
- type: payload.type || "magiclink"
1732
+ type: payload.type || "magiclink",
1733
+ ...payload.state ? { state: payload.state } : {}
1313
1734
  });
1314
- const body = res.data;
1315
- if (body?.success === false) throw new Error(body?.error?.message || "Magic link verification failed");
1316
- const data = {
1317
- access_token: body.tokens?.access_token || body.access_token,
1318
- refresh_token: body.tokens?.refresh_token || body.refresh_token,
1319
- user: body.user
1320
- };
1321
- this.accessToken = data.access_token;
1322
- this.refreshToken = data.refresh_token;
1323
- return data;
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
+ }
1324
1797
  },
1325
1798
  solana: {
1326
1799
  linkWallet: async (payload) => {
@@ -1952,6 +2425,92 @@ var SPAPSClient = class _SPAPSClient {
1952
2425
  return this.unwrapApiResponse(res, "Failed to list usage history");
1953
2426
  }
1954
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
+ };
1955
2514
  // Stripe Methods
1956
2515
  async createCheckoutSession(priceId, successUrl, cancelUrl) {
1957
2516
  return this.client.post("/api/stripe/checkout-sessions", {
@@ -2088,11 +2647,12 @@ var SPAPSClient = class _SPAPSClient {
2088
2647
  if (!this.accessToken) {
2089
2648
  throw new Error("Authentication required. Please authenticate first.");
2090
2649
  }
2091
- return this.client.delete(`/api/stripe/products/${productId}`, {
2650
+ const res = await this.client.delete(`/api/stripe/products/${productId}`, {
2092
2651
  headers: {
2093
2652
  "Authorization": `Bearer ${this.accessToken}`
2094
2653
  }
2095
2654
  });
2655
+ return this.unwrapApiResponse(res, "Failed to archive product");
2096
2656
  }
2097
2657
  /**
2098
2658
  * Create a new price for a product (Admin required)
@@ -2404,8 +2964,7 @@ function isErrorEnvelope(value) {
2404
2964
  function unwrapEnvelope(value, fallbackMessage) {
2405
2965
  if (!isEnvelope(value)) return value;
2406
2966
  if (value.success === false) {
2407
- const message = isErrorEnvelope(value) ? value.error.message : void 0;
2408
- throw new Error(message || fallbackMessage || "SPAPS request failed");
2967
+ throw buildSPAPSSDKError(value, fallbackMessage || "SPAPS request failed");
2409
2968
  }
2410
2969
  return value.data;
2411
2970
  }
@@ -2453,6 +3012,7 @@ function detectKeyType(key) {
2453
3012
  RoleHierarchy,
2454
3013
  SPAPS,
2455
3014
  SPAPSClient,
3015
+ SPAPSSDKError,
2456
3016
  TokenManager,
2457
3017
  WalletUtils,
2458
3018
  WebSocketAuthHelper,