@tier0/sdk-v2 0.1.0 → 0.2.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.
Files changed (170) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +13 -11
  3. package/dist/cjs/app-identity-contract.generated.js.map +1 -1
  4. package/dist/cjs/capabilities.js.map +1 -1
  5. package/dist/cjs/cloud-server.js.map +1 -1
  6. package/dist/cjs/cloud-transport.d.ts +21 -0
  7. package/dist/cjs/cloud-transport.js +81 -1
  8. package/dist/cjs/cloud-transport.js.map +1 -1
  9. package/dist/cjs/controls.js.map +1 -1
  10. package/dist/cjs/data/bootstrap.d.ts +4 -0
  11. package/dist/cjs/data/bootstrap.js +15 -6
  12. package/dist/cjs/data/bootstrap.js.map +1 -1
  13. package/dist/cjs/data/call.d.ts +26 -9
  14. package/dist/cjs/data/call.js +179 -14
  15. package/dist/cjs/data/call.js.map +1 -1
  16. package/dist/cjs/data/client.d.ts +44 -2
  17. package/dist/cjs/data/client.js +87 -4
  18. package/dist/cjs/data/client.js.map +1 -1
  19. package/dist/cjs/data/collection.d.ts +151 -14
  20. package/dist/cjs/data/collection.js +213 -50
  21. package/dist/cjs/data/collection.js.map +1 -1
  22. package/dist/cjs/data/context.d.ts +4 -2
  23. package/dist/cjs/data/context.js +14 -3
  24. package/dist/cjs/data/context.js.map +1 -1
  25. package/dist/cjs/data/define.d.ts +9 -1
  26. package/dist/cjs/data/define.js.map +1 -1
  27. package/dist/cjs/data/error.d.ts +30 -12
  28. package/dist/cjs/data/error.js +61 -63
  29. package/dist/cjs/data/error.js.map +1 -1
  30. package/dist/cjs/data/index.d.ts +6 -3
  31. package/dist/cjs/data/index.js +7 -1
  32. package/dist/cjs/data/index.js.map +1 -1
  33. package/dist/cjs/data/schema.d.ts +7 -1
  34. package/dist/cjs/data/schema.js +54 -4
  35. package/dist/cjs/data/schema.js.map +1 -1
  36. package/dist/cjs/data/subscribe.d.ts +108 -0
  37. package/dist/cjs/data/subscribe.js +270 -0
  38. package/dist/cjs/data/subscribe.js.map +1 -0
  39. package/dist/cjs/mq/broker.js.map +1 -1
  40. package/dist/cjs/mq/client.js.map +1 -1
  41. package/dist/cjs/mq/index.js.map +1 -1
  42. package/dist/cjs/mq/types.js.map +1 -1
  43. package/dist/cjs/runtime-context.js.map +1 -1
  44. package/dist/cjs/runtime-env.js.map +1 -1
  45. package/dist/cjs/uns-v2/client.d.ts +90 -12
  46. package/dist/cjs/uns-v2/client.js +238 -63
  47. package/dist/cjs/uns-v2/client.js.map +1 -1
  48. package/dist/cjs/uns-v2/codec.js.map +1 -1
  49. package/dist/cjs/uns-v2/generated.d.ts +9619 -6923
  50. package/dist/cjs/uns-v2/generated.js +124 -119
  51. package/dist/cjs/uns-v2/generated.js.map +1 -1
  52. package/dist/cjs/uns-v2/index.js.map +1 -1
  53. package/dist/cjs/uns-v2/sse.d.ts +20 -0
  54. package/dist/cjs/uns-v2/sse.js +65 -0
  55. package/dist/cjs/uns-v2/sse.js.map +1 -0
  56. package/dist/esm/app-identity-contract.generated.js.map +1 -1
  57. package/dist/esm/capabilities.js.map +1 -1
  58. package/dist/esm/cloud-server.js.map +1 -1
  59. package/dist/esm/cloud-transport.d.ts +21 -0
  60. package/dist/esm/cloud-transport.js +81 -1
  61. package/dist/esm/cloud-transport.js.map +1 -1
  62. package/dist/esm/controls.js.map +1 -1
  63. package/dist/esm/data/bootstrap.d.ts +4 -0
  64. package/dist/esm/data/bootstrap.js +14 -5
  65. package/dist/esm/data/bootstrap.js.map +1 -1
  66. package/dist/esm/data/call.d.ts +26 -9
  67. package/dist/esm/data/call.js +177 -13
  68. package/dist/esm/data/call.js.map +1 -1
  69. package/dist/esm/data/client.d.ts +44 -2
  70. package/dist/esm/data/client.js +89 -7
  71. package/dist/esm/data/client.js.map +1 -1
  72. package/dist/esm/data/collection.d.ts +151 -14
  73. package/dist/esm/data/collection.js +212 -49
  74. package/dist/esm/data/collection.js.map +1 -1
  75. package/dist/esm/data/context.d.ts +4 -2
  76. package/dist/esm/data/context.js +13 -3
  77. package/dist/esm/data/context.js.map +1 -1
  78. package/dist/esm/data/define.d.ts +9 -1
  79. package/dist/esm/data/define.js.map +1 -1
  80. package/dist/esm/data/error.d.ts +30 -12
  81. package/dist/esm/data/error.js +61 -63
  82. package/dist/esm/data/error.js.map +1 -1
  83. package/dist/esm/data/index.d.ts +6 -3
  84. package/dist/esm/data/index.js +3 -1
  85. package/dist/esm/data/index.js.map +1 -1
  86. package/dist/esm/data/schema.d.ts +7 -1
  87. package/dist/esm/data/schema.js +54 -4
  88. package/dist/esm/data/schema.js.map +1 -1
  89. package/dist/esm/data/subscribe.d.ts +108 -0
  90. package/dist/esm/data/subscribe.js +265 -0
  91. package/dist/esm/data/subscribe.js.map +1 -0
  92. package/dist/esm/mq/broker.js.map +1 -1
  93. package/dist/esm/mq/client.js.map +1 -1
  94. package/dist/esm/mq/index.js.map +1 -1
  95. package/dist/esm/mq/types.js.map +1 -1
  96. package/dist/esm/runtime-context.js.map +1 -1
  97. package/dist/esm/runtime-env.js.map +1 -1
  98. package/dist/esm/uns-v2/client.d.ts +90 -12
  99. package/dist/esm/uns-v2/client.js +236 -63
  100. package/dist/esm/uns-v2/client.js.map +1 -1
  101. package/dist/esm/uns-v2/codec.js.map +1 -1
  102. package/dist/esm/uns-v2/generated.d.ts +9619 -6923
  103. package/dist/esm/uns-v2/generated.js +123 -118
  104. package/dist/esm/uns-v2/generated.js.map +1 -1
  105. package/dist/esm/uns-v2/index.js.map +1 -1
  106. package/dist/esm/uns-v2/sse.d.ts +20 -0
  107. package/dist/esm/uns-v2/sse.js +60 -0
  108. package/dist/esm/uns-v2/sse.js.map +1 -0
  109. package/package.json +29 -16
  110. package/skills/tier0-sdk-v2/SKILL.md +14 -14
  111. package/skills/{tier0-sdk-v2-data → tier0-sdk-v2/tier0-sdk-v2-data}/SKILL.md +3 -2
  112. package/skills/{tier0-sdk-v2-data → tier0-sdk-v2/tier0-sdk-v2-data}/references/consistency.md +3 -3
  113. package/skills/{tier0-sdk-v2-data → tier0-sdk-v2/tier0-sdk-v2-data}/references/errors.md +23 -10
  114. package/skills/{tier0-sdk-v2-data → tier0-sdk-v2/tier0-sdk-v2-data}/references/modeling.md +36 -0
  115. package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/read-write.md +172 -0
  116. package/skills/{tier0-sdk-v2-mq → tier0-sdk-v2/tier0-sdk-v2-mq}/references/quickstart.md +1 -1
  117. package/skills/{tier0-sdk-v2-source → tier0-sdk-v2/tier0-sdk-v2-source}/SKILL.md +3 -3
  118. package/skills/{tier0-sdk-v2-source → tier0-sdk-v2/tier0-sdk-v2-source}/references/create.md +3 -6
  119. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/delete.md +39 -0
  120. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/state.md +36 -0
  121. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/update.md +80 -0
  122. package/skills/{tier0-sdk-v2-stream → tier0-sdk-v2/tier0-sdk-v2-stream}/SKILL.md +6 -6
  123. package/skills/{tier0-sdk-v2-stream → tier0-sdk-v2/tier0-sdk-v2-stream}/references/create.md +15 -14
  124. package/skills/{tier0-sdk-v2-stream → tier0-sdk-v2/tier0-sdk-v2-stream}/references/deploy.md +11 -9
  125. package/skills/{tier0-sdk-v2-stream → tier0-sdk-v2/tier0-sdk-v2-stream}/references/lifecycle.md +2 -1
  126. package/skills/{tier0-sdk-v2-stream → tier0-sdk-v2/tier0-sdk-v2-stream}/references/update.md +5 -6
  127. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/SKILL.md +55 -0
  128. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/create.md +57 -0
  129. package/skills/{tier0-sdk-v2-uns → tier0-sdk-v2/tier0-sdk-v2-uns}/references/data-workflows.md +3 -7
  130. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/delete.md +53 -0
  131. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/namespace.md +38 -0
  132. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/read.md +34 -0
  133. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/restore.md +39 -0
  134. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/update.md +62 -0
  135. package/skills/tier0-sdk-v2-data/references/read-write.md +0 -72
  136. package/skills/tier0-sdk-v2-source/references/delete.md +0 -47
  137. package/skills/tier0-sdk-v2-source/references/state.md +0 -37
  138. package/skills/tier0-sdk-v2-source/references/update.md +0 -61
  139. package/skills/tier0-sdk-v2-uns/SKILL.md +0 -53
  140. package/skills/tier0-sdk-v2-uns/references/create.md +0 -85
  141. package/skills/tier0-sdk-v2-uns/references/delete.md +0 -69
  142. package/skills/tier0-sdk-v2-uns/references/namespace.md +0 -75
  143. package/skills/tier0-sdk-v2-uns/references/read.md +0 -32
  144. package/skills/tier0-sdk-v2-uns/references/restore.md +0 -41
  145. package/skills/tier0-sdk-v2-uns/references/update.md +0 -86
  146. /package/skills/{tier0-sdk-v2-agent → tier0-sdk-v2/tier0-sdk-v2-agent}/SKILL.md +0 -0
  147. /package/skills/{tier0-sdk-v2-agent → tier0-sdk-v2/tier0-sdk-v2-agent}/references/results.md +0 -0
  148. /package/skills/{tier0-sdk-v2-controls → tier0-sdk-v2/tier0-sdk-v2-controls}/SKILL.md +0 -0
  149. /package/skills/{tier0-sdk-v2-data → tier0-sdk-v2/tier0-sdk-v2-data}/references/schema-evolution.md +0 -0
  150. /package/skills/{tier0-sdk-v2-files → tier0-sdk-v2/tier0-sdk-v2-files}/SKILL.md +0 -0
  151. /package/skills/{tier0-sdk-v2-files → tier0-sdk-v2/tier0-sdk-v2-files}/references/delete.md +0 -0
  152. /package/skills/{tier0-sdk-v2-files → tier0-sdk-v2/tier0-sdk-v2-files}/references/download.md +0 -0
  153. /package/skills/{tier0-sdk-v2-files → tier0-sdk-v2/tier0-sdk-v2-files}/references/multipart.md +0 -0
  154. /package/skills/{tier0-sdk-v2-files → tier0-sdk-v2/tier0-sdk-v2-files}/references/upload.md +0 -0
  155. /package/skills/{tier0-sdk-v2-files → tier0-sdk-v2/tier0-sdk-v2-files}/references/url.md +0 -0
  156. /package/skills/{tier0-sdk-v2-members → tier0-sdk-v2/tier0-sdk-v2-members}/SKILL.md +0 -0
  157. /package/skills/{tier0-sdk-v2-members → tier0-sdk-v2/tier0-sdk-v2-members}/references/app-members.md +0 -0
  158. /package/skills/{tier0-sdk-v2-members → tier0-sdk-v2/tier0-sdk-v2-members}/references/platform-members.md +0 -0
  159. /package/skills/{tier0-sdk-v2-mq → tier0-sdk-v2/tier0-sdk-v2-mq}/SKILL.md +0 -0
  160. /package/skills/{tier0-sdk-v2-notifications → tier0-sdk-v2/tier0-sdk-v2-notifications}/SKILL.md +0 -0
  161. /package/skills/{tier0-sdk-v2-notifications → tier0-sdk-v2/tier0-sdk-v2-notifications}/references/get.md +0 -0
  162. /package/skills/{tier0-sdk-v2-notifications → tier0-sdk-v2/tier0-sdk-v2-notifications}/references/send.md +0 -0
  163. /package/skills/{tier0-sdk-v2-source → tier0-sdk-v2/tier0-sdk-v2-source}/references/changes.md +0 -0
  164. /package/skills/{tier0-sdk-v2-source → tier0-sdk-v2/tier0-sdk-v2-source}/references/protocols.md +0 -0
  165. /package/skills/{tier0-sdk-v2-source → tier0-sdk-v2/tier0-sdk-v2-source}/references/read.md +0 -0
  166. /package/skills/{tier0-sdk-v2-stream → tier0-sdk-v2/tier0-sdk-v2-stream}/references/delete.md +0 -0
  167. /package/skills/{tier0-sdk-v2-stream → tier0-sdk-v2/tier0-sdk-v2-stream}/references/read.md +0 -0
  168. /package/skills/{tier0-sdk-v2-system → tier0-sdk-v2/tier0-sdk-v2-system}/SKILL.md +0 -0
  169. /package/skills/{tier0-sdk-v2-system → tier0-sdk-v2/tier0-sdk-v2-system}/references/info.md +0 -0
  170. /package/skills/{tier0-sdk-v2-system → tier0-sdk-v2/tier0-sdk-v2-system}/references/whoami.md +0 -0
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 FREEZONEX
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 FREEZONEX
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -2,14 +2,16 @@
2
2
 
