@the-open-engine/zeroshot 6.29.0 → 6.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (347) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/cli/index.js +2 -4
  3. package/lib/agent-cli-provider/adapters/codex.d.ts.map +1 -1
  4. package/lib/agent-cli-provider/adapters/codex.js +0 -1
  5. package/lib/agent-cli-provider/adapters/codex.js.map +1 -1
  6. package/lib/agent-cli-provider/contract-actions.d.ts +1 -1
  7. package/lib/agent-cli-provider/contract-actions.d.ts.map +1 -1
  8. package/lib/agent-cli-provider/contract-actions.js +5 -5
  9. package/lib/agent-cli-provider/contract-actions.js.map +1 -1
  10. package/lib/agent-cli-provider/contract-invoke.d.ts +1 -1
  11. package/lib/agent-cli-provider/contract-invoke.d.ts.map +1 -1
  12. package/lib/agent-cli-provider/contract-invoke.js +2 -2
  13. package/lib/agent-cli-provider/contract-invoke.js.map +1 -1
  14. package/lib/agent-cli-provider/contract-support.d.ts +1 -1
  15. package/lib/agent-cli-provider/contract-support.d.ts.map +1 -1
  16. package/lib/agent-cli-provider/contract-support.js +2 -2
  17. package/lib/agent-cli-provider/contract-support.js.map +1 -1
  18. package/lib/agent-cli-provider/contract.d.ts +1 -0
  19. package/lib/agent-cli-provider/contract.d.ts.map +1 -1
  20. package/lib/agent-cli-provider/contract.js +1 -1
  21. package/lib/agent-cli-provider/contract.js.map +1 -1
  22. package/lib/agent-cli-provider/index.d.ts +1 -1
  23. package/lib/agent-cli-provider/index.d.ts.map +1 -1
  24. package/lib/agent-cli-provider/index.js +2 -1
  25. package/lib/agent-cli-provider/index.js.map +1 -1
  26. package/lib/agent-cli-provider/provider-registry.d.ts +1 -0
  27. package/lib/agent-cli-provider/provider-registry.d.ts.map +1 -1
  28. package/lib/agent-cli-provider/provider-registry.js +4 -0
  29. package/lib/agent-cli-provider/provider-registry.js.map +1 -1
  30. package/lib/agent-cli-provider/single-agent-runtime.d.ts +3 -3
  31. package/lib/agent-cli-provider/single-agent-runtime.d.ts.map +1 -1
  32. package/lib/agent-cli-provider/single-agent-runtime.js +22 -48
  33. package/lib/agent-cli-provider/single-agent-runtime.js.map +1 -1
  34. package/lib/cluster/client.cjs +30 -7
  35. package/lib/cluster/client.d.cts +52 -0
  36. package/lib/cluster/client.d.mts +52 -0
  37. package/lib/cluster/client.d.ts +4 -6
  38. package/lib/cluster/client.mjs +32 -9
  39. package/lib/cluster/connection-state.cjs +25 -0
  40. package/lib/cluster/connection-state.d.cts +13 -0
  41. package/lib/cluster/connection-state.d.mts +13 -0
  42. package/lib/cluster/connection-state.d.ts +13 -0
  43. package/lib/cluster/connection-state.mjs +21 -0
  44. package/lib/{target/hosted-run/contracts.js → cluster/connection-types.cjs} +0 -1
  45. package/lib/cluster/connection-types.d.cts +33 -0
  46. package/lib/cluster/connection-types.d.mts +33 -0
  47. package/lib/cluster/connection-types.d.ts +33 -0
  48. package/lib/cluster/connection-types.mjs +1 -0
  49. package/lib/cluster/connection.cjs +18 -46
  50. package/lib/cluster/connection.d.cts +26 -0
  51. package/lib/cluster/connection.d.mts +26 -0
  52. package/lib/cluster/connection.d.ts +7 -25
  53. package/lib/cluster/connection.mjs +12 -42
  54. package/lib/cluster/errors.cjs +9 -1
  55. package/lib/cluster/errors.d.cts +29 -0
  56. package/lib/cluster/errors.d.mts +29 -0
  57. package/lib/cluster/errors.d.ts +4 -0
  58. package/lib/cluster/errors.mjs +7 -0
  59. package/lib/cluster/frames.d.cts +12 -0
  60. package/lib/cluster/frames.d.mts +12 -0
  61. package/lib/cluster/generated/protocol-schema.d.cts +1 -0
  62. package/lib/cluster/generated/protocol-schema.d.mts +1 -0
  63. package/lib/cluster/generated/protocol.d.cts +781 -0
  64. package/lib/cluster/generated/protocol.d.mts +781 -0
  65. package/lib/cluster/index.cjs +2 -2
  66. package/lib/cluster/index.d.cts +13 -0
  67. package/lib/cluster/index.d.mts +13 -0
  68. package/lib/cluster/index.d.ts +3 -3
  69. package/lib/cluster/index.mjs +2 -2
  70. package/lib/cluster/json-source.cjs +1 -0
  71. package/lib/cluster/json-source.d.cts +5 -0
  72. package/lib/cluster/json-source.d.mts +5 -0
  73. package/lib/cluster/json-source.d.ts +1 -0
  74. package/lib/cluster/json-source.mjs +1 -0
  75. package/lib/cluster/payload-value.cjs +1 -0
  76. package/lib/cluster/payload-value.d.cts +8 -0
  77. package/lib/cluster/payload-value.d.mts +8 -0
  78. package/lib/cluster/payload-value.d.ts +1 -0
  79. package/lib/cluster/payload-value.mjs +1 -0
  80. package/lib/cluster/queue.d.cts +15 -0
  81. package/lib/cluster/queue.d.mts +15 -0
  82. package/lib/cluster/socket.cjs +8 -0
  83. package/lib/cluster/socket.d.cts +13 -0
  84. package/lib/cluster/socket.d.mts +13 -0
  85. package/lib/cluster/socket.d.ts +2 -0
  86. package/lib/cluster/socket.mjs +7 -0
  87. package/lib/cluster/subscriptions.d.cts +73 -0
  88. package/lib/cluster/subscriptions.d.mts +73 -0
  89. package/lib/cluster/subscriptions.d.ts +5 -1
  90. package/lib/cluster/validators.cjs +1 -0
  91. package/lib/cluster/validators.d.cts +7 -0
  92. package/lib/cluster/validators.d.mts +7 -0
  93. package/lib/cluster/validators.d.ts +1 -0
  94. package/lib/cluster/validators.mjs +1 -0
  95. package/lib/cluster-worker/engine-adapter-common.js +37 -0
  96. package/lib/cluster-worker/engine-adapter.js +24 -30
  97. package/lib/cluster-worker/engine-start.js +59 -0
  98. package/lib/cluster-worker/index.js +49 -67
  99. package/lib/cluster-worker/profiles.js +1 -42
  100. package/lib/cluster-worker/runtime-dependencies.js +49 -0
  101. package/lib/cluster-worker/runtime-support.js +2 -34
  102. package/lib/cluster-worker/terminal-normalizer.js +9 -10
  103. package/lib/hosted-session/authority.cjs +61 -0
  104. package/lib/hosted-session/authority.d.cts +3 -0
  105. package/lib/hosted-session/authority.d.mts +3 -0
  106. package/lib/hosted-session/authority.d.ts +3 -0
  107. package/lib/hosted-session/authority.mjs +57 -0
  108. package/lib/hosted-session/coordinator.cjs +78 -51
  109. package/lib/hosted-session/coordinator.d.cts +11 -0
  110. package/lib/hosted-session/coordinator.d.mts +11 -0
  111. package/lib/hosted-session/coordinator.d.ts +4 -2
  112. package/lib/hosted-session/coordinator.mjs +75 -51
  113. package/lib/hosted-session/errors.cjs +25 -0
  114. package/lib/hosted-session/errors.d.cts +10 -0
  115. package/lib/hosted-session/errors.d.mts +10 -0
  116. package/lib/hosted-session/errors.d.ts +10 -0
  117. package/lib/hosted-session/errors.mjs +19 -0
  118. package/lib/hosted-session/index.cjs +4 -1
  119. package/lib/hosted-session/index.d.cts +2 -0
  120. package/lib/hosted-session/index.d.mts +2 -0
  121. package/lib/hosted-session/index.d.ts +2 -2
  122. package/lib/hosted-session/index.mjs +1 -1
  123. package/lib/hosted-session/reconnecting-watch.cjs +131 -0
  124. package/lib/hosted-session/reconnecting-watch.d.cts +13 -0
  125. package/lib/hosted-session/reconnecting-watch.d.mts +13 -0
  126. package/lib/hosted-session/reconnecting-watch.d.ts +13 -0
  127. package/lib/hosted-session/reconnecting-watch.mjs +127 -0
  128. package/lib/hosted-session/types.d.cts +32 -0
  129. package/lib/hosted-session/types.d.mts +32 -0
  130. package/lib/hosted-session/types.d.ts +19 -7
  131. package/lib/hosted-target/access-url.cjs +44 -0
  132. package/lib/hosted-target/access-url.d.cts +2 -0
  133. package/lib/hosted-target/access-url.d.mts +2 -0
  134. package/lib/hosted-target/access-url.d.ts +2 -0
  135. package/lib/hosted-target/access-url.mjs +41 -0
  136. package/lib/hosted-target/adapter-request.cjs +12 -0
  137. package/lib/hosted-target/adapter-request.d.cts +17 -0
  138. package/lib/hosted-target/adapter-request.d.mts +17 -0
  139. package/lib/hosted-target/adapter-request.d.ts +17 -0
  140. package/lib/hosted-target/adapter-request.mjs +9 -0
  141. package/lib/hosted-target/adapter-types.cjs +2 -0
  142. package/lib/hosted-target/adapter-types.d.cts +27 -0
  143. package/lib/hosted-target/adapter-types.d.mts +27 -0
  144. package/lib/hosted-target/adapter-types.d.ts +27 -0
  145. package/lib/hosted-target/adapter-types.mjs +1 -0
  146. package/lib/hosted-target/bounds.cjs +10 -0
  147. package/lib/hosted-target/bounds.d.cts +7 -0
  148. package/lib/hosted-target/bounds.d.mts +7 -0
  149. package/lib/hosted-target/bounds.d.ts +7 -0
  150. package/lib/hosted-target/bounds.mjs +7 -0
  151. package/lib/hosted-target/capsule-error-response.cjs +76 -0
  152. package/lib/hosted-target/capsule-error-response.d.cts +2 -0
  153. package/lib/hosted-target/capsule-error-response.d.mts +2 -0
  154. package/lib/hosted-target/capsule-error-response.d.ts +2 -0
  155. package/lib/hosted-target/capsule-error-response.mjs +73 -0
  156. package/lib/hosted-target/errors.cjs +88 -0
  157. package/lib/hosted-target/errors.d.cts +36 -0
  158. package/lib/hosted-target/errors.d.mts +36 -0
  159. package/lib/hosted-target/errors.d.ts +36 -0
  160. package/lib/hosted-target/errors.mjs +75 -0
  161. package/lib/hosted-target/index.cjs +16 -0
  162. package/lib/hosted-target/index.d.cts +3 -0
  163. package/lib/hosted-target/index.d.mts +3 -0
  164. package/lib/hosted-target/index.d.ts +3 -0
  165. package/lib/hosted-target/index.mjs +2 -0
  166. package/lib/hosted-target/response-validation.cjs +169 -0
  167. package/lib/hosted-target/response-validation.d.cts +5 -0
  168. package/lib/hosted-target/response-validation.d.mts +5 -0
  169. package/lib/hosted-target/response-validation.d.ts +5 -0
  170. package/lib/hosted-target/response-validation.mjs +163 -0
  171. package/lib/hosted-target/retry-executor.cjs +51 -0
  172. package/lib/hosted-target/retry-executor.d.cts +8 -0
  173. package/lib/hosted-target/retry-executor.d.mts +8 -0
  174. package/lib/hosted-target/retry-executor.d.ts +8 -0
  175. package/lib/hosted-target/retry-executor.mjs +48 -0
  176. package/lib/hosted-target/retry.cjs +78 -0
  177. package/lib/hosted-target/retry.d.cts +9 -0
  178. package/lib/hosted-target/retry.d.mts +9 -0
  179. package/lib/hosted-target/retry.d.ts +9 -0
  180. package/lib/hosted-target/retry.mjs +73 -0
  181. package/lib/hosted-target/target-adapter.cjs +10 -0
  182. package/lib/hosted-target/target-adapter.d.cts +3 -0
  183. package/lib/hosted-target/target-adapter.d.mts +3 -0
  184. package/lib/hosted-target/target-adapter.d.ts +3 -0
  185. package/lib/hosted-target/target-adapter.mjs +7 -0
  186. package/lib/hosted-target/types.cjs +4 -0
  187. package/lib/hosted-target/types.d.cts +50 -0
  188. package/lib/hosted-target/types.d.mts +50 -0
  189. package/lib/hosted-target/types.d.ts +50 -0
  190. package/lib/hosted-target/types.mjs +1 -0
  191. package/lib/hosted-target/zero-cloud-v1-adapter.cjs +185 -0
  192. package/lib/hosted-target/zero-cloud-v1-adapter.d.cts +13 -0
  193. package/lib/hosted-target/zero-cloud-v1-adapter.d.mts +13 -0
  194. package/lib/hosted-target/zero-cloud-v1-adapter.d.ts +13 -0
  195. package/lib/hosted-target/zero-cloud-v1-adapter.mjs +181 -0
  196. package/lib/start-cluster.js +3 -3
  197. package/lib/target/bounded-response.cjs +51 -0
  198. package/lib/target/bounded-response.d.cts +1 -0
  199. package/lib/target/bounded-response.d.mts +1 -0
  200. package/lib/target/bounded-response.d.ts +1 -0
  201. package/lib/target/bounded-response.js +51 -0
  202. package/lib/target/bounded-response.mjs +48 -0
  203. package/lib/target/credential-lock.js +1 -3
  204. package/lib/target/credential-store.js +9 -4
  205. package/lib/target/device-flow.cjs +213 -0
  206. package/lib/target/device-flow.d.cts +54 -0
  207. package/lib/target/device-flow.d.mts +54 -0
  208. package/lib/target/device-flow.d.ts +26 -14
  209. package/lib/target/device-flow.js +162 -58
  210. package/lib/target/device-flow.mjs +203 -0
  211. package/lib/target/discovery-errors.cjs +10 -0
  212. package/lib/target/discovery-errors.d.cts +3 -0
  213. package/lib/target/discovery-errors.d.mts +3 -0
  214. package/lib/target/discovery-errors.d.ts +3 -0
  215. package/lib/target/discovery-errors.js +10 -0
  216. package/lib/target/discovery-errors.mjs +6 -0
  217. package/lib/target/discovery-sections.cjs +191 -0
  218. package/lib/target/discovery-sections.d.cts +52 -0
  219. package/lib/target/discovery-sections.d.mts +52 -0
  220. package/lib/target/discovery-sections.d.ts +52 -0
  221. package/lib/target/discovery-sections.js +191 -0
  222. package/lib/target/discovery-sections.mjs +179 -0
  223. package/lib/target/discovery-validation.cjs +109 -0
  224. package/lib/target/discovery-validation.d.cts +28 -0
  225. package/lib/target/discovery-validation.d.mts +28 -0
  226. package/lib/target/discovery-validation.d.ts +28 -0
  227. package/lib/target/discovery-validation.js +109 -0
  228. package/lib/target/discovery-validation.mjs +99 -0
  229. package/lib/target/discovery.cjs +112 -0
  230. package/lib/target/discovery.d.cts +74 -0
  231. package/lib/target/discovery.d.mts +74 -0
  232. package/lib/target/discovery.d.ts +67 -5
  233. package/lib/target/discovery.js +94 -79
  234. package/lib/target/discovery.mjs +105 -0
  235. package/lib/target/index.d.ts +6 -6
  236. package/lib/target/index.js +36 -36
  237. package/lib/target/oauth-http.d.ts +2 -0
  238. package/lib/target/oauth-http.js +25 -0
  239. package/lib/target/refresh-exchange.d.ts +11 -0
  240. package/lib/target/refresh-exchange.js +24 -0
  241. package/lib/target/refresh-revocation.d.ts +8 -0
  242. package/lib/target/refresh-revocation.js +19 -0
  243. package/lib/target/route-template.cjs +85 -0
  244. package/lib/target/route-template.d.cts +7 -0
  245. package/lib/target/route-template.d.mts +7 -0
  246. package/lib/target/route-template.d.ts +7 -0
  247. package/lib/target/route-template.js +85 -0
  248. package/lib/target/route-template.mjs +81 -0
  249. package/lib/target/session-errors.d.ts +4 -0
  250. package/lib/target/session-errors.js +12 -0
  251. package/lib/target/session-verification.d.ts +10 -0
  252. package/lib/target/session-verification.js +42 -0
  253. package/lib/target/target-registry.d.ts +7 -3
  254. package/lib/target/target-registry.js +41 -10
  255. package/lib/target/target-session-manager.d.ts +48 -0
  256. package/lib/target/target-session-manager.js +226 -0
  257. package/lib/target/target-session.d.ts +39 -32
  258. package/lib/target/target-session.js +63 -151
  259. package/lib/target/token-response.cjs +51 -0
  260. package/lib/target/token-response.d.cts +7 -0
  261. package/lib/target/token-response.d.mts +7 -0
  262. package/lib/target/token-response.d.ts +7 -0
  263. package/lib/target/token-response.js +51 -0
  264. package/lib/target/token-response.mjs +48 -0
  265. package/package.json +14 -7
  266. package/protocol/openengine-cluster/v1/worker.schema.json +171 -9
  267. package/scripts/build-cluster.js +23 -3
  268. package/scripts/opcore-introduced-check.js +0 -2
  269. package/src/agent-cli-provider/adapters/codex.ts +0 -1
  270. package/src/agent-cli-provider/contract-actions.ts +9 -5
  271. package/src/agent-cli-provider/contract-invoke.ts +3 -2
  272. package/src/agent-cli-provider/contract-support.ts +12 -6
  273. package/src/agent-cli-provider/contract.ts +6 -1
  274. package/src/agent-cli-provider/index.ts +1 -0
  275. package/src/agent-cli-provider/provider-registry.ts +4 -0
  276. package/src/agent-cli-provider/single-agent-runtime.ts +32 -45
  277. package/src/cluster/client.ts +42 -15
  278. package/src/cluster/connection-state.ts +33 -0
  279. package/src/cluster/connection-types.ts +28 -0
  280. package/src/cluster/connection.ts +37 -68
  281. package/src/cluster/errors.ts +5 -0
  282. package/src/cluster/index.ts +3 -1
  283. package/src/cluster/json-source.ts +1 -0
  284. package/src/cluster/payload-value.ts +1 -0
  285. package/src/cluster/socket.ts +13 -0
  286. package/src/cluster/subscriptions.ts +7 -2
  287. package/src/cluster/validators.ts +1 -0
  288. package/src/cluster/ws.d.ts +1 -1
  289. package/src/hosted-session/authority.ts +77 -0
  290. package/src/hosted-session/coordinator.ts +113 -56
  291. package/src/hosted-session/errors.ts +21 -0
  292. package/src/hosted-session/index.ts +14 -2
  293. package/src/hosted-session/reconnecting-watch.ts +148 -0
  294. package/src/hosted-session/types.ts +22 -8
  295. package/src/hosted-target/access-url.ts +46 -0
  296. package/src/hosted-target/adapter-request.ts +28 -0
  297. package/src/hosted-target/adapter-types.ts +39 -0
  298. package/src/hosted-target/bounds.ts +1 -0
  299. package/src/hosted-target/capsule-error-response.ts +107 -0
  300. package/src/hosted-target/errors.ts +36 -35
  301. package/src/hosted-target/index.ts +10 -23
  302. package/src/hosted-target/response-validation.ts +170 -62
  303. package/src/hosted-target/retry-executor.ts +62 -0
  304. package/src/hosted-target/retry.ts +47 -11
  305. package/src/hosted-target/target-adapter.ts +12 -8
  306. package/src/hosted-target/types.ts +19 -18
  307. package/src/hosted-target/zero-cloud-v1-adapter.ts +229 -316
  308. package/src/isolation-manager.js +1 -16
  309. package/src/target/bounded-response.ts +68 -0
  310. package/src/target/credential-lock.ts +1 -3
  311. package/src/target/credential-store.ts +14 -10
  312. package/src/target/device-flow.ts +209 -85
  313. package/src/target/discovery-errors.ts +6 -0
  314. package/src/target/discovery-sections.ts +251 -0
  315. package/src/target/discovery-validation.ts +144 -0
  316. package/src/target/discovery.ts +163 -97
  317. package/src/target/index.ts +15 -11
  318. package/src/target/oauth-http.ts +27 -0
  319. package/src/target/refresh-exchange.ts +36 -0
  320. package/src/target/refresh-revocation.ts +29 -0
  321. package/src/target/route-template.ts +105 -0
  322. package/src/target/session-errors.ts +9 -0
  323. package/src/target/session-verification.ts +51 -0
  324. package/src/target/target-registry.ts +60 -27
  325. package/src/target/target-session-manager.ts +285 -0
  326. package/src/target/target-session.ts +105 -226
  327. package/src/target/token-response.ts +62 -0
  328. package/docker/zeroshot-oecp/Cargo.toml +0 -12
  329. package/docker/zeroshot-oecp/Dockerfile +0 -65
  330. package/docker/zeroshot-oecp/src/main.rs +0 -32
  331. package/lib/target/bounded-json.d.ts +0 -6
  332. package/lib/target/bounded-json.js +0 -43
  333. package/lib/target/hosted-run/client.d.ts +0 -26
  334. package/lib/target/hosted-run/client.js +0 -158
  335. package/lib/target/hosted-run/commands.d.ts +0 -4
  336. package/lib/target/hosted-run/commands.js +0 -113
  337. package/lib/target/hosted-run/contracts.d.ts +0 -49
  338. package/lib/target/hosted-run/input.d.ts +0 -5
  339. package/lib/target/hosted-run/input.js +0 -200
  340. package/lib/target/hosted-run.d.ts +0 -4
  341. package/lib/target/hosted-run.js +0 -12
  342. package/src/target/bounded-json.ts +0 -48
  343. package/src/target/hosted-run/client.ts +0 -198
  344. package/src/target/hosted-run/commands.ts +0 -140
  345. package/src/target/hosted-run/contracts.ts +0 -53
  346. package/src/target/hosted-run/input.ts +0 -199
  347. package/src/target/hosted-run.ts +0 -8
