@acosmi/sdk-ts 1.2.0 → 1.3.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.
@@ -0,0 +1,265 @@
1
+ # Compliance SDK Guide
2
+
3
+ This guide covers the public TypeScript SDK surface for compliance workflows:
4
+ timestamps, evidence assets, evidence packages, reports, signing envelopes, seal
5
+ approvals, and provider request polling.
6
+
7
+ The SDK exposes Acosmi domain objects only. It does not expose provider
8
+ credentials, provider endpoints, raw provider payloads, certificates, private
9
+ keys, signing containers, or billing commit internals.
10
+
11
+ ## Quick Start
12
+
13
+ ```ts
14
+ import {
15
+ Client,
16
+ ScopeComplianceEvidenceRead,
17
+ ScopeComplianceEvidenceWrite,
18
+ ScopeComplianceTimestampIssue,
19
+ ScopeComplianceTimestampVerify,
20
+ } from '@acosmi/sdk-ts';
21
+
22
+ const client = await Client.create({
23
+ serverURL: process.env.ACOSMI_SERVER_URL!,
24
+ // Defaults to `${serverURL}/admin-api` when omitted.
25
+ complianceBaseURL: process.env.ACOSMI_COMPLIANCE_BASE_URL,
26
+ });
27
+
28
+ await client.login('Compliance Example', [
29
+ ScopeComplianceEvidenceRead,
30
+ ScopeComplianceEvidenceWrite,
31
+ ScopeComplianceTimestampIssue,
32
+ ScopeComplianceTimestampVerify,
33
+ ]);
34
+
35
+ const idempotencyKey = await loadOrCreateIdempotencyKey('timestamp:order-123');
36
+
37
+ const asset = await client.compliance.createEvidenceAsset(
38
+ {
39
+ assetType: 'HASH_ONLY',
40
+ name: 'release-manifest',
41
+ hashAlgorithm: 'sha256',
42
+ declaredHash: process.env.RELEASE_MANIFEST_SHA256!,
43
+ digestSource: 'CLIENT',
44
+ privacyLevel: 'private',
45
+ },
46
+ { idempotencyKey },
47
+ );
48
+
49
+ const token = await client.compliance.issueTimestampForAsset(asset.id, {
50
+ idempotencyKey: await loadOrCreateIdempotencyKey(`timestamp:${asset.evidenceNo}`),
51
+ });
52
+
53
+ const verified = await client.compliance.waitForTimestampVerified(token.id, {
54
+ timeoutMs: 60_000,
55
+ });
56
+
57
+ console.log(verified.verificationStatus);
58
+ ```
59
+
60
+ ## Scopes
61
+
62
+ Request the smallest scope set that matches the workflow. `complianceScopes()`
63
+ returns all compliance scopes, but production apps should usually choose a
64
+ subset:
65
+
66
+ ```ts
67
+ import {
68
+ ScopeComplianceEvidenceRead,
69
+ ScopeComplianceReportsRead,
70
+ ScopeComplianceTimestampVerify,
71
+ } from '@acosmi/sdk-ts';
72
+
73
+ await client.login('Read-only Compliance App', [
74
+ ScopeComplianceEvidenceRead,
75
+ ScopeComplianceTimestampVerify,
76
+ ScopeComplianceReportsRead,
77
+ ]);
78
+ ```
79
+
80
+ Compliance scopes are independent from `ScopeAI`, `ScopeSkills`, and
81
+ `ScopeAccount`. Holding the general scopes does not grant compliance access.
82
+
83
+ ## Base URL
84
+
85
+ `Client` keeps the existing model gateway path under `/api/v4`. Compliance uses
86
+ `client.complianceURL(path)` and defaults to `${serverURL}/admin-api`, so it does
87
+ not collide with the existing API path.
88
+
89
+ Set `Config.complianceBaseURL` only when compliance is exposed through a
90
+ separate ingress:
91
+
92
+ ```ts
93
+ const client = new Client({
94
+ serverURL: process.env.ACOSMI_SERVER_URL!,
95
+ complianceBaseURL: process.env.ACOSMI_COMPLIANCE_BASE_URL,
96
+ });
97
+ ```
98
+
99
+ ## Idempotency And Retry Rules
100
+
101
+ Every compliance write method accepts `ComplianceWriteOptions`:
102
+
103
+ ```ts
104
+ await client.compliance.publishReport(reportId, {
105
+ idempotencyKey,
106
+ signal,
107
+ });
108
+ ```
109
+
110
+ Persist idempotency keys outside the process before sending a write request.
111
+ After a restart, timeout, network failure, or 401, reuse the same key for the
112
+ same business action.
113
+
114
+ Compliance write methods intentionally do not use automatic retry:
115
+
116
+ - POST/PUT/DELETE write calls do not retry 5xx, 429, timeouts, or transport
117
+ errors.
118
+ - Write calls do not refresh and replay on 401.
119
+ - GET read calls can perform one safe 401 refresh retry.
120
+ - The caller owns user re-authentication and must reuse the same idempotency key
121
+ when resuming the same business action.
122
+
123
+ ## Evidence, Timestamp, And Report Flow
124
+
125
+ ```ts
126
+ const asset = await client.compliance.createEvidenceAsset(
127
+ {
128
+ assetType: 'HASH_ONLY',
129
+ name: 'artifact-manifest',
130
+ hashAlgorithm: 'sha256',
131
+ declaredHash: sha256Hex,
132
+ digestSource: 'CLIENT',
133
+ privacyLevel: 'private',
134
+ },
135
+ { idempotencyKey: assetKey },
136
+ );
137
+
138
+ const token = await client.compliance.issueTimestampForAsset(asset.id, {
139
+ idempotencyKey: timestampKey,
140
+ });
141
+
142
+ await client.compliance.waitForTimestampVerified(token.id);
143
+
144
+ const pkg = await client.compliance.buildEvidencePackage(asset.id, token.id, {
145
+ idempotencyKey: packageKey,
146
+ });
147
+
148
+ const report = await client.compliance.createReport(
149
+ { assetId: asset.id, packageId: pkg.id },
150
+ { idempotencyKey: reportKey },
151
+ );
152
+
153
+ const download = await client.compliance.downloadReport(report.id);
154
+ console.log(download.reportNo, download.packageHash);
155
+ ```
156
+
157
+ `downloadReport` returns an offline verification view: report hash, asset hash,
158
+ package hash, and timestamp summary. It does not include contract body content,
159
+ storage keys, provider raw payloads, or subject snapshots.
160
+
161
+ ## Public Verification
162
+
163
+ `verifyEvidencePublic` returns a privacy-preserving verification result:
164
+
165
+ ```ts
166
+ const result = await client.compliance.verifyEvidencePublic({
167
+ evidenceNo: process.env.EVIDENCE_NO,
168
+ });
169
+
170
+ console.log(result.manifestOfflineVerify);
171
+ ```
172
+
173
+ The public result includes stable evidence and hash fields only. It excludes PII,
174
+ contract originals, storage bucket/key values, subject snapshot IDs, provider raw
175
+ payloads, and timestamp authority internals.
176
+
177
+ ## Signing And Provider Request Polling
178
+
179
+ Signing envelope methods expose the Acosmi workflow state, not provider-specific
180
+ fields. `signEnvelope` and `createH5SigningUrl` can return step-up or gate-closed
181
+ business errors; callers should surface those states instead of retrying.
182
+
183
+ ```ts
184
+ import { BusinessError, classifyComplianceError, isComplianceBusinessError } from '@acosmi/sdk-ts';
185
+
186
+ try {
187
+ await client.compliance.signEnvelope(envelopeId, request, { idempotencyKey });
188
+ } catch (err) {
189
+ if (err instanceof BusinessError && isComplianceBusinessError(err)) {
190
+ const info = classifyComplianceError(err);
191
+ if (info.stepUpRequired) {
192
+ await promptUserToReauthenticate();
193
+ return;
194
+ }
195
+ if (info.terminal) {
196
+ showTerminalComplianceState(info.key);
197
+ return;
198
+ }
199
+ }
200
+ throw err;
201
+ }
202
+ ```
203
+
204
+ Provider request polling is read-only and exposes a public status view:
205
+
206
+ ```ts
207
+ const view = await client.compliance.waitForProviderRequestTerminal(
208
+ providerRequestId,
209
+ { timeoutMs: 30_000 },
210
+ );
211
+
212
+ if (view.status === 'SUCCESS') {
213
+ // Provider success is not a billing commit. Check the envelope/report state.
214
+ }
215
+ ```
216
+
217
+ ## Error Classification
218
+
219
+ Compliance business errors are returned as numeric Java error codes in the
220
+ standard `BusinessError.code` field. The SDK maps those codes to symbolic keys:
221
+
222
+ ```ts
223
+ const info = classifyComplianceError(err);
224
+ switch (info.key) {
225
+ case 'COMPLIANCE_STEP_UP_REQUIRED':
226
+ await promptUserToReauthenticate();
227
+ break;
228
+ case 'ENVELOPE_GATE_CLOSED':
229
+ case 'PROVIDER_NOT_CONFIGURED':
230
+ showTerminalComplianceState(info.key);
231
+ break;
232
+ }
233
+ ```
234
+
235
+ `CompliancePollError` is used by polling helpers for terminal failure, timeout,
236
+ abort, and unknown states.
237
+
238
+ ## Safety Boundary
239
+
240
+ Do not place any of the following in SDK code, tests, examples, docs, git
241
+ history, environment templates, or package tarballs:
242
+
243
+ - Provider endpoints or provider raw request/response payloads.
244
+ - Certificates, private keys, keystores, signing containers, or passwords.
245
+ - Provider product IDs, provider user IDs, transaction codes, project codes, or
246
+ provider seal IDs.
247
+ - Contract originals, PII, storage bucket/key values, subject snapshots, or
248
+ callback billing commit payloads.
249
+
250
+ The Java compliance backend owns provider integration, controlled materials,
251
+ local verification, billing state transitions, and OAuth/JWKS validation. The
252
+ Go OAuth/JWKS layer owns token issuance and introspection. The TypeScript SDK
253
+ only requests scopes, sends Acosmi public DTOs, classifies public errors, and
254
+ polls safe public status views.
255
+
256
+ ## Packaged Examples
257
+
258
+ The npm package includes these examples:
259
+
260
+ - `examples/compliance-read.ts`
261
+ - `examples/compliance-evidence-timestamp.ts`
262
+ - `examples/compliance-envelope.ts`
263
+
264
+ They require caller-provided environment variables and do not contain real
265
+ endpoints, secrets, provider materials, or raw provider payloads.
@@ -0,0 +1,112 @@
1
+ // examples/compliance-envelope.ts — Signing envelope + step-up / gate 错误处理示例。
2
+ //
3
+ // 演示:
4
+ // 1. 创建合同签署 envelope
5
+ // 2. 查询 envelope 状态
6
+ // 3. 正确处理 step-up / gate closed 错误(不重试、不伪成功)
7
+ // 4. 查询 provider request 脱敏状态(SUCCESS 不等于扣费 commit)
8
+ //
9
+ // 红线:
10
+ // - 不传 provider 侧印章、项目或主体字段;这些由后端归一映射。
11
+ // - sign / h5-url 在后端闸门关闭时会返回稳定错误,SDK 不重试、不伪成功。
12
+ // - provider success 不等于 billing committed;最终扣费状态以 envelope 业务字段为准。
13
+
14
+ import {
15
+ BusinessError,
16
+ Client,
17
+ CompliancePollError,
18
+ ScopeComplianceContractSigningRead,
19
+ ScopeComplianceContractSigningWrite,
20
+ ScopeComplianceSealApprovalRequest,
21
+ classifyComplianceError,
22
+ isComplianceBusinessError,
23
+ } from '@acosmi/sdk-ts';
24
+
25
+ async function main() {
26
+ const serverURL = process.env.ACOSMI_SERVER_URL;
27
+ if (!serverURL) {
28
+ throw new Error('ACOSMI_SERVER_URL is required');
29
+ }
30
+ const client = await Client.create({
31
+ serverURL,
32
+ complianceBaseURL: process.env.ACOSMI_COMPLIANCE_BASE_URL,
33
+ });
34
+
35
+ await client.login('Envelope Example', [
36
+ ScopeComplianceContractSigningRead,
37
+ ScopeComplianceContractSigningWrite,
38
+ ScopeComplianceSealApprovalRequest,
39
+ ]);
40
+
41
+ // 1) 创建 envelope (DRAFT)
42
+ const envelopeKey = `envelope-${Date.now()}`;
43
+ const envelopeId = await client.compliance.createSigningEnvelope(
44
+ {
45
+ envelopeNo: `EV-${Date.now()}`,
46
+ requestId: envelopeKey,
47
+ billingGroupId: `BG-${Date.now()}`,
48
+ },
49
+ { idempotencyKey: envelopeKey },
50
+ );
51
+ console.log('[envelope created] id=', envelopeId);
52
+
53
+ // 2) 查询 envelope 详情
54
+ const envelope = await client.compliance.getSigningEnvelope(envelopeId);
55
+ console.log('[envelope detail]', envelope.envelopeNo,
56
+ 'status=', envelope.status,
57
+ 'pendingReason=', envelope.pendingReason);
58
+
59
+ // 3) 试调用 sign — 后端闸门关闭时会失败(ENVELOPE_GATE_CLOSED)
60
+ try {
61
+ await client.compliance.signEnvelope(envelopeId, {
62
+ contractHash: 'dummy-hash',
63
+ idempotencyKey: `sign-${envelopeKey}`,
64
+ });
65
+ } catch (e) {
66
+ if (e instanceof BusinessError && isComplianceBusinessError(e)) {
67
+ const info = classifyComplianceError(e);
68
+ if (info.stepUpRequired) {
69
+ console.warn('[sign] step-up required — 请引导用户重新做 OAuth introspection / 重登录后用同一 idempotency-key 重试');
70
+ } else if (info.key === 'ENVELOPE_GATE_CLOSED') {
71
+ console.warn('[sign] gate closed — 后端闸门未开放,不要重试,向用户展示"功能开放中"');
72
+ } else if (info.terminal) {
73
+ console.warn('[sign] terminal:', info.key, '— 重试无用');
74
+ } else {
75
+ console.warn('[sign] business error:', info.key, info.message);
76
+ }
77
+ } else {
78
+ console.error('[sign] unexpected error:', e);
79
+ }
80
+ }
81
+
82
+ // 4) 查询 provider request 状态 (脱敏)
83
+ const providerRequestId = Number(process.env.PROVIDER_REQUEST_ID ?? 0);
84
+ if (providerRequestId) {
85
+ try {
86
+ const view = await client.compliance.waitForProviderRequestTerminal(providerRequestId, {
87
+ timeoutMs: 30_000,
88
+ });
89
+ console.log('[provider request terminal] status=', view.status,
90
+ 'terminal=', view.terminal,
91
+ 'retryable=', view.retryable);
92
+ if (view.status === 'SUCCESS') {
93
+ console.log('NOTE: provider SUCCESS 不等于 billing committed;以 envelope 的 committedAt 字段为准。');
94
+ }
95
+ } catch (e) {
96
+ if (e instanceof CompliancePollError) {
97
+ if (e.kind === 'timeout') {
98
+ console.warn('[provider request] still pending — DO NOT 重发原请求;下次查询/对账');
99
+ } else if (e.kind === 'terminal_failure') {
100
+ console.warn('[provider request] FAILED — 走人工对账');
101
+ }
102
+ } else {
103
+ throw e;
104
+ }
105
+ }
106
+ }
107
+ }
108
+
109
+ main().catch((err) => {
110
+ console.error('envelope example failed:', err);
111
+ process.exit(1);
112
+ });
@@ -0,0 +1,130 @@
1
+ // examples/compliance-evidence-timestamp.ts — hash-only evidence + timestamp 链路示例。
2
+ //
3
+ // 演示:
4
+ // 1. 本地对普通业务内容做 sha256 (不传原文)
5
+ // 2. 创建 hash-only evidence asset
6
+ // 3. 给资产申请时间章 (持久化 Idempotency-Key)
7
+ // 4. polling 等到本地 verify 通过
8
+ // 5. 构建 evidence package
9
+ // 6. 下载报告所需的离线复核 VO
10
+ //
11
+ // 红线:
12
+ // - 不传 provider 字段;服务端按配置选 provider。
13
+ // - 不读取证书/密钥材料或 provider 签名材料;这些是后端实现细节。
14
+ // - Idempotency-Key 必须在内存外持久化,重启 / 重试时复用同一 key。
15
+
16
+ import { createHash } from 'node:crypto';
17
+ import {
18
+ Client,
19
+ CompliancePollError,
20
+ ScopeComplianceEvidenceRead,
21
+ ScopeComplianceEvidenceWrite,
22
+ ScopeComplianceTimestampIssue,
23
+ ScopeComplianceTimestampVerify,
24
+ ScopeComplianceReportsRead,
25
+ } from '@acosmi/sdk-ts';
26
+
27
+ // 模拟持久化的 Idempotency-Key 存储;生产环境应落 DB / 本地文件 / 业务订单表。
28
+ const KEY_STORE = new Map<string, string>();
29
+
30
+ function loadOrCreateKey(slot: string): string {
31
+ let key = KEY_STORE.get(slot);
32
+ if (!key) {
33
+ key = `${slot}-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
34
+ KEY_STORE.set(slot, key);
35
+ }
36
+ return key;
37
+ }
38
+
39
+ async function main() {
40
+ const serverURL = process.env.ACOSMI_SERVER_URL;
41
+ if (!serverURL) {
42
+ throw new Error('ACOSMI_SERVER_URL is required');
43
+ }
44
+ const client = await Client.create({
45
+ serverURL,
46
+ complianceBaseURL: process.env.ACOSMI_COMPLIANCE_BASE_URL,
47
+ });
48
+
49
+ await client.login('Evidence + Timestamp Example', [
50
+ ScopeComplianceEvidenceRead,
51
+ ScopeComplianceEvidenceWrite,
52
+ ScopeComplianceTimestampIssue,
53
+ ScopeComplianceTimestampVerify,
54
+ ScopeComplianceReportsRead,
55
+ ]);
56
+
57
+ // 1) 本地 sha256 (用户业务内容)
58
+ const content = Buffer.from('release v1.2.3 manifest line-1\nrelease v1.2.3 manifest line-2', 'utf8');
59
+ const sha256 = createHash('sha256').update(content).digest('hex');
60
+
61
+ // 2) 创建 hash-only evidence asset
62
+ const assetKey = loadOrCreateKey('asset:release-v1.2.3');
63
+ const asset = await client.compliance.createEvidenceAsset(
64
+ {
65
+ assetType: 'HASH_ONLY',
66
+ name: 'release-v1.2.3.manifest',
67
+ hashAlgorithm: 'sha256',
68
+ declaredHash: sha256,
69
+ digestSource: 'CLIENT',
70
+ privacyLevel: 'private',
71
+ },
72
+ { idempotencyKey: assetKey },
73
+ );
74
+ console.log('[asset]', asset.id, asset.evidenceNo);
75
+
76
+ // 3) 申请时间章 — Idempotency-Key 持久化复用
77
+ const tsKey = loadOrCreateKey('ts:release-v1.2.3');
78
+ const token = await client.compliance.issueTimestampForAsset(asset.id, {
79
+ idempotencyKey: tsKey,
80
+ });
81
+ console.log('[timestamp issued]', token.id, 'status=', token.verificationStatus);
82
+
83
+ // 4) polling 到本地 verify 通过
84
+ try {
85
+ const verified = await client.compliance.waitForTimestampVerified(token.id, {
86
+ timeoutMs: 60_000,
87
+ initialIntervalMs: 1_000,
88
+ maxIntervalMs: 5_000,
89
+ });
90
+ console.log('[timestamp verified] serial=', verified.serialNumber,
91
+ 'genTime=', verified.genTime);
92
+ } catch (e) {
93
+ if (e instanceof CompliancePollError && e.kind === 'terminal_failure') {
94
+ console.error('time stamp local verify failed — DO NOT retry with same key; 起新链路');
95
+ throw e;
96
+ }
97
+ if (e instanceof CompliancePollError && e.kind === 'timeout') {
98
+ console.warn('timestamp still UNKNOWN; polling timed out — wait for sync or retry later');
99
+ return; // 不自动重发原 provider 请求
100
+ }
101
+ throw e;
102
+ }
103
+
104
+ // 5) 构建 evidence package
105
+ const pkgKey = loadOrCreateKey('pkg:release-v1.2.3');
106
+ const pkg = await client.compliance.buildEvidencePackage(asset.id, token.id, {
107
+ idempotencyKey: pkgKey,
108
+ });
109
+ console.log('[package]', pkg.id, 'manifestHash=', pkg.manifestHash,
110
+ 'packageHash=', pkg.packageHash);
111
+
112
+ // 6) 创建报告并下载离线复核 VO
113
+ const reportKey = loadOrCreateKey('report:release-v1.2.3');
114
+ const report = await client.compliance.createReport(
115
+ { assetId: asset.id, packageId: pkg.id },
116
+ { idempotencyKey: reportKey },
117
+ );
118
+ const download = await client.compliance.downloadReport(report.id);
119
+ console.log('[report download]', download.reportNo,
120
+ 'assetHash=', download.assetContentHash,
121
+ 'tsSerial=', download.timestampSerialNumber);
122
+
123
+ // 持久化 download 到本地文件作为长期可重复验证依据
124
+ // fs.writeFileSync(`./compliance-evidence/${download.reportNo}.json`, JSON.stringify(download, null, 2));
125
+ }
126
+
127
+ main().catch((err) => {
128
+ console.error('evidence + timestamp example failed:', err);
129
+ process.exit(1);
130
+ });
@@ -0,0 +1,72 @@
1
+ // examples/compliance-read.ts — Compliance 只读查询示例。
2
+ //
3
+ // 演示:
4
+ // 1. OAuth 登录 (按业务最小集合申请 compliance scope)
5
+ // 2. 通过 evidence_no 做公开 verify (隐私边界:返回字段不含 PII / 合同原文 / storage)
6
+ // 3. 查询已申请的时间章 / 已发布的报告 / 已创建的签署 envelope
7
+ //
8
+ // 严禁:本示例 / SDK / 仓库不包含 provider endpoint、证书/密钥材料、口令、
9
+ // provider 原始报文、callback billing commit 字段。
10
+
11
+ import {
12
+ Client,
13
+ ScopeComplianceEvidenceRead,
14
+ ScopeComplianceTimestampVerify,
15
+ ScopeComplianceContractSigningRead,
16
+ ScopeComplianceReportsRead,
17
+ } from '@acosmi/sdk-ts';
18
+
19
+ async function main() {
20
+ const serverURL = process.env.ACOSMI_SERVER_URL;
21
+ if (!serverURL) {
22
+ throw new Error('ACOSMI_SERVER_URL is required');
23
+ }
24
+ const client = await Client.create({
25
+ serverURL,
26
+ // complianceBaseURL 不配置 → 默认 ${serverURL}/admin-api。
27
+ // 如部署到独立 ingress,可通过 ACOSMI_COMPLIANCE_BASE_URL 显式设置。
28
+ complianceBaseURL: process.env.ACOSMI_COMPLIANCE_BASE_URL,
29
+ });
30
+
31
+ await client.login('Compliance Read Example', [
32
+ ScopeComplianceEvidenceRead,
33
+ ScopeComplianceTimestampVerify,
34
+ ScopeComplianceContractSigningRead,
35
+ ScopeComplianceReportsRead,
36
+ ]);
37
+
38
+ // === 公开 verify ===
39
+ // 通过对外稳定的 evidence_no 查询。该端点不要求 compliance scope(但带 token 可让审计完整)。
40
+ const evidenceNo = process.env.EVIDENCE_NO ?? 'EV-2026-0001';
41
+ const verifyResult = await client.compliance.verifyEvidencePublic({ evidenceNo });
42
+ console.log('[public verify] manifest offline verify:', verifyResult.manifestOfflineVerify);
43
+ console.log('[public verify] content hash:', verifyResult.contentHash);
44
+ console.log('[public verify] verified at:', verifyResult.verifiedAt);
45
+ // 注意:以下字段不在返回中(隐私边界):
46
+ // - storageBucket / storageKey / subjectSnapshotId
47
+ // - 用户手机号 / 邮箱 / 真实姓名
48
+ // - 合同原文 / provider 内部主体 id / TSA 内部 object id
49
+
50
+ // === 读时间章 / 报告 / envelope ===
51
+ const tokenId = Number(process.env.TIMESTAMP_TOKEN_ID ?? 1);
52
+ const token = await client.compliance.getTimestamp(tokenId);
53
+ console.log('[timestamp]', token.id, 'serialNumber=', token.serialNumber,
54
+ 'status=', token.verificationStatus);
55
+
56
+ const reportId = Number(process.env.REPORT_ID ?? 1);
57
+ const report = await client.compliance.getReport(reportId);
58
+ console.log('[report]', report.id, report.reportNo, 'status=', report.status);
59
+
60
+ // 租户由 access token principal 推导,SDK 不发送 tenant-id header。
61
+ const envelopeId = Number(process.env.ENVELOPE_ID ?? 0);
62
+ if (envelopeId) {
63
+ const envelope = await client.compliance.getSigningEnvelope(envelopeId);
64
+ console.log('[envelope]', envelope.envelopeNo, 'status=', envelope.status,
65
+ 'pendingReason=', envelope.pendingReason);
66
+ }
67
+ }
68
+
69
+ main().catch((err) => {
70
+ console.error('compliance read example failed:', err);
71
+ process.exit(1);
72
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@acosmi/sdk-ts",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "Acosmi 模型网关与 Agent Run Gateway TypeScript SDK — 双格式 (Anthropic + OpenAI) 多端 (浏览器 / Node ≥18 / Deno / Bun)。",
5
5
  "type": "module",
6
6
  "main": "./dist/node/index.cjs",
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "./package.json": "./package.json"
37
37
  },
38
- "files": ["dist", "README.md", "CHANGELOG.md", "LICENSE"],
38
+ "files": ["dist", "README.md", "CHANGELOG.md", "LICENSE", "docs/compliance.md", "examples"],
39
39
  "scripts": {
40
40
  "build": "tsup",
41
41
  "test": "vitest run",