3
3
  Tier0 云端新架构的独立 TypeScript / JavaScript SDK。新仓库、新 npm 包,不覆盖 `@tier0/sdk`。
4
4
 
5
- 当前版本 `0.1.0` 是待联调的首版源码,尚未发布 npm,也不表示开发环境已部署对应后端。要求 Node.js 20.19+。浏览器 HTTP、MQTT、React、Vue 和服务端身份验签分别提供独立入口。
5
+ 当前版本 `0.2.2` 对应 UNS v2 契约 5.0.0,与 0.1.0 不兼容(新错误模型 `execution` / `retry`、封顶计数、删除 `recordChangesPoll` 等)。Collection 支持 int、float、double 和 datetime 声明;格式注解不新增数值范围或日期格式校验,Sample 外层 time 保持不变。使用时需确认目标环境已部署对应后端。要求 Node.js 20.19+。浏览器 HTTP、MQTT、React、Vue 和服务端身份验签分别提供独立入口。
6
+
7
+ 本次更新:Source 无引用时支持直接修改、停用和删除;Stream 发布与回滚返回带类型的发布回执;UNS 插入可在同一次写入中返回创建快照,App 数据层同步支持 `returnDocument` / `projection` 和投影字段的可选类型。
6
8
 
7
9
  ## 安装与初始化
8
10
 
9
- 首发前在本仓库运行 `npm ci`、`npm run check`、`npm pack`,业务项目安装生成的 `.tgz`。发布后使用:
11
+ 发布前在本仓库运行 `npm ci`、`npm run check`,验证生成的 `.tgz`。业务项目安装精确版本:
10
12
 
11
13
  ```sh
12
- npm install @tier0/sdk-v2
14
+ npm install --save-exact @tier0/sdk-v2@0.2.2
13
15
  ```
14
16
 
15
17
  ```ts
@@ -48,14 +50,14 @@ const capabilities = await tier0.capabilities.discover();
48
50
  | `@tier0/sdk-v2/react` | `useTier0Query()`、`useTier0Mutation()`,需要 React 和 TanStack Query |
49
51
  | `@tier0/sdk-v2/vue` | `useTier0Request()`,需要 Vue 3 |
50
52
  | `@tier0/sdk-v2/server` | `createCloudAppRequestVerifier()`,仅服务端加载 `node:crypto` |
51
- | `@tier0/sdk-v2/data` | App 数据层:`defineCollection()` 声明集合、`createDataClient()` 首次访问时 ensure,Mongo 风格读写、原子批量与 `transact`、员工数据主体透传;仅服务端,需要 `zod` 4 |
53
+ | `@tier0/sdk-v2/data` | App 数据层:`defineCollection()` 声明集合(含 TTL)、`createDataClient()` 首次访问时 ensure,Mongo 风格读写、带总数分页与封顶计数、原子批量与 `transact`、`subscribe` 变更订阅、员工数据主体透传;自动幂等键、并发上限与按 `retry.safe` 重试;仅服务端,需要 `zod` 4 |
52
54
  | `@tier0/sdk-v2/data/define` | 集合声明与类型:`defineCollection()`、`Doc` / `NewDoc` 等、`compileCollection()`、`validateDocument()`;可进浏览器包,组件和 route 的客户端代码只从这里取声明和类型 |
53
55
 
54
56
  不保留 UNS v1、旧 Flow、`getCurrentProjectId()`、project 成员查询或 `/gw/reload`。Workspace 成员不等于能使用某个 App 的成员,不可用前者在客户端猜测 App 权限。
55
57
 
56
58
  ## Source、Stream 与 UNS 分域
57
59
 
58
- Source 负责连接外部系统,Stream 负责处理与运行,UNS 负责命名空间与业务数据。共用底层 106 个公开生成操作,业务入口按领域组织;Control 使用 `tier0.controls` 的专属契约。
60
+ Source 负责连接外部系统,Stream 负责处理与运行,UNS 负责命名空间与业务数据。公开操作由固定的上游契约生成,业务入口按领域组织;Control 使用 `tier0.controls` 的专属契约。目录、Topic、集合基础 CRUD 统一使用 `metadata*`,查询、批量操作、软删除及恢复见 UNS Skill。
59
61
 
60
62
  ```ts
61
63
  const sources = await tier0.source.documents.list({ page: 1, size: 20 });
@@ -67,7 +69,7 @@ Source/Stream 仍保留 `{ code, msg, requestId, data }` 响应以及 `UnsV2Erro
67
69
 
68
70
  从最初提交迁移:`uns.sourceList` → `source.list`;`uns.sourceDocumentGet` → `source.documents.get`;`uns.streamProgramDeploy` → `stream.programs.deploy`;`uns.streamDocumentValidate` → `stream.documents.validate`。这些管理方法已移出主入口的 `uns`。底层 `createUnsV2Client()` 仍提供完整生成契约供契约工具使用;数据专用客户端可用 `createUnsDataClient()`。
69
71
 
70
- 随包提供 12 个可独立发现的 Skill,包含完整流程、参数边界、错误处理与可类型检查的示例:[入口](skills/tier0-sdk-v2/SKILL.md)、[Source](skills/tier0-sdk-v2-source/SKILL.md)、[Stream](skills/tier0-sdk-v2-stream/SKILL.md)、[UNS](skills/tier0-sdk-v2-uns/SKILL.md)、[通知](skills/tier0-sdk-v2-notifications/SKILL.md)、[系统](skills/tier0-sdk-v2-system/SKILL.md)、[文件](skills/tier0-sdk-v2-files/SKILL.md)、[MQTT](skills/tier0-sdk-v2-mq/SKILL.md)、[成员](skills/tier0-sdk-v2-members/SKILL.md)、[Controls](skills/tier0-sdk-v2-controls/SKILL.md)、[Agent](skills/tier0-sdk-v2-agent/SKILL.md)、[App 数据](skills/tier0-sdk-v2-data/SKILL.md)。复杂流程的参考文档随 Skill 一起打包。
72
+ 随包提供 Skill:总入口 [tier0-sdk-v2](skills/tier0-sdk-v2/SKILL.md) 下嵌套 11 个领域子 Skill(`skills/tier0-sdk-v2/tier0-sdk-v2-<领域>/`),每个仍可独立发现,包含完整流程、参数边界、错误处理与可类型检查的示例:[Source](skills/tier0-sdk-v2/tier0-sdk-v2-source/SKILL.md)、[Stream](skills/tier0-sdk-v2/tier0-sdk-v2-stream/SKILL.md)、[UNS](skills/tier0-sdk-v2/tier0-sdk-v2-uns/SKILL.md)、[通知](skills/tier0-sdk-v2/tier0-sdk-v2-notifications/SKILL.md)、[系统](skills/tier0-sdk-v2/tier0-sdk-v2-system/SKILL.md)、[文件](skills/tier0-sdk-v2/tier0-sdk-v2-files/SKILL.md)、[MQTT](skills/tier0-sdk-v2/tier0-sdk-v2-mq/SKILL.md)、[成员](skills/tier0-sdk-v2/tier0-sdk-v2-members/SKILL.md)、[Controls](skills/tier0-sdk-v2/tier0-sdk-v2-controls/SKILL.md)、[Agent](skills/tier0-sdk-v2/tier0-sdk-v2-agent/SKILL.md)、[App 数据](skills/tier0-sdk-v2/tier0-sdk-v2-data/SKILL.md)。复杂流程的参考文档随 Skill 一起打包。在 Tier0 Console 上传时,把整个 `skills/tier0-sdk-v2/` 目录打成一个 zip。
71
73
 
72
74
  ## UNS 数据访问
73
75
 
@@ -83,13 +85,13 @@ await tier0.uns.recordFind(
83
85
  );
84
86
  ```
85
87
 
86
- 实际集合 ID 和有效权限从平台配置/数据上下文取得。管理操作中,App 凭证只能调用本 App 集合的 `appCollectionsEnsure` / `appCollectionsSchemaReplace` / `appCollectionsArchive` / `appCollectionsRestore`;SDK 中存在 `collectionCreate` 等其他管理方法,不表示 App 凭证有对应权限。App 数据授权 `appDataPolicyGet` / `appDataPolicyUpdate` 的调用方必须是:持有 `uns.write` 的登录会话、持有 `uns.write` 且 full_access、不绑定 App 的 personal / agent Key,或治理会话;运行时 App 凭证不能管理授权。Core-only 后台接口不导出到公开 SDK。
88
+ 实际集合 ID 和有效权限从平台配置/数据上下文取得。管理操作中,App 凭证只能调用本 App 集合的 `appCollectionsEnsure` / `appCollectionsSchemaReplace` / `appCollectionsArchive` / `appCollectionsRestore`;SDK 中存在 `metadataInsertOne` 等其他管理方法,不表示 App 凭证有对应权限。App 数据授权 `appDataPolicyGet` / `appDataPolicyUpdate` 的调用方必须是:持有 `uns.write` 的登录会话、持有 `uns.write` 且 full_access、不绑定 App 的 personal / agent Key,或治理会话;运行时 App 凭证不能管理授权。Core-only 后台接口不导出到公开 SDK。
87
89
 
88
90
  UNS 保留 `{ code, msg, requestId, data }` 完整响应。普通 v1 包装接口返回已解包的 `data`,通知/Control/能力发现返回服务端直接对象。业务错误即使 HTTP 为 200 也会抛出 `ApiError`。
89
91
 
90
92
  `int64` 和普通 v1 整数字段使用 `number | bigint`:安全范围内返回 number,超出范围返回 bigint。UNS 任意 JSON 中无法无损表示的数字用 `UnsV2RawNumber`;传回 SDK 可保持原值。对外输出 JSON 时自行确定 bigint/精确数字的表示,不要直接 `JSON.stringify` 包含这些值的对象。
91
93
 
92
- HTTP 操作不自动重试。`UnsV2OutcomeUnknownError`、`ControlResultUnknownError` 或 `ApiError.outcomeUnknown` 表示写操作可能已执行;先查询结果/作业,按业务意图保留原幂等键,不自动生成新键重放。查询与写入均可受配置超时约束。
94
+ `createClient()` 的 HTTP 操作不自动重试。UNS v2 错误带 `execution`(`notStarted` / `rolledBack` / `committed` / `unknown`)与 `retry: { safe, afterMs? }`:`safe` 表示可以用同一请求(同一幂等键)重发。`execution` 为 `unknown` 时抛出 `UnsV2OutcomeUnknownError`;它与 `ControlResultUnknownError`、`ApiError.outcomeUnknown` 一样表示写操作可能已执行,先读回对账,按业务意图保留原幂等键,不自动生成新键重放。查询与写入均可受配置超时约束。App 数据层 `@tier0/sdk-v2/data` 另有自己的策略:每次调用从开始算最多 25 秒(含排队与重试)、每进程最多 6 个并发请求、写入自动生成幂等键、按 `retry.safe` 最多自动重试 2 次;`runWithRequestContext(request, …)` 传入请求本身时,请求中止后排队中的调用不再发出。
93
95
 
94
96
  ## 通知
95
97
 
@@ -167,7 +169,7 @@ Vue 由 `execute()` 显式执行,后发请求的结果优先;取消不表示
167
169
 
168
170
  ## 契约更新与验证
169
171
 
170
- 上游:`FREEZONEX/Tier0-Backend`,固定提交 `fb35598ae8404e1a64bdc8a500341f12aeff2744`。`contracts/upstream.json` 记录来源和 SHA-256。
172
+ 上游:`FREEZONEX/Tier0-Backend`,固定提交 `6d0fbbca15ddbfd4d9b313b1abbc843b36d14dd0`。`contracts/upstream.json` 记录来源和 SHA-256。
171
173
 
