okengine 0.17.2 → 0.18.4

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 (209) hide show
  1. package/AGENTS.md +5 -3
  2. package/README.md +14 -10
  3. package/manifest.v1.schema.json +61 -2
  4. package/package.json +19 -5
  5. package/site/content/docs/ai/index.mdx +1 -1
  6. package/site/content/docs/ai/mcp.mdx +10 -1
  7. package/site/content/docs/ai/skills.mdx +9 -9
  8. package/site/content/docs/elements/ai.mdx +1 -1
  9. package/site/content/docs/elements/clock.mdx +1 -1
  10. package/site/content/docs/elements/flow.mdx +25 -1
  11. package/site/content/docs/elements/gate.mdx +3 -2
  12. package/site/content/docs/elements/store.mdx +289 -341
  13. package/site/content/docs/elements/vault.mdx +5 -5
  14. package/site/content/docs/get-started/basic-usage.mdx +3 -10
  15. package/site/content/docs/get-started/index.mdx +1 -1
  16. package/site/content/docs/get-started/installation.mdx +2 -3
  17. package/site/content/docs/get-started/introduction.mdx +58 -121
  18. package/site/content/docs/get-started/meta.json +9 -1
  19. package/site/content/docs/get-started/project-structure.mdx +4 -11
  20. package/site/content/docs/get-started/testing.mdx +328 -0
  21. package/site/content/docs/get-started/why.mdx +93 -71
  22. package/site/content/docs/index.mdx +44 -11
  23. package/site/content/docs/meta.json +8 -5
  24. package/site/content/docs/plugins/apple.mdx +151 -0
  25. package/site/content/docs/plugins/discord.mdx +139 -0
  26. package/site/content/docs/plugins/facebook.mdx +134 -0
  27. package/site/content/docs/plugins/figma.mdx +138 -0
  28. package/site/content/docs/plugins/github.mdx +138 -0
  29. package/site/content/docs/plugins/google.mdx +153 -0
  30. package/site/content/docs/plugins/index.mdx +47 -1
  31. package/site/content/docs/plugins/meta.json +10 -0
  32. package/site/content/docs/plugins/microsoft.mdx +151 -0
  33. package/site/content/docs/plugins/oauth.mdx +188 -0
  34. package/site/content/docs/plugins/x.mdx +125 -0
  35. package/site/content/docs/providers/index.mdx +2 -0
  36. package/site/content/docs/recipes/index.mdx +2 -0
  37. package/site/content/docs/reference/cli.md +3 -2
  38. package/site/content/docs/reference/client.mdx +58 -1
  39. package/site/content/docs/reference/configuration.mdx +2 -4
  40. package/site/content/docs/reference/fx.mdx +3 -1
  41. package/site/content/docs/reference/index.mdx +0 -5
  42. package/site/content/docs/reference/meta.json +2 -2
  43. package/site/content/docs/reference/okid.mdx +137 -0
  44. package/src/auth/bindings.ts +1 -1
  45. package/src/auth/config.ts +9 -0
  46. package/src/auth/identity-sql.ts +314 -0
  47. package/src/auth/identity.ts +140 -2
  48. package/src/auth/index.ts +17 -1
  49. package/src/auth/method-context.ts +3 -0
  50. package/src/auth/oauth-as/cimd.ts +132 -0
  51. package/src/auth/oauth-as/crypto.test.ts +101 -0
  52. package/src/auth/oauth-as/crypto.ts +393 -0
  53. package/src/auth/oauth-as/errors.ts +68 -0
  54. package/src/auth/oauth-as/http.test.ts +419 -0
  55. package/src/auth/oauth-as/http.ts +842 -0
  56. package/src/auth/oauth-as/stores.ts +61 -0
  57. package/src/auth/oauth-as/tables.ts +142 -0
  58. package/src/auth/tables.ts +0 -11
  59. package/src/bench/README.md +83 -0
  60. package/src/bench/REPORT.md +176 -0
  61. package/src/bench/g01-rls-stamp.bench.ts +194 -0
  62. package/src/bench/g02-clock-per-tenant.bench.ts +158 -0
  63. package/src/bench/g03-signal-once.bench.ts +157 -0
  64. package/src/bench/g03-signal-reconnect.bench.ts +254 -0
  65. package/src/bench/g03-signal-sse-memory.bench.ts +191 -0
  66. package/src/bench/g04-auth-vault-hotpath.bench.ts +170 -0
  67. package/src/bench/g05-sustained-full.bench.ts +265 -0
  68. package/src/bench/g06-mixed-load.bench.ts +260 -0
  69. package/src/bench/g07-vault-crypto.bench.ts +100 -0
  70. package/src/bench/g07-vault-rotate-under-read.bench.ts +285 -0
  71. package/src/bench/g08-conn-oversubscribe.bench.ts +194 -0
  72. package/src/bench/g08-store-kv-durable.bench.ts +133 -0
  73. package/src/bench/g08-store-sql.bench.ts +178 -0
  74. package/src/bench/g09-journal-sustained.bench.ts +203 -0
  75. package/src/bench/g10-observability-contention.bench.ts +246 -0
  76. package/src/bench/g11-cold-start-cycle.bench.ts +164 -0
  77. package/src/bench/g13-elements.bench.ts +427 -0
  78. package/src/bench/g14-graceful-shutdown.bench.ts +244 -0
  79. package/src/bench/g15-postgres-degradation.bench.ts +264 -0
  80. package/src/bench/g16-live-query-fanout.bench.ts +206 -0
  81. package/src/bench/lib/event-loop-lag.ts +26 -0
  82. package/src/bench/lib/infra.ts +60 -0
  83. package/src/bench/lib/report.ts +52 -0
  84. package/src/bench/lib/rss-sampler.ts +61 -0
  85. package/src/bench/lib/signal-pg.ts +88 -0
  86. package/src/bench/load-app.ts +337 -0
  87. package/src/bench/load-child.ts +108 -0
  88. package/src/bench/smoke.bench.ts +43 -0
  89. package/src/cli/competitor-mention-removal.test.ts +28 -0
  90. package/src/cli/doctor-fd.ts +117 -0
  91. package/src/cli/doctor.test.ts +192 -0
  92. package/src/cli/doctor.ts +129 -1
  93. package/src/client/create.ts +95 -1
  94. package/src/client/index.ts +9 -2
  95. package/src/client/transport.ts +11 -4
  96. package/src/client/use-live-query.ts +154 -0
  97. package/src/client-react/index.ts +15 -1
  98. package/src/client-react/live-resource.ts +246 -0
  99. package/src/client-react/use-live-query.test.ts +475 -0
  100. package/src/client-react/use-live-query.ts +530 -0
  101. package/src/compiler/extract.test.ts +518 -0
  102. package/src/compiler/extract.ts +386 -19
  103. package/src/console/server/invoke-user-flow.ts +2 -1
  104. package/src/console/ui-next/dist/assets/{access-page-DnWbnGzq.js → access-page-De7Lc2JC.js} +1 -1
  105. package/src/console/ui-next/dist/assets/{flows-page-BiZ4-6yQ.js → flows-page-RGy7VEA_.js} +1 -1
  106. package/src/console/ui-next/dist/assets/{index-C8NRK2R-.js → index-_rgpdVzo.js} +3 -3
  107. package/src/console/ui-next/dist/assets/{observability-page-CrB6vd1T.js → observability-page-Ds6pcnh-.js} +1 -1
  108. package/src/console/ui-next/dist/assets/{store-page-CS5-aETQ.js → store-page-02xOiqIK.js} +3 -3
  109. package/src/console/ui-next/dist/assets/{units-page-CjtdlW8l.js → units-page-4rHOePuE.js} +1 -1
  110. package/src/console/ui-next/dist/assets/{vault-page-C6Xxm9SA.js → vault-page-DISPgxLM.js} +1 -1
  111. package/src/console/ui-next/dist/index.html +1 -1
  112. package/src/console/ui-next/src/features/store/lib/fields-from-table.ts +36 -2
  113. package/src/drivers/cdc-outbox.ts +389 -0
  114. package/src/drivers/memory.ts +20 -0
  115. package/src/drivers/oauth-apple.ts +156 -0
  116. package/src/drivers/oauth-discord.ts +79 -0
  117. package/src/drivers/oauth-facebook.ts +80 -0
  118. package/src/drivers/oauth-figma.ts +116 -0
  119. package/src/drivers/oauth-github.ts +92 -0
  120. package/src/drivers/oauth-google.ts +142 -0
  121. package/src/drivers/oauth-microsoft.ts +174 -0
  122. package/src/drivers/oauth-oidc.ts +293 -0
  123. package/src/drivers/oauth-shared.ts +326 -0
  124. package/src/drivers/oauth-types.ts +159 -0
  125. package/src/drivers/oauth-x.ts +77 -0
  126. package/src/drivers/oauth2-common.ts +95 -0
  127. package/src/drivers/oauth2-token.ts +61 -0
  128. package/src/drivers/pg-rls-row-passes.ts +251 -0
  129. package/src/drivers/pg-rls.ts +2 -0
  130. package/src/drivers/postgres.ts +45 -2
  131. package/src/drivers/signal-postgres.ts +2 -1
  132. package/src/elements/channel/runtime.ts +29 -2
  133. package/src/elements/channel.test.ts +52 -0
  134. package/src/elements/gate/boot.ts +29 -2
  135. package/src/elements/store/emit-drizzle.ts +147 -14
  136. package/src/elements/store/field-ddl.test.ts +118 -0
  137. package/src/elements/store/field-types.test.ts +455 -0
  138. package/src/elements/store/list-query.golden.json +777 -0
  139. package/src/elements/store/list-query.parity.test.ts +396 -0
  140. package/src/elements/store/list-query.ts +792 -0
  141. package/src/elements/store/live-default.test.ts +136 -0
  142. package/src/elements/store/live-http.test.ts +160 -0
  143. package/src/elements/store/live-isolation.test.ts +291 -0
  144. package/src/elements/store/live-query-runtime.test.ts +323 -0
  145. package/src/elements/store/live-query-runtime.ts +403 -0
  146. package/src/elements/store/live-query-server.test.ts +377 -0
  147. package/src/elements/store/live-query-server.ts +102 -0
  148. package/src/elements/store/live-query.ts +97 -0
  149. package/src/elements/store/resource.ts +189 -680
  150. package/src/elements/store/rls-row-passes-policies.parity.test.ts +665 -0
  151. package/src/elements/store/schema-decl.ts +539 -41
  152. package/src/elements/store/sql-rls-stamp.test.ts +27 -0
  153. package/src/elements/store/sql-session.ts +297 -35
  154. package/src/elements/store/table.ts +102 -21
  155. package/src/elements/store.test.ts +3 -1
  156. package/src/elements/store.ts +12 -1
  157. package/src/elements/vault/chaos-child.ts +74 -1
  158. package/src/elements/vault/chaos.test.ts +4 -2
  159. package/src/elements/vault/storage.ts +4 -2
  160. package/src/index.ts +5 -2
  161. package/src/kernel/app-auth.ts +1 -0
  162. package/src/kernel/app.ts +116 -2
  163. package/src/kernel/auth-sharing.test.ts +196 -0
  164. package/src/kernel/boot.test.ts +3 -3
  165. package/src/kernel/errors.ts +8 -0
  166. package/src/kernel/fx.test.ts +1 -0
  167. package/src/kernel/fx.ts +14 -2
  168. package/src/kernel/horizontal-child.ts +2 -1
  169. package/src/kernel/http-resource.ts +33 -7
  170. package/src/kernel/identity-host-persist.test.ts +119 -0
  171. package/src/kernel/instance-id.ts +4 -2
  172. package/src/kernel/journal.ts +2 -1
  173. package/src/kernel/mcp-tool.test.ts +95 -0
  174. package/src/kernel/on.ts +9 -0
  175. package/src/kernel/realtime-bind.ts +326 -0
  176. package/src/kernel/resource-live.ts +117 -0
  177. package/src/kernel/triggers.ts +86 -4
  178. package/src/manifest/diff.ts +37 -0
  179. package/src/manifest/types.ts +64 -2
  180. package/src/okid.bench.test.ts +64 -0
  181. package/src/okid.test.ts +338 -0
  182. package/src/okid.ts +245 -0
  183. package/src/plugins/anonymous.ts +19 -1
  184. package/src/plugins/auth/shared.ts +15 -0
  185. package/src/plugins/index.ts +2 -0
  186. package/src/plugins/magic-link.ts +10 -8
  187. package/src/plugins/mcp-oauth.ts +208 -0
  188. package/src/plugins/oauth/flow-store.ts +117 -0
  189. package/src/plugins/oauth/link.ts +69 -0
  190. package/src/plugins/oauth/shared.ts +108 -0
  191. package/src/plugins/oauth/token-vault.ts +100 -0
  192. package/src/plugins/oauth.security.test.ts +535 -0
  193. package/src/plugins/oauth.ts +532 -0
  194. package/src/plugins/otp.ts +48 -6
  195. package/src/plugins/passkey.ts +20 -1
  196. package/src/plugins/two-factor.ts +11 -0
  197. package/src/plugins/username.ts +40 -7
  198. package/src/release/build-lib.ts +7 -1
  199. package/src/release/measure.ts +1 -0
  200. package/src/release/official-plugins.ts +4 -1
  201. package/src/runs/collect.ts +2 -1
  202. package/src/runs/drivers/files.ts +2 -1
  203. package/src/test/create-test-app.ts +114 -5
  204. package/src/test/export-bundle.test.ts +33 -0
  205. package/src/test/live-signals.test.ts +83 -0
  206. package/src/test/tenant-isolation.test.ts +175 -0
  207. package/src/testing.ts +26 -0
  208. package/src/upgrade/codemods.ts +1 -1
  209. package/site/content/docs/reference/migrating-environments.mdx +0 -158
