okengine 0.13.0 → 0.15.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. package/manifest.v1.schema.json +7 -1
  2. package/package.json +4 -5
  3. package/site/content/docs/ai/mcp.mdx +27 -2
  4. package/site/content/docs/elements/ai.mdx +59 -11
  5. package/site/content/docs/elements/channel.mdx +1 -0
  6. package/site/content/docs/elements/clock.mdx +30 -12
  7. package/site/content/docs/elements/flow.mdx +9 -3
  8. package/site/content/docs/elements/gate.mdx +25 -22
  9. package/site/content/docs/elements/signal.mdx +71 -25
  10. package/site/content/docs/elements/store.mdx +87 -28
  11. package/site/content/docs/elements/vault.mdx +1 -0
  12. package/site/content/docs/get-started/basic-usage.mdx +22 -13
  13. package/site/content/docs/get-started/index.mdx +5 -0
  14. package/site/content/docs/get-started/installation.mdx +2 -2
  15. package/site/content/docs/get-started/introduction.mdx +11 -3
  16. package/site/content/docs/get-started/meta.json +1 -1
  17. package/site/content/docs/get-started/project-structure.mdx +932 -0
  18. package/site/content/docs/reference/cli.md +13 -10
  19. package/site/content/docs/reference/client.mdx +25 -21
  20. package/site/content/docs/reference/fx.mdx +27 -22
  21. package/site/content/docs/reference/security.md +1 -1
  22. package/src/auth/bindings.ts +14 -5
  23. package/src/auth/cross-plane.ts +10 -3
  24. package/src/cli/ai-setup/ai-setup.test.ts +62 -0
  25. package/src/cli/ai-setup/apply.ts +32 -1
  26. package/src/cli/ai-setup/recommend.test.ts +25 -0
  27. package/src/cli/ai-setup/recommend.ts +8 -3
  28. package/src/cli/attach-host-console.test.ts +3 -2
  29. package/src/cli/attach-host-console.ts +3 -0
  30. package/src/cli/build.test.ts +4 -2
  31. package/src/cli/db-seed.ts +48 -15
  32. package/src/cli/db.test.ts +104 -0
  33. package/src/cli/db.ts +122 -10
  34. package/src/cli/dev-controls.test.ts +20 -0
  35. package/src/cli/dev-controls.ts +13 -0
  36. package/src/cli/dev.test.ts +15 -4
  37. package/src/cli/dev.ts +102 -29
  38. package/src/cli/ensure-drizzle-config.ts +2 -1
  39. package/src/cli/tui/DevLive.tsx +12 -2
  40. package/src/cli/tui/keys.test.ts +2 -1
  41. package/src/cli/tui/keys.ts +3 -2
  42. package/src/compiler/aot.test.ts +1 -1
  43. package/src/compiler/effects-infer.ts +58 -3
  44. package/src/compiler/extract.test.ts +458 -29
  45. package/src/compiler/extract.ts +387 -69
  46. package/src/compiler/flow-path.test.ts +96 -0
  47. package/src/compiler/flow-path.ts +173 -0
  48. package/src/compiler/generate-adopt.test.ts +112 -3
  49. package/src/compiler/generate-adopt.ts +280 -26
  50. package/src/compiler/response.ts +45 -1
  51. package/src/compiler/schema-from-ast.ts +609 -0
  52. package/src/console/server/ai.ts +5 -2
  53. package/src/console/server/bind.ts +2 -2
  54. package/src/console/server/console.test.ts +3 -0
  55. package/src/console/server/flows.ts +121 -40
  56. package/src/console/server/invoke-user-flow.test.ts +3 -1
  57. package/src/console/server/invoke-user-flow.ts +17 -2
  58. package/src/console/server/iso-at.test.ts +9 -0
  59. package/src/console/server/iso-at.ts +11 -0
  60. package/src/console/server/security-headers.ts +6 -3
  61. package/src/console/server/serve.ts +17 -2
  62. package/src/console/server/spa-proxy.test.ts +1 -0
  63. package/src/console/server/sql-catalog.ts +147 -7
  64. package/src/console/server/sql-rls.test.ts +16 -0
  65. package/src/console/server/state.ts +8 -0
  66. package/src/console/server/store.test.ts +7 -4
  67. package/src/console/server/store.ts +142 -58
  68. package/src/console/ui-next/dist/assets/agent-disclosure-C0X1fbWF.js +1 -0
  69. package/src/console/ui-next/dist/assets/cache-glyph-F1FI122b.js +1 -0
  70. package/src/console/ui-next/dist/assets/{call-pii-button-bqkxMrJH.js → call-pii-button-DEDCl_j3.js} +1 -1
  71. package/src/console/ui-next/dist/assets/collapsible-LPqGvfoz.js +1 -0
  72. package/src/console/ui-next/dist/assets/{confirm-sheet-DDCRmG62.js → confirm-sheet-3ptDzXbz.js} +1 -1
  73. package/src/console/ui-next/dist/assets/{duration-tone-oiRxPVsZ.js → duration-tone-sC3lGABz.js} +1 -1
  74. package/src/console/ui-next/dist/assets/{explorer-empty-HjTnVQoR.js → explorer-empty-BvYrygyO.js} +1 -1
  75. package/src/console/ui-next/dist/assets/flows-page-Dluo1Bd7.js +1 -0
  76. package/src/console/ui-next/dist/assets/{highlighted-json-CvDPvveV.js → highlighted-json-CS_O8L-r.js} +1 -1
  77. package/src/console/ui-next/dist/assets/http-method--sWDdXSB.js +1 -0
  78. package/src/console/ui-next/dist/assets/index-Ca3HZMVq.js +66 -0
  79. package/src/console/ui-next/dist/assets/index-UtTDRQpS.css +2 -0
  80. package/src/console/ui-next/dist/assets/{link-DF7SZ9Ek.js → link-COeyggt-.js} +1 -1
  81. package/src/console/ui-next/dist/assets/observability-page-HK9-BO8z.js +4 -0
  82. package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +1 -0
  83. package/src/console/ui-next/dist/assets/replica-lag-DBIFFf7d.js +18 -0
  84. package/src/console/ui-next/dist/assets/sheet-form-Dnwa5oOR.js +1 -0
  85. package/src/console/ui-next/dist/assets/shortcut-keys-CoqwEIi0.js +1 -0
  86. package/src/console/ui-next/dist/assets/skeleton-BHcfDYcb.js +1 -0
  87. package/src/console/ui-next/dist/assets/store-page-BSohH3wM.js +41 -0
  88. package/src/console/ui-next/dist/assets/trace-detail-sheet-CFIGRnnA.js +2 -0
  89. package/src/console/ui-next/dist/assets/tree-expand-toggle-BgLl34w7.js +54 -0
  90. package/src/console/ui-next/dist/assets/units-page-B0cFE76A.js +1 -0
  91. package/src/console/ui-next/dist/assets/{use-vault-list-Cl79j_ku.js → use-vault-list-BLbZhzyF.js} +1 -1
  92. package/src/console/ui-next/dist/assets/vault-page-B1SbYe10.js +2 -0
  93. package/src/console/ui-next/dist/index.html +6 -6
  94. package/src/console/ui-next/seed-invoke-host.ts +2 -0
  95. package/src/console/ui-next/src/client.ts +35 -7
  96. package/src/console/ui-next/src/components/motion/table/index.tsx +16 -0
  97. package/src/console/ui-next/src/components/motion/table/types.ts +4 -0
  98. package/src/console/ui-next/src/components/ui/kbd.tsx +2 -2
  99. package/src/console/ui-next/src/features/flows/graph/build-flow-graph.test.ts +18 -0
  100. package/src/console/ui-next/src/features/flows/graph/build-flow-graph.ts +14 -1
  101. package/src/console/ui-next/src/features/flows/graph/neighborhood.test.ts +17 -0
  102. package/src/console/ui-next/src/features/flows/graph/neighborhood.ts +16 -3
  103. package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +3 -1
  104. package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +24 -0
  105. package/src/console/ui-next/src/features/flows/traces/http-method.ts +19 -0
  106. package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +9 -3
  107. package/src/console/ui-next/src/features/flows/traces/trace-detail.test.ts +29 -2
  108. package/src/console/ui-next/src/features/flows/traces/traces-pane.tsx +10 -3
  109. package/src/console/ui-next/src/features/observability/lib/ask-count.test.ts +25 -0
  110. package/src/console/ui-next/src/features/observability/lib/ask-count.ts +4 -1
  111. package/src/console/ui-next/src/features/store/detail/browse-section.tsx +45 -1
  112. package/src/console/ui-next/src/features/store/detail/resource-panel.tsx +78 -16
  113. package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +155 -14
  114. package/src/console/ui-next/src/features/store/explorer/store-tree.tsx +33 -133
  115. package/src/console/ui-next/src/features/store/files/file-preview.tsx +4 -1
  116. package/src/console/ui-next/src/features/store/grid/rls-policy-sheet.tsx +326 -165
  117. package/src/console/ui-next/src/features/store/grid/sql-insert-sheet.tsx +6 -0
  118. package/src/console/ui-next/src/features/store/grid/store-data-grid.tsx +50 -3
  119. package/src/console/ui-next/src/features/store/lib/files-meta.test.ts +3 -0
  120. package/src/console/ui-next/src/features/store/lib/files-meta.ts +12 -0
  121. package/src/console/ui-next/src/features/store/lib/query-defaults.test.ts +25 -0
  122. package/src/console/ui-next/src/features/store/lib/query-defaults.ts +85 -3
  123. package/src/console/ui-next/src/features/store/lib/query-gate.ts +30 -4
  124. package/src/console/ui-next/src/features/store/lib/rls-policy.test.ts +139 -0
  125. package/src/console/ui-next/src/features/store/lib/rls-policy.ts +223 -21
  126. package/src/console/ui-next/src/features/store/lib/schema-graph.ts +4 -0
  127. package/src/console/ui-next/src/features/store/lib/sql-catalog.test.ts +24 -0
  128. package/src/console/ui-next/src/features/store/lib/sql-catalog.ts +19 -0
  129. package/src/console/ui-next/src/features/store/lib/store-tree.test.ts +6 -0
  130. package/src/console/ui-next/src/features/store/lib/store-tree.ts +13 -0
  131. package/src/console/ui-next/src/features/store/query/query-console.tsx +48 -14
  132. package/src/console/ui-next/src/features/store/query/query-gate-menu.tsx +19 -20
  133. package/src/console/ui-next/src/features/store/query/query-gate-parts.tsx +2 -1
  134. package/src/console/ui-next/src/features/store/query/query-results.tsx +110 -83
  135. package/src/console/ui-next/src/features/store/schema/schema-table-node.tsx +17 -0
  136. package/src/console/ui-next/src/features/units/call/call-api-panel.tsx +112 -72
  137. package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +12 -4
  138. package/src/console/ui-next/src/features/units/lib/contract-input.test.ts +206 -1
  139. package/src/console/ui-next/src/features/units/lib/contract-input.ts +55 -0
  140. package/src/console/ui-next/src/features/vault/lib/types.ts +1 -1
  141. package/src/docker/compose-health.test.ts +27 -0
  142. package/src/docker/compose-health.ts +19 -3
  143. package/src/docker/docker.test.ts +4 -1
  144. package/src/docker/dockerfile.ts +1 -1
  145. package/src/docker/recipes/pgdog.ts +2 -0
  146. package/src/drivers/ai-anthropic.ts +5 -0
  147. package/src/drivers/ai-ollama.ts +49 -30
  148. package/src/drivers/ai-openai-compatible.ts +57 -46
  149. package/src/drivers/ai-providers.test.ts +3 -0
  150. package/src/drivers/bun-native-completeness.test.ts +7 -9
  151. package/src/drivers/clock-postgres.ts +13 -9
  152. package/src/drivers/instances-postgres.ts +4 -6
  153. package/src/drivers/journal-postgres.ts +13 -9
  154. package/src/drivers/pg-rls.test.ts +87 -0
  155. package/src/drivers/pg-rls.ts +233 -7
  156. package/src/drivers/pglite.ts +26 -3
  157. package/src/drivers/postgres.test.ts +23 -0
  158. package/src/drivers/postgres.ts +133 -9
  159. package/src/drivers/redis.ts +11 -4
  160. package/src/drivers/signal-redis.ts +24 -14
  161. package/src/drivers/signal-types.ts +2 -1
  162. package/src/drivers/types.ts +10 -0
  163. package/src/elements/ai/declare.ts +109 -0
  164. package/src/elements/ai/errors.test.ts +5 -1
  165. package/src/elements/ai/errors.ts +30 -2
  166. package/src/elements/ai/eval.ts +4 -6
  167. package/src/elements/ai/mcp-client.test.ts +206 -0
  168. package/src/elements/ai/mcp-client.ts +362 -0
  169. package/src/elements/ai/mcp-http.ts +159 -0
  170. package/src/elements/ai/mcp-mock.ts +134 -0
  171. package/src/elements/ai/mcp-protocol.ts +234 -0
  172. package/src/elements/ai/mcp-stdio.test.ts +50 -0
  173. package/src/elements/ai/mcp-stdio.ts +212 -0
  174. package/src/elements/ai/mcp-transport.ts +70 -0
  175. package/src/elements/ai/runtime.ts +159 -29
  176. package/src/elements/ai.test.ts +139 -0
  177. package/src/elements/ai.ts +16 -0
  178. package/src/elements/clock/declare.ts +26 -1
  179. package/src/elements/clock/health.test.ts +43 -0
  180. package/src/elements/clock/runtime.ts +55 -2
  181. package/src/elements/clock/schedule.ts +71 -142
  182. package/src/elements/clock.test.ts +9 -40
  183. package/src/elements/clock.ts +6 -1
  184. package/src/elements/gate/boot.ts +5 -5
  185. package/src/elements/gate/declare.ts +36 -4
  186. package/src/elements/gate/flatten.ts +1 -1
  187. package/src/elements/gate/runtime.ts +1 -1
  188. package/src/elements/index.ts +2 -0
  189. package/src/elements/signal/declare.ts +2 -1
  190. package/src/elements/signal/runtime.ts +16 -1
  191. package/src/elements/signal.ts +1 -0
  192. package/src/elements/store/cache.test.ts +2 -0
  193. package/src/elements/store/cache.ts +3 -3
  194. package/src/elements/store/declare.ts +9 -6
  195. package/src/elements/store/emit-drizzle.ts +44 -8
  196. package/src/elements/store/resource.test.ts +1 -1
  197. package/src/elements/store/rls-identity.test.ts +95 -0
  198. package/src/elements/store/rls-identity.ts +116 -0
  199. package/src/elements/store/runtime.ts +4 -0
  200. package/src/elements/store/schema-decl.test.ts +37 -0
  201. package/src/elements/store/schema-decl.ts +161 -0
  202. package/src/elements/store/seed.ts +1 -1
  203. package/src/elements/store/sql-condition.test.ts +12 -0
  204. package/src/elements/store/sql-condition.ts +26 -2
  205. package/src/elements/store/sql-rls-isolation.test.ts +165 -0
  206. package/src/elements/store/sql-rls-stamp.test.ts +117 -0
  207. package/src/elements/store/sql-session.ts +81 -3
  208. package/src/elements/store/upsert-app.test.ts +1 -1
  209. package/src/elements/store.ts +14 -0
  210. package/src/elements/vault/builtin-adapter.ts +17 -0
  211. package/src/full.ts +2 -0
  212. package/src/http.ts +20 -3
  213. package/src/index.ts +14 -1
  214. package/src/kernel/adopt-barrel-fresh.test.ts +1 -1
  215. package/src/kernel/adopt-routes.ts +30 -2
  216. package/src/kernel/app.ts +227 -77
  217. package/src/kernel/auto-cache.test.ts +8 -8
  218. package/src/kernel/auto-registry.test.ts +54 -9
  219. package/src/kernel/boot-bind/ai.ts +24 -0
  220. package/src/kernel/boot-bind/clock.ts +2 -0
  221. package/src/kernel/boot.test.ts +4 -4
  222. package/src/kernel/boot.ts +5 -3
  223. package/src/kernel/effects-stamping.test.ts +3 -3
  224. package/src/kernel/element-registries.ts +15 -5
  225. package/src/kernel/errors.ts +24 -0
  226. package/src/kernel/flow-units.ts +64 -0
  227. package/src/kernel/flow.ts +29 -17
  228. package/src/kernel/fx-dead-letters.test.ts +77 -0
  229. package/src/kernel/fx.test.ts +22 -0
  230. package/src/kernel/fx.ts +135 -6
  231. package/src/kernel/horizontal-child.ts +4 -4
  232. package/src/kernel/http-path-pending.ts +20 -0
  233. package/src/kernel/http-resource.ts +4 -0
  234. package/src/kernel/http-stream.test.ts +174 -0
  235. package/src/kernel/index.ts +2 -0
  236. package/src/kernel/pipeline.test.ts +2 -2
  237. package/src/kernel/plugin-elements.test.ts +1 -1
  238. package/src/kernel/plugin-needs.test.ts +1 -1
  239. package/src/kernel/ready.test.ts +2 -2
  240. package/src/kernel/resource-mount.test.ts +14 -0
  241. package/src/kernel/run-duration.test.ts +2 -2
  242. package/src/kernel/stamp-http.test.ts +79 -0
  243. package/src/kernel/stamp-http.ts +75 -0
  244. package/src/kernel/triggers.ts +52 -27
  245. package/src/manifest/mcp-ref.ts +88 -0
  246. package/src/manifest/types.ts +41 -2
  247. package/src/manifest/validate.test.ts +20 -0
  248. package/src/mcp/docs-server.ts +1 -1
  249. package/src/mcp/server.ts +1 -1
  250. package/src/plugins/compression.test.ts +21 -0
  251. package/src/plugins/compression.ts +1 -0
  252. package/src/release/measure.ts +2 -2
  253. package/src/runtime/bun.ts +41 -4
  254. package/src/runtime/json-code-block.test.ts +2 -2
  255. package/src/runtime/serve.test.ts +4 -4
  256. package/src/term.test.ts +52 -4
  257. package/src/term.ts +125 -17
  258. package/src/test/reset-element-registries.ts +10 -3
  259. package/src/cli/ask-seed.test.ts +0 -96
  260. package/src/cli/ask-seed.ts +0 -82
  261. package/src/console/ui-next/dist/assets/cache-glyph-CLPBqZeb.js +0 -1
  262. package/src/console/ui-next/dist/assets/collapsible-DYb0xU8C.js +0 -1
  263. package/src/console/ui-next/dist/assets/flows-page-Dg8CTE29.js +0 -1
  264. package/src/console/ui-next/dist/assets/http-method-BJ92Z_ke.js +0 -1
  265. package/src/console/ui-next/dist/assets/index-Bp-R7jtM.js +0 -66
  266. package/src/console/ui-next/dist/assets/index-D4Ldtj79.css +0 -2
  267. package/src/console/ui-next/dist/assets/observability-page-DAnpEaq1.js +0 -4
  268. package/src/console/ui-next/dist/assets/query-gate-parts-1m8m1iNp.js +0 -2
  269. package/src/console/ui-next/dist/assets/react-B1ML8gxg.js +0 -1
  270. package/src/console/ui-next/dist/assets/replica-lag-C8_BRt2x.js +0 -18
  271. package/src/console/ui-next/dist/assets/sheet-form-D-ata7jy.js +0 -1
  272. package/src/console/ui-next/dist/assets/shortcut-keys-DO4IsVqv.js +0 -1
  273. package/src/console/ui-next/dist/assets/skeleton-CL_X0GCj.js +0 -1
  274. package/src/console/ui-next/dist/assets/store-page-v3LXdYpr.js +0 -45
  275. package/src/console/ui-next/dist/assets/trace-detail-sheet-D16lWQMt.js +0 -2
  276. package/src/console/ui-next/dist/assets/units-page-BtQ0bqMe.js +0 -1
  277. package/src/console/ui-next/dist/assets/vault-page-Ca-MvcmJ.js +0 -2