172
174
  ```sh
173
175
  npm ci
@@ -181,7 +183,7 @@ npm run check
181
183
 
182
184
  v1 来自网关 Swagger,并按实际 handler 补齐响应外层;UNS 来自 `contract_generated.go#ContractJSON` 中已经应用 Cloud 扩展的契约,结合 manifest/registry 生成。不能直接使用仍含 Enterprise 基础操作的 `share/unscontract/contract.json` 作为最终云端契约。
183
185
 
184
- `npm run check` 包含契约一致性、Skill 注册及递归引用检查、所有 Skill TypeScript 示例的源码/安装包类型校验、单元和本地 HTTP 测试、ESM/CJS 构建、实际 npm 包安装、浏览器打包及导入验证。完整行为测试还会在独立 consumer 中对已安装的 `.tgz` 再跑一遍,导入目标严格指向包内 `dist`;包内调试映射包含源内容。当前 652 项测试包含全部 157 个公开操作的路由检查。路由检查使用本地 HTTP fixture,不等于每个操作的业务验收。
186
+ `npm run check` 包含契约一致性、Skill 注册及递归引用检查、所有 Skill TypeScript 示例的源码/安装包类型校验、单元和本地 HTTP 测试、ESM/CJS 构建、实际 npm 包安装、浏览器打包及导入验证。完整行为测试还会在独立 consumer 中对已安装的 `.tgz` 再跑一遍,导入目标严格指向包内 `dist`;包内调试映射包含源内容。测试覆盖全部公开操作的路由检查。路由检查使用本地 HTTP fixture,不等于每个操作的业务验收。
185
187
 
186
188
  `tests/skill-workflows.test.ts` 直接提取 Markdown 示例,验证 Source/Stream/UNS 的创建、查询、修改、删除或归档恢复,影响分页和结果未知分支,以及通知请求、状态查询和成员展示。默认检查不调用线上接口。
187
189
 
@@ -199,4 +201,4 @@ node scripts/check-live-transports.mjs <consumer> <workspaceId> .tmp/live-transp
199
201
 
200
202
  写入验收不发布 Stream、不启用 Source、不发送通知。归档资源保留正常产品恢复能力;报告区分通过、服务端拒绝和未验证范围。分片上传失败会保留错误原因,确认尚未尝试 complete 时清理本次会话;完成结果未知时先对账。完整结果见 [2026-10-22 验收报告](docs/acceptance-2026-10-22.md)。
201
203
 