package/AGENTS.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # OKE — Agent Contract
2
2
 
3
+ One law. Eight elements. One contract. The backend model stays small; operational surfaces are derived from it instead of maintained separately.
4
+
3
5
  This file is loaded by every later session. It prevents drift. Product documentation lives in `site/content/docs/`. **If the documentation is silent, stop and ask.**
4
6
 
5
7
  ## The one law
@@ -27,13 +29,13 @@ There are no separate species called endpoints, handlers, consumers, jobs, subsc
27
29
 
28
30
  An element earns its place only if it has irreducible physics. New infrastructure becomes a new **driver** for an existing element — never a ninth element.
29
31
 
30
- ## The ten exports
32
+ ## Core programming vocabulary
31
33
 
32
34
  ```typescript
33
35
  import { on, flow, signal, store, clock, gate, vault, channel, ai, plugin } from "okengine";
34
36
  ```
35
37
 
36
- That is the entire public vocabulary. Everything else is derived.
38
+ That is the core programming vocabulary. Everything else is derived.
37
39
 
38
40
  ## Governing rule
39
41
 
@@ -80,7 +82,7 @@ Published packages:
80
82
  - `okengine` — framework. Subpath exports: `.`, `./client`, `./test`, `./config`, `./auth`, `./plugins`, `./drivers/*`. `"sideEffects": false`. CLI binary: `oke`.
