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
@@ -1,120 +1,45 @@
1
1
  /**
2
2
  * Optional auth helpers for {@link createClient} — not a second client factory.
3
3
  *
4
+ * Prefer `createClient(url, { auth: { mode, … } })` so `api.auth` is attached.
5
+ * {@link createAuthClient} remains the compose / bind escape hatch.
6
+ *
4
7
  * @module
5
8
  */
6
9
 
7
- /** Common auth Flow error codes (server `fail` codes). */
8
- export const AUTH_ERROR_CODES = {
9
- AuthFailed: "AuthFailed",
10
- AuthRateLimited: "AuthRateLimited",
11
- Unauthorized: "Unauthorized",
12
- Forbidden: "Forbidden",
13
- } as const;
14
-
15
- /** In-memory session token bag for SPA / Node clients. */
16
- export interface MemorySession {
17
- accessToken: string | null;
18
- refreshToken: string | null;
19
- accessExpiresAt: number | null;
20
- userId: string | null;
21
- set(tokens: {
22
- readonly accessToken: string;
23
- readonly refreshToken: string;
24
- readonly accessExpiresAt?: number;
25
- readonly userId?: string;
26
- }): void;
27
- clear(): void;
28
- /** Wire into `createClient` `auth.getToken`. */
29
- getToken(): string | null;
30
- /**
31
- * Wire into `createClient` `auth.refresh` — calls the refresh Flow via the client.
32
- *
33
- * @param api - Client with `auth.refresh` route (or custom path)
34
- */
35
- refresh(api: {
36
- auth: {
37
- refresh: (input: { refreshToken: string }) => Promise<{
38
- data: {
39
- accessToken: string;
40
- refreshToken: string;
41
- accessExpiresAt?: number;
42
- userId?: string;
43
- } | null;
44
- error: unknown;
45
- }>;
46
- };
47
- }): Promise<string | null>;
48
- }
49
-
50
- /**
51
- * Create an in-memory session helper for Bearer `createClient` wiring.
52
- */
53
- export function memorySession(): MemorySession {
54
- const state: {
55
- accessToken: string | null;
56
- refreshToken: string | null;
57
- accessExpiresAt: number | null;
58
- userId: string | null;
59
- } = {
60
- accessToken: null,
61
- refreshToken: null,
62
- accessExpiresAt: null,
63
- userId: null,
64
- };
65
-
66
- return {
67
- get accessToken() {
68
- return state.accessToken;
69
- },
70
- set accessToken(v) {
71
- state.accessToken = v;
72
- },
73
- get refreshToken() {
74
- return state.refreshToken;
75
- },
76
- set refreshToken(v) {
77
- state.refreshToken = v;
78
- },
79
- get accessExpiresAt() {
80
- return state.accessExpiresAt;
81
- },
82
- set accessExpiresAt(v) {
83
- state.accessExpiresAt = v;
84
- },
85
- get userId() {
86
- return state.userId;
87
- },
88
- set userId(v) {
89
- state.userId = v;
90
- },
91
- set(tokens) {
92
- state.accessToken = tokens.accessToken;
93
- state.refreshToken = tokens.refreshToken;
94
- state.accessExpiresAt = tokens.accessExpiresAt ?? null;
95
- state.userId = tokens.userId ?? null;
96
- },
97
- clear() {
98
- state.accessToken = null;
99
- state.refreshToken = null;
100
- state.accessExpiresAt = null;
101
- state.userId = null;
102
- },
103
- getToken() {
104
- return state.accessToken;
105
- },
106
- async refresh(api) {
107
- if (!state.refreshToken) return null;
108
- const { data, error } = await api.auth.refresh({ refreshToken: state.refreshToken });
109
- if (error || !data) {
110
- state.accessToken = null;
111
- return null;
112
- }
113
- state.accessToken = data.accessToken;
114
- state.refreshToken = data.refreshToken;
115
- state.accessExpiresAt = data.accessExpiresAt ?? null;
116
- if (data.userId) state.userId = data.userId;
117
- return data.accessToken;
118
- },
119
- };
120
- }
10
+ export {
11
+ AUTH_ERROR_CODES,
12
+ forbiddenScopes,
13
+ isAuthRateLimited,
14
+ isCsrf,
15
+ isForbidden,
16
+ isSessionTokens,
17
+ isTwoFactorRequired,
18
+ isUnauthorized,
19
+ } from "./auth/denials.ts";
20
+ export {
21
+ createAuthClient,
22
+ type AuthApi,
23
+ type AuthClient,
24
+ type AuthMode,
25
+ type AuthPersist,
26
+ type AuthorizeQuery,
27
+ type AuthorizeResult,
28
+ type CreateAuthClientOptions,
29
+ type SignInResult,
30
+ } from "./auth/create-auth-client.ts";
31
+ export {
32
+ tokenFromRequestCookies,
33
+ type CookieSource,
34
+ type TokenFromCookiesOptions,
35
+ } from "./auth/cookies.ts";
36
+ export { createServerClient } from "./create-with-session.ts";
37
+ export {
38
+ memorySession,
39
+ persistSession,
40
+ type MemorySession,
41
+ type MemorySessionOptions,
42
+ type SessionListener,
43
+ type SessionTokens,
44
+ type SessionUser,
45
+ } from "./auth/session.ts";
@@ -0,0 +1,245 @@
1
+ /**
2
+ * `createClient` with optional session `auth` → `api.auth` ({@link AuthClient}).
3
+ *
4
+ * Bare transport stays in {@link ./create.ts} (budget entry). This wrapper is
5
+ * what `okengine/client` exports.
6
+ *
7
+ * @module
8
+ */
9
+
10
+ import {
11
+ createAuthClient,
12
+ type AuthApi,
13
+ type AuthClient,
14
+ type CreateAuthClientOptions,
15
+ } from "./auth/create-auth-client.ts";
16
+ import { tokenFromRequestCookies, type CookieSource } from "./auth/cookies.ts";
17
+ import {
18
+ createClient as createClientCore,
19
+ flattenRoutes,
20
+ transportOf,
21
+ type AppWithRoutes,
22
+ type TransportBag,
23
+ } from "./create.ts";
24
+ import type {
25
+ Client,
26
+ ClientHeaders,
27
+ ClientOptions,
28
+ ClientSessionAuthOptions,
29
+ ClientTransportAuth,
30
+ ResolveApp,
31
+ } from "./types.ts";
32
+
33
+ export { flattenRoutes, transportOf };
34
+ export type { AppWithRoutes, TransportBag };
35
+
36
+ /** Session-option keys that distinguish orchestration from bare transport hooks. */
37
+ const SESSION_AUTH_KEYS = [
38
+ "mode",
39
+ "persist",
40
+ "csrfConfigured",
41
+ "storageKey",
42
+ "session",
43
+ "tenantHeader",
44
+ "env",
45
+ ] as const;
46
+
47
+ /**
48
+ * True when `auth` is bare `{ getToken, refresh }` without session keys.
49
+ *
50
+ * @param auth - Client auth option
51
+ */
52
+ export function isTransportAuthOnly(auth: unknown): auth is ClientTransportAuth {
53
+ if (auth === null || typeof auth !== "object") return false;
54
+ const bag = auth as Record<string, unknown>;
55
+ const hasHooks = typeof bag.getToken === "function" && typeof bag.refresh === "function";
56
+ if (!hasHooks) return false;
57
+ for (const key of SESSION_AUTH_KEYS) {
58
+ if (key in bag && bag[key] !== undefined) return false;
59
+ }
60
+ return true;
61
+ }
62
+
63
+ /**
64
+ * True when `auth` should construct an {@link AuthClient} on the client.
65
+ *
66
+ * @param auth - Client auth option
67
+ */
68
+ export function isSessionAuthOptions(auth: unknown): auth is ClientSessionAuthOptions {
69
+ return auth !== null && typeof auth === "object" && !isTransportAuthOnly(auth);
70
+ }
71
+
72
+ /**
73
+ * Create a fully typed client from an adopted app value (types + REST).
74
+ *
75
+ * @typeParam App - `typeof app` after `.adopt({ notes })`
76
+ */
77
+ export function createClient<App extends AppWithRoutes>(
78
+ app: App,
79
+ url: string,
80
+ opts?: ClientOptions,
81
+ ): Client<App>;
82
+
83
+ /**
84
+ * Create a fully typed client from an App type argument / ambient Register.
85
+ *
86
+ * @typeParam App - `typeof app`, {@link AppOf} route map, or omit for {@link Register}
87
+ */
88
+ export function createClient<App = never>(
89
+ url: string,
90
+ opts?: ClientOptions,
91
+ ): Client<ResolveApp<App>>;
92
+
93
+ /**
94
+ * @param appOrUrl - App instance or base URL
95
+ * @param urlOrOpts - Base URL (when app given) or options
96
+ * @param maybeOpts - Options when app + url form is used
97
+ */
98
+ export function createClient(
99
+ appOrUrl: AppWithRoutes | string,
100
+ urlOrOpts?: string | ClientOptions,
101
+ maybeOpts?: ClientOptions,
102
+ ): Client {
103
+ const { url, opts } = normalizeArgs(appOrUrl, urlOrOpts, maybeOpts);
104
+ if (!opts?.auth || isTransportAuthOnly(opts.auth)) {
105
+ return createClientCore(appOrUrl as never, urlOrOpts as never, maybeOpts as never);
106
+ }
107
+ return buildWithSession(url, opts);
108
+ }
109
+
110
+ function normalizeArgs(
111
+ appOrUrl: AppWithRoutes | string,
112
+ urlOrOpts?: string | ClientOptions,
113
+ maybeOpts?: ClientOptions,
114
+ ): { url: string; opts: ClientOptions } {
115
+ if (typeof appOrUrl === "string") {
116
+ return { url: appOrUrl, opts: (urlOrOpts as ClientOptions | undefined) ?? {} };
117
+ }
118
+ const url = typeof urlOrOpts === "string" ? urlOrOpts : "";
119
+ const opts = (typeof urlOrOpts === "string" ? maybeOpts : urlOrOpts) ?? {};
120
+ return {
121
+ url,
122
+ opts: { ...opts, $routes: opts.$routes ?? appOrUrl.$routes },
123
+ };
124
+ }
125
+
126
+ function buildWithSession(url: string, opts: ClientOptions): Client {
127
+ const sessionOpts = opts.auth as CreateAuthClientOptions;
128
+ const { auth: _drop, ...rest } = opts;
129
+ const shell = createClientCore(url, rest) as Client & AuthApi;
130
+ const authClient = createAuthClient(shell, sessionOpts);
131
+ const merged = mergeClientOptions(rest, authClient, sessionOpts);
132
+ const api = createClientCore(url, merged) as Client & AuthApi;
133
+ authClient.bind(api);
134
+ return attachAuth(api, authClient);
135
+ }
136
+
137
+ function mergeClientOptions(
138
+ base: ClientOptions,
139
+ authClient: AuthClient,
140
+ sessionOpts: CreateAuthClientOptions,
141
+ ): ClientOptions {
142
+ const fromAuth = authClient.clientOptions;
143
+ const transportAuth: ClientTransportAuth = {
144
+ getToken: sessionOpts.getToken ?? fromAuth.auth?.getToken ?? (() => null),
145
+ refresh: sessionOpts.refresh ?? fromAuth.auth?.refresh ?? (async () => null),
146
+ };
147
+ return {
148
+ ...base,
149
+ credentials: fromAuth.credentials ?? base.credentials,
150
+ auth: transportAuth,
151
+ headers: mergeHeaderGetters(base.headers, fromAuth.headers),
152
+ };
153
+ }
154
+
155
+ function mergeHeaderGetters(
156
+ base: ClientOptions["headers"],
157
+ over: (() => Record<string, string>) | undefined,
158
+ ): ClientOptions["headers"] {
159
+ if (!over) return base;
160
+ if (!base) return over;
161
+ return async () => {
162
+ const a = typeof base === "function" ? await base() : base;
163
+ const b = over();
164
+ return mergeHeaderBags(a, b);
165
+ };
166
+ }
167
+
168
+ function mergeHeaderBags(a: ClientHeaders | undefined, b: Record<string, string>): ClientHeaders {
169
+ if (!a) return b;
170
+ if (!Array.isArray(a)) return { ...a, ...b };
171
+ return [...a, ...Object.entries(b)];
172
+ }
173
+
174
+ /**
175
+ * Attach {@link AuthClient} at `api.auth`, preserving unit Flow access
176
+ * (`api.auth.me`, `api.auth.signInEmail`, …) for unbound props.
177
+ *
178
+ * @param api - Typed client
179
+ * @param auth - Session helper
180
+ */
181
+ function attachAuth(api: Client, auth: AuthClient): Client {
182
+ return new Proxy(api as object, {
183
+ get(target, prop, receiver) {
184
+ if (prop === "auth") {
185
+ const flows = Reflect.get(target, "auth", receiver);
186
+ return mergeAuthSurface(auth, flows);
187
+ }
188
+ return Reflect.get(target, prop, receiver);
189
+ },
190
+ }) as Client;
191
+ }
192
+
193
+ function mergeAuthSurface(auth: AuthClient, flows: unknown): AuthClient {
194
+ return new Proxy(auth as object, {
195
+ get(target, prop, receiver) {
196
+ if (typeof prop === "symbol") return Reflect.get(target, prop, receiver);
197
+ if (prop in (target as object)) return Reflect.get(target, prop, receiver);
198
+ if (flows !== null && (typeof flows === "object" || typeof flows === "function")) {
199
+ return Reflect.get(flows as object, prop, flows);
200
+ }
201
+ return undefined;
202
+ },
203
+ has(target, prop) {
204
+ if (prop in (target as object)) return true;
205
+ if (flows === null || (typeof flows !== "object" && typeof flows !== "function")) {
206
+ return false;
207
+ }
208
+ // Unit namespaces from createClient are Proxies that often implement get
209
+ // without has — treat a defined get as present so `"me" in api.auth` works.
210
+ if (prop in (flows as object)) return true;
211
+ return Reflect.get(flows as object, prop, flows) !== undefined;
212
+ },
213
+ }) as AuthClient;
214
+ }
215
+
216
+ /**
217
+ * Thin SSR helper — same {@link createClient} with cookie token from the request.
218
+ *
219
+ * @param req - Incoming request (cookies)
220
+ * @param url - API base URL
221
+ * @param opts - Client options
222
+ */
223
+ export function createServerClient(
224
+ req: CookieSource,
225
+ url: string,
226
+ opts: ClientOptions = {},
227
+ ): Client {
228
+ const prior = opts.auth;
229
+ const sessionBase =
230
+ prior && isSessionAuthOptions(prior)
231
+ ? prior
232
+ : prior && isTransportAuthOnly(prior)
233
+ ? {}
234
+ : ((prior as ClientSessionAuthOptions | undefined) ?? {});
235
+ return createClient(url, {
236
+ ...opts,
237
+ credentials: opts.credentials ?? "include",
238
+ auth: {
239
+ ...sessionBase,
240
+ mode: "cookie",
241
+ csrfConfigured: "csrfConfigured" in sessionBase ? sessionBase.csrfConfigured : true,
242
+ getToken: () => tokenFromRequestCookies(req),
243
+ },
244
+ });
245
+ }
@@ -22,11 +22,13 @@ import {
22
22
  type LiveByFlow,
23
23
  type LiveRouteTable,
24
24
  } from "./live.ts";
