@tier0/sdk-v2 0.0.0-stage → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +7 -0
  3. package/README.md +201 -2
  4. package/dist/cjs/app-identity-contract.generated.d.ts +22 -0
  5. package/dist/cjs/app-identity-contract.generated.js +51 -0
  6. package/dist/cjs/app-identity-contract.generated.js.map +1 -0
  7. package/dist/cjs/capabilities.d.ts +54 -0
  8. package/dist/cjs/capabilities.js +134 -0
  9. package/dist/cjs/capabilities.js.map +1 -0
  10. package/dist/cjs/client.d.ts +604 -0
  11. package/dist/cjs/client.js +35 -0
  12. package/dist/cjs/client.js.map +1 -0
  13. package/dist/cjs/cloud-server.d.ts +31 -0
  14. package/dist/cjs/cloud-server.js +114 -0
  15. package/dist/cjs/cloud-server.js.map +1 -0
  16. package/dist/cjs/cloud-transport.d.ts +67 -0
  17. package/dist/cjs/cloud-transport.js +272 -0
  18. package/dist/cjs/cloud-transport.js.map +1 -0
  19. package/dist/cjs/controls.d.ts +93 -0
  20. package/dist/cjs/controls.js +169 -0
  21. package/dist/cjs/controls.js.map +1 -0
  22. package/dist/cjs/data/bootstrap.d.ts +70 -0
  23. package/dist/cjs/data/bootstrap.js +291 -0
  24. package/dist/cjs/data/bootstrap.js.map +1 -0
  25. package/dist/cjs/data/call.d.ts +33 -0
  26. package/dist/cjs/data/call.js +216 -0
  27. package/dist/cjs/data/call.js.map +1 -0
  28. package/dist/cjs/data/client.d.ts +134 -0
  29. package/dist/cjs/data/client.js +185 -0
  30. package/dist/cjs/data/client.js.map +1 -0
  31. package/dist/cjs/data/collection.d.ts +335 -0
  32. package/dist/cjs/data/collection.js +601 -0
  33. package/dist/cjs/data/collection.js.map +1 -0
  34. package/dist/cjs/data/context.d.ts +12 -0
  35. package/dist/cjs/data/context.js +50 -0
  36. package/dist/cjs/data/context.js.map +1 -0
  37. package/dist/cjs/data/declarations.d.ts +11 -0
  38. package/dist/cjs/data/declarations.js +18 -0
  39. package/dist/cjs/data/declarations.js.map +1 -0
  40. package/dist/cjs/data/define.d.ts +77 -0
  41. package/dist/cjs/data/define.js +31 -0
  42. package/dist/cjs/data/define.js.map +1 -0
  43. package/dist/cjs/data/error.d.ts +78 -0
  44. package/dist/cjs/data/error.js +182 -0
  45. package/dist/cjs/data/error.js.map +1 -0
  46. package/dist/cjs/data/index.d.ts +24 -0
  47. package/dist/cjs/data/index.js +49 -0
  48. package/dist/cjs/data/index.js.map +1 -0
  49. package/dist/cjs/data/schema.d.ts +88 -0
  50. package/dist/cjs/data/schema.js +657 -0
  51. package/dist/cjs/data/schema.js.map +1 -0
  52. package/dist/cjs/data/sort.d.ts +8 -0
  53. package/dist/cjs/data/sort.js +21 -0
  54. package/dist/cjs/data/sort.js.map +1 -0
  55. package/dist/cjs/data/subscribe.d.ts +108 -0
  56. package/dist/cjs/data/subscribe.js +270 -0
  57. package/dist/cjs/data/subscribe.js.map +1 -0
  58. package/dist/cjs/files.d.ts +67 -0
  59. package/dist/cjs/files.js +119 -0
  60. package/dist/cjs/files.js.map +1 -0
  61. package/dist/cjs/framework-scope.d.ts +1 -0
  62. package/dist/cjs/framework-scope.js +14 -0
  63. package/dist/cjs/framework-scope.js.map +1 -0
  64. package/dist/cjs/index.d.ts +14 -0
  65. package/dist/cjs/index.js +33 -0
  66. package/dist/cjs/index.js.map +1 -0
  67. package/dist/cjs/mq/broker.d.ts +65 -0
  68. package/dist/cjs/mq/broker.js +115 -0
  69. package/dist/cjs/mq/broker.js.map +1 -0
  70. package/dist/cjs/mq/client.d.ts +37 -0
  71. package/dist/cjs/mq/client.js +321 -0
  72. package/dist/cjs/mq/client.js.map +1 -0
  73. package/dist/cjs/mq/index.d.ts +5 -0
  74. package/dist/cjs/mq/index.js +11 -0
  75. package/dist/cjs/mq/index.js.map +1 -0
  76. package/dist/cjs/mq/types.d.ts +48 -0
  77. package/dist/cjs/mq/types.js +3 -0
  78. package/dist/cjs/mq/types.js.map +1 -0
  79. package/dist/cjs/openapi/api.generated.d.ts +820 -0
  80. package/dist/cjs/openapi/api.generated.js +607 -0
  81. package/dist/cjs/openapi/api.generated.js.map +1 -0
  82. package/dist/cjs/openapi/client.d.ts +56 -0
  83. package/dist/cjs/openapi/client.js +219 -0
  84. package/dist/cjs/openapi/client.js.map +1 -0
  85. package/dist/cjs/openapi/codecs.generated.d.ts +2234 -0
  86. package/dist/cjs/openapi/codecs.generated.js +6 -0
  87. package/dist/cjs/openapi/codecs.generated.js.map +1 -0
  88. package/dist/cjs/openapi/index.d.ts +5 -0
  89. package/dist/cjs/openapi/index.js +12 -0
  90. package/dist/cjs/openapi/index.js.map +1 -0
  91. package/dist/cjs/openapi/types.generated.d.ts +3227 -0
  92. package/dist/cjs/openapi/types.generated.js +3 -0
  93. package/dist/cjs/openapi/types.generated.js.map +1 -0
  94. package/dist/cjs/package.json +1 -0
  95. package/dist/cjs/react.d.ts +9 -0
  96. package/dist/cjs/react.js +16 -0
  97. package/dist/cjs/react.js.map +1 -0
  98. package/dist/cjs/runtime-context.d.ts +9 -0
  99. package/dist/cjs/runtime-context.js +25 -0
  100. package/dist/cjs/runtime-context.js.map +1 -0
  101. package/dist/cjs/runtime-env.d.ts +1 -0
  102. package/dist/cjs/runtime-env.js +18 -0
  103. package/dist/cjs/runtime-env.js.map +1 -0
  104. package/dist/cjs/source.d.ts +39 -0
  105. package/dist/cjs/source.js +29 -0
  106. package/dist/cjs/source.js.map +1 -0
  107. package/dist/cjs/stream.d.ts +40 -0
  108. package/dist/cjs/stream.js +33 -0
  109. package/dist/cjs/stream.js.map +1 -0
  110. package/dist/cjs/uns-v2/client.d.ts +132 -0
  111. package/dist/cjs/uns-v2/client.js +352 -0
  112. package/dist/cjs/uns-v2/client.js.map +1 -0
  113. package/dist/cjs/uns-v2/codec.d.ts +11 -0
  114. package/dist/cjs/uns-v2/codec.js +290 -0
  115. package/dist/cjs/uns-v2/codec.js.map +1 -0
  116. package/dist/cjs/uns-v2/data-client.d.ts +10 -0
  117. package/dist/cjs/uns-v2/data-client.js +18 -0
  118. package/dist/cjs/uns-v2/data-client.js.map +1 -0
  119. package/dist/cjs/uns-v2/generated.d.ts +18178 -0
  120. package/dist/cjs/uns-v2/generated.js +144 -0
  121. package/dist/cjs/uns-v2/generated.js.map +1 -0
  122. package/dist/cjs/uns-v2/index.d.ts +5 -0
  123. package/dist/cjs/uns-v2/index.js +24 -0
  124. package/dist/cjs/uns-v2/index.js.map +1 -0
  125. package/dist/cjs/uns-v2/sse.d.ts +20 -0
  126. package/dist/cjs/uns-v2/sse.js +65 -0
  127. package/dist/cjs/uns-v2/sse.js.map +1 -0
  128. package/dist/cjs/vue.d.ts +9 -0
  129. package/dist/cjs/vue.js +39 -0
  130. package/dist/cjs/vue.js.map +1 -0
  131. package/dist/esm/app-identity-contract.generated.d.ts +22 -0
  132. package/dist/esm/app-identity-contract.generated.js +48 -0
  133. package/dist/esm/app-identity-contract.generated.js.map +1 -0
  134. package/dist/esm/capabilities.d.ts +54 -0
  135. package/dist/esm/capabilities.js +129 -0
  136. package/dist/esm/capabilities.js.map +1 -0
  137. package/dist/esm/client.d.ts +604 -0
  138. package/dist/esm/client.js +32 -0
  139. package/dist/esm/client.js.map +1 -0
  140. package/dist/esm/cloud-server.d.ts +31 -0
  141. package/dist/esm/cloud-server.js +109 -0
  142. package/dist/esm/cloud-server.js.map +1 -0
  143. package/dist/esm/cloud-transport.d.ts +67 -0
  144. package/dist/esm/cloud-transport.js +267 -0
  145. package/dist/esm/cloud-transport.js.map +1 -0
  146. package/dist/esm/controls.d.ts +93 -0
  147. package/dist/esm/controls.js +163 -0
  148. package/dist/esm/controls.js.map +1 -0
  149. package/dist/esm/data/bootstrap.d.ts +70 -0
  150. package/dist/esm/data/bootstrap.js +286 -0
  151. package/dist/esm/data/bootstrap.js.map +1 -0
  152. package/dist/esm/data/call.d.ts +33 -0
  153. package/dist/esm/data/call.js +211 -0
  154. package/dist/esm/data/call.js.map +1 -0
  155. package/dist/esm/data/client.d.ts +134 -0
  156. package/dist/esm/data/client.js +181 -0
  157. package/dist/esm/data/client.js.map +1 -0
  158. package/dist/esm/data/collection.d.ts +335 -0
  159. package/dist/esm/data/collection.js +594 -0
  160. package/dist/esm/data/collection.js.map +1 -0
  161. package/dist/esm/data/context.d.ts +12 -0
  162. package/dist/esm/data/context.js +44 -0
  163. package/dist/esm/data/context.js.map +1 -0
  164. package/dist/esm/data/declarations.d.ts +11 -0
  165. package/dist/esm/data/declarations.js +10 -0
  166. package/dist/esm/data/declarations.js.map +1 -0
  167. package/dist/esm/data/define.d.ts +77 -0
  168. package/dist/esm/data/define.js +27 -0
  169. package/dist/esm/data/define.js.map +1 -0
  170. package/dist/esm/data/error.d.ts +78 -0
  171. package/dist/esm/data/error.js +176 -0
  172. package/dist/esm/data/error.js.map +1 -0
  173. package/dist/esm/data/index.d.ts +24 -0
  174. package/dist/esm/data/index.js +20 -0
  175. package/dist/esm/data/index.js.map +1 -0
  176. package/dist/esm/data/schema.d.ts +88 -0
  177. package/dist/esm/data/schema.js +646 -0
  178. package/dist/esm/data/schema.js.map +1 -0
  179. package/dist/esm/data/sort.d.ts +8 -0
  180. package/dist/esm/data/sort.js +18 -0
  181. package/dist/esm/data/sort.js.map +1 -0
  182. package/dist/esm/data/subscribe.d.ts +108 -0
  183. package/dist/esm/data/subscribe.js +265 -0
  184. package/dist/esm/data/subscribe.js.map +1 -0
  185. package/dist/esm/files.d.ts +67 -0
  186. package/dist/esm/files.js +113 -0
  187. package/dist/esm/files.js.map +1 -0
  188. package/dist/esm/framework-scope.d.ts +1 -0
  189. package/dist/esm/framework-scope.js +11 -0
  190. package/dist/esm/framework-scope.js.map +1 -0
  191. package/dist/esm/index.d.ts +14 -0
  192. package/dist/esm/index.js +10 -0
  193. package/dist/esm/index.js.map +1 -0
  194. package/dist/esm/mq/broker.d.ts +65 -0
  195. package/dist/esm/mq/broker.js +109 -0
  196. package/dist/esm/mq/broker.js.map +1 -0
  197. package/dist/esm/mq/client.d.ts +37 -0
  198. package/dist/esm/mq/client.js +314 -0
  199. package/dist/esm/mq/client.js.map +1 -0
  200. package/dist/esm/mq/index.d.ts +5 -0
  201. package/dist/esm/mq/index.js +3 -0
  202. package/dist/esm/mq/index.js.map +1 -0
  203. package/dist/esm/mq/types.d.ts +48 -0
  204. package/dist/esm/mq/types.js +2 -0
  205. package/dist/esm/mq/types.js.map +1 -0
  206. package/dist/esm/openapi/api.generated.d.ts +820 -0
  207. package/dist/esm/openapi/api.generated.js +603 -0
  208. package/dist/esm/openapi/api.generated.js.map +1 -0
  209. package/dist/esm/openapi/client.d.ts +56 -0
  210. package/dist/esm/openapi/client.js +210 -0
  211. package/dist/esm/openapi/client.js.map +1 -0
  212. package/dist/esm/openapi/codecs.generated.d.ts +2234 -0
  213. package/dist/esm/openapi/codecs.generated.js +3 -0
  214. package/dist/esm/openapi/codecs.generated.js.map +1 -0
  215. package/dist/esm/openapi/index.d.ts +5 -0
  216. package/dist/esm/openapi/index.js +3 -0
  217. package/dist/esm/openapi/index.js.map +1 -0
  218. package/dist/esm/openapi/types.generated.d.ts +3227 -0
  219. package/dist/esm/openapi/types.generated.js +2 -0
  220. package/dist/esm/openapi/types.generated.js.map +1 -0
  221. package/dist/esm/package.json +1 -0
  222. package/dist/esm/react.d.ts +9 -0
  223. package/dist/esm/react.js +12 -0
  224. package/dist/esm/react.js.map +1 -0
  225. package/dist/esm/runtime-context.d.ts +9 -0
  226. package/dist/esm/runtime-context.js +22 -0
  227. package/dist/esm/runtime-context.js.map +1 -0
  228. package/dist/esm/runtime-env.d.ts +1 -0
  229. package/dist/esm/runtime-env.js +15 -0
  230. package/dist/esm/runtime-env.js.map +1 -0
  231. package/dist/esm/source.d.ts +39 -0
  232. package/dist/esm/source.js +25 -0
  233. package/dist/esm/source.js.map +1 -0
  234. package/dist/esm/stream.d.ts +40 -0
  235. package/dist/esm/stream.js +29 -0
  236. package/dist/esm/stream.js.map +1 -0
  237. package/dist/esm/uns-v2/client.d.ts +132 -0
  238. package/dist/esm/uns-v2/client.js +343 -0
  239. package/dist/esm/uns-v2/client.js.map +1 -0
  240. package/dist/esm/uns-v2/codec.d.ts +11 -0
  241. package/dist/esm/uns-v2/codec.js +284 -0
  242. package/dist/esm/uns-v2/codec.js.map +1 -0
  243. package/dist/esm/uns-v2/data-client.d.ts +10 -0
  244. package/dist/esm/uns-v2/data-client.js +14 -0
  245. package/dist/esm/uns-v2/data-client.js.map +1 -0
  246. package/dist/esm/uns-v2/generated.d.ts +18178 -0
  247. package/dist/esm/uns-v2/generated.js +141 -0
  248. package/dist/esm/uns-v2/generated.js.map +1 -0
  249. package/dist/esm/uns-v2/index.d.ts +5 -0
  250. package/dist/esm/uns-v2/index.js +5 -0
  251. package/dist/esm/uns-v2/index.js.map +1 -0
  252. package/dist/esm/uns-v2/sse.d.ts +20 -0
  253. package/dist/esm/uns-v2/sse.js +60 -0
  254. package/dist/esm/uns-v2/sse.js.map +1 -0
  255. package/dist/esm/vue.d.ts +9 -0
  256. package/dist/esm/vue.js +36 -0
  257. package/dist/esm/vue.js.map +1 -0
  258. package/docs/acceptance-2026-10-22.md +88 -0
  259. package/package.json +243 -4
  260. package/skills/tier0-sdk-v2/SKILL.md +66 -0
  261. package/skills/tier0-sdk-v2/references/integration.md +72 -0
  262. package/skills/tier0-sdk-v2/tier0-sdk-v2-agent/SKILL.md +73 -0
  263. package/skills/tier0-sdk-v2/tier0-sdk-v2-agent/references/results.md +45 -0
  264. package/skills/tier0-sdk-v2/tier0-sdk-v2-controls/SKILL.md +63 -0
  265. package/skills/tier0-sdk-v2/tier0-sdk-v2-data/SKILL.md +58 -0
  266. package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/consistency.md +70 -0
  267. package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/errors.md +82 -0
  268. package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/modeling.md +113 -0
  269. package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/read-write.md +168 -0
  270. package/skills/tier0-sdk-v2/tier0-sdk-v2-data/references/schema-evolution.md +36 -0
  271. package/skills/tier0-sdk-v2/tier0-sdk-v2-files/SKILL.md +85 -0
  272. package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/delete.md +22 -0
  273. package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/download.md +49 -0
  274. package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/multipart.md +42 -0
  275. package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/upload.md +27 -0
  276. package/skills/tier0-sdk-v2/tier0-sdk-v2-files/references/url.md +22 -0
  277. package/skills/tier0-sdk-v2/tier0-sdk-v2-members/SKILL.md +56 -0
  278. package/skills/tier0-sdk-v2/tier0-sdk-v2-members/references/app-members.md +41 -0
  279. package/skills/tier0-sdk-v2/tier0-sdk-v2-members/references/platform-members.md +56 -0
  280. package/skills/tier0-sdk-v2/tier0-sdk-v2-mq/SKILL.md +78 -0
  281. package/skills/tier0-sdk-v2/tier0-sdk-v2-mq/references/quickstart.md +69 -0
  282. package/skills/tier0-sdk-v2/tier0-sdk-v2-notifications/SKILL.md +42 -0
  283. package/skills/tier0-sdk-v2/tier0-sdk-v2-notifications/references/get.md +34 -0
  284. package/skills/tier0-sdk-v2/tier0-sdk-v2-notifications/references/send.md +72 -0
  285. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/SKILL.md +38 -0
  286. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/changes.md +40 -0
  287. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/create.md +63 -0
  288. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/delete.md +47 -0
  289. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/protocols.md +36 -0
  290. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/read.md +34 -0
  291. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/state.md +37 -0
  292. package/skills/tier0-sdk-v2/tier0-sdk-v2-source/references/update.md +62 -0
  293. package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/SKILL.md +43 -0
  294. package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/create.md +56 -0
  295. package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/delete.md +35 -0
  296. package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/deploy.md +64 -0
  297. package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/lifecycle.md +26 -0
  298. package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/read.md +35 -0
  299. package/skills/tier0-sdk-v2/tier0-sdk-v2-stream/references/update.md +36 -0
  300. package/skills/tier0-sdk-v2/tier0-sdk-v2-system/SKILL.md +64 -0
  301. package/skills/tier0-sdk-v2/tier0-sdk-v2-system/references/info.md +23 -0
  302. package/skills/tier0-sdk-v2/tier0-sdk-v2-system/references/whoami.md +21 -0
  303. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/SKILL.md +55 -0
  304. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/create.md +56 -0
  305. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/data-workflows.md +69 -0
  306. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/delete.md +53 -0
  307. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/namespace.md +38 -0
  308. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/read.md +34 -0
  309. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/restore.md +39 -0
  310. package/skills/tier0-sdk-v2/tier0-sdk-v2-uns/references/update.md +62 -0