81
83
  - `create-oke` — scaffold CLI (`bunx create-oke@latest <name>`). Lives in `packages/create-oke` and ships Notes starters from `packages/create-oke/templates/{standard,advanced}`.
82
84
 
83
- Engine: Bun `>=1.3.14`.
85
+ Engine: Bun `>=1.4.0`.
84
86
 
85
87
  ## Documentation authority
86
88
 
package/README.md CHANGED
@@ -2,11 +2,11 @@
2
2
  <picture>
3
3
  <source
4
4
  media="(prefers-color-scheme: dark)"
5
- srcset="https://shieldcn.dev/header/grid.svg?title=okengine&subtitle=One+law.+Eight+elements.+Ten+exports.&logo=https://raw.githubusercontent.com/omqkhafi/okengine/main/site/public/logo/OKE-W.svg&theme=zinc&size=banner&mode=dark&font=geist&align=left"
5
+ srcset="https://shieldcn.dev/header/grid.svg?title=okengine&subtitle=One+law.+Eight+elements.+One+contract.&logo=https://raw.githubusercontent.com/omqkhafi/okengine/main/site/public/logo/OKE-W.svg&theme=zinc&size=banner&mode=dark&font=geist&align=left"
6
6
  />
7
7
  <img
8
- alt="okengine — One law. Eight elements. Ten exports."
9
- src="https://shieldcn.dev/header/grid.svg?title=okengine&subtitle=One+law.+Eight+elements.+Ten+exports.&logo=https://raw.githubusercontent.com/omqkhafi/okengine/main/site/public/logo/OKE-B.svg&theme=zinc&size=banner&mode=light&font=geist&align=left"
8
+ alt="okengine — One law. Eight elements. One contract."
9
+ src="https://shieldcn.dev/header/grid.svg?title=okengine&subtitle=One+law.+Eight+elements.+One+contract.&logo=https://raw.githubusercontent.com/omqkhafi/okengine/main/site/public/logo/OKE-B.svg&theme=zinc&size=banner&mode=light&font=geist&align=left"
10
10
  width="750"
