@acosmi/sdk-ts 1.4.0 → 1.4.2

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.
@@ -10,11 +10,7 @@ var __export = (target, all) => {
10
10
  __defProp(target, name, { get: all[name], enumerable: true });
11
11
  };
12
12
 
13
- // src/types.ts
14
- function tokenSetIsExpired(t) {
15
- const expiresAt = new Date(t.expires_at).getTime();
16
- return Date.now() > expiresAt - 3e4;
17
- }
13
+ // src/models/types.ts
18
14
  function bucketInfoIsCommercial(b) {
19
15
  if (!b) return false;
20
16
  return b.bucketClass.toLowerCase() === exports.BucketClassCommercial.toLowerCase();
@@ -62,23 +58,6 @@ function parseSourcesEvent(ev) {
62
58
  }
63
59
  return { sources: wrapper.sources, session_id: wrapper.session_id };
64
60
  }
65
- function anthropicResponseTextContent(r) {
66
- const parts = [];
67
- for (const b of r.content) {
68
- if (b.type === "text" && b.text) parts.push(b.text);
69
- }
70
- return parts.join("");
71
- }
72
- function anthropicResponseThinkingContent(r) {
73
- const parts = [];
74
- for (const b of r.content) {
75
- if (b.type === "thinking" && b.thinking) parts.push(b.thinking);
76
- }
77
- return parts.join("");
78
- }
79
- function anthropicResponseToolUseBlocks(r) {
80
- return r.content.filter((b) => b.type === "tool_use");
81
- }
82
61
  function parseSettlement(ev) {
83
62
  if (ev.event !== "settled" && ev.event !== "pending_settle") {
84
63
  return null;
@@ -99,36 +78,9 @@ function parseSettlement(ev) {
99
78
  callRemaining: s.callRemaining ?? -1
100
79
  };
101
80
  }
102
- function apiResponseGetMessage(r) {
103
- return r.message ?? r.msg ?? "";
104
- }
105
- function apiResponseBusinessError(r) {
106
- if (r.code !== 0) {
107
- return new exports.BusinessError(r.code, apiResponseGetMessage(r));
108
- }
109
- return null;
110
- }
111
- function parseNotificationEvent(ev) {
112
- if (ev.type !== "event" || ev.topic !== "system") {
113
- return null;
114
- }
115
- if (ev.data == null) return null;
116
- let n;
117
- try {
118
- if (typeof ev.data === "string") {
119
- n = JSON.parse(ev.data);
120
- } else {
121
- n = ev.data;
122
- }
123
- } catch {
124
- return null;
125
- }
126
- if (!n.id) return null;
127
- return n;
128
- }
129
- exports.BucketClassCommercial = void 0; exports.BucketClassGeneric = void 0; exports.ThinkingOff = void 0; exports.ThinkingHigh = void 0; exports.ThinkingMax = void 0; exports.ThinkingHighMinMaxTokens = void 0; exports.ThinkingMaxFallbackMaxTokens = void 0; exports.ServerToolTypeWebSearch = void 0; exports.RateLimitError = void 0; exports.BusinessError = void 0; exports.OrderTerminalError = void 0; exports.ModelNotFoundError = void 0; exports.HTTPError = void 0; exports.NetworkError = void 0; exports.StreamError = void 0;
81
+ exports.BucketClassCommercial = void 0; exports.BucketClassGeneric = void 0; exports.ThinkingOff = void 0; exports.ThinkingHigh = void 0; exports.ThinkingMax = void 0; exports.ThinkingHighMinMaxTokens = void 0; exports.ThinkingMaxFallbackMaxTokens = void 0; exports.ServerToolTypeWebSearch = void 0;
130
82
  var init_types = __esm({
131
- "src/types.ts"() {
83
+ "src/models/types.ts"() {
132
84
  exports.BucketClassCommercial = "COMMERCIAL";
133
85
  exports.BucketClassGeneric = "GENERIC";
134
86
  exports.ThinkingOff = "off";
@@ -137,6 +89,13 @@ var init_types = __esm({
137
89
  exports.ThinkingHighMinMaxTokens = 32e3;
138
90
  exports.ThinkingMaxFallbackMaxTokens = 128e3;
139
91
  exports.ServerToolTypeWebSearch = "web_search_20250305";
92
+ }
93
+ });
94
+
95
+ // src/shared/errors.ts
96
+ exports.RateLimitError = void 0; exports.BusinessError = void 0; exports.OrderTerminalError = void 0; exports.ModelNotFoundError = void 0; exports.HTTPError = void 0; exports.NetworkError = void 0; exports.StreamError = void 0;
97
+ var init_errors = __esm({
98
+ "src/shared/errors.ts"() {
140
99
  exports.RateLimitError = class extends Error {
141
100
  retryAfter;
142
101
  raw;
@@ -256,7 +215,7 @@ var init_types = __esm({
256
215
  }
257
216
  });
258
217
 
259
- // src/betas.ts
218
+ // src/models/betas.ts
260
219
  function buildBetas(caps, req) {
261
220
  const betas = [];
262
221
  if (caps.supports_isp) {
@@ -303,7 +262,7 @@ function uniqueMerge(base, extra) {
303
262
  }
304
263
  var betaInterleavedThinking, betaContext1M, betaContextManagement, betaStructuredOutputs, betaAdvancedToolUse, betaEffort, betaPromptCachingScope, betaFastMode, betaRedactThinking, betaTokenEfficientTools;
305
264
  var init_betas = __esm({
306
- "src/betas.ts"() {
265
+ "src/models/betas.ts"() {
307
266
  init_types();
308
267
  betaInterleavedThinking = "interleaved-thinking-2025-05-14";
309
268
  betaContext1M = "context-1m-2025-08-07";
@@ -318,7 +277,7 @@ var init_betas = __esm({
318
277
  }
319
278
  });
320
279
 
321
- // src/adapters/anthropic.ts
280
+ // src/models/adapters/anthropic.ts
322
281
  function resolveThinkingLevel(body, req, caps) {
323
282
  const level = req.thinking?.level ?? "";
324
283
  if (level === exports.ThinkingOff) {
@@ -365,8 +324,9 @@ function resolveThinkingLevel(body, req, caps) {
365
324
  }
366
325
  exports.AnthropicAdapter = void 0;
367
326
  var init_anthropic = __esm({
368
- "src/adapters/anthropic.ts"() {
327
+ "src/models/adapters/anthropic.ts"() {
369
328
  init_types();
329
+ init_errors();
370
330
  init_betas();
371
331
  init_adapters();
372
332
  exports.AnthropicAdapter = class {
@@ -500,7 +460,7 @@ var init_anthropic = __esm({
500
460
  }
501
461
  });
502
462
 
503
- // src/adapters/openai.ts
463
+ // src/models/adapters/openai.ts
504
464
  var openai_exports = {};
505
465
  __export(openai_exports, {
506
466
  OpenAIAdapter: () => exports.OpenAIAdapter,
@@ -695,8 +655,9 @@ function newOpenAIStreamConverter() {
695
655
  }
696
656
  exports.OpenAIAdapter = void 0; var OpenAIStreamConverter;
697
657
  var init_openai = __esm({
698
- "src/adapters/openai.ts"() {
658
+ "src/models/adapters/openai.ts"() {
699
659
  init_types();
660
+ init_errors();
700
661
  init_adapters();
701
662
  exports.OpenAIAdapter = class {
702
663
  format() {
@@ -964,7 +925,7 @@ var init_openai = __esm({
964
925
  }
965
926
  });
966
927
 
967
- // src/adapters/index.ts
928
+ // src/models/adapters/index.ts
968
929
  function getAdapter(provider) {
969
930
  const a = adapterRegistry[provider.toLowerCase()];
970
931
  if (a) return a;
@@ -996,7 +957,7 @@ function getAdapterForModel(m) {
996
957
  }
997
958
  exports.ProviderFormat = void 0; var adapterRegistry, defaultOpenAIAdapter;
998
959
  var init_adapters = __esm({
999
- "src/adapters/index.ts"() {
960
+ "src/models/adapters/index.ts"() {
1000
961
  init_anthropic();
1001
962
  init_openai();
1002
963
  exports.ProviderFormat = /* @__PURE__ */ ((ProviderFormat2) => {
@@ -1013,50 +974,31 @@ var init_adapters = __esm({
1013
974
  }
1014
975
  });
1015
976
 
1016
- // src/index.ts
977
+ // src/core/client.ts
1017
978
  init_types();
1018
979
 
1019
- // src/model-helpers.ts
1020
- function modelSupportsInputModality(model, modality) {
1021
- if (!model) return false;
1022
- const mods = model.inputModalities;
1023
- if (!Array.isArray(mods)) return false;
1024
- return mods.includes(modality);
980
+ // src/auth/types.ts
981
+ function tokenSetIsExpired(t) {
982
+ const expiresAt = new Date(t.expires_at).getTime();
983
+ return Date.now() > expiresAt - 3e4;
1025
984
  }
1026
- function modelSupportsImageInput(model) {
1027
- return modelSupportsInputModality(model, "image");
985
+
986
+ // src/core/client.ts
987
+ init_errors();
988
+
989
+ // src/shared/api-response.ts
990
+ init_errors();
991
+ function apiResponseGetMessage(r) {
992
+ return r.message ?? r.msg ?? "";
1028
993
  }
1029
- function findFirstModelByInputModality(models, modality) {
1030
- if (!Array.isArray(models)) return null;
1031
- for (const m of models) {
1032
- if (!m) continue;
1033
- if (m.isEnabled === false) continue;
1034
- if (!modelSupportsInputModality(m, modality)) continue;
1035
- return m;
994
+ function apiResponseBusinessError(r) {
995
+ if (r.code !== 0) {
996
+ return new exports.BusinessError(r.code, apiResponseGetMessage(r));
1036
997
  }
1037
998
  return null;
1038
999
  }
1039
- function findDesktopVisualUnderstandingModel(models) {
1040
- if (!Array.isArray(models)) return null;
1041
- const candidates = [];
1042
- for (const m of models) {
1043
- if (!m) continue;
1044
- if (m.isEnabled === false) continue;
1045
- if (m.capabilities?.supports_desktop_visual_understanding !== true) continue;
1046
- if (!modelSupportsInputModality(m, "image")) continue;
1047
- candidates.push(m);
1048
- }
1049
- if (candidates.length === 0) return null;
1050
- for (const m of candidates) {
1051
- if (m.isDefault === true) return m;
1052
- }
1053
- return candidates[0];
1054
- }
1055
-
1056
- // src/index.ts
1057
- init_adapters();
1058
1000
 
1059
- // src/auth.ts
1001
+ // src/auth/auth.ts
1060
1002
  var authTimeoutMs = 3e4;
1061
1003
  async function discoverWithProfile(serverURL, profile, signal) {
1062
1004
  let parsed;
@@ -1506,251 +1448,29 @@ function withTimeout(ms, parent) {
1506
1448
  };
1507
1449
  }
1508
1450
 
1509
- // src/scopes.ts
1510
- var ScopeAI = "ai";
1511
- var ScopeSkills = "skills";
1512
- var ScopeAccount = "account";
1513
- var ScopeModels = "models";
1514
- var ScopeModelsChat = "models:chat";
1515
- var ScopeEntitlements = "entitlements";
1516
- var ScopeTokenPackages = "token-packages";
1517
- var ScopeSkillStore = "skill_store";
1518
- var ScopeTools = "tools";
1519
- var ScopeToolsExecute = "tools:execute";
1520
- var ScopeWallet = "wallet";
1521
- var ScopeWalletReadonly = "wallet:readonly";
1522
- var ScopeProfile = "profile";
1523
- var ScopeComplianceEvidenceRead = "compliance:evidence:read";
1524
- var ScopeComplianceEvidenceWrite = "compliance:evidence:write";
1525
- var ScopeComplianceTimestampIssue = "compliance:timestamp:issue";
1526
- var ScopeComplianceTimestampVerify = "compliance:timestamp:verify";
1527
- var ScopeComplianceContractSigningRead = "compliance:contract_signing:read";
1528
- var ScopeComplianceContractSigningWrite = "compliance:contract_signing:write";
1529
- var ScopeComplianceSealManage = "compliance:seal:manage";
1530
- var ScopeComplianceSealApprovalRequest = "compliance:seal_approval:request";
1531
- var ScopeComplianceSealApprovalApprove = "compliance:seal_approval:approve";
1532
- var ScopeComplianceSealUseExecute = "compliance:seal_use:execute";
1533
- var ScopeComplianceReportsRead = "compliance:reports:read";
1534
- var ScopeComplianceReportsWrite = "compliance:reports:write";
1535
- var ScopeComplianceReportsPublish = "compliance:reports:publish";
1536
- function allScopes() {
1537
- return [ScopeAI, ScopeSkills, ScopeAccount];
1538
- }
1539
- function complianceScopes() {
1540
- return [
1541
- ScopeComplianceEvidenceRead,
1542
- ScopeComplianceEvidenceWrite,
1543
- ScopeComplianceTimestampIssue,
1544
- ScopeComplianceTimestampVerify,
1545
- ScopeComplianceContractSigningRead,
1546
- ScopeComplianceContractSigningWrite,
1547
- ScopeComplianceSealManage,
1548
- ScopeComplianceSealApprovalRequest,
1549
- ScopeComplianceSealApprovalApprove,
1550
- ScopeComplianceSealUseExecute,
1551
- ScopeComplianceReportsRead,
1552
- ScopeComplianceReportsWrite,
1553
- ScopeComplianceReportsPublish
1554
- ];
1555
- }
1556
- function modelScopes() {
1557
- return [ScopeAI];
1558
- }
1559
- function commerceScopes() {
1560
- return [ScopeAI, ScopeAccount];
1561
- }
1562
- function skillScopes() {
1563
- return [ScopeSkills];
1564
- }
1565
-
1566
- // src/compliance-status.ts
1567
- var ErrComplianceStepUpRequired = "COMPLIANCE_STEP_UP_REQUIRED";
1568
- var ErrEnvelopeGateClosed = "ENVELOPE_GATE_CLOSED";
1569
- var ErrProviderNotConfigured = "PROVIDER_NOT_CONFIGURED";
1570
- var ErrProviderUnknownNoRetry = "PROVIDER_REQUEST_UNKNOWN_NO_RETRY";
1571
- var ErrBillingCallbackCannotCommit = "BILLING_CALLBACK_CANNOT_COMMIT";
1572
- var ErrBillingCommitRequiresLocalVerify = "BILLING_COMMIT_REQUIRES_LOCAL_VERIFY";
1573
- var ErrBillingS2sForbidden = "BILLING_S2S_FORBIDDEN";
1574
- var ErrSealApprovalNotApproved = "SEAL_APPROVAL_STATE_NOT_APPROVED";
1575
- var ErrSealApprovalExpired = "SEAL_APPROVAL_EXPIRED";
1576
- var ErrSealApprovalNonceUsed = "SEAL_APPROVAL_NONCE_USED";
1577
- var ErrSealApprovalContractHashMismatch = "SEAL_APPROVAL_CONTRACT_HASH_MISMATCH";
1578
- var ErrSealApprovalSealMismatch = "SEAL_APPROVAL_SEAL_MISMATCH";
1579
- var ErrSealApprovalLocationMismatch = "SEAL_APPROVAL_LOCATION_MISMATCH";
1580
- var ErrSealApprovalTransactorMismatch = "SEAL_APPROVAL_TRANSACTOR_MISMATCH";
1581
- var ErrSealUseAlreadyConsumed = "SEAL_USE_ALREADY_CONSUMED";
1582
- function isComplianceTerminalError(code) {
1583
- switch (code) {
1584
- case ErrEnvelopeGateClosed:
1585
- case ErrProviderNotConfigured:
1586
- case ErrProviderUnknownNoRetry:
1587
- case ErrBillingCallbackCannotCommit:
1588
- case ErrBillingCommitRequiresLocalVerify:
1589
- case ErrBillingS2sForbidden:
1590
- case ErrSealApprovalNonceUsed:
1591
- case ErrSealApprovalExpired:
1592
- case ErrSealApprovalContractHashMismatch:
1593
- case ErrSealApprovalSealMismatch:
1594
- case ErrSealApprovalLocationMismatch:
1595
- case ErrSealApprovalTransactorMismatch:
1596
- case ErrSealUseAlreadyConsumed:
1597
- return true;
1598
- default:
1599
- return false;
1600
- }
1601
- }
1602
- function isBillingConfirmable(providerStatus, billingStatus) {
1603
- return providerStatus === "success" && billingStatus === "committed";
1604
- }
1605
-
1606
- // src/compliance-errors.ts
1607
- var CODE_TO_KEY = {
1608
- // 通用 / token / scope (1-031-000-xxx)
1609
- 1031000001: "COMPLIANCE_UNAUTHORIZED",
1610
- 1031000002: "COMPLIANCE_TOKEN_INVALID",
1611
- 1031000003: "COMPLIANCE_TOKEN_INVALID",
1612
- 1031000004: "COMPLIANCE_TOKEN_INVALID",
1613
- 1031000005: "COMPLIANCE_TOKEN_INVALID",
1614
- 1031000006: "COMPLIANCE_TOKEN_INVALID",
1615
- 1031000007: "COMPLIANCE_TOKEN_INVALID",
1616
- 1031000008: "COMPLIANCE_TOKEN_INVALID",
1617
- 1031000009: "COMPLIANCE_TOKEN_INVALID",
1618
- 1031000010: "COMPLIANCE_TOKEN_INVALID",
1619
- 1031000011: "COMPLIANCE_TOKEN_INVALID",
1620
- 1031000012: "COMPLIANCE_INSUFFICIENT_SCOPE",
1621
- 1031000013: "COMPLIANCE_STEP_UP_REQUIRED",
1622
- // Subject snapshot (1-031-001-xxx)
1623
- 1031001001: "SUBJECT_SNAPSHOT_NOT_FOUND",
1624
- 1031001002: "SUBJECT_SNAPSHOT_TENANT_MISMATCH",
1625
- 1031001003: "SUBJECT_SNAPSHOT_REQUIRED",
1626
- // Evidence / Timestamp / Package / Report (1-031-002-xxx)
1627
- 1031002001: "EVIDENCE_ASSET_NOT_FOUND",
1628
- 1031002002: "SUBJECT_SNAPSHOT_TENANT_MISMATCH",
1629
- 1031002003: "EVIDENCE_ASSET_HASH_MISMATCH",
1630
- 1031002004: "EVIDENCE_ASSET_PAYLOAD_REQUIRED",
1631
- 1031002005: "EVIDENCE_ASSET_PAYLOAD_REQUIRED",
1632
- 1031002006: "TIMESTAMP_TOKEN_NOT_FOUND",
1633
- 1031002007: "TIMESTAMP_PROVIDER_FAILED",
1634
- 1031002008: "TIMESTAMP_PROVIDER_UNKNOWN",
1635
- 1031002009: "TIMESTAMP_LOCAL_VERIFY_FAILED",
1636
- 1031002010: "TIMESTAMP_PROVIDER_NOT_AVAILABLE",
1637
- 1031002011: "EVIDENCE_PACKAGE_NOT_FOUND",
1638
- 1031002012: "EVIDENCE_PACKAGE_TIMESTAMP_REQUIRED",
1639
- 1031002013: "EVIDENCE_PACKAGE_MANIFEST_HASH_MISMATCH",
1640
- 1031002014: "REPORT_NOT_FOUND",
1641
- 1031002015: "REPORT_ALREADY_PUBLISHED",
1642
- 1031002016: "REPORT_DRAFT_REQUIRED",
1643
- 1031002017: "EVIDENCE_VERIFY_TARGET_REQUIRED",
1644
- 1031002018: "EVIDENCE_VERIFY_TARGET_NOT_FOUND",
1645
- // Provider request (1-031-003-xxx)
1646
- 1031003001: "PROVIDER_REQUEST_UNKNOWN_NO_RETRY",
1647
- 1031003002: "PROVIDER_CALLBACK_SOURCE_INVALID",
1648
- 1031003003: "PROVIDER_NOT_CONFIGURED",
1649
- 1031003010: "PROVIDER_REQUEST_NOT_FOUND",
1650
- 1031003011: "PROVIDER_REQUEST_IDEMPOTENCY_REQUIRED",
1651
- 1031003012: "PROVIDER_REQUEST_STATUS_NOT_TERMINAL",
1652
- // Envelope (1-031-004-xxx)
1653
- 1031004001: "ENVELOPE_NOT_FOUND",
1654
- 1031004002: "ENVELOPE_TENANT_MISMATCH",
1655
- 1031004003: "ENVELOPE_STATE_NOT_ALLOWED",
1656
- 1031004004: "ENVELOPE_GATE_CLOSED",
1657
- 1031004005: "CONTRACT_NOT_FOUND",
1658
- 1031004006: "CONTRACT_HASH_MISMATCH",
1659
- 1031004007: "CONTRACT_NOT_FOUND",
1660
- 1031004008: "PROVIDER_AUTHORIZATION_NOT_CONFIRMED",
1661
- 1031004009: "PROVIDER_AUTHORIZATION_NOT_CONFIRMED",
1662
- 1031004010: "ENVELOPE_EVIDENCE_NOT_READY",
1663
- // Seal approval / use (1-031-005-xxx)
1664
- 1031005001: "SEAL_ASSET_NOT_FOUND",
1665
- 1031005010: "SEAL_APPROVAL_NOT_FOUND",
1666
- 1031005011: "SEAL_APPROVAL_NOT_FOUND",
1667
- 1031005012: "SEAL_APPROVAL_STATE_NOT_APPROVED",
1668
- 1031005013: "SEAL_APPROVAL_EXPIRED",
1669
- 1031005014: "SEAL_APPROVAL_ALREADY_USED",
1670
- 1031005015: "SEAL_APPROVAL_NONCE_USED",
1671
- 1031005016: "SEAL_APPROVAL_SEAL_MISMATCH",
1672
- 1031005017: "SEAL_APPROVAL_LOCATION_MISMATCH",
1673
- 1031005018: "SEAL_APPROVAL_TRANSACTOR_MISMATCH",
1674
- 1031005019: "SEAL_APPROVAL_CONTRACT_HASH_MISMATCH",
1675
- 1031005020: "SEAL_APPROVAL_INVALID_TRANSITION",
1676
- 1031005030: "SEAL_USE_ALREADY_CONSUMED",
1677
- // Billing (1-031-006-xxx)
1678
- 1031006004: "BILLING_COMMIT_REQUIRES_LOCAL_VERIFY",
1679
- 1031006005: "BILLING_COMMIT_REQUIRES_PROVIDER_SUCCESS",
1680
- 1031006007: "BILLING_CALLBACK_CANNOT_COMMIT",
1681
- 1031006008: "BILLING_PROVIDER_UNKNOWN_NOT_COMMITTABLE",
1682
- 1031006009: "BILLING_S2S_FORBIDDEN",
1683
- // Audit (1-031-007-xxx)
1684
- 1031007011: "AUDIT_CHAIN_TAMPER_DETECTED"
1685
- };
1686
- var STEP_UP_KEYS = /* @__PURE__ */ new Set(["COMPLIANCE_STEP_UP_REQUIRED"]);
1687
- var TERMINAL_KEYS = /* @__PURE__ */ new Set([
1688
- "ENVELOPE_GATE_CLOSED",
1689
- "PROVIDER_NOT_CONFIGURED",
1690
- "PROVIDER_REQUEST_UNKNOWN_NO_RETRY",
1691
- "BILLING_CALLBACK_CANNOT_COMMIT",
1692
- "BILLING_COMMIT_REQUIRES_LOCAL_VERIFY",
1693
- "BILLING_COMMIT_REQUIRES_PROVIDER_SUCCESS",
1694
- "BILLING_PROVIDER_UNKNOWN_NOT_COMMITTABLE",
1695
- "BILLING_S2S_FORBIDDEN",
1696
- "SEAL_APPROVAL_NONCE_USED",
1697
- "SEAL_APPROVAL_EXPIRED",
1698
- "SEAL_APPROVAL_CONTRACT_HASH_MISMATCH",
1699
- "SEAL_APPROVAL_SEAL_MISMATCH",
1700
- "SEAL_APPROVAL_LOCATION_MISMATCH",
1701
- "SEAL_APPROVAL_TRANSACTOR_MISMATCH",
1702
- "SEAL_USE_ALREADY_CONSUMED",
1703
- "CONTRACT_HASH_MISMATCH",
1704
- "TIMESTAMP_LOCAL_VERIFY_FAILED",
1705
- "EVIDENCE_PACKAGE_MANIFEST_HASH_MISMATCH",
1706
- "AUDIT_CHAIN_TAMPER_DETECTED",
1707
- "PROVIDER_REQUEST_NOT_FOUND",
1708
- "EVIDENCE_ASSET_HASH_MISMATCH",
1709
- "EVIDENCE_VERIFY_TARGET_NOT_FOUND",
1710
- "REPORT_ALREADY_PUBLISHED"
1711
- ]);
1712
- var RETRYABLE_KEYS = /* @__PURE__ */ new Set([]);
1713
- function classifyComplianceError(err) {
1714
- const key = CODE_TO_KEY[err.code] ?? "UNKNOWN_COMPLIANCE_ERROR";
1715
- return {
1716
- code: err.code,
1717
- message: err.message,
1718
- key,
1719
- retryable: RETRYABLE_KEYS.has(key),
1720
- terminal: TERMINAL_KEYS.has(key),
1721
- stepUpRequired: STEP_UP_KEYS.has(key)
1722
- };
1723
- }
1724
- function isComplianceBusinessError(err) {
1725
- return err.code >= 1031e6 && err.code <= 1031999999;
1726
- }
1727
-
1728
- // src/client.ts
1729
- init_types();
1730
-
1731
- // src/store.ts
1732
- var fileLockDefaults = {
1733
- /** 获取锁的超时上限 (毫秒). refresh 流程含网络 < 30s, 30s 已远超正常完成时间. */
1734
- acquireTimeoutMs: 3e4,
1735
- /** 旧锁判定阈值 (毫秒). 锁文件 mtime 早于此值视为 stale 进程崩溃残留, 自动 break. */
1736
- staleMs: 6e4,
1737
- /** 重试间隔基数 (毫秒). 真实间隔 = base + random(0, jitter). */
1738
- retryBaseMs: 30,
1739
- retryJitterMs: 70
1740
- };
1741
- var FileTokenStore = class {
1742
- path;
1743
- /** 进程内串行化 (Promise chain) — 与跨进程 flock 配合, 避免单进程内并发持锁产生死锁式互等. */
1744
- chain = Promise.resolve();
1745
- constructor(path) {
1746
- if (typeof process === "undefined" || !process.versions || !process.versions.node) {
1747
- throw new Error("FileTokenStore requires Node.js environment; use LocalStorageTokenStore or InMemoryTokenStore in browser");
1748
- }
1749
- if (path && path !== "") {
1750
- this.path = path;
1751
- } else {
1752
- this.path = "";
1753
- }
1451
+ // src/core/store.ts
1452
+ var fileLockDefaults = {
1453
+ /** 获取锁的超时上限 (毫秒). refresh 流程含网络 < 30s, 30s 已远超正常完成时间. */
1454
+ acquireTimeoutMs: 3e4,
1455
+ /** 旧锁判定阈值 (毫秒). 锁文件 mtime 早于此值视为 stale 进程崩溃残留, 自动 break. */
1456
+ staleMs: 6e4,
1457
+ /** 重试间隔基数 (毫秒). 真实间隔 = base + random(0, jitter). */
1458
+ retryBaseMs: 30,
1459
+ retryJitterMs: 70
1460
+ };
1461
+ var FileTokenStore = class {
1462
+ path;
1463
+ /** 进程内串行化 (Promise chain) — 与跨进程 flock 配合, 避免单进程内并发持锁产生死锁式互等. */
1464
+ chain = Promise.resolve();
1465
+ constructor(path) {
1466
+ if (typeof process === "undefined" || !process.versions || !process.versions.node) {
1467
+ throw new Error("FileTokenStore requires Node.js environment; use LocalStorageTokenStore or InMemoryTokenStore in browser");
1468
+ }
1469
+ if (path && path !== "") {
1470
+ this.path = path;
1471
+ } else {
1472
+ this.path = "";
1473
+ }
1754
1474
  }
1755
1475
  async resolvePath() {
1756
1476
  if (this.path && this.path !== "") return this.path;
@@ -1947,8 +1667,8 @@ var InMemoryTokenStore = class {
1947
1667
  }
1948
1668
  };
1949
1669
 
1950
- // src/retry.ts
1951
- init_types();
1670
+ // src/core/retry.ts
1671
+ init_errors();
1952
1672
  var DefaultRetryPolicy = {
1953
1673
  maxAttempts: 2,
1954
1674
  backoffMs: 200,
@@ -2003,10 +1723,10 @@ function computeBackoff(p, attempt, err) {
2003
1723
  return d;
2004
1724
  }
2005
1725
 
2006
- // src/client.ts
1726
+ // src/core/client.ts
2007
1727
  init_adapters();
2008
1728
 
2009
- // src/stream-meta.ts
1729
+ // src/models/stream-meta.ts
2010
1730
  function extractAnthropicBlockMeta(eventType, data, blockTypeMap) {
2011
1731
  switch (eventType) {
2012
1732
  case "content_block_start": {
@@ -2052,11 +1772,11 @@ function extractAnthropicBlockMeta(eventType, data, blockTypeMap) {
2052
1772
  }
2053
1773
  }
2054
1774
 
2055
- // src/client.ts
1775
+ // src/core/client.ts
2056
1776
  init_openai();
2057
1777
 
2058
- // src/client-helpers.ts
2059
- init_types();
1778
+ // src/core/http.ts
1779
+ init_errors();
2060
1780
  var maxDownloadSize = 50 * 1024 * 1024;
2061
1781
  var maxErrorBodySize = 1 * 1024 * 1024;
2062
1782
  var maxSSELineSize = 1 * 1024 * 1024;
@@ -2232,7 +1952,7 @@ async function readLimitedText(body, maxBytes) {
2232
1952
  return new TextDecoder("utf-8").decode(buf);
2233
1953
  }
2234
1954
 
2235
- // src/client.ts
1955
+ // src/core/client.ts
2236
1956
  var FilterStatusOK = "ok";
2237
1957
  var FilterStatusAdminBypass = "admin-bypass";
2238
1958
  var FilterStatusInternalBypass = "internal-bypass";
@@ -2242,6 +1962,9 @@ var FilterStatusFallbackTkdistSkew = "fallback-tkdist-deployment-skew";
2242
1962
  var FilterStatusFallbackNoBuckets = "fallback-no-buckets";
2243
1963
  var FilterStatusFallbackMissingUser = "fallback-missing-userid";
2244
1964
  var FilterStatusUnknown = "";
1965
+ var ErrOAuthCORSBlocked = "oauth_cors_blocked";
1966
+ var ErrRefreshProxyFailed = "refresh_proxy_failed";
1967
+ var ErrTokenExpired = "token_expired";
2245
1968
  function newDeferred() {
2246
1969
  let resolve;
2247
1970
  let reject;
@@ -2259,6 +1982,10 @@ var Client = class _Client {
2259
1982
  complianceBaseURL;
2260
1983
  /** OAuth metadata profile — 刷新 token 时发现 metadata 用 (默认 'desktop') */
2261
1984
  oauthMetadataProfile;
1985
+ /** Browser Web OAuth refresh strategy (default 'direct') */
1986
+ browserRefreshMode;
1987
+ /** Same-origin refresh proxy URL for browserRefreshMode='server-proxy' */
1988
+ refreshProxyURL;
2262
1989
  /** OAuth metadata (lazy loaded) */
2263
1990
  meta = null;
2264
1991
  /** 当前 token (内存) */
@@ -2294,6 +2021,8 @@ var Client = class _Client {
2294
2021
  this.serverURL = (cfg.serverURL ?? "https://acosmi.com").replace(/\/+$/, "");
2295
2022
  this.complianceBaseURL = cfg.complianceBaseURL ? cfg.complianceBaseURL.replace(/\/+$/, "") : null;
2296
2023
  this.oauthMetadataProfile = cfg.oauthMetadataProfile ?? "desktop";
2024
+ this.browserRefreshMode = cfg.browserRefreshMode ?? "direct";
2025
+ this.refreshProxyURL = cfg.refreshProxyURL ?? null;
2297
2026
  this.store = cfg.store ?? defaultTokenStore();
2298
2027
  this.fetchImpl = cfg.fetchImpl ?? globalThis.fetch.bind(globalThis);
2299
2028
  this.retryPolicy = effectivePolicy(cfg.retryPolicy ?? null);
@@ -2537,27 +2266,7 @@ var Client = class _Client {
2537
2266
  if (!tokenSetIsExpired(this.tokens)) {
2538
2267
  return this.tokens.access_token;
2539
2268
  }
2540
- if (this.meta == null) {
2541
- try {
2542
- this.meta = await discoverWithProfile(this.serverURL, this.oauthMetadataProfile, signal);
2543
- } catch (e) {
2544
- throw new Error(
2545
- `discover for refresh: ${e instanceof Error ? e.message : String(e)}`
2546
- );
2547
- }
2548
- }
2549
- let tokenResp;
2550
- try {
2551
- tokenResp = await refreshToken(this.meta, this.tokens.client_id, this.tokens.refresh_token, signal);
2552
- } catch (e) {
2553
- throw new Error(`refresh token: ${e instanceof Error ? e.message : String(e)}`);
2554
- }
2555
- this.tokens = newTokenSet(tokenResp, this.tokens.client_id, this.serverURL);
2556
- try {
2557
- await this.store.save(this.tokens);
2558
- } catch (e) {
2559
- console.warn(`[acosmi-sdk] warning: save refreshed token failed: ${e instanceof Error ? e.message : String(e)}`);
2560
- }
2269
+ await this.refreshCurrentToken(signal);
2561
2270
  return this.tokens.access_token;
2562
2271
  })
2563
2272
  );
@@ -2570,26 +2279,111 @@ var Client = class _Client {
2570
2279
  if (this.tokens == null) {
2571
2280
  throw new Error("no tokens to refresh");
2572
2281
  }
2573
- if (this.meta == null) {
2574
- this.meta = await discoverWithProfile(this.serverURL, this.oauthMetadataProfile, signal);
2575
- }
2576
- const tokenResp = await refreshToken(
2577
- this.meta,
2578
- this.tokens.client_id,
2579
- this.tokens.refresh_token,
2580
- signal
2581
- );
2582
- this.tokens = newTokenSet(tokenResp, this.tokens.client_id, this.serverURL);
2583
- try {
2584
- await this.store.save(this.tokens);
2585
- } catch (e) {
2586
- console.warn(
2587
- `[acosmi-sdk] warning: save refreshed token failed: ${e instanceof Error ? e.message : String(e)}`
2588
- );
2589
- }
2282
+ await this.refreshCurrentToken(signal);
2590
2283
  })
2591
2284
  );
2592
2285
  }
2286
+ async refreshCurrentToken(signal) {
2287
+ if (this.tokens == null) {
2288
+ throw new Error("no tokens to refresh");
2289
+ }
2290
+ if (this.browserRefreshMode === "none") {
2291
+ throw new Error(`${ErrTokenExpired}: token refresh disabled`);
2292
+ }
2293
+ if (this.browserRefreshMode === "server-proxy") {
2294
+ await this.refreshCurrentTokenViaProxy(signal);
2295
+ return;
2296
+ }
2297
+ await this.refreshCurrentTokenDirect(signal);
2298
+ }
2299
+ async refreshCurrentTokenDirect(signal) {
2300
+ if (this.tokens == null) {
2301
+ throw new Error("no tokens to refresh");
2302
+ }
2303
+ if (this.meta == null) {
2304
+ try {
2305
+ this.meta = await discoverWithProfile(this.serverURL, this.oauthMetadataProfile, signal);
2306
+ } catch (e) {
2307
+ throw new Error(
2308
+ `discover for refresh: ${e instanceof Error ? e.message : String(e)}`
2309
+ );
2310
+ }
2311
+ }
2312
+ let tokenResp;
2313
+ try {
2314
+ tokenResp = await refreshToken(
2315
+ this.meta,
2316
+ this.tokens.client_id,
2317
+ this.tokens.refresh_token,
2318
+ signal
2319
+ );
2320
+ } catch (e) {
2321
+ const message = e instanceof Error ? e.message : String(e);
2322
+ if (isLikelyBrowserOAuthCORSError(message)) {
2323
+ throw new Error(`${ErrOAuthCORSBlocked}: refresh token: ${message}`);
2324
+ }
2325
+ throw new Error(`refresh token: ${message}`);
2326
+ }
2327
+ this.tokens = newTokenSet(tokenResp, this.tokens.client_id, this.serverURL);
2328
+ await this.saveRefreshedToken();
2329
+ }
2330
+ async refreshCurrentTokenViaProxy(signal) {
2331
+ if (this.tokens == null) {
2332
+ throw new Error("no tokens to refresh");
2333
+ }
2334
+ if (!this.refreshProxyURL) {
2335
+ throw new Error(`${ErrRefreshProxyFailed}: refreshProxyURL is required`);
2336
+ }
2337
+ let resp;
2338
+ try {
2339
+ resp = await this.fetchImpl(this.refreshProxyURL, {
2340
+ method: "POST",
2341
+ headers: { "Content-Type": "application/json" },
2342
+ body: JSON.stringify({
2343
+ client_id: this.tokens.client_id,
2344
+ refresh_token: this.tokens.refresh_token,
2345
+ server_url: this.tokens.server_url || this.serverURL
2346
+ }),
2347
+ signal
2348
+ });
2349
+ } catch (e) {
2350
+ throw new Error(
2351
+ `${ErrRefreshProxyFailed}: ${e instanceof Error ? e.message : String(e)}`
2352
+ );
2353
+ }
2354
+ if (!resp.ok) {
2355
+ let message = "";
2356
+ try {
2357
+ const body2 = await resp.json();
2358
+ if (typeof body2.error === "string") message = body2.error;
2359
+ } catch {
2360
+ }
2361
+ throw new Error(`${ErrRefreshProxyFailed}: HTTP ${resp.status}: ${message}`);
2362
+ }
2363
+ let body;
2364
+ try {
2365
+ body = await resp.json();
2366
+ } catch (e) {
2367
+ throw new Error(
2368
+ `${ErrRefreshProxyFailed}: decode: ${e instanceof Error ? e.message : String(e)}`
2369
+ );
2370
+ }
2371
+ if (!isTokenSetLike(body.tokenSet)) {
2372
+ throw new Error(`${ErrRefreshProxyFailed}: response missing tokenSet`);
2373
+ }
2374
+ this.tokens = body.tokenSet;
2375
+ await this.saveRefreshedToken();
2376
+ }
2377
+ async saveRefreshedToken() {
2378
+ if (this.tokens == null) return;
2379
+ try {
2380
+ await this.store.save(this.tokens);
2381
+ } catch (e) {
2382
+ console.warn(
2383
+ `[acosmi-sdk] warning: save refreshed token failed: ${e instanceof Error ? e.message : String(e)}`
2384
+ );
2385
+ }
2386
+ }
2593
2387
  /** 互斥锁 helper (替代 Go sync.Mutex) */
2594
2388
  withMu(fn) {
2595
2389
  const next = this.mu.then(fn, fn);
@@ -3288,6 +3082,15 @@ function defaultTokenStore() {
3288
3082
  }
3289
3083
  return new InMemoryTokenStore();
3290
3084
  }
3085
+ function isLikelyBrowserOAuthCORSError(message) {
3086
+ const lower = message.toLowerCase();
3087
+ return lower.includes("failed to fetch") || lower.includes("networkerror") || lower.includes("cors") || lower.includes("http 403");
3088
+ }
3089
+ function isTokenSetLike(value) {
3090
+ if (value == null || typeof value !== "object") return false;
3091
+ const candidate = value;
3092
+ return typeof candidate.access_token === "string" && typeof candidate.refresh_token === "string" && typeof candidate.expires_at === "string" && typeof candidate.scope === "string" && typeof candidate.client_id === "string" && typeof candidate.server_url === "string";
3093
+ }
3291
3094
  function zeroModelCapabilities() {
3292
3095
  return {
3293
3096
  supports_thinking: false,
@@ -3364,802 +3167,1177 @@ async function sleep(ms, signal) {
3364
3167
  });
3365
3168
  }
3366
3169
 
3367
- // src/client/compliance.ts
3368
- init_types();
3369
- var cache = /* @__PURE__ */ new WeakMap();
3370
- Object.defineProperty(Client.prototype, "compliance", {
3371
- configurable: true,
3372
- enumerable: false,
3373
- get() {
3374
- let existing = cache.get(this);
3375
- if (!existing) {
3376
- existing = new ComplianceClient(this);
3377
- cache.set(this, existing);
3378
- }
3379
- return existing;
3380
- }
3170
+ // src/sanitize/index.ts
3171
+ var sanitize_exports = {};
3172
+ __export(sanitize_exports, {
3173
+ BlockCodeExecutionToolResult: () => BlockCodeExecutionToolResult,
3174
+ BlockContainerUpload: () => BlockContainerUpload,
3175
+ BlockDeniedError: () => BlockDeniedError,
3176
+ BlockDocument: () => BlockDocument,
3177
+ BlockImage: () => BlockImage,
3178
+ BlockMCPToolResult: () => BlockMCPToolResult,
3179
+ BlockMCPToolUse: () => BlockMCPToolUse,
3180
+ BlockRedactedThinking: () => BlockRedactedThinking,
3181
+ BlockSearchResult: () => BlockSearchResult,
3182
+ BlockServerToolUse: () => BlockServerToolUse,
3183
+ BlockText: () => BlockText,
3184
+ BlockThinking: () => BlockThinking,
3185
+ BlockToolReference: () => BlockToolReference,
3186
+ BlockToolResult: () => BlockToolResult,
3187
+ BlockToolUse: () => BlockToolUse,
3188
+ BlockVideo: () => BlockVideo,
3189
+ BlockWebSearchToolResult: () => BlockWebSearchToolResult,
3190
+ DeltaCitations: () => DeltaCitations,
3191
+ DeltaInputJSON: () => DeltaInputJSON,
3192
+ DeltaSignature: () => DeltaSignature,
3193
+ DeltaText: () => DeltaText,
3194
+ DeltaThinking: () => DeltaThinking,
3195
+ EphemeralMarkerField: () => EphemeralMarkerField,
3196
+ ErrBlockDenied: () => ErrBlockDenied,
3197
+ ErrHistoryTooDeep: () => ErrHistoryTooDeep,
3198
+ HistoryTooDeepError: () => HistoryTooDeepError,
3199
+ SizeError: () => SizeError,
3200
+ dropBlocks: () => dropBlocks,
3201
+ sanitize: () => sanitize,
3202
+ stripEphemeral: () => stripEphemeral
3381
3203
  });
3382
- var DEFAULT_POLL = {
3383
- timeoutMs: 6e4,
3384
- initialIntervalMs: 1e3,
3385
- maxIntervalMs: 5e3,
3386
- multiplier: 1.5
3387
- };
3388
- var CompliancePollError = class extends Error {
3389
- kind;
3390
- lastInfo;
3391
- constructor(message, kind, lastInfo) {
3392
- super(message);
3393
- this.name = "CompliancePollError";
3394
- this.kind = kind;
3395
- this.lastInfo = lastInfo;
3204
+
3205
+ // src/sanitize/types.ts
3206
+ var BlockText = "text";
3207
+ var BlockImage = "image";
3208
+ var BlockVideo = "video";
3209
+ var BlockDocument = "document";
3210
+ var BlockSearchResult = "search_result";
3211
+ var BlockThinking = "thinking";
3212
+ var BlockRedactedThinking = "redacted_thinking";
3213
+ var BlockToolUse = "tool_use";
3214
+ var BlockToolResult = "tool_result";
3215
+ var BlockToolReference = "tool_reference";
3216
+ var BlockServerToolUse = "server_tool_use";
3217
+ var BlockWebSearchToolResult = "web_search_tool_result";
3218
+ var BlockCodeExecutionToolResult = "code_execution_tool_result";
3219
+ var BlockMCPToolUse = "mcp_tool_use";
3220
+ var BlockMCPToolResult = "mcp_tool_result";
3221
+ var BlockContainerUpload = "container_upload";
3222
+ var DeltaText = "text_delta";
3223
+ var DeltaInputJSON = "input_json_delta";
3224
+ var DeltaThinking = "thinking_delta";
3225
+ var DeltaSignature = "signature_delta";
3226
+ var DeltaCitations = "citations_delta";
3227
+ var EphemeralMarkerField = "acosmi_ephemeral";
3228
+
3229
+ // src/sanitize/config.ts
3230
+ var HistoryTooDeepError = class extends Error {
3231
+ constructor() {
3232
+ super("sanitize: messages history exceeds configured depth");
3233
+ this.name = "HistoryTooDeepError";
3396
3234
  }
3397
3235
  };
3398
- var ComplianceClient = class {
3399
- constructor(client) {
3400
- this.client = client;
3236
+ var BlockDeniedError = class extends Error {
3237
+ constructor() {
3238
+ super("sanitize: block type permanently denied");
3239
+ this.name = "BlockDeniedError";
3401
3240
  }
3402
- client;
3403
- // =========================================================================
3404
- // Evidence Asset
3405
- // =========================================================================
3406
- /** 创建证据资产(写)。 */
3407
- createEvidenceAsset(req, opts = {}) {
3408
- return this.write(
3409
- "POST",
3410
- "/compliance/evidence/assets",
3411
- req,
3412
- writeCtx(opts)
3413
- );
3241
+ };
3242
+ var SizeError = class extends Error {
3243
+ blockType;
3244
+ actual;
3245
+ limit;
3246
+ constructor(blockType, actual, limit) {
3247
+ super(`sanitize: ${blockType} base64 size ${actual} exceeds limit ${limit}`);
3248
+ this.name = "SizeError";
3249
+ this.blockType = blockType;
3250
+ this.actual = actual;
3251
+ this.limit = limit;
3414
3252
  }
3415
- /** 读 — 证据资产详情。 */
3416
- getEvidenceAsset(id, signal) {
3417
- return this.read(
3418
- "GET",
3419
- `/compliance/evidence/assets/${encodeURIComponent(id)}`,
3420
- null,
3421
- signal
3422
- );
3253
+ };
3254
+ var ErrHistoryTooDeep = new HistoryTooDeepError();
3255
+ var ErrBlockDenied = new BlockDeniedError();
3256
+
3257
+ // src/sanitize/history.ts
3258
+ function dropBlocks(messages, pred) {
3259
+ const droppedToolUseIDs = collectDroppedToolUseIDs(messages, pred);
3260
+ const out = [];
3261
+ for (const msg of messages) {
3262
+ if (!isPlainObject(msg)) {
3263
+ out.push(msg);
3264
+ continue;
3265
+ }
3266
+ const content = msg["content"];
3267
+ if (!Array.isArray(content)) {
3268
+ out.push(msg);
3269
+ continue;
3270
+ }
3271
+ const { kept, changed } = filterBlocks(content, pred, droppedToolUseIDs);
3272
+ if (!changed) {
3273
+ out.push(msg);
3274
+ continue;
3275
+ }
3276
+ if (kept.length === 0) {
3277
+ continue;
3278
+ }
3279
+ const newMsg = { ...msg };
3280
+ newMsg["content"] = kept;
3281
+ out.push(newMsg);
3423
3282
  }
3424
- /**
3425
- * 公开 verify。隐私边界:返回字段不含 PII / 合同原文 / storage / provider raw。
3426
- *
3427
- * 匿名可调用:未 login 时走匿名请求,不会抛 `not authorized, call login() first`。
3428
- * login / 已持有 token 时附带 `Authorization` 以保留审计上下文。public 端点不
3429
- * 应要求认证 — 收到 401 直接抛 HTTPError,不触发 `forceRefresh`,也不做 refresh
3430
- * replay。
3431
- */
3432
- verifyEvidencePublic(params, signal) {
3433
- const q = new URLSearchParams();
3434
- if (params.evidenceNo) q.set("evidenceNo", params.evidenceNo);
3435
- if (params.publicVerifyCode) q.set("publicVerifyCode", params.publicVerifyCode);
3436
- const qs = q.toString();
3437
- return this.publicRead(
3438
- "GET",
3439
- `/compliance/evidence/verify${qs ? "?" + qs : ""}`,
3440
- signal
3441
- );
3283
+ return out;
3284
+ }
3285
+ function collectDroppedToolUseIDs(messages, pred) {
3286
+ const ids = /* @__PURE__ */ new Set();
3287
+ for (const msg of messages) {
3288
+ if (!isPlainObject(msg)) continue;
3289
+ const content = msg["content"];
3290
+ if (!Array.isArray(content)) continue;
3291
+ for (const raw of content) {
3292
+ if (!isPlainObject(raw)) continue;
3293
+ if (!pred(raw)) continue;
3294
+ const t = raw["type"];
3295
+ if (typeof t !== "string") continue;
3296
+ if (t === "tool_use" || t === "server_tool_use" || t === "mcp_tool_use") {
3297
+ const id = raw["id"];
3298
+ if (typeof id === "string" && id !== "") ids.add(id);
3299
+ }
3300
+ }
3442
3301
  }
3443
- // =========================================================================
3444
- // Timestamp
3445
- // =========================================================================
3446
- /** 申请时间章(写)。SDK 永远不传 provider 字段。 */
3447
- issueTimestamp(req, opts = {}) {
3448
- return this.write("POST", "/compliance/timestamps", req, writeCtx(opts));
3302
+ return ids;
3303
+ }
3304
+ function filterBlocks(content, pred, droppedToolUseIDs) {
3305
+ const kept = [];
3306
+ let changed = false;
3307
+ for (const raw of content) {
3308
+ if (!isPlainObject(raw)) {
3309
+ kept.push(raw);
3310
+ continue;
3311
+ }
3312
+ if (pred(raw)) {
3313
+ changed = true;
3314
+ continue;
3315
+ }
3316
+ if (droppedToolUseIDs.size > 0) {
3317
+ const t = raw["type"];
3318
+ if (t === "tool_result" || t === "mcp_tool_result") {
3319
+ const id = raw["tool_use_id"];
3320
+ if (typeof id === "string" && id !== "" && droppedToolUseIDs.has(id)) {
3321
+ changed = true;
3322
+ continue;
3323
+ }
3324
+ }
3325
+ }
3326
+ kept.push(raw);
3449
3327
  }
3450
- /** 给已有资产申请时间章。SDK 永远不传 provider 字段。 */
3451
- issueTimestampForAsset(assetId, opts = {}) {
3452
- return this.write(
3453
- "POST",
3454
- `/compliance/evidence/assets/${encodeURIComponent(assetId)}/timestamp`,
3455
- null,
3456
- writeCtx(opts)
3457
- );
3328
+ return { kept, changed };
3329
+ }
3330
+ function stripEphemeral(messages) {
3331
+ return dropBlocks(messages, (b) => {
3332
+ const t = b["type"];
3333
+ if (t === "thinking" || t === "redacted_thinking") {
3334
+ return false;
3335
+ }
3336
+ const v = b[EphemeralMarkerField];
3337
+ return v === true;
3338
+ });
3339
+ }
3340
+ function isPlainObject(v) {
3341
+ return typeof v === "object" && v !== null && !Array.isArray(v);
3342
+ }
3343
+
3344
+ // src/sanitize/defensive.ts
3345
+ function sanitize(messages, cfg) {
3346
+ if ((cfg.maxMessagesTurns ?? 0) > 0 && messages.length > cfg.maxMessagesTurns) {
3347
+ throw ErrHistoryTooDeep;
3458
3348
  }
3459
- /** 时间章 token 详情。 */
3460
- getTimestamp(id, signal) {
3461
- return this.read(
3462
- "GET",
3463
- `/compliance/timestamps/${encodeURIComponent(id)}`,
3464
- null,
3465
- signal
3466
- );
3349
+ if ((cfg.maxImageBytes ?? 0) > 0 || (cfg.maxVideoBytes ?? 0) > 0 || (cfg.maxPDFBytes ?? 0) > 0) {
3350
+ checkMediaSizes(messages, cfg);
3467
3351
  }
3468
- /** verify 本地离线校验已申请的时间章。 */
3469
- verifyTimestamp(req, opts = {}) {
3470
- return this.write(
3471
- "POST",
3472
- "/compliance/timestamps/verify",
3473
- req,
3474
- writeCtx(opts)
3475
- );
3352
+ if (cfg.permanentDenyBlocks && cfg.permanentDenyBlocks.length > 0) {
3353
+ const denySet = /* @__PURE__ */ new Set();
3354
+ for (const bt of cfg.permanentDenyBlocks) denySet.add(bt);
3355
+ messages = dropBlocks(messages, (b) => {
3356
+ const t = b["type"];
3357
+ return typeof t === "string" && denySet.has(t);
3358
+ });
3476
3359
  }
3477
- /**
3478
- * 轮询到 VERIFIED 终态。
3479
- * - VERIFIED → 返回 token;
3480
- * - FAILED / LOCAL_VERIFY_FAILED → 抛 {@link CompliancePollError} kind='terminal_failure';
3481
- * - UNKNOWN / RETRYING / PENDING → 继续轮询直到 timeout;
3482
- * - timeout → 抛 {@link CompliancePollError} kind='timeout'。
3483
- */
3484
- async waitForTimestampVerified(id, opts = {}) {
3485
- return this.poll(
3486
- () => this.getTimestamp(id, opts.signal),
3487
- (t) => classifyTimestamp(t.verificationStatus),
3488
- opts
3489
- );
3360
+ return messages;
3361
+ }
3362
+ function checkMediaSizes(messages, cfg) {
3363
+ for (const msg of messages) {
3364
+ if (!isPlainObject2(msg)) continue;
3365
+ const content = msg["content"];
3366
+ if (!Array.isArray(content)) continue;
3367
+ for (const raw of content) {
3368
+ if (!isPlainObject2(raw)) continue;
3369
+ const bt = raw["type"];
3370
+ if (typeof bt !== "string") continue;
3371
+ let limit = 0;
3372
+ switch (bt) {
3373
+ case "image":
3374
+ limit = cfg.maxImageBytes ?? 0;
3375
+ break;
3376
+ case "video":
3377
+ limit = cfg.maxVideoBytes ?? 0;
3378
+ break;
3379
+ case "document":
3380
+ limit = cfg.maxPDFBytes ?? 0;
3381
+ break;
3382
+ default:
3383
+ continue;
3384
+ }
3385
+ if (limit <= 0) continue;
3386
+ const data = extractBase64Data(raw);
3387
+ if (data === "") continue;
3388
+ const actual = base64DecodedLen(data);
3389
+ if (actual > limit) {
3390
+ throw new SizeError(bt, actual, limit);
3391
+ }
3392
+ }
3490
3393
  }
3491
- // =========================================================================
3492
- // Evidence Package
3493
- // =========================================================================
3494
- /** 构建证据包(写)。 */
3495
- buildEvidencePackage(assetId, timestampTokenId, opts = {}) {
3496
- const tsParam = timestampTokenId == null ? "" : "?timestampTokenId=" + encodeURIComponent(timestampTokenId);
3497
- return this.write(
3498
- "POST",
3499
- `/compliance/evidence/assets/${encodeURIComponent(assetId)}/packages${tsParam}`,
3500
- null,
3501
- writeCtx(opts)
3502
- );
3394
+ }
3395
+ function extractBase64Data(block) {
3396
+ const src = block["source"];
3397
+ if (!isPlainObject2(src)) return "";
3398
+ if (src["type"] !== "base64") return "";
3399
+ const dataRaw = src["data"];
3400
+ if (typeof dataRaw !== "string") return "";
3401
+ let data = dataRaw;
3402
+ const i = data.indexOf("base64,");
3403
+ if (i >= 0) {
3404
+ data = data.slice(i + "base64,".length);
3503
3405
  }
3504
- // =========================================================================
3505
- // Report
3506
- // =========================================================================
3507
- /** 创建证据报告(写)。 */
3508
- createReport(req, opts = {}) {
3509
- return this.write("POST", "/compliance/reports", req, writeCtx(opts));
3510
- }
3511
- /** 报告详情。 */
3512
- getReport(id, signal) {
3513
- return this.read(
3514
- "GET",
3515
- `/compliance/reports/${encodeURIComponent(id)}`,
3516
- null,
3517
- signal
3518
- );
3406
+ return data;
3407
+ }
3408
+ function base64DecodedLen(b64) {
3409
+ const n = b64.length;
3410
+ let pad = 0;
3411
+ if (n >= 1 && b64[n - 1] === "=") pad++;
3412
+ if (n >= 2 && b64[n - 2] === "=") pad++;
3413
+ return Math.floor(n * 3 / 4) - pad;
3414
+ }
3415
+ function isPlainObject2(v) {
3416
+ return typeof v === "object" && v !== null && !Array.isArray(v);
3417
+ }
3418
+
3419
+ // src/core/sanitize-bridge.ts
3420
+ Client.prototype.setDefensiveSanitize = function(cfg) {
3421
+ this.defensiveCfg = cfg;
3422
+ };
3423
+ Client.prototype.setAutoStripEphemeralHistory = function(on) {
3424
+ this.autoStripEphemeral = on;
3425
+ };
3426
+ Client.prototype.applyRequestSanitizers = function(req) {
3427
+ const cfg = this.defensiveCfg;
3428
+ const strip = this.autoStripEphemeral;
3429
+ if (cfg == null && !strip) return;
3430
+ if (req.rawMessages != null) {
3431
+ let msgs;
3432
+ try {
3433
+ msgs = normalizeRawMessages(req.rawMessages);
3434
+ } catch (e) {
3435
+ throw new Error(
3436
+ `sanitize: normalize raw messages: ${e instanceof Error ? e.message : String(e)}`
3437
+ );
3438
+ }
3439
+ if (cfg) {
3440
+ msgs = sanitize(msgs, cfg);
3441
+ }
3442
+ if (strip) {
3443
+ msgs = stripEphemeral(msgs);
3444
+ }
3445
+ req.rawMessages = msgs;
3446
+ return;
3519
3447
  }
3520
- /**
3521
- * 发布报告(写,step-up 必须)。
3522
- *
3523
- * `@status gated` — step-up 闸门未闭合前服务端会一致返回
3524
- * `COMPLIANCE_STEP_UP_REQUIRED`(数值码 1031000013)。SDK 不会自动重试、不伪成功;
3525
- * 调用方需要引导用户重新做 OAuth introspection 或重新登录后再次调用本方法
3526
- *(使用同一 idempotency-key)。方法状态分级见 `docs/compliance.md` Method Status。
3527
- */
3528
- publishReport(id, opts = {}) {
3529
- return this.write(
3530
- "POST",
3531
- `/compliance/reports/${encodeURIComponent(id)}/publish`,
3532
- null,
3533
- writeCtx(opts)
3534
- );
3448
+ if (cfg && (cfg.maxMessagesTurns ?? 0) > 0 && (req.messages?.length ?? 0) > cfg.maxMessagesTurns) {
3449
+ throw ErrHistoryTooDeep;
3535
3450
  }
3536
- /**
3537
- * 下载报告(读)。返回 {@link ReportDownload}:报告 hash + 资产 hash + 证据包 hash +
3538
- * 时间章 serial/genTime,足以离线复核。
3539
- * 不返回 bodyCanonicalJson / storage key / subject snapshot id。
3540
- */
3541
- downloadReport(id, signal) {
3542
- return this.read(
3543
- "GET",
3544
- `/compliance/reports/${encodeURIComponent(id)}/download`,
3545
- null,
3546
- signal
3547
- );
3451
+ };
3452
+ function normalizeRawMessages(rm) {
3453
+ if (Array.isArray(rm)) return rm;
3454
+ let s;
3455
+ try {
3456
+ s = JSON.parse(JSON.stringify(rm));
3457
+ } catch (e) {
3458
+ throw new Error(`raw messages: ${e instanceof Error ? e.message : String(e)}`);
3548
3459
  }
3549
- // =========================================================================
3550
- // Signing Envelope
3551
- // =========================================================================
3552
- /** 创建 envelope(写)。返回 envelope id。 */
3553
- createSigningEnvelope(req, opts = {}) {
3554
- return this.write(
3555
- "POST",
3556
- "/compliance/signing-envelopes",
3557
- req,
3558
- writeCtx(opts)
3559
- );
3460
+ if (!Array.isArray(s)) {
3461
+ throw new Error("raw messages must be a JSON array");
3560
3462
  }
3561
- /** 读 — envelope 详情。租户由服务端从 compliance token principal 推导。 */
3562
- getSigningEnvelope(envelopeId, signal) {
3563
- return this.read(
3564
- "GET",
3565
- `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}`,
3566
- null,
3567
- signal
3568
- );
3463
+ return s;
3464
+ }
3465
+
3466
+ // src/shared/index.ts
3467
+ init_errors();
3468
+
3469
+ // src/auth/scopes.ts
3470
+ var ScopeAI = "ai";
3471
+ var ScopeSkills = "skills";
3472
+ var ScopeAccount = "account";
3473
+ var ScopeModels = "models";
3474
+ var ScopeModelsChat = "models:chat";
3475
+ var ScopeEntitlements = "entitlements";
3476
+ var ScopeTokenPackages = "token-packages";
3477
+ var ScopeSkillStore = "skill_store";
3478
+ var ScopeTools = "tools";
3479
+ var ScopeToolsExecute = "tools:execute";
3480
+ var ScopeWallet = "wallet";
3481
+ var ScopeWalletReadonly = "wallet:readonly";
3482
+ var ScopeProfile = "profile";
3483
+ function allScopes() {
3484
+ return [ScopeAI, ScopeSkills, ScopeAccount];
3485
+ }
3486
+ function modelScopes() {
3487
+ return [ScopeAI];
3488
+ }
3489
+ function commerceScopes() {
3490
+ return [ScopeAI, ScopeAccount];
3491
+ }
3492
+ function skillScopes() {
3493
+ return [ScopeSkills];
3494
+ }
3495
+
3496
+ // src/models/index.ts
3497
+ init_types();
3498
+
3499
+ // src/models/wire-anthropic.ts
3500
+ function anthropicResponseTextContent(r) {
3501
+ const parts = [];
3502
+ for (const b of r.content) {
3503
+ if (b.type === "text" && b.text) parts.push(b.text);
3569
3504
  }
3570
- /**
3571
- * 正式签署(写,step-up 必须)。
3572
- *
3573
- * `@status gated` — 服务端闸门关闭时会一致返回 `ENVELOPE_GATE_CLOSED` (1031004004)。
3574
- * SDK 不重试、不伪成功;调用方应该将该错误展示为"功能未开放"。
3575
- */
3576
- signEnvelope(envelopeId, req, opts = {}) {
3577
- return this.write(
3578
- "POST",
3579
- `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}/sign`,
3580
- req,
3581
- writeCtx(opts)
3582
- );
3505
+ return parts.join("");
3506
+ }
3507
+ function anthropicResponseThinkingContent(r) {
3508
+ const parts = [];
3509
+ for (const b of r.content) {
3510
+ if (b.type === "thinking" && b.thinking) parts.push(b.thinking);
3583
3511
  }
3584
- /**
3585
- * 创建 H5 签署短链(写,step-up 必须)。
3586
- *
3587
- * `@status gated` {@link signEnvelope}:服务端闸门关闭时 SDK 不重试、不伪成功。
3588
- */
3589
- createH5SigningUrl(envelopeId, req, opts = {}) {
3590
- return this.write(
3591
- "POST",
3592
- `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}/h5-url`,
3593
- req,
3594
- writeCtx(opts)
3595
- );
3512
+ return parts.join("");
3513
+ }
3514
+ function anthropicResponseToolUseBlocks(r) {
3515
+ return r.content.filter((b) => b.type === "tool_use");
3516
+ }
3517
+
3518
+ // src/models/model-helpers.ts
3519
+ function modelSupportsInputModality(model, modality) {
3520
+ if (!model) return false;
3521
+ const mods = model.inputModalities;
3522
+ if (!Array.isArray(mods)) return false;
3523
+ return mods.includes(modality);
3524
+ }
3525
+ function modelSupportsImageInput(model) {
3526
+ return modelSupportsInputModality(model, "image");
3527
+ }
3528
+ function findFirstModelByInputModality(models, modality) {
3529
+ if (!Array.isArray(models)) return null;
3530
+ for (const m of models) {
3531
+ if (!m) continue;
3532
+ if (m.isEnabled === false) continue;
3533
+ if (!modelSupportsInputModality(m, modality)) continue;
3534
+ return m;
3596
3535
  }
3597
- /** 同步 provider 状态(写但只读对账,不创建新 provider 请求)。 */
3598
- syncSigningEnvelopeStatus(envelopeId, opts = {}) {
3599
- return this.write(
3600
- "POST",
3601
- `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}/sync-provider-status`,
3602
- null,
3603
- writeCtx(opts)
3604
- );
3536
+ return null;
3537
+ }
3538
+ function findDesktopVisualUnderstandingModel(models) {
3539
+ if (!Array.isArray(models)) return null;
3540
+ const candidates = [];
3541
+ for (const m of models) {
3542
+ if (!m) continue;
3543
+ if (m.isEnabled === false) continue;
3544
+ if (m.capabilities?.supports_desktop_visual_understanding !== true) continue;
3545
+ if (!modelSupportsInputModality(m, "image")) continue;
3546
+ candidates.push(m);
3605
3547
  }
3606
- // =========================================================================
3607
- // Seal Approval
3608
- // =========================================================================
3609
- /**
3610
- * 提交用印审批申请(写)。
3611
- *
3612
- * `@status production-ready` — 服务端以 `Idempotency-Key` + 业务请求指纹做重放保护:
3613
- * 同 key + 同请求 → 返回原审批 id;同 key + 不同请求 → 拒绝复用幂等键。强烈建议调用方
3614
- * 持久化 `idempotencyKey`,网络重试 / 任务恢复时复用,避免重复创建审批单。
3615
- */
3616
- submitSealApproval(req, opts = {}) {
3617
- return this.write(
3618
- "POST",
3619
- "/compliance/seal-approvals",
3620
- req,
3621
- writeCtx(opts)
3622
- );
3548
+ if (candidates.length === 0) return null;
3549
+ for (const m of candidates) {
3550
+ if (m.isDefault === true) return m;
3623
3551
  }
3624
- /**
3625
- * 审批通过用印申请(写,step-up 必须)。
3626
- *
3627
- * `@status gated` — step-up 未闭合前服务端会返回 `COMPLIANCE_STEP_UP_REQUIRED`。
3628
- * SDK 不重试、不伪成功。方法状态分级见 `docs/compliance.md` Method Status。
3629
- */
3630
- approveSealApproval(id, query, opts = {}) {
3631
- const q = new URLSearchParams();
3632
- if (query.expiresAt) q.set("expiresAt", query.expiresAt);
3633
- if (query.note) q.set("note", query.note);
3634
- const qs = q.toString();
3635
- return this.write(
3636
- "POST",
3637
- `/compliance/seal-approvals/${encodeURIComponent(id)}/approve${qs ? "?" + qs : ""}`,
3638
- null,
3639
- writeCtx(opts)
3640
- );
3641
- }
3642
- rejectSealApproval(id, query, opts = {}) {
3643
- const q = new URLSearchParams();
3644
- if (query.reason) q.set("reason", query.reason);
3645
- const qs = q.toString();
3646
- return this.write(
3647
- "POST",
3648
- `/compliance/seal-approvals/${encodeURIComponent(id)}/reject${qs ? "?" + qs : ""}`,
3649
- null,
3650
- writeCtx(opts)
3651
- );
3652
- }
3653
- cancelSealApproval(id, query, opts = {}) {
3654
- const q = new URLSearchParams();
3655
- if (query.reason) q.set("reason", query.reason);
3656
- const qs = q.toString();
3657
- return this.write(
3658
- "POST",
3659
- `/compliance/seal-approvals/${encodeURIComponent(id)}/cancel${qs ? "?" + qs : ""}`,
3660
- null,
3661
- writeCtx(opts)
3662
- );
3663
- }
3664
- listPendingSealApprovals(signal) {
3665
- return this.read(
3666
- "GET",
3667
- "/compliance/seal-approvals/pending",
3668
- null,
3669
- signal
3670
- );
3671
- }
3672
- getSealApproval(id, signal) {
3673
- return this.read(
3674
- "GET",
3675
- `/compliance/seal-approvals/${encodeURIComponent(id)}`,
3676
- null,
3677
- signal
3678
- );
3679
- }
3680
- // =========================================================================
3681
- // Provider Request (read-only)
3682
- // =========================================================================
3683
- getProviderRequest(id, signal) {
3684
- return this.read(
3685
- "GET",
3686
- `/compliance/provider-requests/${encodeURIComponent(id)}`,
3687
- null,
3688
- signal
3689
- );
3552
+ return candidates[0];
3553
+ }
3554
+
3555
+ // src/models/index.ts
3556
+ init_adapters();
3557
+ init_betas();
3558
+
3559
+ // src/billing/entitlements.ts
3560
+ Client.prototype.getBalance = async function(signal) {
3561
+ const resp = await this.doJSON(
3562
+ "GET",
3563
+ "/entitlements/balance",
3564
+ null,
3565
+ signal
3566
+ );
3567
+ return resp.data;
3568
+ };
3569
+ Client.prototype.getBalanceDetail = async function(signal) {
3570
+ const resp = await this.doJSON(
3571
+ "GET",
3572
+ "/entitlements/balance-detail",
3573
+ null,
3574
+ signal
3575
+ );
3576
+ return resp.data;
3577
+ };
3578
+ Client.prototype.listEntitlements = async function(status, signal) {
3579
+ let path = "/entitlements";
3580
+ if (status !== "") {
3581
+ path += `?status=${encodeURIComponent(status)}`;
3690
3582
  }
3691
- /**
3692
- * 轮询 provider request 到 SUCCESS / FAILED 终态。
3693
- * - SUCCESS / FAILED → 返回最后视图;
3694
- * - UNKNOWN / RETRYING / PENDING → 继续轮询;
3695
- * - timeout → 抛 {@link CompliancePollError} kind='timeout',不自动重发原 provider 请求。
3696
- *
3697
- * SUCCESS 不代表 billing 已 commit;调用方仍需通过业务侧 envelope / asset 终态判断。
3698
- */
3699
- async waitForProviderRequestTerminal(id, opts = {}) {
3700
- return this.poll(
3701
- () => this.getProviderRequest(id, opts.signal),
3702
- (v) => classifyProviderStatus(v.status),
3703
- opts
3704
- );
3583
+ const resp = await this.doJSON("GET", path, null, signal);
3584
+ return resp.data;
3585
+ };
3586
+ Client.prototype.listConsumeRecords = async function(page, pageSize, signal) {
3587
+ const path = `/entitlements/consume-records?page=${page}&pageSize=${pageSize}`;
3588
+ const resp = await this.doJSON("GET", path, null, signal);
3589
+ return resp.data;
3590
+ };
3591
+ Client.prototype.claimMonthlyFree = async function(signal) {
3592
+ const resp = await this.doJSON(
3593
+ "POST",
3594
+ "/entitlements/claim-monthly",
3595
+ null,
3596
+ signal
3597
+ );
3598
+ return resp.data;
3599
+ };
3600
+ Client.prototype.getByModel = async function(modelID, signal) {
3601
+ if (modelID === "") throw new Error("modelID required");
3602
+ const path = `/entitlements/by-model?modelId=${encodeURIComponent(modelID)}`;
3603
+ const resp = await this.doJSON("GET", path, null, signal);
3604
+ return resp.data;
3605
+ };
3606
+ Client.prototype.listBuckets = async function(signal) {
3607
+ const resp = await this.doJSON(
3608
+ "GET",
3609
+ "/entitlements/buckets",
3610
+ null,
3611
+ signal
3612
+ );
3613
+ return resp.data;
3614
+ };
3615
+ Client.prototype.listCoefficients = async function(signal) {
3616
+ if (this.coefCacheData && Date.now() - this.coefCacheTimeMs < coefCacheTTLMs) {
3617
+ return [...this.coefCacheData];
3705
3618
  }
3706
- // =========================================================================
3707
- // Error classification (re-export for convenience)
3708
- // =========================================================================
3709
- classifyError(err) {
3710
- if (!isBusinessErrorLike(err)) return null;
3711
- if (!isComplianceBusinessError(err)) return null;
3712
- return classifyComplianceError(err);
3619
+ const resp = await this.doJSON(
3620
+ "GET",
3621
+ "/entitlements/coefficients",
3622
+ null,
3623
+ signal
3624
+ );
3625
+ this.coefCacheData = [...resp.data];
3626
+ this.coefCacheTimeMs = Date.now();
3627
+ return resp.data;
3628
+ };
3629
+ Client.prototype.invalidateCoefficientCache = function() {
3630
+ this.coefCacheData = null;
3631
+ this.coefCacheTimeMs = 0;
3632
+ };
3633
+
3634
+ // src/billing/packages.ts
3635
+ init_errors();
3636
+ Client.prototype.listTokenPackages = async function(signal) {
3637
+ const raw = await this.doJSON("GET", "/token-packages", null, signal);
3638
+ if (raw.data && typeof raw.data === "object" && "list" in raw.data) {
3639
+ const page = raw.data;
3640
+ if (Array.isArray(page.list)) return page.list;
3713
3641
  }
3714
- // =========================================================================
3715
- // Internal helpers
3716
- // =========================================================================
3717
- /**
3718
- * 读路径:GET / 公开 verify。允许 401 单次刷新后重放(GET 幂等安全)。
3719
- * 与 client.doJSONFullInternal 行为一致;不复用其代码因为 base URL 不同。
3720
- */
3721
- async read(method, path, body, signal, extraHeaders = {}) {
3722
- return this.executeJson(method, path, body, signal, {
3723
- retryOn401: true,
3724
- extraHeaders
3725
- });
3642
+ if (Array.isArray(raw.data)) return raw.data;
3643
+ throw new Error("decode token packages: unexpected shape");
3644
+ };
3645
+ Client.prototype.getTokenPackageDetail = async function(packageID, signal) {
3646
+ const resp = await this.doJSON(
3647
+ "GET",
3648
+ `/token-packages/${encodeURIComponent(packageID)}`,
3649
+ null,
3650
+ signal
3651
+ );
3652
+ return resp.data;
3653
+ };
3654
+ Client.prototype.buyTokenPackage = async function(packageID, payload, signal) {
3655
+ const body = payload ?? null;
3656
+ const resp = await this.doJSON(
3657
+ "POST",
3658
+ `/token-packages/${encodeURIComponent(packageID)}/buy`,
3659
+ body,
3660
+ signal
3661
+ );
3662
+ return resp.data;
3663
+ };
3664
+ Client.prototype.getOrderStatus = async function(orderID, signal) {
3665
+ const resp = await this.doJSON(
3666
+ "GET",
3667
+ `/token-packages/orders/${encodeURIComponent(orderID)}/status`,
3668
+ null,
3669
+ signal
3670
+ );
3671
+ return resp.data;
3672
+ };
3673
+ Client.prototype.listMyOrders = async function(signal) {
3674
+ const raw = await this.doJSON("GET", "/token-packages/my", null, signal);
3675
+ if (raw.data && typeof raw.data === "object" && "list" in raw.data) {
3676
+ const page = raw.data;
3677
+ if (Array.isArray(page.list)) return page.list;
3726
3678
  }
3727
- /**
3728
- * 公开读路径:public verify。
3729
- *
3730
- * {@link read} 的区别 public 端点不应要求认证:
3731
- * - token 时匿名请求:ensureToken `not authorized` 会被吞掉,继续匿名发送。
3732
- * - token 时附带 `Authorization`,保留后端审计上下文。
3733
- * - 不做 401 refresh replay:401 直接抛 HTTPError,不触发 `forceRefresh`。
3734
- *
3735
- * URL 仍走 `client.complianceURL(path)`,不复用 `/api/v4`;底层复用
3736
- * `client.doRequest`,不新增 fetch/axios 直连。
3737
- */
3738
- async publicRead(method, path, signal) {
3739
- let token = "";
3740
- try {
3741
- token = await this.client.ensureToken(signal);
3742
- } catch {
3743
- }
3744
- const url = this.client.complianceURL(path);
3745
- const headers = { Accept: "application/json" };
3746
- if (token) headers.Authorization = `Bearer ${token}`;
3747
- const resp = await this.client.doRequest({ method, url, headers }, signal);
3748
- if (resp.status < 200 || resp.status >= 300) {
3749
- const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
3750
- throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
3679
+ if (Array.isArray(raw.data)) return raw.data;
3680
+ throw new Error("decode orders: unexpected shape");
3681
+ };
3682
+ Client.prototype.waitForPayment = async function(orderID, pollIntervalMs, signal) {
3683
+ if (pollIntervalMs <= 0) pollIntervalMs = 2e3;
3684
+ while (true) {
3685
+ const status = await this.getOrderStatus(orderID, signal);
3686
+ if (isOrderTerminal(status.status)) {
3687
+ if (isOrderSuccess(status.status)) return status;
3688
+ throw new exports.OrderTerminalError(orderID, status.status);
3751
3689
  }
3752
- const text = await resp.text();
3753
- if (!text) return void 0;
3754
- const parsed = JSON.parse(text);
3755
- const bizErr = apiResponseBusinessError(parsed);
3756
- if (bizErr) throw bizErr;
3757
- return parsed.data;
3690
+ await sleepWithSignal(pollIntervalMs, signal);
3758
3691
  }
3759
- /**
3760
- * 写路径:POST。
3761
- * - 发送前 ensureToken 一次确保 token fresh。
3762
- * - 不自动 401 重放:401 抛 HTTPError;调用方必须自己刷新 token 后用同一
3763
- * idempotency-key 重新发起,避免 provider 侧重复请求。
3764
- * - 不走 doRequestWithRetry:写操作不允许 5xx/timeout 自动重试。
3765
- */
3766
- async write(method, path, body, ctx) {
3767
- const headers = { ...ctx.extraHeaders ?? {} };
3768
- if (ctx.idempotencyKey) headers["Idempotency-Key"] = ctx.idempotencyKey;
3769
- return this.executeJson(method, path, body, ctx.signal, {
3770
- retryOn401: false,
3771
- extraHeaders: headers
3772
- });
3692
+ };
3693
+ async function sleepWithSignal(ms, signal) {
3694
+ if (ms <= 0) return;
3695
+ if (signal && signal.aborted) throw new Error("aborted");
3696
+ return new Promise((resolve, reject) => {
3697
+ const t = setTimeout(() => {
3698
+ if (signal && abortHandler) signal.removeEventListener("abort", abortHandler);
3699
+ resolve();
3700
+ }, ms);
3701
+ let abortHandler;
3702
+ if (signal) {
3703
+ abortHandler = () => {
3704
+ clearTimeout(t);
3705
+ signal.removeEventListener("abort", abortHandler);
3706
+ reject(new Error("aborted"));
3707
+ };
3708
+ signal.addEventListener("abort", abortHandler);
3709
+ }
3710
+ });
3711
+ }
3712
+
3713
+ // src/billing/wallet.ts
3714
+ Client.prototype.getWalletStats = async function(signal) {
3715
+ const resp = await this.doJSON("GET", "/wallet/stats", null, signal);
3716
+ return resp.data;
3717
+ };
3718
+ Client.prototype.getWalletTransactions = async function(signal) {
3719
+ const resp = await this.doJSON(
3720
+ "GET",
3721
+ "/wallet/transactions",
3722
+ null,
3723
+ signal
3724
+ );
3725
+ return resp.data;
3726
+ };
3727
+
3728
+ // src/skills/skills.ts
3729
+ init_errors();
3730
+ Client.prototype.browseSkillStore = async function(query, signal) {
3731
+ const resp = await this.browseSkills(
3732
+ 1,
3733
+ 50,
3734
+ query.category ?? "",
3735
+ query.keyword ?? "",
3736
+ query.tag ?? "",
3737
+ "",
3738
+ signal
3739
+ );
3740
+ return resp.items;
3741
+ };
3742
+ Client.prototype.browseSkills = async function(page, pageSize, category, keyword, tag, source, signal) {
3743
+ const qv = new URLSearchParams();
3744
+ qv.set("page", String(page));
3745
+ qv.set("pageSize", String(pageSize));
3746
+ if (category) qv.set("category", category);
3747
+ if (keyword) qv.set("keyword", keyword);
3748
+ if (tag) qv.set("tag", tag);
3749
+ if (source) qv.set("source", source);
3750
+ const resp = await this.doPublicJSON(
3751
+ "GET",
3752
+ `/skill-store?${qv.toString()}`,
3753
+ null,
3754
+ signal
3755
+ );
3756
+ return resp.data;
3757
+ };
3758
+ Client.prototype.browseSkillsList = async function(page, pageSize, category, keyword, tag, source, signal) {
3759
+ const qv = new URLSearchParams();
3760
+ qv.set("page", String(page));
3761
+ qv.set("pageSize", String(pageSize));
3762
+ qv.set("fields", "minimal");
3763
+ if (category) qv.set("category", category);
3764
+ if (keyword) qv.set("keyword", keyword);
3765
+ if (tag) qv.set("tag", tag);
3766
+ if (source) qv.set("source", source);
3767
+ const resp = await this.doPublicJSON(
3768
+ "GET",
3769
+ `/skill-store?${qv.toString()}`,
3770
+ null,
3771
+ signal
3772
+ );
3773
+ return resp.data;
3774
+ };
3775
+ Client.prototype.getSkillDetail = async function(skillID, signal) {
3776
+ const resp = await this.doPublicJSON(
3777
+ "GET",
3778
+ `/skill-store/${encodeURIComponent(skillID)}`,
3779
+ null,
3780
+ signal
3781
+ );
3782
+ return resp.data;
3783
+ };
3784
+ Client.prototype.resolveSkill = async function(key, signal) {
3785
+ const resp = await this.doPublicJSON(
3786
+ "GET",
3787
+ `/skill-store/resolve/${encodeURIComponent(key)}`,
3788
+ null,
3789
+ signal
3790
+ );
3791
+ return resp.data;
3792
+ };
3793
+ Client.prototype.installSkill = async function(skillID, signal) {
3794
+ const resp = await this.doJSON(
3795
+ "POST",
3796
+ `/skill-store/${encodeURIComponent(skillID)}/install`,
3797
+ null,
3798
+ signal
3799
+ );
3800
+ return resp.data;
3801
+ };
3802
+ Client.prototype.downloadSkill = async function(skillID, signal) {
3803
+ const ctl = new AbortController();
3804
+ const timer = setTimeout(() => ctl.abort(), 5 * 60 * 1e3);
3805
+ let parentHandler;
3806
+ if (signal) {
3807
+ if (signal.aborted) ctl.abort();
3808
+ else {
3809
+ parentHandler = () => ctl.abort();
3810
+ signal.addEventListener("abort", parentHandler);
3811
+ }
3773
3812
  }
3774
- async executeJson(method, path, body, signal, opts, retried = false) {
3775
- const token = await this.client.ensureToken(signal);
3776
- const url = this.client.complianceURL(path);
3777
- const headers = {
3778
- Authorization: `Bearer ${token}`,
3779
- Accept: "application/json",
3780
- ...opts.extraHeaders
3781
- };
3782
- let bodyStr;
3783
- if (body != null) {
3784
- bodyStr = typeof body === "string" ? body : JSON.stringify(body);
3785
- headers["Content-Type"] = "application/json";
3813
+ try {
3814
+ const url = this.apiURL(`/skill-store/${encodeURIComponent(skillID)}/download`);
3815
+ const headers = {};
3816
+ let token = "";
3817
+ try {
3818
+ token = await this.ensureToken(ctl.signal);
3819
+ } catch {
3786
3820
  }
3787
- const resp = await this.client.doRequest({ method, url, headers, body: bodyStr }, signal);
3788
- if (resp.status === 401 && opts.retryOn401 && !retried) {
3821
+ if (token) headers["Authorization"] = `Bearer ${token}`;
3822
+ let resp;
3823
+ try {
3824
+ resp = await this.fetchImpl(url, { method: "GET", headers, signal: ctl.signal });
3825
+ } catch (e) {
3826
+ throw classifyTransport(`GET /skill-store/${skillID}/download`, url, e);
3827
+ }
3828
+ if (resp.status === 429) {
3829
+ const bodyText = await readLimitedText(resp.body, maxErrorBodySize);
3830
+ throw new exports.RateLimitError("\u533F\u540D\u4E0B\u8F7D\u5DF2\u8FBE\u9650\u5236", resp.headers.get("Retry-After") ?? "", bodyText);
3831
+ }
3832
+ if (!resp.ok) {
3833
+ const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
3834
+ throw new Error(
3835
+ `download skill: ${parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers).message}`
3836
+ );
3837
+ }
3838
+ const data = await readLimited(resp.body, maxDownloadSize + 1);
3839
+ if (data.byteLength > maxDownloadSize) {
3840
+ throw new Error(`download skill: response exceeds ${maxDownloadSize >> 20}MB limit`);
3841
+ }
3842
+ let filename = "skill.zip";
3843
+ const cd = resp.headers.get("Content-Disposition");
3844
+ if (cd) {
3845
+ const idx = cd.indexOf("filename");
3846
+ if (idx !== -1) {
3847
+ const parts = cd.slice(idx).split("=", 2);
3848
+ if (parts.length === 2) {
3849
+ filename = parts[1].trim().replace(/^["' ]+|["' ]+$/g, "");
3850
+ }
3851
+ }
3852
+ }
3853
+ return { data, filename };
3854
+ } finally {
3855
+ clearTimeout(timer);
3856
+ if (parentHandler && signal) signal.removeEventListener("abort", parentHandler);
3857
+ }
3858
+ };
3859
+ Client.prototype.uploadSkill = async function(zipData, scope, intent, signal) {
3860
+ return uploadSkillInternal(this, zipData, scope, intent, false, signal);
3861
+ };
3862
+ async function uploadSkillInternal(c, zipData, scope, intent, retried, signal) {
3863
+ const ctl = new AbortController();
3864
+ const timer = setTimeout(() => ctl.abort(), 5 * 60 * 1e3);
3865
+ let parentHandler;
3866
+ if (signal) {
3867
+ if (signal.aborted) ctl.abort();
3868
+ else {
3869
+ parentHandler = () => ctl.abort();
3870
+ signal.addEventListener("abort", parentHandler);
3871
+ }
3872
+ }
3873
+ try {
3874
+ const token = await c.ensureToken(ctl.signal);
3875
+ const form = new FormData();
3876
+ form.append("scope", scope);
3877
+ form.append("intent", intent);
3878
+ const blob = new Blob([zipData], { type: "application/zip" });
3879
+ form.append("file", blob, "skill.zip");
3880
+ const url = c.apiURL("/skill-store/upload");
3881
+ let resp;
3882
+ try {
3883
+ resp = await c.fetchImpl(url, {
3884
+ method: "POST",
3885
+ headers: { Authorization: `Bearer ${token}` },
3886
+ body: form,
3887
+ signal: ctl.signal
3888
+ });
3889
+ } catch (e) {
3890
+ throw classifyTransport("POST /skill-store/upload", url, e);
3891
+ }
3892
+ if (resp.status === 401 && !retried) {
3789
3893
  try {
3790
3894
  await resp.body?.cancel();
3791
3895
  } catch {
3792
3896
  }
3793
- await this.client.forceRefresh(signal);
3794
- return this.executeJson(method, path, body, signal, opts, true);
3897
+ try {
3898
+ await c.forceRefresh(ctl.signal);
3899
+ } catch (refreshErr) {
3900
+ throw new Error(
3901
+ `upload: unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
3902
+ );
3903
+ }
3904
+ return uploadSkillInternal(c, zipData, scope, intent, true, signal);
3795
3905
  }
3796
3906
  if (resp.status < 200 || resp.status >= 300) {
3797
- const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
3798
- throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
3907
+ const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
3908
+ throw new Error(
3909
+ `upload: ${parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers).message}`
3910
+ );
3799
3911
  }
3800
3912
  const text = await resp.text();
3801
- if (!text) return void 0;
3802
- const parsed = JSON.parse(text);
3803
- const bizErr = apiResponseBusinessError(parsed);
3804
- if (bizErr) throw bizErr;
3805
- return parsed.data;
3913
+ const result = JSON.parse(text);
3914
+ return result.data.skill;
3915
+ } finally {
3916
+ clearTimeout(timer);
3917
+ if (parentHandler && signal) signal.removeEventListener("abort", parentHandler);
3806
3918
  }
3807
- async poll(fetcher, classify, opts) {
3808
- const cfg = {
3809
- timeoutMs: opts.timeoutMs ?? DEFAULT_POLL.timeoutMs,
3810
- initialIntervalMs: opts.initialIntervalMs ?? DEFAULT_POLL.initialIntervalMs,
3811
- maxIntervalMs: opts.maxIntervalMs ?? DEFAULT_POLL.maxIntervalMs,
3812
- multiplier: opts.multiplier ?? DEFAULT_POLL.multiplier
3813
- };
3814
- const deadline = Date.now() + cfg.timeoutMs;
3815
- let interval = cfg.initialIntervalMs;
3816
- let lastValue;
3817
- while (Date.now() < deadline) {
3818
- if (opts.signal?.aborted) {
3819
- throw new CompliancePollError("compliance poll aborted", "unknown");
3820
- }
3821
- lastValue = await fetcher();
3822
- const decision = classify(lastValue);
3823
- if (decision === "done") return lastValue;
3824
- if (decision === "failed") {
3825
- throw new CompliancePollError(
3826
- "compliance poll observed terminal failure",
3827
- "terminal_failure"
3828
- );
3829
- }
3830
- const sleepMs = Math.min(interval, deadline - Date.now());
3831
- if (sleepMs <= 0) break;
3832
- await sleep2(sleepMs, opts.signal);
3833
- interval = Math.min(Math.floor(interval * cfg.multiplier), cfg.maxIntervalMs);
3834
- }
3835
- throw new CompliancePollError("compliance poll timed out", "timeout");
3836
- }
3837
- };
3838
- function classifyTimestamp(status) {
3839
- switch (status) {
3840
- case "VERIFIED":
3841
- return "done";
3842
- case "FAILED":
3843
- case "LOCAL_VERIFY_FAILED":
3844
- return "failed";
3845
- case "PENDING":
3846
- case "UNKNOWN":
3847
- case "RETRYING":
3848
- default:
3849
- return "continue";
3850
- }
3851
- }
3852
- function classifyProviderStatus(status) {
3853
- switch (status) {
3854
- case "SUCCESS":
3855
- return "done";
3856
- case "FAILED":
3857
- return "failed";
3858
- case "PENDING":
3859
- case "UNKNOWN":
3860
- case "RETRYING":
3861
- default:
3862
- return "continue";
3863
- }
3864
- }
3865
- function writeCtx(opts, extraHeaders = {}) {
3866
- return {
3867
- idempotencyKey: opts.idempotencyKey,
3868
- signal: opts.signal,
3869
- extraHeaders
3870
- };
3871
- }
3872
- function isBusinessErrorLike(err) {
3873
- if (err == null || typeof err !== "object") return false;
3874
- return typeof err.code === "number";
3875
- }
3876
- function sleep2(ms, signal) {
3877
- return new Promise((resolve, reject) => {
3878
- if (signal?.aborted) {
3879
- reject(new CompliancePollError("compliance poll aborted", "unknown"));
3880
- return;
3881
- }
3882
- const timer = setTimeout(() => {
3883
- signal?.removeEventListener("abort", onAbort);
3884
- resolve();
3885
- }, ms);
3886
- const onAbort = () => {
3887
- clearTimeout(timer);
3888
- signal?.removeEventListener("abort", onAbort);
3889
- reject(new CompliancePollError("compliance poll aborted", "unknown"));
3890
- };
3891
- signal?.addEventListener("abort", onAbort, { once: true });
3892
- });
3893
3919
  }
3894
-
3895
- // src/sanitize/index.ts
3896
- var sanitize_exports = {};
3897
- __export(sanitize_exports, {
3898
- BlockCodeExecutionToolResult: () => BlockCodeExecutionToolResult,
3899
- BlockContainerUpload: () => BlockContainerUpload,
3900
- BlockDeniedError: () => BlockDeniedError,
3901
- BlockDocument: () => BlockDocument,
3902
- BlockImage: () => BlockImage,
3903
- BlockMCPToolResult: () => BlockMCPToolResult,
3904
- BlockMCPToolUse: () => BlockMCPToolUse,
3905
- BlockRedactedThinking: () => BlockRedactedThinking,
3906
- BlockSearchResult: () => BlockSearchResult,
3907
- BlockServerToolUse: () => BlockServerToolUse,
3908
- BlockText: () => BlockText,
3909
- BlockThinking: () => BlockThinking,
3910
- BlockToolReference: () => BlockToolReference,
3911
- BlockToolResult: () => BlockToolResult,
3912
- BlockToolUse: () => BlockToolUse,
3913
- BlockVideo: () => BlockVideo,
3914
- BlockWebSearchToolResult: () => BlockWebSearchToolResult,
3915
- DeltaCitations: () => DeltaCitations,
3916
- DeltaInputJSON: () => DeltaInputJSON,
3917
- DeltaSignature: () => DeltaSignature,
3918
- DeltaText: () => DeltaText,
3919
- DeltaThinking: () => DeltaThinking,
3920
- EphemeralMarkerField: () => EphemeralMarkerField,
3921
- ErrBlockDenied: () => ErrBlockDenied,
3922
- ErrHistoryTooDeep: () => ErrHistoryTooDeep,
3923
- HistoryTooDeepError: () => HistoryTooDeepError,
3924
- SizeError: () => SizeError,
3925
- dropBlocks: () => dropBlocks,
3926
- sanitize: () => sanitize,
3927
- stripEphemeral: () => stripEphemeral
3928
- });
3929
-
3930
- // src/sanitize/types.ts
3931
- var BlockText = "text";
3932
- var BlockImage = "image";
3933
- var BlockVideo = "video";
3934
- var BlockDocument = "document";
3935
- var BlockSearchResult = "search_result";
3936
- var BlockThinking = "thinking";
3937
- var BlockRedactedThinking = "redacted_thinking";
3938
- var BlockToolUse = "tool_use";
3939
- var BlockToolResult = "tool_result";
3940
- var BlockToolReference = "tool_reference";
3941
- var BlockServerToolUse = "server_tool_use";
3942
- var BlockWebSearchToolResult = "web_search_tool_result";
3943
- var BlockCodeExecutionToolResult = "code_execution_tool_result";
3944
- var BlockMCPToolUse = "mcp_tool_use";
3945
- var BlockMCPToolResult = "mcp_tool_result";
3946
- var BlockContainerUpload = "container_upload";
3947
- var DeltaText = "text_delta";
3948
- var DeltaInputJSON = "input_json_delta";
3949
- var DeltaThinking = "thinking_delta";
3950
- var DeltaSignature = "signature_delta";
3951
- var DeltaCitations = "citations_delta";
3952
- var EphemeralMarkerField = "acosmi_ephemeral";
3953
-
3954
- // src/sanitize/config.ts
3955
- var HistoryTooDeepError = class extends Error {
3956
- constructor() {
3957
- super("sanitize: messages history exceeds configured depth");
3958
- this.name = "HistoryTooDeepError";
3959
- }
3920
+ Client.prototype.getSkillSummary = async function(signal) {
3921
+ const resp = await this.doJSON("GET", "/skills/summary", null, signal);
3922
+ return resp.data;
3960
3923
  };
3961
- var BlockDeniedError = class extends Error {
3962
- constructor() {
3963
- super("sanitize: block type permanently denied");
3964
- this.name = "BlockDeniedError";
3965
- }
3924
+ Client.prototype.certifySkill = async function(skillID, signal) {
3925
+ await this.doJSON(
3926
+ "POST",
3927
+ `/skill-store/${encodeURIComponent(skillID)}/certify`,
3928
+ null,
3929
+ signal
3930
+ );
3966
3931
  };
3967
- var SizeError = class extends Error {
3968
- blockType;
3969
- actual;
3970
- limit;
3971
- constructor(blockType, actual, limit) {
3972
- super(`sanitize: ${blockType} base64 size ${actual} exceeds limit ${limit}`);
3973
- this.name = "SizeError";
3974
- this.blockType = blockType;
3975
- this.actual = actual;
3976
- this.limit = limit;
3977
- }
3932
+ Client.prototype.getCertificationStatus = async function(skillID, signal) {
3933
+ const resp = await this.doJSON(
3934
+ "GET",
3935
+ `/skill-store/${encodeURIComponent(skillID)}/certification`,
3936
+ null,
3937
+ signal
3938
+ );
3939
+ return resp.data;
3940
+ };
3941
+ Client.prototype.generateSkill = async function(req, signal) {
3942
+ const resp = await this.doJSON(
3943
+ "POST",
3944
+ "/skill-generator/generate",
3945
+ req,
3946
+ signal
3947
+ );
3948
+ return resp.data;
3949
+ };
3950
+ Client.prototype.optimizeSkill = async function(req, signal) {
3951
+ const resp = await this.doJSON(
3952
+ "POST",
3953
+ "/skill-generator/optimize",
3954
+ req,
3955
+ signal
3956
+ );
3957
+ return resp.data;
3958
+ };
3959
+ Client.prototype.validateSkill = async function(skillName, signal) {
3960
+ await this.doJSON(
3961
+ "POST",
3962
+ "/skill-generator/validate",
3963
+ { skillName },
3964
+ signal
3965
+ );
3978
3966
  };
3979
- var ErrHistoryTooDeep = new HistoryTooDeepError();
3980
- var ErrBlockDenied = new BlockDeniedError();
3981
3967
 
3982
- // src/sanitize/history.ts
3983
- function dropBlocks(messages, pred) {
3984
- const droppedToolUseIDs = collectDroppedToolUseIDs(messages, pred);
3985
- const out = [];
3986
- for (const msg of messages) {
3987
- if (!isPlainObject(msg)) {
3988
- out.push(msg);
3989
- continue;
3990
- }
3991
- const content = msg["content"];
3992
- if (!Array.isArray(content)) {
3993
- out.push(msg);
3994
- continue;
3995
- }
3996
- const { kept, changed } = filterBlocks(content, pred, droppedToolUseIDs);
3997
- if (!changed) {
3998
- out.push(msg);
3999
- continue;
4000
- }
4001
- if (kept.length === 0) {
4002
- continue;
3968
+ // src/skills/tools.ts
3969
+ Client.prototype.listTools = async function(signal) {
3970
+ const resp = await this.doJSON("GET", "/tools", null, signal);
3971
+ return resp.data.skills;
3972
+ };
3973
+ Client.prototype.getTool = async function(toolID, signal) {
3974
+ const resp = await this.doJSON(
3975
+ "GET",
3976
+ `/tools/${encodeURIComponent(toolID)}`,
3977
+ null,
3978
+ signal
3979
+ );
3980
+ return resp.data;
3981
+ };
3982
+
3983
+ // src/notifications/types.ts
3984
+ function parseNotificationEvent(ev) {
3985
+ if (ev.type !== "event" || ev.topic !== "system") {
3986
+ return null;
3987
+ }
3988
+ if (ev.data == null) return null;
3989
+ let n;
3990
+ try {
3991
+ if (typeof ev.data === "string") {
3992
+ n = JSON.parse(ev.data);
3993
+ } else {
3994
+ n = ev.data;
4003
3995
  }
4004
- const newMsg = { ...msg };
4005
- newMsg["content"] = kept;
4006
- out.push(newMsg);
3996
+ } catch {
3997
+ return null;
4007
3998
  }
4008
- return out;
4009
- }
4010
- function collectDroppedToolUseIDs(messages, pred) {
4011
- const ids = /* @__PURE__ */ new Set();
4012
- for (const msg of messages) {
4013
- if (!isPlainObject(msg)) continue;
4014
- const content = msg["content"];
4015
- if (!Array.isArray(content)) continue;
4016
- for (const raw of content) {
4017
- if (!isPlainObject(raw)) continue;
4018
- if (!pred(raw)) continue;
4019
- const t = raw["type"];
4020
- if (typeof t !== "string") continue;
4021
- if (t === "tool_use" || t === "server_tool_use" || t === "mcp_tool_use") {
4022
- const id = raw["id"];
4023
- if (typeof id === "string" && id !== "") ids.add(id);
4024
- }
4025
- }
4026
- }
4027
- return ids;
4028
- }
4029
- function filterBlocks(content, pred, droppedToolUseIDs) {
4030
- const kept = [];
4031
- let changed = false;
4032
- for (const raw of content) {
4033
- if (!isPlainObject(raw)) {
4034
- kept.push(raw);
4035
- continue;
4036
- }
4037
- if (pred(raw)) {
4038
- changed = true;
4039
- continue;
4040
- }
4041
- if (droppedToolUseIDs.size > 0) {
4042
- const t = raw["type"];
4043
- if (t === "tool_result" || t === "mcp_tool_result") {
4044
- const id = raw["tool_use_id"];
4045
- if (typeof id === "string" && id !== "" && droppedToolUseIDs.has(id)) {
4046
- changed = true;
4047
- continue;
4048
- }
4049
- }
4050
- }
4051
- kept.push(raw);
4052
- }
4053
- return { kept, changed };
4054
- }
4055
- function stripEphemeral(messages) {
4056
- return dropBlocks(messages, (b) => {
4057
- const t = b["type"];
4058
- if (t === "thinking" || t === "redacted_thinking") {
4059
- return false;
4060
- }
4061
- const v = b[EphemeralMarkerField];
4062
- return v === true;
4063
- });
4064
- }
4065
- function isPlainObject(v) {
4066
- return typeof v === "object" && v !== null && !Array.isArray(v);
3999
+ if (!n.id) return null;
4000
+ return n;
4067
4001
  }
4068
4002
 
4069
- // src/sanitize/defensive.ts
4070
- function sanitize(messages, cfg) {
4071
- if ((cfg.maxMessagesTurns ?? 0) > 0 && messages.length > cfg.maxMessagesTurns) {
4072
- throw ErrHistoryTooDeep;
4073
- }
4074
- if ((cfg.maxImageBytes ?? 0) > 0 || (cfg.maxVideoBytes ?? 0) > 0 || (cfg.maxPDFBytes ?? 0) > 0) {
4075
- checkMediaSizes(messages, cfg);
4076
- }
4077
- if (cfg.permanentDenyBlocks && cfg.permanentDenyBlocks.length > 0) {
4078
- const denySet = /* @__PURE__ */ new Set();
4079
- for (const bt of cfg.permanentDenyBlocks) denySet.add(bt);
4080
- messages = dropBlocks(messages, (b) => {
4081
- const t = b["type"];
4082
- return typeof t === "string" && denySet.has(t);
4083
- });
4003
+ // src/notifications/notifications.ts
4004
+ Client.prototype.listNotifications = async function(page, pageSize, typeFilter, signal) {
4005
+ let path = `/notifications?page=${page}&pageSize=${pageSize}`;
4006
+ if (typeFilter) path += `&type=${encodeURIComponent(typeFilter)}`;
4007
+ const resp = await this.doJSON("GET", path, null, signal);
4008
+ return resp.data;
4009
+ };
4010
+ Client.prototype.getUnreadCount = async function(signal) {
4011
+ const resp = await this.doJSON(
4012
+ "GET",
4013
+ "/notifications/unread-count",
4014
+ null,
4015
+ signal
4016
+ );
4017
+ return resp.data.unreadCount;
4018
+ };
4019
+ Client.prototype.markNotificationRead = async function(id, signal) {
4020
+ await this.doJSON(
4021
+ "PUT",
4022
+ `/notifications/${encodeURIComponent(id)}/read`,
4023
+ null,
4024
+ signal
4025
+ );
4026
+ };
4027
+ Client.prototype.markAllNotificationsRead = async function(signal) {
4028
+ await this.doJSON("PUT", "/notifications/read-all", null, signal);
4029
+ };
4030
+ Client.prototype.deleteNotification = async function(id, signal) {
4031
+ await this.doJSON(
4032
+ "DELETE",
4033
+ `/notifications/${encodeURIComponent(id)}`,
4034
+ null,
4035
+ signal
4036
+ );
4037
+ };
4038
+ Client.prototype.registerDevice = async function(reg, signal) {
4039
+ await this.doJSON("POST", "/devices/register", reg, signal);
4040
+ };
4041
+ Client.prototype.unregisterDevice = async function(token, signal) {
4042
+ await this.doJSON(
4043
+ "DELETE",
4044
+ `/devices/${encodeURIComponent(token)}`,
4045
+ null,
4046
+ signal
4047
+ );
4048
+ };
4049
+ Client.prototype.listNotificationPreferences = async function(signal) {
4050
+ const resp = await this.doJSON(
4051
+ "GET",
4052
+ "/notification-preferences",
4053
+ null,
4054
+ signal
4055
+ );
4056
+ return resp.data;
4057
+ };
4058
+ Client.prototype.updateNotificationPreference = async function(typeCode, pref, signal) {
4059
+ await this.doJSON(
4060
+ "PUT",
4061
+ `/notification-preferences/${encodeURIComponent(typeCode)}`,
4062
+ pref,
4063
+ signal
4064
+ );
4065
+ };
4066
+
4067
+ // src/notifications/ws.ts
4068
+ Client.prototype.connect = async function(cfg, signal) {
4069
+ const noop = () => {
4070
+ };
4071
+ const filledCfg = {
4072
+ onEvent: cfg.onEvent ?? noop,
4073
+ onConnect: cfg.onConnect ?? noop,
4074
+ onDisconnect: cfg.onDisconnect ?? noop,
4075
+ topics: cfg.topics ?? [],
4076
+ reconnectMinMs: cfg.reconnectMinMs ?? 2e3,
4077
+ reconnectMaxMs: cfg.reconnectMaxMs ?? 6e4,
4078
+ autoReconnect: cfg.autoReconnect ?? true
4079
+ };
4080
+ let resolveDone;
4081
+ const done = new Promise((r) => {
4082
+ resolveDone = r;
4083
+ });
4084
+ const abort = new AbortController();
4085
+ if (signal) {
4086
+ if (signal.aborted) abort.abort();
4087
+ else signal.addEventListener("abort", () => abort.abort());
4084
4088
  }
4085
- return messages;
4086
- }
4087
- function checkMediaSizes(messages, cfg) {
4088
- for (const msg of messages) {
4089
- if (!isPlainObject2(msg)) continue;
4090
- const content = msg["content"];
4091
- if (!Array.isArray(content)) continue;
4092
- for (const raw of content) {
4093
- if (!isPlainObject2(raw)) continue;
4094
- const bt = raw["type"];
4095
- if (typeof bt !== "string") continue;
4096
- let limit = 0;
4097
- switch (bt) {
4098
- case "image":
4099
- limit = cfg.maxImageBytes ?? 0;
4100
- break;
4101
- case "video":
4102
- limit = cfg.maxVideoBytes ?? 0;
4103
- break;
4104
- case "document":
4105
- limit = cfg.maxPDFBytes ?? 0;
4106
- break;
4107
- default:
4108
- continue;
4109
- }
4110
- if (limit <= 0) continue;
4111
- const data = extractBase64Data(raw);
4112
- if (data === "") continue;
4113
- const actual = base64DecodedLen(data);
4114
- if (actual > limit) {
4115
- throw new SizeError(bt, actual, limit);
4116
- }
4089
+ const ws = {
4090
+ conn: null,
4091
+ cfg: filledCfg,
4092
+ abort,
4093
+ done,
4094
+ doneResolve: resolveDone,
4095
+ connected: false
4096
+ };
4097
+ await wsConnectOnce(this, ws);
4098
+ this.ws = ws;
4099
+ void wsLoop(this, ws);
4100
+ };
4101
+ Client.prototype.disconnect = async function() {
4102
+ const ws = this.ws;
4103
+ this.ws = null;
4104
+ if (!ws) return;
4105
+ ws.abort.abort();
4106
+ ws.connected = false;
4107
+ if (ws.conn) {
4108
+ try {
4109
+ ws.conn.close(1e3, "");
4110
+ } catch {
4117
4111
  }
4118
4112
  }
4113
+ await Promise.race([
4114
+ ws.done,
4115
+ new Promise((resolve) => setTimeout(resolve, 5e3))
4116
+ ]);
4117
+ };
4118
+ Client.prototype.isConnected = function() {
4119
+ const ws = this.ws;
4120
+ if (!ws) return false;
4121
+ return ws.connected;
4122
+ };
4123
+ function wsURL(c) {
4124
+ const base = c.apiURL("/ws");
4125
+ return base.replace(/^http:\/\//, "ws://").replace(/^https:\/\//, "wss://");
4119
4126
  }
4120
- function extractBase64Data(block) {
4121
- const src = block["source"];
4122
- if (!isPlainObject2(src)) return "";
4123
- if (src["type"] !== "base64") return "";
4124
- const dataRaw = src["data"];
4125
- if (typeof dataRaw !== "string") return "";
4126
- let data = dataRaw;
4127
- const i = data.indexOf("base64,");
4128
- if (i >= 0) {
4129
- data = data.slice(i + "base64,".length);
4127
+ function getWebSocketCtor() {
4128
+ const WSCtor = globalThis.WebSocket;
4129
+ if (!WSCtor) {
4130
+ throw new Error(
4131
+ 'WebSocket not available \u2014 on Node \u226421 set globalThis.WebSocket = require("ws") before connect'
4132
+ );
4130
4133
  }
4131
- return data;
4132
- }
4133
- function base64DecodedLen(b64) {
4134
- const n = b64.length;
4135
- let pad = 0;
4136
- if (n >= 1 && b64[n - 1] === "=") pad++;
4137
- if (n >= 2 && b64[n - 2] === "=") pad++;
4138
- return Math.floor(n * 3 / 4) - pad;
4139
- }
4140
- function isPlainObject2(v) {
4141
- return typeof v === "object" && v !== null && !Array.isArray(v);
4134
+ return WSCtor;
4142
4135
  }
4143
-
4144
- // src/agent-runs-types.ts
4145
- var AgentRunStreamError = class extends Error {
4146
- event;
4147
- code;
4148
- stage;
4149
- retryable;
4150
- constructor(event) {
4151
- const err = event.error;
4152
- super(err.stage ? `agent run failed: ${err.stage}: ${err.message}` : `agent run failed: ${err.message}`);
4153
- this.name = "AgentRunStreamError";
4154
- this.event = event;
4136
+ async function wsConnectOnce(c, ws) {
4137
+ const token = await c.ensureToken(ws.abort.signal);
4138
+ const url = wsURL(c);
4139
+ const WSCtor = getWebSocketCtor();
4140
+ const u = new URL(url);
4141
+ u.searchParams.set("token", token);
4142
+ let conn;
4143
+ try {
4144
+ conn = new WSCtor(u.toString());
4145
+ } catch (e) {
4146
+ throw new Error(`dial: ${e instanceof Error ? e.message : String(e)}`);
4147
+ }
4148
+ await new Promise((resolve, reject) => {
4149
+ let opened = false;
4150
+ const handshakeTimer = setTimeout(() => {
4151
+ if (!opened) {
4152
+ try {
4153
+ conn.close();
4154
+ } catch {
4155
+ }
4156
+ reject(new Error("dial: handshake timeout"));
4157
+ }
4158
+ }, 3e4);
4159
+ conn.addEventListener("open", () => {
4160
+ opened = true;
4161
+ });
4162
+ conn.addEventListener("error", (e) => {
4163
+ clearTimeout(handshakeTimer);
4164
+ reject(new Error(`dial: ${e.message ?? "connection error"}`));
4165
+ });
4166
+ conn.addEventListener("message", (e) => {
4167
+ try {
4168
+ const msg = e.data;
4169
+ const welcome = JSON.parse(msg);
4170
+ if (welcome.type !== "welcome") {
4171
+ clearTimeout(handshakeTimer);
4172
+ try {
4173
+ conn.close();
4174
+ } catch {
4175
+ }
4176
+ reject(new Error(`unexpected first message: ${welcome.type}`));
4177
+ return;
4178
+ }
4179
+ clearTimeout(handshakeTimer);
4180
+ ws.conn = conn;
4181
+ ws.connected = true;
4182
+ if (ws.cfg.topics.length > 0) {
4183
+ try {
4184
+ conn.send(
4185
+ JSON.stringify({
4186
+ type: "subscribe",
4187
+ topics: ws.cfg.topics
4188
+ })
4189
+ );
4190
+ } catch (sendErr) {
4191
+ ws.conn = null;
4192
+ ws.connected = false;
4193
+ try {
4194
+ conn.close();
4195
+ } catch {
4196
+ }
4197
+ reject(new Error(`send subscribe: ${sendErr instanceof Error ? sendErr.message : String(sendErr)}`));
4198
+ return;
4199
+ }
4200
+ }
4201
+ ws.cfg.onConnect();
4202
+ console.log(`[acosmi-sdk] websocket connected, connId=${welcome.connId ?? ""}`);
4203
+ resolve();
4204
+ } catch (parseErr) {
4205
+ clearTimeout(handshakeTimer);
4206
+ try {
4207
+ conn.close();
4208
+ } catch {
4209
+ }
4210
+ reject(new Error(`parse welcome: ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`));
4211
+ }
4212
+ }, { once: true });
4213
+ });
4214
+ }
4215
+ async function wsLoop(c, ws) {
4216
+ try {
4217
+ while (true) {
4218
+ await wsReadLoop(ws);
4219
+ if (ws.abort.signal.aborted) return;
4220
+ if (ws.conn) {
4221
+ try {
4222
+ ws.conn.close();
4223
+ } catch {
4224
+ }
4225
+ ws.conn = null;
4226
+ }
4227
+ ws.connected = false;
4228
+ if (!ws.cfg.autoReconnect) return;
4229
+ let delay = ws.cfg.reconnectMinMs;
4230
+ while (true) {
4231
+ if (ws.abort.signal.aborted) return;
4232
+ await sleepWithSignal2(delay, ws.abort.signal).catch(() => {
4233
+ });
4234
+ if (ws.abort.signal.aborted) return;
4235
+ console.log(`[acosmi-sdk] websocket reconnecting (delay=${delay}ms)...`);
4236
+ try {
4237
+ await wsConnectOnce(c, ws);
4238
+ break;
4239
+ } catch (err) {
4240
+ console.log(`[acosmi-sdk] websocket reconnect failed: ${err instanceof Error ? err.message : String(err)}`);
4241
+ delay = Math.min(delay * 2, ws.cfg.reconnectMaxMs);
4242
+ }
4243
+ }
4244
+ }
4245
+ } finally {
4246
+ ws.doneResolve();
4247
+ }
4248
+ }
4249
+ async function wsReadLoop(ws) {
4250
+ const conn = ws.conn;
4251
+ if (!conn) return;
4252
+ return new Promise((resolve) => {
4253
+ const handleMessage = (e) => {
4254
+ try {
4255
+ const data = e.data;
4256
+ const event = JSON.parse(data);
4257
+ try {
4258
+ ws.cfg.onEvent(event);
4259
+ } catch {
4260
+ }
4261
+ } catch {
4262
+ }
4263
+ };
4264
+ const handleClose = (e) => {
4265
+ conn.removeEventListener("message", handleMessage);
4266
+ conn.removeEventListener("close", handleClose);
4267
+ conn.removeEventListener("error", handleError);
4268
+ try {
4269
+ ws.cfg.onDisconnect(new Error(`closed: code=${e.code} reason=${e.reason}`));
4270
+ } catch {
4271
+ }
4272
+ resolve();
4273
+ };
4274
+ const handleError = (e) => {
4275
+ conn.removeEventListener("message", handleMessage);
4276
+ conn.removeEventListener("close", handleClose);
4277
+ conn.removeEventListener("error", handleError);
4278
+ try {
4279
+ ws.cfg.onDisconnect(e);
4280
+ } catch {
4281
+ }
4282
+ resolve();
4283
+ };
4284
+ conn.addEventListener("message", handleMessage);
4285
+ conn.addEventListener("close", handleClose);
4286
+ conn.addEventListener("error", handleError);
4287
+ if (ws.abort.signal.aborted) {
4288
+ try {
4289
+ conn.close();
4290
+ } catch {
4291
+ }
4292
+ } else {
4293
+ ws.abort.signal.addEventListener(
4294
+ "abort",
4295
+ () => {
4296
+ try {
4297
+ conn.close();
4298
+ } catch {
4299
+ }
4300
+ },
4301
+ { once: true }
4302
+ );
4303
+ }
4304
+ });
4305
+ }
4306
+ async function sleepWithSignal2(ms, signal) {
4307
+ if (ms <= 0) return;
4308
+ if (signal.aborted) throw new Error("aborted");
4309
+ return new Promise((resolve, reject) => {
4310
+ const t = setTimeout(() => {
4311
+ signal.removeEventListener("abort", abortHandler);
4312
+ resolve();
4313
+ }, ms);
4314
+ const abortHandler = () => {
4315
+ clearTimeout(t);
4316
+ signal.removeEventListener("abort", abortHandler);
4317
+ reject(new Error("aborted"));
4318
+ };
4319
+ signal.addEventListener("abort", abortHandler);
4320
+ });
4321
+ }
4322
+
4323
+ // src/agent-runs/types.ts
4324
+ var AgentRunStreamError = class extends Error {
4325
+ event;
4326
+ code;
4327
+ stage;
4328
+ retryable;
4329
+ constructor(event) {
4330
+ const err = event.error;
4331
+ super(err.stage ? `agent run failed: ${err.stage}: ${err.message}` : `agent run failed: ${err.message}`);
4332
+ this.name = "AgentRunStreamError";
4333
+ this.event = event;
4155
4334
  this.code = err.code ?? "";
4156
4335
  this.stage = err.stage ?? "";
4157
4336
  this.retryable = err.retryable ?? false;
4158
4337
  }
4159
4338
  };
4160
4339
 
4161
- // src/client/agent-runs.ts
4162
- init_types();
4340
+ // src/agent-runs/client.ts
4163
4341
  var agentRunsByClient = /* @__PURE__ */ new WeakMap();
4164
4342
  Object.defineProperty(Client.prototype, "agentRuns", {
4165
4343
  configurable: true,
@@ -4637,801 +4815,728 @@ function errorMessage(e) {
4637
4815
  return e instanceof Error ? e.message : String(e);
4638
4816
  }
4639
4817
 
4640
- // src/index.ts
4641
- init_betas();
4818
+ // src/compliance/scopes.ts
4819
+ var ScopeComplianceEvidenceRead = "compliance:evidence:read";
4820
+ var ScopeComplianceEvidenceWrite = "compliance:evidence:write";
4821
+ var ScopeComplianceTimestampIssue = "compliance:timestamp:issue";
4822
+ var ScopeComplianceTimestampVerify = "compliance:timestamp:verify";
4823
+ var ScopeComplianceContractSigningRead = "compliance:contract_signing:read";
4824
+ var ScopeComplianceContractSigningWrite = "compliance:contract_signing:write";
4825
+ var ScopeComplianceSealManage = "compliance:seal:manage";
4826
+ var ScopeComplianceSealApprovalRequest = "compliance:seal_approval:request";
4827
+ var ScopeComplianceSealApprovalApprove = "compliance:seal_approval:approve";
4828
+ var ScopeComplianceSealUseExecute = "compliance:seal_use:execute";
4829
+ var ScopeComplianceReportsRead = "compliance:reports:read";
4830
+ var ScopeComplianceReportsWrite = "compliance:reports:write";
4831
+ var ScopeComplianceReportsPublish = "compliance:reports:publish";
4832
+ function complianceScopes() {
4833
+ return [
4834
+ ScopeComplianceEvidenceRead,
4835
+ ScopeComplianceEvidenceWrite,
4836
+ ScopeComplianceTimestampIssue,
4837
+ ScopeComplianceTimestampVerify,
4838
+ ScopeComplianceContractSigningRead,
4839
+ ScopeComplianceContractSigningWrite,
4840
+ ScopeComplianceSealManage,
4841
+ ScopeComplianceSealApprovalRequest,
4842
+ ScopeComplianceSealApprovalApprove,
4843
+ ScopeComplianceSealUseExecute,
4844
+ ScopeComplianceReportsRead,
4845
+ ScopeComplianceReportsWrite,
4846
+ ScopeComplianceReportsPublish
4847
+ ];
4848
+ }
4642
4849
 
4643
- // src/client/entitlements.ts
4644
- Client.prototype.getBalance = async function(signal) {
4645
- const resp = await this.doJSON(
4646
- "GET",
4647
- "/entitlements/balance",
4648
- null,
4649
- signal
4650
- );
4651
- return resp.data;
4652
- };
4653
- Client.prototype.getBalanceDetail = async function(signal) {
4654
- const resp = await this.doJSON(
4655
- "GET",
4656
- "/entitlements/balance-detail",
4657
- null,
4658
- signal
4659
- );
4660
- return resp.data;
4661
- };
4662
- Client.prototype.listEntitlements = async function(status, signal) {
4663
- let path = "/entitlements";
4664
- if (status !== "") {
4665
- path += `?status=${encodeURIComponent(status)}`;
4666
- }
4667
- const resp = await this.doJSON("GET", path, null, signal);
4668
- return resp.data;
4669
- };
4670
- Client.prototype.listConsumeRecords = async function(page, pageSize, signal) {
4671
- const path = `/entitlements/consume-records?page=${page}&pageSize=${pageSize}`;
4672
- const resp = await this.doJSON("GET", path, null, signal);
4673
- return resp.data;
4674
- };
4675
- Client.prototype.claimMonthlyFree = async function(signal) {
4676
- const resp = await this.doJSON(
4677
- "POST",
4678
- "/entitlements/claim-monthly",
4679
- null,
4680
- signal
4681
- );
4682
- return resp.data;
4683
- };
4684
- Client.prototype.getByModel = async function(modelID, signal) {
4685
- if (modelID === "") throw new Error("modelID required");
4686
- const path = `/entitlements/by-model?modelId=${encodeURIComponent(modelID)}`;
4687
- const resp = await this.doJSON("GET", path, null, signal);
4688
- return resp.data;
4689
- };
4690
- Client.prototype.listBuckets = async function(signal) {
4691
- const resp = await this.doJSON(
4692
- "GET",
4693
- "/entitlements/buckets",
4694
- null,
4695
- signal
4696
- );
4697
- return resp.data;
4698
- };
4699
- Client.prototype.listCoefficients = async function(signal) {
4700
- if (this.coefCacheData && Date.now() - this.coefCacheTimeMs < coefCacheTTLMs) {
4701
- return [...this.coefCacheData];
4850
+ // src/compliance/status.ts
4851
+ var ErrComplianceStepUpRequired = "COMPLIANCE_STEP_UP_REQUIRED";
4852
+ var ErrEnvelopeGateClosed = "ENVELOPE_GATE_CLOSED";
4853
+ var ErrProviderNotConfigured = "PROVIDER_NOT_CONFIGURED";
4854
+ var ErrProviderUnknownNoRetry = "PROVIDER_REQUEST_UNKNOWN_NO_RETRY";
4855
+ var ErrBillingCallbackCannotCommit = "BILLING_CALLBACK_CANNOT_COMMIT";
4856
+ var ErrBillingCommitRequiresLocalVerify = "BILLING_COMMIT_REQUIRES_LOCAL_VERIFY";
4857
+ var ErrBillingS2sForbidden = "BILLING_S2S_FORBIDDEN";
4858
+ var ErrSealApprovalNotApproved = "SEAL_APPROVAL_STATE_NOT_APPROVED";
4859
+ var ErrSealApprovalExpired = "SEAL_APPROVAL_EXPIRED";
4860
+ var ErrSealApprovalNonceUsed = "SEAL_APPROVAL_NONCE_USED";
4861
+ var ErrSealApprovalContractHashMismatch = "SEAL_APPROVAL_CONTRACT_HASH_MISMATCH";
4862
+ var ErrSealApprovalSealMismatch = "SEAL_APPROVAL_SEAL_MISMATCH";
4863
+ var ErrSealApprovalLocationMismatch = "SEAL_APPROVAL_LOCATION_MISMATCH";
4864
+ var ErrSealApprovalTransactorMismatch = "SEAL_APPROVAL_TRANSACTOR_MISMATCH";
4865
+ var ErrSealUseAlreadyConsumed = "SEAL_USE_ALREADY_CONSUMED";
4866
+ function isComplianceTerminalError(code) {
4867
+ switch (code) {
4868
+ case ErrEnvelopeGateClosed:
4869
+ case ErrProviderNotConfigured:
4870
+ case ErrProviderUnknownNoRetry:
4871
+ case ErrBillingCallbackCannotCommit:
4872
+ case ErrBillingCommitRequiresLocalVerify:
4873
+ case ErrBillingS2sForbidden:
4874
+ case ErrSealApprovalNonceUsed:
4875
+ case ErrSealApprovalExpired:
4876
+ case ErrSealApprovalContractHashMismatch:
4877
+ case ErrSealApprovalSealMismatch:
4878
+ case ErrSealApprovalLocationMismatch:
4879
+ case ErrSealApprovalTransactorMismatch:
4880
+ case ErrSealUseAlreadyConsumed:
4881
+ return true;
4882
+ default:
4883
+ return false;
4702
4884
  }
4703
- const resp = await this.doJSON(
4704
- "GET",
4705
- "/entitlements/coefficients",
4706
- null,
4707
- signal
4708
- );
4709
- this.coefCacheData = [...resp.data];
4710
- this.coefCacheTimeMs = Date.now();
4711
- return resp.data;
4712
- };
4713
- Client.prototype.invalidateCoefficientCache = function() {
4714
- this.coefCacheData = null;
4715
- this.coefCacheTimeMs = 0;
4885
+ }
4886
+ function isBillingConfirmable(providerStatus, billingStatus) {
4887
+ return providerStatus === "success" && billingStatus === "committed";
4888
+ }
4889
+
4890
+ // src/compliance/errors.ts
4891
+ var CODE_TO_KEY = {
4892
+ // 通用 / token / scope (1-031-000-xxx)
4893
+ 1031000001: "COMPLIANCE_UNAUTHORIZED",
4894
+ 1031000002: "COMPLIANCE_TOKEN_INVALID",
4895
+ 1031000003: "COMPLIANCE_TOKEN_INVALID",
4896
+ 1031000004: "COMPLIANCE_TOKEN_INVALID",
4897
+ 1031000005: "COMPLIANCE_TOKEN_INVALID",
4898
+ 1031000006: "COMPLIANCE_TOKEN_INVALID",
4899
+ 1031000007: "COMPLIANCE_TOKEN_INVALID",
4900
+ 1031000008: "COMPLIANCE_TOKEN_INVALID",
4901
+ 1031000009: "COMPLIANCE_TOKEN_INVALID",
4902
+ 1031000010: "COMPLIANCE_TOKEN_INVALID",
4903
+ 1031000011: "COMPLIANCE_TOKEN_INVALID",
4904
+ 1031000012: "COMPLIANCE_INSUFFICIENT_SCOPE",
4905
+ 1031000013: "COMPLIANCE_STEP_UP_REQUIRED",
4906
+ // Subject snapshot (1-031-001-xxx)
4907
+ 1031001001: "SUBJECT_SNAPSHOT_NOT_FOUND",
4908
+ 1031001002: "SUBJECT_SNAPSHOT_TENANT_MISMATCH",
4909
+ 1031001003: "SUBJECT_SNAPSHOT_REQUIRED",
4910
+ // Evidence / Timestamp / Package / Report (1-031-002-xxx)
4911
+ 1031002001: "EVIDENCE_ASSET_NOT_FOUND",
4912
+ 1031002002: "SUBJECT_SNAPSHOT_TENANT_MISMATCH",
4913
+ 1031002003: "EVIDENCE_ASSET_HASH_MISMATCH",
4914
+ 1031002004: "EVIDENCE_ASSET_PAYLOAD_REQUIRED",
4915
+ 1031002005: "EVIDENCE_ASSET_PAYLOAD_REQUIRED",
4916
+ 1031002006: "TIMESTAMP_TOKEN_NOT_FOUND",
4917
+ 1031002007: "TIMESTAMP_PROVIDER_FAILED",
4918
+ 1031002008: "TIMESTAMP_PROVIDER_UNKNOWN",
4919
+ 1031002009: "TIMESTAMP_LOCAL_VERIFY_FAILED",
4920
+ 1031002010: "TIMESTAMP_PROVIDER_NOT_AVAILABLE",
4921
+ 1031002011: "EVIDENCE_PACKAGE_NOT_FOUND",
4922
+ 1031002012: "EVIDENCE_PACKAGE_TIMESTAMP_REQUIRED",
4923
+ 1031002013: "EVIDENCE_PACKAGE_MANIFEST_HASH_MISMATCH",
4924
+ 1031002014: "REPORT_NOT_FOUND",
4925
+ 1031002015: "REPORT_ALREADY_PUBLISHED",
4926
+ 1031002016: "REPORT_DRAFT_REQUIRED",
4927
+ 1031002017: "EVIDENCE_VERIFY_TARGET_REQUIRED",
4928
+ 1031002018: "EVIDENCE_VERIFY_TARGET_NOT_FOUND",
4929
+ // Provider request (1-031-003-xxx)
4930
+ 1031003001: "PROVIDER_REQUEST_UNKNOWN_NO_RETRY",
4931
+ 1031003002: "PROVIDER_CALLBACK_SOURCE_INVALID",
4932
+ 1031003003: "PROVIDER_NOT_CONFIGURED",
4933
+ 1031003010: "PROVIDER_REQUEST_NOT_FOUND",
4934
+ 1031003011: "PROVIDER_REQUEST_IDEMPOTENCY_REQUIRED",
4935
+ 1031003012: "PROVIDER_REQUEST_STATUS_NOT_TERMINAL",
4936
+ // Envelope (1-031-004-xxx)
4937
+ 1031004001: "ENVELOPE_NOT_FOUND",
4938
+ 1031004002: "ENVELOPE_TENANT_MISMATCH",
4939
+ 1031004003: "ENVELOPE_STATE_NOT_ALLOWED",
4940
+ 1031004004: "ENVELOPE_GATE_CLOSED",
4941
+ 1031004005: "CONTRACT_NOT_FOUND",
4942
+ 1031004006: "CONTRACT_HASH_MISMATCH",
4943
+ 1031004007: "CONTRACT_NOT_FOUND",
4944
+ 1031004008: "PROVIDER_AUTHORIZATION_NOT_CONFIRMED",
4945
+ 1031004009: "PROVIDER_AUTHORIZATION_NOT_CONFIRMED",
4946
+ 1031004010: "ENVELOPE_EVIDENCE_NOT_READY",
4947
+ // Seal approval / use (1-031-005-xxx)
4948
+ 1031005001: "SEAL_ASSET_NOT_FOUND",
4949
+ 1031005010: "SEAL_APPROVAL_NOT_FOUND",
4950
+ 1031005011: "SEAL_APPROVAL_NOT_FOUND",
4951
+ 1031005012: "SEAL_APPROVAL_STATE_NOT_APPROVED",
4952
+ 1031005013: "SEAL_APPROVAL_EXPIRED",
4953
+ 1031005014: "SEAL_APPROVAL_ALREADY_USED",
4954
+ 1031005015: "SEAL_APPROVAL_NONCE_USED",
4955
+ 1031005016: "SEAL_APPROVAL_SEAL_MISMATCH",
4956
+ 1031005017: "SEAL_APPROVAL_LOCATION_MISMATCH",
4957
+ 1031005018: "SEAL_APPROVAL_TRANSACTOR_MISMATCH",
4958
+ 1031005019: "SEAL_APPROVAL_CONTRACT_HASH_MISMATCH",
4959
+ 1031005020: "SEAL_APPROVAL_INVALID_TRANSITION",
4960
+ 1031005030: "SEAL_USE_ALREADY_CONSUMED",
4961
+ // Billing (1-031-006-xxx)
4962
+ 1031006004: "BILLING_COMMIT_REQUIRES_LOCAL_VERIFY",
4963
+ 1031006005: "BILLING_COMMIT_REQUIRES_PROVIDER_SUCCESS",
4964
+ 1031006007: "BILLING_CALLBACK_CANNOT_COMMIT",
4965
+ 1031006008: "BILLING_PROVIDER_UNKNOWN_NOT_COMMITTABLE",
4966
+ 1031006009: "BILLING_S2S_FORBIDDEN",
4967
+ // Audit (1-031-007-xxx)
4968
+ 1031007011: "AUDIT_CHAIN_TAMPER_DETECTED"
4716
4969
  };
4970
+ var STEP_UP_KEYS = /* @__PURE__ */ new Set(["COMPLIANCE_STEP_UP_REQUIRED"]);
4971
+ var TERMINAL_KEYS = /* @__PURE__ */ new Set([
4972
+ "ENVELOPE_GATE_CLOSED",
4973
+ "PROVIDER_NOT_CONFIGURED",
4974
+ "PROVIDER_REQUEST_UNKNOWN_NO_RETRY",
4975
+ "BILLING_CALLBACK_CANNOT_COMMIT",
4976
+ "BILLING_COMMIT_REQUIRES_LOCAL_VERIFY",
4977
+ "BILLING_COMMIT_REQUIRES_PROVIDER_SUCCESS",
4978
+ "BILLING_PROVIDER_UNKNOWN_NOT_COMMITTABLE",
4979
+ "BILLING_S2S_FORBIDDEN",
4980
+ "SEAL_APPROVAL_NONCE_USED",
4981
+ "SEAL_APPROVAL_EXPIRED",
4982
+ "SEAL_APPROVAL_CONTRACT_HASH_MISMATCH",
4983
+ "SEAL_APPROVAL_SEAL_MISMATCH",
4984
+ "SEAL_APPROVAL_LOCATION_MISMATCH",
4985
+ "SEAL_APPROVAL_TRANSACTOR_MISMATCH",
4986
+ "SEAL_USE_ALREADY_CONSUMED",
4987
+ "CONTRACT_HASH_MISMATCH",
4988
+ "TIMESTAMP_LOCAL_VERIFY_FAILED",
4989
+ "EVIDENCE_PACKAGE_MANIFEST_HASH_MISMATCH",
4990
+ "AUDIT_CHAIN_TAMPER_DETECTED",
4991
+ "PROVIDER_REQUEST_NOT_FOUND",
4992
+ "EVIDENCE_ASSET_HASH_MISMATCH",
4993
+ "EVIDENCE_VERIFY_TARGET_NOT_FOUND",
4994
+ "REPORT_ALREADY_PUBLISHED"
4995
+ ]);
4996
+ var RETRYABLE_KEYS = /* @__PURE__ */ new Set([]);
4997
+ function classifyComplianceError(err) {
4998
+ const key = CODE_TO_KEY[err.code] ?? "UNKNOWN_COMPLIANCE_ERROR";
4999
+ return {
5000
+ code: err.code,
5001
+ message: err.message,
5002
+ key,
5003
+ retryable: RETRYABLE_KEYS.has(key),
5004
+ terminal: TERMINAL_KEYS.has(key),
5005
+ stepUpRequired: STEP_UP_KEYS.has(key)
5006
+ };
5007
+ }
5008
+ function isComplianceBusinessError(err) {
5009
+ return err.code >= 1031e6 && err.code <= 1031999999;
5010
+ }
4717
5011
 
4718
- // src/client/packages.ts
4719
- init_types();
4720
- Client.prototype.listTokenPackages = async function(signal) {
4721
- const raw = await this.doJSON("GET", "/token-packages", null, signal);
4722
- if (raw.data && typeof raw.data === "object" && "list" in raw.data) {
4723
- const page = raw.data;
4724
- if (Array.isArray(page.list)) return page.list;
5012
+ // src/compliance/client.ts
5013
+ var cache = /* @__PURE__ */ new WeakMap();
5014
+ Object.defineProperty(Client.prototype, "compliance", {
5015
+ configurable: true,
5016
+ enumerable: false,
5017
+ get() {
5018
+ let existing = cache.get(this);
5019
+ if (!existing) {
5020
+ existing = new ComplianceClient(this);
5021
+ cache.set(this, existing);
5022
+ }
5023
+ return existing;
4725
5024
  }
4726
- if (Array.isArray(raw.data)) return raw.data;
4727
- throw new Error("decode token packages: unexpected shape");
4728
- };
4729
- Client.prototype.getTokenPackageDetail = async function(packageID, signal) {
4730
- const resp = await this.doJSON(
4731
- "GET",
4732
- `/token-packages/${encodeURIComponent(packageID)}`,
4733
- null,
4734
- signal
4735
- );
4736
- return resp.data;
5025
+ });
5026
+ var DEFAULT_POLL = {
5027
+ timeoutMs: 6e4,
5028
+ initialIntervalMs: 1e3,
5029
+ maxIntervalMs: 5e3,
5030
+ multiplier: 1.5
4737
5031
  };
4738
- Client.prototype.buyTokenPackage = async function(packageID, payload, signal) {
4739
- const body = payload ?? null;
4740
- const resp = await this.doJSON(
4741
- "POST",
4742
- `/token-packages/${encodeURIComponent(packageID)}/buy`,
4743
- body,
4744
- signal
4745
- );
4746
- return resp.data;
5032
+ var CompliancePollError = class extends Error {
5033
+ kind;
5034
+ lastInfo;
5035
+ constructor(message, kind, lastInfo) {
5036
+ super(message);
5037
+ this.name = "CompliancePollError";
5038
+ this.kind = kind;
5039
+ this.lastInfo = lastInfo;
5040
+ }
4747
5041
  };
4748
- Client.prototype.getOrderStatus = async function(orderID, signal) {
4749
- const resp = await this.doJSON(
4750
- "GET",
4751
- `/token-packages/orders/${encodeURIComponent(orderID)}/status`,
4752
- null,
4753
- signal
4754
- );
4755
- return resp.data;
4756
- };
4757
- Client.prototype.listMyOrders = async function(signal) {
4758
- const raw = await this.doJSON("GET", "/token-packages/my", null, signal);
4759
- if (raw.data && typeof raw.data === "object" && "list" in raw.data) {
4760
- const page = raw.data;
4761
- if (Array.isArray(page.list)) return page.list;
5042
+ var ComplianceClient = class {
5043
+ constructor(client) {
5044
+ this.client = client;
4762
5045
  }
4763
- if (Array.isArray(raw.data)) return raw.data;
4764
- throw new Error("decode orders: unexpected shape");
4765
- };
4766
- Client.prototype.waitForPayment = async function(orderID, pollIntervalMs, signal) {
4767
- if (pollIntervalMs <= 0) pollIntervalMs = 2e3;
4768
- while (true) {
4769
- const status = await this.getOrderStatus(orderID, signal);
4770
- if (isOrderTerminal(status.status)) {
4771
- if (isOrderSuccess(status.status)) return status;
4772
- throw new exports.OrderTerminalError(orderID, status.status);
4773
- }
4774
- await sleepWithSignal(pollIntervalMs, signal);
5046
+ client;
5047
+ // =========================================================================
5048
+ // Evidence Asset
5049
+ // =========================================================================
5050
+ /** 创建证据资产(写)。 */
5051
+ createEvidenceAsset(req, opts = {}) {
5052
+ return this.write(
5053
+ "POST",
5054
+ "/compliance/evidence/assets",
5055
+ req,
5056
+ writeCtx(opts)
5057
+ );
4775
5058
  }
4776
- };
4777
- async function sleepWithSignal(ms, signal) {
4778
- if (ms <= 0) return;
4779
- if (signal && signal.aborted) throw new Error("aborted");
4780
- return new Promise((resolve, reject) => {
4781
- const t = setTimeout(() => {
4782
- if (signal && abortHandler) signal.removeEventListener("abort", abortHandler);
4783
- resolve();
4784
- }, ms);
4785
- let abortHandler;
4786
- if (signal) {
4787
- abortHandler = () => {
4788
- clearTimeout(t);
4789
- signal.removeEventListener("abort", abortHandler);
4790
- reject(new Error("aborted"));
4791
- };
4792
- signal.addEventListener("abort", abortHandler);
4793
- }
4794
- });
4795
- }
4796
-
4797
- // src/client/wallet.ts
4798
- Client.prototype.getWalletStats = async function(signal) {
4799
- const resp = await this.doJSON("GET", "/wallet/stats", null, signal);
4800
- return resp.data;
4801
- };
4802
- Client.prototype.getWalletTransactions = async function(signal) {
4803
- const resp = await this.doJSON(
4804
- "GET",
4805
- "/wallet/transactions",
4806
- null,
4807
- signal
4808
- );
4809
- return resp.data;
4810
- };
4811
-
4812
- // src/client/skills.ts
4813
- init_types();
4814
- Client.prototype.browseSkillStore = async function(query, signal) {
4815
- const resp = await this.browseSkills(
4816
- 1,
4817
- 50,
4818
- query.category ?? "",
4819
- query.keyword ?? "",
4820
- query.tag ?? "",
4821
- "",
4822
- signal
4823
- );
4824
- return resp.items;
4825
- };
4826
- Client.prototype.browseSkills = async function(page, pageSize, category, keyword, tag, source, signal) {
4827
- const qv = new URLSearchParams();
4828
- qv.set("page", String(page));
4829
- qv.set("pageSize", String(pageSize));
4830
- if (category) qv.set("category", category);
4831
- if (keyword) qv.set("keyword", keyword);
4832
- if (tag) qv.set("tag", tag);
4833
- if (source) qv.set("source", source);
4834
- const resp = await this.doPublicJSON(
4835
- "GET",
4836
- `/skill-store?${qv.toString()}`,
4837
- null,
4838
- signal
4839
- );
4840
- return resp.data;
4841
- };
4842
- Client.prototype.browseSkillsList = async function(page, pageSize, category, keyword, tag, source, signal) {
4843
- const qv = new URLSearchParams();
4844
- qv.set("page", String(page));
4845
- qv.set("pageSize", String(pageSize));
4846
- qv.set("fields", "minimal");
4847
- if (category) qv.set("category", category);
4848
- if (keyword) qv.set("keyword", keyword);
4849
- if (tag) qv.set("tag", tag);
4850
- if (source) qv.set("source", source);
4851
- const resp = await this.doPublicJSON(
4852
- "GET",
4853
- `/skill-store?${qv.toString()}`,
4854
- null,
4855
- signal
4856
- );
4857
- return resp.data;
4858
- };
4859
- Client.prototype.getSkillDetail = async function(skillID, signal) {
4860
- const resp = await this.doPublicJSON(
4861
- "GET",
4862
- `/skill-store/${encodeURIComponent(skillID)}`,
4863
- null,
4864
- signal
4865
- );
4866
- return resp.data;
4867
- };
4868
- Client.prototype.resolveSkill = async function(key, signal) {
4869
- const resp = await this.doPublicJSON(
4870
- "GET",
4871
- `/skill-store/resolve/${encodeURIComponent(key)}`,
4872
- null,
4873
- signal
4874
- );
4875
- return resp.data;
4876
- };
4877
- Client.prototype.installSkill = async function(skillID, signal) {
4878
- const resp = await this.doJSON(
4879
- "POST",
4880
- `/skill-store/${encodeURIComponent(skillID)}/install`,
4881
- null,
4882
- signal
4883
- );
4884
- return resp.data;
4885
- };
4886
- Client.prototype.downloadSkill = async function(skillID, signal) {
4887
- const ctl = new AbortController();
4888
- const timer = setTimeout(() => ctl.abort(), 5 * 60 * 1e3);
4889
- let parentHandler;
4890
- if (signal) {
4891
- if (signal.aborted) ctl.abort();
4892
- else {
4893
- parentHandler = () => ctl.abort();
4894
- signal.addEventListener("abort", parentHandler);
4895
- }
5059
+ /** 读 — 证据资产详情。 */
5060
+ getEvidenceAsset(id, signal) {
5061
+ return this.read(
5062
+ "GET",
5063
+ `/compliance/evidence/assets/${encodeURIComponent(id)}`,
5064
+ null,
5065
+ signal
5066
+ );
4896
5067
  }
4897
- try {
4898
- const url = this.apiURL(`/skill-store/${encodeURIComponent(skillID)}/download`);
4899
- const headers = {};
4900
- let token = "";
4901
- try {
4902
- token = await this.ensureToken(ctl.signal);
4903
- } catch {
4904
- }
4905
- if (token) headers["Authorization"] = `Bearer ${token}`;
4906
- let resp;
4907
- try {
4908
- resp = await this.fetchImpl(url, { method: "GET", headers, signal: ctl.signal });
4909
- } catch (e) {
4910
- throw classifyTransport(`GET /skill-store/${skillID}/download`, url, e);
4911
- }
4912
- if (resp.status === 429) {
4913
- const bodyText = await readLimitedText(resp.body, maxErrorBodySize);
4914
- throw new exports.RateLimitError("\u533F\u540D\u4E0B\u8F7D\u5DF2\u8FBE\u9650\u5236", resp.headers.get("Retry-After") ?? "", bodyText);
4915
- }
4916
- if (!resp.ok) {
4917
- const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
4918
- throw new Error(
4919
- `download skill: ${parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers).message}`
4920
- );
4921
- }
4922
- const data = await readLimited(resp.body, maxDownloadSize + 1);
4923
- if (data.byteLength > maxDownloadSize) {
4924
- throw new Error(`download skill: response exceeds ${maxDownloadSize >> 20}MB limit`);
4925
- }
4926
- let filename = "skill.zip";
4927
- const cd = resp.headers.get("Content-Disposition");
4928
- if (cd) {
4929
- const idx = cd.indexOf("filename");
4930
- if (idx !== -1) {
4931
- const parts = cd.slice(idx).split("=", 2);
4932
- if (parts.length === 2) {
4933
- filename = parts[1].trim().replace(/^["' ]+|["' ]+$/g, "");
4934
- }
4935
- }
4936
- }
4937
- return { data, filename };
4938
- } finally {
4939
- clearTimeout(timer);
4940
- if (parentHandler && signal) signal.removeEventListener("abort", parentHandler);
5068
+ /**
5069
+ * 公开 verify。隐私边界:返回字段不含 PII / 合同原文 / storage / provider raw。
5070
+ *
5071
+ * 匿名可调用:未 login 时走匿名请求,不会抛 `not authorized, call login() first`。
5072
+ * 已 login / 已持有 token 时附带 `Authorization` 以保留审计上下文。public 端点不
5073
+ * 应要求认证 收到 401 直接抛 HTTPError,不触发 `forceRefresh`,也不做 refresh
5074
+ * replay。
5075
+ */
5076
+ verifyEvidencePublic(params, signal) {
5077
+ const q = new URLSearchParams();
5078
+ if (params.evidenceNo) q.set("evidenceNo", params.evidenceNo);
5079
+ if (params.publicVerifyCode) q.set("publicVerifyCode", params.publicVerifyCode);
5080
+ const qs = q.toString();
5081
+ return this.publicRead(
5082
+ "GET",
5083
+ `/compliance/evidence/verify${qs ? "?" + qs : ""}`,
5084
+ signal
5085
+ );
4941
5086
  }
4942
- };
4943
- Client.prototype.uploadSkill = async function(zipData, scope, intent, signal) {
4944
- return uploadSkillInternal(this, zipData, scope, intent, false, signal);
4945
- };
4946
- async function uploadSkillInternal(c, zipData, scope, intent, retried, signal) {
4947
- const ctl = new AbortController();
4948
- const timer = setTimeout(() => ctl.abort(), 5 * 60 * 1e3);
4949
- let parentHandler;
4950
- if (signal) {
4951
- if (signal.aborted) ctl.abort();
4952
- else {
4953
- parentHandler = () => ctl.abort();
4954
- signal.addEventListener("abort", parentHandler);
4955
- }
5087
+ // =========================================================================
5088
+ // Timestamp
5089
+ // =========================================================================
5090
+ /** 申请时间章(写)。SDK 永远不传 provider 字段。 */
5091
+ issueTimestamp(req, opts = {}) {
5092
+ return this.write("POST", "/compliance/timestamps", req, writeCtx(opts));
4956
5093
  }
4957
- try {
4958
- const token = await c.ensureToken(ctl.signal);
4959
- const form = new FormData();
4960
- form.append("scope", scope);
4961
- form.append("intent", intent);
4962
- const blob = new Blob([zipData], { type: "application/zip" });
4963
- form.append("file", blob, "skill.zip");
4964
- const url = c.apiURL("/skill-store/upload");
4965
- let resp;
4966
- try {
4967
- resp = await c.fetchImpl(url, {
4968
- method: "POST",
4969
- headers: { Authorization: `Bearer ${token}` },
4970
- body: form,
4971
- signal: ctl.signal
4972
- });
4973
- } catch (e) {
4974
- throw classifyTransport("POST /skill-store/upload", url, e);
4975
- }
4976
- if (resp.status === 401 && !retried) {
4977
- try {
4978
- await resp.body?.cancel();
4979
- } catch {
4980
- }
4981
- try {
4982
- await c.forceRefresh(ctl.signal);
4983
- } catch (refreshErr) {
4984
- throw new Error(
4985
- `upload: unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
4986
- );
4987
- }
4988
- return uploadSkillInternal(c, zipData, scope, intent, true, signal);
4989
- }
4990
- if (resp.status < 200 || resp.status >= 300) {
4991
- const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
4992
- throw new Error(
4993
- `upload: ${parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers).message}`
4994
- );
4995
- }
4996
- const text = await resp.text();
4997
- const result = JSON.parse(text);
4998
- return result.data.skill;
4999
- } finally {
5000
- clearTimeout(timer);
5001
- if (parentHandler && signal) signal.removeEventListener("abort", parentHandler);
5094
+ /** 给已有资产申请时间章。SDK 永远不传 provider 字段。 */
5095
+ issueTimestampForAsset(assetId, opts = {}) {
5096
+ return this.write(
5097
+ "POST",
5098
+ `/compliance/evidence/assets/${encodeURIComponent(assetId)}/timestamp`,
5099
+ null,
5100
+ writeCtx(opts)
5101
+ );
5002
5102
  }
5003
- }
5004
- Client.prototype.getSkillSummary = async function(signal) {
5005
- const resp = await this.doJSON("GET", "/skills/summary", null, signal);
5006
- return resp.data;
5007
- };
5008
- Client.prototype.certifySkill = async function(skillID, signal) {
5009
- await this.doJSON(
5010
- "POST",
5011
- `/skill-store/${encodeURIComponent(skillID)}/certify`,
5012
- null,
5013
- signal
5014
- );
5015
- };
5016
- Client.prototype.getCertificationStatus = async function(skillID, signal) {
5017
- const resp = await this.doJSON(
5018
- "GET",
5019
- `/skill-store/${encodeURIComponent(skillID)}/certification`,
5020
- null,
5021
- signal
5022
- );
5023
- return resp.data;
5024
- };
5025
- Client.prototype.generateSkill = async function(req, signal) {
5026
- const resp = await this.doJSON(
5027
- "POST",
5028
- "/skill-generator/generate",
5029
- req,
5030
- signal
5031
- );
5032
- return resp.data;
5033
- };
5034
- Client.prototype.optimizeSkill = async function(req, signal) {
5035
- const resp = await this.doJSON(
5036
- "POST",
5037
- "/skill-generator/optimize",
5038
- req,
5039
- signal
5040
- );
5041
- return resp.data;
5042
- };
5043
- Client.prototype.validateSkill = async function(skillName, signal) {
5044
- await this.doJSON(
5045
- "POST",
5046
- "/skill-generator/validate",
5047
- { skillName },
5048
- signal
5049
- );
5050
- };
5051
-
5052
- // src/client/tools.ts
5053
- Client.prototype.listTools = async function(signal) {
5054
- const resp = await this.doJSON("GET", "/tools", null, signal);
5055
- return resp.data.skills;
5056
- };
5057
- Client.prototype.getTool = async function(toolID, signal) {
5058
- const resp = await this.doJSON(
5059
- "GET",
5060
- `/tools/${encodeURIComponent(toolID)}`,
5061
- null,
5062
- signal
5063
- );
5064
- return resp.data;
5065
- };
5066
-
5067
- // src/client/notifications.ts
5068
- Client.prototype.listNotifications = async function(page, pageSize, typeFilter, signal) {
5069
- let path = `/notifications?page=${page}&pageSize=${pageSize}`;
5070
- if (typeFilter) path += `&type=${encodeURIComponent(typeFilter)}`;
5071
- const resp = await this.doJSON("GET", path, null, signal);
5072
- return resp.data;
5073
- };
5074
- Client.prototype.getUnreadCount = async function(signal) {
5075
- const resp = await this.doJSON(
5076
- "GET",
5077
- "/notifications/unread-count",
5078
- null,
5079
- signal
5080
- );
5081
- return resp.data.unreadCount;
5082
- };
5083
- Client.prototype.markNotificationRead = async function(id, signal) {
5084
- await this.doJSON(
5085
- "PUT",
5086
- `/notifications/${encodeURIComponent(id)}/read`,
5087
- null,
5088
- signal
5089
- );
5090
- };
5091
- Client.prototype.markAllNotificationsRead = async function(signal) {
5092
- await this.doJSON("PUT", "/notifications/read-all", null, signal);
5093
- };
5094
- Client.prototype.deleteNotification = async function(id, signal) {
5095
- await this.doJSON(
5096
- "DELETE",
5097
- `/notifications/${encodeURIComponent(id)}`,
5098
- null,
5099
- signal
5100
- );
5101
- };
5102
- Client.prototype.registerDevice = async function(reg, signal) {
5103
- await this.doJSON("POST", "/devices/register", reg, signal);
5104
- };
5105
- Client.prototype.unregisterDevice = async function(token, signal) {
5106
- await this.doJSON(
5107
- "DELETE",
5108
- `/devices/${encodeURIComponent(token)}`,
5109
- null,
5110
- signal
5111
- );
5112
- };
5113
- Client.prototype.listNotificationPreferences = async function(signal) {
5114
- const resp = await this.doJSON(
5115
- "GET",
5116
- "/notification-preferences",
5117
- null,
5118
- signal
5119
- );
5120
- return resp.data;
5121
- };
5122
- Client.prototype.updateNotificationPreference = async function(typeCode, pref, signal) {
5123
- await this.doJSON(
5124
- "PUT",
5125
- `/notification-preferences/${encodeURIComponent(typeCode)}`,
5126
- pref,
5127
- signal
5128
- );
5129
- };
5130
-
5131
- // src/sanitize-bridge.ts
5132
- Client.prototype.setDefensiveSanitize = function(cfg) {
5133
- this.defensiveCfg = cfg;
5134
- };
5135
- Client.prototype.setAutoStripEphemeralHistory = function(on) {
5136
- this.autoStripEphemeral = on;
5137
- };
5138
- Client.prototype.applyRequestSanitizers = function(req) {
5139
- const cfg = this.defensiveCfg;
5140
- const strip = this.autoStripEphemeral;
5141
- if (cfg == null && !strip) return;
5142
- if (req.rawMessages != null) {
5143
- let msgs;
5144
- try {
5145
- msgs = normalizeRawMessages(req.rawMessages);
5146
- } catch (e) {
5147
- throw new Error(
5148
- `sanitize: normalize raw messages: ${e instanceof Error ? e.message : String(e)}`
5149
- );
5150
- }
5151
- if (cfg) {
5152
- msgs = sanitize(msgs, cfg);
5153
- }
5154
- if (strip) {
5155
- msgs = stripEphemeral(msgs);
5156
- }
5157
- req.rawMessages = msgs;
5158
- return;
5103
+ /** 读 — 时间章 token 详情。 */
5104
+ getTimestamp(id, signal) {
5105
+ return this.read(
5106
+ "GET",
5107
+ `/compliance/timestamps/${encodeURIComponent(id)}`,
5108
+ null,
5109
+ signal
5110
+ );
5159
5111
  }
5160
- if (cfg && (cfg.maxMessagesTurns ?? 0) > 0 && (req.messages?.length ?? 0) > cfg.maxMessagesTurns) {
5161
- throw ErrHistoryTooDeep;
5112
+ /** verify 本地离线校验已申请的时间章。 */
5113
+ verifyTimestamp(req, opts = {}) {
5114
+ return this.write(
5115
+ "POST",
5116
+ "/compliance/timestamps/verify",
5117
+ req,
5118
+ writeCtx(opts)
5119
+ );
5120
+ }
5121
+ /**
5122
+ * 轮询到 VERIFIED 终态。
5123
+ * - VERIFIED → 返回 token;
5124
+ * - FAILED / LOCAL_VERIFY_FAILED → 抛 {@link CompliancePollError} kind='terminal_failure';
5125
+ * - UNKNOWN / RETRYING / PENDING → 继续轮询直到 timeout;
5126
+ * - timeout → 抛 {@link CompliancePollError} kind='timeout'。
5127
+ */
5128
+ async waitForTimestampVerified(id, opts = {}) {
5129
+ return this.poll(
5130
+ () => this.getTimestamp(id, opts.signal),
5131
+ (t) => classifyTimestamp(t.verificationStatus),
5132
+ opts
5133
+ );
5134
+ }
5135
+ // =========================================================================
5136
+ // Evidence Package
5137
+ // =========================================================================
5138
+ /** 构建证据包(写)。 */
5139
+ buildEvidencePackage(assetId, timestampTokenId, opts = {}) {
5140
+ const tsParam = timestampTokenId == null ? "" : "?timestampTokenId=" + encodeURIComponent(timestampTokenId);
5141
+ return this.write(
5142
+ "POST",
5143
+ `/compliance/evidence/assets/${encodeURIComponent(assetId)}/packages${tsParam}`,
5144
+ null,
5145
+ writeCtx(opts)
5146
+ );
5147
+ }
5148
+ // =========================================================================
5149
+ // Report
5150
+ // =========================================================================
5151
+ /** 创建证据报告(写)。 */
5152
+ createReport(req, opts = {}) {
5153
+ return this.write("POST", "/compliance/reports", req, writeCtx(opts));
5154
+ }
5155
+ /** 读 — 报告详情。 */
5156
+ getReport(id, signal) {
5157
+ return this.read(
5158
+ "GET",
5159
+ `/compliance/reports/${encodeURIComponent(id)}`,
5160
+ null,
5161
+ signal
5162
+ );
5163
+ }
5164
+ /**
5165
+ * 发布报告(写,step-up 必须)。
5166
+ *
5167
+ * `@status gated` — step-up 闸门未闭合前服务端会一致返回
5168
+ * `COMPLIANCE_STEP_UP_REQUIRED`(数值码 1031000013)。SDK 不会自动重试、不伪成功;
5169
+ * 调用方需要引导用户重新做 OAuth introspection 或重新登录后再次调用本方法
5170
+ *(使用同一 idempotency-key)。方法状态分级见 `docs/compliance.md` Method Status。
5171
+ */
5172
+ publishReport(id, opts = {}) {
5173
+ return this.write(
5174
+ "POST",
5175
+ `/compliance/reports/${encodeURIComponent(id)}/publish`,
5176
+ null,
5177
+ writeCtx(opts)
5178
+ );
5179
+ }
5180
+ /**
5181
+ * 下载报告(读)。返回 {@link ReportDownload}:报告 hash + 资产 hash + 证据包 hash +
5182
+ * 时间章 serial/genTime,足以离线复核。
5183
+ * 不返回 bodyCanonicalJson / storage key / subject snapshot id。
5184
+ */
5185
+ downloadReport(id, signal) {
5186
+ return this.read(
5187
+ "GET",
5188
+ `/compliance/reports/${encodeURIComponent(id)}/download`,
5189
+ null,
5190
+ signal
5191
+ );
5192
+ }
5193
+ // =========================================================================
5194
+ // Signing Envelope
5195
+ // =========================================================================
5196
+ /** 创建 envelope(写)。返回 envelope id。 */
5197
+ createSigningEnvelope(req, opts = {}) {
5198
+ return this.write(
5199
+ "POST",
5200
+ "/compliance/signing-envelopes",
5201
+ req,
5202
+ writeCtx(opts)
5203
+ );
5204
+ }
5205
+ /** 读 — envelope 详情。租户由服务端从 compliance token principal 推导。 */
5206
+ getSigningEnvelope(envelopeId, signal) {
5207
+ return this.read(
5208
+ "GET",
5209
+ `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}`,
5210
+ null,
5211
+ signal
5212
+ );
5213
+ }
5214
+ /**
5215
+ * 正式签署(写,step-up 必须)。
5216
+ *
5217
+ * `@status gated` — 服务端闸门关闭时会一致返回 `ENVELOPE_GATE_CLOSED` (1031004004)。
5218
+ * SDK 不重试、不伪成功;调用方应该将该错误展示为"功能未开放"。
5219
+ */
5220
+ signEnvelope(envelopeId, req, opts = {}) {
5221
+ return this.write(
5222
+ "POST",
5223
+ `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}/sign`,
5224
+ req,
5225
+ writeCtx(opts)
5226
+ );
5227
+ }
5228
+ /**
5229
+ * 创建 H5 签署短链(写,step-up 必须)。
5230
+ *
5231
+ * `@status gated` — 同 {@link signEnvelope}:服务端闸门关闭时 SDK 不重试、不伪成功。
5232
+ */
5233
+ createH5SigningUrl(envelopeId, req, opts = {}) {
5234
+ return this.write(
5235
+ "POST",
5236
+ `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}/h5-url`,
5237
+ req,
5238
+ writeCtx(opts)
5239
+ );
5240
+ }
5241
+ /** 同步 provider 状态(写但只读对账,不创建新 provider 请求)。 */
5242
+ syncSigningEnvelopeStatus(envelopeId, opts = {}) {
5243
+ return this.write(
5244
+ "POST",
5245
+ `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}/sync-provider-status`,
5246
+ null,
5247
+ writeCtx(opts)
5248
+ );
5162
5249
  }
5163
- };
5164
- function normalizeRawMessages(rm) {
5165
- if (Array.isArray(rm)) return rm;
5166
- let s;
5167
- try {
5168
- s = JSON.parse(JSON.stringify(rm));
5169
- } catch (e) {
5170
- throw new Error(`raw messages: ${e instanceof Error ? e.message : String(e)}`);
5250
+ // =========================================================================
5251
+ // Seal Approval
5252
+ // =========================================================================
5253
+ /**
5254
+ * 提交用印审批申请(写)。
5255
+ *
5256
+ * `@status production-ready` — 服务端以 `Idempotency-Key` + 业务请求指纹做重放保护:
5257
+ * key + 同请求 返回原审批 id;同 key + 不同请求 → 拒绝复用幂等键。强烈建议调用方
5258
+ * 持久化 `idempotencyKey`,网络重试 / 任务恢复时复用,避免重复创建审批单。
5259
+ */
5260
+ submitSealApproval(req, opts = {}) {
5261
+ return this.write(
5262
+ "POST",
5263
+ "/compliance/seal-approvals",
5264
+ req,
5265
+ writeCtx(opts)
5266
+ );
5171
5267
  }
5172
- if (!Array.isArray(s)) {
5173
- throw new Error("raw messages must be a JSON array");
5268
+ /**
5269
+ * 审批通过用印申请(写,step-up 必须)。
5270
+ *
5271
+ * `@status gated` — step-up 未闭合前服务端会返回 `COMPLIANCE_STEP_UP_REQUIRED`。
5272
+ * SDK 不重试、不伪成功。方法状态分级见 `docs/compliance.md` Method Status。
5273
+ */
5274
+ approveSealApproval(id, query, opts = {}) {
5275
+ const q = new URLSearchParams();
5276
+ if (query.expiresAt) q.set("expiresAt", query.expiresAt);
5277
+ if (query.note) q.set("note", query.note);
5278
+ const qs = q.toString();
5279
+ return this.write(
5280
+ "POST",
5281
+ `/compliance/seal-approvals/${encodeURIComponent(id)}/approve${qs ? "?" + qs : ""}`,
5282
+ null,
5283
+ writeCtx(opts)
5284
+ );
5174
5285
  }
5175
- return s;
5176
- }
5177
-
5178
- // src/ws.ts
5179
- Client.prototype.connect = async function(cfg, signal) {
5180
- const noop = () => {
5181
- };
5182
- const filledCfg = {
5183
- onEvent: cfg.onEvent ?? noop,
5184
- onConnect: cfg.onConnect ?? noop,
5185
- onDisconnect: cfg.onDisconnect ?? noop,
5186
- topics: cfg.topics ?? [],
5187
- reconnectMinMs: cfg.reconnectMinMs ?? 2e3,
5188
- reconnectMaxMs: cfg.reconnectMaxMs ?? 6e4,
5189
- autoReconnect: cfg.autoReconnect ?? true
5190
- };
5191
- let resolveDone;
5192
- const done = new Promise((r) => {
5193
- resolveDone = r;
5194
- });
5195
- const abort = new AbortController();
5196
- if (signal) {
5197
- if (signal.aborted) abort.abort();
5198
- else signal.addEventListener("abort", () => abort.abort());
5286
+ rejectSealApproval(id, query, opts = {}) {
5287
+ const q = new URLSearchParams();
5288
+ if (query.reason) q.set("reason", query.reason);
5289
+ const qs = q.toString();
5290
+ return this.write(
5291
+ "POST",
5292
+ `/compliance/seal-approvals/${encodeURIComponent(id)}/reject${qs ? "?" + qs : ""}`,
5293
+ null,
5294
+ writeCtx(opts)
5295
+ );
5199
5296
  }
5200
- const ws = {
5201
- conn: null,
5202
- cfg: filledCfg,
5203
- abort,
5204
- done,
5205
- doneResolve: resolveDone,
5206
- connected: false
5207
- };
5208
- await wsConnectOnce(this, ws);
5209
- this.ws = ws;
5210
- void wsLoop(this, ws);
5211
- };
5212
- Client.prototype.disconnect = async function() {
5213
- const ws = this.ws;
5214
- this.ws = null;
5215
- if (!ws) return;
5216
- ws.abort.abort();
5217
- ws.connected = false;
5218
- if (ws.conn) {
5219
- try {
5220
- ws.conn.close(1e3, "");
5221
- } catch {
5222
- }
5297
+ cancelSealApproval(id, query, opts = {}) {
5298
+ const q = new URLSearchParams();
5299
+ if (query.reason) q.set("reason", query.reason);
5300
+ const qs = q.toString();
5301
+ return this.write(
5302
+ "POST",
5303
+ `/compliance/seal-approvals/${encodeURIComponent(id)}/cancel${qs ? "?" + qs : ""}`,
5304
+ null,
5305
+ writeCtx(opts)
5306
+ );
5223
5307
  }
5224
- await Promise.race([
5225
- ws.done,
5226
- new Promise((resolve) => setTimeout(resolve, 5e3))
5227
- ]);
5228
- };
5229
- Client.prototype.isConnected = function() {
5230
- const ws = this.ws;
5231
- if (!ws) return false;
5232
- return ws.connected;
5233
- };
5234
- function wsURL(c) {
5235
- const base = c.apiURL("/ws");
5236
- return base.replace(/^http:\/\//, "ws://").replace(/^https:\/\//, "wss://");
5237
- }
5238
- function getWebSocketCtor() {
5239
- const WSCtor = globalThis.WebSocket;
5240
- if (!WSCtor) {
5241
- throw new Error(
5242
- 'WebSocket not available \u2014 on Node \u226421 set globalThis.WebSocket = require("ws") before connect'
5308
+ listPendingSealApprovals(signal) {
5309
+ return this.read(
5310
+ "GET",
5311
+ "/compliance/seal-approvals/pending",
5312
+ null,
5313
+ signal
5243
5314
  );
5244
5315
  }
5245
- return WSCtor;
5246
- }
5247
- async function wsConnectOnce(c, ws) {
5248
- const token = await c.ensureToken(ws.abort.signal);
5249
- const url = wsURL(c);
5250
- const WSCtor = getWebSocketCtor();
5251
- const u = new URL(url);
5252
- u.searchParams.set("token", token);
5253
- let conn;
5254
- try {
5255
- conn = new WSCtor(u.toString());
5256
- } catch (e) {
5257
- throw new Error(`dial: ${e instanceof Error ? e.message : String(e)}`);
5316
+ getSealApproval(id, signal) {
5317
+ return this.read(
5318
+ "GET",
5319
+ `/compliance/seal-approvals/${encodeURIComponent(id)}`,
5320
+ null,
5321
+ signal
5322
+ );
5258
5323
  }
5259
- await new Promise((resolve, reject) => {
5260
- let opened = false;
5261
- const handshakeTimer = setTimeout(() => {
5262
- if (!opened) {
5263
- try {
5264
- conn.close();
5265
- } catch {
5266
- }
5267
- reject(new Error("dial: handshake timeout"));
5268
- }
5269
- }, 3e4);
5270
- conn.addEventListener("open", () => {
5271
- opened = true;
5272
- });
5273
- conn.addEventListener("error", (e) => {
5274
- clearTimeout(handshakeTimer);
5275
- reject(new Error(`dial: ${e.message ?? "connection error"}`));
5276
- });
5277
- conn.addEventListener("message", (e) => {
5278
- try {
5279
- const msg = e.data;
5280
- const welcome = JSON.parse(msg);
5281
- if (welcome.type !== "welcome") {
5282
- clearTimeout(handshakeTimer);
5283
- try {
5284
- conn.close();
5285
- } catch {
5286
- }
5287
- reject(new Error(`unexpected first message: ${welcome.type}`));
5288
- return;
5289
- }
5290
- clearTimeout(handshakeTimer);
5291
- ws.conn = conn;
5292
- ws.connected = true;
5293
- if (ws.cfg.topics.length > 0) {
5294
- try {
5295
- conn.send(
5296
- JSON.stringify({
5297
- type: "subscribe",
5298
- topics: ws.cfg.topics
5299
- })
5300
- );
5301
- } catch (sendErr) {
5302
- ws.conn = null;
5303
- ws.connected = false;
5304
- try {
5305
- conn.close();
5306
- } catch {
5307
- }
5308
- reject(new Error(`send subscribe: ${sendErr instanceof Error ? sendErr.message : String(sendErr)}`));
5309
- return;
5310
- }
5311
- }
5312
- ws.cfg.onConnect();
5313
- console.log(`[acosmi-sdk] websocket connected, connId=${welcome.connId ?? ""}`);
5314
- resolve();
5315
- } catch (parseErr) {
5316
- clearTimeout(handshakeTimer);
5317
- try {
5318
- conn.close();
5319
- } catch {
5320
- }
5321
- reject(new Error(`parse welcome: ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`));
5322
- }
5323
- }, { once: true });
5324
- });
5325
- }
5326
- async function wsLoop(c, ws) {
5327
- try {
5328
- while (true) {
5329
- await wsReadLoop(ws);
5330
- if (ws.abort.signal.aborted) return;
5331
- if (ws.conn) {
5332
- try {
5333
- ws.conn.close();
5334
- } catch {
5335
- }
5336
- ws.conn = null;
5337
- }
5338
- ws.connected = false;
5339
- if (!ws.cfg.autoReconnect) return;
5340
- let delay = ws.cfg.reconnectMinMs;
5341
- while (true) {
5342
- if (ws.abort.signal.aborted) return;
5343
- await sleepWithSignal2(delay, ws.abort.signal).catch(() => {
5344
- });
5345
- if (ws.abort.signal.aborted) return;
5346
- console.log(`[acosmi-sdk] websocket reconnecting (delay=${delay}ms)...`);
5347
- try {
5348
- await wsConnectOnce(c, ws);
5349
- break;
5350
- } catch (err) {
5351
- console.log(`[acosmi-sdk] websocket reconnect failed: ${err instanceof Error ? err.message : String(err)}`);
5352
- delay = Math.min(delay * 2, ws.cfg.reconnectMaxMs);
5353
- }
5354
- }
5324
+ // =========================================================================
5325
+ // Provider Request (read-only)
5326
+ // =========================================================================
5327
+ getProviderRequest(id, signal) {
5328
+ return this.read(
5329
+ "GET",
5330
+ `/compliance/provider-requests/${encodeURIComponent(id)}`,
5331
+ null,
5332
+ signal
5333
+ );
5334
+ }
5335
+ /**
5336
+ * 轮询 provider request 到 SUCCESS / FAILED 终态。
5337
+ * - SUCCESS / FAILED → 返回最后视图;
5338
+ * - UNKNOWN / RETRYING / PENDING → 继续轮询;
5339
+ * - timeout → 抛 {@link CompliancePollError} kind='timeout',不自动重发原 provider 请求。
5340
+ *
5341
+ * SUCCESS 不代表 billing 已 commit;调用方仍需通过业务侧 envelope / asset 终态判断。
5342
+ */
5343
+ async waitForProviderRequestTerminal(id, opts = {}) {
5344
+ return this.poll(
5345
+ () => this.getProviderRequest(id, opts.signal),
5346
+ (v) => classifyProviderStatus(v.status),
5347
+ opts
5348
+ );
5349
+ }
5350
+ // =========================================================================
5351
+ // Error classification (re-export for convenience)
5352
+ // =========================================================================
5353
+ classifyError(err) {
5354
+ if (!isBusinessErrorLike(err)) return null;
5355
+ if (!isComplianceBusinessError(err)) return null;
5356
+ return classifyComplianceError(err);
5357
+ }
5358
+ // =========================================================================
5359
+ // Internal helpers
5360
+ // =========================================================================
5361
+ /**
5362
+ * 读路径:GET / 公开 verify。允许 401 单次刷新后重放(GET 幂等安全)。
5363
+ * 与 client.doJSONFullInternal 行为一致;不复用其代码因为 base URL 不同。
5364
+ */
5365
+ async read(method, path, body, signal, extraHeaders = {}) {
5366
+ return this.executeJson(method, path, body, signal, {
5367
+ retryOn401: true,
5368
+ extraHeaders
5369
+ });
5370
+ }
5371
+ /**
5372
+ * 公开读路径:public verify。
5373
+ *
5374
+ * 与 {@link read} 的区别 — public 端点不应要求认证:
5375
+ * - 无 token 时匿名请求:ensureToken 抛 `not authorized` 会被吞掉,继续匿名发送。
5376
+ * - 有 token 时附带 `Authorization`,保留后端审计上下文。
5377
+ * - 不做 401 refresh replay:401 直接抛 HTTPError,不触发 `forceRefresh`。
5378
+ *
5379
+ * URL 仍走 `client.complianceURL(path)`,不复用 `/api/v4`;底层复用
5380
+ * `client.doRequest`,不新增 fetch/axios 直连。
5381
+ */
5382
+ async publicRead(method, path, signal) {
5383
+ let token = "";
5384
+ try {
5385
+ token = await this.client.ensureToken(signal);
5386
+ } catch {
5355
5387
  }
5356
- } finally {
5357
- ws.doneResolve();
5388
+ const url = this.client.complianceURL(path);
5389
+ const headers = { Accept: "application/json" };
5390
+ if (token) headers.Authorization = `Bearer ${token}`;
5391
+ const resp = await this.client.doRequest({ method, url, headers }, signal);
5392
+ if (resp.status < 200 || resp.status >= 300) {
5393
+ const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
5394
+ throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
5395
+ }
5396
+ const text = await resp.text();
5397
+ if (!text) return void 0;
5398
+ const parsed = JSON.parse(text);
5399
+ const bizErr = apiResponseBusinessError(parsed);
5400
+ if (bizErr) throw bizErr;
5401
+ return parsed.data;
5358
5402
  }
5359
- }
5360
- async function wsReadLoop(ws) {
5361
- const conn = ws.conn;
5362
- if (!conn) return;
5363
- return new Promise((resolve) => {
5364
- const handleMessage = (e) => {
5365
- try {
5366
- const data = e.data;
5367
- const event = JSON.parse(data);
5368
- try {
5369
- ws.cfg.onEvent(event);
5370
- } catch {
5371
- }
5372
- } catch {
5373
- }
5403
+ /**
5404
+ * 写路径:POST。
5405
+ * - 发送前 ensureToken 一次确保 token fresh。
5406
+ * - 不自动 401 重放:401 → 抛 HTTPError;调用方必须自己刷新 token 后用同一
5407
+ * idempotency-key 重新发起,避免 provider 侧重复请求。
5408
+ * - 不走 doRequestWithRetry:写操作不允许 5xx/timeout 自动重试。
5409
+ */
5410
+ async write(method, path, body, ctx) {
5411
+ const headers = { ...ctx.extraHeaders ?? {} };
5412
+ if (ctx.idempotencyKey) headers["Idempotency-Key"] = ctx.idempotencyKey;
5413
+ return this.executeJson(method, path, body, ctx.signal, {
5414
+ retryOn401: false,
5415
+ extraHeaders: headers
5416
+ });
5417
+ }
5418
+ async executeJson(method, path, body, signal, opts, retried = false) {
5419
+ const token = await this.client.ensureToken(signal);
5420
+ const url = this.client.complianceURL(path);
5421
+ const headers = {
5422
+ Authorization: `Bearer ${token}`,
5423
+ Accept: "application/json",
5424
+ ...opts.extraHeaders
5374
5425
  };
5375
- const handleClose = (e) => {
5376
- conn.removeEventListener("message", handleMessage);
5377
- conn.removeEventListener("close", handleClose);
5378
- conn.removeEventListener("error", handleError);
5426
+ let bodyStr;
5427
+ if (body != null) {
5428
+ bodyStr = typeof body === "string" ? body : JSON.stringify(body);
5429
+ headers["Content-Type"] = "application/json";
5430
+ }
5431
+ const resp = await this.client.doRequest({ method, url, headers, body: bodyStr }, signal);
5432
+ if (resp.status === 401 && opts.retryOn401 && !retried) {
5379
5433
  try {
5380
- ws.cfg.onDisconnect(new Error(`closed: code=${e.code} reason=${e.reason}`));
5434
+ await resp.body?.cancel();
5381
5435
  } catch {
5382
5436
  }
5383
- resolve();
5437
+ await this.client.forceRefresh(signal);
5438
+ return this.executeJson(method, path, body, signal, opts, true);
5439
+ }
5440
+ if (resp.status < 200 || resp.status >= 300) {
5441
+ const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
5442
+ throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
5443
+ }
5444
+ const text = await resp.text();
5445
+ if (!text) return void 0;
5446
+ const parsed = JSON.parse(text);
5447
+ const bizErr = apiResponseBusinessError(parsed);
5448
+ if (bizErr) throw bizErr;
5449
+ return parsed.data;
5450
+ }
5451
+ async poll(fetcher, classify, opts) {
5452
+ const cfg = {
5453
+ timeoutMs: opts.timeoutMs ?? DEFAULT_POLL.timeoutMs,
5454
+ initialIntervalMs: opts.initialIntervalMs ?? DEFAULT_POLL.initialIntervalMs,
5455
+ maxIntervalMs: opts.maxIntervalMs ?? DEFAULT_POLL.maxIntervalMs,
5456
+ multiplier: opts.multiplier ?? DEFAULT_POLL.multiplier
5384
5457
  };
5385
- const handleError = (e) => {
5386
- conn.removeEventListener("message", handleMessage);
5387
- conn.removeEventListener("close", handleClose);
5388
- conn.removeEventListener("error", handleError);
5389
- try {
5390
- ws.cfg.onDisconnect(e);
5391
- } catch {
5458
+ const deadline = Date.now() + cfg.timeoutMs;
5459
+ let interval = cfg.initialIntervalMs;
5460
+ let lastValue;
5461
+ while (Date.now() < deadline) {
5462
+ if (opts.signal?.aborted) {
5463
+ throw new CompliancePollError("compliance poll aborted", "unknown");
5392
5464
  }
5393
- resolve();
5394
- };
5395
- conn.addEventListener("message", handleMessage);
5396
- conn.addEventListener("close", handleClose);
5397
- conn.addEventListener("error", handleError);
5398
- if (ws.abort.signal.aborted) {
5399
- try {
5400
- conn.close();
5401
- } catch {
5465
+ lastValue = await fetcher();
5466
+ const decision = classify(lastValue);
5467
+ if (decision === "done") return lastValue;
5468
+ if (decision === "failed") {
5469
+ throw new CompliancePollError(
5470
+ "compliance poll observed terminal failure",
5471
+ "terminal_failure"
5472
+ );
5402
5473
  }
5403
- } else {
5404
- ws.abort.signal.addEventListener(
5405
- "abort",
5406
- () => {
5407
- try {
5408
- conn.close();
5409
- } catch {
5410
- }
5411
- },
5412
- { once: true }
5413
- );
5474
+ const sleepMs = Math.min(interval, deadline - Date.now());
5475
+ if (sleepMs <= 0) break;
5476
+ await sleep2(sleepMs, opts.signal);
5477
+ interval = Math.min(Math.floor(interval * cfg.multiplier), cfg.maxIntervalMs);
5414
5478
  }
5415
- });
5479
+ throw new CompliancePollError("compliance poll timed out", "timeout");
5480
+ }
5481
+ };
5482
+ function classifyTimestamp(status) {
5483
+ switch (status) {
5484
+ case "VERIFIED":
5485
+ return "done";
5486
+ case "FAILED":
5487
+ case "LOCAL_VERIFY_FAILED":
5488
+ return "failed";
5489
+ case "PENDING":
5490
+ case "UNKNOWN":
5491
+ case "RETRYING":
5492
+ default:
5493
+ return "continue";
5494
+ }
5416
5495
  }
5417
- async function sleepWithSignal2(ms, signal) {
5418
- if (ms <= 0) return;
5419
- if (signal.aborted) throw new Error("aborted");
5496
+ function classifyProviderStatus(status) {
5497
+ switch (status) {
5498
+ case "SUCCESS":
5499
+ return "done";
5500
+ case "FAILED":
5501
+ return "failed";
5502
+ case "PENDING":
5503
+ case "UNKNOWN":
5504
+ case "RETRYING":
5505
+ default:
5506
+ return "continue";
5507
+ }
5508
+ }
5509
+ function writeCtx(opts, extraHeaders = {}) {
5510
+ return {
5511
+ idempotencyKey: opts.idempotencyKey,
5512
+ signal: opts.signal,
5513
+ extraHeaders
5514
+ };
5515
+ }
5516
+ function isBusinessErrorLike(err) {
5517
+ if (err == null || typeof err !== "object") return false;
5518
+ return typeof err.code === "number";
5519
+ }
5520
+ function sleep2(ms, signal) {
5420
5521
  return new Promise((resolve, reject) => {
5421
- const t = setTimeout(() => {
5422
- signal.removeEventListener("abort", abortHandler);
5522
+ if (signal?.aborted) {
5523
+ reject(new CompliancePollError("compliance poll aborted", "unknown"));
5524
+ return;
5525
+ }
5526
+ const timer = setTimeout(() => {
5527
+ signal?.removeEventListener("abort", onAbort);
5423
5528
  resolve();
5424
5529
  }, ms);
5425
- const abortHandler = () => {
5426
- clearTimeout(t);
5427
- signal.removeEventListener("abort", abortHandler);
5428
- reject(new Error("aborted"));
5530
+ const onAbort = () => {
5531
+ clearTimeout(timer);
5532
+ signal?.removeEventListener("abort", onAbort);
5533
+ reject(new CompliancePollError("compliance poll aborted", "unknown"));
5429
5534
  };
5430
- signal.addEventListener("abort", abortHandler);
5535
+ signal?.addEventListener("abort", onAbort, { once: true });
5431
5536
  });
5432
5537
  }
5433
5538
 
5434
- // src/bug-report.ts
5539
+ // src/support/bug-report.ts
5435
5540
  Client.prototype.submitBugReport = async function(reportData, signal) {
5436
5541
  if (reportData == null) {
5437
5542
  throw new Error("acosmi: reportData required");
@@ -5478,8 +5583,10 @@ exports.ErrBrowserOpen = ErrBrowserOpen;
5478
5583
  exports.ErrComplianceStepUpRequired = ErrComplianceStepUpRequired;
5479
5584
  exports.ErrDiscovery = ErrDiscovery;
5480
5585
  exports.ErrEnvelopeGateClosed = ErrEnvelopeGateClosed;
5586
+ exports.ErrOAuthCORSBlocked = ErrOAuthCORSBlocked;
5481
5587
  exports.ErrProviderNotConfigured = ErrProviderNotConfigured;
5482
5588
  exports.ErrProviderUnknownNoRetry = ErrProviderUnknownNoRetry;
5589
+ exports.ErrRefreshProxyFailed = ErrRefreshProxyFailed;
5483
5590
  exports.ErrRegistration = ErrRegistration;
5484
5591
  exports.ErrSSLProxy = ErrSSLProxy;
5485
5592
  exports.ErrSealApprovalContractHashMismatch = ErrSealApprovalContractHashMismatch;
@@ -5493,6 +5600,7 @@ exports.ErrSealUseAlreadyConsumed = ErrSealUseAlreadyConsumed;
5493
5600
  exports.ErrStateMismatch = ErrStateMismatch;
5494
5601
  exports.ErrTimeout = ErrTimeout;
5495
5602
  exports.ErrTokenExchange = ErrTokenExchange;
5603
+ exports.ErrTokenExpired = ErrTokenExpired;
5496
5604
  exports.EventAuthURL = EventAuthURL;
5497
5605
  exports.EventComplete = EventComplete;
5498
5606
  exports.EventError = EventError;