okengine 0.18.5 → 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 (510) 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/llms-txt.mdx +1 -1
  5. package/site/content/docs/ai/meta.json +1 -1
  6. package/site/content/docs/ai/skills.mdx +4 -1
  7. package/site/content/docs/ai/try-it.mdx +58 -0
  8. package/site/content/docs/client/auth.mdx +208 -0
  9. package/site/content/docs/client/calling.mdx +451 -0
  10. package/site/content/docs/client/index.mdx +209 -0
  11. package/site/content/docs/client/live.mdx +234 -0
  12. package/site/content/docs/client/meta.json +5 -0
  13. package/site/content/docs/client/react.mdx +249 -0
  14. package/site/content/docs/elements/ai/agents.mdx +232 -0
  15. package/site/content/docs/elements/ai/index.mdx +341 -0
  16. package/site/content/docs/elements/ai/mcp.mdx +275 -0
  17. package/site/content/docs/elements/ai/meta.json +5 -0
  18. package/site/content/docs/elements/ai/models.mdx +283 -0
  19. package/site/content/docs/elements/ai/prompts.mdx +256 -0
  20. package/site/content/docs/elements/channel/email.mdx +266 -0
  21. package/site/content/docs/elements/channel/index.mdx +344 -0
  22. package/site/content/docs/elements/channel/meta.json +5 -0
  23. package/site/content/docs/elements/channel/push.mdx +218 -0
  24. package/site/content/docs/elements/channel/receipts.mdx +206 -0
  25. package/site/content/docs/elements/channel/sms.mdx +264 -0
  26. package/site/content/docs/elements/channel/whatsapp.mdx +220 -0
  27. package/site/content/docs/elements/clock/index.mdx +300 -0
  28. package/site/content/docs/elements/clock/meta.json +5 -0
  29. package/site/content/docs/elements/clock/schedules.mdx +508 -0
  30. package/site/content/docs/elements/clock/sleep.mdx +445 -0
  31. package/site/content/docs/elements/flow/consumers.mdx +707 -0
  32. package/site/content/docs/elements/flow/http.mdx +1080 -0
  33. package/site/content/docs/elements/flow/index.mdx +618 -0
  34. package/site/content/docs/elements/flow/meta.json +5 -0
  35. package/site/content/docs/elements/flow/routing.mdx +559 -0
  36. package/site/content/docs/elements/flow/workflows.mdx +640 -0
  37. package/site/content/docs/elements/gate/auth.mdx +371 -0
  38. package/site/content/docs/elements/gate/authorization.mdx +298 -0
  39. package/site/content/docs/elements/gate/index.mdx +418 -0
  40. package/site/content/docs/elements/gate/meta.json +5 -0
  41. package/site/content/docs/elements/gate/rate-limits.mdx +365 -0
  42. package/site/content/docs/elements/gate/rls.mdx +303 -0
  43. package/site/content/docs/elements/gate/tenancy.mdx +372 -0
  44. package/site/content/docs/elements/index.mdx +20 -10
  45. package/site/content/docs/elements/signal/broadcast.mdx +517 -0
  46. package/site/content/docs/elements/signal/index.mdx +352 -0
  47. package/site/content/docs/elements/signal/live.mdx +590 -0
  48. package/site/content/docs/elements/signal/meta.json +5 -0
  49. package/site/content/docs/elements/signal/once.mdx +596 -0
  50. package/site/content/docs/elements/store/files.mdx +659 -0
  51. package/site/content/docs/elements/store/index.mdx +310 -0
  52. package/site/content/docs/elements/store/kv.mdx +629 -0
  53. package/site/content/docs/elements/store/meta.json +5 -0
  54. package/site/content/docs/elements/store/search.mdx +946 -0
  55. package/site/content/docs/elements/store/sql.mdx +937 -0
  56. package/site/content/docs/elements/vault/config.mdx +256 -0
  57. package/site/content/docs/elements/vault/index.mdx +356 -0
  58. package/site/content/docs/elements/vault/meta.json +5 -0
  59. package/site/content/docs/elements/vault/rotation.mdx +273 -0
  60. package/site/content/docs/elements/vault/secrets.mdx +285 -0
  61. package/site/content/docs/index.mdx +63 -36
  62. package/site/content/docs/meta.json +8 -7
  63. package/site/content/docs/plugins/cors.mdx +2 -1
  64. package/site/content/docs/plugins/csrf.mdx +4 -1
  65. package/site/content/docs/plugins/headers.mdx +2 -1
  66. package/site/content/docs/plugins/ip-allowlist.mdx +2 -1
  67. package/site/content/docs/plugins/magic-link.mdx +6 -0
  68. package/site/content/docs/plugins/maintenance-mode.mdx +2 -1
  69. package/site/content/docs/plugins/oauth.mdx +1 -1
  70. package/site/content/docs/plugins/otp.mdx +12 -1
  71. package/site/content/docs/plugins/passkey.mdx +39 -15
  72. package/site/content/docs/plugins/two-factor.mdx +91 -34
  73. package/site/content/docs/plugins/username.mdx +1 -1
  74. package/site/content/docs/recipes/caddy.mdx +3 -3
  75. package/site/content/docs/recipes/index.mdx +18 -28
  76. package/site/content/docs/recipes/mailpit.mdx +1 -1
  77. package/site/content/docs/recipes/meilisearch.mdx +3 -3
  78. package/site/content/docs/recipes/meta.json +1 -4
  79. package/site/content/docs/recipes/nginx.mdx +2 -2
  80. package/site/content/docs/recipes/openrouter.mdx +283 -0
  81. package/site/content/docs/recipes/pgdog.mdx +3 -3
  82. package/site/content/docs/recipes/postgres.mdx +1 -2
  83. package/site/content/docs/recipes/rustfs.mdx +2 -2
  84. package/site/content/docs/recipes/traefik.mdx +3 -3
  85. package/site/content/docs/reference/cli.mdx +231 -0
  86. package/site/content/docs/reference/configuration.mdx +30 -10
  87. package/site/content/docs/reference/environment-variables.mdx +93 -20
  88. package/site/content/docs/reference/errors.mdx +132 -29
  89. package/site/content/docs/reference/fx.mdx +137 -73
  90. package/site/content/docs/reference/index.mdx +13 -21
  91. package/site/content/docs/reference/meta.json +4 -5
  92. package/site/content/docs/reference/okid.mdx +42 -17
  93. package/site/content/docs/reference/plugins.mdx +4 -3
  94. package/site/content/docs/reference/security.mdx +197 -0
  95. package/site/content/docs/understand/meta.json +5 -0
  96. package/site/content/docs/understand/the-anatomy.mdx +132 -0
  97. package/site/content/docs/understand/the-model.mdx +32 -0
  98. package/site/content/docs/understand/the-problem.mdx +74 -0
  99. package/site/content/docs/understand/the-vocabulary.mdx +26 -0
  100. package/src/auth/api-keys.ts +2 -1
  101. package/src/auth/bindings.ts +64 -16
  102. package/src/auth/gate-auth.test.ts +6 -1
  103. package/src/auth/identity.ts +152 -5
  104. package/src/auth/index.ts +29 -0
  105. package/src/auth/invites.ts +2 -1
  106. package/src/auth/method-context.ts +41 -0
  107. package/src/auth/oauth-as/crypto.ts +2 -1
  108. package/src/auth/oauth-as/stores.ts +2 -1
  109. package/src/auth/operator.ts +2 -1
  110. package/src/auth/sessions-jwt.test.ts +77 -0
  111. package/src/auth/sessions.ts +20 -4
  112. package/src/auth/tenants.ts +3 -2
  113. package/src/auth/two-factor-challenge.test.ts +61 -0
  114. package/src/auth/two-factor-challenge.ts +284 -0
  115. package/src/auth/verification.ts +5 -0
  116. package/src/bench/REPORT.md +49 -0
  117. package/src/bench/g03-signal-once.bench.ts +1 -1
  118. package/src/bench/g10-observability-contention.bench.ts +1 -1
  119. package/src/bench/g17-hybrid-search.bench.ts +572 -0
  120. package/src/bench/load-app.ts +2 -10
  121. package/src/cli/ai-setup/ai-setup.test.ts +331 -42
  122. package/src/cli/ai-setup/apply.ts +294 -52
  123. package/src/cli/ai-setup/catalog.ts +238 -1342
  124. package/src/cli/ai-setup/index.ts +14 -99
  125. package/src/cli/ai-setup/prompts.ts +60 -443
  126. package/src/cli/ask-seed.test.ts +96 -0
  127. package/src/cli/ask-seed.ts +82 -0
  128. package/src/cli/ask-vault-gaps.test.ts +84 -0
  129. package/src/cli/ask-vault-gaps.ts +146 -0
  130. package/src/cli/build.ts +2 -2
  131. package/src/cli/client-add.test.ts +26 -1
  132. package/src/cli/client-add.ts +106 -27
  133. package/src/cli/db-seed.ts +2 -0
  134. package/src/cli/db.ts +150 -11
  135. package/src/cli/dev.ts +119 -211
  136. package/src/cli/docker-clean.ts +2 -2
  137. package/src/cli/docker-cli.test.ts +1 -1
  138. package/src/cli/doctor-diff.ts +4 -2
  139. package/src/cli/doctor-pii.test.ts +1 -1
  140. package/src/cli/doctor.ts +14 -1
  141. package/src/cli/hero-meta.test.ts +4 -2
  142. package/src/cli/load-config.images.test.ts +8 -10
  143. package/src/cli/load-config.ts +1 -1
  144. package/src/cli/registry.ts +22 -10
  145. package/src/cli/replay.ts +3 -1
  146. package/src/cli/start.ts +1 -1
  147. package/src/cli/tui/keys.ts +2 -3
  148. package/src/client/auth/cookies.ts +74 -0
  149. package/src/client/auth/create-auth-client.ts +636 -0
  150. package/src/client/auth/denials.ts +99 -0
  151. package/src/client/auth/session.ts +283 -0
  152. package/src/client/auth.test.ts +251 -0
  153. package/src/client/auth.ts +39 -114
  154. package/src/client/create-with-session.ts +245 -0
  155. package/src/client/create.ts +51 -5
  156. package/src/client/index.ts +11 -1
  157. package/src/client/live.ts +11 -79
  158. package/src/client/notes-contract.test.ts +5 -10
  159. package/src/client/sse.ts +137 -0
  160. package/src/client/stream.ts +147 -0
  161. package/src/client/transport.test.ts +32 -0
  162. package/src/client/transport.ts +123 -26
  163. package/src/client/types.ts +118 -14
  164. package/src/client-react/index.ts +185 -24
  165. package/src/client-react/use-live-query.ts +13 -3
  166. package/src/compiler/aot.test.ts +7 -4
  167. package/src/compiler/effects-embed.test.ts +56 -0
  168. package/src/compiler/effects-fetch.test.ts +43 -0
  169. package/src/compiler/effects-infer.ts +58 -2
  170. package/src/compiler/extract.test.ts +257 -43
  171. package/src/compiler/extract.ts +566 -48
  172. package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -4
  173. package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +2 -8
  174. package/src/compiler/fixtures/skyport.expected.json +4 -4
  175. package/src/compiler/fixtures/triggers/five-triggers.ts +14 -10
  176. package/src/compiler/response.ts +2 -2
  177. package/src/compiler/search-writer-isolation.test.ts +40 -0
  178. package/src/config/index.ts +11 -0
  179. package/src/console/server/app.ts +17 -23
  180. package/src/console/server/bind.ts +4 -0
  181. package/src/console/server/console.test.ts +2 -2
  182. package/src/console/server/flows-invoke.test.ts +50 -34
  183. package/src/console/server/flows.ts +436 -255
  184. package/src/console/server/runs-ingest.test.ts +6 -3
  185. package/src/console/server/serve.ts +1 -1
  186. package/src/console/server/signals.test.ts +1 -5
  187. package/src/console/server/signals.ts +8 -6
  188. package/src/console/server/state.ts +6 -1
  189. package/src/console/server/store.ts +1 -1
  190. package/src/console/ui-next/dist/assets/FileExportIcon-Ck-5od4R.js +1 -0
  191. package/src/console/ui-next/dist/assets/MoreHorizontalCircle01Icon-gMNGsE37.js +1 -0
  192. package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +1 -0
  193. package/src/console/ui-next/dist/assets/UnavailableIcon-D9cvHVPr.js +1 -0
  194. package/src/console/ui-next/dist/assets/UserIcon-DaE2PB5_.js +1 -0
  195. package/src/console/ui-next/dist/assets/access-page-DFeymU07.js +4 -0
  196. package/src/console/ui-next/dist/assets/agent-disclosure-U1rdfblp.js +1 -0
  197. package/src/console/ui-next/dist/assets/cache-glyph-BeFJeqBG.js +1 -0
  198. package/src/console/ui-next/dist/assets/call-pii-button-CVAONPii.js +1 -0
  199. package/src/console/ui-next/dist/assets/collapsible-D2A6NJ-3.js +1 -0
  200. package/src/console/ui-next/dist/assets/copy-inline-button-CAYD18cr.js +1 -0
  201. package/src/console/ui-next/dist/assets/dagre.esm-B1_XeuLP.js +1 -0
  202. package/src/console/ui-next/dist/assets/detail-header-DVWNjWjg.js +1 -0
  203. package/src/console/ui-next/dist/assets/dropdown-menu-4h2LOVXM.js +1 -0
  204. package/src/console/ui-next/dist/assets/duration-tone-Cgk_h5ja.js +9 -0
  205. package/src/console/ui-next/dist/assets/element-icons-BI8cJgdh.js +1 -0
  206. package/src/console/ui-next/dist/assets/explorer-empty-CJs5A-wm.js +1 -0
  207. package/src/console/ui-next/dist/assets/flows-page-Dss7941e.js +1 -0
  208. package/src/console/ui-next/dist/assets/highlighted-json-MYZQtRnw.js +154 -0
  209. package/src/console/ui-next/dist/assets/http-method-Jrh39p7A.js +1 -0
  210. package/src/console/ui-next/dist/assets/index-D0zS5rKO.css +2 -0
  211. package/src/console/ui-next/dist/assets/index-DXP2dBIF.js +63 -0
  212. package/src/console/ui-next/dist/assets/observability-page-HvolXxTI.js +4 -0
  213. package/src/console/ui-next/dist/assets/react-dom-Ddte4I-Q.js +9 -0
  214. package/src/console/ui-next/dist/assets/replica-lag-CSh2dzrb.js +18 -0
  215. package/src/console/ui-next/dist/assets/request-meta-BatF8KrK.js +1 -0
  216. package/src/console/ui-next/dist/assets/shortcut-keys-3ILd8oGn.js +1 -0
  217. package/src/console/ui-next/dist/assets/{sql-BskegiFM.js → sql-BsFa4tDR.js} +1 -1
  218. package/src/console/ui-next/dist/assets/store-page-eiKiHnNe.js +41 -0
  219. package/src/console/ui-next/dist/assets/trace-detail-sheet-CZkMeKS-.js +2 -0
  220. package/src/console/ui-next/dist/assets/tree-expand-toggle-CW8y5A2h.js +55 -0
  221. package/src/console/ui-next/dist/assets/units-page-B_RWJrEO.js +1 -0
  222. package/src/console/ui-next/dist/assets/{use-vault-list-uk4WVboC.js → use-vault-list-CT4-gajj.js} +1 -1
  223. package/src/console/ui-next/dist/assets/vault-page-CWrg-A68.js +2 -0
  224. package/src/console/ui-next/dist/assets/xyflow-CSyC6ryz.css +1 -0
  225. package/src/console/ui-next/dist/assets/xyflow-yApv7D4e.js +7 -0
  226. package/src/console/ui-next/dist/index.html +6 -13
  227. package/src/console/ui-next/seed-invoke-host.ts +21 -18
  228. package/src/console/ui-next/src/client.ts +7 -2
  229. package/src/console/ui-next/src/features/flows/graph/element-map.ts +2 -0
  230. package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +12 -2
  231. package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +4 -0
  232. package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +8 -0
  233. package/src/console/ui-next/src/features/flows/traces/waterfall-bars.ts +4 -0
  234. package/src/console/ui-next/src/features/flows/traces/waterfall-tooltip.ts +9 -3
  235. package/src/console/ui-next/src/features/store/detail/reveal-cell.tsx +7 -11
  236. package/src/console/ui-next/src/features/store/detail/store-row-detail-sheet.tsx +2 -2
  237. package/src/console/ui-next/src/features/store/lib/fields-from-table.ts +2 -0
  238. package/src/console/ui-next/src/features/store/lib/grid-model.test.ts +25 -1
  239. package/src/console/ui-next/src/features/store/lib/grid-model.ts +36 -1
  240. package/src/console/ui-next/src/features/store/query/query-results.tsx +3 -3
  241. package/src/console/ui-next/src/features/units/detail/effects-summary.tsx +2 -0
  242. package/src/console/ui-next/src/features/units/lib/call-read-safe.ts +3 -1
  243. package/src/console/ui-next/src/features/units/lib/fields-from-schema.ts +6 -0
  244. package/src/docker/ai-model-status.test.ts +1 -12
  245. package/src/docker/ai-model-status.ts +10 -38
  246. package/src/docker/compose-up.test.ts +100 -0
  247. package/src/docker/compose-up.ts +292 -0
  248. package/src/docker/compose.ts +4 -14
  249. package/src/docker/derive.ts +9 -34
  250. package/src/docker/docker.test.ts +16 -261
  251. package/src/docker/images-config.test.ts +13 -25
  252. package/src/docker/index.ts +1 -24
  253. package/src/docker/recipes/index.ts +0 -23
  254. package/src/docker/recipes/pgdog.ts +6 -4
  255. package/src/docker/stack-id.test.ts +2 -2
  256. package/src/docker/stack-id.ts +0 -1
  257. package/src/docker/types.ts +2 -2
  258. package/src/drivers/ai-anthropic.ts +10 -0
  259. package/src/drivers/ai-openai-compatible.ts +34 -7
  260. package/src/drivers/ai-providers.test.ts +0 -107
  261. package/src/drivers/ai-stream.test.ts +0 -34
  262. package/src/drivers/ai-types.ts +17 -8
  263. package/src/drivers/channel-fcm.ts +6 -1
  264. package/src/drivers/channel-msegat.ts +6 -1
  265. package/src/drivers/channel-resend.ts +5 -1
  266. package/src/drivers/channel-smtp.ts +5 -1
  267. package/src/drivers/channel-sndr.ts +10 -1
  268. package/src/drivers/channel-taqnyat-mail.ts +5 -1
  269. package/src/drivers/channel-taqnyat-whatsapp.ts +6 -1
  270. package/src/drivers/channel-taqnyat.ts +6 -1
  271. package/src/drivers/channel-types.ts +10 -0
  272. package/src/drivers/channel-unifonic.ts +6 -1
  273. package/src/drivers/channel-wa-cloud.ts +6 -1
  274. package/src/drivers/channel-webpush.ts +6 -1
  275. package/src/drivers/external.ts +33 -0
  276. package/src/drivers/index.ts +0 -10
  277. package/src/drivers/meilisearch.ts +6 -0
  278. package/src/drivers/oauth-types.ts +4 -0
  279. package/src/drivers/postgres.test.ts +74 -3
  280. package/src/drivers/postgres.ts +175 -6
  281. package/src/drivers/signal-types.ts +5 -5
  282. package/src/drivers/types.ts +7 -0
  283. package/src/drivers/vault-types.ts +5 -0
  284. package/src/elements/ai/declare.ts +17 -4
  285. package/src/elements/ai/eval.ts +1 -1
  286. package/src/elements/ai/mcp-http.ts +1 -1
  287. package/src/elements/ai/pii.ts +1 -1
  288. package/src/elements/ai/providers.test.ts +289 -0
  289. package/src/elements/ai/providers.ts +169 -0
  290. package/src/elements/ai/runtime.ts +68 -5
  291. package/src/elements/ai/schema.ts +2 -2
  292. package/src/elements/ai.test.ts +7 -7
  293. package/src/elements/ai.ts +17 -1
  294. package/src/elements/channel/runtime.ts +105 -12
  295. package/src/elements/clock/cron-fields.test.ts +144 -0
  296. package/src/elements/clock/cron-fields.ts +185 -0
  297. package/src/elements/clock/declare.ts +247 -3
  298. package/src/elements/clock.ts +21 -1
  299. package/src/elements/index.ts +15 -0
  300. package/src/elements/signal/chaos-child.ts +1 -2
  301. package/src/elements/signal/declare.ts +65 -37
  302. package/src/elements/signal/delivery-modes.test.ts +11 -31
  303. package/src/elements/signal/dry-run-replay.test.ts +1 -7
  304. package/src/elements/signal/dry-run-write-isolation.test.ts +1 -7
  305. package/src/elements/signal/key-ordering.test.ts +6 -26
  306. package/src/elements/signal/lease-reclaim.test.ts +2 -6
  307. package/src/elements/signal/optional-emit.test.ts +6 -9
  308. package/src/elements/signal/order-lifecycle.test.ts +4 -17
  309. package/src/elements/signal/orphan-messages.test.ts +4 -15
  310. package/src/elements/signal/reconcile.test.ts +2 -2
  311. package/src/elements/signal/runtime.ts +1 -1
  312. package/src/elements/signal/schema-emit.test.ts +4 -8
  313. package/src/elements/signal.test.ts +24 -49
  314. package/src/elements/signal.ts +9 -2
  315. package/src/elements/store/domain-ddl.test.ts +1 -1
  316. package/src/elements/store/live-http.test.ts +9 -4
  317. package/src/elements/store/prepare-row.test.ts +123 -0
  318. package/src/elements/store/resource.ts +43 -12
  319. package/src/elements/store/schema-decl.ts +117 -0
  320. package/src/elements/store/search-backfill.ts +205 -0
  321. package/src/elements/store/search-bind.ts +66 -0
  322. package/src/elements/store/search-bm25.ts +78 -0
  323. package/src/elements/store/search-ddl.ts +156 -0
  324. package/src/elements/store/search-embed-flow.ts +141 -0
  325. package/src/elements/store/search-errors.ts +34 -0
  326. package/src/elements/store/search-fusion.ts +112 -0
  327. package/src/elements/store/search-lsh.ts +179 -0
  328. package/src/elements/store/search-runtime.ts +300 -0
  329. package/src/elements/store/search.test.ts +144 -0
  330. package/src/elements/store/sql-session.test.ts +1 -0
  331. package/src/elements/store/sql-session.ts +83 -3
  332. package/src/elements/store/table.ts +23 -2
  333. package/src/elements/store/upsert-app.test.ts +1 -3
  334. package/src/elements/store.ts +50 -0
  335. package/src/full.ts +4 -2
  336. package/src/http.ts +4 -1
  337. package/src/i18n/catalogs/ar.ts +14 -6
  338. package/src/i18n/catalogs/en.ts +14 -6
  339. package/src/index.ts +6 -1
  340. package/src/kernel/adopt-barrel-fresh.test.ts +7 -7
  341. package/src/kernel/adopt-routes.ts +9 -1
  342. package/src/kernel/app-auth.ts +5 -0
  343. package/src/kernel/app.ts +102 -9
  344. package/src/kernel/auto-cache.test.ts +6 -12
  345. package/src/kernel/auto-registry.test.ts +3 -3
  346. package/src/kernel/boot-bind/ai.test.ts +22 -19
  347. package/src/kernel/boot-bind/ai.ts +5 -43
  348. package/src/kernel/boot-bind/clock.ts +23 -5
  349. package/src/kernel/boot-bind/honor-config.test.ts +4 -4
  350. package/src/kernel/boot.test.ts +11 -6
  351. package/src/kernel/boot.ts +66 -16
  352. package/src/kernel/boundary-contract.ts +93 -0
  353. package/src/kernel/budget.test.ts +1 -1
  354. package/src/kernel/call.ts +89 -0
  355. package/src/kernel/capability.ts +6 -0
  356. package/src/kernel/client-descriptor.ts +123 -0
  357. package/src/kernel/clock-timezone.test.ts +80 -0
  358. package/src/kernel/correlation.test.ts +1 -1
  359. package/src/kernel/dry-run.ts +11 -8
  360. package/src/kernel/effects-stamping.test.ts +42 -9
  361. package/src/kernel/effects.test.ts +4 -2
  362. package/src/kernel/effects.ts +51 -9
  363. package/src/kernel/errors-channel.ts +17 -0
  364. package/src/kernel/errors-live-resume.ts +3 -2
  365. package/src/kernel/errors-tenant.ts +7 -4
  366. package/src/kernel/errors.registry-helpers.ts +96 -0
  367. package/src/kernel/errors.registry.test.ts +139 -25
  368. package/src/kernel/errors.ts +102 -23
  369. package/src/kernel/external-effects.test.ts +196 -0
  370. package/src/kernel/flow.test.ts +13 -4
  371. package/src/kernel/flow.ts +69 -71
  372. package/src/kernel/fx-ask-telemetry.test.ts +2 -2
  373. package/src/kernel/fx-dead-letters.test.ts +3 -3
  374. package/src/kernel/fx-fetch.ts +55 -0
  375. package/src/kernel/fx-live-stream.ts +2 -2
  376. package/src/kernel/fx-live.test.ts +8 -8
  377. package/src/kernel/fx.test.ts +17 -11
  378. package/src/kernel/fx.ts +180 -57
  379. package/src/kernel/horizontal-child.ts +1 -1
  380. package/src/kernel/http-query.test.ts +3 -6
  381. package/src/kernel/index.ts +13 -3
  382. package/src/kernel/instance-id.ts +1 -1
  383. package/src/kernel/instances.test.ts +40 -0
  384. package/src/kernel/instances.ts +47 -9
  385. package/src/kernel/live-http.test.ts +6 -7
  386. package/src/kernel/live-http.ts +6 -2
  387. package/src/kernel/live-resume.test.ts +1 -1
  388. package/src/kernel/mcp-tool.test.ts +3 -3
  389. package/src/kernel/on.ts +98 -4
  390. package/src/kernel/pipeline.test.ts +12 -15
  391. package/src/kernel/plugin-elements.test.ts +1 -1
  392. package/src/kernel/stamp-http.test.ts +3 -3
  393. package/src/kernel/triggers.ts +210 -95
  394. package/src/kernel-entry.ts +0 -1
  395. package/src/manifest/diff.ts +11 -1
  396. package/src/manifest/fixtures/skyport.excerpt.json +1 -1
  397. package/src/manifest/types.ts +46 -2
  398. package/src/mcp/docs-index.ts +3 -3
  399. package/src/mcp/docs-mcp.test.ts +2 -2
  400. package/src/mcp/docs-tools.ts +1 -1
  401. package/src/okid.test.ts +56 -0
  402. package/src/okid.ts +55 -11
  403. package/src/plugins/anonymous.ts +8 -4
  404. package/src/plugins/auth/shared.ts +27 -3
  405. package/src/plugins/auth-delivery.mailpit.integration.test.ts +1 -1
  406. package/src/plugins/auth-methods.security.test.ts +561 -23
  407. package/src/plugins/config-source.ts +1 -1
  408. package/src/plugins/csrf.test.ts +65 -0
  409. package/src/plugins/index.ts +2 -0
  410. package/src/plugins/magic-link.ts +36 -16
  411. package/src/plugins/oauth/shared.ts +3 -1
  412. package/src/plugins/oauth.ts +22 -14
  413. package/src/plugins/otp.ts +37 -21
  414. package/src/plugins/passkey-webauthn.ts +9 -6
  415. package/src/plugins/passkey.ts +98 -26
  416. package/src/plugins/pre-account-hijack.test.ts +223 -0
  417. package/src/plugins/two-factor.ts +466 -37
  418. package/src/plugins/username.ts +19 -7
  419. package/src/release/build-lib.ts +1 -0
  420. package/src/release/limits.ts +2 -2
  421. package/src/release/measure.ts +1 -1
  422. package/src/runs/collect.test.ts +0 -2
  423. package/src/runtime/json-code-block.test.ts +250 -20
  424. package/src/runtime/json-code-block.ts +1261 -41
  425. package/src/term.test.ts +1 -1
  426. package/src/test/create-test-app.test.ts +12 -12
  427. package/src/test/live-signals.test.ts +6 -6
  428. package/src/test/provisions.integration.test.ts +10 -14
  429. package/src/test/reset-element-registries.ts +1 -1
  430. package/src/test/tenant-isolation.test.ts +12 -6
  431. package/site/content/docs/deployment/docker-swarm.mdx +0 -164
  432. package/site/content/docs/deployment/docker.mdx +0 -227
  433. package/site/content/docs/deployment/index.mdx +0 -83
  434. package/site/content/docs/deployment/kubernetes.mdx +0 -176
  435. package/site/content/docs/deployment/meta.json +0 -5
  436. package/site/content/docs/deployment/reverse-proxy.mdx +0 -234
  437. package/site/content/docs/elements/ai.mdx +0 -385
  438. package/site/content/docs/elements/channel.mdx +0 -346
  439. package/site/content/docs/elements/clock.mdx +0 -244
  440. package/site/content/docs/elements/flow.mdx +0 -420
  441. package/site/content/docs/elements/gate.mdx +0 -436
  442. package/site/content/docs/elements/signal.mdx +0 -380
  443. package/site/content/docs/elements/store.mdx +0 -1099
  444. package/site/content/docs/elements/vault.mdx +0 -405
  445. package/site/content/docs/get-started/basic-usage.mdx +0 -173
  446. package/site/content/docs/get-started/index.mdx +0 -43
  447. package/site/content/docs/get-started/installation.mdx +0 -220
  448. package/site/content/docs/get-started/introduction.mdx +0 -144
  449. package/site/content/docs/get-started/meta.json +0 -13
  450. package/site/content/docs/get-started/project-structure.mdx +0 -925
  451. package/site/content/docs/get-started/testing.mdx +0 -328
  452. package/site/content/docs/get-started/why.mdx +0 -114
  453. package/site/content/docs/recipes/llama-cpp.mdx +0 -151
  454. package/site/content/docs/recipes/ollama.mdx +0 -142
  455. package/site/content/docs/recipes/sglang.mdx +0 -105
  456. package/site/content/docs/recipes/vllm.mdx +0 -106
  457. package/site/content/docs/reference/cli.md +0 -232
  458. package/site/content/docs/reference/client.mdx +0 -469
  459. package/site/content/docs/reference/security.md +0 -74
  460. package/src/cli/ai-setup/detect-ollama.ts +0 -213
  461. package/src/cli/ai-setup/recommend.test.ts +0 -225
  462. package/src/cli/ai-setup/recommend.ts +0 -225
  463. package/src/cli/dev-controls.test.ts +0 -122
  464. package/src/cli/dev-controls.ts +0 -164
  465. package/src/cli/tui/DevLive.tsx +0 -126
  466. package/src/console/ui-next/dist/assets/access-page-3-EFj-2G.js +0 -4
  467. package/src/console/ui-next/dist/assets/agent-disclosure-BP0Y0Sux.js +0 -1
  468. package/src/console/ui-next/dist/assets/cache-glyph-B5X-NM0-.js +0 -1
  469. package/src/console/ui-next/dist/assets/call-pii-button-ChAUiLo9.js +0 -1
  470. package/src/console/ui-next/dist/assets/collapsible-DGnOM2ph.js +0 -1
  471. package/src/console/ui-next/dist/assets/copy-inline-button-DBHhgHKP.js +0 -1
  472. package/src/console/ui-next/dist/assets/dagre.esm-ZwcdTuZZ.js +0 -1
  473. package/src/console/ui-next/dist/assets/detail-header-DhHM1iaZ.js +0 -1
  474. package/src/console/ui-next/dist/assets/dropdown-menu-_NjTEo5_.js +0 -1
  475. package/src/console/ui-next/dist/assets/duration-tone-sC3lGABz.js +0 -9
  476. package/src/console/ui-next/dist/assets/element-icons-BVXtRyd3.js +0 -1
  477. package/src/console/ui-next/dist/assets/explorer-empty-2uIhBu0_.js +0 -1
  478. package/src/console/ui-next/dist/assets/flows-page-cVFnA4HH.js +0 -1
  479. package/src/console/ui-next/dist/assets/highlighted-json-Awq7gYdu.js +0 -154
  480. package/src/console/ui-next/dist/assets/http-method-_UHM2ODJ.js +0 -1
  481. package/src/console/ui-next/dist/assets/index-CMIgUbD0.js +0 -66
  482. package/src/console/ui-next/dist/assets/index-Ck88Jmv8.css +0 -2
  483. package/src/console/ui-next/dist/assets/link-BX6Vqztd.js +0 -1
  484. package/src/console/ui-next/dist/assets/observability-page-CQ3p34ip.js +0 -4
  485. package/src/console/ui-next/dist/assets/preload-helper-oH4irX4C.js +0 -1
  486. package/src/console/ui-next/dist/assets/react-D8E3mtu1.js +0 -1
  487. package/src/console/ui-next/dist/assets/react-dom-Bph1y7z7.js +0 -9
  488. package/src/console/ui-next/dist/assets/replica-lag-DKRrbvdo.js +0 -18
  489. package/src/console/ui-next/dist/assets/request-meta-DV0ywz7t.js +0 -1
  490. package/src/console/ui-next/dist/assets/shortcut-JQIZlWfm.js +0 -1
  491. package/src/console/ui-next/dist/assets/shortcut-keys-DKxNTe_m.js +0 -1
  492. package/src/console/ui-next/dist/assets/skeleton-D-czQJT6.js +0 -1
  493. package/src/console/ui-next/dist/assets/store-page-02xOiqIK.js +0 -41
  494. package/src/console/ui-next/dist/assets/trace-detail-sheet-B09O8rA6.js +0 -2
  495. package/src/console/ui-next/dist/assets/tree-expand-toggle-BtyhmWb4.js +0 -55
  496. package/src/console/ui-next/dist/assets/units-page-l8FeKfnP.js +0 -1
  497. package/src/console/ui-next/dist/assets/useMutation-B8EO02Ej.js +0 -1
  498. package/src/console/ui-next/dist/assets/useRender-BE2A9BWC.js +0 -1
  499. package/src/console/ui-next/dist/assets/vault-page-CL-d_mLE.js +0 -2
  500. package/src/console/ui-next/dist/assets/xyflow-D7n4g6go.js +0 -7
  501. package/src/console/ui-next/dist/assets/xyflow-DZ0Ws1xk.css +0 -1
  502. package/src/docker/ollama-pull.ts +0 -232
  503. package/src/docker/recipes/llama-cpp.ts +0 -298
  504. package/src/docker/recipes/ollama.ts +0 -44
  505. package/src/docker/recipes/sglang.ts +0 -55
  506. package/src/docker/recipes/vllm.ts +0 -44
  507. package/src/drivers/ai-ollama-tools.integration.test.ts +0 -109
  508. package/src/drivers/ai-ollama.integration.test.ts +0 -184
  509. package/src/drivers/ai-ollama.ts +0 -389
  510. package/src/drivers/ollama.ts +0 -14
