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
@@ -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
  };