okengine 0.18.4 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (512) hide show
  1. package/AGENTS.md +18 -10
  2. package/README.md +2 -2
  3. package/package.json +51 -50
  4. package/site/content/docs/ai/index.mdx +25 -6
  5. package/site/content/docs/ai/llms-txt.mdx +1 -1
  6. package/site/content/docs/ai/meta.json +1 -1
  7. package/site/content/docs/ai/skills.mdx +4 -1
  8. package/site/content/docs/ai/try-it.mdx +58 -0
  9. package/site/content/docs/client/auth.mdx +208 -0
  10. package/site/content/docs/client/calling.mdx +451 -0
  11. package/site/content/docs/client/index.mdx +209 -0
  12. package/site/content/docs/client/live.mdx +234 -0
  13. package/site/content/docs/client/meta.json +5 -0
  14. package/site/content/docs/client/react.mdx +249 -0
  15. package/site/content/docs/elements/ai/agents.mdx +232 -0
  16. package/site/content/docs/elements/ai/index.mdx +341 -0
  17. package/site/content/docs/elements/ai/mcp.mdx +275 -0
  18. package/site/content/docs/elements/ai/meta.json +5 -0
  19. package/site/content/docs/elements/ai/models.mdx +283 -0
  20. package/site/content/docs/elements/ai/prompts.mdx +256 -0
  21. package/site/content/docs/elements/channel/email.mdx +266 -0
  22. package/site/content/docs/elements/channel/index.mdx +344 -0
  23. package/site/content/docs/elements/channel/meta.json +5 -0
  24. package/site/content/docs/elements/channel/push.mdx +218 -0
  25. package/site/content/docs/elements/channel/receipts.mdx +206 -0
  26. package/site/content/docs/elements/channel/sms.mdx +264 -0
  27. package/site/content/docs/elements/channel/whatsapp.mdx +220 -0
  28. package/site/content/docs/elements/clock/index.mdx +300 -0
  29. package/site/content/docs/elements/clock/meta.json +5 -0
  30. package/site/content/docs/elements/clock/schedules.mdx +508 -0
  31. package/site/content/docs/elements/clock/sleep.mdx +445 -0
  32. package/site/content/docs/elements/flow/consumers.mdx +707 -0
  33. package/site/content/docs/elements/flow/http.mdx +1080 -0
  34. package/site/content/docs/elements/flow/index.mdx +618 -0
  35. package/site/content/docs/elements/flow/meta.json +5 -0
  36. package/site/content/docs/elements/flow/routing.mdx +559 -0
  37. package/site/content/docs/elements/flow/workflows.mdx +640 -0
  38. package/site/content/docs/elements/gate/auth.mdx +371 -0
  39. package/site/content/docs/elements/gate/authorization.mdx +298 -0
  40. package/site/content/docs/elements/gate/index.mdx +418 -0
  41. package/site/content/docs/elements/gate/meta.json +5 -0
  42. package/site/content/docs/elements/gate/rate-limits.mdx +365 -0
  43. package/site/content/docs/elements/gate/rls.mdx +303 -0
  44. package/site/content/docs/elements/gate/tenancy.mdx +372 -0
  45. package/site/content/docs/elements/index.mdx +52 -11
  46. package/site/content/docs/elements/signal/broadcast.mdx +517 -0
  47. package/site/content/docs/elements/signal/index.mdx +352 -0
  48. package/site/content/docs/elements/signal/live.mdx +590 -0
  49. package/site/content/docs/elements/signal/meta.json +5 -0
  50. package/site/content/docs/elements/signal/once.mdx +596 -0
  51. package/site/content/docs/elements/store/files.mdx +659 -0
  52. package/site/content/docs/elements/store/index.mdx +310 -0
  53. package/site/content/docs/elements/store/kv.mdx +629 -0
  54. package/site/content/docs/elements/store/meta.json +5 -0
  55. package/site/content/docs/elements/store/search.mdx +946 -0
  56. package/site/content/docs/elements/store/sql.mdx +937 -0
  57. package/site/content/docs/elements/vault/config.mdx +256 -0
  58. package/site/content/docs/elements/vault/index.mdx +356 -0
  59. package/site/content/docs/elements/vault/meta.json +5 -0
  60. package/site/content/docs/elements/vault/rotation.mdx +273 -0
  61. package/site/content/docs/elements/vault/secrets.mdx +285 -0
  62. package/site/content/docs/index.mdx +78 -30
  63. package/site/content/docs/meta.json +11 -8
  64. package/site/content/docs/plugins/cors.mdx +2 -1
  65. package/site/content/docs/plugins/csrf.mdx +4 -1
  66. package/site/content/docs/plugins/headers.mdx +2 -1
  67. package/site/content/docs/plugins/ip-allowlist.mdx +2 -1
  68. package/site/content/docs/plugins/magic-link.mdx +6 -0
  69. package/site/content/docs/plugins/maintenance-mode.mdx +2 -1
  70. package/site/content/docs/plugins/oauth.mdx +1 -1
  71. package/site/content/docs/plugins/otp.mdx +12 -1
  72. package/site/content/docs/plugins/passkey.mdx +39 -15
  73. package/site/content/docs/plugins/two-factor.mdx +91 -34
  74. package/site/content/docs/plugins/username.mdx +1 -1
  75. package/site/content/docs/recipes/caddy.mdx +3 -3
  76. package/site/content/docs/recipes/index.mdx +18 -28
  77. package/site/content/docs/recipes/mailpit.mdx +1 -1
  78. package/site/content/docs/recipes/meilisearch.mdx +3 -3
  79. package/site/content/docs/recipes/meta.json +1 -4
  80. package/site/content/docs/recipes/nginx.mdx +2 -2
  81. package/site/content/docs/recipes/openrouter.mdx +283 -0
  82. package/site/content/docs/recipes/pgdog.mdx +3 -3
  83. package/site/content/docs/recipes/postgres.mdx +1 -2
  84. package/site/content/docs/recipes/rustfs.mdx +2 -2
  85. package/site/content/docs/recipes/traefik.mdx +3 -3
  86. package/site/content/docs/reference/cli.mdx +231 -0
  87. package/site/content/docs/reference/configuration.mdx +30 -10
  88. package/site/content/docs/reference/environment-variables.mdx +93 -20
  89. package/site/content/docs/reference/errors.mdx +132 -29
  90. package/site/content/docs/reference/fx.mdx +137 -73
  91. package/site/content/docs/reference/index.mdx +13 -21
  92. package/site/content/docs/reference/meta.json +4 -5
  93. package/site/content/docs/reference/okid.mdx +42 -17
  94. package/site/content/docs/reference/plugins.mdx +4 -3
  95. package/site/content/docs/reference/security.mdx +197 -0
  96. package/site/content/docs/understand/meta.json +5 -0
  97. package/site/content/docs/understand/the-anatomy.mdx +132 -0
  98. package/site/content/docs/understand/the-model.mdx +32 -0
  99. package/site/content/docs/understand/the-problem.mdx +74 -0
  100. package/site/content/docs/understand/the-vocabulary.mdx +26 -0
  101. package/src/auth/api-keys.ts +2 -1
  102. package/src/auth/bindings.ts +64 -16
  103. package/src/auth/gate-auth.test.ts +6 -1
  104. package/src/auth/identity.ts +152 -5
  105. package/src/auth/index.ts +29 -0
  106. package/src/auth/invites.ts +2 -1
  107. package/src/auth/method-context.ts +41 -0
  108. package/src/auth/oauth-as/crypto.ts +2 -1
  109. package/src/auth/oauth-as/stores.ts +2 -1
  110. package/src/auth/operator.ts +2 -1
  111. package/src/auth/sessions-jwt.test.ts +77 -0
  112. package/src/auth/sessions.ts +20 -4
  113. package/src/auth/tenants.ts +3 -2
  114. package/src/auth/two-factor-challenge.test.ts +61 -0
  115. package/src/auth/two-factor-challenge.ts +284 -0
  116. package/src/auth/verification.ts +5 -0
  117. package/src/bench/REPORT.md +49 -0
  118. package/src/bench/g03-signal-once.bench.ts +1 -1
  119. package/src/bench/g10-observability-contention.bench.ts +1 -1
  120. package/src/bench/g17-hybrid-search.bench.ts +572 -0
  121. package/src/bench/load-app.ts +2 -10
  122. package/src/cli/ai-setup/ai-setup.test.ts +331 -42
  123. package/src/cli/ai-setup/apply.ts +294 -52
  124. package/src/cli/ai-setup/catalog.ts +238 -1342
  125. package/src/cli/ai-setup/index.ts +14 -99
  126. package/src/cli/ai-setup/prompts.ts +60 -443
  127. package/src/cli/ask-seed.test.ts +96 -0
  128. package/src/cli/ask-seed.ts +82 -0
  129. package/src/cli/ask-vault-gaps.test.ts +84 -0
  130. package/src/cli/ask-vault-gaps.ts +146 -0
  131. package/src/cli/build.ts +2 -2
  132. package/src/cli/client-add.test.ts +26 -1
  133. package/src/cli/client-add.ts +106 -27
  134. package/src/cli/competitor-mention-removal.test.ts +1 -1
  135. package/src/cli/db-seed.ts +2 -0
  136. package/src/cli/db.ts +150 -11
  137. package/src/cli/dev.ts +119 -211
  138. package/src/cli/docker-clean.ts +2 -2
  139. package/src/cli/docker-cli.test.ts +1 -1
  140. package/src/cli/doctor-diff.ts +4 -2
  141. package/src/cli/doctor-pii.test.ts +1 -1
  142. package/src/cli/doctor.ts +14 -1
  143. package/src/cli/hero-meta.test.ts +4 -2
  144. package/src/cli/load-config.images.test.ts +8 -10
  145. package/src/cli/load-config.ts +1 -1
  146. package/src/cli/registry.ts +22 -10
  147. package/src/cli/replay.ts +3 -1
  148. package/src/cli/start.ts +1 -1
  149. package/src/cli/tui/keys.ts +2 -3
  150. package/src/client/auth/cookies.ts +74 -0
  151. package/src/client/auth/create-auth-client.ts +636 -0
  152. package/src/client/auth/denials.ts +99 -0
  153. package/src/client/auth/session.ts +283 -0
  154. package/src/client/auth.test.ts +251 -0
  155. package/src/client/auth.ts +39 -114
  156. package/src/client/create-with-session.ts +245 -0
  157. package/src/client/create.ts +51 -5
  158. package/src/client/index.ts +11 -1
  159. package/src/client/live.ts +11 -79
  160. package/src/client/notes-contract.test.ts +5 -10
  161. package/src/client/sse.ts +137 -0
  162. package/src/client/stream.ts +147 -0
  163. package/src/client/transport.test.ts +32 -0
  164. package/src/client/transport.ts +123 -26
  165. package/src/client/types.ts +118 -14
  166. package/src/client-react/index.ts +185 -24
  167. package/src/client-react/use-live-query.ts +13 -3
  168. package/src/compiler/aot.test.ts +7 -4
  169. package/src/compiler/effects-embed.test.ts +56 -0
  170. package/src/compiler/effects-fetch.test.ts +43 -0
  171. package/src/compiler/effects-infer.ts +58 -2
  172. package/src/compiler/extract.test.ts +258 -44
  173. package/src/compiler/extract.ts +566 -48
  174. package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -4
  175. package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +2 -8
  176. package/src/compiler/fixtures/skyport.expected.json +4 -4
  177. package/src/compiler/fixtures/triggers/five-triggers.ts +14 -10
  178. package/src/compiler/response.ts +2 -2
  179. package/src/compiler/search-writer-isolation.test.ts +40 -0
  180. package/src/config/index.ts +11 -0
  181. package/src/console/server/app.ts +17 -23
  182. package/src/console/server/bind.ts +4 -0
  183. package/src/console/server/console.test.ts +2 -2
  184. package/src/console/server/flows-invoke.test.ts +50 -34
  185. package/src/console/server/flows.ts +436 -255
  186. package/src/console/server/runs-ingest.test.ts +6 -3
  187. package/src/console/server/serve.ts +1 -1
  188. package/src/console/server/signals.test.ts +1 -5
  189. package/src/console/server/signals.ts +8 -6
  190. package/src/console/server/state.ts +6 -1
  191. package/src/console/server/store.ts +1 -1
  192. package/src/console/ui-next/dist/assets/FileExportIcon-Ck-5od4R.js +1 -0
  193. package/src/console/ui-next/dist/assets/MoreHorizontalCircle01Icon-gMNGsE37.js +1 -0
  194. package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +1 -0
  195. package/src/console/ui-next/dist/assets/UnavailableIcon-D9cvHVPr.js +1 -0
  196. package/src/console/ui-next/dist/assets/UserIcon-DaE2PB5_.js +1 -0
  197. package/src/console/ui-next/dist/assets/access-page-DFeymU07.js +4 -0
  198. package/src/console/ui-next/dist/assets/agent-disclosure-U1rdfblp.js +1 -0
  199. package/src/console/ui-next/dist/assets/cache-glyph-BeFJeqBG.js +1 -0
  200. package/src/console/ui-next/dist/assets/call-pii-button-CVAONPii.js +1 -0
  201. package/src/console/ui-next/dist/assets/collapsible-D2A6NJ-3.js +1 -0
  202. package/src/console/ui-next/dist/assets/copy-inline-button-CAYD18cr.js +1 -0
  203. package/src/console/ui-next/dist/assets/dagre.esm-B1_XeuLP.js +1 -0
  204. package/src/console/ui-next/dist/assets/detail-header-DVWNjWjg.js +1 -0
  205. package/src/console/ui-next/dist/assets/dropdown-menu-4h2LOVXM.js +1 -0
  206. package/src/console/ui-next/dist/assets/duration-tone-Cgk_h5ja.js +9 -0
  207. package/src/console/ui-next/dist/assets/element-icons-BI8cJgdh.js +1 -0
  208. package/src/console/ui-next/dist/assets/explorer-empty-CJs5A-wm.js +1 -0
  209. package/src/console/ui-next/dist/assets/flows-page-Dss7941e.js +1 -0
  210. package/src/console/ui-next/dist/assets/highlighted-json-MYZQtRnw.js +154 -0
  211. package/src/console/ui-next/dist/assets/http-method-Jrh39p7A.js +1 -0
  212. package/src/console/ui-next/dist/assets/index-D0zS5rKO.css +2 -0
  213. package/src/console/ui-next/dist/assets/index-DXP2dBIF.js +63 -0
  214. package/src/console/ui-next/dist/assets/observability-page-HvolXxTI.js +4 -0
  215. package/src/console/ui-next/dist/assets/react-dom-Ddte4I-Q.js +9 -0
  216. package/src/console/ui-next/dist/assets/replica-lag-CSh2dzrb.js +18 -0
  217. package/src/console/ui-next/dist/assets/request-meta-BatF8KrK.js +1 -0
  218. package/src/console/ui-next/dist/assets/shortcut-keys-3ILd8oGn.js +1 -0
  219. package/src/console/ui-next/dist/assets/{sql-BskegiFM.js → sql-BsFa4tDR.js} +1 -1
  220. package/src/console/ui-next/dist/assets/store-page-eiKiHnNe.js +41 -0
  221. package/src/console/ui-next/dist/assets/trace-detail-sheet-CZkMeKS-.js +2 -0
  222. package/src/console/ui-next/dist/assets/tree-expand-toggle-CW8y5A2h.js +55 -0
  223. package/src/console/ui-next/dist/assets/units-page-B_RWJrEO.js +1 -0
  224. package/src/console/ui-next/dist/assets/{use-vault-list-uk4WVboC.js → use-vault-list-CT4-gajj.js} +1 -1
  225. package/src/console/ui-next/dist/assets/vault-page-CWrg-A68.js +2 -0
  226. package/src/console/ui-next/dist/assets/xyflow-CSyC6ryz.css +1 -0
  227. package/src/console/ui-next/dist/assets/xyflow-yApv7D4e.js +7 -0
  228. package/src/console/ui-next/dist/index.html +6 -13
  229. package/src/console/ui-next/seed-invoke-host.ts +21 -18
  230. package/src/console/ui-next/src/client.ts +7 -2
  231. package/src/console/ui-next/src/features/flows/graph/element-map.ts +2 -0
  232. package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +12 -2
  233. package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +4 -0
  234. package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +8 -0
  235. package/src/console/ui-next/src/features/flows/traces/waterfall-bars.ts +4 -0
  236. package/src/console/ui-next/src/features/flows/traces/waterfall-tooltip.ts +9 -3
  237. package/src/console/ui-next/src/features/store/detail/reveal-cell.tsx +7 -11
  238. package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +2 -2
  239. package/src/console/ui-next/src/features/store/lib/fields-from-table.ts +2 -0
  240. package/src/console/ui-next/src/features/store/lib/grid-model.test.ts +25 -1
  241. package/src/console/ui-next/src/features/store/lib/grid-model.ts +36 -1
  242. package/src/console/ui-next/src/features/store/query/query-results.tsx +3 -3
  243. package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +2 -0
  244. package/src/console/ui-next/src/features/units/lib/call-read-safe.ts +3 -1
  245. package/src/console/ui-next/src/features/units/lib/fields-from-schema.ts +6 -0
  246. package/src/docker/ai-model-status.test.ts +1 -12
  247. package/src/docker/ai-model-status.ts +10 -38
  248. package/src/docker/compose-up.test.ts +100 -0
  249. package/src/docker/compose-up.ts +292 -0
  250. package/src/docker/compose.ts +4 -14
  251. package/src/docker/derive.ts +9 -34
  252. package/src/docker/docker.test.ts +16 -261
  253. package/src/docker/images-config.test.ts +13 -25
  254. package/src/docker/index.ts +1 -24
  255. package/src/docker/recipes/index.ts +0 -23
  256. package/src/docker/recipes/pgdog.ts +6 -4
  257. package/src/docker/stack-id.test.ts +2 -2
  258. package/src/docker/stack-id.ts +0 -1
  259. package/src/docker/types.ts +2 -2
  260. package/src/drivers/ai-anthropic.ts +10 -0
  261. package/src/drivers/ai-openai-compatible.ts +34 -7
  262. package/src/drivers/ai-providers.test.ts +0 -107
  263. package/src/drivers/ai-stream.test.ts +0 -34
  264. package/src/drivers/ai-types.ts +17 -8
  265. package/src/drivers/channel-fcm.ts +6 -1
  266. package/src/drivers/channel-msegat.ts +6 -1
  267. package/src/drivers/channel-resend.ts +5 -1
  268. package/src/drivers/channel-smtp.ts +5 -1
  269. package/src/drivers/channel-sndr.ts +10 -1
  270. package/src/drivers/channel-taqnyat-mail.ts +5 -1
  271. package/src/drivers/channel-taqnyat-whatsapp.ts +6 -1
  272. package/src/drivers/channel-taqnyat.ts +6 -1
  273. package/src/drivers/channel-types.ts +10 -0
  274. package/src/drivers/channel-unifonic.ts +6 -1
  275. package/src/drivers/channel-wa-cloud.ts +6 -1
  276. package/src/drivers/channel-webpush.ts +6 -1
  277. package/src/drivers/external.ts +33 -0
  278. package/src/drivers/index.ts +0 -10
  279. package/src/drivers/meilisearch.ts +6 -0
  280. package/src/drivers/oauth-types.ts +4 -0
  281. package/src/drivers/postgres.test.ts +74 -3
  282. package/src/drivers/postgres.ts +175 -6
  283. package/src/drivers/signal-types.ts +5 -5
  284. package/src/drivers/types.ts +7 -0
  285. package/src/drivers/vault-types.ts +5 -0
  286. package/src/elements/ai/declare.ts +17 -4
  287. package/src/elements/ai/eval.ts +1 -1
  288. package/src/elements/ai/mcp-http.ts +1 -1
  289. package/src/elements/ai/pii.ts +1 -1
  290. package/src/elements/ai/providers.test.ts +289 -0
  291. package/src/elements/ai/providers.ts +169 -0
  292. package/src/elements/ai/runtime.ts +68 -5
  293. package/src/elements/ai/schema.ts +2 -2
  294. package/src/elements/ai.test.ts +7 -7
  295. package/src/elements/ai.ts +17 -1
  296. package/src/elements/channel/runtime.ts +105 -12
  297. package/src/elements/clock/cron-fields.test.ts +144 -0
  298. package/src/elements/clock/cron-fields.ts +185 -0
  299. package/src/elements/clock/declare.ts +247 -3
  300. package/src/elements/clock.ts +21 -1
  301. package/src/elements/index.ts +15 -0
  302. package/src/elements/signal/chaos-child.ts +1 -2
  303. package/src/elements/signal/declare.ts +65 -37
  304. package/src/elements/signal/delivery-modes.test.ts +11 -31
  305. package/src/elements/signal/dry-run-replay.test.ts +1 -7
  306. package/src/elements/signal/dry-run-write-isolation.test.ts +1 -7
  307. package/src/elements/signal/key-ordering.test.ts +6 -26
  308. package/src/elements/signal/lease-reclaim.test.ts +2 -6
  309. package/src/elements/signal/optional-emit.test.ts +6 -9
  310. package/src/elements/signal/order-lifecycle.test.ts +4 -17
  311. package/src/elements/signal/orphan-messages.test.ts +4 -15
  312. package/src/elements/signal/reconcile.test.ts +2 -2
  313. package/src/elements/signal/runtime.ts +1 -1
  314. package/src/elements/signal/schema-emit.test.ts +4 -8
  315. package/src/elements/signal.test.ts +24 -49
  316. package/src/elements/signal.ts +9 -2
  317. package/src/elements/store/domain-ddl.test.ts +1 -1
  318. package/src/elements/store/live-http.test.ts +9 -4
  319. package/src/elements/store/prepare-row.test.ts +123 -0
  320. package/src/elements/store/resource.ts +43 -12
  321. package/src/elements/store/schema-decl.ts +117 -0
  322. package/src/elements/store/search-backfill.ts +205 -0
  323. package/src/elements/store/search-bind.ts +66 -0
  324. package/src/elements/store/search-bm25.ts +78 -0
  325. package/src/elements/store/search-ddl.ts +156 -0
  326. package/src/elements/store/search-embed-flow.ts +141 -0
  327. package/src/elements/store/search-errors.ts +34 -0
  328. package/src/elements/store/search-fusion.ts +112 -0
  329. package/src/elements/store/search-lsh.ts +179 -0
  330. package/src/elements/store/search-runtime.ts +300 -0
  331. package/src/elements/store/search.test.ts +144 -0
  332. package/src/elements/store/sql-session.test.ts +1 -0
  333. package/src/elements/store/sql-session.ts +83 -3
  334. package/src/elements/store/table.ts +23 -2
  335. package/src/elements/store/upsert-app.test.ts +1 -3
  336. package/src/elements/store.ts +50 -0
  337. package/src/full.ts +4 -2
  338. package/src/http.ts +4 -1
  339. package/src/i18n/catalogs/ar.ts +14 -6
  340. package/src/i18n/catalogs/en.ts +14 -6
  341. package/src/index.ts +6 -1
  342. package/src/kernel/adopt-barrel-fresh.test.ts +7 -7
  343. package/src/kernel/adopt-routes.ts +9 -1
  344. package/src/kernel/app-auth.ts +5 -0
  345. package/src/kernel/app.ts +102 -9
  346. package/src/kernel/auto-cache.test.ts +6 -12
  347. package/src/kernel/auto-registry.test.ts +3 -3
  348. package/src/kernel/boot-bind/ai.test.ts +22 -19
  349. package/src/kernel/boot-bind/ai.ts +5 -43
  350. package/src/kernel/boot-bind/clock.ts +23 -5
  351. package/src/kernel/boot-bind/honor-config.test.ts +4 -4
  352. package/src/kernel/boot.test.ts +11 -6
  353. package/src/kernel/boot.ts +66 -16
  354. package/src/kernel/boundary-contract.ts +93 -0
  355. package/src/kernel/budget.test.ts +1 -1
  356. package/src/kernel/call.ts +89 -0
  357. package/src/kernel/capability.ts +6 -0
  358. package/src/kernel/client-descriptor.ts +123 -0
  359. package/src/kernel/clock-timezone.test.ts +80 -0
  360. package/src/kernel/correlation.test.ts +1 -1
  361. package/src/kernel/dry-run.ts +11 -8
  362. package/src/kernel/effects-stamping.test.ts +42 -9
  363. package/src/kernel/effects.test.ts +4 -2
  364. package/src/kernel/effects.ts +51 -9
  365. package/src/kernel/errors-channel.ts +17 -0
  366. package/src/kernel/errors-live-resume.ts +3 -2
  367. package/src/kernel/errors-tenant.ts +7 -4
  368. package/src/kernel/errors.registry-helpers.ts +96 -0
  369. package/src/kernel/errors.registry.test.ts +139 -25
  370. package/src/kernel/errors.ts +102 -23
  371. package/src/kernel/external-effects.test.ts +196 -0
  372. package/src/kernel/flow.test.ts +13 -4
  373. package/src/kernel/flow.ts +69 -71
  374. package/src/kernel/fx-ask-telemetry.test.ts +2 -2
  375. package/src/kernel/fx-dead-letters.test.ts +3 -3
  376. package/src/kernel/fx-fetch.ts +55 -0
  377. package/src/kernel/fx-live-stream.ts +2 -2
  378. package/src/kernel/fx-live.test.ts +8 -8
  379. package/src/kernel/fx.test.ts +17 -11
  380. package/src/kernel/fx.ts +180 -57
  381. package/src/kernel/horizontal-child.ts +1 -1
  382. package/src/kernel/http-query.test.ts +3 -6
  383. package/src/kernel/index.ts +13 -3
  384. package/src/kernel/instance-id.ts +1 -1
  385. package/src/kernel/instances.test.ts +40 -0
  386. package/src/kernel/instances.ts +47 -9
  387. package/src/kernel/live-http.test.ts +6 -7
  388. package/src/kernel/live-http.ts +6 -2
  389. package/src/kernel/live-resume.test.ts +1 -1
  390. package/src/kernel/mcp-tool.test.ts +3 -3
  391. package/src/kernel/on.ts +98 -4
  392. package/src/kernel/pipeline.test.ts +12 -15
  393. package/src/kernel/plugin-elements.test.ts +1 -1
  394. package/src/kernel/stamp-http.test.ts +3 -3
  395. package/src/kernel/triggers.ts +210 -95
  396. package/src/kernel-entry.ts +0 -1
  397. package/src/manifest/diff.ts +11 -1
  398. package/src/manifest/fixtures/skyport.excerpt.json +1 -1
  399. package/src/manifest/types.ts +46 -2
  400. package/src/mcp/docs-index.ts +3 -3
  401. package/src/mcp/docs-mcp.test.ts +2 -2
  402. package/src/mcp/docs-tools.ts +1 -1
  403. package/src/okid.test.ts +56 -0
  404. package/src/okid.ts +55 -11
  405. package/src/plugins/anonymous.ts +8 -4
  406. package/src/plugins/auth/shared.ts +27 -3
  407. package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
  408. package/src/plugins/auth-methods.security.test.ts +561 -23
  409. package/src/plugins/config-source.ts +1 -1
  410. package/src/plugins/csrf.test.ts +65 -0
  411. package/src/plugins/index.ts +2 -0
  412. package/src/plugins/magic-link.ts +36 -16
  413. package/src/plugins/oauth/shared.ts +3 -1
  414. package/src/plugins/oauth.ts +22 -14
  415. package/src/plugins/otp.ts +37 -21
  416. package/src/plugins/passkey-webauthn.ts +9 -6
  417. package/src/plugins/passkey.ts +98 -26
  418. package/src/plugins/pre-account-hijack.test.ts +223 -0
  419. package/src/plugins/two-factor.ts +466 -37
  420. package/src/plugins/username.ts +19 -7
  421. package/src/release/build-lib.ts +1 -0
  422. package/src/release/limits.ts +2 -2
  423. package/src/release/measure.ts +1 -1
  424. package/src/runs/collect.test.ts +0 -2
  425. package/src/runtime/json-code-block.test.ts +250 -20
  426. package/src/runtime/json-code-block.ts +1261 -41
  427. package/src/term.test.ts +1 -1
  428. package/src/test/create-test-app.test.ts +12 -12
  429. package/src/test/live-signals.test.ts +6 -6
  430. package/src/test/provisions.integration.test.ts +10 -14
  431. package/src/test/reset-element-registries.ts +1 -1
  432. package/src/test/tenant-isolation.test.ts +12 -6
  433. package/site/content/docs/deployment/docker-swarm.mdx +0 -164
  434. package/site/content/docs/deployment/docker.mdx +0 -227
  435. package/site/content/docs/deployment/index.mdx +0 -83
  436. package/site/content/docs/deployment/kubernetes.mdx +0 -176
  437. package/site/content/docs/deployment/meta.json +0 -5
  438. package/site/content/docs/deployment/reverse-proxy.mdx +0 -234
  439. package/site/content/docs/elements/ai.mdx +0 -385
  440. package/site/content/docs/elements/channel.mdx +0 -346
  441. package/site/content/docs/elements/clock.mdx +0 -244
  442. package/site/content/docs/elements/flow.mdx +0 -420
  443. package/site/content/docs/elements/gate.mdx +0 -436
  444. package/site/content/docs/elements/signal.mdx +0 -380
  445. package/site/content/docs/elements/store.mdx +0 -1099
  446. package/site/content/docs/elements/vault.mdx +0 -405
  447. package/site/content/docs/get-started/basic-usage.mdx +0 -173
  448. package/site/content/docs/get-started/index.mdx +0 -43
  449. package/site/content/docs/get-started/installation.mdx +0 -220
  450. package/site/content/docs/get-started/introduction.mdx +0 -132
  451. package/site/content/docs/get-started/meta.json +0 -13
  452. package/site/content/docs/get-started/project-structure.mdx +0 -925
  453. package/site/content/docs/get-started/testing.mdx +0 -328
  454. package/site/content/docs/get-started/why.mdx +0 -162
  455. package/site/content/docs/recipes/llama-cpp.mdx +0 -151
  456. package/site/content/docs/recipes/ollama.mdx +0 -142
  457. package/site/content/docs/recipes/sglang.mdx +0 -105
  458. package/site/content/docs/recipes/vllm.mdx +0 -106
  459. package/site/content/docs/reference/cli.md +0 -232
  460. package/site/content/docs/reference/client.mdx +0 -469
  461. package/site/content/docs/reference/security.md +0 -74
  462. package/src/cli/ai-setup/detect-ollama.ts +0 -213
  463. package/src/cli/ai-setup/recommend.test.ts +0 -225
  464. package/src/cli/ai-setup/recommend.ts +0 -225
  465. package/src/cli/dev-controls.test.ts +0 -122
  466. package/src/cli/dev-controls.ts +0 -164
  467. package/src/cli/tui/DevLive.tsx +0 -126
  468. package/src/console/ui-next/dist/assets/access-page-De7Lc2JC.js +0 -4
  469. package/src/console/ui-next/dist/assets/agent-disclosure-BP0Y0Sux.js +0 -1
  470. package/src/console/ui-next/dist/assets/cache-glyph-B5X-NM0-.js +0 -1
  471. package/src/console/ui-next/dist/assets/call-pii-button-ChAUiLo9.js +0 -1
  472. package/src/console/ui-next/dist/assets/collapsible-DGnOM2ph.js +0 -1
  473. package/src/console/ui-next/dist/assets/copy-inline-button-DBHhgHKP.js +0 -1
  474. package/src/console/ui-next/dist/assets/dagre.esm-ZwcdTuZZ.js +0 -1
  475. package/src/console/ui-next/dist/assets/detail-header-DhHM1iaZ.js +0 -1
  476. package/src/console/ui-next/dist/assets/dropdown-menu-_NjTEo5_.js +0 -1
  477. package/src/console/ui-next/dist/assets/duration-tone-sC3lGABz.js +0 -9
  478. package/src/console/ui-next/dist/assets/element-icons-BVXtRyd3.js +0 -1
  479. package/src/console/ui-next/dist/assets/explorer-empty-2uIhBu0_.js +0 -1
  480. package/src/console/ui-next/dist/assets/flows-page-RGy7VEA_.js +0 -1
  481. package/src/console/ui-next/dist/assets/highlighted-json-Awq7gYdu.js +0 -154
  482. package/src/console/ui-next/dist/assets/http-method-_UHM2ODJ.js +0 -1
  483. package/src/console/ui-next/dist/assets/index-Ck88Jmv8.css +0 -2
  484. package/src/console/ui-next/dist/assets/index-_rgpdVzo.js +0 -66
  485. package/src/console/ui-next/dist/assets/link-BX6Vqztd.js +0 -1
  486. package/src/console/ui-next/dist/assets/observability-page-Ds6pcnh-.js +0 -4
  487. package/src/console/ui-next/dist/assets/preload-helper-oH4irX4C.js +0 -1
  488. package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +0 -1
  489. package/src/console/ui-next/dist/assets/react-dom-Bph1y7z7.js +0 -9
  490. package/src/console/ui-next/dist/assets/replica-lag-DKRrbvdo.js +0 -18
  491. package/src/console/ui-next/dist/assets/request-meta-DV0ywz7t.js +0 -1
  492. package/src/console/ui-next/dist/assets/shortcut-JQIZlWfm.js +0 -1
  493. package/src/console/ui-next/dist/assets/shortcut-keys-DKxNTe_m.js +0 -1
  494. package/src/console/ui-next/dist/assets/skeleton-D-czQJT6.js +0 -1
  495. package/src/console/ui-next/dist/assets/store-page-02xOiqIK.js +0 -41
  496. package/src/console/ui-next/dist/assets/trace-detail-sheet-B09O8rA6.js +0 -2
  497. package/src/console/ui-next/dist/assets/tree-expand-toggle-BtyhmWb4.js +0 -55
  498. package/src/console/ui-next/dist/assets/units-page-4rHOePuE.js +0 -1
  499. package/src/console/ui-next/dist/assets/useMutation-B8EO02Ej.js +0 -1
  500. package/src/console/ui-next/dist/assets/useRender-BE2A9BWC.js +0 -1
  501. package/src/console/ui-next/dist/assets/vault-page-DISPgxLM.js +0 -2
  502. package/src/console/ui-next/dist/assets/xyflow-D7n4g6go.js +0 -7
  503. package/src/console/ui-next/dist/assets/xyflow-DZ0Ws1xk.css +0 -1
  504. package/src/docker/ollama-pull.ts +0 -232
  505. package/src/docker/recipes/llama-cpp.ts +0 -298
  506. package/src/docker/recipes/ollama.ts +0 -44
  507. package/src/docker/recipes/sglang.ts +0 -55
  508. package/src/docker/recipes/vllm.ts +0 -44
  509. package/src/drivers/ai-ollama-tools.integration.test.ts +0 -109
  510. package/src/drivers/ai-ollama.integration.test.ts +0 -184
  511. package/src/drivers/ai-ollama.ts +0 -389
  512. package/src/drivers/ollama.ts +0 -14