@@ -0,0 +1,93 @@
1
+ import { type HttpClient, type ClientConfig } from './openapi/client.js';
2
+ import { type CloudTransportConfig } from './cloud-transport.js';
3
+ /** Cloud Control contracts are independent of generated OpenAPI / Enterprise flow types. */
4
+ export type ControlJSON = null | boolean | number | string | ControlJSON[] | {
5
+ [key: string]: ControlJSON;
6
+ };
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; UNS v2 options never affect Control execution or headers. */
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
+ /** Gateway string errorCode, or an SDK-local CONTROL_* transport/protocol code. */
51
+ errorCode: string;
52
+ runID?: string;
53
+ contractVersion?: string;
54
+ runStatus?: string;
55
+ replayed?: boolean;
56
+ }
57
+ /** No Control error is automatically retried, including authentication failures. */
58
+ export declare class ControlError extends Error {
59
+ readonly status?: number;
60
+ readonly errorCode: string;
61
+ readonly runID?: string;
62
+ readonly contractVersion?: string;
63
+ readonly runStatus?: string;
64
+ readonly replayed?: boolean;
65
+ readonly retryable = false;
66
+ constructor(message: string, info: ControlErrorInfo);
67
+ }
68
+ /** Execution may have happened. Reconcile run information; any deliberate replay must reuse the same key. */
69
+ export declare class ControlResultUnknownError extends ControlError {
70
+ readonly outcomeUnknown = true;
71
+ constructor(info: ControlErrorInfo);
72
+ }
73
+ export interface ControlHandle<Input = ControlJSON, Result = ControlJSON> {
74
+ describe(): Promise<PublicControl>;
75
+ /**
76
+ * One POST only. Input is opaque business JSON, including fields named streamId,
77
+ * entryId, deploymentVersion or timeoutMs. Only the server chooses binding/version/timeout.
78
+ * Generic types are caller assertions; the server validates the contract schemas.
79
+ */
80
+ invoke(input: Input, options?: ControlInvokeOptions): Promise<ControlInvokeResponse<Result>>;
81
+ }
82
+ export declare class ControlsClient {
83
+ private readonly transport;
84
+ constructor(resolveClient?: () => HttpClient, config?: ControlTransportConfig);
85
+ private post;
86
+ /** Discover visible contracts; defaults and authorization are resolved by the server. */
87
+ discover(options?: ControlDiscoverOptions): Promise<ControlDiscoverResponse>;
88
+ use<Input = ControlJSON, Result = ControlJSON>(selector: {
89
+ code: string;
90
+ }): ControlHandle<Input, Result>;
91
+ }
92
+ /** Uses configureClient()/TIER0_API_HOST/TIER0_API_KEY, resolved for every call. */
93
+ export declare const controls: ControlsClient;
@@ -0,0 +1,163 @@
1
+ import { getClient } from './openapi/client.js';
2
+ import { CloudTransport, CloudTransportError, DEFAULT_CLOUD_TRANSPORT_TIMEOUT_MS } from './cloud-transport.js';
3
+ export const DEFAULT_CONTROL_TRANSPORT_TIMEOUT_MS = DEFAULT_CLOUD_TRANSPORT_TIMEOUT_MS;
4
+ /** No Control error is automatically retried, including authentication failures. */
5
+ export class ControlError extends Error {
6
+ status;
7
+ errorCode;
8
+ runID;
9
+ contractVersion;
10
+ runStatus;
11
+ replayed;
12
+ retryable = false;
13
+ constructor(message, info) {
14
+ super(message);
15
+ this.name = 'ControlError';
16
+ this.status = info.status;
17
+ this.errorCode = info.errorCode;
18
+ this.runID = info.runID;
19
+ this.contractVersion = info.contractVersion;
20
+ this.runStatus = info.runStatus;
21
+ this.replayed = info.replayed;
22
+ }
23
+ }
24
+ /** Execution may have happened. Reconcile run information; any deliberate replay must reuse the same key. */
25
+ export class ControlResultUnknownError extends ControlError {
26
+ outcomeUnknown = true;
27
+ constructor(info) {
28
+ super('Control result is unknown; execution may have occurred. Do not automatically retry.', info);
29
+ this.name = 'ControlResultUnknownError';
30
+ }
31
+ }
32
+ function record(value) {
33
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
34
+ }
35
+ function keys(value, allowed) {
36
+ if (!record(value) || Reflect.ownKeys(value).some(key => typeof key !== 'string' || !allowed.includes(key))) {
37
+ throw new TypeError('Tier0 SDK: unsupported Control option.');
38
+ }
39
+ }
40
+ function json(value, seen = new Set()) {
41
+ if (value === null || typeof value === 'string' || typeof value === 'boolean')
42
+ return true;
43
+ if (typeof value === 'number')
44
+ return Number.isFinite(value);
45
+ if (typeof value !== 'object' || seen.has(value))
46
+ return false;
47
+ if (!Array.isArray(value) && Object.getPrototypeOf(value) !== Object.prototype && Object.getPrototypeOf(value) !== null) {
48
+ return false;
49
+ }
50
+ seen.add(value);
51
+ const valid = (Array.isArray(value) ? Array.from(value) : Object.values(value)).every(item => json(item, seen));
52
+ seen.delete(value);
53
+ return valid;
54
+ }
55
+ function definition(value) {
56
+ if (!record(value))
57
+ return false;
58
+ return ['code', 'name', 'description', 'contractVersion', 'status'].every(key => typeof value[key] === 'string') &&
59
+ value.code !== '' && value.contractVersion !== '' && record(value.inputSchema) && record(value.outputSchema) &&
60
+ ['read', 'write'].includes(value.sideEffect) &&
61
+ ['none', 'optional', 'required'].includes(value.idempotency) &&
62
+ typeof value.timeoutMs === 'number' && Number.isSafeInteger(value.timeoutMs) && value.timeoutMs > 0;
63
+ }
64
+ function runInfo(value) {
65
+ if (!record(value))
66
+ return {};
67
+ return {
68
+ runID: typeof value.runID === 'string' ? value.runID : undefined,
69
+ contractVersion: typeof value.contractVersion === 'string' ? value.contractVersion : undefined,
70
+ runStatus: typeof value.status === 'string' ? value.status : undefined,
71
+ replayed: typeof value.replayed === 'boolean' ? value.replayed : undefined,
72
+ };
73
+ }
74
+ export class ControlsClient {
75
+ transport;
76
+ constructor(resolveClient = getClient, config = {}) {
77
+ this.transport = new CloudTransport(resolveClient, config);
78
+ }
79
+ async post(path, body, invoked) {
80
+ let response;
81
+ try {
82
+ response = await this.transport.post(path, body);
83
+ }
84
+ catch (error) {
85
+ if (!(error instanceof CloudTransportError))
86
+ throw error;
87
+ const info = { status: error.status, errorCode: `CONTROL_${error.kind}` };
88
+ if (invoked)
89
+ throw new ControlResultUnknownError(info);
90
+ const message = error.kind === 'TRANSPORT_TIMEOUT' ? 'Control HTTP transport deadline exceeded.' :
91
+ error.kind === 'PROTOCOL_ERROR' ? 'Invalid Control response.' : 'Control transport failed.';
92
+ throw new ControlError(message, info);
93
+ }
94
+ const { value, status, ok } = response;
95
+ if (!ok) {
96
+ const error = record(value) ? value : {};
97
+ const valid = typeof error.errorCode === 'string' && typeof error.message === 'string';
98
+ const info = {
99
+ ...runInfo(value), status,
100
+ errorCode: valid ? error.errorCode : 'CONTROL_PROTOCOL_ERROR',
101
+ };
102
+ if (info.errorCode === 'CONTROL_RESULT_UNKNOWN' || (invoked && !valid)) {
103
+ throw new ControlResultUnknownError(info);
104
+ }
105
+ throw new ControlError(valid ? error.message : 'Invalid Control error response.', info);
106
+ }
107
+ return { value, status };
108
+ }
109
+ /** Discover visible contracts; defaults and authorization are resolved by the server. */
110
+ async discover(options = {}) {
111
+ keys(options, ['page', 'size', 'search']);
112
+ if ((options.page !== undefined && (!Number.isSafeInteger(options.page) || options.page < 1)) ||
113
+ (options.size !== undefined && (!Number.isSafeInteger(options.size) || options.size < 1 || options.size > 200)) ||
114
+ (options.search !== undefined && typeof options.search !== 'string')) {
115
+ throw new TypeError('Tier0 SDK: invalid Control discovery options.');
116
+ }
117
+ const { value, status } = await this.post('/openapi/v1/controls/discover', options, false);
118
+ if (!record(value) || !Number.isSafeInteger(value.total) || value.total < 0 ||
119
+ !Array.isArray(value.list) || !value.list.every(definition)) {
120
+ throw new ControlError('Invalid Control discovery response.', { status, errorCode: 'CONTROL_PROTOCOL_ERROR' });
121
+ }
122
+ return value;
123
+ }
124
+ use(selector) {
125
+ keys(selector, ['code']);
126
+ const code = selector.code;
127
+ if (typeof code !== 'string' || code.length > 128 || !/^[a-z][a-z0-9]*(?:[._-][a-z0-9]+)*$/.test(code)) {
128
+ throw new TypeError('Tier0 SDK: invalid Control code.');
129
+ }
130
+ const path = `/openapi/v1/controls/${encodeURIComponent(code)}`;
131
+ return {
132
+ describe: async () => {
133
+ const { value, status } = await this.post(`${path}/describe`, {}, false);
134
+ if (!definition(value) || value.code !== code) {
135
+ throw new ControlError('Invalid Control description.', { status, errorCode: 'CONTROL_PROTOCOL_ERROR' });
136
+ }
137
+ return value;
138
+ },
139
+ invoke: async (input, options = {}) => {
140
+ keys(options, ['idempotencyKey']);
141
+ const key = options.idempotencyKey;
142
+ if (key !== undefined && (typeof key !== 'string' || !key || key.trim() !== key || new TextEncoder().encode(key).length > 128)) {
143
+ throw new TypeError('Tier0 SDK: invalid Control idempotency key.');
144
+ }
145
+ if (!json(input))
146
+ throw new TypeError('Tier0 SDK: Control input must be JSON.');
147
+ const { value, status } = await this.post(`${path}/invoke`, {
148
+ input, ...(key === undefined ? {} : { idempotencyKey: key }),
149
+ }, true);
150
+ if (!record(value) || value.code !== code || typeof value.contractVersion !== 'string' || !value.contractVersion ||
151
+ !Object.prototype.hasOwnProperty.call(value, 'result') || typeof value.runID !== 'string' || !value.runID ||
152
+ typeof value.status !== 'string' || !value.status || ['accepted', 'queued', 'pending', 'running'].includes(value.status) ||
153
+ typeof value.replayed !== 'boolean') {
154
+ throw new ControlResultUnknownError({ ...runInfo(value), status, errorCode: 'CONTROL_PROTOCOL_ERROR' });
155
+ }
156
+ return value;
157
+ },
158
+ };
159
+ }
160
+ }
161
+ /** Uses configureClient()/TIER0_API_HOST/TIER0_API_KEY, resolved for every call. */
162
+ export const controls = new ControlsClient();
163
+ //# sourceMappingURL=controls.js.map
@@ -0,0 +1 @@
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 { CloudTransport, CloudTransportError, DEFAULT_CLOUD_TRANSPORT_TIMEOUT_MS, type CloudTransportConfig } from './cloud-transport.js';\n\n/** Cloud Control contracts are independent of generated OpenAPI / Enterprise flow types. */\nexport type ControlJSON = null | boolean | number | string | ControlJSON[] | { [key: string]: ControlJSON };\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; UNS v2 options never affect Control execution or headers. */\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 /** Gateway string errorCode, or an SDK-local CONTROL_* transport/protocol code. */\n errorCode: string;\n runID?: string;\n contractVersion?: string;\n runStatus?: string;\n replayed?: boolean;\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 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 }\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') 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 transport: CloudTransport;\n\n constructor(resolveClient: () => HttpClient = getClient, config: ControlTransportConfig = {}) {\n this.transport = new CloudTransport(resolveClient, config);\n }\n\n private async post(path: string, body: unknown, invoked: boolean): Promise<{ value: unknown; status: number }> {\n let response: Awaited<ReturnType<CloudTransport['post']>>;\n try {\n response = await this.transport.post(path, body);\n } catch (error) {\n if (!(error instanceof CloudTransportError)) throw error;\n const info = { status: error.status, errorCode: `CONTROL_${error.kind}` };\n if (invoked) throw new ControlResultUnknownError(info);\n const message = error.kind === 'TRANSPORT_TIMEOUT' ? 'Control HTTP transport deadline exceeded.' :\n error.kind === 'PROTOCOL_ERROR' ? 'Invalid Control response.' : 'Control transport failed.';\n throw new ControlError(message, info);\n }\n const { value, status, ok } = response;\n if (!ok) {\n const error = record(value) ? value : {};\n const valid = typeof error.errorCode === 'string' && typeof error.message === 'string';\n const info: ControlErrorInfo = {\n ...runInfo(value), status,\n errorCode: valid ? error.errorCode as string : 'CONTROL_PROTOCOL_ERROR',\n };\n if (info.errorCode === 'CONTROL_RESULT_UNKNOWN' || (invoked && !valid)) {\n throw new ControlResultUnknownError(info);\n }\n throw new ControlError(valid ? error.message as string : 'Invalid Control error response.', info);\n }\n return { value, status };\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('/openapi/v1/controls/discover', options, false);\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 value as unknown as ControlDiscoverResponse;\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 const path = `/openapi/v1/controls/${encodeURIComponent(code)}`;\n return {\n describe: async () => {\n const { value, status } = await this.post(`${path}/describe`, {}, false);\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(`${path}/invoke`, {\n input, ...(key === undefined ? {} : { idempotencyKey: key }),\n }, true);\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 value as unknown as ControlInvokeResponse<Result>;\n },\n };\n }\n}\n\n/** Uses configureClient()/TIER0_API_HOST/TIER0_API_KEY, resolved for every call. */\nexport const controls = new ControlsClient();\n"]}
@@ -0,0 +1,70 @@
1
+ import type { DataCall } from './call.js';
2
+ import type { CollectionDefinition } from './define.js';
3
+ import { DataError } from './error.js';
4
+ export type DataEnvironment = 'preview' | 'deployed';
5
+ export interface EnsureWarning {
6
+ code: string;
7
+ path?: string;
8
+ message?: string;
9
+ }
10
+ export interface EnsureNote {
11
+ path: string;
12
+ reason?: string;
13
+ message?: string;
14
+ }
15
+ export interface EnsureResult {
16
+ alias: string;
17
+ collectionId: string;
18
+ revision: number;
19
+ status: 'created' | 'unchanged' | 'widened';
20
+ ignored?: EnsureNote[];
21
+ warnings?: EnsureWarning[];
22
+ indexStatus?: unknown[];
23
+ }
24
+ export interface EnsureConflict {
25
+ alias: string;
26
+ collectionId?: string;
27
+ path?: string;
28
+ reason?: string;
29
+ current?: string;
30
+ declared?: string;
31
+ }
32
+ export interface EnsureState {
33
+ appId?: string;
34
+ results: EnsureResult[];
35
+ /** Lower-cased alias → collection ID. */
36
+ collectionIds: Map<string, string>;
37
+ /** Declarations that conflicted in a deployment (served with their existing ID, if any). */
38
+ conflicts: EnsureConflict[];
39
+ }
40
+ export interface Logger {
41
+ info(...args: unknown[]): void;
42
+ warn(...args: unknown[]): void;
43
+ error(...args: unknown[]): void;
44
+ }
45
+ export interface BootstrapConfig {
46
+ call: DataCall;
47
+ collections: readonly CollectionDefinition[];
48
+ environment: DataEnvironment;
49
+ logger: Logger;
50
+ }
51
+ /** Wait before replaying seed chunk attempt n+1: n × this. */
52
+ export declare const SEED_RETRY_MS = 1000;
53
+ /** At most one self-healing rebuild per client in this window. */
54
+ export declare const REBUILD_INTERVAL_MS = 30000;
55
+ /**
56
+ * Whether a record call failed because the collection ID it used is gone or
57
+ * no longer granted, by UNS's stable `data.reason` code. Archive and Preview
58
+ * purge also remove the App grant, so most stale IDs answer
59
+ * COLLECTION_NOT_GRANTED or COLLECTION_NOT_FOUND. APP_PERMISSION_MISSING (the
60
+ * key lacks e.g. `uns.delete`) and APP_GRANT_REVOKED are not stale IDs.
61
+ */
62
+ export declare function isStaleCollectionError(error: unknown): boolean;
63
+ export declare function createBootstrap(config: BootstrapConfig): {
64
+ ensure: () => Promise<EnsureState>;
65
+ resolve: (definition: CollectionDefinition) => Promise<string>;
66
+ recover: <R>(fn: () => Promise<R>, options?: {
67
+ retry?: boolean;
68
+ }) => Promise<R>;
69
+ rebuild: (before: EnsureState, cause: DataError) => Promise<boolean>;
70
+ };
@@ -0,0 +1,286 @@
1
+ /**
2
+ * First-access bootstrap: one batched `ensure` of every declared collection.
3
+ *
4
+ * - ensure only creates or widens; storage never narrows from here, so old
5
+ * and new code may cold-start in any order.
6
+ * - The result is memoized per client, i.e. per server process; a client
7
+ * built from edited declarations ensures again.
8
+ * Failures are not memoized: a later call retries (an imported App may
9
+ * answer "hosted App is not ready").
10
+ * - Seed documents are inserted only for collections ensure reports as
11
+ * `created`: fixed `_id`s, atomic chunks of 200 with a stable idempotency
12
+ * key per chunk, so a failed chunk (outcome unknown, or marked safe to
13
+ * resend) is replayed after a short wait instead of duplicated. Seed writes
14
+ * never carry a data subject.
15
+ * - Preview throws on SCHEMA_CONFLICT and warnings so the worker sees them;
16
+ * a deployment logs them and keeps serving with the IDs it has.
17
+ * - Self-healing: a Preview reset hard-deletes collections, and a worker or
18
+ * admin may archive one, while this process still holds the old IDs. A
19
+ * record call that fails with `data.reason` COLLECTION_NOT_FOUND or
20
+ * COLLECTION_NOT_GRANTED drops the memo, ensures again (seeding what is created)
21
+ * and retries the call once, but only when a collection ID actually
22
+ * changed. Rebuilds are limited to one per REBUILD_INTERVAL_MS per client;
23
+ * APP_GRANT_REVOKED is never retried (ensure itself reports it).
24
+ * - `ignored` notes never fail a request. ensure never writes annotations, so
25
+ * an edited `.describe()` or collection description comes back as
26
+ * ANNOTATION_NOT_APPLIED; it is logged as a warning pointing at
27
+ * schema:replace, which is the only way to change stored annotations.
28
+ */
29
+ import { createHash } from 'node:crypto';
30
+ import { MAX_ATOMIC_ITEMS } from './collection.js';
31
+ import { ACCESS_REASONS, DataError } from './error.js';
32
+ import { compileCollection, validateDocument } from './schema.js';
33
+ const SEED_ATTEMPTS = 3;
34
+ /** Wait before replaying seed chunk attempt n+1: n × this. */
35
+ export const SEED_RETRY_MS = 1_000;
36
+ /** At most one self-healing rebuild per client in this window. */
37
+ export const REBUILD_INTERVAL_MS = 30_000;
38
+ /**
39
+ * Whether a record call failed because the collection ID it used is gone or
40
+ * no longer granted, by UNS's stable `data.reason` code. Archive and Preview
41
+ * purge also remove the App grant, so most stale IDs answer
42
+ * COLLECTION_NOT_GRANTED or COLLECTION_NOT_FOUND. APP_PERMISSION_MISSING (the
43
+ * key lacks e.g. `uns.delete`) and APP_GRANT_REVOKED are not stale IDs.
44
+ */
45
+ export function isStaleCollectionError(error) {
46
+ return (error instanceof DataError &&
47
+ (error.reason === ACCESS_REASONS.notGranted || error.reason === ACCESS_REASONS.notFound));
48
+ }
49
+ function sameCollectionIds(a, b) {
50
+ if (a.collectionIds.size !== b.collectionIds.size)
51
+ return false;
52
+ for (const [alias, id] of a.collectionIds) {
53
+ if (b.collectionIds.get(alias) !== id)
54
+ return false;
55
+ }
56
+ return true;
57
+ }
58
+ /** Idempotency key of one seed chunk (UNS keys are at most 96 characters). */
59
+ function seedChunkKey(collectionId, chunk) {
60
+ return `seed-${createHash('sha256').update(collectionId).digest('hex').slice(0, 40)}-${chunk}`;
61
+ }
62
+ /** What to do about each SCHEMA_CONFLICT reason (CloudAppCollectionConflict.reason). */
63
+ const CONFLICT_HINTS = {
64
+ TYPE_CONFLICT: "a field's type cannot change; use a new field name and backfill with updateMany",
65
+ LIMIT_EXCEEDED: 'the joined schema exceeds a UNS limit (depth, properties, enum values or indexes); split the structure',
66
+ OPEN_OBJECT: 'every object must be closed; declare it with z.object',
67
+ ALIAS_IN_USE: 'the alias belongs to another collection; pick another alias',
68
+ NAME_IN_USE: 'the name belongs to another collection; pick another alias',
69
+ INVALID_INDEX: 'fix the index declaration',
70
+ JOIN_UNSUPPORTED: 'the stored schema holds a node the declaration cannot widen (e.g. enum values outside its range); repair it with schema:replace via the tier0 MCP',
71
+ DATA_RULE_FIELD: 'an employee data rule (ownerField / stateField) uses this field; keep it required with the same type, or ask a workspace admin to change the rule',
72
+ };
73
+ function describeConflicts(conflicts) {
74
+ return conflicts
75
+ .map((conflict) => {
76
+ const where = `${conflict.alias}${conflict.path ? `.${conflict.path}` : ''}`;
77
+ const types = conflict.current || conflict.declared ? ` (stored ${conflict.current ?? '?'}, declared ${conflict.declared ?? '?'})` : '';
78
+ const hint = conflict.reason && CONFLICT_HINTS[conflict.reason] ? ` — ${CONFLICT_HINTS[conflict.reason]}` : '';
79
+ return ` - ${where}: ${conflict.reason ?? 'conflict'}${types}${hint}`;
80
+ })
81
+ .join('\n');
82
+ }
83
+ function notePath(alias, note) {
84
+ return note.path ? `${alias}.${note.path}` : alias;
85
+ }
86
+ function describeWarnings(results) {
87
+ return results
88
+ .flatMap((result) => (result.warnings ?? []).map((warning) => ` - ${result.alias}${warning.path ? `.${warning.path}` : ''}: ${warning.code}${warning.message ? ` — ${warning.message}` : ''}`))
89
+ .join('\n');
90
+ }
91
+ export function createBootstrap(config) {
92
+ const { call, collections, environment, logger } = config;
93
+ let pending = null;
94
+ let lastRebuild = Number.NEGATIVE_INFINITY;
95
+ async function requestEnsure(items) {
96
+ // ensure is App-level work: it never carries the employee data subject.
97
+ return call('appCollectionsEnsure', { collections: items });
98
+ }
99
+ async function insertSeedChunk(collectionId, chunk, documents) {
100
+ for (let attempt = 1;; attempt += 1) {
101
+ try {
102
+ await call('recordInsertMany', {
103
+ collectionId,
104
+ documents,
105
+ ordered: true,
106
+ atomic: true,
107
+ idempotencyKey: seedChunkKey(collectionId, chunk),
108
+ });
109
+ return;
110
+ }
111
+ catch (error) {
112
+ // The chunk key is stable, so replaying is safe even when the outcome is unknown: a chunk
113
+ // that did commit replays its receipt. Wait first, so a write still running can finish.
114
+ if (!(error instanceof DataError) || !(error.outcomeUnknown || error.retry.safe) || attempt >= SEED_ATTEMPTS)
115
+ throw error;
116
+ await new Promise((resolve) => setTimeout(resolve, SEED_RETRY_MS * attempt));
117
+ }
118
+ }
119
+ }
120
+ async function writeSeeds(results) {
121
+ for (const result of results) {
122
+ if (result.status !== 'created')
123
+ continue;
124
+ const definition = collections.find((candidate) => candidate.alias.toLowerCase() === result.alias.toLowerCase());
125
+ const seed = definition?.seed;
126
+ if (!definition || !seed || seed.length === 0)
127
+ continue;
128
+ try {
129
+ const documents = seed.map((document) => {
130
+ const { id, data } = validateDocument(definition, document);
131
+ return { id, data };
132
+ });
133
+ for (let start = 0; start < documents.length; start += MAX_ATOMIC_ITEMS) {
134
+ await insertSeedChunk(result.collectionId, start / MAX_ATOMIC_ITEMS, documents.slice(start, start + MAX_ATOMIC_ITEMS));
135
+ }
136
+ logger.info(`[data] seeded ${documents.length} record(s) into "${result.alias}"`);
137
+ }
138
+ catch (error) {
139
+ // The collection exists now; a later ensure reports "unchanged" and
140
+ // never re-seeds, so the failure must be visible in the server log.
141
+ logger.error(`[data] seed for new collection "${result.alias}" failed; it keeps the chunks written so far:`, error);
142
+ }
143
+ }
144
+ }
145
+ async function run(payload) {
146
+ const conflicts = [];
147
+ let remaining = payload;
148
+ let response = { results: [] };
149
+ while (remaining.length > 0) {
150
+ try {
151
+ response = await requestEnsure(remaining);
152
+ break;
153
+ }
154
+ catch (error) {
155
+ if (!(error instanceof DataError) || error.code !== 'SCHEMA_CONFLICT')
156
+ throw error;
157
+ const reported = Array.isArray(error.details.conflicts) ? error.details.conflicts : [];
158
+ const summary = describeConflicts(reported);
159
+ if (environment === 'preview') {
160
+ throw new DataError({
161
+ message: `The collection declarations conflict with the stored collection schemas; nothing was changed:\n${summary}`,
162
+ status: 409,
163
+ code: 'SCHEMA_CONFLICT',
164
+ upstreamStatus: error.upstreamStatus,
165
+ requestId: error.requestId,
166
+ execution: error.execution,
167
+ attempts: error.attempts,
168
+ details: error.details,
169
+ });
170
+ }
171
+ // A deployment keeps serving: drop the conflicting declarations (the
172
+ // whole batch was rejected) and ensure the rest again.
173
+ const conflicting = new Set(reported.map((conflict) => conflict.alias.toLowerCase()));
174
+ const next = remaining.filter((item) => !conflicting.has(item.alias.toLowerCase()));
175
+ if (next.length === remaining.length)
176
+ throw error;
177
+ logger.error(`[data] ensure: declarations conflict with stored schemas; serving them unchanged:\n${summary}`);
178
+ conflicts.push(...reported);
179
+ remaining = next;
180
+ }
181
+ }
182
+ const results = response.results ?? [];
183
+ const collectionIds = new Map();
184
+ for (const conflict of conflicts) {
185
+ if (conflict.collectionId)
186
+ collectionIds.set(conflict.alias.toLowerCase(), conflict.collectionId);
187
+ }
188
+ for (const result of results) {
189
+ collectionIds.set(result.alias.toLowerCase(), result.collectionId);
190
+ const notes = result.ignored ?? [];
191
+ const annotations = notes.filter((note) => note.reason === 'ANNOTATION_NOT_APPLIED');
192
+ const wider = notes.filter((note) => note.reason !== 'ANNOTATION_NOT_APPLIED');
193
+ if (wider.length > 0) {
194
+ logger.info(`[data] "${result.alias}" storage is wider than this declaration (or has retired parts); ignored: ` +
195
+ wider.map((note) => `${note.path || '(root)'} ${note.reason ?? ''}`.trim()).join(', '));
196
+ }
197
+ if (annotations.length > 0) {
198
+ // A hint, not an error: storage keeps its annotations and serves as before.
199
+ logger.warn(`[data] ensure does not change stored titles/descriptions; not applied: ${annotations.map((note) => notePath(result.alias, note)).join(', ')}. ` +
200
+ `Apply them with schema:replace via the tier0 MCP, using compileCollection(...) of the declaration as the body.`);
201
+ }
202
+ }
203
+ await writeSeeds(results);
204
+ const warnings = describeWarnings(results);
205
+ if (warnings) {
206
+ if (environment === 'preview') {
207
+ throw new DataError({
208
+ message: `Collections were ensured with warnings:\n${warnings}\n` +
209
+ 'REQUIRED_NOT_ENFORCED: make the field optional again or narrow explicitly with schema:replace via the tier0 MCP. ' +
210
+ 'INDEX_BUILD_FAILED: fix the duplicate or invalid data, then the next ensure retries the index.',
211
+ status: 500,
212
+ code: 'SCHEMA_WARNINGS',
213
+ // ensure did apply; only the warnings fail the Preview request.
214
+ execution: 'committed',
215
+ details: { results },
216
+ });
217
+ }
218
+ logger.warn(`[data] ensure warnings:\n${warnings}`);
219
+ }
220
+ return { appId: response.appId, results, collectionIds, conflicts };
221
+ }
222
+ /** Ensures every declaration once per client; a failure is forgotten so the next call retries. */
223
+ function ensure() {
224
+ pending ??= Promise.resolve()
225
+ .then(() => run(collections.map(compileCollection)))
226
+ .catch((error) => {
227
+ pending = null;
228
+ throw error;
229
+ });
230
+ return pending;
231
+ }
232
+ /**
233
+ * Re-ensures after `before` turned out stale. Joins a rebuild already in
234
+ * flight; otherwise rebuilds at most once per REBUILD_INTERVAL_MS. Resolves
235
+ * whether any collection ID changed; ensure errors (APP_GRANT_REVOKED, …)
236
+ * propagate.
237
+ */
238
+ async function rebuild(before, cause) {
239
+ const current = ensure();
240
+ const latest = await current;
241
+ if (latest !== before)
242
+ return !sameCollectionIds(before, latest);
243
+ if (pending !== current)
244
+ return !sameCollectionIds(before, await ensure());
245
+ const now = Date.now();
246
+ if (now - lastRebuild < REBUILD_INTERVAL_MS)
247
+ return false;
248
+ lastRebuild = now;
249
+ logger.warn(`[data] a collection ID is no longer usable (${cause.code}: ${cause.message}); ensuring collections again`);
250
+ pending = null;
251
+ return !sameCollectionIds(before, await ensure());
252
+ }
253
+ /**
254
+ * Runs one data call; when it fails on a stale collection ID, rebuilds and
255
+ * runs it once more if an ID changed. `retry: false` (calls continuing a
256
+ * cursor or resumeAfter token of the old collection) only rebuilds.
257
+ */
258
+ async function recover(fn, options = {}) {
259
+ const before = await ensure();
260
+ try {
261
+ return await fn();
262
+ }
263
+ catch (error) {
264
+ if (!isStaleCollectionError(error))
265
+ throw error;
266
+ const changed = await rebuild(before, error);
267
+ if (!changed || options.retry === false)
268
+ throw error;
269
+ return fn();
270
+ }
271
+ }
272
+ async function resolve(definition) {
273
+ const state = await ensure();
274
+ const id = state.collectionIds.get(definition.alias.toLowerCase());
275
+ if (!id) {
276
+ throw new DataError({
277
+ message: `Collection "${definition.alias}" is unavailable: ensure did not return it (see the server log).`,
278
+ status: 503,
279
+ code: 'COLLECTION_UNAVAILABLE',
280
+ });
281
+ }
282
+ return id;
283
+ }
284
+ return { ensure, resolve, recover, rebuild };
285
+ }
286
+ //# sourceMappingURL=bootstrap.js.map