@@ -41,19 +41,7 @@ import {
41
41
  valkey,
42
42
  writeDerivedFiles,
43
43
  yugabyte,
44
- ensureOllamaModel,
45
- llamaCpp,
46
- LLAMA_CPP_IMAGE,
47
- LLAMA_CPP_MIN_SAFE_BUILD,
48
- OllamaPullError,
49
- OLLAMA_IMAGE,
50
- OLLAMA_MIN_SAFE_VERSION,
51
- sglang,
52
- SGLANG_IMAGE,
53
- vllm,
54
- VLLM_IMAGE,
55
44
  type ImageRecipe,
56
- type OllamaFetch,
57
45
  type ServiceSpec,
58
46
  } from "./index.ts";
59
47
 
@@ -370,12 +358,12 @@ describe("image recipes", () => {
370
358
  });
371
359
 
372
360
  test("pgdog matches the official image and waits on store-sql", () => {
373
- expect(recipeFor("ghcr.io/pgdogdev/pgdog:v0.1.53").id).toBe("pgdog");
361
+ expect(recipeFor("ghcr.io/pgdogdev/pgdog:v0.1.57").id).toBe("pgdog");
374
362
  expect(pgdog.match("ghcr.io/pgdogdev/pgdog:main")).toBe(true);
375
363
  const applied = pgdog.apply({
376
364
  role: "pgdog",
377
365
  serviceName: "pgdog",
378
- image: "ghcr.io/pgdogdev/pgdog:v0.1.53",
366
+ image: "ghcr.io/pgdogdev/pgdog:v0.1.57",
379
367
  port: 6432,
380
368
  hostPort: 6432,
381
369
  credentials: fixedCreds["store.sql"],
@@ -384,6 +372,8 @@ describe("image recipes", () => {
384
372
  expect(applied.volumes).toContain("./pgdog/pgdog.toml:/pgdog/pgdog.toml:ro");
385
373
  expect(applied.volumes).toContain("./pgdog/users.toml:/pgdog/users.toml:ro");
386
374
  expect(applied.healthcheck?.test.join(" ")).toContain("pg_isready");
375
+ expect(applied.healthcheck?.interval).toBe("2s");
376
+ expect(applied.healthcheck?.start_period).toBe("2s");
387
377
  });
388
378
 
389
379
  test("pgdog.toml + users.toml match upstream config shape", () => {
@@ -434,184 +424,6 @@ describe("image recipes", () => {
434
424
  expect(url).toBe("http://127.0.0.1:7700");
435
425
  });
436
426
 
437
- test("ollama matches the official image, serves on 11434, emits http URL", () => {
438
- expect(recipeFor(OLLAMA_IMAGE).id).toBe("ollama");
439
- expect(OLLAMA_IMAGE).not.toContain("latest");
440
- expect(OLLAMA_MIN_SAFE_VERSION).toBe("0.17.1");
441
- const spec: ServiceSpec = {
442
- role: "ai",
443
- serviceName: "ai",
444
- image: OLLAMA_IMAGE,
445
- port: 11434,
446
- hostPort: 11434,
447
- credentials: { user: "oke", password: "unused", database: "oke" },
448
- };
449
- const applied = recipeFor(spec.image).apply(spec);
450
- expect(applied.environment?.OKE_AI_MODEL).toBe("${OKE_AI_MODEL:-qwen3.5:9b}");
451
- expect(applied.environment?.OLLAMA_HOST).toBe("0.0.0.0:11434");
452
- expect(applied.publishBind).toBe("127.0.0.1");
453
- expect(applied.volumes).toContain("ai-data:/root/.ollama");
454
- expect(applied.healthcheck?.test.join(" ")).toContain("ollama list");
455
- // Pull is host-side via ensureOllamaModel — never a boot `ollama pull` CLI.
456
- expect(applied.command).toBeUndefined();
457
- expect(applied.entrypoint).toBeUndefined();
458
- const url = recipeFor(spec.image).url(spec, {
459
- host: "127.0.0.1",
460
- port: 11434,
461
- user: "oke",
462
- password: "unused",
463
- database: "oke",
464
- });
465
- expect(url).toBe("http://127.0.0.1:11434");
466
- });
467
-
468
- test("llama-cpp is the default local AI recipe — OpenAI /v1, loopback publish, pinned ≥ b8146", () => {
469
- expect(recipeFor(LLAMA_CPP_IMAGE).id).toBe("llama-cpp");
470
- expect(LLAMA_CPP_IMAGE).not.toContain("latest");
471
- const build = Number(/server-b(\d+)/.exec(LLAMA_CPP_IMAGE)?.[1]);
472
- expect(build).toBeGreaterThanOrEqual(LLAMA_CPP_MIN_SAFE_BUILD);
473
- const spec: ServiceSpec = {
474
- role: "ai",
475
- serviceName: "ai",
476
- image: LLAMA_CPP_IMAGE,
477
- port: 8080,
478
- hostPort: 8080,
479
- credentials: { user: "oke", password: "unused", database: "oke" },
480
- };
481
- const applied = llamaCpp.apply(spec);
482
- expect(applied.publishBind).toBe("127.0.0.1");
483
- // Never put docker-repo / models-preset / interpolated OKE_AI_MODEL in
484
- // service environment — router children recurse / OOM; Compose ${} would
485
- // also override env_file from an empty host shell.
486
- expect(applied.environment?.LLAMA_ARG_MODELS_PRESET).toBeUndefined();
487
- expect(applied.environment?.LLAMA_ARG_DOCKER_REPO).toBeUndefined();
488
- expect(applied.environment?.OKE_AI_MODEL).toBeUndefined();
489
- expect(applied.entrypoint).toEqual(["/usr/bin/python3", "/oke/llama-entrypoint.py"]);
490
- expect(applied.command).toBeUndefined();
491
- expect(applied.volumes?.some((v) => v.includes("../.oke/llama-entrypoint.py"))).toBe(true);
492
- expect(applied.extraPorts).toBeUndefined();
493
- expect(llamaCpp.url(spec, { host: "127.0.0.1", port: 8080, ...spec.credentials })).toBe(
494
- "http://127.0.0.1:8080/v1",
495
- );
496
- });
497
-
498
- test("vllm recipe is GPU-aware, OpenAI /v1, loopback publish, never latest", () => {
499
- expect(recipeFor(VLLM_IMAGE).id).toBe("vllm");
500
- expect(VLLM_IMAGE).not.toContain("latest");
501
- const spec: ServiceSpec = {
502
- role: "ai",
503
- serviceName: "ai",
504
- image: VLLM_IMAGE,
505
- port: 8000,
506
- hostPort: 8000,
507
- credentials: { user: "oke", password: "unused", database: "oke" },
508
- };
509
- const applied = vllm.apply(spec);
510
- expect(applied.publishBind).toBe("127.0.0.1");
511
- expect(applied.ipc).toBe("host");
512
- expect(JSON.stringify(applied.deploy)).toContain("nvidia");
513
- expect(vllm.url(spec, { host: "127.0.0.1", port: 8000, ...spec.credentials })).toBe(
514
- "http://127.0.0.1:8000/v1",
515
- );
516
- });
517
-
518
- test("sglang recipe is GPU-aware, OpenAI /v1, loopback publish, never latest", () => {
519
- expect(recipeFor(SGLANG_IMAGE).id).toBe("sglang");
520
- expect(SGLANG_IMAGE).not.toContain("latest");
521
- const spec: ServiceSpec = {
522
- role: "ai",
523
- serviceName: "ai",
524
- image: SGLANG_IMAGE,
525
- port: 30000,
526
- hostPort: 30000,
527
- credentials: { user: "oke", password: "unused", database: "oke" },
528
- };
529
- const applied = sglang.apply(spec);
530
- expect(applied.publishBind).toBe("127.0.0.1");
531
- expect(applied.ipc).toBe("host");
532
- expect(JSON.stringify(applied.deploy)).toContain("nvidia");
533
- expect(sglang.url(spec, { host: "127.0.0.1", port: 30000, ...spec.credentials })).toBe(
534
- "http://127.0.0.1:30000/v1",
535
- );
536
- });
537
-
538
- test("ensureOllamaModel POSTs /api/pull to the container base URL (not a host CLI)", async () => {
539
- const calls: { url: string; method: string; body?: string }[] = [];
540
- const fetchFn: OllamaFetch = async (input, init) => {
541
- const url = String(input);
542
- const method = (init?.method ?? "GET").toUpperCase();
543
- const body = typeof init?.body === "string" ? init.body : undefined;
544
- calls.push({ url, method, ...(body !== undefined ? { body } : {}) });
545
- if (url.endsWith("/api/tags") && method === "GET") {
546
- return new Response(JSON.stringify({ models: [] }), { status: 200 });
547
- }
548
- if (url.endsWith("/api/pull") && method === "POST") {
549
- expect(body).toContain('"model":"qwen3.5:9b"');
550
- expect(body).toContain('"stream":true');
551
- return new Response(`${JSON.stringify({ status: "success" })}\n`, { status: 200 });
552
- }
553
- return new Response("unexpected", { status: 500 });
554
- };
555
-
556
- await ensureOllamaModel({
557
- url: "http://127.0.0.1:11434",
558
- model: "qwen3.5:9b",
559
- fetch: fetchFn,
560
- readyTimeoutMs: 2_000,
561
- pullTimeoutMs: 5_000,
562
- });
563
-
564
- expect(
565
- calls.some((c) => c.url === "http://127.0.0.1:11434/api/tags" && c.method === "GET"),
566
- ).toBe(true);
567
- const pull = calls.find((c) => c.url === "http://127.0.0.1:11434/api/pull");
568
- expect(pull?.method).toBe("POST");
569
- expect(pull?.body).toBe(JSON.stringify({ model: "qwen3.5:9b", stream: true }));
570
- // No host-side `ollama` binary assumption — only HTTP to the given URL.
571
- expect(calls.every((c) => c.url.startsWith("http://127.0.0.1:11434/"))).toBe(true);
572
- });
573
-
574
- test("ensureOllamaModel skips pull when /api/tags already lists the model", async () => {
575
- const calls: string[] = [];
576
- const statuses: string[] = [];
577
- const fetchFn: OllamaFetch = async (input, init) => {
578
- const url = String(input);
579
- const method = (init?.method ?? "GET").toUpperCase();
580
- calls.push(`${method} ${url}`);
581
- if (url.endsWith("/api/tags")) {
582
- return new Response(JSON.stringify({ models: [{ name: "gemma4:e4b" }] }), {
583
- status: 200,
584
- });
585
- }
586
- return new Response("should not pull", { status: 500 });
587
- };
588
-
589
- await ensureOllamaModel({
590
- url: "http://127.0.0.1:23100",
591
- model: "gemma4:e4b",
592
- fetch: fetchFn,
593
- readyTimeoutMs: 2_000,
594
- onStatus: (line) => statuses.push(line),
595
- });
596
-
597
- expect(calls.some((c) => c.includes("/api/pull"))).toBe(false);
598
- expect(statuses.some((s) => /already has gemma4:e4b/.test(s))).toBe(true);
599
- });
600
-
601
- test("ensureOllamaModel fails loud when the container API never becomes ready", async () => {
602
- const fetchFn: OllamaFetch = async () => {
603
- throw new Error("connection refused");
604
- };
605
- await expect(
606
- ensureOllamaModel({
607
- url: "http://127.0.0.1:59999",
608
- model: "qwen3.5:9b",
609
- fetch: fetchFn,
610
- readyTimeoutMs: 800,
611
- }),
612
- ).rejects.toBeInstanceOf(OllamaPullError);
613
- });
614
-
615
427
  test("a new image recipe is ≤15 lines", async () => {
616
428
  const src = await Bun.file(`${import.meta.dir}/recipes/postgres.ts`).text();
617
429
  const exportLines = src
@@ -792,9 +604,8 @@ describe("deriveInfrastructure", () => {
792
604
  test("compose YAML spaces services and adds role comments", () => {
793
605
  const result = deriveInfrastructure({
794
606
  images: {
795
- ai: "ghcr.io/ggml-org/llama.cpp:server",
796
- "channel.email": "axllent/mailpit:v1.30.7",
797
- pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.53",
607
+ "channel.email": "axllent/mailpit:v1.31.1",
608
+ pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
798
609
  "store.sql": "postgres:16",
799
610
  },
800
611
  credentials: { "store.sql": fixedCreds["store.sql"] },
@@ -803,15 +614,14 @@ describe("deriveInfrastructure", () => {
803
614
  });
804
615
  const yml = result.files.find((f) => f.path === DOCKER_COMPOSE)!.content;
805
616
  expect(yml).toContain("# Generated by `oke docker`");
806
- expect(yml).toContain("# ai — local inference");
807
617
  expect(yml).toContain("# channel.email — Mailpit");
808
618
  expect(yml).toContain("# pgdog — connection pooler");
809
619
  expect(yml).toContain("# store.sql — Postgres");
810
620
  // Blank line between adjacent service blocks (comment → key → … → blank → comment).
811
- expect(yml).toMatch(/# ai —[^\n]+\n ai:\n[\s\S]+\n\n # channel\.email —/);
621
+ expect(yml).toMatch(/# channel\.email —[^\n]+\n channel-email:\n[\s\S]+\n\n # pgdog —/);
812
622
  expect(yml).toMatch(/\nnetworks:\n[\s\S]+\n\nservices:\n/);
813
623
  expect(serviceNamesFromComposeYaml(yml)).toEqual(
814
- new Set(["ai", "channel-email", "pgdog", "store-sql"]),
624
+ new Set(["channel-email", "pgdog", "store-sql"]),
815
625
  );
816
626
  });
817
627
 
@@ -916,7 +726,7 @@ describe("deriveInfrastructure", () => {
916
726
  const result = deriveInfrastructure({
917
727
  images: {
918
728
  "store.sql": "postgres:18-alpine",
919
- pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.53",
729
+ pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
920
730
  },
921
731
  credentials: { "store.sql": fixedCreds["store.sql"] },
922
732
  prod: true,
@@ -931,7 +741,7 @@ describe("deriveInfrastructure", () => {
931
741
  expect(result.stackEnv.OKE_STORE_SQL_URL).toContain(":5432/");
932
742
 
933
743
  const pgdogYml = result.files.find((f) => f.path === DOCKER_COMPOSE)!.content;
934
- expect(pgdogYml).toContain("ghcr.io/pgdogdev/pgdog:v0.1.53");
744
+ expect(pgdogYml).toContain("ghcr.io/pgdogdev/pgdog:v0.1.57");
935
745
  expect(pgdogYml).toContain("store-sql");
936
746
  expect(pgdogYml).toContain("service_healthy");
937
747
  expect(pgdogYml).not.toContain(fixedCreds["store.sql"].password);
@@ -1015,68 +825,13 @@ describe("deriveInfrastructure", () => {
1015
825
  expect(result.stackEnv.DATABASE_URL).toBeUndefined();
1016
826
  });
1017
827
 
1018
- test("ai ollama emits OKE_AI_URL, loopback publish, and never binds 0.0.0.0 on the host", () => {
1019
- const result = deriveInfrastructure({
1020
- images: { ai: OLLAMA_IMAGE },
1021
- app: "skyport",
1022
- });
1023
- const yml = result.files.find((f) => f.path === DOCKER_COMPOSE)!.content;
1024
- expect(yml).toContain(OLLAMA_IMAGE);
1025
- expect(yml).toContain("OKE_AI_MODEL");
1026
- expect(yml).toContain("qwen3.5:9b");
1027
- expect(yml).toContain("127.0.0.1:11434:11434");
1028
- expect(yml).not.toMatch(/ports:\s*\n\s*-\s*"?11434:11434"?/);
1029
- expect(result.stackEnv.OKE_AI_URL).toBe("http://127.0.0.1:11434");
1030
- const envText = formatStackEnv(result.stackEnv);
1031
- expect(envText).toContain("# ── ai — local inference");
1032
- expect(envText.match(/^OKE_AI_URL=/gm)?.length).toBe(1);
1033
- });
1034
-
1035
- test("ai llama-cpp (default) emits /v1 URL and loopback-only publish", () => {
1036
- const result = deriveInfrastructure({
1037
- images: { ai: LLAMA_CPP_IMAGE },
1038
- app: "skyport",
1039
- controls: { OKE_AI_MODEL: "gemma4:e4b-q4_K_M" },
1040
- });
1041
- const yml = result.files.find((f) => f.path === DOCKER_COMPOSE)!.content;
1042
- expect(yml).toContain(LLAMA_CPP_IMAGE);
1043
- expect(yml).toContain("127.0.0.1:8080:8080");
1044
- expect(yml).toContain("llama-entrypoint.py");
1045
- expect(yml).toContain("../.oke/llama-entrypoint.py");
1046
- expect(yml).toContain("/oke/llama-entrypoint.py");
1047
- expect(yml).not.toMatch(/ports:\s*\n\s*-\s*"?8080:8080"?/);
1048
- expect(result.stackEnv.OKE_AI_URL).toBe("http://127.0.0.1:8080/v1");
1049
- expect(result.stackEnv.OKE_AI_MODEL).toBe("gemma4:e4b-q4_K_M");
1050
- const entry = result.files.find((f) => f.path === "../.oke/llama-entrypoint.py")!.content;
1051
- expect(entry).toContain("Generated by oke");
1052
- expect(entry).toContain("llama download");
1053
- expect(entry).toContain("org.cncf.model.filepath");
1054
- expect(entry).toContain("CNCF / Hub registry pull");
1055
- expect(entry).toContain("llama-server");
1056
- expect(entry).toContain("--alias");
1057
- expect(yml).not.toContain("--models-preset");
1058
- });
1059
-
1060
- test("ai vllm and sglang emit loopback publish + GPU deploy", () => {
1061
- for (const [image, port, path] of [
1062
- [VLLM_IMAGE, 8000, DOCKER_COMPOSE],
1063
- [SGLANG_IMAGE, 30000, DOCKER_COMPOSE],
1064
- ] as const) {
1065
- const result = deriveInfrastructure({ images: { ai: image }, app: "skyport" });
1066
- const yml = result.files.find((f) => f.path === path)!.content;
1067
- expect(yml).toContain(`127.0.0.1:${port}:${port}`);
1068
- expect(yml).toContain("nvidia");
1069
- expect(result.stackEnv.OKE_AI_URL).toBe(`http://127.0.0.1:${port}/v1`);
1070
- }
1071
- });
1072
-
1073
828
  test("emits protocol-specific env keys plus optional control notes", () => {
1074
829
  const result = deriveInfrastructure({
1075
830
  images: {
1076
831
  "store.sql": "postgres:18-alpine",
1077
832
  "store.kv": "redis:8-alpine",
1078
- "store.files": "rustfs/rustfs:1.0.0-rc.2",
1079
- "channel.email": "axllent/mailpit:v1.30.7",
833
+ "store.files": "rustfs/rustfs:1.0.0-rc.5",
834
+ "channel.email": "axllent/mailpit:v1.31.1",
1080
835
  },
1081
836
  credentials: {
1082
837
  ...fixedCreds,
@@ -1119,8 +874,8 @@ describe("deriveInfrastructure", () => {
1119
874
  const n = Number.parseInt(id.slice(0, 4), 16) % 1000;
1120
875
  const result = deriveInfrastructure({
1121
876
  images: {
1122
- "channel.email": "axllent/mailpit:v1.30.7",
1123
- "store.files": "rustfs/rustfs:1.0.0-rc.2",
877
+ "channel.email": "axllent/mailpit:v1.31.1",
878
+ "store.files": "rustfs/rustfs:1.0.0-rc.5",
1124
879
  },
1125
880
  instanceId: id,
1126
881
  credentials: {
@@ -1158,8 +913,8 @@ describe("deriveInfrastructure", () => {
1158
913
  const n = Number.parseInt(id.slice(0, 4), 16) % 1000;
1159
914
  const rows = resolveStack({
1160
915
  images: {
1161
- "channel.email": "axllent/mailpit:v1.30.7",
1162
- "store.files": "rustfs/rustfs:1.0.0-rc.2",
916
+ "channel.email": "axllent/mailpit:v1.31.1",
917
+ "store.files": "rustfs/rustfs:1.0.0-rc.5",
1163
918
  },
1164
919
  instanceId: id,
1165
920
  credentials: {
@@ -66,9 +66,9 @@ describe("ImagesConfig nesting — recipe coverage", () => {
66
66
  },
67
67
  // store.files / store.index
68
68
  {
69
- images: { store: { files: "rustfs/rustfs:1.0.0-rc.2" } },
69
+ images: { store: { files: "rustfs/rustfs:1.0.0-rc.5" } },
70
70
  role: "store.files",
71
- image: "rustfs/rustfs:1.0.0-rc.2",
71
+ image: "rustfs/rustfs:1.0.0-rc.5",
72
72
  },
73
73
  {
74
74
  images: { store: { index: "getmeili/meilisearch:v1.53" } },
@@ -77,27 +77,15 @@ describe("ImagesConfig nesting — recipe coverage", () => {
77
77
  },
78
78
  // channel.email
79
79
  {
80
- images: { channel: { email: "axllent/mailpit:v1.30.7" } },
80
+ images: { channel: { email: "axllent/mailpit:v1.31.1" } },
81
81
  role: "channel.email",
82
- image: "axllent/mailpit:v1.30.7",
82
+ image: "axllent/mailpit:v1.31.1",
83
83
  },
84
- // flat roles no driver counterpart in DriversConfig
84
+ // ai role: no compose recipes (BYO OKE_AI_URL) — not covered here
85
85
  {
86
- images: { ai: "ghcr.io/ggml-org/llama.cpp:server-b10450" },
87
- role: "ai",
88
- image: "ghcr.io/ggml-org/llama.cpp:server-b10450",
89
- },
90
- { images: { ai: "vllm/vllm-openai:v0.27.1" }, role: "ai", image: "vllm/vllm-openai:v0.27.1" },
91
- {
92
- images: { ai: "lmsysorg/sglang:v0.5.17-runtime" },
93
- role: "ai",
94
- image: "lmsysorg/sglang:v0.5.17-runtime",
95
- },
96
- { images: { ai: "ollama/ollama:0.32.13" }, role: "ai", image: "ollama/ollama:0.32.13" },
97
- {
98
- images: { pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.53" },
86
+ images: { pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57" },
99
87
  role: "pgdog",
100
- image: "ghcr.io/pgdogdev/pgdog:v0.1.53",
88
+ image: "ghcr.io/pgdogdev/pgdog:v0.1.57",
101
89
  },
102
90
  { images: { proxy: "caddy:2-alpine" }, role: "proxy", image: "caddy:2-alpine" },
103
91
  { images: { proxy: "traefik:v3.1" }, role: "proxy", image: "traefik:v3.1" },
@@ -120,22 +108,22 @@ describe("ImagesConfig nesting — compose output parity", () => {
120
108
  test("nested config derives byte-identical output to its flat-shape equivalent", () => {
121
109
  const flatImages: Readonly<Record<string, string>> = {
122
110
  "store.sql": "postgres:18-alpine",
123
- pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.53",
111
+ pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
124
112
  "store.kv": "redis:8-alpine",
125
- "store.files": "rustfs/rustfs:1.0.0-rc.2",
113
+ "store.files": "rustfs/rustfs:1.0.0-rc.5",
126
114
  "store.index": "getmeili/meilisearch:v1.53",
127
- "channel.email": "axllent/mailpit:v1.30.7",
115
+ "channel.email": "axllent/mailpit:v1.31.1",
128
116
  };
129
117
 
130
118
  const nestedImages: ImagesConfig = {
131
119
  store: {
132
120
  sql: "postgres:18-alpine",
133
121
  kv: "redis:8-alpine",
134
- files: "rustfs/rustfs:1.0.0-rc.2",
122
+ files: "rustfs/rustfs:1.0.0-rc.5",
135
123
  index: "getmeili/meilisearch:v1.53",
136
124
  },
137
- channel: { email: "axllent/mailpit:v1.30.7" },
138
- pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.53",
125
+ channel: { email: "axllent/mailpit:v1.31.1" },
126
+ pgdog: "ghcr.io/pgdogdev/pgdog:v0.1.57",
139
127
  };
140
128
 
141
129
  // Same nested→flat set, written in a different field order — proves the
@@ -61,22 +61,12 @@ export {
61
61
  type ComposeYamlOptions,
62
62
  } from "./helpers.ts";
63
63
  export { generateCredentials } from "./credentials.ts";
64
- export {
65
- ensureOllamaModel,
66
- normalizeOllamaPullUrl,
67
- ollamaTagsInclude,
68
- parseOllamaTagsNames,
69
- OllamaPullError,
70
- type EnsureOllamaModelOptions,
71
- type OllamaFetch,
72
- } from "./ollama-pull.ts";
73
64
  export {
74
65
  aiModelIdsMatch,
75
66
  formatAiModelStatusMessage,
76
67
  normalizeAiProbeUrl,
77
68
  probeAiModelStatus,
78
69
  startAiModelWatch,
79
- statusFromOllamaTags,
80
70
  statusFromOpenAiModels,
81
71
  type AiModelFetch,
82
72
  type AiModelPhase,
@@ -102,19 +92,9 @@ export {
102
92
  caddy,
103
93
  cockroach,
104
94
  dragonfly,
105
- llamaCpp,
106
- buildLlamaCppEntrypoint,
107
- LLAMA_CPP_ENTRYPOINT_FILE,
108
- LLAMA_CPP_ENTRYPOINT_HOST_PATH,
109
- LLAMA_CPP_ENTRYPOINT_MOUNT,
110
- LLAMA_CPP_IMAGE,
111
- LLAMA_CPP_MIN_SAFE_BUILD,
112
95
  mailpit,
113
96
  meilisearch,
114
97
  nginx,
115
- ollama,
116
- OLLAMA_IMAGE,
117
- OLLAMA_MIN_SAFE_VERSION,
118
98
  pgdog,
119
99
  postgres,
120
100
  postgresAdvisor,
@@ -126,13 +106,10 @@ export {
126
106
  recipeFor,
127
107
  redis,
128
108
  rustfs,
129
- sglang,
130
- SGLANG_IMAGE,
109
+ supabase,
131
110
  timescale,
132
111
  traefik,
133
112
  valkey,
134
- vllm,
135
- VLLM_IMAGE,
136
113
  yugabyte,
137
114
  } from "./recipes/index.ts";
138
115
  export { CADDY_APP_SERVICE, buildCaddyfile } from "./recipes/caddy.ts";
@@ -6,22 +6,18 @@ import type { ImageRecipe } from "../types.ts";
6
6
  import { caddy } from "./caddy.ts";
7
7
  import { cockroach } from "./cockroach.ts";
8
8
  import { dragonfly } from "./dragonfly.ts";
9
- import { llamaCpp } from "./llama-cpp.ts";
10
9
  import { mailpit } from "./mailpit.ts";
11
10
  import { meilisearch } from "./meilisearch.ts";
12
11
  import { nginx } from "./nginx.ts";
13
- import { ollama } from "./ollama.ts";
14
12
  import { pgdog } from "./pgdog.ts";
15
13
  import { postgresAdvisor } from "./postgres-advisor.ts";
16
14
  import { postgres } from "./postgres.ts";
17
15
  import { redis } from "./redis.ts";
18
16
  import { rustfs } from "./rustfs.ts";
19
- import { sglang } from "./sglang.ts";
20
17
  import { supabase } from "./supabase.ts";
21
18
  import { timescale } from "./timescale.ts";
22
19
  import { traefik } from "./traefik.ts";
23
20
  import { valkey } from "./valkey.ts";
24
- import { vllm } from "./vllm.ts";
25
21
  import { yugabyte } from "./yugabyte.ts";
26
22
 
27
23
  /** Default recipe catalogue — more specific image matches before protocol peers. */
@@ -39,10 +35,6 @@ export const builtinRecipes: readonly ImageRecipe[] = [
39
35
  mailpit,
40
36
  rustfs,
41
37
  meilisearch,
42
- llamaCpp,
43
- vllm,
44
- sglang,
45
- ollama,
46
38
  caddy,
47
39
  nginx,
48
40
  traefik,
@@ -52,36 +44,21 @@ export {
52
44
  caddy,
53
45
  cockroach,
54
46
  dragonfly,
55
- llamaCpp,
56
47
  mailpit,
57
48
  meilisearch,
58
49
  nginx,
59
- ollama,
60
50
  pgdog,
61
51
  postgres,
62
52
  postgresAdvisor,
63
53
  redis,
64
54
  rustfs,
65
- sglang,
66
55
  supabase,
67
56
  timescale,
68
57
  traefik,
69
58
  valkey,
70
- vllm,
71
59
  yugabyte,
72
60
  };
73
61
 
74
- export {
75
- buildLlamaCppEntrypoint,
76
- LLAMA_CPP_ENTRYPOINT_FILE,
77
- LLAMA_CPP_ENTRYPOINT_HOST_PATH,
78
- LLAMA_CPP_ENTRYPOINT_MOUNT,
79
- LLAMA_CPP_IMAGE,
80
- LLAMA_CPP_MIN_SAFE_BUILD,
81
- } from "./llama-cpp.ts";
82
- export { OLLAMA_IMAGE, OLLAMA_MIN_SAFE_VERSION } from "./ollama.ts";
83
- export { SGLANG_IMAGE } from "./sglang.ts";
84
- export { VLLM_IMAGE } from "./vllm.ts";
85
62
  export {
86
63
  emitPostgresAdvisorDockerfile,
87
64
  HYPOPG_GIT_TAG,
@@ -80,11 +80,13 @@ export const pgdog: ImageRecipe = {
80
80
  [PGDOG_BACKEND_SERVICE]: { condition: "service_healthy" },
81
81
  },
82
82
  healthcheck: {
83
+ // Tight interval — pooler is ready seconds after store-sql healthy;
84
+ // 5s polls made `oke dev` look stuck on pgdog for a long time.
83
85
  test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -p 6432 || exit 1"],
84
- interval: "5s",
85
- timeout: "3s",
86
- retries: 12,
87
- start_period: "5s",
86
+ interval: "2s",
87
+ timeout: "2s",
88
+ retries: 20,
89
+ start_period: "2s",
88
90
  },
89
91
  }),
90
92
  url: (_s, c) =>
@@ -142,8 +142,8 @@ describe("deriveInfrastructure instanceId", () => {
142
142
  const n = instancePortOffset(id);
143
143
  const result = deriveInfrastructure({
144
144
  images: {
145
- "channel.email": "axllent/mailpit:v1.30.7",
146
- "store.files": "rustfs/rustfs:1.0.0-rc.2",
145
+ "channel.email": "axllent/mailpit:v1.31.1",
146
+ "store.files": "rustfs/rustfs:1.0.0-rc.5",
147
147
  },
148
148
  app: `dev-${id}`,
149
149
  instanceId: id,
@@ -127,7 +127,6 @@ export const STACK_CONTROL_KEYS = [
127
127
  "MP_SMTP_AUTH_ACCEPT_ANY",
128
128
  "MP_SMTP_AUTH_ALLOW_INSECURE",
129
129
  "OKE_AI_MODEL",
130
- "OKE_AI_CTX_SIZE",
131
130
  "OKE_PROXY_HOST",
132
131
  "OKE_PROXY_ACME_EMAIL",
133
132
  ] as const;
@@ -84,9 +84,9 @@ export interface RecipeApplyResult {
84
84
  * omit this for inference servers (raw API must not bind `0.0.0.0`).
85
85
  */
86
86
  readonly publishBind?: RecipePublishBind;
87
- /** Compose `ipc` (e.g. vLLM `host` for shared-memory workers). */
87
+ /** Compose `ipc` (e.g. `host` for shared-memory workers). */
88
88
  readonly ipc?: string;
89
- /** Compose `deploy` (e.g. GPU device reservations for vLLM / SGLang). */
89
+ /** Compose `deploy` (e.g. GPU device reservations). */
90
90
  readonly deploy?: Readonly<Record<string, unknown>>;
91
91
  /**
92
92
  * Compose `depends_on` (e.g. pooler waits for Postgres).
@@ -12,6 +12,7 @@ import type {
12
12
  AiModelClient,
13
13
  AiOpenOptions,
14
14
  } from "./ai-types.ts";
15
+ import { hostFromUrl } from "./external.ts";
15
16
 
16
17
  const DEFAULT_BASE = "https://api.anthropic.com";
17
18
  const ANTHROPIC_VERSION = "2023-06-01";
@@ -33,6 +34,14 @@ export async function openAnthropic(options: AiOpenOptions = {}): Promise<AiMode
33
34
  if (typeof preconnect === "function") {
34
35
  preconnect(baseUrl);
35
36
  }
37
+ const host = hostFromUrl(baseUrl);
38
+ const external = host
39
+ ? {
40
+ host,
41
+ kind: options.external?.kind ?? ("third-party" as const),
42
+ provider: options.external?.provider ?? "anthropic",
43
+ }
44
+ : undefined;
36
45
 
37
46
  return {
38
47
  driverId: "anthropic",
@@ -71,6 +80,7 @@ export async function openAnthropic(options: AiOpenOptions = {}): Promise<AiMode
71
80
  inputTokens: raw.usage?.input_tokens,
72
81
  outputTokens: raw.usage?.output_tokens,
73
82
  },
83
+ ...(external !== undefined ? { external } : {}),
74
84
  };
75
85
  },
76
86
  };