@tier0/sdk-v2 0.2.1 → 0.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.
- package/README.md +29 -12
- package/dist/cjs/capabilities.js +2 -2
- package/dist/cjs/capabilities.js.map +1 -1
- package/dist/cjs/client.d.ts +284 -374
- package/dist/cjs/cloud-transport.js +6 -1
- package/dist/cjs/cloud-transport.js.map +1 -1
- package/dist/cjs/controls.d.ts +19 -7
- package/dist/cjs/controls.js +37 -34
- package/dist/cjs/controls.js.map +1 -1
- package/dist/cjs/data/bootstrap.js +3 -2
- package/dist/cjs/data/bootstrap.js.map +1 -1
- package/dist/cjs/data/collection.d.ts +64 -2
- package/dist/cjs/data/collection.js +15 -11
- package/dist/cjs/data/collection.js.map +1 -1
- package/dist/cjs/data/index.d.ts +1 -1
- package/dist/cjs/data/index.js.map +1 -1
- package/dist/cjs/files.d.ts +9 -9
- package/dist/cjs/mq/broker.d.ts +1 -1
- package/dist/cjs/mq/broker.js +1 -1
- package/dist/cjs/mq/broker.js.map +1 -1
- package/dist/cjs/mq/types.d.ts +1 -1
- package/dist/cjs/mq/types.js.map +1 -1
- package/dist/cjs/openapi/api.generated.d.ts +417 -541
- package/dist/cjs/openapi/api.generated.js +292 -377
- package/dist/cjs/openapi/api.generated.js.map +1 -1
- package/dist/cjs/openapi/client.js +1 -1
- package/dist/cjs/openapi/client.js.map +1 -1
- package/dist/cjs/openapi/codecs.generated.d.ts +394 -652
- package/dist/cjs/openapi/codecs.generated.js +2 -2
- package/dist/cjs/openapi/codecs.generated.js.map +1 -1
- package/dist/cjs/openapi/types.generated.d.ts +697 -906
- package/dist/cjs/openapi/types.generated.js.map +1 -1
- package/dist/cjs/source.d.ts +0 -7
- package/dist/cjs/source.js +1 -3
- package/dist/cjs/source.js.map +1 -1
- package/dist/cjs/stream.d.ts +0 -5
- package/dist/cjs/stream.js +3 -4
- package/dist/cjs/stream.js.map +1 -1
- package/dist/cjs/uns-v2/codec.js +1 -1
- package/dist/cjs/uns-v2/codec.js.map +1 -1
- package/dist/cjs/uns-v2/generated.d.ts +4741 -13453
- package/dist/cjs/uns-v2/generated.js +12 -33
- package/dist/cjs/uns-v2/generated.js.map +1 -1
- package/dist/esm/capabilities.js +2 -2
- package/dist/esm/capabilities.js.map +1 -1
- package/dist/esm/client.d.ts +284 -374
- package/dist/esm/cloud-transport.js +6 -1
- package/dist/esm/cloud-transport.js.map +1 -1
- package/dist/esm/controls.d.ts +19 -7
- package/dist/esm/controls.js +38 -35
- package/dist/esm/controls.js.map +1 -1
- package/dist/esm/data/bootstrap.js +4 -3
- package/dist/esm/data/bootstrap.js.map +1 -1
- package/dist/esm/data/collection.d.ts +64 -2
- package/dist/esm/data/collection.js +15 -12
- package/dist/esm/data/collection.js.map +1 -1
- package/dist/esm/data/index.d.ts +1 -1
- package/dist/esm/data/index.js.map +1 -1
- package/dist/esm/files.d.ts +9 -9
- package/dist/esm/mq/broker.d.ts +1 -1
- package/dist/esm/mq/broker.js +1 -1
- package/dist/esm/mq/broker.js.map +1 -1
- package/dist/esm/mq/types.d.ts +1 -1
- package/dist/esm/mq/types.js.map +1 -1
- package/dist/esm/openapi/api.generated.d.ts +417 -541
- package/dist/esm/openapi/api.generated.js +292 -377
- package/dist/esm/openapi/api.generated.js.map +1 -1
- package/dist/esm/openapi/client.js +1 -1
- package/dist/esm/openapi/client.js.map +1 -1
- package/dist/esm/openapi/codecs.generated.d.ts +394 -652
- 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 +697 -906
- package/dist/esm/openapi/types.generated.js.map +1 -1
- package/dist/esm/source.d.ts +0 -7
- package/dist/esm/source.js +1 -3
- package/dist/esm/source.js.map +1 -1
- package/dist/esm/stream.d.ts +0 -5
- package/dist/esm/stream.js +3 -4
- package/dist/esm/stream.js.map +1 -1
- package/dist/esm/uns-v2/codec.js +2 -2
- package/dist/esm/uns-v2/codec.js.map +1 -1
- package/dist/esm/uns-v2/generated.d.ts +4741 -13453
- package/dist/esm/uns-v2/generated.js +12 -33
- package/dist/esm/uns-v2/generated.js.map +1 -1
- package/package.json +17 -5
- package/skills/tier0-sdk-v2/SKILL.md +5 -3
- package/skills/tier0-sdk-v2/tier0-sdk-v2-agent/SKILL.md +4 -4
- package/skills/tier0-sdk-v2/tier0-sdk-v2-controls/SKILL.md +3 -3
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/read-write.md +17 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/delete.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/url.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-members/references/app-members.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-members/references/platform-members.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-notifications/references/get.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-notifications/references/send.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/SKILL.md +5 -5
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/changes.md +4 -4
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/create.md +3 -6
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/delete.md +10 -18
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/read.md +2 -2
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/state.md +9 -10
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/update.md +39 -21
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/SKILL.md +7 -7
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/create.md +13 -13
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/deploy.md +21 -11
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/lifecycle.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/read.md +25 -5
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/update.md +3 -5
- package/skills/tier0-sdk-v2/tier0-sdk-v2-system/references/info.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-system/references/whoami.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/SKILL.md +3 -3
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/create.md +14 -9
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/delete.md +5 -5
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/namespace.md +4 -4
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/read.md +8 -7
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/restore.md +2 -2
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/update.md +4 -4
|
@@ -3,31 +3,41 @@
|
|
|
3
3
|
| 方法 | POST 路径 | 必要参数 |
|
|
4
4
|
| --- | --- | --- |
|
|
5
5
|
| programs.deploy | /openapi/v2/uns/streams/program/deploy | id、dryRun;建议 expectedRevision |
|
|
6
|
-
| programs.disable | /openapi/v2/uns/streams/program/disable | id、dryRun;建议 expectedRevision |
|
|
7
6
|
| programs.rollback | /openapi/v2/uns/streams/program/rollback | id、versionId、dryRun;建议 expectedRevision |
|
|
8
7
|
| documents.disable | /openapi/v2/uns/streams/documents/disable | id、expectedRevision、expectedActiveRelease、dryRun |
|
|
9
8
|
|
|
10
9
|
全部写操作使用各自的 idempotencyKey。expectedSourceRevision 只适用于恰好一个 Source 依赖,且同时保护草稿冻结修订与当前 Source head;多源不能塞入单个修订值。原生文档没有 documents.deploy,当前云端 program 模型发布走 programs.deploy。
|
|
11
10
|
|
|
11
|
+
发布、停用和回滚需要 uns.stream.manage;相关 Source 访问还受各自授权约束。保存回执中的 revision、发布回执中的 activeVersion 与 activeRelease 分别用于不同目的:
|
|
12
|
+
|
|
13
|
+
| 字段 | 含义与用途 |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| revision | 草稿修订;传给下次写入的 expectedRevision,冲突时显式处理 |
|
|
16
|
+
| activeVersion | 不可变发布版本 ID;回滚的 versionId 使用这个 ID,不使用发布序号 |
|
|
17
|
+
| activeRelease | 本次事务记录的正整数发布序号;与 runs.list 中的 release 对照;无活跃发布或旧回执未记录时省略 |
|
|
18
|
+
|
|
19
|
+
programs 回执的 activeVersion:'0' 表示无活跃版本;新增 activeRelease 不用 0 表示未发布。原生 documents 回执的既有 activeRelease 约定不变。
|
|
20
|
+
|
|
12
21
|
```ts
|
|
13
|
-
import { createClient, type Tier0Client } from '@tier0/sdk-v2';
|
|
22
|
+
import { createClient, type Tier0Client, type CloudStreamDocumentView } from '@tier0/sdk-v2';
|
|
14
23
|
|
|
15
|
-
export async function deployStream(
|
|
16
|
-
const { data: current } = await client.stream.documents.get({ id, view: 'full' });
|
|
17
|
-
if (!('document' in current)) throw new Error('需要完整 Stream 文档');
|
|
24
|
+
export async function deployStream(current: CloudStreamDocumentView, intentKey: string, client: Tier0Client = createClient()) {
|
|
18
25
|
const sources = current.document.sources ?? [];
|
|
19
26
|
const request = {
|
|
20
|
-
id, expectedRevision: current.revision,
|
|
27
|
+
id: current.id, expectedRevision: current.revision,
|
|
21
28
|
...(sources.length === 1 ? { expectedSourceRevision: sources[0]!.configRevision } : {}),
|
|
22
29
|
};
|
|
23
30
|
const receipt = await client.stream.programs.deploy({
|
|
24
31
|
...request, dryRun: false, idempotencyKey: intentKey,
|
|
25
32
|
});
|
|
26
|
-
if (
|
|
33
|
+
if (!('id' in receipt.data) || receipt.data.activeVersion === '0') {
|
|
27
34
|
throw new Error('未确认发布版本');
|
|
28
35
|
}
|
|
29
|
-
|
|
30
|
-
|
|
36
|
+
const release = receipt.data.activeRelease;
|
|
37
|
+
if (release === undefined || BigInt(String(release)) <= 0n) {
|
|
38
|
+
throw new Error('历史回执缺少发布编号;保留原请求,不用当前发布编号替代');
|
|
39
|
+
}
|
|
40
|
+
return { receipt, release };
|
|
31
41
|
}
|
|
32
42
|
|
|
33
43
|
export async function disableStream(id: string, intentKey: string, client: Tier0Client = createClient()) {
|
|
@@ -43,7 +53,7 @@ export async function disableStream(id: string, intentKey: string, client: Tier0
|
|
|
43
53
|
}
|
|
44
54
|
```
|
|
45
55
|
|
|
46
|
-
|
|
56
|
+
将创建或更新回执的 current 传给 deployStream,只发一次发布请求。只有手上没有草稿快照时才先 documents.get。使用 [按发布号查询运行记录](read.md#观察本次发布) 才能观察这次发布,观察窗口汇总不能证明该版本运行。发布成功不表示外部连接健康或执行成功。停用保留草稿。仅修改草稿的任务不额外发布/停用。
|
|
47
57
|
|
|
48
58
|
## 回滚到明确版本
|
|
49
59
|
|
|
@@ -61,4 +71,4 @@ export async function rollbackStream(
|
|
|
61
71
|
}
|
|
62
72
|
```
|
|
63
73
|
|
|
64
|
-
检查回执 activeVersion
|
|
74
|
+
检查回执 activeVersion 与 activeRelease。超时或 UnsV2OutcomeUnknownError 时保留原路由、载荷和幂等键;允许恢复时原样重发以取得原回执,不用新键再次发布。旧回执可能没有 activeRelease,不能读取当前 head 后冒充旧请求的发布编号。相同草稿使用不同键仍会创建新发布,expectedRevision 仅保护草稿修订。预览用 dryRun=true,返回 validated/sideEffects,不保证稍后的实际发布一定成功。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Stream 样例测试与流程衔接
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
创建并发布时,将 [创建](create.md) 或 [修改](update.md) 回执中的草稿直接交给 [发布](deploy.md),再用发布回执的 activeRelease [观察运行](read.md#观察本次发布),无需在发布前后各 get 一次。只有缺少当前草稿、处理版本冲突或需要最新状态时才 [查询](read.md)。停用、回滚和 [删除](delete.md) 按任务选择,不自动执行整套生命周期。
|
|
4
4
|
|
|
5
5
|
## 原生文档样例测试
|
|
6
6
|
|
|
@@ -3,22 +3,20 @@
|
|
|
3
3
|
| 方法 | POST 路径 | 输入 | 结果 |
|
|
4
4
|
| --- | --- | --- | --- |
|
|
5
5
|
| programs.list | /openapi/v2/uns/streams/program/list | page、size、search、sourceId、model、status、archived | list、total、hasMore、nextPage |
|
|
6
|
-
|
|
|
7
|
-
| documents.get | /openapi/v2/uns/streams/documents/get | id | 完整草稿、revision、status、activeRelease、可选 activeDocument |
|
|
6
|
+
| documents.get | /openapi/v2/uns/streams/documents/get | id;可选 view:summary/full | summary 返回摘要;full 返回完整草稿、revision、status、activeRelease、可选 activeDocument |
|
|
8
7
|
| observations.get | /openapi/v2/uns/streams/observation/get | id | 运行观测 |
|
|
9
8
|
| runs.list | /openapi/v2/uns/streams/runs/list | id、size、cursor | 执行记录 |
|
|
10
9
|
| programs.versions.list | /openapi/v2/uns/streams/program/versions/list | id、page、size | list、total,含 versionId |
|
|
11
10
|
|
|
12
|
-
page 从 1 开始,size 最大 200
|
|
11
|
+
page 从 1 开始,size 最大 200。summary 只需 uns.stream.view 或 uns.stream.manage;full 或省略 view 需要 uns.stream.manage,API Key 还必须是 full_access。摘要不含脚本,不能据此重建草稿。已有创建或更新回执时可复用其文档与 revision,不必再读取。
|
|
13
12
|
|
|
14
13
|
```ts
|
|
15
14
|
import { createClient, type Tier0Client } from '@tier0/sdk-v2';
|
|
16
15
|
|
|
17
16
|
export async function readStream(id: string, client: Tier0Client = createClient()) {
|
|
18
17
|
const draft = await client.stream.documents.get({ id });
|
|
19
|
-
const summary = await client.stream.programs.get({ id });
|
|
20
18
|
const observation = await client.stream.observations.get({ id });
|
|
21
|
-
return { draft: draft.data,
|
|
19
|
+
return { draft: draft.data, observation: observation.data };
|
|
22
20
|
}
|
|
23
21
|
export async function* listStreams(client: Tier0Client = createClient()) {
|
|
24
22
|
let page = 1;
|
|
@@ -33,3 +31,25 @@ export async function* listStreams(client: Tier0Client = createClient()) {
|
|
|
33
31
|
```
|
|
34
32
|
|
|
35
33
|
保存、发布、某次执行成功是三个事实。显示实际 revision/activeVersion/release,不用旧 runs 证明新版本生效。版本列表不保证与普通列表相同分页结构;按其 list/total/page/size 读取,versionId 不是 release 序号。
|
|
34
|
+
|
|
35
|
+
## 观察本次发布
|
|
36
|
+
|
|
37
|
+
把 deploy 回执的 activeRelease 原样传入,不需要先读取当前 head。runs.list 需要 uns.stream.view 或 uns.stream.manage;它没有服务端 release 过滤参数,按返回的 nextCursor 继续翻页并在客户端匹配发布号:
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { createClient, type Tier0Client, type UnsV2Integer } from '@tier0/sdk-v2';
|
|
41
|
+
|
|
42
|
+
export async function readPublishedRuns(
|
|
43
|
+
id: string, release: UnsV2Integer, cursor?: string,
|
|
44
|
+
client: Tier0Client = createClient(),
|
|
45
|
+
) {
|
|
46
|
+
if (typeof release === 'number' && !Number.isSafeInteger(release)) {
|
|
47
|
+
throw new Error('发布号必须保留回执中的精确整数,不能传已失真的 number');
|
|
48
|
+
}
|
|
49
|
+
if (BigInt(String(release)) <= 0n) throw new Error('需要发布回执中的正整数发布号');
|
|
50
|
+
const { data } = await client.stream.runs.list({ id, size: 100, ...(cursor ? { cursor } : {}) });
|
|
51
|
+
return { ...data, items: data.items.filter(run => run.release === String(release)) };
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
此函数只读一页。items 为空但 nextCursor 非空时,下一页仍可能有匹配记录;达到调用方的观察时限就报告“尚未观察到”。匹配记录也要检查 status、entryId 和时间,不能把存在记录当成执行成功。历史幂等回执若缺少 activeRelease,应保留为未确认,不能用当前 head 的发布号代替。
|
|
@@ -21,16 +21,14 @@ export async function updateStreamDescription(
|
|
|
21
21
|
const { data: current } = await client.stream.documents.get({ id, view: 'full' });
|
|
22
22
|
if (!('document' in current)) throw new Error('需要完整 Stream 文档');
|
|
23
23
|
const document: CloudStreamDocument = { ...current.document, description };
|
|
24
|
-
const checked = await client.stream.documents.validate({ document });
|
|
25
|
-
if (!checked.data.valid) throw new Error('Stream 文档校验失败,请检查 issues');
|
|
26
24
|
const saved = await client.stream.documents.update({
|
|
27
25
|
id, expectedRevision: current.revision, document, dryRun: false, idempotencyKey: intentKey,
|
|
28
26
|
});
|
|
29
27
|
if (!('id' in saved.data)) throw new Error('未返回已保存文档');
|
|
30
|
-
return { receipt: saved, current:
|
|
28
|
+
return { receipt: saved, current: saved.data };
|
|
31
29
|
}
|
|
32
30
|
```
|
|
33
31
|
|
|
34
|
-
|
|
32
|
+
代码应用可直接用 documents.update({id, expectedRevision, program, dryRun:false, idempotencyKey}),由服务端编译入口和绑定。编辑完整文档时保留 sdkVersion/timeoutMs,并同步 entries/sources;写入本身执行校验,只有需要提前展示问题时才单独 validate。不要对documents.get 的 summary 做展开更新。
|
|
35
33
|
|
|
36
|
-
响应是完整 CloudStreamDocumentView
|
|
34
|
+
响应是完整 CloudStreamDocumentView 或预检结果;把 saved.data 直接传给下一步[发布示例](deploy.md),无需为了 revision 再读取。已有当前完整文档时可省去示例最初的 get。保存草稿不会自动部署,activeDocument 可能仍是旧发布版本。VERSION_CONFLICT 后重新读取、比较并决策;不无条件覆盖。
|
|
@@ -13,7 +13,7 @@ UNS 管数据命名空间、集合、Record 和 Sample;外部连接与脚本
|
|
|
13
13
|
| --- | --- | --- |
|
|
14
14
|
| 创建集合、定义 Schema、新增记录 | [创建](references/create.md) | metadataInsertOne/Many、recordInsertOne |
|
|
15
15
|
| 查询集合、筛选/排序记录 | [查询](references/read.md) | dataAppContext、metadataFind/FindOne(非 App 凭证)、collectionDescribe、recordFind |
|
|
16
|
-
| 改记录、集合名称、扩展 Schema | [修改](references/update.md) | recordUpdateOne、metadataUpdateOne/Many
|
|
16
|
+
| 改记录、集合名称、扩展 Schema | [修改](references/update.md) | recordUpdateOne、metadataUpdateOne/Many |
|
|
17
17
|
| 删记录、软删除集合 | [删除](references/delete.md) | recordDeleteOne、metadataDeleteOne/Many |
|
|
18
18
|
| 恢复集合或记录 | [恢复](references/restore.md) | metadataRestore、recordRestore |
|
|
19
19
|
| 分页、历史采样、事务、写入结果 | [数据工作流](references/data-workflows.md) | sampleFind、recordTransactionExecute |
|
|
@@ -42,7 +42,7 @@ export async function findAppCollection(alias: string) {
|
|
|
42
42
|
## 核心约束
|
|
43
43
|
|
|
44
44
|
1. 记录行是 id/data/revision;filter 与 update 的业务路径用 name、customer.name,不加 data.;系统路径用 _id、_meta.revision。
|
|
45
|
-
2.
|
|
45
|
+
2. 改/删使用最近写回执或读取取得的 revision 作为 expectedRevision;创建时可用 returnDocument:'after' 取得快照。历史重放不是当前最新版本,冲突时显式处理;不同操作使用独立意图键,长度上限以当前操作契约为准。
|
|
46
46
|
3. metadataUpdateOne 的 $set.recordSchema 替换完整 Schema,不迁移已有记录;未更新的 sampleSchema/indexes 保留。先预检兼容性。
|
|
47
47
|
4. 集合无硬删除入口,用 metadataDeleteOne/Many 软删除;Record 删除会物理删除关联 Sample,恢复 Record 不会恢复这些 Sample。
|
|
48
48
|
5. recordFind 使用 pageInfo.hasMore/nextCursor,limit 1–200;sort 为 [['field',1]]。单页不是全量,跨页不是稳定快照。
|
|
@@ -50,6 +50,6 @@ export async function findAppCollection(alias: string) {
|
|
|
50
50
|
|
|
51
51
|
## 结果与异常
|
|
52
52
|
|
|
53
|
-
响应为 code/msg/requestId/data。元数据 find 返回 items/pageInfo
|
|
53
|
+
响应为 code/msg/requestId/data。元数据 find 返回 items/pageInfo;单条 updateOne/replaceOne/deleteOne 请求 returnDocument 时附带 value;普通写入默认返回对应计数和 ID。metadataTransact 的 results 按 opId 对应。检查 committed、每项错误和实际计数;dryRun 只校验。metadataBulkWrite 默认原子,显式非原子时必须逐项检查 results/errors;跨 kind 的依赖写入使用 metadataTransact。recordBulkWrite 不保证跨集合事务。
|
|
54
54
|
|
|
55
55
|
大整数与 JSON 精确数字可能为 bigint/UnsV2RawNumber;保留读取到的 revision 类型,不用 Number 或普通 JSON.stringify 做无损往返。错误带 execution(notStarted / rolledBack / committed / unknown)与 retry(safe、afterMs)。UnsV2OutcomeUnknownError(execution 为 unknown)先读回核对内容;retry.safe 时可以用同一请求、同一幂等键原样重发。取消请求不撤销写入;client.uns 不自动重试。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 创建集合与记录
|
|
2
2
|
|
|
3
|
-
元数据使用 metadataInsertOne(POST /openapi/v2/uns/metadata)或
|
|
3
|
+
元数据使用 metadataInsertOne(POST /openapi/v2/uns/metadata)或 metadataBulkWrite 的 insertOne 项;kind 指定 directory/topic/collection。单条提供 data、可选 id;批量提供同一 kind 的 operations[{insertOne:{id?,data}}]。idempotencyKey 标识一个写入意图;dryRun=true 仅校验。schemaVersion 由服务端赋默认值。
|
|
4
4
|
|
|
5
5
|
集合 data 必须包含 name、recordSchema,可选 description、parentId、sampleSchema、indexes、semantics。parentId=null 表示根目录。索引创建后仍需确认状态为 ready。
|
|
6
6
|
|
|
@@ -28,13 +28,19 @@ export async function createDeviceCollection(
|
|
|
28
28
|
if (preview.data.status !== 'validated') throw new Error('集合预检未通过');
|
|
29
29
|
const receipt = await client.uns.metadataInsertOne({ ...request, dryRun: false, idempotencyKey: intentKey });
|
|
30
30
|
if (receipt.data.status !== 'committed') return { state: 'unconfirmed' as const, receipt };
|
|
31
|
-
const current = await client.uns.
|
|
32
|
-
if (!current.data.
|
|
33
|
-
return { state: 'committed' as const, receipt, current: current.data.
|
|
31
|
+
const current = await client.uns.metadataFind({ kind: 'collection', filter: { _id: collectionId }, limit: 1 });
|
|
32
|
+
if (!current.data.items[0]) throw new Error('集合创建有回执,读回未确认');
|
|
33
|
+
return { state: 'committed' as const, receipt, current: current.data.items[0] };
|
|
34
34
|
}
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
单条 Record 新增默认返回 insertedId/status/replayed。需要创建后的数据、revision 和时间戳时,传 returnDocument:'after',同一次写入返回 value,无需再查询;可配合 projection,调用者必须同时具有读取权限。幂等重放返回原始创建快照,后续读取最新状态仍用 recordGet/recordFind。dryRun 的 value 是未提交预览。
|
|
38
|
+
|
|
39
|
+
returnDocument 只允许 none(默认)或 after,不支持 before;projection 只能和 after 一起传。新增仍是 insert,已存在的 ID 不会变成更新。after 的 value 包括服务端补入的字段,但只返回当前授权可见的数据:普通数据权限需 uns.write 和 uns.read,App 还要满足集合的 record:write / record:read 及当前员工、行和字段策略。服务端在提交前校验读取权限,重放时也重新校验;旧回执不能绕过已撤销的授权。
|
|
40
|
+
|
|
41
|
+
省略 returnDocument 与显式 none 保持相同幂等语义。不能用同一个意图键把原来的 none 改成 after 补取快照,否则返回 IDEMPOTENCY_CONFLICT;已创建的记录应改用读取接口。after 重放可对原始快照应用 projection,但不会变成最新记录。创建快照中的 revision 可用于下一次修改;若已有并发修改,版本冲突仍需显式处理。
|
|
42
|
+
|
|
43
|
+
批量新增返回 insertedCount/insertedIds 及适用的逐项错误。insertedIds 的键是原始输入从 0 开始的索引。省略自定义 ID 时从成功回执取得实际 ID,不能把名称当成 ID。
|
|
38
44
|
|
|
39
45
|
```ts
|
|
40
46
|
import { createClient, type Tier0Client } from '@tier0/sdk-v2';
|
|
@@ -44,12 +50,11 @@ export async function insertDevice(
|
|
|
44
50
|
client: Tier0Client = createClient(),
|
|
45
51
|
) {
|
|
46
52
|
const receipt = await client.uns.recordInsertOne({
|
|
47
|
-
collectionId, id, data: { name, enabled: true }, dryRun: false, idempotencyKey: intentKey,
|
|
53
|
+
collectionId, id, data: { name, enabled: true }, dryRun: false, idempotencyKey: intentKey, returnDocument: 'after',
|
|
48
54
|
});
|
|
49
55
|
if (receipt.data.status !== 'committed') return { state: 'unconfirmed' as const, receipt };
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return { state: 'committed' as const, receipt, current: found.data.items[0] };
|
|
56
|
+
if (!receipt.data.value) throw new Error('创建回执缺少请求的快照');
|
|
57
|
+
return { state: 'committed' as const, receipt, created: receipt.data.value };
|
|
53
58
|
}
|
|
54
59
|
```
|
|
55
60
|
|
|
@@ -23,7 +23,7 @@ export async function deleteDevice(
|
|
|
23
23
|
}
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
元数据使用 metadataDeleteOne/Many,或
|
|
26
|
+
元数据使用 metadataDeleteOne/Many,或 metadataDeleteOne + returnDocument:before 返回删除前对象。它们执行软删除,增加 revision,不隐式级联目录后代、引用对象或集合数据。引用约束与版本冲突必须处理,不能自行扩展删除范围。
|
|
27
27
|
|
|
28
28
|
```ts
|
|
29
29
|
import { createClient, type Tier0Client } from '@tier0/sdk-v2';
|
|
@@ -31,7 +31,7 @@ import { createClient, type Tier0Client } from '@tier0/sdk-v2';
|
|
|
31
31
|
export async function deleteCollection(
|
|
32
32
|
id: string, intentKey: string, client: Tier0Client = createClient(),
|
|
33
33
|
) {
|
|
34
|
-
const current = (await client.uns.
|
|
34
|
+
const current = (await client.uns.metadataFind({ kind: 'collection', filter: { _id: id }, limit: 1 })).data.items[0];
|
|
35
35
|
if (!current) throw new Error('集合不存在或不可见,未执行删除');
|
|
36
36
|
const receipt = await client.uns.metadataDeleteOne({
|
|
37
37
|
kind: 'collection', filter: { _id: id }, expectedRevision: current.revision,
|
|
@@ -40,9 +40,9 @@ export async function deleteCollection(
|
|
|
40
40
|
if (receipt.data.status !== 'committed' || String(receipt.data.deletedCount) !== '1') {
|
|
41
41
|
return { state: 'unconfirmed' as const, receipt };
|
|
42
42
|
}
|
|
43
|
-
const deleted = await client.uns.
|
|
44
|
-
if (!deleted.data.
|
|
45
|
-
return { state: 'deleted' as const, receipt, deleted: deleted.data.
|
|
43
|
+
const deleted = await client.uns.metadataFind({ kind: 'collection', filter: { _id: id }, state: 'deleted', limit: 1 });
|
|
44
|
+
if (!deleted.data.items[0]) throw new Error('删除有回执,但删除状态读回未确认');
|
|
45
|
+
return { state: 'deleted' as const, receipt, deleted: deleted.data.items[0] };
|
|
46
46
|
}
|
|
47
47
|
```
|
|
48
48
|
|
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
| 场景 | 方法 |
|
|
6
6
|
| --- | --- |
|
|
7
|
-
| 单条/批量新增 | metadataInsertOne /
|
|
7
|
+
| 单条/批量新增 | metadataInsertOne / metadataBulkWrite 的 insertOne 项 |
|
|
8
8
|
| 单条/批量条件更新 | metadataUpdateOne / metadataUpdateMany |
|
|
9
|
-
| 更新并读取原子结果 |
|
|
9
|
+
| 更新并读取原子结果 | metadataUpdateOne / metadataReplaceOne + returnDocument:before/after |
|
|
10
10
|
| 同 kind 混合写入 | metadataBulkWrite |
|
|
11
11
|
| 跨 kind、有依赖的组合操作 | metadataTransact |
|
|
12
|
-
| 软删除并返回原对象 |
|
|
12
|
+
| 软删除并返回原对象 | metadataDeleteOne + returnDocument:before |
|
|
13
13
|
| 按明确 ID 批量恢复 | metadataRestore |
|
|
14
14
|
|
|
15
|
-
普通写操作只指定一个 kind。
|
|
15
|
+
普通写操作只指定一个 kind。updateMany/deleteMany/restore 固定原子执行;bulkWrite 默认 atomic=true,原子批次不接受 ordered=false。bulkWrite 显式 atomic=false 时 ordered=true 遇错停止,false 继续,并检查 results/errors。非原子执行有任一项已提交后失败时,`execution` 为 committed、`retry.safe` 为 false,错误的 data 是累计结果:序号小于 `nextIndex` 且不在 errors 里的操作已提交;有 `unknownUntil` 时 `[nextIndex, unknownUntil)` 结局未知,用同一个幂等键重试(不带键时只有按 id 的操作能先读回再续做,所以非原子批次始终带幂等键);没有 `unknownUntil` 时从 `nextIndex` 续做。第一块就结局未知时 `execution` 为 unknown。批次最多 200 项。不要给所有对象套一个相同 expectedRevision:需要逐项版本检查时在 bulkWrite 中分别提供。
|
|
16
16
|
|
|
17
17
|
```ts
|
|
18
18
|
import { createClient, type Tier0Client } from '@tier0/sdk-v2';
|
|
@@ -3,23 +3,24 @@
|
|
|
3
3
|
| 方法 | 必要输入 | 返回 data |
|
|
4
4
|
| --- | --- | --- |
|
|
5
5
|
| metadataFind | kinds;可选 filter、sort、projection、page、state | items、pageInfo |
|
|
6
|
-
|
|
|
7
|
-
| metadataCount /
|
|
6
|
+
| metadataFind + limit:1 | kind、filter;可选 state | 取 items[0],空结果视为未匹配 |
|
|
7
|
+
| metadataCount / metadataAggregate | kind/kinds 与查询条件;去重 pipeline 为 [{ $distinct: field }] | count / items、pageInfo;去重每项为 {value} |
|
|
8
8
|
| collectionDescribe | collectionId | 集合结构和数据能力 |
|
|
9
9
|
| recordFind | collectionId;可选 filter、sort、limit、cursor | items、pageInfo |
|
|
10
10
|
|
|
11
|
-
元数据查询配置字段写 name、parentId;系统字段写 _id、_meta.kind、_meta.revision。返回资源的配置在
|
|
11
|
+
元数据查询配置字段写 name、parentId;系统字段写 _id、_meta.kind、_meta.revision。返回资源的配置在 items[].data 中。state 为 active/deleted/all,默认 active。对象身份始终是 kind + id。
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
14
|
import { createClient, type Tier0Client } from '@tier0/sdk-v2';
|
|
15
15
|
|
|
16
16
|
export async function readDevices(collectionId: string, client: Tier0Client = createClient()) {
|
|
17
|
-
const collection = await client.uns.
|
|
18
|
-
|
|
17
|
+
const collection = await client.uns.metadataFind({ kind: 'collection', filter: { _id: collectionId }, limit: 1 });
|
|
18
|
+
const definition = collection.data.items[0];
|
|
19
|
+
if (!definition) throw new Error('集合不存在或不可见');
|
|
19
20
|
const records = await client.uns.recordFind({
|
|
20
21
|
collectionId, filter: { enabled: true }, sort: [['name', 1]], limit: 20,
|
|
21
22
|
});
|
|
22
|
-
return { definition:
|
|
23
|
+
return { definition: definition.data, items: records.data.items, pageInfo: records.data.pageInfo };
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
export async function listCollections(page = 1, client: Tier0Client = createClient()) {
|
|
@@ -31,4 +32,4 @@ export async function listCollections(page = 1, client: Tier0Client = createClie
|
|
|
31
32
|
|
|
32
33
|
按 pageInfo.hasMore/nextPage 继续元数据分页;不要把第一页当全量。recordFind 的游标循环见[数据工作流](data-workflows.md)。sort 是数组元组。
|
|
33
34
|
|
|
34
|
-
以上 metadataFind
|
|
35
|
+
以上 metadataFind 示例用于 Workspace 集成(会话、personal / agent Key)。App 凭证不能调用 metadataFind:用 dataAppContext 精确选择授权 alias,集合的 revision、indexStatus、ttl 也在其中。数据授权不等于元数据管理授权。网络/权限错误必须传播,不能用空数组掩盖错误。
|
|
@@ -8,7 +8,7 @@ import { createClient, type Tier0Client } from '@tier0/sdk-v2';
|
|
|
8
8
|
export async function restoreCollection(
|
|
9
9
|
id: string, intentKey: string, client: Tier0Client = createClient(),
|
|
10
10
|
) {
|
|
11
|
-
const deleted = (await client.uns.
|
|
11
|
+
const deleted = (await client.uns.metadataFind({ kind: 'collection', filter: { _id: id }, state: 'deleted', limit: 1 })).data.items[0];
|
|
12
12
|
if (!deleted) throw new Error('未找到待恢复集合');
|
|
13
13
|
const receipt = await client.uns.metadataRestore({
|
|
14
14
|
kind: 'collection', items: [{ id, expectedRevision: deleted.revision }], idempotencyKey: intentKey,
|
|
@@ -16,7 +16,7 @@ export async function restoreCollection(
|
|
|
16
16
|
if (receipt.data.status !== 'committed' || String(receipt.data.restoredCount) !== '1') {
|
|
17
17
|
return { state: 'unconfirmed' as const, receipt };
|
|
18
18
|
}
|
|
19
|
-
const current = (await client.uns.
|
|
19
|
+
const current = (await client.uns.metadataFind({ kind: 'collection', filter: { _id: id }, limit: 1 })).data.items[0];
|
|
20
20
|
if (!current) throw new Error('恢复有回执,读回未确认');
|
|
21
21
|
return { state: 'committed' as const, receipt, current };
|
|
22
22
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 修改记录、元数据和 Schema
|
|
2
2
|
|
|
3
|
-
元数据单条使用 metadataUpdateOne
|
|
3
|
+
元数据单条使用 metadataUpdateOne;returnDocument 默认 none,需要原子返回 value 时显式传 before/after。批量相同更新使用 metadataUpdateMany;不同更新使用 metadataBulkWrite。完整替换使用 metadataReplaceOne,replacement 是完整可写配置。
|
|
4
4
|
|
|
5
5
|
update 首版支持 $set/$unset/$setOnInsert。字段使用裸配置路径;_id/_meta 为只读。写前读取 revision,编辑页面携带 expectedRevision,冲突后重新比较。单条 upsert 需明确 _id 等值条件,新增内容满足完整创建约束;同 ID 的软删除对象必须显式恢复。
|
|
6
6
|
|
|
@@ -10,9 +10,9 @@ import { createClient, type Tier0Client } from '@tier0/sdk-v2';
|
|
|
10
10
|
export async function renameCollection(
|
|
11
11
|
id: string, name: string, intentKey: string, client: Tier0Client = createClient(),
|
|
12
12
|
) {
|
|
13
|
-
const current = (await client.uns.
|
|
13
|
+
const current = (await client.uns.metadataFind({ kind: 'collection', filter: { _id: id }, limit: 1 })).data.items[0];
|
|
14
14
|
if (!current) throw new Error('集合不存在或不可见');
|
|
15
|
-
return client.uns.
|
|
15
|
+
return client.uns.metadataUpdateOne({
|
|
16
16
|
kind: 'collection', filter: { _id: id }, expectedRevision: current.revision,
|
|
17
17
|
update: { $set: { name } }, returnDocument: 'after', upsert: false, idempotencyKey: intentKey,
|
|
18
18
|
});
|
|
@@ -27,7 +27,7 @@ import { createClient, type Tier0Client, type Schema } from '@tier0/sdk-v2';
|
|
|
27
27
|
export async function replaceRecordSchema(
|
|
28
28
|
id: string, recordSchema: Schema, intentKey: string, client: Tier0Client = createClient(),
|
|
29
29
|
) {
|
|
30
|
-
const current = (await client.uns.
|
|
30
|
+
const current = (await client.uns.metadataFind({ kind: 'collection', filter: { _id: id }, limit: 1 })).data.items[0];
|
|
31
31
|
if (!current) throw new Error('集合不存在或不可见');
|
|
32
32
|
const request = { kind: 'collection' as const, filter: { _id: id },
|
|
33
33
|
expectedRevision: current.revision, update: { $set: { recordSchema } } };
|