@tier0/sdk-v2 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/NOTICE.md +7 -0
- package/README.md +201 -2
- package/dist/cjs/app-identity-contract.generated.d.ts +22 -0
- package/dist/cjs/app-identity-contract.generated.js +51 -0
- package/dist/cjs/app-identity-contract.generated.js.map +1 -0
- package/dist/cjs/capabilities.d.ts +54 -0
- package/dist/cjs/capabilities.js +134 -0
- package/dist/cjs/capabilities.js.map +1 -0
- package/dist/cjs/client.d.ts +604 -0
- package/dist/cjs/client.js +35 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/cloud-server.d.ts +31 -0
- package/dist/cjs/cloud-server.js +114 -0
- package/dist/cjs/cloud-server.js.map +1 -0
- package/dist/cjs/cloud-transport.d.ts +67 -0
- package/dist/cjs/cloud-transport.js +272 -0
- package/dist/cjs/cloud-transport.js.map +1 -0
- package/dist/cjs/controls.d.ts +93 -0
- package/dist/cjs/controls.js +169 -0
- package/dist/cjs/controls.js.map +1 -0
- package/dist/cjs/data/bootstrap.d.ts +70 -0
- package/dist/cjs/data/bootstrap.js +291 -0
- package/dist/cjs/data/bootstrap.js.map +1 -0
- package/dist/cjs/data/call.d.ts +33 -0
- package/dist/cjs/data/call.js +216 -0
- package/dist/cjs/data/call.js.map +1 -0
- package/dist/cjs/data/client.d.ts +134 -0
- package/dist/cjs/data/client.js +185 -0
- package/dist/cjs/data/client.js.map +1 -0
- package/dist/cjs/data/collection.d.ts +335 -0
- package/dist/cjs/data/collection.js +601 -0
- package/dist/cjs/data/collection.js.map +1 -0
- package/dist/cjs/data/context.d.ts +12 -0
- package/dist/cjs/data/context.js +50 -0
- package/dist/cjs/data/context.js.map +1 -0
- package/dist/cjs/data/declarations.d.ts +11 -0
- package/dist/cjs/data/declarations.js +18 -0
- package/dist/cjs/data/declarations.js.map +1 -0
- package/dist/cjs/data/define.d.ts +77 -0
- package/dist/cjs/data/define.js +31 -0
- package/dist/cjs/data/define.js.map +1 -0
- package/dist/cjs/data/error.d.ts +78 -0
- package/dist/cjs/data/error.js +182 -0
- package/dist/cjs/data/error.js.map +1 -0
- package/dist/cjs/data/index.d.ts +24 -0
- package/dist/cjs/data/index.js +49 -0
- package/dist/cjs/data/index.js.map +1 -0
- package/dist/cjs/data/schema.d.ts +88 -0
- package/dist/cjs/data/schema.js +657 -0
- package/dist/cjs/data/schema.js.map +1 -0
- package/dist/cjs/data/sort.d.ts +8 -0
- package/dist/cjs/data/sort.js +21 -0
- package/dist/cjs/data/sort.js.map +1 -0
- package/dist/cjs/data/subscribe.d.ts +108 -0
- package/dist/cjs/data/subscribe.js +270 -0
- package/dist/cjs/data/subscribe.js.map +1 -0
- package/dist/cjs/files.d.ts +67 -0
- package/dist/cjs/files.js +119 -0
- package/dist/cjs/files.js.map +1 -0
- package/dist/cjs/framework-scope.d.ts +1 -0
- package/dist/cjs/framework-scope.js +14 -0
- package/dist/cjs/framework-scope.js.map +1 -0
- package/dist/cjs/index.d.ts +14 -0
- package/dist/cjs/index.js +33 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/mq/broker.d.ts +65 -0
- package/dist/cjs/mq/broker.js +115 -0
- package/dist/cjs/mq/broker.js.map +1 -0
- package/dist/cjs/mq/client.d.ts +37 -0
- package/dist/cjs/mq/client.js +321 -0
- package/dist/cjs/mq/client.js.map +1 -0
- package/dist/cjs/mq/index.d.ts +5 -0
- package/dist/cjs/mq/index.js +11 -0
- package/dist/cjs/mq/index.js.map +1 -0
- package/dist/cjs/mq/types.d.ts +48 -0
- package/dist/cjs/mq/types.js +3 -0
- package/dist/cjs/mq/types.js.map +1 -0
- package/dist/cjs/openapi/api.generated.d.ts +820 -0
- package/dist/cjs/openapi/api.generated.js +607 -0
- package/dist/cjs/openapi/api.generated.js.map +1 -0
- package/dist/cjs/openapi/client.d.ts +56 -0
- package/dist/cjs/openapi/client.js +219 -0
- package/dist/cjs/openapi/client.js.map +1 -0
- package/dist/cjs/openapi/codecs.generated.d.ts +2234 -0
- package/dist/cjs/openapi/codecs.generated.js +6 -0
- package/dist/cjs/openapi/codecs.generated.js.map +1 -0
- package/dist/cjs/openapi/index.d.ts +5 -0
- package/dist/cjs/openapi/index.js +12 -0
- package/dist/cjs/openapi/index.js.map +1 -0
- package/dist/cjs/openapi/types.generated.d.ts +3227 -0
- package/dist/cjs/openapi/types.generated.js +3 -0
- package/dist/cjs/openapi/types.generated.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/react.d.ts +9 -0
- package/dist/cjs/react.js +16 -0
- package/dist/cjs/react.js.map +1 -0
- package/dist/cjs/runtime-context.d.ts +9 -0
- package/dist/cjs/runtime-context.js +25 -0
- package/dist/cjs/runtime-context.js.map +1 -0
- package/dist/cjs/runtime-env.d.ts +1 -0
- package/dist/cjs/runtime-env.js +18 -0
- package/dist/cjs/runtime-env.js.map +1 -0
- package/dist/cjs/source.d.ts +39 -0
- package/dist/cjs/source.js +29 -0
- package/dist/cjs/source.js.map +1 -0
- package/dist/cjs/stream.d.ts +40 -0
- package/dist/cjs/stream.js +33 -0
- package/dist/cjs/stream.js.map +1 -0
- package/dist/cjs/uns-v2/client.d.ts +132 -0
- package/dist/cjs/uns-v2/client.js +352 -0
- package/dist/cjs/uns-v2/client.js.map +1 -0
- package/dist/cjs/uns-v2/codec.d.ts +11 -0
- package/dist/cjs/uns-v2/codec.js +290 -0
- package/dist/cjs/uns-v2/codec.js.map +1 -0
- package/dist/cjs/uns-v2/data-client.d.ts +10 -0
- package/dist/cjs/uns-v2/data-client.js +18 -0
- package/dist/cjs/uns-v2/data-client.js.map +1 -0
- package/dist/cjs/uns-v2/generated.d.ts +18178 -0
- package/dist/cjs/uns-v2/generated.js +144 -0
- package/dist/cjs/uns-v2/generated.js.map +1 -0
- package/dist/cjs/uns-v2/index.d.ts +5 -0
- package/dist/cjs/uns-v2/index.js +24 -0
- package/dist/cjs/uns-v2/index.js.map +1 -0
- package/dist/cjs/uns-v2/sse.d.ts +20 -0
- package/dist/cjs/uns-v2/sse.js +65 -0
- package/dist/cjs/uns-v2/sse.js.map +1 -0
- package/dist/cjs/vue.d.ts +9 -0
- package/dist/cjs/vue.js +39 -0
- package/dist/cjs/vue.js.map +1 -0
- package/dist/esm/app-identity-contract.generated.d.ts +22 -0
- package/dist/esm/app-identity-contract.generated.js +48 -0
- package/dist/esm/app-identity-contract.generated.js.map +1 -0
- package/dist/esm/capabilities.d.ts +54 -0
- package/dist/esm/capabilities.js +129 -0
- package/dist/esm/capabilities.js.map +1 -0
- package/dist/esm/client.d.ts +604 -0
- package/dist/esm/client.js +32 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/cloud-server.d.ts +31 -0
- package/dist/esm/cloud-server.js +109 -0
- package/dist/esm/cloud-server.js.map +1 -0
- package/dist/esm/cloud-transport.d.ts +67 -0
- package/dist/esm/cloud-transport.js +267 -0
- package/dist/esm/cloud-transport.js.map +1 -0
- package/dist/esm/controls.d.ts +93 -0
- package/dist/esm/controls.js +163 -0
- package/dist/esm/controls.js.map +1 -0
- package/dist/esm/data/bootstrap.d.ts +70 -0
- package/dist/esm/data/bootstrap.js +286 -0
- package/dist/esm/data/bootstrap.js.map +1 -0
- package/dist/esm/data/call.d.ts +33 -0
- package/dist/esm/data/call.js +211 -0
- package/dist/esm/data/call.js.map +1 -0
- package/dist/esm/data/client.d.ts +134 -0
- package/dist/esm/data/client.js +181 -0
- package/dist/esm/data/client.js.map +1 -0
- package/dist/esm/data/collection.d.ts +335 -0
- package/dist/esm/data/collection.js +594 -0
- package/dist/esm/data/collection.js.map +1 -0
- package/dist/esm/data/context.d.ts +12 -0
- package/dist/esm/data/context.js +44 -0
- package/dist/esm/data/context.js.map +1 -0
- package/dist/esm/data/declarations.d.ts +11 -0
- package/dist/esm/data/declarations.js +10 -0
- package/dist/esm/data/declarations.js.map +1 -0
- package/dist/esm/data/define.d.ts +77 -0
- package/dist/esm/data/define.js +27 -0
- package/dist/esm/data/define.js.map +1 -0
- package/dist/esm/data/error.d.ts +78 -0
- package/dist/esm/data/error.js +176 -0
- package/dist/esm/data/error.js.map +1 -0
- package/dist/esm/data/index.d.ts +24 -0
- package/dist/esm/data/index.js +20 -0
- package/dist/esm/data/index.js.map +1 -0
- package/dist/esm/data/schema.d.ts +88 -0
- package/dist/esm/data/schema.js +646 -0
- package/dist/esm/data/schema.js.map +1 -0
- package/dist/esm/data/sort.d.ts +8 -0
- package/dist/esm/data/sort.js +18 -0
- package/dist/esm/data/sort.js.map +1 -0
- package/dist/esm/data/subscribe.d.ts +108 -0
- package/dist/esm/data/subscribe.js +265 -0
- package/dist/esm/data/subscribe.js.map +1 -0
- package/dist/esm/files.d.ts +67 -0
- package/dist/esm/files.js +113 -0
- package/dist/esm/files.js.map +1 -0
- package/dist/esm/framework-scope.d.ts +1 -0
- package/dist/esm/framework-scope.js +11 -0
- package/dist/esm/framework-scope.js.map +1 -0
- package/dist/esm/index.d.ts +14 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/mq/broker.d.ts +65 -0
- package/dist/esm/mq/broker.js +109 -0
- package/dist/esm/mq/broker.js.map +1 -0
- package/dist/esm/mq/client.d.ts +37 -0
- package/dist/esm/mq/client.js +314 -0
- package/dist/esm/mq/client.js.map +1 -0
- package/dist/esm/mq/index.d.ts +5 -0
- package/dist/esm/mq/index.js +3 -0
- package/dist/esm/mq/index.js.map +1 -0
- package/dist/esm/mq/types.d.ts +48 -0
- package/dist/esm/mq/types.js +2 -0
- package/dist/esm/mq/types.js.map +1 -0
- package/dist/esm/openapi/api.generated.d.ts +820 -0
- package/dist/esm/openapi/api.generated.js +603 -0
- package/dist/esm/openapi/api.generated.js.map +1 -0
- package/dist/esm/openapi/client.d.ts +56 -0
- package/dist/esm/openapi/client.js +210 -0
- package/dist/esm/openapi/client.js.map +1 -0
- package/dist/esm/openapi/codecs.generated.d.ts +2234 -0
- package/dist/esm/openapi/codecs.generated.js +3 -0
- package/dist/esm/openapi/codecs.generated.js.map +1 -0
- package/dist/esm/openapi/index.d.ts +5 -0
- package/dist/esm/openapi/index.js +3 -0
- package/dist/esm/openapi/index.js.map +1 -0
- package/dist/esm/openapi/types.generated.d.ts +3227 -0
- package/dist/esm/openapi/types.generated.js +2 -0
- package/dist/esm/openapi/types.generated.js.map +1 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/react.d.ts +9 -0
- package/dist/esm/react.js +12 -0
- package/dist/esm/react.js.map +1 -0
- package/dist/esm/runtime-context.d.ts +9 -0
- package/dist/esm/runtime-context.js +22 -0
- package/dist/esm/runtime-context.js.map +1 -0
- package/dist/esm/runtime-env.d.ts +1 -0
- package/dist/esm/runtime-env.js +15 -0
- package/dist/esm/runtime-env.js.map +1 -0
- package/dist/esm/source.d.ts +39 -0
- package/dist/esm/source.js +25 -0
- package/dist/esm/source.js.map +1 -0
- package/dist/esm/stream.d.ts +40 -0
- package/dist/esm/stream.js +29 -0
- package/dist/esm/stream.js.map +1 -0
- package/dist/esm/uns-v2/client.d.ts +132 -0
- package/dist/esm/uns-v2/client.js +343 -0
- package/dist/esm/uns-v2/client.js.map +1 -0
- package/dist/esm/uns-v2/codec.d.ts +11 -0
- package/dist/esm/uns-v2/codec.js +284 -0
- package/dist/esm/uns-v2/codec.js.map +1 -0
- package/dist/esm/uns-v2/data-client.d.ts +10 -0
- package/dist/esm/uns-v2/data-client.js +14 -0
- package/dist/esm/uns-v2/data-client.js.map +1 -0
- package/dist/esm/uns-v2/generated.d.ts +18178 -0
- package/dist/esm/uns-v2/generated.js +141 -0
- package/dist/esm/uns-v2/generated.js.map +1 -0
- package/dist/esm/uns-v2/index.d.ts +5 -0
- package/dist/esm/uns-v2/index.js +5 -0
- package/dist/esm/uns-v2/index.js.map +1 -0
- package/dist/esm/uns-v2/sse.d.ts +20 -0
- package/dist/esm/uns-v2/sse.js +60 -0
- package/dist/esm/uns-v2/sse.js.map +1 -0
- package/dist/esm/vue.d.ts +9 -0
- package/dist/esm/vue.js +36 -0
- package/dist/esm/vue.js.map +1 -0
- package/docs/acceptance-2026-10-22.md +88 -0
- package/package.json +243 -4
- package/skills/tier0-sdk-v2/SKILL.md +66 -0
- package/skills/tier0-sdk-v2/references/integration.md +72 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-agent/SKILL.md +73 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-agent/references/results.md +45 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-controls/SKILL.md +63 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/SKILL.md +58 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/consistency.md +70 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/errors.md +82 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/modeling.md +113 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/read-write.md +168 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/schema-evolution.md +36 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-files/SKILL.md +85 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/delete.md +22 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/download.md +49 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/multipart.md +42 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/upload.md +27 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/url.md +22 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-members/SKILL.md +56 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-members/references/app-members.md +41 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-members/references/platform-members.md +56 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-mq/SKILL.md +78 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-mq/references/quickstart.md +69 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-notifications/SKILL.md +42 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-notifications/references/get.md +34 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-notifications/references/send.md +72 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/SKILL.md +38 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/changes.md +40 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/create.md +63 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/delete.md +47 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/protocols.md +36 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/read.md +34 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/state.md +37 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/update.md +62 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/SKILL.md +43 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/create.md +56 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/delete.md +35 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/deploy.md +64 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/lifecycle.md +26 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/read.md +35 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/update.md +36 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-system/SKILL.md +64 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-system/references/info.md +23 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-system/references/whoami.md +21 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/SKILL.md +55 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/create.md +56 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/data-workflows.md +69 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/delete.md +53 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/namespace.md +38 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/read.md +34 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/restore.md +39 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/update.md +62 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tier0-sdk-v2-agent
|
|
3
|
+
description: 使用 @tier0/sdk-v2 的 client.agent 查询和管理 Agent 作业、运行记录、分析、结果、卡片、资料库与关系,处理调度副作用和并发编辑。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Agent 作业与结果
|
|
7
|
+
|
|
8
|
+
Agent 是平台应用能力,区别于 Stream 数据处理程序。使用服务端 client.agent;本领域普通 v1 响应已解包,直接读取 list/job/run/result 等字段。
|
|
9
|
+
|
|
10
|
+
## 入口选择
|
|
11
|
+
|
|
12
|
+
| 入口 | 方法与用途 |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| jobs | list/get/create/update/pause/resume/trigger/delete,管理任务与调度 |
|
|
15
|
+
| jobRuns | list/get,查看具体执行 |
|
|
16
|
+
| analyses | dispatch/get,分发分析和读取结果 |
|
|
17
|
+
| results | create/get/list/pin,保存分析产物并固定到画布 |
|
|
18
|
+
| cards | list/get/update/delete,操作画布卡片 |
|
|
19
|
+
| canvases | list,查找画布 |
|
|
20
|
+
| library | list/get/create/update/delete,复用卡片定义 |
|
|
21
|
+
| nodes | searchSemantic/indexSync,语义搜索与索引同步 |
|
|
22
|
+
| relations | list/teach,读取和写入数据关系 |
|
|
23
|
+
|
|
24
|
+
dispatch、trigger、indexSync、teach 都有副作用,不能在普通查询流程中悄悄执行。
|
|
25
|
+
|
|
26
|
+
## 查询作业与运行
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
import { createClient } from '@tier0/sdk-v2';
|
|
30
|
+
|
|
31
|
+
export async function listJobs(page = 1) {
|
|
32
|
+
return createClient().agent.jobs.list({ page, size: 20 });
|
|
33
|
+
}
|
|
34
|
+
export async function inspectJob(jobId: string) {
|
|
35
|
+
const client = createClient();
|
|
36
|
+
const job = await client.agent.jobs.get({ jobId });
|
|
37
|
+
const runs = await client.agent.jobRuns.list({ jobId, page: 1, size: 20 });
|
|
38
|
+
return { job: job.job, runs: runs.list, total: runs.total };
|
|
39
|
+
}
|
|
40
|
+
export async function inspectJobRun(jobId: string, jobRunId: string) {
|
|
41
|
+
const response = await createClient().agent.jobRuns.get({ jobId, jobRunId });
|
|
42
|
+
return response.run;
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
作业 ID 与运行 ID 不同;不能拿 resultId 去查 jobRuns。分页接口一般要求 page/size,按返回 total/list 继续。status/dispatchState 按服务端值处理,收到派发回执不等于作业完成。
|
|
47
|
+
|
|
48
|
+
## 创建与调度
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
import { createClient, type Tier0Client } from '@tier0/sdk-v2';
|
|
52
|
+
|
|
53
|
+
type CreateJob = Parameters<Tier0Client['agent']['jobs']['create']>[0];
|
|
54
|
+
export async function createConfiguredJob(input: CreateJob) {
|
|
55
|
+
// input 的调度和 task 内容来自当前平台认可的业务配置。
|
|
56
|
+
return createClient().agent.jobs.create(input);
|
|
57
|
+
}
|
|
58
|
+
export async function triggerExistingJob(jobId: string) {
|
|
59
|
+
return createClient().agent.jobs.trigger({ jobId });
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
创建必填 name/scheduleKind/task/sourceType/sessionId。scheduleKind 的可用值、task 对象和时间单位须来自实际业务契约,Swagger 中的 string/unknown 不意味着可以任意填写。pause/resume/trigger 是不同意图;不要用“暂停后再恢复”来替代查询。
|
|
64
|
+
|
|
65
|
+
jobs.update 的 notifyEnabled:省略保留原通知,1 要求提供 notify,2 关闭通知且不带 notify。没有通用作业幂等键字段时,不得额外塞 idempotencyKey;不确定的 trigger 先查运行列表对账。
|
|
66
|
+
|
|
67
|
+
## 保存结果与并发编辑
|
|
68
|
+
|
|
69
|
+
result.create 的 operationId 由调用方持有;保存超时后可用 `results.get({ operationId })` 查回,不能再创建新 operationId 重复保存。get 按 resultId 或 operationId 二选一。
|
|
70
|
+
|
|
71
|
+
cards.update 要带读取时的完整 expectedCardSpec;library.update 要带完整 expectedItem 快照。409 表示内容已变化,应重新读取并合并用户意图,不能自动覆盖。具体示例见 [结果与卡片编辑](references/results.md)。
|
|
72
|
+
|
|
73
|
+
结果附件/图片使用 [文件 Skill](../tier0-sdk-v2-files/SKILL.md) 的持久化 filePath,不保存签名 URL 作为长期资源。失败保留 ApiError.status/code/errorCode;写入 outcomeUnknown 时先查询对应资源,不自动重发。
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Agent 结果与并发编辑
|
|
2
|
+
|
|
3
|
+
## 按原意图查回保存结果
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { createClient, type Tier0Client } from '@tier0/sdk-v2';
|
|
7
|
+
|
|
8
|
+
type SaveInput = Parameters<Tier0Client['agent']['results']['create']>[0];
|
|
9
|
+
export async function saveResult(input: SaveInput) {
|
|
10
|
+
return createClient().agent.results.create(input);
|
|
11
|
+
}
|
|
12
|
+
export async function reconcileResult(operationId: string) {
|
|
13
|
+
return createClient().agent.results.get({ operationId });
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
保存必填 resultSchemaVersion/title/missingData/operationId/source;source 至少含 platformSessionId/agentId。版本和 manifest 字段以实际业务契约为准。保存前持久化 operationId;结果未知时按同一个 operationId 查回,禁止换 ID 重复创建。
|
|
18
|
+
|
|
19
|
+
results.get 的 resultId 与 operationId 二选一。results.pin({ resultId, canvasId }) 是写操作,canvasId 从 canvases.list 取得,不能因查看结果而自动固定到画布。
|
|
20
|
+
|
|
21
|
+
## 卡片乐观并发
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { createClient, type Tier0Client } from '@tier0/sdk-v2';
|
|
25
|
+
|
|
26
|
+
type CardUpdate = Parameters<Tier0Client['agent']['cards']['update']>[0];
|
|
27
|
+
export async function submitCardEdit(input: CardUpdate) {
|
|
28
|
+
// expectedCardSpec 是读取时的完整原值,cardSpec 是编辑后的新值。
|
|
29
|
+
return createClient().agent.cards.update(input);
|
|
30
|
+
}
|
|
31
|
+
type LibraryUpdate = Parameters<Tier0Client['agent']['library']['update']>[0];
|
|
32
|
+
export async function submitLibraryEdit(input: LibraryUpdate) {
|
|
33
|
+
return createClient().agent.library.update(input);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
cardId/cardSpec/expectedCardSpec 必填;ord 省略表示不改,不能为了凑参数默认传 0。资料库更新要求 libraryItemId、expectedItem、cardSpec,expectedItem 包括原 cardKey/cardSpec/tags/sourceSessionId。
|
|
38
|
+
|
|
39
|
+
409 时重新读取并展示冲突,保留用户本次编辑意图后再合并。不要用刚读的新内容填充 expected*,却仍提交覆盖别人修改的旧全文。
|
|
40
|
+
|
|
41
|
+
## 作业查询与触发边界
|
|
42
|
+
|
|
43
|
+
jobs.trigger 回执中的 jobRunId 用于 jobRuns.get;dispatchState 不是执行结果。查询列表可以按业务需要有界轮询,不自动再次触发。更新 notifyEnabled=2 时省略 notify;notifyEnabled=1 时提供当前认可的通知结构。
|
|
44
|
+
|
|
45
|
+
nodes.indexSync 会改变索引状态,relations.teach 会新增关系;用户只要搜索或查关系列表时分别用 searchSemantic 和 relations.list。
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tier0-sdk-v2-controls
|
|
3
|
+
description: 使用 @tier0/sdk-v2 发现、描述和调用 Tier0 Control 业务契约,区分读写副作用、契约版本、幂等要求和执行结果未知。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Control 契约调用
|
|
7
|
+
|
|
8
|
+
Control 是已发布的业务调用入口;它可由 Stream 提供,但调用方不选择内部 streamId、entryId 或部署版本。使用服务端 client.controls,不重建旧 Flow 调用。
|
|
9
|
+
|
|
10
|
+
## 发现和读取契约
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { createClient } from '@tier0/sdk-v2';
|
|
14
|
+
|
|
15
|
+
export async function discoverControls(search: string) {
|
|
16
|
+
return createClient().controls.discover({ search, page: 1, size: 20 });
|
|
17
|
+
}
|
|
18
|
+
export async function describeControl(code: string) {
|
|
19
|
+
return createClient().controls.use({ code }).describe();
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
discover 返回 total/list,分页从 1 开始,size 为 1–200。code 取自发现结果,不由显示名称猜测。describe 返回 inputSchema、outputSchema、sideEffect、idempotency、contractVersion、timeoutMs 和 status。
|
|
24
|
+
|
|
25
|
+
## 构造调用
|
|
26
|
+
|
|
27
|
+
1. 依据 inputSchema 填写输入,业务 JSON 不等于任意控制参数。SDK 的泛型只提供静态提示,不能替代契约校验。
|
|
28
|
+
2. 判断 sideEffect=read/write,与用户本次任务的授权范围一致。
|
|
29
|
+
3. 当 idempotency=required 时提供稳定的业务意图键;optional/none 按契约决定,不自动生成 UUID 重试。
|
|
30
|
+
4. 调用后检查业务 result 与 status,记录 runID/contractVersion,不能只看请求未抛错。
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import {
|
|
34
|
+
createClient, ControlResultUnknownError, type ControlJSON,
|
|
35
|
+
} from '@tier0/sdk-v2';
|
|
36
|
+
|
|
37
|
+
export async function invokePreparedControl(code: string, input: ControlJSON, intentKey?: string) {
|
|
38
|
+
const handle = createClient().controls.use({ code });
|
|
39
|
+
const definition = await handle.describe();
|
|
40
|
+
if (definition.idempotency === 'required' && !intentKey) {
|
|
41
|
+
throw new Error('该 Control 要求业务幂等键');
|
|
42
|
+
}
|
|
43
|
+
// 调用方已经按 definition.inputSchema 校验输入,并确认本次业务意图。
|
|
44
|
+
try {
|
|
45
|
+
return await handle.invoke(input, intentKey ? { idempotencyKey: intentKey } : {});
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (error instanceof ControlResultUnknownError) {
|
|
48
|
+
return { outcomeUnknown: true as const, runID: error.runID, errorCode: error.errorCode };
|
|
49
|
+
}
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
幂等键非空、不能有首尾空白,最多 128 UTF-8 字节。输入只能是普通 JSON,不传 Date、函数、循环对象、bigint、NaN/Infinity。业务 input 内名为 timeoutMs/streamId 的字段仍只是业务输入;不能借它覆盖服务端绑定、版本或执行超时。
|
|
56
|
+
|
|
57
|
+
## 返回与失败
|
|
58
|
+
|
|
59
|
+
成功值为直接对象:code(Control 标识)、contractVersion、result、runID、status、replayed。这里的 code 不是 HTTP 业务状态码;replayed 只有服务端明确报告重放时才为 true。
|
|
60
|
+
|
|
61
|
+
`ControlError` 含 status/errorCode/runID 等信息,SDK 不自动重试。`ControlResultUnknownError` 表示执行可能已经发生,包括调用响应无法证明最终结果的情况;按业务或平台运行记录对账。本 SDK 未提供通用 `controls.getRun`,不要虚构方法。若业务明确允许重放,保留原 key 和原输入,不能换新 key 重做。
|
|
62
|
+
|
|
63
|
+
`client.capabilities.discover()` 的 control.invoke.v1 就绪只是入口条件,不等于有权调用每一个 Control。执行源发布和内部绑定管理请使用 [Stream Skill](../tier0-sdk-v2-stream/SKILL.md)。
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tier0-sdk-v2-data
|
|
3
|
+
description: 使用 @tier0/sdk-v2/data 在 App 服务端声明并读写本 App 的 UNS 集合:Zod 建模、种子与 TTL、Mongo 风格读写、带总数分页与分组计数、原子批量与事务、变更订阅、员工数据主体、Schema 演进和错误码处理。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# App 数据层
|
|
7
|
+
|
|
8
|
+
`@tier0/sdk-v2/data` 是 App 自有业务数据的服务端入口:用 `defineCollection` 声明集合,`createDataClient` 在首次访问时一次性 ensure 全部声明,然后用 Mongo 驱动风格的集合句柄读写 UNS 记录。没有 SQL、ORM、连接串或迁移步骤;Preview 与部署后的 App 共用同一批集合和记录。
|
|
9
|
+
|
|
10
|
+
数据读写只在服务端代码(业务 service)里用 `@tier0/sdk-v2/data`:该入口依赖 Node 内置模块,浏览器打包会直接失败。组件和 route 的客户端代码只能从 `@tier0/sdk-v2/data/define` 取集合声明和类型(`defineCollection`、`Doc`、`NewDoc` 等),它不加载数据运行时,可以进浏览器包。需要 `zod` 4。底层调用 SDK 生成的 UNS 操作(`appCollectionsEnsure`、`recordFind`、`recordTransactionExecute` 等),凭证读取平台注入的 TIER0_API_HOST / TIER0_API_KEY。
|
|
11
|
+
|
|
12
|
+
## 按任务加载参考
|
|
13
|
+
|
|
14
|
+
| 用户任务 | 参考 |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| 声明集合、选字段类型、索引、种子数据、文档建模 | [建模](references/modeling.md) |
|
|
17
|
+
| 查询、按 ID 读取、一页一次请求(queryBatch)、分页、聚合、写入、批量与原子性、订阅变更 | [读写](references/read-write.md) |
|
|
18
|
+
| 状态流转、并发编辑、跨文档不变量、计数器、员工身份与后台任务 | [一致性与身份](references/consistency.md) |
|
|
19
|
+
| 加字段、改类型、改描述、收窄 Schema | [Schema 演进](references/schema-evolution.md) |
|
|
20
|
+
| DataError 字段、UNS 错误码与处理 | [错误码](references/errors.md) |
|
|
21
|
+
|
|
22
|
+
## 最小用法
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { z } from 'zod';
|
|
26
|
+
import { createDataClient } from '@tier0/sdk-v2/data';
|
|
27
|
+
import { defineCollection, type Doc } from '@tier0/sdk-v2/data/define';
|
|
28
|
+
|
|
29
|
+
export const workOrders = defineCollection({
|
|
30
|
+
alias: 'work_orders',
|
|
31
|
+
description: 'Production work orders',
|
|
32
|
+
schema: z.object({
|
|
33
|
+
code: z.string(),
|
|
34
|
+
status: z.enum(['DRAFT', 'RELEASED', 'DONE', 'CANCELLED']),
|
|
35
|
+
targetQty: z.number().int().min(1),
|
|
36
|
+
dueAt: z.string(),
|
|
37
|
+
}),
|
|
38
|
+
indexes: [{ path: 'code', unique: true }, { path: 'status' }],
|
|
39
|
+
});
|
|
40
|
+
export type WorkOrder = Doc<typeof workOrders>;
|
|
41
|
+
|
|
42
|
+
// 每个服务端进程一个 client:ensure 结果按 client 缓存。
|
|
43
|
+
export const data = createDataClient({ collections: [workOrders] });
|
|
44
|
+
|
|
45
|
+
export async function releasedOrders(): Promise<WorkOrder[]> {
|
|
46
|
+
return data.collection(workOrders).find({ status: 'RELEASED' }, { sort: { '_meta.createdAt': -1 }, limit: 50 }).toArray();
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## 核心约束
|
|
51
|
+
|
|
52
|
+
1. 声明文件只从 `@tier0/sdk-v2/data/define` 导入,客户端代码可以安全引用它;全部集合在一个 `collections` 列表里声明(每个 App 最多 64 个),只建一个进程级 client;不要手动 ensure、不要在 import 时访问数据、不要自建“已初始化”标记。
|
|
53
|
+
2. 集合 Schema 是存储 Schema:只能用可存储的 Zod 子集,输入规则(格式、长度、默认值、transform)放在 API 入参 Schema。
|
|
54
|
+
3. 写入前按声明严格校验,未知字段、类型错误、未声明的更新路径直接抛 `ZodError`;读取不做严格解析,旧版本写入的字段、新枚举值或缺字段都可能出现。
|
|
55
|
+
4. `insertMany` / `bulkWrite` / `transact` 每次最多 200 项且原子;`updateMany` / `deleteMany` 逐条提交、非原子。
|
|
56
|
+
5. 按 `DataError.code` 与 `reason`(`data.reason`)分支,不匹配 message 文本;`status` 是 App 应回给自己调用方的 HTTP 状态。
|
|
57
|
+
6. `schema:replace`、`archive`、`restore` 是 worker 通过 tier0 MCP 的显式操作,不在运行时代码里调用。
|
|
58
|
+
7. 调用策略由数据层负责:每次调用从开始算最多 25 秒(排队、重试都算在内),每进程最多 6 个并发数据请求(其余排队,超时或业务请求中止时不再发出),UNS 标记 `retry.safe` 的失败(过载 429、暂时不可用 503、已回滚的写入冲突等)按 `retry.afterMs` 自动重试最多 2 次。每次写入调用自动带一个新的幂等键并在重试中复用,不需要手写;只有“同一业务意图跨多次调用只生效一次”(如按订单号预留库存)才显式传 `idempotencyKey`。不要在外面再包一层重试循环。
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# 一致性与调用身份
|
|
2
|
+
|
|
3
|
+
## 一致性写法
|
|
4
|
+
|
|
5
|
+
- 单个文档的写入是原子的:必须一起变化的数据放在同一个文档里。
|
|
6
|
+
- 状态流转把期望状态写进过滤条件:`findOneAndUpdate({ _id, status: 'DRAFT' }, { $set: { status: 'RELEASED' } })`;返回 `null` 表示记录不存在或已被别人改走,回 409。
|
|
7
|
+
- 并发编辑:编辑表单带回 `_meta.revision`,作为 `expectedRevision` 发送;`VERSION_CONFLICT`(409)表示重新读取后再试。
|
|
8
|
+
- 跨文档不变量(库存 + 预留、订单 + 审计记录):一次 `data.transact([...])`(≤200 步),用 `record.check` / `record.update` / `record.create` 步骤、`dependsOn` 与 `bindings`;`record.query` 步骤可断言 `expectCount: { min, max }`。整体全部提交或全不提交;它不是会话,不能在里面“先读再决定”。步骤的 `data` 不能含 `_id`(在步骤上设 `id`);由 `bindings` 填充的字段在 UNS 提交时校验,其余字面量字段在发送前校验。
|
|
9
|
+
- 计数器与流水号:声明一个计数器集合,`findOneAndUpdate({ _id: 'work_orders' }, { $inc: { value: 1 } }, { upsert: true })`。
|
|
10
|
+
- upsert 的过滤条件必须含 `_id` 或某个已就绪唯一索引的全部字段,否则 `UPSERT_REQUIRES_UNIQUE_INDEX`;新声明的唯一索引是异步构建的。
|
|
11
|
+
- `DUPLICATE_KEY`(409)表示唯一索引拒绝了该值,按字段错误展示。
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
import { createDataClient, defineCollection } from '@tier0/sdk-v2/data';
|
|
16
|
+
|
|
17
|
+
const stock = defineCollection({ alias: 'stock', schema: z.object({ sku: z.string(), available: z.number().int().min(0) }) });
|
|
18
|
+
const reservations = defineCollection({ alias: 'reservations', schema: z.object({ sku: z.string(), qty: z.number().int().min(1), orderId: z.string() }) });
|
|
19
|
+
const counters = defineCollection({ alias: 'counters', schema: z.object({ value: z.number().int() }) });
|
|
20
|
+
const data = createDataClient({ collections: [stock, reservations, counters] });
|
|
21
|
+
|
|
22
|
+
/** 扣减库存并写预留:库存不足时整体不提交。 */
|
|
23
|
+
export async function reserve(sku: string, qty: number, orderId: string) {
|
|
24
|
+
return data.transact(
|
|
25
|
+
[
|
|
26
|
+
{ opId: 'check', action: 'record.check', collection: stock, filter: { _id: sku, available: { $gte: qty } } },
|
|
27
|
+
{ opId: 'take', action: 'record.update', collection: stock, id: sku, update: { $inc: { available: -qty } }, dependsOn: ['check'] },
|
|
28
|
+
{ opId: 'hold', action: 'record.create', collection: reservations, data: { sku, qty, orderId }, dependsOn: ['take'] },
|
|
29
|
+
],
|
|
30
|
+
{ idempotencyKey: `reserve-${orderId}` },
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function nextOrderNumber() {
|
|
35
|
+
const counter = await data.collection(counters).findOneAndUpdate({ _id: 'sales_orders' }, { $inc: { value: 1 } }, { upsert: true });
|
|
36
|
+
return counter?.value;
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`transact` 的结果状态不是 `committed`(`dryRun` 时为 `validated`)会抛 `TRANSACTION_FAILED`,`details.results` 带每一步的错误。
|
|
41
|
+
|
|
42
|
+
## 调用身份
|
|
43
|
+
|
|
44
|
+
每次调用都使用平台注入的 App Key。处理业务请求时,数据层还会转发网关签发的员工断言(`X-Tier0-App-Data-Subject`),让 UNS 的数据规则与记录租约作用于该员工。集合 ensure 与种子写入以 App 身份执行。
|
|
45
|
+
|
|
46
|
+
App 的请求入口用 `runWithRequestContext(request, next)` 打开请求上下文(传 `Request` 本身:调用方断开时,还在排队的数据调用不再发出,进行中的被取消;只传 `request.headers` 则没有取消);脱离请求的工作(定时器、队列、发出即不管的后续任务)放进 `runAsApp(() => ...)`,这些调用不带员工身份;员工身份下取得的租约不能由这类 App 级工作释放。断言格式由 SDK 校验(三段 base64url),格式不合法时调用在发出请求前失败。
|
|
47
|
+
|
|
48
|
+
```ts
|
|
49
|
+
import { currentDataSubject, runAsApp, runWithRequestContext } from '@tier0/sdk-v2/data';
|
|
50
|
+
|
|
51
|
+
export function handleRequest<T>(request: Request, next: () => Promise<T>): Promise<T> {
|
|
52
|
+
return runWithRequestContext(request, next);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function scheduleFollowUp(task: () => Promise<void>) {
|
|
56
|
+
setTimeout(() => void runAsApp(task), 1000);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function servingEmployee(): boolean {
|
|
60
|
+
return currentDataSubject() !== undefined;
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 首次访问与自愈
|
|
65
|
+
|
|
66
|
+
进程内第一次数据访问会一次性 ensure 全部声明:缺失的集合会被创建(随后写入种子),更宽的声明会放宽存储,存储永远不会被收窄。ensure 失败不缓存,下一次请求会重试(刚导入的 App 可能短暂返回 `APP_NOT_READY`,数据层先自动重试,仍失败时按 503 回答)。
|
|
67
|
+
|
|
68
|
+
运行中的进程在所用集合消失时会自愈(Preview 重置会删除集合,worker 或管理员可能归档集合):UNS 以 `data.reason` 为 `COLLECTION_NOT_FOUND` 或 `COLLECTION_NOT_GRANTED` 拒绝调用时,数据层重新 ensure(重建并重新写入种子),并在集合 ID 确实变化时把该调用重试一次。每个 client 每 30 秒最多重建一次;`APP_GRANT_REVOKED`(管理员决定)从不重试。延续旧集合游标的分页、`updateMany` / `deleteMany` 的续写直接失败,不会重试。
|
|
69
|
+
|
|
70
|
+
Preview(`environment: 'preview'`,`NODE_ENV` 不是 production 时的默认值)下,Schema 冲突或 ensure 警告会让请求失败并带上详情;部署环境只记录日志、继续服务。`ignored` 提示从不让请求失败:存储比声明更宽的部分记为 info,`ANNOTATION_NOT_APPLIED`(ensure 不会改写的描述)记为指向 `schema:replace` 的 warning。
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# 错误处理
|
|
2
|
+
|
|
3
|
+
数据调用的每一种失败都是 `DataError`;写入校验失败是 `ZodError`,不能存储的声明是 `CollectionSchemaError`。
|
|
4
|
+
|
|
5
|
+
| 字段 | 含义 |
|
|
6
|
+
| --- | --- |
|
|
7
|
+
| `status` | App 应回给自己调用方的 HTTP 状态:UNS 401 → 502(平台凭证问题,不是用户登出);平台状态 `APP_NOT_READY` / `DEPENDENCY_UNAVAILABLE` / `CREDENTIAL_CHANGED` / `OUTCOME_UNKNOWN` / `TEMPORARILY_UNAVAILABLE` → 503;400/403/404/409/413/422/429 原样;其他 5xx → 502/503 |
|
|
8
|
+
| `code` | UNS 错误码(`DUPLICATE_KEY`…)或数据层错误码 |
|
|
9
|
+
| `reason` | UNS 错误体的稳定 `data.reason`,例如 `COLLECTION_NOT_FOUND` |
|
|
10
|
+
| `upstreamStatus` | UNS 实际返回的 HTTP 状态;未收到响应时为 0 |
|
|
11
|
+
| `requestId` | UNS 请求 ID,排障时一并记录 |
|
|
12
|
+
| `execution` | 执行到哪一步:`notStarted` / `rolledBack` 没有改动,`committed` 已生效,`unknown`(只出现在写入)可能已生效 |
|
|
13
|
+
| `retry` | `{ safe, afterMs? }`:同一调用能否稍后再发、建议等待多久。数据层已经按它自动重试过(最多 2 次) |
|
|
14
|
+
| `outcomeUnknown` | 即 `execution === 'unknown'`:写入可能已执行,先读回核对,再决定是否再写 |
|
|
15
|
+
| `attempts` | 本次调用实际发出的请求数(含重试);发送前就失败时为 0 |
|
|
16
|
+
| `idempotencyKey` | 写入所用的幂等键(未显式传时为数据层生成的);`outcomeUnknown` 时用同一个键重发同一写入不会重复生效 |
|
|
17
|
+
| `details` | UNS 错误体的 `data`(如 `conflicts`、`resource`、`missingPermission`),或数据层附带的详情 |
|
|
18
|
+
| `cause` | 原始 `UnsV2Error` |
|
|
19
|
+
|
|
20
|
+
按 `code` / `reason` 分支,不匹配 message 文本。
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { DataError } from '@tier0/sdk-v2/data';
|
|
24
|
+
import { ZodError } from 'zod';
|
|
25
|
+
|
|
26
|
+
/** 把数据层错误转成 App 自己的 HTTP 响应。 */
|
|
27
|
+
export function toResponse(error: unknown): Response {
|
|
28
|
+
if (error instanceof DataError) {
|
|
29
|
+
if (error.code === 'DUPLICATE_KEY') return Response.json({ error: '编号已存在', code: error.code }, { status: 409 });
|
|
30
|
+
return Response.json({ error: error.message, code: error.code, requestId: error.requestId }, { status: error.status });
|
|
31
|
+
}
|
|
32
|
+
if (error instanceof ZodError) return Response.json({ error: error.issues[0]?.message ?? 'Validation failed' }, { status: 400 });
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 数据层错误码
|
|
38
|
+
|
|
39
|
+
| code | 含义 |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| `DATA_NOT_CONFIGURED` (503) | 缺少 TIER0_API_HOST / TIER0_API_KEY(或 apiHost / apiKey) |
|
|
42
|
+
| `DATA_TIMEOUT` (503) | UNS 未在超时内应答(每次调用从开始算共 25 秒,含排队与重试,`transportTimeoutMs` 可调);写入时 `outcomeUnknown` 为 true、不重试 |
|
|
43
|
+
| `DATA_OVERLOADED` (503) | 本进程 6 个请求名额一直占满,调用在超时前没排到,**没有发出**(`execution: 'notStarted'`,`retry.safe`);减少并发或合并读取 |
|
|
44
|
+
| `DATA_ABORTED` (499) | 业务请求已中止(`runWithRequestContext(request, …)` 的 `request.signal`):排队中的调用不再发出(`notStarted`),已发出的写入 `outcomeUnknown` |
|
|
45
|
+
| `DATA_UNREACHABLE` (503) | 连不上数据服务(读会自动重试);网关地址只在原始错误里,不进 message |
|
|
46
|
+
| `HTTP_502` / `HTTP_503` / `HTTP_504` (503) | 网关在滚动发布、Pod 重启时未经 UNS 直接返回;读会自动重试,写入时 `outcomeUnknown` 为 true、不重试 |
|
|
47
|
+
| `DATA_BAD_RESPONSE` (502) | UNS 应答不符合契约 |
|
|
48
|
+
| `BATCH_LIMIT_EXCEEDED` (400) | 原子批量超过 200 项,未发送 |
|
|
49
|
+
| `WRITE_ERRORS` (409) | 批量写入有条目被拒;`details.writeErrors` 列出各条,`updateMany` / `deleteMany` 的 `details` 还有累计数量与 `resumeAfter`;`insertMany` / `bulkWrite` 是原子的,整批回滚 |
|
|
50
|
+
| `TRANSACTION_FAILED` (409) | 事务未提交;`details.results` 列出各步骤 |
|
|
51
|
+
| `SCHEMA_CONFLICT` (409) | Preview 下声明与存储冲突(部署环境记日志,冲突集合按已有 ID 继续服务) |
|
|
52
|
+
| `SCHEMA_WARNINGS` (500) | Preview 下 ensure 带警告(`REQUIRED_NOT_ENFORCED`、`INDEX_BUILD_FAILED`) |
|
|
53
|
+
| `COLLECTION_UNAVAILABLE` (503) | ensure 没有返回该集合(见服务端日志) |
|
|
54
|
+
|
|
55
|
+
`updateMany` / `deleteMany` 已提交一部分后失败(之前的页,或 UNS 报告的本页部分提交)时,错误保留失败的 `code` 与 `status`,但 `execution` 为 `'committed'`(失败页结局未知时为 `'unknown'`)、`retry.safe` 为 false;`details` 是整个调用的累计结果 `{ matchedCount, modifiedCount | deletedCount, status: 'partiallyCommitted', hasMore, resumeAfter }`,与 UNS 部分提交的错误体相同。用 `resumeAfter` 续做,不要整体重做。
|
|
56
|
+
|
|
57
|
+
## UNS 错误码
|
|
58
|
+
|
|
59
|
+
| code | 含义与处理 |
|
|
60
|
+
| --- | --- |
|
|
61
|
+
| `SCHEMA_CONFLICT` (409) | 声明无法与存储合并,没有任何改动。`data.conflicts` 列出 `{ alias, path, reason, current?, declared? }`:`TYPE_CONFLICT` → 换新字段名;`LIMIT_EXCEEDED` → 拆分结构;`JOIN_UNSUPPORTED` → 存储中有声明无法放宽的节点,用 `schema:replace` 修复;`DATA_RULE_FIELD` → 员工数据规则(owner/state 字段)在用该路径,保持必填且类型不变,或请管理员修改规则;`OPEN_OBJECT` → 用 `z.object`;`ALIAS_IN_USE` / `NAME_IN_USE` → 换 alias;`INVALID_INDEX` → 修正索引 |
|
|
62
|
+
| `ANNOTATION_NOT_APPLIED`(`ignored` 提示) | 不是错误:ensure 保留已存储的描述,用 `schema:replace` 应用修改 |
|
|
63
|
+
| `REQUIRED_NOT_ENFORCED`(警告) | 声明要求的字段在存储中仍是可选;改回可选,或回填后用 `schema:replace` 收窄 |
|
|
64
|
+
| `INDEX_BUILD_FAILED`(警告) | 已有记录违反新唯一索引;修正重复数据,下次 ensure 会重试建索引 |
|
|
65
|
+
| `UPSERT_REQUIRES_UNIQUE_INDEX` | upsert 过滤条件缺少 `_id` 或已就绪唯一索引的全部字段 |
|
|
66
|
+
| `DUPLICATE_KEY` (409) | 唯一索引拒绝该值;restore 时表示与活动记录冲突、未恢复任何记录 |
|
|
67
|
+
| `VERSION_CONFLICT` (409) | 记录在读取后已变化;重新读取后用新 revision 重试 |
|
|
68
|
+
| `OVERLOADED` (429) | 本 workspace 的数据请求超过并发份额,`retry.afterMs` 后可重试(数据层已自动重试);页面读取合并成一次 `queryBatch`,不要逐条循环调用 |
|
|
69
|
+
| `APP_NOT_READY` (503) | App 刚导入,平台仍在准备;数据层已自动重试,稍后再试 |
|
|
70
|
+
| `DEPENDENCY_UNAVAILABLE` (503) | 平台鉴权依赖暂不可用,稍后重试 |
|
|
71
|
+
| `CREDENTIAL_CHANGED` (409 → 503) | App Key 在请求执行期间被修改,写入已回滚;网关已自动重试一次 |
|
|
72
|
+
| `OUTCOME_UNKNOWN` (503) | 写入提交阶段连接断开,可能已生效;先读回核对 |
|
|
73
|
+
| `FEATURE_NOT_ENABLED` (403) | 工作区未开通 UNS v2 |
|
|
74
|
+
| `QUERY_TIMEOUT` (504 → 503) | 查询执行超时(`retry.safe` 为 false,不会自动重试);按 `repair` 加有索引的条件或缩小范围 |
|
|
75
|
+
| `TEMPORARILY_UNAVAILABLE` (503) | 暂时性失败,数据层已按 `retry` 自动重试 |
|
|
76
|
+
| `APP_GRANT_REVOKED` (403) | 管理员撤销了本 App 对集合的授权;ensure 不会自动恢复,请管理员处理 |
|
|
77
|
+
| `APP_QUOTA_EXCEEDED` (409) | `data.resource` 指出触达的每 App 上限(64):`collections` → 归档不用的集合;`indexes` → 从声明删索引并 `schema:replace`;`archivedCollections` → 恢复一个或请管理员清理 |
|
|
78
|
+
| `INDEX_QUOTA_EXCEEDED` (409) | Workspace 实际存在的索引已达 200;删除不用的索引 |
|
|
79
|
+
| `COLLECTION_TOO_LARGE` (409) | archive / restore 最多处理 2000 条记录(`data.maxRecords`);不要归档大集合 |
|
|
80
|
+
| `FORBIDDEN` (403) | Key 不能做该操作(其他 App 或共享集合),或 Key 已吊销 |
|
|
81
|
+
|
|
82
|
+
记录调用上的 `data.reason`:`COLLECTION_NOT_GRANTED`(403,授权不覆盖该集合或操作)与 `COLLECTION_NOT_FOUND`(403/404,已归档或删除)会触发数据层重新 ensure;`APP_PERMISSION_MISSING`(403,`data.missingPermission`)表示 Key 缺少权限,例如删除记录需要 `uns.delete`——业务记录通常以状态结束(`CANCELLED`、`ARCHIVED`)而不是删除。
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# 声明集合与建模
|
|
2
|
+
|
|
3
|
+
`defineCollection({ alias, schema, indexes?, description?, seed? })` 返回冻结的声明;全部声明放进一个数组传给 `createDataClient({ collections })`。声明文件从 `@tier0/sdk-v2/data/define` 导入:它不含数据运行时,组件和 route 也能引用这些声明与 `Doc` 类型。alias 在 App 内唯一、不区分大小写,匹配 `^[A-Za-z][A-Za-z0-9_-]{0,62}$`。
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { defineCollection, type Doc } from '@tier0/sdk-v2/data/define';
|
|
8
|
+
|
|
9
|
+
export const customers = defineCollection({
|
|
10
|
+
alias: 'customers',
|
|
11
|
+
schema: z.object({ name: z.string(), tier: z.enum(['A', 'B', 'C']) }),
|
|
12
|
+
indexes: [{ path: 'name' }],
|
|
13
|
+
seed: [
|
|
14
|
+
{ _id: 'cust-1', name: 'Acme', tier: 'A' },
|
|
15
|
+
{ _id: 'cust-2', name: 'Globex', tier: 'B' },
|
|
16
|
+
],
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const salesOrders = defineCollection({
|
|
20
|
+
alias: 'sales_orders',
|
|
21
|
+
description: 'Customer sales orders',
|
|
22
|
+
schema: z.object({
|
|
23
|
+
code: z.string(),
|
|
24
|
+
status: z.enum(['DRAFT', 'CONFIRMED', 'SHIPPED', 'CANCELLED']),
|
|
25
|
+
customer: z.object({ id: z.string(), name: z.string() }),
|
|
26
|
+
lines: z.array(z.object({ sku: z.string(), qty: z.number().int().min(1) })),
|
|
27
|
+
notes: z.string().optional(),
|
|
28
|
+
orderedOn: z.string().describe('YYYY-MM-DD'),
|
|
29
|
+
confirmedAt: z.string().optional().describe('ISO-8601 UTC from toISOString()'),
|
|
30
|
+
}),
|
|
31
|
+
indexes: [{ path: 'code', unique: true }, { paths: ['status', 'orderedOn'] }, { path: 'lines', kind: 'gin' }],
|
|
32
|
+
seed: [
|
|
33
|
+
{ _id: 'so-1', code: 'SO-1', status: 'DRAFT', customer: { id: 'cust-1', name: 'Acme' }, lines: [], orderedOn: '2026-01-05' },
|
|
34
|
+
],
|
|
35
|
+
});
|
|
36
|
+
export type SalesOrder = Doc<typeof salesOrders>;
|
|
37
|
+
|
|
38
|
+
export const collections = [customers, salesOrders] as const;
|
|
39
|
+
|
|
40
|
+
// API 入参 Schema 从声明派生,再追加输入规则。
|
|
41
|
+
export const createSalesOrderInput = salesOrders.schema
|
|
42
|
+
.omit({ status: true, confirmedAt: true })
|
|
43
|
+
.extend({ code: z.string().trim().min(1).max(32) });
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## 可存储的 Zod 子集
|
|
47
|
+
|
|
48
|
+
集合 Schema 会转成 UNS 记录 Schema 子集;不能存储的写法在 `compileCollection` / 首次 ensure 时抛 `CollectionSchemaError`,并给出替代写法。
|
|
49
|
+
|
|
50
|
+
| 使用 | 不要用 |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `z.string()`、`z.number()`、`z.number().int()`、`z.boolean()` | `z.date()`、`z.bigint()`、`z.any()`、`z.unknown()` |
|
|
53
|
+
| 数字上的 `.min()` / `.max()`(闭区间) | `.positive()`、`.gt()`、`.lt()`、`.multipleOf()` |
|
|
54
|
+
| `z.enum([...])` | `z.literal()`、union、`.nullable()`、`.nullish()` |
|
|
55
|
+
| `.optional()`(字段可缺省) | 存 `null`:不写该字段,清空用 `$unset` |
|
|
56
|
+
| `z.object({...})`(始终封闭)、`z.array(item)` | `z.record()`、`z.looseObject()`、`.catchall()`、`z.tuple()` |
|
|
57
|
+
| 普通 `z.string()`,格式与长度在 API 入参校验 | `z.email()`、`z.uuid()`、`.regex()`、字符串 `.min(1)` |
|
|
58
|
+
| 在 service 里补默认值 | `.default()`、`.catch()`、`.transform()` |
|
|
59
|
+
|
|
60
|
+
日期存 `"YYYY-MM-DD"` 字符串,时刻存 `toISOString()` 的 ISO-8601 UTC 字符串,两者都能按字符串排序和范围过滤。`_id` 与 `_meta`(`revision`、`createdAt`、`updatedAt`,Unix 毫秒)是系统字段,不要声明。
|
|
61
|
+
|
|
62
|
+
限制:对象最多嵌套 8 层、每个对象 128 个属性、每个字段 100 个枚举值;`.describe()` 最多 2048 个 UTF-8 字节(约 680 个汉字);集合 `description` 最多 512 个字符。字段与集合描述只在首次创建时写入,之后修改要走 `schema:replace`(见 [Schema 演进](schema-evolution.md))。
|
|
63
|
+
|
|
64
|
+
## 字段类型标注
|
|
65
|
+
|
|
66
|
+
需要在 Collection 中明确显示 `int`、`float`、`double`、`datetime` 时,通过 Zod 元数据添加格式声明。传输仍使用 JSON Schema 的 `integer` / `number` / `string`:
|
|
67
|
+
|
|
68
|
+
| 声明 | 传输 Schema | 显示类型 |
|
|
69
|
+
| --- | --- | --- |
|
|
70
|
+
| `z.int().meta({ format: 'int32' })` | `{ type: 'integer', format: 'int32' }` | `int` |
|
|
71
|
+
| `z.number().meta({ format: 'float' })` | `{ type: 'number', format: 'float' }` | `float` |
|
|
72
|
+
| `z.number().meta({ format: 'double' })` | `{ type: 'number', format: 'double' }` | `double` |
|
|
73
|
+
| `z.string().meta({ format: 'date-time' })` | `{ type: 'string', format: 'date-time' }` | `datetime` |
|
|
74
|
+
|
|
75
|
+
`format` 当前是类型展示注解,不额外限制数值范围或精度,也不舍入数据。写入仍按原来的 Zod 类型和显式 `.min()` / `.max()` 校验;需要业务范围时应继续声明边界。普通 `z.number()`、`z.int()`、`z.number().int()` 和 `z.string()` 保持原有行为,不会自动追加格式或收窄已有集合。只接受上表四种类型与格式组合。
|
|
76
|
+
|
|
77
|
+
`datetime` 仍保存原始字符串,不校验日期是否有效、不解析或转换时区;`"not a date"` 也能通过字符串类型校验。需要日期合法性保证时,在 API 入参 Schema 单独使用 `z.iso.datetime()`;这类带 `pattern` 的验证器不能直接作为可存储的集合声明。新增注解不改变 Sample 外层 `time` 的毫秒时间戳协议、已有校验和业务时间含义。
|
|
78
|
+
|
|
79
|
+
## 索引
|
|
80
|
+
|
|
81
|
+
`{ path }` 或复合 `{ paths }`(最多 3 个不同路径);业务键加 `unique: true`;一个数组/对象字段用 `kind: 'gin'`;每个集合最多 16 个。路径只能沿对象属性走:数组元素里的字段(`lines.sku`)不能直接建索引,改为给 `lines` 建 GIN 或把值放到顶层字段。列表页过滤和排序用到的字段要建索引。
|
|
82
|
+
|
|
83
|
+
### 过期自动删除(TTL)
|
|
84
|
+
|
|
85
|
+
会话、验证码、临时预约这类到期就该消失的记录,用 TTL 索引让 UNS 自动删除,不要写定时清理任务:
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import { z } from 'zod';
|
|
89
|
+
import { defineCollection } from '@tier0/sdk-v2/data/define';
|
|
90
|
+
|
|
91
|
+
export const loginCodes = defineCollection({
|
|
92
|
+
alias: 'login_codes',
|
|
93
|
+
schema: z.object({ phone: z.string(), code: z.string(), issuedAt: z.number().int() }),
|
|
94
|
+
// issuedAt 存 Date.now();签发 5 分钟后删除。
|
|
95
|
+
indexes: [{ path: 'phone' }, { path: 'issuedAt', expireAfterSeconds: 300 }],
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
- 字段声明为 `z.number().int()`,存 Unix 毫秒(通常是 `Date.now()`);记录在该时刻再过 `expireAfterSeconds`(60–31536000 秒)后被删除。删除有分钟级延迟,读取时仍要自己比较时间。
|
|
100
|
+
- 每个集合最多 1 个 TTL 索引,只能是单个 `path`、不能 `unique`。缺这个字段的记录不会过期。
|
|
101
|
+
- 过期删除是**物理删除**,不能 restore;软删除的记录同样按 TTL 清理。
|
|
102
|
+
- ensure 只能新增 TTL 或把时间加长;缩短或去掉要通过 tier0 MCP 的 `schema:replace`。
|
|
103
|
+
|
|
104
|
+
## 种子数据
|
|
105
|
+
|
|
106
|
+
种子是基线记录:固定 `_id`,各生命周期状态自洽,相互引用用这些 ID;每个集合最多 1000 条。只在 ensure 报告集合为 `created` 时写入一次(每 200 条一个原子分块,分块带固定幂等键,重试安全);修改 `seed` 不会改动已存在的集合。不要在服务启动或列表为空时从代码插入基线数据。构建期可以对每条种子调用 `validateDocument(definition, document)` 校验。
|
|
107
|
+
|
|
108
|
+
## 按文档建模,而不是按表
|
|
109
|
+
|
|
110
|
+
- 属于同一记录、随它一起变化的内容(订单行、检查步骤、审批历史)嵌在该文档的数组里,一次写入保持一致;数组保持有界。
|
|
111
|
+
- 共享实体按 ID 引用,并快照需要展示的字段(`customer: { id, name }`),不要在读取时 join。`aggregate` 有 `$lookup`,但有行数限制,不要用它搭列表页。
|
|
112
|
+
- 每种业务对象一个集合,而不是每个页面一个集合。
|
|
113
|
+
- “最新优先”用 `_meta.createdAt` / `_meta.updatedAt`,由 UNS 维护。
|