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