11
11
  />
12
12
  </picture>
@@ -16,13 +16,13 @@
16
16
  <a href="https://www.npmjs.com/package/okengine"><img alt="npm" src="https://shieldcn.dev/npm/okengine.svg?size=sm&variant=outline" /></a>
17
17
  <a href="https://jsr.io/@omqkhafi/okengine"><img alt="JSR" src="https://shieldcn.dev/jsr/@omqkhafi/okengine.svg?size=sm&variant=outline" /></a>
18
18
  <a href="https://opensource.org/licenses/MIT"><img alt="MIT" src="https://shieldcn.dev/npm/license/okengine.svg?size=sm&variant=outline" /></a>
19
- <a href="https://bun.sh"><img alt="Bun >=1.3.14" src="https://shieldcn.dev/badge/Bun-%3E%3D1.3.14.svg?logo=bun&size=sm&variant=outline" /></a>
19
+ <a href="https://bun.sh"><img alt="Bun >=1.4.0" src="https://shieldcn.dev/badge/Bun-%3E%3D1.4.0.svg?logo=bun&size=sm&variant=outline" /></a>
20
20
  <a href="https://github.com/omqkhafi/okengine/actions"><img alt="CI" src="https://shieldcn.dev/github/ci/omqkhafi/okengine.svg?size=sm&variant=outline" /></a>
21
21
  <a href="https://github.com/omqkhafi/okengine/commits"><img alt="last commit" src="https://shieldcn.dev/github/last-commit/omqkhafi/okengine.svg?size=sm&variant=outline" /></a>
22
22
  </p>
23
23
 
24
24
  <p align="center">
25
- <em>Stop gluing APIs, jobs, and queues into one backend. One law collapses them — client, Console, and infra come free. Yours to host.</em>
25
+ <em>Modern backends became a pile of disconnected systems. One law collapses them — client, Console, and infra derived from one contract. Yours to host.</em>
26
26
  </p>
27
27
 
28
28
  <p align="center">
@@ -39,7 +39,7 @@
39
39
 
40
40
  ## Install
41
41
 
