@acosmi/sdk-ts 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,12 @@ All notable changes to `@acosmi/sdk-ts` will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.0.1] - 2026-05-25 — Packaging fix
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- `package.json` `files` 字段白名单遗漏 — v2.0.0 publish 后发现 `docs/pii-role-matrix.md` (新建) 与 `docs/开发与发布手册.md` (修订) 未进 npm 包. 集成方 `npm install @acosmi/sdk-ts` 后 `node_modules/@acosmi/sdk-ts/docs/` 缺这两份关键文档. 修白名单加显式三份 `docs/*.md` (排除 `docs/api/` 1.7MB TypeDoc 输出避免包膨胀).
|
|
13
|
+
|
|
8
14
|
## [2.0.0] - 2026-05-25 — BREAKING (Phase 3 复核 + 全量根治)
|
|
9
15
|
|
|
10
16
|
商品化 P1-P7 Phase 3 深度复核审计 (主仓 9 commit, HEAD `e510f68a`) + SDK 全量同步.
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# PII 角色可见性矩阵 (v1.9.0+)
|
|
2
|
+
|
|
3
|
+
> 适用版本: `@acosmi/sdk-ts` v1.9.0+
|
|
4
|
+
> 对应主仓: K10a PII Aspect (`@FieldEncrypt` / `@Sensitive` 切面) + IMPL-A 角色严格化
|
|
5
|
+
> 最后更新: 2026-05-25
|
|
6
|
+
|
|
7
|
+
## 1. 背景
|
|
8
|
+
|
|
9
|
+
商品化 P1-P7 Phase 3 收口时, 主仓 (tk-dist Java) 完成两条根因修复并随 SDK v1.9.0
|
|
10
|
+
发布:
|
|
11
|
+
|
|
12
|
+
- **K10a PII Aspect**: `dist_invoice` / `dist_corporate_transfer` / `dist_refund_record`
|
|
13
|
+
等 finance 表族 + `dist_lawyer_profile` 法律表族 + `dist_enterprise_*` 企业席位表族
|
|
14
|
+
敏感列改走 `@FieldEncrypt` 切面真加密落盘. V63 列宽 VARCHAR→TEXT 兜密文; V64 backfill
|
|
15
|
+
老明文 → v2 payload.
|
|
16
|
+
|
|
17
|
+
- **IMPL-A 角色严格化** (`SensitiveSerializer.normalizeAuthority`): yudao 通用
|
|
18
|
+
`ROLE_ADMIN` / `ROLE_USER` / `INTERNAL` 三个老别名 fail-OPEN 升级为 platform_admin
|
|
19
|
+
视角的隐患已根治. 调用方传 token 必须真有正式角色, 否则视同 guest.
|
|
20
|
+
|
|
21
|
+
SDK 边界: 类型注释只描述 PII 级别, 不内置脱敏逻辑 — 真实脱敏由后端 `PiiDesensitizer`
|
|
22
|
+
按角色返回不同字符串 (明文 / `***1234` / 全 `***`). SDK 调用方 (Web / Desktop / CLI)
|
|
23
|
+
需理解角色矩阵以正确渲染.
|
|
24
|
+
|
|
25
|
+
## 2. 4 角色枚举
|
|
26
|
+
|
|
27
|
+
来源: `SensitiveSerializer.normalizeAuthority` (主仓
|
|
28
|
+
`yudao-module-distribution/...impl/serializer/SensitiveSerializer.java`).
|
|
29
|
+
|
|
30
|
+
| 角色常量 | 含义 | 典型颁发方 |
|
|
31
|
+
| --- | --- | --- |
|
|
32
|
+
| `ROLE_PLATFORM_ADMIN` | 平台管理员 (跨租户) — 后台运营 / 客服 / 财务工作台 | 主仓 yudao admin 登录 + claim platform_admin |
|
|
33
|
+
| `ROLE_S2S` | 服务对服务调用 — Nexus Go 网关 / 微服务内部互调 | S2S Token (X-Service-Secret) |
|
|
34
|
+
| `ROLE_LAWYER` | 律师 — 仅查看自己执业资料 + 自己接单的案件 | C 端登录 + 律师资质审核通过 |
|
|
35
|
+
| `ROLE_CONSUMER` | 消费者 — 普通 C 端用户, 仅查看自己的数据 | C 端 OAuth (`/api/consumer/**`) |
|
|
36
|
+
| (guest / unknown) | 匿名 / 未登录 / 角色不匹配 | 无 token / Bearer 无效 / 角色字符串非上述 4 个 |
|
|
37
|
+
|
|
38
|
+
## 3. PII 级 × 角色矩阵
|
|
39
|
+
|
|
40
|
+
PII 分 3 级 (与 `@Sensitive(level=...)` 严格对齐):
|
|
41
|
+
|
|
42
|
+
- **L1 公开** — 任何场景明文 (id / orderId / amountFen / status / createdAt 等)
|
|
43
|
+
- **L2 半遮** — 部分场景半遮 (title / contactAddress / nickname / avatarUrl 等)
|
|
44
|
+
- **L3 仅 admin** — 强敏感字段, 默认全脱敏 (taxId / bankAccount / contactPhone /
|
|
45
|
+
bankName / licenseNo / idCardNo 等)
|
|
46
|
+
|
|
47
|
+
| 角色 | L1 公开 | L2 半遮 | L3 仅 admin |
|
|
48
|
+
| --- | --- | --- | --- |
|
|
49
|
+
| `ROLE_PLATFORM_ADMIN` | 明文 | 明文 | 明文 |
|
|
50
|
+
| `ROLE_S2S` | 明文 | 明文 | 明文 |
|
|
51
|
+
| `ROLE_LAWYER` | 明文 | 明文 | 脱敏 (`***1234`) |
|
|
52
|
+
| `ROLE_CONSUMER` | 明文 | 明文 | 脱敏 (`***1234`) |
|
|
53
|
+
| (guest / unknown) | 明文 | 脱敏 | 脱敏 |
|
|
54
|
+
|
|
55
|
+
> **Note**: `ROLE_LAWYER` / `ROLE_CONSUMER` 自己的数据 L3 字段仍可通过专门的 admin 直读
|
|
56
|
+
> 端点 (`/api/distribution/**/me/decrypted`) 解密, 但默认 listMyXxx 端点走脱敏视图.
|
|
57
|
+
> SDK 类型上不强制 — 调用方按上下文判定.
|
|
58
|
+
|
|
59
|
+
## 4. Breaking Change — v1.9.0+ 旧别名失效
|
|
60
|
+
|
|
61
|
+
主仓 IMPL-A 角色严格化把以下 3 条 fail-OPEN 别名根治:
|
|
62
|
+
|
|
63
|
+
| 旧别名 (≤ v1.8.x) | 误升级到 (旧行为) | v1.9.0+ 处理 |
|
|
64
|
+
| --- | --- | --- |
|
|
65
|
+
| `ROLE_ADMIN` | `platform_admin` (L3 明文) | 视同 `guest` (L2/L3 全脱敏) |
|
|
66
|
+
| `ROLE_USER` | `consumer` (L1/L2 明文) | 视同 `guest` (L2/L3 全脱敏) |
|
|
67
|
+
| `INTERNAL` | `s2s` (L3 明文) | 视同 `guest` (L2/L3 全脱敏) |
|
|
68
|
+
|
|
69
|
+
### 集成方应对
|
|
70
|
+
|
|
71
|
+
1. **token 升级到正式角色**: yudao admin 后台 token 改派发 `ROLE_PLATFORM_ADMIN`;
|
|
72
|
+
微服务 S2S 调用切到 `ROLE_S2S` claim; C 端 OAuth 已自动派发 `ROLE_CONSUMER`.
|
|
73
|
+
2. **fallback 走 guest 视角**: 升级期 (灰度) 旧 token 调用 `/api/distribution/admin/**`
|
|
74
|
+
会拿到脱敏数据 — 这是设计内行为, 不是 bug.
|
|
75
|
+
3. **角色字符串大小写敏感**: 必须全大写 `ROLE_PLATFORM_ADMIN`, 小写 / 缺前缀的
|
|
76
|
+
`platform_admin` 会被 `normalizeAuthority` 拒绝.
|
|
77
|
+
|
|
78
|
+
## 5. 实际生效字段示例
|
|
79
|
+
|
|
80
|
+
按 v1.9.0 SDK 主要类型清单 (与主仓 `@Sensitive` 注解严格对齐):
|
|
81
|
+
|
|
82
|
+
### finance namespace (`src/finance/types.ts`)
|
|
83
|
+
|
|
84
|
+
| 字段 | 级别 | 角色匹配后明文示例 | guest 视图 |
|
|
85
|
+
| --- | --- | --- | --- |
|
|
86
|
+
| `Invoice.id / invoiceNo / orderId / amountFen / status` | L1 | `INV20260525001` | 同 |
|
|
87
|
+
| `Invoice.title` | L2 | `Acosmi Tech Ltd` | `Acos*****td` |
|
|
88
|
+
| `Invoice.contactAddress` | L2 | `北京市朝阳区...` | `北京市*****` |
|
|
89
|
+
| `Invoice.taxId` | L3 | `91110108MA01ABC123` | `91**********23` |
|
|
90
|
+
| `Invoice.bankAccount` | L3 | `6225882104567890` | `6225********7890` |
|
|
91
|
+
| `Invoice.bankName` | L3 | `招商银行北京分行` | `招商***` |
|
|
92
|
+
| `Invoice.contactPhone` | L3 | `13800001234` | `138****1234` |
|
|
93
|
+
|
|
94
|
+
### enterprise namespace (`src/enterprise/types.ts`)
|
|
95
|
+
|
|
96
|
+
| 字段 | 级别 |
|
|
97
|
+
| --- | --- |
|
|
98
|
+
| `EnterpriseSummary.contactPhone` | L3 (仅 OWNER/ADMIN 可见) |
|
|
99
|
+
| `EnterpriseSummary.contactEmail` | L3 |
|
|
100
|
+
| `EnterpriseSummary.creditCode` | L2 |
|
|
101
|
+
|
|
102
|
+
### casehall namespace (`src/casehall/types.ts`)
|
|
103
|
+
|
|
104
|
+
| 字段 | 级别 |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| `LawyerSummary.licenseNo` | L3 (公开 listLawyers 已脱敏剥离, 仅 admin 直读) |
|
|
107
|
+
| `LawyerSummary.idCardNo` | L3 |
|
|
108
|
+
| `LawyerSummary.realName` | L2 |
|
|
109
|
+
| `CaseLead.disputeAmountFen` | L1 |
|
|
110
|
+
| `CaseLead.contactPhone` | L3 |
|
|
111
|
+
|
|
112
|
+
## 6. 脱敏算法引用
|
|
113
|
+
|
|
114
|
+
后端 `PiiDesensitizer` (主仓 `yudao-module-distribution/...PiiDesensitizer.java`) 按字段
|
|
115
|
+
类型自动派生脱敏策略:
|
|
116
|
+
|
|
117
|
+
| 策略 | 输入 | 输出 |
|
|
118
|
+
| --- | --- | --- |
|
|
119
|
+
| `PHONE` | `13800001234` | `138****1234` |
|
|
120
|
+
| `EMAIL` | `user@acosmi.com` | `u***@acosmi.com` |
|
|
121
|
+
| `ID_CARD` | `110101199001011234` | `1101**********1234` |
|
|
122
|
+
| `BANK_CARD` | `6225882104567890` | `6225********7890` |
|
|
123
|
+
| `NAME` | `张三丰` | `张*丰` |
|
|
124
|
+
| `ADDRESS` | `北京市朝阳区...` | `北京市*****` |
|
|
125
|
+
| `GENERIC` | 任意其他 L2/L3 字符串 | `XX*****XX` (前后 2 字符+中间星号) |
|
|
126
|
+
|
|
127
|
+
`@Sensitive(strategy=...)` 显式指定策略时优先; 否则按字段名启发 (字段名含 phone/mobile
|
|
128
|
+
→ PHONE, 含 email → EMAIL, 等).
|
|
129
|
+
|
|
130
|
+
## 7. 测试集成方应做的 mock
|
|
131
|
+
|
|
132
|
+
集成方 (Web / Desktop / 微服务) 在单测中应 mock 不同角色 token 切换, 验证渲染层正确处理:
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
// vitest 示例 — Web 端验证 admin 视图 vs guest 视图字段差异
|
|
136
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
137
|
+
import { Client } from '@acosmi/sdk-ts';
|
|
138
|
+
|
|
139
|
+
describe('Invoice rendering across roles', () => {
|
|
140
|
+
it('platform_admin sees L3 plain', async () => {
|
|
141
|
+
// mock token 含 ROLE_PLATFORM_ADMIN claim
|
|
142
|
+
const client = new Client({ serverURL, token: mintToken({ role: 'ROLE_PLATFORM_ADMIN' }) });
|
|
143
|
+
const list = await client.listMyInvoices();
|
|
144
|
+
expect(list[0].bankAccount).toMatch(/^\d{16}$/); // 明文
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('consumer sees L3 desensitized', async () => {
|
|
148
|
+
const client = new Client({ serverURL, token: mintToken({ role: 'ROLE_CONSUMER' }) });
|
|
149
|
+
const list = await client.listMyInvoices();
|
|
150
|
+
expect(list[0].bankAccount).toMatch(/^\d{4}\*+\d{4}$/); // 6225********7890
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('guest (no token) sees L2/L3 desensitized', async () => {
|
|
154
|
+
const client = new Client({ serverURL });
|
|
155
|
+
// (公开列表端点, 无登录)
|
|
156
|
+
const lawyers = await client.listLawyers();
|
|
157
|
+
expect(lawyers.items[0].licenseNo).toBeUndefined(); // L3 直接剥字段
|
|
158
|
+
expect(lawyers.items[0].realName).toMatch(/\*/); // L2 半遮
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('ROLE_ADMIN (legacy alias) is treated as guest in v1.9.0+', async () => {
|
|
162
|
+
// 旧 yudao admin token, role=ROLE_ADMIN (无 platform_admin)
|
|
163
|
+
const client = new Client({ serverURL, token: mintToken({ role: 'ROLE_ADMIN' }) });
|
|
164
|
+
const list = await client.listMyInvoices();
|
|
165
|
+
expect(list[0].bankAccount).toMatch(/\*/); // 视同 guest, L3 脱敏
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## 8. 参考链接
|
|
171
|
+
|
|
172
|
+
- 主仓 PII Aspect: `yudao-module-distribution/...impl/aspect/PiiEncryptAspect.java`
|
|
173
|
+
- 主仓角色规范化: `yudao-module-distribution/...impl/serializer/SensitiveSerializer.java`
|
|
174
|
+
- 主仓脱敏算法: `yudao-module-distribution/...impl/serializer/PiiDesensitizer.java`
|
|
175
|
+
- 主仓迁移 V51 (finance 表族加密): `nexus-v4/sql/yudao-server-v51-pii-encrypt-init.sql`
|
|
176
|
+
- 主仓迁移 V63 (列宽兜底): `nexus-v4/sql/yudao-server-v63-pii-column-text.sql`
|
|
177
|
+
- 主仓迁移 V64 (backfill): `nexus-v4/sql/yudao-server-v64-pii-backfill-v2.sql`
|
|
178
|
+
- SDK 类型注释: `src/finance/types.ts` `Invoice` JSDoc
|
package/docs//345/274/200/345/217/221/344/270/216/345/217/221/345/270/203/346/211/213/345/206/214.md
ADDED
|
@@ -0,0 +1,736 @@
|
|
|
1
|
+
# @acosmi/sdk-ts 开发与发布手册
|
|
2
|
+
|
|
3
|
+
> 适用版本: v1.0.0+
|
|
4
|
+
> 最后更新: 2026-05-25
|
|
5
|
+
|
|
6
|
+
## 1. 项目概览
|
|
7
|
+
|
|
8
|
+
`@acosmi/sdk-ts` 是 Acosmi 模型网关、SDK-facing Agent Run Gateway 与 compliance API 的 TypeScript SDK。**自 2026-05-22 起 TS SDK 成为主实现 / 事实标准**:Go SDK `acosmi-sdk-go` 暂停维护,本仓专注把 TS 做好做稳;待 TS 稳定后再从 TS 反向翻译补齐 Go。早期版本由 Go 端口而来,但布局与演进已不再受 Go 约束。
|
|
9
|
+
|
|
10
|
+
| 项目 | 值 |
|
|
11
|
+
| -------- | -- |
|
|
12
|
+
| 实现地位 | **主实现 / 事实标准**;Go SDK 暂停维护,后续从 TS 反向翻译 |
|
|
13
|
+
| 当前版本 | 1.9.0(商品化 P1-P7 namespace 全量:subscription / pricing / products / csign 合规 SKU / casehall / enterprise / finance) |
|
|
14
|
+
| 版本策略 | TS 独立演进;wire-format / API 不兼容变更升 major |
|
|
15
|
+
| 主消费者 | `crabcode` (Anthropic 格式)、`crabdesign` / `crabclaw` 等下游产品 |
|
|
16
|
+
| 长期保留 | `OpenAIAdapter` (P0 红线,`crabclaw` 暂不用 TS 但保留双格式等地位) |
|
|
17
|
+
| LICENSE | MIT — Copyright (c) 2026 Acosmi |
|
|
18
|
+
|
|
19
|
+
## 2. 仓库与发布拓扑
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
SDK 独立仓 (public) npm 公开包
|
|
23
|
+
/Users/fushihua/Desktop/Acosmi/acosmi-sdk-ts → npmjs.com/@acosmi/sdk-ts
|
|
24
|
+
└── github.com/acosmi/sdk-ts └── tag v* 触发 release workflow
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**铁律**:
|
|
28
|
+
- SDK 是独立发布物,提交与 tag 只在 `acosmi-sdk-ts` 仓库内完成。
|
|
29
|
+
- 不把外层 monorepo 的 Java / Go / CFCA real provider 改动带入 SDK commit。
|
|
30
|
+
- 公开仓 history 和提交信息必须保持产品/SDK 语义,不包含协作工具或开发过程元数据。
|
|
31
|
+
- `docs/` 可放公开用户文档;内部 audit、证书材料、provider runbook 不进公开仓。
|
|
32
|
+
|
|
33
|
+
## 3. 开发环境
|
|
34
|
+
|
|
35
|
+
- Node.js **≥18**(package.json `engines.node` 公开承诺,不动);推荐本地 24 Active LTS;CI 用 24(含 JS-actions runtime, `FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true`)
|
|
36
|
+
- npm ≥8
|
|
37
|
+
- 推荐 IDE:VSCode + ESLint + Prettier 扩展
|
|
38
|
+
|
|
39
|
+
## 4. 目录结构
|
|
40
|
+
|
|
41
|
+
`src/` 按**业务域文件夹**组织:每个域一个文件夹 + 一个 `index.ts` barrel,`core/`
|
|
42
|
+
收口运行时基座,`shared/` 收口跨域基础设施。根 `src/index.ts` 只从各域 barrel
|
|
43
|
+
re-export。新增业务域时落对应文件夹,规则唯一明确。
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
acosmi-sdk-ts/
|
|
47
|
+
├── src/ # 源码(按域文件夹组织)
|
|
48
|
+
│ ├── index.ts # 公共入口 barrel(从各域 re-export)
|
|
49
|
+
│ ├── browser.ts # 浏览器构建入口
|
|
50
|
+
│ ├── core/ # 运行时基座,无业务域
|
|
51
|
+
│ │ ├── client.ts # 主 Client class
|
|
52
|
+
│ │ ├── store.ts # FileTokenStore + LocalStorageTokenStore + InMemoryTokenStore
|
|
53
|
+
│ │ ├── retry.ts # 重试策略
|
|
54
|
+
│ │ ├── http.ts # HTTP / SSE helper
|
|
55
|
+
│ │ └── sanitize-bridge.ts # Client × sanitize 胶水 (declaration merging)
|
|
56
|
+
│ ├── shared/ # 跨域基础设施 + 跨域共享 DTO(v1.5.0)
|
|
57
|
+
│ │ ├── api-response.ts # APIResponse / YudaoPageResult
|
|
58
|
+
│ │ ├── errors.ts # HTTPError / NetworkError / StreamError / BusinessError / ...
|
|
59
|
+
│ │ ├── pagination.ts # PageRequest / PageResult(= YudaoPageResult 别名)/ SortDirection
|
|
60
|
+
│ │ ├── operation.ts # OperationId / Source / Status / VerifyStatus / IdempotencyKey(Header)
|
|
61
|
+
│ │ ├── retry-advice.ts # RetryAdvice + reason 映射(叠加层,不替换 RetryPolicy)
|
|
62
|
+
│ │ ├── principal.ts # PrincipalRef / TenantRef / ApiClientRef 轻量引用
|
|
63
|
+
│ │ └── gate.ts # FeatureGateStatus / StepUpStatus / BillingPreflightResult
|
|
64
|
+
│ ├── auth/ # 鉴权 / 身份域
|
|
65
|
+
│ │ ├── auth.ts # OAuth 2.1 PKCE / 动态注册 / token refresh / revoke
|
|
66
|
+
│ │ ├── scopes.ts # 分组 scope
|
|
67
|
+
│ │ └── types.ts # ServerMetadata / TokenResponse / TokenSet / ClientRegistration
|
|
68
|
+
│ ├── models/ # 模型网关域
|
|
69
|
+
│ │ ├── types.ts # ManagedModel / Chat* / StreamEvent / ...
|
|
70
|
+
│ │ ├── wire-anthropic.ts wire-openai.ts # 两套 wire-format DTO
|
|
71
|
+
│ │ ├── adapters/ # AnthropicAdapter + OpenAIAdapter (P0 双格式红线)
|
|
72
|
+
│ │ └── model-helpers.ts stream-meta.ts betas.ts
|
|
73
|
+
│ ├── billing/ # 计费域(entitlements / packages / wallet)
|
|
74
|
+
│ ├── casehall/ # 法律案件咨询(v1.8.0)— 律师公开视图 / 案件线索 / 咨询 / 5 SKU
|
|
75
|
+
│ ├── certification/ # 预留 — 实名 / 人脸 / 活体 / 企业认证 / CA
|
|
76
|
+
│ ├── compliance/ # 合规域(重点扩张:evidence / timestamp / signing / ...)
|
|
77
|
+
│ ├── enterprise/ # 企业席位(v1.8.1)— 企业组织 / 成员 / 订阅 / 席位 / 用量
|
|
78
|
+
│ ├── finance/ # 财务域(v1.9.0)— 发票 / 退款 / 对公转账(决策 14/15 + R12)
|
|
79
|
+
│ ├── notifications/ # 通知 / 推送 / WebSocket
|
|
80
|
+
│ ├── agent-runs/ # SDK-facing Agent Run Gateway(client + 公开协议类型)
|
|
81
|
+
│ ├── pricing/ # 公开业务参数(v1.7.0)+ csign 合规 SKU 报价(v1.7.0)
|
|
82
|
+
│ ├── products/ # 商品中心(v1.7.0)— productFamily / audience / billingMode 索引
|
|
83
|
+
│ ├── sanitize/ # 历史消息清理子包
|
|
84
|
+
│ ├── skills/ # 技能商店 + 工具列表
|
|
85
|
+
│ ├── subscription/ # 订阅档位(v1.7.0)— SubscriptionPlan / UserSubscription
|
|
86
|
+
│ ├── support/ # bug-report 等
|
|
87
|
+
│ └── apiClients/ tenant/ iam/ audit/ operations/ mcp/ gateway/
|
|
88
|
+
│ # 全域命名空间预留骨架(能力见对外鉴权层独立计划)
|
|
89
|
+
├── test/ # vitest 单元测试
|
|
90
|
+
├── examples/ # npm 包随附示例
|
|
91
|
+
│ ├── core-chat.ts
|
|
92
|
+
│ ├── auth-oauth-flow.ts
|
|
93
|
+
│ ├── agent-runs-stream.ts
|
|
94
|
+
│ ├── compliance-read.ts
|
|
95
|
+
│ ├── compliance-evidence-timestamp.ts
|
|
96
|
+
│ └── compliance-envelope.ts
|
|
97
|
+
├── docs/
|
|
98
|
+
│ ├── compliance.md # npm 包随附 compliance API 指南
|
|
99
|
+
│ ├── api/ # TypeDoc 生成的 API 参考(npm run docs)
|
|
100
|
+
│ └── 开发与发布手册.md # 仓库维护手册,不随 npm 包发布
|
|
101
|
+
├── dist/ # 构建产物 (gitignored, CI 编译)
|
|
102
|
+
├── package.json
|
|
103
|
+
├── tsup.config.ts # 多端构建
|
|
104
|
+
├── tsconfig.json
|
|
105
|
+
├── typedoc.json # TypeDoc API 参考文档配置
|
|
106
|
+
├── .eslintrc.json
|
|
107
|
+
├── .npmignore # 排除 src/test/configs/.github
|
|
108
|
+
├── README.md # 用户文档(API 总览 + 示例)
|
|
109
|
+
├── LICENSE # MIT
|
|
110
|
+
└── .github/workflows/
|
|
111
|
+
└── release.yml # push tag v* → npm publish + GitHub Release
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
> 重组为**非破坏性**:对外导出符号、`package.json` 的 `exports`、`dist/` 产物路径
|
|
115
|
+
> 全部不变;下游 `crabcode` / `crabclaw` / `csign` 零感知。`node.ts` 因是未接线的
|
|
116
|
+
> 死入口(无 `./node` 子路径导出、非任何 build entry)已删除。
|
|
117
|
+
|
|
118
|
+
## 5. 编码规范
|
|
119
|
+
|
|
120
|
+
### TypeScript 风格(硬规则)
|
|
121
|
+
|
|
122
|
+
| 类别 | 规则 | 例 |
|
|
123
|
+
|------|------|----|
|
|
124
|
+
| 函数/方法 | **camelCase** | `discover`, `getAdapterForModel` |
|
|
125
|
+
| 类 / 接口 / 类型 | **PascalCase** | `Client`, `ServerMetadata`, `AnthropicAdapter` |
|
|
126
|
+
| Error 子类 | **PascalCase + Error 后缀** | `HTTPError`, `BusinessError`, `OrderTerminalError` |
|
|
127
|
+
| 常量 | **PascalCase**(前缀型)或 **UPPER_CASE** | `ErrDiscovery`, `ScopeAI`, `EventComplete` |
|
|
128
|
+
| 文件名 | **kebab-case** | `stream-meta.ts`, `bug-report.ts` |
|
|
129
|
+
| Wire-format 字段 | **snake_case**(与 Go json tag 严格对齐) | `preferred_format`, `created_at`, `max_tokens` |
|
|
130
|
+
|
|
131
|
+
### 不要使用的 Go-isms(硬禁止)
|
|
132
|
+
|
|
133
|
+
- ❌ **PascalCase 函数** — TS 公开 API 必须 camelCase(`AllScopes()` 是 Go 风格,改 `allScopes()`)
|
|
134
|
+
- ❌ **多返回值 `[T, Error]` 元组** — 用 `throw` + 类型化 Error 子类
|
|
135
|
+
- ❌ **`nil` 字面量** — 用 `null` / `undefined`
|
|
136
|
+
- ❌ **`: any`** — 优先 `: unknown` 或精确类型
|
|
137
|
+
- ❌ **Go 关键字识别符**:`func`, `package`, `chan`, `defer`, `goroutine`
|
|
138
|
+
- ❌ **指针风格 `T | null`** — 用 optional `?: T`(除非 wire-format 必须)
|
|
139
|
+
- ❌ **`fmt.Sprintf` / `fmt.Errorf` / `log.Println`** — 用模板字符串 / `new Error()` / `console`
|
|
140
|
+
|
|
141
|
+
### 跨语言契约印记(TS→Go 反向翻译对照基准,不许改)
|
|
142
|
+
|
|
143
|
+
TS 现为主实现,**文件级与 Go 1:1 对齐的约束已作废** —— `src/` 布局完全自由(见 §4
|
|
144
|
+
域文件夹结构)。但以下跨语言契约仍是将来把 TS 反向翻译为 Go 时的对照基准,必须保留:
|
|
145
|
+
|
|
146
|
+
- ✅ **snake_case wire-format 字段名** — wire 协议契约(50+ struct 已对齐),不可漂移
|
|
147
|
+
- ✅ **符号名跨语言一致** — 导出的类型 / 方法 / 错误名是 TS↔Go 对照锚点
|
|
148
|
+
- ✅ **bug-for-bug 行为对齐**(e.g. retry POST=false 默认,sanitize thinking 硬豁免)
|
|
149
|
+
- ✅ **ISO 8601 字符串时间** — 与 Go RFC3339 wire-compat
|
|
150
|
+
- ✅ **string 表示金额 / json.Number 字段** — 避免 JS number 精度损失(金融安全)
|
|
151
|
+
- ✅ **双 adapter 等地位** — `AnthropicAdapter` + `OpenAIAdapter` P0 红线,不可降级
|
|
152
|
+
- ✅ **已有端口代码的 "端口自 X.go" 溯源注释** — 历史对照保留;compliance、对外鉴权层等
|
|
153
|
+
新域本就无 Go 对应物,不写该注释
|
|
154
|
+
|
|
155
|
+
### TS 不可避免的偏移(与 Go 不 1:1)
|
|
156
|
+
|
|
157
|
+
| 维度 | Go | TS |
|
|
158
|
+
|------|----|----|
|
|
159
|
+
| 错误处理 | `(val, err)` 多返回值 | `throw` + 类型化 Error 子类 |
|
|
160
|
+
| 上下文取消 | `context.Context` | `AbortSignal` |
|
|
161
|
+
| 流返回 | `(eventCh, errCh chan)` | `AsyncIterable<StreamEvent>` |
|
|
162
|
+
| 锁 | `sync.Mutex` | Promise chain (`this.mu`) |
|
|
163
|
+
| IO | 同步 `os.ReadFile` | `fs/promises` async |
|
|
164
|
+
| Token Store 持久化 | 同步 file IO | `async` Save/Load/Clear |
|
|
165
|
+
|
|
166
|
+
## 6. 开发流程
|
|
167
|
+
|
|
168
|
+
### 改源码 → 提交
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
cd /Users/fushihua/Desktop/Acosmi/acosmi-sdk-ts
|
|
172
|
+
|
|
173
|
+
# 改完后必须通过发布前验证
|
|
174
|
+
npm run typecheck # 0 errors
|
|
175
|
+
npm run lint # 0 errors
|
|
176
|
+
npm test # all pass
|
|
177
|
+
npm run build # 多端 dist/ 全部生成
|
|
178
|
+
npm run test:pack # packed tarball consumer smoke
|
|
179
|
+
|
|
180
|
+
# commit (仅 SDK 独立仓)
|
|
181
|
+
git status --short
|
|
182
|
+
git diff --check
|
|
183
|
+
git add <files>
|
|
184
|
+
git commit -m "fix: ..."
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Commit message 规范
|
|
188
|
+
|
|
189
|
+
`type(scope): subject` 风格(与 Go SDK 仓库一致):
|
|
190
|
+
|
|
191
|
+
- `feat(sdk-ts): ...` 新功能
|
|
192
|
+
- `fix(sdk-ts): ...` bug fix
|
|
193
|
+
- `refactor(sdk-ts): ...` 重构(无功能变化)
|
|
194
|
+
- `docs(sdk-ts): ...` 文档
|
|
195
|
+
- `test(sdk-ts): ...` 测试
|
|
196
|
+
- `release(sdk-ts): vX.Y.Z` 版本发布
|
|
197
|
+
|
|
198
|
+
公开仓提交信息只写产品/SDK 变更,不写协作工具、临时计划或开发过程元数据。
|
|
199
|
+
|
|
200
|
+
## 7. 测试
|
|
201
|
+
|
|
202
|
+
- 框架:**vitest**(Node + jsdom 兼容)
|
|
203
|
+
- 位置:`test/`(随功能增长,发版前以 `npm test` 实际输出为准)
|
|
204
|
+
- 命令:`npm test` 单跑 / `npm run test:watch` watch
|
|
205
|
+
|
|
206
|
+
### 必测 P0 红线(改了就必跑)
|
|
207
|
+
|
|
208
|
+
- `test/adapters/routing.test.ts` — 双格式四级路由 8 case(**P0 红线**)
|
|
209
|
+
- `test/adapters/anthropic-build.test.ts` — buildRequestBody 14 case
|
|
210
|
+
- `test/sanitize/history.test.ts` — StripEphemeral / DropBlocks / thinking 豁免 7 case
|
|
211
|
+
- `test/scopes.test.ts` — 分组 scope 5 case
|
|
212
|
+
- `test/agent-runs.test.ts` — Agent Runs create/stream/401/local-tool/artifact 公开协议
|
|
213
|
+
- `test/model-helpers.test.ts` — v1.2 InputModality catalog helpers + sidecar 选择规则
|
|
214
|
+
- `test/list-models-input-modalities.test.ts` — v1.2 snake_case → camelCase 归一化 + undefined 保留
|
|
215
|
+
- `test/compliance.test.ts` — v1.3 compliance URL / 401 / no-retry / idempotency / error classify / polling / privacy boundary
|
|
216
|
+
- `test/compliance-scopes.test.ts` — **15 个** compliance scope 常量与 `complianceScopes()`(v1.3.0 首发 12 个 → v1.3.2 +`compliance:reports:write` → v1.5.0 S5 +`compliance:contract_template:{read,write}` 合计 15;含 `compliance:reports:publish` 等 step-up gated 写 scope)
|
|
217
|
+
- `test/shared.test.ts` — v1.5 跨域共享 DTO:`PageResult` 别名等价 / retryAdvice reason 映射 / 叠加投影只读性 / `classifyComplianceError` 零回归红线 17 case
|
|
218
|
+
|
|
219
|
+
### Agent Runs 公开 API 范围
|
|
220
|
+
|
|
221
|
+
从 v1.1.0 起,SDK 不再只是模型网关客户端,还包含下游产品可用的云端智能体任务协议:
|
|
222
|
+
|
|
223
|
+
- `client.agentRuns.create(req, signal?)`
|
|
224
|
+
- `client.agentRuns.stream(runId, opts?, signal?)`
|
|
225
|
+
- `client.agentRuns.run(req, opts?, signal?)`
|
|
226
|
+
- `client.agentRuns.cancel(runId, signal?)`
|
|
227
|
+
- `client.agentRuns.get(runId, signal?)`
|
|
228
|
+
- `client.agentRuns.listArtifacts(runId, signal?)`
|
|
229
|
+
- `client.agentRuns.downloadArtifact(runId, artifactId, signal?)`
|
|
230
|
+
- `client.agentRuns.submitLocalToolResult(runId, result, signal?)`
|
|
231
|
+
- `client.agentRuns.runWithLocalTools(req, handlers, opts?, signal?)`
|
|
232
|
+
|
|
233
|
+
红线:
|
|
234
|
+
- 下游产品禁止直连 Nexus 内部 `/api/v4/chat/completions` 或 `/api/v4/managed-models/:id/...` 来实现智能体循环。
|
|
235
|
+
- Agent Runs wire-format 使用 snake_case;SDK public API 使用 camelCase。
|
|
236
|
+
- Agent Runs 服务端状态必须按 `tenantId + userId` 隔离并持久化;run/SSE event/artifact/local-tool-result 不能只放进进程内存。
|
|
237
|
+
- Agent Runs 执行必须接入统一 entitlement hold/settle/release 链路;settle 失败必须进入既有 pending settlement 补偿机制。
|
|
238
|
+
- Agent Runs 结算只能使用 provider/ADK 透传的 `exact: true` usage;不得用字符数、输入长度或其他估算 token 扣费。provider usage 缺失时必须 release hold,并向 stream 返回稳定的 `usage_missing_released` settlement 状态。
|
|
239
|
+
- `create`、`submitLocalToolResult` 等可能产生副作用的 POST 遇到 401 不自动 refresh 后重放,避免重复创建或重复计费;GET/stream/download 这类安全查询允许单次 refresh 重试。
|
|
240
|
+
- SDK 不内置 CrabDesign/CrabCode/CrabClaw 专属本地文件读取逻辑;`local_tool_request` 只定义协议,handler 必须由下游显式传入;`allowedTools` 使用 ASCII function name。
|
|
241
|
+
|
|
242
|
+
### InputModality + 桌面视觉理解 sidecar 契约(v1.2.0)
|
|
243
|
+
|
|
244
|
+
从 v1.2.0 起,SDK 暴露上游 `ManagedModel` 的输入模态字段 + 桌面视觉理解 sidecar capability,供 CrabCode desktop automation / computer-use 通过 catalog(而非模型名 substring)选模型:
|
|
245
|
+
|
|
246
|
+
**类型契约**:
|
|
247
|
+
|
|
248
|
+
- `InputModality = 'text' | 'image'`(严格白名单)
|
|
249
|
+
- `ManagedModel.inputModalities?: InputModality[]` — 模型可接收的用户输入模态;`undefined` = 未声明(保守按 text-only / unknown 处理)
|
|
250
|
+
- `ModelCapabilities.supports_desktop_visual_understanding?: boolean` — 模型是否被运营标记为桌面截图解析 sidecar(输入 screenshot,输出 UI 结构化描述)
|
|
251
|
+
|
|
252
|
+
**4 个 catalog helper**(`src/models/model-helpers.ts`):
|
|
253
|
+
|
|
254
|
+
- `modelSupportsInputModality(model, modality): boolean`
|
|
255
|
+
- `modelSupportsImageInput(model): boolean`
|
|
256
|
+
- `findFirstModelByInputModality(models, modality): ManagedModel | null` — 按 catalog 顺序,跳过 `isEnabled === false`
|
|
257
|
+
- `findDesktopVisualUnderstandingModel(models): ManagedModel | null` — 选择规则:`isEnabled !== false` + `supports_desktop_visual_understanding === true` + `inputModalities` 含 `image` + `isDefault` 优先 / 否则 catalog 顺序第一
|
|
258
|
+
|
|
259
|
+
**协议归一化**:
|
|
260
|
+
|
|
261
|
+
- `listModels` / `listModelsWithStatus` 会归一化上游 snake_case `input_modalities` → camelCase `inputModalities`(兼容老网关)
|
|
262
|
+
- 同时存在 camelCase + snake_case 时 camelCase 胜
|
|
263
|
+
- `zeroModelCapabilities()` 显式置 `supports_desktop_visual_understanding: false`,避免 `undefined` 误判
|
|
264
|
+
|
|
265
|
+
**红线(严禁违反)**:
|
|
266
|
+
|
|
267
|
+
- 客户端**不得**在本地硬编码模型名做能力推断(如检测 modelId 含 "vision");一切视觉模型选择必须来自 SDK catalog 字段
|
|
268
|
+
- 上游 `ManagedModel` 缺失 `inputModalities` 时,SDK 保留 `undefined`,**不**自动补 `['text']` — 调用方必须保守按 text-only / unknown 处理,**严禁默认假设支持 image**
|
|
269
|
+
- 网关后端强约束:`supports_desktop_visual_understanding=true` 必须 `inputModalities` 含 `image`(handler 400 拒绝错配置)
|
|
270
|
+
- `inputModalities` 与 `capabilities.supports_desktop_visual_understanding` 是正交两件事:前者描述"模型能不能吃图",后者描述"运营是否把该模型标为桌面 UI 解析专用 sidecar"
|
|
271
|
+
|
|
272
|
+
**新增单测**:
|
|
273
|
+
|
|
274
|
+
- `test/list-models-input-modalities.test.ts` — listModels snake/camel 归一化 + undefined 保留 8 case
|
|
275
|
+
- `test/model-helpers.test.ts` — 4 个 helper + isEnabled/isDefault 优先级 15 case
|
|
276
|
+
|
|
277
|
+
加测试规则:
|
|
278
|
+
- 端口自 Go SDK 的测试用例必须保留 bug-for-bug
|
|
279
|
+
- TS-only 测试(e.g. AbortSignal 行为)单独写文件,不混进端口测试
|
|
280
|
+
|
|
281
|
+
### Compliance SDK 契约(v1.3.0)
|
|
282
|
+
|
|
283
|
+
从 v1.3.0 起,SDK 暴露 `client.compliance` 子客户端,覆盖时间章、电子证据、
|
|
284
|
+
证据包、报告、合同签署 envelope、用印审批和 provider request 脱敏状态轮询。
|
|
285
|
+
|
|
286
|
+
**公开 API 边界**:
|
|
287
|
+
|
|
288
|
+
- `Config.complianceBaseURL` 默认 `${serverURL}/admin-api`,不复用 `/api/v4`。
|
|
289
|
+
- `src/compliance/client.ts` 只发送 Acosmi 公共 DTO,不发送 provider 选择字段。
|
|
290
|
+
- compliance 类型文件(`src/compliance/**/types.ts` —— 各子域 `evidence/timestamp/signing/...`
|
|
291
|
+
的 `types.ts` 及共享 `src/compliance/types.ts`)不得暴露 provider
|
|
292
|
+
product/user/transaction/project/seal-provider 字段。
|
|
293
|
+
- `src/compliance/errors.ts` 只按 Java numeric `BusinessError.code` 分类,不从 message 文案做正则。
|
|
294
|
+
- `src/index.ts` 以 `export * from './compliance'` 导出 compliance 域;`src/compliance/index.ts`
|
|
295
|
+
barrel 从 `./client` re-export `ComplianceClient`,该 re-export 即加载 `client.ts`,
|
|
296
|
+
其 `Client.prototype` 的 `compliance` getter declaration-merging 随 barrel 一并生效。
|
|
297
|
+
|
|
298
|
+
**写操作红线**:
|
|
299
|
+
|
|
300
|
+
- POST/PUT/DELETE 不自动 retry。
|
|
301
|
+
- 写操作 401 不 refresh + replay;调用方重新认证后用同一 `Idempotency-Key` 恢复。
|
|
302
|
+
- GET 读路径可以做单次 401 refresh retry。
|
|
303
|
+
- 所有写方法必须允许传递 `Idempotency-Key`。
|
|
304
|
+
|
|
305
|
+
**安全红线**:
|
|
306
|
+
|
|
307
|
+
- SDK / docs / examples / tests / dist / tarball 不得包含 provider endpoint、证书、私钥、
|
|
308
|
+
JKS/PFX/P12、P7、zip、jar、口令、provider raw payload 或 callback billing commit payload。
|
|
309
|
+
- Java compliance 后端负责 provider 集成、受控材料、local verify 和 billing 状态机。
|
|
310
|
+
- Go OAuth/JWKS 层负责 token 签发、scope 与 step-up/introspection 语义。
|
|
311
|
+
- TS SDK 只申请 scope、发送公共 DTO、分类公开错误码并轮询脱敏状态。
|
|
312
|
+
|
|
313
|
+
**必测**:
|
|
314
|
+
|
|
315
|
+
- `npm test -- --run test/compliance.test.ts test/compliance-scopes.test.ts`
|
|
316
|
+
- `npm run test:pack` 必须覆盖 `client.compliance` consumer 视角类型调用。
|
|
317
|
+
- `npm pack --dry-run` 必须确认 tarball 仅包含 dist、README、CHANGELOG、LICENSE、
|
|
318
|
+
`docs/compliance.md` 和 `examples/` 等预期文件。
|
|
319
|
+
|
|
320
|
+
**v1.3.2 增补**(生产闭环实施计划 Phase 1 / 5 / 7):
|
|
321
|
+
|
|
322
|
+
- `verifyEvidencePublic` 收口为匿名公开验真:未 `login()` 时直接发匿名请求,不再抛
|
|
323
|
+
`not authorized`;已持 token 则附 `Authorization` 保留审计上下文;public 端点 `401`
|
|
324
|
+
不触发 `forceRefresh`、不做 refresh replay。
|
|
325
|
+
- 新增第 13 个 compliance scope `compliance:reports:write`:`createReport` 对应的服务端
|
|
326
|
+
scope 从 read 切到独立写 scope;`complianceScopes()` 已含;Go/Java/TS 三端字面量一致。
|
|
327
|
+
- `docs/compliance.md` 新增「Method Status」一节,把每个 `client.compliance.*` 方法标注为
|
|
328
|
+
`production-ready` / `gated` / `draft contract` / `internal-only` 四档。`gated`
|
|
329
|
+
(`publishReport` / `signEnvelope` / `createH5SigningUrl` / `approveSealApproval`)在服务端
|
|
330
|
+
step-up / 闸门未闭合前 fail-closed,SDK 不重试、不伪成功;distribution billing 等
|
|
331
|
+
`internal-only` 能力不进入 SDK 调用面。
|
|
332
|
+
|
|
333
|
+
### 跨域共享 DTO 契约(v1.5.0)
|
|
334
|
+
|
|
335
|
+
从 v1.5.0 起,`src/shared/` 除 `errors.ts` / `api-response.ts` 外,新增 5 个跨域
|
|
336
|
+
共享 DTO 文件,为后续平台控制面(`tenant` / `iam` / `operations` / `gateway`
|
|
337
|
+
等占位命名空间)与 `compliance` 分页 / gate 能力预沉淀【共享原语】。依据:能力
|
|
338
|
+
缺口总账 `docs/audit/saas-sdk-backend-capability-gap-register-2026-05-22` §9.4 /
|
|
339
|
+
§9.5(Phase 0.3 / 0.5)。
|
|
340
|
+
|
|
341
|
+
**落位规则**:
|
|
342
|
+
|
|
343
|
+
- 共享 DTO 一律落 `src/shared/`,按【关注点】分文件(`pagination` / `operation` /
|
|
344
|
+
`retry-advice` / `principal` / `gate`),不堆进 `shared/index.ts`,不在 `src/`
|
|
345
|
+
根新增散文件,不回退巨型 `types.ts`。
|
|
346
|
+
- `shared/index.ts` barrel 汇总 re-export;根 `src/index.ts` 经 `export * from
|
|
347
|
+
'./shared'` 自动导出,新增文件无需改根入口。
|
|
348
|
+
|
|
349
|
+
**冲突避免红线(严禁违反)**:
|
|
350
|
+
|
|
351
|
+
- ✅ **`PageResult<T>` 是 `YudaoPageResult<T>` 的别名**,不引入第二套
|
|
352
|
+
`{list,total}` 分页结果结构——避免 billing / compliance / skills /
|
|
353
|
+
notifications 之间双分页标准。`PageRequest` 为新增【可选】类型,**不回填改写**
|
|
354
|
+
既有 4 处内联分页签名(破坏性变更)。
|
|
355
|
+
- ✅ **`RetryAdvice` 是叠加层**——独立类型、独立字段,**不修改也不替换**
|
|
356
|
+
`core/retry.ts` 的 `RetryPolicy`(决定 SDK 传输层是否自动重试)与
|
|
357
|
+
`compliance/errors.ts` 的 `ComplianceErrorInfo`(`retryable`/`terminal`/
|
|
358
|
+
`stepUpRequired`)。否则 `csign sdk-client.ts:classifyVerifyError` 破裂。
|
|
359
|
+
- ✅ **`RetryAdviceReason` 不开第四套错误码登记表**——它是既有三套登记表
|
|
360
|
+
(Java 数值码 `1_031_xxx` / SDK 符号 key / Go OAuth 标准字符串)的小写归一化
|
|
361
|
+
映射;`retry-advice.ts` 内 `Record<ComplianceErrorKey, RetryAdviceReason>`
|
|
362
|
+
以编译期穷举强约束映射表不漏。
|
|
363
|
+
- ✅ **`ProviderRequestStatus` 复用**既有 `ComplianceProviderRequestStatus`,
|
|
364
|
+
不另造同名近似类型。
|
|
365
|
+
- ✅ **`IdempotencyKeyHeader`(`'Idempotency-Key'`)是写接口幂等键 header 的
|
|
366
|
+
单一真相源**,新写接口一律引用该常量。
|
|
367
|
+
|
|
368
|
+
**关键约束**:使 8 个占位命名空间(`tenant` / `iam` / `apiClients` /
|
|
369
|
+
`operations` / `audit` / `gateway` / `mcp` / `certification`)变成真实导出 = 写出
|
|
370
|
+
调用后端端点的 SDK 方法;对应后端端点**当前不存在**。在后端端点与契约就绪前,
|
|
371
|
+
这些命名空间保持 `export {}` 占位,**不实现**——提前写空转方法属编造契约。共享
|
|
372
|
+
DTO 是纯类型 / 纯函数沉淀,不构成对后端契约的预设,故可先行落地。
|
|
373
|
+
|
|
374
|
+
**必测**:`test/shared.test.ts`(17 case)。
|
|
375
|
+
|
|
376
|
+
### Compliance gateway S1-S6 rollup(v1.5.0)
|
|
377
|
+
|
|
378
|
+
v1.5.0 同时把 compliance gateway S1-S6(roadmap 原 v1.6.0-v1.11.0)全量 rollup 进
|
|
379
|
+
当前版本,**新增 SDK 公开方法 25+ 个**,全部走 `client.compliance.*`,红线(写不
|
|
380
|
+
重试 / 写 401 不 replay / GET 单次 401 refresh)不变。CHANGELOG 各节用 "原 1.X.0"
|
|
381
|
+
注解标出来源。
|
|
382
|
+
|
|
383
|
+
- **S1(原 v1.6.0 / U-1 / 后端 G1)**——6 个分页列表读端点:`listEvidenceAssets`
|
|
384
|
+
/ `listTimestamps` / `listEvidencePackages` / `listReports` /
|
|
385
|
+
`listSigningEnvelopes` / `listSealApprovals`。统一走 `GET .../page`,返回 yudao
|
|
386
|
+
`PageResult<T>`(`{ total, list }`),请求参数继承共享 `PageRequest`。
|
|
387
|
+
- **S2(原 v1.7.0 / U-5 + U-6 / 后端 G2)**——capability gate + 操作投影读:
|
|
388
|
+
`getCapabilities` / `getFeatureGate(action)` / `listOperations` / `getOperation`。
|
|
389
|
+
能力闸门拿不到时必须 fail-closed。
|
|
390
|
+
- **S3(原 v1.8.0 / U-7 / 后端 G3)**——TSA 只读视图:`listTsaProviders` /
|
|
391
|
+
`getTsaStats`。
|
|
392
|
+
- **S4(原 v1.9.0 / U-10 + U-12 子集 / 后端 G4)**——envelope 收尾:
|
|
393
|
+
`listEnvelopeContracts` / `listEnvelopeProviderRequests`(GET 读,返回普通数组
|
|
394
|
+
而非 `PageResult`),`voidEnvelope`(写,带 `Idempotency-Key`,`reason` 随 body
|
|
395
|
+
提交)。envelope 的 send / remind / authorize / download / token 等 W3 闸门动作
|
|
396
|
+
仍后端推迟。
|
|
397
|
+
- **S5(原 v1.10.0 / U-2 / 后端 G5)**——合同模板 9 个方法 DRAFT → PUBLISHED →
|
|
398
|
+
ARCHIVED 全生命周期:`createContractTemplate` / `updateContractTemplate` /
|
|
399
|
+
`deleteContractTemplate` / `getContractTemplate` / `listContractTemplates` /
|
|
400
|
+
`uploadContractTemplatePdf` / `publishContractTemplate` /
|
|
401
|
+
`archiveContractTemplate` / `listContractTemplateVersions`。新增 2 个 scope
|
|
402
|
+
`compliance:contract_template:{read,write}`(不要求 step-up)。
|
|
403
|
+
- **S6(原 v1.11.0 / U-4 / 后端 G6)**——用印执行分页:`listSealUses`。复用既有
|
|
404
|
+
`compliance:contract_signing:read` scope,不引入新 scope。
|
|
405
|
+
|
|
406
|
+
> 当前 compliance scope 总数 **15** 个(首发 12 + v1.3.2 `compliance:reports:write`
|
|
407
|
+
> + S5 两个 contract_template = 15;其中 `compliance:reports:publish` 在首发批次
|
|
408
|
+
> 内)。`complianceScopes()` 返回全部 15 个;生产建议按最小集合申请。
|
|
409
|
+
|
|
410
|
+
## 8. 构建
|
|
411
|
+
|
|
412
|
+
- 工具:**tsup**
|
|
413
|
+
- 命令:`npm run build`
|
|
414
|
+
- 产物结构:
|
|
415
|
+
- `dist/node/` — Node ESM (`.mjs`) + CJS (`.cjs`) + `.d.ts`
|
|
416
|
+
- `dist/browser/` — Browser ESM + `.d.ts`
|
|
417
|
+
- `dist/` — Deno/Bun ESM + `.d.ts`
|
|
418
|
+
- 大小:~120KB(压缩前)
|
|
419
|
+
- `package.json.files`:`dist`、`README.md`、`CHANGELOG.md`、`LICENSE`、
|
|
420
|
+
`docs/compliance.md`、`examples/`
|
|
421
|
+
- `prepublishOnly` 钩子:`typecheck && lint && test && build && test:pack`(npm publish 前自动跑)
|
|
422
|
+
|
|
423
|
+
## 9. 发布流程
|
|
424
|
+
|
|
425
|
+
### 9.1 一次性配置(首次发布前)
|
|
426
|
+
|
|
427
|
+
#### A. 公开仓 GitHub Repo
|
|
428
|
+
|
|
429
|
+
```
|
|
430
|
+
github.com/acosmi/sdk-ts (public, MIT)
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
由企业账号 `acosmi`(lowercase)持有。
|
|
434
|
+
|
|
435
|
+
#### B. 获取独立 SDK 仓
|
|
436
|
+
|
|
437
|
+
```bash
|
|
438
|
+
git clone https://github.com/acosmi/sdk-ts.git
|
|
439
|
+
cd sdk-ts
|
|
440
|
+
git config user.name "acosmi-fushihua"
|
|
441
|
+
git config user.email "fushihua@acosmi.com"
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
> 用 HTTPS(不是 SSH),避免 host key verification 失败。
|
|
445
|
+
|
|
446
|
+
#### C. npm Token(**关键**:bypass 2FA)
|
|
447
|
+
|
|
448
|
+
| Token 类型 | bypass 2FA | 推荐度 |
|
|
449
|
+
|------------|------------|--------|
|
|
450
|
+
| **Classic Publish token** | ❌(账号开 2FA 时不能用 CI) | 不推荐 |
|
|
451
|
+
| **Classic Automation token** | ✅(天然 bypass) | 推荐(最简单) |
|
|
452
|
+
| **Granular Access Token** | ⚠️ 默认 ❌,**必须勾选 "Bypass two-factor authentication"** | 推荐(颗粒度细) |
|
|
453
|
+
|
|
454
|
+
**Granular Token 配置步骤**:
|
|
455
|
+
1. npmjs.com → Account → Granular Access Tokens → Generate New Token
|
|
456
|
+
2. Name:`acosmi-sdk-ts-ci`
|
|
457
|
+
3. Expiration:建议 1 年
|
|
458
|
+
4. Permissions:Read & Write
|
|
459
|
+
5. Packages:选 `@acosmi/sdk-ts`
|
|
460
|
+
6. **勾选 "Bypass two-factor authentication when publishing"** ← 漏勾就 E403
|
|
461
|
+
7. 复制 token
|
|
462
|
+
|
|
463
|
+
**GitHub repo Secret**:
|
|
464
|
+
- repo → Settings → Secrets and variables → Actions → New repository secret
|
|
465
|
+
- Name: `NPM_TOKEN`
|
|
466
|
+
- Value: 上一步 token
|
|
467
|
+
|
|
468
|
+
#### D. 验证 release.yml
|
|
469
|
+
|
|
470
|
+
公开仓 `.github/workflows/release.yml` 关键内容:
|
|
471
|
+
|
|
472
|
+
```yaml
|
|
473
|
+
on:
|
|
474
|
+
push:
|
|
475
|
+
tags: ['v*']
|
|
476
|
+
|
|
477
|
+
jobs:
|
|
478
|
+
publish:
|
|
479
|
+
runs-on: ubuntu-latest
|
|
480
|
+
# JS-based actions (checkout / setup-node / action-gh-release) 走 Node 24,
|
|
481
|
+
# 提前进入 2026-06-02 GitHub 默认状态,避免 Node 20 弃用 annotation。
|
|
482
|
+
env:
|
|
483
|
+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true'
|
|
484
|
+
steps:
|
|
485
|
+
- uses: actions/checkout@v4
|
|
486
|
+
- uses: actions/setup-node@v4
|
|
487
|
+
with:
|
|
488
|
+
# CI 跑 Node 24(Active LTS),与 JS-action 运行时一致;
|
|
489
|
+
# SDK consumer 仍按 package.json engines.node >=18 兼容承诺。
|
|
490
|
+
node-version: '24'
|
|
491
|
+
registry-url: 'https://registry.npmjs.org'
|
|
492
|
+
- run: npm ci
|
|
493
|
+
- run: npm run typecheck
|
|
494
|
+
- run: npm run lint
|
|
495
|
+
- run: npm test
|
|
496
|
+
- run: npm run build
|
|
497
|
+
- run: npm publish --provenance --access public
|
|
498
|
+
env:
|
|
499
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
500
|
+
- uses: softprops/action-gh-release@v2
|
|
501
|
+
with:
|
|
502
|
+
generate_release_notes: true
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### 9.2 每次发布
|
|
506
|
+
|
|
507
|
+
```bash
|
|
508
|
+
# === Step 1:确认 SDK 独立仓 ===
|
|
509
|
+
cd /Users/fushihua/Desktop/Acosmi/acosmi-sdk-ts
|
|
510
|
+
git rev-parse --show-toplevel
|
|
511
|
+
git remote -v
|
|
512
|
+
git status --short
|
|
513
|
+
|
|
514
|
+
# === Step 2:改源码 + 文档 + 升 version ===
|
|
515
|
+
npm run typecheck
|
|
516
|
+
npm run lint
|
|
517
|
+
npm test
|
|
518
|
+
npm run build
|
|
519
|
+
npm run test:pack
|
|
520
|
+
npm pack --dry-run
|
|
521
|
+
|
|
522
|
+
# === Step 3:审计 ===
|
|
523
|
+
git diff --check
|
|
524
|
+
git diff --stat
|
|
525
|
+
# 额外执行敏感材料扫描,确认没有证书、私钥、keystore、真实 provider endpoint、raw payload。
|
|
526
|
+
|
|
527
|
+
# === Step 4:提交并推送当前分支 ===
|
|
528
|
+
git add <sdk files>
|
|
529
|
+
git commit -m "feat: add compliance SDK client"
|
|
530
|
+
git push
|
|
531
|
+
|
|
532
|
+
# === Step 5:发布 tag(会触发 npm publish)===
|
|
533
|
+
# 只有在确认要触发 npm/GitHub Release 时才执行:
|
|
534
|
+
git tag vX.Y.Z
|
|
535
|
+
git push origin vX.Y.Z
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
### 9.3 公开仓清洁度检查(push 前必看)
|
|
539
|
+
|
|
540
|
+
- [ ] 作者 = `acosmi-fushihua <fushihua@acosmi.com>`,提交信息干净
|
|
541
|
+
- [ ] commit 范围只包含 SDK 发布相关文件
|
|
542
|
+
- [ ] 没有 Java / Go / CFCA real provider 改动
|
|
543
|
+
- [ ] `docs/` 不包含内部 audit 文档或 provider runbook
|
|
544
|
+
- [ ] `.github/workflows/release.yml` 存在
|
|
545
|
+
- [ ] `package.json` `"version"` 已升
|
|
546
|
+
- [ ] `package.json` `"private"` 字段不存在或为 `false`
|
|
547
|
+
- [ ] 不含 `dist/` `node_modules/` `.eslintcache`
|
|
548
|
+
- [ ] 不含证书、私钥、JKS/PFX/P12、zip、jar、口令、真实 provider endpoint、provider raw payload
|
|
549
|
+
|
|
550
|
+
## 10. 版本号策略
|
|
551
|
+
|
|
552
|
+
**自 2026-05-22 起版本策略以 TS 为准**:TS SDK 是主实现,独立演进;Go SDK `acosmi-sdk-go`
|
|
553
|
+
暂停维护,原"Go + TS 主版本号联动"约束已挂起,TS 不再等 Go 对齐版本号。
|
|
554
|
+
|
|
555
|
+
- **minor**(1.x.0):新业务方法 / 新域 / 向后兼容的协议扩展
|
|
556
|
+
- **patch**(1.x.y):bug fix、文档、内部 refactor
|
|
557
|
+
- **major**(x.0.0):wire-format 不兼容变更、API 移除、TokenStore 接口变化
|
|
558
|
+
|
|
559
|
+
> 历史背景:v1.0.0 时曾约定 Go + TS 主版本号同步、patch 各自独立。该联动机制因 Go SDK
|
|
560
|
+
> 暂停维护已挂起。将来 Go SDK 从 TS 反向翻译重启时(见 §11、计划 §3),版本对齐策略需
|
|
561
|
+
> 重新评估,本节届时一并修订。
|
|
562
|
+
|
|
563
|
+
## 11. Go SDK 反向翻译流程(当前暂停)
|
|
564
|
+
|
|
565
|
+
> **状态:暂停**。本节描述的是将来 Go SDK 重启时的方向,目前不执行。
|
|
566
|
+
|
|
567
|
+
历史上本节是「Go SDK 升级 → 镜像到 TS」的同步流程;自 2026-05-22 起 TS 成为主实现、
|
|
568
|
+
Go SDK 暂停维护,该 Go→TS 镜像流程已不再适用。
|
|
569
|
+
|
|
570
|
+
未来方向(计划 §3):待 TS SDK 稳定后,从 **TS 反向翻译补齐 Go**,方向是 TS→Go。
|
|
571
|
+
反向翻译以 §5「跨语言契约印记」为基准:
|
|
572
|
+
|
|
573
|
+
- 导出的类型 / 方法 / 错误**符号名**跨语言一致,作为 TS↔Go 对照锚点
|
|
574
|
+
- **snake_case wire-format 字段名**严格一致(wire 协议契约不可漂移)
|
|
575
|
+
- **bug-for-bug 行为对齐**(retry POST=false 默认、sanitize thinking 硬豁免等)
|
|
576
|
+
- 翻译时引入 Go 端不可避免的偏移(`(val, err)` 多返回值、`context.Context`、channel 流等,见 §5 偏移表的反向)
|
|
577
|
+
|
|
578
|
+
在 Go SDK 重启反向翻译之前,TS SDK 的发版只走 §9.2,不需要任何 Go 侧同步动作。
|
|
579
|
+
|
|
580
|
+
## 12. 故障排查
|
|
581
|
+
|
|
582
|
+
### 12.1 npm publish 失败
|
|
583
|
+
|
|
584
|
+
| 错误 | 原因 | 排查 |
|
|
585
|
+
|------|------|------|
|
|
586
|
+
| `403 Forbidden` "Two-factor authentication or granular access token with bypass 2fa enabled is required" | Token 没开 bypass 2FA | 重建 Granular token,**勾选 "Bypass two-factor authentication"**;或换 Classic Automation token |
|
|
587
|
+
| `403 Forbidden`(其他) | `NPM_TOKEN` secret 失效 / 包名权限不够 | 重建 token,确保 packages 选了 `@acosmi/sdk-ts` |
|
|
588
|
+
| `EPUBLISHCONFLICT` / `cannot publish over the previously published versions` | 没升 version | 升 `package.json` `"version"` |
|
|
589
|
+
| `package private` | `package.json` 还有 `"private": true` | 删掉或改 `false` |
|
|
590
|
+
| `provenance attestation failed` | 仓库 visibility / OIDC 配置不对 | workflow 里**去掉** `--provenance` flag |
|
|
591
|
+
| `404 Not Found` 在 publish 时 | 包名拼错或 `publishConfig.access` 缺 | `package.json` 加 `"publishConfig": { "access": "public" }` |
|
|
592
|
+
|
|
593
|
+
### 12.2 typecheck 失败
|
|
594
|
+
|
|
595
|
+
- 改了某个域的 wire-format 类型(`src/models/types.ts` / `src/compliance/**/types.ts` 等)→ 检查所有 caller
|
|
596
|
+
- import 路径错 → `npm run typecheck` 输出文件:行号
|
|
597
|
+
- TS strict 默认开 → 看具体 error,不要图方便加 `as any`
|
|
598
|
+
|
|
599
|
+
### 12.3 test 失败
|
|
600
|
+
|
|
601
|
+
- `routing.test.ts` 红 = **P0 红线破坏,严重停车**,立刻回滚
|
|
602
|
+
- `history.test.ts` 红 = sanitize 行为漂移(检查 thinking 豁免 / tool_use_id 联动)
|
|
603
|
+
- `anthropic-build.test.ts` 红 = adapter buildRequestBody 行为变了(确认是有意的契约变更,而非回归)
|
|
604
|
+
|
|
605
|
+
### 12.4 公开仓 push 失败
|
|
606
|
+
|
|
607
|
+
| 错误 | 排查 |
|
|
608
|
+
|------|------|
|
|
609
|
+
| `Host key verification failed` | 把 remote URL 从 `git@github.com:` 改成 `https://github.com/` |
|
|
610
|
+
| `Updates were rejected because the remote contains work` | 先 `git fetch` + `git pull --ff-only`;只有维护者明确要重写历史时才 force push |
|
|
611
|
+
| `This repository moved. Please use the new location` | 仓库被 transfer 了,更新 remote URL(见原始 enterprise repo) |
|
|
612
|
+
| GitHub Contributors 显示异常作者 | 检查本地 `git config user.name/user.email`,必要时修正后重新提交 |
|
|
613
|
+
|
|
614
|
+
### 12.5 下游 crabcode 报 type / 模块 缺失
|
|
615
|
+
|
|
616
|
+
- 检查 `package.json` `exports` 字段 `types` 是否齐
|
|
617
|
+
- `dist/node/index.d.ts` 必须存在(build 产物)
|
|
618
|
+
- `npm pack --dry-run` 看实际 publish 内容
|
|
619
|
+
- 用户问"缺 X" → 先核 SDK 仓 `src/` 是否已实现该能力 → 多数是 README 未文档化(更新 README);若确实未实现则按需新增
|
|
620
|
+
|
|
621
|
+
## 13. 下游消费指引
|
|
622
|
+
|
|
623
|
+
下游产品(crabcode / crabclaw / 任意第三方)使用方式:
|
|
624
|
+
|
|
625
|
+
```bash
|
|
626
|
+
npm install @acosmi/sdk-ts
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
```ts
|
|
630
|
+
import { Client } from '@acosmi/sdk-ts';
|
|
631
|
+
const client = new Client({ serverURL: process.env.ACOSMI_SERVER_URL! });
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
完整 API 文档见公开仓 [README.md](../README.md)。
|
|
635
|
+
|
|
636
|
+
下游报"缺 X"时先按 §12.5 排查;如确实未实现,新增 issue → 主仓改 → 走发布流程。
|
|
637
|
+
|
|
638
|
+
## 14. 发布前严格审计(5-phase)
|
|
639
|
+
|
|
640
|
+
每次重大发版(含首次发版 / API 重构)必走:
|
|
641
|
+
|
|
642
|
+
| Phase | 内容 | 输出 |
|
|
643
|
+
|-------|------|------|
|
|
644
|
+
| **A. TS 代码审计** | `src/core/client.ts` + 各业务域 barrel 与子模块逐文件 + 红线扫描 | P0/P1/P2 issue 列表 |
|
|
645
|
+
| **B. Wire-format 对齐** | 50+ struct 的 snake_case 字段名 + 类型 + optional 标记守住跨语言契约(§5)| 0 偏移确认 |
|
|
646
|
+
| **C. 脚手架审计** | package.json / tsup / .npmignore / release.yml / README | 0 漏配置 |
|
|
647
|
+
| **D. 开发手册自审** | 本文件各节是否覆盖实际流程 | 修订列表 |
|
|
648
|
+
| **E. Go SDK 自审** | **暂停** —— Go SDK `acosmi-sdk-go` 已停止维护,无须同步自审;待 Go 从 TS 反向翻译重启后再恢复本 Phase | —(当前不执行)|
|
|
649
|
+
|
|
650
|
+
四绿 PASS 后再走 §9.2。审计报告归档主仓 `docs/audit/acosmi-sdk-ts-发布前严格复核审计-YYYY-MM-DD.md`,**不进公开仓**。
|
|
651
|
+
|
|
652
|
+
## 15. 关键文档与链接
|
|
653
|
+
|
|
654
|
+
- 用户文档:[README.md](../README.md)(公开仓 + 主仓同步)
|
|
655
|
+
- 端口完成档:主仓 `docs/audit/TS-SDK-端口完成-2026-05-01.md`
|
|
656
|
+
- 端口初稿计划:主仓 `docs/audit/acosmi-sdk-ts-port-初稿计划-2026-05-01.md`
|
|
657
|
+
- 严格审计报告:主仓 `docs/audit/acosmi-sdk-ts-发布前严格复核审计-2026-05-01.md`
|
|
658
|
+
- npm 包:https://www.npmjs.com/package/@acosmi/sdk-ts
|
|
659
|
+
- npm 旧包名(待 deprecate):https://www.npmjs.com/package/acosmi-sdk-ts — 1.0.0 已发布占位;下次新版发布时单独窗口执行 `npm deprecate acosmi-sdk-ts@1.0.0 "Renamed to @acosmi/sdk-ts"`
|
|
660
|
+
- 公开仓:https://github.com/acosmi/sdk-ts
|
|
661
|
+
- Go SDK 端口源:https://github.com/acosmi/acosmi-sdk-go
|
|
662
|
+
|
|
663
|
+
## 16. 维护者
|
|
664
|
+
|
|
665
|
+
- 源码改动:SDK 独立仓维护者
|
|
666
|
+
- 公开仓:通过 §9.2 流程提交与发布,不接受无维护者确认的外部发布 PR
|
|
667
|
+
- npm 包:GitHub Actions 自动发布(push tag v* 触发)
|
|
668
|
+
- 安全 Issue:通过 GitHub Security Advisory 私下沟通
|
|
669
|
+
|
|
670
|
+
## 17. v1.0.0 翻车教训 + 烟测加固(2026-05-01)
|
|
671
|
+
|
|
672
|
+
### 时间线
|
|
673
|
+
|
|
674
|
+
- 2026-05-01 07:51:35Z — `npm publish @acosmi/sdk-ts@1.0.0`(首发,CI 自动)
|
|
675
|
+
- 同日 — 下游 crabcode(Anthropic 兼容格式消费方)反馈 P0 双层 broken
|
|
676
|
+
- 同日 — 源码侧 7 commit 修复落地(C0~C6: 4d53585 → 885c08a)
|
|
677
|
+
- 同日 — SDK 公开仓同步并重写为干净发布提交(commit `e60a88e → 0d8c0a9`)
|
|
678
|
+
- 同日 — `git tag v1.0.1 && git push origin v1.0.1` 触发 release.yml CI 自动 npm publish
|
|
679
|
+
- 同日 — `npm publish @acosmi/sdk-ts@1.0.1` 完成(tarball 594.4 kB / 36 文件 / shasum `f8805a04..` / SLSA v1 provenance)
|
|
680
|
+
- 同日 — audit Part 2: `npm i @acosmi/sdk-ts@1.0.1` consumer 视角实拉 + smoke `tsc --noEmit` 全绿,9 处 declare module 在 dist/node/index.d.ts 行 548/571/592/601/645/654/677/720/761 全包名
|
|
681
|
+
- 同日 — `npm deprecate @acosmi/sdk-ts@1.0.0 'broken packaging, use 1.0.1+'`(手动单独跑,CI 不含)
|
|
682
|
+
|
|
683
|
+
### 翻车的两层根因
|
|
684
|
+
|
|
685
|
+
| 层 | 现象 | 根因 |
|
|
686
|
+
| --- | --- | --- |
|
|
687
|
+
| Layer 1 — packaging | bun / Node ESM `Cannot find module '@acosmi/sdk-ts'` | `tsup.config.ts` 无 `outExtension`(默认输出 `.js + .cjs`),`package.json.exports` 8 处写死 `.mjs` 引用,两侧无对账 |
|
|
688
|
+
| Layer 2 — d.ts augmentation | consumer 项目 `getBalance` / `submitBugReport` 等 50+ 方法 TS2339 | 9 处 `declare module` 用相对路径(`'../client'` / `'./client'`),tsup 打包 d.ts 不做 path rewrite,consumer 视角下相对路径指向不存在的文件 |
|
|
689
|
+
| 流程根因 | publish 前没拦截 | `prepublishOnly` 仅跑源码侧(typecheck / lint / vitest / build),不验证 **packed product 在 consumer 视角能否解析** |
|
|
690
|
+
|
|
691
|
+
### 修复点
|
|
692
|
+
|
|
693
|
+
- **Layer 1**:`tsup.config.ts` 三 entry 显式 `outExtension: ({ format }) => ({ js: format === 'esm' ? '.mjs' : '.cjs' })`
|
|
694
|
+
- **Layer 2**:9 处 `declare module '../client'` / `'./client'` → `declare module '@acosmi/sdk-ts'`;附加 `tsconfig.json` 的 `paths` 让源码 typecheck self-reference
|
|
695
|
+
- **流程**:新增 `scripts/smoke-pack.mjs` + `prepublishOnly` 末尾 `&& npm run test:pack`
|
|
696
|
+
|
|
697
|
+
### 烟测脚本设计要点
|
|
698
|
+
|
|
699
|
+
- **跨平台**:用 `spawnSync` 不用 `exec/execSync`(无 shell injection);`shell: isWin`(Node 20.12+ Windows 安全限制 CVE-2024-27980 修复后跑 `.cmd` 必需)
|
|
700
|
+
- **隔离 consumer**:`mkdtempSync(os.tmpdir())` 临时目录,不污染 caller 的 `node_modules`
|
|
701
|
+
- **覆盖 9 处 augmentation**:`smoke.ts` 内调用每个 `declare module` 文件至少一个 method(`getBalance` / `getWalletStats` / `listTokenPackages` / `listNotifications` / `listTools` / `browseSkillStore` / `submitBugReport` / `applyRequestSanitizers` / WS `connect` typeof 验证)
|
|
702
|
+
- **失败保留**:smoke 失败时保留临时目录供调试;成功才清理
|
|
703
|
+
|
|
704
|
+
### 未来发版前必读
|
|
705
|
+
|
|
706
|
+
1. **任何改 `tsup.config.ts` / `package.json.exports` / `declare module` 的 PR**,merge 前必须本地跑 `npm run test:pack`
|
|
707
|
+
2. **publish 流程**:`npm publish` 会自动跑 `prepublishOnly`(含 `test:pack`);不可手动跳过
|
|
708
|
+
3. **新增 augmentation 时**:`smoke.ts` 内补对应 method 调用,确保 consumer 视角验证覆盖
|
|
709
|
+
4. **手动 deprecate 已发布版本**:`npm deprecate @acosmi/sdk-ts@<version> '<reason>'`(无法撤回但可加警告)
|
|
710
|
+
|
|
711
|
+
### 详细变更
|
|
712
|
+
|
|
713
|
+
**历史修复 commits**:
|
|
714
|
+
- `f4972d3` C1 Layer 1 — tsup outExtension
|
|
715
|
+
- `1597d61` C2 Layer 2a — 6 处 `src/client/*.ts` declare module 绑包名 + tsconfig paths self-reference
|
|
716
|
+
- `47e7307` C3 Layer 2b — 3 处 `src/{ws,sanitize-bridge,bug-report}.ts` declare module 绑包名
|
|
717
|
+
- `9f94561` C4 Layer 3 — 新建 `scripts/smoke-pack.mjs` + `prepublishOnly` 加 `test:pack`
|
|
718
|
+
- `b8feb5b` C5 版本同步 1.0.0 → 1.0.1
|
|
719
|
+
- `885c08a` C6 文档闭环 — README + CHANGELOG + 本节 + `package.json.files` 加 CHANGELOG.md
|
|
720
|
+
|
|
721
|
+
**SDK 公开仓发布历史**:
|
|
722
|
+
- `0d8c0a9` release: v1.0.1 — 19 文件 745+/192-(amend + reset-author 自 `e60a88e`)
|
|
723
|
+
- tag: `v1.0.1` → 触发 release.yml CI
|
|
724
|
+
|
|
725
|
+
**npm registry 实拉验证** (audit Part 2 PASS):
|
|
726
|
+
- 包: `@acosmi/sdk-ts@1.0.1`
|
|
727
|
+
- tarball: `https://registry.npmjs.org/@acosmi/sdk-ts/-/sdk-ts-1.0.1.tgz`
|
|
728
|
+
- shasum: `f8805a0443c9b36ce7d559bd333a472ecb8fcef4`
|
|
729
|
+
- integrity: `sha512-CwJMxyCRULQCZT34O/dACSR65bjkRDY2T357oc0q31YFEw8LDEA/+r1Kuy7u/MmuZlsXc0q85cxFjcVcn5RgkA==`
|
|
730
|
+
- 包大小: 594.4 kB / 解包 2.42 MB / 36 文件
|
|
731
|
+
- provenance: SLSA v1(CI 自动签 attestation)
|
|
732
|
+
- 0 production vulnerabilities(vitest devDep 链 esbuild GHSA-67mh-4wv8-2f99 不进 production,作技术债务下个 patch 处理)
|
|
733
|
+
- consumer 视角 smoke `tsc --noEmit` 全绿;dist/node/index.d.ts 9 处 declare module 全 `'@acosmi/sdk-ts'`(line 548/571/592/601/645/654/677/720/761)
|
|
734
|
+
|
|
735
|
+
**完整执行档**:主仓 `docs/audit/sdk-ts-1.0.0-fix-plan-2026-05-01.md`
|
|
736
|
+
**CHANGELOG**:`./CHANGELOG.md`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@acosmi/sdk-ts",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Acosmi TypeScript SDK:模型网关、Agent Run Gateway 与 Compliance(电子证据、时间章、报告、签署 envelope)统一客户端,支持浏览器 / Node ≥18 / Deno / Bun。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/node/index.cjs",
|
|
@@ -41,6 +41,8 @@
|
|
|
41
41
|
"CHANGELOG.md",
|
|
42
42
|
"LICENSE",
|
|
43
43
|
"docs/compliance.md",
|
|
44
|
+
"docs/pii-role-matrix.md",
|
|
45
|
+
"docs/开发与发布手册.md",
|
|
44
46
|
"examples"
|
|
45
47
|
],
|
|
46
48
|
"scripts": {
|