@@ -0,0 +1,251 @@
1
+ import { TargetDiscoveryError } from './discovery-errors.js';
2
+ import {
3
+ closedRecord,
4
+ exact,
5
+ exactStringSet,
6
+ integer,
7
+ parseCredentialInstall,
8
+ sameOriginUrl,
9
+ stringField,
10
+ type CredentialInstallDescriptor,
11
+ } from './discovery-validation.js';
12
+ import { routeTemplate } from './route-template.js';
13
+
14
+ export function parseAdapter(discovery: Record<string, unknown>): {
15
+ readonly name: 'fargate' | 'docker' | 'local';
16
+ readonly majorVersion: 1;
17
+ } {
18
+ const adapter = closedRecord(discovery.adapter, 'adapter', ['name', 'major_version']);
19
+ if (!['fargate', 'docker', 'local'].includes(String(adapter.name))) {
20
+ throw new TargetDiscoveryError('adapter.name is not supported');
21
+ }
22
+ exact(adapter.major_version, 1, 'adapter.major_version');
23
+ return Object.freeze({
24
+ name: adapter.name as 'fargate' | 'docker' | 'local',
25
+ majorVersion: 1 as const,
26
+ });
27
+ }
28
+
29
+ export function validateCachePolicy(discovery: Record<string, unknown>): void {
30
+ const cache = closedRecord(discovery.cache_policy, 'cache_policy', ['control', 'discovery']);
31
+ exact(cache.control, 'no-store', 'cache_policy.control');
32
+ if (cache.discovery !== undefined && cache.discovery !== null &&
33
+ typeof cache.discovery !== 'string') {
34
+ throw new TargetDiscoveryError('cache_policy.discovery must be a string or null');
35
+ }
36
+ }
37
+
38
+ export function parseSizes(discovery: Record<string, unknown>): {
39
+ readonly catalog: readonly ('tiny' | 'small' | 'standard' | 'large')[];
40
+ readonly default: 'tiny' | 'small' | 'standard' | 'large';
41
+ } {
42
+ const sizes = closedRecord(discovery.sizes, 'sizes', ['catalog', 'default']);
43
+ if (!Array.isArray(sizes.catalog) || sizes.catalog.length === 0 ||
44
+ new Set(sizes.catalog).size !== sizes.catalog.length ||
45
+ sizes.catalog.some((size) => !['tiny', 'small', 'standard', 'large'].includes(String(size)))) {
46
+ throw new TargetDiscoveryError('sizes.catalog contains an unsupported size');
47
+ }
48
+ if (!sizes.catalog.includes(sizes.default)) {
49
+ throw new TargetDiscoveryError('sizes.default is not in sizes.catalog');
50
+ }
51
+ return Object.freeze({
52
+ catalog: Object.freeze([...(sizes.catalog as Array<'tiny' | 'small' | 'standard' | 'large'>)]),
53
+ default: sizes.default as 'tiny' | 'small' | 'standard' | 'large',
54
+ });
55
+ }
56
+
57
+ export function parseExtensions(
58
+ discovery: Record<string, unknown>,
59
+ origin: string,
60
+ ): CredentialInstallDescriptor | null {
61
+ if (discovery.extensions === undefined || discovery.extensions === null) return null;
62
+ const extensions = closedRecord(discovery.extensions, 'extensions', [
63
+ 'connections', 'credential_install',
64
+ ]);
65
+ if (extensions.connections === undefined) {
66
+ throw new TargetDiscoveryError('extensions.connections is required');
67
+ }
68
+ const connections = closedRecord(extensions.connections, 'extensions.connections', [
69
+ 'kind', 'base_url', 'route_templates',
70
+ ]);
71
+ exact(connections.kind, 'zerocloud.connections/v1', 'extensions.connections.kind');
72
+ sameOriginUrl(connections.base_url, 'extensions.connections.base_url', origin);
73
+ const routes = closedRecord(connections.route_templates, 'extensions.connections.route_templates', [
74
+ 'list', 'create', 'update',
75
+ ]);
76
+ routeTemplate(routes.list, 'extensions.connections.route_templates.list', []);
77
+ routeTemplate(routes.create, 'extensions.connections.route_templates.create', []);
78
+ routeTemplate(routes.update, 'extensions.connections.route_templates.update', ['connection_id']);
79
+ return parseCredentialInstall(extensions.credential_install);
80
+ }
81
+
82
+ export function validateOAuthMetadata(
83
+ metadata: Record<string, unknown>,
84
+ origin: string,
85
+ expected: readonly [string, string, string],
86
+ ): void {
87
+ const device = sameOriginUrl(
88
+ metadata.device_authorization_endpoint,
89
+ 'OAuth metadata device_authorization_endpoint',
90
+ origin,
91
+ );
92
+ const token = sameOriginUrl(metadata.token_endpoint, 'OAuth metadata token_endpoint', origin);
93
+ const revoke = sameOriginUrl(
94
+ metadata.revocation_endpoint,
95
+ 'OAuth metadata revocation_endpoint',
96
+ origin,
97
+ );
98
+ if (device !== expected[0] || token !== expected[1] || revoke !== expected[2]) {
99
+ throw new TargetDiscoveryError('OAuth metadata does not match hosted-target discovery');
100
+ }
101
+ }
102
+
103
+ export function parseEndpoint(discovery: Record<string, unknown>, origin: string) {
104
+ const protocol = closedRecord(discovery.protocol, 'protocol', ['name', 'major_version']);
105
+ exact(protocol.name, 'openengine.cluster/v1', 'protocol.name');
106
+ exact(protocol.major_version, 1, 'protocol.major_version');
107
+ const binding = closedRecord(discovery.binding, 'binding', ['scope', 'auth_location']);
108
+ exact(binding.scope, 'organization', 'binding.scope');
109
+ exact(binding.auth_location, 'authorization_header', 'binding.auth_location');
110
+ const endpoint = closedRecord(discovery.endpoint, 'endpoint', ['url', 'capabilities']);
111
+ const capabilities = exactStringSet(
112
+ endpoint.capabilities,
113
+ 'endpoint.capabilities',
114
+ ['exec', 'log_stream'],
115
+ ) as readonly ['exec', 'log_stream'];
116
+ const pagination = closedRecord(discovery.pagination, 'pagination', [
117
+ 'default_page_size',
118
+ 'max_page_size',
119
+ ]);
120
+ const defaultPageSize = integer(
121
+ pagination.default_page_size,
122
+ 'pagination.default_page_size',
123
+ 1,
124
+ );
125
+ const maxPageSize = integer(pagination.max_page_size, 'pagination.max_page_size', 1);
126
+ if (defaultPageSize > maxPageSize) {
127
+ throw new TargetDiscoveryError('pagination.default_page_size exceeds maximum');
128
+ }
129
+ validateCachePolicy(discovery);
130
+ const schemaLinks = closedRecord(discovery.schema_links, 'schema_links', [
131
+ 'self',
132
+ 'problem',
133
+ 'errors',
134
+ ]);
135
+ sameOriginUrl(schemaLinks.self, 'schema_links.self', origin);
136
+ sameOriginUrl(schemaLinks.problem, 'schema_links.problem', origin);
137
+ sameOriginUrl(schemaLinks.errors, 'schema_links.errors', origin);
138
+ return Object.freeze({
139
+ url: sameOriginUrl(endpoint.url, 'endpoint.url', origin),
140
+ capabilities,
141
+ pagination: Object.freeze({ defaultPageSize, maxPageSize }),
142
+ });
143
+ }
144
+
145
+ export function parseCapsule(discovery: Record<string, unknown>, origin: string) {
146
+ const capsule = closedRecord(discovery.capsule_protocol, 'capsule_protocol', [
147
+ 'name',
148
+ 'major_version',
149
+ 'base_url',
150
+ 'route_templates',
151
+ ]);
152
+ exact(capsule.name, 'openengine.capsules/v1', 'capsule_protocol.name');
153
+ exact(capsule.major_version, 1, 'capsule_protocol.major_version');
154
+ const routes = closedRecord(
155
+ capsule.route_templates,
156
+ 'capsule_protocol.route_templates',
157
+ ['allocate', 'list', 'inspect', 'terminate', 'limits', 'access'],
158
+ );
159
+ const route = (name: string, variables: readonly string[]) =>
160
+ routeTemplate(routes[name], `capsule_protocol.route_templates.${name}`, variables);
161
+ return Object.freeze({
162
+ baseUrl: sameOriginUrl(capsule.base_url, 'capsule_protocol.base_url', origin),
163
+ routes: Object.freeze({
164
+ allocate: route('allocate', ['org_id']),
165
+ list: route('list', ['org_id', 'cursor', 'limit']),
166
+ inspect: route('inspect', ['org_id', 'capsule_id']),
167
+ terminate: route('terminate', ['org_id', 'capsule_id']),
168
+ limits: route('limits', ['org_id']),
169
+ access: route('access', ['capsule_id']),
170
+ }),
171
+ });
172
+ }
173
+
174
+ export function parseOAuth(discovery: Record<string, unknown>, origin: string) {
175
+ const oauth = closedRecord(discovery.oauth, 'oauth', [
176
+ 'metadata_url',
177
+ 'device_authorization_endpoint',
178
+ 'token_endpoint',
179
+ 'revocation_endpoint',
180
+ 'client_id',
181
+ 'device_grant_type',
182
+ 'device_exchange_fields',
183
+ 'audience',
184
+ ]);
185
+ exact(
186
+ oauth.device_grant_type,
187
+ 'urn:ietf:params:oauth:grant-type:device_code',
188
+ 'oauth.device_grant_type',
189
+ );
190
+ exactStringSet(
191
+ oauth.device_exchange_fields,
192
+ 'oauth.device_exchange_fields',
193
+ ['device_token', 'device_label'],
194
+ );
195
+ exact(oauth.audience, 'capsule', 'oauth.audience');
196
+ return Object.freeze({
197
+ metadataUrl: sameOriginUrl(oauth.metadata_url, 'oauth.metadata_url', origin),
198
+ deviceAuthorizationEndpoint: sameOriginUrl(
199
+ oauth.device_authorization_endpoint,
200
+ 'oauth.device_authorization_endpoint',
201
+ origin,
202
+ ),
203
+ tokenEndpoint: sameOriginUrl(oauth.token_endpoint, 'oauth.token_endpoint', origin),
204
+ revocationEndpoint: sameOriginUrl(
205
+ oauth.revocation_endpoint,
206
+ 'oauth.revocation_endpoint',
207
+ origin,
208
+ ),
209
+ clientId: stringField(oauth, 'client_id', 'oauth.'),
210
+ deviceGrantType: 'urn:ietf:params:oauth:grant-type:device_code' as const,
211
+ audience: 'capsule' as const,
212
+ });
213
+ }
214
+
215
+ export function parseSession(discovery: Record<string, unknown>) {
216
+ const session = closedRecord(discovery.session, 'session', [
217
+ 'route_template',
218
+ 'method',
219
+ 'cache_policy',
220
+ ]);
221
+ exact(session.method, 'GET', 'session.method');
222
+ exact(session.cache_policy, 'no-store', 'session.cache_policy');
223
+ return Object.freeze({
224
+ routeTemplate: routeTemplate(session.route_template, 'session.route_template', []),
225
+ method: 'GET' as const,
226
+ });
227
+ }
228
+
229
+ export function parseTransport(discovery: Record<string, unknown>) {
230
+ const transport = closedRecord(discovery.transport, 'transport', [
231
+ 'websocket_route_template',
232
+ 'unauthorized_status',
233
+ 'close_codes',
234
+ ]);
235
+ exact(transport.unauthorized_status, 401, 'transport.unauthorized_status');
236
+ const closeCodes = closedRecord(transport.close_codes, 'transport.close_codes', [
237
+ 'expired',
238
+ 'revoked',
239
+ ]);
240
+ exact(closeCodes.expired, 4401, 'transport.close_codes.expired');
241
+ exact(closeCodes.revoked, 4403, 'transport.close_codes.revoked');
242
+ return Object.freeze({
243
+ websocketRouteTemplate: routeTemplate(
244
+ transport.websocket_route_template,
245
+ 'transport.websocket_route_template',
246
+ ['capsule_id'],
247
+ ),
248
+ unauthorizedStatus: 401 as const,
249
+ closeCodes: Object.freeze({ expired: 4401 as const, revoked: 4403 as const }),
250
+ });
251
+ }
@@ -0,0 +1,144 @@
1
+ import { TargetDiscoveryError } from './discovery-errors.js';
2
+ import { routeTemplate, type RouteTemplate } from './route-template.js';
3
+
4
+ export interface CredentialInstallDescriptor {
5
+ readonly kind: 'openengine.capsule-credential-install/v1';
6
+ readonly grant: { readonly routeTemplate: RouteTemplate; readonly method: 'POST' };
7
+ readonly install: { readonly routeTemplate: RouteTemplate; readonly method: 'PUT' };
8
+ readonly uploadUrlOrigin: 'same_origin';
9
+ readonly sealedEnvelopeAlgorithms: readonly ['RSA-OAEP-3072-SHA256'];
10
+ readonly bounds: {
11
+ readonly maxEnvelopeBytes: number;
12
+ readonly maxBodyBytes: number;
13
+ readonly grantTtlSeconds: number;
14
+ readonly maxClockSkewSeconds: number;
15
+ };
16
+ }
17
+
18
+ export function record(value: unknown, field: string): Record<string, unknown> {
19
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
20
+ throw new TargetDiscoveryError(`${field} must be an object`);
21
+ }
22
+ return value as Record<string, unknown>;
23
+ }
24
+
25
+ export function closedRecord(
26
+ value: unknown,
27
+ field: string,
28
+ fields: readonly string[],
29
+ ): Record<string, unknown> {
30
+ const result = record(value, field);
31
+ const unknown = Object.keys(result).find((key) => !fields.includes(key));
32
+ if (unknown !== undefined) throw new TargetDiscoveryError(`${field}.${unknown} is not supported`);
33
+ return result;
34
+ }
35
+
36
+ export function stringField(
37
+ source: Record<string, unknown>,
38
+ field: string,
39
+ parent = '',
40
+ ): string {
41
+ const value = source[field];
42
+ if (typeof value !== 'string' || value.length === 0) {
43
+ throw new TargetDiscoveryError(`${parent}${field} must be a non-empty string`);
44
+ }
45
+ return value;
46
+ }
47
+
48
+ export function exact(value: unknown, expected: unknown, field: string): void {
49
+ if (value !== expected) throw new TargetDiscoveryError(`${field} is not supported`);
50
+ }
51
+
52
+ export function integer(
53
+ value: unknown,
54
+ field: string,
55
+ min: number,
56
+ max = Number.MAX_SAFE_INTEGER,
57
+ ): number {
58
+ if (!Number.isSafeInteger(value) || (value as number) < min || (value as number) > max) {
59
+ throw new TargetDiscoveryError(`${field} is outside the supported bounds`);
60
+ }
61
+ return value as number;
62
+ }
63
+
64
+ export function exactStringSet(
65
+ value: unknown,
66
+ field: string,
67
+ expected: readonly string[],
68
+ ): readonly string[] {
69
+ if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) {
70
+ throw new TargetDiscoveryError(`${field} must be an array of strings`);
71
+ }
72
+ if (value.length !== expected.length || new Set(value).size !== value.length ||
73
+ expected.some((item) => !value.includes(item))) {
74
+ throw new TargetDiscoveryError(`${field} does not match the supported contract`);
75
+ }
76
+ return Object.freeze([...value]) as readonly string[];
77
+ }
78
+
79
+ function hasForbiddenUrlComponent(
80
+ url: URL,
81
+ value: string,
82
+ protocols: readonly string[],
83
+ ): boolean {
84
+ return !protocols.includes(url.protocol) ||
85
+ url.username !== '' ||
86
+ url.password !== '' ||
87
+ url.search !== '' ||
88
+ url.hash !== '' ||
89
+ url.href !== value;
90
+ }
91
+
92
+ export function sameOriginUrl(
93
+ value: unknown,
94
+ field: string,
95
+ origin: string,
96
+ protocols: readonly string[] = ['https:', 'http:'],
97
+ ): string {
98
+ if (typeof value !== 'string' || /[\u0000-\u0020\u007f]|\s/u.test(value)) {
99
+ throw new TargetDiscoveryError(`${field} must be a canonical absolute URL`);
100
+ }
101
+ let url: URL;
102
+ try {
103
+ url = new URL(value);
104
+ } catch {
105
+ throw new TargetDiscoveryError(`${field} must be an absolute URL`);
106
+ }
107
+ if (hasForbiddenUrlComponent(url, value, protocols)) {
108
+ throw new TargetDiscoveryError(`${field} contains forbidden URL components`);
109
+ }
110
+ if (url.origin !== origin) {
111
+ throw new TargetDiscoveryError(`${field} must remain on the target origin`);
112
+ }
113
+ return url.href;
114
+ }
115
+
116
+ export function parseCredentialInstall(value: unknown): CredentialInstallDescriptor | null {
117
+ if (value === undefined || value === null) return null;
118
+ const extension = closedRecord(value, 'extensions.credential_install', [
119
+ 'kind', 'grant', 'install', 'upload_url_origin', 'sealed_envelope_algorithms', 'bounds',
120
+ ]);
121
+ exact(extension.kind, 'openengine.capsule-credential-install/v1', 'extensions.credential_install.kind');
122
+ const grant = closedRecord(extension.grant, 'extensions.credential_install.grant', ['route_template', 'method']);
123
+ const install = closedRecord(extension.install, 'extensions.credential_install.install', ['route_template', 'method']);
124
+ exact(grant.method, 'POST', 'extensions.credential_install.grant.method');
125
+ exact(install.method, 'PUT', 'extensions.credential_install.install.method');
126
+ exact(extension.upload_url_origin, 'same_origin', 'extensions.credential_install.upload_url_origin');
127
+ exactStringSet(extension.sealed_envelope_algorithms, 'extensions.credential_install.sealed_envelope_algorithms', ['RSA-OAEP-3072-SHA256']);
128
+ const bounds = closedRecord(extension.bounds, 'extensions.credential_install.bounds', [
129
+ 'max_envelope_bytes', 'max_body_bytes', 'grant_ttl_seconds', 'max_clock_skew_seconds',
130
+ ]);
131
+ return Object.freeze({
132
+ kind: 'openengine.capsule-credential-install/v1' as const,
133
+ grant: Object.freeze({ routeTemplate: routeTemplate(grant.route_template, 'extensions.credential_install.grant.route_template', ['capsule_id']), method: 'POST' as const }),
134
+ install: Object.freeze({ routeTemplate: routeTemplate(install.route_template, 'extensions.credential_install.install.route_template', ['capsule_id']), method: 'PUT' as const }),
135
+ uploadUrlOrigin: 'same_origin' as const,
136
+ sealedEnvelopeAlgorithms: Object.freeze(['RSA-OAEP-3072-SHA256'] as const),
137
+ bounds: Object.freeze({
138
+ maxEnvelopeBytes: integer(bounds.max_envelope_bytes, 'extensions.credential_install.bounds.max_envelope_bytes', 1, 1_048_576),
139
+ maxBodyBytes: integer(bounds.max_body_bytes, 'extensions.credential_install.bounds.max_body_bytes', 1, 1_048_576),
140
+ grantTtlSeconds: integer(bounds.grant_ttl_seconds, 'extensions.credential_install.bounds.grant_ttl_seconds', 1, 3_600),
141
+ maxClockSkewSeconds: integer(bounds.max_clock_skew_seconds, 'extensions.credential_install.bounds.max_clock_skew_seconds', 0, 300),
142
+ }),
143
+ });
144
+ }