@acosmi/sdk-ts 1.4.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +160 -0
  2. package/README.md +99 -5
  3. package/dist/browser/index.mjs +2432 -1891
  4. package/dist/browser/index.mjs.map +1 -1
  5. package/dist/index.mjs +2432 -1891
  6. package/dist/index.mjs.map +1 -1
  7. package/dist/node/adapters/anthropic.cjs +6 -4
  8. package/dist/node/adapters/anthropic.cjs.map +1 -1
  9. package/dist/node/adapters/anthropic.d.cts +1 -1
  10. package/dist/node/adapters/anthropic.d.ts +1 -1
  11. package/dist/node/adapters/anthropic.mjs +6 -4
  12. package/dist/node/adapters/anthropic.mjs.map +1 -1
  13. package/dist/node/adapters/openai.cjs +4 -2
  14. package/dist/node/adapters/openai.cjs.map +1 -1
  15. package/dist/node/adapters/openai.d.cts +2 -64
  16. package/dist/node/adapters/openai.d.ts +2 -64
  17. package/dist/node/adapters/openai.mjs +4 -2
  18. package/dist/node/adapters/openai.mjs.map +1 -1
  19. package/dist/node/index-DEA6LXw6.d.cts +409 -0
  20. package/dist/node/index-DEA6LXw6.d.ts +409 -0
  21. package/dist/node/index.cjs +2438 -1890
  22. package/dist/node/index.cjs.map +1 -1
  23. package/dist/node/index.d.cts +2846 -1225
  24. package/dist/node/index.d.ts +2846 -1225
  25. package/dist/node/index.mjs +2432 -1891
  26. package/dist/node/index.mjs.map +1 -1
  27. package/dist/node/openai-BDodfhsG.d.cts +125 -0
  28. package/dist/node/openai-vfUUgdvL.d.ts +125 -0
  29. package/docs/compliance.md +452 -2
  30. package/examples/agent-runs-stream.ts +118 -0
  31. package/examples/auth-oauth-flow.ts +97 -0
  32. package/examples/core-chat.ts +85 -0
  33. package/package.json +5 -2
  34. package/dist/node/index-CbG9NqE-.d.cts +0 -1027
  35. package/dist/node/index-CbG9NqE-.d.ts +0 -1027
@@ -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";
@@ -3445,850 +3165,1334 @@ async function sleep(ms, signal) {
3445
3165
  });
3446
3166
  }
3447
3167
 
3448
- // src/client/compliance.ts
3449
- init_types();
3450
- var cache = /* @__PURE__ */ new WeakMap();
3451
- Object.defineProperty(Client.prototype, "compliance", {
3452
- configurable: true,
3453
- enumerable: false,
3454
- get() {
3455
- let existing = cache.get(this);
3456
- if (!existing) {
3457
- existing = new ComplianceClient(this);
3458
- cache.set(this, existing);
3459
- }
3460
- return existing;
3461
- }
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
3462
3201
  });
3463
- var DEFAULT_POLL = {
3464
- timeoutMs: 6e4,
3465
- initialIntervalMs: 1e3,
3466
- maxIntervalMs: 5e3,
3467
- multiplier: 1.5
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";
3232
+ }
3468
3233
  };
3469
- var CompliancePollError = class extends Error {
3470
- kind;
3471
- lastInfo;
3472
- constructor(message, kind, lastInfo) {
3473
- super(message);
3474
- this.name = "CompliancePollError";
3475
- this.kind = kind;
3476
- this.lastInfo = lastInfo;
3234
+ var BlockDeniedError = class extends Error {
3235
+ constructor() {
3236
+ super("sanitize: block type permanently denied");
3237
+ this.name = "BlockDeniedError";
3477
3238
  }
3478
3239
  };
3479
- var ComplianceClient = class {
3480
- constructor(client) {
3481
- this.client = client;
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;
3482
3250
  }
3483
- client;
3484
- // =========================================================================
3485
- // Evidence Asset
3486
- // =========================================================================
3487
- /** 创建证据资产(写)。 */
3488
- createEvidenceAsset(req, opts = {}) {
3489
- return this.write(
3490
- "POST",
3491
- "/compliance/evidence/assets",
3492
- req,
3493
- writeCtx(opts)
3494
- );
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);
3495
3280
  }
3496
- /** 读 — 证据资产详情。 */
3497
- getEvidenceAsset(id, signal) {
3498
- return this.read(
3499
- "GET",
3500
- `/compliance/evidence/assets/${encodeURIComponent(id)}`,
3501
- null,
3502
- signal
3503
- );
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
+ }
3504
3299
  }
3505
- /**
3506
- * 公开 verify。隐私边界:返回字段不含 PII / 合同原文 / storage / provider raw。
3507
- *
3508
- * 匿名可调用:未 login 时走匿名请求,不会抛 `not authorized, call login() first`。
3509
- * login / 已持有 token 时附带 `Authorization` 以保留审计上下文。public 端点不
3510
- * 应要求认证 收到 401 直接抛 HTTPError,不触发 `forceRefresh`,也不做 refresh
3511
- * replay。
3512
- */
3513
- verifyEvidencePublic(params, signal) {
3514
- const q = new URLSearchParams();
3515
- if (params.evidenceNo) q.set("evidenceNo", params.evidenceNo);
3516
- if (params.publicVerifyCode) q.set("publicVerifyCode", params.publicVerifyCode);
3517
- const qs = q.toString();
3518
- return this.publicRead(
3519
- "GET",
3520
- `/compliance/evidence/verify${qs ? "?" + qs : ""}`,
3521
- signal
3522
- );
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);
3523
3325
  }
3524
- // =========================================================================
3525
- // Timestamp
3526
- // =========================================================================
3527
- /** 申请时间章(写)。SDK 永远不传 provider 字段。 */
3528
- issueTimestamp(req, opts = {}) {
3529
- return this.write("POST", "/compliance/timestamps", req, writeCtx(opts));
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;
3530
3346
  }
3531
- /** 给已有资产申请时间章。SDK 永远不传 provider 字段。 */
3532
- issueTimestampForAsset(assetId, opts = {}) {
3533
- return this.write(
3534
- "POST",
3535
- `/compliance/evidence/assets/${encodeURIComponent(assetId)}/timestamp`,
3536
- null,
3537
- writeCtx(opts)
3538
- );
3347
+ if ((cfg.maxImageBytes ?? 0) > 0 || (cfg.maxVideoBytes ?? 0) > 0 || (cfg.maxPDFBytes ?? 0) > 0) {
3348
+ checkMediaSizes(messages, cfg);
3539
3349
  }
3540
- /** 时间章 token 详情。 */
3541
- getTimestamp(id, signal) {
3542
- return this.read(
3543
- "GET",
3544
- `/compliance/timestamps/${encodeURIComponent(id)}`,
3545
- null,
3546
- signal
3547
- );
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
+ });
3548
3357
  }
3549
- /** verify — 本地离线校验已申请的时间章。 */
3550
- verifyTimestamp(req, opts = {}) {
3551
- return this.write(
3552
- "POST",
3553
- "/compliance/timestamps/verify",
3554
- req,
3555
- writeCtx(opts)
3556
- );
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
+ }
3557
3391
  }
3558
- /**
3559
- * 轮询到 VERIFIED 终态。
3560
- * - VERIFIED → 返回 token;
3561
- * - FAILED / LOCAL_VERIFY_FAILED → 抛 {@link CompliancePollError} kind='terminal_failure';
3562
- * - UNKNOWN / RETRYING / PENDING → 继续轮询直到 timeout;
3563
- * - timeout → 抛 {@link CompliancePollError} kind='timeout'。
3564
- */
3565
- async waitForTimestampVerified(id, opts = {}) {
3566
- return this.poll(
3567
- () => this.getTimestamp(id, opts.signal),
3568
- (t) => classifyTimestamp(t.verificationStatus),
3569
- opts
3570
- );
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);
3571
3403
  }
3572
- // =========================================================================
3573
- // Evidence Package
3574
- // =========================================================================
3575
- /** 构建证据包(写)。 */
3576
- buildEvidencePackage(assetId, timestampTokenId, opts = {}) {
3577
- const tsParam = timestampTokenId == null ? "" : "?timestampTokenId=" + encodeURIComponent(timestampTokenId);
3578
- return this.write(
3579
- "POST",
3580
- `/compliance/evidence/assets/${encodeURIComponent(assetId)}/packages${tsParam}`,
3581
- null,
3582
- writeCtx(opts)
3583
- );
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;
3584
3445
  }
