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,82 @@
1
+ /**
2
+ * One-time interactive prompt: run `oke db seed` after first successful push.
3
+ */
4
+
5
+ import { confirm, isCancel } from "@clack/prompts";
6
+ import type { ConfigEnv } from "../config/index.ts";
7
+ import { resolveSeedIdentity, seedPromptMessage } from "../elements/store/seed.ts";
8
+ import { formatCliChrome } from "../term.ts";
9
+ import { loadSeedDef, resolveSeedModulePath, runSeed } from "./db-seed.ts";
10
+ import { isProjectSeeded, markProjectSeeded } from "./project-state.ts";
11
+
12
+ /** @deprecated Use `.oke/state.json` `seededAt` via {@link isProjectSeeded}. */
13
+ export { LEGACY_SEEDED_MARKER as SEEDED_MARKER } from "./project-state.ts";
14
+
15
+ /** Options for {@link maybeAskSeed}. */
16
+ export interface AskSeedOptions {
17
+ readonly cwd: string;
18
+ readonly env: ConfigEnv;
19
+ readonly write?: (text: string) => void;
20
+ readonly stdinIsTTY?: boolean;
21
+ /** Skip prompt (tests / `--yes` / non-interactive). */
22
+ readonly skip?: boolean;
23
+ /** Injectable confirm (tests). */
24
+ readonly confirmFn?: () => Promise<boolean>;
25
+ /** Injectable seed runner (tests). */
26
+ readonly seedFn?: (cwd: string, env: ConfigEnv) => Promise<number>;
27
+ }
28
+
29
+ /**
30
+ * After a successful `oke db push`, ask once whether to seed this app
31
+ * (`defineSeed({ name })` or the project folder). Skips when non-TTY,
32
+ * already seeded for that identity, or no seed module.
33
+ *
34
+ * @param options - Project / env / injectables
35
+ */
36
+ export async function maybeAskSeed(options: AskSeedOptions): Promise<void> {
37
+ if (options.skip) return;
38
+ const tty = options.stdinIsTTY ?? Boolean(process.stdin.isTTY);
39
+ if (!tty) return;
40
+
41
+ const cwd = options.cwd;
42
+ const seedPath = await resolveSeedModulePath(cwd);
43
+ if (!(await Bun.file(seedPath).exists())) return;
44
+
45
+ const def = await loadSeedDef(cwd).catch(() => undefined);
46
+ const identity = resolveSeedIdentity(def, cwd);
47
+ if (await isProjectSeeded(cwd, identity.name)) return;
48
+
49
+ const write = options.write ?? ((t) => process.stdout.write(t));
50
+ const chromeWrite = (t: string) => write(formatCliChrome(t));
51
+ const ok =
52
+ options.confirmFn !== undefined
53
+ ? await options.confirmFn()
54
+ : await (async () => {
55
+ const value = await confirm({
56
+ message: seedPromptMessage(identity),
57
+ initialValue: true,
58
+ });
59
+ if (isCancel(value)) return false;
60
+ return Boolean(value);
61
+ })();
62
+
63
+ if (!ok) {
64
+ chromeWrite("oke db seed: skipped (run `oke db seed` later)\n");
65
+ return;
66
+ }
67
+
68
+ const seed =
69
+ options.seedFn ??
70
+ ((projectCwd, env) =>
71
+ runSeed({
72
+ cwd: projectCwd,
73
+ env,
74
+ write: chromeWrite,
75
+ force: true,
76
+ stdinIsTTY: false,
77
+ }));
78
+ const code = await seed(cwd, options.env);
79
+ if (code === 0) {
80
+ await markProjectSeeded(cwd, { seed: identity.name });
81
+ }
82
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Tests for interactive Vault gap fill during `oke dev`.
3
+ */
4
+
5
+ import { describe, expect, test } from "bun:test";
6
+ import { mkdtempSync, readFileSync, rmSync } from "node:fs";
7
+ import { tmpdir } from "node:os";
8
+ import { join } from "node:path";
9
+ import { maybeAskVaultGaps } from "./ask-vault-gaps.ts";
10
+
11
+ describe("maybeAskVaultGaps", () => {
12
+ test("skips when non-TTY", async () => {
13
+ const dir = mkdtempSync(join(tmpdir(), "ask-vault-"));
14
+ try {
15
+ let reads = 0;
16
+ const code = await maybeAskVaultGaps({
17
+ cwd: dir,
18
+ stdinIsTTY: false,
19
+ gapsFn: async () => [{ name: "OPENROUTER_API_KEY", description: "OpenRouter API key" }],
20
+ readSecret: async () => {
21
+ reads += 1;
22
+ return "sk-test";
23
+ },
24
+ });
25
+ expect(code).toBe(0);
26
+ expect(reads).toBe(0);
27
+ } finally {
28
+ rmSync(dir, { recursive: true, force: true });
29
+ }
30
+ });
31
+
32
+ test("writes each gap into .env.local and hydrates process.env", async () => {
33
+ const dir = mkdtempSync(join(tmpdir(), "ask-vault-"));
34
+ const prev = process.env.OPENROUTER_API_KEY;
35
+ try {
36
+ delete process.env.OPENROUTER_API_KEY;
37
+ const prompts: string[] = [];
38
+ const code = await maybeAskVaultGaps({
39
+ cwd: dir,
40
+ stdinIsTTY: true,
41
+ gapsFn: async () => [
42
+ { name: "OPENROUTER_API_KEY", description: "OpenRouter API key" },
43
+ { name: "OTHER_SECRET" },
44
+ ],
45
+ readSecret: async (prompt) => {
46
+ prompts.push(prompt);
47
+ return prompt.includes("OPENROUTER") ? "sk-or-v1-test" : "other-value";
48
+ },
49
+ });
50
+ expect(code).toBe(0);
51
+ expect(prompts).toHaveLength(2);
52
+ // `delete process.env.OPENROUTER_API_KEY` narrows that property to
53
+ // `undefined` for the rest of the block — widen before asserting.
54
+ expect(process.env.OPENROUTER_API_KEY as string | undefined).toBe("sk-or-v1-test");
55
+ expect(process.env.OTHER_SECRET as string | undefined).toBe("other-value");
56
+ const env = readFileSync(join(dir, ".env.local"), "utf8");
57
+ expect(env).toContain("OPENROUTER_API_KEY=sk-or-v1-test");
58
+ expect(env).toContain("OTHER_SECRET=other-value");
59
+ } finally {
60
+ if (prev === undefined) delete process.env.OPENROUTER_API_KEY;
61
+ else process.env.OPENROUTER_API_KEY = prev;
62
+ delete process.env.OTHER_SECRET;
63
+ rmSync(dir, { recursive: true, force: true });
64
+ }
65
+ });
66
+
67
+ test("empty value leaves a gap and returns 1", async () => {
68
+ const dir = mkdtempSync(join(tmpdir(), "ask-vault-"));
69
+ try {
70
+ const logs: string[] = [];
71
+ const code = await maybeAskVaultGaps({
72
+ cwd: dir,
73
+ stdinIsTTY: true,
74
+ write: (t) => logs.push(t),
75
+ gapsFn: async () => [{ name: "OPENROUTER_API_KEY" }],
76
+ readSecret: async () => "",
77
+ });
78
+ expect(code).toBe(1);
79
+ expect(logs.some((l) => l.includes("missing secret"))).toBe(true);
80
+ } finally {
81
+ rmSync(dir, { recursive: true, force: true });
82
+ }
83
+ });
84
+ });
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Interactive fill for Vault boot gaps during `oke dev`.
3
+ *
4
+ * Probes the same gap set app boot would throw (`allowDevFallbacks` on for
5
+ * `dev`), then prompts one-by-one and persists into `.env.local`.
6
+ */
7
+
8
+ import { resolve } from "node:path";
9
+ import { resolveDriverId } from "../config/index.ts";
10
+ import { VAULT_DEFAULTS } from "../config/driver-defaults.ts";
11
+ import { resolveAppEntryForPluginTables } from "../elements/store/load-plugin-tables.ts";
12
+ import { buildVaultBootChain, normalizeVaultDriverId } from "../elements/vault/boot-chain.ts";
13
+ import { createVaultRuntime, VaultBootError, type VaultGap } from "../elements/vault/runtime.ts";
14
+ import { requiredEnvRegistry, secretRegistry } from "../kernel/element-registries.ts";
15
+ import { formatCliChrome } from "../term.ts";
16
+ import { loadOkeConfig } from "./load-config.ts";
17
+ import { openEnvStore } from "./vault-cmd.ts";
18
+ import { promptHidden } from "./vault-secure-input.ts";
19
+
20
+ /** Options for {@link maybeAskVaultGaps}. */
21
+ export interface AskVaultGapsOptions {
22
+ readonly cwd: string;
23
+ /** App entry override (relative or absolute). */
24
+ readonly entry?: string;
25
+ readonly write?: (text: string) => void;
26
+ readonly stdinIsTTY?: boolean;
27
+ /** Skip prompt (tests / non-interactive). */
28
+ readonly skip?: boolean;
29
+ /**
30
+ * Injectable gap probe (tests). Default: import entry + vault boot.
31
+ */
32
+ readonly gapsFn?: () => Promise<readonly VaultGap[]>;
33
+ /**
34
+ * Injectable secret reader (tests). Default: {@link promptHidden}.
35
+ */
36
+ readonly readSecret?: (prompt: string) => Promise<string>;
37
+ /**
38
+ * Env file relative to cwd (default `.env.local`).
39
+ */
40
+ readonly envFile?: string;
41
+ }
42
+
43
+ /**
44
+ * Probe Vault contracts declared by the app entry and return boot gaps.
45
+ *
46
+ * @param cwd - Project root
47
+ * @param entry - Optional entry override
48
+ */
49
+ export async function probeVaultGaps(cwd: string, entry?: string): Promise<readonly VaultGap[]> {
50
+ const prevSecrets = secretRegistry.slice();
51
+ const prevRequired = requiredEnvRegistry.slice();
52
+ secretRegistry.length = 0;
53
+ requiredEnvRegistry.length = 0;
54
+ try {
55
+ const entryAbs = await resolveAppEntryForPluginTables(cwd, entry);
56
+ if (!entryAbs) return [];
57
+ await import(entryAbs);
58
+ const secrets = secretRegistry.slice();
59
+ const requiredEnv = requiredEnvRegistry.slice();
60
+ if (secrets.length === 0 && requiredEnv.length === 0) return [];
61
+
62
+ const loaded = await loadOkeConfig(cwd).catch(() => null);
63
+ const configEnv = "dev" as const;
64
+ const driverId = normalizeVaultDriverId(
65
+ resolveDriverId(loaded?.config?.drivers?.vault, configEnv, VAULT_DEFAULTS) ?? "env",
66
+ );
67
+ const chain = buildVaultBootChain({
68
+ driverId,
69
+ env: configEnv,
70
+ cwd,
71
+ seed: {},
72
+ });
73
+ const vault = createVaultRuntime({
74
+ secrets,
75
+ requiredEnv,
76
+ chain,
77
+ allowDevFallbacks: true,
78
+ });
79
+ try {
80
+ await vault.boot();
81
+ return [];
82
+ } catch (err) {
83
+ if (err instanceof VaultBootError) return err.gaps;
84
+ throw err;
85
+ }
86
+ } finally {
87
+ secretRegistry.length = 0;
88
+ secretRegistry.push(...prevSecrets);
89
+ requiredEnvRegistry.length = 0;
90
+ requiredEnvRegistry.push(...prevRequired);
91
+ }
92
+ }
93
+
94
+ /**
95
+ * After compose hydrate (and usually schema push), fill Vault boot gaps
96
+ * one-by-one into `.env.local`. Skips when non-TTY or no gaps.
97
+ *
98
+ * @param options - Project / injectables
99
+ * @returns `0` when ready to continue, `1` when aborted (still missing)
100
+ */
101
+ export async function maybeAskVaultGaps(options: AskVaultGapsOptions): Promise<number> {
102
+ if (options.skip) return 0;
103
+ const tty = options.stdinIsTTY ?? Boolean(process.stdin.isTTY);
104
+ if (!tty) return 0;
105
+
106
+ const cwd = options.cwd;
107
+ const write = options.write ?? ((t) => process.stdout.write(t));
108
+ const chromeWrite = (t: string) => write(formatCliChrome(t));
109
+
110
+ const gaps = options.gapsFn ? await options.gapsFn() : await probeVaultGaps(cwd, options.entry);
111
+ if (gaps.length === 0) return 0;
112
+
113
+ chromeWrite(
114
+ gaps.length === 1
115
+ ? "oke vault: 1 missing secret — enter a value (stored in .env.local)\n"
116
+ : `oke vault: ${gaps.length} missing secrets — enter each value (stored in .env.local)\n`,
117
+ );
118
+
119
+ const envPath = resolve(cwd, options.envFile ?? ".env.local");
120
+ const store = await openEnvStore(envPath);
121
+ const read =
122
+ options.readSecret ?? ((prompt: string) => promptHidden(prompt, { write: chromeWrite }));
123
+
124
+ const remaining: VaultGap[] = [];
125
+ for (const gap of gaps) {
126
+ const label = gap.description ? `${gap.name} (${gap.description})` : gap.name;
127
+ const value = (await read(`Enter value for ${label}: `)).trim();
128
+ if (value.length === 0) {
129
+ remaining.push(gap);
130
+ chromeWrite(`oke vault: skipped ${gap.name} (empty)\n`);
131
+ continue;
132
+ }
133
+ store.set(gap.name, value);
134
+ process.env[gap.name] = value;
135
+ chromeWrite(`oke vault: set ${gap.name}\n`);
136
+ }
137
+ await store.save?.();
138
+
139
+ if (remaining.length > 0) {
140
+ const err = new VaultBootError(remaining);
141
+ chromeWrite(`${err.message}\n`);
142
+ chromeWrite("oke vault: set the missing names, then re-run `oke dev`\n");
143
+ return 1;
144
+ }
145
+ return 0;
146
+ }
package/src/cli/build.ts CHANGED
@@ -44,7 +44,7 @@ async function defaultSyncAdoptBarrel(rootDir: string): Promise<readonly string[
44
44
  }
45
45
 
46
46
  /**
47
- * Build a deployable bundle. Edge target aims at the &lt;16 kB kernel budget.
47
+ * Build a deployable bundle. Edge target aims at the &lt;17 kB kernel budget.
48
48
  *
49
49
  * @param options - Target / entry
50
50
  */
@@ -109,7 +109,7 @@ export async function buildCli(args: readonly string[]): Promise<number> {
109
109
  else if (a === "--help" || a === "-h") {
110
110
  console.log(`oke build [--target|-t bun|node|edge] [--entry|-e src/app.ts]
111
111
 
112
- Tree-shaken bundle. --target edge aims at the <16 kB kernel budget.
112
+ Tree-shaken bundle. --target edge aims at the <17 kB kernel budget.
113
113
  `);
114
114
  return 0;
115
115
  }
@@ -35,12 +35,37 @@ describe("oke client add", () => {
35
35
  expect(src).toContain("export {}");
36
36
  });
37
37
 
38
- test("writes a compiling .d.ts", async () => {
38
+ test("emitAmbient includes live/stream stamps", () => {
39
+ const src = emitAmbient({
40
+ routes: {
41
+ orders: {
42
+ events: {
43
+ in: "{ orderId: string }",
44
+ out: "{ status: string }",
45
+ errors: {},
46
+ method: "GET",
47
+ path: "/orders/:orderId/events",
48
+ live: "order-status",
49
+ stream: true,
50
+ matchKey: ["orderId"],
51
+ },
52
+ },
53
+ },
54
+ });
55
+ expect(src).toContain('live: "order-status"');
56
+ expect(src).toContain("stream: true");
57
+ expect(src).toContain('matchKey: ["orderId"]');
58
+ });
59
+
60
+ test("writes ambient + routes modules and a compiling .d.ts", async () => {
39
61
  const dir = await mkdtemp(join(tmpdir(), "oke-client-add-"));
40
62
  const out = join(dir, "oke-client.d.ts");
41
63
 
42
64
  const result = await clientAdd({ descriptor: fixture, out });
43
65
  expect(result.out).toBe(out);
66
+ expect(result.routesOut).toContain("oke-client.routes.ts");
67
+ expect(result.routesSource).toContain("export const routes");
68
+ expect(result.routesSource).toContain('"/bookings"');
44
69
  expect(result.source).toContain("FlightFull");
45
70
 
46
71
  // Ambient-only project — proves the .d.ts itself is valid TypeScript.
@@ -1,8 +1,9 @@
1
1
  /**
2
2
  * `oke client add <url>` — ambient client types for a separate frontend repo.
3
3
  *
4
- * Fetches `GET {url}/_oke/client.json` and writes a compiling `.d.ts` that
5
- * augments `okengine/client`'s {@link Register} interface.
4
+ * Fetches `GET {url}/_oke/client.json` and writes:
5
+ * - `oke-client.d.ts` Register augmentation
6
+ * - `oke-client.routes.ts` — value `$routes` for REST / live / stream wire
6
7
  */
7
8
 
8
9
  import type { ClientDescriptor, ClientFetch } from "../client/types.ts";
@@ -11,24 +12,30 @@ import type { ClientDescriptor, ClientFetch } from "../client/types.ts";
11
12
  export interface ClientAddOptions {
12
13
  /** App base URL (required unless `descriptor` is provided). */
13
14
  readonly url?: string;
14
- /** Output path (default: `oke-client.d.ts`). */
15
+ /** Output path for ambient types (default: `oke-client.d.ts`). */
15
16
  readonly out?: string;
16
17
  /** Override fetch (tests). */
17
18
  readonly fetch?: ClientFetch;
18
19
  /** Inject a descriptor instead of fetching (tests). */
19
20
  readonly descriptor?: ClientDescriptor;
21
+ /** Skip writing `oke-client.routes.ts` (tests). */
22
+ readonly skipRoutes?: boolean;
20
23
  }
21
24
 
22
25
  /** Result of a successful {@link clientAdd}. */
23
26
  export interface ClientAddResult {
24
- /** Absolute or relative path written. */
27
+ /** Absolute or relative path written for ambient types. */
25
28
  readonly out: string;
26
29
  /** Emitted TypeScript declaration source. */
27
30
  readonly source: string;
31
+ /** Routes module path when written. */
32
+ readonly routesOut?: string;
33
+ /** Routes module source when written. */
34
+ readonly routesSource?: string;
28
35
  }
29
36
 
30
37
  /**
31
- * Fetch (or accept) a client descriptor and write an ambient declaration.
38
+ * Fetch (or accept) a client descriptor and write ambient + routes modules.
32
39
  *
33
40
  * @param options - URL / out / test overrides
34
41
  */
@@ -37,7 +44,14 @@ export async function clientAdd(options: ClientAddOptions): Promise<ClientAddRes
37
44
  const descriptor = options.descriptor ?? (await fetchDescriptor(options.url, options.fetch));
38
45
  const source = emitAmbient(descriptor);
39
46
  await Bun.write(out, source);
40
- return { out, source };
47
+ let routesOut: string | undefined;
48
+ let routesSource: string | undefined;
49
+ if (!options.skipRoutes) {
50
+ routesOut = routesPathFor(out);
51
+ routesSource = emitRoutes(descriptor);
52
+ await Bun.write(routesOut, routesSource);
53
+ }
54
+ return { out, source, routesOut, routesSource };
41
55
  }
42
56
 
43
57
  /**
@@ -65,6 +79,7 @@ export async function clientAddCli(args: readonly string[]): Promise<number> {
65
79
  try {
66
80
  const result = await clientAdd({ url, out });
67
81
  console.log(`Wrote ${result.out}`);
82
+ if (result.routesOut) console.log(`Wrote ${result.routesOut}`);
68
83
  return 0;
69
84
  } catch (err) {
70
85
  console.error(err instanceof Error ? err.message : String(err));
@@ -85,27 +100,7 @@ export function emitAmbient(descriptor: ClientDescriptor): string {
85
100
  : units
86
101
  .map(([unit, flows]) => {
87
102
  const flowLines = Object.entries(flows)
88
- .map(([flow, c]) => {
89
- const errors = c.errors
90
- ? Object.entries(c.errors)
91
- .map(([code, ty]) => ` ${JSON.stringify(code)}: ${ty}`)
92
- .join(";\n")
93
- : "";
94
- const errorBlock = errors
95
- ? ` errors: {\n${errors};\n };`
96
- : " errors: {};";
97
- return [
98
- ` ${JSON.stringify(flow)}: {`,
99
- ` in: ${c.in ?? "unknown"};`,
100
- ` out: ${c.out ?? "unknown"};`,
101
- errorBlock,
102
- c.method ? ` method: ${JSON.stringify(c.method)};` : undefined,
103
- c.path ? ` path: ${JSON.stringify(c.path)};` : undefined,
104
- ` }`,
105
- ]
106
- .filter((line): line is string => line !== undefined)
107
- .join("\n");
108
- })
103
+ .map(([flow, c]) => emitFlowContract(flow, c, "ambient"))
109
104
  .join(";\n");
110
105
  return ` ${JSON.stringify(unit)}: {\n${flowLines};\n }`;
111
106
  })
@@ -115,6 +110,7 @@ export function emitAmbient(descriptor: ClientDescriptor): string {
115
110
  /**
116
111
  * Generated by \`oke client add\` — do not edit by hand.
117
112
  * Ambient types for \`createClient(url)\` without importing App.
113
+ * Pair with \`oke-client.routes.ts\`: createClient(url, { $routes: routes }).
118
114
  */
119
115
  declare module "okengine/client" {
120
116
  interface Register {
@@ -130,6 +126,89 @@ export {};
130
126
  `;
131
127
  }
132
128
 
129
+ /**
130
+ * Emit a value `$routes` module for wire REST / live / stream.
131
+ *
132
+ * @param descriptor - Client descriptor
133
+ */
134
+ export function emitRoutes(descriptor: ClientDescriptor): string {
135
+ const units = Object.entries(descriptor.routes);
136
+ const body =
137
+ units.length === 0
138
+ ? " // no HTTP flows"
139
+ : units
140
+ .map(([unit, flows]) => {
141
+ const flowLines = Object.entries(flows)
142
+ .map(([flow, c]) => emitFlowContract(flow, c, "value"))
143
+ .join(",\n");
144
+ return ` ${JSON.stringify(unit)}: {\n${flowLines},\n }`;
145
+ })
146
+ .join(",\n");
147
+
148
+ return `/* eslint-disable */
149
+ /**
150
+ * Generated by \`oke client add\` — do not edit by hand.
151
+ * Runtime route stamps for createClient(url, { $routes: routes }).
152
+ */
153
+ export const routes = {
154
+ ${body},
155
+ } as const;
156
+
157
+ export default routes;
158
+ `;
159
+ }
160
+
161
+ function emitFlowContract(
162
+ flow: string,
163
+ c: ClientDescriptor["routes"][string][string],
164
+ mode: "ambient" | "value",
165
+ ): string {
166
+ if (mode === "value") {
167
+ const fields = [
168
+ c.method !== undefined ? ` method: ${JSON.stringify(c.method)}` : undefined,
169
+ c.path !== undefined ? ` path: ${JSON.stringify(c.path)}` : undefined,
170
+ c.live !== undefined ? ` live: ${JSON.stringify(c.live)}` : undefined,
171
+ c.stream === true ? ` stream: true as const` : undefined,
172
+ c.matchKey !== undefined ? ` matchKey: ${JSON.stringify(c.matchKey)} as const` : undefined,
173
+ c.gates !== undefined && c.gates.length > 0
174
+ ? ` gates: ${JSON.stringify(c.gates)} as const`
175
+ : undefined,
176
+ ].filter((line): line is string => line !== undefined);
177
+ if (fields.length === 0) return ` ${JSON.stringify(flow)}: {}`;
178
+ return ` ${JSON.stringify(flow)}: {\n${fields.join(",\n")},\n }`;
179
+ }
180
+
181
+ const errors = c.errors
182
+ ? Object.entries(c.errors)
183
+ .map(([code, ty]) => ` ${JSON.stringify(code)}: ${ty}`)
184
+ .join(";\n")
185
+ : "";
186
+ const errorBlock = errors
187
+ ? ` errors: {\n${errors};\n };`
188
+ : " errors: {};";
189
+ return [
190
+ ` ${JSON.stringify(flow)}: {`,
191
+ ` in: ${c.in ?? "unknown"};`,
192
+ ` out: ${c.out ?? "unknown"};`,
193
+ errorBlock,
194
+ c.method ? ` method: ${JSON.stringify(c.method)};` : undefined,
195
+ c.path ? ` path: ${JSON.stringify(c.path)};` : undefined,
196
+ c.live ? ` live: ${JSON.stringify(c.live)};` : undefined,
197
+ c.stream === true ? ` stream: true;` : undefined,
198
+ c.matchKey ? ` matchKey: ${JSON.stringify(c.matchKey)};` : undefined,
199
+ c.gates && c.gates.length > 0 ? ` gates: ${JSON.stringify(c.gates)};` : undefined,
200
+ ` }`,
201
+ ]
202
+ .filter((line): line is string => line !== undefined)
203
+ .join("\n");
204
+ }
205
+
206
+ function routesPathFor(dtsOut: string): string {
207
+ if (dtsOut.endsWith(".d.ts")) return `${dtsOut.slice(0, -5)}.routes.ts`;
208
+ if (dtsOut.endsWith(".ts")) return dtsOut.replace(/\.ts$/, ".routes.ts");
209
+ return `${dtsOut}.routes.ts`;
210
+ }
211
+
133
212
  async function fetchDescriptor(
134
213
  url: string | undefined,
135
214
  fetchFn: ClientFetch = globalThis.fetch.bind(globalThis),
@@ -48,7 +48,7 @@ const OKID_PROMPT_ALLOW = [
48
48
  // Minified zod-core inside the vendored Console bundle registers string
49
49
  // format validators whose names collide with peer library names — vendor
50
50
  // identifiers, not authored comparisons. Hash changes on Console rebuilds.
51
- "src/console/ui-next/dist/assets/index-DSEpMBPY.js:",
51
+ "src/console/ui-next/dist/",
52
52
  ];
53
53
 
54
54
  /**
@@ -329,6 +329,8 @@ export async function runSeed(options: SeedOptions = {}): Promise<number> {
329
329
  : await bootSeedFx(cwd, env, options.entry, loaded?.config);
330
330
  stop = session.stop;
331
331
  await executeSeedDef(def, env, session.fx, write);
332
+ const { markProjectSeeded } = await import("./project-state.ts");
333
+ await markProjectSeeded(cwd, { seed: identity.name });
332
334
  write("oke db seed: ok\n");
333
335
  return finish(EXIT_OK, "oke db seed: ok");
334
336
  } catch (err) {