@tier0/sdk-v2 0.6.3 → 0.7.2
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 +31 -9
- package/dist/cjs/capabilities.d.ts +20 -4
- package/dist/cjs/capabilities.js +66 -6
- package/dist/cjs/capabilities.js.map +1 -1
- package/dist/cjs/client.d.ts +9 -7
- package/dist/cjs/client.js +0 -2
- package/dist/cjs/client.js.map +1 -1
- package/dist/cjs/cloud-transport.d.ts +3 -2
- package/dist/cjs/cloud-transport.js +8 -7
- package/dist/cjs/cloud-transport.js.map +1 -1
- package/dist/cjs/index.d.ts +0 -1
- package/dist/cjs/index.js +0 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/openapi/api.generated.d.ts +9 -5
- package/dist/cjs/openapi/codecs.generated.d.ts +943 -684
- package/dist/cjs/openapi/codecs.generated.js +1 -1
- package/dist/cjs/openapi/codecs.generated.js.map +1 -1
- package/dist/cjs/openapi/types.generated.d.ts +638 -508
- package/dist/cjs/openapi/types.generated.js.map +1 -1
- package/dist/cjs/uns-v2/client.js +2 -2
- package/dist/cjs/uns-v2/client.js.map +1 -1
- package/dist/cjs/uns-v2/generated.d.ts +182 -253
- package/dist/cjs/uns-v2/generated.js +16 -19
- package/dist/cjs/uns-v2/generated.js.map +1 -1
- package/dist/esm/capabilities.d.ts +20 -4
- package/dist/esm/capabilities.js +66 -6
- package/dist/esm/capabilities.js.map +1 -1
- package/dist/esm/client.d.ts +9 -7
- package/dist/esm/client.js +0 -2
- package/dist/esm/client.js.map +1 -1
- package/dist/esm/cloud-transport.d.ts +3 -2
- package/dist/esm/cloud-transport.js +8 -7
- package/dist/esm/cloud-transport.js.map +1 -1
- package/dist/esm/index.d.ts +0 -1
- package/dist/esm/index.js +0 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/openapi/api.generated.d.ts +9 -5
- package/dist/esm/openapi/codecs.generated.d.ts +943 -684
- 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 +638 -508
- package/dist/esm/openapi/types.generated.js.map +1 -1
- package/dist/esm/uns-v2/client.js +2 -2
- package/dist/esm/uns-v2/client.js.map +1 -1
- package/dist/esm/uns-v2/generated.d.ts +182 -253
- package/dist/esm/uns-v2/generated.js +16 -19
- package/dist/esm/uns-v2/generated.js.map +1 -1
- package/package.json +5 -7
- package/skills/tier0-sdk-v2/SKILL.md +14 -4
- package/skills/tier0-sdk-v2/tier0-sdk-v2-mq/SKILL.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-mq/references/quickstart.md +1 -1
- 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 +10 -6
- package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/protocols.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/SKILL.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/create.md +6 -2
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/http-server.md +1 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/lifecycle.md +2 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/read.md +4 -0
- package/skills/tier0-sdk-v2/tier0-sdk-v2-system/SKILL.md +7 -2
- package/dist/cjs/controls.d.ts +0 -105
- package/dist/cjs/controls.js +0 -172
- package/dist/cjs/controls.js.map +0 -1
- package/dist/esm/controls.d.ts +0 -105
- package/dist/esm/controls.js +0 -166
- package/dist/esm/controls.js.map +0 -1
- package/skills/tier0-sdk-v2/tier0-sdk-v2-controls/SKILL.md +0 -65
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tier0/sdk-v2",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Tier0 Cloud new-architecture SDK for TypeScript and JavaScript",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -155,7 +155,7 @@
|
|
|
155
155
|
"scripts": {
|
|
156
156
|
"sync:contracts": "node scripts/sync-contracts.mjs",
|
|
157
157
|
"generate": "node scripts/generate-openapi.mjs && node scripts/generate-uns-v2.mjs",
|
|
158
|
-
"check:contracts": "node scripts/check-contracts.mjs && node --test scripts/retired-stream-probe.test.mjs scripts/retired-http-push.test.mjs scripts/sync-contracts.test.mjs scripts/live-program-contract.test.mjs scripts/sync-http-run-observations.test.mjs && node scripts/generate-openapi.mjs --check && node scripts/generate-uns-v2.mjs --check",
|
|
158
|
+
"check:contracts": "node scripts/check-contracts.mjs && node --test scripts/retired-stream-probe.test.mjs scripts/retired-http-push.test.mjs scripts/retired-controls.test.mjs scripts/retired-public-labels.test.mjs scripts/platform-schema-projection.test.mjs scripts/data-capability-vector.test.mjs scripts/sync-contracts.test.mjs scripts/live-program-contract.test.mjs scripts/sync-http-run-observations.test.mjs && node scripts/generate-openapi.mjs --check && node scripts/generate-uns-v2.mjs --check",
|
|
159
159
|
"check:skills": "node scripts/check-skills.mjs && node scripts/check-skill-examples.mjs",
|
|
160
160
|
"typecheck": "tsc --noEmit && tsc -p tsconfig.tests.json",
|
|
161
161
|
"build": "node scripts/build.mjs",
|
|
@@ -199,7 +199,9 @@
|
|
|
199
199
|
"vitest": "^4.1.7",
|
|
200
200
|
"esbuild": "^0.25.0",
|
|
201
201
|
"yaml": "^2.8.0",
|
|
202
|
-
"zod": "^4.0.0"
|
|
202
|
+
"zod": "^4.0.0",
|
|
203
|
+
"ajv": "^8.20.0",
|
|
204
|
+
"ajv-formats": "^3.0.1"
|
|
203
205
|
},
|
|
204
206
|
"agents": {
|
|
205
207
|
"skills": [
|
|
@@ -239,10 +241,6 @@
|
|
|
239
241
|
"name": "tier0-sdk-v2-system",
|
|
240
242
|
"path": "./skills/tier0-sdk-v2/tier0-sdk-v2-system"
|
|
241
243
|
},
|
|
242
|
-
{
|
|
243
|
-
"name": "tier0-sdk-v2-controls",
|
|
244
|
-
"path": "./skills/tier0-sdk-v2/tier0-sdk-v2-controls"
|
|
245
|
-
},
|
|
246
244
|
{
|
|
247
245
|
"name": "tier0-sdk-v2-agent",
|
|
248
246
|
"path": "./skills/tier0-sdk-v2/tier0-sdk-v2-agent"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: tier0-sdk-v2
|
|
3
|
-
description: 使用 @tier0/sdk-v2
|
|
3
|
+
description: 使用 @tier0/sdk-v2 开发或迁移 Tier0 云端 TypeScript/JavaScript 应用:Source 数据源、Stream 处理程序、UNS 集合与记录、App 自有数据(@tier0/sdk-v2/data)、通知、文件存储、MQTT、成员、系统身份与能力和 Agent,按任务进入对应子 Skill,并处理配置、身份和框架集成。
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Tier0 SDK v2 应用集成
|
|
@@ -20,7 +20,6 @@ description: 使用 @tier0/sdk-v2 开发 Tier0 云端 TypeScript/JavaScript 应
|
|
|
20
20
|
| 附件、头像、导入导出、生成报告 | `client.files` | [文件](tier0-sdk-v2-files/SKILL.md) |
|
|
21
21
|
| 实时主题订阅/发布 | `@tier0/sdk-v2/mq`、`client.mqttAuth` | [MQTT](tier0-sdk-v2-mq/SKILL.md) |
|
|
22
22
|
| Workspace 收件人/成员检索、App 可用成员 | `client.members` | [成员](tier0-sdk-v2-members/SKILL.md) |
|
|
23
|
-
| 调用已发布的 Control | `client.controls` | [Controls](tier0-sdk-v2-controls/SKILL.md) |
|
|
24
23
|
| Agent 作业、运行、分析结果和卡片 | `client.agent` | [Agent](tier0-sdk-v2-agent/SKILL.md) |
|
|
25
24
|
|
|
26
25
|
每个领域 Skill 可单独使用,无需先加载本文件。Source → Stream → UNS 是接入、处理与数据存储三个领域;不是要求每个数据读取场景都创建一套流水线。通知和系统能力独立于这条链路。
|
|
@@ -48,12 +47,23 @@ export async function inspectConnection() {
|
|
|
48
47
|
| Source、Stream、UNS | 完整 `{ code, msg, requestId, data }` | `UnsV2Error` / `UnsV2OutcomeUnknownError` |
|
|
49
48
|
| 平台 v2,如 system、members、agent、mqttAuth | 解包后的 `data` | `ApiError` / `TransportError` |
|
|
50
49
|
| notifications | 直接对象,如 `messageId`、`status` | `ApiError` |
|
|
51
|
-
|
|
|
50
|
+
| capabilities | 专属响应对象 | `CapabilityError` |
|
|
52
51
|
|
|
53
52
|
方法存在不等于目标环境已部署或当前 Key 有权限。整数可能为 `bigint`;UNS 任意 JSON 中还可能含 `UnsV2RawNumber`。不要将标识符强制转为 Number;给浏览器返回数据时显式定义精确数字的序列化格式。
|
|
54
53
|
|
|
55
54
|
`createClient()` 的 HTTP 不自动重试。UNS 错误的 `execution` 说明执行到哪一步、`retry.safe` 说明能否用同一请求重发;带 `outcomeUnknown` 的失败应先对账,保留原意图键;取消请求不代表服务端撤销。App 数据层(`@tier0/sdk-v2/data`)会按 `retry.safe` 自动重试,见 App 数据 Skill。Source/Stream 仍使用底层 UNS v2 契约,所以错误类名保留 UNS,不代表它们仍属于数据入口。
|
|
56
55
|
|
|
56
|
+
## 从首版入口迁移
|
|
57
|
+
|
|
58
|
+
- `client.uns.sourceList(body)` → `client.source.documents.list(body)`。
|
|
59
|
+
- `client.uns.sourceDocumentGet(body)` → `client.source.documents.get(body)`。
|
|
60
|
+
- `client.uns.streamProgramDeploy(body)` → `client.stream.programs.deploy(body)`。
|
|
61
|
+
- `client.uns.streamDocumentValidate(body)` → `client.stream.documents.validate(body)`。
|
|
62
|
+
- `client.uns.recordFind(body)` 保持不变。
|
|
63
|
+
- 低层 `createUnsV2Client` 保留完整生成契约,供契约工具使用;业务主入口不再把 Source/Stream 管理混入 `client.uns`。
|
|
64
|
+
|
|
57
65
|
React/Vue 示例与验签见 [集成参考](references/integration.md)。完成接入时验证目标入口、真实身份、响应解包和错误分支;SDK 本地测试通过不代表环境联调完成。
|
|
58
66
|
|
|
59
|
-
|
|
67
|
+
Stream 请求与消息交互由独立包 `@tier0/sdk` 的 `client.streams.requests` / `client.streams.messages` 提供;本包负责数据访问和 Source/Stream 管理,不重复实现交互 API。Scaffold 分别接入这两个包,不能将本包的 `client.stream` 管理接口当作运行时请求入口。
|
|
68
|
+
|
|
69
|
+
本包公开 HTTP 入口统一为 `/openapi/v2`。旧的重复操作已退役,不生成兼容调用或回退。Source 配置用 documents.*,Stream 草稿用 documents.*、发布用 programs.deploy;App 数据层仍提供 insertMany/findOneAnd*/distinct 等便捷方法。历史旧写结果未知时先核对业务状态,不能转换路由后盲目重放。
|
|
@@ -69,7 +69,7 @@ export async function publishMeasurement(mq: Tier0MQClient, topic: string, value
|
|
|
69
69
|
}
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
-
publish 目前在建立连接并调用 MQTT 库发布后返回,不等待业务执行确认,也不保证已收到 broker PUBACK。需要闭环时使用业务 ACK 主题/关联 ID
|
|
72
|
+
publish 目前在建立连接并调用 MQTT 库发布后返回,不等待业务执行确认,也不保证已收到 broker PUBACK。需要闭环时使用业务 ACK 主题/关联 ID 或独立交互 SDK 的 Stream 请求合同,不能把 Promise resolve 当成设备执行完成。
|
|
73
73
|
|
|
74
74
|
订阅内部 QoS 为 1;发布默认 QoS 0、retain=false。业务消费者需考虑重复消息。对象 payload 经 JSON.stringify,不能直接包含 bigint;按协议约定编码精确值,不假设 MQTT 自动使用 UNS 的无损 codec。
|
|
75
75
|
|
|
@@ -58,7 +58,7 @@ export async function publishEvent(mq: Tier0MQClient, topic: string, eventId: st
|
|
|
58
58
|
}
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
-
payload 必须符合实际主题契约;对象用 JSON.stringify,不可包含 bigint。publish resolve 不证明已收 PUBACK,更不证明设备执行;业务闭环用关联 ID/ACK
|
|
61
|
+
payload 必须符合实际主题契约;对象用 JSON.stringify,不可包含 bigint。publish resolve 不证明已收 PUBACK,更不证明设备执行;业务闭环用关联 ID/ACK 或独立交互 SDK 的 Stream 请求。订阅 QoS 1,发布默认 QoS 0/retain=false,消费端考虑重复消息。
|
|
62
62
|
|
|
63
63
|
## 事件、背压和鉴权
|
|
64
64
|
|
|
@@ -26,13 +26,13 @@ Source 维护连接配置、认证引用与源状态。脚本处理用 [Stream](
|
|
|
26
26
|
1. Source 配置统一使用 documents.*,原生文档为 `{name,protocol,config}`,HTTP API 显式指定 `config.role`。HTTP 统一为 `protocol: http-api` + `config.role: client/server`;Client 主动请求,Server 接收入站请求,不能互换。HTTPServer 统一接收入站请求,固定前缀后的路由和响应时机属于 Stream。
|
|
27
27
|
2. 已有 ID 和 revision 时优先用 documents.update 的 patch,避免额外 get;完整替换 document 前读取完整文档,安全列表摘要不能无损回写。原生 ID 是十进制字符串,revision 原样传递,不转 Number。
|
|
28
28
|
3. 现有 Source 修改、启停、删除都要 expectedRevision。没有任何 Stream 引用时可直接提交;有草稿、活动、历史或不可见引用时仍需 confirmedImpactRevision。先形成精确意图,再读取全部影响分页;回执不可合成、跨意图复用或静默刷新。提供的回执始终严格校验,不自动获取并同意影响。
|
|
29
|
-
4. 配置中保留认证/TLS 引用,不写明文秘密;HTTP Client 新凭据走创建专用 credentials
|
|
29
|
+
4. 配置中保留认证/TLS 引用,不写明文秘密;HTTP Client 新凭据走创建专用 credentials,普通创建省略 credentials.method(服务端默认 REQUEST 基址绑定),真实 method/path/query 由 Stream 定义。Basic/Bearer 显式凭据方法限制精确 URL 和方法,OAuth 旧 GET 保留既有兼容语义,不自动扩大旧授权;Server 不携带 Client auth/TLS 配置。
|
|
30
30
|
5. desiredState 不代表实际健康,保存配置不代表 Stream 已切换至新 configRevision。运行状态另行读取。
|
|
31
31
|
|
|
32
32
|
## 返回值与异常
|
|
33
33
|
|
|
34
34
|
所有调用返回完整 code/msg/requestId/data。documents.create/update 的预检返回 validated/sideEffects,提交返回完整 Source view,可直接使用其中的文档和 revision,无需额外 get;批量状态/删除返回 Outcome。只有 committed 且无项错误才可报告提交成功;accepted/jobId 继续查询作业。预检按需使用,不是每次提交的必经步骤。
|
|
35
35
|
|
|
36
|
-
需要查看历史用 source.history({id,beforeRevision,size}),按 nextBeforeRevision 继续;探测用 source.probe
|
|
36
|
+
需要查看历史用 source.history({id,beforeRevision,size}),按 nextBeforeRevision 继续;探测用 source.probe,其外部系统访问应属于当前任务。配置校验或连接探测成功不证明某个 Stream 请求已获授权或采集成功,实际结果看对应发布的 runs。连接配置修改使用 documents.update,遵守同一影响确认契约。
|
|
37
37
|
|
|
38
38
|
UnsV2Error 表示已知拒绝;UnsV2OutcomeUnknownError 表示可能已写入。保存 requestId、原请求和意图键,先查详情/历史/作业对账。取消等待不撤销服务端操作;SDK 不自动重试。权限不足不能解释为资源不存在。
|
|
@@ -41,7 +41,9 @@ HTTP Server 同样使用 `protocol: http-api`,角色为 `config.role: server`
|
|
|
41
41
|
|
|
42
42
|
## HTTP Client Bearer 凭据
|
|
43
43
|
|
|
44
|
-
token 从服务端密钥提供者取得,不写入脚本、文档、日志或仓库。
|
|
44
|
+
Source 保存 API 基址和认证;实际请求的 method/path/query 由 Stream 设置。例如 endpoint 使用 `https://inventory.example.com/api/v1`,再由 [Stream 示例](../../tier0-sdk-v2-stream/references/create.md)请求 `GET inventory`。token 从服务端密钥提供者取得,不写入脚本、文档、日志或仓库。
|
|
45
|
+
|
|
46
|
+
普通创建省略 `credentials.method`,服务端按 `REQUEST` 绑定 Source 基址。REQUEST 是凭据适用范围标记,不是发送给上游的 HTTP 方法;实际 GET 请求仍由执行宿主逐次授权。
|
|
45
47
|
|
|
46
48
|
```ts
|
|
47
49
|
import { createClient, type Tier0Client } from '@tier0/sdk-v2';
|
|
@@ -53,7 +55,7 @@ export async function createAuthenticatedHttpSource(
|
|
|
53
55
|
const saved = await client.source.documents.create({
|
|
54
56
|
dryRun: false, idempotencyKey: intentKey,
|
|
55
57
|
document: { name, protocol: 'http-api', config: { role: 'client', endpoint, options: {} } },
|
|
56
|
-
credentials: {
|
|
58
|
+
credentials: { kind: 'bearer', material: { token } },
|
|
57
59
|
});
|
|
58
60
|
if (!('id' in saved.data)) throw new Error('未返回 Source ID');
|
|
59
61
|
return { receipt: saved, current: saved.data };
|
|
@@ -92,12 +94,14 @@ Server 的固定前缀 `/ingest/v1/{workspaceId}/{sourceId}` 和 Bearer 要求
|
|
|
92
94
|
|
|
93
95
|
| kind | material | method |
|
|
94
96
|
| --- | --- | --- |
|
|
95
|
-
| basic | username、password | 省略时 REQUEST
|
|
96
|
-
| bearer | token | 省略时 REQUEST
|
|
97
|
+
| basic | username、password | 省略时 REQUEST;显式方法绑定精确 URL 和该方法 |
|
|
98
|
+
| bearer | token | 省略时 REQUEST;显式方法绑定精确 URL 和该方法 |
|
|
97
99
|
| apiKey | headerName、value | 省略或 REQUEST |
|
|
98
|
-
| oauth2ClientCredentials | tokenUrl、clientId、clientSecret;可选 scope、clientAuthentication |
|
|
100
|
+
| oauth2ClientCredentials | tokenUrl、clientId、clientSecret;可选 scope、clientAuthentication | 普通创建省略;旧 GET 保留既有兼容语义 |
|
|
101
|
+
|
|
102
|
+
Basic/Bearer 显式 `credentials.method: 'GET'` 表示凭据只用于所绑定精确 URL 的 GET,不表示该基址下所有 GET 都可使用:绑定 `/api/v1` 不授权 `/api/v1/inventory?limit=5000`。仅在任务明确需要该限制时传入;已有绑定保持原限制,不自动迁移或在拒绝后回退 REQUEST。
|
|
99
103
|
|
|
100
|
-
OAuth 的 `clientAuthentication` 支持 `client_secret_post`(默认)和 `client_secret_basic
|
|
104
|
+
OAuth 的 `clientAuthentication` 支持 `client_secret_post`(默认)和 `client_secret_basic`;method 接受省略、REQUEST 或旧 GET,旧 GET 保留现有兼容语义,不能把 Basic/Bearer 的精确 URL 规则跨认证类型套用。普通创建仍省略 method。vendor SESSION 合同独立保留,不是此 inline 创建的 method,也不新增独立公开凭据 API。
|
|
101
105
|
|
|
102
106
|
```ts
|
|
103
107
|
import { createClient, type Tier0Client, type CloudSourceCreateCredentials } from '@tier0/sdk-v2';
|
|
@@ -39,4 +39,4 @@ HTTP Client 示例不能用于 Server。HTTPServer 通过 `source.documents.*`
|
|
|
39
39
|
|
|
40
40
|
Cloud 的角色位于 `config.role`;Enterprise 投影的顶层 `role` 不能直接抄入 Cloud 管理文档。Server 配置见[创建](create.md),以 `http://managed` 和空 options 保存,不从 Client 模板推导。
|
|
41
41
|
|
|
42
|
-
HTTP Client 的单条 inline 认证支持 basic / bearer / apiKey / oauth2ClientCredentials
|
|
42
|
+
HTTP Client 的单条 inline 认证支持 basic / bearer / apiKey / oauth2ClientCredentials。普通创建省略 credentials.method,由服务端按 REQUEST 绑定 Source 基址;实际 method/path/query 在 Stream 设置。Basic/Bearer 显式凭据方法同时限制精确 URL,不覆盖基址下的子路径;存量绑定保持限制,不自动扩大权限。APIKey 材料为 headerName/value,OAuth 可提供 clientAuthentication,旧 OAuth GET 保留既有兼容语义。见[创建](create.md)。
|
|
@@ -26,7 +26,7 @@ description: 使用 @tier0/sdk-v2 的 client.stream 创建、查询、修改和
|
|
|
26
26
|
| Runtime program | name、script 字符串、sourceBindings、timeoutMs | documents.create/update/validate({program}) |
|
|
27
27
|
| 云端原生文档 | name、model、script 对象、sources、entries | documents.create/get/update/validate |
|
|
28
28
|
|
|
29
|
-
程序必须是完整 `module.exports = api => { ... }`,执行器 API 是 api.sources/api.uns/api.stream,与 npm 包的 client.source 不同。Runtime sourceBindings 为 sourceId/configRevision/acquisition;原生 sources 还使用 alias/resources。连接凭据不进脚本或 acquisition,秘密材料由 Source 执行宿主管理,不通过脚本读取、记录或返回。定时入口使用 api.stream.every
|
|
29
|
+
程序必须是完整 `module.exports = api => { ... }`,执行器 API 是 api.sources/api.uns/api.stream,与 npm 包的 client.source 不同。Runtime sourceBindings 为 sourceId/configRevision/acquisition;原生 sources 还使用 alias/resources。连接凭据不进脚本或 acquisition,秘密材料由 Source 执行宿主管理,不通过脚本读取、记录或返回。定时入口使用 api.stream.every,不传播旧注册别名;App 请求与消息交互由独立 @tier0/sdk 的 client.streams.requests/messages 提供,不作为 Goja 注册参数。
|
|
30
30
|
|
|
31
31
|
## 核心约束
|
|
32
32
|
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
|
|
16
16
|
先按[Source 查询](../../tier0-sdk-v2-source/references/read.md)选定真实 HTTP Client Source。脚本的 api.sources 属于平台执行器,与应用中的 client.source 不同。sourceId 保持字符串,configRevision 使用 Source 创建、更新回执或完整查询得到的修订。已有回执时直接传入 source;没有快照时再调用 source.documents.get({id,view:"full"}) 并检查 data.document。省略 `config.role` 时按正式协议目录默认为 client;Server 走入站语义,不能创建为主动请求程序。
|
|
17
17
|
|
|
18
|
+
Source 负责基址和认证,Stream 负责请求的 method/path/query。以下示例与 [Source Bearer 创建](../../tier0-sdk-v2-source/references/create.md#http-client-bearer-凭据)配合:Source endpoint 为 `https://inventory.example.com/api/v1`,凭据使用默认基址绑定;实际请求是 `GET https://inventory.example.com/api/v1/inventory?limit=5000`。已有 Source 的凭据若只绑定精确 URL `/api/v1` 的 GET,不能用于此子路径;不要通过改写请求为 REQUEST 或自动扩大凭据授权来绕过拒绝。
|
|
19
|
+
|
|
18
20
|
```ts
|
|
19
21
|
import { createClient, type Tier0Client, type RuntimeStreamDefinition, type CloudSourceDocumentView } from '@tier0/sdk-v2';
|
|
20
22
|
|
|
@@ -34,7 +36,7 @@ export async function createHttpStream(
|
|
|
34
36
|
'module.exports = api => {',
|
|
35
37
|
' const upstream = api.sources.use({ id: ' + JSON.stringify(sourceId) + ', resources: [] });',
|
|
36
38
|
' api.stream.every({ id: "tick", intervalMs: 60000 }, async () => {',
|
|
37
|
-
' const response = await upstream.request({ method: "GET", path: "
|
|
39
|
+
' const response = await upstream.request({ method: "GET", path: "inventory", query: { limit: "5000" } });',
|
|
38
40
|
' return response.data;',
|
|
39
41
|
' });',
|
|
40
42
|
'};',
|
|
@@ -48,10 +50,12 @@ export async function createHttpStream(
|
|
|
48
50
|
}
|
|
49
51
|
```
|
|
50
52
|
|
|
51
|
-
将 path="
|
|
53
|
+
将 path="inventory"、query 和 60 秒周期改为业务实际值。示例保存草稿,不部署,也不将返回值自动写入 UNS;需要写入集合时按执行器能力定义 api.uns 操作。resources=[] 是空冻结资源集,不是通配授权。源地址和凭据留在 Source,不能拷进 acquisition 或脚本。
|
|
52
54
|
|
|
53
55
|
创建 data 为 CloudStreamDocumentView 或预检结果,实际保存返回 id、revision 和完整 document;预检不生成 ID。需要展示预检时单独调用 documents.validate({program});普通保存无需先校验再保存。当前后端创建/校验需要注册 Worker 可用。TEMPORARILY_UNAVAILABLE 不代表脚本一定错误。
|
|
54
56
|
|
|
57
|
+
validate 检查配置、程序和可确定的绑定问题,不执行任意业务分支,也不证明上游可达。尤其是运行时拼接的 path/query,仍需在授权范围内执行代表性采集,并检查本次发布的 runs 与业务结果;一次成功也只覆盖实际执行的请求。Source 连接探测和 isolated-sample 都不能替代真实采集验证。
|
|
58
|
+
|
|
55
59
|
创建结局未知时先按已知 ID 或业务标识核对状态;允许重试时保留原请求与幂等键。
|
|
56
60
|
|
|
57
61
|
原生编辑器形态 `documents.create({dryRun, document})` 的 document 为 name/model/script对象/sources/entries,script 为 `{code,timeoutMs}`,sources 用 alias/sourceId/configRevision/resources/acquisition。不要把上面的 script 字符串直接塞入原生文档。
|
|
@@ -84,6 +84,6 @@ export async function createHttpServerEarlyReplyStream(
|
|
|
84
84
|
}
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
-
`ctx.reply` 只用于 HTTP `api.stream.onRequest`,一次执行只回复一次;不要在 `every
|
|
87
|
+
`ctx.reply` 只用于 HTTP `api.stream.onRequest`,一次执行只回复一次;不要在 `every`或普通事件 handler 中调用,也不增加 npm App API 或公开 HTTP endpoint。示例先发 202 再写 Record,202 表示已回复接受,不能报告写入或提交成功;失败通过 Stream 运行记录检查,不能再发送第二份响应。
|
|
88
88
|
|
|
89
89
|
回复后的处理仍受 Stream timeout(本例 5000 ms)、并发上限和实时权限约束。客户端断线不会取消已回复后的执行,服务 shutdown 仍可取消。进程崩溃不保证重放;业务若需持久投递、去重或恢复,必须另行设计,不能把 `ctx.reply` 当作持久队列。凭据和权限均沿用现有 Source/Stream 合同。
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
创建并发布时,将 [创建](create.md) 或 [修改](update.md) 回执中的草稿直接交给 [发布](deploy.md),再用发布回执的 activeRelease [观察运行](read.md#观察本次发布),无需在发布前后各 get 一次。只有缺少当前草稿、处理版本冲突或需要最新状态时才 [查询](read.md)。停用、回滚和 [删除](delete.md) 按任务选择,不自动执行整套生命周期。
|
|
4
4
|
|
|
5
|
+
HTTP 采集的常规顺序是选定或创建 Source → 用 Source 回执绑定并保存 Stream → 发布 → 观察该发布的真实采集。Source 保存基址和认证,Stream 指定 method/path/query。预检按需使用;静态校验只能发现可确定的问题,脚本动态请求仍需通过代表性实际运行验证,不能把配置通过、网络可达或样例通过等同于采集成功。
|
|
6
|
+
|
|
5
7
|
## 原生文档样例测试
|
|
6
8
|
|
|
7
9
|
方法:stream.sampleTest;输入 document、entryId、input。document 来自 documents.get 的完整草稿,entryId 必须在该文档注册的 entries 内。
|
|
@@ -53,3 +53,7 @@ export async function readPublishedRuns(
|
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
此函数只读一页。items 为空但 nextCursor 非空时,下一页仍可能有匹配记录;达到调用方的观察时限就报告“尚未观察到”。匹配记录也要检查 status、entryId 和时间,不能把存在记录当成执行成功。历史幂等回执若缺少 activeRelease,应保留为未确认,不能用当前 head 的发布号代替。
|
|
56
|
+
|
|
57
|
+
失败或结果未知的运行可带 `error:{code,stage,message,repair,sourceRequest?}` 安全诊断。`SOURCE_TARGET_SCOPE_MISMATCH`、`stage:validate_binding` 表示请求超出 Source 凭据范围,应检查绑定基址与实际 method/path/query,保留原授权限制。`sourceRequest:notDispatched` 只证明失败的这一次 Source 请求未发送,不能推断整个 Stream 未开始或此前没有写入。
|
|
58
|
+
|
|
59
|
+
`EXECUTION_FAILED` 和 `RESULT_UNKNOWN` 是安全通用诊断,分别保留失败和结果未知的区别。按 code/stage 判断,展示服务端 message/repair;没有 error 的旧记录仍按 status 解释,不补造原因,也不因可重试猜测而自动重新执行。运行诊断不包含 token、凭据引用或完整请求 URL。
|
|
@@ -43,13 +43,18 @@ info 返回 name/version/mqttBroker/capabilities,字段可能省略。MQTT bro
|
|
|
43
43
|
| 字段/状态 | 判断 |
|
|
44
44
|
| --- | --- |
|
|
45
45
|
| releaseEnabled | 平台/Workspace 发布开关,不代表运行时已准备好 |
|
|
46
|
-
| allowed |
|
|
46
|
+
| allowed | 当前身份的授权摘要,不是某个具体操作的执行许可 |
|
|
47
47
|
| enabled、state=ready | 服务端评估就绪 |
|
|
48
48
|
| availability=available | 能力可用性,不是设备在线、业务执行或 ACK |
|
|
49
49
|
| disabled / not_supported / unavailable | 展示具体不可用原因,不强制调用 |
|
|
50
50
|
| readiness_unknown | 保留未知状态,不能按成功处理 |
|
|
51
|
+
| operations | Source / Stream 各操作独立判断;整体不可用不等于读取或安全停用不可用 |
|
|
52
|
+
| reasonCode / checkedAt / validUntil | 保留服务端原因及证明时间,过期后重新发现,不把旧证明当成持续就绪 |
|
|
53
|
+
| requiresResourceCheck | 实际调用仍要检查具体资源的权限、配置和依赖 |
|
|
51
54
|
|
|
52
|
-
|
|
55
|
+
本数据 SDK 的能力目录识别 namespace.v2、source、stream;其他 SDK 的可选交互能力按各自合同处理,不阻断 Namespace 发现。Source/Stream 的 contractVersions 使用 openapi/v2,不要求或返回解释器版本。contractVersions、apiContractVersions、sdkContractVersions 是契约标签,不是 npm 包版本;productVersion 未配置时可缺省。顶层要求受支持的核心 OpenAPI v2 合同,已识别能力也必须满足其合同;不要求全局交互 SDK 标签,不把未知能力投影为已支持。
|
|
56
|
+
|
|
57
|
+
发现统一使用 `POST /openapi/v2/capabilities/discover`,请求为 `{}`,不接受 Workspace 参数。Cloud / Enterprise 返回同一合同;此 SDK 只消费 Namespace、Source、Stream 管理能力;App 交互域由 App SDK 提供,其版本不作为管理接口的前置条件。SDK 只投影已知操作与公开诊断字段;未知扩展不被解释为就绪,不自动重试。
|
|
53
58
|
|
|
54
59
|
## 定位问题
|
|
55
60
|
|
package/dist/cjs/controls.d.ts
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import { type HttpClient, type ClientConfig } from './openapi/client.js';
|
|
2
|
-
import { type CloudTransportConfig } from './cloud-transport.js';
|
|
3
|
-
import { type UnsV2Execution, type UnsV2Retry } from './uns-v2/client.js';
|
|
4
|
-
import type { UnsV2JSONValue } from './uns-v2/generated.js';
|
|
5
|
-
/** Control convenience API over the canonical UNS v2 routes. Exact numbers are preserved. */
|
|
6
|
-
export type ControlJSON = UnsV2JSONValue;
|
|
7
|
-
export interface PublicControl {
|
|
8
|
-
code: string;
|
|
9
|
-
name: string;
|
|
10
|
-
description: string;
|
|
11
|
-
contractVersion: string;
|
|
12
|
-
inputSchema: Record<string, ControlJSON>;
|
|
13
|
-
outputSchema: Record<string, ControlJSON>;
|
|
14
|
-
sideEffect: 'read' | 'write';
|
|
15
|
-
idempotency: 'none' | 'optional' | 'required';
|
|
16
|
-
timeoutMs: number;
|
|
17
|
-
status: string;
|
|
18
|
-
}
|
|
19
|
-
export interface ControlDiscoverOptions {
|
|
20
|
-
page?: number;
|
|
21
|
-
size?: number;
|
|
22
|
-
search?: string;
|
|
23
|
-
}
|
|
24
|
-
export interface ControlDiscoverResponse {
|
|
25
|
-
total: number;
|
|
26
|
-
list: PublicControl[];
|
|
27
|
-
}
|
|
28
|
-
/** Shared HTTP settings. The server still resolves the Control binding and authorization. */
|
|
29
|
-
export interface ControlTransportConfig extends CloudTransportConfig {
|
|
30
|
-
}
|
|
31
|
-
export interface CloudClientConfig extends ClientConfig, ControlTransportConfig {
|
|
32
|
-
}
|
|
33
|
-
export declare const DEFAULT_CONTROL_TRANSPORT_TIMEOUT_MS = 60000;
|
|
34
|
-
export interface ControlInvokeOptions {
|
|
35
|
-
/** Stable caller-owned key for one business intent, at most 128 UTF-8 bytes. Never generated or retried by the SDK. */
|
|
36
|
-
idempotencyKey?: string;
|
|
37
|
-
}
|
|
38
|
-
export interface ControlInvokeResponse<Result = ControlJSON> {
|
|
39
|
-
code: string;
|
|
40
|
-
contractVersion: string;
|
|
41
|
-
result: Result;
|
|
42
|
-
runID: string;
|
|
43
|
-
status: string;
|
|
44
|
-
/** True only when the server explicitly reports an idempotent replay. */
|
|
45
|
-
replayed: boolean;
|
|
46
|
-
}
|
|
47
|
-
export interface ControlErrorInfo {
|
|
48
|
-
/** HTTP status, absent when no HTTP response was received. */
|
|
49
|
-
status?: number;
|
|
50
|
-
/** Canonical UNS error.code, or an SDK-local CONTROL_* transport/protocol code. */
|
|
51
|
-
errorCode: string;
|
|
52
|
-
runID?: string;
|
|
53
|
-
contractVersion?: string;
|
|
54
|
-
runStatus?: string;
|
|
55
|
-
replayed?: boolean;
|
|
56
|
-
requestId?: string;
|
|
57
|
-
execution?: UnsV2Execution;
|
|
58
|
-
retry?: UnsV2Retry;
|
|
59
|
-
reason?: string;
|
|
60
|
-
details?: Record<string, unknown>[];
|
|
61
|
-
data?: unknown;
|
|
62
|
-
}
|
|
63
|
-
/** No Control error is automatically retried, including authentication failures. */
|
|
64
|
-
export declare class ControlError extends Error {
|
|
65
|
-
readonly status?: number;
|
|
66
|
-
readonly errorCode: string;
|
|
67
|
-
readonly runID?: string;
|
|
68
|
-
readonly contractVersion?: string;
|
|
69
|
-
readonly runStatus?: string;
|
|
70
|
-
readonly replayed?: boolean;
|
|
71
|
-
readonly requestId?: string;
|
|
72
|
-
readonly execution?: UnsV2Execution;
|
|
73
|
-
readonly retry?: UnsV2Retry;
|
|
74
|
-
readonly reason?: string;
|
|
75
|
-
readonly details?: Record<string, unknown>[];
|
|
76
|
-
readonly data?: unknown;
|
|
77
|
-
readonly retryable = false;
|
|
78
|
-
constructor(message: string, info: ControlErrorInfo);
|
|
79
|
-
}
|
|
80
|
-
/** Execution may have happened. Reconcile run information; any deliberate replay must reuse the same key. */
|
|
81
|
-
export declare class ControlResultUnknownError extends ControlError {
|
|
82
|
-
readonly outcomeUnknown = true;
|
|
83
|
-
constructor(info: ControlErrorInfo);
|
|
84
|
-
}
|
|
85
|
-
export interface ControlHandle<Input = ControlJSON, Result = ControlJSON> {
|
|
86
|
-
describe(): Promise<PublicControl>;
|
|
87
|
-
/**
|
|
88
|
-
* One POST only. Input is opaque business JSON, including fields named streamId,
|
|
89
|
-
* entryId, deploymentVersion or timeoutMs. Only the server chooses binding/version/timeout.
|
|
90
|
-
* Generic types are caller assertions; the server validates the contract schemas.
|
|
91
|
-
*/
|
|
92
|
-
invoke(input: Input, options?: ControlInvokeOptions): Promise<ControlInvokeResponse<Result>>;
|
|
93
|
-
}
|
|
94
|
-
export declare class ControlsClient {
|
|
95
|
-
private readonly uns;
|
|
96
|
-
constructor(resolveClient?: () => HttpClient, config?: ControlTransportConfig);
|
|
97
|
-
private post;
|
|
98
|
-
/** Discover visible contracts; defaults and authorization are resolved by the server. */
|
|
99
|
-
discover(options?: ControlDiscoverOptions): Promise<ControlDiscoverResponse>;
|
|
100
|
-
use<Input = ControlJSON, Result = ControlJSON>(selector: {
|
|
101
|
-
code: string;
|
|
102
|
-
}): ControlHandle<Input, Result>;
|
|
103
|
-
}
|
|
104
|
-
/** Uses configureClient()/TIER0_API_HOST/TIER0_API_KEY, resolved for every call. */
|
|
105
|
-
export declare const controls: ControlsClient;
|
package/dist/cjs/controls.js
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.controls = exports.ControlsClient = exports.ControlResultUnknownError = exports.ControlError = exports.DEFAULT_CONTROL_TRANSPORT_TIMEOUT_MS = void 0;
|
|
4
|
-
const client_js_1 = require("./openapi/client.js");
|
|
5
|
-
const cloud_transport_js_1 = require("./cloud-transport.js");
|
|
6
|
-
const client_js_2 = require("./uns-v2/client.js");
|
|
7
|
-
const codec_js_1 = require("./uns-v2/codec.js");
|
|
8
|
-
exports.DEFAULT_CONTROL_TRANSPORT_TIMEOUT_MS = cloud_transport_js_1.DEFAULT_CLOUD_TRANSPORT_TIMEOUT_MS;
|
|
9
|
-
/** No Control error is automatically retried, including authentication failures. */
|
|
10
|
-
class ControlError extends Error {
|
|
11
|
-
status;
|
|
12
|
-
errorCode;
|
|
13
|
-
runID;
|
|
14
|
-
contractVersion;
|
|
15
|
-
runStatus;
|
|
16
|
-
replayed;
|
|
17
|
-
requestId;
|
|
18
|
-
execution;
|
|
19
|
-
retry;
|
|
20
|
-
reason;
|
|
21
|
-
details;
|
|
22
|
-
data;
|
|
23
|
-
retryable = false;
|
|
24
|
-
constructor(message, info) {
|
|
25
|
-
super(message);
|
|
26
|
-
this.name = 'ControlError';
|
|
27
|
-
this.status = info.status;
|
|
28
|
-
this.errorCode = info.errorCode;
|
|
29
|
-
this.runID = info.runID;
|
|
30
|
-
this.contractVersion = info.contractVersion;
|
|
31
|
-
this.runStatus = info.runStatus;
|
|
32
|
-
this.replayed = info.replayed;
|
|
33
|
-
this.requestId = info.requestId;
|
|
34
|
-
this.execution = info.execution;
|
|
35
|
-
this.retry = info.retry;
|
|
36
|
-
this.reason = info.reason;
|
|
37
|
-
this.details = info.details;
|
|
38
|
-
this.data = info.data;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
exports.ControlError = ControlError;
|
|
42
|
-
/** Execution may have happened. Reconcile run information; any deliberate replay must reuse the same key. */
|
|
43
|
-
class ControlResultUnknownError extends ControlError {
|
|
44
|
-
outcomeUnknown = true;
|
|
45
|
-
constructor(info) {
|
|
46
|
-
super('Control result is unknown; execution may have occurred. Do not automatically retry.', info);
|
|
47
|
-
this.name = 'ControlResultUnknownError';
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
exports.ControlResultUnknownError = ControlResultUnknownError;
|
|
51
|
-
function record(value) {
|
|
52
|
-
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
53
|
-
}
|
|
54
|
-
function keys(value, allowed) {
|
|
55
|
-
if (!record(value) || Reflect.ownKeys(value).some(key => typeof key !== 'string' || !allowed.includes(key))) {
|
|
56
|
-
throw new TypeError('Tier0 SDK: unsupported Control option.');
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
function json(value, seen = new Set()) {
|
|
60
|
-
if (value === null || typeof value === 'string' || typeof value === 'boolean' || value instanceof codec_js_1.UnsV2RawNumber)
|
|
61
|
-
return true;
|
|
62
|
-
if (typeof value === 'number')
|
|
63
|
-
return Number.isFinite(value);
|
|
64
|
-
if (typeof value !== 'object' || seen.has(value))
|
|
65
|
-
return false;
|
|
66
|
-
if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
seen.add(value);
|
|
70
|
-
const valid = (Array.isArray(value) ? Array.from(value) : Object.values(value)).every(item => json(item, seen));
|
|
71
|
-
seen.delete(value);
|
|
72
|
-
return valid;
|
|
73
|
-
}
|
|
74
|
-
function definition(value) {
|
|
75
|
-
if (!record(value))
|
|
76
|
-
return false;
|
|
77
|
-
return ['code', 'name', 'description', 'contractVersion', 'status'].every(key => typeof value[key] === 'string') &&
|
|
78
|
-
value.code !== '' && value.contractVersion !== '' && record(value.inputSchema) && record(value.outputSchema) &&
|
|
79
|
-
['read', 'write'].includes(value.sideEffect) &&
|
|
80
|
-
['none', 'optional', 'required'].includes(value.idempotency) &&
|
|
81
|
-
typeof value.timeoutMs === 'number' && Number.isSafeInteger(value.timeoutMs) && value.timeoutMs > 0;
|
|
82
|
-
}
|
|
83
|
-
function runInfo(value) {
|
|
84
|
-
if (!record(value))
|
|
85
|
-
return {};
|
|
86
|
-
return {
|
|
87
|
-
runID: typeof value.runId === 'string' ? value.runId : undefined,
|
|
88
|
-
contractVersion: typeof value.contractVersion === 'string' ? value.contractVersion : undefined,
|
|
89
|
-
runStatus: typeof value.status === 'string' ? value.status : undefined,
|
|
90
|
-
replayed: typeof value.replayed === 'boolean' ? value.replayed : undefined,
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
class ControlsClient {
|
|
94
|
-
uns;
|
|
95
|
-
constructor(resolveClient = client_js_1.getClient, config = {}) {
|
|
96
|
-
this.uns = new client_js_2.UnsV2ClientCore(resolveClient, config);
|
|
97
|
-
}
|
|
98
|
-
async post(operation, body) {
|
|
99
|
-
try {
|
|
100
|
-
const response = await this.uns.call(operation, body);
|
|
101
|
-
return { value: response.data, status: 200 };
|
|
102
|
-
}
|
|
103
|
-
catch (error) {
|
|
104
|
-
if (!(error instanceof client_js_2.UnsV2Error))
|
|
105
|
-
throw error;
|
|
106
|
-
const info = {
|
|
107
|
-
...runInfo(error.data), status: error.status,
|
|
108
|
-
errorCode: error.code.replace(/^UNS_V2_/, 'CONTROL_'),
|
|
109
|
-
requestId: error.requestId, execution: error.execution, retry: error.retry,
|
|
110
|
-
reason: error.reason, details: error.details, data: error.data,
|
|
111
|
-
};
|
|
112
|
-
if (error.outcomeUnknown)
|
|
113
|
-
throw new ControlResultUnknownError(info);
|
|
114
|
-
throw new ControlError(error.message, info);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
/** Discover visible contracts; defaults and authorization are resolved by the server. */
|
|
118
|
-
async discover(options = {}) {
|
|
119
|
-
keys(options, ['page', 'size', 'search']);
|
|
120
|
-
if ((options.page !== undefined && (!Number.isSafeInteger(options.page) || options.page < 1)) ||
|
|
121
|
-
(options.size !== undefined && (!Number.isSafeInteger(options.size) || options.size < 1 || options.size > 200)) ||
|
|
122
|
-
(options.search !== undefined && typeof options.search !== 'string')) {
|
|
123
|
-
throw new TypeError('Tier0 SDK: invalid Control discovery options.');
|
|
124
|
-
}
|
|
125
|
-
const { value, status } = await this.post('controlDiscover', options);
|
|
126
|
-
if (!record(value) || !Number.isSafeInteger(value.total) || value.total < 0 ||
|
|
127
|
-
!Array.isArray(value.list) || !value.list.every(definition)) {
|
|
128
|
-
throw new ControlError('Invalid Control discovery response.', { status, errorCode: 'CONTROL_PROTOCOL_ERROR' });
|
|
129
|
-
}
|
|
130
|
-
return { total: value.total, list: value.list };
|
|
131
|
-
}
|
|
132
|
-
use(selector) {
|
|
133
|
-
keys(selector, ['code']);
|
|
134
|
-
const code = selector.code;
|
|
135
|
-
if (typeof code !== 'string' || code.length > 128 || !/^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/.test(code)) {
|
|
136
|
-
throw new TypeError('Tier0 SDK: invalid Control code.');
|
|
137
|
-
}
|
|
138
|
-
return {
|
|
139
|
-
describe: async () => {
|
|
140
|
-
const { value, status } = await this.post('controlDescribe', { code });
|
|
141
|
-
if (!definition(value) || value.code !== code) {
|
|
142
|
-
throw new ControlError('Invalid Control description.', { status, errorCode: 'CONTROL_PROTOCOL_ERROR' });
|
|
143
|
-
}
|
|
144
|
-
return value;
|
|
145
|
-
},
|
|
146
|
-
invoke: async (input, options = {}) => {
|
|
147
|
-
keys(options, ['idempotencyKey']);
|
|
148
|
-
const key = options.idempotencyKey;
|
|
149
|
-
if (key !== undefined && (typeof key !== 'string' || !key || key.trim() !== key || new TextEncoder().encode(key).length > 128)) {
|
|
150
|
-
throw new TypeError('Tier0 SDK: invalid Control idempotency key.');
|
|
151
|
-
}
|
|
152
|
-
if (!json(input))
|
|
153
|
-
throw new TypeError('Tier0 SDK: Control input must be JSON.');
|
|
154
|
-
const { value, status } = await this.post('controlInvoke', {
|
|
155
|
-
code, input: input, ...(key === undefined ? {} : { idempotencyKey: key }),
|
|
156
|
-
});
|
|
157
|
-
if (!record(value) || value.code !== code || typeof value.contractVersion !== 'string' || !value.contractVersion ||
|
|
158
|
-
!Object.prototype.hasOwnProperty.call(value, 'result') || typeof value.runId !== 'string' || !value.runId ||
|
|
159
|
-
typeof value.status !== 'string' || !value.status || ['accepted', 'queued', 'pending', 'running'].includes(value.status) ||
|
|
160
|
-
typeof value.replayed !== 'boolean') {
|
|
161
|
-
throw new ControlResultUnknownError({ ...runInfo(value), status, errorCode: 'CONTROL_PROTOCOL_ERROR' });
|
|
162
|
-
}
|
|
163
|
-
return { code: value.code, contractVersion: value.contractVersion, result: value.result,
|
|
164
|
-
runID: value.runId, status: value.status, replayed: value.replayed };
|
|
165
|
-
},
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
exports.ControlsClient = ControlsClient;
|
|
170
|
-
/** Uses configureClient()/TIER0_API_HOST/TIER0_API_KEY, resolved for every call. */
|
|
171
|
-
exports.controls = new ControlsClient();
|
|
172
|
-
//# sourceMappingURL=controls.js.map
|
package/dist/cjs/controls.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"controls.js","sourceRoot":"","sources":["../../src/controls.ts"],"names":[],"mappings":"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","sourcesContent":["import { getClient, type HttpClient, type ClientConfig } from './openapi/client.js';\nimport { DEFAULT_CLOUD_TRANSPORT_TIMEOUT_MS, type CloudTransportConfig } from './cloud-transport.js';\nimport { UnsV2ClientCore, UnsV2Error, type UnsV2Execution, type UnsV2Retry } from './uns-v2/client.js';\nimport { UnsV2RawNumber } from './uns-v2/codec.js';\nimport type { UnsV2JSONValue, UnsV2Request } from './uns-v2/generated.js';\n\n/** Control convenience API over the canonical UNS v2 routes. Exact numbers are preserved. */\nexport type ControlJSON = UnsV2JSONValue;\n\nexport interface PublicControl {\n code: string;\n name: string;\n description: string;\n contractVersion: string;\n inputSchema: Record<string, ControlJSON>;\n outputSchema: Record<string, ControlJSON>;\n sideEffect: 'read' | 'write';\n idempotency: 'none' | 'optional' | 'required';\n timeoutMs: number;\n status: string;\n}\n\nexport interface ControlDiscoverOptions {\n page?: number;\n size?: number;\n search?: string;\n}\n\nexport interface ControlDiscoverResponse {\n total: number;\n list: PublicControl[];\n}\n\n/** Shared HTTP settings. The server still resolves the Control binding and authorization. */\nexport interface ControlTransportConfig extends CloudTransportConfig {}\n\nexport interface CloudClientConfig extends ClientConfig, ControlTransportConfig {}\n\nexport const DEFAULT_CONTROL_TRANSPORT_TIMEOUT_MS = DEFAULT_CLOUD_TRANSPORT_TIMEOUT_MS;\n\nexport interface ControlInvokeOptions {\n /** Stable caller-owned key for one business intent, at most 128 UTF-8 bytes. Never generated or retried by the SDK. */\n idempotencyKey?: string;\n}\n\nexport interface ControlInvokeResponse<Result = ControlJSON> {\n code: string;\n contractVersion: string;\n result: Result;\n runID: string;\n status: string;\n /** True only when the server explicitly reports an idempotent replay. */\n replayed: boolean;\n}\n\nexport interface ControlErrorInfo {\n /** HTTP status, absent when no HTTP response was received. */\n status?: number;\n /** Canonical UNS error.code, or an SDK-local CONTROL_* transport/protocol code. */\n errorCode: string;\n runID?: string;\n contractVersion?: string;\n runStatus?: string;\n replayed?: boolean;\n requestId?: string;\n execution?: UnsV2Execution;\n retry?: UnsV2Retry;\n reason?: string;\n details?: Record<string, unknown>[];\n data?: unknown;\n}\n\n/** No Control error is automatically retried, including authentication failures. */\nexport class ControlError extends Error {\n readonly status?: number;\n readonly errorCode: string;\n readonly runID?: string;\n readonly contractVersion?: string;\n readonly runStatus?: string;\n readonly replayed?: boolean;\n readonly requestId?: string;\n readonly execution?: UnsV2Execution;\n readonly retry?: UnsV2Retry;\n readonly reason?: string;\n readonly details?: Record<string, unknown>[];\n readonly data?: unknown;\n readonly retryable = false;\n\n constructor(message: string, info: ControlErrorInfo) {\n super(message);\n this.name = 'ControlError';\n this.status = info.status;\n this.errorCode = info.errorCode;\n this.runID = info.runID;\n this.contractVersion = info.contractVersion;\n this.runStatus = info.runStatus;\n this.replayed = info.replayed;\n this.requestId = info.requestId;\n this.execution = info.execution;\n this.retry = info.retry;\n this.reason = info.reason;\n this.details = info.details;\n this.data = info.data;\n }\n}\n\n/** Execution may have happened. Reconcile run information; any deliberate replay must reuse the same key. */\nexport class ControlResultUnknownError extends ControlError {\n readonly outcomeUnknown = true;\n\n constructor(info: ControlErrorInfo) {\n super('Control result is unknown; execution may have occurred. Do not automatically retry.', info);\n this.name = 'ControlResultUnknownError';\n }\n}\n\nfunction record(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction keys(value: unknown, allowed: string[]): void {\n if (!record(value) || Reflect.ownKeys(value).some(key => typeof key !== 'string' || !allowed.includes(key))) {\n throw new TypeError('Tier0 SDK: unsupported Control option.');\n }\n}\n\nfunction json(value: unknown, seen = new Set<unknown>()): boolean {\n if (value === null || typeof value === 'string' || typeof value === 'boolean' || value instanceof UnsV2RawNumber) return true;\n if (typeof value === 'number') return Number.isFinite(value);\n if (typeof value !== 'object' || seen.has(value)) return false;\n if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {\n return false;\n }\n seen.add(value);\n const valid = (Array.isArray(value) ? Array.from(value) : Object.values(value)).every(item => json(item, seen));\n seen.delete(value);\n return valid;\n}\n\nfunction definition(value: unknown): value is PublicControl {\n if (!record(value)) return false;\n return ['code', 'name', 'description', 'contractVersion', 'status'].every(key => typeof value[key] === 'string') &&\n value.code !== '' && value.contractVersion !== '' && record(value.inputSchema) && record(value.outputSchema) &&\n ['read', 'write'].includes(value.sideEffect as string) &&\n ['none', 'optional', 'required'].includes(value.idempotency as string) &&\n typeof value.timeoutMs === 'number' && Number.isSafeInteger(value.timeoutMs) && value.timeoutMs > 0;\n}\n\nfunction runInfo(value: unknown): Partial<ControlErrorInfo> {\n if (!record(value)) return {};\n return {\n runID: typeof value.runId === 'string' ? value.runId : undefined,\n contractVersion: typeof value.contractVersion === 'string' ? value.contractVersion : undefined,\n runStatus: typeof value.status === 'string' ? value.status : undefined,\n replayed: typeof value.replayed === 'boolean' ? value.replayed : undefined,\n };\n}\n\nexport interface ControlHandle<Input = ControlJSON, Result = ControlJSON> {\n describe(): Promise<PublicControl>;\n /**\n * One POST only. Input is opaque business JSON, including fields named streamId,\n * entryId, deploymentVersion or timeoutMs. Only the server chooses binding/version/timeout.\n * Generic types are caller assertions; the server validates the contract schemas.\n */\n invoke(input: Input, options?: ControlInvokeOptions): Promise<ControlInvokeResponse<Result>>;\n}\n\nexport class ControlsClient {\n private readonly uns: UnsV2ClientCore;\n\n constructor(resolveClient: () => HttpClient = getClient, config: ControlTransportConfig = {}) {\n this.uns = new UnsV2ClientCore(resolveClient, config);\n }\n\n private async post<Name extends 'controlDiscover' | 'controlDescribe' | 'controlInvoke'>(\n operation: Name, body: UnsV2Request<Name>,\n ): Promise<{ value: unknown; status: number }> {\n try {\n const response = await this.uns.call(operation, body);\n return { value: response.data, status: 200 };\n } catch (error) {\n if (!(error instanceof UnsV2Error)) throw error;\n const info: ControlErrorInfo = {\n ...runInfo(error.data), status: error.status,\n errorCode: error.code.replace(/^UNS_V2_/, 'CONTROL_'),\n requestId: error.requestId, execution: error.execution, retry: error.retry,\n reason: error.reason, details: error.details, data: error.data,\n };\n if (error.outcomeUnknown) throw new ControlResultUnknownError(info);\n throw new ControlError(error.message, info);\n }\n }\n\n /** Discover visible contracts; defaults and authorization are resolved by the server. */\n async discover(options: ControlDiscoverOptions = {}): Promise<ControlDiscoverResponse> {\n keys(options, ['page', 'size', 'search']);\n if ((options.page !== undefined && (!Number.isSafeInteger(options.page) || options.page < 1)) ||\n (options.size !== undefined && (!Number.isSafeInteger(options.size) || options.size < 1 || options.size > 200)) ||\n (options.search !== undefined && typeof options.search !== 'string')) {\n throw new TypeError('Tier0 SDK: invalid Control discovery options.');\n }\n const { value, status } = await this.post('controlDiscover', options);\n if (!record(value) || !Number.isSafeInteger(value.total) || (value.total as number) < 0 ||\n !Array.isArray(value.list) || !value.list.every(definition)) {\n throw new ControlError('Invalid Control discovery response.', { status, errorCode: 'CONTROL_PROTOCOL_ERROR' });\n }\n return { total: value.total as number, list: value.list as PublicControl[] };\n }\n\n use<Input = ControlJSON, Result = ControlJSON>(selector: { code: string }): ControlHandle<Input, Result> {\n keys(selector, ['code']);\n const code = selector.code;\n if (typeof code !== 'string' || code.length > 128 || !/^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/.test(code)) {\n throw new TypeError('Tier0 SDK: invalid Control code.');\n }\n return {\n describe: async () => {\n const { value, status } = await this.post('controlDescribe', { code });\n if (!definition(value) || value.code !== code) {\n throw new ControlError('Invalid Control description.', { status, errorCode: 'CONTROL_PROTOCOL_ERROR' });\n }\n return value;\n },\n invoke: async (input, options = {}) => {\n keys(options, ['idempotencyKey']);\n const key = options.idempotencyKey;\n if (key !== undefined && (typeof key !== 'string' || !key || key.trim() !== key || new TextEncoder().encode(key).length > 128)) {\n throw new TypeError('Tier0 SDK: invalid Control idempotency key.');\n }\n if (!json(input)) throw new TypeError('Tier0 SDK: Control input must be JSON.');\n const { value, status } = await this.post('controlInvoke', {\n code, input: input as ControlJSON, ...(key === undefined ? {} : { idempotencyKey: key }),\n });\n if (!record(value) || value.code !== code || typeof value.contractVersion !== 'string' || !value.contractVersion ||\n !Object.prototype.hasOwnProperty.call(value, 'result') || typeof value.runId !== 'string' || !value.runId ||\n typeof value.status !== 'string' || !value.status || ['accepted', 'queued', 'pending', 'running'].includes(value.status) ||\n typeof value.replayed !== 'boolean') {\n throw new ControlResultUnknownError({ ...runInfo(value), status, errorCode: 'CONTROL_PROTOCOL_ERROR' });\n }\n return { code: value.code, contractVersion: value.contractVersion, result: value.result as Result,\n runID: value.runId, status: value.status, replayed: value.replayed };\n },\n };\n }\n}\n\n/** Uses configureClient()/TIER0_API_HOST/TIER0_API_KEY, resolved for every call. */\nexport const controls = new ControlsClient();\n"]}
|