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,436 +0,0 @@
1
- ---
2
- title: "Gate"
3
- description: "Permission to act — policies, rate limits, and built-in auth on the HTTP trigger, evaluated before any effect runs."
4
- icon: "ShieldCheck"
5
- source: "docs/spec/unified-theory.md"
6
- ---
7
-
8
- Gate answers **"may this happen?"** before it happens: is this a verified member? has this IP
9
- burned its minute quota? Attach gates to the HTTP trigger — the pipeline checks them before a
10
- store write, emit, or channel send runs.
11
-
12
- > **Same Semantics Across Planes:** OKE does not create separate security models for users, operators, and agents. They enter the same execution model through different triggers and planes: users via sessions, operators via Console policies, and agents via `mcp.tool()` + OAuth 2.1 AS.
13
-
14
- <Callout title="The one rule">
15
- Every HTTP trigger declares posture: attach a real gate, or attach `.public()`. Omitting both
16
- fails boot. Denial is a typed error value — never a thrown exception mid-`do`.
17
- </Callout>
18
-
19
- ## Quick start
20
-
21
- <Steps>
22
-
23
- <Step>
24
- ### Declare policies
25
-
26
- Policies are named predicates; rate limits are declarative budgets. Import the module before
27
- `oke()` — they auto-register. `oke({ gate: { policies } })` is still valid and additive.
28
-
29
- ```typescript title="src/gates.ts"
30
- import { gate } from "okengine";
31
-
32
- export const member = gate.policy("member", ({ auth }) => !!auth.verified);
33
-
34
- export const canBook = gate.scope("booking:create");
35
-
36
- export const fair = gate.rate({
37
- max: 60,
38
- per: "1m",
39
- keyBy: "ip",
40
- });
41
- ```
42
-
43
- `gate.scope(name)` is sugar for
44
- `gate.policy(name, ({ auth }) => auth.scopes.has(name))` — one string is both the policy id and
45
- the scope checked.
46
-
47
- ```typescript title="src/app.ts"
48
- import "./gates";
49
- import { oke } from "okengine";
50
-
51
- export const app = oke({ name: "shop", env: "dev" });
52
- ```
53
-
54
- </Step>
55
-
56
- <Step>
57
- ### Attach them to triggers
58
-
59
- `.gate(...)` composes left to right — first denial wins. Public routes must say so explicitly. Path and name can come from the file tree — see [Project structure](/docs/get-started/project-structure).
60
-
61
- ```typescript title="src/flows/links/shorten.ts"
62
- import { on, flow, http, gate } from "okengine";
63
- import { member, canBook, fair } from "../../gates";
64
-
65
- export const health = on(
66
- http.get("/health").public(),
67
- flow("health.check", {
68
- do: () => ({ ok: true }),
69
- }),
70
- );
71
-
72
- export const write = gate.all(member, canBook, fair);
73
-
74
- export const shorten = on(
75
- http.post("/links").gate(write),
76
- flow("links.shorten", {
77
- in: NewLink,
78
- out: LinkCode,
79
- errors: { Taken },
80
- do: async ({ url, code }, fx) => {
81
- /* runs only if every gate passed */
82
- },
83
- }),
84
- );
85
- ```
86
-
87
- A single gate stays `.gate(member)`. Reuse two or more with `gate.all` — `.gate(write)`
88
- flattens. `http.resource(path, ops).gate(...)` stamps every verb. Public routes use
89
- `.public()` — do **not** put `gate.public` in `gate.policies`.
90
-
91
- </Step>
92
-
93
- <Step>
94
- ### See typed denials
95
-
96
- A denied request never reaches `do`. It returns one of three typed failures:
97
-
98
- | Gate result | Typed failure |
99
- | -------------------------------- | ------------------------------------- |
100
- | Policy denied, not authenticated | `Unauthorized` |
101
- | Policy denied, authenticated | `Forbidden` (with gate name + reason) |
102
- | Rate limit exceeded | `RateLimited` (with `retryAfterMs`) |
103
-
104
- </Step>
105
-
106
- </Steps>
107
-
108
- ## First denial wins
109
-
110
- <GatePipeline />
111
-
112
- `.gate(member, canBook, fair)` and `.gate(write)` (from `gate.all`) evaluate left
113
- to right — first denial wins (`Unauthorized` · `Forbidden` · `RateLimited`); later
114
- gates are skipped. `do` runs only when every gate passed.
115
-
116
- ## `oke({ gate })` bag
117
-
118
- | Option | Type | Default | Meaning |
119
- | --------------- | ----------------------- | -------- | --------------------------------------------------------------- |
120
- | `policies` | `GateDecl[]` | `[]` | Policy / rate decls — `gate.all` handles flatten to members |
121
- | `auth` | `GateAuthOptions` | — | Builtin hybrid sessions + `/auth/*` Flows (see below) |
122
- | `rateLimit` | `{ enabled?: boolean }` | see note | When auth is on, defaults `true` — stricter rates on auth paths |
123
- | `unguardedHttp` | `"deny"` \| `"allow"` | `"deny"` | `"allow"` skips posture audit **only** when `env === "test"` |
124
-
125
- ## Declarations
126
-
127
- | Declaration | Question it answers | Evaluated against |
128
- | ------------------------------------- | ------------------------------------------- | ---------------------------------- |
129
- | `gate.policy(name, check \| options)` | Is this principal allowed? (ABAC) | auth / operator / request metadata |
130
- | `gate.scope(name)` | Does `auth.scopes` contain this exact name? | `auth.scopes` |
131
- | `gate.public` / `.public()` | Intentionally unauthenticated surface | always allows |
132
- | `gate.rate(options)` | Is there budget left for this subject? | an atomic counter on the kv driver |
133
- | `gate.all(...members)` | Reuse this chain on many triggers | flattens; each member is evaluated |
134
-
135
- Pass `{ check, description }` on `gate.policy` when you want a human title in the Console (falls
136
- back to the policy name). The name `"public"` is reserved — mark the trigger with
137
- `.public()`, not `gate.policy("public", …)`.
138
-
139
- `gate.all()` with no members throws. Nested `all` handles flatten.
140
- Members auto-register when declared; `oke({ gate: { policies: [write] } })` is additive.
141
-
142
- ### Policy context
143
-
144
- | Field | Contents |
145
- | ---------- | -------------------------------------------------------- |
146
- | `auth` | User principal: `userId`, `scopes` (a `Set`), `verified` |
147
- | `operator` | Operator principal (Console plane): `id` |
148
- | `meta` | Request metadata for keying: `ip`, `userId`, … |
149
-
150
- A policy name containing `:` is also a `Module:Action` permission for Console role reviews.
151
- Fine-grained authorization (`gate.scope`, roles) stays opt-in — attach it only where you need it.
152
-
153
- ### Rate options
154
-
155
- | Option | Type | Default | Meaning |
156
- | ------------- | ------------ | -------------------------- | -------------------------------------------------------- |
157
- | `max` | number | — (**required**) | Takes allowed within `per` |
158
- | `per` | string | — (**required**) | Window / refill period (`"1m"`, `"60s"`, …) |
159
- | `keyBy` | string | — | Subject dimension (`"ip"`, `"user"`, …) |
160
- | `strategy` | RateStrategy | `"sliding-window-counter"` | Algorithm (below) |
161
- | `overridable` | boolean | `false` | Catalog flag in Console (rate edit UI not shipped) |
162
- | `description` | string | — | Human title in the Console (falls back to the rate name) |
163
-
164
- | Strategy | Behavior |
165
- | ------------------------ | ------------------------------------------------------ |
166
- | `sliding-window-counter` | Near-exact, two keys, no boundary bursts — the default |
167
- | `fixed-window` | Cheapest; allows bursts at window boundaries |
168
- | `sliding-log` | Exact; stores one timestamp per take |
169
- | `token-bucket` | Steady refill; permits saved-up bursts |
170
- | `leaky-bucket` | Smooths output to a constant rate |
171
-
172
- All five run as atomic Lua on the kv driver — correct under concurrency, identical on the memory
173
- driver in tests. Boot opens a dedicated `oke:gates` namespace on **`drivers.store.kv`**
174
- (`memory` in test · `redis` in `dev`/`prod`) so multi-instance rate limits share counters.
175
-
176
- ## Auth posture at boot
177
-
178
- Every HTTP trigger must carry a gate or `.public()`. Omitting both fails boot with
179
- `GateBootError` — message starts with `gate boot failed —` and lists every gap.
180
-
181
- ```typescript
182
- on(http.get("/health").public(), flow("health.check", {/* … */}));
183
- on(http.post("/bookings").gate(member, canBook), flow("bookings.create", {/* … */}));
184
- ```
185
-
186
- **Consequence:** first `fetch` / `execute` auto-boots (`autoBoot` defaults to `true`).
187
- `oke({ autoBoot: false })` is a unit-test escape hatch only. A rate-only chain is declared
188
- posture but does **not** authenticate.
189
-
190
- `gate: { unguardedHttp: "allow" }` skips the audit **only** when `env === "test"`.
191
- In `dev` / `prod` migrate with per-trigger `.public()`.
192
-
193
- ## Built-in auth (`gate.auth`)
194
-
195
- Enable hybrid sessions (Bearer access + revocable refresh). Auth HTTP surfaces are ordinary
196
- Bindings under `/auth` — same posture audit and pipeline as your app Flows:
197
-
198
- ```typescript title="src/app.ts"
199
- import { oke } from "okengine";
200
- import { member, canBook } from "./gates";
201
-
202
- export const app = oke({
203
- name: "shop",
204
- env: "dev",
205
- gate: {
206
- auth: {
207
- emailAndPassword: { enabled: true },
208
- session: { freshAgeMs: 24 * 60 * 60_000 },
209
- },
210
- policies: [member, canBook],
211
- },
212
- });
213
- ```
214
-
215
- | Surface | When |
216
- | -------------------------- | -------------------------------------- |
217
- | `POST /auth/sign-up/email` | `emailAndPassword.enabled` |
218
- | `POST /auth/sign-in/email` | `emailAndPassword.enabled` |
219
- | `POST /auth/refresh` | when `gate.auth` is set |
220
- | `POST /auth/revoke` | when `gate.auth` is set |
221
- | `GET /auth/me` | Bearer session (`auth.session` policy) |
222
-
223
- | Auth option | Default | Meaning |
224
- | ------------------------------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------- |
225
- | `secret` | minted\* | HMAC for access tokens (\*`prod` requires you set it) |
226
- | `basePath` | `"/auth"` | HTTP prefix for auth Flows |
227
- | `http` | `true` | `false` = secret/tables only (no `/auth/*` Bindings) |
228
- | `audience` | `oke-app` | Audience stamped on access tokens |
229
- | `emailAndPassword.enabled` | `false` | Sign-up / sign-in email Flows |
230
- | `emailAndPassword.requireEmailVerification` | `false` | Block sign-in until email is verified |
231
- | `passwordPolicy` | secure\* | `\*` minLength 8, letter + number + upper + lower + special (`requireSpecial`); sign-up → `AuthFailed` / `password_policy` |
232
- | `breachCheck` | unset | `(password) => Promise<boolean>` — `true` rejects as `password_breached` |
233
- | `session.freshAgeMs` | 24h | Window for step-up `auth.fresh` policy |
234
- | `session.accessTtlMs` / `refreshTtlMs` | 14m / 30d | Access / refresh lifetimes |
235
- | `session.idleTtlMs` | unset | Opt-in: reject refresh when idle too long |
236
- | `session.absoluteTtlMs` | unset | Opt-in: hard cap from session creation |
237
- | `session.singleSessionPerUser` | `false` | Opt-in: issuing a session revokes other families for that user |
238
- | `cookies.enabled` | `false` | Opt-in HttpOnly cookie mirror (Bearer stays default) |
239
- | `secondaryStorage.enabled` | `false` | Hot auth data in `store.kv` when configured |
240
- | `tenant` | unset | Opt-in identity dimension — `true` or `{ required, source, header, resolve, authoritative }` |
241
- | `user` / `session` / … | defaults | `modelName` / `fields` / `additionalFields` |
242
-
243
- HIBP via `createHibpBreachCheck` from `okengine/auth` (k-anonymity range API; requires
244
- `userAgent`; `onError` defaults to `"reject"` — fail closed while the check is enabled):
245
-
246
- ```typescript
247
- import { createHibpBreachCheck } from "okengine/auth";
248
-
249
- gate: {
250
- auth: {
251
- emailAndPassword: { enabled: true },
252
- breachCheck: createHibpBreachCheck({ userAgent: "shop/1.0" }),
253
- },
254
- }
255
- ```
256
-
257
- Customize tables, then `oke schema generate` (`.oke/schema/oke.ts`; `--check` in CI). Extra
258
- sign-in shapes: [Plugins](/docs/plugins). Call auth from
259
- [createClient](/docs/reference/client) — helpers in `okengine/client/auth`.
260
-
261
- ## Tenants (identity dimension)
262
-
263
- `gate.auth.tenant: true` (or an options bag) is **not** a second authorization system and not an
264
- organizations product. Tenant is a dimension of identity, like `fx.auth` / `fx.operator`.
265
-
266
- ```typescript
267
- export const app = oke({
268
- name: "shop",
269
- gate: { auth: { tenant: true } },
270
- });
271
- ```
272
-
273
- | Option | Default | Meaning |
274
- | --------------- | -------------- | ------------------------------------------------------------------------------------------------ |
275
- | `required` | `false` | Pure B2B: authenticated user-plane requests without a tenant are `Forbidden` / `tenant_required` |
276
- | `source` | `"claim"` | `"claim"` · `"header"` · `"subdomain"` · `"resolve"` |
277
- | `header` | `x-oke-tenant` | Header name when `source` is `"header"` |
278
- | `resolve` | unset | Callback that returns an id; membership is still checked unless `authoritative` |
279
- | `authoritative` | `false` | Trust `resolve` without a membership query |
280
-
281
- Three tiers, fail-safe:
282
-
283
- 1. **Claim** — signed JWT `tid` or API-key `tenantId`. The id is trusted; no membership query.
284
- 2. **Header / subdomain** — never trust a client-supplied id without membership.
285
- 3. **`resolve`** — still membership-checked unless `authoritative: true`.
286
-
287
- `required: false` (default) is B2C+B2B: `fx.tenant.id` may be `null`. Internal / cron / `fx.call`
288
- have no HTTP request — header and subdomain sources keep the stamped claim.
289
-
290
- `fx.auth.switchTenant(id)` issues a **new** access+refresh pair and a **new** family (so tab A
291
- rotation cannot reuse-detect tab B). It never Set-Cookies.
292
-
293
- Refresh copies that row's `tid`; tenant-role scopes never melt into the JWT.
294
-
295
- `fx.auth.listTenants` / `createTenant` / `addMember` / `upsertTenantRole` are session-only
296
- (`auth:tenants`). Tenant roles may grant application scopes only — `console:*` fails like an
297
- unknown name.
298
-
299
- Live `fx.auth.scopes` unions those grants only when `fx.tenant.id` is set, the flow is
300
- tenant-scoped (default on; `flow({ tenantScoped: false })` opts out), and user-plane.
301
- `gate.scope()` still reads `auth.scopes.has(name)`.
302
-
303
- SQL stamps `oke.tenant()` when tenancy is on — [Store](/docs/elements/store) and
304
- built-in [Vault](/docs/elements/vault#tenant-isolation-built-in-store) ciphertext.
305
-
306
- ## API keys
307
-
308
- A key is the **issuer with fewer gates** — not a second permission system.
309
- Bearer secrets authenticate as the creator; `fx.auth.scopes` shrink to the key.
310
-
311
- | Field | Session | API key |
312
- | ----------------------------------- | -------------- | ----------------------- |
313
- | `fx.auth.userId` / `fx.operator.id` | subject | creator (`creatorId`) |
314
- | `fx.auth.scopes` | session scopes | key scopes (attenuated) |
315
- | `fx.auth.apiKeyId` | `null` | key id |
316
- | WideEvent `principal` | subject | issuer |
317
- | `dimensions.api_key` | absent | key id |
318
-
319
- `gate.auth` always creates a shared key store (HMAC-SHA-256 with `gate.auth.secret`).
320
- Do not pass `apiKeyStore` unless you are injecting a test Map.
321
-
322
- <Callout title="Keys live on the app database">
323
- With `store.sql()`, boot hydrates public `oke_api_keys` on that connection (`DATABASE_URL`) and
324
- write-through persists create / rotate / revoke. Console **Access** attaches this host store — it
325
- does not keep a second key database.
326
- </Callout>
327
-
328
- Session Flows manage keys via [fx](/docs/reference/fx) (`createApiKey`, `listApiKeys`,
329
- `revokeApiKey`, `rotateApiKey`, `updateApiKey`). A key-authenticated caller cannot.
330
-
331
- Declare `effects.reads: ["auth:api-keys"]` / `effects.writes: ["auth:api-keys"]` — never
332
- `sql:oke_api_keys`. Console **Access** (`:6533` → `/access`) mints operator keys as the
333
- operator, and user-plane keys only as a picked issuer (`creatorUserId`).
334
-
335
- Verify rejects expired, revoked, allowlist-miss, and over-rate secrets with `401`
336
- and no `api_key` dimension.
337
-
338
- ## Identity and decisions
339
-
340
- Gates decide on principals that already exist. `gate.auth` issues hybrid sessions onto
341
- `fx.auth` (Console: `fx.operator`). Audit across `fx.call` uses read-only `fx.principal`
342
- (see [fx](/docs/reference/fx)).
343
-
344
- Pass **and** deny land on the run's `gates` dimension. Console (`:6533` → `/flows`) shows the
345
- chain on the flow contract. Rate `overridable` is a catalog flag only — Clock schedules are what the Console can
346
- edit live today.
347
-
348
- <Callout title="RLS reads the stamped principal">
349
- After HTTP Gate passes, user-plane `fx.store` stamps `oke.gate()`, `oke.user()`, and
350
- `oke.has_scope()`. With `gate.auth.tenant` on, a fourth GUC `oke.tenant()` is set. Rate, cron,
351
- CDC, and signal stay unstamped. Helpers: [Store](/docs/elements/store).
352
- </Callout>
353
-
354
- ## Troubleshooting
355
-
356
- <Accordions>
357
- <Accordion title="Boot: gate boot failed — N HTTP trigger(s) missing auth posture">
358
-
359
- Empty `.gate(...)` chain. Attach a policy/rate gate, or `.public()`. First `fetch`
360
- auto-boots — do not rely on `gate.unguardedHttp: "allow"` outside `env: "test"`.
361
-
362
- </Accordion>
363
- <Accordion title="Can a policy read the request body?">
364
-
365
- No. Gates run before the flow, so they see only `auth`, `operator`, and `meta`. Body-dependent
366
- decisions belong inside `do` as typed `errors`.
367
-
368
- </Accordion>
369
- <Accordion title="Logged-in users still get Forbidden">
370
-
371
- `Forbidden` means authenticated but a policy said no. Check `verified` or a missing scope —
372
- the failure includes the gate name and reason.
373
-
374
- </Accordion>
375
- <Accordion title="Forbidden tenant_required / not_member">
376
-
377
- `required: true` and no resolved tenant → `tenant_required`. Header/subdomain id that is not a
378
- membership → `not_member`. Call `fx.auth.switchTenant(id)` or send a signed `tid`.
379
-
380
- </Accordion>
381
- <Accordion title="Prod boot: gate.auth: secret is required">
382
-
383
- Set `gate.auth.secret` (or provide it before boot). Non-prod may mint a development secret.
384
-
385
- </Accordion>
386
- <Accordion title="Sign-up returns AuthFailed password_policy">
387
-
388
- Default policy: length ≥ 8 plus upper, lower, number, and special (`"123"` is rejected).
389
- Tighten via `gate.auth.passwordPolicy`. Console claim uses min length 12 with the same
390
- character classes.
391
-
392
- </Accordion>
393
- <Accordion title="Which keyBy should I use?">
394
-
395
- `"ip"` for public surfaces (sign-up, password reset), `"user"` for authenticated quotas.
396
- Keying an authenticated endpoint by IP punishes shared NAT.
397
-
398
- </Accordion>
399
- <Accordion title="API key Bearer returns 401">
400
-
401
- Expired, revoked, allowlist miss, or over `rateLimit`. `ipAllowlist` uses the
402
- same X-Forwarded-For hop as `ip-allowlist` (IP or hostname; lookup failure is closed).
403
- Rotate if the secret was shown once and then lost.
404
-
405
- </Accordion>
406
- <Accordion title="Keys vanish after an app restart">
407
-
408
- No SQL store, or a new `gate.auth.secret`. Declare `store.sql()`, keep
409
- `DATABASE_URL` (or the same PGlite datadir) and the auth secret stable.
410
- Console does not persist keys in `oke_console`.
411
-
412
- </Accordion>
413
- <Accordion title="Key can call a route the issuer cannot">
414
-
415
- That is a bug in the mint. `createApiKey` / `fx.auth.createApiKey` re-run
416
- `assertAttenuated` against the issuer's live scopes. Custom `gate.policy`
417
- predicates that ignore scopes still see `verified: true`.
418
-
419
- </Accordion>
420
- </Accordions>
421
-
422
- ## Learn more
423
-
424
- - [Project structure](/docs/get-started/project-structure) — `http.get()` and `flow({…})` fill path and name from the file tree
425
- - [Flow](/docs/elements/flow) — the trigger pipeline gates plug into
426
- - [fx](/docs/reference/fx) — `fx.auth`, `fx.operator`, `fx.principal`, `fx.tenant`
427
- - [Client](/docs/reference/client) — Bearer `createClient` + `okengine/client/auth`
428
- - [Plugins](/docs/plugins) — username, magic link, OTP, TOTP, passkeys
429
- - [Vault](/docs/elements/vault) — credentials your policies protect
430
-
431
- ## Next
432
-
433
- <Cards>
434
- <Card title="Vault" description="Continue to Vault." href="/docs/elements/vault" />
435
- <Card title="Plugins" description="Sign-in method plugins under /auth." href="/docs/plugins" />
436
- </Cards>