@tier0/sdk-v2 0.3.0 → 0.5.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 +14 -5
- package/dist/cjs/client.d.ts +1 -3
- package/dist/cjs/cloud-transport.js +1 -2
- package/dist/cjs/cloud-transport.js.map +1 -1
- package/dist/cjs/data/schema.js +5 -1
- package/dist/cjs/data/schema.js.map +1 -1
- package/dist/cjs/openapi/types.generated.d.ts +1 -1
- package/dist/cjs/openapi/types.generated.js.map +1 -1
- package/dist/cjs/source.d.ts +1 -0
- package/dist/cjs/source.js +1 -0
- package/dist/cjs/source.js.map +1 -1
- package/dist/cjs/stream.d.ts +0 -3
- package/dist/cjs/stream.js +0 -1
- package/dist/cjs/stream.js.map +1 -1
- package/dist/cjs/uns-v2/generated.d.ts +566 -114
- package/dist/cjs/uns-v2/generated.js +19 -19
- package/dist/cjs/uns-v2/generated.js.map +1 -1
- package/dist/esm/client.d.ts +1 -3
- package/dist/esm/cloud-transport.js +1 -2
- package/dist/esm/cloud-transport.js.map +1 -1
- package/dist/esm/data/schema.js +5 -1
- package/dist/esm/data/schema.js.map +1 -1
- package/dist/esm/openapi/types.generated.d.ts +1 -1
- package/dist/esm/openapi/types.generated.js.map +1 -1
- package/dist/esm/source.d.ts +1 -0
- package/dist/esm/source.js +1 -0
- package/dist/esm/source.js.map +1 -1
- package/dist/esm/stream.d.ts +0 -3
- package/dist/esm/stream.js +0 -1
- package/dist/esm/stream.js.map +1 -1
- package/dist/esm/uns-v2/generated.d.ts +566 -114
- package/dist/esm/uns-v2/generated.js +19 -19
- package/dist/esm/uns-v2/generated.js.map +1 -1
- package/docs/acceptance-2026-10-22.md +3 -1
- package/package.json +2 -2
- package/skills/tier0-sdk-v2/tier0-sdk-v2-controls/SKILL.md +2 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/SKILL.md +2 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/consistency.md +3 -3
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/modeling.md +6 -4
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/read-write.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/schema-evolution.md +2 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/SKILL.md +2 -2
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/create.md +66 -8
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/protocols.md +11 -4
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/SKILL.md +2 -2
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/create.md +7 -4
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/SKILL.md +2 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/create.md +1 -1
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
日期:2026-10-22。包:`@tier0/sdk-v2@0.1.0`。
|
|
4
4
|
|
|
5
|
+
> 历史记录:以下结果仅适用于当时版本。2026-10-27 已退役 Stream 就绪探针及逐 Key Control scopes/codes;当前 SDK 不再导出该探针。不得将下文历史 403 当作 Stream 故障或按旧授权模型要求扩权。后续验收见 [Tier0-doc 新版架构专题](https://github.com/FREEZONEX/Tier0-doc/blob/main/docs/新版架构/03-Cloud新版改造/112-Stream控制就绪探针退役.md)。
|
|
6
|
+
|
|
5
7
|
验收对应 SDK 提交 `5d30d5154354bac94bbbe88402a8303d6c43526d` 的安装包。报告提交时远端已合入其他功能(至 `78f5168`);下列测试数量和业务结论不覆盖那些新增功能。
|
|
6
8
|
|
|
7
9
|
结论:安装包和本地自动化通过;多组真实业务操作通过,但不能宣称“所有功能已可用”。追加验收已完成真实站内通知发送、Stream 发布、当前 release 的真实执行、停用及归档。Source 创建预检、Control 权限、Stream 能力查询、Agent 真实用户身份及文件大分片传输仍有阻断或限制。
|
|
@@ -62,7 +64,7 @@ Source 的 503 是后端返回的统一生命周期错误。对固定版本代
|
|
|
62
64
|
| --- | --- | --- |
|
|
63
65
|
| Source 创建 503 | 当前镜像仍复现;requestId `8b0197c1-3479-4277-ba70-89e131512437`。错误映射将多种内部错误合并为 `cloud lifecycle service unavailable`,现有日志未能将根因关联到此请求 | 服务端在 Source 管理身份刷新、租户解析、凭据绑定预检、事务写入边界增加不含凭据的阶段码和 requestId 关联,再针对确切失败修复。暂不能声称重启、加权限或迁库能解决。未修改部署或数据库 |
|
|
64
66
|
| 大文件分片 PUT 超时 | 追加对照中 1 KiB 的 PUT=200、complete=200;5 MiB 首片仍超过 20 秒。原测试 30/60 秒同样超时;额外把 Blob 转为 Uint8Array 发送,60 秒仍超时。小文件完成后的下载 URL 查询另遇连接错误,文件已删除,大分片会话已 abort | 签名对小分片有效,替换 Blob 发送体未解决。仍需上传路径/OSS 服务端证据定位;仅增大 timeout 不能算修复,须以两片上传、合并及下载 hash 比对为验收 |
|
|
65
|
-
| Control 与 runtime capabilities 403 |
|
|
67
|
+
| 当时的 Control 与 runtime capabilities 403 | 当时部署代码将能力查询放在旧 Control 权限分支 | 历史原因,不适用当前版本。探针现已退役,实际调用归入统一权限,不再要求逐 Key Control scopes/codes |
|
|
66
68
|
| Agent jobs 身份限制 | 当前是 service Key;任务管理明确要求真实用户 | 使用有任务权限的真实成员 personal Key 或该功能支持的会话身份。扩大 service Key scope 不能把它变成真实用户 |
|
|
67
69
|
|
|
68
70
|
ACK 日志另有 `UNS control metadata requires explicit migration before startup`,但尚未证实属于本 Workspace 或此次 Source 请求,不能把该日志当成本次 503 的根因。部署、重启、授权变更和数据库迁移均未执行。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tier0/sdk-v2",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Tier0 Cloud new-architecture SDK for TypeScript and JavaScript",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
"scripts": {
|
|
157
157
|
"sync:contracts": "node scripts/sync-contracts.mjs",
|
|
158
158
|
"generate": "node scripts/generate-openapi.mjs && node scripts/generate-uns-v2.mjs",
|
|
159
|
-
"check:contracts": "node scripts/check-contracts.mjs && node scripts/generate-openapi.mjs --check && node scripts/generate-uns-v2.mjs --check",
|
|
159
|
+
"check:contracts": "node scripts/check-contracts.mjs && node --test scripts/retired-stream-probe.test.mjs scripts/sync-contracts.test.mjs && node scripts/generate-openapi.mjs --check && node scripts/generate-uns-v2.mjs --check",
|
|
160
160
|
"check:skills": "node scripts/check-skills.mjs && node scripts/check-skill-examples.mjs",
|
|
161
161
|
"typecheck": "tsc --noEmit && tsc -p tsconfig.tests.json",
|
|
162
162
|
"build": "node scripts/build.mjs",
|
|
@@ -7,6 +7,8 @@ description: 使用 @tier0/sdk-v2 发现、描述和调用 Tier0 Control 业务
|
|
|
7
7
|
|
|
8
8
|
Control 是已发布的业务调用入口;它可由 Stream 提供,但调用方不选择内部 streamId、entryId 或部署版本。使用服务端 client.controls,实际调用 `/openapi/v2/uns/controls/discover|describe|invoke`,不重建旧 Flow 调用。
|
|
9
9
|
|
|
10
|
+
调用按服务端现有统一权限及 App 业务策略校验;不配置逐 Key 的 Control scopes/codes。旧 Stream 就绪探针已经退役,不能因为它的历史 403 判断当前入口不可用或要求扩权。
|
|
11
|
+
|
|
10
12
|
## 发现和读取契约
|
|
11
13
|
|
|
12
14
|
```ts
|
|
@@ -32,7 +32,7 @@ export const workOrders = defineCollection({
|
|
|
32
32
|
schema: z.object({
|
|
33
33
|
code: z.string(),
|
|
34
34
|
status: z.enum(['DRAFT', 'RELEASED', 'DONE', 'CANCELLED']),
|
|
35
|
-
targetQty: z.number().int().min(1),
|
|
35
|
+
targetQty: z.number().int().min(1).meta({ format: 'int32' }),
|
|
36
36
|
dueAt: z.string(),
|
|
37
37
|
}),
|
|
38
38
|
indexes: [{ path: 'code', unique: true }, { path: 'status' }],
|
|
@@ -51,6 +51,7 @@ export async function releasedOrders(): Promise<WorkOrder[]> {
|
|
|
51
51
|
|
|
52
52
|
1. 声明文件只从 `@tier0/sdk-v2/data/define` 导入,客户端代码可以安全引用它;全部集合在一个 `collections` 列表里声明(每个 App 最多 64 个),只建一个进程级 client;不要手动 ensure、不要在 import 时访问数据、不要自建“已初始化”标记。
|
|
53
53
|
2. 集合 Schema 是存储 Schema:只能用可存储的 Zod 子集,输入规则(格式、长度、默认值、transform)放在 API 入参 Schema。
|
|
54
|
+
新建数值字段明确选择 int(integer + int32)、float 或 double(number + 对应 format);普通小数选 double,嵌套对象和数组元素同样处理。SDK 会为未标注的 integer/number 补齐 int32/double;直接 MCP 请求必须自行提供 format。
|
|
54
55
|
3. 写入前按声明严格校验,未知字段、类型错误、未声明的更新路径直接抛 `ZodError`;读取不做严格解析,旧版本写入的字段、新枚举值或缺字段都可能出现。
|
|
55
56
|
4. `insertMany` / `bulkWrite` / `transact` 每次最多 200 项且原子;`updateMany` / `deleteMany` 逐条提交、非原子。
|
|
56
57
|
5. 按 `DataError.code` 与 `reason`(`data.reason`)分支,不匹配 message 文本;`status` 是 App 应回给自己调用方的 HTTP 状态。
|
|
@@ -14,9 +14,9 @@
|
|
|
14
14
|
import { z } from 'zod';
|
|
15
15
|
import { createDataClient, defineCollection } from '@tier0/sdk-v2/data';
|
|
16
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() }) });
|
|
17
|
+
const stock = defineCollection({ alias: 'stock', schema: z.object({ sku: z.string(), available: z.number().int().min(0).meta({ format: 'int32' }) }) });
|
|
18
|
+
const reservations = defineCollection({ alias: 'reservations', schema: z.object({ sku: z.string(), qty: z.number().int().min(1).meta({ format: 'int32' }), orderId: z.string() }) });
|
|
19
|
+
const counters = defineCollection({ alias: 'counters', schema: z.object({ value: z.number().int().meta({ format: 'int32' }) }) });
|
|
20
20
|
const data = createDataClient({ collections: [stock, reservations, counters] });
|
|
21
21
|
|
|
22
22
|
/** 扣减库存并写预留:库存不足时整体不提交。 */
|
|
@@ -23,7 +23,7 @@ export const salesOrders = defineCollection({
|
|
|
23
23
|
code: z.string(),
|
|
24
24
|
status: z.enum(['DRAFT', 'CONFIRMED', 'SHIPPED', 'CANCELLED']),
|
|
25
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) })),
|
|
26
|
+
lines: z.array(z.object({ sku: z.string(), qty: z.number().int().min(1).meta({ format: 'int32' }) })),
|
|
27
27
|
notes: z.string().optional(),
|
|
28
28
|
orderedOn: z.string().describe('YYYY-MM-DD'),
|
|
29
29
|
confirmedAt: z.string().optional().describe('ISO-8601 UTC from toISOString()'),
|
|
@@ -63,7 +63,7 @@ export const createSalesOrderInput = salesOrders.schema
|
|
|
63
63
|
|
|
64
64
|
## 字段类型标注
|
|
65
65
|
|
|
66
|
-
|
|
66
|
+
新建数值字段必须明确选择 int、float 或 double,普通小数默认 double。需要在 Collection 中明确显示 `int`、`float`、`double`、`datetime` 时,通过 Zod 元数据添加格式声明。传输仍使用 JSON Schema 的 `integer` / `number` / `string`:
|
|
67
67
|
|
|
68
68
|
| 声明 | 传输 Schema | 显示类型 |
|
|
69
69
|
| --- | --- | --- |
|
|
@@ -72,7 +72,7 @@ export const createSalesOrderInput = salesOrders.schema
|
|
|
72
72
|
| `z.number().meta({ format: 'double' })` | `{ type: 'number', format: 'double' }` | `double` |
|
|
73
73
|
| `z.string().meta({ format: 'date-time' })` | `{ type: 'string', format: 'date-time' }` | `datetime` |
|
|
74
74
|
|
|
75
|
-
`format` 当前是类型展示注解,不额外限制数值范围或精度,也不舍入数据。写入仍按原来的 Zod 类型和显式 `.min()` / `.max()`
|
|
75
|
+
`format` 当前是类型展示注解,不额外限制数值范围或精度,也不舍入数据。写入仍按原来的 Zod 类型和显式 `.min()` / `.max()` 校验;需要业务范围时应继续声明边界。SDK 编译时递归为普通 `z.number()` 补 `double`,为 `z.int()` / `z.number().int()` 补 `int32`;显式 float/double 与 date-time 保留,普通字符串不补格式,也不根据样本数值推断精度。只接受上表四种类型与格式组合。
|
|
76
76
|
|
|
77
77
|
`datetime` 仍保存原始字符串,不校验日期是否有效、不解析或转换时区;`"not a date"` 也能通过字符串类型校验。需要日期合法性保证时,在 API 入参 Schema 单独使用 `z.iso.datetime()`;这类带 `pattern` 的验证器不能直接作为可存储的集合声明。新增注解不改变 Sample 外层 `time` 的毫秒时间戳协议、已有校验和业务时间含义。
|
|
78
78
|
|
|
@@ -90,7 +90,7 @@ import { defineCollection } from '@tier0/sdk-v2/data/define';
|
|
|
90
90
|
|
|
91
91
|
export const loginCodes = defineCollection({
|
|
92
92
|
alias: 'login_codes',
|
|
93
|
-
schema: z.object({ phone: z.string(), code: z.string(), issuedAt: z.number().int() }),
|
|
93
|
+
schema: z.object({ phone: z.string(), code: z.string(), issuedAt: z.number().int().meta({ format: 'int32' }) }),
|
|
94
94
|
// issuedAt 存 Date.now();签发 5 分钟后删除。
|
|
95
95
|
indexes: [{ path: 'phone' }, { path: 'issuedAt', expireAfterSeconds: 300 }],
|
|
96
96
|
});
|
|
@@ -111,3 +111,5 @@ export const loginCodes = defineCollection({
|
|
|
111
111
|
- 共享实体按 ID 引用,并快照需要展示的字段(`customer: { id, name }`),不要在读取时 join。`aggregate` 有 `$lookup`,但有行数限制,不要用它搭列表页。
|
|
112
112
|
- 每种业务对象一个集合,而不是每个页面一个集合。
|
|
113
113
|
- “最新优先”用 `_meta.createdAt` / `_meta.updatedAt`,由 UNS 维护。
|
|
114
|
+
|
|
115
|
+
直接通过 MCP 提交 recordSchema/sampleSchema 时必须提供上述 type + format;Zod 编译兜底不处理原始请求。ensure 保留已有字段注解,无格式的存量字段需读取完整 Schema、保留其他约束,通过 schema:replace 先 dryRun 再按明确迁移授权执行。
|
|
@@ -12,7 +12,7 @@ const workOrders = defineCollection({
|
|
|
12
12
|
code: z.string(),
|
|
13
13
|
status: z.enum(['DRAFT', 'RELEASED', 'DONE']),
|
|
14
14
|
line: z.object({ id: z.string(), name: z.string() }),
|
|
15
|
-
targetQty: z.number().int().min(1),
|
|
15
|
+
targetQty: z.number().int().min(1).meta({ format: 'int32' }),
|
|
16
16
|
notes: z.string().optional(),
|
|
17
17
|
}),
|
|
18
18
|
indexes: [{ path: 'code', unique: true }, { path: 'status' }],
|
|
@@ -34,3 +34,5 @@ export function replaceBody(expectedRevision: number) {
|
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
Schema 中 `ignored`、`warnings`、`conflicts`、`violations` 的路径用 `.` 连接属性,用 `[]` 表示数组元素(`lines.[].qty`)。
|
|
37
|
+
|
|
38
|
+
新声明的 number/integer 默认带 double/int32 格式;ensure 不改写已有字段注解,原无格式字段仍保持 legacy 显示。已有字段格式迁移需读取并保留完整 Schema,先通过 schema:replace dryRun 检查,再按明确迁移授权执行。
|
|
@@ -23,10 +23,10 @@ Source 维护连接配置、认证引用与源状态。脚本处理用 [Stream](
|
|
|
23
23
|
|
|
24
24
|
## 核心约束
|
|
25
25
|
|
|
26
|
-
1. Source 配置统一使用 documents.*,原生文档为 `{name,protocol,config}`。
|
|
26
|
+
1. Source 配置统一使用 documents.*,原生文档为 `{name,protocol,config}`,HTTP API 显式指定 `config.role`。HTTP 统一为 `protocol: http-api` + `config.role: client/server`;Client 主动请求,Server 接收入站请求,不能互换。独立异步 http_push 的 202 accepted 合同继续保留。
|
|
27
27
|
2. 已有 ID 和 revision 时优先用 documents.update 的 patch,避免额外 get;完整替换 document 前读取完整文档,安全列表摘要不能无损回写。原生 ID 是十进制字符串,revision 原样传递,不转 Number。
|
|
28
28
|
3. 现有 Source 修改、启停、删除都要 expectedRevision。没有任何 Stream 引用时可直接提交;有草稿、活动、历史或不可见引用时仍需 confirmedImpactRevision。先形成精确意图,再读取全部影响分页;回执不可合成、跨意图复用或静默刷新。提供的回执始终严格校验,不自动获取并同意影响。
|
|
29
|
-
4. 配置中保留认证/TLS 引用,不写明文秘密;HTTP 新凭据走创建专用 credentials
|
|
29
|
+
4. 配置中保留认证/TLS 引用,不写明文秘密;HTTP Client 新凭据走创建专用 credentials;Server 不携带 Client auth/TLS 配置。
|
|
30
30
|
5. desiredState 不代表实际健康,保存配置不代表 Stream 已切换至新 configRevision。运行状态另行读取。
|
|
31
31
|
|
|
32
32
|
## 返回值与异常
|
|
@@ -6,15 +6,16 @@
|
|
|
6
6
|
| --- | --- | --- | --- |
|
|
7
7
|
| dryRun | boolean | 是 | true 校验;false 保存 |
|
|
8
8
|
| document.name | string | 是 | 1–128 字符 |
|
|
9
|
-
| document.protocol | string | 是 | 原生协议,如 http、mqtt、modbus |
|
|
9
|
+
| document.protocol | string | 是 | 原生协议,如 http-api、mqtt、modbus |
|
|
10
|
+
| document.config.role | client / server | HTTP API 显式指定 | client 主动请求;server 接收入站请求 |
|
|
10
11
|
| document.config | object | 是 | configVersion=2、endpoint、options;见[协议配置](protocols.md) |
|
|
11
12
|
| document.description | string | 否 | 最多 512 字符 |
|
|
12
|
-
| credentials | object | 否 |
|
|
13
|
+
| credentials | object | 否 | 仅创建 HTTP Client 时提供新凭据,与已有 auth/TLS 引用互斥 |
|
|
13
14
|
| idempotencyKey | string | 否 | 建议提供,最多 128 字符,同一业务意图保持不变 |
|
|
14
15
|
|
|
15
|
-
## 完整示例:HTTP 数据源
|
|
16
|
+
## 完整示例:HTTP Client 数据源
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
传入实际端点、名称和意图键。此函数创建 `http-api` + `config.role: client` 配置,不启用源。client 从服务端环境读取 API Host/Key,也可显式注入。
|
|
18
19
|
|
|
19
20
|
```ts
|
|
20
21
|
import { createClient, type Tier0Client, type CloudSourceDocument } from '@tier0/sdk-v2';
|
|
@@ -23,8 +24,8 @@ export async function createHttpSource(
|
|
|
23
24
|
endpoint: string, name: string, intentKey: string, client: Tier0Client = createClient(),
|
|
24
25
|
) {
|
|
25
26
|
const document: CloudSourceDocument = {
|
|
26
|
-
name, protocol: 'http', description: '订单系统 HTTP 接入',
|
|
27
|
-
config: { configVersion: 2, endpoint, options: {} },
|
|
27
|
+
name, protocol: 'http-api', description: '订单系统 HTTP 接入',
|
|
28
|
+
config: { configVersion: 2, role: 'client', endpoint, options: {} },
|
|
28
29
|
};
|
|
29
30
|
const saved = await client.source.documents.create({
|
|
30
31
|
dryRun: false, document, idempotencyKey: intentKey,
|
|
@@ -36,7 +37,9 @@ export async function createHttpSource(
|
|
|
36
37
|
|
|
37
38
|
一次提交即可返回完整 data:id、revision、document、desiredState、runtimeState、health、createdAt、updatedAt,无需另行 get。需要单独预检时可先传 `dryRun: true`,返回 `{ validated: true, sideEffects: false }`,没有 ID。预检不保留提交条件;实际保存仍会校验。ID 原样保留十进制字符串。
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
HTTP Server 同样使用 `protocol: http-api`,角色为 `config.role: server`;其配置以 `source.protocols.list({})` 返回的正式合同为准,不能复用下方 Client 的主动请求示例。独立异步 `http_push` 的 202 accepted 合同仍保留;202 仅表示接受,不能据此报告 Stream 执行完成。
|
|
41
|
+
|
|
42
|
+
## HTTP Client Bearer 凭据
|
|
40
43
|
|
|
41
44
|
token 从服务端密钥提供者取得,不写入脚本、文档、日志或仓库。
|
|
42
45
|
|
|
@@ -49,7 +52,7 @@ export async function createAuthenticatedHttpSource(
|
|
|
49
52
|
) {
|
|
50
53
|
const saved = await client.source.documents.create({
|
|
51
54
|
dryRun: false, idempotencyKey: intentKey,
|
|
52
|
-
document: { name, protocol: 'http', config: { configVersion: 2, endpoint, options: {} } },
|
|
55
|
+
document: { name, protocol: 'http-api', config: { configVersion: 2, role: 'client', endpoint, options: {} } },
|
|
53
56
|
credentials: { method: 'GET', kind: 'bearer', material: { token } },
|
|
54
57
|
});
|
|
55
58
|
if (!('id' in saved.data)) throw new Error('未返回 Source ID');
|
|
@@ -58,3 +61,58 @@ export async function createAuthenticatedHttpSource(
|
|
|
58
61
|
```
|
|
59
62
|
|
|
60
63
|
配置保存不代表连接健康;见[查询](read.md)。仅在任务包含启用时执行[启停](state.md)。结果未知时保留原请求、requestId、意图键,先核对列表/历史,不自动重复创建。
|
|
64
|
+
|
|
65
|
+
## HTTP Server:管理配置
|
|
66
|
+
|
|
67
|
+
正式协议目录规定 Server 的 `config.endpoint` 为 `http://managed`、`options` 为 `{}`,不携带 Client 的 `auth` / `tls` 或创建专用 `credentials`。该函数只保存 Source,不启用、不创建 Stream,也不发起入站请求。
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import { createClient, type Tier0Client, type CloudSourceDocument } from '@tier0/sdk-v2';
|
|
71
|
+
|
|
72
|
+
export async function createHttpServerSource(
|
|
73
|
+
name: string, intentKey: string, client: Tier0Client = createClient(),
|
|
74
|
+
) {
|
|
75
|
+
const document: CloudSourceDocument = {
|
|
76
|
+
name, protocol: 'http-api',
|
|
77
|
+
config: { configVersion: 2, role: 'server', endpoint: 'http://managed', options: {} },
|
|
78
|
+
};
|
|
79
|
+
const saved = await client.source.documents.create({
|
|
80
|
+
dryRun: false, document, idempotencyKey: intentKey,
|
|
81
|
+
});
|
|
82
|
+
if (!('id' in saved.data)) throw new Error('未返回已保存的 Source');
|
|
83
|
+
return { receipt: saved, current: saved.data };
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Server 的同步入站语义和 Bearer 要求由协议目录的 `x-tier0-http-in` 描述;本 npm 包提供 Source 管理方法,不把 Client 的 `upstream.request` 当作 Server 入站入口。独立异步 `http_push` 仍按自己的 202 accepted 合同处理。
|
|
88
|
+
|
|
89
|
+
## 四类 inline 认证与 REQUEST 绑定
|
|
90
|
+
|
|
91
|
+
单条创建可通过 `credentials` 提供以下只写材料;与已有 auth/TLS 引用互斥,并要求本次创建的 `idempotencyKey`。材料从调用方已授权的密钥提供者注入,不在示例中读取文件或环境中的秘密,不记录或返回材料。
|
|
92
|
+
|
|
93
|
+
| kind | material | method |
|
|
94
|
+
| --- | --- | --- |
|
|
95
|
+
| basic | username、password | 省略时 REQUEST;可显式绑定受限 HTTP 方法 |
|
|
96
|
+
| bearer | token | 省略时 REQUEST;上方 GET 示例保持明确的方法限制 |
|
|
97
|
+
| apiKey | headerName、value | 省略或 REQUEST;不接受旧 name/key 形态 |
|
|
98
|
+
| oauth2ClientCredentials | tokenUrl、clientId、clientSecret;可选 scope、clientAuthentication | 省略、REQUEST 或 GET |
|
|
99
|
+
|
|
100
|
+
OAuth 的 `clientAuthentication` 支持 `client_secret_post`(默认)和 `client_secret_basic`。REQUEST 表示绑定 Source 基址,实际路径和方法仍由执行宿主逐次授权;显式方法的已有绑定不能解释成 REQUEST 的基址范围。vendor SESSION 合同独立保留,不是此 inline 创建的 method,也不新增独立公开凭据 API。
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
import { createClient, type Tier0Client, type CloudSourceCreateCredentials } from '@tier0/sdk-v2';
|
|
104
|
+
|
|
105
|
+
export async function createHttpSourceWithCredentials(
|
|
106
|
+
endpoint: string, name: string, credentials: CloudSourceCreateCredentials, intentKey: string,
|
|
107
|
+
client: Tier0Client = createClient(),
|
|
108
|
+
) {
|
|
109
|
+
const saved = await client.source.documents.create({
|
|
110
|
+
dryRun: false, idempotencyKey: intentKey,
|
|
111
|
+
document: { name, protocol: 'http-api',
|
|
112
|
+
config: { configVersion: 2, role: 'client', endpoint, options: {} } },
|
|
113
|
+
credentials,
|
|
114
|
+
});
|
|
115
|
+
if (!('id' in saved.data)) throw new Error('未返回已保存的 Source');
|
|
116
|
+
return { receipt: saved, current: saved.data };
|
|
117
|
+
}
|
|
118
|
+
```
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# 协议与连接配置
|
|
2
2
|
|
|
3
|
-
先调用 `source.protocols.list({})
|
|
3
|
+
先调用 `source.protocols.list({})`。协议枚举存在不等于目标环境驱动或凭据解析器已就绪。HTTP Source 统一使用 `protocol: 'http-api'`,通过文档的 `config.role: 'client' | 'server'` 区分主动请求和入站服务,与 Enterprise 的一协议两角色模型一致。角色和协议能力以目标环境目录为准;旧 `http` 不作为新建示例。
|
|
4
4
|
|
|
5
5
|
| 配置字段 | 类型 | 必填 | 说明 |
|
|
6
6
|
| --- | --- | --- | --- |
|
|
7
|
+
| role | client / server | HTTP 示例显式指定 | 省略时为 client;Server 使用托管地址和空 options |
|
|
7
8
|
| configVersion | 2 | 是 | 新架构配置快照 |
|
|
8
9
|
| endpoint | string | 是 | 地址,不内嵌凭据 |
|
|
9
10
|
| options | object | 是 | 协议专用选项 |
|
|
@@ -19,8 +20,8 @@ import { createClient, type CloudSourceDocument } from '@tier0/sdk-v2';
|
|
|
19
20
|
export async function inspectProtocolExamples() {
|
|
20
21
|
const capabilities = await createClient().source.protocols.list({});
|
|
21
22
|
const examples: CloudSourceDocument[] = [
|
|
22
|
-
{ name: 'orders-http', protocol: 'http',
|
|
23
|
-
config: { configVersion: 2, endpoint: 'https://orders.example.com', options: {} } },
|
|
23
|
+
{ name: 'orders-http', protocol: 'http-api',
|
|
24
|
+
config: { configVersion: 2, role: 'client', endpoint: 'https://orders.example.com', options: {} } },
|
|
24
25
|
{ name: 'line-plc', protocol: 'modbus',
|
|
25
26
|
config: { configVersion: 2, endpoint: 'tcp://plc.example.com:502', options: { unitId: 1 } } },
|
|
26
27
|
{ name: 'line-mqtt', protocol: 'mqtt',
|
|
@@ -31,6 +32,12 @@ export async function inspectProtocolExamples() {
|
|
|
31
32
|
}
|
|
32
33
|
```
|
|
33
34
|
|
|
34
|
-
HTTP
|
|
35
|
+
HTTP Client 的 options 支持 headers 和 parameters;headers 可包含目录允许的非秘密自定义头,Accept/Content-Type 保留 MIME 校验,认证及传输头保留给服务端,不能塞 Authorization/Cookie。Modbus 寄存器范围和轮询频率在 Stream acquisition 中定义;MQTT QoS 为 0/1/2。认证创建见[创建](create.md),修改时保留原 auth/tls 引用。
|
|
35
36
|
|
|
36
37
|
SQL options 包含 tlsMode(verify-full/disable)和 queries(资源名→固定 SQL);脚本不能替换任意 SQL。OPC UA、SAP、Teamcenter 等按能力和服务端校验配置,不从 HTTP 模板生造字段。不要为通过校验自动移除认证或关闭 TLS。
|
|
38
|
+
|
|
39
|
+
HTTP Client 示例不能用于 Server。独立异步 `http_push` 保留自己的 202 accepted 合同,不等同于同步 HTTP API Server 的响应;本管理 SDK 通过 `source.documents.*` 配置源,不据此新增 HTTP In 调用入口。
|
|
40
|
+
|
|
41
|
+
Cloud 的角色位于 `config.role`;Enterprise 投影的顶层 `role` 不能直接抄入 Cloud 管理文档。Server 配置见[创建](create.md),以 `http://managed` 和空 options 保存,不从 Client 模板推导。
|
|
42
|
+
|
|
43
|
+
HTTP Client 的单条 inline 认证支持 basic / bearer / apiKey / oauth2ClientCredentials,method 省略时由服务端按 REQUEST 绑定 Source 基址;显式方法限制保持不变。APIKey 材料为 headerName/value,OAuth 可提供 clientAuthentication。见[创建](create.md)。
|
|
@@ -25,7 +25,7 @@ description: 使用 @tier0/sdk-v2 的 client.stream 创建、查询、修改和
|
|
|
25
25
|
| Runtime program | name、sdkVersion、script 字符串、sourceBindings、timeoutMs | documents.create/update/validate({program}) |
|
|
26
26
|
| 云端原生文档 | name、model、script 对象、sources、entries | documents.create/get/update/validate |
|
|
27
27
|
|
|
28
|
-
程序必须是完整 `module.exports = api => { ... }`,执行器 API 是 api.sources/api.uns/api.stream,与 npm 包的 client.source 不同。Runtime sourceBindings 为 sourceId/configRevision/acquisition;原生 sources 还使用 alias/resources。连接凭据不进脚本或 acquisition
|
|
28
|
+
程序必须是完整 `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,不传播旧注册别名;npm 的 client.controls 管理入口不作为 Goja 的 Stream 注册参数。
|
|
29
29
|
|
|
30
30
|
## 核心约束
|
|
31
31
|
|
|
@@ -33,7 +33,7 @@ description: 使用 @tier0/sdk-v2 的 client.stream 创建、查询、修改和
|
|
|
33
33
|
2. create/update 保存草稿,不自动发布;documents 没有 deploy,云端 program 发布使用 programs.deploy。不能将已保存报告为已运行。
|
|
34
34
|
3. 所有更新/部署/删除携带当前 expectedRevision。原生停用另需 expectedActiveRelease,避免停掉他人刚发布的版本。
|
|
35
35
|
4. versionId 从 versions.list 取得,不把 release 序号当 ID。expectedSourceRevision 仅用于恰好一个依赖源,不代表多个源的修订。
|
|
36
|
-
5. resources=[]
|
|
36
|
+
5. resources=[] 是空冻结资源集,不是通配符。写入本身由服务端校验,需要预览时单独 validate;当前云端程序 timeoutMs 上限 30000。旧 runtime.capabilities 查询已退役,不作为管理或执行前置检查,不为此增加 Control scope 或逐 Key 控制码授权。
|
|
37
37
|
6. 仅执行用户要求的生命周期步骤;修改脚本不自动授予发布、停用或删除权限。
|
|
38
38
|
|
|
39
39
|
## 成功与异常
|
|
@@ -12,9 +12,9 @@
|
|
|
12
12
|
| program.sourceBindings | array | 否 | sourceId、configRevision、acquisition |
|
|
13
13
|
| idempotencyKey | string | 否 | 最多 128 字符,本次创建的固定意图键 |
|
|
14
14
|
|
|
15
|
-
## HTTP Source 绑定示例
|
|
15
|
+
## HTTP Client Source 绑定示例
|
|
16
16
|
|
|
17
|
-
先按[Source 查询](../../tier0-sdk-v2-source/references/read.md)选定真实 HTTP Source。脚本的 api.sources 属于平台执行器,与应用中的 client.source 不同。sourceId 保持字符串,configRevision
|
|
17
|
+
先按[Source 查询](../../tier0-sdk-v2-source/references/read.md)选定真实 HTTP Client Source。脚本的 api.sources 属于平台执行器,与应用中的 client.source 不同。sourceId 保持字符串,configRevision 从完整源读取。省略 `config.role` 时按正式协议目录默认为 client;Server 走入站语义,不能创建为主动请求程序。
|
|
18
18
|
|
|
19
19
|
```ts
|
|
20
20
|
import { createClient, type Tier0Client, type RuntimeStreamDefinition } from '@tier0/sdk-v2';
|
|
@@ -25,14 +25,17 @@ export async function createHttpStream(
|
|
|
25
25
|
if (!/^[1-9][0-9]*$/.test(sourceId)) throw new Error('Source ID 必须是正十进制字符串');
|
|
26
26
|
const source = await client.source.documents.get({ id: sourceId, view: 'full' });
|
|
27
27
|
if (!('document' in source.data)) throw new Error('需要完整 Source 文档');
|
|
28
|
-
if (source.data.document.protocol !== 'http'
|
|
28
|
+
if (source.data.document.protocol !== 'http-api' || source.data.document.config.configVersion !== 2 ||
|
|
29
|
+
(source.data.document.config.role ?? 'client') !== 'client') {
|
|
30
|
+
throw new Error('此主动请求示例需要 HTTP API Client Source');
|
|
31
|
+
}
|
|
29
32
|
const document: RuntimeStreamDefinition = {
|
|
30
33
|
name, sdkVersion: 'tier0-stream/v2', timeoutMs: 5000,
|
|
31
34
|
sourceBindings: [{ sourceId, configRevision: source.data.revision, acquisition: {} }],
|
|
32
35
|
script: [
|
|
33
36
|
'module.exports = api => {',
|
|
34
37
|
' const upstream = api.sources.use({ id: ' + JSON.stringify(sourceId) + ', resources: [] });',
|
|
35
|
-
' api.stream.
|
|
38
|
+
' api.stream.every({ id: "tick", intervalMs: 60000 }, async () => {',
|
|
36
39
|
' const response = await upstream.request({ method: "GET", path: "orders" });',
|
|
37
40
|
' return response.data;',
|
|
38
41
|
' });',
|
|
@@ -48,6 +48,8 @@ export async function findAppCollection(alias: string) {
|
|
|
48
48
|
5. recordFind 使用 pageInfo.hasMore/nextCursor,limit 1–200;sort 为 [['field',1]]。单页不是全量,跨页不是稳定快照。
|
|
49
49
|
6. Sample 的时间是 Unix 毫秒,查询范围 [from,to)。Record 代表业务实体,不用覆盖它来保存历史。
|
|
50
50
|
|
|
51
|
+
7. 新建 recordSchema/sampleSchema 数值字段必须明确格式:int 用 `{ type: 'integer', format: 'int32' }`,float/double 用 `{ type: 'number', format: 'float'/'double' }`;普通小数默认选 double。递归覆盖嵌套对象和数组元素,不创建无 format 的 legacy number/integer;不把 type 写成 int/float/double。已有字段迁移先 dryRun 校验。
|
|
52
|
+
|
|
51
53
|
## 结果与异常
|
|
52
54
|
|
|
53
55
|
响应为 code/msg/requestId/data。元数据 find 返回 items/pageInfo;单条 updateOne/replaceOne/deleteOne 请求 returnDocument 时附带 value;普通写入默认返回对应计数和 ID。metadataTransact 的 results 按 opId 对应。检查 committed、每项错误和实际计数;dryRun 只校验。metadataBulkWrite 默认原子,显式非原子时必须逐项检查 results/errors;跨 kind 的依赖写入使用 metadataTransact。recordBulkWrite 不保证跨集合事务。
|
|
@@ -20,7 +20,7 @@ export async function createDeviceCollection(
|
|
|
20
20
|
},
|
|
21
21
|
sampleSchema: {
|
|
22
22
|
type: 'object', additionalProperties: false, required: ['temperature'],
|
|
23
|
-
properties: { temperature: { type: 'number', unit: '°C' } },
|
|
23
|
+
properties: { temperature: { type: 'number', format: 'double', unit: '°C' } },
|
|
24
24
|
},
|
|
25
25
|
},
|
|
26
26
|
};
|