@@ -39,10 +39,20 @@ export type AppFlowRoute<
39
39
  readonly path?: undefined;
40
40
  };
41
41
 
42
- /** Unit → flow → contract. */
42
+ /**
43
+ * Unit → flow → contract. Leaf is the HTTP / call-only union — do not
44
+ * index with `AppFlowRoute<any, any, any, any, any>` (`any extends string`
45
+ * makes `method`/`path` required and rejects cron / signal flows).
46
+ */
43
47
  export type AppRouteMap = {
44
48
  readonly [unit: string]: {
45
- readonly [flow: string]: AppFlowRoute<any, any, any, any, any>;
49
+ readonly [flow: string]: {
50
+ readonly in?: unknown;
51
+ readonly out?: unknown;
52
+ readonly errors?: unknown;
53
+ readonly method?: string;
54
+ readonly path?: string;
55
+ };
46
56
  };
47
57
  };
48
58
 
@@ -170,6 +180,7 @@ export function accumulateAdoptArgs(args: readonly unknown[], into: RuntimeRoute
170
180
  const unitBag = into[unit] ?? (into[unit] = {});
171
181
  for (const [flowName, flowDef] of Object.entries(value as Record<string, unknown>)) {
172
182
  if (!isFlow(flowDef)) continue;
183
+ stampAdoptedFlow(flowDef, unit, flowName);
173
184
  found.push(flowDef);
174
185
  unitBag[flowName] = runtimeRouteFromFlow(flowDef);
175
186
  }
@@ -178,3 +189,20 @@ export function accumulateAdoptArgs(args: readonly unknown[], into: RuntimeRoute
178
189
 
179
190
  return found;
180
191
  }
192
+
193
+ /**
194
+ * Stamp `unit.export` on nameless flows — same rule as {@link unit}.
195
+ *
196
+ * @param flowDef - Flow to stamp
197
+ * @param unit - Client unit (folder / adopt key)
198
+ * @param exportName - Namespace export
199
+ */
200
+ function stampAdoptedFlow(flowDef: AnyFlowDef, unit: string, exportName: string): void {
201
+ const f = flowDef as { name: string; unit: string | undefined };
202
+ if (!f.name || f.name.startsWith("flow_")) {
203
+ f.name = `${unit}.${exportName}`;
204
+ }
205
+ if (!f.unit) {
206
+ f.unit = unit;
207
+ }
208
+ }
package/src/kernel/app.ts CHANGED
@@ -14,6 +14,7 @@ import {
14
14
  accumulateAdoptArgs,
15
15
  type AppRouteMap,
16
16
  type RoutesFromAdoptArgs,
17
+ type RoutesFromNamespace,
17
18
  type RuntimeRouteMap,
18
19
  } from "./adopt-routes.ts";
19
20
  // `./boot.ts` pulls in every element + driver module (vault, store, signal,
@@ -37,10 +38,12 @@ import { runWithLocale } from "../i18n/locale-context.ts";
37
38
  import { runDurable } from "../elements/clock/durable.ts";
38
39
  import { isFlow, type AnyFlowDef } from "./flow.ts";
39
40
  import { failureFromUnknown, runCompensationPhase } from "./compensate.ts";
41
+ import { withAbortSignal } from "./abort-scope.ts";
40
42
  import { fxRetry } from "./concurrency.ts";
41
43
  import {
42
44
  createFxContext,
43
45
  freezePrincipal,
46
+ isJsonStreamResult,
44
47
  resolveName,
45
48
  type CreateFxOptions,
46
49
  type Fx,
@@ -57,7 +60,8 @@ import {
57
60
  } from "../runtime/dev-request-log.ts";
58
61
  import { asBrowserJsonCodeBlock, httpNavGroups } from "../runtime/json-code-block.ts";
59
62
  import { resolveDurationMs } from "./elapsed.ts";
60
- import { fail } from "./errors.ts";
63
+ import { fail, throwOke } from "./errors.ts";
64
+ import { consumeRegisteredFlowUnits, type FlowUnitBag } from "./flow-units.ts";
61
65
  import {
62
66
  isFlowFailure,
63
67
  mergeHooks,
@@ -85,9 +89,12 @@ import { listBindings, resetBindings, type Binding } from "./on.ts";
85
89
  import {
86
90
  aiAgentRegistry,
87
91
  aiEmbedRegistry,
92
+ aiMcpServerRegistry,
88
93
  aiModelRegistry,
89
94
  aiPromptRegistry,
90
95
  channelTemplateRegistry,
96
+ clockRegistry,
97
+ gateRegistry,
91
98
  requiredEnvRegistry,
92
99
  secretRegistry,
93
100
  signalRegistry,
@@ -96,6 +103,7 @@ import {
96
103
  import {
97
104
  applyPrincipal,
98
105
  createElementPipelineHooks,
106
+ gateNamesOf,
99
107
  type PrincipalBag,
100
108
  type ResolvedPrincipal,
101
109
  } from "./pipeline.ts";
@@ -115,6 +123,7 @@ import {
115
123
  type RouterPreset,
116
124
  type SmartRouter,
117
125
  } from "./router.ts";
126
+ import { isPendingHttpPath } from "./http-path-pending.ts";
118
127
  import type {
119
128
  CdcTrigger,
120
129
  EveryTrigger,
@@ -296,6 +305,21 @@ export interface UnitHooks<D extends Record<string, unknown> = {}> {
296
305
  plug<P extends PluginDef>(pluginDef: P): UnitHooks<AccumulateDecorations<D, P>>;
297
306
  }
298
307
 
308
+ /**
309
+ * Module-augmentation slot filled by `src/flows/generated.ts`.
310
+ * Kernel tests do not import an app generated file, so this stays `{}`.
311
+ */
312
+ export interface RegisteredFlowUnits {}
313
+
314
+ /**
315
+ * `$routes` derived from {@link RegisteredFlowUnits} after `import generated`.
316
+ *
317
+ * @typeParam U - Augmented unit map
318
+ */
319
+ export type RoutesFromRegisteredUnits<U = RegisteredFlowUnits> = {
320
+ [K in keyof U]: U[K] extends Record<string, unknown> ? RoutesFromNamespace<U[K]> : never;
321
+ };
322
+
299
323
  /**
300
324
  * Application instance — adopts flows, routes HTTP, runs the pipeline.
301
325
  *
@@ -432,6 +456,8 @@ export interface OkeApp<D extends Record<string, unknown> = {}, R extends AppRou
432
456
  * Takes effect only with {@link trustedInvoke}.
433
457
  */
434
458
  readonly revealPii?: boolean;
459
+ /** Forced RLS bag (Console / Call API). Operator omit = no stamp. */
460
+ readonly rls?: import("../drivers/pg-rls.ts").RlsIdentity;
435
461
  /** Parent WideEvent id when this execution was caused by another. */
436
462
  readonly parentId?: string;
437
463
  /** Explicit run / WideEvent id (defaults to a new UUID). */
@@ -531,18 +557,21 @@ function mergeAiOptions(
531
557
  readonly prompts: NonNullable<BootOptions["ai"]>["prompts"];
532
558
  readonly embeds: NonNullable<BootOptions["ai"]>["embeds"];
533
559
  readonly agents: NonNullable<BootOptions["ai"]>["agents"];
560
+ readonly mcpServers: NonNullable<BootOptions["ai"]>["mcpServers"];
534
561
  },
535
562
  ): BootOptions["ai"] | undefined {
536
563
  const models = mergeUnique(explicit?.models, fromRegistry.models ?? []);
537
564
  const prompts = mergeUnique(explicit?.prompts, fromRegistry.prompts ?? []);
538
565
  const embeds = mergeUnique(explicit?.embeds, fromRegistry.embeds ?? []);
539
566
  const agents = mergeUnique(explicit?.agents, fromRegistry.agents ?? []);
567
+ const mcpServers = mergeUnique(explicit?.mcpServers, fromRegistry.mcpServers ?? []);
540
568
  if (
541
569
  explicit === undefined &&
542
570
  models.length === 0 &&
543
571
  prompts.length === 0 &&
544
572
  embeds.length === 0 &&
545
- agents.length === 0
573
+ agents.length === 0 &&
574
+ mcpServers.length === 0
546
575
  ) {
547
576
  return undefined;
548
577
  }
@@ -552,14 +581,61 @@ function mergeAiOptions(
552
581
  ...(prompts.length > 0 ? { prompts } : {}),
553
582
  ...(embeds.length > 0 ? { embeds } : {}),
554
583
  ...(agents.length > 0 ? { agents } : {}),
584
+ ...(mcpServers.length > 0 ? { mcpServers } : {}),
555
585
  };
556
586
  }
557
587
 
588
+ /**
589
+ * Refuse an unresolved path sentinel or a nameless HTTP flow.
590
+ *
591
+ * @param binding - HTTP binding
592
+ */
593
+ function assertHttpBindingReady(binding: Binding): void {
594
+ const trigger = binding.trigger;
595
+ if (trigger.kind !== "http") return;
596
+ if (isPendingHttpPath(trigger.path)) {
597
+ throwOke("HTTP_PATH_UNRESOLVED", {
598
+ flow: binding.flow.name || "(unnamed)",
599
+ method: trigger.method,
600
+ });
601
+ }
602
+ if (!binding.flow.name || binding.flow.name.startsWith("flow_")) {
603
+ throwOke("HTTP_FLOW_UNNAMED", {
604
+ method: trigger.method,
605
+ path: trigger.path,
606
+ });
607
+ }
608
+ }
609
+
610
+ /**
611
+ * Fold `generated.ts` units into `$routes` and `flowsByName`.
612
+ *
613
+ * @param units - Drained {@link registerFlowUnits} bag
614
+ * @param routes - Runtime `$routes`
615
+ * @param registerFlow - App flow index
616
+ */
617
+ function drainGeneratedUnits(
618
+ units: Record<string, FlowUnitBag>,
619
+ routes: RuntimeRouteMap,
620
+ registerFlow: (flowDef: AnyFlowDef) => void,
621
+ ): void {
622
+ if (Object.keys(units).length === 0) return;
623
+ const flows = accumulateAdoptArgs([units], routes);
624
+ for (const flowDef of flows) {
625
+ registerFlow(flowDef);
626
+ }
627
+ }
628
+
558
629
  /**
559
630
  * Create an application. Adopts bindings registered via {@link on}.
631
+ * Drains {@link registerFlowUnits} into `$routes` unless `registry: "ignore"`.
560
632
  *
561
633
  * @param options - App name and router preset
562
634
  */
635
+ export function oke(
636
+ options: OkeOptions & { readonly registry: "ignore" },
637
+ ): OkeApp<Record<string, never>, Record<string, never>>;
638
+ export function oke(options: OkeOptions): OkeApp<{}, RoutesFromRegisteredUnits>;
563
639
  export function oke(options: OkeOptions): OkeApp {
564
640
  const aot = options.aot !== false;
565
641
  const registry = options.registry ?? "consume";
@@ -569,11 +645,12 @@ export function oke(options: OkeOptions): OkeApp {
569
645
  : [...listBindings(), ...(options.bindings ?? [])];
570
646
  if (registry === "consume") resetBindings();
571
647
 
572
- // Same registry mode drains store.sql/store.files, vault.secret, signal(),
573
- // channel.<medium>().template(), and ai.model/prompt/embed/agent —
574
- // module-evaluation registries that mirror `on`'s trigger drain
575
- // (`listBindings`/`resetBindings` above). Explicit `options.stores` /
576
- // `secrets` / `signals` / `channel.templates` / `ai` are additive, never
648
+ // Same registry mode drains store.*, vault.secret, signal(), clock(),
649
+ // gate.policy/scope/rate, channel.<medium>().template(), and
650
+ // ai.model/prompt/embed/agent/mcpServer — module-evaluation registries
651
+ // that mirror `on`'s trigger drain (`listBindings`/`resetBindings` above).
652
+ // Explicit `options.stores` / `secrets` / `signals` / `clocks` /
653
+ // `gate.policies` / `channel.templates` / `ai` are additive, never
577
654
  // silently ignored — deduped by reference so an explicitly-passed decl
578
655
  // that is also in the registry is not doubled.
579
656
  const registrySnapshot =
@@ -583,37 +660,48 @@ export function oke(options: OkeOptions): OkeApp {
583
660
  secrets: [],
584
661
  requiredEnv: [],
585
662
  signals: [],
663
+ clocks: [],
664
+ gates: [],
586
665
  channelTemplates: [],
587
666
  aiModels: [],
588
667
  aiPrompts: [],
589
668
  aiEmbeds: [],
590
669
  aiAgents: [],
670
+ aiMcpServers: [],
591
671
  }
592
672
  : {
593
673
  stores: storeRegistry.slice(),
594
674
  secrets: secretRegistry.slice(),
595
675
  requiredEnv: requiredEnvRegistry.slice(),
596
676
  signals: signalRegistry.slice(),
677
+ clocks: clockRegistry.slice(),
678
+ gates: gateRegistry.slice(),
597
679
  channelTemplates: channelTemplateRegistry.slice(),
598
680
  aiModels: aiModelRegistry.slice(),
599
681
  aiPrompts: aiPromptRegistry.slice(),
600
682
  aiEmbeds: aiEmbedRegistry.slice(),
601
683
  aiAgents: aiAgentRegistry.slice(),
684
+ aiMcpServers: aiMcpServerRegistry.slice(),
602
685
  };
603
686
  if (registry === "consume") {
604
687
  storeRegistry.length = 0;
605
688
  secretRegistry.length = 0;
606
689
  requiredEnvRegistry.length = 0;
607
690
  signalRegistry.length = 0;
691
+ clockRegistry.length = 0;
692
+ gateRegistry.length = 0;
608
693
  channelTemplateRegistry.length = 0;
609
694
  aiModelRegistry.length = 0;
610
695
  aiPromptRegistry.length = 0;
611
696
  aiEmbedRegistry.length = 0;
612
697
  aiAgentRegistry.length = 0;
698
+ aiMcpServerRegistry.length = 0;
613
699
  }
614
700
  const effectiveStores = mergeUnique(options.stores, registrySnapshot.stores);
615
701
  const effectiveSecrets = mergeUnique(options.secrets, registrySnapshot.secrets);
616
702
  const effectiveSignals = mergeUnique(options.signals, registrySnapshot.signals);
703
+ const effectiveClocks = mergeUnique(options.clocks, registrySnapshot.clocks);
704
+ const effectivePolicies = mergeUnique(options.gate?.policies, registrySnapshot.gates);
617
705
  /**
618
706
  * Fold registered `vault.env.required` names into the vault boot options so
619
707
  * boot reports missing env vars in the same gap list as missing secrets.
@@ -643,20 +731,28 @@ export function oke(options: OkeOptions): OkeApp {
643
731
  prompts: registrySnapshot.aiPrompts,
644
732
  embeds: registrySnapshot.aiEmbeds,
645
733
  agents: registrySnapshot.aiAgents,
734
+ mcpServers: registrySnapshot.aiMcpServers,
646
735
  });
647
736
 
648
737
  // Resolve Gate bag early so auth HTTP Bindings join `adopted` + the router
649
738
  // before posture audit (same ensureBoot → doBoot path — never a side channel).
739
+ const mergedGate: GateOptions | undefined =
740
+ effectivePolicies.length > 0 ? { ...options.gate, policies: effectivePolicies } : options.gate;
650
741
  const gateConfig: ResolvedGateConfig = resolveGateConfig({
651
- gate: options.gate,
742
+ gate: mergedGate,
652
743
  env: options.env,
653
744
  });
654
745
 
655
- /** Retained for test harness / boot merges (includes auto-drained AI decls). */
656
- const $options: OkeOptions =
657
- effectiveAi === undefined || options.ai === effectiveAi
658
- ? options
659
- : { ...options, ai: effectiveAi };
746
+ /** Retained for test harness / boot merges (includes auto-drained decls). */
747
+ const $options: OkeOptions = {
748
+ ...options,
749
+ ...(effectiveAi !== undefined ? { ai: effectiveAi } : {}),
750
+ ...(effectiveStores.length > 0 ? { stores: effectiveStores } : {}),
751
+ ...(effectiveSecrets.length > 0 ? { secrets: effectiveSecrets } : {}),
752
+ ...(effectiveSignals.length > 0 ? { signals: effectiveSignals } : {}),
753
+ ...(effectiveClocks.length > 0 ? { clocks: effectiveClocks } : {}),
754
+ ...(mergedGate !== undefined ? { gate: mergedGate } : {}),
755
+ };
660
756
 
661
757
  const appHooks: HookMap = {};
662
758
  const unitHooks = new Map<string, HookMap>();
@@ -690,8 +786,19 @@ export function oke(options: OkeOptions): OkeApp {
690
786
  }
691
787
 
692
788
  const smart = createRouter<Binding>(options.router ?? "default");
789
+ const seenHttpRoutes = new Set<string>();
693
790
  for (const b of adopted) {
694
791
  if (b.trigger.kind === "http") {
792
+ assertHttpBindingReady(b);
793
+ const key = `${b.trigger.method} ${b.trigger.path}`;
794
+ if (seenHttpRoutes.has(key)) {
795
+ throwOke("HTTP_ROUTE_DUPLICATE", {
796
+ method: b.trigger.method,
797
+ path: b.trigger.path,
798
+ flow: b.flow.name || "(unnamed)",
799
+ });
800
+ }
801
+ seenHttpRoutes.add(key);
695
802
  smart.add(b.trigger.method, b.trigger.path, b);
696
803
  compiled.set(b, compileHttpBinding(b, aot));
697
804
  }
@@ -704,6 +811,16 @@ export function oke(options: OkeOptions): OkeApp {
704
811
  adopted.push(b);
705
812
  registerFlow(b.flow);
706
813
  if (b.trigger.kind === "http") {
814
+ assertHttpBindingReady(b);
815
+ const key = `${b.trigger.method} ${b.trigger.path}`;
816
+ if (seenHttpRoutes.has(key)) {
817
+ throwOke("HTTP_ROUTE_DUPLICATE", {
818
+ method: b.trigger.method,
819
+ path: b.trigger.path,
820
+ flow: b.flow.name || "(unnamed)",
821
+ });
822
+ }
823
+ seenHttpRoutes.add(key);
707
824
  smart.add(b.trigger.method, b.trigger.path, b);
708
825
  compiled.set(b, compileHttpBinding(b, aot));
709
826
  }
@@ -777,6 +894,11 @@ export function oke(options: OkeOptions): OkeApp {
777
894
  registerFlow(b.flow);
778
895
  }
779
896
 
897
+ if (registry !== "ignore") {
898
+ const generatedUnits = consumeRegisteredFlowUnits();
899
+ drainGeneratedUnits(generatedUnits, routes, registerFlow);
900
+ }
901
+
780
902
  // --- boot (vault → store → signal → clock → channel → AI → runs → caps) ---
781
903
  let bootResult: BootResult | undefined;
782
904
  let bootPromise: Promise<BootResult> | undefined;
@@ -952,7 +1074,7 @@ export function oke(options: OkeOptions): OkeApp {
952
1074
  vault: withRequiredEnv(overrides?.vault ?? options.vault),
953
1075
  gates: [...baseGates, ...authGates],
954
1076
  signals: overrides?.signals ?? effectiveSignals,
955
- clocks: overrides?.clocks ?? options.clocks,
1077
+ clocks: overrides?.clocks ?? effectiveClocks,
956
1078
  stores: overrides?.stores ?? effectiveStores,
957
1079
  channel: overrides?.channel ?? effectiveChannel,
958
1080
  ai: overrides?.ai ?? effectiveAi,
@@ -1008,7 +1130,7 @@ export function oke(options: OkeOptions): OkeApp {
1008
1130
 
1009
1131
  const baseSecrets = overrides?.secrets ?? effectiveSecrets;
1010
1132
  const baseSignals = overrides?.signals ?? effectiveSignals;
1011
- const baseClocks = overrides?.clocks ?? options.clocks ?? [];
1133
+ const baseClocks = overrides?.clocks ?? effectiveClocks;
1012
1134
  const baseChannel = overrides?.channel ?? effectiveChannel;
1013
1135
  const mergedCatalog = mergeTemplateCatalogs(baseChannel?.catalog, ...pluginChannelCatalogs);
1014
1136
 
@@ -1127,6 +1249,8 @@ export function oke(options: OkeOptions): OkeApp {
1127
1249
  readonly bypassGates?: boolean;
1128
1250
  /** Console Call API — cleartext store PII. Requires {@link trustedInvoke}. */
1129
1251
  readonly revealPii?: boolean;
1252
+ /** Forced RLS bag (Console / Call API). Operator omit = no stamp. */
1253
+ readonly rls?: import("../drivers/pg-rls.ts").RlsIdentity;
1130
1254
  /** Frozen origin identity for {@link Fx.principal} across `fx.call`. */
1131
1255
  readonly originPrincipal?: FxPrincipal;
1132
1256
  /** Explicit locale override for {@link Fx.t} / channel sends. */
@@ -1149,16 +1273,19 @@ export function oke(options: OkeOptions): OkeApp {
1149
1273
  defaultLocale,
1150
1274
  );
1151
1275
 
1152
- return runWithLocale({ locale: resolvedLocale, defaultLocale }, () =>
1153
- executeInLocale({
1154
- flowDef,
1155
- input,
1156
- trigger,
1157
- extras,
1158
- resolvedLocale,
1159
- defaultLocale,
1160
- }),
1161
- );
1276
+ return runWithLocale({ locale: resolvedLocale, defaultLocale }, () => {
1277
+ const run = () =>
1278
+ executeInLocale({
1279
+ flowDef,
1280
+ input,
1281
+ trigger,
1282
+ extras,
1283
+ resolvedLocale,
1284
+ defaultLocale,
1285
+ });
1286
+ const signal = extras?.request?.signal;
1287
+ return signal ? withAbortSignal(signal, run) : run();
1288
+ });
1162
1289
  }
1163
1290
 
1164
1291
  async function executeInLocale(args: {
@@ -1175,6 +1302,7 @@ export function oke(options: OkeOptions): OkeApp {
1175
1302
  readonly trustedInvoke?: boolean;
1176
1303
  readonly bypassGates?: boolean;
1177
1304
  readonly revealPii?: boolean;
1305
+ readonly rls?: import("../drivers/pg-rls.ts").RlsIdentity;
1178
1306
  readonly originPrincipal?: FxPrincipal;
1179
1307
  readonly locale?: string;
1180
1308
  readonly parentId?: string;
@@ -1325,6 +1453,9 @@ export function oke(options: OkeOptions): OkeApp {
1325
1453
  ...(principals ? { auth: principals.auth as FxAuth, operator: principals.operator } : {}),
1326
1454
  ...(extras?.originPrincipal ? { principal: extras.originPrincipal } : {}),
1327
1455
  ...(extras?.trustedInvoke === true && extras.revealPii === true ? { revealPii: true } : {}),
1456
+ rlsGateNames: gateNamesOf(trigger),
1457
+ rlsBypass: extras?.bypassGates === true || flowDef.plane === "operator",
1458
+ ...(extras?.rls ? { rls: extras.rls } : {}),
1328
1459
  ...(capability ? { capability } : {}),
1329
1460
  ...(booted
1330
1461
  ? {
@@ -1451,7 +1582,7 @@ export function oke(options: OkeOptions): OkeApp {
1451
1582
  durable: flowDef.durable,
1452
1583
  effects: putEffects,
1453
1584
  });
1454
- if (storeAfter && output !== undefined) {
1585
+ if (storeAfter && output !== undefined && !isJsonStreamResult(output)) {
1455
1586
  const ttlMs =
1456
1587
  typeof flowDef.cache === "string" ? cache.parseTtlMs(flowDef.cache) : undefined;
1457
1588
  storeRt.putTier1(
@@ -1499,60 +1630,79 @@ export function oke(options: OkeOptions): OkeApp {
1499
1630
 
1500
1631
  const endedAt = now();
1501
1632
  const durationMs = resolveDurationMs(endedAt - startedAt, performance.now() - startedHr);
1633
+ const streamOut = isJsonStreamResult(result.output) ? result.output : undefined;
1634
+
1635
+ const finalizeRun = async (): Promise<void> => {
1636
+ // Stream rows land in Traces only after close. Measure wall time then
1637
+ // so duration / waterfall cover the open stream, not just TTFB.
1638
+ const recordEndedAt = streamOut ? now() : endedAt;
1639
+ const recordDurationMs = streamOut
1640
+ ? resolveDurationMs(recordEndedAt - startedAt, performance.now() - startedHr)
1641
+ : durationMs;
1642
+ if (journalSession) {
1643
+ inflightRuns.delete(journalSession.runId);
1644
+ const sleeping = ctx.state.sleeping as
1645
+ | { readonly wakeAt: number; readonly label: string; readonly runId: string }
1646
+ | undefined;
1647
+ // Lease-capable stores make the shared row the wake schedule; the
1648
+ // in-process map is only for custom stores without the lease surface.
1649
+ if (sleeping && !hasJournalLease(activeJournal().store)) {
1650
+ sleepingRuns.set(sleeping.runId, {
1651
+ flow: flowDef,
1652
+ input: ctx.input,
1653
+ wakeAt: sleeping.wakeAt,
1654
+ });
1655
+ } else if (!sleeping && isTerminalFailure(result)) {
1656
+ const terminalErr = result.failure ?? result.ctx.error;
1657
+ await runCompensationPhase({
1658
+ flow: flowDef,
1659
+ input: ctx.input,
1660
+ session: journalSession,
1661
+ fx,
1662
+ error: terminalErr,
1663
+ });
1664
+ } else if (!sleeping) {
1665
+ await journalSession.commit("completed", {
1666
+ output: streamOut ? { streamed: true } : result.output,
1667
+ });
1668
+ }
1669
+ }
1502
1670
 
1503
- if (journalSession) {
1504
- inflightRuns.delete(journalSession.runId);
1505
- const sleeping = ctx.state.sleeping as
1506
- | { readonly wakeAt: number; readonly label: string; readonly runId: string }
1507
- | undefined;
1508
- // Lease-capable stores make the shared row the wake schedule; the
1509
- // in-process map is only for custom stores without the lease surface.
1510
- if (sleeping && !hasJournalLease(activeJournal().store)) {
1511
- sleepingRuns.set(sleeping.runId, {
1512
- flow: flowDef,
1513
- input: ctx.input,
1514
- wakeAt: sleeping.wakeAt,
1515
- });
1516
- } else if (!sleeping && isTerminalFailure(result)) {
1517
- const terminalErr = result.failure ?? result.ctx.error;
1518
- await runCompensationPhase({
1519
- flow: flowDef,
1520
- input: ctx.input,
1521
- session: journalSession,
1522
- fx,
1523
- error: terminalErr,
1524
- });
1525
- } else if (!sleeping) {
1526
- await journalSession.commit("completed", { output: result.output });
1671
+ const runsRuntime =
1672
+ booted?.runs ?? (isRunsRuntimeLike(options.runs) ? options.runs : undefined);
1673
+ if (runsRuntime) {
1674
+ const archiveCleartext = archiveFromInput(ctx.input, options.archiveInputFields);
1675
+ const replayInput = redactArchivedFields(ctx.input, options.archiveInputFields);
1676
+ const recordFailure =
1677
+ result.failure ??
1678
+ (isTerminalFailure(result) ? failureFromUnknown(result.ctx.error) : undefined);
1679
+ await runsRuntime.record(
1680
+ {
1681
+ flow: flowDef,
1682
+ trigger,
1683
+ fx,
1684
+ ledger,
1685
+ telemetry,
1686
+ startedAt,
1687
+ endedAt: recordEndedAt,
1688
+ durationMs: recordDurationMs,
1689
+ failure: recordFailure,
1690
+ id: runId,
1691
+ input: replayInput,
1692
+ ...(result.output !== undefined && !recordFailure
1693
+ ? { output: streamOut ? { streamed: true } : result.output }
1694
+ : {}),
1695
+ ...(parentId !== undefined ? { parentId } : {}),
1696
+ },
1697
+ archiveCleartext,
1698
+ );
1527
1699
  }
1528
- }
1700
+ };
1529
1701
 
1530
- const runsRuntime =
1531
- booted?.runs ?? (isRunsRuntimeLike(options.runs) ? options.runs : undefined);
1532
- if (runsRuntime) {
1533
- const archiveCleartext = archiveFromInput(ctx.input, options.archiveInputFields);
1534
- const replayInput = redactArchivedFields(ctx.input, options.archiveInputFields);
1535
- const recordFailure =
1536
- result.failure ??
1537
- (isTerminalFailure(result) ? failureFromUnknown(result.ctx.error) : undefined);
1538
- await runsRuntime.record(
1539
- {
1540
- flow: flowDef,
1541
- trigger,
1542
- fx,
1543
- ledger,
1544
- telemetry,
1545
- startedAt,
1546
- endedAt,
1547
- durationMs,
1548
- failure: recordFailure,
1549
- id: runId,
1550
- input: replayInput,
1551
- ...(result.output !== undefined && !recordFailure ? { output: result.output } : {}),
1552
- ...(parentId !== undefined ? { parentId } : {}),
1553
- },
1554
- archiveCleartext,
1555
- );
1702
+ if (streamOut && !isTerminalFailure(result)) {
1703
+ streamOut.finalize = finalizeRun;
1704
+ } else {
1705
+ await finalizeRun();
1556
1706
  }
1557
1707
 
1558
1708
  return {
@@ -44,7 +44,7 @@ describe("automatic tier-1 cache from effects", () => {
44
44
  const db = store.sql("app", { schema: { notes } });
45
45
  let lists = 0;
46
46
  const list = on(
47
- http.get("/notes").gate.public,
47
+ http.get("/notes").public(),
48
48
  flow("notes.list", {
49
49
  out: z.array(NoteOut),
50
50
  effects: { reads: ["sql:notes"] },
@@ -80,7 +80,7 @@ describe("automatic tier-1 cache from effects", () => {
80
80
  resetFlowSeq();
81
81
  const db = store.sql("app", { schema: { notes } });
82
82
  const list = on(
83
- http.get("/notes").gate.public,
83
+ http.get("/notes").public(),
84
84
  flow("notes.list", {
85
85
  out: z.array(NoteOut),
86
86
  effects: { reads: ["sql:notes"] },
@@ -115,7 +115,7 @@ describe("automatic tier-1 cache from effects", () => {
115
115
  const db = store.sql("app", { schema: { notes } });
116
116
  let lists = 0;
117
117
  const list = on(
118
- http.get("/notes").gate.public,
118
+ http.get("/notes").public(),
119
119
  flow("notes.list", {
120
120
  cache: false,
121
121
  effects: { reads: ["sql:notes"] },
@@ -146,7 +146,7 @@ describe("automatic tier-1 cache from effects", () => {
146
146
  const db = store.sql("app", { schema: { notes } });
147
147
  let lists = 0;
148
148
  const list = on(
149
- http.get("/notes").gate.public,
149
+ http.get("/notes").public(),
150
150
  flow("notes.list", {
151
151
  out: z.array(NoteOut),
152
152
  do: async (_input, fx) => {
@@ -191,7 +191,7 @@ describe("automatic tier-1 cache from effects", () => {
191
191
  const db = store.sql("app", { schema: { notes } });
192
192
  let lists = 0;
193
193
  const list = on(
194
- http.get("/notes").gate.public,
194
+ http.get("/notes").public(),
195
195
  flow("notes.list", {
196
196
  effects: { reads: ["sql:notes"] },
197
197
  do: () => {
@@ -201,7 +201,7 @@ describe("automatic tier-1 cache from effects", () => {
201
201
  }),
202
202
  );
203
203
  const create = on(
204
- http.post("/notes").gate.public,
204
+ http.post("/notes").public(),
205
205
  flow("notes.create", {
206
206
  in: z.object({ title: z.string() }),
207
207
  effects: { writes: ["sql:notes"] },
@@ -231,7 +231,7 @@ describe("automatic tier-1 cache from effects", () => {
231
231
  const db = store.sql("app", { schema: { notes } });
232
232
  let lists = 0;
233
233
  const list = on(
234
- http.get("/notes").gate.public,
234
+ http.get("/notes").public(),
235
235
  flow("notes.list", {
236
236
  out: z.array(NoteOut),
237
237
  do: async (_input, fx) => {
@@ -242,7 +242,7 @@ describe("automatic tier-1 cache from effects", () => {
242
242
  }),
243
243
  );
244
244
  const create = on(
245
- http.post("/notes").gate.public,
245
+ http.post("/notes").public(),
246
246
  flow("notes.create", {
247
247
  in: z.object({ title: z.string() }),
248
248
  do: async (input, fx) => {