okengine 0.2.6 → 0.3.2

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 (681) hide show
  1. package/AGENTS.md +33 -30
  2. package/README.md +74 -340
  3. package/{spec/manifest.v1.schema.json → manifest.v1.schema.json} +40 -9
  4. package/package.json +47 -44
  5. package/site/content/docs/ai/llms-txt.mdx +54 -0
  6. package/site/content/docs/ai/mcp.mdx +123 -0
  7. package/site/content/docs/ai/meta.json +5 -0
  8. package/site/content/docs/ai/skills.mdx +53 -0
  9. package/site/content/docs/console/access.mdx +29 -0
  10. package/site/content/docs/console/ai.mdx +35 -0
  11. package/site/content/docs/console/architecture.mdx +35 -0
  12. package/site/content/docs/console/channels.mdx +37 -0
  13. package/site/content/docs/console/clock.mdx +31 -0
  14. package/site/content/docs/console/flows.mdx +31 -0
  15. package/site/content/docs/console/gates.mdx +35 -0
  16. package/site/content/docs/console/manifest-diff.mdx +34 -0
  17. package/site/content/docs/console/meta.json +23 -0
  18. package/site/content/docs/console/overview.mdx +40 -0
  19. package/site/content/docs/console/plugins.mdx +41 -0
  20. package/site/content/docs/console/privacy.mdx +32 -0
  21. package/site/content/docs/console/runs.mdx +40 -0
  22. package/site/content/docs/console/signals.mdx +31 -0
  23. package/site/content/docs/console/store.mdx +32 -0
  24. package/site/content/docs/console/tenancy.mdx +32 -0
  25. package/site/content/docs/console/traces.mdx +34 -0
  26. package/site/content/docs/console/vault.mdx +37 -0
  27. package/site/content/docs/elements/ai.mdx +180 -0
  28. package/site/content/docs/elements/channel.mdx +167 -0
  29. package/site/content/docs/elements/clock.mdx +182 -0
  30. package/site/content/docs/elements/flow.mdx +288 -0
  31. package/site/content/docs/elements/gate.mdx +171 -0
  32. package/site/content/docs/elements/meta.json +5 -0
  33. package/site/content/docs/elements/signal.mdx +171 -0
  34. package/site/content/docs/elements/store.mdx +320 -0
  35. package/site/content/docs/elements/vault.mdx +263 -0
  36. package/site/content/docs/get-started/basic-usage.mdx +124 -0
  37. package/site/content/docs/get-started/comparison.mdx +65 -0
  38. package/site/content/docs/get-started/installation.mdx +113 -0
  39. package/site/content/docs/get-started/introduction.mdx +123 -0
  40. package/site/content/docs/get-started/meta.json +5 -0
  41. package/site/content/docs/index.mdx +63 -0
  42. package/site/content/docs/meta.json +5 -0
  43. package/site/content/docs/plugins/compression.mdx +60 -0
  44. package/site/content/docs/plugins/cors.mdx +92 -0
  45. package/site/content/docs/plugins/csrf.mdx +96 -0
  46. package/site/content/docs/plugins/ip-allowlist.mdx +92 -0
  47. package/site/content/docs/plugins/maintenance-mode.mdx +101 -0
  48. package/site/content/docs/plugins/meta.json +15 -0
  49. package/site/content/docs/plugins/security-headers.mdx +136 -0
  50. package/site/content/docs/reference/cli.md +101 -0
  51. package/site/content/docs/reference/configuration.mdx +159 -0
  52. package/site/content/docs/reference/environment-variables.mdx +87 -0
  53. package/site/content/docs/reference/errors.mdx +80 -0
  54. package/site/content/docs/reference/fx.mdx +117 -0
  55. package/site/content/docs/reference/meta.json +5 -0
  56. package/site/content/docs/reference/plugins.mdx +249 -0
  57. package/site/content/docs/reference/security.md +63 -0
  58. package/src/auth/api-keys.ts +2 -5
  59. package/src/auth/attenuation.ts +2 -6
  60. package/src/auth/auth.test.ts +56 -31
  61. package/src/auth/invoke-as.ts +1 -3
  62. package/src/auth/operator.ts +8 -26
  63. package/src/auth/planes.ts +2 -7
  64. package/src/auth/plugin.ts +4 -7
  65. package/src/auth/roles.ts +1 -5
  66. package/src/auth/sessions.ts +10 -39
  67. package/src/cli/args.ts +1 -5
  68. package/src/cli/ask-dev-mode.ts +40 -0
  69. package/src/cli/build.ts +1 -2
  70. package/src/cli/client-add.test.ts +8 -15
  71. package/src/cli/client-add.ts +5 -14
  72. package/src/cli/completion.test.ts +1 -5
  73. package/src/cli/completion.ts +4 -17
  74. package/src/cli/db-auto-push.test.ts +64 -0
  75. package/src/cli/db-auto-push.ts +72 -0
  76. package/src/cli/db.test.ts +189 -0
  77. package/src/cli/db.ts +456 -0
  78. package/src/cli/dev-app-runner.ts +2 -8
  79. package/src/cli/dev-db-push.test.ts +193 -0
  80. package/src/cli/dev-mode.test.ts +45 -0
  81. package/src/cli/dev-mode.ts +78 -0
  82. package/src/cli/dev-schema-sync.test.ts +66 -0
  83. package/src/cli/dev-schema-sync.ts +139 -0
  84. package/src/cli/dev.test.ts +264 -15
  85. package/src/cli/dev.ts +355 -139
  86. package/src/cli/doc-staleness.test.ts +69 -0
  87. package/src/cli/docker-cli.test.ts +27 -8
  88. package/src/cli/docker.ts +11 -3
  89. package/src/cli/doctor-diff.test.ts +1 -5
  90. package/src/cli/doctor-diff.ts +17 -46
  91. package/src/cli/doctor-pii.ts +2 -7
  92. package/src/cli/doctor.test.ts +26 -4
  93. package/src/cli/doctor.ts +35 -11
  94. package/src/cli/drizzle-env.test.ts +67 -0
  95. package/src/cli/drizzle-env.ts +78 -0
  96. package/src/cli/ensure-drizzle-config.ts +50 -0
  97. package/src/cli/eval.ts +4 -14
  98. package/src/cli/gates-list.ts +1 -4
  99. package/src/cli/hero-meta.test.ts +17 -19
  100. package/src/cli/hero-meta.ts +20 -30
  101. package/src/cli/images.ts +3 -8
  102. package/src/cli/index.ts +11 -2
  103. package/src/cli/load-config.images.test.ts +14 -14
  104. package/src/cli/load-config.ts +47 -47
  105. package/src/cli/mcp-from-console.ts +1 -4
  106. package/src/cli/mode.ts +65 -0
  107. package/src/cli/openbao-bootstrap.test.ts +147 -0
  108. package/src/cli/openbao-bootstrap.ts +280 -0
  109. package/src/cli/openbao-restart.integration.test.ts +136 -0
  110. package/src/cli/ports.test.ts +7 -14
  111. package/src/cli/ports.ts +7 -5
  112. package/src/cli/privacy-erase.ts +1 -3
  113. package/src/cli/registry.ts +75 -25
  114. package/src/cli/resolve-dev-sql-env.test.ts +48 -0
  115. package/src/cli/resolve-dev-sql-env.ts +42 -0
  116. package/src/cli/schema.ts +3 -10
  117. package/src/cli/stack.ts +8 -10
  118. package/src/cli/start.ts +4 -15
  119. package/src/cli/upgrade.ts +1 -4
  120. package/src/cli/vault-cmd.ts +63 -0
  121. package/src/client/budget-entry.ts +1 -6
  122. package/src/client/create.test.ts +6 -12
  123. package/src/client/create.ts +2 -8
  124. package/src/client/errors.ts +1 -4
  125. package/src/client/index.ts +1 -6
  126. package/src/client/notes-contract.test.ts +4 -13
  127. package/src/client/transport.ts +9 -30
  128. package/src/client/types.ts +15 -30
  129. package/src/compiler/aot.test.ts +2 -9
  130. package/src/compiler/aot.ts +1 -4
  131. package/src/compiler/differential.test.ts +3 -11
  132. package/src/compiler/dynamic.ts +1 -4
  133. package/src/compiler/effects-infer.ts +8 -34
  134. package/src/compiler/emit.ts +1 -3
  135. package/src/compiler/extract.test.ts +136 -30
  136. package/src/compiler/extract.ts +485 -157
  137. package/src/compiler/fixtures/skyport/oke.config.ts +3 -3
  138. package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +7 -3
  139. package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +1 -3
  140. package/src/compiler/fixtures/skyport/src/flows/support/index.ts +4 -1
  141. package/src/compiler/fixtures/skyport.expected.json +24 -83
  142. package/src/compiler/fixtures/triggers/five-triggers.ts +1 -2
  143. package/src/compiler/http-parse.ts +2 -9
  144. package/src/compiler/index.ts +1 -5
  145. package/src/compiler/response.ts +16 -7
  146. package/src/compiler/sucrose.ts +11 -31
  147. package/src/config/define-config.test.ts +55 -34
  148. package/src/config/index.ts +177 -46
  149. package/src/config/resolve-driver.test.ts +28 -17
  150. package/src/console/budget.test.ts +1 -4
  151. package/src/console/index.ts +1 -4
  152. package/src/console/server/access.test.ts +15 -43
  153. package/src/console/server/access.ts +19 -49
  154. package/src/console/server/ai.test.ts +3 -11
  155. package/src/console/server/ai.ts +23 -46
  156. package/src/console/server/app.ts +16 -45
  157. package/src/console/server/auth-rate.test.ts +4 -12
  158. package/src/console/server/bind.ts +1 -5
  159. package/src/console/server/channels.test.ts +2 -6
  160. package/src/console/server/channels.ts +10 -35
  161. package/src/console/server/claim.ts +2 -8
  162. package/src/console/server/clock.test.ts +2 -6
  163. package/src/console/server/clock.ts +8 -26
  164. package/src/console/server/console.test.ts +1 -3
  165. package/src/console/server/diff.test.ts +5 -17
  166. package/src/console/server/diff.ts +10 -31
  167. package/src/console/server/dry-run.audit.test.ts +2 -8
  168. package/src/console/server/flows.ts +64 -233
  169. package/src/console/server/gates.test.ts +14 -50
  170. package/src/console/server/gates.ts +13 -48
  171. package/src/console/server/index.ts +2 -9
  172. package/src/console/server/live.ts +3 -12
  173. package/src/console/server/operator-db.test.ts +4 -15
  174. package/src/console/server/operator-db.ts +13 -32
  175. package/src/console/server/plugin.ts +50 -53
  176. package/src/console/server/plugins.test.ts +2 -6
  177. package/src/console/server/plugins.ts +17 -56
  178. package/src/console/server/runs-pii.ts +2 -7
  179. package/src/console/server/security.gate.test.ts +18 -40
  180. package/src/console/server/serve.ts +10 -25
  181. package/src/console/server/signals.test.ts +1 -3
  182. package/src/console/server/signals.ts +17 -40
  183. package/src/console/server/state.ts +21 -59
  184. package/src/console/server/store.test.ts +20 -22
  185. package/src/console/server/store.ts +31 -76
  186. package/src/console/server/vault.test.ts +12 -29
  187. package/src/console/server/vault.ts +44 -66
  188. package/src/console/ui/access/AccessA11yView.tsx +6 -21
  189. package/src/console/ui/access/a11y.test.tsx +3 -12
  190. package/src/console/ui/access/acknowledgement.test.ts +1 -4
  191. package/src/console/ui/access/acknowledgement.ts +1 -3
  192. package/src/console/ui/access/blast-radius.ts +1 -3
  193. package/src/console/ui/access/confirmation.test.ts +1 -5
  194. package/src/console/ui/access/confirmation.ts +1 -4
  195. package/src/console/ui/access/fixture.ts +1 -5
  196. package/src/console/ui/access/grantable.test.ts +1 -3
  197. package/src/console/ui/access/grantable.ts +2 -7
  198. package/src/console/ui/access/index.ts +2 -9
  199. package/src/console/ui/access/provenance.test.ts +1 -3
  200. package/src/console/ui/access/provenance.ts +2 -6
  201. package/src/console/ui/access/search.test.ts +1 -5
  202. package/src/console/ui/access/search.ts +2 -6
  203. package/src/console/ui/ai/AiA11yView.tsx +6 -17
  204. package/src/console/ui/ai/a11y.test.tsx +2 -5
  205. package/src/console/ui/ai/fixture.ts +2 -7
  206. package/src/console/ui/ai/format.ts +1 -3
  207. package/src/console/ui/ai/group.test.ts +1 -3
  208. package/src/console/ui/ai/group.ts +4 -12
  209. package/src/console/ui/ai/index.ts +2 -9
  210. package/src/console/ui/ai/promotion.test.ts +2 -7
  211. package/src/console/ui/ai/promotion.ts +4 -13
  212. package/src/console/ui/ai/search.test.ts +2 -11
  213. package/src/console/ui/ai/search.ts +3 -13
  214. package/src/console/ui/ai/types.ts +1 -8
  215. package/src/console/ui/architecture/ArchitectureA11yView.tsx +8 -29
  216. package/src/console/ui/architecture/a11y.test.tsx +1 -2
  217. package/src/console/ui/architecture/declared.ts +1 -5
  218. package/src/console/ui/architecture/index.ts +7 -35
  219. package/src/console/ui/architecture/layout.ts +1 -3
  220. package/src/console/ui/architecture/pathologies.ts +10 -19
  221. package/src/console/ui/architecture/search.ts +6 -15
  222. package/src/console/ui/architecture/traffic.ts +4 -14
  223. package/src/console/ui/architecture/types.ts +2 -10
  224. package/src/console/ui/architecture/view.test.ts +7 -19
  225. package/src/console/ui/architecture/view.ts +9 -36
  226. package/src/console/ui/channels/ChannelsA11yView.tsx +4 -13
  227. package/src/console/ui/channels/a11y.test.tsx +1 -2
  228. package/src/console/ui/channels/confirmation.test.ts +1 -4
  229. package/src/console/ui/channels/confirmation.ts +1 -4
  230. package/src/console/ui/channels/findings.ts +1 -5
  231. package/src/console/ui/channels/index.ts +2 -8
  232. package/src/console/ui/channels/locale.test.ts +1 -3
  233. package/src/console/ui/channels/locale.ts +2 -8
  234. package/src/console/ui/channels/search.ts +4 -13
  235. package/src/console/ui/channels/taxonomy.ts +1 -3
  236. package/src/console/ui/clock/ClockA11yView.tsx +9 -26
  237. package/src/console/ui/clock/a11y.test.tsx +2 -5
  238. package/src/console/ui/clock/confirmation.test.ts +1 -3
  239. package/src/console/ui/clock/confirmation.ts +1 -4
  240. package/src/console/ui/clock/findings.ts +1 -4
  241. package/src/console/ui/clock/health.ts +2 -7
  242. package/src/console/ui/clock/index.ts +2 -10
  243. package/src/console/ui/clock/search.test.ts +1 -3
  244. package/src/console/ui/clock/search.ts +2 -6
  245. package/src/console/ui/clock/timeline.test.ts +1 -3
  246. package/src/console/ui/clock/waiting-on.test.ts +1 -5
  247. package/src/console/ui/clock/waiting-on.ts +2 -7
  248. package/src/console/ui/diff/DiffA11yView.tsx +8 -17
  249. package/src/console/ui/diff/a11y.test.tsx +2 -5
  250. package/src/console/ui/diff/group.test.ts +3 -13
  251. package/src/console/ui/diff/group.ts +2 -8
  252. package/src/console/ui/diff/index.ts +2 -8
  253. package/src/console/ui/diff/search.test.ts +1 -5
  254. package/src/console/ui/diff/search.ts +4 -16
  255. package/src/console/ui/diff/summary.ts +1 -2
  256. package/src/console/ui/dist/assets/{index-Dy4jht9P.js → index-BWo8R7NR.js} +2 -2
  257. package/src/console/ui/dist/assets/{panel-access-Dd37LU2c.js → panel-access-C0J2D-a2.js} +1 -1
  258. package/src/console/ui/dist/assets/{panel-ai-CC7LR6-J.js → panel-ai-D_m6WQI8.js} +1 -1
  259. package/src/console/ui/dist/assets/{panel-architecture-B5b3iKCz.js → panel-architecture-CKnXFyUx.js} +1 -1
  260. package/src/console/ui/dist/assets/{panel-channels-CeNjTKXp.js → panel-channels-BOmQ-onL.js} +1 -1
  261. package/src/console/ui/dist/assets/{panel-clock-DgFTLoHV.js → panel-clock-giAq0Ccv.js} +1 -1
  262. package/src/console/ui/dist/assets/{panel-diff-DxehccqB.js → panel-diff-cdonmH8c.js} +1 -1
  263. package/src/console/ui/dist/assets/{panel-flows-BtrVn-Eg.js → panel-flows-DlCU5zjA.js} +2 -2
  264. package/src/console/ui/dist/assets/{panel-gates-Z9MKRGdH.js → panel-gates-XclZxWD5.js} +1 -1
  265. package/src/console/ui/dist/assets/{panel-overview-Dt_AeXgd.js → panel-overview-BznEOTnb.js} +1 -1
  266. package/src/console/ui/dist/assets/{panel-plugins-DWd0TowH.js → panel-plugins-CcGM1g64.js} +1 -1
  267. package/src/console/ui/dist/assets/{panel-runs-DGstFHeq.js → panel-runs-CGWNHLR4.js} +1 -1
  268. package/src/console/ui/dist/assets/{panel-signals-DzEa2Fnt.js → panel-signals-CNywkdak.js} +1 -1
  269. package/src/console/ui/dist/assets/{panel-store-BJkbNgxx.js → panel-store-KmTbFHMH.js} +1 -1
  270. package/src/console/ui/dist/assets/{panel-traces-BaRVO3gM.js → panel-traces-DBLx2ilD.js} +1 -1
  271. package/src/console/ui/dist/assets/panel-vault-CEnFc0dk.js +1 -0
  272. package/src/console/ui/dist/index.html +1 -1
  273. package/src/console/ui/flows/FlowsA11yView.tsx +7 -22
  274. package/src/console/ui/flows/a11y.test.tsx +2 -8
  275. package/src/console/ui/flows/buffer.test.ts +3 -11
  276. package/src/console/ui/flows/buffer.ts +4 -11
  277. package/src/console/ui/flows/confirmation.ts +1 -3
  278. package/src/console/ui/flows/contract.test.ts +3 -7
  279. package/src/console/ui/flows/contract.ts +12 -36
  280. package/src/console/ui/flows/graph.test.ts +3 -11
  281. package/src/console/ui/flows/graph.ts +5 -15
  282. package/src/console/ui/flows/index.ts +1 -6
  283. package/src/console/ui/flows/save-as-test.ts +1 -3
  284. package/src/console/ui/flows/search.ts +8 -25
  285. package/src/console/ui/flows/tiers.ts +2 -9
  286. package/src/console/ui/gates/GatesA11yView.tsx +4 -13
  287. package/src/console/ui/gates/a11y.test.tsx +2 -5
  288. package/src/console/ui/gates/audit.ts +1 -3
  289. package/src/console/ui/gates/denial.test.ts +1 -3
  290. package/src/console/ui/gates/denial.ts +4 -12
  291. package/src/console/ui/gates/findings.ts +1 -3
  292. package/src/console/ui/gates/group.test.ts +3 -3
  293. package/src/console/ui/gates/group.ts +3 -11
  294. package/src/console/ui/gates/index.ts +2 -10
  295. package/src/console/ui/gates/search.ts +3 -10
  296. package/src/console/ui/overview/OverviewA11yView.tsx +9 -27
  297. package/src/console/ui/overview/a11y.test.tsx +1 -2
  298. package/src/console/ui/overview/busiest.ts +1 -3
  299. package/src/console/ui/overview/compose.ts +1 -13
  300. package/src/console/ui/overview/cost.ts +34 -38
  301. package/src/console/ui/overview/fixture.ts +21 -26
  302. package/src/console/ui/overview/golden.ts +4 -14
  303. package/src/console/ui/overview/index.ts +2 -9
  304. package/src/console/ui/overview/rank.test.ts +3 -10
  305. package/src/console/ui/overview/rank.ts +2 -7
  306. package/src/console/ui/overview/slo.test.ts +5 -9
  307. package/src/console/ui/overview/slo.ts +6 -23
  308. package/src/console/ui/overview/verdict.ts +3 -10
  309. package/src/console/ui/plugins/PluginsA11yView.tsx +8 -18
  310. package/src/console/ui/plugins/a11y.test.tsx +1 -2
  311. package/src/console/ui/plugins/fixture.ts +2 -4
  312. package/src/console/ui/plugins/group.test.ts +1 -3
  313. package/src/console/ui/plugins/group.ts +1 -6
  314. package/src/console/ui/plugins/index.ts +3 -13
  315. package/src/console/ui/plugins/search.ts +7 -19
  316. package/src/console/ui/runs/RunsA11yView.tsx +5 -20
  317. package/src/console/ui/runs/a11y.test.tsx +2 -5
  318. package/src/console/ui/runs/explain.ts +2 -6
  319. package/src/console/ui/runs/group.ts +3 -12
  320. package/src/console/ui/runs/histogram.test.ts +2 -11
  321. package/src/console/ui/runs/histogram.ts +1 -4
  322. package/src/console/ui/runs/index.ts +4 -18
  323. package/src/console/ui/runs/project.ts +2 -6
  324. package/src/console/ui/runs/query.test.ts +1 -3
  325. package/src/console/ui/runs/query.ts +12 -35
  326. package/src/console/ui/runs/search.ts +5 -19
  327. package/src/console/ui/runs/trace-link.test.ts +2 -6
  328. package/src/console/ui/runs/trace-link.ts +4 -16
  329. package/src/console/ui/runs/types.ts +1 -3
  330. package/src/console/ui/shell/App.tsx +2 -10
  331. package/src/console/ui/shell/client.ts +22 -115
  332. package/src/console/ui/shell/components/ui.tsx +1 -4
  333. package/src/console/ui/shell/layout/Shell.tsx +2 -4
  334. package/src/console/ui/shell/main.tsx +31 -96
  335. package/src/console/ui/shell/panels/access/AccessPanel.tsx +34 -98
  336. package/src/console/ui/shell/panels/ai/AiPanel.tsx +35 -106
  337. package/src/console/ui/shell/panels/architecture/ArchitecturePanel.tsx +18 -66
  338. package/src/console/ui/shell/panels/channels/ChannelsPanel.tsx +20 -57
  339. package/src/console/ui/shell/panels/clock/ClockPanel.tsx +22 -54
  340. package/src/console/ui/shell/panels/diff/DiffPanel.tsx +20 -61
  341. package/src/console/ui/shell/panels/flows/ContractEditor.tsx +6 -23
  342. package/src/console/ui/shell/panels/flows/FlowDrawer.tsx +13 -28
  343. package/src/console/ui/shell/panels/flows/FlowsPanel.tsx +9 -29
  344. package/src/console/ui/shell/panels/gates/GatesPanel.tsx +24 -80
  345. package/src/console/ui/shell/panels/overview/OverviewPanel.tsx +20 -58
  346. package/src/console/ui/shell/panels/plugins/PluginsPanel.tsx +16 -41
  347. package/src/console/ui/shell/panels/runs/RunsPanel.tsx +31 -99
  348. package/src/console/ui/shell/panels/signals/SignalsPanel.tsx +38 -101
  349. package/src/console/ui/shell/panels/store/StorePanel.tsx +27 -66
  350. package/src/console/ui/shell/panels/traces/TracesPanel.tsx +28 -89
  351. package/src/console/ui/shell/panels/vault/VaultPanel.tsx +22 -53
  352. package/src/console/ui/shell/setup/Wizard.tsx +3 -5
  353. package/src/console/ui/shell/styles.css +1 -2
  354. package/src/console/ui/signals/SignalsA11yView.tsx +9 -33
  355. package/src/console/ui/signals/a11y.test.tsx +2 -5
  356. package/src/console/ui/signals/confirmation.test.ts +1 -5
  357. package/src/console/ui/signals/confirmation.ts +2 -6
  358. package/src/console/ui/signals/dry-run.ts +1 -3
  359. package/src/console/ui/signals/durable.ts +1 -3
  360. package/src/console/ui/signals/findings.ts +1 -3
  361. package/src/console/ui/signals/group.test.ts +2 -8
  362. package/src/console/ui/signals/group.ts +2 -10
  363. package/src/console/ui/signals/index.ts +1 -4
  364. package/src/console/ui/signals/monitor.ts +2 -7
  365. package/src/console/ui/signals/schema-form.test.ts +3 -14
  366. package/src/console/ui/signals/schema-form.ts +1 -4
  367. package/src/console/ui/signals/search.ts +4 -13
  368. package/src/console/ui/store/StoreA11yView.tsx +3 -9
  369. package/src/console/ui/store/a11y.test.tsx +2 -5
  370. package/src/console/ui/store/confirmation.test.ts +1 -3
  371. package/src/console/ui/store/confirmation.ts +1 -4
  372. package/src/console/ui/store/dry-run.ts +2 -5
  373. package/src/console/ui/store/fixture.ts +1 -2
  374. package/src/console/ui/store/group.test.ts +1 -6
  375. package/src/console/ui/store/group.ts +1 -4
  376. package/src/console/ui/store/index.ts +1 -5
  377. package/src/console/ui/store/search.ts +2 -6
  378. package/src/console/ui/store/will-not-fire.ts +1 -2
  379. package/src/console/ui/traces/TracesA11yView.tsx +10 -29
  380. package/src/console/ui/traces/a11y.test.tsx +1 -2
  381. package/src/console/ui/traces/chain.test.ts +5 -19
  382. package/src/console/ui/traces/chain.ts +1 -3
  383. package/src/console/ui/traces/critical-path.test.ts +1 -3
  384. package/src/console/ui/traces/critical-path.ts +2 -6
  385. package/src/console/ui/traces/filter.test.ts +2 -6
  386. package/src/console/ui/traces/filter.ts +5 -13
  387. package/src/console/ui/traces/fold.test.ts +4 -12
  388. package/src/console/ui/traces/fold.ts +1 -3
  389. package/src/console/ui/traces/mini.ts +1 -3
  390. package/src/console/ui/traces/replay.test.ts +1 -3
  391. package/src/console/ui/traces/replay.ts +1 -3
  392. package/src/console/ui/traces/sampling.ts +1 -4
  393. package/src/console/ui/traces/search.ts +4 -17
  394. package/src/console/ui/traces/tier.ts +1 -3
  395. package/src/console/ui/vault/VaultA11yView.tsx +5 -17
  396. package/src/console/ui/vault/a11y.test.tsx +1 -2
  397. package/src/console/ui/vault/blast-radius.ts +1 -3
  398. package/src/console/ui/vault/confirmation.test.ts +1 -5
  399. package/src/console/ui/vault/confirmation.ts +1 -4
  400. package/src/console/ui/vault/dormant.test.ts +1 -4
  401. package/src/console/ui/vault/export-safe.test.ts +1 -5
  402. package/src/console/ui/vault/export-safe.ts +1 -4
  403. package/src/console/ui/vault/fixture.ts +3 -3
  404. package/src/console/ui/vault/group.ts +1 -2
  405. package/src/console/ui/vault/index.ts +2 -10
  406. package/src/console/ui/vault/search.ts +2 -6
  407. package/src/console/ui/vault/types.ts +1 -1
  408. package/src/console/xss.gate.test.ts +1 -3
  409. package/src/docker/compose.ts +215 -27
  410. package/src/docker/derive.ts +6 -14
  411. package/src/docker/docker.test.ts +118 -15
  412. package/src/docker/dockerfile.integration.test.ts +12 -21
  413. package/src/docker/helpers.ts +5 -4
  414. package/src/docker/index.ts +9 -6
  415. package/src/docker/pin.ts +1 -9
  416. package/src/docker/recipes/index.ts +6 -6
  417. package/src/docker/recipes/mailpit.ts +22 -0
  418. package/src/docker/recipes/openbao.ts +47 -0
  419. package/src/docker/recipes/postgres.ts +17 -6
  420. package/src/docker/recipes/redis.ts +11 -2
  421. package/src/docker/recipes/rustfs.ts +32 -0
  422. package/src/docker/stack-id.test.ts +73 -5
  423. package/src/docker/stack-id.ts +124 -33
  424. package/src/docker/stack.integration.test.ts +6 -21
  425. package/src/docker/stack.ts +36 -4
  426. package/src/docker/types.ts +16 -4
  427. package/src/docs-origin.ts +4 -4
  428. package/src/drivers/ai-anthropic.ts +5 -14
  429. package/src/drivers/ai-mock.ts +2 -5
  430. package/src/drivers/ai-openai-compatible.ts +4 -10
  431. package/src/drivers/ai-providers.test.ts +6 -13
  432. package/src/drivers/bun-native-completeness.test.ts +6 -15
  433. package/src/drivers/channel-console.ts +6 -7
  434. package/src/drivers/channel-fcm.ts +20 -30
  435. package/src/drivers/channel-resend.ts +1 -3
  436. package/src/drivers/channel-smtp.ts +2 -6
  437. package/src/drivers/channel-types.ts +2 -12
  438. package/src/drivers/channel-unifonic.ts +2 -6
  439. package/src/drivers/channel-wa-cloud.ts +2 -6
  440. package/src/drivers/channel-webpush.ts +21 -60
  441. package/src/drivers/conformance.test.ts +2 -10
  442. package/src/drivers/conformance.ts +8 -21
  443. package/src/drivers/drizzle-dialect.test.ts +20 -0
  444. package/src/drivers/drizzle-dialect.ts +37 -0
  445. package/src/drivers/fs.ts +2 -8
  446. package/src/drivers/index.ts +12 -57
  447. package/src/drivers/memory.ts +287 -75
  448. package/src/drivers/pgvector.ts +7 -11
  449. package/src/drivers/postgres.ts +7 -13
  450. package/src/drivers/redis.ts +13 -37
  451. package/src/drivers/s3.ts +15 -18
  452. package/src/drivers/signal-engine.ts +12 -49
  453. package/src/drivers/signal-memory.ts +2 -8
  454. package/src/drivers/signal-nats.ts +4 -9
  455. package/src/drivers/signal-postgres.ts +62 -129
  456. package/src/drivers/signal-redis.ts +7 -21
  457. package/src/drivers/signal-types.ts +1 -4
  458. package/src/drivers/sqlite.ts +3 -12
  459. package/src/drivers/types.ts +4 -23
  460. package/src/drivers/vault-driver-removal.test.ts +55 -0
  461. package/src/drivers/vault-env.ts +2 -6
  462. package/src/drivers/vault-infisical.ts +1 -5
  463. package/src/drivers/vault-managed.ts +1 -5
  464. package/src/drivers/vault-memory.ts +1 -5
  465. package/src/drivers/vault-openbao.test.ts +97 -0
  466. package/src/drivers/vault-openbao.ts +103 -40
  467. package/src/drivers/vault-types.ts +3 -16
  468. package/src/elements/ai/declare.ts +4 -14
  469. package/src/elements/ai/eval.ts +2 -6
  470. package/src/elements/ai/pii.ts +1 -3
  471. package/src/elements/ai/runtime.ts +12 -50
  472. package/src/elements/ai/schema.ts +4 -15
  473. package/src/elements/ai.test.ts +13 -24
  474. package/src/elements/ai.ts +1 -5
  475. package/src/elements/channel/consent.ts +3 -12
  476. package/src/elements/channel/costs.ts +4 -15
  477. package/src/elements/channel/declare.ts +1 -4
  478. package/src/elements/channel/email-auth.ts +1 -4
  479. package/src/elements/channel/locale.ts +2 -10
  480. package/src/elements/channel/mask.ts +1 -3
  481. package/src/elements/channel/mime.ts +2 -12
  482. package/src/elements/channel/outcomes.test.ts +1 -5
  483. package/src/elements/channel/outcomes.ts +5 -15
  484. package/src/elements/channel/receipts.ts +2 -7
  485. package/src/elements/channel/runtime.ts +28 -74
  486. package/src/elements/channel/suppression.ts +8 -14
  487. package/src/elements/channel.test.ts +8 -31
  488. package/src/elements/channel.ts +3 -14
  489. package/src/elements/clock/actions.ts +6 -18
  490. package/src/elements/clock/declare.ts +1 -3
  491. package/src/elements/clock/dst.ts +1 -5
  492. package/src/elements/clock/durable.ts +4 -16
  493. package/src/elements/clock/health.ts +2 -7
  494. package/src/elements/clock/leader.ts +2 -9
  495. package/src/elements/clock/reconcile.ts +4 -15
  496. package/src/elements/clock/runtime.ts +2 -5
  497. package/src/elements/clock/schedule.ts +4 -20
  498. package/src/elements/clock.test.ts +2 -7
  499. package/src/elements/clock.ts +5 -23
  500. package/src/elements/gate/permissions.ts +1 -4
  501. package/src/elements/gate/runtime.ts +7 -28
  502. package/src/elements/gate.ts +1 -5
  503. package/src/elements/index.ts +9 -7
  504. package/src/elements/signal/declare.ts +2 -7
  505. package/src/elements/signal/reconcile.test.ts +1 -4
  506. package/src/elements/signal/runtime.ts +1 -3
  507. package/src/elements/signal.test.ts +3 -15
  508. package/src/elements/signal.ts +2 -8
  509. package/src/elements/store/cache.test.ts +46 -0
  510. package/src/elements/store/cache.ts +3 -11
  511. package/src/elements/store/classify.ts +5 -22
  512. package/src/elements/store/declare.ts +11 -17
  513. package/src/elements/store/domain-ddl.test.ts +86 -0
  514. package/src/elements/store/emit-drizzle.ts +363 -0
  515. package/src/elements/store/files-policy.test.ts +1 -5
  516. package/src/elements/store/files-policy.ts +4 -12
  517. package/src/elements/store/load-plugin-tables.ts +103 -0
  518. package/src/elements/store/missing-relation.test.ts +83 -0
  519. package/src/elements/store/missing-relation.ts +38 -0
  520. package/src/elements/store/replica.ts +1 -4
  521. package/src/elements/store/resource-list-docs.fixture.ts +56 -0
  522. package/src/elements/store/resource-list-docs.test.ts +79 -0
  523. package/src/elements/store/resource.test.ts +253 -0
  524. package/src/elements/store/resource.ts +786 -0
  525. package/src/elements/store/runtime.ts +25 -28
  526. package/src/elements/store/schema-decl.test.ts +227 -0
  527. package/src/elements/store/schema-decl.ts +516 -0
  528. package/src/elements/store/sql-condition.test.ts +132 -0
  529. package/src/elements/store/sql-condition.ts +293 -65
  530. package/src/elements/store/sql-session.test.ts +135 -0
  531. package/src/elements/store/sql-session.ts +241 -84
  532. package/src/elements/store/table.ts +69 -23
  533. package/src/elements/store.test.ts +17 -39
  534. package/src/elements/store.ts +53 -31
  535. package/src/elements/vault/chain.ts +34 -0
  536. package/src/elements/vault/declare.ts +22 -32
  537. package/src/elements/vault/fingerprint.ts +2 -7
  538. package/src/elements/vault/redact.ts +2 -6
  539. package/src/elements/vault/runtime.ts +19 -33
  540. package/src/elements/vault.test.ts +12 -55
  541. package/src/elements/vault.ts +9 -13
  542. package/src/index.ts +5 -2
  543. package/src/kernel/adopt-routes.ts +15 -29
  544. package/src/kernel/app.ts +92 -118
  545. package/src/kernel/auth-resolve.ts +2 -9
  546. package/src/kernel/boot-bind/ai.ts +1 -4
  547. package/src/kernel/boot-bind/channel.test.ts +60 -0
  548. package/src/kernel/boot-bind/channel.ts +61 -5
  549. package/src/kernel/boot-bind/clock.ts +2 -6
  550. package/src/kernel/boot-bind/gate.ts +2 -8
  551. package/src/kernel/boot-bind/runs.ts +1 -3
  552. package/src/kernel/boot-bind/signal.ts +3 -10
  553. package/src/kernel/boot-bind/store.test.ts +27 -18
  554. package/src/kernel/boot-bind/store.ts +93 -52
  555. package/src/kernel/boot-bind/vault.ts +2 -8
  556. package/src/kernel/boot.test.ts +4 -10
  557. package/src/kernel/boot.ts +30 -77
  558. package/src/kernel/budget.test.ts +1 -3
  559. package/src/kernel/capability.ts +3 -10
  560. package/src/kernel/dry-run.test.ts +1 -4
  561. package/src/kernel/dry-run.ts +3 -11
  562. package/src/kernel/edge.test.ts +68 -0
  563. package/src/kernel/effects.test.ts +1 -5
  564. package/src/kernel/effects.ts +4 -11
  565. package/src/kernel/errors.registry.test.ts +2 -8
  566. package/src/kernel/errors.ts +23 -32
  567. package/src/kernel/flow.test.ts +12 -25
  568. package/src/kernel/flow.ts +13 -25
  569. package/src/kernel/fx.test.ts +31 -40
  570. package/src/kernel/fx.ts +135 -90
  571. package/src/kernel/hook-timing.test.ts +3 -6
  572. package/src/kernel/hook-timing.ts +5 -14
  573. package/src/kernel/hooks.test.ts +43 -10
  574. package/src/kernel/hooks.ts +25 -12
  575. package/src/kernel/index.ts +11 -17
  576. package/src/kernel/journal.ts +7 -31
  577. package/src/kernel/on.ts +45 -9
  578. package/src/kernel/pipeline.test.ts +10 -19
  579. package/src/kernel/pipeline.ts +5 -17
  580. package/src/kernel/plug.ts +4 -11
  581. package/src/kernel/plugin/conflicts.test.ts +13 -25
  582. package/src/kernel/plugin/decorate.test.ts +8 -13
  583. package/src/kernel/plugin/scoping.test.ts +4 -11
  584. package/src/kernel/plugin.ts +81 -27
  585. package/src/kernel/registry-isolation.test.ts +74 -0
  586. package/src/kernel/registry.ts +102 -30
  587. package/src/kernel/router.test.ts +15 -13
  588. package/src/kernel/router.ts +9 -29
  589. package/src/kernel/routing-budget.test.ts +1 -3
  590. package/src/kernel/run-telemetry.ts +1 -3
  591. package/src/kernel/triggers.ts +63 -21
  592. package/src/manifest/diff.test.ts +26 -91
  593. package/src/manifest/diff.ts +95 -225
  594. package/src/manifest/fixtures/skyport.excerpt.json +1 -1
  595. package/src/manifest/fixtures/skyport.manifest.json +1 -1
  596. package/src/manifest/index.ts +3 -10
  597. package/src/manifest/types.ts +30 -6
  598. package/src/manifest/undeclared.test.ts +4 -12
  599. package/src/manifest/undeclared.ts +1 -2
  600. package/src/manifest/validate.test.ts +2 -6
  601. package/src/manifest/validate.ts +5 -15
  602. package/src/mcp/authorization.ts +8 -27
  603. package/src/mcp/confirmation.ts +3 -10
  604. package/src/mcp/data.ts +2 -6
  605. package/src/mcp/docs-index.ts +4 -7
  606. package/src/mcp/docs-mcp.test.ts +3 -12
  607. package/src/mcp/docs-server.ts +7 -27
  608. package/src/mcp/docs-tools.ts +2 -6
  609. package/src/mcp/index.ts +1 -6
  610. package/src/mcp/injection.gate.test.ts +4 -18
  611. package/src/mcp/mcp.test.ts +18 -49
  612. package/src/mcp/protocol.ts +3 -10
  613. package/src/mcp/server.ts +11 -52
  614. package/src/mcp/session.ts +4 -14
  615. package/src/mcp/tools.ts +14 -50
  616. package/src/plugins/catalogue.test.ts +3 -7
  617. package/src/plugins/catalogue.ts +1 -3
  618. package/src/plugins/compression.test.ts +127 -0
  619. package/src/plugins/compression.ts +94 -0
  620. package/src/plugins/config-source.test.ts +204 -0
  621. package/src/plugins/config-source.ts +209 -0
  622. package/src/plugins/cors.test.ts +138 -0
  623. package/src/plugins/cors.ts +129 -0
  624. package/src/plugins/csrf.test.ts +102 -0
  625. package/src/plugins/csrf.ts +86 -0
  626. package/src/plugins/headers.ts +54 -0
  627. package/src/plugins/index.ts +26 -0
  628. package/src/plugins/ip-allowlist.test.ts +105 -0
  629. package/src/plugins/ip-allowlist.ts +76 -0
  630. package/src/plugins/maintenance-mode.test.ts +91 -0
  631. package/src/plugins/maintenance-mode.ts +85 -0
  632. package/src/plugins/node-import-scan.ts +2 -5
  633. package/src/plugins/security-headers.test.ts +243 -0
  634. package/src/plugins/security-headers.ts +255 -0
  635. package/src/plugins/supply-chain.ts +5 -17
  636. package/src/release/exports.ts +3 -8
  637. package/src/release/measure.exports.test.ts +1 -3
  638. package/src/release/measure.ts +16 -45
  639. package/src/runs/bench.test.ts +1 -3
  640. package/src/runs/collect.ts +8 -25
  641. package/src/runs/drivers/clickhouse.ts +2 -9
  642. package/src/runs/drivers/files.ts +9 -31
  643. package/src/runs/drivers/memory.ts +5 -22
  644. package/src/runs/drivers/postgres.ts +8 -20
  645. package/src/runs/duckdb.ts +2 -8
  646. package/src/runs/index.ts +3 -14
  647. package/src/runs/outlier.ts +3 -10
  648. package/src/runs/parquet.ts +8 -26
  649. package/src/runs/privacy.ts +2 -8
  650. package/src/runs/runs.test.ts +3 -9
  651. package/src/runs/runtime.ts +7 -32
  652. package/src/runs/shred.ts +10 -29
  653. package/src/runs/types.ts +1 -4
  654. package/src/runtime/bun.ts +4 -15
  655. package/src/runtime/cold-start.bench.ts +1 -3
  656. package/src/runtime/dev-request-log.test.ts +1 -4
  657. package/src/runtime/dev-request-log.ts +1 -4
  658. package/src/runtime/index.ts +1 -6
  659. package/src/runtime/primitives.ts +5 -4
  660. package/src/runtime/security.ts +3 -13
  661. package/src/runtime/serve.test.ts +4 -7
  662. package/src/runtime/types.ts +1 -4
  663. package/src/runtime/web-standard.ts +3 -15
  664. package/src/term.test.ts +4 -6
  665. package/src/term.ts +49 -98
  666. package/src/test/create-test-app.test.ts +4 -14
  667. package/src/test/create-test-app.ts +27 -33
  668. package/src/test/provisions.integration.test.ts +3 -11
  669. package/src/upgrade/codemods.test.ts +25 -6
  670. package/src/upgrade/codemods.ts +116 -3
  671. package/src/validation/standard-schema.test.ts +2 -5
  672. package/src/validation/standard-schema.ts +13 -33
  673. package/docs/spec/console.md +0 -739
  674. package/docs/spec/example.md +0 -1196
  675. package/docs/spec/four-applications.md +0 -1195
  676. package/docs/spec/unified-theory.md +0 -489
  677. package/src/cli/doc-drift.test.ts +0 -146
  678. package/src/cli/doc-drift.ts +0 -430
  679. package/src/cli/doctor-diff-examples.ts +0 -92
  680. package/src/console/ui/dist/assets/panel-vault-BbfWdox0.js +0 -1
  681. package/src/drivers/vault-sops.ts +0 -271