25
+ import { flattenStreamRoutes, openStream, type StreamByFlow } from "./stream.ts";
25
26
  import type {
26
27
  Client,
27
28
  ClientHeaders,
28
29
  ClientLive,
29
30
  ClientOptions,
31
+ ClientResult,
30
32
  ClientRouteMap,
31
33
  LiveHandlers,
32
34
  ResolveApp,
@@ -97,6 +99,7 @@ function buildClient(url: string, opts: ClientOptions = {}): Client {
97
99
  const base = url.replace(/\/+$/, "");
98
100
  const routes = opts.routes ?? flattenRoutes(opts.$routes);
99
101
  const live = flattenLiveRoutes(opts.$routes);
102
+ const streamByFlow = flattenStreamRoutes(opts.$routes);
100
103
  const transport = createTransport(base, { ...opts, routes });
101
104
  const perCallHeaders = createPerCallHeaders();
102
105
  return proxy(transport, [], {
@@ -104,6 +107,7 @@ function buildClient(url: string, opts: ClientOptions = {}): Client {
104
107
  opts,
105
108
  liveBySignal: live.bySignal,
106
109
  liveByFlow: live.byFlow,
110
+ streamByFlow,
107
111
  perCallHeaders,
108
112
  }) as Client;
109
113
  }
@@ -113,6 +117,7 @@ type ProxyCtx = {
113
117
  readonly opts: ClientOptions;
114
118
  readonly liveBySignal: LiveRouteTable;
115
119
  readonly liveByFlow: LiveByFlow;
120
+ readonly streamByFlow: StreamByFlow;
116
121
  /**
117
122
  * Extra headers attached to the next transport call, then cleared — the
118
123
  * `X-Oke-Mutation-Id` channel for optimistic dedupe (one-shot by design;
@@ -187,7 +192,7 @@ export function flattenRoutes(
187
192
  * @param path - Accumulated property path
188
193
  */
189
194
  function proxy(transport: Transport, path: readonly string[], ctx: ProxyCtx): unknown {
190
- const invoke = async (input?: unknown) => {
195
+ const invoke = async (input?: unknown, callOpts?: CallOpts): Promise<ClientResult> => {
191
196
  if (path.length < 2) {
192
197
  return attachPager(
193
198
  {
@@ -199,16 +204,20 @@ function proxy(transport: Transport, path: readonly string[], ctx: ProxyCtx): un
199
204
  },
200
205
  },
201
206
  },
202
- invoke,
207
+ (nextInput) => invoke(nextInput, callOpts),
203
208
  input,
204
209
  );
205
210
  }
206
211
  const unit = path[0]!;
207
212
  const flow = path.slice(1).join(".");
208
- const result = await transport.call(`${unit}/${flow}`, input, ctx.perCallHeaders.read());
209
- return attachPager(result, invoke, input);
213
+ const result = await transport.call(`${unit}/${flow}`, input, {
214
+ headers: ctx.perCallHeaders.read(),
215
+ ...(callOpts?.response !== undefined ? { response: callOpts.response } : {}),
216
+ ...(callOpts?.signal !== undefined ? { signal: callOpts.signal } : {}),
217
+ });
218
+ return attachPager(result, (nextInput) => invoke(nextInput, callOpts), input);
210
219
  };
211
- const call = (a?: unknown, b?: unknown) => {
220
+ const call = (a?: unknown, b?: unknown): unknown => {
212
221
  if (path.length >= 2) {
213
222
  const key = `${path[0]}.${path.slice(1).join(".")}`;
214
223
  const exposure = ctx.liveByFlow[key];
@@ -217,6 +226,20 @@ function proxy(transport: Transport, path: readonly string[], ctx: ProxyCtx): un
217
226
  const input = isLiveHandlers(a) ? undefined : a;
218
227
  return subscribeLive(ctx.base, exposure, input, handlers, ctx.opts);
219
228
  }
229
+ const streamRoute = ctx.streamByFlow[key];
230
+ if (streamRoute) {
231
+ const input = isCallOpts(a) ? undefined : a;
232
+ const opts = isCallOpts(a) ? a : isCallOpts(b) ? b : undefined;
233
+ const merged: ClientOptions = opts?.signal
234
+ ? { ...ctx.opts, signal: opts.signal }
235
+ : ctx.opts;
236
+ return openStream(ctx.base, streamRoute, input, merged);
237
+ }
238
+ if (isCallOpts(a) || isCallOpts(b)) {
239
+ const input = isCallOpts(a) ? undefined : a;
240
+ const opts = (isCallOpts(a) ? a : b) as CallOpts;
241
+ return asThenableIterable((next) => invoke(next, opts), input);
242
+ }
220
243
  }
221
244
  return asThenableIterable(invoke, a);
222
245
  };
@@ -313,3 +336,26 @@ function makeLive(ctx: ProxyCtx): ClientLive {
313
336
  return subscribeLive(ctx.base, exposure, input, handlers, ctx.opts);
314
337
  }) as ClientLive;
315
338
  }
339
+
340
+ function isCallOpts(value: unknown): value is CallOpts {
341
+ if (value === null || typeof value !== "object" || isLiveHandlers(value)) return false;
342
+ const v = value as Record<string, unknown>;
343
+ if ("response" in v) {
344
+ return (
345
+ v.response === undefined ||
346
+ v.response === "json" ||
347
+ v.response === "blob" ||
348
+ v.response === "arrayBuffer"
349
+ );
350
+ }
351
+ if ("signal" in v) {
352
+ return v.signal === undefined || v.signal instanceof AbortSignal;
353
+ }
354
+ return false;
355
+ }
356
+
357
+ /** Per-call options on a Flow invoke (binary decode / abort). */
358
+ export interface CallOpts {
359
+ readonly response?: "json" | "blob" | "arrayBuffer";
360
+ readonly signal?: AbortSignal;
361
+ }
@@ -13,7 +13,12 @@ export {
13
13
  nextResubscribeDelay,
14
14
  pickLiveExposure,
15
15
  } from "./live.ts";
16
- export { createClient, flattenRoutes, transportOf } from "./create.ts";
16
+ export {
17
+ createClient,
18
+ flattenRoutes,
19
+ transportOf,
20
+ createServerClient,
21
+ } from "./create-with-session.ts";
17
22
  export type { AppWithRoutes, TransportBag } from "./create.ts";
18
23
  export { isErrorCode, isFail, isOk, isTransportError } from "./errors.ts";
19
24
  export { isPagerMeta, pagerLink } from "./pager.ts";
@@ -32,12 +37,17 @@ export type {
32
37
  Client,
33
38
  ClientApp,
34
39
  ClientCall,
40
+ ClientCallOpts,
35
41
  ClientDescriptor,
36
42
  ClientError,
37
43
  ClientFetch,
38
44
  ClientFromRoutes,
39
45
  ClientHeaders,
46
+ ClientBodyInit,
47
+ ClientCredentials,
40
48
  ClientOptions,
49
+ ClientSessionAuthOptions,
50
+ ClientTransportAuth,
41
51
  ClientEnvelope,
42
52
  ClientListMeta,
43
53
  ClientPagerLink,
@@ -4,6 +4,7 @@
4
4
 
5
5
  import type { ClientFetch, ClientOptions, ClientRouteMap, FlowContract } from "./types.ts";
6
6
  import type { LiveHandlers, LiveUnsubscribe } from "./types.ts";
7
+ import { readSse, sseError } from "./sse.ts";
7
8
 
8
9
  /** One HTTP exposure of a live signal. */
9
10
  export interface LiveExposure {
@@ -285,13 +286,21 @@ async function openSse(
285
286
  } else if (extra) {
286
287
  for (const [k, v] of Object.entries(extra)) headers.set(k, v);
287
288
  }
288
- const token = opts.auth ? await opts.auth.getToken() : undefined;
289
+ const token =
290
+ opts.auth && "getToken" in opts.auth && typeof opts.auth.getToken === "function"
291
+ ? await opts.auth.getToken()
292
+ : undefined;
289
293
  if (token && !headers.has("authorization")) {
290
294
  headers.set("authorization", `Bearer ${token}`);
291
295
  }
292
296
  if (lastSeenId) headers.set("last-event-id", lastSeenId);
293
297
  const fetchFn: ClientFetch = opts.fetch ?? globalThis.fetch.bind(globalThis);
294
- return fetchFn(url, { method, headers, signal });
298
+ return fetchFn(url, {
299
+ method,
300
+ headers,
301
+ signal,
302
+ ...(opts.credentials !== undefined ? { credentials: opts.credentials } : {}),
303
+ });
295
304
  }
296
305
 
297
306
  function restGet(base: string, path: string, input: unknown): { url: string; method: string } {
@@ -310,80 +319,3 @@ function restGet(base: string, path: string, input: unknown): { url: string; met
310
319
  const qs = query.length ? `?${query.join("&")}` : "";
311
320
  return { url: `${base}${pathOut}${qs}`, method: "GET" };
312
321
  }
313
-
314
- async function readSse(
315
- res: Response,
316
- onEvent: (event: unknown, id: string | undefined) => void,
317
- signal: AbortSignal,
318
- onOpen?: () => void,
319
- ): Promise<void> {
320
- if (signal.aborted) return;
321
- const ct = res.headers.get("content-type") ?? "";
322
- if (!res.ok || !res.body) {
323
- const text = await res.text().catch(() => "");
324
- throw sseError(res.status, text);
325
- }
326
- if (!ct.includes("text/event-stream")) {
327
- const text = await res.text().catch(() => "");
328
- throw sseError(res.status, text || `Expected text/event-stream, got ${ct || "none"}`);
329
- }
330
- onOpen?.();
331
- const reader = res.body.getReader();
332
- const dec = new TextDecoder();
333
- let buf = "";
334
- try {
335
- for (;;) {
336
- if (signal.aborted) return;
337
- const { done, value } = await reader.read();
338
- if (done) break;
339
- buf += dec.decode(value, { stream: true });
340
- let sep = buf.indexOf("\n\n");
341
- while (sep >= 0) {
342
- const raw = buf.slice(0, sep);
343
- buf = buf.slice(sep + 2);
344
- const stop = dispatchFrame(raw, onEvent, signal);
345
- if (stop || signal.aborted) return;
346
- sep = buf.indexOf("\n\n");
347
- }
348
- }
349
- } finally {
350
- reader.releaseLock();
351
- }
352
- }
353
-
354
- function dispatchFrame(
355
- raw: string,
356
- onEvent: (event: unknown, id: string | undefined) => void,
357
- signal: AbortSignal,
358
- ): boolean {
359
- const dataLines: string[] = [];
360
- let id: string | undefined;
361
- for (const line of raw.split("\n")) {
362
- if (line.startsWith("id:")) id = line.slice(3).replace(/^ /, "");
363
- if (line.startsWith("data:")) dataLines.push(line.slice(5).replace(/^ /, ""));
364
- }
365
- if (dataLines.length === 0) return false;
366
- const data = dataLines.join("\n");
367
- if (data === "[DONE]") return true;
368
- if (signal.aborted) return true;
369
- onEvent(JSON.parse(data) as unknown, id);
370
- return false;
371
- }
372
-
373
- function sseError(status: number, body: string): Error {
374
- let message = `HTTP ${status}`;
375
- if (body) {
376
- try {
377
- const json: unknown = JSON.parse(body);
378
- if (json !== null && typeof json === "object" && "error" in json) {
379
- const err = (json as { error?: { code?: string; data?: { message?: string } } }).error;
380
- message = err?.data?.message ?? err?.code ?? message;
381
- }
382
- } catch {
383
- message = body.slice(0, 200);
384
- }
385
- }
386
- const e = new Error(message);
387
- (e as Error & { status?: number }).status = status;
388
- return e;
389
- }