@@ -0,0 +1,89 @@
1
+ /**
2
+ * `call(name, opts)` — call-only Flow sugar with invoke contract on the bag.
3
+ *
4
+ * Same species as `flow` + internal trigger; contracts live here (not on `flow()`).
5
+ */
6
+
7
+ import {
8
+ stampBoundaryContract,
9
+ type BoundaryContract,
10
+ type InferBoundaryErrors,
11
+ type InferBoundaryIn,
12
+ type InferBoundaryOut,
13
+ } from "./boundary-contract.ts";
14
+ import {
15
+ flow,
16
+ type FlowDef,
17
+ type FlowErrorMap,
18
+ type FlowHandler,
19
+ type FlowOptions,
20
+ } from "./flow.ts";
21
+ import { internal } from "./triggers.ts";
22
+
23
+ /** Options for {@link call} — boundary contract + flow runtime + `do`. */
24
+ export type CallOptions<
25
+ I = unknown,
26
+ O = unknown,
27
+ E extends FlowErrorMap = FlowErrorMap,
28
+ > = BoundaryContract<unknown, unknown, E> &
29
+ Omit<FlowOptions<I, O>, "do"> & {
30
+ readonly do: FlowHandler<I, O>;
31
+ };
32
+
33
+ type InferCallIn<Opts> = Opts extends { readonly in: unknown }
34
+ ? InferBoundaryIn<Opts>
35
+ : Opts extends { readonly do: FlowHandler<infer I, infer _O> }
36
+ ? I
37
+ : unknown;
38
+
39
+ type InferCallOut<Opts> = Opts extends { readonly out: unknown }
40
+ ? InferBoundaryOut<Opts>
41
+ : Opts extends { readonly do: FlowHandler<infer _I, infer O> }
42
+ ? O
43
+ : unknown;
44
+
45
+ /**
46
+ * Define a call-only Flow with its invoke contract on the same bag.
47
+ *
48
+ * @param name - Stable Manifest / `fx.call` name
49
+ * @param options - Contract + runtime + `do`
50
+ */
51
+ export function call<Opts extends CallOptions<any, any, any>>(
52
+ name: string,
53
+ options: Opts & { readonly name?: never },
54
+ ): FlowDef<InferCallIn<Opts>, InferCallOut<Opts>, InferBoundaryErrors<Opts>> {
55
+ if (typeof name !== "string" || name.trim().length === 0) {
56
+ throw new TypeError("call(name, opts): name is required");
57
+ }
58
+ const {
59
+ in: inSchema,
60
+ out: outSchema,
61
+ errors,
62
+ breaking,
63
+ do: handler,
64
+ ...runtime
65
+ } = options as CallOptions<any, any, any>;
66
+
67
+ const def = flow(name, {
68
+ ...runtime,
69
+ do: handler as FlowHandler,
70
+ }) as FlowDef<InferCallIn<Opts>, InferCallOut<Opts>, InferBoundaryErrors<Opts>>;
71
+
72
+ const stamped = stampBoundaryContract({
73
+ in: inSchema,
74
+ out: outSchema,
75
+ errors,
76
+ breaking,
77
+ });
78
+ def.in = stamped.in;
79
+ def.out = stamped.out;
80
+ def.errors = stamped.errors as InferBoundaryErrors<Opts> | undefined;
81
+ def.breaking = stamped.breaking;
82
+
83
+ // Mark as internal / call-only exposure (addressable trigger kind).
84
+ const triggers = def.triggers as import("./triggers.ts").Trigger[];
85
+ triggers.push(internal);
86
+ (def as { $trigger: typeof internal }).$trigger = internal;
87
+
88
+ return def;
89
+ }
@@ -17,8 +17,10 @@ const UNDECLARED_KEY: Readonly<Record<EffectKind, keyof typeof OKE_ERRORS>> = {
17
17
  emit: "UNDECLARED_EMIT",
18
18
  send: "UNDECLARED_SEND",
19
19
  ask: "UNDECLARED_ASK",
20
+ embed: "UNDECLARED_EMBED",
20
21
  secret: "UNDECLARED_SECRET",
21
22
  call: "UNDECLARED_CALL",
23
+ fetch: "UNDECLARED_FETCH",
22
24
  };