@@ -0,0 +1,516 @@
1
+ /**
2
+ * Abstract store schema — ORM-agnostic declare site (`field.*` + `store.schema.table`).
3
+ *
4
+ * Survey-backed v1 primitives: `text` · `integer` + modifiers + PII tags + FKs.
5
+ * Dialect-specific Drizzle is emitted separately ({@link emitDrizzleSource}).
6
+ */
7
+
8
+ import type { ColumnClassification } from "../../manifest/types.ts";
9
+ import type { ColumnDef, TableHandle } from "./table.ts";
10
+ import { id as idHelper, now as nowHelper } from "./table.ts";
11
+
12
+ /** SQL type primitives supported in v1. */
13
+ export type FieldSqlType = "text" | "integer";
14
+
15
+ /** Known `$defaultFn` helpers recognized by the Drizzle emitter. */
16
+ export type DefaultFnKind = "id" | "now" | "custom";
17
+
18
+ /** FK action — mirrors Drizzle `UpdateDeleteAction`. */
19
+ export type ReferenceAction = "cascade" | "restrict" | "no action" | "set null" | "set default";
20
+
21
+ /** Optional ON DELETE / ON UPDATE for {@link FieldBuilder.references}. */
22
+ export interface ReferenceActions {
23
+ readonly onDelete?: ReferenceAction;
24
+ readonly onUpdate?: ReferenceAction;
25
+ }
26
+
27
+ /** Resolved foreign-key target (lazy ref evaluated at finalize/emit). */
28
+ export interface ColumnReference {
29
+ /** Lazy target column (evaluated when emitting / finalizing). */
30
+ readonly ref: () => SchemaColumnDecl;
31
+ readonly actions?: ReferenceActions;
32
+ }
33
+
34
+ /**
35
+ * Finalized column declaration — also satisfies {@link ColumnDef} so
36
+ * {@link classificationsFromTable} / runtime masking work without Drizzle.
37
+ */
38
+ export interface SchemaColumnDecl extends ColumnDef {
39
+ /** JS object key (e.g. `createdAt`). */
40
+ readonly key: string;
41
+ /** Database column name (e.g. `created_at`). */
42
+ readonly sqlName: string;
43
+ /** Declared SQL type. */
44
+ readonly sqlType: FieldSqlType;
45
+ readonly primaryKey: boolean;
46
+ readonly notNull: boolean;
47
+ readonly unique: boolean;
48
+ /** Literal `.default(v)` when set. */
49
+ readonly defaultValue?: string | number | boolean | null;
50
+ /** Runtime default applied on insert when the key is missing. */
51
+ readonly defaultFn?: () => unknown;
52
+ /** Emitter hint for `$defaultFn(id|now)`. */
53
+ readonly defaultFnKind?: DefaultFnKind;
54
+ /** Owning table SQL name (stamped by {@link schemaTable}). */
55
+ readonly tableName?: string;
56
+ /** Foreign key when `.references()` was used. */
57
+ readonly references?: ColumnReference;
58
+ }
59
+
60
+ /** Table from {@link store.schema.table} — extends {@link TableHandle}. */
61
+ export interface SchemaTableDecl extends TableHandle {
62
+ readonly kind: "schema-table";
63
+ readonly columns: Readonly<Record<string, SchemaColumnDecl>>;
64
+ }
65
+
66
+ /** Fluent field builder before key finalization. */
67
+ export interface FieldBuilder {
68
+ primaryKey(): FieldBuilder;
69
+ notNull(): FieldBuilder;
70
+ unique(): FieldBuilder;
71
+ default(value: string | number | boolean | null): FieldBuilder;
72
+ defaultFn(fn: () => unknown): FieldBuilder;
73
+ pii(): FieldBuilder;
74
+ sensitive(): FieldBuilder;
75
+ retain(duration: string): FieldBuilder;
76
+ /** Override snake_case SQL name. */
77
+ as(sqlName: string): FieldBuilder;
78
+ /**
79
+ * Declare a foreign key to another column (dialect-agnostic).
80
+ *
81
+ * @param ref - Lazy target column (`() => links.code`)
82
+ * @param actions - Optional ON DELETE / ON UPDATE
83
+ */
84
+ references(ref: () => SchemaColumnDecl, actions?: ReferenceActions): FieldBuilder;
85
+ /**
86
+ * Bind the JS key and produce a {@link SchemaColumnDecl}.
87
+ *
88
+ * @param key - Object key in the table column map
89
+ */
90
+ finalize(key: string): SchemaColumnDecl;
91
+ }
92
+
93
+ interface FieldState {
94
+ readonly sqlType: FieldSqlType;
95
+ readonly primaryKey: boolean;
96
+ readonly notNull: boolean;
97
+ readonly unique: boolean;
98
+ readonly defaultValue?: string | number | boolean | null;
99
+ readonly defaultFn?: () => unknown;
100
+ readonly defaultFnKind?: DefaultFnKind;
101
+ readonly classification?: ColumnClassification;
102
+ readonly sqlName?: string;
103
+ readonly references?: ColumnReference;
104
+ }
105
+
106
+ function camelToSnake(key: string): string {
107
+ return key
108
+ .replace(/([a-z0-9])([A-Z])/g, "$1_$2")
109
+ .replace(/([A-Z])([A-Z][a-z])/g, "$1_$2")
110
+ .toLowerCase();
111
+ }
112
+
113
+ function defaultFnKindOf(fn: () => unknown): DefaultFnKind {
114
+ if (fn === idHelper) return "id";
115
+ if (fn === nowHelper) return "now";
116
+ const name = typeof fn.name === "string" ? fn.name : "";
117
+ if (name === "id") return "id";
118
+ if (name === "now") return "now";
119
+ return "custom";
120
+ }
121
+
122
+ function mergeClassification(
123
+ current: ColumnClassification | undefined,
124
+ patch: ColumnClassification,
125
+ ): ColumnClassification {
126
+ return { ...(current ?? {}), ...patch };
127
+ }
128
+
129
+ function createBuilder(state: FieldState): FieldBuilder {
130
+ const next = (patch: Partial<FieldState>): FieldBuilder => createBuilder({ ...state, ...patch });
131
+
132
+ return {
133
+ primaryKey: () => next({ primaryKey: true, notNull: true }),
134
+ notNull: () => next({ notNull: true }),
135
+ unique: () => next({ unique: true }),
136
+ default: (value) => next({ defaultValue: value }),
137
+ defaultFn: (fn) =>
138
+ next({
139
+ defaultFn: fn,
140
+ defaultFnKind: defaultFnKindOf(fn),
141
+ }),
142
+ pii: () => next({ classification: mergeClassification(state.classification, { pii: true }) }),
143
+ sensitive: () =>
144
+ next({ classification: mergeClassification(state.classification, { sensitive: true }) }),
145
+ retain: (duration) =>
146
+ next({ classification: mergeClassification(state.classification, { retain: duration }) }),
147
+ as: (sqlName) => next({ sqlName }),
148
+ references: (ref, actions) =>
149
+ next({
150
+ references: actions ? { ref, actions } : { ref },
151
+ }),
152
+ finalize(key: string): SchemaColumnDecl {
153
+ const sqlName = state.sqlName ?? camelToSnake(key);
154
+ return {
155
+ key,
156
+ name: sqlName,
157
+ sqlName,
158
+ sqlType: state.sqlType,
159
+ primaryKey: state.primaryKey,
160
+ notNull: state.notNull || state.primaryKey,
161
+ unique: state.unique,
162
+ ...(state.defaultValue !== undefined ? { defaultValue: state.defaultValue } : {}),
163
+ ...(state.defaultFn ? { defaultFn: state.defaultFn } : {}),
164
+ ...(state.defaultFnKind ? { defaultFnKind: state.defaultFnKind } : {}),
165
+ ...(state.classification ? { classification: state.classification } : {}),
166
+ ...(state.references ? { references: state.references } : {}),
167
+ };
168
+ },
169
+ };
170
+ }
171
+
172
+ /**
173
+ * Field builders — `field.text()` / `field.integer()`.
174
+ */
175
+ export const field = {
176
+ text: (): FieldBuilder =>
177
+ createBuilder({
178
+ sqlType: "text",
179
+ primaryKey: false,
180
+ notNull: false,
181
+ unique: false,
182
+ }),
183
+ integer: (): FieldBuilder =>
184
+ createBuilder({
185
+ sqlType: "integer",
186
+ primaryKey: false,
187
+ notNull: false,
188
+ unique: false,
189
+ }),
190
+ } as const;
191
+
192
+ /** Column map input for {@link schemaTable}. */
193
+ export type SchemaColumnInput = FieldBuilder | SchemaColumnDecl;
194
+
195
+ /**
196
+ * Whether a value is a finalized {@link SchemaColumnDecl}.
197
+ *
198
+ * @param value - Unknown
199
+ */
200
+ export function isSchemaColumnDecl(value: unknown): value is SchemaColumnDecl {
201
+ return (
202
+ !!value &&
203
+ typeof value === "object" &&
204
+ "sqlType" in value &&
205
+ "sqlName" in value &&
206
+ "primaryKey" in value &&
207
+ typeof (value as SchemaColumnDecl).sqlType === "string" &&
208
+ typeof (value as SchemaColumnDecl).sqlName === "string"
209
+ );
210
+ }
211
+
212
+ /**
213
+ * Whether a value is a fluent {@link FieldBuilder}.
214
+ *
215
+ * @param value - Unknown
216
+ */
217
+ export function isFieldBuilder(value: unknown): value is FieldBuilder {
218
+ return (
219
+ !!value &&
220
+ typeof value === "object" &&
221
+ typeof (value as FieldBuilder).finalize === "function" &&
222
+ typeof (value as FieldBuilder).primaryKey === "function" &&
223
+ !isSchemaColumnDecl(value)
224
+ );
225
+ }
226
+
227
+ /**
228
+ * Finalize a column map (builders → decls).
229
+ *
230
+ * @param columns - Key → builder or decl
231
+ */
232
+ export function finalizeColumnMap(
233
+ columns: Readonly<Record<string, SchemaColumnInput>>,
234
+ ): Record<string, SchemaColumnDecl> {
235
+ const out: Record<string, SchemaColumnDecl> = {};
236
+ for (const [key, value] of Object.entries(columns)) {
237
+ out[key] = isFieldBuilder(value) ? value.finalize(key) : value;
238
+ }
239
+ return out;
240
+ }
241
+
242
+ /**
243
+ * Whether a value is a {@link SchemaTableDecl}.
244
+ *
245
+ * @param value - Unknown
246
+ */
247
+ export function isSchemaTableDecl(value: unknown): value is SchemaTableDecl {
248
+ return (
249
+ !!value &&
250
+ typeof value === "object" &&
251
+ (value as SchemaTableDecl).kind === "schema-table" &&
252
+ typeof (value as SchemaTableDecl).name === "string" &&
253
+ "columns" in value
254
+ );
255
+ }
256
+
257
+ /**
258
+ * Table decl with columns as own properties (`links.code`) for FK / relations.
259
+ */
260
+ export type SchemaTableWithColumns<
261
+ C extends Record<string, SchemaColumnDecl> = Record<string, SchemaColumnDecl>,
262
+ > = Omit<SchemaTableDecl, "columns"> & {
263
+ readonly columns: Readonly<C>;
264
+ } & C;
265
+
266
+ /**
267
+ * Declare an abstract schema table (ORM-agnostic).
268
+ *
269
+ * Columns are also exposed as own properties (`links.code`) for
270
+ * `.references(() => links.code)` ergonomics matching Drizzle.
271
+ *
272
+ * @param name - SQL table name
273
+ * @param columns - Column map using {@link field} builders
274
+ */
275
+ export function schemaTable<C extends Record<string, SchemaColumnInput>>(
276
+ name: string,
277
+ columns: C,
278
+ ): SchemaTableWithColumns<{ [K in keyof C]: SchemaColumnDecl }> {
279
+ const finalized = finalizeColumnMap(columns);
280
+ const stamped: Record<string, SchemaColumnDecl> = {};
281
+ for (const [key, col] of Object.entries(finalized)) {
282
+ stamped[key] = { ...col, tableName: name };
283
+ }
284
+ const table = {
285
+ kind: "schema-table" as const,
286
+ name,
287
+ columns: stamped,
288
+ ...stamped,
289
+ };
290
+ return table as SchemaTableWithColumns<{ [K in keyof C]: SchemaColumnDecl }>;
291
+ }
292
+
293
+ // ─── Relations (mirrors drizzle-orm `defineRelations`) ───────────────────────
294
+
295
+ /** Column path recorded by relation helpers (`r.links.code`). */
296
+ export interface RelationColumnRef {
297
+ readonly table: string;
298
+ readonly column: string;
299
+ }
300
+
301
+ /** One relation config (serializable for emit). */
302
+ export interface SchemaRelationOne {
303
+ readonly kind: "one";
304
+ readonly target: string;
305
+ readonly from?: RelationColumnRef | readonly RelationColumnRef[];
306
+ readonly to?: RelationColumnRef | readonly RelationColumnRef[];
307
+ readonly optional?: boolean;
308
+ readonly alias?: string;
309
+ }
310
+
311
+ /** Many relation config (serializable for emit). */
312
+ export interface SchemaRelationMany {
313
+ readonly kind: "many";
314
+ readonly target: string;
315
+ readonly from?: RelationColumnRef | readonly RelationColumnRef[];
316
+ readonly to?: RelationColumnRef | readonly RelationColumnRef[];
317
+ readonly alias?: string;
318
+ }
319
+
320
+ /** One named relation on a source table. */
321
+ export type SchemaRelationEntry = SchemaRelationOne | SchemaRelationMany;
322
+
323
+ /** Per-table relation map. */
324
+ export type SchemaTableRelations = Readonly<Record<string, SchemaRelationEntry>>;
325
+
326
+ /** Full relations declaration from {@link schemaRelations}. */
327
+ export interface SchemaRelationsDecl {
328
+ readonly kind: "schema-relations";
329
+ /** Export names of tables passed to {@link schemaRelations}. */
330
+ readonly tableKeys: readonly string[];
331
+ /** Table export name → relation name → config. */
332
+ readonly config: Readonly<Record<string, SchemaTableRelations>>;
333
+ }
334
+
335
+ /** Config input for one/many helpers. */
336
+ export interface RelationHelperConfig {
337
+ readonly from?: RelationColumnRef | readonly RelationColumnRef[];
338
+ readonly to?: RelationColumnRef | readonly RelationColumnRef[];
339
+ readonly optional?: boolean;
340
+ readonly alias?: string;
341
+ }
342
+
343
+ type RelationTableCols = Record<string, RelationColumnRef> & {
344
+ readonly __table: string;
345
+ };
346
+
347
+ type RelationsBuilderFor<Keys extends string> = {
348
+ readonly [K in Keys]: RelationTableCols;
349
+ } & {
350
+ readonly one: {
351
+ readonly [K in Keys]: (config?: RelationHelperConfig) => SchemaRelationOne;
352
+ };
353
+ readonly many: {
354
+ readonly [K in Keys]: (config?: RelationHelperConfig) => SchemaRelationMany;
355
+ };
356
+ };
357
+
358
+ /** Untyped relations builder (emit / dynamic paths). */
359
+ type RelationsBuilder = RelationsBuilderFor<string>;
360
+
361
+ /**
362
+ * Whether a value is a {@link SchemaRelationsDecl}.
363
+ *
364
+ * @param value - Unknown
365
+ */
366
+ export function isSchemaRelationsDecl(value: unknown): value is SchemaRelationsDecl {
367
+ return (
368
+ !!value &&
369
+ typeof value === "object" &&
370
+ (value as SchemaRelationsDecl).kind === "schema-relations" &&
371
+ Array.isArray((value as SchemaRelationsDecl).tableKeys) &&
372
+ typeof (value as SchemaRelationsDecl).config === "object"
373
+ );
374
+ }
375
+
376
+ function columnRefFrom(value: unknown): RelationColumnRef | undefined {
377
+ if (!value || typeof value !== "object") return undefined;
378
+ const col = value as SchemaColumnDecl & RelationColumnRef;
379
+ if (typeof col.table === "string" && typeof col.column === "string") {
380
+ return { table: col.table, column: col.column };
381
+ }
382
+ if (isSchemaColumnDecl(col) && typeof col.tableName === "string" && typeof col.key === "string") {
383
+ return { table: col.tableName, column: col.key };
384
+ }
385
+ return undefined;
386
+ }
387
+
388
+ function normalizeColRefs(
389
+ value: RelationColumnRef | readonly RelationColumnRef[] | undefined,
390
+ ): RelationColumnRef | readonly RelationColumnRef[] | undefined {
391
+ if (value === undefined) return undefined;
392
+ if (Array.isArray(value)) {
393
+ const out: RelationColumnRef[] = [];
394
+ for (const item of value) {
395
+ const ref = columnRefFrom(item) ?? (item as RelationColumnRef);
396
+ if (ref?.table && ref?.column) out.push({ table: ref.table, column: ref.column });
397
+ }
398
+ return out.length === 1 ? out[0] : out;
399
+ }
400
+ return columnRefFrom(value) ?? value;
401
+ }
402
+
403
+ /**
404
+ * Build recording helpers isomorphic to drizzle-orm `defineRelations` helpers.
405
+ *
406
+ * @param tableKeys - Export names of tables in the schema object
407
+ * @param tables - Table decls keyed by export name
408
+ */
409
+ function createRelationsBuilder(
410
+ tableKeys: readonly string[],
411
+ tables: Readonly<Record<string, SchemaTableDecl>>,
412
+ ): RelationsBuilder {
413
+ const builder: Record<string, unknown> = {};
414
+
415
+ for (const key of tableKeys) {
416
+ const table = tables[key];
417
+ if (!table) continue;
418
+ const cols = { __table: table.name } as RelationTableCols;
419
+ for (const [colKey] of Object.entries(table.columns)) {
420
+ cols[colKey] = { table: key, column: colKey };
421
+ }
422
+ builder[key] = cols;
423
+ }
424
+
425
+ const one: Record<string, (config?: RelationHelperConfig) => SchemaRelationOne> = {};
426
+ const many: Record<string, (config?: RelationHelperConfig) => SchemaRelationMany> = {};
427
+
428
+ for (const key of tableKeys) {
429
+ one[key] = (config) => ({
430
+ kind: "one",
431
+ target: key,
432
+ ...(config?.from !== undefined ? { from: normalizeColRefs(config.from) } : {}),
433
+ ...(config?.to !== undefined ? { to: normalizeColRefs(config.to) } : {}),
434
+ ...(config?.optional !== undefined ? { optional: config.optional } : {}),
435
+ ...(config?.alias !== undefined ? { alias: config.alias } : {}),
436
+ });
437
+ many[key] = (config) => ({
438
+ kind: "many",
439
+ target: key,
440
+ ...(config?.from !== undefined ? { from: normalizeColRefs(config.from) } : {}),
441
+ ...(config?.to !== undefined ? { to: normalizeColRefs(config.to) } : {}),
442
+ ...(config?.alias !== undefined ? { alias: config.alias } : {}),
443
+ });
444
+ }
445
+
446
+ builder.one = one;
447
+ builder.many = many;
448
+ return builder as RelationsBuilder;
449
+ }
450
+
451
+ /**
452
+ * Declare abstract relations — mirrors drizzle-orm `defineRelations` shape.
453
+ *
454
+ * @param tables - Schema object of {@link SchemaTableDecl}s (export-name keys)
455
+ * @param configure - `(r) => ({ links: { daily: r.many.daily({ from, to }) } })`
456
+ */
457
+ export function schemaRelations<T extends Readonly<Record<string, SchemaTableDecl>>>(
458
+ tables: T,
459
+ configure: (
460
+ r: RelationsBuilderFor<Extract<keyof T, string>>,
461
+ ) => Readonly<Record<string, SchemaTableRelations | undefined>>,
462
+ ): SchemaRelationsDecl {
463
+ const tableKeys = Object.keys(tables).filter((k) => isSchemaTableDecl(tables[k]));
464
+ const tableMap: Record<string, SchemaTableDecl> = {};
465
+ for (const k of tableKeys) {
466
+ tableMap[k] = tables[k]!;
467
+ }
468
+ const builder = createRelationsBuilder(tableKeys, tableMap) as RelationsBuilderFor<
469
+ Extract<keyof T, string>
470
+ >;
471
+ const raw = configure(builder);
472
+ const config: Record<string, SchemaTableRelations> = {};
473
+ for (const [tableKey, rels] of Object.entries(raw)) {
474
+ if (!rels) continue;
475
+ config[tableKey] = rels;
476
+ }
477
+ return {
478
+ kind: "schema-relations",
479
+ tableKeys,
480
+ config,
481
+ };
482
+ }
483
+
484
+ /** `store.schema` namespace — avoids colliding with {@link SqlStoreDecl.table} CDC. */
485
+ export const schema = {
486
+ table: schemaTable,
487
+ relations: schemaRelations,
488
+ } as const;
489
+
490
+ /**
491
+ * Collect {@link SchemaTableDecl} values from a module's exports.
492
+ *
493
+ * @param mod - Module namespace object
494
+ */
495
+ export function tablesFromExports(mod: Readonly<Record<string, unknown>>): SchemaTableDecl[] {
496
+ const out: SchemaTableDecl[] = [];
497
+ for (const value of Object.values(mod)) {
498
+ if (isSchemaTableDecl(value)) out.push(value);
499
+ }
500
+ return out;
501
+ }
502
+
503
+ /**
504
+ * Collect {@link SchemaRelationsDecl} values from a module's exports.
505
+ *
506
+ * @param mod - Module namespace object
507
+ */
508
+ export function relationsFromExports(
509
+ mod: Readonly<Record<string, unknown>>,
510
+ ): SchemaRelationsDecl[] {
511
+ const out: SchemaRelationsDecl[] = [];
512
+ for (const value of Object.values(mod)) {
513
+ if (isSchemaRelationsDecl(value)) out.push(value);
514
+ }
515
+ return out;
516
+ }
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Drizzle condition compiler — parenthesized `or`/`and` groups, `like` /
3
+ * `ilike`, loud failures on unsupported operators, and `orderBy` terms.
4
+ */
5
+
6
+ import { describe, expect, test } from "bun:test";
7
+ import {
8
+ and,
9
+ asc,
10
+ between,
11
+ desc,
12
+ eq,
13
+ ilike,
14
+ inArray,
15
+ isNotNull,
16
+ isNull,
17
+ like,
18
+ lt,
19
+ not,
20
+ or,
21
+ sql,
22
+ } from "drizzle-orm";
23
+ import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
24
+ import { compileOrderBy, compileWhere } from "./sql-condition.ts";
25
+
26
+ const notes = sqliteTable("notes", {
27
+ id: text("id").primaryKey(),
28
+ title: text("title").notNull(),
29
+ createdAt: integer("created_at").notNull(),
30
+ });
31
+
32
+ describe("compileWhere", () => {
33
+ test("bare comparison stays unparenthesized", () => {
34
+ const c = compileWhere(eq(notes.id, "n1"));
35
+ expect(c.clause).toBe(`"id" = ?`);
36
+ expect(c.params).toEqual(["n1"]);
37
+ });
38
+
39
+ test("like compiles to LIKE + bound pattern", () => {
40
+ const c = compileWhere(like(notes.title, "%hello%"));
41
+ expect(c.clause).toBe(`"title" like ?`);
42
+ expect(c.params).toEqual(["%hello%"]);
43
+ });
44
+
45
+ test("ilike compiles to ILIKE + bound pattern (postgres parity)", () => {
46
+ const c = compileWhere(ilike(notes.title, "%Hello%"));
47
+ expect(c.clause).toBe(`"title" ilike ?`);
48
+ expect(c.params).toEqual(["%Hello%"]);
49
+ });
50
+
51
+ test("and joins with AND", () => {
52
+ const c = compileWhere(and(eq(notes.id, "n1"), eq(notes.title, "t")));
53
+ expect(c.clause).toBe(`("id" = ?) AND ("title" = ?)`);
54
+ expect(c.params).toEqual(["n1", "t"]);
55
+ });
56
+
57
+ test("or produces a parenthesized OR group — never flattened into AND", () => {
58
+ const c = compileWhere(or(eq(notes.id, "n1"), lt(notes.createdAt, 10)));
59
+ expect(c.clause).toBe(`("id" = ?) OR ("created_at" < ?)`);
60
+ expect(c.params).toEqual(["n1", 10]);
61
+ });
62
+
63
+ test("composite cursor predicate keeps OR/AND precedence", () => {
64
+ const c = compileWhere(
65
+ and(
66
+ like(notes.title, "%x%"),
67
+ or(lt(notes.createdAt, 100), and(eq(notes.createdAt, 100), lt(notes.id, "n1"))),
68
+ ),
69
+ );
70
+ expect(c.clause).toBe(
71
+ `("title" like ?) AND (("created_at" < ?) OR (("created_at" = ?) AND ("id" < ?)))`,
72
+ );
73
+ expect(c.params).toEqual(["%x%", 100, 100, "n1"]);
74
+ expect(c.predicates.map((p) => p.op)).toEqual(["like", "<", "=", "<"]);
75
+ });
76
+
77
+ test("single-condition or() collapses to the leaf", () => {
78
+ const c = compileWhere(or(eq(notes.id, "n1")));
79
+ expect(c.clause).toBe(`"id" = ?`);
80
+ expect(c.params).toEqual(["n1"]);
81
+ });
82
+
83
+ test("plain equality maps are unchanged", () => {
84
+ const c = compileWhere({ id: "n1", title: "t" });
85
+ expect(c.clause).toBe(`"id" = ? AND "title" = ?`);
86
+ expect(c.params).toEqual(["n1", "t"]);
87
+ });
88
+
89
+ test("inArray expands one placeholder per value", () => {
90
+ const c = compileWhere(inArray(notes.id, ["a", "b", "c"]));
91
+ expect(c.clause).toBe(`"id" in (?, ?, ?)`);
92
+ expect(c.params).toEqual(["a", "b", "c"]);
93
+ expect(c.predicates.map((p) => p.op)).toEqual(["in"]);
94
+ });
95
+
96
+ test("isNull / isNotNull bind no value", () => {
97
+ const nil = compileWhere(isNull(notes.title));
98
+ expect(nil.clause).toBe(`"title" is null`);
99
+ expect(nil.params).toEqual([]);
100
+ const notNil = compileWhere(and(eq(notes.id, "n1"), isNotNull(notes.title)));
101
+ expect(notNil.clause).toBe(`("id" = ?) AND ("title" is not null)`);
102
+ expect(notNil.params).toEqual(["n1"]);
103
+ });
104
+
105
+ test("boolean equality binds the boolean", () => {
106
+ const c = compileWhere(eq(notes.id, true as never));
107
+ expect(c.clause).toBe(`"id" = ?`);
108
+ expect(c.params).toEqual([true]);
109
+ });
110
+
111
+ test("unsupported operators fail loudly instead of dropping predicates", () => {
112
+ expect(() => compileWhere(between(notes.createdAt, 1, 2))).toThrow(/unsupported operator/);
113
+ expect(() => compileWhere(not(eq(notes.id, "n1")))).toThrow(/unsupported fragment/);
114
+ expect(() => compileWhere(sql`title = 1`)).toThrow(/unsupported fragment/);
115
+ });
116
+ });
117
+
118
+ describe("compileOrderBy", () => {
119
+ test("asc/desc terms with bare-column default", () => {
120
+ const terms = compileOrderBy([desc(notes.createdAt), asc(notes.id), notes.title]);
121
+ expect(terms).toEqual([
122
+ { column: "created_at", direction: "DESC" },
123
+ { column: "id", direction: "ASC" },
124
+ { column: "title", direction: "ASC" },
125
+ ]);
126
+ });
127
+
128
+ test("garbage terms fail loudly", () => {
129
+ expect(() => compileOrderBy([sql`random()`])).toThrow(/orderBy/);
130
+ expect(() => compileOrderBy([42])).toThrow(/orderBy/);
131
+ });
132
+ });