202
- 首发前仍需:解决验收报告中的阻断并补齐未验收范围、App 脚手架切换精确依赖 `"@tier0/sdk-v2": "0.1.0"`、新 Skill 上传和 npm 发布授权。
204
+ 业务接入时仍需核对验收报告中的环境限制并补齐未验收范围、将 App 脚手架精确依赖更新为 `"@tier0/sdk-v2": "0.2.2"`,并按需更新已安装的 Skill。
@@ -1 +1 @@
1
- {"version":3,"file":"app-identity-contract.generated.js","sourceRoot":"","sources":["../../src/app-identity-contract.generated.ts"],"names":[],"mappings":";;;AAAA,8EAA8E;AAC9E,mFAAmF;AACtE,QAAA,6BAA6B,GAAG;IAC3C,SAAS,EAAE,+BAA+B;IAC1C,QAAQ,EAAE,sBAAsB;IAChC,MAAM,EAAE,uBAAuB;IAC/B,WAAW,EAAE,OAAO;IACpB,QAAQ,EAAE,mBAAmB;IAC7B,UAAU,EAAE,mBAAmB;IAC/B,eAAe,EAAE,IAAI;IACrB,cAAc,EAAE,KAAK;IACrB,aAAa,EAAE,IAAI;IACnB,eAAe,EAAE,EAAE;IACnB,kBAAkB,EAAE,CAAC;IACrB,UAAU,EAAE,EAAE;IACd,cAAc,EAAE,GAAG;IACnB,SAAS,EAAE,CAAC;IACZ,cAAc,EAAE,mCAAmC;IACnD,cAAc,EAAE,2EAA2E;IAC3F,gBAAgB,EAAE;QAChB,KAAK;QACL,KAAK;QACL,KAAK;QACL,KAAK;QACL,aAAa;QACb,OAAO;QACP,QAAQ;QACR,YAAY;QACZ,YAAY;QACZ,KAAK;QACL,KAAK;QACL,KAAK;QACL,OAAO;KACR;IACD,eAAe,EAAE,eAAe;IAChC,sBAAsB,EAAE;QACtB,KAAK;QACL,KAAK;QACL,KAAK;KACN;IACD,iBAAiB,EAAE;QACjB,KAAK;QACL,KAAK;QACL,GAAG;QACH,KAAK;KACN;CACO,CAAC","sourcesContent":["// Generated from SWE gatewayheader/app-request-identity.v1.json; do not edit.\r\n// Source SHA-256: ac5ec2efb882395e63a46c9ec479de16c09943b88fc0bd906dd77c7f9f4bfaa3\r\nexport const APP_REQUEST_IDENTITY_CONTRACT = {\r\n \"version\": \"tier0.app-request-identity/v1\",\r\n \"header\": \"X-Tier0-App-Identity\",\r\n \"type\": \"tier0-app-request+jwt\",\r\n \"algorithm\": \"EdDSA\",\r\n \"issuer\": \"tier0-app-gateway\",\r\n \"audience\": \"tier0-app-runtime\",\r\n \"maxTokenBytes\": 8192,\r\n \"maxBodyBytes\": 65536,\r\n \"maxURIBytes\": 8192,\r\n \"maxTTLSeconds\": 30,\r\n \"clockSkewSeconds\": 5,\r\n \"maxRoles\": 32,\r\n \"maxRoleBytes\": 128,\r\n \"maxKeys\": 8,\r\n \"keyIDPattern\": \"^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$\",\r\n \"appIDPattern\": \"^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$\",\r\n \"requiredClaims\": [\r\n \"ver\",\r\n \"iss\",\r\n \"aud\",\r\n \"sub\",\r\n \"workspaceID\",\r\n \"appID\",\r\n \"method\",\r\n \"requestURI\",\r\n \"bodySHA256\",\r\n \"iat\",\r\n \"exp\",\r\n \"jti\",\r\n \"roles\"\r\n ],\r\n \"methodPattern\": \"^[A-Z]{1,16}$\",\r\n \"requiredHeaderFields\": [\r\n \"alg\",\r\n \"typ\",\r\n \"kid\"\r\n ],\r\n \"publicKeyFields\": [\r\n \"kty\",\r\n \"crv\",\r\n \"x\",\r\n \"kid\"\r\n ]\r\n} as const;\r\n"]}
1
+ {"version":3,"file":"app-identity-contract.generated.js","sourceRoot":"","sources":["../../src/app-identity-contract.generated.ts"],"names":[],"mappings":";;;AAAA,8EAA8E;AAC9E,mFAAmF;AACtE,QAAA,6BAA6B,GAAG;IAC3C,SAAS,EAAE,+BAA+B;IAC1C,QAAQ,EAAE,sBAAsB;IAChC,MAAM,EAAE,uBAAuB;IAC/B,WAAW,EAAE,OAAO;IACpB,QAAQ,EAAE,mBAAmB;IAC7B,UAAU,EAAE,mBAAmB;IAC/B,eAAe,EAAE,IAAI;IACrB,cAAc,EAAE,KAAK;IACrB,aAAa,EAAE,IAAI;IACnB,eAAe,EAAE,EAAE;IACnB,kBAAkB,EAAE,CAAC;IACrB,UAAU,EAAE,EAAE;IACd,cAAc,EAAE,GAAG;IACnB,SAAS,EAAE,CAAC;IACZ,cAAc,EAAE,mCAAmC;IACnD,cAAc,EAAE,2EAA2E;IAC3F,gBAAgB,EAAE;QAChB,KAAK;QACL,KAAK;QACL,KAAK;QACL,KAAK;QACL,aAAa;QACb,OAAO;QACP,QAAQ;QACR,YAAY;QACZ,YAAY;QACZ,KAAK;QACL,KAAK;QACL,KAAK;QACL,OAAO;KACR;IACD,eAAe,EAAE,eAAe;IAChC,sBAAsB,EAAE;QACtB,KAAK;QACL,KAAK;QACL,KAAK;KACN;IACD,iBAAiB,EAAE;QACjB,KAAK;QACL,KAAK;QACL,GAAG;QACH,KAAK;KACN;CACO,CAAC","sourcesContent":["// Generated from SWE gatewayheader/app-request-identity.v1.json; do not edit.\n// Source SHA-256: ac5ec2efb882395e63a46c9ec479de16c09943b88fc0bd906dd77c7f9f4bfaa3\nexport const APP_REQUEST_IDENTITY_CONTRACT = {\n \"version\": \"tier0.app-request-identity/v1\",\n \"header\": \"X-Tier0-App-Identity\",\n \"type\": \"tier0-app-request+jwt\",\n \"algorithm\": \"EdDSA\",\n \"issuer\": \"tier0-app-gateway\",\n \"audience\": \"tier0-app-runtime\",\n \"maxTokenBytes\": 8192,\n \"maxBodyBytes\": 65536,\n \"maxURIBytes\": 8192,\n \"maxTTLSeconds\": 30,\n \"clockSkewSeconds\": 5,\n \"maxRoles\": 32,\n \"maxRoleBytes\": 128,\n \"maxKeys\": 8,\n \"keyIDPattern\": \"^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$\",\n \"appIDPattern\": \"^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$\",\n \"requiredClaims\": [\n \"ver\",\n \"iss\",\n \"aud\",\n \"sub\",\n \"workspaceID\",\n \"appID\",\n \"method\",\n \"requestURI\",\n \"bodySHA256\",\n \"iat\",\n \"exp\",\n \"jti\",\n \"roles\"\n ],\n \"methodPattern\": \"^[A-Z]{1,16}$\",\n \"requiredHeaderFields\": [\n \"alg\",\n \"typ\",\n \"kid\"\n ],\n \"publicKeyFields\": [\n \"kty\",\n \"crv\",\n \"x\",\n \"kid\"\n ]\n} as const;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/capabilities.ts"],"names":[],"mappings":"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","sourcesContent":["import { CloudTransport, CloudTransportError, type CloudTransportConfig } from './cloud-transport.js';\r\nimport { getClient, type HttpClient } from './openapi/client.js';\r\n\r\nexport type CapabilityCode = 'namespace.v2' | 'source.v1' | 'stream.v2' | 'control.v1' | 'control.invoke.v1';\r\nexport type CapabilityState = 'disabled' | 'not_supported' | 'unavailable' | 'readiness_unknown' | 'ready';\r\nexport type CapabilityAvailability = 'unavailable' | 'unknown' | 'available';\r\n\r\nexport interface PublicCapability {\r\n code: CapabilityCode;\r\n /** Public release and workspace gates; does not establish runtime readiness. */\r\n releaseEnabled: boolean;\r\n /** Server-assessed implementation/readiness, never inferred from releaseEnabled. */\r\n enabled: boolean;\r\n /** Authorization summary, not a grant for every individual Control code. */\r\n allowed: boolean;\r\n state: CapabilityState;\r\n /** Not device online status or execution/ACK confirmation. */\r\n availability: CapabilityAvailability;\r\n contractVersions: string[];\r\n}\r\n\r\nexport interface CapabilityDeprecation {\r\n contract: string;\r\n replacement?: string;\r\n sunsetAt?: string;\r\n}\r\n\r\nexport interface CapabilityDiscoverResponse {\r\n product: 'cloud';\r\n /** Trusted server configuration only; absent when unconfigured. */\r\n productVersion?: string;\r\n contractVersion: '1.0';\r\n apiContractVersions: string[];\r\n interpreterContractVersions: string[];\r\n /** Public SDK contract labels, not npm package versions. */\r\n sdkContractVersions: string[];\r\n capabilities: PublicCapability[];\r\n deprecations: CapabilityDeprecation[];\r\n}\r\n\r\nexport interface CapabilityErrorInfo {\r\n status?: number;\r\n /** Gateway string code (including unknown future codes), or an SDK-local CAPABILITY_* code. */\r\n errorCode: string;\r\n}\r\n\r\nexport class CapabilityError extends Error {\r\n readonly status?: number;\r\n readonly errorCode: string;\r\n readonly retryable = false;\r\n\r\n constructor(message: string, info: CapabilityErrorInfo) {\r\n super(message);\r\n this.name = 'CapabilityError';\r\n this.status = info.status;\r\n this.errorCode = info.errorCode;\r\n }\r\n}\r\n\r\nconst contracts: Record<CapabilityCode, string[]> = {\r\n 'namespace.v2': ['openapi/v2'],\r\n 'source.v1': ['openapi/v1'],\r\n 'stream.v2': ['tier0-stream/v2'],\r\n 'control.v1': ['openapi/v1', 'control/v1'],\r\n 'control.invoke.v1': ['openapi/v1', 'tier0-stream/v2', 'control/v1'],\r\n};\r\n\r\nfunction record(value: unknown): value is Record<string, unknown> {\r\n return value !== null && typeof value === 'object' && !Array.isArray(value);\r\n}\r\nfunction text(value: unknown): value is string {\r\n return typeof value === 'string' && value.length > 0;\r\n}\r\nfunction strings(value: unknown): value is string[] {\r\n return Array.isArray(value) && value.every(text) && new Set(value).size === value.length;\r\n}\r\n\r\n/** Validate and explicitly project the frozen contract; unknown capabilities/extension fields are ignored. */\r\nfunction discovery(value: unknown, status: number): CapabilityDiscoverResponse {\r\n const fail = (version = false): never => {\r\n throw new CapabilityError(version ? 'Unsupported capability contract version.' : 'Invalid capability discovery response.', {\r\n status, errorCode: version ? 'CAPABILITY_UNSUPPORTED_VERSION' : 'CAPABILITY_PROTOCOL_ERROR',\r\n });\r\n };\r\n if (!record(value)) return fail();\r\n if (!text(value.product) || !text(value.contractVersion) ||\r\n !strings(value.apiContractVersions) || !strings(value.interpreterContractVersions) || !strings(value.sdkContractVersions) ||\r\n !Array.isArray(value.capabilities) || !Array.isArray(value.deprecations) ||\r\n (value.productVersion !== undefined && !text(value.productVersion))) return fail();\r\n if (value.product !== 'cloud' || value.contractVersion !== '1.0' ||\r\n !value.apiContractVersions.includes('openapi/v1') ||\r\n !value.interpreterContractVersions.includes('tier0-stream/v2') ||\r\n !value.sdkContractVersions.includes('control/v1')) return fail(true);\r\n\r\n const capabilities: PublicCapability[] = [];\r\n const seen = new Set<string>();\r\n for (const item of value.capabilities) {\r\n if (!record(item) || !text(item.code)) return fail();\r\n if (!Object.prototype.hasOwnProperty.call(contracts, item.code)) continue;\r\n const code = item.code as CapabilityCode;\r\n if (seen.has(code)) return fail();\r\n seen.add(code);\r\n if (typeof item.releaseEnabled !== 'boolean' || typeof item.enabled !== 'boolean' || typeof item.allowed !== 'boolean' ||\r\n !['disabled', 'not_supported', 'unavailable', 'readiness_unknown', 'ready'].includes(item.state as string) ||\r\n !['unavailable', 'unknown', 'available'].includes(item.availability as string) || !strings(item.contractVersions)) return fail();\r\n if (contracts[code].some(version =>\r\n !(item.contractVersions as string[]).includes(version) ||\r\n (version.startsWith('openapi/') && !(value.apiContractVersions as string[]).includes(version)))) return fail(true);\r\n const ready = item.state === 'ready';\r\n const expectedAvailability = ready ? 'available' : item.state === 'readiness_unknown' ? 'unknown' : 'unavailable';\r\n if (item.enabled !== ready || item.availability !== expectedAvailability ||\r\n (ready && (!item.releaseEnabled || !item.allowed)) ||\r\n (item.state === 'disabled' ? item.releaseEnabled : !item.releaseEnabled)) return fail();\r\n capabilities.push({\r\n code, releaseEnabled: item.releaseEnabled, enabled: item.enabled, allowed: item.allowed,\r\n state: item.state as CapabilityState, availability: item.availability as CapabilityAvailability,\r\n contractVersions: [...item.contractVersions],\r\n });\r\n }\r\n const deprecations: CapabilityDeprecation[] = [];\r\n for (const item of value.deprecations) {\r\n if (!record(item) || !text(item.contract) ||\r\n (item.replacement !== undefined && !text(item.replacement)) ||\r\n (item.sunsetAt !== undefined && !text(item.sunsetAt))) return fail();\r\n deprecations.push({ contract: item.contract,\r\n ...(item.replacement === undefined ? {} : { replacement: item.replacement as string }),\r\n ...(item.sunsetAt === undefined ? {} : { sunsetAt: item.sunsetAt as string }),\r\n });\r\n }\r\n return {\r\n product: 'cloud', ...(value.productVersion === undefined ? {} : { productVersion: value.productVersion as string }),\r\n contractVersion: '1.0', apiContractVersions: [...value.apiContractVersions],\r\n interpreterContractVersions: [...value.interpreterContractVersions], sdkContractVersions: [...value.sdkContractVersions],\r\n capabilities, deprecations,\r\n };\r\n}\r\n\r\nexport class CapabilitiesClient {\r\n private readonly transport: CloudTransport;\r\n\r\n constructor(resolveClient: () => HttpClient = getClient, config: CloudTransportConfig = {}) {\r\n this.transport = new CloudTransport(resolveClient, config);\r\n }\r\n\r\n /** Workspace comes exclusively from the authenticated key. One POST, no automatic retries or caching. */\r\n async discover(): Promise<CapabilityDiscoverResponse> {\r\n if (arguments.length !== 0) throw new TypeError('Tier0 SDK: capability discovery accepts no arguments.');\r\n let response: Awaited<ReturnType<CloudTransport['post']>>;\r\n try {\r\n response = await this.transport.post('/openapi/v1/capabilities/discover', {});\r\n } catch (error) {\r\n if (!(error instanceof CloudTransportError)) throw error;\r\n throw new CapabilityError('Capability discovery HTTP exchange failed.', {\r\n status: error.status, errorCode: `CAPABILITY_${error.kind}`,\r\n });\r\n }\r\n const { value, status, ok } = response;\r\n if (!ok) {\r\n if (!record(value) || !text(value.errorCode) || typeof value.message !== 'string') {\r\n throw new CapabilityError('Invalid capability error response.', { status, errorCode: 'CAPABILITY_PROTOCOL_ERROR' });\r\n }\r\n throw new CapabilityError(value.message, { status, errorCode: value.errorCode });\r\n }\r\n return discovery(value, status);\r\n }\r\n}\r\n\r\n/** Uses configureClient()/runtime environment, resolving the host and workspace key on every call. */\r\nexport const capabilities = new CapabilitiesClient();\r\n"]}
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/capabilities.ts"],"names":[],"mappings":"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","sourcesContent":["import { CloudTransport, CloudTransportError, type CloudTransportConfig } from './cloud-transport.js';\nimport { getClient, type HttpClient } from './openapi/client.js';\n\nexport type CapabilityCode = 'namespace.v2' | 'source.v1' | 'stream.v2' | 'control.v1' | 'control.invoke.v1';\nexport type CapabilityState = 'disabled' | 'not_supported' | 'unavailable' | 'readiness_unknown' | 'ready';\nexport type CapabilityAvailability = 'unavailable' | 'unknown' | 'available';\n\nexport interface PublicCapability {\n code: CapabilityCode;\n /** Public release and workspace gates; does not establish runtime readiness. */\n releaseEnabled: boolean;\n /** Server-assessed implementation/readiness, never inferred from releaseEnabled. */\n enabled: boolean;\n /** Authorization summary, not a grant for every individual Control code. */\n allowed: boolean;\n state: CapabilityState;\n /** Not device online status or execution/ACK confirmation. */\n availability: CapabilityAvailability;\n contractVersions: string[];\n}\n\nexport interface CapabilityDeprecation {\n contract: string;\n replacement?: string;\n sunsetAt?: string;\n}\n\nexport interface CapabilityDiscoverResponse {\n product: 'cloud';\n /** Trusted server configuration only; absent when unconfigured. */\n productVersion?: string;\n contractVersion: '1.0';\n apiContractVersions: string[];\n interpreterContractVersions: string[];\n /** Public SDK contract labels, not npm package versions. */\n sdkContractVersions: string[];\n capabilities: PublicCapability[];\n deprecations: CapabilityDeprecation[];\n}\n\nexport interface CapabilityErrorInfo {\n status?: number;\n /** Gateway string code (including unknown future codes), or an SDK-local CAPABILITY_* code. */\n errorCode: string;\n}\n\nexport class CapabilityError extends Error {\n readonly status?: number;\n readonly errorCode: string;\n readonly retryable = false;\n\n constructor(message: string, info: CapabilityErrorInfo) {\n super(message);\n this.name = 'CapabilityError';\n this.status = info.status;\n this.errorCode = info.errorCode;\n }\n}\n\nconst contracts: Record<CapabilityCode, string[]> = {\n 'namespace.v2': ['openapi/v2'],\n 'source.v1': ['openapi/v1'],\n 'stream.v2': ['tier0-stream/v2'],\n 'control.v1': ['openapi/v1', 'control/v1'],\n 'control.invoke.v1': ['openapi/v1', 'tier0-stream/v2', 'control/v1'],\n};\n\nfunction record(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\nfunction text(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0;\n}\nfunction strings(value: unknown): value is string[] {\n return Array.isArray(value) && value.every(text) && new Set(value).size === value.length;\n}\n\n/** Validate and explicitly project the frozen contract; unknown capabilities/extension fields are ignored. */\nfunction discovery(value: unknown, status: number): CapabilityDiscoverResponse {\n const fail = (version = false): never => {\n throw new CapabilityError(version ? 'Unsupported capability contract version.' : 'Invalid capability discovery response.', {\n status, errorCode: version ? 'CAPABILITY_UNSUPPORTED_VERSION' : 'CAPABILITY_PROTOCOL_ERROR',\n });\n };\n if (!record(value)) return fail();\n if (!text(value.product) || !text(value.contractVersion) ||\n !strings(value.apiContractVersions) || !strings(value.interpreterContractVersions) || !strings(value.sdkContractVersions) ||\n !Array.isArray(value.capabilities) || !Array.isArray(value.deprecations) ||\n (value.productVersion !== undefined && !text(value.productVersion))) return fail();\n if (value.product !== 'cloud' || value.contractVersion !== '1.0' ||\n !value.apiContractVersions.includes('openapi/v1') ||\n !value.interpreterContractVersions.includes('tier0-stream/v2') ||\n !value.sdkContractVersions.includes('control/v1')) return fail(true);\n\n const capabilities: PublicCapability[] = [];\n const seen = new Set<string>();\n for (const item of value.capabilities) {\n if (!record(item) || !text(item.code)) return fail();\n if (!Object.prototype.hasOwnProperty.call(contracts, item.code)) continue;\n const code = item.code as CapabilityCode;\n if (seen.has(code)) return fail();\n seen.add(code);\n if (typeof item.releaseEnabled !== 'boolean' || typeof item.enabled !== 'boolean' || typeof item.allowed !== 'boolean' ||\n !['disabled', 'not_supported', 'unavailable', 'readiness_unknown', 'ready'].includes(item.state as string) ||\n !['unavailable', 'unknown', 'available'].includes(item.availability as string) || !strings(item.contractVersions)) return fail();\n if (contracts[code].some(version =>\n !(item.contractVersions as string[]).includes(version) ||\n (version.startsWith('openapi/') && !(value.apiContractVersions as string[]).includes(version)))) return fail(true);\n const ready = item.state === 'ready';\n const expectedAvailability = ready ? 'available' : item.state === 'readiness_unknown' ? 'unknown' : 'unavailable';\n if (item.enabled !== ready || item.availability !== expectedAvailability ||\n (ready && (!item.releaseEnabled || !item.allowed)) ||\n (item.state === 'disabled' ? item.releaseEnabled : !item.releaseEnabled)) return fail();\n capabilities.push({\n code, releaseEnabled: item.releaseEnabled, enabled: item.enabled, allowed: item.allowed,\n state: item.state as CapabilityState, availability: item.availability as CapabilityAvailability,\n contractVersions: [...item.contractVersions],\n });\n }\n const deprecations: CapabilityDeprecation[] = [];\n for (const item of value.deprecations) {\n if (!record(item) || !text(item.contract) ||\n (item.replacement !== undefined && !text(item.replacement)) ||\n (item.sunsetAt !== undefined && !text(item.sunsetAt))) return fail();\n deprecations.push({ contract: item.contract,\n ...(item.replacement === undefined ? {} : { replacement: item.replacement as string }),\n ...(item.sunsetAt === undefined ? {} : { sunsetAt: item.sunsetAt as string }),\n });\n }\n return {\n product: 'cloud', ...(value.productVersion === undefined ? {} : { productVersion: value.productVersion as string }),\n contractVersion: '1.0', apiContractVersions: [...value.apiContractVersions],\n interpreterContractVersions: [...value.interpreterContractVersions], sdkContractVersions: [...value.sdkContractVersions],\n capabilities, deprecations,\n };\n}\n\nexport class CapabilitiesClient {\n private readonly transport: CloudTransport;\n\n constructor(resolveClient: () => HttpClient = getClient, config: CloudTransportConfig = {}) {\n this.transport = new CloudTransport(resolveClient, config);\n }\n\n /** Workspace comes exclusively from the authenticated key. One POST, no automatic retries or caching. */\n async discover(): Promise<CapabilityDiscoverResponse> {\n if (arguments.length !== 0) throw new TypeError('Tier0 SDK: capability discovery accepts no arguments.');\n let response: Awaited<ReturnType<CloudTransport['post']>>;\n try {\n response = await this.transport.post('/openapi/v1/capabilities/discover', {});\n } catch (error) {\n if (!(error instanceof CloudTransportError)) throw error;\n throw new CapabilityError('Capability discovery HTTP exchange failed.', {\n status: error.status, errorCode: `CAPABILITY_${error.kind}`,\n });\n }\n const { value, status, ok } = response;\n if (!ok) {\n if (!record(value) || !text(value.errorCode) || typeof value.message !== 'string') {\n throw new CapabilityError('Invalid capability error response.', { status, errorCode: 'CAPABILITY_PROTOCOL_ERROR' });\n }\n throw new CapabilityError(value.message, { status, errorCode: value.errorCode });\n }\n return discovery(value, status);\n }\n}\n\n/** Uses configureClient()/runtime environment, resolving the host and workspace key on every call. */\nexport const capabilities = new CapabilitiesClient();\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"cloud-server.js","sourceRoot":"","sources":["../../src/cloud-server.ts"],"names":[],"mappings":"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","sourcesContent":["// Server-only entry point. Browser HTTP clients remain independent of node:crypto.\r\nimport { createHash, createPublicKey, verify, type KeyObject } from 'node:crypto';\r\nimport { APP_REQUEST_IDENTITY_CONTRACT as contract } from './app-identity-contract.generated.js';\r\n\r\nexport const APP_REQUEST_IDENTITY_HEADER = contract.header;\r\n\r\nexport class AppRequestIdentityError extends Error {\r\n constructor(public readonly code: 'APP_IDENTITY_INVALID' | 'APP_IDENTITY_CONFIGURATION_INVALID') {\r\n super(code);\r\n this.name = 'AppRequestIdentityError';\r\n }\r\n}\r\n\r\nexport interface VerifiedCloudAppUser {\r\n readonly kind: 'gateway-user';\r\n readonly userID: string;\r\n readonly workspaceID: string;\r\n readonly appID: string;\r\n readonly roleKeys: readonly string[];\r\n readonly requestID: string;\r\n readonly issuedAt: number;\r\n readonly expiresAt: number;\r\n readonly verificationKeyID: string;\r\n}\r\n\r\nexport interface CloudAppIdentityAuthority {\r\n appID: string;\r\n workspaceID: string;\r\n /** Pinned server configuration, never a key or URL taken from the request. */\r\n publicKeys: unknown;\r\n}\r\n\r\nexport interface CloudAppIdentityRequest {\r\n assertion: string | undefined;\r\n method: string;\r\n requestURI: string;\r\n /** Exact bytes received from the gateway, before JSON parsing or normalization. */\r\n body: Uint8Array;\r\n}\r\n\r\nconst invalid = () => new AppRequestIdentityError('APP_IDENTITY_INVALID');\r\nconst invalidConfig = () => new AppRequestIdentityError('APP_IDENTITY_CONFIGURATION_INVALID');\r\nconst appPattern = new RegExp(contract.appIDPattern);\r\nconst kidPattern = new RegExp(contract.keyIDPattern);\r\nconst methodPattern = new RegExp(contract.methodPattern);\r\nconst maxID = BigInt('9223372036854775807');\r\nconst validID = (value: unknown): value is string =>\r\n typeof value === 'string' && /^[1-9]\\d{0,18}$/.test(value) && BigInt(value) <= maxID;\r\nconst isObject = (value: unknown): value is Record<string, unknown> =>\r\n !!value && typeof value === 'object' && !Array.isArray(value);\r\nconst exactKeys = (value: Record<string, unknown>, keys: readonly string[]) =>\r\n Object.keys(value).length === keys.length && Object.keys(value).every((key) => keys.includes(key));\r\nconst validString = (value: unknown, maxBytes: number): value is string =>\r\n typeof value === 'string' && value.length > 0 && Buffer.byteLength(value) <= maxBytes &&\r\n Buffer.from(value).toString('utf8') === value && !/[\\u0000-\\u001f\\u007f-\\u009f]/.test(value);\r\nconst decode = (value: string) => {\r\n if (!/^[A-Za-z0-9_-]+$/.test(value)) throw invalid();\r\n const bytes = Buffer.from(value, 'base64url');\r\n if (bytes.toString('base64url') !== value) throw invalid();\r\n return bytes;\r\n};\r\n\r\n/** Verifies request provenance, not business authorization or delegated UNS permissions. */\r\nexport function createCloudAppRequestVerifier(authority: CloudAppIdentityAuthority) {\r\n if (!isObject(authority) || typeof authority.appID !== 'string' || !appPattern.test(authority.appID) || !validID(authority.workspaceID)) throw invalidConfig();\r\n const appID = authority.appID;\r\n const workspaceID = authority.workspaceID;\r\n const keys = new Map<string, KeyObject>();\r\n try {\r\n let raw = authority.publicKeys;\r\n if (typeof raw === 'string') {\r\n if (Buffer.byteLength(raw) > contract.maxTokenBytes * contract.maxKeys) throw invalidConfig();\r\n raw = JSON.parse(raw);\r\n }\r\n if (!isObject(raw) || !exactKeys(raw, ['keys']) || !Array.isArray(raw.keys) ||\r\n raw.keys.length === 0 || raw.keys.length > contract.maxKeys) throw invalidConfig();\r\n for (const key of raw.keys) {\r\n if (!isObject(key) || !exactKeys(key, contract.publicKeyFields) || key.kty !== 'OKP' ||\r\n key.crv !== 'Ed25519' || typeof key.kid !== 'string' || !kidPattern.test(key.kid) ||\r\n keys.has(key.kid) || typeof key.x !== 'string' || decode(key.x).length !== 32) throw invalidConfig();\r\n keys.set(key.kid, createPublicKey({ key: { kty: 'OKP', crv: 'Ed25519', x: key.x }, format: 'jwk' }));\r\n }\r\n } catch { throw invalidConfig(); }\r\n\r\n return (request: CloudAppIdentityRequest): VerifiedCloudAppUser => {\r\n try {\r\n if (typeof request.assertion !== 'string' || Buffer.byteLength(request.assertion) > contract.maxTokenBytes ||\r\n !(request.body instanceof Uint8Array) || request.body.byteLength > contract.maxBodyBytes ||\r\n !methodPattern.test(request.method) || !validString(request.requestURI, contract.maxURIBytes) ||\r\n !request.requestURI.startsWith('/') || request.requestURI.startsWith('//')) throw invalid();\r\n const parts = request.assertion.split('.');\r\n if (parts.length !== 3) throw invalid();\r\n const header: unknown = JSON.parse(decode(parts[0]).toString('utf8'));\r\n if (!isObject(header) || !exactKeys(header, contract.requiredHeaderFields) ||\r\n header.alg !== contract.algorithm || header.typ !== contract.type ||\r\n typeof header.kid !== 'string' || !kidPattern.test(header.kid)) throw invalid();\r\n const key = keys.get(header.kid);\r\n const signature = decode(parts[2]);\r\n if (!key || signature.length !== 64 ||\r\n !verify(null, Buffer.from(parts[0] + '.' + parts[1], 'ascii'), key, signature)) throw invalid();\r\n const claims: unknown = JSON.parse(decode(parts[1]).toString('utf8'));\r\n if (!isObject(claims) || !exactKeys(claims, contract.requiredClaims) ||\r\n claims.ver !== contract.version || claims.iss !== contract.issuer || claims.aud !== contract.audience ||\r\n !validID(claims.sub) || claims.workspaceID !== workspaceID || claims.appID !== appID ||\r\n claims.method !== request.method || claims.requestURI !== request.requestURI ||\r\n typeof claims.bodySHA256 !== 'string' || !/^[a-f0-9]{64}$/.test(claims.bodySHA256) ||\r\n claims.bodySHA256 !== createHash('sha256').update(request.body).digest('hex') ||\r\n typeof claims.iat !== 'number' || !Number.isSafeInteger(claims.iat) || claims.iat <= 0 ||\r\n typeof claims.exp !== 'number' || !Number.isSafeInteger(claims.exp) || claims.exp <= claims.iat ||\r\n claims.exp - claims.iat > contract.maxTTLSeconds ||\r\n typeof claims.jti !== 'string' || !/^[a-f0-9]{32}$/.test(claims.jti) ||\r\n !Array.isArray(claims.roles) || claims.roles.length > contract.maxRoles ||\r\n claims.roles.some((role) => !validString(role, contract.maxRoleBytes) || role.trim() !== role) ||\r\n new Set(claims.roles).size !== claims.roles.length) throw invalid();\r\n const now = Math.floor(Date.now() / 1000);\r\n if (claims.iat > now + contract.clockSkewSeconds || now >= claims.exp + contract.clockSkewSeconds) throw invalid();\r\n return Object.freeze({\r\n kind: 'gateway-user' as const, userID: claims.sub, workspaceID, appID,\r\n roleKeys: Object.freeze([...claims.roles] as string[]), requestID: claims.jti,\r\n issuedAt: claims.iat, expiresAt: claims.exp, verificationKeyID: header.kid,\r\n });\r\n } catch { throw invalid(); }\r\n };\r\n}\r\n"]}
1
+ {"version":3,"file":"cloud-server.js","sourceRoot":"","sources":["../../src/cloud-server.ts"],"names":[],"mappings":";;;AA+DA,sEA4DC;AA3HD,mFAAmF;AACnF,6CAAkF;AAClF,6FAAiG;AAEpF,QAAA,2BAA2B,GAAG,kEAAQ,CAAC,MAAM,CAAC;AAE3D,MAAa,uBAAwB,SAAQ,KAAK;IACpB;IAA5B,YAA4B,IAAmE;QAC7F,KAAK,CAAC,IAAI,CAAC,CAAC;QADc,SAAI,GAAJ,IAAI,CAA+D;QAE7F,IAAI,CAAC,IAAI,GAAG,yBAAyB,CAAC;IACxC,CAAC;CACF;AALD,0DAKC;AA6BD,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,IAAI,uBAAuB,CAAC,sBAAsB,CAAC,CAAC;AAC1E,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,IAAI,uBAAuB,CAAC,oCAAoC,CAAC,CAAC;AAC9F,MAAM,UAAU,GAAG,IAAI,MAAM,CAAC,kEAAQ,CAAC,YAAY,CAAC,CAAC;AACrD,MAAM,UAAU,GAAG,IAAI,MAAM,CAAC,kEAAQ,CAAC,YAAY,CAAC,CAAC;AACrD,MAAM,aAAa,GAAG,IAAI,MAAM,CAAC,kEAAQ,CAAC,aAAa,CAAC,CAAC;AACzD,MAAM,KAAK,GAAG,MAAM,CAAC,qBAAqB,CAAC,CAAC;AAC5C,MAAM,OAAO,GAAG,CAAC,KAAc,EAAmB,EAAE,CAClD,OAAO,KAAK,KAAK,QAAQ,IAAI,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC;AACvF,MAAM,QAAQ,GAAG,CAAC,KAAc,EAAoC,EAAE,CACpE,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAChE,MAAM,SAAS,GAAG,CAAC,KAA8B,EAAE,IAAuB,EAAE,EAAE,CAC5E,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;AACrG,MAAM,WAAW,GAAG,CAAC,KAAc,EAAE,QAAgB,EAAmB,EAAE,CACxE,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,QAAQ;IACrF,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,8BAA8B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC/F,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,EAAE;IAC/B,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,OAAO,EAAE,CAAC;IACrD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IAC9C,IAAI,KAAK,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,KAAK;QAAE,MAAM,OAAO,EAAE,CAAC;IAC3D,OAAO,KAAK,CAAC;AACf,CAAC,CAAC;AAEF,4FAA4F;AAC5F,SAAgB,6BAA6B,CAAC,SAAoC;IAChF,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,OAAO,SAAS,CAAC,KAAK,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC;QAAE,MAAM,aAAa,EAAE,CAAC;IAC/J,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC;IAC9B,MAAM,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC;IAC1C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC1C,IAAI,CAAC;QACH,IAAI,GAAG,GAAG,SAAS,CAAC,UAAU,CAAC;QAC/B,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;YAC5B,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,kEAAQ,CAAC,aAAa,GAAG,kEAAQ,CAAC,OAAO;gBAAE,MAAM,aAAa,EAAE,CAAC;YAC9F,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;YACvE,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,kEAAQ,CAAC,OAAO;YAAE,MAAM,aAAa,EAAE,CAAC;QACvF,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;YAC3B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,kEAAQ,CAAC,eAAe,CAAC,IAAI,GAAG,CAAC,GAAG,KAAK,KAAK;gBAChF,GAAG,CAAC,GAAG,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;gBACjF,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,EAAE;gBAAE,MAAM,aAAa,EAAE,CAAC;YACzG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,IAAA,6BAAe,EAAC,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QACvG,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QAAC,MAAM,aAAa,EAAE,CAAC;IAAC,CAAC;IAElC,OAAO,CAAC,OAAgC,EAAwB,EAAE;QAChE,IAAI,CAAC;YACH,IAAI,OAAO,OAAO,CAAC,SAAS,KAAK,QAAQ,IAAI,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,kEAAQ,CAAC,aAAa;gBACtG,CAAC,CAAC,OAAO,CAAC,IAAI,YAAY,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,UAAU,GAAG,kEAAQ,CAAC,YAAY;gBACxF,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,UAAU,EAAE,kEAAQ,CAAC,WAAW,CAAC;gBAC7F,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC;gBAAE,MAAM,OAAO,EAAE,CAAC;YAChG,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC3C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;gBAAE,MAAM,OAAO,EAAE,CAAC;YACxC,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;YACtE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,kEAAQ,CAAC,oBAAoB,CAAC;gBACtE,MAAM,CAAC,GAAG,KAAK,kEAAQ,CAAC,SAAS,IAAI,MAAM,CAAC,GAAG,KAAK,kEAAQ,CAAC,IAAI;gBACjE,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;gBAAE,MAAM,OAAO,EAAE,CAAC;YACpF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjC,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;YACnC,IAAI,CAAC,GAAG,IAAI,SAAS,CAAC,MAAM,KAAK,EAAE;gBAC/B,CAAC,IAAA,oBAAM,EAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC;gBAAE,MAAM,OAAO,EAAE,CAAC;YACpG,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;YACtE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,kEAAQ,CAAC,cAAc,CAAC;gBAChE,MAAM,CAAC,GAAG,KAAK,kEAAQ,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,KAAK,kEAAQ,CAAC,MAAM,IAAI,MAAM,CAAC,GAAG,KAAK,kEAAQ,CAAC,QAAQ;gBACrG,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,WAAW,KAAK,WAAW,IAAI,MAAM,CAAC,KAAK,KAAK,KAAK;gBACpF,MAAM,CAAC,MAAM,KAAK,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC,UAAU,KAAK,OAAO,CAAC,UAAU;gBAC5E,OAAO,MAAM,CAAC,UAAU,KAAK,QAAQ,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;gBAClF,MAAM,CAAC,UAAU,KAAK,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;gBAC7E,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,IAAI,CAAC;gBACtF,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,GAAG;gBAC/F,MAAM,CAAC,GAAG,GAAG,MAAM,CAAC,GAAG,GAAG,kEAAQ,CAAC,aAAa;gBAChD,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;gBACpE,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,kEAAQ,CAAC,QAAQ;gBACvE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,kEAAQ,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC;gBAC9F,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,KAAK,CAAC,MAAM;gBAAE,MAAM,OAAO,EAAE,CAAC;YACxE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;YAC1C,IAAI,MAAM,CAAC,GAAG,GAAG,GAAG,GAAG,kEAAQ,CAAC,gBAAgB,IAAI,GAAG,IAAI,MAAM,CAAC,GAAG,GAAG,kEAAQ,CAAC,gBAAgB;gBAAE,MAAM,OAAO,EAAE,CAAC;YACnH,OAAO,MAAM,CAAC,MAAM,CAAC;gBACnB,IAAI,EAAE,cAAuB,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK;gBACrE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAa,CAAC,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG;gBAC7E,QAAQ,EAAE,MAAM,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,EAAE,iBAAiB,EAAE,MAAM,CAAC,GAAG;aAC3E,CAAC,CAAC;QACL,CAAC;QAAC,MAAM,CAAC;YAAC,MAAM,OAAO,EAAE,CAAC;QAAC,CAAC;IAC9B,CAAC,CAAC;AACJ,CAAC","sourcesContent":["// Server-only entry point. Browser HTTP clients remain independent of node:crypto.\nimport { createHash, createPublicKey, verify, type KeyObject } from 'node:crypto';\nimport { APP_REQUEST_IDENTITY_CONTRACT as contract } from './app-identity-contract.generated.js';\n\nexport const APP_REQUEST_IDENTITY_HEADER = contract.header;\n\nexport class AppRequestIdentityError extends Error {\n constructor(public readonly code: 'APP_IDENTITY_INVALID' | 'APP_IDENTITY_CONFIGURATION_INVALID') {\n super(code);\n this.name = 'AppRequestIdentityError';\n }\n}\n\nexport interface VerifiedCloudAppUser {\n readonly kind: 'gateway-user';\n readonly userID: string;\n readonly workspaceID: string;\n readonly appID: string;\n readonly roleKeys: readonly string[];\n readonly requestID: string;\n readonly issuedAt: number;\n readonly expiresAt: number;\n readonly verificationKeyID: string;\n}\n\nexport interface CloudAppIdentityAuthority {\n appID: string;\n workspaceID: string;\n /** Pinned server configuration, never a key or URL taken from the request. */\n publicKeys: unknown;\n}\n\nexport interface CloudAppIdentityRequest {\n assertion: string | undefined;\n method: string;\n requestURI: string;\n /** Exact bytes received from the gateway, before JSON parsing or normalization. */\n body: Uint8Array;\n}\n\nconst invalid = () => new AppRequestIdentityError('APP_IDENTITY_INVALID');\nconst invalidConfig = () => new AppRequestIdentityError('APP_IDENTITY_CONFIGURATION_INVALID');\nconst appPattern = new RegExp(contract.appIDPattern);\nconst kidPattern = new RegExp(contract.keyIDPattern);\nconst methodPattern = new RegExp(contract.methodPattern);\nconst maxID = BigInt('9223372036854775807');\nconst validID = (value: unknown): value is string =>\n typeof value === 'string' && /^[1-9]\\d{0,18}$/.test(value) && BigInt(value) <= maxID;\nconst isObject = (value: unknown): value is Record<string, unknown> =>\n !!value && typeof value === 'object' && !Array.isArray(value);\nconst exactKeys = (value: Record<string, unknown>, keys: readonly string[]) =>\n Object.keys(value).length === keys.length && Object.keys(value).every((key) => keys.includes(key));\nconst validString = (value: unknown, maxBytes: number): value is string =>\n typeof value === 'string' && value.length > 0 && Buffer.byteLength(value) <= maxBytes &&\n Buffer.from(value).toString('utf8') === value && !/[\\u0000-\\u001f\\u007f-\\u009f]/.test(value);\nconst decode = (value: string) => {\n if (!/^[A-Za-z0-9_-]+$/.test(value)) throw invalid();\n const bytes = Buffer.from(value, 'base64url');\n if (bytes.toString('base64url') !== value) throw invalid();\n return bytes;\n};\n\n/** Verifies request provenance, not business authorization or delegated UNS permissions. */\nexport function createCloudAppRequestVerifier(authority: CloudAppIdentityAuthority) {\n if (!isObject(authority) || typeof authority.appID !== 'string' || !appPattern.test(authority.appID) || !validID(authority.workspaceID)) throw invalidConfig();\n const appID = authority.appID;\n const workspaceID = authority.workspaceID;\n const keys = new Map<string, KeyObject>();\n try {\n let raw = authority.publicKeys;\n if (typeof raw === 'string') {\n if (Buffer.byteLength(raw) > contract.maxTokenBytes * contract.maxKeys) throw invalidConfig();\n raw = JSON.parse(raw);\n }\n if (!isObject(raw) || !exactKeys(raw, ['keys']) || !Array.isArray(raw.keys) ||\n raw.keys.length === 0 || raw.keys.length > contract.maxKeys) throw invalidConfig();\n for (const key of raw.keys) {\n if (!isObject(key) || !exactKeys(key, contract.publicKeyFields) || key.kty !== 'OKP' ||\n key.crv !== 'Ed25519' || typeof key.kid !== 'string' || !kidPattern.test(key.kid) ||\n keys.has(key.kid) || typeof key.x !== 'string' || decode(key.x).length !== 32) throw invalidConfig();\n keys.set(key.kid, createPublicKey({ key: { kty: 'OKP', crv: 'Ed25519', x: key.x }, format: 'jwk' }));\n }\n } catch { throw invalidConfig(); }\n\n return (request: CloudAppIdentityRequest): VerifiedCloudAppUser => {\n try {\n if (typeof request.assertion !== 'string' || Buffer.byteLength(request.assertion) > contract.maxTokenBytes ||\n !(request.body instanceof Uint8Array) || request.body.byteLength > contract.maxBodyBytes ||\n !methodPattern.test(request.method) || !validString(request.requestURI, contract.maxURIBytes) ||\n !request.requestURI.startsWith('/') || request.requestURI.startsWith('//')) throw invalid();\n const parts = request.assertion.split('.');\n if (parts.length !== 3) throw invalid();\n const header: unknown = JSON.parse(decode(parts[0]).toString('utf8'));\n if (!isObject(header) || !exactKeys(header, contract.requiredHeaderFields) ||\n header.alg !== contract.algorithm || header.typ !== contract.type ||\n typeof header.kid !== 'string' || !kidPattern.test(header.kid)) throw invalid();\n const key = keys.get(header.kid);\n const signature = decode(parts[2]);\n if (!key || signature.length !== 64 ||\n !verify(null, Buffer.from(parts[0] + '.' + parts[1], 'ascii'), key, signature)) throw invalid();\n const claims: unknown = JSON.parse(decode(parts[1]).toString('utf8'));\n if (!isObject(claims) || !exactKeys(claims, contract.requiredClaims) ||\n claims.ver !== contract.version || claims.iss !== contract.issuer || claims.aud !== contract.audience ||\n !validID(claims.sub) || claims.workspaceID !== workspaceID || claims.appID !== appID ||\n claims.method !== request.method || claims.requestURI !== request.requestURI ||\n typeof claims.bodySHA256 !== 'string' || !/^[a-f0-9]{64}$/.test(claims.bodySHA256) ||\n claims.bodySHA256 !== createHash('sha256').update(request.body).digest('hex') ||\n typeof claims.iat !== 'number' || !Number.isSafeInteger(claims.iat) || claims.iat <= 0 ||\n typeof claims.exp !== 'number' || !Number.isSafeInteger(claims.exp) || claims.exp <= claims.iat ||\n claims.exp - claims.iat > contract.maxTTLSeconds ||\n typeof claims.jti !== 'string' || !/^[a-f0-9]{32}$/.test(claims.jti) ||\n !Array.isArray(claims.roles) || claims.roles.length > contract.maxRoles ||\n claims.roles.some((role) => !validString(role, contract.maxRoleBytes) || role.trim() !== role) ||\n new Set(claims.roles).size !== claims.roles.length) throw invalid();\n const now = Math.floor(Date.now() / 1000);\n if (claims.iat > now + contract.clockSkewSeconds || now >= claims.exp + contract.clockSkewSeconds) throw invalid();\n return Object.freeze({\n kind: 'gateway-user' as const, userID: claims.sub, workspaceID, appID,\n roleKeys: Object.freeze([...claims.roles] as string[]), requestID: claims.jti,\n issuedAt: claims.iat, expiresAt: claims.exp, verificationKeyID: header.kid,\n });\n } catch { throw invalid(); }\n };\n}\n"]}
@@ -32,10 +32,31 @@ export declare class CloudTransport {
32
32
  private readonly timeoutMs;
33
33
  private readonly unsV2MaxResponseBytes;
34
34
  constructor(resolveClient?: () => HttpClient, config?: CloudTransportConfig);
35
+ /** `retryAfter`: the raw `Retry-After` header, for answers without a UNS error body. */
35
36
  postText(path: string, body: string, options?: RequestOptions): Promise<{
36
37
  text: string;
37
38
  status: number;
38
39
  ok: boolean;
40
+ retryAfter?: string;
41
+ }>;
42
+ /**
43
+ * Opens a server-sent event stream (GET, `Accept: text/event-stream`
44
+ * exactly, as the gateway requires). The deadline covers the response
45
+ * headers, and a non-stream body; a response that is not an event stream
46
+ * is read whole (bounded like any UNS v2 response) and returned as `text`.
47
+ * An open stream belongs to the caller: `close()` ends it and drops the
48
+ * link to `signal`, which also ends it.
49
+ */
50
+ getEventStream(path: string, options?: {
51
+ lastEventId?: string;
52
+ signal?: AbortSignal;
53
+ }): Promise<{
54
+ status: number;
55
+ stream: ReadableStream<Uint8Array>;
56
+ close(): void;
57
+ } | {
58
+ status: number;
59
+ text: string;
39
60
  }>;
40
61
  post(path: string, body: unknown): Promise<{
41
62
  value: unknown;
@@ -45,6 +45,7 @@ class CloudTransport {
45
45
  }
46
46
  this.#unsV2AppDataSubject = subject;
47
47
  }
48
+ /** `retryAfter`: the raw `Retry-After` header, for answers without a UNS error body. */
48
49
  async postText(path, body, options = {}) {
49
50
  options.signal?.throwIfAborted();
50
51
  const client = this.resolveClient();
@@ -116,7 +117,8 @@ class CloudTransport {
116
117
  reader.releaseLock();
117
118
  reader = undefined;
118
119
  }
119
- return { text: chunks.join(''), status: response.status, ok: response.ok };
120
+ const retryAfter = response.headers.get('retry-after') ?? undefined;
121
+ return { text: chunks.join(''), status: response.status, ok: response.ok, ...(retryAfter === undefined ? {} : { retryAfter }) };
120
122
  };
121
123
  try {
122
124
  const deadline = new Promise((_resolve, reject) => {
@@ -139,6 +141,84 @@ class CloudTransport {
139
141
  options.signal?.removeEventListener('abort', onAbort);
140
142
  }
141
143
  }
144
+ /**
145
+ * Opens a server-sent event stream (GET, `Accept: text/event-stream`
146
+ * exactly, as the gateway requires). The deadline covers the response
147
+ * headers, and a non-stream body; a response that is not an event stream
148
+ * is read whole (bounded like any UNS v2 response) and returned as `text`.
149
+ * An open stream belongs to the caller: `close()` ends it and drops the
150
+ * link to `signal`, which also ends it.
151
+ */
152
+ async getEventStream(path, options = {}) {
153
+ options.signal?.throwIfAborted();
154
+ const client = this.resolveClient();
155
+ const url = `${client.getBaseURL()}${path}`;
156
+ const key = client.getApiKey();
157
+ const headers = { Accept: 'text/event-stream' };
158
+ if (path.startsWith('/openapi/v2/uns/') && this.#unsV2AppDataSubject !== undefined) {
159
+ headers[exports.UNS_V2_APP_DATA_SUBJECT_HEADER] = this.#unsV2AppDataSubject;
160
+ }
161
+ if (options.lastEventId !== undefined)
162
+ headers['Last-Event-ID'] = options.lastEventId;
163
+ if (key) {
164
+ headers.Authorization = `Bearer ${key}`;
165
+ headers['X-API-Key'] = key;
166
+ }
167
+ const controller = new AbortController();
168
+ const onAbort = () => controller.abort();
169
+ const close = () => {
170
+ options.signal?.removeEventListener('abort', onAbort);
171
+ controller.abort();
172
+ };
173
+ options.signal?.addEventListener('abort', onAbort, { once: true });
174
+ let expired = false;
175
+ const timer = setTimeout(() => { expired = true; controller.abort(); }, this.timeoutMs);
176
+ const failure = (kind, status) => new CloudTransportError(expired ? 'TRANSPORT_TIMEOUT' : controller.signal.aborted ? 'TRANSPORT_ABORTED' : kind, status);
177
+ let response;
178
+ try {
179
+ response = await client.getFetch()(url, { method: 'GET', headers, redirect: 'manual', signal: controller.signal });
180
+ }
181
+ catch {
182
+ clearTimeout(timer);
183
+ close();
184
+ throw failure('TRANSPORT_ERROR');
185
+ }
186
+ const type = response.headers.get('content-type') ?? '';
187
+ if (response.status === 200 && /^text\/event-stream\b/i.test(type) && response.body) {
188
+ clearTimeout(timer);
189
+ return { status: response.status, stream: response.body, close };
190
+ }
191
+ try {
192
+ if (!response.body)
193
+ return { status: response.status, text: '' };
194
+ const reader = response.body.getReader();
195
+ const decoder = new TextDecoder('utf-8', { fatal: true });
196
+ const chunks = [];
197
+ let size = 0;
198
+ while (true) {
199
+ const { done, value } = await reader.read();
200
+ if (done)
201
+ break;
202
+ size += value.byteLength;
203
+ if (size > this.unsV2MaxResponseBytes) {
204
+ await reader.cancel().catch(() => undefined);
205
+ throw new CloudTransportError('PROTOCOL_ERROR', response.status);
206
+ }
207
+ chunks.push(decoder.decode(value, { stream: true }));
208
+ }
209
+ chunks.push(decoder.decode());
210
+ return { status: response.status, text: chunks.join('') };
211
+ }
212
+ catch (error) {
213
+ if (error instanceof CloudTransportError)
214
+ throw error;
215
+ throw failure('PROTOCOL_ERROR', response.status);
216
+ }
217
+ finally {
218
+ clearTimeout(timer);
219
+ close();
220
+ }
221
+ }
142
222
  async post(path, body) {
143
223
  const client = this.resolveClient();
144
224
  const url = `${client.getBaseURL()}${path}`;
@@ -1 +1 @@
1
- {"version":3,"file":"cloud-transport.js","sourceRoot":"","sources":["../../src/cloud-transport.ts"],"names":[],"mappings":"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","sourcesContent":["import { getClient, type HttpClient, type RequestOptions } from './openapi/client.js';\n\nexport interface CloudTransportConfig {\n /** Whole HTTP exchange including the response body, in milliseconds; default 60,000. */\n transportTimeoutMs?: number;\n /** UNS v2 response body limit; may only tighten the 20 MiB contract/RPC ceiling. */\n unsV2MaxResponseBytes?: number;\n /**\n * Opaque proof from the trusted App Gateway only: tier0.app-data-subject/v1,\n * X-Tier0-App-Data-Subject, aud tier0-uns-data. Proof alone is not authentication;\n * the SDK checks only compact syntax, never parses or trusts claims.\n * Create a new client per incoming request; never reuse a token across users.\n * Do not automatically forward the runtime App request assertion: its audience differs.\n */\n unsV2AppDataSubject?: string;\n}\n\nexport const DEFAULT_CLOUD_TRANSPORT_TIMEOUT_MS = 60_000;\n/** Header carrying `unsV2AppDataSubject`; the trusted App Gateway sets it on each business request. */\nexport const UNS_V2_APP_DATA_SUBJECT_HEADER = 'X-Tier0-App-Data-Subject';\nexport const UNS_V2_MAX_REQUEST_BYTES = 16 << 20;\nexport const UNS_V2_MAX_RESPONSE_BYTES = 20 << 20;\n\ntype Failure = 'TRANSPORT_ERROR' | 'PROTOCOL_ERROR' | 'TRANSPORT_TIMEOUT' | 'TRANSPORT_ABORTED';\n\n/** Internal redacted failure, translated by each public contract client. */\nexport class CloudTransportError extends Error {\n constructor(readonly kind: Failure, readonly status?: number) {\n super(kind);\n this.name = 'CloudTransportError';\n }\n}\n\n/** Single fetch, no redirects/retries; one deadline covers both headers and body. */\nexport class CloudTransport {\n private readonly timeoutMs: number;\n private readonly unsV2MaxResponseBytes: number;\n readonly #unsV2AppDataSubject: string | undefined;\n\n constructor(private readonly resolveClient: () => HttpClient = getClient, config: CloudTransportConfig = {}) {\n const timeout = config.transportTimeoutMs ?? DEFAULT_CLOUD_TRANSPORT_TIMEOUT_MS;\n if (!Number.isInteger(timeout) || timeout < 1 || timeout > 2_147_483_647) {\n throw new TypeError('Tier0 SDK: transportTimeoutMs must be an integer between 1 and 2147483647.');\n }\n this.timeoutMs = timeout;\n const maxResponseBytes = config.unsV2MaxResponseBytes ?? UNS_V2_MAX_RESPONSE_BYTES;\n if (!Number.isInteger(maxResponseBytes) || maxResponseBytes < 1 || maxResponseBytes > UNS_V2_MAX_RESPONSE_BYTES) {\n throw new TypeError('Tier0 SDK: unsV2MaxResponseBytes must be an integer between 1 and 20971520.');\n }\n this.unsV2MaxResponseBytes = maxResponseBytes;\n const subject = config.unsV2AppDataSubject;\n // ASCII-only syntax makes string length equal byte length. Do not trim or decode.\n if (subject !== undefined && (typeof subject !== 'string' || subject.length > 8192 || /[^A-Za-z0-9_.-]/.test(subject) ||\n !/^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$/.test(subject))) {\n throw new TypeError('Tier0 SDK: unsV2AppDataSubject must be a compact three-segment base64url token of at most 8192 ASCII bytes.');\n }\n this.#unsV2AppDataSubject = subject;\n }\n\n async postText(path: string, body: string, options: RequestOptions = {}): Promise<{ text: string; status: number; ok: boolean }> {\n options.signal?.throwIfAborted();\n const client = this.resolveClient();\n const url = `${client.getBaseURL()}${path}`;\n const key = client.getApiKey();\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n // Control routes also live under UNS v2, but must never receive data delegation.\n // Keep this per-client proof out of shared HTTP headers and Control capabilities.\n if (path.startsWith('/openapi/v2/uns/') &&\n !path.startsWith('/openapi/v2/uns/controls/') &&\n path !== '/openapi/v2/uns/streams/runtime/capabilities/get' &&\n this.#unsV2AppDataSubject !== undefined) {\n headers[UNS_V2_APP_DATA_SUBJECT_HEADER] = this.#unsV2AppDataSubject;\n }\n if (key) {\n headers.Authorization = `Bearer ${key}`;\n headers['X-API-Key'] = key;\n }\n const controller = new AbortController();\n let response: Response | undefined;\n let reader: ReadableStreamDefaultReader<Uint8Array> | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let rejectAbort: (error: Error) => void = () => undefined;\n const cancelled = new Promise<never>((_, reject) => { rejectAbort = reject; });\n const onAbort = () => {\n controller.abort();\n void reader?.cancel().catch(() => undefined);\n rejectAbort(new CloudTransportError('TRANSPORT_ABORTED', response?.status));\n };\n options.signal?.addEventListener('abort', onAbort, { once: true });\n const exchange = async () => {\n try {\n response = await client.getFetch()(url, { method: 'POST', headers, body, redirect: 'manual', signal: controller.signal });\n } catch {\n throw new CloudTransportError('TRANSPORT_ERROR');\n }\n const declaredLength = response.headers.get('content-length');\n if (declaredLength !== null && /^\\d+$/.test(declaredLength) && Number(declaredLength) > this.unsV2MaxResponseBytes) {\n await response.body?.cancel().catch(() => undefined);\n throw new CloudTransportError('PROTOCOL_ERROR', response.status);\n }\n if (!response.body) throw new CloudTransportError('PROTOCOL_ERROR', response.status);\n reader = response.body.getReader();\n const decoder = new TextDecoder('utf-8', { fatal: true });\n const chunks: string[] = [];\n let receivedBytes = 0;\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n receivedBytes += value.byteLength;\n if (receivedBytes > this.unsV2MaxResponseBytes) {\n await reader.cancel().catch(() => undefined);\n throw new CloudTransportError('PROTOCOL_ERROR', response.status);\n }\n chunks.push(decoder.decode(value, { stream: true }));\n }\n chunks.push(decoder.decode());\n } catch (error) {\n if (error instanceof CloudTransportError) throw error;\n throw new CloudTransportError('PROTOCOL_ERROR', response.status);\n } finally {\n reader.releaseLock();\n reader = undefined;\n }\n return { text: chunks.join(''), status: response.status, ok: response.ok };\n };\n try {\n const deadline = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n controller.abort();\n void reader?.cancel().catch(() => undefined);\n reject(new CloudTransportError('TRANSPORT_TIMEOUT', response?.status));\n }, this.timeoutMs);\n });\n // Also bounds custom transports which ignore AbortSignal.\n return await Promise.race([exchange(), deadline, cancelled]);\n } catch (error) {\n if (controller.signal.aborted) throw new CloudTransportError(options.signal?.aborted ? 'TRANSPORT_ABORTED' : 'TRANSPORT_TIMEOUT', response?.status);\n throw error;\n } finally {\n clearTimeout(timer);\n options.signal?.removeEventListener('abort', onAbort);\n }\n }\n\n async post(path: string, body: unknown): Promise<{ value: unknown; status: number; ok: boolean }> {\n const client = this.resolveClient();\n const url = `${client.getBaseURL()}${path}`;\n const key = client.getApiKey();\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (key) {\n headers.Authorization = `Bearer ${key}`;\n headers['X-API-Key'] = key;\n }\n const serialized = JSON.stringify(body);\n const controller = new AbortController();\n let response: Response | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const exchange = async () => {\n try {\n response = await client.getFetch()(url, { method: 'POST', headers, body: serialized, redirect: 'manual', signal: controller.signal });\n } catch {\n throw new CloudTransportError('TRANSPORT_ERROR');\n }\n let value: unknown;\n try {\n value = await response.json();\n } catch {\n throw new CloudTransportError('PROTOCOL_ERROR', response.status);\n }\n return { value, status: response.status, ok: response.ok };\n };\n try {\n const deadline = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n controller.abort();\n reject(new CloudTransportError('TRANSPORT_TIMEOUT', response?.status));\n }, this.timeoutMs);\n });\n // Also bounds custom transports which ignore AbortSignal.\n return await Promise.race([exchange(), deadline]);\n } catch (error) {\n if (controller.signal.aborted) throw new CloudTransportError('TRANSPORT_TIMEOUT', response?.status);\n throw error;\n } finally {\n clearTimeout(timer);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"cloud-transport.js","sourceRoot":"","sources":["../../src/cloud-transport.ts"],"names":[],"mappings":"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","sourcesContent":["import { getClient, type HttpClient, type RequestOptions } from './openapi/client.js';\n\nexport interface CloudTransportConfig {\n /** Whole HTTP exchange including the response body, in milliseconds; default 60,000. */\n transportTimeoutMs?: number;\n /** UNS v2 response body limit; may only tighten the 20 MiB contract/RPC ceiling. */\n unsV2MaxResponseBytes?: number;\n /**\n * Opaque proof from the trusted App Gateway only: tier0.app-data-subject/v1,\n * X-Tier0-App-Data-Subject, aud tier0-uns-data. Proof alone is not authentication;\n * the SDK checks only compact syntax, never parses or trusts claims.\n * Create a new client per incoming request; never reuse a token across users.\n * Do not automatically forward the runtime App request assertion: its audience differs.\n */\n unsV2AppDataSubject?: string;\n}\n\nexport const DEFAULT_CLOUD_TRANSPORT_TIMEOUT_MS = 60_000;\n/** Header carrying `unsV2AppDataSubject`; the trusted App Gateway sets it on each business request. */\nexport const UNS_V2_APP_DATA_SUBJECT_HEADER = 'X-Tier0-App-Data-Subject';\nexport const UNS_V2_MAX_REQUEST_BYTES = 16 << 20;\nexport const UNS_V2_MAX_RESPONSE_BYTES = 20 << 20;\n\ntype Failure = 'TRANSPORT_ERROR' | 'PROTOCOL_ERROR' | 'TRANSPORT_TIMEOUT' | 'TRANSPORT_ABORTED';\n\n/** Internal redacted failure, translated by each public contract client. */\nexport class CloudTransportError extends Error {\n constructor(readonly kind: Failure, readonly status?: number) {\n super(kind);\n this.name = 'CloudTransportError';\n }\n}\n\n/** Single fetch, no redirects/retries; one deadline covers both headers and body. */\nexport class CloudTransport {\n private readonly timeoutMs: number;\n private readonly unsV2MaxResponseBytes: number;\n readonly #unsV2AppDataSubject: string | undefined;\n\n constructor(private readonly resolveClient: () => HttpClient = getClient, config: CloudTransportConfig = {}) {\n const timeout = config.transportTimeoutMs ?? DEFAULT_CLOUD_TRANSPORT_TIMEOUT_MS;\n if (!Number.isInteger(timeout) || timeout < 1 || timeout > 2_147_483_647) {\n throw new TypeError('Tier0 SDK: transportTimeoutMs must be an integer between 1 and 2147483647.');\n }\n this.timeoutMs = timeout;\n const maxResponseBytes = config.unsV2MaxResponseBytes ?? UNS_V2_MAX_RESPONSE_BYTES;\n if (!Number.isInteger(maxResponseBytes) || maxResponseBytes < 1 || maxResponseBytes > UNS_V2_MAX_RESPONSE_BYTES) {\n throw new TypeError('Tier0 SDK: unsV2MaxResponseBytes must be an integer between 1 and 20971520.');\n }\n this.unsV2MaxResponseBytes = maxResponseBytes;\n const subject = config.unsV2AppDataSubject;\n // ASCII-only syntax makes string length equal byte length. Do not trim or decode.\n if (subject !== undefined && (typeof subject !== 'string' || subject.length > 8192 || /[^A-Za-z0-9_.-]/.test(subject) ||\n !/^[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$/.test(subject))) {\n throw new TypeError('Tier0 SDK: unsV2AppDataSubject must be a compact three-segment base64url token of at most 8192 ASCII bytes.');\n }\n this.#unsV2AppDataSubject = subject;\n }\n\n /** `retryAfter`: the raw `Retry-After` header, for answers without a UNS error body. */\n async postText(path: string, body: string, options: RequestOptions = {}): Promise<{ text: string; status: number; ok: boolean; retryAfter?: string }> {\n options.signal?.throwIfAborted();\n const client = this.resolveClient();\n const url = `${client.getBaseURL()}${path}`;\n const key = client.getApiKey();\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n // Control routes also live under UNS v2, but must never receive data delegation.\n // Keep this per-client proof out of shared HTTP headers and Control capabilities.\n if (path.startsWith('/openapi/v2/uns/') &&\n !path.startsWith('/openapi/v2/uns/controls/') &&\n path !== '/openapi/v2/uns/streams/runtime/capabilities/get' &&\n this.#unsV2AppDataSubject !== undefined) {\n headers[UNS_V2_APP_DATA_SUBJECT_HEADER] = this.#unsV2AppDataSubject;\n }\n if (key) {\n headers.Authorization = `Bearer ${key}`;\n headers['X-API-Key'] = key;\n }\n const controller = new AbortController();\n let response: Response | undefined;\n let reader: ReadableStreamDefaultReader<Uint8Array> | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let rejectAbort: (error: Error) => void = () => undefined;\n const cancelled = new Promise<never>((_, reject) => { rejectAbort = reject; });\n const onAbort = () => {\n controller.abort();\n void reader?.cancel().catch(() => undefined);\n rejectAbort(new CloudTransportError('TRANSPORT_ABORTED', response?.status));\n };\n options.signal?.addEventListener('abort', onAbort, { once: true });\n const exchange = async () => {\n try {\n response = await client.getFetch()(url, { method: 'POST', headers, body, redirect: 'manual', signal: controller.signal });\n } catch {\n throw new CloudTransportError('TRANSPORT_ERROR');\n }\n const declaredLength = response.headers.get('content-length');\n if (declaredLength !== null && /^\\d+$/.test(declaredLength) && Number(declaredLength) > this.unsV2MaxResponseBytes) {\n await response.body?.cancel().catch(() => undefined);\n throw new CloudTransportError('PROTOCOL_ERROR', response.status);\n }\n if (!response.body) throw new CloudTransportError('PROTOCOL_ERROR', response.status);\n reader = response.body.getReader();\n const decoder = new TextDecoder('utf-8', { fatal: true });\n const chunks: string[] = [];\n let receivedBytes = 0;\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n receivedBytes += value.byteLength;\n if (receivedBytes > this.unsV2MaxResponseBytes) {\n await reader.cancel().catch(() => undefined);\n throw new CloudTransportError('PROTOCOL_ERROR', response.status);\n }\n chunks.push(decoder.decode(value, { stream: true }));\n }\n chunks.push(decoder.decode());\n } catch (error) {\n if (error instanceof CloudTransportError) throw error;\n throw new CloudTransportError('PROTOCOL_ERROR', response.status);\n } finally {\n reader.releaseLock();\n reader = undefined;\n }\n const retryAfter = response.headers.get('retry-after') ?? undefined;\n return { text: chunks.join(''), status: response.status, ok: response.ok, ...(retryAfter === undefined ? {} : { retryAfter }) };\n };\n try {\n const deadline = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n controller.abort();\n void reader?.cancel().catch(() => undefined);\n reject(new CloudTransportError('TRANSPORT_TIMEOUT', response?.status));\n }, this.timeoutMs);\n });\n // Also bounds custom transports which ignore AbortSignal.\n return await Promise.race([exchange(), deadline, cancelled]);\n } catch (error) {\n if (controller.signal.aborted) throw new CloudTransportError(options.signal?.aborted ? 'TRANSPORT_ABORTED' : 'TRANSPORT_TIMEOUT', response?.status);\n throw error;\n } finally {\n clearTimeout(timer);\n options.signal?.removeEventListener('abort', onAbort);\n }\n }\n\n /**\n * Opens a server-sent event stream (GET, `Accept: text/event-stream`\n * exactly, as the gateway requires). The deadline covers the response\n * headers, and a non-stream body; a response that is not an event stream\n * is read whole (bounded like any UNS v2 response) and returned as `text`.\n * An open stream belongs to the caller: `close()` ends it and drops the\n * link to `signal`, which also ends it.\n */\n async getEventStream(path: string, options: { lastEventId?: string; signal?: AbortSignal } = {}):\n Promise<{ status: number; stream: ReadableStream<Uint8Array>; close(): void } | { status: number; text: string }> {\n options.signal?.throwIfAborted();\n const client = this.resolveClient();\n const url = `${client.getBaseURL()}${path}`;\n const key = client.getApiKey();\n const headers: Record<string, string> = { Accept: 'text/event-stream' };\n if (path.startsWith('/openapi/v2/uns/') && this.#unsV2AppDataSubject !== undefined) {\n headers[UNS_V2_APP_DATA_SUBJECT_HEADER] = this.#unsV2AppDataSubject;\n }\n if (options.lastEventId !== undefined) headers['Last-Event-ID'] = options.lastEventId;\n if (key) {\n headers.Authorization = `Bearer ${key}`;\n headers['X-API-Key'] = key;\n }\n const controller = new AbortController();\n const onAbort = () => controller.abort();\n const close = () => {\n options.signal?.removeEventListener('abort', onAbort);\n controller.abort();\n };\n options.signal?.addEventListener('abort', onAbort, { once: true });\n let expired = false;\n const timer = setTimeout(() => { expired = true; controller.abort(); }, this.timeoutMs);\n const failure = (kind: Failure, status?: number) =>\n new CloudTransportError(expired ? 'TRANSPORT_TIMEOUT' : controller.signal.aborted ? 'TRANSPORT_ABORTED' : kind, status);\n let response: Response;\n try {\n response = await client.getFetch()(url, { method: 'GET', headers, redirect: 'manual', signal: controller.signal });\n } catch {\n clearTimeout(timer);\n close();\n throw failure('TRANSPORT_ERROR');\n }\n const type = response.headers.get('content-type') ?? '';\n if (response.status === 200 && /^text\\/event-stream\\b/i.test(type) && response.body) {\n clearTimeout(timer);\n return { status: response.status, stream: response.body, close };\n }\n try {\n if (!response.body) return { status: response.status, text: '' };\n const reader = response.body.getReader();\n const decoder = new TextDecoder('utf-8', { fatal: true });\n const chunks: string[] = [];\n let size = 0;\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n size += value.byteLength;\n if (size > this.unsV2MaxResponseBytes) {\n await reader.cancel().catch(() => undefined);\n throw new CloudTransportError('PROTOCOL_ERROR', response.status);\n }\n chunks.push(decoder.decode(value, { stream: true }));\n }\n chunks.push(decoder.decode());\n return { status: response.status, text: chunks.join('') };\n } catch (error) {\n if (error instanceof CloudTransportError) throw error;\n throw failure('PROTOCOL_ERROR', response.status);\n } finally {\n clearTimeout(timer);\n close();\n }\n }\n\n async post(path: string, body: unknown): Promise<{ value: unknown; status: number; ok: boolean }> {\n const client = this.resolveClient();\n const url = `${client.getBaseURL()}${path}`;\n const key = client.getApiKey();\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n if (key) {\n headers.Authorization = `Bearer ${key}`;\n headers['X-API-Key'] = key;\n }\n const serialized = JSON.stringify(body);\n const controller = new AbortController();\n let response: Response | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const exchange = async () => {\n try {\n response = await client.getFetch()(url, { method: 'POST', headers, body: serialized, redirect: 'manual', signal: controller.signal });\n } catch {\n throw new CloudTransportError('TRANSPORT_ERROR');\n }\n let value: unknown;\n try {\n value = await response.json();\n } catch {\n throw new CloudTransportError('PROTOCOL_ERROR', response.status);\n }\n return { value, status: response.status, ok: response.ok };\n };\n try {\n const deadline = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n controller.abort();\n reject(new CloudTransportError('TRANSPORT_TIMEOUT', response?.status));\n }, this.timeoutMs);\n });\n // Also bounds custom transports which ignore AbortSignal.\n return await Promise.race([exchange(), deadline]);\n } catch (error) {\n if (controller.signal.aborted) throw new CloudTransportError('TRANSPORT_TIMEOUT', response?.status);\n throw error;\n } finally {\n clearTimeout(timer);\n }\n }\n}\n"]}