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
@@ -3,9 +3,18 @@
3
3
  *
4
4
  * Named clocks are reconciled into the Store at boot; the scheduler reads
5
5
  * the effective state from the Store (console §5), never the code directly.
6
+ *
7
+ * Helpers (`clock.daily` · `cron` · `every` · …) compile to the same
8
+ * {@link ClockDecl} shape as `clock(name, { cron })`.
6
9
  */
7
10
 
8
11
  import { clockRegistry } from "../../kernel/element-registries.ts";
12
+ import {
13
+ assertValidCronExpression,
14
+ buildCronExpression,
15
+ type CronField,
16
+ type CronFields,
17
+ } from "./cron-fields.ts";
9
18
 
10
19
  /** Options for {@link clock}. */
11
20
  export interface ClockOptions {
@@ -29,6 +38,51 @@ export interface ClockOptions {
29
38
  readonly perTenant?: boolean;
30
39
  }
31
40
 
41
+ /**
42
+ * Shared options for convenience helpers (no `cron` / `every` — those are
43
+ * supplied by the helper).
44
+ */
45
+ export type ClockHelperOptions = Omit<ClockOptions, "cron" | "every">;
46
+
47
+ /** Options for {@link clock.daily}. */
48
+ export type ClockDailyOptions = ClockHelperOptions & {
49
+ /** Wall-clock time (`"06:00"`). Default midnight. */
50
+ readonly at?: string;
51
+ };
52
+
53
+ /** Options for {@link clock.hourly}. */
54
+ export type ClockHourlyOptions = ClockHelperOptions & {
55
+ /** Minute of each hour (default `0`). */
56
+ readonly minute?: number;
57
+ };
58
+
59
+ /** Day-of-week token for {@link clock.weekly}. */
60
+ export type ClockWeekday = CronField;
61
+
62
+ /** Options for {@link clock.weekly}. */
63
+ export type ClockWeeklyOptions = ClockHelperOptions & {
64
+ /** Day(s) of week (`"mon"` · `1` · `["mon", "fri"]` · `"1-5"`). */
65
+ readonly on: ClockWeekday;
66
+ /** Wall-clock time (default `"00:00"`). */
67
+ readonly at?: string;
68
+ };
69
+
70
+ /** Options for {@link clock.monthly}. */
71
+ export type ClockMonthlyOptions = ClockHelperOptions & {
72
+ /** Day(s) of month (`1` · `[1, 15]`). */
73
+ readonly on: CronField;
74
+ /** Wall-clock time (default `"00:00"`). */
75
+ readonly at?: string;
76
+ };
77
+
78
+ /**
79
+ * Structured cron bag + shared helper options for {@link clock.cron}.
80
+ *
81
+ * Schedule keys (`minute` · `hour` · … · `at`) build the expression;
82
+ * remaining keys are {@link ClockHelperOptions}.
83
+ */
84
+ export type ClockCronFieldsOptions = CronFields & ClockHelperOptions;
85
+
32
86
  /**
33
87
  * Declared clock handle — reconciled into `oke_crons` at boot.
34
88
  */
@@ -41,6 +95,13 @@ export interface ClockDecl {
41
95
  readonly every?: string;
42
96
  /** IANA timezone. */
43
97
  readonly timezone: string;
98
+ /**
99
+ * When true, `timezone` was omitted at declare and may be replaced by
100
+ * `oke({ clock: { timezone } })` / `defineConfig({ clock: { timezone } })`.
101
+ *
102
+ * @internal
103
+ */
104
+ readonly timezoneDefaulted?: boolean;
44
105
  /** Whether Console override is allowed. */
45
106
  readonly overridable: boolean;
46
107
  /** Optional human description. */
@@ -80,11 +141,16 @@ function declareClock(name: string, options: ClockOptions = {}): ClockDecl {
80
141
  if (!options.cron && !options.every) {
81
142
  throw new TypeError(`clock("${name}"): require cron or every`);
82
143
  }
144
+ if (options.cron) {
145
+ assertValidCronExpression(options.cron, `clock("${name}")`);
146
+ }
147
+ const timezoneDefaulted = options.timezone === undefined;
83
148
  const decl: ClockDecl = {
84
149
  name,
85
150
  cron: options.cron,
86
151
  every: options.every,
87
152
  timezone: options.timezone ?? "UTC",
153
+ ...(timezoneDefaulted ? { timezoneDefaulted: true } : {}),
88
154
  overridable: options.overridable ?? false,
89
155
  ...(options.description !== undefined ? { description: options.description } : {}),
90
156
  ...(options.perTenant === true ? { perTenant: true } : {}),
@@ -93,6 +159,35 @@ function declareClock(name: string, options: ClockOptions = {}): ClockDecl {
93
159
  return decl;
94
160
  }
95
161
 
162
+ /**
163
+ * Apply an app-wide default timezone to clocks that omitted `timezone`.
164
+ *
165
+ * Explicit `timezone: "…"` on a declaration always wins. When `defaultTimezone`
166
+ * is omitted / empty, defaulted clocks stay on `"UTC"`.
167
+ *
168
+ * @param decls - Declared clocks
169
+ * @param defaultTimezone - IANA zone from `oke({ clock })` / config
170
+ */
171
+ export function applyClockTimezoneDefaults(
172
+ decls: readonly ClockDecl[],
173
+ defaultTimezone: string | undefined,
174
+ ): ClockDecl[] {
175
+ const zone = defaultTimezone?.trim();
176
+ if (!zone) return decls.slice();
177
+ return decls.map((d) => {
178
+ if (!d.timezoneDefaulted) return d;
179
+ return {
180
+ name: d.name,
181
+ ...(d.cron !== undefined ? { cron: d.cron } : {}),
182
+ ...(d.every !== undefined ? { every: d.every } : {}),
183
+ timezone: zone,
184
+ overridable: d.overridable,
185
+ ...(d.description !== undefined ? { description: d.description } : {}),
186
+ ...(d.perTenant === true ? { perTenant: true } : {}),
187
+ };
188
+ });
189
+ }
190
+
96
191
  /**
97
192
  * Per-tenant schedule template — one `oke_crons` row per tenant.
98
193
  *
@@ -103,6 +198,134 @@ function declarePerTenantClock(name: string, options: ClockOptions = {}): ClockD
103
198
  return declareClock(name, { ...options, perTenant: true });
104
199
  }
105
200
 
201
+ /**
202
+ * Interval helper — `clock.every("health.ping", "30s")`.
203
+ *
204
+ * @param name - Schedule name
205
+ * @param duration - Interval (`"30s"`, `"1h"`, …)
206
+ * @param options - Timezone / overridable / description / perTenant
207
+ */
208
+ function declareEveryClock(
209
+ name: string,
210
+ duration: string,
211
+ options: ClockHelperOptions = {},
212
+ ): ClockDecl {
213
+ return declareClock(name, { ...options, every: duration });
214
+ }
215
+
216
+ /**
217
+ * Split structured cron fields from shared helper options.
218
+ *
219
+ * @param bag - Mixed `CronFields` + `ClockHelperOptions`
220
+ */
221
+ function splitCronBag(bag: ClockCronFieldsOptions): {
222
+ readonly fields: CronFields;
223
+ readonly opts: ClockHelperOptions;
224
+ } {
225
+ const {
226
+ minute,
227
+ hour,
228
+ dayOfMonth,
229
+ month,
230
+ dayOfWeek,
231
+ at,
232
+ timezone,
233
+ overridable,
234
+ description,
235
+ perTenant,
236
+ } = bag;
237
+ return {
238
+ fields: {
239
+ ...(minute !== undefined ? { minute } : {}),
240
+ ...(hour !== undefined ? { hour } : {}),
241
+ ...(dayOfMonth !== undefined ? { dayOfMonth } : {}),
242
+ ...(month !== undefined ? { month } : {}),
243
+ ...(dayOfWeek !== undefined ? { dayOfWeek } : {}),
244
+ ...(at !== undefined ? { at } : {}),
245
+ },
246
+ opts: {
247
+ ...(timezone !== undefined ? { timezone } : {}),
248
+ ...(overridable !== undefined ? { overridable } : {}),
249
+ ...(description !== undefined ? { description } : {}),
250
+ ...(perTenant !== undefined ? { perTenant } : {}),
251
+ },
252
+ };
253
+ }
254
+
255
+ /**
256
+ * Cron helper — string expression or structured fields.
257
+ *
258
+ * @param name - Schedule name
259
+ * @param expressionOrFields - Five-field / nickname string, or field bag
260
+ * @param options - Shared options when the second arg is a string
261
+ */
262
+ function declareCronClock(
263
+ name: string,
264
+ expressionOrFields: string | ClockCronFieldsOptions,
265
+ options: ClockHelperOptions = {},
266
+ ): ClockDecl {
267
+ if (typeof expressionOrFields === "string") {
268
+ return declareClock(name, { ...options, cron: expressionOrFields });
269
+ }
270
+ const { fields, opts } = splitCronBag(expressionOrFields);
271
+ const cron = buildCronExpression(fields);
272
+ return declareClock(name, { ...opts, cron });
273
+ }
274
+
275
+ /**
276
+ * Daily preset — midnight unless `at` is set.
277
+ *
278
+ * @param name - Schedule name
279
+ * @param options - `at` + shared options
280
+ */
281
+ function declareDailyClock(name: string, options: ClockDailyOptions = {}): ClockDecl {
282
+ const { at, ...opts } = options;
283
+ const cron = buildCronExpression({ at: at ?? "00:00" });
284
+ return declareClock(name, { ...opts, cron });
285
+ }
286
+
287
+ /**
288
+ * Hourly preset — top of the hour unless `minute` is set.
289
+ *
290
+ * @param name - Schedule name
291
+ * @param options - `minute` + shared options
292
+ */
293
+ function declareHourlyClock(name: string, options: ClockHourlyOptions = {}): ClockDecl {
294
+ const { minute, ...opts } = options;
295
+ const cron = buildCronExpression({ minute: minute ?? 0 });
296
+ return declareClock(name, { ...opts, cron });
297
+ }
298
+
299
+ /**
300
+ * Weekly / multi-weekday preset.
301
+ *
302
+ * @param name - Schedule name
303
+ * @param options - `on` (required) + optional `at`
304
+ */
305
+ function declareWeeklyClock(name: string, options: ClockWeeklyOptions): ClockDecl {
306
+ const { on, at, ...opts } = options;
307
+ const cron = buildCronExpression({
308
+ at: at ?? "00:00",
309
+ dayOfWeek: on,
310
+ });
311
+ return declareClock(name, { ...opts, cron });
312
+ }
313
+
314
+ /**
315
+ * Monthly / multi-DOM preset.
316
+ *
317
+ * @param name - Schedule name
318
+ * @param options - `on` (required) + optional `at`
319
+ */
320
+ function declareMonthlyClock(name: string, options: ClockMonthlyOptions): ClockDecl {
321
+ const { on, at, ...opts } = options;
322
+ const cron = buildCronExpression({
323
+ at: at ?? "00:00",
324
+ dayOfMonth: on,
325
+ });
326
+ return declareClock(name, { ...opts, cron });
327
+ }
328
+
106
329
  /**
107
330
  * Separator between a per-tenant template name and the tenant id.
108
331
  */
@@ -137,12 +360,33 @@ export function parsePerTenantCronName(
137
360
  return { template, tenantId };
138
361
  }
139
362
 
363
+ /** Public Clock declaration namespace — callable + convenience helpers. */
364
+ export interface ClockNamespace {
365
+ (name: string, options?: ClockOptions): ClockDecl;
366
+ readonly perTenant: typeof declarePerTenantClock;
367
+ readonly every: typeof declareEveryClock;
368
+ readonly cron: typeof declareCronClock;
369
+ readonly daily: typeof declareDailyClock;
370
+ readonly hourly: typeof declareHourlyClock;
371
+ readonly weekly: typeof declareWeeklyClock;
372
+ readonly monthly: typeof declareMonthlyClock;
373
+ }
374
+
140
375
  /**
141
376
  * Declare a named clock / cron schedule.
142
377
  *
378
+ * Helpers: `clock.every` · `clock.cron` · `clock.daily` · `clock.hourly` ·
379
+ * `clock.weekly` · `clock.monthly` · `clock.perTenant`.
380
+ *
143
381
  * @param name - Schedule name
144
382
  * @param options - `cron` and/or `every`, timezone, overridable
145
383
  */
146
- export const clock: ((name: string, options?: ClockOptions) => ClockDecl) & {
147
- readonly perTenant: typeof declarePerTenantClock;
148
- } = Object.assign(declareClock, { perTenant: declarePerTenantClock });
384
+ export const clock: ClockNamespace = Object.assign(declareClock, {
385
+ perTenant: declarePerTenantClock,
386
+ every: declareEveryClock,
387
+ cron: declareCronClock,
388
+ daily: declareDailyClock,
389
+ hourly: declareHourlyClock,
390
+ weekly: declareWeeklyClock,
391
+ monthly: declareMonthlyClock,
392
+ });
@@ -14,9 +14,29 @@ export {
14
14
  clock,
15
15
  perTenantCronName,
16
16
  parsePerTenantCronName,
17
+ applyClockTimezoneDefaults,
17
18
  PER_TENANT_CRON_SEP,
18
19
  } from "./clock/declare.ts";
19
- export type { ClockDecl, ClockOptions } from "./clock/declare.ts";
20
+ export type {
21
+ ClockDecl,
22
+ ClockOptions,
23
+ ClockHelperOptions,
24
+ ClockDailyOptions,
25
+ ClockHourlyOptions,
26
+ ClockWeeklyOptions,
27
+ ClockMonthlyOptions,
28
+ ClockCronFieldsOptions,
29
+ ClockWeekday,
30
+ ClockNamespace,
31
+ } from "./clock/declare.ts";
32
+
33
+ export {
34
+ buildCronExpression,
35
+ parseAtTime,
36
+ serializeCronField,
37
+ assertValidCronExpression,
38
+ } from "./clock/cron-fields.ts";
39
+ export type { CronField, CronFields } from "./clock/cron-fields.ts";
20
40
 
21
41
  export { parseDurationMs } from "./clock/duration.ts";
22
42
 
@@ -43,7 +43,11 @@ export type {
43
43
  export { signal, createSignalRuntime } from "./signal.ts";
44
44
  export type {
45
45
  SignalDecl,
46
+ SignalLiveOptions,
47
+ SignalNamespace,
46
48
  SignalOptions,
49
+ SignalRetention,
50
+ SignalSharedOptions,
47
51
  SignalRuntime,
48
52
  CreateSignalRuntimeOptions,
49
53
  } from "./signal.ts";
@@ -59,6 +63,17 @@ export {
59
63
  parseDurationMs,
60
64
  } from "./clock.ts";
61
65
  export type { ClockDecl, ClockOptions, ClockRuntime, TimeTravel, DurableResult } from "./clock.ts";
66
+ export type {
67
+ ClockHelperOptions,
68
+ ClockDailyOptions,
69
+ ClockHourlyOptions,
70
+ ClockWeeklyOptions,
71
+ ClockMonthlyOptions,
72
+ ClockCronFieldsOptions,
73
+ ClockNamespace,
74
+ CronField,
75
+ CronFields,
76
+ } from "./clock.ts";
62
77
 
63
78
  export {
64
79
  gate,
@@ -26,8 +26,7 @@ if (!durablePath) {
26
26
  process.exit(2);
27
27
  }
28
28
 
29
- const orderPlaced = signal("order-placed", {
30
- delivery: "once",
29
+ const orderPlaced = signal.once("order-placed", {
31
30
  retries: 3,
32
31
  deadLetter: true,
33
32
  // Producer-only / cross-process consumer: no local subscriber at emit time.
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Signal declaration — data in motion.
3
3
  *
4
- * `delivery` is mandatory with no default: queue / pub-sub / stream were
5
- * always one object with different physics (unified-theory §3).
4
+ * Delivery physics are chosen by helper name (`signal.once` / `broadcast` /
5
+ * `live`), matching `http.get` / `http.post` no default, no options bag for mode.
6
6
  */
7
7
 
8
8
  import type { SignalDelivery } from "../../manifest/types.ts";
@@ -17,8 +17,8 @@ export interface SignalRetention {
17
17
  readonly maxCount?: number;
18
18
  }
19
19
 
20
- /** Shared options for every {@link signal} delivery mode. */
21
- interface SignalOptionsBase {
20
+ /** Shared options for every {@link signal} delivery helper. */
21
+ export interface SignalSharedOptions {
22
22
  /** Optional human description for Console / docs (falls back to the signal name). */
23
23
  readonly description?: string;
24
24
  /** Max delivery attempts before dead-letter (once). */
@@ -34,20 +34,16 @@ interface SignalOptionsBase {
34
34
  readonly optional?: boolean;
35
35
  }
36
36
 
37
+ /** Options for {@link signal.live} — shared fields plus optional tape retention. */
38
+ export type SignalLiveOptions = SignalSharedOptions & {
39
+ readonly retention?: SignalRetention;
40
+ };
41
+
37
42
  /**
38
- * Options for {@link signal}.
39
- *
40
- * `retention` is live-only — a type error on `once` / `broadcast`.
43
+ * @deprecated Prefer {@link SignalSharedOptions} / {@link SignalLiveOptions}.
44
+ * Alias kept for type-only imports that still name `SignalOptions`.
41
45
  */
42
- export type SignalOptions =
43
- | (SignalOptionsBase & {
44
- readonly delivery: "once" | "broadcast";
45
- readonly retention?: never;
46
- })
47
- | (SignalOptionsBase & {
48
- readonly delivery: "live";
49
- readonly retention?: SignalRetention;
50
- });
46
+ export type SignalOptions = SignalSharedOptions | SignalLiveOptions;
51
47
 
52
48
  /**
53
49
  * Declared signal handle — usable as `on(signal, flow)`, `fx.emit(signal, …)`,
@@ -74,8 +70,33 @@ export interface SignalDecl<T = unknown> {
74
70
  readonly _payload?: T;
75
71
  }
76
72
 
73
+ /** Public Signal declaration namespace — `signal.once` / `broadcast` / `live`. */
74
+ export interface SignalNamespace {
75
+ /**
76
+ * Competing queue — exactly one subscriber claims each message.
77
+ *
78
+ * @param name - Signal name
79
+ * @param options - Retry / DLQ / schema policy
80
+ */
81
+ once<T = unknown>(name: string, options?: SignalSharedOptions): SignalDecl<T>;
82
+ /**
83
+ * Pub/sub fan-out — every subscriber receives each message.
84
+ *
85
+ * @param name - Signal name
86
+ * @param options - Schema / optional policy
87
+ */
88
+ broadcast<T = unknown>(name: string, options?: SignalSharedOptions): SignalDecl<T>;
89
+ /**
90
+ * Live SSE tape — retained stream for `http.live` / `.live(signal)`.
91
+ *
92
+ * @param name - Signal name
93
+ * @param options - Retention / schema / optional policy
94
+ */
95
+ live<T = unknown>(name: string, options?: SignalLiveOptions): SignalDecl<T>;
96
+ }
97
+
77
98
  /**
78
- * `signal()` pushes into the shared {@link signalRegistry}
99
+ * `signal.*` pushes into the shared {@link signalRegistry}
79
100
  * (`src/kernel/element-registries.ts`) so {@link oke} can auto-populate
80
101
  * `signals` with zero explicit array — mirrors the {@link on} trigger-drain
81
102
  * registry (`src/kernel/on.ts`).
@@ -95,45 +116,52 @@ export function resetSignals(): void {
95
116
  signalRegistry.length = 0;
96
117
  }
97
118
 
98
- /**
99
- * Declare a signal. `delivery` is mandatory — omitting it is a type error.
100
- *
101
- * @param name - Signal name
102
- * @param options - Delivery physics and retry / DLQ policy
103
- */
104
- export function signal<T = unknown>(name: string, options: SignalOptions): SignalDecl<T> {
105
- if (
106
- options.delivery !== "once" &&
107
- options.delivery !== "broadcast" &&
108
- options.delivery !== "live"
109
- ) {
110
- throw new TypeError(`signal("${name}"): delivery is mandatory (once | broadcast | live)`);
111
- }
119
+ function declareSignal<T = unknown>(
120
+ name: string,
121
+ delivery: SignalDelivery,
122
+ options: SignalSharedOptions | SignalLiveOptions = {},
123
+ ): SignalDecl<T> {
112
124
  const retention = "retention" in options ? options.retention : undefined;
113
- if (retention !== undefined && options.delivery !== "live") {
114
- throw new TypeError(`signal("${name}"): retention is only valid with delivery: "live"`);
125
+ if (retention !== undefined && delivery !== "live") {
126
+ throw new TypeError(`signal.${delivery}("${name}"): retention is only valid with signal.live`);
115
127
  }
116
128
  if (retention?.maxAge !== undefined && parseDurationMs(retention.maxAge) <= 0) {
117
129
  throw new TypeError(
118
- `signal("${name}"): retention.maxAge must be a duration like "24h" or "30s"`,
130
+ `signal.live("${name}"): retention.maxAge must be a duration like "24h" or "30s"`,
119
131
  );
120
132
  }
121
133
  if (
122
134
  retention?.maxCount !== undefined &&
123
135
  (!Number.isInteger(retention.maxCount) || retention.maxCount < 1)
124
136
  ) {
125
- throw new TypeError(`signal("${name}"): retention.maxCount must be an integer ≥ 1`);
137
+ throw new TypeError(`signal.live("${name}"): retention.maxCount must be an integer ≥ 1`);
126
138
  }
127
139
  const decl: SignalDecl<T> = {
128
140
  name,
129
- delivery: options.delivery,
141
+ delivery,
130
142
  ...(options.description !== undefined ? { description: options.description } : {}),
131
143
  retries: options.retries ?? 3,
132
144
  deadLetter: options.deadLetter ?? true,
133
145
  schema: options.schema,
134
146
  optional: options.optional ?? false,
135
- ...(options.delivery === "live" && retention !== undefined ? { retention } : {}),
147
+ ...(delivery === "live" && retention !== undefined ? { retention } : {}),
136
148
  };
137
149
  signalRegistry.push(decl as SignalDecl);
138
150
  return decl;
139
151
  }
152
+
153
+ /**
154
+ * Declare a signal. Delivery physics are chosen by helper name —
155
+ * `signal.once` · `signal.broadcast` · `signal.live`.
156
+ */
157
+ export const signal: SignalNamespace = {
158
+ once<T = unknown>(name: string, options?: SignalSharedOptions): SignalDecl<T> {
159
+ return declareSignal(name, "once", options);
160
+ },
161
+ broadcast<T = unknown>(name: string, options?: SignalSharedOptions): SignalDecl<T> {
162
+ return declareSignal(name, "broadcast", options);
163
+ },
164
+ live<T = unknown>(name: string, options?: SignalLiveOptions): SignalDecl<T> {
165
+ return declareSignal(name, "live", options);
166
+ },
167
+ };
@@ -90,11 +90,7 @@ for (const { label, driver, setup } of drivers) {
90
90
  describe(`signal delivery modes · ${label}`, () => {
91
91
  test("once: one message reaches exactly one of two competing consumers", async () => {
92
92
  // Shape matches Linkly linkClicked / Provisions order-placed.
93
- const once = signal("link-clicked", {
94
- delivery: "once",
95
- retries: 3,
96
- deadLetter: true,
97
- });
93
+ const once = signal.once("link-clicked", { retries: 3, deadLetter: true });
98
94
  const bus = await openBus(driver, [once], setup?.() ?? {});
99
95
  const got: string[] = [];
100
96
 
@@ -113,11 +109,7 @@ for (const { label, driver, setup } of drivers) {
113
109
  });
114
110
 
115
111
  test("once: retries+1 attempts then dead-letter when deadLetter: true", async () => {
116
- const once = signal("flaky", {
117
- delivery: "once",
118
- retries: 2,
119
- deadLetter: true,
120
- });
112
+ const once = signal.once("flaky", { retries: 2, deadLetter: true });
121
113
  const bus = await openBus(driver, [once], setup?.() ?? {});
122
114
  let attempts = 0;
123
115
  await bus.subscribe("flaky", "c1", async () => {
@@ -136,11 +128,7 @@ for (const { label, driver, setup } of drivers) {
136
128
  });
137
129
 
138
130
  test("once: deadLetter: false marks delivered after exhausting retries", async () => {
139
- const once = signal("flaky-drop", {
140
- delivery: "once",
141
- retries: 1,
142
- deadLetter: false,
143
- });
131
+ const once = signal.once("flaky-drop", { retries: 1, deadLetter: false });
144
132
  const bus = await openBus(driver, [once], setup?.() ?? {});
145
133
  let attempts = 0;
146
134
  await bus.subscribe("flaky-drop", "c1", async () => {
@@ -159,7 +147,7 @@ for (const { label, driver, setup } of drivers) {
159
147
  });
160
148
 
161
149
  test("broadcast: every subscriber receives its own copy", async () => {
162
- const bcast = signal("news", { delivery: "broadcast" });
150
+ const bcast = signal.broadcast("news");
163
151
  const bus = await openBus(driver, [bcast], setup?.() ?? {});
164
152
  const a: unknown[] = [];
165
153
  const b: unknown[] = [];
@@ -179,7 +167,7 @@ for (const { label, driver, setup } of drivers) {
179
167
 
180
168
  test("live: late subscriber replays full retained history (unbounded)", async () => {
181
169
  // Shape matches Skyport seat-feed.
182
- const live = signal("seat-feed", { delivery: "live", optional: true });
170
+ const live = signal.live("seat-feed", { optional: true });
183
171
  const bus = await openBus(driver, [live], setup?.() ?? {});
184
172
 
185
173
  await bus.emit("seat-feed", { seat: "12A" });
@@ -194,11 +182,7 @@ for (const { label, driver, setup } of drivers) {
194
182
  });
195
183
 
196
184
  test("live: maxCount keeps the newest N", async () => {
197
- const live = signal("seat-feed", {
198
- delivery: "live",
199
- optional: true,
200
- retention: { maxCount: 2 },
201
- });
185
+ const live = signal.live("seat-feed", { optional: true, retention: { maxCount: 2 } });
202
186
  const bus = await openBus(driver, [live], setup?.() ?? {});
203
187
 
204
188
  for (const seat of ["12A", "12B", "12C", "12D", "12E"]) {
@@ -212,11 +196,7 @@ for (const { label, driver, setup } of drivers) {
212
196
 
213
197
  test("live: maxAge prunes on emit and on live() open", async () => {
214
198
  let t = 1_000;
215
- const live = signal("seat-feed", {
216
- delivery: "live",
217
- optional: true,
218
- retention: { maxAge: "1s" },
219
- });
199
+ const live = signal.live("seat-feed", { optional: true, retention: { maxAge: "1s" } });
220
200
  const bus = await openBus(driver, [live], { now: () => t, ...(setup?.() ?? {}) });
221
201
 
222
202
  await bus.emit("seat-feed", { seat: "old" });
@@ -230,7 +210,7 @@ for (const { label, driver, setup } of drivers) {
230
210
  });
231
211
 
232
212
  test("live: afterId skips already-delivered events", async () => {
233
- const live = signal("seat-feed", { delivery: "live", optional: true });
213
+ const live = signal.live("seat-feed", { optional: true });
234
214
  const bus = await openBus(driver, [live], setup?.() ?? {});
235
215
 
236
216
  await bus.emit("seat-feed", { seat: "12A" });
@@ -248,15 +228,15 @@ for (const { label, driver, setup } of drivers) {
248
228
  expect(rest.map((e) => e.payload)).toEqual([{ seat: "12B" }, { seat: "12C" }]);
249
229
  });
250
230
 
251
- test("live: unknown afterId throws OKE1014", async () => {
252
- const live = signal("seat-feed", { delivery: "live", optional: true });
231
+ test("live: unknown afterId throws OKE1210", async () => {
232
+ const live = signal.live("seat-feed", { optional: true });
253
233
  const bus = await openBus(driver, [live], setup?.() ?? {});
254
234
  await bus.emit("seat-feed", { seat: "12A" });
255
235
  await bus.drain();
256
236
 
257
237
  const it = bus.live("seat-feed", { afterId: "missing" })[Symbol.asyncIterator]();
258
238
  try {
259
- await expect(it.next()).rejects.toMatchObject({ code: 1014 });
239
+ await expect(it.next()).rejects.toMatchObject({ code: 1210 });
260
240
  } finally {
261
241
  await it.return?.();
262
242
  }
@@ -23,13 +23,7 @@ describe("signal dry-run replay — external effects stubbed", () => {
23
23
  } as unknown as ChannelRuntime;
24
24
 
25
25
  const runtime = createSignalRuntime({ driver: memorySignalDriver });
26
- runtime.register(
27
- signal("order-placed", {
28
- delivery: "once",
29
- retries: 0,
30
- deadLetter: true,
31
- }),
32
- );
26
+ runtime.register(signal.once("order-placed", { retries: 0, deadLetter: true }));
33
27
  const bus = await runtime.start();
34
28
 
35
29
  // Seed DLQ with a failing consumer, then replace with a send consumer.
@@ -18,13 +18,7 @@ describe("signal dry-run replay — write isolation", () => {
18
18
  const before = structuredClone(stockRow);
19
19
 
20
20
  const runtime = createSignalRuntime({ driver: memorySignalDriver });
21
- runtime.register(
22
- signal("order-placed", {
23
- delivery: "once",
24
- retries: 0,
25
- deadLetter: true,
26
- }),
27
- );
21
+ runtime.register(signal.once("order-placed", { retries: 0, deadLetter: true }));
28
22
  const bus = await runtime.start();
29
23
 
30
24
  const unsubFail = await bus.subscribe("order-placed", "flaky", async () => {