okengine 0.1.4

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 (674) hide show
  1. package/AGENTS.md +91 -0
  2. package/README.md +327 -0
  3. package/docs/spec/complete-example.md +1188 -0
  4. package/docs/spec/console.md +739 -0
  5. package/docs/spec/four-applications.md +1188 -0
  6. package/docs/spec/unified-theory.md +489 -0
  7. package/package.json +152 -0
  8. package/spec/manifest.v1.schema.json +624 -0
  9. package/src/auth/api-keys.ts +168 -0
  10. package/src/auth/attenuation.ts +116 -0
  11. package/src/auth/auth.test.ts +273 -0
  12. package/src/auth/cross-plane.ts +98 -0
  13. package/src/auth/index.ts +112 -0
  14. package/src/auth/invites.ts +66 -0
  15. package/src/auth/invoke-as.ts +49 -0
  16. package/src/auth/operator.ts +178 -0
  17. package/src/auth/planes.ts +102 -0
  18. package/src/auth/plugin.ts +44 -0
  19. package/src/auth/roles.ts +84 -0
  20. package/src/auth/sessions.ts +418 -0
  21. package/src/auth/tables.ts +131 -0
  22. package/src/cli/args.ts +50 -0
  23. package/src/cli/branch.ts +75 -0
  24. package/src/cli/build.ts +86 -0
  25. package/src/cli/client-add.test.ts +140 -0
  26. package/src/cli/client-add.ts +164 -0
  27. package/src/cli/completion.test.ts +58 -0
  28. package/src/cli/completion.ts +296 -0
  29. package/src/cli/dev-app-runner.ts +77 -0
  30. package/src/cli/dev.test.ts +435 -0
  31. package/src/cli/dev.ts +594 -0
  32. package/src/cli/doc-drift.test.ts +146 -0
  33. package/src/cli/doc-drift.ts +397 -0
  34. package/src/cli/docker-cli.test.ts +221 -0
  35. package/src/cli/docker.ts +127 -0
  36. package/src/cli/doctor-diff-examples.ts +92 -0
  37. package/src/cli/doctor-diff.test.ts +91 -0
  38. package/src/cli/doctor-diff.ts +274 -0
  39. package/src/cli/doctor-pii.test.ts +98 -0
  40. package/src/cli/doctor-pii.ts +151 -0
  41. package/src/cli/doctor.test.ts +150 -0
  42. package/src/cli/doctor.ts +223 -0
  43. package/src/cli/eval.ts +122 -0
  44. package/src/cli/exit.ts +19 -0
  45. package/src/cli/gates-list.test.ts +47 -0
  46. package/src/cli/gates-list.ts +84 -0
  47. package/src/cli/images.ts +277 -0
  48. package/src/cli/index.ts +99 -0
  49. package/src/cli/json-out.test.ts +129 -0
  50. package/src/cli/load-config.ts +71 -0
  51. package/src/cli/mcp-from-console.ts +50 -0
  52. package/src/cli/privacy-erase.ts +73 -0
  53. package/src/cli/registry.ts +455 -0
  54. package/src/cli/safe-defaults.test.ts +92 -0
  55. package/src/cli/schema.ts +196 -0
  56. package/src/cli/stack.ts +82 -0
  57. package/src/cli/start.ts +106 -0
  58. package/src/cli/upgrade.ts +105 -0
  59. package/src/cli/vault-cmd.ts +140 -0
  60. package/src/client/budget-entry.ts +34 -0
  61. package/src/client/budget.test.ts +17 -0
  62. package/src/client/create.test.ts +159 -0
  63. package/src/client/create.ts +152 -0
  64. package/src/client/errors.ts +60 -0
  65. package/src/client/index.ts +35 -0
  66. package/src/client/notes-contract.test.ts +289 -0
  67. package/src/client/transport.test.ts +123 -0
  68. package/src/client/transport.ts +254 -0
  69. package/src/client/types.ts +282 -0
  70. package/src/compiler/aot.test.ts +248 -0
  71. package/src/compiler/aot.ts +182 -0
  72. package/src/compiler/differential.test.ts +241 -0
  73. package/src/compiler/dynamic.ts +54 -0
  74. package/src/compiler/effects-infer.ts +541 -0
  75. package/src/compiler/emit.ts +40 -0
  76. package/src/compiler/extract.test.ts +177 -0
  77. package/src/compiler/extract.ts +1368 -0
  78. package/src/compiler/fixtures/raw/raw-unannotated.ts +28 -0
  79. package/src/compiler/fixtures/skyport/oke.config.ts +24 -0
  80. package/src/compiler/fixtures/skyport/src/ai.ts +15 -0
  81. package/src/compiler/fixtures/skyport/src/app.ts +10 -0
  82. package/src/compiler/fixtures/skyport/src/channels.ts +6 -0
  83. package/src/compiler/fixtures/skyport/src/core.ts +3 -0
  84. package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +57 -0
  85. package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +11 -0
  86. package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +14 -0
  87. package/src/compiler/fixtures/skyport/src/flows/support/index.ts +20 -0
  88. package/src/compiler/fixtures/skyport/src/gates.ts +14 -0
  89. package/src/compiler/fixtures/skyport/src/journeys.ts +9 -0
  90. package/src/compiler/fixtures/skyport/src/schema.ts +3 -0
  91. package/src/compiler/fixtures/skyport/src/vault.ts +6 -0
  92. package/src/compiler/fixtures/skyport.expected.json +241 -0
  93. package/src/compiler/fixtures/triggers/five-triggers.ts +69 -0
  94. package/src/compiler/http-parse.ts +214 -0
  95. package/src/compiler/index.ts +67 -0
  96. package/src/compiler/response.ts +89 -0
  97. package/src/compiler/sucrose.ts +238 -0
  98. package/src/config/index.ts +167 -0
  99. package/src/console/budget.test.ts +73 -0
  100. package/src/console/index.ts +30 -0
  101. package/src/console/server/access.test.ts +370 -0
  102. package/src/console/server/access.ts +777 -0
  103. package/src/console/server/ai.test.ts +172 -0
  104. package/src/console/server/ai.ts +632 -0
  105. package/src/console/server/app.ts +294 -0
  106. package/src/console/server/auth-rate.test.ts +81 -0
  107. package/src/console/server/auth-rate.ts +72 -0
  108. package/src/console/server/bind.ts +25 -0
  109. package/src/console/server/channels.test.ts +179 -0
  110. package/src/console/server/channels.ts +469 -0
  111. package/src/console/server/claim.test.ts +66 -0
  112. package/src/console/server/claim.ts +134 -0
  113. package/src/console/server/clock.test.ts +239 -0
  114. package/src/console/server/clock.ts +390 -0
  115. package/src/console/server/console.test.ts +338 -0
  116. package/src/console/server/diff.test.ts +299 -0
  117. package/src/console/server/diff.ts +352 -0
  118. package/src/console/server/dry-run.audit.test.ts +118 -0
  119. package/src/console/server/flows-invoke.test.ts +148 -0
  120. package/src/console/server/flows.ts +3633 -0
  121. package/src/console/server/gates.test.ts +360 -0
  122. package/src/console/server/gates.ts +869 -0
  123. package/src/console/server/index.ts +141 -0
  124. package/src/console/server/live.test.ts +30 -0
  125. package/src/console/server/live.ts +109 -0
  126. package/src/console/server/plugin.ts +50 -0
  127. package/src/console/server/plugins.test.ts +131 -0
  128. package/src/console/server/plugins.ts +429 -0
  129. package/src/console/server/runs-pii.ts +98 -0
  130. package/src/console/server/security-headers.ts +97 -0
  131. package/src/console/server/security.gate.test.ts +286 -0
  132. package/src/console/server/serve.ts +319 -0
  133. package/src/console/server/signals.test.ts +88 -0
  134. package/src/console/server/signals.ts +282 -0
  135. package/src/console/server/state.ts +982 -0
  136. package/src/console/server/store.test.ts +233 -0
  137. package/src/console/server/store.ts +861 -0
  138. package/src/console/server/structural.ts +95 -0
  139. package/src/console/server/vault.test.ts +251 -0
  140. package/src/console/server/vault.ts +430 -0
  141. package/src/console/ui/access/AccessA11yView.tsx +237 -0
  142. package/src/console/ui/access/a11y.test.tsx +122 -0
  143. package/src/console/ui/access/acknowledgement.test.ts +13 -0
  144. package/src/console/ui/access/acknowledgement.ts +35 -0
  145. package/src/console/ui/access/blast-radius.test.ts +26 -0
  146. package/src/console/ui/access/blast-radius.ts +40 -0
  147. package/src/console/ui/access/confirmation.test.ts +38 -0
  148. package/src/console/ui/access/confirmation.ts +36 -0
  149. package/src/console/ui/access/fixture.ts +203 -0
  150. package/src/console/ui/access/grantable.test.ts +17 -0
  151. package/src/console/ui/access/grantable.ts +36 -0
  152. package/src/console/ui/access/hygiene.test.ts +12 -0
  153. package/src/console/ui/access/hygiene.ts +39 -0
  154. package/src/console/ui/access/index.ts +54 -0
  155. package/src/console/ui/access/provenance.test.ts +12 -0
  156. package/src/console/ui/access/provenance.ts +29 -0
  157. package/src/console/ui/access/search.test.ts +17 -0
  158. package/src/console/ui/access/search.ts +72 -0
  159. package/src/console/ui/access/types.ts +111 -0
  160. package/src/console/ui/ai/AiA11yView.tsx +265 -0
  161. package/src/console/ui/ai/a11y.test.tsx +99 -0
  162. package/src/console/ui/ai/findings.ts +41 -0
  163. package/src/console/ui/ai/fixture.ts +182 -0
  164. package/src/console/ui/ai/format.ts +90 -0
  165. package/src/console/ui/ai/group.test.ts +37 -0
  166. package/src/console/ui/ai/group.ts +88 -0
  167. package/src/console/ui/ai/index.ts +66 -0
  168. package/src/console/ui/ai/promotion.test.ts +77 -0
  169. package/src/console/ui/ai/promotion.ts +150 -0
  170. package/src/console/ui/ai/search.test.ts +40 -0
  171. package/src/console/ui/ai/search.ts +89 -0
  172. package/src/console/ui/ai/types.ts +139 -0
  173. package/src/console/ui/architecture/ArchitectureA11yView.tsx +163 -0
  174. package/src/console/ui/architecture/a11y.test.tsx +97 -0
  175. package/src/console/ui/architecture/boundary.ts +42 -0
  176. package/src/console/ui/architecture/declared.ts +165 -0
  177. package/src/console/ui/architecture/fixture.ts +74 -0
  178. package/src/console/ui/architecture/index.ts +84 -0
  179. package/src/console/ui/architecture/layers.ts +64 -0
  180. package/src/console/ui/architecture/layout.ts +68 -0
  181. package/src/console/ui/architecture/pathologies.ts +260 -0
  182. package/src/console/ui/architecture/search.ts +145 -0
  183. package/src/console/ui/architecture/traffic.ts +102 -0
  184. package/src/console/ui/architecture/types.ts +144 -0
  185. package/src/console/ui/architecture/view.test.ts +165 -0
  186. package/src/console/ui/architecture/view.ts +516 -0
  187. package/src/console/ui/channels/ChannelsA11yView.tsx +180 -0
  188. package/src/console/ui/channels/a11y.test.tsx +96 -0
  189. package/src/console/ui/channels/confirmation.test.ts +37 -0
  190. package/src/console/ui/channels/confirmation.ts +27 -0
  191. package/src/console/ui/channels/fallback.test.ts +15 -0
  192. package/src/console/ui/channels/fallback.ts +20 -0
  193. package/src/console/ui/channels/findings.ts +38 -0
  194. package/src/console/ui/channels/fixture.ts +134 -0
  195. package/src/console/ui/channels/group.ts +25 -0
  196. package/src/console/ui/channels/index.ts +57 -0
  197. package/src/console/ui/channels/locale.test.ts +17 -0
  198. package/src/console/ui/channels/locale.ts +31 -0
  199. package/src/console/ui/channels/mask.test.ts +14 -0
  200. package/src/console/ui/channels/mask.ts +12 -0
  201. package/src/console/ui/channels/search.ts +58 -0
  202. package/src/console/ui/channels/taxonomy.test.ts +17 -0
  203. package/src/console/ui/channels/taxonomy.ts +49 -0
  204. package/src/console/ui/channels/types.ts +117 -0
  205. package/src/console/ui/clock/ClockA11yView.tsx +182 -0
  206. package/src/console/ui/clock/a11y.test.tsx +99 -0
  207. package/src/console/ui/clock/confirmation.test.ts +32 -0
  208. package/src/console/ui/clock/confirmation.ts +34 -0
  209. package/src/console/ui/clock/findings.ts +40 -0
  210. package/src/console/ui/clock/fixture.ts +111 -0
  211. package/src/console/ui/clock/health.test.ts +25 -0
  212. package/src/console/ui/clock/health.ts +61 -0
  213. package/src/console/ui/clock/index.ts +49 -0
  214. package/src/console/ui/clock/search.test.ts +39 -0
  215. package/src/console/ui/clock/search.ts +76 -0
  216. package/src/console/ui/clock/timeline.test.ts +44 -0
  217. package/src/console/ui/clock/timeline.ts +41 -0
  218. package/src/console/ui/clock/types.ts +78 -0
  219. package/src/console/ui/clock/waiting-on.test.ts +34 -0
  220. package/src/console/ui/clock/waiting-on.ts +83 -0
  221. package/src/console/ui/confirmation.unify.test.ts +92 -0
  222. package/src/console/ui/diff/DiffA11yView.tsx +85 -0
  223. package/src/console/ui/diff/a11y.test.tsx +99 -0
  224. package/src/console/ui/diff/fixture.ts +85 -0
  225. package/src/console/ui/diff/group.test.ts +58 -0
  226. package/src/console/ui/diff/group.ts +97 -0
  227. package/src/console/ui/diff/index.ts +38 -0
  228. package/src/console/ui/diff/search.test.ts +32 -0
  229. package/src/console/ui/diff/search.ts +75 -0
  230. package/src/console/ui/diff/summary.ts +74 -0
  231. package/src/console/ui/diff/types.ts +48 -0
  232. package/src/console/ui/dist/assets/index-B71Yl_SS.js +10 -0
  233. package/src/console/ui/dist/assets/panel-access-Dd37LU2c.js +64 -0
  234. package/src/console/ui/dist/assets/panel-ai-CC7LR6-J.js +1 -0
  235. package/src/console/ui/dist/assets/panel-architecture-B5b3iKCz.js +1 -0
  236. package/src/console/ui/dist/assets/panel-channels-CeNjTKXp.js +1 -0
  237. package/src/console/ui/dist/assets/panel-clock-DgFTLoHV.js +1 -0
  238. package/src/console/ui/dist/assets/panel-diff-DxehccqB.js +1 -0
  239. package/src/console/ui/dist/assets/panel-flows-BtrVn-Eg.js +45 -0
  240. package/src/console/ui/dist/assets/panel-gates-Z9MKRGdH.js +1 -0
  241. package/src/console/ui/dist/assets/panel-overview-Bd48d9km.js +1 -0
  242. package/src/console/ui/dist/assets/panel-plugins-DWd0TowH.js +1 -0
  243. package/src/console/ui/dist/assets/panel-runs-BwsWqKeB.js +1 -0
  244. package/src/console/ui/dist/assets/panel-signals-9najbZY2.js +1 -0
  245. package/src/console/ui/dist/assets/panel-store-OHkP2pDp.js +1 -0
  246. package/src/console/ui/dist/assets/panel-traces-tn2JoY8U.js +1 -0
  247. package/src/console/ui/dist/assets/panel-vault-BbfWdox0.js +1 -0
  248. package/src/console/ui/dist/assets/rolldown-runtime-CNC7AqOf.js +1 -0
  249. package/src/console/ui/dist/assets/style-Cnl7WLya.css +3 -0
  250. package/src/console/ui/dist/index.html +14 -0
  251. package/src/console/ui/flows/FlowsA11yView.tsx +155 -0
  252. package/src/console/ui/flows/a11y.test.tsx +105 -0
  253. package/src/console/ui/flows/buffer.test.ts +91 -0
  254. package/src/console/ui/flows/buffer.ts +118 -0
  255. package/src/console/ui/flows/confirmation.ts +131 -0
  256. package/src/console/ui/flows/contract.test.ts +89 -0
  257. package/src/console/ui/flows/contract.ts +353 -0
  258. package/src/console/ui/flows/fixture.ts +81 -0
  259. package/src/console/ui/flows/graph.test.ts +101 -0
  260. package/src/console/ui/flows/graph.ts +549 -0
  261. package/src/console/ui/flows/index.ts +87 -0
  262. package/src/console/ui/flows/save-as-test.test.ts +47 -0
  263. package/src/console/ui/flows/save-as-test.ts +99 -0
  264. package/src/console/ui/flows/search.ts +255 -0
  265. package/src/console/ui/flows/tiers.ts +140 -0
  266. package/src/console/ui/gates/GatesA11yView.tsx +192 -0
  267. package/src/console/ui/gates/a11y.test.tsx +116 -0
  268. package/src/console/ui/gates/audit.test.ts +40 -0
  269. package/src/console/ui/gates/audit.ts +63 -0
  270. package/src/console/ui/gates/denial.test.ts +36 -0
  271. package/src/console/ui/gates/denial.ts +51 -0
  272. package/src/console/ui/gates/findings.ts +19 -0
  273. package/src/console/ui/gates/fixture.ts +189 -0
  274. package/src/console/ui/gates/group.test.ts +30 -0
  275. package/src/console/ui/gates/group.ts +102 -0
  276. package/src/console/ui/gates/index.ts +47 -0
  277. package/src/console/ui/gates/search.test.ts +49 -0
  278. package/src/console/ui/gates/search.ts +115 -0
  279. package/src/console/ui/gates/types.ts +121 -0
  280. package/src/console/ui/overview/OverviewA11yView.tsx +152 -0
  281. package/src/console/ui/overview/a11y.test.tsx +113 -0
  282. package/src/console/ui/overview/busiest.ts +26 -0
  283. package/src/console/ui/overview/compose.ts +133 -0
  284. package/src/console/ui/overview/cost.test.ts +39 -0
  285. package/src/console/ui/overview/cost.ts +138 -0
  286. package/src/console/ui/overview/fixture.ts +161 -0
  287. package/src/console/ui/overview/golden.ts +57 -0
  288. package/src/console/ui/overview/index.ts +59 -0
  289. package/src/console/ui/overview/rank.test.ts +136 -0
  290. package/src/console/ui/overview/rank.ts +210 -0
  291. package/src/console/ui/overview/slo.test.ts +73 -0
  292. package/src/console/ui/overview/slo.ts +229 -0
  293. package/src/console/ui/overview/types.ts +121 -0
  294. package/src/console/ui/overview/verdict.ts +131 -0
  295. package/src/console/ui/plugins/PluginsA11yView.tsx +227 -0
  296. package/src/console/ui/plugins/a11y.test.tsx +97 -0
  297. package/src/console/ui/plugins/command.test.ts +22 -0
  298. package/src/console/ui/plugins/command.ts +27 -0
  299. package/src/console/ui/plugins/findings.ts +39 -0
  300. package/src/console/ui/plugins/fixture.ts +233 -0
  301. package/src/console/ui/plugins/group.test.ts +38 -0
  302. package/src/console/ui/plugins/group.ts +67 -0
  303. package/src/console/ui/plugins/index.ts +40 -0
  304. package/src/console/ui/plugins/search.ts +67 -0
  305. package/src/console/ui/plugins/types.ts +115 -0
  306. package/src/console/ui/runs/RunsA11yView.tsx +267 -0
  307. package/src/console/ui/runs/a11y.test.tsx +99 -0
  308. package/src/console/ui/runs/explain.test.ts +23 -0
  309. package/src/console/ui/runs/explain.ts +32 -0
  310. package/src/console/ui/runs/fixture.ts +189 -0
  311. package/src/console/ui/runs/group.test.ts +24 -0
  312. package/src/console/ui/runs/group.ts +85 -0
  313. package/src/console/ui/runs/histogram.test.ts +31 -0
  314. package/src/console/ui/runs/histogram.ts +85 -0
  315. package/src/console/ui/runs/index.ts +75 -0
  316. package/src/console/ui/runs/project.ts +122 -0
  317. package/src/console/ui/runs/query.test.ts +50 -0
  318. package/src/console/ui/runs/query.ts +283 -0
  319. package/src/console/ui/runs/search.test.ts +45 -0
  320. package/src/console/ui/runs/search.ts +141 -0
  321. package/src/console/ui/runs/trace-link.test.ts +30 -0
  322. package/src/console/ui/runs/trace-link.ts +99 -0
  323. package/src/console/ui/runs/types.ts +137 -0
  324. package/src/console/ui/shell/App.tsx +56 -0
  325. package/src/console/ui/shell/client.ts +1715 -0
  326. package/src/console/ui/shell/components/ui.tsx +110 -0
  327. package/src/console/ui/shell/index.html +12 -0
  328. package/src/console/ui/shell/layout/Shell.tsx +95 -0
  329. package/src/console/ui/shell/main.tsx +281 -0
  330. package/src/console/ui/shell/panels/Access.tsx +5 -0
  331. package/src/console/ui/shell/panels/Ai.tsx +5 -0
  332. package/src/console/ui/shell/panels/Architecture.tsx +5 -0
  333. package/src/console/ui/shell/panels/Channels.tsx +5 -0
  334. package/src/console/ui/shell/panels/Clock.tsx +5 -0
  335. package/src/console/ui/shell/panels/Diff.tsx +5 -0
  336. package/src/console/ui/shell/panels/Flows.tsx +5 -0
  337. package/src/console/ui/shell/panels/Gates.tsx +5 -0
  338. package/src/console/ui/shell/panels/Overview.tsx +6 -0
  339. package/src/console/ui/shell/panels/Plugins.tsx +5 -0
  340. package/src/console/ui/shell/panels/Runs.tsx +5 -0
  341. package/src/console/ui/shell/panels/Signals.tsx +5 -0
  342. package/src/console/ui/shell/panels/Store.tsx +5 -0
  343. package/src/console/ui/shell/panels/Traces.tsx +5 -0
  344. package/src/console/ui/shell/panels/Vault.tsx +5 -0
  345. package/src/console/ui/shell/panels/access/AccessPanel.tsx +813 -0
  346. package/src/console/ui/shell/panels/ai/AiPanel.tsx +563 -0
  347. package/src/console/ui/shell/panels/architecture/ArchitecturePanel.tsx +377 -0
  348. package/src/console/ui/shell/panels/channels/ChannelsPanel.tsx +454 -0
  349. package/src/console/ui/shell/panels/clock/ClockPanel.tsx +479 -0
  350. package/src/console/ui/shell/panels/diff/DiffPanel.tsx +275 -0
  351. package/src/console/ui/shell/panels/flows/ContractEditor.tsx +301 -0
  352. package/src/console/ui/shell/panels/flows/FlowDrawer.tsx +350 -0
  353. package/src/console/ui/shell/panels/flows/FlowsPanel.tsx +502 -0
  354. package/src/console/ui/shell/panels/gates/GatesPanel.tsx +482 -0
  355. package/src/console/ui/shell/panels/overview/OverviewPanel.tsx +428 -0
  356. package/src/console/ui/shell/panels/plugins/PluginsPanel.tsx +413 -0
  357. package/src/console/ui/shell/panels/runs/RunsPanel.tsx +649 -0
  358. package/src/console/ui/shell/panels/signals/SignalsPanel.tsx +840 -0
  359. package/src/console/ui/shell/panels/store/StorePanel.tsx +787 -0
  360. package/src/console/ui/shell/panels/traces/TracesPanel.tsx +539 -0
  361. package/src/console/ui/shell/panels/vault/VaultPanel.tsx +449 -0
  362. package/src/console/ui/shell/plugin/Sandbox.tsx +29 -0
  363. package/src/console/ui/shell/setup/Wizard.tsx +189 -0
  364. package/src/console/ui/shell/styles.css +75 -0
  365. package/src/console/ui/signals/SignalsA11yView.tsx +276 -0
  366. package/src/console/ui/signals/a11y.test.tsx +99 -0
  367. package/src/console/ui/signals/confirmation.test.ts +39 -0
  368. package/src/console/ui/signals/confirmation.ts +63 -0
  369. package/src/console/ui/signals/dry-run.test.ts +18 -0
  370. package/src/console/ui/signals/dry-run.ts +36 -0
  371. package/src/console/ui/signals/durable.test.ts +22 -0
  372. package/src/console/ui/signals/durable.ts +41 -0
  373. package/src/console/ui/signals/findings.ts +33 -0
  374. package/src/console/ui/signals/fixture.ts +242 -0
  375. package/src/console/ui/signals/group.test.ts +32 -0
  376. package/src/console/ui/signals/group.ts +49 -0
  377. package/src/console/ui/signals/index.ts +52 -0
  378. package/src/console/ui/signals/monitor.test.ts +30 -0
  379. package/src/console/ui/signals/monitor.ts +79 -0
  380. package/src/console/ui/signals/schema-form.test.ts +34 -0
  381. package/src/console/ui/signals/schema-form.ts +112 -0
  382. package/src/console/ui/signals/search.ts +102 -0
  383. package/src/console/ui/signals/types.ts +71 -0
  384. package/src/console/ui/store/StoreA11yView.tsx +199 -0
  385. package/src/console/ui/store/a11y.test.tsx +99 -0
  386. package/src/console/ui/store/cache-view.test.ts +13 -0
  387. package/src/console/ui/store/cache-view.ts +36 -0
  388. package/src/console/ui/store/confirmation.test.ts +38 -0
  389. package/src/console/ui/store/confirmation.ts +55 -0
  390. package/src/console/ui/store/dry-run.test.ts +15 -0
  391. package/src/console/ui/store/dry-run.ts +29 -0
  392. package/src/console/ui/store/fixture.ts +163 -0
  393. package/src/console/ui/store/group.test.ts +21 -0
  394. package/src/console/ui/store/group.ts +41 -0
  395. package/src/console/ui/store/index.ts +40 -0
  396. package/src/console/ui/store/search.ts +78 -0
  397. package/src/console/ui/store/types.ts +65 -0
  398. package/src/console/ui/store/will-not-fire.test.ts +19 -0
  399. package/src/console/ui/store/will-not-fire.ts +40 -0
  400. package/src/console/ui/traces/TracesA11yView.tsx +200 -0
  401. package/src/console/ui/traces/a11y.test.tsx +97 -0
  402. package/src/console/ui/traces/chain.test.ts +61 -0
  403. package/src/console/ui/traces/chain.ts +144 -0
  404. package/src/console/ui/traces/critical-path.test.ts +24 -0
  405. package/src/console/ui/traces/critical-path.ts +59 -0
  406. package/src/console/ui/traces/filter.test.ts +78 -0
  407. package/src/console/ui/traces/filter.ts +112 -0
  408. package/src/console/ui/traces/fixture.ts +126 -0
  409. package/src/console/ui/traces/fold.test.ts +67 -0
  410. package/src/console/ui/traces/fold.ts +170 -0
  411. package/src/console/ui/traces/index.ts +64 -0
  412. package/src/console/ui/traces/mini.ts +65 -0
  413. package/src/console/ui/traces/replay.test.ts +24 -0
  414. package/src/console/ui/traces/replay.ts +35 -0
  415. package/src/console/ui/traces/sampling.test.ts +26 -0
  416. package/src/console/ui/traces/sampling.ts +66 -0
  417. package/src/console/ui/traces/search.ts +148 -0
  418. package/src/console/ui/traces/tier.ts +72 -0
  419. package/src/console/ui/traces/types.ts +125 -0
  420. package/src/console/ui/tsconfig.json +20 -0
  421. package/src/console/ui/vault/VaultA11yView.tsx +177 -0
  422. package/src/console/ui/vault/a11y.test.tsx +97 -0
  423. package/src/console/ui/vault/blast-radius.test.ts +35 -0
  424. package/src/console/ui/vault/blast-radius.ts +55 -0
  425. package/src/console/ui/vault/confirmation.test.ts +41 -0
  426. package/src/console/ui/vault/confirmation.ts +39 -0
  427. package/src/console/ui/vault/dormant.test.ts +37 -0
  428. package/src/console/ui/vault/dormant.ts +28 -0
  429. package/src/console/ui/vault/export-safe.test.ts +30 -0
  430. package/src/console/ui/vault/export-safe.ts +65 -0
  431. package/src/console/ui/vault/fixture.ts +75 -0
  432. package/src/console/ui/vault/group.test.ts +25 -0
  433. package/src/console/ui/vault/group.ts +50 -0
  434. package/src/console/ui/vault/index.ts +45 -0
  435. package/src/console/ui/vault/search.ts +62 -0
  436. package/src/console/ui/vault/types.ts +57 -0
  437. package/src/console/ui/vite.config.ts +84 -0
  438. package/src/console/xss.gate.test.ts +118 -0
  439. package/src/docker/compose.ts +226 -0
  440. package/src/docker/credentials.ts +25 -0
  441. package/src/docker/derive.ts +83 -0
  442. package/src/docker/docker.test.ts +185 -0
  443. package/src/docker/dockerfile.integration.test.ts +170 -0
  444. package/src/docker/dockerfile.ts +39 -0
  445. package/src/docker/helpers.ts +103 -0
  446. package/src/docker/index.ts +52 -0
  447. package/src/docker/pin.ts +90 -0
  448. package/src/docker/recipes/index.ts +33 -0
  449. package/src/docker/recipes/postgres.ts +18 -0
  450. package/src/docker/recipes/redis.ts +18 -0
  451. package/src/docker/stack.integration.test.ts +140 -0
  452. package/src/docker/stack.ts +62 -0
  453. package/src/docker/types.ts +134 -0
  454. package/src/drivers/ai-anthropic.ts +128 -0
  455. package/src/drivers/ai-mock.ts +82 -0
  456. package/src/drivers/ai-openai-compatible.ts +139 -0
  457. package/src/drivers/ai-providers.test.ts +163 -0
  458. package/src/drivers/ai-types.ts +83 -0
  459. package/src/drivers/bun-native-completeness.test.ts +155 -0
  460. package/src/drivers/channel-console.ts +118 -0
  461. package/src/drivers/channel-fcm.ts +96 -0
  462. package/src/drivers/channel-resend.ts +27 -0
  463. package/src/drivers/channel-smtp.ts +33 -0
  464. package/src/drivers/channel-types.ts +160 -0
  465. package/src/drivers/channel-unifonic.ts +79 -0
  466. package/src/drivers/channel-wa-cloud.ts +84 -0
  467. package/src/drivers/channel-webpush.ts +317 -0
  468. package/src/drivers/conformance.test.ts +89 -0
  469. package/src/drivers/conformance.ts +162 -0
  470. package/src/drivers/fs.ts +73 -0
  471. package/src/drivers/index.ts +194 -0
  472. package/src/drivers/kv-lua.ts +222 -0
  473. package/src/drivers/memory.ts +472 -0
  474. package/src/drivers/pgvector.ts +130 -0
  475. package/src/drivers/postgres.ts +221 -0
  476. package/src/drivers/redis.ts +254 -0
  477. package/src/drivers/s3.ts +129 -0
  478. package/src/drivers/signal-engine.ts +690 -0
  479. package/src/drivers/signal-memory.ts +27 -0
  480. package/src/drivers/signal-nats.ts +131 -0
  481. package/src/drivers/signal-postgres.ts +1089 -0
  482. package/src/drivers/signal-redis.ts +275 -0
  483. package/src/drivers/signal-types.ts +328 -0
  484. package/src/drivers/sqlite.ts +53 -0
  485. package/src/drivers/types.ts +334 -0
  486. package/src/drivers/vault-dotenv-parse.ts +56 -0
  487. package/src/drivers/vault-env.ts +101 -0
  488. package/src/drivers/vault-infisical.ts +61 -0
  489. package/src/drivers/vault-managed.ts +42 -0
  490. package/src/drivers/vault-memory.ts +38 -0
  491. package/src/drivers/vault-openbao.ts +80 -0
  492. package/src/drivers/vault-sops.ts +252 -0
  493. package/src/drivers/vault-types.ts +84 -0
  494. package/src/elements/ai/declare.ts +206 -0
  495. package/src/elements/ai/eval.ts +113 -0
  496. package/src/elements/ai/pii.ts +108 -0
  497. package/src/elements/ai/runtime.ts +540 -0
  498. package/src/elements/ai/schema.ts +194 -0
  499. package/src/elements/ai.test.ts +393 -0
  500. package/src/elements/ai.ts +56 -0
  501. package/src/elements/channel/consent.ts +81 -0
  502. package/src/elements/channel/costs.test.ts +62 -0
  503. package/src/elements/channel/costs.ts +130 -0
  504. package/src/elements/channel/declare.ts +141 -0
  505. package/src/elements/channel/email-auth.test.ts +47 -0
  506. package/src/elements/channel/email-auth.ts +109 -0
  507. package/src/elements/channel/locale.ts +97 -0
  508. package/src/elements/channel/mask.test.ts +19 -0
  509. package/src/elements/channel/mask.ts +60 -0
  510. package/src/elements/channel/mime.ts +23 -0
  511. package/src/elements/channel/outcomes.test.ts +40 -0
  512. package/src/elements/channel/outcomes.ts +126 -0
  513. package/src/elements/channel/receipts.ts +121 -0
  514. package/src/elements/channel/runtime.ts +500 -0
  515. package/src/elements/channel/suppression.ts +136 -0
  516. package/src/elements/channel.test.ts +232 -0
  517. package/src/elements/channel.ts +109 -0
  518. package/src/elements/clock/actions.ts +170 -0
  519. package/src/elements/clock/declare.ts +58 -0
  520. package/src/elements/clock/dst.ts +197 -0
  521. package/src/elements/clock/durable.ts +140 -0
  522. package/src/elements/clock/duration.ts +29 -0
  523. package/src/elements/clock/health.test.ts +103 -0
  524. package/src/elements/clock/health.ts +112 -0
  525. package/src/elements/clock/leader.ts +127 -0
  526. package/src/elements/clock/reconcile.ts +241 -0
  527. package/src/elements/clock/runtime.ts +243 -0
  528. package/src/elements/clock/schedule.ts +262 -0
  529. package/src/elements/clock/time-travel.ts +53 -0
  530. package/src/elements/clock.test.ts +365 -0
  531. package/src/elements/clock.ts +80 -0
  532. package/src/elements/gate/declare.ts +134 -0
  533. package/src/elements/gate/permissions.ts +104 -0
  534. package/src/elements/gate/runtime.ts +177 -0
  535. package/src/elements/gate/strategies.ts +388 -0
  536. package/src/elements/gate.test.ts +145 -0
  537. package/src/elements/gate.ts +41 -0
  538. package/src/elements/index.ts +169 -0
  539. package/src/elements/signal/chaos-child.ts +47 -0
  540. package/src/elements/signal/declare.ts +77 -0
  541. package/src/elements/signal/dry-run-replay.test.ts +95 -0
  542. package/src/elements/signal/dry-run-write-isolation.test.ts +94 -0
  543. package/src/elements/signal/reconcile.test.ts +23 -0
  544. package/src/elements/signal/reconcile.ts +122 -0
  545. package/src/elements/signal/runtime.ts +94 -0
  546. package/src/elements/signal.test.ts +457 -0
  547. package/src/elements/signal.ts +26 -0
  548. package/src/elements/store/cache.ts +197 -0
  549. package/src/elements/store/classify.ts +125 -0
  550. package/src/elements/store/declare.ts +200 -0
  551. package/src/elements/store/files-policy.test.ts +31 -0
  552. package/src/elements/store/files-policy.ts +70 -0
  553. package/src/elements/store/replica.ts +68 -0
  554. package/src/elements/store/runtime.ts +393 -0
  555. package/src/elements/store/sql-condition.ts +205 -0
  556. package/src/elements/store/sql-session.ts +579 -0
  557. package/src/elements/store/table.ts +282 -0
  558. package/src/elements/store.test.ts +370 -0
  559. package/src/elements/store.ts +99 -0
  560. package/src/elements/vault/declare.ts +143 -0
  561. package/src/elements/vault/fingerprint.ts +30 -0
  562. package/src/elements/vault/redact.ts +52 -0
  563. package/src/elements/vault/runtime.ts +461 -0
  564. package/src/elements/vault.test.ts +296 -0
  565. package/src/elements/vault.ts +44 -0
  566. package/src/index.ts +183 -0
  567. package/src/kernel/adopt-routes.ts +194 -0
  568. package/src/kernel/app.ts +1068 -0
  569. package/src/kernel/auth-resolve.ts +93 -0
  570. package/src/kernel/boot.test.ts +173 -0
  571. package/src/kernel/boot.ts +439 -0
  572. package/src/kernel/budget-entry.ts +55 -0
  573. package/src/kernel/budget.test.ts +19 -0
  574. package/src/kernel/call.test.ts +83 -0
  575. package/src/kernel/capability.ts +113 -0
  576. package/src/kernel/dry-run.test.ts +64 -0
  577. package/src/kernel/dry-run.ts +171 -0
  578. package/src/kernel/effects.test.ts +89 -0
  579. package/src/kernel/effects.ts +140 -0
  580. package/src/kernel/errors.registry.test.ts +39 -0
  581. package/src/kernel/errors.ts +225 -0
  582. package/src/kernel/flow.test.ts +154 -0
  583. package/src/kernel/flow.ts +290 -0
  584. package/src/kernel/fx.test.ts +245 -0
  585. package/src/kernel/fx.ts +996 -0
  586. package/src/kernel/hook-timing.test.ts +72 -0
  587. package/src/kernel/hook-timing.ts +190 -0
  588. package/src/kernel/hooks.test.ts +181 -0
  589. package/src/kernel/hooks.ts +275 -0
  590. package/src/kernel/index.ts +278 -0
  591. package/src/kernel/journal.ts +405 -0
  592. package/src/kernel/journey.ts +75 -0
  593. package/src/kernel/on.ts +74 -0
  594. package/src/kernel/pipeline.test.ts +349 -0
  595. package/src/kernel/pipeline.ts +245 -0
  596. package/src/kernel/plug.ts +82 -0
  597. package/src/kernel/plugin/capabilities.test.ts +84 -0
  598. package/src/kernel/plugin/conflicts.test.ts +106 -0
  599. package/src/kernel/plugin/decorate.test.ts +111 -0
  600. package/src/kernel/plugin/scoping.test.ts +138 -0
  601. package/src/kernel/plugin.ts +485 -0
  602. package/src/kernel/rate-limit.ts +25 -0
  603. package/src/kernel/registry.ts +398 -0
  604. package/src/kernel/router.test.ts +114 -0
  605. package/src/kernel/router.ts +556 -0
  606. package/src/kernel/routing-budget.test.ts +19 -0
  607. package/src/kernel/run-telemetry.ts +70 -0
  608. package/src/kernel/triggers.ts +324 -0
  609. package/src/kernel/unit.ts +88 -0
  610. package/src/manifest/diff.test.ts +866 -0
  611. package/src/manifest/diff.ts +1670 -0
  612. package/src/manifest/fixtures/base.manifest.json +112 -0
  613. package/src/manifest/fixtures/skyport.excerpt.json +51 -0
  614. package/src/manifest/fixtures/skyport.manifest.json +153 -0
  615. package/src/manifest/index.ts +27 -0
  616. package/src/manifest/types.ts +358 -0
  617. package/src/manifest/undeclared.test.ts +82 -0
  618. package/src/manifest/undeclared.ts +65 -0
  619. package/src/manifest/validate.test.ts +105 -0
  620. package/src/manifest/validate.ts +174 -0
  621. package/src/mcp/authorization.ts +340 -0
  622. package/src/mcp/confirmation.ts +174 -0
  623. package/src/mcp/data.ts +90 -0
  624. package/src/mcp/index.ts +80 -0
  625. package/src/mcp/injection.gate.test.ts +176 -0
  626. package/src/mcp/mcp.test.ts +348 -0
  627. package/src/mcp/protocol.ts +172 -0
  628. package/src/mcp/server.ts +283 -0
  629. package/src/mcp/session.ts +139 -0
  630. package/src/mcp/tools.ts +391 -0
  631. package/src/plugins/catalogue.test.ts +48 -0
  632. package/src/plugins/catalogue.ts +113 -0
  633. package/src/plugins/node-import-scan.test.ts +28 -0
  634. package/src/plugins/node-import-scan.ts +98 -0
  635. package/src/plugins/supply-chain.test.ts +48 -0
  636. package/src/plugins/supply-chain.ts +460 -0
  637. package/src/release/index.ts +30 -0
  638. package/src/release/limits.ts +20 -0
  639. package/src/release/measure.ts +443 -0
  640. package/src/release/publish.ts +56 -0
  641. package/src/runs/bench.test.ts +93 -0
  642. package/src/runs/collect.ts +144 -0
  643. package/src/runs/drivers/clickhouse.ts +108 -0
  644. package/src/runs/drivers/files.ts +201 -0
  645. package/src/runs/drivers/memory.ts +94 -0
  646. package/src/runs/drivers/postgres.ts +110 -0
  647. package/src/runs/duckdb.ts +99 -0
  648. package/src/runs/index.ts +82 -0
  649. package/src/runs/outlier.ts +180 -0
  650. package/src/runs/parquet.ts +210 -0
  651. package/src/runs/privacy.ts +49 -0
  652. package/src/runs/runs.test.ts +324 -0
  653. package/src/runs/runtime.ts +229 -0
  654. package/src/runs/shred.ts +243 -0
  655. package/src/runs/telemetry.ts +10 -0
  656. package/src/runs/types.ts +179 -0
  657. package/src/runtime/bun.ts +140 -0
  658. package/src/runtime/cold-start.bench.ts +20 -0
  659. package/src/runtime/index.ts +46 -0
  660. package/src/runtime/primitives.ts +242 -0
  661. package/src/runtime/security.test.ts +170 -0
  662. package/src/runtime/security.ts +168 -0
  663. package/src/runtime/serve.test.ts +223 -0
  664. package/src/runtime/types.ts +217 -0
  665. package/src/runtime/web-standard.ts +77 -0
  666. package/src/test/create-test-app.test.ts +161 -0
  667. package/src/test/create-test-app.ts +533 -0
  668. package/src/test/index.ts +21 -0
  669. package/src/test/provisions.integration.test.ts +174 -0
  670. package/src/upgrade/codemods.test.ts +58 -0
  671. package/src/upgrade/codemods.ts +83 -0
  672. package/src/validation/index.ts +23 -0
  673. package/src/validation/standard-schema.test.ts +96 -0
  674. package/src/validation/standard-schema.ts +316 -0
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Transport — retry, timeout, auth refresh.
3
+ */
4
+
5
+ import { describe, expect, test } from "bun:test";
6
+ import { createClient } from "./create.ts";
7
+ import type { AppOf } from "./types.ts";
8
+
9
+ type PingApp = AppOf<{
10
+ sys: {
11
+ ping: {
12
+ out: { ok: true };
13
+ errors: Record<string, never>;
14
+ };
15
+ };
16
+ }>;
17
+
18
+ describe("transport — retry", () => {
19
+ test("retries 5xx then succeeds", async () => {
20
+ let n = 0;
21
+ const api = createClient<PingApp>("http://app.test", {
22
+ retry: { retries: 2, delay: 1, backoff: 1 },
23
+ fetch: async () => {
24
+ n += 1;
25
+ if (n < 3) return new Response("nope", { status: 503 });
26
+ return Response.json({ data: { ok: true }, error: null });
27
+ },
28
+ });
29
+
30
+ const { data, error } = await api.sys.ping();
31
+ expect(error).toBeNull();
32
+ expect(data).toEqual({ ok: true });
33
+ expect(n).toBe(3);
34
+ });
35
+
36
+ test("exhausts retries into TransportError", async () => {
37
+ let n = 0;
38
+ const api = createClient<PingApp>("http://app.test", {
39
+ retry: { retries: 1, delay: 1, backoff: 1 },
40
+ fetch: async () => {
41
+ n += 1;
42
+ return new Response("nope", { status: 502 });
43
+ },
44
+ });
45
+
46
+ const { error } = await api.sys.ping();
47
+ expect(error?.code).toBe("TransportError");
48
+ expect(n).toBe(2);
49
+ });
50
+ });
51
+
52
+ describe("transport — timeout", () => {
53
+ test("AbortError becomes TransportError", async () => {
54
+ const api = createClient<PingApp>("http://app.test", {
55
+ timeout: 10,
56
+ fetch: async (_input, init) => {
57
+ const signal = init?.signal;
58
+ await new Promise<void>((resolve, reject) => {
59
+ if (!signal) {
60
+ resolve();
61
+ return;
62
+ }
63
+ if (signal.aborted) {
64
+ reject(new DOMException("Aborted", "AbortError"));
65
+ return;
66
+ }
67
+ signal.addEventListener("abort", () => {
68
+ reject(new DOMException("Aborted", "AbortError"));
69
+ });
70
+ });
71
+ return Response.json({ data: { ok: true }, error: null });
72
+ },
73
+ });
74
+
75
+ const { error } = await api.sys.ping();
76
+ expect(error?.code).toBe("TransportError");
77
+ });
78
+ });
79
+
80
+ describe("transport — auth refresh", () => {
81
+ test("401 triggers refresh once and retries", async () => {
82
+ let token = "old";
83
+ let refreshes = 0;
84
+ let auths: Array<string | null> = [];
85
+
86
+ const api = createClient<PingApp>("http://app.test", {
87
+ auth: {
88
+ getToken: () => token,
89
+ refresh: async () => {
90
+ refreshes += 1;
91
+ token = "new";
92
+ return token;
93
+ },
94
+ },
95
+ fetch: async (_input, init) => {
96
+ const headers = new Headers(init?.headers);
97
+ const auth = headers.get("authorization");
98
+ auths.push(auth);
99
+ if (auth === "Bearer old") {
100
+ return new Response("unauthorized", { status: 401 });
101
+ }
102
+ return Response.json({ data: { ok: true }, error: null });
103
+ },
104
+ });
105
+
106
+ const { data, error } = await api.sys.ping();
107
+ expect(error).toBeNull();
108
+ expect(data).toEqual({ ok: true });
109
+ expect(refreshes).toBe(1);
110
+ expect(auths).toEqual(["Bearer old", "Bearer new"]);
111
+ });
112
+
113
+ test("401 without refresh returns TransportError envelope", async () => {
114
+ const api = createClient<PingApp>("http://app.test", {
115
+ fetch: async () => new Response("no", { status: 401 }),
116
+ });
117
+ const { error } = await api.sys.ping();
118
+ expect(error?.code).toBe("TransportError");
119
+ if (error?.code === "TransportError") {
120
+ expect(error.data.status).toBe(401);
121
+ }
122
+ });
123
+ });
@@ -0,0 +1,254 @@
1
+ /**
2
+ * HTTP transport: timeout, retry, and auth refresh.
3
+ *
4
+ * Wire default: `POST {base}/_oke/{unit}/{flow}` with JSON body.
5
+ * Optional `routes` map switches to REST (`method` + path template).
6
+ */
7
+
8
+ import type { ClientFetch, ClientOptions, ClientResult } from "./types.ts";
9
+
10
+ /** Internal transport handle. */
11
+ export interface Transport {
12
+ /**
13
+ * Invoke a flow by `unit/flow` key.
14
+ *
15
+ * @param key - `unit/flow`
16
+ * @param input - JSON body / path-param source
17
+ */
18
+ call(key: string, input: unknown): Promise<ClientResult>;
19
+ }
20
+
21
+ /**
22
+ * Create a transport bound to a base URL.
23
+ *
24
+ * @param base - Absolute origin (no trailing slash)
25
+ * @param opts - Client options
26
+ */
27
+ export function createTransport(
28
+ base: string,
29
+ opts: ClientOptions = {},
30
+ ): Transport {
31
+ const fetchFn: ClientFetch =
32
+ opts.fetch ?? globalThis.fetch.bind(globalThis);
33
+ const retries = opts.retry?.retries ?? 0;
34
+ const delay0 = opts.retry?.delay ?? 50;
35
+ const backoff = opts.retry?.backoff ?? 2;
36
+
37
+ return {
38
+ async call(key, input) {
39
+ let refreshed = false;
40
+ let attempt = 0;
41
+ let delay = delay0;
42
+
43
+ for (;;) {
44
+ try {
45
+ const res = await once(base, key, input, opts, fetchFn);
46
+ if (res.status === 401 && opts.auth?.refresh && !refreshed) {
47
+ refreshed = true;
48
+ await opts.auth.refresh();
49
+ continue;
50
+ }
51
+ return decode(res);
52
+ } catch (err) {
53
+ const transient = isTransient(err);
54
+ if (!transient || attempt >= retries) {
55
+ return {
56
+ data: null,
57
+ error: {
58
+ code: "TransportError",
59
+ data: {
60
+ message: err instanceof Error ? err.message : String(err),
61
+ },
62
+ },
63
+ };
64
+ }
65
+ await sleep(delay);
66
+ delay *= backoff;
67
+ attempt += 1;
68
+ }
69
+ }
70
+ },
71
+ };
72
+ }
73
+
74
+ /**
75
+ * Single HTTP attempt. Throws on network / abort / 5xx (retryable).
76
+ *
77
+ * @param base - Origin
78
+ * @param key - `unit/flow`
79
+ * @param input - Payload
80
+ * @param opts - Options
81
+ * @param fetchFn - Fetch implementation
82
+ * @param _reserved - Reserved
83
+ */
84
+ async function once(
85
+ base: string,
86
+ key: string,
87
+ input: unknown,
88
+ opts: ClientOptions,
89
+ fetchFn: ClientFetch,
90
+ ): Promise<Response> {
91
+ const route = opts.routes?.[key.replace("/", ".")];
92
+ const { url, method, body } = route
93
+ ? restRequest(base, route.method, route.path, input)
94
+ : rpcRequest(base, key, input);
95
+
96
+ const headers = new Headers();
97
+ const extra =
98
+ typeof opts.headers === "function"
99
+ ? await opts.headers()
100
+ : opts.headers;
101
+ if (Array.isArray(extra)) {
102
+ for (const [k, v] of extra) headers.set(k, v);
103
+ } else if (extra) {
104
+ for (const [k, v] of Object.entries(extra)) headers.set(k, v);
105
+ }
106
+ if (body !== undefined && !headers.has("content-type")) {
107
+ headers.set("content-type", "application/json");
108
+ }
109
+
110
+ const token = opts.auth ? await opts.auth.getToken() : undefined;
111
+ if (token && !headers.has("authorization")) {
112
+ headers.set("authorization", `Bearer ${token}`);
113
+ }
114
+
115
+ const ctrl = opts.timeout !== undefined ? new AbortController() : undefined;
116
+ const timer =
117
+ ctrl && opts.timeout !== undefined
118
+ ? setTimeout(() => ctrl.abort(), opts.timeout)
119
+ : undefined;
120
+
121
+ try {
122
+ const res = await fetchFn(url, {
123
+ method,
124
+ headers,
125
+ body,
126
+ signal: ctrl?.signal,
127
+ });
128
+ if (res.status >= 500) {
129
+ throw new Error(`HTTP ${res.status}`);
130
+ }
131
+ return res;
132
+ } finally {
133
+ if (timer !== undefined) clearTimeout(timer);
134
+ }
135
+ }
136
+
137
+ function rpcRequest(
138
+ base: string,
139
+ key: string,
140
+ input: unknown,
141
+ ): { url: string; method: string; body: string | undefined } {
142
+ const url = `${base}/_oke/${key}`;
143
+ const body =
144
+ input === undefined ? undefined : JSON.stringify(input ?? {});
145
+ return { url, method: "POST", body };
146
+ }
147
+
148
+ function restRequest(
149
+ base: string,
150
+ method: string,
151
+ path: string,
152
+ input: unknown,
153
+ ): { url: string; method: string; body: string | undefined } {
154
+ const params =
155
+ input !== null && typeof input === "object"
156
+ ? (input as Record<string, unknown>)
157
+ : {};
158
+ let pathOut = path;
159
+ const query: string[] = [];
160
+ const rest: Record<string, unknown> = {};
161
+
162
+ for (const [k, v] of Object.entries(params)) {
163
+ const token = `:${k}`;
164
+ if (pathOut.includes(token)) {
165
+ pathOut = pathOut.replaceAll(token, encodeURIComponent(String(v)));
166
+ } else {
167
+ rest[k] = v;
168
+ }
169
+ }
170
+
171
+ const upper = method.toUpperCase();
172
+ let body: string | undefined;
173
+ if (upper === "GET" || upper === "HEAD") {
174
+ for (const [k, v] of Object.entries(rest)) {
175
+ if (v !== undefined) {
176
+ query.push(
177
+ `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`,
178
+ );
179
+ }
180
+ }
181
+ } else if (Object.keys(rest).length > 0 || path === pathOut) {
182
+ body = JSON.stringify(
183
+ Object.keys(rest).length > 0 ? rest : (input ?? {}),
184
+ );
185
+ }
186
+
187
+ const qs = query.length ? `?${query.join("&")}` : "";
188
+ return { url: `${base}${pathOut}${qs}`, method: upper, body };
189
+ }
190
+
191
+ async function decode(res: Response): Promise<ClientResult> {
192
+ if (res.status === 204) {
193
+ return { data: undefined, error: null };
194
+ }
195
+
196
+ const text = await res.text();
197
+ if (!text) {
198
+ if (res.ok) return { data: undefined, error: null };
199
+ return {
200
+ data: null,
201
+ error: {
202
+ code: "TransportError",
203
+ data: { message: `HTTP ${res.status}`, status: res.status },
204
+ },
205
+ };
206
+ }
207
+
208
+ let json: unknown;
209
+ try {
210
+ json = JSON.parse(text);
211
+ } catch {
212
+ return {
213
+ data: null,
214
+ error: {
215
+ code: "TransportError",
216
+ data: {
217
+ message: `Invalid JSON (${res.status})`,
218
+ status: res.status,
219
+ },
220
+ },
221
+ };
222
+ }
223
+
224
+ if (
225
+ json !== null &&
226
+ typeof json === "object" &&
227
+ "data" in json &&
228
+ "error" in json
229
+ ) {
230
+ return json as ClientResult;
231
+ }
232
+
233
+ if (res.ok) {
234
+ return { data: json, error: null };
235
+ }
236
+
237
+ return {
238
+ data: null,
239
+ error: {
240
+ code: "TransportError",
241
+ data: { message: `HTTP ${res.status}`, status: res.status },
242
+ },
243
+ };
244
+ }
245
+
246
+ function isTransient(err: unknown): boolean {
247
+ if (!(err instanceof Error)) return false;
248
+ if (err.name === "AbortError") return false;
249
+ return true;
250
+ }
251
+
252
+ function sleep(ms: number): Promise<void> {
253
+ return new Promise((r) => setTimeout(r, ms));
254
+ }
@@ -0,0 +1,282 @@
1
+ /**
2
+ * Typed client contract surface — type-level only.
3
+ *
4
+ * Same-repo: pass `App` with `$routes` (or a bare route map) to {@link createClient}.
5
+ * Local / separate-repo: augment {@link Register} so `createClient(url)` needs no import.
6
+ */
7
+
8
+ /**
9
+ * One flow's client contract. `in` / `out` / `errors` are phantom (type-only).
10
+ *
11
+ * @typeParam I - Request input
12
+ * @typeParam O - Success data
13
+ * @typeParam E - Map of error code → data shape
14
+ */
15
+ export interface FlowContract<
16
+ I = unknown,
17
+ O = unknown,
18
+ E extends Record<string, unknown> = Record<string, unknown>,
19
+ > {
20
+ /** Phantom input type. */
21
+ readonly in?: I;
22
+ /** Phantom success type. */
23
+ readonly out?: O;
24
+ /** Phantom error map (`FlightFull` → `{ seatsLeft: number }`). */
25
+ readonly errors?: E;
26
+ /** Optional HTTP method when the wire uses REST instead of `/_oke` RPC. */
27
+ readonly method?: string;
28
+ /** Optional HTTP path template (`/notes/:id`). */
29
+ readonly path?: string;
30
+ }
31
+
32
+ /**
33
+ * Unit → flow → contract. Drives `api.notes.get(...)`.
34
+ */
35
+ export type ClientRouteMap = {
36
+ readonly [unit: string]: {
37
+ readonly [flow: string]: FlowContract;
38
+ };
39
+ };
40
+
41
+ /**
42
+ * App shape accepted by {@link createClient}. Either a `$routes` carrier
43
+ * (future `typeof app`) or a bare {@link ClientRouteMap}.
44
+ */
45
+ export type ClientApp = {
46
+ readonly $routes: ClientRouteMap;
47
+ };
48
+
49
+ /**
50
+ * Module-augmentation slot for modes that skip `import type { App }`.
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * declare module "okengine/client" {
55
+ * interface Register {
56
+ * app: { $routes: { notes: { get: { in: { id: string }; out: Note; errors: { NotFound: {} } } } } };
57
+ * }
58
+ * }
59
+ * ```
60
+ */
61
+ export interface Register {
62
+ // intentionally empty — augmented by `oke dev` / `oke client add`
63
+ }
64
+
65
+ /**
66
+ * Resolve the App type: explicit type argument wins; else {@link Register}.
67
+ *
68
+ * @typeParam App - Explicit app / route map
69
+ */
70
+ export type ResolveApp<App = never> = [App] extends [never]
71
+ ? Register extends { readonly app: infer A }
72
+ ? A
73
+ : { readonly $routes: {} }
74
+ : App;
75
+
76
+ /**
77
+ * Extract a {@link ClientRouteMap} from an App type.
78
+ *
79
+ * Accepts `typeof app` (OkeApp with accumulated `$routes`), {@link ClientApp},
80
+ * or a bare route map.
81
+ *
82
+ * @typeParam App - {@link ClientApp}, `typeof app`, or bare route map
83
+ */
84
+ export type RoutesOf<App> = App extends { readonly $routes: infer R }
85
+ ? R extends ClientRouteMap
86
+ ? R
87
+ : R extends Record<string, Record<string, FlowContract>>
88
+ ? R
89
+ : {
90
+ [U in keyof R]: {
91
+ [F in keyof R[U]]: R[U][F] extends FlowContract
92
+ ? R[U][F]
93
+ : FlowContract;
94
+ };
95
+ }
96
+ : App extends ClientRouteMap
97
+ ? App
98
+ : {};
99
+
100
+ /**
101
+ * Discriminated flow-boundary error. Narrow with `error.code === "FlightFull"`.
102
+ *
103
+ * @typeParam E - Error code → data map
104
+ */
105
+ export type ClientError<
106
+ E extends Record<string, unknown> = Record<string, unknown>,
107
+ > = {
108
+ [K in keyof E & string]: {
109
+ readonly code: K;
110
+ readonly data: E[K];
111
+ readonly message?: string;
112
+ };
113
+ }[keyof E & string];
114
+
115
+ /**
116
+ * Transport / protocol failure (not a declared flow error).
117
+ */
118
+ export interface TransportError {
119
+ readonly code: "TransportError";
120
+ readonly data: {
121
+ readonly message: string;
122
+ readonly status?: number;
123
+ };
124
+ readonly message?: string;
125
+ }
126
+
127
+ /**
128
+ * Client call result — errors are values, never thrown for flow failures.
129
+ *
130
+ * @typeParam O - Success data
131
+ * @typeParam E - Declared error map
132
+ */
133
+ export type ClientResult<
134
+ O = unknown,
135
+ E extends Record<string, unknown> = Record<string, unknown>,
136
+ > =
137
+ | { readonly data: O; readonly error: null }
138
+ | { readonly data: null; readonly error: ClientError<E> | TransportError };
139
+
140
+ /** Minimal fetch signature (avoids DOM `HeadersInit` / `preconnect` coupling). */
141
+ export type ClientFetch = (
142
+ input: string | URL | Request,
143
+ init?: RequestInit,
144
+ ) => Promise<Response>;
145
+
146
+ /** Header bag accepted by the client. */
147
+ export type ClientHeaders = Record<string, string> | [string, string][];
148
+
149
+ /**
150
+ * Options for {@link createClient}.
151
+ */
152
+ export interface ClientOptions {
153
+ /** Override `globalThis.fetch`. */
154
+ readonly fetch?: ClientFetch;
155
+ /** Static headers, or a getter invoked per request. */
156
+ readonly headers?:
157
+ | ClientHeaders
158
+ | (() => ClientHeaders | Promise<ClientHeaders>);
159
+ /** Abort the request after this many milliseconds. */
160
+ readonly timeout?: number;
161
+ /** Retry transient failures (network / 5xx). */
162
+ readonly retry?: {
163
+ /** Extra attempts after the first (default 0). */
164
+ readonly retries?: number;
165
+ /** Initial delay in ms (default 50). */
166
+ readonly delay?: number;
167
+ /** Multiplier applied after each retry (default 2). */
168
+ readonly backoff?: number;
169
+ };
170
+ /**
171
+ * Auth token + refresh. On HTTP 401, `refresh` runs once and the
172
+ * request is retried with the new token.
173
+ */
174
+ readonly auth?: {
175
+ /** Current access token (Bearer), or null. */
176
+ readonly getToken: () =>
177
+ | string
178
+ | null
179
+ | undefined
180
+ | Promise<string | null | undefined>;
181
+ /** Obtain a new access token after 401. */
182
+ readonly refresh: () => Promise<string | null | undefined>;
183
+ };
184
+ /**
185
+ * Runtime REST table (optional). Keys are `unit.flow`.
186
+ * When absent, the client uses `POST /_oke/{unit}/{flow}` unless
187
+ * {@link ClientOptions.$routes} supplies HTTP method/path from adopt.
188
+ */
189
+ readonly routes?: Readonly<
190
+ Record<string, { readonly method: string; readonly path: string }>
191
+ >;
192
+ /**
193
+ * Runtime route map from `app.$routes` (typed adopt). HTTP triggers become
194
+ * REST; flows without method/path fall back to RPC.
195
+ */
196
+ readonly $routes?: ClientRouteMap;
197
+ }
198
+
199
+ /**
200
+ * Call signature for one flow.
201
+ *
202
+ * @typeParam I - Input
203
+ * @typeParam O - Output
204
+ * @typeParam E - Errors
205
+ */
206
+ export type ClientCall<
207
+ I,
208
+ O,
209
+ E extends Record<string, unknown>,
210
+ > = [I] extends [void]
211
+ ? () => Promise<ClientResult<O, E>>
212
+ : Partial<I> extends I
213
+ ? (input?: I) => Promise<ClientResult<O, E>>
214
+ : (input: I) => Promise<ClientResult<O, E>>;
215
+
216
+ /**
217
+ * Pull input from a contract shape (supports required or phantom-optional `in`).
218
+ */
219
+ type ContractIn<C> = "in" extends keyof C
220
+ ? [NonNullable<C["in"]>] extends [never]
221
+ ? void
222
+ : NonNullable<C["in"]>
223
+ : void;
224
+
225
+ /** Pull output from a contract shape. */
226
+ type ContractOut<C> = "out" extends keyof C
227
+ ? NonNullable<C["out"]>
228
+ : unknown;
229
+
230
+ /** Pull error map from a contract shape. */
231
+ type ContractErrors<C> = "errors" extends keyof C
232
+ ? NonNullable<C["errors"]> extends Record<string, unknown>
233
+ ? NonNullable<C["errors"]>
234
+ : Record<string, never>
235
+ : Record<string, never>;
236
+
237
+ /**
238
+ * Typed client proxy derived from a route map.
239
+ *
240
+ * @typeParam R - Route map
241
+ */
242
+ export type ClientFromRoutes<R extends ClientRouteMap> = {
243
+ readonly [U in keyof R]: {
244
+ readonly [F in keyof R[U]]: ClientCall<
245
+ ContractIn<R[U][F]>,
246
+ ContractOut<R[U][F]>,
247
+ ContractErrors<R[U][F]>
248
+ >;
249
+ };
250
+ };
251
+
252
+ /**
253
+ * Fully typed client for an App.
254
+ *
255
+ * @typeParam App - App or route map
256
+ */
257
+ export type Client<App = never> = ClientFromRoutes<RoutesOf<ResolveApp<App>>>;
258
+
259
+ /**
260
+ * Convenience: brand a route map as an App (`export type App = AppOf<…>`).
261
+ *
262
+ * @typeParam R - Route map
263
+ */
264
+ export type AppOf<R extends ClientRouteMap> = { readonly $routes: R };
265
+
266
+ /**
267
+ * JSON shape served at `GET /_oke/client.json` for {@link clientAdd}.
268
+ */
269
+ export interface ClientDescriptor {
270
+ /** Route contracts with TypeScript type strings for emission. */
271
+ readonly routes: {
272
+ readonly [unit: string]: {
273
+ readonly [flow: string]: {
274
+ readonly in?: string;
275
+ readonly out?: string;
276
+ readonly errors?: Readonly<Record<string, string>>;
277
+ readonly method?: string;
278
+ readonly path?: string;
279
+ };
280
+ };
281
+ };
282
+ }