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,996 @@
1
+ /**
2
+ * `fx` — the single door to the outside world.
3
+ *
4
+ * All world access goes through this object. Nothing in `src/elements` or
5
+ * user flows may import `node:` / `bun:` modules directly. Every call that
6
+ * touches a declared effect kind is capability-checked and ledgered.
7
+ *
8
+ * Drivers are stubs in v1 (in-memory). The surface is swappable wholesale
9
+ * for deterministic tests (§7.6).
10
+ */
11
+
12
+ import type { Effects, ResourceRef } from "../manifest/types.ts";
13
+ import type {
14
+ StoreDecl,
15
+ StoreHandle,
16
+ StoreRuntime,
17
+ SqlStoreHandle,
18
+ } from "../elements/store.ts";
19
+ import type { SignalRuntime } from "../elements/signal.ts";
20
+ import type { VaultRuntime } from "../elements/vault.ts";
21
+ import type { ChannelRuntime } from "../elements/channel.ts";
22
+ import type { AiRuntime } from "../elements/ai.ts";
23
+ import { parseDurationMs } from "../elements/clock/duration.ts";
24
+ import {
25
+ createCapabilityToken,
26
+ type CapabilityToken,
27
+ } from "./capability.ts";
28
+ import {
29
+ createEffectLedger,
30
+ recordEffect,
31
+ reversibilityOf,
32
+ type EffectLedger,
33
+ } from "./effects.ts";
34
+ import {
35
+ DryRunWriteIsolationError,
36
+ isDryRun,
37
+ recordWouldHaveFired,
38
+ touchDryRunStore,
39
+ } from "./dry-run.ts";
40
+ import { fail, type FailOptions, type FlowFailure } from "./errors.ts";
41
+ import type { JournalSession } from "./journal.ts";
42
+ import type { RunTelemetry } from "./run-telemetry.ts";
43
+
44
+ /** Named ref: plain string or `{ name }` element handle. */
45
+ export type NamedRef = string | { readonly name: string };
46
+
47
+ /** Resolve a {@link NamedRef} to its string id. */
48
+ export function resolveName(ref: NamedRef): string {
49
+ return typeof ref === "string" ? ref : ref.name;
50
+ }
51
+
52
+ /** Resolve a store argument to a `facet:name` resource ref. */
53
+ export function resolveStoreRef(ref: NamedRef | { readonly ref: ResourceRef }): ResourceRef {
54
+ if (typeof ref === "string") return ref as ResourceRef;
55
+ if ("ref" in ref) return ref.ref;
56
+ return ref.name as ResourceRef;
57
+ }
58
+
59
+ /** Auth principal on the user plane. */
60
+ export interface FxAuth {
61
+ readonly userId: string | null;
62
+ readonly scopes: ReadonlySet<string>;
63
+ /** Whether the identity has completed verification (email / MFA). */
64
+ readonly verified?: boolean;
65
+ }
66
+
67
+ /** Operator principal on the Console plane. */
68
+ export interface FxOperator {
69
+ readonly id: string | null;
70
+ }
71
+
72
+ /** Active tenant (multi-tenancy as a dimension of `fx`). */
73
+ export interface FxTenant {
74
+ readonly id: string | null;
75
+ }
76
+
77
+ /** Clock surface on `fx`. */
78
+ export interface FxClock {
79
+ /** Current epoch-ms (injectable via {@link CreateFxOptions.now}). */
80
+ now(): number;
81
+ /**
82
+ * Durable sleep — when the flow is `durable`, journals the wake time and
83
+ * survives restart / deploy. Without a journal, resolves immediately
84
+ * (non-durable flows).
85
+ *
86
+ * @param label - Step label for the journal
87
+ * @param duration - Duration string (e.g. `"7d"`, `"2m"`)
88
+ */
89
+ sleep(label: string, duration: string): Promise<void>;
90
+ }
91
+
92
+ /** In-memory cache surface. */
93
+ export interface FxCache {
94
+ /**
95
+ * Get a cached value.
96
+ *
97
+ * @param key - Cache key
98
+ */
99
+ get<T = unknown>(key: string): Promise<T | undefined>;
100
+ /**
101
+ * Set a cached value.
102
+ *
103
+ * @param key - Cache key
104
+ * @param value - Value to store
105
+ * @param ttl - Optional TTL string (ignored by the stub)
106
+ */
107
+ set(key: string, value: unknown, ttl?: string): Promise<void>;
108
+ /**
109
+ * Get-or-set helper.
110
+ *
111
+ * @param key - Cache key
112
+ * @param ttl - TTL string (ignored by the stub)
113
+ * @param produce - Producer when missing
114
+ */
115
+ getOrSet<T>(key: string, ttl: string, produce: () => T | Promise<T>): Promise<T>;
116
+ }
117
+
118
+ /** Structured logger surface. */
119
+ export interface FxLog {
120
+ /** Debug line. */
121
+ debug(message: string, data?: Record<string, unknown>): void;
122
+ /** Info line. */
123
+ info(message: string, data?: Record<string, unknown>): void;
124
+ /** Warning line. */
125
+ warn(message: string, data?: Record<string, unknown>): void;
126
+ /** Error line. */
127
+ error(message: string, data?: Record<string, unknown>): void;
128
+ }
129
+
130
+ /**
131
+ * In-memory / stub store handle when no {@link StoreRuntime} is bound.
132
+ * Read ops record `read`; write ops record `write`.
133
+ */
134
+ export interface FxStubStoreHandle {
135
+ /** Resource ref this handle is bound to. */
136
+ readonly ref: ResourceRef;
137
+ /**
138
+ * Read a value by key (records a `read` effect).
139
+ *
140
+ * @param key - Row / entry key
141
+ */
142
+ get(key: string): Promise<unknown>;
143
+ /**
144
+ * Write a value by key (records a `write` effect).
145
+ *
146
+ * @param key - Row / entry key
147
+ * @param value - Value to store
148
+ */
149
+ set(key: string, value: unknown): Promise<void>;
150
+ /**
151
+ * Stub select — records a `read` and returns all rows.
152
+ */
153
+ select(): Promise<unknown[]>;
154
+ /**
155
+ * Stub insert — records a `write`.
156
+ *
157
+ * @param row - Row to insert
158
+ */
159
+ insert(row: Record<string, unknown>): Promise<{ id: string }>;
160
+ /**
161
+ * Stub delete — records a `write`.
162
+ *
163
+ * @param key - Row key
164
+ */
165
+ delete(key: string): Promise<boolean>;
166
+ /**
167
+ * Audit-plugin convenience (no-op on the stub).
168
+ *
169
+ * @param _ctx - Unused context
170
+ */
171
+ log(_ctx?: unknown): Promise<void>;
172
+ /** Audit-plugin CLI convenience. */
173
+ exportCsv(): Promise<string>;
174
+ }
175
+
176
+ /**
177
+ * Handle returned by {@link Fx.store} — driver-backed SQL/KV/files/index
178
+ * when a runtime is bound, otherwise the in-memory stub.
179
+ */
180
+ export type FxStoreHandle = StoreHandle | FxStubStoreHandle;
181
+
182
+ /** Options for {@link Fx.send}. */
183
+ export interface FxSendOptions {
184
+ readonly to?: string;
185
+ readonly via?: readonly NamedRef[];
186
+ readonly data?: Record<string, unknown>;
187
+ }
188
+
189
+ /** Options for {@link Fx.ask}. */
190
+ export interface FxAskOptions {
191
+ readonly via?: readonly NamedRef[];
192
+ }
193
+
194
+ /** Options for {@link Fx.search}. */
195
+ export interface FxSearchOptions {
196
+ readonly topK?: number;
197
+ }
198
+
199
+ /**
200
+ * The `fx` context object — v1 surface.
201
+ *
202
+ * Implementations must be plain objects so tests can replace `fx` wholesale.
203
+ */
204
+ export interface Fx {
205
+ /**
206
+ * Open a store handle for `ref` (capability checked on each op).
207
+ *
208
+ * When a {@link CreateFxOptions.storeRuntime} is bound and `ref` is a
209
+ * registered store declaration, returns the driver-backed handle.
210
+ *
211
+ * @param ref - Store resource ref, named handle, or store declaration
212
+ */
213
+ store(
214
+ ref: NamedRef | { readonly ref: ResourceRef } | StoreDecl,
215
+ ): FxStoreHandle;
216
+ /**
217
+ * Emit a signal (records `emit`).
218
+ *
219
+ * @param signal - Signal name or handle
220
+ * @param payload - Payload
221
+ */
222
+ emit(signal: NamedRef, payload?: unknown): Promise<void>;
223
+ /**
224
+ * Call another flow (records `call`). Stub returns `undefined`.
225
+ *
226
+ * @param flow - Flow name or handle
227
+ * @param input - Input payload
228
+ */
229
+ call(flow: NamedRef, input?: unknown): Promise<unknown>;
230
+ /** Clock surface. */
231
+ readonly clock: FxClock;
232
+ /**
233
+ * Read a vault secret (records `secret`).
234
+ *
235
+ * @param secret - Secret name or handle
236
+ */
237
+ vault(secret: NamedRef): string;
238
+ /** Cache surface. */
239
+ readonly cache: FxCache;
240
+ /**
241
+ * Send a channel template (records `send`).
242
+ *
243
+ * @param template - Template name or handle
244
+ * @param opts - Recipient / data
245
+ */
246
+ send(template: NamedRef, opts?: FxSendOptions): Promise<{ ok: true }>;
247
+ /**
248
+ * Ask an AI prompt (records `ask`). Stub returns `{}`.
249
+ *
250
+ * @param prompt - Prompt name or handle
251
+ * @param input - Prompt input
252
+ * @param opts - Model routing opts
253
+ */
254
+ ask(
255
+ prompt: NamedRef,
256
+ input?: unknown,
257
+ opts?: FxAskOptions,
258
+ ): Promise<Record<string, unknown>>;
259
+ /**
260
+ * Similarity search over an index/embed (records `read` on the embed ref).
261
+ *
262
+ * @param embed - Index / embed name or handle
263
+ * @param query - Query text or vector
264
+ * @param opts - Search options
265
+ */
266
+ search(
267
+ embed: NamedRef,
268
+ query: unknown,
269
+ opts?: FxSearchOptions,
270
+ ): Promise<unknown[]>;
271
+ /**
272
+ * Run a bounded AI agent (records `ask`).
273
+ *
274
+ * @param agent - Agent name or handle
275
+ * @param input - Agent input (`{ message }` or string)
276
+ */
277
+ run(
278
+ agent: NamedRef,
279
+ input?: unknown,
280
+ ): Promise<unknown>;
281
+ /**
282
+ * Stream model tokens (records `ask`). Returns an async iterable of chunks.
283
+ *
284
+ * @param model - Model name or handle
285
+ * @param opts - Prompt / data
286
+ */
287
+ stream(
288
+ model: NamedRef,
289
+ opts?: { readonly prompt?: string; readonly data?: unknown },
290
+ ): AsyncIterable<string>;
291
+ /** Logger. */
292
+ readonly log: FxLog;
293
+ /**
294
+ * i18n stub — returns the key, optionally with JSON params suffix.
295
+ *
296
+ * @param key - Message key
297
+ * @param params - Interpolation params
298
+ */
299
+ t(key: string, params?: Record<string, unknown>): string;
300
+ /** Generate a unique id (UUID). */
301
+ id(): string;
302
+ /** User-plane auth principal. */
303
+ readonly auth: FxAuth;
304
+ /** Operator-plane principal. */
305
+ readonly operator: FxOperator;
306
+ /** Active tenant. */
307
+ readonly tenant: FxTenant;
308
+ /**
309
+ * Flow-boundary failure value (does not throw).
310
+ *
311
+ * @param code - Declared error code (narrowed by clients via `error.code`)
312
+ * @param data - Error payload
313
+ * @param opts - Optional message
314
+ */
315
+ fail<E>(code: string, data: E, opts?: FailOptions): FlowFailure<E>;
316
+ /**
317
+ * Named durable step — never re-runs on journal replay.
318
+ *
319
+ * @param name - Step name
320
+ * @param fn - Step body
321
+ */
322
+ step<T>(name: string, fn: () => T | Promise<T>): Promise<T>;
323
+ }
324
+
325
+ /**
326
+ * Dispatch target for {@link Fx.call}. Wired by the app so untriggered
327
+ * flows execute through the same pipeline as triggered ones.
328
+ */
329
+ export type FxCallHandler = (
330
+ name: string,
331
+ input: unknown,
332
+ ) => Promise<unknown>;
333
+
334
+ /** Options for {@link createFx}. */
335
+ export interface CreateFxOptions {
336
+ /** Flow id — used in capability error messages. */
337
+ readonly flow: string;
338
+ /** Declared effects that mint the capability token. */
339
+ readonly effects?: Effects;
340
+ /** Ledger to append to (created if omitted). */
341
+ readonly ledger?: EffectLedger;
342
+ /** Pre-built token (defaults from `flow` + `effects`). */
343
+ readonly capability?: CapabilityToken;
344
+ /** Injectable clock for timestamps / `fx.clock.now`. */
345
+ readonly now?: () => number;
346
+ /** Auth principal. */
347
+ readonly auth?: FxAuth;
348
+ /** Operator principal. */
349
+ readonly operator?: FxOperator;
350
+ /** Tenant. */
351
+ readonly tenant?: FxTenant;
352
+ /** Secret name → value map for `fx.vault`. */
353
+ readonly secrets?: Readonly<Record<string, string>>;
354
+ /** Seed data for in-memory stores: ref → key → value. */
355
+ readonly storeData?: Readonly<
356
+ Record<string, Readonly<Record<string, unknown>>>
357
+ >;
358
+ /** Optional log sink (defaults to no-op). */
359
+ readonly onLog?: (
360
+ level: "debug" | "info" | "warn" | "error",
361
+ message: string,
362
+ data?: Record<string, unknown>,
363
+ ) => void;
364
+ /**
365
+ * Real `fx.call` dispatch. When omitted, calls are ledgered and return
366
+ * `undefined` (v1 stub).
367
+ */
368
+ readonly callHandler?: FxCallHandler;
369
+ /**
370
+ * Optional store runtime (protocol drivers). When set, `fx.store(decl)`
371
+ * opens driver-backed handles; string refs still use the in-memory stub
372
+ * unless registered on the runtime.
373
+ */
374
+ readonly storeRuntime?: StoreRuntime;
375
+ /**
376
+ * Optional signal runtime. When set, `fx.emit` enrols through the
377
+ * configured driver (postgres = same transaction as store writes).
378
+ */
379
+ readonly signalRuntime?: SignalRuntime;
380
+ /**
381
+ * Optional vault runtime. When set, `fx.vault` reads through it and
382
+ * `fx.log` redacts loaded secret values automatically.
383
+ */
384
+ readonly vaultRuntime?: VaultRuntime;
385
+ /**
386
+ * Optional channel runtime. When set, `fx.send` delivers through it
387
+ * (templates, consent, fallback chains, receipts).
388
+ */
389
+ readonly channelRuntime?: ChannelRuntime;
390
+ /**
391
+ * Optional AI runtime. When set, `fx.ask` routes through it.
392
+ * Nondeterministic ⇒ journaling forced; auto-cache disabled.
393
+ */
394
+ readonly aiRuntime?: AiRuntime;
395
+ /**
396
+ * Optional run telemetry collector. When set, `fx.cache` and `fx.log`
397
+ * accumulate dimensions / log lines for the wide-event runs store
398
+ * with zero flow instrumentation.
399
+ */
400
+ readonly runTelemetry?: RunTelemetry;
401
+ /** Reveal PII through the store runtime (requires `pii:reveal` upstream). */
402
+ readonly revealPii?: boolean;
403
+ /**
404
+ * Active journal session when the flow is durable. Every `fx` call is
405
+ * recorded; `step` / `sleep` replay from the journal on resume.
406
+ */
407
+ readonly journal?: JournalSession;
408
+ /** When true (or when `journal` is set), journal every fx call. */
409
+ readonly durable?: boolean;
410
+ }
411
+
412
+ /** Bundle returned by {@link createFxContext}. */
413
+ export interface FxContext {
414
+ /** The context object passed into flows. */
415
+ readonly fx: Fx;
416
+ /** Effect ledger for this invocation. */
417
+ readonly ledger: EffectLedger;
418
+ /** Capability token enforcing declared effects. */
419
+ readonly capability: CapabilityToken;
420
+ }
421
+
422
+ /**
423
+ * Create an in-memory `fx` context (v1 stubs, full surface).
424
+ *
425
+ * @param options - Flow identity, declared effects, ledger, principals
426
+ */
427
+ export function createFx(options: CreateFxOptions): Fx {
428
+ return createFxContext(options).fx;
429
+ }
430
+
431
+ /**
432
+ * Create `fx` plus its ledger and capability token.
433
+ *
434
+ * @param options - Same as {@link createFx}
435
+ */
436
+ export function createFxContext(options: CreateFxOptions): FxContext {
437
+ const ledger = options.ledger ?? createEffectLedger();
438
+ const capability =
439
+ options.capability ??
440
+ createCapabilityToken(options.flow, options.effects);
441
+ const now = options.now ?? (() => Date.now());
442
+ const secrets = options.secrets ?? {};
443
+ const onLog = options.onLog;
444
+
445
+ const stores = new Map<string, Map<string, unknown>>();
446
+ for (const [ref, rows] of Object.entries(options.storeData ?? {})) {
447
+ stores.set(ref, new Map(Object.entries(rows)));
448
+ }
449
+ const cacheStore = new Map<string, unknown>();
450
+
451
+ const auth: FxAuth = options.auth ?? {
452
+ userId: null,
453
+ scopes: new Set(),
454
+ };
455
+ const operator: FxOperator = options.operator ?? { id: null };
456
+ const tenant: FxTenant = options.tenant ?? { id: null };
457
+ const journal = options.journal;
458
+
459
+ async function gated<T>(
460
+ kind: Parameters<CapabilityToken["assert"]>[0],
461
+ resource: string,
462
+ body: () => T | Promise<T>,
463
+ ): Promise<T> {
464
+ capability.assert(kind, resource);
465
+ const execute = () => recordEffect(ledger, kind, resource, now, body);
466
+ if (journal) {
467
+ return journal.effect(kind, resource, execute);
468
+ }
469
+ return execute();
470
+ }
471
+
472
+ function stubStoreHandle(ref: ResourceRef): FxStubStoreHandle {
473
+ const table = (): Map<string, unknown> => {
474
+ let m = stores.get(ref);
475
+ if (!m) {
476
+ m = new Map();
477
+ stores.set(ref, m);
478
+ }
479
+ // Snapshot before any dry-run touch so writes can be rolled back.
480
+ touchDryRunStore(ref, m);
481
+ return m;
482
+ };
483
+
484
+ return {
485
+ ref,
486
+ get(key: string): Promise<unknown> {
487
+ return gated("read", ref, () => {
488
+ const v = table().get(key);
489
+ if (v === undefined || v === null) return null;
490
+ // Clone during dry-run so in-place mutation cannot leak past rollback.
491
+ return isDryRun() ? structuredClone(v) : v;
492
+ });
493
+ },
494
+ set(key: string, value: unknown): Promise<void> {
495
+ return gated("write", ref, () => {
496
+ table().set(key, value);
497
+ });
498
+ },
499
+ select(): Promise<unknown[]> {
500
+ return gated("read", ref, () => {
501
+ const values = [...table().values()];
502
+ return isDryRun()
503
+ ? values.map((v) => structuredClone(v))
504
+ : values;
505
+ });
506
+ },
507
+ insert(row: Record<string, unknown>): Promise<{ id: string }> {
508
+ return gated("write", ref, () => {
509
+ const id =
510
+ typeof row.id === "string" ? row.id : crypto.randomUUID();
511
+ table().set(id, { ...row, id });
512
+ return { id };
513
+ });
514
+ },
515
+ delete(key: string): Promise<boolean> {
516
+ return gated("write", ref, () => table().delete(key));
517
+ },
518
+ /** Audit-plugin convenience (no-op on the stub). */
519
+ async log(_ctx?: unknown): Promise<void> {
520
+ /* stub */
521
+ },
522
+ /** Audit-plugin CLI convenience. */
523
+ async exportCsv(): Promise<string> {
524
+ return "";
525
+ },
526
+ };
527
+ }
528
+
529
+ /**
530
+ * Lazy, capability-gated proxy over a driver-backed {@link SqlStoreHandle}.
531
+ *
532
+ * @param decl - Store declaration
533
+ * @param open - Opens (and caches) the runtime handle
534
+ */
535
+ function gatedSqlHandle(
536
+ decl: StoreDecl,
537
+ open: () => Promise<SqlStoreHandle>,
538
+ ): SqlStoreHandle {
539
+ const ref = decl.ref as `sql:${string}`;
540
+ let cached: SqlStoreHandle | undefined;
541
+ const ensure = async (): Promise<SqlStoreHandle> => {
542
+ if (!cached) cached = await open();
543
+ return cached;
544
+ };
545
+ /** Driver-backed SQL has no dry-run transaction — refuse writes. */
546
+ const refuseDryRunWrite = (): void => {
547
+ if (isDryRun()) {
548
+ throw new DryRunWriteIsolationError(
549
+ `Driver-backed store "${ref}" cannot isolate writes during dry-run; dry-run refused rather than risk a double-write.`,
550
+ );
551
+ }
552
+ };
553
+
554
+ return {
555
+ ref,
556
+ get routedRole() {
557
+ return cached?.routedRole ?? "primary";
558
+ },
559
+ get driverId() {
560
+ return cached?.driverId ?? "memory";
561
+ },
562
+ select(columns?) {
563
+ return {
564
+ from(table) {
565
+ const all = gated("read", ref, async () => {
566
+ const h = await ensure();
567
+ return h.select(columns).from(table);
568
+ });
569
+ return {
570
+ where(where) {
571
+ const filtered = gated("read", ref, async () => {
572
+ const h = await ensure();
573
+ return h.select(columns).from(table).where(where);
574
+ });
575
+ return {
576
+ limit(n) {
577
+ return gated("read", ref, async () => {
578
+ const h = await ensure();
579
+ return h.select(columns).from(table).where(where).limit(n);
580
+ });
581
+ },
582
+ then(onfulfilled, onrejected) {
583
+ return filtered.then(onfulfilled, onrejected);
584
+ },
585
+ };
586
+ },
587
+ then(onfulfilled, onrejected) {
588
+ return all.then(onfulfilled, onrejected);
589
+ },
590
+ };
591
+ },
592
+ };
593
+ },
594
+ insert(table) {
595
+ return {
596
+ values(row) {
597
+ const runExecute = () =>
598
+ gated("write", ref, async () => {
599
+ refuseDryRunWrite();
600
+ const h = await ensure();
601
+ await h.insert(table).values(row).execute();
602
+ });
603
+ return {
604
+ returning() {
605
+ return gated("write", ref, async () => {
606
+ refuseDryRunWrite();
607
+ const h = await ensure();
608
+ return h.insert(table).values(row).returning();
609
+ });
610
+ },
611
+ execute: runExecute,
612
+ then(onfulfilled, onrejected) {
613
+ return runExecute().then(onfulfilled, onrejected);
614
+ },
615
+ };
616
+ },
617
+ };
618
+ },
619
+ update(table) {
620
+ return {
621
+ set(row) {
622
+ return {
623
+ where(where) {
624
+ return gated("write", ref, async () => {
625
+ refuseDryRunWrite();
626
+ const h = await ensure();
627
+ return h.update(table).set(row).where(where);
628
+ });
629
+ },
630
+ };
631
+ },
632
+ };
633
+ },
634
+ findById(table, id) {
635
+ return gated("read", ref, async () => {
636
+ const h = await ensure();
637
+ return h.findById(table, id);
638
+ });
639
+ },
640
+ delete(table: Parameters<SqlStoreHandle["delete"]>[0], id?: string) {
641
+ if (id !== undefined) {
642
+ return gated("write", ref, async () => {
643
+ refuseDryRunWrite();
644
+ const h = await ensure();
645
+ return h.delete(table, id);
646
+ });
647
+ }
648
+ return {
649
+ where(where: unknown) {
650
+ return gated("write", ref, async () => {
651
+ refuseDryRunWrite();
652
+ const h = await ensure();
653
+ return h.delete(table).where(where);
654
+ });
655
+ },
656
+ };
657
+ },
658
+ exists(table, idOrWhere) {
659
+ return gated("read", ref, async () => {
660
+ const h = await ensure();
661
+ return h.exists(table, idOrWhere);
662
+ });
663
+ },
664
+ increment(table, id, column, by) {
665
+ return gated("write", ref, async () => {
666
+ refuseDryRunWrite();
667
+ const h = await ensure();
668
+ return h.increment(table, id, column, by);
669
+ });
670
+ },
671
+ raw(sql, params) {
672
+ return gated("read", ref, async () => {
673
+ const h = await ensure();
674
+ return h.raw(sql, params);
675
+ });
676
+ },
677
+ ensureTable(table) {
678
+ return gated("write", ref, async () => {
679
+ refuseDryRunWrite();
680
+ const h = await ensure();
681
+ return h.ensureTable(table);
682
+ });
683
+ },
684
+ } as SqlStoreHandle;
685
+ }
686
+
687
+ function storeHandle(
688
+ ref: NamedRef | { readonly ref: ResourceRef } | StoreDecl,
689
+ ): FxStoreHandle {
690
+ const runtime = options.storeRuntime;
691
+ if (runtime && typeof ref === "object" && ref !== null && "facet" in ref) {
692
+ const decl = ref;
693
+ const cache: { handle?: StoreHandle } = {};
694
+ const open = async () => {
695
+ if (!cache.handle) {
696
+ cache.handle = await runtime.open(decl, {
697
+ effects: options.effects ?? {},
698
+ revealPii: options.revealPii,
699
+ });
700
+ }
701
+ return cache.handle;
702
+ };
703
+
704
+ if (decl.facet === "sql") {
705
+ return gatedSqlHandle(decl, async () => {
706
+ const h = await open();
707
+ return h as SqlStoreHandle;
708
+ });
709
+ }
710
+
711
+ // KV / files / index — thin gated wrappers preserving driver methods.
712
+ const baseRef = decl.ref;
713
+ return new Proxy({} as StoreHandle, {
714
+ get(_t, prop) {
715
+ if (prop === "ref") return baseRef;
716
+ if (prop === "then") return undefined;
717
+ const isRead =
718
+ prop === "get" || prop === "search" || prop === "list";
719
+ return (...args: unknown[]) =>
720
+ gated(isRead ? "read" : "write", baseRef, async () => {
721
+ if (!isRead && isDryRun()) {
722
+ throw new DryRunWriteIsolationError(
723
+ `Driver-backed store "${baseRef}" cannot isolate writes during dry-run; dry-run refused rather than risk a double-write.`,
724
+ );
725
+ }
726
+ const h = await open();
727
+ const fn = (h as unknown as Record<string | symbol, unknown>)[
728
+ prop
729
+ ];
730
+ if (typeof fn !== "function") return undefined;
731
+ return (fn as (...a: unknown[]) => unknown).apply(h, args);
732
+ });
733
+ },
734
+ });
735
+ }
736
+ return stubStoreHandle(
737
+ resolveStoreRef(ref as NamedRef | { readonly ref: ResourceRef }),
738
+ );
739
+ }
740
+
741
+ const clock: FxClock = {
742
+ now,
743
+ async sleep(label: string, duration: string): Promise<void> {
744
+ if (journal) {
745
+ await journal.sleep(label, duration, parseDurationMs);
746
+ return;
747
+ }
748
+ /* non-durable: resolve immediately (tests / sync flows) */
749
+ void label;
750
+ void duration;
751
+ },
752
+ };
753
+
754
+ const aiDisablesCache = options.aiRuntime?.autoCacheDisabled === true;
755
+ const telemetry = options.runTelemetry;
756
+
757
+ const cache: FxCache = {
758
+ async get<T = unknown>(key: string): Promise<T | undefined> {
759
+ if (aiDisablesCache) return undefined;
760
+ if (cacheStore.has(key)) {
761
+ if (telemetry) telemetry.cacheHits += 1;
762
+ return cacheStore.get(key) as T | undefined;
763
+ }
764
+ if (telemetry) telemetry.cacheMisses += 1;
765
+ return undefined;
766
+ },
767
+ async set(key: string, value: unknown, _ttl?: string): Promise<void> {
768
+ if (aiDisablesCache) return;
769
+ cacheStore.set(key, value);
770
+ },
771
+ async getOrSet<T>(
772
+ key: string,
773
+ _ttl: string,
774
+ produce: () => T | Promise<T>,
775
+ ): Promise<T> {
776
+ if (aiDisablesCache) return await produce();
777
+ if (cacheStore.has(key)) {
778
+ if (telemetry) telemetry.cacheHits += 1;
779
+ return cacheStore.get(key) as T;
780
+ }
781
+ if (telemetry) telemetry.cacheMisses += 1;
782
+ const value = await produce();
783
+ cacheStore.set(key, value);
784
+ return value;
785
+ },
786
+ };
787
+
788
+ function redactLog(
789
+ message: string,
790
+ data?: Record<string, unknown>,
791
+ ): { message: string; data?: Record<string, unknown> } {
792
+ const vault = options.vaultRuntime;
793
+ if (!vault) return { message, data };
794
+ const safeMessage = vault.redactString(message);
795
+ const safeData = data
796
+ ? (vault.redact(data) as Record<string, unknown>)
797
+ : undefined;
798
+ return { message: safeMessage, data: safeData };
799
+ }
800
+
801
+ function emitLog(
802
+ level: "debug" | "info" | "warn" | "error",
803
+ message: string,
804
+ data?: Record<string, unknown>,
805
+ ): void {
806
+ const r = redactLog(message, data);
807
+ if (telemetry) {
808
+ telemetry.logs.push({
809
+ level,
810
+ message: r.message,
811
+ ...(r.data !== undefined ? { data: r.data } : {}),
812
+ at: now(),
813
+ });
814
+ }
815
+ onLog?.(level, r.message, r.data);
816
+ }
817
+
818
+ const log: FxLog = {
819
+ debug(message, data) {
820
+ emitLog("debug", message, data);
821
+ },
822
+ info(message, data) {
823
+ emitLog("info", message, data);
824
+ },
825
+ warn(message, data) {
826
+ emitLog("warn", message, data);
827
+ },
828
+ error(message, data) {
829
+ emitLog("error", message, data);
830
+ },
831
+ };
832
+
833
+ const fx: Fx = {
834
+ store(ref) {
835
+ return storeHandle(ref);
836
+ },
837
+ emit(signal, payload) {
838
+ const name = resolveName(signal);
839
+ return gated("emit", name, async () => {
840
+ if (options.signalRuntime) {
841
+ await options.signalRuntime.emit(name, payload);
842
+ }
843
+ });
844
+ },
845
+ call(flow, input) {
846
+ const name = resolveName(flow);
847
+ return gated("call", name, async () => {
848
+ if (options.callHandler) {
849
+ return options.callHandler(name, input);
850
+ }
851
+ return undefined;
852
+ });
853
+ },
854
+ clock,
855
+ vault(secret) {
856
+ const name = resolveName(secret);
857
+ // vault is sync in the public examples; check + record synchronously
858
+ capability.assert("secret", name);
859
+ const timestamp = now();
860
+ const value = options.vaultRuntime
861
+ ? options.vaultRuntime.read(name)
862
+ : (secrets[name] ?? `[secret:${name}]`);
863
+ ledger.record({
864
+ kind: "secret",
865
+ resource: name,
866
+ timestamp,
867
+ duration: Math.max(0, now() - timestamp),
868
+ reversibility: reversibilityOf("secret"),
869
+ });
870
+ return value;
871
+ },
872
+ cache,
873
+ send(template, opts) {
874
+ const name = resolveName(template);
875
+ return gated("send", name, async () => {
876
+ // Dry-run: record "would have fired" — never contact a real channel
877
+ // (console §9.1 · §9.3 · §9.4).
878
+ if (isDryRun()) {
879
+ recordWouldHaveFired("send", name);
880
+ return { ok: true as const };
881
+ }
882
+ if (options.channelRuntime) {
883
+ const result = await options.channelRuntime.send(name, {
884
+ to: opts?.to ?? "",
885
+ data: opts?.data,
886
+ via: opts?.via?.map(resolveName),
887
+ });
888
+ return { ok: result.ok as true };
889
+ }
890
+ return { ok: true as const };
891
+ });
892
+ },
893
+ ask(prompt, input, opts) {
894
+ const name = resolveName(prompt);
895
+ return gated("ask", name, async () => {
896
+ // Dry-run: stub the model call the same way as send.
897
+ if (isDryRun()) {
898
+ recordWouldHaveFired("ask", name);
899
+ return {};
900
+ }
901
+ if (options.aiRuntime) {
902
+ return options.aiRuntime.ask(name, input, {
903
+ via: opts?.via?.map(resolveName),
904
+ });
905
+ }
906
+ return {};
907
+ });
908
+ },
909
+ search(embed, query, opts) {
910
+ const name = resolveName(embed);
911
+ return gated("read", name, async () => {
912
+ if (options.aiRuntime && "search" in options.aiRuntime) {
913
+ const searchFn = (
914
+ options.aiRuntime as {
915
+ search?: (
916
+ embed: string,
917
+ query: unknown,
918
+ opts?: FxSearchOptions,
919
+ ) => Promise<unknown[]>;
920
+ }
921
+ ).search;
922
+ if (typeof searchFn === "function") {
923
+ return searchFn(name, query, opts);
924
+ }
925
+ }
926
+ // Deterministic stub for tests without an index driver.
927
+ if (typeof query === "string" && query.length > 0) {
928
+ return [{ id: "stub", score: 1, text: query, topK: opts?.topK ?? 5 }];
929
+ }
930
+ return [];
931
+ });
932
+ },
933
+ run(agent, input) {
934
+ const name = resolveName(agent);
935
+ return gated("ask", name, async () => {
936
+ if (options.aiRuntime) {
937
+ const message =
938
+ typeof input === "string"
939
+ ? input
940
+ : input && typeof input === "object" && "message" in input
941
+ ? String((input as { message: unknown }).message)
942
+ : JSON.stringify(input ?? {});
943
+ return options.aiRuntime.runAgent(name, {
944
+ message,
945
+ auth: {
946
+ userId: auth.userId,
947
+ scopes: auth.scopes,
948
+ verified: auth.verified,
949
+ },
950
+ });
951
+ }
952
+ return { ok: true, steps: 0, denials: [], output: input };
953
+ });
954
+ },
955
+ stream(model, opts) {
956
+ const name = resolveName(model);
957
+ const chunks = (async function* () {
958
+ await gated("ask", name, async () => undefined);
959
+ const text =
960
+ typeof opts?.data === "object" && opts?.data !== null
961
+ ? JSON.stringify(opts.data)
962
+ : String(opts?.prompt ?? "");
963
+ if (text.length === 0) {
964
+ yield "";
965
+ return;
966
+ }
967
+ // Chunk for clients that consume streaming tokens.
968
+ const size = Math.max(1, Math.ceil(text.length / 3));
969
+ for (let i = 0; i < text.length; i += size) {
970
+ yield text.slice(i, i + size);
971
+ }
972
+ })();
973
+ return chunks;
974
+ },
975
+ log,
976
+ t(key, params) {
977
+ if (params === undefined) return key;
978
+ return `${key}:${JSON.stringify(params)}`;
979
+ },
980
+ id() {
981
+ return crypto.randomUUID();
982
+ },
983
+ auth,
984
+ operator,
985
+ tenant,
986
+ fail,
987
+ async step<T>(name: string, fn: () => T | Promise<T>): Promise<T> {
988
+ if (journal) {
989
+ return journal.step(name, fn);
990
+ }
991
+ return await fn();
992
+ },
993
+ };
994
+
995
+ return { fx, ledger, capability };
996
+ }