23
25
 
24
26
  /** Maps effect kind → the corresponding `Effects` field. */
@@ -28,8 +30,10 @@ const EFFECTS_FIELD: Readonly<Record<EffectKind, keyof Effects>> = {
28
30
  emit: "emits",
29
31
  send: "sends",
30
32
  ask: "asks",
33
+ embed: "embeds",
31
34
  secret: "secrets",
32
35
  call: "calls",
36
+ fetch: "fetches",
33
37
  };
34
38
 
35
39
  /**
@@ -83,8 +87,10 @@ export function createCapabilityToken(flow: string, declared?: Effects): Capabil
83
87
  emit: new Set(effects.emits ?? []),
84
88
  send: new Set(effects.sends ?? []),
85
89
  ask: new Set(effects.asks ?? []),
90
+ embed: new Set(effects.embeds ?? []),
86
91
  secret: new Set(effects.secrets ?? []),
87
92
  call: new Set(effects.calls ?? []),
93
+ fetch: new Set(effects.fetches ?? []),
88
94
  };
89
95
 
90
96
  return {
@@ -0,0 +1,123 @@
1
+ /**
2
+ * Build {@link ClientDescriptor} for `GET /_oke/client.json` / `oke client add`.
3
+ *
4
+ * @module
5
+ */
6
+
7
+ import type { ClientDescriptor } from "../client/types.ts";
8
+ import type { AnyFlowDef } from "./flow.ts";
9
+ import type { RuntimeRouteMap } from "./adopt-routes.ts";
10
+ import { z } from "zod";
11
+
12
+ /**
13
+ * Build a client descriptor from runtime routes + flow defs (type strings + stamps).
14
+ *
15
+ * @param routes - Runtime `$routes` map
16
+ * @param flowsByName - Flow name → definition (for schemas)
17
+ */
18
+ export function buildClientDescriptor(
19
+ routes: RuntimeRouteMap,
20
+ flowsByName: ReadonlyMap<string, AnyFlowDef> | Readonly<Record<string, AnyFlowDef>>,
21
+ ): ClientDescriptor {
22
+ const lookup =
23
+ flowsByName instanceof Map
24
+ ? flowsByName
25
+ : new Map(Object.entries(flowsByName as Record<string, AnyFlowDef>));
26
+
27
+ type RouteEntry = ClientDescriptor["routes"][string][string];
28
+ const out: Record<string, Record<string, RouteEntry>> = {};
29
+ for (const [unit, flows] of Object.entries(routes)) {
30
+ const unitOut: Record<string, RouteEntry> = {};
31
+ for (const [flowName, stamp] of Object.entries(flows)) {
32
+ const full = `${unit}.${flowName}`;
33
+ const def = lookup.get(full) ?? lookup.get(flowName);
34
+ const errors: Record<string, string> = {};
35
+ if (def?.errors) {
36
+ for (const [code, schema] of Object.entries(def.errors)) {
37
+ errors[code] = schemaToTsString(schema);
38
+ }
39
+ }
40
+ unitOut[flowName] = {
41
+ in: schemaToTsString(def?.in),
42
+ out: schemaToTsString(def?.out),
43
+ ...(Object.keys(errors).length > 0 ? { errors } : { errors: {} }),
44
+ ...(stamp.method !== undefined ? { method: stamp.method } : {}),
45
+ ...(stamp.path !== undefined ? { path: stamp.path } : {}),
46
+ ...(stamp.live !== undefined ? { live: stamp.live } : {}),
47
+ ...(stamp.stream === true ? { stream: true as const } : {}),
48
+ ...(stamp.matchKey !== undefined ? { matchKey: stamp.matchKey } : {}),
49
+ ...(stamp.gates !== undefined && stamp.gates.length > 0 ? { gates: stamp.gates } : {}),
50
+ };
51
+ }
52
+ out[unit] = unitOut;
53
+ }
54
+ return { routes: out };
55
+ }
56
+
57
+ /**
58
+ * Print a compact TypeScript type string from a schema (Zod / JSON Schema).
59
+ * Falls back to `unknown` when unprintable.
60
+ *
61
+ * @param schema - Flow in/out/error schema
62
+ */
63
+ export function schemaToTsString(schema: unknown): string {
64
+ if (schema === undefined || schema === null) return "unknown";
65
+ try {
66
+ if (hasToJSONSchema(schema)) {
67
+ return jsonSchemaToTs(schema.toJSONSchema());
68
+ }
69
+ // Zod 4 schemas expose `~standard` — convert via z.toJSONSchema when possible.
70
+ const json = z.toJSONSchema(schema as never);
71
+ return jsonSchemaToTs(json);
72
+ } catch {
73
+ if (isObjectSchema(schema)) return jsonSchemaToTs(schema);
74
+ return "unknown";
75
+ }
76
+ }
77
+
78
+ function hasToJSONSchema(value: unknown): value is { toJSONSchema: () => unknown } {
79
+ return (
80
+ value !== null &&
81
+ typeof value === "object" &&
82
+ "toJSONSchema" in value &&
83
+ typeof (value as { toJSONSchema?: unknown }).toJSONSchema === "function"
84
+ );
85
+ }
86
+
87
+ function isObjectSchema(value: unknown): value is Record<string, unknown> {
88
+ return value !== null && typeof value === "object" && !Array.isArray(value) && "type" in value;
89
+ }
90
+
91
+ function jsonSchemaToTs(schema: unknown): string {
92
+ if (schema === null || typeof schema !== "object") return "unknown";
93
+ const s = schema as Record<string, unknown>;
94
+ if (Array.isArray(s.anyOf) || Array.isArray(s.oneOf)) {
95
+ const parts = ((s.anyOf ?? s.oneOf) as unknown[]).map(jsonSchemaToTs);
96
+ return parts.join(" | ") || "unknown";
97
+ }
98
+ if (s.const !== undefined) return JSON.stringify(s.const);
99
+ if (Array.isArray(s.enum)) {
100
+ return s.enum.map((v) => JSON.stringify(v)).join(" | ") || "unknown";
101
+ }
102
+ const typ = s.type;
103
+ if (typ === "string") return "string";
104
+ if (typ === "number" || typ === "integer") return "number";
105
+ if (typ === "boolean") return "boolean";
106
+ if (typ === "null") return "null";
107
+ if (typ === "array") {
108
+ const items = s.items !== undefined ? jsonSchemaToTs(s.items) : "unknown";
109
+ return `readonly ${items}[]`;
110
+ }
111
+ if (typ === "object" || s.properties) {
112
+ const props = (s.properties ?? {}) as Record<string, unknown>;
113
+ const required = new Set(
114
+ Array.isArray(s.required) ? s.required.filter((k): k is string => typeof k === "string") : [],
115
+ );
116
+ const lines = Object.entries(props).map(([k, v]) => {
117
+ const opt = required.has(k) ? "" : "?";
118
+ return `${JSON.stringify(k)}${opt}: ${jsonSchemaToTs(v)}`;
119
+ });
120
+ return `{ ${lines.join("; ")} }`;
121
+ }
122
+ return "unknown";
123
+ }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * App-wide Clock timezone — `oke({ clock })` / `defineConfig({ clock })`.
3
+ */
4
+
5
+ import { describe, expect, test } from "bun:test";
6
+
7
+ import { clock, resetClocks } from "../elements/clock/declare.ts";
8
+ import { defineConfig } from "../config/index.ts";
9
+ import { bootApplication } from "./boot.ts";
10
+ import { oke } from "./app.ts";
11
+ import { resetBindings } from "./on.ts";
12
+
13
+ describe("oke({ clock: { timezone } })", () => {
14
+ test("applies to clocks that omit timezone; explicit wins", async () => {
15
+ resetBindings();
16
+ resetClocks();
17
+
18
+ clock.daily("local", { at: "06:00" });
19
+ clock.daily("ny", { at: "09:00", timezone: "America/New_York" });
20
+
21
+ const app = oke({
22
+ name: "tz-oke",
23
+ autoBoot: false,
24
+ startScheduler: false,
25
+ clock: { timezone: "Asia/Riyadh" },
26
+ });
27
+
28
+ expect(app.$options.clocks?.find((c) => c.name === "local")?.timezone).toBe("Asia/Riyadh");
29
+ expect(app.$options.clocks?.find((c) => c.name === "ny")?.timezone).toBe("America/New_York");
30
+
31
+ await app.boot({ env: "test" });
32
+ expect(app.bootResult?.clock?.declarations.get("local")?.timezone).toBe("Asia/Riyadh");
33
+ expect(app.bootResult?.clock?.declarations.get("ny")?.timezone).toBe("America/New_York");
34
+ await app.bootResult?.close();
35
+ });
36
+
37
+ test("defineConfig({ clock: { timezone } }) applies at bind when oke omits it", async () => {
38
+ resetBindings();
39
+ resetClocks();
40
+
41
+ const digest = clock.daily("digest", { at: "08:00" });
42
+ expect(digest.timezoneDefaulted).toBe(true);
43
+
44
+ const result = await bootApplication({
45
+ env: "test",
46
+ clocks: [digest],
47
+ config: defineConfig({
48
+ clock: { timezone: "Asia/Riyadh" },
49
+ drivers: { clock: { test: "frozen" } },
50
+ }),
51
+ });
52
+ try {
53
+ expect(result.clock?.declarations.get("digest")?.timezone).toBe("Asia/Riyadh");
54
+ } finally {
55
+ await result.close();
56
+ }
57
+ });
58
+
59
+ test("oke({ clock }) wins over defineConfig", async () => {
60
+ resetBindings();
61
+ resetClocks();
62
+
63
+ clock.daily("digest", { at: "08:00" });
64
+
65
+ const app = oke({
66
+ name: "tz-precedence",
67
+ autoBoot: false,
68
+ startScheduler: false,
69
+ clock: { timezone: "Europe/Berlin" },
70
+ config: defineConfig({
71
+ clock: { timezone: "Asia/Riyadh" },
72
+ }),
73
+ });
74
+
75
+ expect(app.$options.clocks?.[0]?.timezone).toBe("Europe/Berlin");
76
+ await app.boot({ env: "test" });
77
+ expect(app.bootResult?.clock?.declarations.get("digest")?.timezone).toBe("Europe/Berlin");
78
+ await app.bootResult?.close();
79
+ });
80
+ });
@@ -13,7 +13,7 @@ import { http } from "./triggers.ts";
13
13
  describe("correlation — parentId across Flow → Signal → Flow", () => {
14
14
  test("consumer WideEvent.parentId equals producer run id", async () => {
15
15
  resetBindings();
16
- const orderPlaced = signal("corr-order-placed", { delivery: "once" });
16
+ const orderPlaced = signal.once("corr-order-placed");
17
17
  const runs = createRunsRuntime({ driver: "memory" });
18
18
  await runs.open();
19
19
 
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Dry-run effect stubbing + write isolation (console §9.1 · §9.3 · §9.4).
3
3
  *
4
- * - Irreversible effects (`send` / `ask`) are intercepted and recorded as
5
- * "would have fired" — never contact a real channel or model.
4
+ * - Irreversible effects (`send` / `ask` / `embed` / `fetch`) are intercepted and
5
+ * recorded as "would have fired" — never contact a real channel, model, or URL.
6
6
  * - Store writes run against real data for an honest pass/fail verdict, then
7
7
  * are always rolled back (snapshot / restore) when the dry-run scope exits.
8
8
  * - Drivers that cannot isolate writes throw {@link DryRunWriteIsolationError};
@@ -14,8 +14,8 @@ import { AsyncLocalStorage } from "node:async_hooks";
14
14
  /** One intercepted irreversible effect during a dry run. */
15
15
  export interface DryRunWouldHaveFired {
16
16
  /** Irreversible kind. */
17
- readonly kind: "send" | "ask";
18
- /** Template / prompt name. */
17
+ readonly kind: "send" | "ask" | "embed" | "fetch";
18
+ /** Template / prompt / model / host name. */
19
19
  readonly resource: string;
20
20
  /** Optional correlating message id (signal dry-run). */
21
21
  readonly messageId?: string;
@@ -23,7 +23,7 @@ export interface DryRunWouldHaveFired {
23
23
 
24
24
  /** Active dry-run bag. */
25
25
  export interface DryRunContext {
26
- /** Intercepted send/ask calls in order. */
26
+ /** Intercepted send/ask/embed calls in order. */
27
27
  readonly wouldHaveFired: DryRunWouldHaveFired[];
28
28
  /** Optional message id stamped onto subsequent intercepts. */
29
29
  messageId?: string;
@@ -89,12 +89,15 @@ export function setDryRunMessageId(messageId: string): void {
89
89
  }
90
90
 
91
91
  /**
92
- * Record that a send/ask would have fired. No-op outside dry-run.
92
+ * Record that a send/ask/embed/fetch would have fired. No-op outside dry-run.
93
93
  *
94
94
  * @param kind - Irreversible kind
95
- * @param resource - Template / prompt name
95
+ * @param resource - Template / prompt / embed-model / host name
96
96
  */
97
- export function recordWouldHaveFired(kind: "send" | "ask", resource: string): void {
97
+ export function recordWouldHaveFired(
98
+ kind: "send" | "ask" | "embed" | "fetch",
99
+ resource: string,
100
+ ): void {
98
101
  const ctx = storage.getStore();
99
102
  if (!ctx) return;
100
103
  ctx.wouldHaveFired.push({
@@ -23,6 +23,7 @@ import { join } from "node:path";
23
23
  import { z } from "zod";
24
24
  import { gate } from "../elements/gate.ts";
25
25
  import { field, id, now, store } from "../elements/store.ts";
26
+ import { passkey } from "../plugins/passkey.ts";
26
27
  import { oke } from "./app.ts";
27
28
  import { resetNoEffectsWarnForTests } from "./boot.ts";
28
29
  import { flow, resetFlowSeq } from "./flow.ts";
@@ -47,10 +48,8 @@ const CreateOut = z.object({ ok: z.boolean() });
47
48
 
48
49
  function buildUnannotatedCreateFlow(db: ReturnType<typeof store.sql>) {
49
50
  return on(
50
- http.post("/notes").public(),
51
+ http.post("/notes", { in: CreateIn, out: CreateOut }).public(),
51
52
  flow("notes.create", {
52
- in: CreateIn,
53
- out: CreateOut,
54
53
  // Deliberately no `effects` — the "let the compiler infer it" case.
55
54
  do: async (input, fx) => {
56
55
  await fx.store(db).insert(notes).values({ id: input.id, title: input.title, createdAt: 1 });
@@ -84,7 +83,7 @@ describe("boot-level: undeclared-effects flow, no manifest / rootDir", () => {
84
83
  expect(res.status).toBe(200);
85
84
  });
86
85
 
87
- test("docker: hard fail at boot — OKE1008, never an open token in a deploy-shaped env", async () => {
86
+ test("docker: hard fail at boot — OKE1020, never an open token in a deploy-shaped env", async () => {
88
87
  resetBindings();
89
88
  resetFlowSeq();
90
89
  const db = store.sql("app", { schema: { notes } });
@@ -107,7 +106,7 @@ describe("boot-level: undeclared-effects flow, no manifest / rootDir", () => {
107
106
  startScheduler: false,
108
107
  config: { drivers: memoryDrivers },
109
108
  }),
110
- ).rejects.toThrow(/OKE1008/);
109
+ ).rejects.toThrow(/OKE1020/);
111
110
  });
112
111
 
113
112
  test("prod: hard fail at boot — same posture as docker", async () => {
@@ -130,7 +129,7 @@ describe("boot-level: undeclared-effects flow, no manifest / rootDir", () => {
130
129
  },
131
130
  },
132
131
  }),
133
- ).rejects.toThrow(/OKE1008/);
132
+ ).rejects.toThrow(/OKE1020/);
134
133
  });
135
134
  });
136
135
 
@@ -140,10 +139,8 @@ describe("boot-level: table-ref resolution stays backward compatible", () => {
140
139
  resetFlowSeq();
141
140
  const db = store.sql("app", { schema: { notes } });
142
141
  const create = on(
143
- http.post("/notes").public(),
142
+ http.post("/notes", { in: CreateIn, out: CreateOut }).public(),
144
143
  flow("notes.create", {
145
- in: CreateIn,
146
- out: CreateOut,
147
144
  // The convention every template/test predates Direction B with —
148
145
  // store-level, not table-level. Must keep working unchanged.
149
146
  effects: { writes: ["sql:app"] },
@@ -227,3 +224,39 @@ export const create = on(
227
224
  }
228
225
  });
229
226
  });
227
+
228
+ describe("boot-level: built-in auth flows under docker", () => {
229
+ test("emailAndPassword + passkey boot with docker:true — empty stamp from Manifest, no hand-declared effects", async () => {
230
+ resetBindings();
231
+ resetFlowSeq();
232
+ const memoryDrivers = {
233
+ store: {
234
+ sql: { dev: "memory", prod: "memory" },
235
+ kv: { dev: "memory", prod: "memory" },
236
+ },
237
+ channel: { email: { dev: "console", prod: "console" } },
238
+ } as const;
239
+ const app = oke({
240
+ name: "auth-stamp-docker",
241
+ registry: "ignore",
242
+ gate: {
243
+ auth: {
244
+ secret: "test-secret-at-least-16",
245
+ emailAndPassword: { enabled: true },
246
+ },
247
+ },
248
+ }).plug(passkey({ origins: ["http://localhost"] }));
249
+
250
+ // Explicit Manifest (as `oke dev` extract would supply for app Flows).
251
+ // Framework auth Flows are absent → mintCapabilities stamps `{}`.
252
+ await app.boot({
253
+ env: "dev",
254
+ docker: true,
255
+ unguardedHttp: "allow",
256
+ startScheduler: false,
257
+ manifest: { oke: "1.0", app: "auth-stamp-docker", flows: {} },
258
+ config: { drivers: memoryDrivers },
259
+ });
260
+ await app.stop();
261
+ });
262
+ });
@@ -10,18 +10,20 @@ import {
10
10
  } from "./effects.ts";
11
11
 
12
12
  describe("effects — reversibility tiers", () => {
13
- test("all seven effect kinds have the correct reversibility tier", () => {
13
+ test("all effect kinds have the correct reversibility tier", () => {
14
14
  const expected: Record<EffectKind, ReversibilityTier> = {
15
15
  read: "none",
16
16
  write: "reversible",
17
17
  emit: "deferred",
18
18
  send: "irreversible",
19
19
  ask: "irreversible",
20
+ embed: "irreversible",
20
21
  secret: "capability",
21
22
  call: "portal",
23
+ fetch: "irreversible",
22
24
  };
23
25
 
24
- expect(EFFECT_KIND_TIERS).toHaveLength(7);
26
+ expect(EFFECT_KIND_TIERS).toHaveLength(9);
25
27
  for (const { kind, reversibility } of EFFECT_KIND_TIERS) {
26
28
  expect(reversibility).toBe(expected[kind]);
27
29
  expect(reversibilityOf(kind)).toBe(expected[kind]);
@@ -7,16 +7,25 @@
7
7
 
8
8
  import { resolveDurationMs } from "./elapsed.ts";
9
9
 
10
- /** The seven load-bearing effect kinds (manifest `effects` keys, singular). */
11
- export type EffectKind = "read" | "write" | "emit" | "send" | "ask" | "secret" | "call";
10
+ /** Load-bearing effect kinds (manifest `effects` keys, singular). */
11
+ export type EffectKind =
12
+ | "read"
13
+ | "write"
14
+ | "emit"
15
+ | "send"
16
+ | "ask"
17
+ | "embed"
18
+ | "secret"
19
+ | "call"
20
+ | "fetch";
12
21
 
13
22
  /**
14
- * Reversibility tier — console §9.1 ranking, applied to all seven kinds.
23
+ * Reversibility tier — console §9.1 ranking, applied to all effect kinds.
15
24
  *
16
25
  * - `none` — reads; no world change
17
26
  * - `reversible` — writes; undoable in-transaction
18
27
  * - `deferred` — emits; commit with the txn, then fan-out
19
- * - `irreversible` — sends / asks; cannot be undone by the runtime
28
+ * - `irreversible` — sends / asks / embeds / fetches; cannot be undone by the runtime
20
29
  * - `capability` — secrets; authority held, not an effect caused
21
30
  * - `portal` — calls; expands to the callee's transitive effects
22
31
  */
@@ -28,11 +37,22 @@ export type ReversibilityTier =
28
37
  | "capability"
29
38
  | "portal";
30
39
 
40
+ /**
41
+ * Optional egress identity for an effect that left the process.
42
+ *
43
+ * Driver-reported — never inferred from hostname patterns. Only `host` is
44
+ * required when present; `provider` and `kind` are additive precision.
45
+ *
46
+ * Re-exported from drivers so kernel and driver contracts share one shape.
47
+ */
48
+ export type { DriverExternal as EffectExternal } from "../drivers/external.ts";
49
+ import type { DriverExternal as EffectExternal } from "../drivers/external.ts";
50
+
31
51
  /** One recorded effect call. */
32
52
  export interface EffectEntry {
33
- /** Which of the seven kinds. */
53
+ /** Which effect kind. */
34
54
  readonly kind: EffectKind;
35
- /** Resource / signal / template / prompt / secret / flow ref. */
55
+ /** Resource / signal / template / prompt / embed-model / secret / flow / host ref. */
36
56
  readonly resource: string;
37
57
  /** Epoch-ms when the call started. */
38
58
  readonly timestamp: number;
@@ -40,6 +60,11 @@ export interface EffectEntry {
40
60
  readonly duration: number;
41
61
  /** Reversibility tier for {@link kind}. */
42
62
  readonly reversibility: ReversibilityTier;
63
+ /**
64
+ * When set, this effect left the process and reached an external peer.
65
+ * Omitted for in-process work (PGlite, mock AI, local channel console).
66
+ */
67
+ readonly external?: EffectExternal;
43
68
  }
44
69
 
45
70
  /** Append-only ledger of effect entries for one flow invocation. */
@@ -63,14 +88,16 @@ const TIER_BY_KIND: Readonly<Record<EffectKind, ReversibilityTier>> = {
63
88
  emit: "deferred",
64
89
  send: "irreversible",
65
90
  ask: "irreversible",
91
+ embed: "irreversible",
66
92
  secret: "capability",
67
93
  call: "portal",
94
+ fetch: "irreversible",
68
95
  };
69
96
 
70
97
  /**
71
98
  * Reversibility tier for an effect kind.
72
99
  *
73
- * @param kind - One of the seven effect kinds
100
+ * @param kind - One of the effect kinds
74
101
  */
75
102
  export function reversibilityOf(kind: EffectKind): ReversibilityTier {
76
103
  return TIER_BY_KIND[kind];
@@ -105,6 +132,7 @@ export function createEffectLedger(): EffectLedger {
105
132
  * @param resource - Resource ref
106
133
  * @param now - Clock (injectable for tests)
107
134
  * @param body - Work to time
135
+ * @param externalOf - Optional egress metadata (static or derived from result / error)
108
136
  */
109
137
  export async function recordEffect<T>(
110
138
  ledger: EffectLedger,
@@ -112,18 +140,29 @@ export async function recordEffect<T>(
112
140
  resource: string,
113
141
  now: () => number,
114
142
  body: () => T | Promise<T>,
143
+ externalOf?:
144
+ | EffectExternal
145
+ | ((result: T | undefined, error: unknown) => EffectExternal | undefined),
115
146
  ): Promise<T> {
116
147
  const timestamp = now();
117
148
  const t0 = performance.now();
149
+ let result: T | undefined;
150
+ let error: unknown;
118
151
  try {
119
- return await body();
152
+ result = await body();
153
+ return result;
154
+ } catch (e) {
155
+ error = e;
156
+ throw e;
120
157
  } finally {
158
+ const external = typeof externalOf === "function" ? externalOf(result, error) : externalOf;
121
159
  recordObservedEffect(
122
160
  ledger,
123
161
  kind,
124
162
  resource,
125
163
  timestamp,
126
164
  resolveDurationMs(now() - timestamp, performance.now() - t0),
165
+ external,
127
166
  );
128
167
  }
129
168
  }
@@ -139,6 +178,7 @@ export async function recordEffect<T>(
139
178
  * @param resource - Resource ref (or kernel cache key)
140
179
  * @param timestamp - Epoch-ms when the call started
141
180
  * @param duration - Measured duration in milliseconds
181
+ * @param external - Optional egress identity
142
182
  */
143
183
  export function recordObservedEffect(
144
184
  ledger: EffectLedger,
@@ -146,6 +186,7 @@ export function recordObservedEffect(
146
186
  resource: string,
147
187
  timestamp: number,
148
188
  duration: number,
189
+ external?: EffectExternal,
149
190
  ): void {
150
191
  ledger.record({
151
192
  kind,
@@ -153,11 +194,12 @@ export function recordObservedEffect(
153
194
  timestamp,
154
195
  duration,
155
196
  reversibility: reversibilityOf(kind),
197
+ ...(external !== undefined ? { external } : {}),
156
198
  });
157
199
  }
158
200
 
159
201
  /**
160
- * All seven kinds with their tiers — useful for exhaustive tests.
202
+ * All effect kinds with their tiers — useful for exhaustive tests.
161
203
  */
162
204
  export const EFFECT_KIND_TIERS: ReadonlyArray<{
163
205
  kind: EffectKind;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * OKE1605 — kept off the kernel edge profile.
3
+ *
4
+ * Channel `fx.send` throws this when template `data` fails the template schema.
5
+ * Loaded via computed `import.meta.require` from {@link lookupOkeError}; the
6
+ * Channel runtime imports it directly (that graph is not in `budget-entry`).
7
+ */
8
+
9
+ import type { OkeErrorDefinition } from "./errors.ts";
10
+
11
+ /** Send payload failed the channel template's declared Standard Schema. */
12
+ export const CHANNEL_SCHEMA: OkeErrorDefinition = {
13
+ code: 1605,
14
+ domain: "channel",
15
+ cause: '"{resource}": {detail}',
16
+ fix: "Fix template data payload or the template schema.",
17
+ };