3585
- // =========================================================================
3586
- // Report
3587
- // =========================================================================
3588
- /** 创建证据报告(写)。 */
3589
- createReport(req, opts = {}) {
3590
- return this.write("POST", "/compliance/reports", req, writeCtx(opts));
3446
+ if (cfg && (cfg.maxMessagesTurns ?? 0) > 0 && (req.messages?.length ?? 0) > cfg.maxMessagesTurns) {
3447
+ throw ErrHistoryTooDeep;
3591
3448
  }
3592
- /** 读 — 报告详情。 */
3593
- getReport(id, signal) {
3594
- return this.read(
3595
- "GET",
3596
- `/compliance/reports/${encodeURIComponent(id)}`,
3597
- null,
3598
- signal
3599
- );
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)}`);
3600
3457
  }
3601
- /**
3602
- * 发布报告(写,step-up 必须)。
3603
- *
3604
- * `@status gated` — step-up 闸门未闭合前服务端会一致返回
3605
- * `COMPLIANCE_STEP_UP_REQUIRED`(数值码 1031000013)。SDK 不会自动重试、不伪成功;
3606
- * 调用方需要引导用户重新做 OAuth introspection 或重新登录后再次调用本方法
3607
- *(使用同一 idempotency-key)。方法状态分级见 `docs/compliance.md` Method Status。
3608
- */
3609
- publishReport(id, opts = {}) {
3610
- return this.write(
3611
- "POST",
3612
- `/compliance/reports/${encodeURIComponent(id)}/publish`,
3613
- null,
3614
- writeCtx(opts)
3615
- );
3458
+ if (!Array.isArray(s)) {
3459
+ throw new Error("raw messages must be a JSON array");
3616
3460
  }
3617
- /**
3618
- * 下载报告(读)。返回 {@link ReportDownload}:报告 hash + 资产 hash + 证据包 hash +
3619
- * 时间章 serial/genTime,足以离线复核。
3620
- * 不返回 bodyCanonicalJson / storage key / subject snapshot id。
3621
- */
3622
- downloadReport(id, signal) {
3623
- return this.read(
3624
- "GET",
3625
- `/compliance/reports/${encodeURIComponent(id)}/download`,
3626
- null,
3627
- signal
3628
- );
3461
+ return s;
3462
+ }
3463
+
3464
+ // src/shared/index.ts
3465
+ init_errors();
3466
+
3467
+ // src/shared/operation.ts
3468
+ var IdempotencyKeyHeader = "Idempotency-Key";
3469
+
3470
+ // src/shared/retry-advice.ts
3471
+ var RETRY_ADVICE_REASONS = [
3472
+ "unknown",
3473
+ "retrying",
3474
+ "failed",
3475
+ "gate_closed",
3476
+ "step_up_required",
3477
+ "tenant_mismatch",
3478
+ "insufficient_scope",
3479
+ "quota_exceeded",
3480
+ "provider_timeout",
3481
+ "local_verify_failed",
3482
+ "billing_preflight_failed"
3483
+ ];
3484
+ var COMPLIANCE_KEY_TO_RETRY_REASON = {
3485
+ // 通用 / token / scope
3486
+ COMPLIANCE_UNAUTHORIZED: "failed",
3487
+ COMPLIANCE_INSUFFICIENT_SCOPE: "insufficient_scope",
3488
+ COMPLIANCE_STEP_UP_REQUIRED: "step_up_required",
3489
+ COMPLIANCE_TOKEN_INVALID: "failed",
3490
+ // 主体快照
3491
+ SUBJECT_SNAPSHOT_REQUIRED: "failed",
3492
+ SUBJECT_SNAPSHOT_NOT_FOUND: "failed",
3493
+ SUBJECT_SNAPSHOT_TENANT_MISMATCH: "tenant_mismatch",
3494
+ // Evidence / Timestamp / Package / Report
3495
+ EVIDENCE_ASSET_NOT_FOUND: "failed",
3496
+ EVIDENCE_ASSET_HASH_MISMATCH: "local_verify_failed",
3497
+ EVIDENCE_ASSET_PAYLOAD_REQUIRED: "failed",
3498
+ TIMESTAMP_TOKEN_NOT_FOUND: "failed",
3499
+ TIMESTAMP_PROVIDER_FAILED: "failed",
3500
+ TIMESTAMP_PROVIDER_UNKNOWN: "unknown",
3501
+ TIMESTAMP_LOCAL_VERIFY_FAILED: "local_verify_failed",
3502
+ TIMESTAMP_PROVIDER_NOT_AVAILABLE: "provider_timeout",
3503
+ EVIDENCE_PACKAGE_NOT_FOUND: "failed",
3504
+ EVIDENCE_PACKAGE_TIMESTAMP_REQUIRED: "failed",
3505
+ EVIDENCE_PACKAGE_MANIFEST_HASH_MISMATCH: "local_verify_failed",
3506
+ REPORT_NOT_FOUND: "failed",
3507
+ REPORT_ALREADY_PUBLISHED: "failed",
3508
+ REPORT_DRAFT_REQUIRED: "failed",
3509
+ EVIDENCE_VERIFY_TARGET_REQUIRED: "failed",
3510
+ EVIDENCE_VERIFY_TARGET_NOT_FOUND: "failed",
3511
+ // Provider request
3512
+ PROVIDER_REQUEST_UNKNOWN_NO_RETRY: "unknown",
3513
+ PROVIDER_CALLBACK_SOURCE_INVALID: "failed",
3514
+ PROVIDER_NOT_CONFIGURED: "gate_closed",
3515
+ PROVIDER_REQUEST_NOT_FOUND: "failed",
3516
+ PROVIDER_REQUEST_IDEMPOTENCY_REQUIRED: "failed",
3517
+ PROVIDER_REQUEST_STATUS_NOT_TERMINAL: "retrying",
3518
+ // Envelope
3519
+ ENVELOPE_NOT_FOUND: "failed",
3520
+ ENVELOPE_TENANT_MISMATCH: "tenant_mismatch",
3521
+ ENVELOPE_STATE_NOT_ALLOWED: "failed",
3522
+ ENVELOPE_GATE_CLOSED: "gate_closed",
3523
+ CONTRACT_NOT_FOUND: "failed",
3524
+ CONTRACT_HASH_MISMATCH: "local_verify_failed",
3525
+ PROVIDER_AUTHORIZATION_NOT_CONFIRMED: "failed",
3526
+ ENVELOPE_EVIDENCE_NOT_READY: "retrying",
3527
+ // Seal approval / use
3528
+ SEAL_ASSET_NOT_FOUND: "failed",
3529
+ SEAL_APPROVAL_NOT_FOUND: "failed",
3530
+ SEAL_APPROVAL_STATE_NOT_APPROVED: "failed",
3531
+ SEAL_APPROVAL_EXPIRED: "failed",
3532
+ SEAL_APPROVAL_ALREADY_USED: "failed",
3533
+ SEAL_APPROVAL_NONCE_USED: "failed",
3534
+ SEAL_APPROVAL_SEAL_MISMATCH: "failed",
3535
+ SEAL_APPROVAL_LOCATION_MISMATCH: "failed",
3536
+ SEAL_APPROVAL_TRANSACTOR_MISMATCH: "failed",
3537
+ SEAL_APPROVAL_CONTRACT_HASH_MISMATCH: "local_verify_failed",
3538
+ SEAL_APPROVAL_INVALID_TRANSITION: "failed",
3539
+ SEAL_USE_ALREADY_CONSUMED: "failed",
3540
+ // Audit chain
3541
+ AUDIT_CHAIN_TAMPER_DETECTED: "local_verify_failed",
3542
+ // Billing
3543
+ BILLING_COMMIT_REQUIRES_LOCAL_VERIFY: "local_verify_failed",
3544
+ BILLING_COMMIT_REQUIRES_PROVIDER_SUCCESS: "billing_preflight_failed",
3545
+ BILLING_CALLBACK_CANNOT_COMMIT: "billing_preflight_failed",
3546
+ BILLING_PROVIDER_UNKNOWN_NOT_COMMITTABLE: "billing_preflight_failed",
3547
+ BILLING_S2S_FORBIDDEN: "failed",
3548
+ // SDK fallback
3549
+ UNKNOWN_COMPLIANCE_ERROR: "unknown"
3550
+ };
3551
+ function retryReasonForComplianceKey(key) {
3552
+ return COMPLIANCE_KEY_TO_RETRY_REASON[key] ?? "unknown";
3553
+ }
3554
+ var OAUTH_ERROR_TO_RETRY_REASON = {
3555
+ insufficient_scope: "insufficient_scope",
3556
+ invalid_token: "failed",
3557
+ invalid_grant: "failed",
3558
+ invalid_request: "failed",
3559
+ access_denied: "failed",
3560
+ unsupported_grant_type: "failed"
3561
+ };
3562
+ function retryReasonForOAuthError(oauthError) {
3563
+ return OAUTH_ERROR_TO_RETRY_REASON[oauthError] ?? "unknown";
3564
+ }
3565
+ function complianceErrorToRetryAdvice(info) {
3566
+ return {
3567
+ retryable: info.retryable,
3568
+ sameIdempotencyKeyRequired: !info.terminal,
3569
+ manualActionRequired: info.terminal || info.stepUpRequired,
3570
+ reason: retryReasonForComplianceKey(info.key),
3571
+ developerMessage: info.message,
3572
+ supportCode: `compliance:${info.code}`
3573
+ };
3574
+ }
3575
+
3576
+ // src/auth/scopes.ts
3577
+ var ScopeAI = "ai";
3578
+ var ScopeSkills = "skills";
3579
+ var ScopeAccount = "account";
3580
+ var ScopeModels = "models";
3581
+ var ScopeModelsChat = "models:chat";
3582
+ var ScopeEntitlements = "entitlements";
3583
+ var ScopeTokenPackages = "token-packages";
3584
+ var ScopeSkillStore = "skill_store";
3585
+ var ScopeTools = "tools";
3586
+ var ScopeToolsExecute = "tools:execute";
3587
+ var ScopeWallet = "wallet";
3588
+ var ScopeWalletReadonly = "wallet:readonly";
3589
+ var ScopeProfile = "profile";
3590
+ function allScopes() {
3591
+ return [ScopeAI, ScopeSkills, ScopeAccount];
3592
+ }
3593
+ function modelScopes() {
3594
+ return [ScopeAI];
3595
+ }
3596
+ function commerceScopes() {
3597
+ return [ScopeAI, ScopeAccount];
3598
+ }
3599
+ function skillScopes() {
3600
+ return [ScopeSkills];
3601
+ }
3602
+
3603
+ // src/models/index.ts
3604
+ init_types();
3605
+
3606
+ // src/models/wire-anthropic.ts
3607
+ function anthropicResponseTextContent(r) {
3608
+ const parts = [];
3609
+ for (const b of r.content) {
3610
+ if (b.type === "text" && b.text) parts.push(b.text);
3629
3611
  }
3630
- // =========================================================================
3631
- // Signing Envelope
3632
- // =========================================================================
3633
- /** 创建 envelope(写)。返回 envelope id。 */
3634
- createSigningEnvelope(req, opts = {}) {
3635
- return this.write(
3636
- "POST",
3637
- "/compliance/signing-envelopes",
3638
- req,
3639
- writeCtx(opts)
3640
- );
3612
+ return parts.join("");
3613
+ }
3614
+ function anthropicResponseThinkingContent(r) {
3615
+ const parts = [];
3616
+ for (const b of r.content) {
3617
+ if (b.type === "thinking" && b.thinking) parts.push(b.thinking);
3641
3618
  }
3642
- /** 读 — envelope 详情。租户由服务端从 compliance token principal 推导。 */
3643
- getSigningEnvelope(envelopeId, signal) {
3644
- return this.read(
3645
- "GET",
3646
- `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}`,
3647
- null,
3648
- signal
3649
- );
3619
+ return parts.join("");
3620
+ }
3621
+ function anthropicResponseToolUseBlocks(r) {
3622
+ return r.content.filter((b) => b.type === "tool_use");
3623
+ }
3624
+
3625
+ // src/models/model-helpers.ts
3626
+ function modelSupportsInputModality(model, modality) {
3627
+ if (!model) return false;
3628
+ const mods = model.inputModalities;
3629
+ if (!Array.isArray(mods)) return false;
3630
+ return mods.includes(modality);
3631
+ }
3632
+ function modelSupportsImageInput(model) {
3633
+ return modelSupportsInputModality(model, "image");
3634
+ }
3635
+ function findFirstModelByInputModality(models, modality) {
3636
+ if (!Array.isArray(models)) return null;
3637
+ for (const m of models) {
3638
+ if (!m) continue;
3639
+ if (m.isEnabled === false) continue;
3640
+ if (!modelSupportsInputModality(m, modality)) continue;
3641
+ return m;
3650
3642
  }
3651
- /**
3652
- * 正式签署(写,step-up 必须)。
3653
- *
3654
- * `@status gated` — 服务端闸门关闭时会一致返回 `ENVELOPE_GATE_CLOSED` (1031004004)。
3655
- * SDK 不重试、不伪成功;调用方应该将该错误展示为"功能未开放"。
3656
- */
3657
- signEnvelope(envelopeId, req, opts = {}) {
3658
- return this.write(
3659
- "POST",
3660
- `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}/sign`,
3661
- req,
3662
- writeCtx(opts)
3663
- );
3643
+ return null;
3644
+ }
3645
+ function findDesktopVisualUnderstandingModel(models) {
3646
+ if (!Array.isArray(models)) return null;
3647
+ const candidates = [];
3648
+ for (const m of models) {
3649
+ if (!m) continue;
3650
+ if (m.isEnabled === false) continue;
3651
+ if (m.capabilities?.supports_desktop_visual_understanding !== true) continue;
3652
+ if (!modelSupportsInputModality(m, "image")) continue;
3653
+ candidates.push(m);
3664
3654
  }
3665
- /**
3666
- * 创建 H5 签署短链(写,step-up 必须)。
3667
- *
3668
- * `@status gated` — 同 {@link signEnvelope}:服务端闸门关闭时 SDK 不重试、不伪成功。
3669
- */
3670
- createH5SigningUrl(envelopeId, req, opts = {}) {
3671
- return this.write(
3672
- "POST",
3673
- `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}/h5-url`,
3674
- req,
3675
- writeCtx(opts)
3676
- );
3655
+ if (candidates.length === 0) return null;
3656
+ for (const m of candidates) {
3657
+ if (m.isDefault === true) return m;
3677
3658
  }
3678
- /** 同步 provider 状态(写但只读对账,不创建新 provider 请求)。 */
3679
- syncSigningEnvelopeStatus(envelopeId, opts = {}) {
3680
- return this.write(
3681
- "POST",
3682
- `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}/sync-provider-status`,
3683
- null,
3684
- writeCtx(opts)
3685
- );
3659
+ return candidates[0];
3660
+ }
3661
+
3662
+ // src/models/index.ts
3663
+ init_adapters();
3664
+ init_betas();
3665
+
3666
+ // src/billing/entitlements.ts
3667
+ Client.prototype.getBalance = async function(signal) {
3668
+ const resp = await this.doJSON(
3669
+ "GET",
3670
+ "/entitlements/balance",
3671
+ null,
3672
+ signal
3673
+ );
3674
+ return resp.data;
3675
+ };
3676
+ Client.prototype.getBalanceDetail = async function(signal) {
3677
+ const resp = await this.doJSON(
3678
+ "GET",
3679
+ "/entitlements/balance-detail",
3680
+ null,
3681
+ signal
3682
+ );
3683
+ return resp.data;
3684
+ };
3685
+ Client.prototype.listEntitlements = async function(status, signal) {
3686
+ let path = "/entitlements";
3687
+ if (status !== "") {
3688
+ path += `?status=${encodeURIComponent(status)}`;
3686
3689
  }
3687
- // =========================================================================
3688
- // Seal Approval
3689
- // =========================================================================
3690
- /**
3691
- * 提交用印审批申请(写)。
3692
- *
3693
- * `@status production-ready` — 服务端以 `Idempotency-Key` + 业务请求指纹做重放保护:
3694
- * 同 key + 同请求 → 返回原审批 id;同 key + 不同请求 → 拒绝复用幂等键。强烈建议调用方
3695
- * 持久化 `idempotencyKey`,网络重试 / 任务恢复时复用,避免重复创建审批单。
3696
- */
3697
- submitSealApproval(req, opts = {}) {
3698
- return this.write(
3699
- "POST",
3700
- "/compliance/seal-approvals",
3701
- req,
3702
- writeCtx(opts)
3703
- );
3690
+ const resp = await this.doJSON("GET", path, null, signal);
3691
+ return resp.data;
3692
+ };
3693
+ Client.prototype.listConsumeRecords = async function(page, pageSize, signal) {
3694
+ const path = `/entitlements/consume-records?page=${page}&pageSize=${pageSize}`;
3695
+ const resp = await this.doJSON("GET", path, null, signal);
3696
+ return resp.data;
3697
+ };
3698
+ Client.prototype.claimMonthlyFree = async function(signal) {
3699
+ const resp = await this.doJSON(
3700
+ "POST",
3701
+ "/entitlements/claim-monthly",
3702
+ null,
3703
+ signal
3704
+ );
3705
+ return resp.data;
3706
+ };
3707
+ Client.prototype.getByModel = async function(modelID, signal) {
3708
+ if (modelID === "") throw new Error("modelID required");
3709
+ const path = `/entitlements/by-model?modelId=${encodeURIComponent(modelID)}`;
3710
+ const resp = await this.doJSON("GET", path, null, signal);
3711
+ return resp.data;
3712
+ };
3713
+ Client.prototype.listBuckets = async function(signal) {
3714
+ const resp = await this.doJSON(
3715
+ "GET",
3716
+ "/entitlements/buckets",
3717
+ null,
3718
+ signal
3719
+ );
3720
+ return resp.data;
3721
+ };
3722
+ Client.prototype.listCoefficients = async function(signal) {
3723
+ if (this.coefCacheData && Date.now() - this.coefCacheTimeMs < coefCacheTTLMs) {
3724
+ return [...this.coefCacheData];
3704
3725
  }
3705
- /**
3706
- * 审批通过用印申请(写,step-up 必须)。
3707
- *
3708
- * `@status gated` — step-up 未闭合前服务端会返回 `COMPLIANCE_STEP_UP_REQUIRED`。
3709
- * SDK 不重试、不伪成功。方法状态分级见 `docs/compliance.md` Method Status。
3710
- */
3711
- approveSealApproval(id, query, opts = {}) {
3712
- const q = new URLSearchParams();
3713
- if (query.expiresAt) q.set("expiresAt", query.expiresAt);
3714
- if (query.note) q.set("note", query.note);
3715
- const qs = q.toString();
3716
- return this.write(
3717
- "POST",
3718
- `/compliance/seal-approvals/${encodeURIComponent(id)}/approve${qs ? "?" + qs : ""}`,
3719
- null,
3720
- writeCtx(opts)
3721
- );
3722
- }
3723
- rejectSealApproval(id, query, opts = {}) {
3724
- const q = new URLSearchParams();
3725
- if (query.reason) q.set("reason", query.reason);
3726
- const qs = q.toString();
3727
- return this.write(
3728
- "POST",
3729
- `/compliance/seal-approvals/${encodeURIComponent(id)}/reject${qs ? "?" + qs : ""}`,
3730
- null,
3731
- writeCtx(opts)
3732
- );
3733
- }
3734
- cancelSealApproval(id, query, opts = {}) {
3735
- const q = new URLSearchParams();
3736
- if (query.reason) q.set("reason", query.reason);
3737
- const qs = q.toString();
3738
- return this.write(
3739
- "POST",
3740
- `/compliance/seal-approvals/${encodeURIComponent(id)}/cancel${qs ? "?" + qs : ""}`,
3741
- null,
3742
- writeCtx(opts)
3743
- );
3744
- }
3745
- listPendingSealApprovals(signal) {
3746
- return this.read(
3747
- "GET",
3748
- "/compliance/seal-approvals/pending",
3749
- null,
3750
- signal
3751
- );
3752
- }
3753
- getSealApproval(id, signal) {
3754
- return this.read(
3755
- "GET",
3756
- `/compliance/seal-approvals/${encodeURIComponent(id)}`,
3757
- null,
3758
- signal
3759
- );
3760
- }
3761
- // =========================================================================
3762
- // Provider Request (read-only)
3763
- // =========================================================================
3764
- getProviderRequest(id, signal) {
3765
- return this.read(
3766
- "GET",
3767
- `/compliance/provider-requests/${encodeURIComponent(id)}`,
3768
- null,
3769
- signal
3770
- );
3771
- }
3772
- /**
3773
- * 轮询 provider request 到 SUCCESS / FAILED 终态。
3774
- * - SUCCESS / FAILED → 返回最后视图;
3775
- * - UNKNOWN / RETRYING / PENDING → 继续轮询;
3776
- * - timeout → 抛 {@link CompliancePollError} kind='timeout',不自动重发原 provider 请求。
3777
- *
3778
- * SUCCESS 不代表 billing 已 commit;调用方仍需通过业务侧 envelope / asset 终态判断。
3779
- */
3780
- async waitForProviderRequestTerminal(id, opts = {}) {
3781
- return this.poll(
3782
- () => this.getProviderRequest(id, opts.signal),
3783
- (v) => classifyProviderStatus(v.status),
3784
- opts
3785
- );
3786
- }
3787
- // =========================================================================
3788
- // Error classification (re-export for convenience)
3789
- // =========================================================================
3790
- classifyError(err) {
3791
- if (!isBusinessErrorLike(err)) return null;
3792
- if (!isComplianceBusinessError(err)) return null;
3793
- return classifyComplianceError(err);
3726
+ const resp = await this.doJSON(
3727
+ "GET",
3728
+ "/entitlements/coefficients",
3729
+ null,
3730
+ signal
3731
+ );
3732
+ this.coefCacheData = [...resp.data];
3733
+ this.coefCacheTimeMs = Date.now();
3734
+ return resp.data;
3735
+ };
3736
+ Client.prototype.invalidateCoefficientCache = function() {
3737
+ this.coefCacheData = null;
3738
+ this.coefCacheTimeMs = 0;
3739
+ };
3740
+
3741
+ // src/billing/packages.ts
3742
+ init_errors();
3743
+ Client.prototype.listTokenPackages = async function(signal) {
3744
+ const raw = await this.doJSON("GET", "/token-packages", null, signal);
3745
+ if (raw.data && typeof raw.data === "object" && "list" in raw.data) {
3746
+ const page = raw.data;
3747
+ if (Array.isArray(page.list)) return page.list;
3794
3748
  }
3795
- // =========================================================================
3796
- // Internal helpers
3797
- // =========================================================================
3798
- /**
3799
- * 读路径:GET / 公开 verify。允许 401 单次刷新后重放(GET 幂等安全)。
3800
- * 与 client.doJSONFullInternal 行为一致;不复用其代码因为 base URL 不同。
3801
- */
3802
- async read(method, path, body, signal, extraHeaders = {}) {
3803
- return this.executeJson(method, path, body, signal, {
3804
- retryOn401: true,
3805
- extraHeaders
3806
- });
3749
+ if (Array.isArray(raw.data)) return raw.data;
3750
+ throw new Error("decode token packages: unexpected shape");
3751
+ };
3752
+ Client.prototype.getTokenPackageDetail = async function(packageID, signal) {
3753
+ const resp = await this.doJSON(
3754
+ "GET",
3755
+ `/token-packages/${encodeURIComponent(packageID)}`,
3756
+ null,
3757
+ signal
3758
+ );
3759
+ return resp.data;
3760
+ };
3761
+ Client.prototype.buyTokenPackage = async function(packageID, payload, signal) {
3762
+ const body = payload ?? null;
3763
+ const resp = await this.doJSON(
3764
+ "POST",
3765
+ `/token-packages/${encodeURIComponent(packageID)}/buy`,
3766
+ body,
3767
+ signal
3768
+ );
3769
+ return resp.data;
3770
+ };
3771
+ Client.prototype.getOrderStatus = async function(orderID, signal) {
3772
+ const resp = await this.doJSON(
3773
+ "GET",
3774
+ `/token-packages/orders/${encodeURIComponent(orderID)}/status`,
3775
+ null,
3776
+ signal
3777
+ );
3778
+ return resp.data;
3779
+ };
3780
+ Client.prototype.listMyOrders = async function(signal) {
3781
+ const raw = await this.doJSON("GET", "/token-packages/my", null, signal);
3782
+ if (raw.data && typeof raw.data === "object" && "list" in raw.data) {
3783
+ const page = raw.data;
3784
+ if (Array.isArray(page.list)) return page.list;
3807
3785
  }
3808
- /**
3809
- * 公开读路径:public verify。
3810
- *
3811
- * {@link read} 的区别 public 端点不应要求认证:
3812
- * - token 时匿名请求:ensureToken `not authorized` 会被吞掉,继续匿名发送。
3813
- * - token 时附带 `Authorization`,保留后端审计上下文。
3814
- * - 不做 401 refresh replay:401 直接抛 HTTPError,不触发 `forceRefresh`。
3815
- *
3816
- * URL 仍走 `client.complianceURL(path)`,不复用 `/api/v4`;底层复用
3817
- * `client.doRequest`,不新增 fetch/axios 直连。
3818
- */
3819
- async publicRead(method, path, signal) {
3820
- let token = "";
3821
- try {
3822
- token = await this.client.ensureToken(signal);
3823
- } catch {
3824
- }
3825
- const url = this.client.complianceURL(path);
3826
- const headers = { Accept: "application/json" };
3827
- if (token) headers.Authorization = `Bearer ${token}`;
3828
- const resp = await this.client.doRequest({ method, url, headers }, signal);
3829
- if (resp.status < 200 || resp.status >= 300) {
3830
- const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
3831
- throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
3786
+ if (Array.isArray(raw.data)) return raw.data;
3787
+ throw new Error("decode orders: unexpected shape");
3788
+ };
3789
+ Client.prototype.waitForPayment = async function(orderID, pollIntervalMs, signal) {
3790
+ if (pollIntervalMs <= 0) pollIntervalMs = 2e3;
3791
+ while (true) {
3792
+ const status = await this.getOrderStatus(orderID, signal);
3793
+ if (isOrderTerminal(status.status)) {
3794
+ if (isOrderSuccess(status.status)) return status;
3795
+ throw new OrderTerminalError(orderID, status.status);
3832
3796
  }
3833
- const text = await resp.text();
3834
- if (!text) return void 0;
3835
- const parsed = JSON.parse(text);
3836
- const bizErr = apiResponseBusinessError(parsed);
3837
- if (bizErr) throw bizErr;
3838
- return parsed.data;
3839
- }
3840
- /**
3841
- * 写路径:POST。
3842
- * - 发送前 ensureToken 一次确保 token fresh。
3843
- * - 不自动 401 重放:401 → 抛 HTTPError;调用方必须自己刷新 token 后用同一
3844
- * idempotency-key 重新发起,避免 provider 侧重复请求。
3845
- * - 不走 doRequestWithRetry:写操作不允许 5xx/timeout 自动重试。
3846
- */
3847
- async write(method, path, body, ctx) {
3848
- const headers = { ...ctx.extraHeaders ?? {} };
3849
- if (ctx.idempotencyKey) headers["Idempotency-Key"] = ctx.idempotencyKey;
3850
- return this.executeJson(method, path, body, ctx.signal, {
3851
- retryOn401: false,
3852
- extraHeaders: headers
3853
- });
3797
+ await sleepWithSignal(pollIntervalMs, signal);
3854
3798
  }
3855
- async executeJson(method, path, body, signal, opts, retried = false) {
3856
- const token = await this.client.ensureToken(signal);
3857
- const url = this.client.complianceURL(path);
3858
- const headers = {
3859
- Authorization: `Bearer ${token}`,
3860
- Accept: "application/json",
3861
- ...opts.extraHeaders
3862
- };
3863
- let bodyStr;
3864
- if (body != null) {
3865
- bodyStr = typeof body === "string" ? body : JSON.stringify(body);
3866
- headers["Content-Type"] = "application/json";
3867
- }
3868
- const resp = await this.client.doRequest({ method, url, headers, body: bodyStr }, signal);
3869
- if (resp.status === 401 && opts.retryOn401 && !retried) {
3870
- try {
3871
- await resp.body?.cancel();
3872
- } catch {
3873
- }
3874
- await this.client.forceRefresh(signal);
3875
- return this.executeJson(method, path, body, signal, opts, true);
3876
- }
3877
- if (resp.status < 200 || resp.status >= 300) {
3878
- const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
3879
- throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
3799
+ };
3800
+ async function sleepWithSignal(ms, signal) {
3801
+ if (ms <= 0) return;
3802
+ if (signal && signal.aborted) throw new Error("aborted");
3803
+ return new Promise((resolve, reject) => {
3804
+ const t = setTimeout(() => {
3805
+ if (signal && abortHandler) signal.removeEventListener("abort", abortHandler);
3806
+ resolve();
3807
+ }, ms);
3808
+ let abortHandler;
3809
+ if (signal) {
3810
+ abortHandler = () => {
3811
+ clearTimeout(t);
3812
+ signal.removeEventListener("abort", abortHandler);
3813
+ reject(new Error("aborted"));
3814
+ };
3815
+ signal.addEventListener("abort", abortHandler);
3880
3816
  }
3881
- const text = await resp.text();
3882
- if (!text) return void 0;
3883
- const parsed = JSON.parse(text);
3884
- const bizErr = apiResponseBusinessError(parsed);
3885
- if (bizErr) throw bizErr;
3886
- return parsed.data;
3887
- }
3888
- async poll(fetcher, classify, opts) {
3889
- const cfg = {
3890
- timeoutMs: opts.timeoutMs ?? DEFAULT_POLL.timeoutMs,
3891
- initialIntervalMs: opts.initialIntervalMs ?? DEFAULT_POLL.initialIntervalMs,
3892
- maxIntervalMs: opts.maxIntervalMs ?? DEFAULT_POLL.maxIntervalMs,
3893
- multiplier: opts.multiplier ?? DEFAULT_POLL.multiplier
3894
- };
3895
- const deadline = Date.now() + cfg.timeoutMs;
3896
- let interval = cfg.initialIntervalMs;
3897
- let lastValue;
3898
- while (Date.now() < deadline) {
3899
- if (opts.signal?.aborted) {
3900
- throw new CompliancePollError("compliance poll aborted", "unknown");
3901
- }
3902
- lastValue = await fetcher();
3903
- const decision = classify(lastValue);
3904
- if (decision === "done") return lastValue;
3905
- if (decision === "failed") {
3906
- throw new CompliancePollError(
3907
- "compliance poll observed terminal failure",
3908
- "terminal_failure"
3909
- );
3910
- }
3911
- const sleepMs = Math.min(interval, deadline - Date.now());
3912
- if (sleepMs <= 0) break;
3913
- await sleep2(sleepMs, opts.signal);
3914
- interval = Math.min(Math.floor(interval * cfg.multiplier), cfg.maxIntervalMs);
3915
- }
3916
- throw new CompliancePollError("compliance poll timed out", "timeout");
3917
- }
3918
- };
3919
- function classifyTimestamp(status) {
3920
- switch (status) {
3921
- case "VERIFIED":
3922
- return "done";
3923
- case "FAILED":
3924
- case "LOCAL_VERIFY_FAILED":
3925
- return "failed";
3926
- case "PENDING":
3927
- case "UNKNOWN":
3928
- case "RETRYING":
3929
- default:
3930
- return "continue";
3931
- }
3932
- }
3933
- function classifyProviderStatus(status) {
3934
- switch (status) {
3935
- case "SUCCESS":
3936
- return "done";
3937
- case "FAILED":
3938
- return "failed";
3939
- case "PENDING":
3940
- case "UNKNOWN":
3941
- case "RETRYING":
3942
- default:
3943
- return "continue";
3944
- }
3945
- }
3946
- function writeCtx(opts, extraHeaders = {}) {
3947
- return {
3948
- idempotencyKey: opts.idempotencyKey,
3949
- signal: opts.signal,
3950
- extraHeaders
3951
- };
3952
- }
3953
- function isBusinessErrorLike(err) {
3954
- if (err == null || typeof err !== "object") return false;
3955
- return typeof err.code === "number";
3956
- }
3957
- function sleep2(ms, signal) {
3958
- return new Promise((resolve, reject) => {
3959
- if (signal?.aborted) {
3960
- reject(new CompliancePollError("compliance poll aborted", "unknown"));
3961
- return;
3962
- }
3963
- const timer = setTimeout(() => {
3964
- signal?.removeEventListener("abort", onAbort);
3965
- resolve();
3966
- }, ms);
3967
- const onAbort = () => {
3968
- clearTimeout(timer);
3969
- signal?.removeEventListener("abort", onAbort);
3970
- reject(new CompliancePollError("compliance poll aborted", "unknown"));
3971
- };
3972
- signal?.addEventListener("abort", onAbort, { once: true });
3973
3817
  });
3974
3818
  }
3975
3819
 
3976
- // src/sanitize/index.ts
3977
- var sanitize_exports = {};
3978
- __export(sanitize_exports, {
3979
- BlockCodeExecutionToolResult: () => BlockCodeExecutionToolResult,
3980
- BlockContainerUpload: () => BlockContainerUpload,
3981
- BlockDeniedError: () => BlockDeniedError,
3982
- BlockDocument: () => BlockDocument,
3983
- BlockImage: () => BlockImage,
3984
- BlockMCPToolResult: () => BlockMCPToolResult,
3985
- BlockMCPToolUse: () => BlockMCPToolUse,
3986
- BlockRedactedThinking: () => BlockRedactedThinking,
3987
- BlockSearchResult: () => BlockSearchResult,
3988
- BlockServerToolUse: () => BlockServerToolUse,
3989
- BlockText: () => BlockText,
3990
- BlockThinking: () => BlockThinking,
3991
- BlockToolReference: () => BlockToolReference,
3992
- BlockToolResult: () => BlockToolResult,
3993
- BlockToolUse: () => BlockToolUse,
3994
- BlockVideo: () => BlockVideo,
3995
- BlockWebSearchToolResult: () => BlockWebSearchToolResult,
3996
- DeltaCitations: () => DeltaCitations,
3997
- DeltaInputJSON: () => DeltaInputJSON,
3998
- DeltaSignature: () => DeltaSignature,
3999
- DeltaText: () => DeltaText,
4000
- DeltaThinking: () => DeltaThinking,
4001
- EphemeralMarkerField: () => EphemeralMarkerField,
4002
- ErrBlockDenied: () => ErrBlockDenied,
4003
- ErrHistoryTooDeep: () => ErrHistoryTooDeep,
4004
- HistoryTooDeepError: () => HistoryTooDeepError,
4005
- SizeError: () => SizeError,
4006
- dropBlocks: () => dropBlocks,
4007
- sanitize: () => sanitize,
4008
- stripEphemeral: () => stripEphemeral
4009
- });
4010
-
4011
- // src/sanitize/types.ts
4012
- var BlockText = "text";
4013
- var BlockImage = "image";
4014
- var BlockVideo = "video";
4015
- var BlockDocument = "document";
4016
- var BlockSearchResult = "search_result";
4017
- var BlockThinking = "thinking";
4018
- var BlockRedactedThinking = "redacted_thinking";
4019
- var BlockToolUse = "tool_use";
4020
- var BlockToolResult = "tool_result";
4021
- var BlockToolReference = "tool_reference";
4022
- var BlockServerToolUse = "server_tool_use";
4023
- var BlockWebSearchToolResult = "web_search_tool_result";
4024
- var BlockCodeExecutionToolResult = "code_execution_tool_result";
4025
- var BlockMCPToolUse = "mcp_tool_use";
4026
- var BlockMCPToolResult = "mcp_tool_result";
4027
- var BlockContainerUpload = "container_upload";
4028
- var DeltaText = "text_delta";
4029
- var DeltaInputJSON = "input_json_delta";
4030
- var DeltaThinking = "thinking_delta";
4031
- var DeltaSignature = "signature_delta";
4032
- var DeltaCitations = "citations_delta";
4033
- var EphemeralMarkerField = "acosmi_ephemeral";
3820
+ // src/billing/wallet.ts
3821
+ Client.prototype.getWalletStats = async function(signal) {
3822
+ const resp = await this.doJSON("GET", "/wallet/stats", null, signal);
3823
+ return resp.data;
3824
+ };
3825
+ Client.prototype.getWalletTransactions = async function(signal) {
3826
+ const resp = await this.doJSON(
3827
+ "GET",
3828
+ "/wallet/transactions",
3829
+ null,
3830
+ signal
3831
+ );
3832
+ return resp.data;
3833
+ };
4034
3834
 
4035
- // src/sanitize/config.ts
4036
- var HistoryTooDeepError = class extends Error {
4037
- constructor() {
4038
- super("sanitize: messages history exceeds configured depth");
4039
- this.name = "HistoryTooDeepError";
4040
- }
3835
+ // src/skills/skills.ts
3836
+ init_errors();
3837
+ Client.prototype.browseSkillStore = async function(query, signal) {
3838
+ const resp = await this.browseSkills(
3839
+ 1,
3840
+ 50,
3841
+ query.category ?? "",
3842
+ query.keyword ?? "",
3843
+ query.tag ?? "",
3844
+ "",
3845
+ signal
3846
+ );
3847
+ return resp.items;
4041
3848
  };
4042
- var BlockDeniedError = class extends Error {
4043
- constructor() {
4044
- super("sanitize: block type permanently denied");
4045
- this.name = "BlockDeniedError";
4046
- }
3849
+ Client.prototype.browseSkills = async function(page, pageSize, category, keyword, tag, source, signal) {
3850
+ const qv = new URLSearchParams();
3851
+ qv.set("page", String(page));
3852
+ qv.set("pageSize", String(pageSize));
3853
+ if (category) qv.set("category", category);
3854
+ if (keyword) qv.set("keyword", keyword);
3855
+ if (tag) qv.set("tag", tag);
3856
+ if (source) qv.set("source", source);
3857
+ const resp = await this.doPublicJSON(
3858
+ "GET",
3859
+ `/skill-store?${qv.toString()}`,
3860
+ null,
3861
+ signal
3862
+ );
3863
+ return resp.data;
4047
3864
  };
4048
- var SizeError = class extends Error {
4049
- blockType;
4050
- actual;
4051
- limit;
4052
- constructor(blockType, actual, limit) {
4053
- super(`sanitize: ${blockType} base64 size ${actual} exceeds limit ${limit}`);
4054
- this.name = "SizeError";
4055
- this.blockType = blockType;
4056
- this.actual = actual;
4057
- this.limit = limit;
4058
- }
3865
+ Client.prototype.browseSkillsList = async function(page, pageSize, category, keyword, tag, source, signal) {
3866
+ const qv = new URLSearchParams();
3867
+ qv.set("page", String(page));
3868
+ qv.set("pageSize", String(pageSize));
3869
+ qv.set("fields", "minimal");
3870
+ if (category) qv.set("category", category);
3871
+ if (keyword) qv.set("keyword", keyword);
3872
+ if (tag) qv.set("tag", tag);
3873
+ if (source) qv.set("source", source);
3874
+ const resp = await this.doPublicJSON(
3875
+ "GET",
3876
+ `/skill-store?${qv.toString()}`,
3877
+ null,
3878
+ signal
3879
+ );
3880
+ return resp.data;
4059
3881
  };
4060
- var ErrHistoryTooDeep = new HistoryTooDeepError();
4061
- var ErrBlockDenied = new BlockDeniedError();
4062
-
4063
- // src/sanitize/history.ts
4064
- function dropBlocks(messages, pred) {
4065
- const droppedToolUseIDs = collectDroppedToolUseIDs(messages, pred);
4066
- const out = [];
4067
- for (const msg of messages) {
4068
- if (!isPlainObject(msg)) {
4069
- out.push(msg);
4070
- continue;
4071
- }
4072
- const content = msg["content"];
4073
- if (!Array.isArray(content)) {
4074
- out.push(msg);
4075
- continue;
4076
- }
4077
- const { kept, changed } = filterBlocks(content, pred, droppedToolUseIDs);
4078
- if (!changed) {
4079
- out.push(msg);
4080
- continue;
4081
- }
4082
- if (kept.length === 0) {
4083
- continue;
4084
- }
4085
- const newMsg = { ...msg };
4086
- newMsg["content"] = kept;
4087
- out.push(newMsg);
4088
- }
4089
- return out;
4090
- }
4091
- function collectDroppedToolUseIDs(messages, pred) {
4092
- const ids = /* @__PURE__ */ new Set();
4093
- for (const msg of messages) {
4094
- if (!isPlainObject(msg)) continue;
4095
- const content = msg["content"];
4096
- if (!Array.isArray(content)) continue;
4097
- for (const raw of content) {
4098
- if (!isPlainObject(raw)) continue;
4099
- if (!pred(raw)) continue;
4100
- const t = raw["type"];
4101
- if (typeof t !== "string") continue;
4102
- if (t === "tool_use" || t === "server_tool_use" || t === "mcp_tool_use") {
4103
- const id = raw["id"];
4104
- if (typeof id === "string" && id !== "") ids.add(id);
4105
- }
3882
+ Client.prototype.getSkillDetail = async function(skillID, signal) {
3883
+ const resp = await this.doPublicJSON(
3884
+ "GET",
3885
+ `/skill-store/${encodeURIComponent(skillID)}`,
3886
+ null,
3887
+ signal
3888
+ );
3889
+ return resp.data;
3890
+ };
3891
+ Client.prototype.resolveSkill = async function(key, signal) {
3892
+ const resp = await this.doPublicJSON(
3893
+ "GET",
3894
+ `/skill-store/resolve/${encodeURIComponent(key)}`,
3895
+ null,
3896
+ signal
3897
+ );
3898
+ return resp.data;
3899
+ };
3900
+ Client.prototype.installSkill = async function(skillID, signal) {
3901
+ const resp = await this.doJSON(
3902
+ "POST",
3903
+ `/skill-store/${encodeURIComponent(skillID)}/install`,
3904
+ null,
3905
+ signal
3906
+ );
3907
+ return resp.data;
3908
+ };
3909
+ Client.prototype.downloadSkill = async function(skillID, signal) {
3910
+ const ctl = new AbortController();
3911
+ const timer = setTimeout(() => ctl.abort(), 5 * 60 * 1e3);
3912
+ let parentHandler;
3913
+ if (signal) {
3914
+ if (signal.aborted) ctl.abort();
3915
+ else {
3916
+ parentHandler = () => ctl.abort();
3917
+ signal.addEventListener("abort", parentHandler);
4106
3918
  }
4107
3919
  }
4108
- return ids;
4109
- }
4110
- function filterBlocks(content, pred, droppedToolUseIDs) {
4111
- const kept = [];
4112
- let changed = false;
4113
- for (const raw of content) {
4114
- if (!isPlainObject(raw)) {
4115
- kept.push(raw);
4116
- continue;
3920
+ try {
3921
+ const url = this.apiURL(`/skill-store/${encodeURIComponent(skillID)}/download`);
3922
+ const headers = {};
3923
+ let token = "";
3924
+ try {
3925
+ token = await this.ensureToken(ctl.signal);
3926
+ } catch {
4117
3927
  }
4118
- if (pred(raw)) {
4119
- changed = true;
4120
- continue;
3928
+ if (token) headers["Authorization"] = `Bearer ${token}`;
3929
+ let resp;
3930
+ try {
3931
+ resp = await this.fetchImpl(url, { method: "GET", headers, signal: ctl.signal });
3932
+ } catch (e) {
3933
+ throw classifyTransport(`GET /skill-store/${skillID}/download`, url, e);
4121
3934
  }
4122
- if (droppedToolUseIDs.size > 0) {
4123
- const t = raw["type"];
4124
- if (t === "tool_result" || t === "mcp_tool_result") {
4125
- const id = raw["tool_use_id"];
4126
- if (typeof id === "string" && id !== "" && droppedToolUseIDs.has(id)) {
4127
- changed = true;
4128
- continue;
3935
+ if (resp.status === 429) {
3936
+ const bodyText = await readLimitedText(resp.body, maxErrorBodySize);
3937
+ throw new RateLimitError("\u533F\u540D\u4E0B\u8F7D\u5DF2\u8FBE\u9650\u5236", resp.headers.get("Retry-After") ?? "", bodyText);
3938
+ }
3939
+ if (!resp.ok) {
3940
+ const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
3941
+ throw new Error(
3942
+ `download skill: ${parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers).message}`
3943
+ );
3944
+ }
3945
+ const data = await readLimited(resp.body, maxDownloadSize + 1);
3946
+ if (data.byteLength > maxDownloadSize) {
3947
+ throw new Error(`download skill: response exceeds ${maxDownloadSize >> 20}MB limit`);
3948
+ }
3949
+ let filename = "skill.zip";
3950
+ const cd = resp.headers.get("Content-Disposition");
3951
+ if (cd) {
3952
+ const idx = cd.indexOf("filename");
3953
+ if (idx !== -1) {
3954
+ const parts = cd.slice(idx).split("=", 2);
3955
+ if (parts.length === 2) {
3956
+ filename = parts[1].trim().replace(/^["' ]+|["' ]+$/g, "");
4129
3957
  }
4130
3958
  }
4131
3959
  }
4132
- kept.push(raw);
3960
+ return { data, filename };
3961
+ } finally {
3962
+ clearTimeout(timer);
3963
+ if (parentHandler && signal) signal.removeEventListener("abort", parentHandler);
4133
3964
  }
4134
- return { kept, changed };
4135
- }
4136
- function stripEphemeral(messages) {
4137
- return dropBlocks(messages, (b) => {
4138
- const t = b["type"];
4139
- if (t === "thinking" || t === "redacted_thinking") {
4140
- return false;
3965
+ };
3966
+ Client.prototype.uploadSkill = async function(zipData, scope, intent, signal) {
3967
+ return uploadSkillInternal(this, zipData, scope, intent, false, signal);
3968
+ };
3969
+ async function uploadSkillInternal(c, zipData, scope, intent, retried, signal) {
3970
+ const ctl = new AbortController();
3971
+ const timer = setTimeout(() => ctl.abort(), 5 * 60 * 1e3);
3972
+ let parentHandler;
3973
+ if (signal) {
3974
+ if (signal.aborted) ctl.abort();
3975
+ else {
3976
+ parentHandler = () => ctl.abort();
3977
+ signal.addEventListener("abort", parentHandler);
4141
3978
  }
4142
- const v = b[EphemeralMarkerField];
4143
- return v === true;
4144
- });
4145
- }
4146
- function isPlainObject(v) {
4147
- return typeof v === "object" && v !== null && !Array.isArray(v);
4148
- }
4149
-
4150
- // src/sanitize/defensive.ts
4151
- function sanitize(messages, cfg) {
4152
- if ((cfg.maxMessagesTurns ?? 0) > 0 && messages.length > cfg.maxMessagesTurns) {
4153
- throw ErrHistoryTooDeep;
4154
- }
4155
- if ((cfg.maxImageBytes ?? 0) > 0 || (cfg.maxVideoBytes ?? 0) > 0 || (cfg.maxPDFBytes ?? 0) > 0) {
4156
- checkMediaSizes(messages, cfg);
4157
- }
4158
- if (cfg.permanentDenyBlocks && cfg.permanentDenyBlocks.length > 0) {
4159
- const denySet = /* @__PURE__ */ new Set();
4160
- for (const bt of cfg.permanentDenyBlocks) denySet.add(bt);
4161
- messages = dropBlocks(messages, (b) => {
4162
- const t = b["type"];
4163
- return typeof t === "string" && denySet.has(t);
4164
- });
4165
3979
  }
4166
- return messages;
4167
- }
4168
- function checkMediaSizes(messages, cfg) {
4169
- for (const msg of messages) {
4170
- if (!isPlainObject2(msg)) continue;
4171
- const content = msg["content"];
4172
- if (!Array.isArray(content)) continue;
4173
- for (const raw of content) {
4174
- if (!isPlainObject2(raw)) continue;
4175
- const bt = raw["type"];
4176
- if (typeof bt !== "string") continue;
4177
- let limit = 0;
4178
- switch (bt) {
4179
- case "image":
4180
- limit = cfg.maxImageBytes ?? 0;
4181
- break;
4182
- case "video":
4183
- limit = cfg.maxVideoBytes ?? 0;
4184
- break;
4185
- case "document":
4186
- limit = cfg.maxPDFBytes ?? 0;
4187
- break;
4188
- default:
4189
- continue;
3980
+ try {
3981
+ const token = await c.ensureToken(ctl.signal);
3982
+ const form = new FormData();
3983
+ form.append("scope", scope);
3984
+ form.append("intent", intent);
3985
+ const blob = new Blob([zipData], { type: "application/zip" });
3986
+ form.append("file", blob, "skill.zip");
3987
+ const url = c.apiURL("/skill-store/upload");
3988
+ let resp;
3989
+ try {
3990
+ resp = await c.fetchImpl(url, {
3991
+ method: "POST",
3992
+ headers: { Authorization: `Bearer ${token}` },
3993
+ body: form,
3994
+ signal: ctl.signal
3995
+ });
3996
+ } catch (e) {
3997
+ throw classifyTransport("POST /skill-store/upload", url, e);
3998
+ }
3999
+ if (resp.status === 401 && !retried) {
4000
+ try {
4001
+ await resp.body?.cancel();
4002
+ } catch {
4190
4003
  }
4191
- if (limit <= 0) continue;
4192
- const data = extractBase64Data(raw);
4193
- if (data === "") continue;
4194
- const actual = base64DecodedLen(data);
4195
- if (actual > limit) {
4196
- throw new SizeError(bt, actual, limit);
4004
+ try {
4005
+ await c.forceRefresh(ctl.signal);
4006
+ } catch (refreshErr) {
4007
+ throw new Error(
4008
+ `upload: unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
4009
+ );
4197
4010
  }