42
- Requires [Bun](https://bun.sh) `>=1.3.14`.
42
+ Requires [Bun](https://bun.sh) `>=1.4.0`.
43
43
 
44
44
  ```bash
45
45
  bunx create-oke@latest my-app # scaffold (recommended)
@@ -69,12 +69,13 @@ Mnemonic: **O·K·E = 6·5·3**.
69
69
  The starter already exports a health Flow — change it and save; App and Console update from the same Manifest:
70
70
 
71
71
  ```typescript
72
- import { on, flow, http, gate } from "okengine";
72
+ // src/flows/main/health.ts folders are the URL: `main/health.ts` → GET /health
73
+ import { on, flow, http } from "okengine";
73
74
  import { z } from "zod";
74
75
 
75
76
  export const health = on(
76
- http.get("/health").gate(gate.public),
77
- flow("health.check", {
77
+ http.get().public(),
78
+ flow({
78
79
  out: z.object({ ok: z.literal(true) }),
79
80
  do: () => ({ ok: true as const }),
80
81
  }),
@@ -91,6 +92,8 @@ const api = createClient<App>("http://localhost:6530");
91
92
  const { data, error } = await api.main.health({});
92
93
  ```
93
94
 
95
+ Native ids: import `okid` from `okengine/okid` — compact, URL-safe, cryptographically random (`okid()`, `okid(16)`, `okid({ sortable: true })`).
96
+
94
97
  Full walkthrough: [Basic usage](https://oke.omqkhafi.dev/docs/get-started/basic-usage).
95
98
 
96
99
  ## One law
@@ -101,7 +104,7 @@ Every backend behavior is a Flow: `on(Trigger) → Effects`. Endpoints, jobs, co
101
104
  import { on, flow, signal, store, clock, gate, vault, channel, ai, plugin } from "okengine";
102
105
  ```
103
106
 
104
- That is the entire public vocabulary. World access goes through `fx` — effects are inferred, so the Manifest can derive the typed client, Console, and MCP without a second source of truth.
107
+ That is the core programming vocabulary. World access goes through `fx` — effects are inferred, so the Manifest can derive the typed client, Console, and MCP without a second source of truth.
105
108
 
106
109
  | Element | Essence |
107
110
  | ----------- | ----------------------------- |
@@ -140,6 +143,7 @@ Store apps sync schema with `oke db push|generate|migrate` (local `oke dev` auto
140
143
  | Agents index | [/llms.txt](https://oke.omqkhafi.dev/llms.txt) |
141
144
  | Manifest | [`manifest.v1.schema.json`](manifest.v1.schema.json) |
142
145
  | Budgets | [`BUDGETS.md`](BUDGETS.md) |
146
+ | Security | [`SECURITY.md`](SECURITY.md) |
143
147
  | Contributing | [`CONTRIBUTING.md`](CONTRIBUTING.md) |
144
148
 
145
149
  ## License
@@ -219,7 +219,17 @@
219
219
  "signal": { "type": "string", "minLength": 1 },
220
220
  "cron": { "type": "string", "minLength": 1 },
221
221
  "every": { "type": "string", "minLength": 1 },
222
- "cdc": { "$ref": "#/$defs/CdcTrigger" }
222
+ "cdc": { "$ref": "#/$defs/CdcTrigger" },
223
+ "mcp": { "$ref": "#/$defs/McpTrigger" }
224
+ }
225
+ },
226
+ "McpTrigger": {
227
+ "description": "Explicit MCP tool exposure. Presence means the flow is listed over MCP for OAuth user-plane clients; absence means not an MCP tool (deny-by-default).",
228
+ "type": "object",
229
+ "required": ["name"],
230
+ "additionalProperties": false,
231
+ "properties": {
232
+ "name": { "type": "string", "minLength": 1 }
223
233
  }
224
234
  },
225
235
  "Slo": {
@@ -378,7 +388,38 @@
378
388
  "type": "object",
379
389
  "additionalProperties": false,
380
390
  "properties": {
381
- "type": { "type": "string", "enum": ["text", "integer"] },
391
+ "type": {
392
+ "type": "string",
393
+ "enum": [
394
+ "text",
395
+ "varchar",
396
+ "char",
397
+ "boolean",
398
+ "smallint",
399
+ "integer",
400
+ "bigint",
401
+ "serial",
402
+ "smallserial",
403
+ "bigserial",
404
+ "numeric",
405
+ "real",
406
+ "doublePrecision",
407
+ "json",
408
+ "jsonb",
409
+ "uuid",
410
+ "time",
411
+ "timestamp",
412
+ "date",
413
+ "interval",
414
+ "point",
415
+ "line",
416
+ "bytea",
417
+ "inet",
418
+ "cidr",
419
+ "macaddr",
420
+ "macaddr8"
421
+ ]
422
+ },
382
423
  "nullable": { "type": "boolean" },
383
424
  "primaryKey": { "type": "boolean" },
384
425
  "unique": { "type": "boolean" },
@@ -390,6 +431,24 @@
390
431
  { "type": "null" }
391
432
  ]
392
433
  },
434
+ "enumValues": {
435
+ "description": "Allowed string values for enum columns (text/varchar/char).",
436
+ "type": "array",
437
+ "items": { "type": "string" },
438
+ "minItems": 1
439
+ },
440
+ "length": { "description": "varchar/char max length.", "type": "integer", "minimum": 1 },
441
+ "precision": {
442
+ "description": "Fractional-second digits (time/timestamp, 0-6) or interval precision.",
443
+ "type": "integer"
444
+ },
445
+ "scale": { "description": "numeric(p, s) scale digits.", "type": "integer" },
446
+ "withTimezone": { "description": "time/timestamp timezone flavor.", "type": "boolean" },
447
+ "mode": {
448
+ "description": "JS mapping selector for temporal/numeric/point/line/bigint columns.",
449
+ "type": "string"
450
+ },
451
+ "fields": { "description": "interval field qualifier.", "type": "string" },
393
452
  "sqlName": { "type": "string", "minLength": 1 },
394
453
  "description": {
395
454
  "description": "Optional human description; consumers fall back to the column map key.",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "okengine",
3
- "version": "0.17.2",
4
- "description": "One law. Eight elements. Ten exports. One package. One manifest. Every backend need is derived, never added.",
3
+ "version": "0.18.4",
4
+ "description": "One law. Eight elements. One contract. The backend model stays small; operational surfaces are derived from it instead of maintained separately.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -72,6 +72,12 @@
72
72
  "./client/auth": "./src/client/auth.ts",
73
73
  "./client-react": "./src/client-react/index.ts",
74
74
  "./test": "./src/test/index.ts",
75
+ "./testing": {
76
+ "types": "./src/testing.ts",
77
+ "bun": "./src/testing.ts",
78
+ "import": "./dist/testing.js",
79
+ "default": "./dist/testing.js"
80
+ },
75
81
  "./config": "./src/config/index.ts",
76
82
  "./auth": "./src/auth/index.ts",
77
83
  "./console": "./src/console/index.ts",
@@ -86,7 +92,13 @@
86
92
  "./ai": "./src/elements/ai.ts",
87
93
  "./runs": "./src/runs/index.ts",
88
94
  "./drivers": "./src/drivers/index.ts",
89
- "./drivers/*": "./src/drivers/*"
95
+ "./drivers/*": "./src/drivers/*",
96
+ "./okid": {
97
+ "types": "./src/okid.ts",
98
+ "bun": "./src/okid.ts",
99
+ "import": "./dist/okid.js",
100
+ "default": "./dist/okid.js"
101
+ }
90
102
  },
91
103
  "scripts": {
92
104
  "typecheck": "tsc --noEmit && tsc --noEmit -p tests/console/tsconfig.ui-next.json && tsc --noEmit -p src/console/ui-next && bun run --cwd packages/create-oke typecheck && bun run --cwd examples/keel typecheck",
@@ -112,7 +124,8 @@
112
124
  "test:keel:docker": "OKE_TEST_DOCKER=1 bun run --cwd examples/keel test",
113
125
  "build:lib": "bun src/release/build-lib.ts",
114
126
  "prepack": "bun run build && bun run build:lib",
115
- "bench": "bun test ./src/runtime/cold-start.bench.ts src/client/budget.test.ts src/console/budget.test.ts src/kernel/budget.test.ts src/kernel/routing-budget.test.ts src/runs/bench.test.ts",
127
+ "bench": "bun test ./src/runtime/cold-start.bench.ts src/client/budget.test.ts src/console/budget.test.ts src/kernel/budget.test.ts src/kernel/routing-budget.test.ts src/runs/bench.test.ts src/okid.bench.test.ts",
128
+ "bench:load": "OKE_BENCH=1 bun test ./src/bench/*.bench.ts --timeout 600000 --pass-with-no-tests",
116
129
  "budgets": "bun src/release/publish.ts",
117
130
  "gate": "PUBLISH_GATE=1 bun test src/cli/doc-staleness.test.ts src/cli/competitor-mention-removal.test.ts src/drivers/vault-driver-removal.test.ts src/kernel/errors.registry.test.ts src/upgrade/codemods.test.ts scripts/publish.gate.test.ts",
118
131
  "dev": "bun run --cwd site dev",
@@ -121,7 +134,8 @@
121
134
  "ci": "bun scripts/ci.ts",
122
135
  "bump": "bun run scripts/bump-version.ts",
123
136
  "release": "bun run scripts/publish.ts",
124
- "g": "gflows"
137
+ "g": "gflows",
138
+ "postinstall": "bun run --cwd examples/keel prepare"
125
139
  },
126
140
  "dependencies": {
127
141
  "@clack/prompts": "^1.7.0",
@@ -5,7 +5,7 @@ icon: "Bot"
5
5
  source: "docs/spec/unified-theory.md"
6
6
  ---
7
7
 
8
- Resources for AI agents that read or operate an OKE app — not the `ai` element itself.
8
+ Resources for AI agents that read or operate an OKE app — not the `ai` element itself. In OKE, **MCP is a surface of the model, not the model itself**. Gate governs agents calling in; the AI element governs apps calling out.
9
9
 
10
10
  ## Pages
11
11
 
@@ -5,7 +5,16 @@ icon: "Plug"
5
5
  source: "docs/spec/unified-theory.md"
6
6
  ---
7
7
 
8
- Two directions, same protocol. **Serve:** OKE exposes your running app on port **6535** so an agent can read the Manifest and take confirmed actions. **Consume:** your Flows call _external_ MCP servers as tools — declared on `ai.mcpServer`, dispatched through `fx.call`.
8
+ ## Two directions, same execution model
9
+
10
+ > **MCP is a surface of the model, not the model itself.**
11
+
12
+ Two genuinely distinct things share the protocol in OKE:
13
+
14
+ 1. **Gate Element (MCP Provider role):** Your app exposes Flows as MCP tools on port **6535** (or via `mcp.tool()` + OAuth 2.1 Authorization Server) so external AI agents (Claude, ChatGPT) can read the Manifest and call declared Flows.
15
+ 2. **AI Element (MCP Client role):** Your app consumes _external_ MCP tool servers via `ai.mcpServer(...)`, routing tool calls through `fx.call` inside prompts and agents.
16
+
17
+ OKE does not create separate security models for users, operators, and agents. They enter the same execution model through different triggers and planes.
9
18
 
10
19
  The server on **6535** speaks JSON-RPC over HTTP (MCP protocol `2024-11-05`), requires a Bearer token **even on localhost**, and never forwards that token upstream — adapters receive structured operator ids instead.
11
20
 
@@ -9,18 +9,18 @@ Tools alone don't make a good operator — an agent also needs to know the _voca
9
9
 
10
10
  ## The layers
11
11
 
12
- | Layer | Path | Loaded when | Teaches |
13
- | ------------------ | ---------------------------- | ------------------------------------------------- | --------------------------------------------------------------------- |
14
- | **Agent contract** | `AGENTS.md` (repo root) | Every agent session, automatically | The one law, eight elements, ten exports, the fx rule, ports, budgets |
15
- | **Element skill** | `.agents/skills/oke/` | Building or changing an okengine app | The element contract in depth — declaration patterns per element |
16
- | **Docs skill** | `.agents/skills/oke-docs/` | Writing or editing docs under `site/content/docs` | The documentation information-architecture standard and its gates |
17
- | **Ship skill** | `.agents/skills/oke-ship/` | After any implementation, before claiming done | Changelog under `## Unreleased` + docs sync via `oke-docs` |
18
- | **Deps skill** | `.agents/skills/oke-deps/` | Updating `package.json` dependencies | Scoped bumps, Bun install, pins (Drizzle RC, fumadocs alias, …) |
19
- | **Images skill** | `.agents/skills/oke-images/` | Updating Compose image pins | Registry probe, pin style, catalog + recipes + Keel + docs lockstep |
12
+ | Layer | Path | Loaded when | Teaches |
13
+ | ------------------ | ---------------------------- | ------------------------------------------------- | ---------------------------------------------------------------------- |
14
+ | **Agent contract** | `AGENTS.md` (repo root) | Every agent session, automatically | The one law, eight elements, one contract, the fx rule, ports, budgets |
15
+ | **Element skill** | `.agents/skills/oke/` | Building or changing an okengine app | The element contract in depth — declaration patterns per element |
16
+ | **Docs skill** | `.agents/skills/oke-docs/` | Writing or editing docs under `site/content/docs` | The documentation information-architecture standard and its gates |
17
+ | **Ship skill** | `.agents/skills/oke-ship/` | After any implementation, before claiming done | Changelog under `## Unreleased` + docs sync via `oke-docs` |
18
+ | **Deps skill** | `.agents/skills/oke-deps/` | Updating `package.json` dependencies | Scoped bumps, Bun install, pins (Drizzle RC, fumadocs alias, …) |
19
+ | **Images skill** | `.agents/skills/oke-images/` | Updating Compose image pins | Registry probe, pin style, catalog + recipes + Keel + docs lockstep |
20
20
 
21
21
  ## AGENTS.md — the root contract
22
22
 
23
- Every OKE app's repo carries an `AGENTS.md` that agents (Cursor, Claude Code, and peers) read at session start. It is deliberately short and absolute: every backend behavior is a Flow (`on(Trigger) → Effects`), there are eight elements and ten exports, all world access goes through `fx`, drivers are named after protocols, and the ports/budgets are fixed. Its closing rule is the one that keeps agents honest: **if the documentation is silent, stop and ask** — never invent the API.
23
+ Every OKE app's repo carries an `AGENTS.md` that agents (Cursor, Claude Code, and peers) read at session start. It is deliberately short and absolute: every backend behavior is a Flow (`on(Trigger) → Effects`), there are eight elements bound to one contract, all world access goes through `fx`, drivers are named after protocols, and the ports/budgets are fixed. Its closing rule is the one that keeps agents honest: **if the documentation is silent, stop and ask** — never invent the API.
24
24
 
25
25
  ## Skills — installable know-how
26
26
 
@@ -129,7 +129,7 @@ const result = await fx.ask(triage, input, {
129
129
  });
130
130
  ```
131
131
 
132
- External MCP tools take the same path. Declare a server with a **required** allowlist, then pass `server.tool("…")` — never whatever `tools/list` happens to expose:
132
+ External MCP tools take the same path. In OKE, **MCP is a surface of the model, not the model itself** — `ai.mcpServer` models the client role (consuming external tools), while `mcp.tool()` + Gate models the provider role (exposing your flows to agents). Declare a server with a **required** allowlist, then pass `server.tool("…")` — never whatever `tools/list` happens to expose:
133
133
 
134
134
  ```typescript
135
135
  export const github = ai.mcpServer("github", {
@@ -141,7 +141,7 @@ reclaimed after its lease expires and continues at the next unfinished step.
141
141
  | Guarantee | What it means |
142
142
  | ------------------ | -------------------------------------------------------------------------------------------------- |
143
143
  | Leader election | Instances that share one CronStore fire a given tick once (lease TTL, default 30s) |
144
- | Process identity | Boot mints one `instanceId` (`inst-<uuid>`) for Clock, Journal, and the fleet registry |
144
+ | Process identity | Boot mints one `instanceId` (`inst-<okid>`) for Clock, Journal, and the fleet registry |
145
145
  | Catch-up `"one"` | Health counts every missed slot; the runtime still fires **once** when overdue — not once per miss |
146
146
  | Reconciled at boot | Named clocks land in `oke_crons`; the scheduler reads the Store, not the source |
147
147
  | DST detection | Ambiguous local times get a Console warning — schedules are not rewritten or blocked |
@@ -111,7 +111,7 @@ Built-in codes attach a localized `message` ([Errors](/docs/reference/errors));
111
111
  — that is the `as never` trap. See [fx](/docs/reference/fx).
112
112
  </Callout>
113
113
 
114
- ## The five triggers
114
+ ## The triggers
115
115
 
116
116
  <FlowTriggers />
117
117
 
@@ -201,6 +201,30 @@ export const getOrder = flow("orders.get", {
201
201
  const order = await fx.call(getOrder, { id: orderId }); // from any other flow
202
202
  ```
203
203
 
204
+ ### mcp — an agent calls a tool
205
+
206
+ `mcp.tool(name)` marks a flow for **OAuth-protected user-plane** exposure over MCP. Deny-by-default: a flow without this trigger is never listed over `tools/list`. A gate is required, exactly like a sensitive HTTP route:
207
+
208
+ ```typescript
209
+ export const createBooking = on(
210
+ mcp.tool("bookings.create").gate(member), // gates required — deny-by-default
211
+ flow("bookings.create", {
212
+ plane: "user",
213
+ in: BookingRef,
214
+ out: Booking,
215
+ do: async ({ id }, fx) => {
216
+ /* … */
217
+ },
218
+ }),
219
+ );
220
+ ```
221
+
222
+ - The tool name is namespaced (`bookings.create`) and appears in the Manifest under `trigger.mcp.name` with its gates.
223
+ - Binding the **same tool name** twice fails boot with **OKE1018** (`MCP tool "{tool}" is bound twice`).
224
+ - Ungated `mcp.tool(...)` fails gate posture at boot (`GateBootError`) — the trigger never exposes an unauthenticated tool.
225
+
226
+ This is one direction of [MCP](/docs/ai/mcp): exposing your flows as tools. The other is consuming external servers as `ai.mcpServer` tools via `fx.ask` / `ai.agent`.
227
+
204
228
  ## fx — the only door
205
229
 
206
230
  Everything a flow may touch, on one object:
@@ -9,6 +9,8 @@ Gate answers **"may this happen?"** before it happens: is this a verified member
9
9
  burned its minute quota? Attach gates to the HTTP trigger — the pipeline checks them before a
10
10
  store write, emit, or channel send runs.
11
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
+
12
14
  <Callout title="The one rule">
13
15
  Every HTTP trigger declares posture: attach a real gate, or attach `.public()`. Omitting both
14
16
  fails boot. Denial is a typed error value — never a thrown exception mid-`do`.
@@ -63,8 +65,7 @@ import { member, canBook, fair } from "../../gates";
63
65
  export const health = on(
64
66
  http.get("/health").public(),
65
67
  flow("health.check", {
66
- out: HealthOut,
67
- do: () => ({ ok: true as const }),
68
+ do: () => ({ ok: true }),
68
69
  }),
69
70
  );
70
71