@tier0/sdk-v2 0.8.0 → 0.9.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.
- package/NOTICE.md +3 -1
- package/README.md +45 -11
- package/dist/cjs/capabilities.d.ts +8 -17
- package/dist/cjs/capabilities.js +14 -27
- package/dist/cjs/capabilities.js.map +1 -1
- package/dist/cjs/client.d.ts +524 -3
- package/dist/cjs/client.js +29 -6
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/cloud-transport.d.ts +4 -2
- package/dist/cjs/cloud-transport.js +27 -18
- package/dist/cjs/cloud-transport.js.map +1 -1
- package/dist/cjs/files.d.ts +26 -6
- package/dist/cjs/files.js +151 -28
- package/dist/cjs/files.js.map +1 -1
- package/dist/cjs/index.d.ts +2 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/openapi/api.generated.d.ts +1 -1
- package/dist/cjs/openapi/codecs.generated.d.ts +30 -161
- package/dist/cjs/openapi/codecs.generated.js +1 -1
- package/dist/cjs/openapi/codecs.generated.js.map +1 -1
- package/dist/cjs/openapi/types.generated.d.ts +33 -85
- package/dist/cjs/openapi/types.generated.js.map +1 -1
- package/dist/cjs/runtime.d.ts +13 -0
- package/dist/cjs/runtime.js +51 -0
- package/dist/cjs/runtime.js.map +1 -0
- package/dist/cjs/streams/capabilities.d.ts +8 -0
- package/dist/cjs/streams/capabilities.js +19 -0
- package/dist/cjs/streams/capabilities.js.map +1 -0
- package/dist/cjs/streams/contract.generated.d.ts +802 -0
- package/dist/cjs/streams/contract.generated.js +7 -0
- package/dist/cjs/streams/contract.generated.js.map +1 -0
- package/dist/cjs/streams/index.d.ts +3 -0
- package/dist/cjs/streams/index.js +20 -0
- package/dist/cjs/streams/index.js.map +1 -0
- package/dist/cjs/streams/messages.d.ts +42 -0
- package/dist/cjs/streams/messages.js +514 -0
- package/dist/cjs/streams/messages.js.map +1 -0
- package/dist/cjs/streams/requests.d.ts +93 -0
- package/dist/cjs/streams/requests.js +167 -0
- package/dist/cjs/streams/requests.js.map +1 -0
- package/dist/cjs/streams/transport.d.ts +16 -0
- package/dist/cjs/streams/transport.js +24 -0
- package/dist/cjs/streams/transport.js.map +1 -0
- package/dist/cjs/uns-v2/generated.d.ts +87 -22
- package/dist/cjs/uns-v2/generated.js +43 -8
- package/dist/cjs/uns-v2/generated.js.map +1 -1
- package/dist/esm/capabilities.d.ts +8 -17
- package/dist/esm/capabilities.js +14 -27
- package/dist/esm/capabilities.js.map +1 -1
- package/dist/esm/client.d.ts +524 -3
- package/dist/esm/client.js +27 -5
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/cloud-transport.d.ts +4 -2
- package/dist/esm/cloud-transport.js +27 -18
- package/dist/esm/cloud-transport.js.map +1 -1
- package/dist/esm/files.d.ts +26 -6
- package/dist/esm/files.js +151 -28
- package/dist/esm/files.js.map +1 -1
- package/dist/esm/index.d.ts +2 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/openapi/api.generated.d.ts +1 -1
- package/dist/esm/openapi/codecs.generated.d.ts +30 -161
- package/dist/esm/openapi/codecs.generated.js +1 -1
- package/dist/esm/openapi/codecs.generated.js.map +1 -1
- package/dist/esm/openapi/types.generated.d.ts +33 -85
- package/dist/esm/openapi/types.generated.js.map +1 -1
- package/dist/esm/runtime.d.ts +13 -0
- package/dist/esm/runtime.js +46 -0
- package/dist/esm/runtime.js.map +1 -0
- package/dist/esm/streams/capabilities.d.ts +8 -0
- package/dist/esm/streams/capabilities.js +15 -0
- package/dist/esm/streams/capabilities.js.map +1 -0
- package/dist/esm/streams/contract.generated.d.ts +802 -0
- package/dist/esm/streams/contract.generated.js +6 -0
- package/dist/esm/streams/contract.generated.js.map +1 -0
- package/dist/esm/streams/index.d.ts +3 -0
- package/dist/esm/streams/index.js +4 -0
- package/dist/esm/streams/index.js.map +1 -0
- package/dist/esm/streams/messages.d.ts +42 -0
- package/dist/esm/streams/messages.js +475 -0
- package/dist/esm/streams/messages.js.map +1 -0
- package/dist/esm/streams/requests.d.ts +93 -0
- package/dist/esm/streams/requests.js +161 -0
- package/dist/esm/streams/requests.js.map +1 -0
- package/dist/esm/streams/transport.d.ts +16 -0
- package/dist/esm/streams/transport.js +20 -0
- package/dist/esm/streams/transport.js.map +1 -0
- package/dist/esm/uns-v2/generated.d.ts +87 -22
- package/dist/esm/uns-v2/generated.js +43 -8
- package/dist/esm/uns-v2/generated.js.map +1 -1
- package/package.json +46 -12
- package/skills/tier0-sdk-v2/SKILL.md +3 -2
- package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/multipart.md +23 -8
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/SKILL.md +3 -3
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/create.md +9 -3
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/state.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/update.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/SKILL.md +2 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/create.md +13 -4
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/deploy.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/update.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-streams/SKILL.md +67 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-system/SKILL.md +5 -9
- package/skills/tier0-sdk-v2/tier0-sdk-v2-system/references/info.md +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tier0/sdk-v2",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Tier0 Cloud new-architecture SDK for TypeScript and JavaScript",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -150,22 +150,52 @@
|
|
|
150
150
|
"default": "./dist/cjs/vue.js"
|
|
151
151
|
}
|
|
152
152
|
},
|
|
153
|
-
"./package.json": "./package.json"
|
|
153
|
+
"./package.json": "./package.json",
|
|
154
|
+
"./runtime": {
|
|
155
|
+
"import": {
|
|
156
|
+
"types": "./dist/esm/runtime.d.ts",
|
|
157
|
+
"default": "./dist/esm/runtime.js"
|
|
158
|
+
},
|
|
159
|
+
"require": {
|
|
160
|
+
"types": "./dist/cjs/runtime.d.ts",
|
|
161
|
+
"default": "./dist/cjs/runtime.js"
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
"./streams": {
|
|
165
|
+
"import": {
|
|
166
|
+
"types": "./dist/esm/streams/index.d.ts",
|
|
167
|
+
"default": "./dist/esm/streams/index.js"
|
|
168
|
+
},
|
|
169
|
+
"require": {
|
|
170
|
+
"types": "./dist/cjs/streams/index.d.ts",
|
|
171
|
+
"default": "./dist/cjs/streams/index.js"
|
|
172
|
+
}
|
|
173
|
+
}
|
|
154
174
|
},
|
|
155
175
|
"scripts": {
|
|
156
176
|
"sync:contracts": "node scripts/sync-contracts.mjs",
|
|
157
177
|
"generate": "node scripts/generate-openapi.mjs && node scripts/generate-uns-v2.mjs",
|
|
158
|
-
"check:contracts": "node scripts/check-contracts.mjs && node --test scripts/retired-stream-probe.test.mjs scripts/retired-http-push.test.mjs scripts/retired-controls.test.mjs scripts/retired-public-labels.test.mjs scripts/platform-schema-projection.test.mjs scripts/data-capability-vector.test.mjs scripts/sync-contracts.test.mjs scripts/live-program-contract.test.mjs scripts/sync-http-run-observations.test.mjs && node scripts/generate-openapi.mjs --check && node scripts/generate-uns-v2.mjs --check",
|
|
178
|
+
"check:contracts": "node scripts/check-contracts.mjs && npm run check:acquisition-contract && node scripts/sync-capability-contract.mjs --check && node --test scripts/retired-stream-probe.test.mjs scripts/retired-http-push.test.mjs scripts/retired-controls.test.mjs scripts/retired-public-labels.test.mjs scripts/platform-schema-projection.test.mjs scripts/data-capability-vector.test.mjs scripts/sync-contracts.test.mjs scripts/sync-capability-contract.test.mjs scripts/live-program-contract.test.mjs scripts/sync-http-run-observations.test.mjs && node scripts/generate-openapi.mjs --check && node scripts/generate-uns-v2.mjs --check && npm run check:stream-contract",
|
|
159
179
|
"check:skills": "node scripts/check-skills.mjs && node scripts/check-skill-examples.mjs",
|
|
160
180
|
"typecheck": "tsc --noEmit && tsc -p tsconfig.tests.json",
|
|
161
181
|
"build": "node scripts/build.mjs",
|
|
162
182
|
"prepare": "npm run build",
|
|
163
183
|
"test": "vitest run",
|
|
164
184
|
"check": "npm run check:contracts && npm run check:skills && npm run typecheck && npm test && npm run build && node scripts/check-package.mjs",
|
|
165
|
-
"prepack": "npm run check:contracts && npm run check:skills && npm run build",
|
|
166
|
-
"prepublishOnly": "npm run check"
|
|
185
|
+
"prepack": "node scripts/sync-stream-contract.mjs --check --committed && node scripts/check-contracts.mjs --committed && npm run check:contracts && npm run check:skills && npm run build",
|
|
186
|
+
"prepublishOnly": "node scripts/sync-stream-contract.mjs --check --committed && node scripts/check-contracts.mjs --committed && npm run check",
|
|
187
|
+
"sync:capability-contract": "node scripts/sync-capability-contract.mjs",
|
|
188
|
+
"check:capability-contract": "node scripts/sync-capability-contract.mjs --check",
|
|
189
|
+
"sync:acquisition-contract": "node scripts/sync-acquisition-contract.mjs",
|
|
190
|
+
"check:acquisition-contract": "node scripts/sync-acquisition-contract.mjs --check && node --test scripts/sync-acquisition-contract.node.mjs",
|
|
191
|
+
"sync:stream-contract": "node scripts/sync-stream-contract.mjs",
|
|
192
|
+
"check:stream-contract": "node scripts/sync-stream-contract.mjs --check && openapi-typescript contracts/openapi/streams.swagger.json -o src/streams/contract.generated.ts --default-non-nullable=false --check",
|
|
193
|
+
"test:streams:nats": "node scripts/test-stream-messages-nats.mjs",
|
|
194
|
+
"test:streams:artifact": "npm run build && node scripts/test-stream-messages-nats.mjs --artifact"
|
|
167
195
|
},
|
|
168
196
|
"dependencies": {
|
|
197
|
+
"@nats-io/nats-core": "3.3.1",
|
|
198
|
+
"@nats-io/nkeys": "2.0.3",
|
|
169
199
|
"mqtt": "^5.3.0"
|
|
170
200
|
},
|
|
171
201
|
"peerDependencies": {
|
|
@@ -189,19 +219,19 @@
|
|
|
189
219
|
}
|
|
190
220
|
},
|
|
191
221
|
"devDependencies": {
|
|
222
|
+
"@tanstack/react-query": "^5.0.0",
|
|
192
223
|
"@types/node": "^22.0.0",
|
|
193
224
|
"@types/react": "^19.0.0",
|
|
194
|
-
"
|
|
225
|
+
"ajv": "^8.20.0",
|
|
226
|
+
"ajv-formats": "^3.0.1",
|
|
227
|
+
"esbuild": "^0.25.0",
|
|
228
|
+
"openapi-typescript": "^7.0.0",
|
|
195
229
|
"react": "^19.0.0",
|
|
196
|
-
"vue": "^3.4.0",
|
|
197
230
|
"typescript": "~5.9.3",
|
|
198
|
-
"openapi-typescript": "^7.0.0",
|
|
199
231
|
"vitest": "^4.1.7",
|
|
200
|
-
"
|
|
232
|
+
"vue": "^3.4.0",
|
|
201
233
|
"yaml": "^2.8.0",
|
|
202
|
-
"zod": "^4.0.0"
|
|
203
|
-
"ajv": "^8.20.0",
|
|
204
|
-
"ajv-formats": "^3.0.1"
|
|
234
|
+
"zod": "^4.0.0"
|
|
205
235
|
},
|
|
206
236
|
"agents": {
|
|
207
237
|
"skills": [
|
|
@@ -248,6 +278,10 @@
|
|
|
248
278
|
{
|
|
249
279
|
"name": "tier0-sdk-v2-data",
|
|
250
280
|
"path": "./skills/tier0-sdk-v2/tier0-sdk-v2-data"
|
|
281
|
+
},
|
|
282
|
+
{
|
|
283
|
+
"name": "tier0-sdk-v2-streams",
|
|
284
|
+
"path": "./skills/tier0-sdk-v2/tier0-sdk-v2-streams"
|
|
251
285
|
}
|
|
252
286
|
]
|
|
253
287
|
}
|
|
@@ -13,6 +13,7 @@ description: 使用 @tier0/sdk-v2 开发或迁移 Tier0 云端 TypeScript/JavaSc
|
|
|
13
13
|
| --- | --- | --- |
|
|
14
14
|
| 连接外部系统、维护采集源、检查连接和影响范围 | `client.source` | [Source](tier0-sdk-v2-source/SKILL.md) |
|
|
15
15
|
| 编写处理程序、配置源绑定、校验和发布、查运行记录 | `client.stream` | [Stream](tier0-sdk-v2-stream/SKILL.md) |
|
|
16
|
+
| 调用业务请求、发布或订阅业务消息、查询 App 交互能力 | `client.streams` | [App Stream 交互](tier0-sdk-v2-streams/SKILL.md) |
|
|
16
17
|
| 集合、目录、Topic、业务记录、历史采样与事务 | `client.uns` | [UNS](tier0-sdk-v2-uns/SKILL.md) |
|
|
17
18
|
| App 自有业务数据:声明集合、Mongo 风格读写与事务 | `@tier0/sdk-v2/data` | [App 数据](tier0-sdk-v2-data/SKILL.md) |
|
|
18
19
|
| 站内信、Web/Desktop 提醒、手机推送 | `client.notifications` | [通知](tier0-sdk-v2-notifications/SKILL.md) |
|
|
@@ -36,7 +37,7 @@ export async function inspectConnection() {
|
|
|
36
37
|
}
|
|
37
38
|
```
|
|
38
39
|
|
|
39
|
-
也可传 `apiHost`、`apiKey` 或 `getApiHost` / `getApiKey` 回调。API Key 留在服务端;不要生成 `VITE_*KEY` 或让页面携带 App Key
|
|
40
|
+
也可传 `apiHost`、`apiKey` 或 `getApiHost` / `getApiKey` 回调。API Key 留在服务端;不要生成 `VITE_*KEY` 或让页面携带 App Key。浏览器通过自己的服务端接口访问平台;App Stream 交互使用根入口 `client` 和受信宿主注入,无需设置密钥。消息要求 WebSocket(Node.js 22+ 或浏览器)。
|
|
40
41
|
|
|
41
42
|
不同身份使用独立实例。含员工数据委托时,每个入站请求新建实例,使用受信 App Gateway 提供的 `unsV2AppDataSubject`;它不是用户 ID,也不是 App 请求验签断言。不要从请求 JSON 拼造委托。身份验签流程见 [身份与框架集成](references/integration.md)。
|
|
42
43
|
|
|
@@ -64,6 +65,6 @@ export async function inspectConnection() {
|
|
|
64
65
|
|
|
65
66
|
React/Vue 示例与验签见 [集成参考](references/integration.md)。完成接入时验证目标入口、真实身份、响应解包和错误分支;SDK 本地测试通过不代表环境联调完成。
|
|
66
67
|
|
|
67
|
-
Stream
|
|
68
|
+
Stream 请求与消息交互统一使用本包 `client.streams.requests` / `client.streams.messages`;[交互说明](tier0-sdk-v2-streams/SKILL.md)。Scaffold 只依赖本包;`client.stream` 管理接口与运行时交互用途不同。
|
|
68
69
|
|
|
69
70
|
本包公开 HTTP 入口统一为 `/openapi/v2`。旧的重复操作已退役,不生成兼容调用或回退。Source 配置用 documents.*,Stream 草稿用 documents.*、发布用 programs.deploy;App 数据层仍提供 insertMany/findOneAnd*/distinct 等便捷方法。历史旧写结果未知时先核对业务状态,不能转换路由后盲目重放。
|
|
@@ -1,20 +1,26 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 分片上传、进度和续传
|
|
2
2
|
|
|
3
3
|
| 调用 | 行为 |
|
|
4
4
|
| --- | --- |
|
|
5
5
|
| files.upload(file) | 大于 100 MiB 自动分片 |
|
|
6
|
+
| files.upload(file, { multipart: options }) | 任意非空文件显式分片;业务元数据仍放在 multipart 外层 |
|
|
6
7
|
| files.uploadMultipart(file, options) | 非空文件显式分片,可报告进度 |
|
|
7
|
-
| files.
|
|
8
|
+
| files.resumeMultipart(file, session, options) | 复用会话,跳过已确认的分片,再提交完成 |
|
|
9
|
+
| files.multipart.init/partUrls/complete/abort | 原子接口,普通业务上传使用上面的助手 |
|
|
8
10
|
|
|
9
11
|
| options 字段 | 类型 | 说明 |
|
|
10
12
|
| --- | --- | --- |
|
|
11
13
|
| partSize | number | 默认 8 MiB,至少 5 MiB;实际采用服务器返回值 |
|
|
12
|
-
|
|
|
14
|
+
| concurrency | number | 默认 4,同时上传的分片上限,至少 1 |
|
|
15
|
+
| maxRetries | number | 默认 3,每个存储 PUT 的额外重试次数,可设为 0 |
|
|
16
|
+
| onProgress | function | 收到 uploadedBytes、totalBytes、doneParts、totalParts、percent(0–100) |
|
|
13
17
|
| signal | AbortSignal | 取消等待/传输 |
|
|
14
18
|
| 其余上传元数据 | string | 与 upload 相同 |
|
|
15
19
|
|
|
20
|
+
resumeMultipart 只接收 concurrency、maxRetries、onProgress、signal;文件元数据和服务器 partSize 来自 session。进度按收到 ETag 的已完成分片计算,续传时包含此前已完成的分片。
|
|
21
|
+
|
|
16
22
|
```ts
|
|
17
|
-
import { createClient, MultipartUploadError, type Tier0Client } from '@tier0/sdk-v2';
|
|
23
|
+
import { createClient, MultipartUploadError, type MultipartSession, type Tier0Client } from '@tier0/sdk-v2';
|
|
18
24
|
|
|
19
25
|
export async function uploadWithProgress(
|
|
20
26
|
file: File, report: (uploadedBytes: number, totalBytes: number) => void,
|
|
@@ -22,7 +28,7 @@ export async function uploadWithProgress(
|
|
|
22
28
|
) {
|
|
23
29
|
try {
|
|
24
30
|
const saved = await client.files.uploadMultipart(file, {
|
|
25
|
-
partSize: 8 * 1024 * 1024, signal,
|
|
31
|
+
partSize: 8 * 1024 * 1024, concurrency: 4, maxRetries: 3, signal,
|
|
26
32
|
onProgress: progress => report(progress.uploadedBytes, progress.totalBytes),
|
|
27
33
|
});
|
|
28
34
|
return { state: 'completed' as const, filePath: saved.filePath };
|
|
@@ -33,10 +39,19 @@ export async function uploadWithProgress(
|
|
|
33
39
|
throw error;
|
|
34
40
|
}
|
|
35
41
|
}
|
|
42
|
+
|
|
43
|
+
export async function resumeUpload(
|
|
44
|
+
originalFile: File, session: MultipartSession,
|
|
45
|
+
client: Tier0Client = createClient(), signal?: AbortSignal,
|
|
46
|
+
) {
|
|
47
|
+
return client.files.resumeMultipart(originalFile, session, { concurrency: 4, signal });
|
|
48
|
+
}
|
|
36
49
|
```
|
|
37
50
|
|
|
38
|
-
成功后才持久化 filePath。中断 session 包含 fileKey、uploadId、parts(partNumber/etag)、completionAttempted
|
|
51
|
+
成功后才持久化 filePath。中断 session 包含 fileKey、uploadId、parts(partNumber/etag)、completionAttempted,以及续传所需的 fileName、fileSize、服务器 partSize。会话不是完成回执,不公开到日志或无关用户。
|
|
52
|
+
|
|
53
|
+
失败时停止领取新分片,等待在途分片结束后返回稳定的 session;不会自动 abort 或在失败后暗中 complete。续传使用原文件(名称和大小必须匹配),保留已确认的 ETag,只重新传输缺少回执的分片。旧 session 若缺少文件信息或服务器 partSize,会明确拒绝续传,不推测分片边界。跨域存储需要暴露 ETag 响应头。
|
|
39
54
|
|
|
40
|
-
|
|
55
|
+
自动重试仅限同一签名地址、同一分片内容的存储 PUT 网络中断、超时或 HTTP 408/429/500/502/503/504;同一 uploadId/partNumber 的 PUT 可覆盖。401/403、用户取消以及平台 init/partUrls/complete 请求不会自动重试。存储请求不携带平台密钥。签名过期可再次 resumeMultipart 获取新的分片地址。
|
|
41
56
|
|
|
42
|
-
completionAttempted=true 表示 complete
|
|
57
|
+
completionAttempted=true 表示 complete 已尝试提交,结果可能未知,resumeMultipart 会拒绝重放;先对账最终文件,不手动清除该标记或直接 abort。明确放弃未完成会话时才调用 abort;初始化请求本身结果未知且无 session 时,保存错误信息交由平台对账,不猜 uploadId。
|
|
@@ -12,7 +12,7 @@ Source 维护连接配置、认证引用与源状态。脚本处理用 [Stream](
|
|
|
12
12
|
| 用户任务 | 参考 | SDK 方法 |
|
|
13
13
|
| --- | --- | --- |
|
|
14
14
|
| 选协议、准备连接配置 | [协议配置](references/protocols.md) | protocols.list |
|
|
15
|
-
| 创建 HTTP
|
|
15
|
+
| 创建 HTTP/SQL 带凭据源 | [创建](references/create.md) | documents.create |
|
|
16
16
|
| 列表、详情、运行状态 | [查询](references/read.md) | documents.list/get、observations.get、runtime.get |
|
|
17
17
|
| 修改名称、端点或配置 | [修改](references/update.md) | documents.update |
|
|
18
18
|
| 查看修改/启停/删除影响 | [影响分析](references/changes.md) | impact |
|
|
@@ -26,12 +26,12 @@ Source 维护连接配置、认证引用与源状态。脚本处理用 [Stream](
|
|
|
26
26
|
1. Source 配置统一使用 documents.*,原生文档为 `{name,protocol,config}`,HTTP API 显式指定 `config.role`。HTTP 统一为 `protocol: http-api` + `config.role: client/server`;Client 主动请求,Server 接收入站请求,不能互换。HTTPServer 统一接收入站请求,固定前缀后的路由和响应时机属于 Stream。
|
|
27
27
|
2. 已有 ID 和 revision 时优先用 documents.update 的 patch,避免额外 get;完整替换 document 前读取完整文档,安全列表摘要不能无损回写。原生 ID 是十进制字符串,revision 原样传递,不转 Number。
|
|
28
28
|
3. 现有 Source 修改、启停、删除都要 expectedRevision。没有任何 Stream 引用时可直接提交;有草稿、活动、历史或不可见引用时仍需 confirmedImpactRevision。先形成精确意图,再读取全部影响分页;回执不可合成、跨意图复用或静默刷新。提供的回执始终严格校验,不自动获取并同意影响。
|
|
29
|
-
4. 配置中保留认证/TLS 引用,不写明文秘密;HTTP Client 新凭据走创建专用 credentials
|
|
29
|
+
4. 配置中保留认证/TLS 引用,不写明文秘密;HTTP Client 与 SQL 新凭据走创建专用 credentials(SQL 使用 usernamePassword,省略 method),普通创建省略 credentials.method(服务端默认 REQUEST 基址绑定),真实 method/path/query 由 Stream 定义。Basic/Bearer 显式凭据方法限制精确 URL 和方法,OAuth 旧 GET 保留既有兼容语义,不自动扩大旧授权;Server 不携带 Client auth/TLS 配置。
|
|
30
30
|
5. desiredState 不代表实际健康,保存配置不代表 Stream 已切换至新 configRevision。运行状态另行读取。
|
|
31
31
|
|
|
32
32
|
## 返回值与异常
|
|
33
33
|
|
|
34
|
-
所有调用返回完整 code/msg/requestId/data。documents.create/update 的预检返回 validated/sideEffects,提交返回完整 Source view,可直接使用其中的文档和 revision,无需额外 get;批量状态/删除返回 Outcome。只有 committed 且无项错误才可报告提交成功;accepted/jobId
|
|
34
|
+
所有调用返回完整 code/msg/requestId/data。documents.create/update 的预检返回 validated/sideEffects,提交返回完整 Source view,可直接使用其中的文档和 revision,无需额外 get;批量状态/删除返回 Outcome。只有 committed 且无项错误才可报告提交成功;accepted/jobId 继续查询作业。创建、更新、状态变更的 dryRun 默认 false;预检按需使用,不是每次提交的必经步骤。
|
|
35
35
|
|
|
36
36
|
需要查看历史用 source.history({id,beforeRevision,size}),按 nextBeforeRevision 继续;探测用 source.probe,其外部系统访问应属于当前任务。配置校验或连接探测成功不证明某个 Stream 请求已获授权或采集成功,实际结果看对应发布的 runs。连接配置修改使用 documents.update,遵守同一影响确认契约。
|
|
37
37
|
|
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
| 字段 | 类型 | 必填 | 说明 |
|
|
6
6
|
| --- | --- | --- | --- |
|
|
7
|
-
| dryRun | boolean |
|
|
7
|
+
| dryRun | boolean | 否 | 默认 false 提交;true 仅预检 |
|
|
8
8
|
| document.name | string | 是 | 1–128 字符 |
|
|
9
9
|
| document.protocol | string | 是 | 原生协议,如 http-api、mqtt、modbus |
|
|
10
10
|
| document.config.role | client / server | HTTP API 显式指定 | client 主动请求;server 接收入站请求 |
|
|
11
11
|
| document.config | object | 是 | endpoint、options;见[协议配置](protocols.md) |
|
|
12
12
|
| document.description | string | 否 | 最多 512 字符 |
|
|
13
|
-
| credentials | object | 否 |
|
|
13
|
+
| credentials | object | 否 | HTTP Client 或 SQL 的只写新凭据;与已有 auth 引用互斥 |
|
|
14
14
|
| idempotencyKey | string | 否 | 建议提供,最多 128 字符,同一业务意图保持不变 |
|
|
15
15
|
|
|
16
16
|
## 完整示例:HTTP Client 数据源
|
|
@@ -90,7 +90,7 @@ Server 的固定前缀 `/ingest/v1/{workspaceId}/{sourceId}` 和 Bearer 要求
|
|
|
90
90
|
|
|
91
91
|
## 四类 inline 认证与 REQUEST 绑定
|
|
92
92
|
|
|
93
|
-
单条创建可通过 `credentials` 提供以下只写材料;与已有 auth/TLS
|
|
93
|
+
HTTP Client 单条创建可通过 `credentials` 提供以下只写材料;与已有 auth 引用互斥,HTTP/SQL 当前不支持 TLS 凭据引用,并要求本次创建的 `idempotencyKey`。材料从调用方已授权的密钥提供者注入,不在示例中读取文件或环境中的秘密,不记录或返回材料。
|
|
94
94
|
|
|
95
95
|
| kind | material | method |
|
|
96
96
|
| --- | --- | --- |
|
|
@@ -120,3 +120,9 @@ export async function createHttpSourceWithCredentials(
|
|
|
120
120
|
return { receipt: saved, current: saved.data };
|
|
121
121
|
}
|
|
122
122
|
```
|
|
123
|
+
|
|
124
|
+
## SQL 用户名和密码
|
|
125
|
+
|
|
126
|
+
SQL 单条创建可直接传入 `credentials: { kind: "usernamePassword", material: { username, password } }`,不再预先调用独立凭据接口。`document.protocol` 为 `sql`,`config.endpoint` 只包含数据库地址(不包含用户名或密码),`credentials.method` 必须省略。仍需 `idempotencyKey`。秘密由 Vault 保存,Source 文档仅含引用;预检不写入凭据。
|
|
127
|
+
|
|
128
|
+
`dryRun` 省略时直接提交;需要预检才设为 true。后续启用 Source、部署 Stream,并通过运行记录和 Collection 读回确认采集成功。
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
| 字段 | 类型 | 必填 | 说明 |
|
|
6
6
|
| --- | --- | --- | --- |
|
|
7
|
-
| dryRun | boolean |
|
|
7
|
+
| dryRun | boolean | 否 | 默认 false 提交;true 仅预检 |
|
|
8
8
|
| items[].id / expectedRevision | string / integer | 是 | 当前对象和已知修订 |
|
|
9
9
|
| items[].desiredState | enabled/disabled | 是 | 目标状态 |
|
|
10
10
|
| items[].confirmedImpactRevision | string | 有引用时 | enable/disable 对应的影响回执 |
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
| patch / document | object / CloudSourceDocument | 二选一 | patch 保留未提供的字段;document 完整替换 |
|
|
9
9
|
| expectedRevision | integer | 是 | 已读取或上次提交返回的 revision,原样传回 |
|
|
10
10
|
| confirmedImpactRevision | string | 有引用时 | 相同修改意图和修订的 impact 回执 |
|
|
11
|
-
| dryRun | boolean |
|
|
11
|
+
| dryRun | boolean | 否 | 默认 false 提交;true 仅预检 |
|
|
12
12
|
| idempotencyKey | string | 否 | 最多 128 字符 |
|
|
13
13
|
|
|
14
14
|
## 示例:一次请求修改名称
|
|
@@ -26,7 +26,7 @@ description: 使用 @tier0/sdk-v2 的 client.stream 创建、查询、修改和
|
|
|
26
26
|
| Runtime program | name、script 字符串、sourceBindings、timeoutMs | documents.create/update/validate({program}) |
|
|
27
27
|
| 云端原生文档 | name、model、script 对象、sources、entries | documents.create/get/update/validate |
|
|
28
28
|
|
|
29
|
-
程序必须是完整 `module.exports = api => { ... }`,执行器 API 是 api.sources/api.uns/api.stream,与 npm 包的 client.source 不同。Runtime sourceBindings 为 sourceId/configRevision/acquisition;原生 sources 还使用 alias/resources。连接凭据不进脚本或 acquisition,秘密材料由 Source 执行宿主管理,不通过脚本读取、记录或返回。定时入口使用 api.stream.every,不传播旧注册别名;App
|
|
29
|
+
程序必须是完整 `module.exports = api => { ... }`,执行器 API 是 api.sources/api.uns/api.stream,与 npm 包的 client.source 不同。Runtime sourceBindings 为 sourceId/configRevision/acquisition;原生 sources 还使用 alias/resources。连接凭据不进脚本或 acquisition,秘密材料由 Source 执行宿主管理,不通过脚本读取、记录或返回。定时入口使用 api.stream.every,不传播旧注册别名;App 请求与消息交互由本包 @tier0/sdk-v2 的 client.streams.requests/messages 提供,不作为 Goja 注册参数。
|
|
30
30
|
|
|
31
31
|
## 核心约束
|
|
32
32
|
|
|
@@ -37,6 +37,7 @@ description: 使用 @tier0/sdk-v2 的 client.stream 创建、查询、修改和
|
|
|
37
37
|
5. resources=[] 是空冻结资源集,不是通配符。写入本身由服务端校验,需要预览时单独 validate;当前云端程序 timeoutMs 上限 30000。
|
|
38
38
|
6. HTTPServer 响应时机在 Stream:普通返回等处理/提交完成;HTTP onRequest 内 await ctx.reply 可先回复一次再继续,仍受超时/并发/权限约束,断线不取消但 shutdown 可取消,不保证崩溃重放。
|
|
39
39
|
7. 仅执行用户要求的生命周期步骤;修改脚本不自动授予发布、停用或删除权限。
|
|
40
|
+
8. 用户要求采集落库时,先创建或复用 Collection 并确定字段映射与稳定 recordId,再绑定已启用 Source 的最新修订;脚本显式 api.uns.use(...).write。部署后核对实际运行并读回记录,返回上游结果、保存草稿或样例预演均不代表已落库。
|
|
40
41
|
|
|
41
42
|
## 成功与异常
|
|
42
43
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
| 字段 | 类型 | 必填 | 说明 |
|
|
6
6
|
| --- | --- | --- | --- |
|
|
7
|
-
| dryRun | boolean |
|
|
7
|
+
| dryRun | boolean | 否 | 默认 false 提交;true 仅预检 |
|
|
8
8
|
| program.name | string | 是 | 1–63 字符 |
|
|
9
9
|
| program.script | string | 是 | 完整 module.exports 程序 |
|
|
10
10
|
| program.timeoutMs | integer | 否 | 当前云端上限 30000 ms |
|
|
@@ -21,8 +21,9 @@ Source 负责基址和认证,Stream 负责请求的 method/path/query。以下
|
|
|
21
21
|
import { createClient, type Tier0Client, type RuntimeStreamDefinition, type CloudSourceDocumentView } from '@tier0/sdk-v2';
|
|
22
22
|
|
|
23
23
|
export async function createHttpStream(
|
|
24
|
-
source: CloudSourceDocumentView, name: string, intentKey: string, client: Tier0Client = createClient(),
|
|
24
|
+
source: CloudSourceDocumentView, collectionId: string, name: string, intentKey: string, client: Tier0Client = createClient(),
|
|
25
25
|
) {
|
|
26
|
+
if (!collectionId.trim()) throw new Error('需要实际 Collection ID');
|
|
26
27
|
const sourceId = source.id;
|
|
27
28
|
if (!/^[1-9][0-9]*$/.test(sourceId)) throw new Error('Source ID 必须是正十进制字符串');
|
|
28
29
|
if (source.document.protocol !== 'http-api' || 'sourceType' in source.document.config ||
|
|
@@ -35,11 +36,17 @@ export async function createHttpStream(
|
|
|
35
36
|
script: [
|
|
36
37
|
'module.exports = api => {',
|
|
37
38
|
' const upstream = api.sources.use({ id: ' + JSON.stringify(sourceId) + ', resources: [] });',
|
|
39
|
+
' const output = api.uns.use({ collectionId: ' + JSON.stringify(collectionId) + ', access: "write" });',
|
|
38
40
|
' api.stream.every({ id: "tick", intervalMs: 60000 }, async () => {',
|
|
39
41
|
' const response = await upstream.request({ method: "GET", path: "inventory", query: { limit: "5000" } });',
|
|
40
42
|
' if (response.status !== 200) throw new Error("Upstream inventory HTTP request failed");',
|
|
41
43
|
' if (!Array.isArray(response.data)) throw new Error("Unexpected upstream inventory response format");',
|
|
42
|
-
'
|
|
44
|
+
' const records = response.data.map(row => {',
|
|
45
|
+
' if (!row || typeof row.sku !== "string" || !row.sku.trim() || typeof row.quantity !== "number" || !Number.isFinite(row.quantity)) throw new Error("Invalid inventory row");',
|
|
46
|
+
' return { recordId: row.sku, record: { sku: row.sku, quantity: row.quantity } };',
|
|
47
|
+
' });',
|
|
48
|
+
' for (const record of records) await output.write(record);',
|
|
49
|
+
' return { acceptedRows: records.length };',
|
|
43
50
|
' });',
|
|
44
51
|
'};',
|
|
45
52
|
].join('\n'),
|
|
@@ -52,7 +59,9 @@ export async function createHttpStream(
|
|
|
52
59
|
}
|
|
53
60
|
```
|
|
54
61
|
|
|
55
|
-
|
|
62
|
+
先创建或复用真实 Collection,再传入 collectionId;此库存示例的 recordSchema 必须包含 sku(string)与 quantity(number),以业务 SKU 作为稳定 recordId。按真实上游合同修改字段映射、path="inventory"、query 和 60 秒周期;不能只返回 response.data 就声称已经落库。resources=[] 是空冻结资源集,不是通配授权。源地址和凭据留在 Source,不能拷进 acquisition 或脚本。
|
|
63
|
+
|
|
64
|
+
此函数保存草稿。完整采集还需启用 Source,取得最新 revision 后更新绑定并部署 Stream;核对本次发布的运行成功,再通过 records:find 读回目标 Collection 的业务记录。acceptedRows 只表示处理器已接受写入,隔离 sampleTest 的 writePreview 不会落库;未完成真实运行和读回前,不得报告采集完成。
|
|
56
65
|
|
|
57
66
|
`upstream.request` 收到完整的 401/403/429/5xx 响应时仍返回 `{status,headers,data}`,不会仅因非 2xx 自动抛错;必须先检查状态,再校验业务数据,最后才缓冲 UNS 写入。此库存示例约定 200 和数组;其他接口按其合同调整,不能把错误响应当业务数据。脚本异常只使用固定文案,不拼接响应正文、认证头或 URL。
|
|
58
67
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
| 方法 | POST 路径 | 必要参数 |
|
|
4
4
|
| --- | --- | --- |
|
|
5
|
-
| programs.deploy | /openapi/v2/uns/streams/program/deploy | id
|
|
5
|
+
| programs.deploy | /openapi/v2/uns/streams/program/deploy | id;dryRun 默认 false,建议 expectedRevision |
|
|
6
6
|
| programs.rollback | /openapi/v2/uns/streams/program/rollback | id、versionId、dryRun;建议 expectedRevision |
|
|
7
7
|
| documents.disable | /openapi/v2/uns/streams/documents/disable | id、expectedRevision、expectedActiveRelease、dryRun |
|
|
8
8
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
| id | string | 是 | 十进制字符串 |
|
|
8
8
|
| document | CloudStreamDocument | 是 | name、model、script、sources、entries 完整文档 |
|
|
9
9
|
| expectedRevision | integer | 建议始终提供 | 当前回执或查询的修订,防止覆盖他人修改 |
|
|
10
|
-
| dryRun | boolean |
|
|
10
|
+
| dryRun | boolean | 否 | 默认 false 提交;true 仅预检 |
|
|
11
11
|
| idempotencyKey | string | 否 | 本次更新独立意图键 |
|
|
12
12
|
|
|
13
13
|
## 示例:更新描述,保持脚本和绑定
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tier0-sdk-v2-streams
|
|
3
|
+
description: "Tier0 App/Stream requests and live business messages: client.streams.requests describe/invoke/discover, client.streams.messages publish/subscribe, trusted App runtime bootstrap and disposable subscriptions. Use for Stream v3 interactions; UNS history, device MQTT and persisted notifications have their own Skills."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# App / Stream Interactions
|
|
7
|
+
|
|
8
|
+
Read the [root Skill](../SKILL.md) first. These APIs require an artifact built from the unified SDK implementation: pin its commit and SHA-256 until the corresponding version is published.
|
|
9
|
+
|
|
10
|
+
## Select the interaction
|
|
11
|
+
|
|
12
|
+
- A public request code with an input/output contract: `client.streams.requests.use({ code })`. Use `describe()` to inspect it; use `client.streams.requests.discover()` to find visible contracts.
|
|
13
|
+
- App request capability discovery: `client.streams.capabilities.discover()`. It validates request/invoke contracts independently of `client.capabilities.discover()`, which covers Namespace/Source/Stream management. Neither grants access or requires a mandatory preflight before every call.
|
|
14
|
+
- A live logical business topic: `client.streams.messages.use({ topic })`. Use `publish(payload)` or `subscribe(handler)` and dispose the returned subscription.
|
|
15
|
+
- Persisted business data belongs to UNS, device-topic MQTT belongs to the MQ Skill, and user-facing notification records belong to the Notifications Skill. Live Stream messages have no retention or replay.
|
|
16
|
+
|
|
17
|
+
Import `client` or `createClient` from `@tier0/sdk-v2`. The same client exposes `uns`, `source`, `stream`, `capabilities`, `files` and `notifications`. The singular `stream` manages documents, programs and runs; plural `streams` performs App requests and live messaging. MQTT stays in the separate `/mq` entry.
|
|
18
|
+
|
|
19
|
+
## Trusted App bootstrap
|
|
20
|
+
|
|
21
|
+
The SWE host installs `globalThis[Symbol.for('tier0.sdk.app-runtime.v1')]` before the App script. The SDK detects it automatically; App business code must not install a replacement provider or resolve credentials itself. The host's provider returns a `Response` for its authenticated request bridge.
|
|
22
|
+
|
|
23
|
+
Browser App code knows only public request codes, logical topics and business payloads. Do not add broker URLs, physical subjects, API keys, JWTs, nkey seeds, workspace/principal headers or message identity claims to App configuration. `@tier0/sdk-v2/runtime` is a trusted host integration entry point, not App setup.
|
|
24
|
+
|
|
25
|
+
For a standalone Node service, the deployment supplies its existing HTTP credential and real App context. Call `createClient()` without literals; never put these server credentials in a browser bundle.
|
|
26
|
+
|
|
27
|
+
## Public caller
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { createClient, type StreamMessageError } from '@tier0/sdk-v2';
|
|
31
|
+
|
|
32
|
+
export async function openOrders(
|
|
33
|
+
reportError: (error: StreamMessageError) => void,
|
|
34
|
+
renderOrderUpdate: (order: { orderId: string }) => void,
|
|
35
|
+
) {
|
|
36
|
+
const sdk = createClient(); // automatically uses the trusted App runtime
|
|
37
|
+
const removeErrorHandler = sdk.streams.messages.onError(reportError);
|
|
38
|
+
const subscription = await sdk.streams.messages.use<{ orderId: string }>({ topic: 'orders/accepted' })
|
|
39
|
+
.subscribe(message => renderOrderUpdate(message.payload));
|
|
40
|
+
const request = sdk.streams.requests.use<{ orderId: string }, { accepted: boolean }>({ code: 'orders.approve' });
|
|
41
|
+
return {
|
|
42
|
+
describe: () => request.describe(),
|
|
43
|
+
approve: (orderId: string, savedIntentId: string) => request.invoke({ orderId }, { idempotencyKey: savedIntentId }),
|
|
44
|
+
async dispose() {
|
|
45
|
+
await subscription.dispose();
|
|
46
|
+
removeErrorHandler();
|
|
47
|
+
await sdk.dispose();
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Persist one caller-owned idempotency key per business intent. A deliberate reconciliation/replay reuses that key. The SDK never generates a request idempotency key, selects deployment versions or retries a write. An unknown result means execution may have happened; reconcile the returned run metadata before any further business action.
|
|
54
|
+
|
|
55
|
+
## Live message lifecycle
|
|
56
|
+
|
|
57
|
+
Messages use a versioned `{ version, messageId, correlationId?, payload }` envelope. Caller-supplied identity in a payload is business data, not authenticated publisher metadata; authorized broker subjects establish identity internally.
|
|
58
|
+
|
|
59
|
+
The SDK uses native Core NATS over WSS, loaded only when messaging starts. Messages require a browser with WebSocket or Node.js 22+; HTTP-only clients remain usable on Node.js 20.19+. Each initial connection, reconnect and renewal gets a new in-memory user key and a public-key-bound JWT. The old socket closes and its private key is wiped before replacement. No private key leaves the SDK. A successful publish means broker flush, not receiver acknowledgement.
|
|
60
|
+
|
|
61
|
+
Register `messages.onError` (or subscription `onError`) to handle asynchronous broker, decoding and handler failures. After an established session disconnects, publish fails immediately: no offline buffering, write retry or message replay. Credential refresh and reconnection restore subscriptions only. Dispose subscriptions and the owned client when the view/service stops.
|
|
62
|
+
|
|
63
|
+
## Stream-side code
|
|
64
|
+
|
|
65
|
+
Current Cloud Source/Stream documents omit `sdkVersion` and `configVersion` selectors. When the coordinated request/message runtime is deployed, request registration uses `api.stream.onRequest({ id, request }, handler)`; business-message consumers use `api.stream.messages.subscribe({ id, topic, inputSchema }, handler)`. Declare each outgoing logical topic with `api.stream.messages.use({ topic, access: 'publish' })` before calling `api.stream.messages.publish({ topic, payload })`. The current `api.stream.onMessage` remains a Source-event handler, not a business-message subscription.
|
|
66
|
+
|
|
67
|
+
Use the [Stream management Skill](../tier0-sdk-v2-stream/SKILL.md) for creating and deploying a program. Historical documents may be displayed as immutable history; do not submit them as current write/validation fixtures or infer that current deployments provide the new message runtime.
|
|
@@ -27,8 +27,7 @@ export async function diagnose() {
|
|
|
27
27
|
keyType: identity.keyType,
|
|
28
28
|
platformVersion: info.version,
|
|
29
29
|
capabilities: discovery.capabilities.map(item => ({
|
|
30
|
-
code: item.code, state: item.state,
|
|
31
|
-
availability: item.availability,
|
|
30
|
+
code: item.code, state: item.state, reasonCode: item.reasonCode,
|
|
32
31
|
})),
|
|
33
32
|
};
|
|
34
33
|
}
|
|
@@ -42,24 +41,21 @@ info 返回 name/version/mqttBroker/capabilities,字段可能省略。MQTT bro
|
|
|
42
41
|
|
|
43
42
|
| 字段/状态 | 判断 |
|
|
44
43
|
| --- | --- |
|
|
45
|
-
|
|
|
46
|
-
| allowed | 当前身份的授权摘要,不是某个具体操作的执行许可 |
|
|
47
|
-
| enabled、state=ready | 服务端评估就绪 |
|
|
48
|
-
| availability=available | 能力可用性,不是设备在线、业务执行或 ACK |
|
|
44
|
+
| state / reasonCode | 唯一状态及原因;就绪不代表具体资源已获授权、设备在线或数据已经落库 |
|
|
49
45
|
| disabled / not_supported / unavailable | 展示具体不可用原因,不强制调用 |
|
|
50
46
|
| readiness_unknown | 保留未知状态,不能按成功处理 |
|
|
51
47
|
| operations | Source / Stream 各操作独立判断;整体不可用不等于读取或安全停用不可用 |
|
|
52
48
|
| reasonCode / checkedAt / validUntil | 保留服务端原因及证明时间,过期后重新发现,不把旧证明当成持续就绪 |
|
|
53
49
|
| requiresResourceCheck | 实际调用仍要检查具体资源的权限、配置和依赖 |
|
|
54
50
|
|
|
55
|
-
|
|
51
|
+
`client.capabilities` 的能力目录识别 namespace.v2、source、stream;同包 `client.streams.capabilities` 独立处理 App 请求/invoke 能力,不阻断 Namespace 发现。Source/Stream 的 contractVersions 使用 openapi/v2,不要求或返回解释器版本。contractVersions、apiContractVersions、sdkContractVersions 是契约标签,不是 npm 包版本;productVersion 未配置时可缺省。顶层要求受支持的核心 OpenAPI v2 合同,已识别能力也必须满足其合同;不要求全局交互 SDK 标签,不把未知能力投影为已支持。
|
|
56
52
|
|
|
57
|
-
发现统一使用 `POST /openapi/v2/capabilities/discover`,请求为 `{}`,不接受 Workspace
|
|
53
|
+
发现统一使用 `POST /openapi/v2/capabilities/discover`,请求为 `{}`,不接受 Workspace 参数。当前合同版本为 2.0;服务端必须部署相同版本,不能回退旧布尔合同。App 交互能力见 [Stream 交互](../tier0-sdk-v2-streams/SKILL.md),其版本不作为管理接口的前置条件。SDK 只投影当前作用域的已知操作与公开诊断字段;未知扩展不被解释为就绪,不自动重试。
|
|
58
54
|
|
|
59
55
|
## 定位问题
|
|
60
56
|
|
|
61
57
|
- 401/403:核对目标 Host、Key 对应 Workspace 和所需权限;不输出完整 Key。
|
|
62
|
-
- 方法存在但能力关闭:记录 code/state/
|
|
58
|
+
- 方法存在但能力关闭:记录 code/state/reasonCode,检查该环境的部署与配置,不能凭本地生成文件推断线上已支持。
|
|
63
59
|
- `CapabilityError`:保留 status/errorCode;不支持的契约版本与错误响应格式需要排查服务端/SDK 配套版本。
|
|
64
60
|
- 系统普通 API 使用 `ApiError`,HTTP 200 的业务失败仍会抛错。
|
|
65
61
|
- 仅上报排查需要的字段;whoami 中的邮箱、角色和 Key 前缀不应无差别返回给浏览器。
|
|
@@ -18,4 +18,4 @@ export async function inspectService(client: Tier0Client = createClient()) {
|
|
|
18
18
|
|
|
19
19
|
返回已解包对象,name/version/capabilities/mqttBroker 均可能省略。mqttBroker 是连接串,可能裸 host、host:port、tcp://host:1883 或完整 ws/wss,不能直接拼 wss:// 前缀。toWebSocketUrl 保留已有 WebSocket URL;TCP 端口不直接复用为 WebSocket 端口。实际端口/路径由环境决定。
|
|
20
20
|
|
|
21
|
-
info.capabilities 的简略字符串列表不是就绪证明。进一步读取 client.capabilities.discover 的
|
|
21
|
+
info.capabilities 的简略字符串列表不是就绪证明。进一步读取 client.capabilities.discover 的 state、reasonCode、operations,区分开关、授权与运行能力;详见[系统 Skill](../SKILL.md)。
|