4011
+ return uploadSkillInternal(c, zipData, scope, intent, true, signal);
4198
4012
  }
4013
+ if (resp.status < 200 || resp.status >= 300) {
4014
+ const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
4015
+ throw new Error(
4016
+ `upload: ${parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers).message}`
4017
+ );
4018
+ }
4019
+ const text = await resp.text();
4020
+ const result = JSON.parse(text);
4021
+ return result.data.skill;
4022
+ } finally {
4023
+ clearTimeout(timer);
4024
+ if (parentHandler && signal) signal.removeEventListener("abort", parentHandler);
4199
4025
  }
4200
4026
  }
4201
- function extractBase64Data(block) {
4202
- const src = block["source"];
4203
- if (!isPlainObject2(src)) return "";
4204
- if (src["type"] !== "base64") return "";
4205
- const dataRaw = src["data"];
4206
- if (typeof dataRaw !== "string") return "";
4207
- let data = dataRaw;
4208
- const i = data.indexOf("base64,");
4209
- if (i >= 0) {
4210
- data = data.slice(i + "base64,".length);
4211
- }
4212
- return data;
4213
- }
4214
- function base64DecodedLen(b64) {
4215
- const n = b64.length;
4216
- let pad = 0;
4217
- if (n >= 1 && b64[n - 1] === "=") pad++;
4218
- if (n >= 2 && b64[n - 2] === "=") pad++;
4219
- return Math.floor(n * 3 / 4) - pad;
4220
- }
4221
- function isPlainObject2(v) {
4222
- return typeof v === "object" && v !== null && !Array.isArray(v);
4223
- }
4224
-
4225
- // src/agent-runs-types.ts
4226
- var AgentRunStreamError = class extends Error {
4227
- event;
4228
- code;
4229
- stage;
4230
- retryable;
4231
- constructor(event) {
4232
- const err = event.error;
4233
- super(err.stage ? `agent run failed: ${err.stage}: ${err.message}` : `agent run failed: ${err.message}`);
4234
- this.name = "AgentRunStreamError";
4235
- this.event = event;
4236
- this.code = err.code ?? "";
4237
- this.stage = err.stage ?? "";
4238
- this.retryable = err.retryable ?? false;
4239
- }
4027
+ Client.prototype.getSkillSummary = async function(signal) {
4028
+ const resp = await this.doJSON("GET", "/skills/summary", null, signal);
4029
+ return resp.data;
4030
+ };
4031
+ Client.prototype.certifySkill = async function(skillID, signal) {
4032
+ await this.doJSON(
4033
+ "POST",
4034
+ `/skill-store/${encodeURIComponent(skillID)}/certify`,
4035
+ null,
4036
+ signal
4037
+ );
4038
+ };
4039
+ Client.prototype.getCertificationStatus = async function(skillID, signal) {
4040
+ const resp = await this.doJSON(
4041
+ "GET",
4042
+ `/skill-store/${encodeURIComponent(skillID)}/certification`,
4043
+ null,
4044
+ signal
4045
+ );
4046
+ return resp.data;
4047
+ };
4048
+ Client.prototype.generateSkill = async function(req, signal) {
4049
+ const resp = await this.doJSON(
4050
+ "POST",
4051
+ "/skill-generator/generate",
4052
+ req,
4053
+ signal
4054
+ );
4055
+ return resp.data;
4056
+ };
4057
+ Client.prototype.optimizeSkill = async function(req, signal) {
4058
+ const resp = await this.doJSON(
4059
+ "POST",
4060
+ "/skill-generator/optimize",
4061
+ req,
4062
+ signal
4063
+ );
4064
+ return resp.data;
4065
+ };
4066
+ Client.prototype.validateSkill = async function(skillName, signal) {
4067
+ await this.doJSON(
4068
+ "POST",
4069
+ "/skill-generator/validate",
4070
+ { skillName },
4071
+ signal
4072
+ );
4240
4073
  };
4241
4074
 
4242
- // src/client/agent-runs.ts
4243
- init_types();
4244
- var agentRunsByClient = /* @__PURE__ */ new WeakMap();
4245
- Object.defineProperty(Client.prototype, "agentRuns", {
4246
- configurable: true,
4247
- enumerable: false,
4248
- get() {
4249
- let existing = agentRunsByClient.get(this);
4250
- if (!existing) {
4251
- existing = new AgentRunsClient(this);
4252
- agentRunsByClient.set(this, existing);
4075
+ // src/skills/tools.ts
4076
+ Client.prototype.listTools = async function(signal) {
4077
+ const resp = await this.doJSON("GET", "/tools", null, signal);
4078
+ return resp.data.skills;
4079
+ };
4080
+ Client.prototype.getTool = async function(toolID, signal) {
4081
+ const resp = await this.doJSON(
4082
+ "GET",
4083
+ `/tools/${encodeURIComponent(toolID)}`,
4084
+ null,
4085
+ signal
4086
+ );
4087
+ return resp.data;
4088
+ };
4089
+
4090
+ // src/notifications/types.ts
4091
+ function parseNotificationEvent(ev) {
4092
+ if (ev.type !== "event" || ev.topic !== "system") {
4093
+ return null;
4094
+ }
4095
+ if (ev.data == null) return null;
4096
+ let n;
4097
+ try {
4098
+ if (typeof ev.data === "string") {
4099
+ n = JSON.parse(ev.data);
4100
+ } else {
4101
+ n = ev.data;
4253
4102
  }
4254
- return existing;
4103
+ } catch {
4104
+ return null;
4255
4105
  }
4256
- });
4257
- var AgentRunsClient = class {
4258
- constructor(client) {
4259
- this.client = client;
4106
+ if (!n.id) return null;
4107
+ return n;
4108
+ }
4109
+
4110
+ // src/notifications/notifications.ts
4111
+ Client.prototype.listNotifications = async function(page, pageSize, typeFilter, signal) {
4112
+ let path = `/notifications?page=${page}&pageSize=${pageSize}`;
4113
+ if (typeFilter) path += `&type=${encodeURIComponent(typeFilter)}`;
4114
+ const resp = await this.doJSON("GET", path, null, signal);
4115
+ return resp.data;
4116
+ };
4117
+ Client.prototype.getUnreadCount = async function(signal) {
4118
+ const resp = await this.doJSON(
4119
+ "GET",
4120
+ "/notifications/unread-count",
4121
+ null,
4122
+ signal
4123
+ );
4124
+ return resp.data.unreadCount;
4125
+ };
4126
+ Client.prototype.markNotificationRead = async function(id, signal) {
4127
+ await this.doJSON(
4128
+ "PUT",
4129
+ `/notifications/${encodeURIComponent(id)}/read`,
4130
+ null,
4131
+ signal
4132
+ );
4133
+ };
4134
+ Client.prototype.markAllNotificationsRead = async function(signal) {
4135
+ await this.doJSON("PUT", "/notifications/read-all", null, signal);
4136
+ };
4137
+ Client.prototype.deleteNotification = async function(id, signal) {
4138
+ await this.doJSON(
4139
+ "DELETE",
4140
+ `/notifications/${encodeURIComponent(id)}`,
4141
+ null,
4142
+ signal
4143
+ );
4144
+ };
4145
+ Client.prototype.registerDevice = async function(reg, signal) {
4146
+ await this.doJSON("POST", "/devices/register", reg, signal);
4147
+ };
4148
+ Client.prototype.unregisterDevice = async function(token, signal) {
4149
+ await this.doJSON(
4150
+ "DELETE",
4151
+ `/devices/${encodeURIComponent(token)}`,
4152
+ null,
4153
+ signal
4154
+ );
4155
+ };
4156
+ Client.prototype.listNotificationPreferences = async function(signal) {
4157
+ const resp = await this.doJSON(
4158
+ "GET",
4159
+ "/notification-preferences",
4160
+ null,
4161
+ signal
4162
+ );
4163
+ return resp.data;
4164
+ };
4165
+ Client.prototype.updateNotificationPreference = async function(typeCode, pref, signal) {
4166
+ await this.doJSON(
4167
+ "PUT",
4168
+ `/notification-preferences/${encodeURIComponent(typeCode)}`,
4169
+ pref,
4170
+ signal
4171
+ );
4172
+ };
4173
+
4174
+ // src/notifications/ws.ts
4175
+ Client.prototype.connect = async function(cfg, signal) {
4176
+ const noop = () => {
4177
+ };
4178
+ const filledCfg = {
4179
+ onEvent: cfg.onEvent ?? noop,
4180
+ onConnect: cfg.onConnect ?? noop,
4181
+ onDisconnect: cfg.onDisconnect ?? noop,
4182
+ topics: cfg.topics ?? [],
4183
+ reconnectMinMs: cfg.reconnectMinMs ?? 2e3,
4184
+ reconnectMaxMs: cfg.reconnectMaxMs ?? 6e4,
4185
+ autoReconnect: cfg.autoReconnect ?? true
4186
+ };
4187
+ let resolveDone;
4188
+ const done = new Promise((r) => {
4189
+ resolveDone = r;
4190
+ });
4191
+ const abort = new AbortController();
4192
+ if (signal) {
4193
+ if (signal.aborted) abort.abort();
4194
+ else signal.addEventListener("abort", () => abort.abort());
4260
4195
  }
4261
- client;
4262
- async create(req, signal) {
4263
- const resp = await this.requestAPI(
4264
- "POST",
4265
- "/agent-runs",
4266
- toWireCreateRequest(req),
4267
- signal,
4268
- { retryOn401: false }
4269
- );
4270
- return fromWireCreateResponse(resp);
4196
+ const ws = {
4197
+ conn: null,
4198
+ cfg: filledCfg,
4199
+ abort,
4200
+ done,
4201
+ doneResolve: resolveDone,
4202
+ connected: false
4203
+ };
4204
+ await wsConnectOnce(this, ws);
4205
+ this.ws = ws;
4206
+ void wsLoop(this, ws);
4207
+ };
4208
+ Client.prototype.disconnect = async function() {
4209
+ const ws = this.ws;
4210
+ this.ws = null;
4211
+ if (!ws) return;
4212
+ ws.abort.abort();
4213
+ ws.connected = false;
4214
+ if (ws.conn) {
4215
+ try {
4216
+ ws.conn.close(1e3, "");
4217
+ } catch {
4218
+ }
4271
4219
  }
4272
- get(runId, signal) {
4273
- return this.requestAPI(
4274
- "GET",
4275
- `/agent-runs/${encodeURIComponent(runId)}`,
4276
- null,
4277
- signal,
4278
- { retryOn401: true }
4279
- ).then(fromWireRun);
4220
+ await Promise.race([
4221
+ ws.done,
4222
+ new Promise((resolve) => setTimeout(resolve, 5e3))
4223
+ ]);
4224
+ };
4225
+ Client.prototype.isConnected = function() {
4226
+ const ws = this.ws;
4227
+ if (!ws) return false;
4228
+ return ws.connected;
4229
+ };
4230
+ function wsURL(c) {
4231
+ const base = c.apiURL("/ws");
4232
+ return base.replace(/^http:\/\//, "ws://").replace(/^https:\/\//, "wss://");
4233
+ }
4234
+ function getWebSocketCtor() {
4235
+ const WSCtor = globalThis.WebSocket;
4236
+ if (!WSCtor) {
4237
+ throw new Error(
4238
+ 'WebSocket not available \u2014 on Node \u226421 set globalThis.WebSocket = require("ws") before connect'
4239
+ );
4280
4240
  }
4281
- stream(runId, opts = {}, signal) {
4282
- return {
4283
- [Symbol.asyncIterator]: () => this.streamGen(runId, opts, signal)
4284
- };
4241
+ return WSCtor;
4242
+ }
4243
+ async function wsConnectOnce(c, ws) {
4244
+ const token = await c.ensureToken(ws.abort.signal);
4245
+ const url = wsURL(c);
4246
+ const WSCtor = getWebSocketCtor();
4247
+ const u = new URL(url);
4248
+ u.searchParams.set("token", token);
4249
+ let conn;
4250
+ try {
4251
+ conn = new WSCtor(u.toString());
4252
+ } catch (e) {
4253
+ throw new Error(`dial: ${e instanceof Error ? e.message : String(e)}`);
4285
4254
  }
4286
- cancel(runId, signal) {
4287
- return this.requestAPI(
4288
- "POST",
4289
- `/agent-runs/${encodeURIComponent(runId)}/cancel`,
4290
- {},
4291
- signal,
4255
+ await new Promise((resolve, reject) => {
4256
+ let opened = false;
4257
+ const handshakeTimer = setTimeout(() => {
4258
+ if (!opened) {
4259
+ try {
4260
+ conn.close();
4261
+ } catch {
4262
+ }
4263
+ reject(new Error("dial: handshake timeout"));
4264
+ }
4265
+ }, 3e4);
4266
+ conn.addEventListener("open", () => {
4267
+ opened = true;
4268
+ });
4269
+ conn.addEventListener("error", (e) => {
4270
+ clearTimeout(handshakeTimer);
4271
+ reject(new Error(`dial: ${e.message ?? "connection error"}`));
4272
+ });
4273
+ conn.addEventListener("message", (e) => {
4274
+ try {
4275
+ const msg = e.data;
4276
+ const welcome = JSON.parse(msg);
4277
+ if (welcome.type !== "welcome") {
4278
+ clearTimeout(handshakeTimer);
4279
+ try {
4280
+ conn.close();
4281
+ } catch {
4282
+ }
4283
+ reject(new Error(`unexpected first message: ${welcome.type}`));
4284
+ return;
4285
+ }
4286
+ clearTimeout(handshakeTimer);
4287
+ ws.conn = conn;
4288
+ ws.connected = true;
4289
+ if (ws.cfg.topics.length > 0) {
4290
+ try {
4291
+ conn.send(
4292
+ JSON.stringify({
4293
+ type: "subscribe",
4294
+ topics: ws.cfg.topics
4295
+ })
4296
+ );
4297
+ } catch (sendErr) {
4298
+ ws.conn = null;
4299
+ ws.connected = false;
4300
+ try {
4301
+ conn.close();
4302
+ } catch {
4303
+ }
4304
+ reject(new Error(`send subscribe: ${sendErr instanceof Error ? sendErr.message : String(sendErr)}`));
4305
+ return;
4306
+ }
4307
+ }
4308
+ ws.cfg.onConnect();
4309
+ console.log(`[acosmi-sdk] websocket connected, connId=${welcome.connId ?? ""}`);
4310
+ resolve();
4311
+ } catch (parseErr) {
4312
+ clearTimeout(handshakeTimer);
4313
+ try {
4314
+ conn.close();
4315
+ } catch {
4316
+ }
4317
+ reject(new Error(`parse welcome: ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`));
4318
+ }
4319
+ }, { once: true });
4320
+ });
4321
+ }
4322
+ async function wsLoop(c, ws) {
4323
+ try {
4324
+ while (true) {
4325
+ await wsReadLoop(ws);
4326
+ if (ws.abort.signal.aborted) return;
4327
+ if (ws.conn) {
4328
+ try {
4329
+ ws.conn.close();
4330
+ } catch {
4331
+ }
4332
+ ws.conn = null;
4333
+ }
4334
+ ws.connected = false;
4335
+ if (!ws.cfg.autoReconnect) return;
4336
+ let delay = ws.cfg.reconnectMinMs;
4337
+ while (true) {
4338
+ if (ws.abort.signal.aborted) return;
4339
+ await sleepWithSignal2(delay, ws.abort.signal).catch(() => {
4340
+ });
4341
+ if (ws.abort.signal.aborted) return;
4342
+ console.log(`[acosmi-sdk] websocket reconnecting (delay=${delay}ms)...`);
4343
+ try {
4344
+ await wsConnectOnce(c, ws);
4345
+ break;
4346
+ } catch (err) {
4347
+ console.log(`[acosmi-sdk] websocket reconnect failed: ${err instanceof Error ? err.message : String(err)}`);
4348
+ delay = Math.min(delay * 2, ws.cfg.reconnectMaxMs);
4349
+ }
4350
+ }
4351
+ }
4352
+ } finally {
4353
+ ws.doneResolve();
4354
+ }
4355
+ }
4356
+ async function wsReadLoop(ws) {
4357
+ const conn = ws.conn;
4358
+ if (!conn) return;
4359
+ return new Promise((resolve) => {
4360
+ const handleMessage = (e) => {
4361
+ try {
4362
+ const data = e.data;
4363
+ const event = JSON.parse(data);
4364
+ try {
4365
+ ws.cfg.onEvent(event);
4366
+ } catch {
4367
+ }
4368
+ } catch {
4369
+ }
4370
+ };
4371
+ const handleClose = (e) => {
4372
+ conn.removeEventListener("message", handleMessage);
4373
+ conn.removeEventListener("close", handleClose);
4374
+ conn.removeEventListener("error", handleError);
4375
+ try {
4376
+ ws.cfg.onDisconnect(new Error(`closed: code=${e.code} reason=${e.reason}`));
4377
+ } catch {
4378
+ }
4379
+ resolve();
4380
+ };
4381
+ const handleError = (e) => {
4382
+ conn.removeEventListener("message", handleMessage);
4383
+ conn.removeEventListener("close", handleClose);
4384
+ conn.removeEventListener("error", handleError);
4385
+ try {
4386
+ ws.cfg.onDisconnect(e);
4387
+ } catch {
4388
+ }
4389
+ resolve();
4390
+ };
4391
+ conn.addEventListener("message", handleMessage);
4392
+ conn.addEventListener("close", handleClose);
4393
+ conn.addEventListener("error", handleError);
4394
+ if (ws.abort.signal.aborted) {
4395
+ try {
4396
+ conn.close();
4397
+ } catch {
4398
+ }
4399
+ } else {
4400
+ ws.abort.signal.addEventListener(
4401
+ "abort",
4402
+ () => {
4403
+ try {
4404
+ conn.close();
4405
+ } catch {
4406
+ }
4407
+ },
4408
+ { once: true }
4409
+ );
4410
+ }
4411
+ });
4412
+ }
4413
+ async function sleepWithSignal2(ms, signal) {
4414
+ if (ms <= 0) return;
4415
+ if (signal.aborted) throw new Error("aborted");
4416
+ return new Promise((resolve, reject) => {
4417
+ const t = setTimeout(() => {
4418
+ signal.removeEventListener("abort", abortHandler);
4419
+ resolve();
4420
+ }, ms);
4421
+ const abortHandler = () => {
4422
+ clearTimeout(t);
4423
+ signal.removeEventListener("abort", abortHandler);
4424
+ reject(new Error("aborted"));
4425
+ };
4426
+ signal.addEventListener("abort", abortHandler);
4427
+ });
4428
+ }
4429
+
4430
+ // src/agent-runs/types.ts
4431
+ var AgentRunStreamError = class extends Error {
4432
+ event;
4433
+ code;
4434
+ stage;
4435
+ retryable;
4436
+ constructor(event) {
4437
+ const err = event.error;
4438
+ super(err.stage ? `agent run failed: ${err.stage}: ${err.message}` : `agent run failed: ${err.message}`);
4439
+ this.name = "AgentRunStreamError";
4440
+ this.event = event;
4441
+ this.code = err.code ?? "";
4442
+ this.stage = err.stage ?? "";
4443
+ this.retryable = err.retryable ?? false;
4444
+ }
4445
+ };
4446
+
4447
+ // src/agent-runs/client.ts
4448
+ var agentRunsByClient = /* @__PURE__ */ new WeakMap();
4449
+ Object.defineProperty(Client.prototype, "agentRuns", {
4450
+ configurable: true,
4451
+ enumerable: false,
4452
+ get() {
4453
+ let existing = agentRunsByClient.get(this);
4454
+ if (!existing) {
4455
+ existing = new AgentRunsClient(this);
4456
+ agentRunsByClient.set(this, existing);
4457
+ }
4458
+ return existing;
4459
+ }
4460
+ });
4461
+ var AgentRunsClient = class {
4462
+ constructor(client) {
4463
+ this.client = client;
4464
+ }
4465
+ client;
4466
+ async create(req, signal) {
4467
+ const resp = await this.requestAPI(
4468
+ "POST",
4469
+ "/agent-runs",
4470
+ toWireCreateRequest(req),
4471
+ signal,
4472
+ { retryOn401: false }
4473
+ );
4474
+ return fromWireCreateResponse(resp);
4475
+ }
4476
+ get(runId, signal) {
4477
+ return this.requestAPI(
4478
+ "GET",
4479
+ `/agent-runs/${encodeURIComponent(runId)}`,
4480
+ null,
4481
+ signal,
4482
+ { retryOn401: true }
4483
+ ).then(fromWireRun);
4484
+ }
4485
+ stream(runId, opts = {}, signal) {
4486
+ return {
4487
+ [Symbol.asyncIterator]: () => this.streamGen(runId, opts, signal)
4488
+ };
4489
+ }
4490
+ cancel(runId, signal) {
4491
+ return this.requestAPI(
4492
+ "POST",
4493
+ `/agent-runs/${encodeURIComponent(runId)}/cancel`,
4494
+ {},
4495
+ signal,
4292
4496
  { retryOn401: false }
4293
4497
  ).then(fromWireRun);
4294
4498
  }
@@ -4718,801 +4922,1138 @@ function errorMessage(e) {
4718
4922
  return e instanceof Error ? e.message : String(e);
4719
4923
  }
4720
4924
 
4721
- // src/index.ts
4722
- init_betas();
4723
-
4724
- // src/client/entitlements.ts
4725
- Client.prototype.getBalance = async function(signal) {
4726
- const resp = await this.doJSON(
4727
- "GET",
4728
- "/entitlements/balance",
4729
- null,
4730
- signal
4731
- );
4732
- return resp.data;
4733
- };
4734
- Client.prototype.getBalanceDetail = async function(signal) {
4735
- const resp = await this.doJSON(
4736
- "GET",
4737
- "/entitlements/balance-detail",
4738
- null,
4739
- signal
4740
- );
4741
- return resp.data;
4742
- };
4743
- Client.prototype.listEntitlements = async function(status, signal) {
4744
- let path = "/entitlements";
4745
- if (status !== "") {
4746
- path += `?status=${encodeURIComponent(status)}`;
4747
- }
4748
- const resp = await this.doJSON("GET", path, null, signal);
4749
- return resp.data;
4750
- };
4751
- Client.prototype.listConsumeRecords = async function(page, pageSize, signal) {
4752
- const path = `/entitlements/consume-records?page=${page}&pageSize=${pageSize}`;
4753
- const resp = await this.doJSON("GET", path, null, signal);
4754
- return resp.data;
4755
- };
4756
- Client.prototype.claimMonthlyFree = async function(signal) {
4757
- const resp = await this.doJSON(
4758
- "POST",
4759
- "/entitlements/claim-monthly",
4760
- null,
4761
- signal
4762
- );
4763
- return resp.data;
4764
- };
4765
- Client.prototype.getByModel = async function(modelID, signal) {
4766
- if (modelID === "") throw new Error("modelID required");
4767
- const path = `/entitlements/by-model?modelId=${encodeURIComponent(modelID)}`;
4768
- const resp = await this.doJSON("GET", path, null, signal);
4769
- return resp.data;
4770
- };
4771
- Client.prototype.listBuckets = async function(signal) {
4772
- const resp = await this.doJSON(
4773
- "GET",
4774
- "/entitlements/buckets",
4775
- null,
4776
- signal
4777
- );
4778
- return resp.data;
4779
- };
4780
- Client.prototype.listCoefficients = async function(signal) {
4781
- if (this.coefCacheData && Date.now() - this.coefCacheTimeMs < coefCacheTTLMs) {
4782
- return [...this.coefCacheData];
4783
- }
4784
- const resp = await this.doJSON(
4785
- "GET",
4786
- "/entitlements/coefficients",
4787
- null,
4788
- signal
4789
- );
4790
- this.coefCacheData = [...resp.data];
4791
- this.coefCacheTimeMs = Date.now();
4792
- return resp.data;
4793
- };
4794
- Client.prototype.invalidateCoefficientCache = function() {
4795
- this.coefCacheData = null;
4796
- this.coefCacheTimeMs = 0;
4797
- };
4925
+ // src/compliance/scopes.ts
4926
+ var ScopeComplianceEvidenceRead = "compliance:evidence:read";
4927
+ var ScopeComplianceEvidenceWrite = "compliance:evidence:write";
4928
+ var ScopeComplianceTimestampIssue = "compliance:timestamp:issue";
4929
+ var ScopeComplianceTimestampVerify = "compliance:timestamp:verify";
4930
+ var ScopeComplianceContractSigningRead = "compliance:contract_signing:read";
4931
+ var ScopeComplianceContractSigningWrite = "compliance:contract_signing:write";
4932
+ var ScopeComplianceSealManage = "compliance:seal:manage";
4933
+ var ScopeComplianceSealApprovalRequest = "compliance:seal_approval:request";
4934
+ var ScopeComplianceSealApprovalApprove = "compliance:seal_approval:approve";
4935
+ var ScopeComplianceSealUseExecute = "compliance:seal_use:execute";
4936
+ var ScopeComplianceReportsRead = "compliance:reports:read";
4937
+ var ScopeComplianceReportsWrite = "compliance:reports:write";
4938
+ var ScopeComplianceReportsPublish = "compliance:reports:publish";
4939
+ var ScopeComplianceContractTemplateRead = "compliance:contract_template:read";
4940
+ var ScopeComplianceContractTemplateWrite = "compliance:contract_template:write";
4941
+ function complianceScopes() {
4942
+ return [
4943
+ ScopeComplianceEvidenceRead,
4944
+ ScopeComplianceEvidenceWrite,
4945
+ ScopeComplianceTimestampIssue,
4946
+ ScopeComplianceTimestampVerify,
4947
+ ScopeComplianceContractSigningRead,
4948
+ ScopeComplianceContractSigningWrite,
4949
+ ScopeComplianceSealManage,
4950
+ ScopeComplianceSealApprovalRequest,
4951
+ ScopeComplianceSealApprovalApprove,
4952
+ ScopeComplianceSealUseExecute,
4953
+ ScopeComplianceReportsRead,
4954
+ ScopeComplianceReportsWrite,
4955
+ ScopeComplianceReportsPublish,
4956
+ ScopeComplianceContractTemplateRead,
4957
+ ScopeComplianceContractTemplateWrite
4958
+ ];
4959
+ }
4798
4960
 
4799
- // src/client/packages.ts
4800
- init_types();
4801
- Client.prototype.listTokenPackages = async function(signal) {
4802
- const raw = await this.doJSON("GET", "/token-packages", null, signal);
4803
- if (raw.data && typeof raw.data === "object" && "list" in raw.data) {
4804
- const page = raw.data;
4805
- if (Array.isArray(page.list)) return page.list;
4806
- }
4807
- if (Array.isArray(raw.data)) return raw.data;
4808
- throw new Error("decode token packages: unexpected shape");
4809
- };
4810
- Client.prototype.getTokenPackageDetail = async function(packageID, signal) {
4811
- const resp = await this.doJSON(
4812
- "GET",
4813
- `/token-packages/${encodeURIComponent(packageID)}`,
4814
- null,
4815
- signal
4816
- );
4817
- return resp.data;
4818
- };
4819
- Client.prototype.buyTokenPackage = async function(packageID, payload, signal) {
4820
- const body = payload ?? null;
4821
- const resp = await this.doJSON(
4822
- "POST",
4823
- `/token-packages/${encodeURIComponent(packageID)}/buy`,
4824
- body,
4825
- signal
4826
- );
4827
- return resp.data;
4828
- };
4829
- Client.prototype.getOrderStatus = async function(orderID, signal) {
4830
- const resp = await this.doJSON(
4831
- "GET",
4832
- `/token-packages/orders/${encodeURIComponent(orderID)}/status`,
4833
- null,
4834
- signal
4835
- );
4836
- return resp.data;
4837
- };
4838
- Client.prototype.listMyOrders = async function(signal) {
4839
- const raw = await this.doJSON("GET", "/token-packages/my", null, signal);
4840
- if (raw.data && typeof raw.data === "object" && "list" in raw.data) {
4841
- const page = raw.data;
4842
- if (Array.isArray(page.list)) return page.list;
4843
- }
4844
- if (Array.isArray(raw.data)) return raw.data;
4845
- throw new Error("decode orders: unexpected shape");
4846
- };
4847
- Client.prototype.waitForPayment = async function(orderID, pollIntervalMs, signal) {
4848
- if (pollIntervalMs <= 0) pollIntervalMs = 2e3;
4849
- while (true) {
4850
- const status = await this.getOrderStatus(orderID, signal);
4851
- if (isOrderTerminal(status.status)) {
4852
- if (isOrderSuccess(status.status)) return status;
4853
- throw new OrderTerminalError(orderID, status.status);
4854
- }
4855
- await sleepWithSignal(pollIntervalMs, signal);
4961
+ // src/compliance/status.ts
4962
+ var ErrComplianceStepUpRequired = "COMPLIANCE_STEP_UP_REQUIRED";
4963
+ var ErrEnvelopeGateClosed = "ENVELOPE_GATE_CLOSED";
4964
+ var ErrProviderNotConfigured = "PROVIDER_NOT_CONFIGURED";
4965
+ var ErrProviderUnknownNoRetry = "PROVIDER_REQUEST_UNKNOWN_NO_RETRY";
4966
+ var ErrBillingCallbackCannotCommit = "BILLING_CALLBACK_CANNOT_COMMIT";
4967
+ var ErrBillingCommitRequiresLocalVerify = "BILLING_COMMIT_REQUIRES_LOCAL_VERIFY";
4968
+ var ErrBillingS2sForbidden = "BILLING_S2S_FORBIDDEN";
4969
+ var ErrSealApprovalNotApproved = "SEAL_APPROVAL_STATE_NOT_APPROVED";
4970
+ var ErrSealApprovalExpired = "SEAL_APPROVAL_EXPIRED";
4971
+ var ErrSealApprovalNonceUsed = "SEAL_APPROVAL_NONCE_USED";
4972
+ var ErrSealApprovalContractHashMismatch = "SEAL_APPROVAL_CONTRACT_HASH_MISMATCH";
4973
+ var ErrSealApprovalSealMismatch = "SEAL_APPROVAL_SEAL_MISMATCH";
4974
+ var ErrSealApprovalLocationMismatch = "SEAL_APPROVAL_LOCATION_MISMATCH";
4975
+ var ErrSealApprovalTransactorMismatch = "SEAL_APPROVAL_TRANSACTOR_MISMATCH";
4976
+ var ErrSealUseAlreadyConsumed = "SEAL_USE_ALREADY_CONSUMED";
4977
+ function isComplianceTerminalError(code) {
4978
+ switch (code) {
4979
+ case ErrEnvelopeGateClosed:
4980
+ case ErrProviderNotConfigured:
4981
+ case ErrProviderUnknownNoRetry:
4982
+ case ErrBillingCallbackCannotCommit:
4983
+ case ErrBillingCommitRequiresLocalVerify:
4984
+ case ErrBillingS2sForbidden:
4985
+ case ErrSealApprovalNonceUsed:
4986
+ case ErrSealApprovalExpired:
4987
+ case ErrSealApprovalContractHashMismatch:
4988
+ case ErrSealApprovalSealMismatch:
4989
+ case ErrSealApprovalLocationMismatch:
4990
+ case ErrSealApprovalTransactorMismatch:
4991
+ case ErrSealUseAlreadyConsumed:
4992
+ return true;
4993
+ default:
4994
+ return false;
4856
4995
  }
4857
- };
4858
- async function sleepWithSignal(ms, signal) {
4859
- if (ms <= 0) return;
4860
- if (signal && signal.aborted) throw new Error("aborted");
4861
- return new Promise((resolve, reject) => {
4862
- const t = setTimeout(() => {
4863
- if (signal && abortHandler) signal.removeEventListener("abort", abortHandler);
4864
- resolve();
4865
- }, ms);
4866
- let abortHandler;
4867
- if (signal) {
4868
- abortHandler = () => {
4869
- clearTimeout(t);
4870
- signal.removeEventListener("abort", abortHandler);
4871
- reject(new Error("aborted"));
4872
- };
4873
- signal.addEventListener("abort", abortHandler);
4874
- }
4875
- });
4996
+ }
4997
+ function isBillingConfirmable(providerStatus, billingStatus) {
4998
+ return providerStatus === "success" && billingStatus === "committed";
4876
4999
  }
4877
5000
 
4878
- // src/client/wallet.ts
4879
- Client.prototype.getWalletStats = async function(signal) {
4880
- const resp = await this.doJSON("GET", "/wallet/stats", null, signal);
4881
- return resp.data;
4882
- };
4883
- Client.prototype.getWalletTransactions = async function(signal) {
4884
- const resp = await this.doJSON(
4885
- "GET",
4886
- "/wallet/transactions",
4887
- null,
4888
- signal
4889
- );
4890
- return resp.data;
4891
- };
4892
-
4893
- // src/client/skills.ts
4894
- init_types();
4895
- Client.prototype.browseSkillStore = async function(query, signal) {
4896
- const resp = await this.browseSkills(
4897
- 1,
4898
- 50,
4899
- query.category ?? "",
4900
- query.keyword ?? "",
4901
- query.tag ?? "",
4902
- "",
4903
- signal
4904
- );
4905
- return resp.items;
4906
- };
4907
- Client.prototype.browseSkills = async function(page, pageSize, category, keyword, tag, source, signal) {
4908
- const qv = new URLSearchParams();
4909
- qv.set("page", String(page));
4910
- qv.set("pageSize", String(pageSize));
4911
- if (category) qv.set("category", category);
4912
- if (keyword) qv.set("keyword", keyword);
4913
- if (tag) qv.set("tag", tag);
4914
- if (source) qv.set("source", source);
4915
- const resp = await this.doPublicJSON(
4916
- "GET",
4917
- `/skill-store?${qv.toString()}`,
4918
- null,
4919
- signal
4920
- );
4921
- return resp.data;
4922
- };
4923
- Client.prototype.browseSkillsList = async function(page, pageSize, category, keyword, tag, source, signal) {
4924
- const qv = new URLSearchParams();
4925
- qv.set("page", String(page));
4926
- qv.set("pageSize", String(pageSize));
4927
- qv.set("fields", "minimal");
4928
- if (category) qv.set("category", category);
4929
- if (keyword) qv.set("keyword", keyword);
4930
- if (tag) qv.set("tag", tag);
4931
- if (source) qv.set("source", source);
4932
- const resp = await this.doPublicJSON(
4933
- "GET",
4934
- `/skill-store?${qv.toString()}`,
4935
- null,
4936
- signal
4937
- );
4938
- return resp.data;
4939
- };
4940
- Client.prototype.getSkillDetail = async function(skillID, signal) {
4941
- const resp = await this.doPublicJSON(
4942
- "GET",
4943
- `/skill-store/${encodeURIComponent(skillID)}`,
4944
- null,
4945
- signal
4946
- );
4947
- return resp.data;
4948
- };
4949
- Client.prototype.resolveSkill = async function(key, signal) {
4950
- const resp = await this.doPublicJSON(
4951
- "GET",
4952
- `/skill-store/resolve/${encodeURIComponent(key)}`,
4953
- null,
4954
- signal
4955
- );
4956
- return resp.data;
4957
- };
4958
- Client.prototype.installSkill = async function(skillID, signal) {
4959
- const resp = await this.doJSON(
4960
- "POST",
4961
- `/skill-store/${encodeURIComponent(skillID)}/install`,
4962
- null,
4963
- signal
4964
- );
4965
- return resp.data;
5001
+ // src/compliance/errors.ts
5002
+ var CODE_TO_KEY = {
5003
+ // 通用 / token / scope (1-031-000-xxx)
5004
+ 1031000001: "COMPLIANCE_UNAUTHORIZED",
5005
+ 1031000002: "COMPLIANCE_TOKEN_INVALID",
5006
+ 1031000003: "COMPLIANCE_TOKEN_INVALID",
5007
+ 1031000004: "COMPLIANCE_TOKEN_INVALID",
5008
+ 1031000005: "COMPLIANCE_TOKEN_INVALID",
5009
+ 1031000006: "COMPLIANCE_TOKEN_INVALID",
5010
+ 1031000007: "COMPLIANCE_TOKEN_INVALID",
5011
+ 1031000008: "COMPLIANCE_TOKEN_INVALID",
5012
+ 1031000009: "COMPLIANCE_TOKEN_INVALID",
5013
+ 1031000010: "COMPLIANCE_TOKEN_INVALID",
5014
+ 1031000011: "COMPLIANCE_TOKEN_INVALID",
5015
+ 1031000012: "COMPLIANCE_INSUFFICIENT_SCOPE",
5016
+ 1031000013: "COMPLIANCE_STEP_UP_REQUIRED",
5017
+ // Subject snapshot (1-031-001-xxx)
5018
+ 1031001001: "SUBJECT_SNAPSHOT_NOT_FOUND",
5019
+ 1031001002: "SUBJECT_SNAPSHOT_TENANT_MISMATCH",
5020
+ 1031001003: "SUBJECT_SNAPSHOT_REQUIRED",
5021
+ // Evidence / Timestamp / Package / Report (1-031-002-xxx)
5022
+ 1031002001: "EVIDENCE_ASSET_NOT_FOUND",
5023
+ 1031002002: "SUBJECT_SNAPSHOT_TENANT_MISMATCH",
5024
+ 1031002003: "EVIDENCE_ASSET_HASH_MISMATCH",
5025
+ 1031002004: "EVIDENCE_ASSET_PAYLOAD_REQUIRED",
5026
+ 1031002005: "EVIDENCE_ASSET_PAYLOAD_REQUIRED",
5027
+ 1031002006: "TIMESTAMP_TOKEN_NOT_FOUND",
5028
+ 1031002007: "TIMESTAMP_PROVIDER_FAILED",
5029
+ 1031002008: "TIMESTAMP_PROVIDER_UNKNOWN",
5030
+ 1031002009: "TIMESTAMP_LOCAL_VERIFY_FAILED",
5031
+ 1031002010: "TIMESTAMP_PROVIDER_NOT_AVAILABLE",
5032
+ 1031002011: "EVIDENCE_PACKAGE_NOT_FOUND",
5033
+ 1031002012: "EVIDENCE_PACKAGE_TIMESTAMP_REQUIRED",
5034
+ 1031002013: "EVIDENCE_PACKAGE_MANIFEST_HASH_MISMATCH",
5035
+ 1031002014: "REPORT_NOT_FOUND",
5036
+ 1031002015: "REPORT_ALREADY_PUBLISHED",
5037
+ 1031002016: "REPORT_DRAFT_REQUIRED",
5038
+ 1031002017: "EVIDENCE_VERIFY_TARGET_REQUIRED",
5039
+ 1031002018: "EVIDENCE_VERIFY_TARGET_NOT_FOUND",
5040
+ // Provider request (1-031-003-xxx)
5041
+ 1031003001: "PROVIDER_REQUEST_UNKNOWN_NO_RETRY",
5042
+ 1031003002: "PROVIDER_CALLBACK_SOURCE_INVALID",
5043
+ 1031003003: "PROVIDER_NOT_CONFIGURED",
5044
+ 1031003010: "PROVIDER_REQUEST_NOT_FOUND",
5045
+ 1031003011: "PROVIDER_REQUEST_IDEMPOTENCY_REQUIRED",
5046
+ 1031003012: "PROVIDER_REQUEST_STATUS_NOT_TERMINAL",
5047
+ // Envelope (1-031-004-xxx)
5048
+ 1031004001: "ENVELOPE_NOT_FOUND",
5049
+ 1031004002: "ENVELOPE_TENANT_MISMATCH",
5050
+ 1031004003: "ENVELOPE_STATE_NOT_ALLOWED",
5051
+ 1031004004: "ENVELOPE_GATE_CLOSED",
5052
+ 1031004005: "CONTRACT_NOT_FOUND",
5053
+ 1031004006: "CONTRACT_HASH_MISMATCH",
5054
+ 1031004007: "CONTRACT_NOT_FOUND",
5055
+ 1031004008: "PROVIDER_AUTHORIZATION_NOT_CONFIRMED",
5056
+ 1031004009: "PROVIDER_AUTHORIZATION_NOT_CONFIRMED",
5057
+ 1031004010: "ENVELOPE_EVIDENCE_NOT_READY",
5058
+ // Seal approval / use (1-031-005-xxx)
5059
+ 1031005001: "SEAL_ASSET_NOT_FOUND",
5060
+ 1031005010: "SEAL_APPROVAL_NOT_FOUND",
5061
+ 1031005011: "SEAL_APPROVAL_NOT_FOUND",
5062
+ 1031005012: "SEAL_APPROVAL_STATE_NOT_APPROVED",
5063
+ 1031005013: "SEAL_APPROVAL_EXPIRED",
5064
+ 1031005014: "SEAL_APPROVAL_ALREADY_USED",
5065
+ 1031005015: "SEAL_APPROVAL_NONCE_USED",
5066
+ 1031005016: "SEAL_APPROVAL_SEAL_MISMATCH",
5067
+ 1031005017: "SEAL_APPROVAL_LOCATION_MISMATCH",
5068
+ 1031005018: "SEAL_APPROVAL_TRANSACTOR_MISMATCH",
5069
+ 1031005019: "SEAL_APPROVAL_CONTRACT_HASH_MISMATCH",
5070
+ 1031005020: "SEAL_APPROVAL_INVALID_TRANSITION",
5071
+ 1031005030: "SEAL_USE_ALREADY_CONSUMED",
5072
+ // Billing (1-031-006-xxx)
5073
+ 1031006004: "BILLING_COMMIT_REQUIRES_LOCAL_VERIFY",
5074
+ 1031006005: "BILLING_COMMIT_REQUIRES_PROVIDER_SUCCESS",
5075
+ 1031006007: "BILLING_CALLBACK_CANNOT_COMMIT",
5076
+ 1031006008: "BILLING_PROVIDER_UNKNOWN_NOT_COMMITTABLE",
5077
+ 1031006009: "BILLING_S2S_FORBIDDEN",
5078
+ // Audit (1-031-007-xxx)
5079
+ 1031007011: "AUDIT_CHAIN_TAMPER_DETECTED"
4966
5080
  };
4967
- Client.prototype.downloadSkill = async function(skillID, signal) {
4968
- const ctl = new AbortController();
4969
- const timer = setTimeout(() => ctl.abort(), 5 * 60 * 1e3);
4970
- let parentHandler;
4971
- if (signal) {
4972
- if (signal.aborted) ctl.abort();
4973
- else {
4974
- parentHandler = () => ctl.abort();
4975
- signal.addEventListener("abort", parentHandler);
4976
- }
4977
- }
4978
- try {
4979
- const url = this.apiURL(`/skill-store/${encodeURIComponent(skillID)}/download`);
4980
- const headers = {};
4981
- let token = "";
4982
- try {
4983
- token = await this.ensureToken(ctl.signal);
4984
- } catch {
4985
- }
4986
- if (token) headers["Authorization"] = `Bearer ${token}`;
4987
- let resp;
4988
- try {
4989
- resp = await this.fetchImpl(url, { method: "GET", headers, signal: ctl.signal });
4990
- } catch (e) {
4991
- throw classifyTransport(`GET /skill-store/${skillID}/download`, url, e);
4992
- }
4993
- if (resp.status === 429) {
4994
- const bodyText = await readLimitedText(resp.body, maxErrorBodySize);
4995
- throw new RateLimitError("\u533F\u540D\u4E0B\u8F7D\u5DF2\u8FBE\u9650\u5236", resp.headers.get("Retry-After") ?? "", bodyText);
4996
- }
4997
- if (!resp.ok) {
4998
- const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
4999
- throw new Error(
5000
- `download skill: ${parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers).message}`
5001
- );
5002
- }
5003
- const data = await readLimited(resp.body, maxDownloadSize + 1);
5004
- if (data.byteLength > maxDownloadSize) {
5005
- throw new Error(`download skill: response exceeds ${maxDownloadSize >> 20}MB limit`);
5006
- }
5007
- let filename = "skill.zip";
5008
- const cd = resp.headers.get("Content-Disposition");
5009
- if (cd) {
5010
- const idx = cd.indexOf("filename");
5011
- if (idx !== -1) {
5012
- const parts = cd.slice(idx).split("=", 2);
5013
- if (parts.length === 2) {
5014
- filename = parts[1].trim().replace(/^["' ]+|["' ]+$/g, "");
5015
- }
5016
- }
5081
+ var STEP_UP_KEYS = /* @__PURE__ */ new Set(["COMPLIANCE_STEP_UP_REQUIRED"]);
5082
+ var TERMINAL_KEYS = /* @__PURE__ */ new Set([
5083
+ "ENVELOPE_GATE_CLOSED",
5084
+ "PROVIDER_NOT_CONFIGURED",
5085
+ "PROVIDER_REQUEST_UNKNOWN_NO_RETRY",
5086
+ "BILLING_CALLBACK_CANNOT_COMMIT",
5087
+ "BILLING_COMMIT_REQUIRES_LOCAL_VERIFY",
5088
+ "BILLING_COMMIT_REQUIRES_PROVIDER_SUCCESS",
5089
+ "BILLING_PROVIDER_UNKNOWN_NOT_COMMITTABLE",
5090
+ "BILLING_S2S_FORBIDDEN",
5091
+ "SEAL_APPROVAL_NONCE_USED",
5092
+ "SEAL_APPROVAL_EXPIRED",
5093
+ "SEAL_APPROVAL_CONTRACT_HASH_MISMATCH",
5094
+ "SEAL_APPROVAL_SEAL_MISMATCH",
5095
+ "SEAL_APPROVAL_LOCATION_MISMATCH",
5096
+ "SEAL_APPROVAL_TRANSACTOR_MISMATCH",
5097
+ "SEAL_USE_ALREADY_CONSUMED",
5098
+ "CONTRACT_HASH_MISMATCH",
5099
+ "TIMESTAMP_LOCAL_VERIFY_FAILED",
5100
+ "EVIDENCE_PACKAGE_MANIFEST_HASH_MISMATCH",
5101
+ "AUDIT_CHAIN_TAMPER_DETECTED",
5102
+ "PROVIDER_REQUEST_NOT_FOUND",
5103
+ "EVIDENCE_ASSET_HASH_MISMATCH",
5104
+ "EVIDENCE_VERIFY_TARGET_NOT_FOUND",
5105
+ "REPORT_ALREADY_PUBLISHED"
5106
+ ]);
5107
+ var RETRYABLE_KEYS = /* @__PURE__ */ new Set([]);
5108
+ function classifyComplianceError(err) {
5109
+ const key = CODE_TO_KEY[err.code] ?? "UNKNOWN_COMPLIANCE_ERROR";
5110
+ return {
5111
+ code: err.code,
5112
+ message: err.message,
5113
+ key,
5114
+ retryable: RETRYABLE_KEYS.has(key),
5115
+ terminal: TERMINAL_KEYS.has(key),
5116
+ stepUpRequired: STEP_UP_KEYS.has(key)
5117
+ };
5118
+ }
5119
+ function isComplianceBusinessError(err) {
5120
+ return err.code >= 1031e6 && err.code <= 1031999999;
5121
+ }
5122
+
5123
+ // src/compliance/client.ts
5124
+ var cache = /* @__PURE__ */ new WeakMap();
5125
+ Object.defineProperty(Client.prototype, "compliance", {
5126
+ configurable: true,
5127
+ enumerable: false,
5128
+ get() {
5129
+ let existing = cache.get(this);
5130
+ if (!existing) {
5131
+ existing = new ComplianceClient(this);
5132
+ cache.set(this, existing);
5017
5133
  }
5018
- return { data, filename };
5019
- } finally {
5020
- clearTimeout(timer);
5021
- if (parentHandler && signal) signal.removeEventListener("abort", parentHandler);
5134
+ return existing;
5022
5135
  }
5136
+ });
5137
+ var DEFAULT_POLL = {
5138
+ timeoutMs: 6e4,
5139
+ initialIntervalMs: 1e3,
5140
+ maxIntervalMs: 5e3,
5141
+ multiplier: 1.5
5023
5142
  };
5024
- Client.prototype.uploadSkill = async function(zipData, scope, intent, signal) {
5025
- return uploadSkillInternal(this, zipData, scope, intent, false, signal);
5143
+ var CompliancePollError = class extends Error {
5144
+ kind;
5145
+ lastInfo;
5146
+ constructor(message, kind, lastInfo) {
5147
+ super(message);
5148
+ this.name = "CompliancePollError";
5149
+ this.kind = kind;
5150
+ this.lastInfo = lastInfo;
5151
+ }
5026
5152
  };
5027
- async function uploadSkillInternal(c, zipData, scope, intent, retried, signal) {
5028
- const ctl = new AbortController();
5029
- const timer = setTimeout(() => ctl.abort(), 5 * 60 * 1e3);
5030
- let parentHandler;
5031
- if (signal) {
5032
- if (signal.aborted) ctl.abort();
5033
- else {
5034
- parentHandler = () => ctl.abort();
5035
- signal.addEventListener("abort", parentHandler);
5036
- }
5153
+ var ComplianceClient = class {
5154
+ constructor(client) {
5155
+ this.client = client;
5037
5156
  }
5038
- try {
5039
- const token = await c.ensureToken(ctl.signal);
5040
- const form = new FormData();
5041
- form.append("scope", scope);
5042
- form.append("intent", intent);
5043
- const blob = new Blob([zipData], { type: "application/zip" });
5044
- form.append("file", blob, "skill.zip");
5045
- const url = c.apiURL("/skill-store/upload");
5046
- let resp;
5047
- try {
5048
- resp = await c.fetchImpl(url, {
5049
- method: "POST",
5050
- headers: { Authorization: `Bearer ${token}` },
5051
- body: form,
5052
- signal: ctl.signal
5053
- });
5054
- } catch (e) {
5055
- throw classifyTransport("POST /skill-store/upload", url, e);
5056
- }
5057
- if (resp.status === 401 && !retried) {
5058
- try {
5059
- await resp.body?.cancel();
5060
- } catch {
5061
- }
5062
- try {
5063
- await c.forceRefresh(ctl.signal);
5064
- } catch (refreshErr) {
5065
- throw new Error(
5066
- `upload: unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
5067
- );
5068
- }
5069
- return uploadSkillInternal(c, zipData, scope, intent, true, signal);
5070
- }
5071
- if (resp.status < 200 || resp.status >= 300) {
5072
- const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
5073
- throw new Error(
5074
- `upload: ${parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers).message}`
5075
- );
5076
- }
5077
- const text = await resp.text();
5078
- const result = JSON.parse(text);
5079
- return result.data.skill;
5080
- } finally {
5081
- clearTimeout(timer);
5082
- if (parentHandler && signal) signal.removeEventListener("abort", parentHandler);
5157
+ client;
5158
+ // =========================================================================
5159
+ // Evidence Asset
5160
+ // =========================================================================
5161
+ /** 创建证据资产(写)。 */
5162
+ createEvidenceAsset(req, opts = {}) {
5163
+ return this.write(
5164
+ "POST",
5165
+ "/compliance/evidence/assets",
5166
+ req,
5167
+ writeCtx(opts)
5168
+ );
5169
+ }
5170
+ /** 读 — 证据资产详情。 */
5171
+ getEvidenceAsset(id, signal) {
5172
+ return this.read(
5173
+ "GET",
5174
+ `/compliance/evidence/assets/${encodeURIComponent(id)}`,
5175
+ null,
5176
+ signal
5177
+ );
5178
+ }
5179
+ /**
5180
+ * 读 — 证据资产分页列表(compliance gateway S1)。
5181
+ *
5182
+ * 走 GET 读路径(允许 401 单次刷新重放)。返回 yudao `PageResult<T>`
5183
+ * (`{ total, list }`)。所有过滤项可选;`createTimeStart` / `createTimeEnd`
5184
+ * 由调用方按 `yyyy-MM-dd HH:mm:ss` 提供,SDK 原样透传。
5185
+ */
5186
+ listEvidenceAssets(req = {}, signal) {
5187
+ return this.read(
5188
+ "GET",
5189
+ `/compliance/evidence/assets/page${pageQuery(req, ["assetType", "status", "createTimeStart", "createTimeEnd"])}`,
5190
+ null,
5191
+ signal
5192
+ );
5193
+ }
5194
+ /**
5195
+ * 公开 verify。隐私边界:返回字段不含 PII / 合同原文 / storage / provider raw。
5196
+ *
5197
+ * 匿名可调用:未 login 时走匿名请求,不会抛 `not authorized, call login() first`。
5198
+ * 已 login / 已持有 token 时附带 `Authorization` 以保留审计上下文。public 端点不
5199
+ * 应要求认证 — 收到 401 直接抛 HTTPError,不触发 `forceRefresh`,也不做 refresh
5200
+ * replay。
5201
+ */
5202
+ verifyEvidencePublic(params, signal) {
5203
+ const q = new URLSearchParams();
5204
+ if (params.evidenceNo) q.set("evidenceNo", params.evidenceNo);
5205
+ if (params.publicVerifyCode) q.set("publicVerifyCode", params.publicVerifyCode);
5206
+ const qs = q.toString();
5207
+ return this.publicRead(
5208
+ "GET",
5209
+ `/compliance/evidence/verify${qs ? "?" + qs : ""}`,
5210
+ signal
5211
+ );
5212
+ }
5213
+ // =========================================================================
5214
+ // Timestamp
5215
+ // =========================================================================
5216
+ /** 申请时间章(写)。SDK 永远不传 provider 字段。 */
5217
+ issueTimestamp(req, opts = {}) {
5218
+ return this.write("POST", "/compliance/timestamps", req, writeCtx(opts));
5219
+ }
5220
+ /** 给已有资产申请时间章。SDK 永远不传 provider 字段。 */
5221
+ issueTimestampForAsset(assetId, opts = {}) {
5222
+ return this.write(
5223
+ "POST",
5224
+ `/compliance/evidence/assets/${encodeURIComponent(assetId)}/timestamp`,
5225
+ null,
5226
+ writeCtx(opts)
5227
+ );
5228
+ }
5229
+ /** 读 — 时间章 token 详情。 */
5230
+ getTimestamp(id, signal) {
5231
+ return this.read(
5232
+ "GET",
5233
+ `/compliance/timestamps/${encodeURIComponent(id)}`,
5234
+ null,
5235
+ signal
5236
+ );
5237
+ }
5238
+ /**
5239
+ * 读 — 时间章分页列表(compliance gateway S1)。
5240
+ *
5241
+ * 走 GET 读路径。返回 yudao `PageResult<T>`。所有过滤项可选;`createTimeStart` /
5242
+ * `createTimeEnd` 由调用方按 `yyyy-MM-dd HH:mm:ss` 提供,SDK 原样透传。
5243
+ */
5244
+ listTimestamps(req = {}, signal) {
5245
+ return this.read(
5246
+ "GET",
5247
+ `/compliance/timestamps/page${pageQuery(req, ["provider", "verificationStatus", "createTimeStart", "createTimeEnd"])}`,
5248
+ null,
5249
+ signal
5250
+ );
5251
+ }
5252
+ /** verify — 本地离线校验已申请的时间章。 */
5253
+ verifyTimestamp(req, opts = {}) {
5254
+ return this.write(
5255
+ "POST",
5256
+ "/compliance/timestamps/verify",
5257
+ req,
5258
+ writeCtx(opts)
5259
+ );
5260
+ }
5261
+ /**
5262
+ * 轮询到 VERIFIED 终态。
5263
+ * - VERIFIED → 返回 token;
5264
+ * - FAILED / LOCAL_VERIFY_FAILED → 抛 {@link CompliancePollError} kind='terminal_failure';
5265
+ * - UNKNOWN / RETRYING / PENDING → 继续轮询直到 timeout;
5266
+ * - timeout → 抛 {@link CompliancePollError} kind='timeout'。
5267
+ */
5268
+ async waitForTimestampVerified(id, opts = {}) {
5269
+ return this.poll(
5270
+ () => this.getTimestamp(id, opts.signal),
5271
+ (t) => classifyTimestamp(t.verificationStatus),
5272
+ opts
5273
+ );
5274
+ }
5275
+ // =========================================================================
5276
+ // TSA readonly views (read-only — compliance gateway S3 / gap-register U-7)
5277
+ // =========================================================================
5278
+ /**
5279
+ * 读 — 时间章授权机构(TSA)provider 列表(compliance gateway S3)。
5280
+ *
5281
+ * 走 GET 读路径(允许 401 单次刷新重放)。后端 G3 为每个 TSA provider 返回
5282
+ * 一条 {@link TsaProvider}:名称、所处环境、当前是否可用。只读视图,不含
5283
+ * provider 端点 / 凭证 / 证书等内部接入材料。
5284
+ */
5285
+ listTsaProviders(signal) {
5286
+ return this.read(
5287
+ "GET",
5288
+ "/compliance/timestamps/providers",
5289
+ null,
5290
+ signal
5291
+ );
5292
+ }
5293
+ /**
5294
+ * 读 — 时间章统计视图(compliance gateway S3)。
5295
+ *
5296
+ * 走 GET 读路径(允许 401 单次刷新重放)。返回 {@link TsaStats}:时间章总数
5297
+ * + 按校验状态分桶的计数。只读聚合视图。
5298
+ */
5299
+ getTsaStats(signal) {
5300
+ return this.read(
5301
+ "GET",
5302
+ "/compliance/timestamps/stats",
5303
+ null,
5304
+ signal
5305
+ );
5306
+ }
5307
+ // =========================================================================
5308
+ // Evidence Package
5309
+ // =========================================================================
5310
+ /** 构建证据包(写)。 */
5311
+ buildEvidencePackage(assetId, timestampTokenId, opts = {}) {
5312
+ const tsParam = timestampTokenId == null ? "" : "?timestampTokenId=" + encodeURIComponent(timestampTokenId);
5313
+ return this.write(
5314
+ "POST",
5315
+ `/compliance/evidence/assets/${encodeURIComponent(assetId)}/packages${tsParam}`,
5316
+ null,
5317
+ writeCtx(opts)
5318
+ );
5319
+ }
5320
+ /**
5321
+ * 读 — 证据包分页列表(compliance gateway S1)。
5322
+ *
5323
+ * 走 GET 读路径。返回 yudao `PageResult<T>`。所有过滤项可选;`createTimeStart` /
5324
+ * `createTimeEnd` 由调用方按 `yyyy-MM-dd HH:mm:ss` 提供,SDK 原样透传。
5325
+ */
5326
+ listEvidencePackages(req = {}, signal) {
5327
+ return this.read(
5328
+ "GET",
5329
+ `/compliance/evidence/packages/page${pageQuery(req, ["status", "createTimeStart", "createTimeEnd"])}`,
5330
+ null,
5331
+ signal
5332
+ );
5333
+ }
5334
+ // =========================================================================
5335
+ // Report
5336
+ // =========================================================================
5337
+ /** 创建证据报告(写)。 */
5338
+ createReport(req, opts = {}) {
5339
+ return this.write("POST", "/compliance/reports", req, writeCtx(opts));
5340
+ }
5341
+ /** 读 — 报告详情。 */
5342
+ getReport(id, signal) {
5343
+ return this.read(
5344
+ "GET",
5345
+ `/compliance/reports/${encodeURIComponent(id)}`,
5346
+ null,
5347
+ signal
5348
+ );
5349
+ }
5350
+ /**
5351
+ * 读 — 证据报告分页列表(compliance gateway S1)。
5352
+ *
5353
+ * 走 GET 读路径。返回 yudao `PageResult<T>`。所有过滤项可选;`createTimeStart` /
5354
+ * `createTimeEnd` 由调用方按 `yyyy-MM-dd HH:mm:ss` 提供,SDK 原样透传。
5355
+ */
5356
+ listReports(req = {}, signal) {
5357
+ return this.read(
5358
+ "GET",
5359
+ `/compliance/reports/page${pageQuery(req, ["status", "createTimeStart", "createTimeEnd"])}`,
5360
+ null,
5361
+ signal
5362
+ );
5363
+ }
5364
+ /**
5365
+ * 发布报告(写,step-up 必须)。
5366
+ *
5367
+ * `@status gated` — step-up 闸门未闭合前服务端会一致返回
5368
+ * `COMPLIANCE_STEP_UP_REQUIRED`(数值码 1031000013)。SDK 不会自动重试、不伪成功;
5369
+ * 调用方需要引导用户重新做 OAuth introspection 或重新登录后再次调用本方法
5370
+ *(使用同一 idempotency-key)。方法状态分级见 `docs/compliance.md` Method Status。
5371
+ */
5372
+ publishReport(id, opts = {}) {
5373
+ return this.write(
5374
+ "POST",
5375
+ `/compliance/reports/${encodeURIComponent(id)}/publish`,
5376
+ null,
5377
+ writeCtx(opts)
5378
+ );
5379
+ }
5380
+ /**
5381
+ * 下载报告(读)。返回 {@link ReportDownload}:报告 hash + 资产 hash + 证据包 hash +
5382
+ * 时间章 serial/genTime,足以离线复核。
5383
+ * 不返回 bodyCanonicalJson / storage key / subject snapshot id。
5384
+ */
5385
+ downloadReport(id, signal) {
5386
+ return this.read(
5387
+ "GET",
5388
+ `/compliance/reports/${encodeURIComponent(id)}/download`,
5389
+ null,
5390
+ signal
5391
+ );
5392
+ }
5393
+ // =========================================================================
5394
+ // Signing Envelope
5395
+ // =========================================================================
5396
+ /** 创建 envelope(写)。返回 envelope id。 */
5397
+ createSigningEnvelope(req, opts = {}) {
5398
+ return this.write(
5399
+ "POST",
5400
+ "/compliance/signing-envelopes",
5401
+ req,
5402
+ writeCtx(opts)
5403
+ );
5404
+ }
5405
+ /** 读 — envelope 详情。租户由服务端从 compliance token principal 推导。 */
5406
+ getSigningEnvelope(envelopeId, signal) {
5407
+ return this.read(
5408
+ "GET",
5409
+ `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}`,
5410
+ null,
5411
+ signal
5412
+ );
5413
+ }
5414
+ /**
5415
+ * 读 — 签署 envelope 分页列表(compliance gateway S1)。
5416
+ *
5417
+ * 走 GET 读路径。返回 yudao `PageResult<T>`。所有过滤项可选;`createTimeStart` /
5418
+ * `createTimeEnd` 由调用方按 `yyyy-MM-dd HH:mm:ss` 提供,SDK 原样透传。
5419
+ */
5420
+ listSigningEnvelopes(req = {}, signal) {
5421
+ return this.read(
5422
+ "GET",
5423
+ `/compliance/signing-envelopes/page${pageQuery(req, ["status", "createTimeStart", "createTimeEnd"])}`,
5424
+ null,
5425
+ signal
5426
+ );
5427
+ }
5428
+ /**
5429
+ * 正式签署(写,step-up 必须)。
5430
+ *
5431
+ * `@status gated` — 服务端闸门关闭时会一致返回 `ENVELOPE_GATE_CLOSED` (1031004004)。
5432
+ * SDK 不重试、不伪成功;调用方应该将该错误展示为"功能未开放"。
5433
+ */
5434
+ signEnvelope(envelopeId, req, opts = {}) {
5435
+ return this.write(
5436
+ "POST",
5437
+ `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}/sign`,
5438
+ req,
5439
+ writeCtx(opts)
5440
+ );
5441
+ }
5442
+ /**
5443
+ * 创建 H5 签署短链(写,step-up 必须)。
5444
+ *
5445
+ * `@status gated` — 同 {@link signEnvelope}:服务端闸门关闭时 SDK 不重试、不伪成功。
5446
+ */
5447
+ createH5SigningUrl(envelopeId, req, opts = {}) {
5448
+ return this.write(
5449
+ "POST",
5450
+ `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}/h5-url`,
5451
+ req,
5452
+ writeCtx(opts)
5453
+ );
5454
+ }
5455
+ /** 同步 provider 状态(写但只读对账,不创建新 provider 请求)。 */
5456
+ syncSigningEnvelopeStatus(envelopeId, opts = {}) {
5457
+ return this.write(
5458
+ "POST",
5459
+ `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}/sync-provider-status`,
5460
+ null,
5461
+ writeCtx(opts)
5462
+ );
5463
+ }
5464
+ /**
5465
+ * 读 — envelope 下挂的合同列表(compliance gateway S4)。
5466
+ *
5467
+ * 走 GET 读路径(允许 401 单次刷新重放)。后端 G4 为每份挂在该 envelope 上的
5468
+ * 合同返回一条 {@link EnvelopeContractItem}:编号 / 标题 / MIME / 大小 / 哈希
5469
+ * 指纹 / 状态。返回普通数组(非 `PageResult`)。SDK-safe 视图——不含合同原文 /
5470
+ * storage key / provider raw payload。
5471
+ */
5472
+ listEnvelopeContracts(envelopeId, signal) {
5473
+ return this.read(
5474
+ "GET",
5475
+ `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}/contracts`,
5476
+ null,
5477
+ signal
5478
+ );
5479
+ }
5480
+ /**
5481
+ * 读 — envelope 关联的 provider 请求列表(compliance gateway S4)。
5482
+ *
5483
+ * 走 GET 读路径(允许 401 单次刷新重放)。后端 G4 复用操作投影
5484
+ * {@link OperationPageItem}:描述每次 provider 请求本身的执行进度,与 envelope
5485
+ * 领域状态正交。返回普通数组(非 `PageResult`)。
5486
+ */
5487
+ listEnvelopeProviderRequests(envelopeId, signal) {
5488
+ return this.read(
5489
+ "GET",
5490
+ `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}/provider-requests`,
5491
+ null,
5492
+ signal
5493
+ );
5494
+ }
5495
+ /**
5496
+ * 作废 envelope(写,compliance gateway S4)。
5497
+ *
5498
+ * 走 compliance 写路径——发送前 `ensureToken` 一次、不自动重试、`401` 不刷新
5499
+ * 重放;支持 `Idempotency-Key` header(强烈建议调用方持久化幂等键,重试 / 恢复
5500
+ * 时复用,避免重复作废)。`req.reason` 为必填的作废原因,随 JSON body 提交。
5501
+ */
5502
+ voidEnvelope(envelopeId, req, opts = {}) {
5503
+ return this.write(
5504
+ "POST",
5505
+ `/compliance/signing-envelopes/${encodeURIComponent(envelopeId)}/void`,
5506
+ req,
5507
+ writeCtx(opts)
5508
+ );
5509
+ }
5510
+ // =========================================================================
5511
+ // Seal Approval
5512
+ // =========================================================================
5513
+ /**
5514
+ * 提交用印审批申请(写)。
5515
+ *
5516
+ * `@status production-ready` — 服务端以 `Idempotency-Key` + 业务请求指纹做重放保护:
5517
+ * 同 key + 同请求 → 返回原审批 id;同 key + 不同请求 → 拒绝复用幂等键。强烈建议调用方
5518
+ * 持久化 `idempotencyKey`,网络重试 / 任务恢复时复用,避免重复创建审批单。
5519
+ */
5520
+ submitSealApproval(req, opts = {}) {
5521
+ return this.write(
5522
+ "POST",
5523
+ "/compliance/seal-approvals",
5524
+ req,
5525
+ writeCtx(opts)
5526
+ );
5527
+ }
5528
+ /**
5529
+ * 审批通过用印申请(写,step-up 必须)。
5530
+ *
5531
+ * `@status gated` — step-up 未闭合前服务端会返回 `COMPLIANCE_STEP_UP_REQUIRED`。
5532
+ * SDK 不重试、不伪成功。方法状态分级见 `docs/compliance.md` Method Status。
5533
+ */
5534
+ approveSealApproval(id, query, opts = {}) {
5535
+ const q = new URLSearchParams();
5536
+ if (query.expiresAt) q.set("expiresAt", query.expiresAt);
5537
+ if (query.note) q.set("note", query.note);
5538
+ const qs = q.toString();
5539
+ return this.write(
5540
+ "POST",
5541
+ `/compliance/seal-approvals/${encodeURIComponent(id)}/approve${qs ? "?" + qs : ""}`,
5542
+ null,
5543
+ writeCtx(opts)
5544
+ );
5083
5545
  }
5084
- }
5085
- Client.prototype.getSkillSummary = async function(signal) {
5086
- const resp = await this.doJSON("GET", "/skills/summary", null, signal);
5087
- return resp.data;
5088
- };
5089
- Client.prototype.certifySkill = async function(skillID, signal) {
5090
- await this.doJSON(
5091
- "POST",
5092
- `/skill-store/${encodeURIComponent(skillID)}/certify`,
5093
- null,
5094
- signal
5095
- );
5096
- };
5097
- Client.prototype.getCertificationStatus = async function(skillID, signal) {
5098
- const resp = await this.doJSON(
5099
- "GET",
5100
- `/skill-store/${encodeURIComponent(skillID)}/certification`,
5101
- null,
5102
- signal
5103
- );
5104
- return resp.data;
5105
- };
5106
- Client.prototype.generateSkill = async function(req, signal) {
5107
- const resp = await this.doJSON(
5108
- "POST",
5109
- "/skill-generator/generate",
5110
- req,
5111
- signal
5112
- );
5113
- return resp.data;
5114
- };
5115
- Client.prototype.optimizeSkill = async function(req, signal) {
5116
- const resp = await this.doJSON(
5117
- "POST",
5118
- "/skill-generator/optimize",
5119
- req,
5120
- signal
5121
- );
5122
- return resp.data;
5123
- };
5124
- Client.prototype.validateSkill = async function(skillName, signal) {
5125
- await this.doJSON(
5126
- "POST",
5127
- "/skill-generator/validate",
5128
- { skillName },
5129
- signal
5130
- );
5131
- };
5132
-
5133
- // src/client/tools.ts
5134
- Client.prototype.listTools = async function(signal) {
5135
- const resp = await this.doJSON("GET", "/tools", null, signal);
5136
- return resp.data.skills;
5137
- };
5138
- Client.prototype.getTool = async function(toolID, signal) {
5139
- const resp = await this.doJSON(
5140
- "GET",
5141
- `/tools/${encodeURIComponent(toolID)}`,
5142
- null,
5143
- signal
5144
- );
5145
- return resp.data;
5146
- };
5147
-
5148
- // src/client/notifications.ts
5149
- Client.prototype.listNotifications = async function(page, pageSize, typeFilter, signal) {
5150
- let path = `/notifications?page=${page}&pageSize=${pageSize}`;
5151
- if (typeFilter) path += `&type=${encodeURIComponent(typeFilter)}`;
5152
- const resp = await this.doJSON("GET", path, null, signal);
5153
- return resp.data;
5154
- };
5155
- Client.prototype.getUnreadCount = async function(signal) {
5156
- const resp = await this.doJSON(
5157
- "GET",
5158
- "/notifications/unread-count",
5159
- null,
5160
- signal
5161
- );
5162
- return resp.data.unreadCount;
5163
- };
5164
- Client.prototype.markNotificationRead = async function(id, signal) {
5165
- await this.doJSON(
5166
- "PUT",
5167
- `/notifications/${encodeURIComponent(id)}/read`,
5168
- null,
5169
- signal
5170
- );
5171
- };
5172
- Client.prototype.markAllNotificationsRead = async function(signal) {
5173
- await this.doJSON("PUT", "/notifications/read-all", null, signal);
5174
- };
5175
- Client.prototype.deleteNotification = async function(id, signal) {
5176
- await this.doJSON(
5177
- "DELETE",
5178
- `/notifications/${encodeURIComponent(id)}`,
5179
- null,
5180
- signal
5181
- );
5182
- };
5183
- Client.prototype.registerDevice = async function(reg, signal) {
5184
- await this.doJSON("POST", "/devices/register", reg, signal);
5185
- };
5186
- Client.prototype.unregisterDevice = async function(token, signal) {
5187
- await this.doJSON(
5188
- "DELETE",
5189
- `/devices/${encodeURIComponent(token)}`,
5190
- null,
5191
- signal
5192
- );
5193
- };
5194
- Client.prototype.listNotificationPreferences = async function(signal) {
5195
- const resp = await this.doJSON(
5196
- "GET",
5197
- "/notification-preferences",
5198
- null,
5199
- signal
5200
- );
5201
- return resp.data;
5202
- };
5203
- Client.prototype.updateNotificationPreference = async function(typeCode, pref, signal) {
5204
- await this.doJSON(
5205
- "PUT",
5206
- `/notification-preferences/${encodeURIComponent(typeCode)}`,
5207
- pref,
5208
- signal
5209
- );
5210
- };
5211
-
5212
- // src/sanitize-bridge.ts
5213
- Client.prototype.setDefensiveSanitize = function(cfg) {
5214
- this.defensiveCfg = cfg;
5215
- };
5216
- Client.prototype.setAutoStripEphemeralHistory = function(on) {
5217
- this.autoStripEphemeral = on;
5218
- };
5219
- Client.prototype.applyRequestSanitizers = function(req) {
5220
- const cfg = this.defensiveCfg;
5221
- const strip = this.autoStripEphemeral;
5222
- if (cfg == null && !strip) return;
5223
- if (req.rawMessages != null) {
5224
- let msgs;
5225
- try {
5226
- msgs = normalizeRawMessages(req.rawMessages);
5227
- } catch (e) {
5228
- throw new Error(
5229
- `sanitize: normalize raw messages: ${e instanceof Error ? e.message : String(e)}`
5230
- );
5231
- }
5232
- if (cfg) {
5233
- msgs = sanitize(msgs, cfg);
5234
- }
5235
- if (strip) {
5236
- msgs = stripEphemeral(msgs);
5237
- }
5238
- req.rawMessages = msgs;
5239
- return;
5546
+ rejectSealApproval(id, query, opts = {}) {
5547
+ const q = new URLSearchParams();
5548
+ if (query.reason) q.set("reason", query.reason);
5549
+ const qs = q.toString();
5550
+ return this.write(
5551
+ "POST",
5552
+ `/compliance/seal-approvals/${encodeURIComponent(id)}/reject${qs ? "?" + qs : ""}`,
5553
+ null,
5554
+ writeCtx(opts)
5555
+ );
5556
+ }
5557
+ cancelSealApproval(id, query, opts = {}) {
5558
+ const q = new URLSearchParams();
5559
+ if (query.reason) q.set("reason", query.reason);
5560
+ const qs = q.toString();
5561
+ return this.write(
5562
+ "POST",
5563
+ `/compliance/seal-approvals/${encodeURIComponent(id)}/cancel${qs ? "?" + qs : ""}`,
5564
+ null,
5565
+ writeCtx(opts)
5566
+ );
5567
+ }
5568
+ listPendingSealApprovals(signal) {
5569
+ return this.read(
5570
+ "GET",
5571
+ "/compliance/seal-approvals/pending",
5572
+ null,
5573
+ signal
5574
+ );
5575
+ }
5576
+ getSealApproval(id, signal) {
5577
+ return this.read(
5578
+ "GET",
5579
+ `/compliance/seal-approvals/${encodeURIComponent(id)}`,
5580
+ null,
5581
+ signal
5582
+ );
5583
+ }
5584
+ /**
5585
+ * 读 — 用印审批分页列表(compliance gateway S1)。
5586
+ *
5587
+ * 与 {@link listPendingSealApprovals}(仅 pending、不分页)不同,本方法支持分页与
5588
+ * 状态 / 时间过滤。走 GET 读路径。返回 yudao `PageResult<T>`。所有过滤项可选;
5589
+ * `createTimeStart` / `createTimeEnd` 由调用方按 `yyyy-MM-dd HH:mm:ss` 提供,
5590
+ * SDK 原样透传。
5591
+ */
5592
+ listSealApprovals(req = {}, signal) {
5593
+ return this.read(
5594
+ "GET",
5595
+ `/compliance/seal-approvals/page${pageQuery(req, ["status", "createTimeStart", "createTimeEnd"])}`,
5596
+ null,
5597
+ signal
5598
+ );
5599
+ }
5600
+ // =========================================================================
5601
+ // Seal Use (read-only — compliance gateway S6 / gap-register U-4)
5602
+ // =========================================================================
5603
+ /**
5604
+ * 读 — 用印执行记录分页列表(compliance gateway S6)。
5605
+ *
5606
+ * 走 GET 读路径(允许 401 单次刷新重放)。返回 yudao `PageResult<T>`
5607
+ * (`{ total, list }`)。一次用印执行(seal use)描述 envelope / contract /
5608
+ * seal / 审批联动后【真正调用 provider 落章】的那一笔记录,与 envelope
5609
+ * 领域状态正交。所有过滤项可选;`createTimeStart` / `createTimeEnd` 由调用方
5610
+ * 按 `yyyy-MM-dd HH:mm:ss` 提供,SDK 原样透传。
5611
+ *
5612
+ * 与后端复用同一只读 scope `CONTRACT_SIGNING_READ`
5613
+ *({@link ScopeComplianceContractSigningRead})——不引入新 scope。
5614
+ */
5615
+ listSealUses(req = {}, signal) {
5616
+ return this.read(
5617
+ "GET",
5618
+ `/compliance/seal-uses/page${pageQuery(req, ["sealId", "envelopeId", "usageStatus", "createTimeStart", "createTimeEnd"])}`,
5619
+ null,
5620
+ signal
5621
+ );
5622
+ }
5623
+ // =========================================================================
5624
+ // Provider Request (read-only)
5625
+ // =========================================================================
5626
+ getProviderRequest(id, signal) {
5627
+ return this.read(
5628
+ "GET",
5629
+ `/compliance/provider-requests/${encodeURIComponent(id)}`,
5630
+ null,
5631
+ signal
5632
+ );
5633
+ }
5634
+ /**
5635
+ * 轮询 provider request 到 SUCCESS / FAILED 终态。
5636
+ * - SUCCESS / FAILED → 返回最后视图;
5637
+ * - UNKNOWN / RETRYING / PENDING → 继续轮询;
5638
+ * - timeout → 抛 {@link CompliancePollError} kind='timeout',不自动重发原 provider 请求。
5639
+ *
5640
+ * SUCCESS 不代表 billing 已 commit;调用方仍需通过业务侧 envelope / asset 终态判断。
5641
+ */
5642
+ async waitForProviderRequestTerminal(id, opts = {}) {
5643
+ return this.poll(
5644
+ () => this.getProviderRequest(id, opts.signal),
5645
+ (v) => classifyProviderStatus(v.status),
5646
+ opts
5647
+ );
5648
+ }
5649
+ // =========================================================================
5650
+ // Capabilities (read-only — compliance gateway S2 / gap-register U-6)
5651
+ // =========================================================================
5652
+ /**
5653
+ * 读 — compliance 能力闸门列表(compliance gateway S2)。
5654
+ *
5655
+ * 走 GET 读路径(允许 401 单次刷新重放)。后端 G2 为每个高风险 / 收费动作
5656
+ * (`signEnvelope` / `createH5SigningUrl` / `publishReport` /
5657
+ * `approveSealApproval` / `executeSealUse` / `createSeal`)返回一条
5658
+ * {@link ComplianceCapability}:是否可执行、所处状态、所需 scope / step-up。
5659
+ *
5660
+ * 调用方在高风险动作执行【前】查询本结果做门控;拿不到能力时必须 fail-closed
5661
+ *(按 `executable=false` 处理)。
5662
+ */
5663
+ getCapabilities(signal) {
5664
+ return this.read(
5665
+ "GET",
5666
+ "/compliance/capabilities",
5667
+ null,
5668
+ signal
5669
+ );
5670
+ }
5671
+ /**
5672
+ * 读 — 单个动作的能力闸门视图(便捷方法)。
5673
+ *
5674
+ * 拉取完整 {@link getCapabilities} 列表并返回 `action` 匹配的那一条,无匹配时
5675
+ * 返回 `undefined`。**每次调用产生一次网络请求**——需要门控多个动作时应改用
5676
+ * {@link getCapabilities} 一次性取回再本地查表,避免重复请求。
5677
+ *
5678
+ * {@link getCapabilities} 一致走 GET 读路径(允许 401 单次刷新重放)。
5679
+ */
5680
+ async getFeatureGate(action, signal) {
5681
+ const caps = await this.getCapabilities(signal);
5682
+ return caps.find((c) => c.action === action);
5683
+ }
5684
+ // =========================================================================
5685
+ // Operation projection (read-only compliance gateway S2 / gap-register U-5)
5686
+ // =========================================================================
5687
+ /**
5688
+ * — compliance 操作投影分页列表(compliance gateway S2)。
5689
+ *
5690
+ * GET 读路径。返回 yudao `PageResult<T>`(`{ total, list }`)。所有过滤项
5691
+ * 可选;`createTimeStart` / `createTimeEnd` 由调用方按 `yyyy-MM-dd HH:mm:ss`
5692
+ * 提供,SDK 原样透传,不做格式校验或时区转换。
5693
+ *
5694
+ * 操作投影描述【一次操作】本身的执行进度,与履约对象的领域状态正交。
5695
+ */
5696
+ listOperations(req = {}, signal) {
5697
+ return this.read(
5698
+ "GET",
5699
+ `/compliance/operations/page${pageQuery(req, ["status", "createTimeStart", "createTimeEnd"])}`,
5700
+ null,
5701
+ signal
5702
+ );
5240
5703
  }
5241
- if (cfg && (cfg.maxMessagesTurns ?? 0) > 0 && (req.messages?.length ?? 0) > cfg.maxMessagesTurns) {
5242
- throw ErrHistoryTooDeep;
5704
+ /**
5705
+ * 读 — compliance 操作投影详情(compliance gateway S2)。
5706
+ *
5707
+ * `id` 为数值行主键(非 `operationId` 幂等键)。走 GET 读路径(允许 401 单次
5708
+ * 刷新重放)。
5709
+ */
5710
+ getOperation(id, signal) {
5711
+ return this.read(
5712
+ "GET",
5713
+ `/compliance/operations/${encodeURIComponent(id)}`,
5714
+ null,
5715
+ signal
5716
+ );
5243
5717
  }
5244
- };
5245
- function normalizeRawMessages(rm) {
5246
- if (Array.isArray(rm)) return rm;
5247
- let s;
5248
- try {
5249
- s = JSON.parse(JSON.stringify(rm));
5250
- } catch (e) {
5251
- throw new Error(`raw messages: ${e instanceof Error ? e.message : String(e)}`);
5718
+ // =========================================================================
5719
+ // Contract Template (compliance gateway S5 — gap-register U-2)
5720
+ // =========================================================================
5721
+ /**
5722
+ * 创建合同模板(写)。
5723
+ *
5724
+ * compliance 写路径——发送前 `ensureToken` 一次、不自动重试、`401` 不刷新
5725
+ * 重放;支持 `Idempotency-Key` header(强烈建议调用方持久化幂等键,重试 / 恢复
5726
+ * 时复用,避免重复创建模板)。模板创建后初始状态为 `DRAFT`。
5727
+ */
5728
+ createContractTemplate(req, opts = {}) {
5729
+ return this.write(
5730
+ "POST",
5731
+ "/compliance/contract-templates",
5732
+ req,
5733
+ writeCtx(opts)
5734
+ );
5252
5735
  }
5253
- if (!Array.isArray(s)) {
5254
- throw new Error("raw messages must be a JSON array");
5736
+ /**
5737
+ * 更新合同模板(写,仅 DRAFT 状态)。
5738
+ *
5739
+ * 走 compliance 写路径——`Idempotency-Key`、不重试、`401` 不刷新重放。所有字段
5740
+ * 可选,缺省字段视为不修改。服务端在 PUBLISHED / ARCHIVED 状态下会拒绝更新。
5741
+ */
5742
+ updateContractTemplate(id, req, opts = {}) {
5743
+ return this.write(
5744
+ "POST",
5745
+ `/compliance/contract-templates/${encodeURIComponent(id)}`,
5746
+ req,
5747
+ writeCtx(opts)
5748
+ );
5255
5749
  }
5256
- return s;
5257
- }
5258
-
5259
- // src/ws.ts
5260
- Client.prototype.connect = async function(cfg, signal) {
5261
- const noop = () => {
5262
- };
5263
- const filledCfg = {
5264
- onEvent: cfg.onEvent ?? noop,
5265
- onConnect: cfg.onConnect ?? noop,
5266
- onDisconnect: cfg.onDisconnect ?? noop,
5267
- topics: cfg.topics ?? [],
5268
- reconnectMinMs: cfg.reconnectMinMs ?? 2e3,
5269
- reconnectMaxMs: cfg.reconnectMaxMs ?? 6e4,
5270
- autoReconnect: cfg.autoReconnect ?? true
5271
- };
5272
- let resolveDone;
5273
- const done = new Promise((r) => {
5274
- resolveDone = r;
5275
- });
5276
- const abort = new AbortController();
5277
- if (signal) {
5278
- if (signal.aborted) abort.abort();
5279
- else signal.addEventListener("abort", () => abort.abort());
5750
+ /**
5751
+ * 删除合同模板(写,仅 DRAFT 状态)。
5752
+ *
5753
+ * 走 compliance 写路径——`Idempotency-Key`、不重试、`401` 不刷新重放。服务端
5754
+ * PUBLISHED / ARCHIVED 状态下会拒绝删除——已发布的模板应改走 `archive`。
5755
+ */
5756
+ deleteContractTemplate(id, opts = {}) {
5757
+ return this.write(
5758
+ "POST",
5759
+ `/compliance/contract-templates/${encodeURIComponent(id)}/delete`,
5760
+ null,
5761
+ writeCtx(opts)
5762
+ );
5280
5763
  }
5281
- const ws = {
5282
- conn: null,
5283
- cfg: filledCfg,
5284
- abort,
5285
- done,
5286
- doneResolve: resolveDone,
5287
- connected: false
5288
- };
5289
- await wsConnectOnce(this, ws);
5290
- this.ws = ws;
5291
- void wsLoop(this, ws);
5292
- };
5293
- Client.prototype.disconnect = async function() {
5294
- const ws = this.ws;
5295
- this.ws = null;
5296
- if (!ws) return;
5297
- ws.abort.abort();
5298
- ws.connected = false;
5299
- if (ws.conn) {
5300
- try {
5301
- ws.conn.close(1e3, "");
5302
- } catch {
5303
- }
5764
+ /** 合同模板详情。 */
5765
+ getContractTemplate(id, signal) {
5766
+ return this.read(
5767
+ "GET",
5768
+ `/compliance/contract-templates/${encodeURIComponent(id)}`,
5769
+ null,
5770
+ signal
5771
+ );
5304
5772
  }
5305
- await Promise.race([
5306
- ws.done,
5307
- new Promise((resolve) => setTimeout(resolve, 5e3))
5308
- ]);
5309
- };
5310
- Client.prototype.isConnected = function() {
5311
- const ws = this.ws;
5312
- if (!ws) return false;
5313
- return ws.connected;
5314
- };
5315
- function wsURL(c) {
5316
- const base = c.apiURL("/ws");
5317
- return base.replace(/^http:\/\//, "ws://").replace(/^https:\/\//, "wss://");
5318
- }
5319
- function getWebSocketCtor() {
5320
- const WSCtor = globalThis.WebSocket;
5321
- if (!WSCtor) {
5322
- throw new Error(
5323
- 'WebSocket not available \u2014 on Node \u226421 set globalThis.WebSocket = require("ws") before connect'
5773
+ /**
5774
+ * 读 — 合同模板分页列表(compliance gateway S5)。
5775
+ *
5776
+ * 走 GET 读路径(允许 401 单次刷新重放)。返回 yudao `PageResult<T>`
5777
+ * (`{ total, list }`)。所有过滤项可选;`createTimeStart` / `createTimeEnd`
5778
+ * 由调用方按 `yyyy-MM-dd HH:mm:ss` 提供,SDK 原样透传。列表项视图
5779
+ * {@link ContractTemplatePageItem} 不含 `fields`——字段叠加只在详情 / 版本
5780
+ * 快照里返回。
5781
+ */
5782
+ listContractTemplates(req = {}, signal) {
5783
+ return this.read(
5784
+ "GET",
5785
+ `/compliance/contract-templates/page${pageQuery(req, ["status", "createTimeStart", "createTimeEnd"])}`,
5786
+ null,
5787
+ signal
5324
5788
  );
5325
5789
  }
5326
- return WSCtor;
5327
- }
5328
- async function wsConnectOnce(c, ws) {
5329
- const token = await c.ensureToken(ws.abort.signal);
5330
- const url = wsURL(c);
5331
- const WSCtor = getWebSocketCtor();
5332
- const u = new URL(url);
5333
- u.searchParams.set("token", token);
5334
- let conn;
5335
- try {
5336
- conn = new WSCtor(u.toString());
5337
- } catch (e) {
5338
- throw new Error(`dial: ${e instanceof Error ? e.message : String(e)}`);
5790
+ /**
5791
+ * 上传合同模板 PDF(写)。
5792
+ *
5793
+ * compliance 写路径——`Idempotency-Key`、不重试、`401` 不刷新重放。请求体
5794
+ * `{ pdfBase64 }`;SDK 不在客户端做 PDF 解析 / 几何校验,原样透传给后端。
5795
+ * 返回上传后的最新模板视图(含 `pdfHash` / `pdfPageCount`)。
5796
+ */
5797
+ uploadContractTemplatePdf(id, req, opts = {}) {
5798
+ return this.write(
5799
+ "POST",
5800
+ `/compliance/contract-templates/${encodeURIComponent(id)}/pdf`,
5801
+ req,
5802
+ writeCtx(opts)
5803
+ );
5339
5804
  }
5340
- await new Promise((resolve, reject) => {
5341
- let opened = false;
5342
- const handshakeTimer = setTimeout(() => {
5343
- if (!opened) {
5344
- try {
5345
- conn.close();
5346
- } catch {
5347
- }
5348
- reject(new Error("dial: handshake timeout"));
5349
- }
5350
- }, 3e4);
5351
- conn.addEventListener("open", () => {
5352
- opened = true;
5353
- });
5354
- conn.addEventListener("error", (e) => {
5355
- clearTimeout(handshakeTimer);
5356
- reject(new Error(`dial: ${e.message ?? "connection error"}`));
5357
- });
5358
- conn.addEventListener("message", (e) => {
5359
- try {
5360
- const msg = e.data;
5361
- const welcome = JSON.parse(msg);
5362
- if (welcome.type !== "welcome") {
5363
- clearTimeout(handshakeTimer);
5364
- try {
5365
- conn.close();
5366
- } catch {
5367
- }
5368
- reject(new Error(`unexpected first message: ${welcome.type}`));
5369
- return;
5370
- }
5371
- clearTimeout(handshakeTimer);
5372
- ws.conn = conn;
5373
- ws.connected = true;
5374
- if (ws.cfg.topics.length > 0) {
5375
- try {
5376
- conn.send(
5377
- JSON.stringify({
5378
- type: "subscribe",
5379
- topics: ws.cfg.topics
5380
- })
5381
- );
5382
- } catch (sendErr) {
5383
- ws.conn = null;
5384
- ws.connected = false;
5385
- try {
5386
- conn.close();
5387
- } catch {
5388
- }
5389
- reject(new Error(`send subscribe: ${sendErr instanceof Error ? sendErr.message : String(sendErr)}`));
5390
- return;
5391
- }
5392
- }
5393
- ws.cfg.onConnect();
5394
- console.log(`[acosmi-sdk] websocket connected, connId=${welcome.connId ?? ""}`);
5395
- resolve();
5396
- } catch (parseErr) {
5397
- clearTimeout(handshakeTimer);
5398
- try {
5399
- conn.close();
5400
- } catch {
5401
- }
5402
- reject(new Error(`parse welcome: ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`));
5403
- }
5404
- }, { once: true });
5405
- });
5406
- }
5407
- async function wsLoop(c, ws) {
5408
- try {
5409
- while (true) {
5410
- await wsReadLoop(ws);
5411
- if (ws.abort.signal.aborted) return;
5412
- if (ws.conn) {
5413
- try {
5414
- ws.conn.close();
5415
- } catch {
5416
- }
5417
- ws.conn = null;
5418
- }
5419
- ws.connected = false;
5420
- if (!ws.cfg.autoReconnect) return;
5421
- let delay = ws.cfg.reconnectMinMs;
5422
- while (true) {
5423
- if (ws.abort.signal.aborted) return;
5424
- await sleepWithSignal2(delay, ws.abort.signal).catch(() => {
5425
- });
5426
- if (ws.abort.signal.aborted) return;
5427
- console.log(`[acosmi-sdk] websocket reconnecting (delay=${delay}ms)...`);
5428
- try {
5429
- await wsConnectOnce(c, ws);
5430
- break;
5431
- } catch (err) {
5432
- console.log(`[acosmi-sdk] websocket reconnect failed: ${err instanceof Error ? err.message : String(err)}`);
5433
- delay = Math.min(delay * 2, ws.cfg.reconnectMaxMs);
5434
- }
5435
- }
5805
+ /**
5806
+ * 发布合同模板(写)。DRAFT PUBLISHED,落版本快照。
5807
+ *
5808
+ * compliance 写路径——`Idempotency-Key`、不重试、`401` 不刷新重放。
5809
+ * publish 后 `currentVersion` 递增,`fields` 与 `pdfHash` 同步固化进版本表。
5810
+ */
5811
+ publishContractTemplate(id, opts = {}) {
5812
+ return this.write(
5813
+ "POST",
5814
+ `/compliance/contract-templates/${encodeURIComponent(id)}/publish`,
5815
+ null,
5816
+ writeCtx(opts)
5817
+ );
5818
+ }
5819
+ /**
5820
+ * 归档合同模板(写)。PUBLISHED → ARCHIVED。
5821
+ *
5822
+ * 走 compliance 写路径——`Idempotency-Key`、不重试、`401` 不刷新重放。
5823
+ * 已归档模板只读,不再允许 publish / 编辑 / 删除。
5824
+ */
5825
+ archiveContractTemplate(id, opts = {}) {
5826
+ return this.write(
5827
+ "POST",
5828
+ `/compliance/contract-templates/${encodeURIComponent(id)}/archive`,
5829
+ null,
5830
+ writeCtx(opts)
5831
+ );
5832
+ }
5833
+ /**
5834
+ * 读 — 合同模板版本快照列表。
5835
+ *
5836
+ * 走 GET 读路径(允许 401 单次刷新重放)。返回 {@link ContractTemplateVersion}
5837
+ * 普通数组(非 `PageResult`)——每次 publish 落一个不可变快照,记录当时的
5838
+ * `name` / `pdfHash` / `fields` / `statusAtSnapshot`,是离线复核 / 版本对账
5839
+ * 的依据。
5840
+ */
5841
+ listContractTemplateVersions(id, signal) {
5842
+ return this.read(
5843
+ "GET",
5844
+ `/compliance/contract-templates/${encodeURIComponent(id)}/versions`,
5845
+ null,
5846
+ signal
5847
+ );
5848
+ }
5849
+ // =========================================================================
5850
+ // Error classification (re-export for convenience)
5851
+ // =========================================================================
5852
+ classifyError(err) {
5853
+ if (!isBusinessErrorLike(err)) return null;
5854
+ if (!isComplianceBusinessError(err)) return null;
5855
+ return classifyComplianceError(err);
5856
+ }
5857
+ // =========================================================================
5858
+ // Internal helpers
5859
+ // =========================================================================
5860
+ /**
5861
+ * 读路径:GET / 公开 verify。允许 401 单次刷新后重放(GET 幂等安全)。
5862
+ * 与 client.doJSONFullInternal 行为一致;不复用其代码因为 base URL 不同。
5863
+ */
5864
+ async read(method, path, body, signal, extraHeaders = {}) {
5865
+ return this.executeJson(method, path, body, signal, {
5866
+ retryOn401: true,
5867
+ extraHeaders
5868
+ });
5869
+ }
5870
+ /**
5871
+ * 公开读路径:public verify。
5872
+ *
5873
+ * {@link read} 的区别 — public 端点不应要求认证:
5874
+ * - token 时匿名请求:ensureToken 抛 `not authorized` 会被吞掉,继续匿名发送。
5875
+ * - 有 token 时附带 `Authorization`,保留后端审计上下文。
5876
+ * - 不做 401 refresh replay:401 直接抛 HTTPError,不触发 `forceRefresh`。
5877
+ *
5878
+ * URL 仍走 `client.complianceURL(path)`,不复用 `/api/v4`;底层复用
5879
+ * `client.doRequest`,不新增 fetch/axios 直连。
5880
+ */
5881
+ async publicRead(method, path, signal) {
5882
+ let token = "";
5883
+ try {
5884
+ token = await this.client.ensureToken(signal);
5885
+ } catch {
5436
5886
  }
5437
- } finally {
5438
- ws.doneResolve();
5887
+ const url = this.client.complianceURL(path);
5888
+ const headers = { Accept: "application/json" };
5889
+ if (token) headers.Authorization = `Bearer ${token}`;
5890
+ const resp = await this.client.doRequest({ method, url, headers }, signal);
5891
+ if (resp.status < 200 || resp.status >= 300) {
5892
+ const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
5893
+ throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
5894
+ }
5895
+ const text = await resp.text();
5896
+ if (!text) return void 0;
5897
+ const parsed = JSON.parse(text);
5898
+ const bizErr = apiResponseBusinessError(parsed);
5899
+ if (bizErr) throw bizErr;
5900
+ return parsed.data;
5439
5901
  }
5440
- }
5441
- async function wsReadLoop(ws) {
5442
- const conn = ws.conn;
5443
- if (!conn) return;
5444
- return new Promise((resolve) => {
5445
- const handleMessage = (e) => {
5446
- try {
5447
- const data = e.data;
5448
- const event = JSON.parse(data);
5449
- try {
5450
- ws.cfg.onEvent(event);
5451
- } catch {
5452
- }
5453
- } catch {
5454
- }
5902
+ /**
5903
+ * 写路径:POST。
5904
+ * - 发送前 ensureToken 一次确保 token fresh。
5905
+ * - 不自动 401 重放:401 → 抛 HTTPError;调用方必须自己刷新 token 后用同一
5906
+ * idempotency-key 重新发起,避免 provider 侧重复请求。
5907
+ * - 不走 doRequestWithRetry:写操作不允许 5xx/timeout 自动重试。
5908
+ */
5909
+ async write(method, path, body, ctx) {
5910
+ const headers = { ...ctx.extraHeaders ?? {} };
5911
+ if (ctx.idempotencyKey) headers["Idempotency-Key"] = ctx.idempotencyKey;
5912
+ return this.executeJson(method, path, body, ctx.signal, {
5913
+ retryOn401: false,
5914
+ extraHeaders: headers
5915
+ });
5916
+ }
5917
+ async executeJson(method, path, body, signal, opts, retried = false) {
5918
+ const token = await this.client.ensureToken(signal);
5919
+ const url = this.client.complianceURL(path);
5920
+ const headers = {
5921
+ Authorization: `Bearer ${token}`,
5922
+ Accept: "application/json",
5923
+ ...opts.extraHeaders
5455
5924
  };
5456
- const handleClose = (e) => {
5457
- conn.removeEventListener("message", handleMessage);
5458
- conn.removeEventListener("close", handleClose);
5459
- conn.removeEventListener("error", handleError);
5925
+ let bodyStr;
5926
+ if (body != null) {
5927
+ bodyStr = typeof body === "string" ? body : JSON.stringify(body);
5928
+ headers["Content-Type"] = "application/json";
5929
+ }
5930
+ const resp = await this.client.doRequest({ method, url, headers, body: bodyStr }, signal);
5931
+ if (resp.status === 401 && opts.retryOn401 && !retried) {
5460
5932
  try {
5461
- ws.cfg.onDisconnect(new Error(`closed: code=${e.code} reason=${e.reason}`));
5933
+ await resp.body?.cancel();
5462
5934
  } catch {
5463
5935
  }
5464
- resolve();
5936
+ await this.client.forceRefresh(signal);
5937
+ return this.executeJson(method, path, body, signal, opts, true);
5938
+ }
5939
+ if (resp.status < 200 || resp.status >= 300) {
5940
+ const bodyBytes = resp.body ? await readLimited(resp.body, maxErrorBodySize) : new Uint8Array();
5941
+ throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
5942
+ }
5943
+ const text = await resp.text();
5944
+ if (!text) return void 0;
5945
+ const parsed = JSON.parse(text);
5946
+ const bizErr = apiResponseBusinessError(parsed);
5947
+ if (bizErr) throw bizErr;
5948
+ return parsed.data;
5949
+ }
5950
+ async poll(fetcher, classify, opts) {
5951
+ const cfg = {
5952
+ timeoutMs: opts.timeoutMs ?? DEFAULT_POLL.timeoutMs,
5953
+ initialIntervalMs: opts.initialIntervalMs ?? DEFAULT_POLL.initialIntervalMs,
5954
+ maxIntervalMs: opts.maxIntervalMs ?? DEFAULT_POLL.maxIntervalMs,
5955
+ multiplier: opts.multiplier ?? DEFAULT_POLL.multiplier
5465
5956
  };
5466
- const handleError = (e) => {
5467
- conn.removeEventListener("message", handleMessage);
5468
- conn.removeEventListener("close", handleClose);
5469
- conn.removeEventListener("error", handleError);
5470
- try {
5471
- ws.cfg.onDisconnect(e);
5472
- } catch {
5957
+ const deadline = Date.now() + cfg.timeoutMs;
5958
+ let interval = cfg.initialIntervalMs;
5959
+ let lastValue;
5960
+ while (Date.now() < deadline) {
5961
+ if (opts.signal?.aborted) {
5962
+ throw new CompliancePollError("compliance poll aborted", "unknown");
5473
5963
  }
5474
- resolve();
5475
- };
5476
- conn.addEventListener("message", handleMessage);
5477
- conn.addEventListener("close", handleClose);
5478
- conn.addEventListener("error", handleError);
5479
- if (ws.abort.signal.aborted) {
5480
- try {
5481
- conn.close();
5482
- } catch {
5964
+ lastValue = await fetcher();
5965
+ const decision = classify(lastValue);
5966
+ if (decision === "done") return lastValue;
5967
+ if (decision === "failed") {
5968
+ throw new CompliancePollError(
5969
+ "compliance poll observed terminal failure",
5970
+ "terminal_failure"
5971
+ );
5483
5972
  }
5484
- } else {
5485
- ws.abort.signal.addEventListener(
5486
- "abort",
5487
- () => {
5488
- try {
5489
- conn.close();
5490
- } catch {
5491
- }
5492
- },
5493
- { once: true }
5494
- );
5973
+ const sleepMs = Math.min(interval, deadline - Date.now());
5974
+ if (sleepMs <= 0) break;
5975
+ await sleep2(sleepMs, opts.signal);
5976
+ interval = Math.min(Math.floor(interval * cfg.multiplier), cfg.maxIntervalMs);
5495
5977
  }
5496
- });
5978
+ throw new CompliancePollError("compliance poll timed out", "timeout");
5979
+ }
5980
+ };
5981
+ function classifyTimestamp(status) {
5982
+ switch (status) {
5983
+ case "VERIFIED":
5984
+ return "done";
5985
+ case "FAILED":
5986
+ case "LOCAL_VERIFY_FAILED":
5987
+ return "failed";
5988
+ case "PENDING":
5989
+ case "UNKNOWN":
5990
+ case "RETRYING":
5991
+ default:
5992
+ return "continue";
5993
+ }
5497
5994
  }
5498
- async function sleepWithSignal2(ms, signal) {
5499
- if (ms <= 0) return;
5500
- if (signal.aborted) throw new Error("aborted");
5995
+ function classifyProviderStatus(status) {
5996
+ switch (status) {
5997
+ case "SUCCESS":
5998
+ return "done";
5999
+ case "FAILED":
6000
+ return "failed";
6001
+ case "PENDING":
6002
+ case "UNKNOWN":
6003
+ case "RETRYING":
6004
+ default:
6005
+ return "continue";
6006
+ }
6007
+ }
6008
+ function pageQuery(req, filterKeys) {
6009
+ const q = new URLSearchParams();
6010
+ const append = (key, value) => {
6011
+ if (value == null) return;
6012
+ const s = typeof value === "string" ? value : String(value);
6013
+ if (s === "") return;
6014
+ q.set(key, s);
6015
+ };
6016
+ append("pageNo", req.pageNo);
6017
+ append("pageSize", req.pageSize);
6018
+ append("sortBy", req.sortBy);
6019
+ append("sortDirection", req.sortDirection);
6020
+ for (const key of filterKeys) {
6021
+ append(String(key), req[key]);
6022
+ }
6023
+ const qs = q.toString();
6024
+ return qs ? "?" + qs : "";
6025
+ }
6026
+ function writeCtx(opts, extraHeaders = {}) {
6027
+ return {
6028
+ idempotencyKey: opts.idempotencyKey,
6029
+ signal: opts.signal,
6030
+ extraHeaders
6031
+ };
6032
+ }
6033
+ function isBusinessErrorLike(err) {
6034
+ if (err == null || typeof err !== "object") return false;
6035
+ return typeof err.code === "number";
6036
+ }
6037
+ function sleep2(ms, signal) {
5501
6038
  return new Promise((resolve, reject) => {
5502
- const t = setTimeout(() => {
5503
- signal.removeEventListener("abort", abortHandler);
6039
+ if (signal?.aborted) {
6040
+ reject(new CompliancePollError("compliance poll aborted", "unknown"));
6041
+ return;
6042
+ }
6043
+ const timer = setTimeout(() => {
6044
+ signal?.removeEventListener("abort", onAbort);
5504
6045
  resolve();
5505
6046
  }, ms);
5506
- const abortHandler = () => {
5507
- clearTimeout(t);
5508
- signal.removeEventListener("abort", abortHandler);
5509
- reject(new Error("aborted"));
6047
+ const onAbort = () => {
6048
+ clearTimeout(timer);
6049
+ signal?.removeEventListener("abort", onAbort);
6050
+ reject(new CompliancePollError("compliance poll aborted", "unknown"));
5510
6051
  };
5511
- signal.addEventListener("abort", abortHandler);
6052
+ signal?.addEventListener("abort", onAbort, { once: true });
5512
6053
  });
5513
6054
  }
5514
6055
 
5515
- // src/bug-report.ts
6056
+ // src/support/bug-report.ts
5516
6057
  Client.prototype.submitBugReport = async function(reportData, signal) {
5517
6058
  if (reportData == null) {
5518
6059
  throw new Error("acosmi: reportData required");
@@ -5545,6 +6086,6 @@ Client.prototype.getBugReport = async function(bugID, signal) {
5545
6086
  return resp.data;
5546
6087
  };
5547
6088
 
5548
- 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 };
6089
+ 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, IdempotencyKeyHeader, InMemoryTokenStore, LocalStorageTokenStore, ModelNotFoundError, NetworkError, OpenAIAdapter, OrderTerminalError, ProviderFormat, RETRY_ADVICE_REASONS, RateLimitError, ScopeAI, ScopeAccount, ScopeComplianceContractSigningRead, ScopeComplianceContractSigningWrite, ScopeComplianceContractTemplateRead, ScopeComplianceContractTemplateWrite, 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, complianceErrorToRetryAdvice, 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, retryReasonForComplianceKey, retryReasonForOAuthError, revokeToken, sanitize_exports as sanitize, skillScopes, tokenSetIsExpired, uniqueMerge };
5549
6090
  //# sourceMappingURL=index.mjs.map
5550
6091
  //# sourceMappingURL=index.mjs.map