@aotter/mantle 0.2.0-alpha.6 → 0.2.0-alpha.7

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 (942) hide show
  1. package/README.md +152 -45
  2. package/dist/auth/adapter.d.ts +32 -0
  3. package/dist/auth/adapter.js +285 -0
  4. package/dist/auth/admin.d.ts +3 -0
  5. package/dist/auth/admin.js +21 -0
  6. package/dist/auth/caller.d.ts +86 -0
  7. package/dist/auth/caller.js +154 -0
  8. package/dist/auth/hardening.d.ts +24 -0
  9. package/dist/auth/hardening.js +40 -0
  10. package/dist/auth/identity.d.ts +121 -0
  11. package/dist/auth/identity.js +203 -0
  12. package/dist/auth/oauth.d.ts +31 -0
  13. package/dist/auth/oauth.js +124 -0
  14. package/dist/auth/resource-seeds.js +10 -0
  15. package/dist/auth/routes.d.ts +32 -0
  16. package/dist/auth/{createAuthRoutes.js → routes.js} +130 -35
  17. package/dist/build/compiler.d.ts +790 -0
  18. package/dist/build/compiler.js +6971 -0
  19. package/dist/{spec → build/spec}/domain/model/ManifestGrammar.d.ts +24 -42
  20. package/dist/{spec → build/spec}/domain/model/RuntimePlan.d.ts +77 -3
  21. package/dist/{spec → build/spec}/domain/model/SqlIr.d.ts +35 -6
  22. package/dist/build/spec/domain/model/UserFields.d.ts +20 -0
  23. package/dist/{spec → build/spec}/domain/service/PlanFingerprint.d.ts +2 -1
  24. package/dist/{spec → build/spec}/kernel/diagnostic.d.ts +1 -30
  25. package/dist/bun/assets.d.ts +2 -0
  26. package/dist/bun/assets.js +24 -0
  27. package/dist/domain/adminOrder.js +24 -0
  28. package/dist/domain/columns.js +55 -0
  29. package/dist/domain/describe/chunk-ZIQVLA7X.js +363 -0
  30. package/dist/domain/describe/index.d.ts +58 -0
  31. package/dist/domain/describe/index.js +115 -0
  32. package/dist/domain/describe/target-hash.d.ts +8 -0
  33. package/dist/domain/describe/target-hash.js +12 -0
  34. package/dist/domain/describe/targets.d.ts +40 -0
  35. package/dist/domain/entry.js +33 -0
  36. package/dist/domain/generated-tools.js +17 -0
  37. package/dist/domain/generation.d.ts +16 -0
  38. package/dist/domain/generation.js +1 -0
  39. package/dist/domain/input.js +17 -0
  40. package/dist/domain/model.js +1 -0
  41. package/dist/domain/paging.js +204 -0
  42. package/dist/domain/recipes.js +19 -0
  43. package/dist/domain/userReferences.js +5 -0
  44. package/dist/domain/wireScalars.js +47 -0
  45. package/dist/infrastructure/adminEntries.js +153 -0
  46. package/dist/infrastructure/adminPaging.js +72 -0
  47. package/dist/infrastructure/artifacts.js +71 -0
  48. package/dist/infrastructure/authSchema.js +83 -0
  49. package/dist/infrastructure/bundle.js +84 -0
  50. package/dist/infrastructure/cli.js +101 -0
  51. package/dist/infrastructure/generate.d.ts +14 -0
  52. package/dist/infrastructure/generate.js +174 -0
  53. package/dist/infrastructure/generateAuth.d.ts +8 -0
  54. package/dist/infrastructure/generateAuth.js +17 -0
  55. package/dist/infrastructure/inputs.js +36 -0
  56. package/dist/infrastructure/wrangler.js +71 -0
  57. package/dist/kernel/authorization.d.ts +4 -0
  58. package/dist/kernel/authorization.js +16 -0
  59. package/dist/kernel/binds.d.ts +51 -0
  60. package/dist/kernel/binds.js +45 -0
  61. package/dist/kernel/caller-identity.d.ts +24 -0
  62. package/dist/kernel/caller-identity.js +22 -0
  63. package/dist/kernel/contract-error.d.ts +12 -0
  64. package/dist/kernel/contract-error.js +14 -0
  65. package/dist/kernel/contracts.d.ts +139 -0
  66. package/dist/kernel/contracts.js +92 -0
  67. package/dist/{spec/domain/service/CloudflareCron.d.ts → kernel/cron.d.ts} +0 -1
  68. package/dist/{spec/domain/service/CloudflareCron.js → kernel/cron.js} +1 -6
  69. package/dist/kernel/dialect/common.d.ts +39 -0
  70. package/dist/kernel/dialect/common.js +6 -0
  71. package/dist/kernel/dialect/postgres.d.ts +16 -0
  72. package/dist/kernel/dialect/postgres.js +18 -0
  73. package/dist/kernel/dialect/sqlite.d.ts +20 -0
  74. package/dist/kernel/dialect/sqlite.js +34 -0
  75. package/dist/kernel/driver/bun-sqlite.d.ts +19 -0
  76. package/dist/kernel/driver/bun-sqlite.js +77 -0
  77. package/dist/kernel/driver/d1.d.ts +24 -0
  78. package/dist/kernel/driver/d1.js +22 -0
  79. package/dist/kernel/driver/postgres.d.ts +25 -0
  80. package/dist/kernel/driver/postgres.js +95 -0
  81. package/dist/kernel/driver/transaction-context.d.ts +10 -0
  82. package/dist/kernel/driver/transaction-context.js +29 -0
  83. package/dist/kernel/email.d.ts +28 -0
  84. package/dist/{auth/emailTemplates.js → kernel/email.js} +13 -2
  85. package/dist/kernel/host-access.d.ts +10 -0
  86. package/dist/kernel/host-access.js +65 -0
  87. package/dist/kernel/host-caller.d.ts +38 -0
  88. package/dist/kernel/host-caller.js +55 -0
  89. package/dist/kernel/json-body.d.ts +4 -0
  90. package/dist/kernel/json-body.js +44 -0
  91. package/dist/kernel/mcp-apps.d.ts +49 -0
  92. package/dist/kernel/mcp-apps.js +40 -0
  93. package/dist/kernel/mcp-call.d.ts +5 -0
  94. package/dist/kernel/mcp-call.js +25 -0
  95. package/dist/kernel/mcp-handler.js +288 -0
  96. package/dist/kernel/mcp.d.ts +101 -0
  97. package/dist/kernel/mcp.js +25 -0
  98. package/dist/kernel/media.d.ts +27 -0
  99. package/dist/kernel/media.js +216 -0
  100. package/dist/kernel/paging.d.ts +55 -0
  101. package/dist/kernel/paging.js +95 -0
  102. package/dist/kernel/publishing.d.ts +4 -0
  103. package/dist/kernel/publishing.js +16 -0
  104. package/dist/{cloudflare/r2Media.d.ts → kernel/r2-media.d.ts} +4 -5
  105. package/dist/kernel/r2-media.js +78 -0
  106. package/dist/kernel/rest-dispatch.js +38 -0
  107. package/dist/kernel/rest-router.js +63 -0
  108. package/dist/kernel/rest.d.ts +58 -0
  109. package/dist/kernel/rest.js +41 -0
  110. package/dist/kernel/scalars.d.ts +6 -0
  111. package/dist/kernel/scalars.js +43 -0
  112. package/dist/kernel/search.js +5 -0
  113. package/dist/{core/site.d.ts → kernel/site-types.d.ts} +38 -9
  114. package/dist/kernel/site-types.js +1 -0
  115. package/dist/kernel/site.d.ts +41 -0
  116. package/dist/kernel/site.js +32 -0
  117. package/dist/kernel/store.d.ts +165 -0
  118. package/dist/kernel/store.js +257 -0
  119. package/dist/kernel/surface.d.ts +10 -0
  120. package/dist/kernel/surface.js +19 -0
  121. package/dist/kernel/sweep.d.ts +17 -0
  122. package/dist/kernel/sweep.js +27 -0
  123. package/dist/kernel/translations.d.ts +1 -0
  124. package/dist/kernel/translations.js +13 -0
  125. package/dist/kernel/user-caller.d.ts +31 -0
  126. package/dist/kernel/user-caller.js +67 -0
  127. package/dist/kernel/user-field-name.js +3 -0
  128. package/dist/kernel/user-fields.d.ts +34 -0
  129. package/dist/kernel/user-fields.js +71 -0
  130. package/dist/kernel/validation.d.ts +15 -0
  131. package/dist/kernel/validation.js +54 -0
  132. package/dist/kernel/web-gateway.js +68 -0
  133. package/dist/kernel/web-head.js +15 -0
  134. package/dist/kernel/web-response.js +8 -0
  135. package/dist/kernel/web.d.ts +75 -0
  136. package/dist/kernel/web.js +155 -0
  137. package/dist/kernel/where.js +27 -0
  138. package/dist/testing/index.d.ts +1 -37
  139. package/dist/testing/index.js +1 -43
  140. package/dist/usecase/adminBindings.js +142 -0
  141. package/dist/usecase/adminDescriptors.js +153 -0
  142. package/dist/usecase/generate.js +164 -0
  143. package/dist/usecase/handlers.js +21 -0
  144. package/dist/usecase/mcp-media.js +17 -0
  145. package/dist/usecase/mcp.js +96 -0
  146. package/dist/usecase/paging.js +72 -0
  147. package/dist/usecase/publishing.js +63 -0
  148. package/dist/usecase/refusals.js +27 -0
  149. package/dist/usecase/rest.js +54 -0
  150. package/dist/usecase/search.js +7 -0
  151. package/dist/usecase/site.js +40 -0
  152. package/dist/usecase/stores.js +62 -0
  153. package/dist/usecase/translations.js +78 -0
  154. package/dist/usecase/ttl.js +20 -0
  155. package/dist/usecase/validation.js +132 -0
  156. package/dist/usecase/web.js +22 -0
  157. package/docs/examples/README.md +31 -16
  158. package/docs/examples/app-shell/README.md +48 -0
  159. package/docs/examples/app-shell/package.json +34 -0
  160. package/docs/examples/app-shell/pnpm-workspace.yaml +8 -0
  161. package/docs/examples/app-shell/smoke-kit.mjs +100 -0
  162. package/docs/examples/app-shell/src/admin.ts +10 -0
  163. package/docs/examples/app-shell/src/auth.ts +55 -0
  164. package/docs/examples/app-shell/src/handlers.ts +5 -0
  165. package/docs/examples/app-shell/src/index.ts +4 -0
  166. package/docs/examples/app-shell/src/routes.ts +13 -0
  167. package/docs/examples/app-shell/src/schedule.ts +8 -0
  168. package/docs/examples/app-shell/src/service.ts +70 -0
  169. package/docs/examples/app-shell/src/sign-in.ts +41 -0
  170. package/docs/examples/app-shell/src/signup.ts +8 -0
  171. package/docs/examples/{reference-service → app-shell}/tsconfig.json +2 -1
  172. package/docs/examples/app-shell/worker-configuration.d.ts +22 -0
  173. package/docs/examples/app-shell/wrangler.jsonc +61 -0
  174. package/docs/examples/club-events/README.md +60 -0
  175. package/docs/examples/club-events/manifests/club-events.yaml +225 -0
  176. package/docs/examples/club-events/smoke.mjs +121 -0
  177. package/docs/examples/club-events/src/handlers.ts +25 -0
  178. package/docs/examples/club-events/src/signup.ts +9 -0
  179. package/docs/examples/generated-web/README.md +74 -0
  180. package/docs/examples/generated-web/posts.yaml +38 -0
  181. package/docs/examples/generated-web/seed.sql +6 -0
  182. package/docs/examples/generated-web/src/worker.ts +43 -0
  183. package/docs/examples/generated-web/tsconfig.json +8 -0
  184. package/docs/examples/generated-web/wrangler.jsonc +7 -0
  185. package/docs/examples/purchasing/.dev.vars.example +6 -0
  186. package/docs/examples/purchasing/README.md +90 -0
  187. package/docs/examples/purchasing/manifests/purchasing.yaml +341 -0
  188. package/docs/examples/purchasing/seed.sql +4 -0
  189. package/docs/examples/purchasing/smoke.mjs +171 -0
  190. package/docs/examples/purchasing/src/admin.ts +12 -0
  191. package/docs/examples/purchasing/src/handlers.ts +33 -0
  192. package/docs/examples/purchasing/src/notify.ts +29 -0
  193. package/docs/examples/purchasing/src/requests-page.ts +57 -0
  194. package/docs/examples/purchasing/src/routes.ts +53 -0
  195. package/docs/examples/purchasing/src/schedule.ts +31 -0
  196. package/docs/examples/purchasing/src/signup.ts +5 -0
  197. package/docs/examples/purchasing/src/supplier.ts +32 -0
  198. package/docs/examples/purchasing/wrangler.jsonc +68 -0
  199. package/docs/examples/recipes/README.md +58 -0
  200. package/docs/examples/recipes/manifests/recipes.yaml +75 -0
  201. package/docs/examples/recipes/smoke.mjs +102 -0
  202. package/docs/examples/recipes/src/media.ts +13 -0
  203. package/docs/examples/recipes/src/pages.ts +99 -0
  204. package/docs/examples/recipes/src/routes.ts +71 -0
  205. package/docs/examples/recipes/src/site-config.ts +12 -0
  206. package/docs/examples/recipes/wrangler.jsonc +73 -0
  207. package/docs/handbook/cloudflare/authentication.md +142 -212
  208. package/docs/handbook/cloudflare/chatgpt-sites.md +4 -113
  209. package/docs/handbook/cloudflare/deploy-and-operate.md +20 -106
  210. package/docs/handbook/cloudflare/media-r2.md +62 -133
  211. package/docs/handbook/cloudflare/service-entry.md +180 -116
  212. package/docs/handbook/concepts/authorization.md +10 -123
  213. package/docs/handbook/concepts/four-atoms.md +9 -92
  214. package/docs/handbook/concepts/lifecycle-and-locales.md +9 -80
  215. package/docs/handbook/concepts/mcp-and-agents.md +10 -141
  216. package/docs/handbook/concepts/procedures-and-triggers.md +5 -162
  217. package/docs/handbook/concepts/runtime-and-adapters.md +15 -224
  218. package/docs/handbook/concepts/views.md +10 -109
  219. package/docs/handbook/examples/hub.md +2 -18
  220. package/docs/handbook/guides/adapter-guide.md +11 -0
  221. package/docs/handbook/guides/admin-extensions.md +12 -183
  222. package/docs/handbook/guides/admin-ui.md +5 -164
  223. package/docs/handbook/guides/agent-setup.md +5 -18
  224. package/docs/handbook/guides/email.md +86 -0
  225. package/docs/handbook/guides/mcp-apps.md +44 -0
  226. package/docs/handbook/guides/native-admin.md +298 -0
  227. package/docs/handbook/guides/native-execution.md +132 -0
  228. package/docs/handbook/guides/oauth.md +105 -0
  229. package/docs/handbook/guides/postgres-adapters.md +56 -0
  230. package/docs/handbook/guides/public-pages.md +53 -0
  231. package/docs/handbook/guides/size-and-startup.md +9 -0
  232. package/docs/handbook/guides/typed-queries.md +39 -102
  233. package/docs/handbook/navigation.json +164 -31
  234. package/docs/handbook/reference/admin-descriptors.md +88 -0
  235. package/docs/handbook/reference/authorization.md +44 -52
  236. package/docs/handbook/reference/describe.md +56 -0
  237. package/docs/handbook/reference/diagnostics.md +15 -79
  238. package/docs/handbook/reference/features.md +45 -53
  239. package/docs/handbook/reference/manifest.md +6 -69
  240. package/docs/handbook/reference/procedure.md +9 -118
  241. package/docs/handbook/reference/schema.md +75 -185
  242. package/docs/handbook/reference/site-config.md +5 -65
  243. package/docs/handbook/reference/surface.md +279 -97
  244. package/docs/handbook/reference/trigger.md +24 -93
  245. package/docs/handbook/reference/view.md +32 -160
  246. package/docs/handbook/releases/index.md +48 -13
  247. package/docs/handbook/start/overview.md +9 -56
  248. package/docs/handbook/start/project-and-cli.md +40 -149
  249. package/docs/handbook/start/quickstart-worker.md +38 -116
  250. package/docs/skills/develop/SKILL.md +34 -123
  251. package/docs/skills/develop/mcp-app.md +37 -77
  252. package/docs/skills/integrate/SKILL.md +42 -84
  253. package/docs/skills/media-gc/SKILL.md +14 -3
  254. package/docs/skills/provision/SKILL.md +25 -91
  255. package/docs/skills/update/SKILL.md +19 -43
  256. package/docs/source/scripts/postgres-adapter.ts +101 -0
  257. package/docs/upgrade-0.1-to-0.2.md +25 -9
  258. package/package.json +96 -112
  259. package/skills/.keep +0 -0
  260. package/skills/README.md +72 -0
  261. package/skills/mantle/SKILL.md +135 -0
  262. package/skills/mantle/references/local-testing.md +11 -0
  263. package/skills/mantle/references/web.md +41 -0
  264. package/skills/mantle/references/website.md +47 -0
  265. package/dist/admin/consent.d.ts +0 -17
  266. package/dist/admin/consent.d.ts.map +0 -1
  267. package/dist/admin/consent.js +0 -17
  268. package/dist/admin/consent.js.map +0 -1
  269. package/dist/admin/createAdminSurface.d.ts +0 -25
  270. package/dist/admin/createAdminSurface.d.ts.map +0 -1
  271. package/dist/admin/createAdminSurface.js +0 -635
  272. package/dist/admin/createAdminSurface.js.map +0 -1
  273. package/dist/admin/design.d.ts +0 -7
  274. package/dist/admin/design.d.ts.map +0 -1
  275. package/dist/admin/design.js +0 -18
  276. package/dist/admin/design.js.map +0 -1
  277. package/dist/admin/developerConsole.d.ts +0 -267
  278. package/dist/admin/developerConsole.d.ts.map +0 -1
  279. package/dist/admin/developerConsole.js +0 -136
  280. package/dist/admin/developerConsole.js.map +0 -1
  281. package/dist/admin/extensions.d.ts +0 -290
  282. package/dist/admin/extensions.d.ts.map +0 -1
  283. package/dist/admin/extensions.js +0 -532
  284. package/dist/admin/extensions.js.map +0 -1
  285. package/dist/admin/identity.d.ts +0 -62
  286. package/dist/admin/identity.d.ts.map +0 -1
  287. package/dist/admin/identity.js +0 -7
  288. package/dist/admin/identity.js.map +0 -1
  289. package/dist/admin/index.d.ts +0 -7
  290. package/dist/admin/index.d.ts.map +0 -1
  291. package/dist/admin/index.js +0 -7
  292. package/dist/admin/index.js.map +0 -1
  293. package/dist/admin/procedureFlow.d.ts +0 -38
  294. package/dist/admin/procedureFlow.d.ts.map +0 -1
  295. package/dist/admin/procedureFlow.js +0 -188
  296. package/dist/admin/procedureFlow.js.map +0 -1
  297. package/dist/auth/ConsoleEmailSender.d.ts +0 -15
  298. package/dist/auth/ConsoleEmailSender.d.ts.map +0 -1
  299. package/dist/auth/ConsoleEmailSender.js +0 -19
  300. package/dist/auth/ConsoleEmailSender.js.map +0 -1
  301. package/dist/auth/appleClientSecret.d.ts +0 -75
  302. package/dist/auth/appleClientSecret.d.ts.map +0 -1
  303. package/dist/auth/appleClientSecret.js +0 -116
  304. package/dist/auth/appleClientSecret.js.map +0 -1
  305. package/dist/auth/buildAuth.d.ts +0 -4568
  306. package/dist/auth/buildAuth.d.ts.map +0 -1
  307. package/dist/auth/buildAuth.js +0 -312
  308. package/dist/auth/buildAuth.js.map +0 -1
  309. package/dist/auth/callerResolver.d.ts +0 -52
  310. package/dist/auth/callerResolver.d.ts.map +0 -1
  311. package/dist/auth/callerResolver.js +0 -52
  312. package/dist/auth/callerResolver.js.map +0 -1
  313. package/dist/auth/createAuthRoutes.d.ts +0 -22
  314. package/dist/auth/createAuthRoutes.d.ts.map +0 -1
  315. package/dist/auth/createAuthRoutes.js.map +0 -1
  316. package/dist/auth/createMantleAuth.d.ts +0 -3
  317. package/dist/auth/createMantleAuth.d.ts.map +0 -1
  318. package/dist/auth/createMantleAuth.js +0 -504
  319. package/dist/auth/createMantleAuth.js.map +0 -1
  320. package/dist/auth/db.d.ts +0 -18
  321. package/dist/auth/db.d.ts.map +0 -1
  322. package/dist/auth/db.js +0 -27
  323. package/dist/auth/db.js.map +0 -1
  324. package/dist/auth/emailTemplates.d.ts +0 -7
  325. package/dist/auth/emailTemplates.d.ts.map +0 -1
  326. package/dist/auth/emailTemplates.js.map +0 -1
  327. package/dist/auth/index.d.ts +0 -9
  328. package/dist/auth/index.d.ts.map +0 -1
  329. package/dist/auth/index.js +0 -7
  330. package/dist/auth/index.js.map +0 -1
  331. package/dist/auth/methods.d.ts +0 -717
  332. package/dist/auth/methods.d.ts.map +0 -1
  333. package/dist/auth/methods.js +0 -321
  334. package/dist/auth/methods.js.map +0 -1
  335. package/dist/auth/oauthTokens.d.ts +0 -24
  336. package/dist/auth/oauthTokens.d.ts.map +0 -1
  337. package/dist/auth/oauthTokens.js +0 -146
  338. package/dist/auth/oauthTokens.js.map +0 -1
  339. package/dist/auth/setupIncomplete.d.ts +0 -16
  340. package/dist/auth/setupIncomplete.d.ts.map +0 -1
  341. package/dist/auth/setupIncomplete.js +0 -50
  342. package/dist/auth/setupIncomplete.js.map +0 -1
  343. package/dist/auth/types.d.ts +0 -440
  344. package/dist/auth/types.d.ts.map +0 -1
  345. package/dist/auth/types.js +0 -10
  346. package/dist/auth/types.js.map +0 -1
  347. package/dist/bun/index.d.ts +0 -21
  348. package/dist/bun/index.d.ts.map +0 -1
  349. package/dist/bun/index.js +0 -46
  350. package/dist/bun/index.js.map +0 -1
  351. package/dist/cli/emitModule.d.ts +0 -7
  352. package/dist/cli/emitModule.d.ts.map +0 -1
  353. package/dist/cli/emitModule.js +0 -127
  354. package/dist/cli/emitModule.js.map +0 -1
  355. package/dist/cli/generate.d.ts +0 -8
  356. package/dist/cli/generate.d.ts.map +0 -1
  357. package/dist/cli/generate.js +0 -391
  358. package/dist/cli/generate.js.map +0 -1
  359. package/dist/cli/main.d.ts +0 -3
  360. package/dist/cli/main.d.ts.map +0 -1
  361. package/dist/cli/main.js +0 -21
  362. package/dist/cli/main.js.map +0 -1
  363. package/dist/cli/preset.d.ts +0 -18
  364. package/dist/cli/preset.d.ts.map +0 -1
  365. package/dist/cli/preset.js +0 -405
  366. package/dist/cli/preset.js.map +0 -1
  367. package/dist/cloudflare/index.d.ts +0 -25
  368. package/dist/cloudflare/index.d.ts.map +0 -1
  369. package/dist/cloudflare/index.js +0 -16
  370. package/dist/cloudflare/index.js.map +0 -1
  371. package/dist/cloudflare/r2Media.d.ts.map +0 -1
  372. package/dist/cloudflare/r2Media.js +0 -69
  373. package/dist/cloudflare/r2Media.js.map +0 -1
  374. package/dist/core/caller.d.ts +0 -35
  375. package/dist/core/caller.d.ts.map +0 -1
  376. package/dist/core/caller.js +0 -3
  377. package/dist/core/caller.js.map +0 -1
  378. package/dist/core/createMantle.d.ts +0 -22
  379. package/dist/core/createMantle.d.ts.map +0 -1
  380. package/dist/core/createMantle.js +0 -117
  381. package/dist/core/createMantle.js.map +0 -1
  382. package/dist/core/dialect.d.ts +0 -53
  383. package/dist/core/dialect.d.ts.map +0 -1
  384. package/dist/core/dialect.js +0 -7
  385. package/dist/core/dialect.js.map +0 -1
  386. package/dist/core/driver.d.ts +0 -24
  387. package/dist/core/driver.d.ts.map +0 -1
  388. package/dist/core/driver.js +0 -2
  389. package/dist/core/driver.js.map +0 -1
  390. package/dist/core/email.d.ts +0 -17
  391. package/dist/core/email.d.ts.map +0 -1
  392. package/dist/core/email.js +0 -2
  393. package/dist/core/email.js.map +0 -1
  394. package/dist/core/index.d.ts +0 -16
  395. package/dist/core/index.d.ts.map +0 -1
  396. package/dist/core/index.js +0 -16
  397. package/dist/core/index.js.map +0 -1
  398. package/dist/core/invocation.d.ts +0 -66
  399. package/dist/core/invocation.d.ts.map +0 -1
  400. package/dist/core/invocation.js +0 -3
  401. package/dist/core/invocation.js.map +0 -1
  402. package/dist/core/observation.d.ts +0 -3
  403. package/dist/core/observation.d.ts.map +0 -1
  404. package/dist/core/observation.js +0 -10
  405. package/dist/core/observation.js.map +0 -1
  406. package/dist/core/runtime/auth.d.ts +0 -9
  407. package/dist/core/runtime/auth.d.ts.map +0 -1
  408. package/dist/core/runtime/auth.js +0 -39
  409. package/dist/core/runtime/auth.js.map +0 -1
  410. package/dist/core/runtime/createRuntime.d.ts +0 -23
  411. package/dist/core/runtime/createRuntime.d.ts.map +0 -1
  412. package/dist/core/runtime/createRuntime.js +0 -214
  413. package/dist/core/runtime/createRuntime.js.map +0 -1
  414. package/dist/core/runtime/verifyPlan.d.ts +0 -34
  415. package/dist/core/runtime/verifyPlan.d.ts.map +0 -1
  416. package/dist/core/runtime/verifyPlan.js +0 -301
  417. package/dist/core/runtime/verifyPlan.js.map +0 -1
  418. package/dist/core/service.d.ts +0 -45
  419. package/dist/core/service.d.ts.map +0 -1
  420. package/dist/core/service.js +0 -2
  421. package/dist/core/service.js.map +0 -1
  422. package/dist/core/sessionUser.d.ts +0 -14
  423. package/dist/core/sessionUser.d.ts.map +0 -1
  424. package/dist/core/sessionUser.js +0 -4
  425. package/dist/core/sessionUser.js.map +0 -1
  426. package/dist/core/site.d.ts.map +0 -1
  427. package/dist/core/site.js +0 -2
  428. package/dist/core/site.js.map +0 -1
  429. package/dist/core/siteConfig.d.ts +0 -5
  430. package/dist/core/siteConfig.d.ts.map +0 -1
  431. package/dist/core/siteConfig.js +0 -24
  432. package/dist/core/siteConfig.js.map +0 -1
  433. package/dist/core/sql/allowlist.d.ts +0 -67
  434. package/dist/core/sql/allowlist.d.ts.map +0 -1
  435. package/dist/core/sql/allowlist.js +0 -737
  436. package/dist/core/sql/allowlist.js.map +0 -1
  437. package/dist/core/sql/ast.d.ts +0 -24
  438. package/dist/core/sql/ast.d.ts.map +0 -1
  439. package/dist/core/sql/ast.js +0 -32
  440. package/dist/core/sql/ast.js.map +0 -1
  441. package/dist/core/sql/compile.d.ts +0 -50
  442. package/dist/core/sql/compile.d.ts.map +0 -1
  443. package/dist/core/sql/compile.js +0 -48
  444. package/dist/core/sql/compile.js.map +0 -1
  445. package/dist/core/sql/policy.d.ts +0 -123
  446. package/dist/core/sql/policy.d.ts.map +0 -1
  447. package/dist/core/sql/policy.js +0 -398
  448. package/dist/core/sql/policy.js.map +0 -1
  449. package/dist/core/sql/positions.d.ts +0 -30
  450. package/dist/core/sql/positions.d.ts.map +0 -1
  451. package/dist/core/sql/positions.js +0 -22
  452. package/dist/core/sql/positions.js.map +0 -1
  453. package/dist/core/sql/run.d.ts +0 -68
  454. package/dist/core/sql/run.d.ts.map +0 -1
  455. package/dist/core/sql/run.js +0 -384
  456. package/dist/core/sql/run.js.map +0 -1
  457. package/dist/core/store/createStore.d.ts +0 -49
  458. package/dist/core/store/createStore.d.ts.map +0 -1
  459. package/dist/core/store/createStore.js +0 -227
  460. package/dist/core/store/createStore.js.map +0 -1
  461. package/dist/core/store/cursor.d.ts +0 -4
  462. package/dist/core/store/cursor.d.ts.map +0 -1
  463. package/dist/core/store/cursor.js +0 -22
  464. package/dist/core/store/cursor.js.map +0 -1
  465. package/dist/core/store/json.d.ts +0 -80
  466. package/dist/core/store/json.d.ts.map +0 -1
  467. package/dist/core/store/json.js +0 -342
  468. package/dist/core/store/json.js.map +0 -1
  469. package/dist/core/store.d.ts +0 -160
  470. package/dist/core/store.d.ts.map +0 -1
  471. package/dist/core/store.js +0 -2
  472. package/dist/core/store.js.map +0 -1
  473. package/dist/core/wire.d.ts +0 -20
  474. package/dist/core/wire.d.ts.map +0 -1
  475. package/dist/core/wire.js +0 -84
  476. package/dist/core/wire.js.map +0 -1
  477. package/dist/core/withCaller.d.ts +0 -24
  478. package/dist/core/withCaller.d.ts.map +0 -1
  479. package/dist/core/withCaller.js +0 -35
  480. package/dist/core/withCaller.js.map +0 -1
  481. package/dist/d1/adapter.d.ts +0 -12
  482. package/dist/d1/adapter.d.ts.map +0 -1
  483. package/dist/d1/adapter.js +0 -23
  484. package/dist/d1/adapter.js.map +0 -1
  485. package/dist/d1/codec.d.ts +0 -14
  486. package/dist/d1/codec.d.ts.map +0 -1
  487. package/dist/d1/codec.js +0 -136
  488. package/dist/d1/codec.js.map +0 -1
  489. package/dist/d1/compile/index.d.ts +0 -9
  490. package/dist/d1/compile/index.d.ts.map +0 -1
  491. package/dist/d1/compile/index.js +0 -9
  492. package/dist/d1/compile/index.js.map +0 -1
  493. package/dist/d1/dialect.d.ts +0 -4
  494. package/dist/d1/dialect.d.ts.map +0 -1
  495. package/dist/d1/dialect.js +0 -13
  496. package/dist/d1/dialect.js.map +0 -1
  497. package/dist/d1/executor.d.ts +0 -15
  498. package/dist/d1/executor.d.ts.map +0 -1
  499. package/dist/d1/executor.js +0 -96
  500. package/dist/d1/executor.js.map +0 -1
  501. package/dist/d1/index.d.ts +0 -6
  502. package/dist/d1/index.d.ts.map +0 -1
  503. package/dist/d1/index.js +0 -6
  504. package/dist/d1/index.js.map +0 -1
  505. package/dist/d1/lower.d.ts +0 -8
  506. package/dist/d1/lower.d.ts.map +0 -1
  507. package/dist/d1/lower.js +0 -167
  508. package/dist/d1/lower.js.map +0 -1
  509. package/dist/d1/media.d.ts +0 -5
  510. package/dist/d1/media.d.ts.map +0 -1
  511. package/dist/d1/media.js +0 -157
  512. package/dist/d1/media.js.map +0 -1
  513. package/dist/d1/migrations.d.ts +0 -12
  514. package/dist/d1/migrations.d.ts.map +0 -1
  515. package/dist/d1/migrations.js +0 -111
  516. package/dist/d1/migrations.js.map +0 -1
  517. package/dist/d1/print.d.ts +0 -28
  518. package/dist/d1/print.d.ts.map +0 -1
  519. package/dist/d1/print.js +0 -54
  520. package/dist/d1/print.js.map +0 -1
  521. package/dist/d1/site.d.ts +0 -17
  522. package/dist/d1/site.d.ts.map +0 -1
  523. package/dist/d1/site.js +0 -63
  524. package/dist/d1/site.js.map +0 -1
  525. package/dist/d1/storage.d.ts +0 -34
  526. package/dist/d1/storage.d.ts.map +0 -1
  527. package/dist/d1/storage.js +0 -288
  528. package/dist/d1/storage.js.map +0 -1
  529. package/dist/d1/tz.d.ts +0 -21
  530. package/dist/d1/tz.d.ts.map +0 -1
  531. package/dist/d1/tz.js +0 -54
  532. package/dist/d1/tz.js.map +0 -1
  533. package/dist/d1/validator.d.ts +0 -10
  534. package/dist/d1/validator.d.ts.map +0 -1
  535. package/dist/d1/validator.js +0 -33
  536. package/dist/d1/validator.js.map +0 -1
  537. package/dist/mcp/apps.d.ts +0 -43
  538. package/dist/mcp/apps.d.ts.map +0 -1
  539. package/dist/mcp/apps.js +0 -57
  540. package/dist/mcp/apps.js.map +0 -1
  541. package/dist/mcp/catalog.d.ts +0 -55
  542. package/dist/mcp/catalog.d.ts.map +0 -1
  543. package/dist/mcp/catalog.js +0 -81
  544. package/dist/mcp/catalog.js.map +0 -1
  545. package/dist/mcp/createMcpSurface.d.ts +0 -60
  546. package/dist/mcp/createMcpSurface.d.ts.map +0 -1
  547. package/dist/mcp/createMcpSurface.js +0 -182
  548. package/dist/mcp/createMcpSurface.js.map +0 -1
  549. package/dist/mcp/index.d.ts +0 -4
  550. package/dist/mcp/index.d.ts.map +0 -1
  551. package/dist/mcp/index.js +0 -4
  552. package/dist/mcp/index.js.map +0 -1
  553. package/dist/mcp/media.d.ts +0 -9
  554. package/dist/mcp/media.d.ts.map +0 -1
  555. package/dist/mcp/media.js +0 -33
  556. package/dist/mcp/media.js.map +0 -1
  557. package/dist/postgres/adapter.d.ts +0 -23
  558. package/dist/postgres/adapter.d.ts.map +0 -1
  559. package/dist/postgres/adapter.js +0 -50
  560. package/dist/postgres/adapter.js.map +0 -1
  561. package/dist/postgres/codec.d.ts +0 -13
  562. package/dist/postgres/codec.d.ts.map +0 -1
  563. package/dist/postgres/codec.js +0 -110
  564. package/dist/postgres/codec.js.map +0 -1
  565. package/dist/postgres/compile/index.d.ts +0 -9
  566. package/dist/postgres/compile/index.d.ts.map +0 -1
  567. package/dist/postgres/compile/index.js +0 -9
  568. package/dist/postgres/compile/index.js.map +0 -1
  569. package/dist/postgres/driver.d.ts +0 -109
  570. package/dist/postgres/driver.d.ts.map +0 -1
  571. package/dist/postgres/driver.js +0 -186
  572. package/dist/postgres/driver.js.map +0 -1
  573. package/dist/postgres/executor.d.ts +0 -28
  574. package/dist/postgres/executor.d.ts.map +0 -1
  575. package/dist/postgres/executor.js +0 -96
  576. package/dist/postgres/executor.js.map +0 -1
  577. package/dist/postgres/index.d.ts +0 -8
  578. package/dist/postgres/index.d.ts.map +0 -1
  579. package/dist/postgres/index.js +0 -8
  580. package/dist/postgres/index.js.map +0 -1
  581. package/dist/postgres/lower.d.ts +0 -6
  582. package/dist/postgres/lower.d.ts.map +0 -1
  583. package/dist/postgres/lower.js +0 -152
  584. package/dist/postgres/lower.js.map +0 -1
  585. package/dist/postgres/print.d.ts +0 -11
  586. package/dist/postgres/print.d.ts.map +0 -1
  587. package/dist/postgres/print.js +0 -108
  588. package/dist/postgres/print.js.map +0 -1
  589. package/dist/postgres/session.d.ts +0 -9
  590. package/dist/postgres/session.d.ts.map +0 -1
  591. package/dist/postgres/session.js +0 -111
  592. package/dist/postgres/session.js.map +0 -1
  593. package/dist/postgres/storage.d.ts +0 -32
  594. package/dist/postgres/storage.d.ts.map +0 -1
  595. package/dist/postgres/storage.js +0 -283
  596. package/dist/postgres/storage.js.map +0 -1
  597. package/dist/postgres/validator.d.ts +0 -13
  598. package/dist/postgres/validator.d.ts.map +0 -1
  599. package/dist/postgres/validator.js +0 -53
  600. package/dist/postgres/validator.js.map +0 -1
  601. package/dist/spec/domain/index.d.ts +0 -3
  602. package/dist/spec/domain/index.d.ts.map +0 -1
  603. package/dist/spec/domain/index.js +0 -3
  604. package/dist/spec/domain/index.js.map +0 -1
  605. package/dist/spec/domain/model/ContentState.d.ts +0 -8
  606. package/dist/spec/domain/model/ContentState.d.ts.map +0 -1
  607. package/dist/spec/domain/model/ContentState.js +0 -7
  608. package/dist/spec/domain/model/ContentState.js.map +0 -1
  609. package/dist/spec/domain/model/Entry.d.ts +0 -29
  610. package/dist/spec/domain/model/Entry.d.ts.map +0 -1
  611. package/dist/spec/domain/model/Entry.js +0 -16
  612. package/dist/spec/domain/model/Entry.js.map +0 -1
  613. package/dist/spec/domain/model/Locale.d.ts +0 -30
  614. package/dist/spec/domain/model/Locale.d.ts.map +0 -1
  615. package/dist/spec/domain/model/Locale.js +0 -33
  616. package/dist/spec/domain/model/Locale.js.map +0 -1
  617. package/dist/spec/domain/model/ManifestGrammar.d.ts.map +0 -1
  618. package/dist/spec/domain/model/ManifestGrammar.js +0 -153
  619. package/dist/spec/domain/model/ManifestGrammar.js.map +0 -1
  620. package/dist/spec/domain/model/MediaMimeAccept.d.ts +0 -55
  621. package/dist/spec/domain/model/MediaMimeAccept.d.ts.map +0 -1
  622. package/dist/spec/domain/model/MediaMimeAccept.js +0 -90
  623. package/dist/spec/domain/model/MediaMimeAccept.js.map +0 -1
  624. package/dist/spec/domain/model/RuntimePlan.d.ts.map +0 -1
  625. package/dist/spec/domain/model/RuntimePlan.js +0 -4
  626. package/dist/spec/domain/model/RuntimePlan.js.map +0 -1
  627. package/dist/spec/domain/model/SiteConfig.d.ts +0 -173
  628. package/dist/spec/domain/model/SiteConfig.d.ts.map +0 -1
  629. package/dist/spec/domain/model/SiteConfig.js +0 -13
  630. package/dist/spec/domain/model/SiteConfig.js.map +0 -1
  631. package/dist/spec/domain/model/SqlIr.d.ts.map +0 -1
  632. package/dist/spec/domain/model/SqlIr.js +0 -95
  633. package/dist/spec/domain/model/SqlIr.js.map +0 -1
  634. package/dist/spec/domain/model/index.d.ts +0 -14
  635. package/dist/spec/domain/model/index.d.ts.map +0 -1
  636. package/dist/spec/domain/model/index.js +0 -14
  637. package/dist/spec/domain/model/index.js.map +0 -1
  638. package/dist/spec/domain/service/CloudflareCron.d.ts.map +0 -1
  639. package/dist/spec/domain/service/CloudflareCron.js.map +0 -1
  640. package/dist/spec/domain/service/CrossSchemaChecker.d.ts +0 -34
  641. package/dist/spec/domain/service/CrossSchemaChecker.d.ts.map +0 -1
  642. package/dist/spec/domain/service/CrossSchemaChecker.js +0 -114
  643. package/dist/spec/domain/service/CrossSchemaChecker.js.map +0 -1
  644. package/dist/spec/domain/service/EntryDataValidator.d.ts +0 -56
  645. package/dist/spec/domain/service/EntryDataValidator.d.ts.map +0 -1
  646. package/dist/spec/domain/service/EntryDataValidator.js +0 -88
  647. package/dist/spec/domain/service/EntryDataValidator.js.map +0 -1
  648. package/dist/spec/domain/service/JsonSchemaToZod.d.ts +0 -29
  649. package/dist/spec/domain/service/JsonSchemaToZod.d.ts.map +0 -1
  650. package/dist/spec/domain/service/JsonSchemaToZod.js +0 -156
  651. package/dist/spec/domain/service/JsonSchemaToZod.js.map +0 -1
  652. package/dist/spec/domain/service/LifecycleStateMachine.d.ts +0 -75
  653. package/dist/spec/domain/service/LifecycleStateMachine.d.ts.map +0 -1
  654. package/dist/spec/domain/service/LifecycleStateMachine.js +0 -76
  655. package/dist/spec/domain/service/LifecycleStateMachine.js.map +0 -1
  656. package/dist/spec/domain/service/LocaleCanonicalizer.d.ts +0 -29
  657. package/dist/spec/domain/service/LocaleCanonicalizer.d.ts.map +0 -1
  658. package/dist/spec/domain/service/LocaleCanonicalizer.js +0 -96
  659. package/dist/spec/domain/service/LocaleCanonicalizer.js.map +0 -1
  660. package/dist/spec/domain/service/ManifestFieldChecks.d.ts +0 -60
  661. package/dist/spec/domain/service/ManifestFieldChecks.d.ts.map +0 -1
  662. package/dist/spec/domain/service/ManifestFieldChecks.js +0 -116
  663. package/dist/spec/domain/service/ManifestFieldChecks.js.map +0 -1
  664. package/dist/spec/domain/service/ManifestGraphValidator.d.ts +0 -15
  665. package/dist/spec/domain/service/ManifestGraphValidator.d.ts.map +0 -1
  666. package/dist/spec/domain/service/ManifestGraphValidator.js +0 -225
  667. package/dist/spec/domain/service/ManifestGraphValidator.js.map +0 -1
  668. package/dist/spec/domain/service/ManifestLinker.d.ts +0 -45
  669. package/dist/spec/domain/service/ManifestLinker.d.ts.map +0 -1
  670. package/dist/spec/domain/service/ManifestLinker.js +0 -92
  671. package/dist/spec/domain/service/ManifestLinker.js.map +0 -1
  672. package/dist/spec/domain/service/ManifestLocaleTrimmer.d.ts +0 -16
  673. package/dist/spec/domain/service/ManifestLocaleTrimmer.d.ts.map +0 -1
  674. package/dist/spec/domain/service/ManifestLocaleTrimmer.js +0 -76
  675. package/dist/spec/domain/service/ManifestLocaleTrimmer.js.map +0 -1
  676. package/dist/spec/domain/service/ManifestParser.d.ts +0 -49
  677. package/dist/spec/domain/service/ManifestParser.d.ts.map +0 -1
  678. package/dist/spec/domain/service/ManifestParser.js +0 -203
  679. package/dist/spec/domain/service/ManifestParser.js.map +0 -1
  680. package/dist/spec/domain/service/ManifestPartition.d.ts +0 -9
  681. package/dist/spec/domain/service/ManifestPartition.d.ts.map +0 -1
  682. package/dist/spec/domain/service/ManifestPartition.js +0 -19
  683. package/dist/spec/domain/service/ManifestPartition.js.map +0 -1
  684. package/dist/spec/domain/service/ManifestPathDiagnoser.d.ts +0 -33
  685. package/dist/spec/domain/service/ManifestPathDiagnoser.d.ts.map +0 -1
  686. package/dist/spec/domain/service/ManifestPathDiagnoser.js +0 -43
  687. package/dist/spec/domain/service/ManifestPathDiagnoser.js.map +0 -1
  688. package/dist/spec/domain/service/ManifestSourceSpans.d.ts +0 -10
  689. package/dist/spec/domain/service/ManifestSourceSpans.d.ts.map +0 -1
  690. package/dist/spec/domain/service/ManifestSourceSpans.js +0 -76
  691. package/dist/spec/domain/service/ManifestSourceSpans.js.map +0 -1
  692. package/dist/spec/domain/service/McpToolNaming.d.ts +0 -25
  693. package/dist/spec/domain/service/McpToolNaming.d.ts.map +0 -1
  694. package/dist/spec/domain/service/McpToolNaming.js +0 -50
  695. package/dist/spec/domain/service/McpToolNaming.js.map +0 -1
  696. package/dist/spec/domain/service/PlanFingerprint.d.ts.map +0 -1
  697. package/dist/spec/domain/service/PlanFingerprint.js +0 -14
  698. package/dist/spec/domain/service/PlanFingerprint.js.map +0 -1
  699. package/dist/spec/domain/service/ProcedureViewSpecChecks.d.ts +0 -4
  700. package/dist/spec/domain/service/ProcedureViewSpecChecks.d.ts.map +0 -1
  701. package/dist/spec/domain/service/ProcedureViewSpecChecks.js +0 -211
  702. package/dist/spec/domain/service/ProcedureViewSpecChecks.js.map +0 -1
  703. package/dist/spec/domain/service/SchemaAdminUiChecker.d.ts +0 -44
  704. package/dist/spec/domain/service/SchemaAdminUiChecker.d.ts.map +0 -1
  705. package/dist/spec/domain/service/SchemaAdminUiChecker.js +0 -333
  706. package/dist/spec/domain/service/SchemaAdminUiChecker.js.map +0 -1
  707. package/dist/spec/domain/service/SchemaIndexChecker.d.ts +0 -33
  708. package/dist/spec/domain/service/SchemaIndexChecker.d.ts.map +0 -1
  709. package/dist/spec/domain/service/SchemaIndexChecker.js +0 -256
  710. package/dist/spec/domain/service/SchemaIndexChecker.js.map +0 -1
  711. package/dist/spec/domain/service/SchemaSearchChecker.d.ts +0 -11
  712. package/dist/spec/domain/service/SchemaSearchChecker.d.ts.map +0 -1
  713. package/dist/spec/domain/service/SchemaSearchChecker.js +0 -78
  714. package/dist/spec/domain/service/SchemaSearchChecker.js.map +0 -1
  715. package/dist/spec/domain/service/SchemaSpecChecks.d.ts +0 -31
  716. package/dist/spec/domain/service/SchemaSpecChecks.d.ts.map +0 -1
  717. package/dist/spec/domain/service/SchemaSpecChecks.js +0 -445
  718. package/dist/spec/domain/service/SchemaSpecChecks.js.map +0 -1
  719. package/dist/spec/domain/service/SiteDefaultsValidator.d.ts +0 -39
  720. package/dist/spec/domain/service/SiteDefaultsValidator.d.ts.map +0 -1
  721. package/dist/spec/domain/service/SiteDefaultsValidator.js +0 -194
  722. package/dist/spec/domain/service/SiteDefaultsValidator.js.map +0 -1
  723. package/dist/spec/domain/service/SqlClassify.d.ts +0 -19
  724. package/dist/spec/domain/service/SqlClassify.d.ts.map +0 -1
  725. package/dist/spec/domain/service/SqlClassify.js +0 -42
  726. package/dist/spec/domain/service/SqlClassify.js.map +0 -1
  727. package/dist/spec/domain/service/SqlRefusal.d.ts +0 -16
  728. package/dist/spec/domain/service/SqlRefusal.d.ts.map +0 -1
  729. package/dist/spec/domain/service/SqlRefusal.js +0 -20
  730. package/dist/spec/domain/service/SqlRefusal.js.map +0 -1
  731. package/dist/spec/domain/service/SqlTypes.d.ts +0 -40
  732. package/dist/spec/domain/service/SqlTypes.d.ts.map +0 -1
  733. package/dist/spec/domain/service/SqlTypes.js +0 -110
  734. package/dist/spec/domain/service/SqlTypes.js.map +0 -1
  735. package/dist/spec/domain/service/StaffRoleHierarchy.d.ts +0 -3
  736. package/dist/spec/domain/service/StaffRoleHierarchy.d.ts.map +0 -1
  737. package/dist/spec/domain/service/StaffRoleHierarchy.js +0 -19
  738. package/dist/spec/domain/service/StaffRoleHierarchy.js.map +0 -1
  739. package/dist/spec/domain/service/TriggerGraphChecks.d.ts +0 -16
  740. package/dist/spec/domain/service/TriggerGraphChecks.d.ts.map +0 -1
  741. package/dist/spec/domain/service/TriggerGraphChecks.js +0 -337
  742. package/dist/spec/domain/service/TriggerGraphChecks.js.map +0 -1
  743. package/dist/spec/domain/service/TriggerSpecChecks.d.ts +0 -4
  744. package/dist/spec/domain/service/TriggerSpecChecks.d.ts.map +0 -1
  745. package/dist/spec/domain/service/TriggerSpecChecks.js +0 -89
  746. package/dist/spec/domain/service/TriggerSpecChecks.js.map +0 -1
  747. package/dist/spec/domain/service/ValidatedAdminUiProjection.d.ts +0 -11
  748. package/dist/spec/domain/service/ValidatedAdminUiProjection.d.ts.map +0 -1
  749. package/dist/spec/domain/service/ValidatedAdminUiProjection.js +0 -26
  750. package/dist/spec/domain/service/ValidatedAdminUiProjection.js.map +0 -1
  751. package/dist/spec/domain/service/ViewAdminUiChecker.d.ts +0 -14
  752. package/dist/spec/domain/service/ViewAdminUiChecker.d.ts.map +0 -1
  753. package/dist/spec/domain/service/ViewAdminUiChecker.js +0 -58
  754. package/dist/spec/domain/service/ViewAdminUiChecker.js.map +0 -1
  755. package/dist/spec/domain/service/index.d.ts +0 -24
  756. package/dist/spec/domain/service/index.d.ts.map +0 -1
  757. package/dist/spec/domain/service/index.js +0 -24
  758. package/dist/spec/domain/service/index.js.map +0 -1
  759. package/dist/spec/index.d.ts +0 -10
  760. package/dist/spec/index.d.ts.map +0 -1
  761. package/dist/spec/index.js +0 -12
  762. package/dist/spec/index.js.map +0 -1
  763. package/dist/spec/infrastructure/cli/parseArgsError.d.ts +0 -16
  764. package/dist/spec/infrastructure/cli/parseArgsError.d.ts.map +0 -1
  765. package/dist/spec/infrastructure/cli/parseArgsError.js +0 -34
  766. package/dist/spec/infrastructure/cli/parseArgsError.js.map +0 -1
  767. package/dist/spec/infrastructure/index.d.ts +0 -2
  768. package/dist/spec/infrastructure/index.d.ts.map +0 -1
  769. package/dist/spec/infrastructure/index.js +0 -2
  770. package/dist/spec/infrastructure/index.js.map +0 -1
  771. package/dist/spec/infrastructure/sql/PgQueryParser.d.ts +0 -18
  772. package/dist/spec/infrastructure/sql/PgQueryParser.d.ts.map +0 -1
  773. package/dist/spec/infrastructure/sql/PgQueryParser.js +0 -17
  774. package/dist/spec/infrastructure/sql/PgQueryParser.js.map +0 -1
  775. package/dist/spec/infrastructure/sql/compilePlan.d.ts +0 -37
  776. package/dist/spec/infrastructure/sql/compilePlan.d.ts.map +0 -1
  777. package/dist/spec/infrastructure/sql/compilePlan.js +0 -287
  778. package/dist/spec/infrastructure/sql/compilePlan.js.map +0 -1
  779. package/dist/spec/infrastructure/sql/compileSql.d.ts +0 -35
  780. package/dist/spec/infrastructure/sql/compileSql.d.ts.map +0 -1
  781. package/dist/spec/infrastructure/sql/compileSql.js +0 -92
  782. package/dist/spec/infrastructure/sql/compileSql.js.map +0 -1
  783. package/dist/spec/infrastructure/sql/frontEnd.d.ts +0 -8
  784. package/dist/spec/infrastructure/sql/frontEnd.d.ts.map +0 -1
  785. package/dist/spec/infrastructure/sql/frontEnd.js +0 -100
  786. package/dist/spec/infrastructure/sql/frontEnd.js.map +0 -1
  787. package/dist/spec/infrastructure/sql/index.d.ts +0 -4
  788. package/dist/spec/infrastructure/sql/index.d.ts.map +0 -1
  789. package/dist/spec/infrastructure/sql/index.js +0 -4
  790. package/dist/spec/infrastructure/sql/index.js.map +0 -1
  791. package/dist/spec/kernel/diagnostic.d.ts.map +0 -1
  792. package/dist/spec/kernel/diagnostic.js +0 -301
  793. package/dist/spec/kernel/diagnostic.js.map +0 -1
  794. package/dist/spec/kernel/index.d.ts +0 -8
  795. package/dist/spec/kernel/index.d.ts.map +0 -1
  796. package/dist/spec/kernel/index.js +0 -8
  797. package/dist/spec/kernel/index.js.map +0 -1
  798. package/dist/spec/usecase/EmitTypes.d.ts +0 -22
  799. package/dist/spec/usecase/EmitTypes.d.ts.map +0 -1
  800. package/dist/spec/usecase/EmitTypes.js +0 -182
  801. package/dist/spec/usecase/EmitTypes.js.map +0 -1
  802. package/dist/spec/usecase/ValidateManifestsUseCase.d.ts +0 -8
  803. package/dist/spec/usecase/ValidateManifestsUseCase.d.ts.map +0 -1
  804. package/dist/spec/usecase/ValidateManifestsUseCase.js +0 -101
  805. package/dist/spec/usecase/ValidateManifestsUseCase.js.map +0 -1
  806. package/dist/spec/usecase/dto/ValidateManifestsRequest.d.ts +0 -27
  807. package/dist/spec/usecase/dto/ValidateManifestsRequest.d.ts.map +0 -1
  808. package/dist/spec/usecase/dto/ValidateManifestsRequest.js +0 -2
  809. package/dist/spec/usecase/dto/ValidateManifestsRequest.js.map +0 -1
  810. package/dist/spec/usecase/dto/ValidateManifestsResponse.d.ts +0 -14
  811. package/dist/spec/usecase/dto/ValidateManifestsResponse.d.ts.map +0 -1
  812. package/dist/spec/usecase/dto/ValidateManifestsResponse.js +0 -2
  813. package/dist/spec/usecase/dto/ValidateManifestsResponse.js.map +0 -1
  814. package/dist/spec/usecase/dto/index.d.ts +0 -3
  815. package/dist/spec/usecase/dto/index.d.ts.map +0 -1
  816. package/dist/spec/usecase/dto/index.js +0 -3
  817. package/dist/spec/usecase/dto/index.js.map +0 -1
  818. package/dist/spec/usecase/index.d.ts +0 -10
  819. package/dist/spec/usecase/index.d.ts.map +0 -1
  820. package/dist/spec/usecase/index.js +0 -10
  821. package/dist/spec/usecase/index.js.map +0 -1
  822. package/dist/testing/cases/before-hook.d.ts +0 -4
  823. package/dist/testing/cases/before-hook.d.ts.map +0 -1
  824. package/dist/testing/cases/before-hook.js +0 -71
  825. package/dist/testing/cases/before-hook.js.map +0 -1
  826. package/dist/testing/cases/corpus.d.ts +0 -14
  827. package/dist/testing/cases/corpus.d.ts.map +0 -1
  828. package/dist/testing/cases/corpus.js +0 -93
  829. package/dist/testing/cases/corpus.js.map +0 -1
  830. package/dist/testing/cases/policy.d.ts +0 -87
  831. package/dist/testing/cases/policy.d.ts.map +0 -1
  832. package/dist/testing/cases/policy.js +0 -143
  833. package/dist/testing/cases/policy.js.map +0 -1
  834. package/dist/testing/cases/printer.d.ts +0 -4
  835. package/dist/testing/cases/printer.d.ts.map +0 -1
  836. package/dist/testing/cases/printer.js +0 -34
  837. package/dist/testing/cases/printer.js.map +0 -1
  838. package/dist/testing/cases/report-view.d.ts +0 -5
  839. package/dist/testing/cases/report-view.d.ts.map +0 -1
  840. package/dist/testing/cases/report-view.js +0 -51
  841. package/dist/testing/cases/report-view.js.map +0 -1
  842. package/dist/testing/cases/requisition.d.ts +0 -4
  843. package/dist/testing/cases/requisition.d.ts.map +0 -1
  844. package/dist/testing/cases/requisition.js +0 -38
  845. package/dist/testing/cases/requisition.js.map +0 -1
  846. package/dist/testing/cases/search-places.d.ts +0 -4
  847. package/dist/testing/cases/search-places.d.ts.map +0 -1
  848. package/dist/testing/cases/search-places.js +0 -60
  849. package/dist/testing/cases/search-places.js.map +0 -1
  850. package/dist/testing/cases/stock.d.ts +0 -4
  851. package/dist/testing/cases/stock.d.ts.map +0 -1
  852. package/dist/testing/cases/stock.js +0 -35
  853. package/dist/testing/cases/stock.js.map +0 -1
  854. package/dist/testing/cases/store.d.ts +0 -4
  855. package/dist/testing/cases/store.d.ts.map +0 -1
  856. package/dist/testing/cases/store.js +0 -100
  857. package/dist/testing/cases/store.js.map +0 -1
  858. package/dist/testing/harness.d.ts +0 -94
  859. package/dist/testing/harness.d.ts.map +0 -1
  860. package/dist/testing/harness.js +0 -168
  861. package/dist/testing/harness.js.map +0 -1
  862. package/dist/testing/index.d.ts.map +0 -1
  863. package/dist/testing/index.js.map +0 -1
  864. package/dist/testing/report.d.ts +0 -15
  865. package/dist/testing/report.d.ts.map +0 -1
  866. package/dist/testing/report.js +0 -22
  867. package/dist/testing/report.js.map +0 -1
  868. package/dist/web/createRestSurface.d.ts +0 -7
  869. package/dist/web/createRestSurface.d.ts.map +0 -1
  870. package/dist/web/createRestSurface.js +0 -41
  871. package/dist/web/createRestSurface.js.map +0 -1
  872. package/dist/web/index.d.ts +0 -2
  873. package/dist/web/index.d.ts.map +0 -1
  874. package/dist/web/index.js +0 -2
  875. package/dist/web/index.js.map +0 -1
  876. package/docs/adr/0001-four-atom-manifest-model.md +0 -440
  877. package/docs/adr/0002-closed-enums-for-bindings.md +0 -253
  878. package/docs/adr/0007-ai-as-primary-author.md +0 -473
  879. package/docs/adr/0008-structured-diagnostic-shape.md +0 -338
  880. package/docs/adr/0009-consumer-supplied-manifests.md +0 -149
  881. package/docs/adr/0010-locale-and-translates.md +0 -453
  882. package/docs/adr/0011-adapter-port-spec.md +0 -281
  883. package/docs/adr/0012-views-as-public-rest.md +0 -161
  884. package/docs/adr/0013-agent-provisioned-consumer-projects.md +0 -154
  885. package/docs/adr/0014-auth-better-auth-and-multi-tenant-mcp.md +0 -939
  886. package/docs/adr/0016-site-semantic-layer.md +0 -70
  887. package/docs/adr/0017-media-multi-variant-agent-side-optimization.md +0 -181
  888. package/docs/adr/0018-core-starters-repository-boundary.md +0 -179
  889. package/docs/adr/0019-sealed-manifest-runtime-pipeline.md +0 -244
  890. package/docs/adr/0020-builtin-handler-contracts-and-matched-upsert.md +0 -199
  891. package/docs/adr/0021-retire-starter-scaffolding.md +0 -30
  892. package/docs/adr/0022-caller-observed-version-occ.md +0 -212
  893. package/docs/adr/0023-port-failure-contract.md +0 -69
  894. package/docs/adr/0024-manifest-native-schema-tables.md +0 -264
  895. package/docs/adr/0025-reserved-native-columns-and-published-only-public-views.md +0 -105
  896. package/docs/adr/0026-progressive-generate.md +0 -36
  897. package/docs/adr/0027-scheduled-procedure-triggers.md +0 -31
  898. package/docs/adr/0028-schema-ttl-expiry.md +0 -33
  899. package/docs/adr/0029-mcp-apps-interaction-contracts.md +0 -324
  900. package/docs/adr/0030-store.md +0 -40
  901. package/docs/adr/0031-host-cloud-core-contract.md +0 -102
  902. package/docs/adr/0032-store-centric-core-and-service-contract.md +0 -384
  903. package/docs/adr/0033-storage-converges-to-the-plan.md +0 -92
  904. package/docs/adr/0034-store-is-authored-as-sql.md +0 -192
  905. package/docs/adr/0035-sql-dialects.md +0 -154
  906. package/docs/adr/0036-host-and-dialect.md +0 -65
  907. package/docs/adr/0037-postgresql-is-the-reference-dialect.md +0 -125
  908. package/docs/adr/0038-bun-native-host.md +0 -63
  909. package/docs/adr/0039-postgresql-is-native.md +0 -130
  910. package/docs/adr/README.md +0 -98
  911. package/docs/adr/adr-lite-1376-admin-extensions.md +0 -330
  912. package/docs/adr/adr-lite-803-request-diagnostics.md +0 -38
  913. package/docs/adr/adr-lite-808-route-readiness.md +0 -47
  914. package/docs/adr/adr-lite-809-bounded-public-content.md +0 -71
  915. package/docs/adr/adr-lite-812-native-parity.md +0 -150
  916. package/docs/adr/adr-lite-823-home-statistics.md +0 -64
  917. package/docs/adr/adr-lite-842-mcp-authoring.md +0 -30
  918. package/docs/adr/adr-lite-845-frontend-client.md +0 -38
  919. package/docs/adr/adr-lite-861-admin-webmcp.md +0 -48
  920. package/docs/adr/adr-lite-909-admin-ui-kit.md +0 -37
  921. package/docs/examples/commerce-inventory.md +0 -498
  922. package/docs/examples/commerce.md +0 -254
  923. package/docs/examples/guarded-api.md +0 -238
  924. package/docs/examples/intake-hooks.md +0 -237
  925. package/docs/examples/intake.md +0 -127
  926. package/docs/examples/legal-documents.md +0 -218
  927. package/docs/examples/procurement.md +0 -226
  928. package/docs/examples/publication.md +0 -211
  929. package/docs/examples/reference-service/.mantle/generated/mantle.ts +0 -174
  930. package/docs/examples/reference-service/.mantle/generated/plan.json +0 -1936
  931. package/docs/examples/reference-service/README.md +0 -33
  932. package/docs/examples/reference-service/manifests/catalog.yaml +0 -103
  933. package/docs/examples/reference-service/manifests/orders.yaml +0 -120
  934. package/docs/examples/reference-service/mantle.config.json +0 -1
  935. package/docs/examples/reference-service/package.json +0 -27
  936. package/docs/examples/reference-service/smoke.mjs +0 -160
  937. package/docs/examples/reference-service/src/handlers.ts +0 -36
  938. package/docs/examples/reference-service/src/index.ts +0 -33
  939. package/docs/examples/reference-service/src/service.ts +0 -78
  940. package/docs/examples/reference-service/wrangler.jsonc +0 -26
  941. package/docs/examples/reservation.md +0 -142
  942. /package/docs/examples/{reference-service → app-shell}/.dev.vars.example +0 -0
@@ -1,192 +0,0 @@
1
- # ADR-0034: Store is authored as SQL and compiled to IR by the CLI
2
-
3
- **Status:** Accepted for 0.2.0 (#1188), after the spike (#1203). Amends ADR-0030, ADR-0032 decisions 1, 2, 3, 4, 5, 10 and 13, and ADR-0033. Amended by [ADR-0035](0035-sql-dialects.md) and [ADR-0037](0037-postgresql-is-the-reference-dialect.md).
4
-
5
- **Date:** 2026-09-29
6
-
7
- **Related:** ADR-0030, ADR-0031, ADR-0032, ADR-0033, #1151, #1196
8
-
9
- ## Context
10
-
11
- ADR-0032 decision 5 made the grammar the IR: an inline Procedure program and a View `select` are JSON write and read ops that #1196 implements. Business rules then asked for more of SQL: branches (`CASE`), column arithmetic, `CHECK` constraints, `RETURNING`, joins, aggregates and window functions. Each would be a node Mantle designs, documents and teaches, and for anything past a filter the result is a private query language (compare a join with an aggregate written as JSON). SQL is the query language agents know best, and it already has every one of these.
12
-
13
- Mantle runs on D1. Measured on production D1 and on local workerd, which enforce the same function allowlist:
14
-
15
- - SQLite is at least 3.45 (`jsonb`, `string_agg`, `concat`, `unixepoch('subsec')`), with window functions, recursive CTEs, `FULL`/`RIGHT JOIN`, `NULLS LAST`, `RETURNING`, `UPDATE … FROM`, `ON CONFLICT … DO UPDATE`, JSON, math functions, `STRICT` tables, virtual generated columns added by `ALTER`, and triggers that `RAISE(ABORT, …)`. Foreign keys are enforced by default.
16
- - D1 authorizes functions from an allowlist (`sqlite_version`, `json_pretty`, `power`, `ceiling`, `unistr` and others are refused), binds at most 100 parameters per statement, accepts statements up to 100 KB and has no interactive transaction: a program is one `batch`, applied in order, all or nothing.
17
- - D1 binds a JavaScript number as a floating-point value (`? / 2` with 5 is 2.5) and rounds integers past 2^53 without an error.
18
-
19
- Four parsers were measured. `libpg-query` (the PostgreSQL parser, MIT, WASM) parsed every case. `pgsql-ast-parser` misses `IS DISTINCT FROM` and `INTERSECT`; `node-sql-parser` misses `ON CONFLICT`, window functions, `INTERSECT`, `UPDATE FROM` and `FULL JOIN`; `sql-parser-cst` covers SQLite fully but is GPL-2.0-or-later, which Mantle's Apache-2.0 package cannot ship. `libpg-query` declares a 128 MiB minimum WASM memory, which is the whole isolate limit of a Cloudflare Worker, so it cannot run in one.
20
-
21
- ## Decision
22
-
23
- ### 1. Manifests carry SQL; the plan carries IR
24
-
25
- SQL is source and the IR is the compiled artifact, the way TypeScript is source and JavaScript is output.
26
-
27
- | Atom | v2 in #1196 | This ADR |
28
- |---|---|---|
29
- | View | `spec.select` (JSON) or `spec.sql` (native) | `spec.sql`: one `SELECT` |
30
- | Procedure | `handler: { store: [ops] }` | `handler: { sql: <statements> }`: one or more statements, applied as one batch |
31
- | Schema | — | `checks: [<boolean expression>]`, `sequences: [<name>]`, `search: [<field>]`, fields with `format: geo` |
32
-
33
- `handler: { ref }` is unchanged. The IR stays internal to the plan. It is public only through `ctx.store.select` and `ctx.store.write` in handler code, which keep ADR-0030's JSON shape; a manifest never contains IR.
34
-
35
- ### 2. The dialect: SQLite semantics in the syntax PostgreSQL and SQLite share
36
-
37
- - **Semantics and functions are SQLite's, limited to what D1 authorizes.** The compiler carries the allowlist measured on D1, and CI checks it against local D1.
38
- - **Syntax is a chosen subset** of what PostgreSQL and SQLite share, parsed by `libpg-query`. It covers what applications commonly do (checked against MongoDB's everyday operations and the repository's examples) and stops where a feature would be hard to control. Anything left out can be added later without breaking a manifest; removing a feature would break one. SQLite-only spellings the parser rejects have shared equivalents: `IS DISTINCT FROM` for `IS NOT`, `ON CONFLICT` for `INSERT OR …`.
39
-
40
- | Area | Supported in 0.2.0 | Rule |
41
- |---|---|---|
42
- | Expressions | columns, aliases, literals, arithmetic, `\|\|`, `CASE`, `COALESCE`, `NULLIF`, `CAST` | `SELECT *` and `RETURNING *` expand to the declared fields, never to scope or system columns. A `CAST` to a Mantle type is rewritten by the compiler. SQLite truncates where PostgreSQL rounds, so `CAST(x AS int)` of anything but an integer literal is refused (`SQL_TYPE`, in the validation the runtime shares) and asks for `round(x)` (a tie rounds away from zero, as PostgreSQL's `numeric` does; PostgreSQL's `float8` rounds half to even); `CAST(x AS bool)` becomes `x <> 0` for a number and PostgreSQL's spellings (`t`, `true`, `yes`, `on`, `1`) for text, since `'false' <> 0` is true in SQLite |
43
- | Conditions | comparison, `AND`/`OR`/`NOT`, `BETWEEN`, `IS [NOT] NULL`, `IS DISTINCT FROM`, `IN (list \| subquery)`, `[NOT] EXISTS`, `LIKE … ESCAPE` | an input array in `IN` lowers to `json_each` and binds once. `LIKE` is case-insensitive in SQLite, unlike PostgreSQL; the diagnostics say so |
44
- | Relations | one Schema, `INNER`/`LEFT JOIN … ON` (self-joins included), a subquery in `FROM`, `json_each(<input or column>)` | the one comma join allowed is `t, json_each(t.col)` (MongoDB's `$unwind`) |
45
- | Subqueries | scalar and correlated | — |
46
- | Aggregation | `count`, `sum`, `min`, `max`, `avg`, `count(DISTINCT)`, `json_group_array([DISTINCT])`, `json_group_object`, `GROUP BY`, `HAVING` | a selected column must be grouped or aggregated |
47
- | Windows | `row_number()`, `rank()`, `sum`/`count … OVER (PARTITION BY … ORDER BY …)`, in Views only | no frame clause; for `row_number()` only, the compiler appends `id` to the window's `ORDER BY`. `rank()` and running aggregates keep PostgreSQL's peer semantics, which an appended key would break |
48
- | Order and paging | `ORDER BY … [NULLS FIRST \| LAST]`, `LIMIT`, `DISTINCT`, cursors | the compiler appends `id` as the final sort key (the group key under `GROUP BY`); `LIMIT` needs an `ORDER BY`; a nullable sort key states its NULL position; `DISTINCT` with `ORDER BY` is refused, since the appended key would change what is distinct; ordering a subquery in `FROM` needs that subquery to output `id` |
49
- | JSON | `->>`, `json_extract`, `json_set`, `json_insert`, `json_remove`, `json_array_length` | a JSON result carries its declared type; `->` is refused |
50
- | Writes | `INSERT … VALUES` (one row), `INSERT … SELECT`, `UPDATE … SET <expr> WHERE`, `DELETE … WHERE`, `RETURNING <columns>`, `ON CONFLICT (…) DO NOTHING \| DO UPDATE … EXCLUDED` | see decision 8 for what a write may name; an `INSERT` on a scoped Schema names no `id`, the compiler generates it. `ON CONFLICT` is a set op, and on a scoped Schema its conflict target includes the scope field |
51
- | Programs | several statements, one batch | statements pass values only through tables |
52
- | Time | `now()`, `date_trunc('hour' \| 'day' \| 'week' \| 'month' \| 'year', ts)`, `extract(year \| month \| day \| dow \| hour FROM ts)`, `ts ± interval` in seconds, minutes or hours, `ts - ts` | `date_trunc` and `extract` compute in the site time zone. `ts - ts` is microseconds. Display formatting belongs to the client |
53
- | Search and places | `search()`, `search_rank()`, `near()`, `distance()` | decision 9 |
54
- | Mantle | `input.<name>`, `auth.uid()`, `auth.role()`, `nextval()`, `numeric(p, s)` columns | below |
55
-
56
- **Deferred** (each is additive): `UNION ALL`, `UNION`, `INTERSECT`, `EXCEPT`; non-recursive CTEs (a subquery in `FROM` covers them); aggregate `FILTER` (`sum(CASE …)` covers it); `string_agg`; `$pull`-style array rebuilds; calendar `interval` units and `timezone()` with any zone but the site's; arithmetic rewriting for `numeric`; before hooks on set ops; a cursor over `distance()`.
57
-
58
- **Refused in 0.2.0:** `RIGHT`/`FULL JOIN` (rewrite as `LEFT JOIN`); `CROSS JOIN` and comma joins other than `json_each`, where one forgotten condition is a Cartesian product; recursive CTEs, whose work has no bound; `LATERAL`, `NATURAL`, `USING`, `GROUPING SETS`; `UPDATE … FROM` and `DELETE … USING`, where SQLite picks an arbitrary row when several match (a correlated subquery in `SET` covers them); multi-row `VALUES` (`json_each(input.items)` covers it); window frames.
59
- - **References.** `input.<name>` reads a declared input property, as PostgreSQL's `NEW`, `OLD` and `EXCLUDED` read pseudo-relations. `auth.uid()` is the caller's application subject key and `auth.role()` its staff role (ADR-0032 decision 8). `now()` is the invocation time. Positional `$1` is refused. `input` and `auth` are reserved and cannot name a Schema or an alias. A Schema's `scope` names the same reference (`scope: { ownerId: "auth.uid()" }`), so ADR-0032's `$input.<path>`, `$ctx.user.id`, `$now` and `{ $literal }` are gone; a SQL literal is a literal.
60
- - **Identifiers resolve case-insensitively,** as SQLite does. The parser folds unquoted identifiers to lower case, so `createdAt` and `createdat` name the same column. SQLite already refuses two tables or two columns whose names differ only by case, and `mantle validate` refuses them first. A Schema whose name is not a plain identifier is quoted: `"support-requests"`. A Schema or field named with one of the 14 keywords that SQLite rejects unquoted and the printer leaves bare is refused: `add alter autoincrement commit delete drop escape index insert nothing raise set transaction update` (measured against all 147 PostgreSQL keywords; `match` and `glob` are fine). The list belongs to `pgsql-deparser` 18.3.8 and D1's SQLite, and the spike's 1d check fails when either changes it.
61
- - **Mantle's additions keep PostgreSQL names** where PostgreSQL has one: `nextval('<sequence>')`, `date_trunc`, `extract`. `nextval()` appears only in a one-row `VALUES`, at most once per sequence per statement.
62
- - **`numeric(p, s)` is a storage type, not an arithmetic rewrite.** Inside SQL a `numeric(12, 2)` column is its integer count of the smallest unit (cents), so `sum`, comparison and integer arithmetic are exact, as Stripe's amounts are. Input and output convert at the boundary. An author who multiplies by a fraction writes the rounding (`round(amount * input.rate)`). Rewriting decimal arithmetic in the compiler is deferred.
63
- - **`interval`.** `second`, `minute` and `hour` compile to a microsecond constant. `day`, `week`, `month` and `year` are calendar units in PostgreSQL (a day is 23 or 25 hours across daylight saving), so 0.2.0 refuses them, and the diagnostic tells the author to bind the boundary as an input. Refusing is better than computing a wrong time; calendar units are additive later.
64
- - **Always refused:** `OFFSET` (cursor pagination only); DDL; transaction control; data-modifying CTEs; `SELECT … FOR UPDATE`; functions outside the allowlist; any table that is not a declared Schema, `_mantle_*` included; table-valued functions other than `json_each`; `rowid`; SQLite's own clock (`'now'`, `CURRENT_TIMESTAMP`), which bypasses `now()`; `strftime`, `date` and `unixepoch` in source, which return NULL on microsecond integers; `printf` width arguments, `zeroblob` and non-constant `randomblob` sizes, which can build values of any size; `ILIKE`; `REGEXP`, which D1 lacks. There is no `native` escape: on D1 nothing sits below SQLite, so an escape could only bypass policy.
65
- - **No `expect` in the source.** A row op must affect exactly one row, or the batch fails with `CONFLICT`. A conditional insert (`INSERT … SELECT … WHERE`) is a set op, and writing no row is a normal result.
66
-
67
- ### 3. Only the CLI parses SQL
68
-
69
- - `@aotter/mantle/spec` exports `compilePlan(sources)`, returning a plan or diagnostics. It is the only compiler. The `mantle` CLI calls it, and so do the plugin's Cloud helper scripts: they load it from the project's installed `@aotter/mantle` with `createRequire`, as they already load the project's `esbuild`, and refuse to run when its version is not the Core version Cloud pinned (ADR-0031). The plugin bundles no parser. `compilePlan`'s signature is the stable contract between plugin and Core.
70
- - No Worker parses SQL. Cloud's Control receives the plan, with the SQL source and its hash, and validates the IR in plain JavaScript: structure, Schema references and compatibility with the pinned Core. A tenant Worker executes the IR.
71
- - Coding agents compile: the Claude Code CLI, desktop and cloud sessions, Cowork, and Codex local and remote all have a working directory and Node. A chat assistant operates a service through the Cloud MCP and does not build one.
72
- - If a browser ever compiles (the Builder), it dynamic-imports the same `libpg-query`; a page that does not compile never loads it.
73
- - **The IR is the parser's own AST.** It is `libpg-query`'s parse tree for the subset, with source locations stripped and each relation tagged `table` or `cte`. Mantle designs no node types. The plan records the PostgreSQL grammar version (`180004`), and the runtime refuses any other, since the AST changes between PostgreSQL majors; `libpg-query`, `@pgsql/types` and the printer are pinned to one major.
74
- - **Validation is an exact allowlist** of node types and of the keys each may carry, shared by the CLI and the runtime. An unknown node or key is refused, never skipped: a printer that skipped keys would silently drop `OFFSET`, `WITH` or `FOR UPDATE`. Diagnostics are produced in the CLI before locations are stripped.
75
- - **The printer is `pgsql-deparser`** (MIT, pure TypeScript, no WASM), subclassed in four places: `ParamRef` (numbered binds `?n`), `TypeCast` (`CAST(… AS …)` instead of `::`), `A_Const` (plain SQL string literals instead of `E'…'`) and `A_Expr` (`x LIKE p ESCAPE e` parses to `like_escape(p, e)`, which SQLite lacks). The `ParamRef` override is a correctness fix: SQLite reads `$n` as a named parameter numbered by first appearance, so binds would shift silently. Four AST rewrites also precede printing: the `pg_catalog.` prefix and SQL-syntax calls, `btrim` to `trim`, `= ANY (subquery)` to `IN`, and type names. The rest of the subset prints as valid SQLite, and each allowlisted node type has a conformance case on local D1. Eight changes are under "about a dozen", so Kysely's SQLite compiler is not needed.
76
- - **Handler-built queries join the same path.** `ctx.store.select` and `ctx.store.write` keep ADR-0030's JSON shape; a converter turns it into the same AST, which then passes the same validation and policy.
77
- - Measured on a prototype over the six programs of the conformance cases: runtime validation 127 lines, policy 97, printer 7 on top of `pgsql-deparser` (43 KB gzipped), no cross-owner leak.
78
-
79
- ### 4. Row ops, set ops and hooks (amends ADR-0032 decisions 2 and 3)
80
-
81
- - **Classification.** An `UPDATE` or `DELETE` whose top-level `WHERE` conjunction contains `id = <scalar>` is a row op, and so is an `INSERT … VALUES` of one row, except that one row of `VALUES` with `ON CONFLICT` is a set op (a `DO NOTHING` that hits the conflict must not fail with `CONFLICT`). Every other write is a set op. A row op with a `version = input.<name>` conjunct is locked (ADR-0022). Classification now decides only two things: `Procedure.target` inference, and whether writing no row is a `CONFLICT`.
82
- - **Before hooks take row ops only.** A set op on a Schema with a `before_*` Trigger for that operation is refused, as ADR-0032 decision 2 already says, and so is a set op on a Schema whose lifecycle is `publishing`. After hooks no longer refuse set ops.
83
- - **One after-hook call per statement and Trigger.** A hook receives `ctx.cause.rows`, a non-empty array (`[Row, ...Row[]]`) whose rows always carry `id` and `version`: for a hooked target the compiler adds hidden `_mantle_id` and `_mantle_version` columns and the executor strips them before the hook sees the rows. `ctx.cause.id` is stable per (statement, hook) across retries. Rows come in no particular order and an upsert may repeat an id, so a handler is idempotent per row. A statement that writes no row calls no hook. Calling once per row is rejected: 500 rows would be 500 subrequests, past Cloud's limit.
84
- - **After hooks** read the statement's `RETURNING` rows, which the compiler adds when the target has an after hook, and run after the commit, as ADR-0032 decision 3 says.
85
-
86
- > **Amendment (2026-10-01, site trial):** The hook's rows and the statement's result are separate. The compiler adds the whole readable row to `RETURNING` under hidden `_mantle_h_` columns whatever the author's own `RETURNING` lists; the runner strips them from the result and hands them to the hook, decoded as `ctx.store.select` returns an entry (declared names, `createdAt`/`updatedAt` as ISO date-times). Before, an author's `RETURNING id, status` was all the hook saw, so the same hook got a different row from Admin, from a Store write and from a Procedure, against decision 3's "the row and version at commit".
87
- - **Before hooks** read the one row first and run on it. The statement then carries the version the hook saw (`AND version = ?`), so a change between the hook and the commit is `CONFLICT`. This is today's OCC path. A before hook's `ctx.cause.rows` holds that one row. When the row is not visible (scope, TTL or published-only), the operation fails with `CONFLICT` and the hook is not called, so a hook cannot probe for another owner's row.
88
- - A snapshot guard that would let before hooks cover set ops (pre-read, then recompute inside the batch and abort on any difference) is deferred. Review found it the costliest mechanism here: it needs read and write set analysis per statement, and a `SET` that reads its own target defeats it.
89
- - `last_insert_rowid()` is refused everywhere.
90
- - **Counting** uses SQLite's `changes()` inside the batch, not D1's `meta.changes`, which includes rows that triggers wrote (5 for a one-row `UPDATE` on a searchable row), so it cannot be used. Count checks fail with `CONFLICT op=<k>`, so `conflict.opIndex` becomes exact (amends ADR-0032 decision 1).
91
- - ADR-0032 decision 3's before-hook rules stand: read-only, fail closed, committed data only, OCC between the hook and the commit.
92
- - `mantle-update` rewrites `ctx.event.entry` into a loop over `ctx.cause.rows`, never into `rows[0]`.
93
-
94
- ### 5. Storage (amends ADR-0033)
95
-
96
- - **Types are encoded so D1 computes them exactly:**
97
- - `timestamptz` (`format: date-time`) is an integer of microseconds since the epoch, exact until the year 2255;
98
- - `date` (`format: date`) is an integer count of days;
99
- - `numeric(p, s)` is an integer scaled by 10^s, with `p` at most 15 because D1 rounds past 2^53 (decision 2).
100
-
101
- Mantle's native timestamps move from milliseconds to microseconds.
102
- - **Every parameter is bound through a `CAST` to its declared input type,** so integer arithmetic gives the same result on D1, which binds numbers as floats, and on every other driver.
103
- - **Schema tables Mantle creates are `STRICT`.** An existing table is not rebuilt. Each carries `_rid INTEGER PRIMARY KEY`, an alias of the rowid, and `id TEXT NOT NULL UNIQUE`: the FTS5 and R*Tree tables key on the rowid, and a rowid that no `INTEGER PRIMARY KEY` aliases may change on `VACUUM`. `_rid` is not addressable.
104
- - **`checks` and foreign keys are enforced by triggers** that storage convergence creates, because SQLite cannot add a `CHECK` or a foreign key to an existing table. The triggers only `RAISE`, except the ones that keep `_mantle_fts_*` and `_mantle_geo_*` in step (decision 9), which write only those system tables. Foreign keys are `RESTRICT` only: storage never creates `CASCADE` or `SET NULL`, whose writes would not run Mantle hooks. A `check` reads only the row's own columns and pure functions, never a subquery.
105
- - **Sequences and time zones use system tables.** `nextval()` increments `_mantle_sequences` with `UPDATE … RETURNING`, and a later statement in the same batch reads the value back. `date_trunc` and `extract` join `_mantle_tz`, the site time zone's UTC-offset transitions, so daylight-saving zones compute correctly. Transitions match `Intl` on every measured instant. Where local time repeats, each pass of the repeated hour truncates to its own hour start; where a zone skips half an hour (Lord Howe), truncating to the hour has no single answer. Neither was compared with PostgreSQL, so parity is not claimed for them. The site time zone is a site setting, and the runtime generates its transitions with `Intl.DateTimeFormat`, whose time zone data ships with workerd and Node, when the setting changes or on deploy; no time zone library is bundled.
106
-
107
- ### 6. One executor, one test line (amends ADR-0032 decisions 4 and 13)
108
-
109
- - **One executor.** `SqliteStoreExecutor` is the only executor, over a `DatabaseDriver`: D1, with Bun and libSQL experimental. `MemoryStoreExecutor`, the in-memory test fake and the IndexedDB repositories are removed, and so is `ViewQueryExecutor`, since every View compiles to IR.
110
- - **`/indexeddb` is removed, with no browser driver in 0.2.0.** Nothing uses `@aotter/mantle-indexeddb` today, and the Builder's preview moves to Cloud. A browser-only application that needs one later gets an additive subpath: a SQLite-in-WASM driver under `SqliteStoreExecutor`, not a new executor.
111
- - **One test line.** `@aotter/mantle/testing` stays engine-free, `runStorageConformance({ create })`, and each driver runs it on its own engine.
112
- - D1 runs it on local D1 inside workerd (`@cloudflare/vitest-pool-workers`), locally and in CI alike; 500 cases take about 3.5 s. Code that runs in a Worker is tested there, while spec and CLI tests stay in Node, where `libpg-query` runs.
113
- - One case prepares every function on the compiler's allowlist against local D1, so CI fails when D1 changes the list.
114
- - D1 test helpers, if published, live at `@aotter/mantle/cloudflare/testing`, with `wrangler` as an optional peer.
115
- - `node:sqlite` is not used, and the `sqlite-d1.ts` fake is removed, because its `batch` runs statements without a transaction.
116
- - Ceiling: workerd's Linux binary needs glibc 2.35 and has no musl build, so the storage tests do not run on Alpine.
117
-
118
- ### 7. Cloud validates the plan (amends ADR-0032 decision 10)
119
-
120
- The platform-verified facts become the **Cloud-validated plan**, the pinned Core, storage matching the plan and the fingerprint handshake. The runtime's Store injects scope, TTL, published-only and OCC at execution whatever compiled the IR, and a plan can express nothing its SQL author could not, provided the runtime enforces decision 8 on every IR it compiles, handler-built IR included. So this loses no guarantee.
121
-
122
- That the IR matches its SQL source is **service-reported**: the plan carries the source's hash, and the compiler is the pinned Core. Host protocol 3 uploads the plan.
123
-
124
- `verifyPlan(plan, storage)` in `@aotter/mantle` is that validation: boot's own checks of the plan (version, fingerprint, dialect, guard and hook targets) and every View and inline Procedure through the storage's dialect, its `restrict` and the policy rewrite, with no database and no SQL parser. It returns the diagnostics, each with the program's path; handlers and schedule wiring stay the host's.
125
-
126
- What `verifyPlan` proves is that a plan reads and writes only through the policy rewrite and refuses what boot would refuse of the plan. It does not type-check the SQL: a statement the database refuses (a function's arity or argument type, an operand type) fails that request, or boot for a Schema check, with the database's error, and never runs past the policy. It does not bound the CPU a plan's request costs either: a JSON Schema `pattern` runs a backtracking JavaScript regex, and the pattern checks catch the shapes that backtrack catastrophically by accident, not every slow regex an author can write. A host that runs untrusted plans bounds CPU per request instead (Cloud dispatches each tenant request with a CPU limit), so a slow plan stalls only its own requests.
127
-
128
- ### 8. Policy injection
129
-
130
- - **Every Schema reference is wrapped.** The compiler has one function that prints a Schema table's name, and it always prints `(SELECT <declared columns> FROM "t" WHERE <scope> AND <ttl> AND <published>) AS <alias>`. Joins, subqueries, set-op branches and window inputs therefore see only visible rows, and a `LEFT JOIN` stays a left join. SQLite flattens the wrapper, so the index the scope leads is still used; RIGHT JOIN would materialize, one more reason it is refused.
131
- - **`UPDATE` and `DELETE` targets** cannot be subqueries in SQLite, so the same predicate is ANDed into their `WHERE`. `ON CONFLICT DO UPDATE` gets it in the `DO UPDATE … WHERE`, TTL included, so a conflict cannot overwrite another owner's row or revive an expired one.
132
- - **A write may not name** the scope field or a system column (`id` on update, `version`, `status`, `authorId`, timestamps) in an `INSERT` column list, an `UPDATE … SET` or a `DO UPDATE SET`. The compiler fills them. On a scoped Schema the compiler also generates `id` on insert, because a caller-chosen id collides with another owner's row and reveals it; a retry-safe insert there is an upsert on a unique key that includes the scope field. The refusal applies per Schema, to that Schema's own scope field. Changing `status` belongs to the lifecycle rules. Moving a row to another owner is impossible by construction.
133
- - **Name resolution is checked at run time too.** The CLI tags each relation `table` or `cte`. The runtime refuses an IR whose `cte` reference is not defined in scope or carries a Schema's name, since SQLite would resolve it to the unwrapped table. The same check runs on IR built by handler code.
134
- - **Constraints do not leak across owners.** On a scoped Schema a unique constraint includes the scope field, so a collision can only be with the caller's own rows. A foreign key between two scoped Schemas requires the same owner (`parent.owner = NEW.owner`), and a foreign key from an unscoped Schema to a scoped one is refused. Otherwise an insert could pin another owner's row or reveal that it exists.
135
- - **Published-only does not follow foreign keys.** A public View that joins a Schema without `publishing` must also join that row to a `publishing` Schema by an explicit condition, or `mantle validate` refuses it.
136
- - **Binds are numbered** (`?1`, `?2`), so the caller and `now()` bind once however many references a statement wraps.
137
- - `runtime.store` is trusted: no scope, TTL still applies (ADR-0030).
138
- - **One conformance case guards the rule.** It lists every relation position the IR has (`from`, joins, subqueries, `json_each`, window input, `INSERT … SELECT`, update and delete targets, `DO UPDATE`, search, near) in a `Record` checked with `satisfies` against the IR's position union, seeds a second owner's rows, including an expired and an unpublished one, and asserts none appear or change. A new position without a probe fails typecheck. The parser's AST does not say which keys hold a relation, so the position union is a hand-kept list, bound three ways: each edge is checked against `@pgsql/types` keys, `ALL_EDGES_REACHED` fails when an edge has no position, and the policy pass fails closed on a relation reached through an edge it cannot name.
139
-
140
- ### 9. Search and places
141
-
142
- - **Full-text search.** A Schema declares `search: [<field>, …]`. Storage keeps `_mantle_fts_<schema>`, an FTS5 external-content table with the `trigram` tokenizer, so Chinese substrings match, in step through triggers, and builds it with FTS5's `rebuild` when `search` is added. `search(t, input.q)` lowers to `t.rowid IN (SELECT rowid FROM _mantle_fts_<schema> WHERE _mantle_fts_<schema> = ?)`, so policy still applies to `t`; the printed form is `fts = q` because PostgreSQL's grammar has no `MATCH`, and FTS5 gives the same results. The policy wrapper also outputs `rowid AS _rid`. `search_rank(t)` orders by `bm25`, taking the query of the `search(t, q)` in the same `SELECT`. The query binds as a quoted phrase, never as FTS5 syntax. A query shorter than three characters, which trigram cannot match, lowers to `LIKE` over the same fields. Admin's `searchFields` uses `search()` when the Schema declares it.
143
- - **Places.** A field with `format: geo` holds `{ lat, lng }` as two `REAL` columns, and storage keeps `_mantle_geo_<schema>`, an R*Tree of the points, in step through triggers. `near(t.f, lat, lng, meters)` binds a bounding box the runtime computes from the radius, then filters by haversine distance. `distance(t.f, lat, lng)` is that distance in meters, for `SELECT` and `ORDER BY`. `near()` requires a literal radius, at most 50 km (coordinates may be inputs or literals, since the bounding box is bound at run time), and a query ordered by `distance()` a `LIMIT` of at most 100: nearby search returns the closest K, with no cursor. A box that crosses the antimeridian or a pole is refused. Polygon containment is not provided.
144
- - Measured on local D1: FTS5 with `trigram` (a three-character Chinese query matches, a two-character one does not), external content kept by a trigger, `bm25` and `snippet`, R*Tree, and `radians`, `sin`, `cos`, `asin`, `sqrt` and `atan2` on the allowlist. Production D1 passed the same probes on 2026-09-29 (FTS5 trigram, R*Tree, the math functions, `RAISE(IGNORE)` with `changes()`; `next/spike/production-probe.sql`). Local D1 needs workerd 1.20260903.1 or later to create an R*Tree.
145
-
146
- ## Conformance cases
147
-
148
- 1. The requisition program: a `CASE` value, `RETURNING`, a `WHERE id AND cond` precondition that fails with `CONFLICT`, and a conditional `INSERT … SELECT … WHERE` that writes zero or one row and calls an after hook only when it writes.
149
- 2. Stock: `SET stock = stock - input.qty` with `checks: ["stock >= 0"]`, where oversell fails through the check trigger.
150
- 3. A report View with a join, `GROUP BY`/`HAVING` and a cursor, where scope and TTL are injected into every joined Schema.
151
- 4. Before hooks: a row op whose row changes between the hook and the commit fails with `CONFLICT`; a set op on a Schema with a before hook is refused.
152
- 5. The dialect: an unknown AST key, `OFFSET`, a function outside the allowlist, `$1`, `RIGHT JOIN`, `UPDATE … FROM`, `CURRENT_TIMESTAMP`, an undeclared table, a `cte` reference carrying a Schema's name and `_mantle_*` are refused with a position in the source SQL.
153
- 6. Types: `? / 2` with an integer input, `sum` over a `numeric(12, 2)` column, a microsecond timestamp compared with `now() - interval '36 hours'`, and `date_trunc('day', ts)` on a daylight-saving day in the site time zone give PostgreSQL's results on D1 (outside the repeated and skipped hours of decision 5); a non-literal `CAST(x AS int)` is refused and `round(x)` matches PostgreSQL; `interval '1 day'` is refused.
154
- 7. Policy: the relation-position probe of decision 8, on local D1.
155
- 8. Search and places: a trigram match and a two-character fallback, a phrase containing FTS5 operators matched literally, another owner's rows absent from `search()` and `near()`, and `near()` returning the closest K in order.
156
-
157
- ## Consequences
158
-
159
- - #1196's JSON program and `select` grammar, and the parser and graph rules written for them, are replaced by SQL lowering; `StoreProgram`'s rules move onto the compiled statement. The spike decides whether #1196 is rewritten or superseded.
160
- - The 16 MiB-patched `libpg-query`, its workerd wrapper and the Control memory test proposed for parsing in Control are not needed.
161
- - The Builder's in-browser preview (`packages/builder/src/lib/memory-storage.ts` in aotter/mantle-home) is built on ports this release removes, so its replacement must be decided before aotter/mantle-home adopts 0.2.0; the direction is a signed-in Cloud preview on the existing candidate preview.
162
- - Admin's Developer Console draws a program from the IR: `CASE` as a branch, a `WHERE` guard as an edge, joins, checks, aggregates and `RETURNING` as nodes, anything else as SQL text.
163
-
164
- ## Alternatives
165
-
166
- - **IR in the manifest** (#1196 as is). Its JSON Schema validates exactly and can constrain an agent's output, and nothing needs a parser. Rejected: past a filter it is a private language agents must learn, and every SQL feature becomes a node Mantle designs.
167
- - **Parse in Control with a `libpg-query` patched to 16 MiB.** Rejected: a patched binary to rebuild on every upstream release, WASM memory that never shrinks (one 1.7 MB statement grew the heap to 221 MiB), and WASM in a Worker.
168
- - **Another parser.** `pgsql-ast-parser` and `node-sql-parser` miss syntax this ADR needs; `sql-parser-cst` is GPL; the Rust `sqlparser` as WASM is 1 MB gzipped and misses the same SQLite-only syntax; native addons and Python's `sqlglot` complicate installing the CLI. In a CLI, WASM is the most portable form.
169
- - **Compile policies into SQL ahead of time and ship statements.** Rejected: `ctx.store.select` in handler code is built at run time, so the runtime compiles IR anyway, and a second path would bypass the one Store.
170
- - **A JavaScript executor or an IndexedDB-backed executor.** Rejected: once the IR is what D1 runs, either is a second SQLite.
171
- - **A second test line on sqlite-wasm made to imitate D1, and a `prepare` check of every compiled statement in the CLI.** Rejected: local D1 in workerd is fast enough for everyday tests, so the imitation would be one more profile to keep in step with D1. The conformance suite on local D1 already catches compiler output that D1 refuses, and without the check the CLI does not depend on sqlite-wasm.
172
- - **Support as much of the shared syntax as possible.** Rejected in review: every feature is a policy position, a guard case and a diagnostic to keep correct, and a removal breaks manifests while an addition does not. The subset starts from what applications do and grows by addition.
173
- - **Inject policy through CTEs that shadow table names, or through persistent views reading a caller row written first in the batch.** Rejected: an `UPDATE` target does not resolve to a CTE, so writes would need a second mechanism, and a view reading a context row turns every read into a write and fails open when the context row is missing.
174
- - **Calling hooks once per row, or rewriting a before-hooked statement to the pre-read ids.** Rejected: the first exceeds subrequest limits; the second reproduced two corruptions on local D1 (a phantom between statements, and an expression reading another table that changed).
175
- - **A Mantle-designed IR printed by a hand-written printer, or Kysely operation nodes.** Rejected: the parser's AST already is a complete, typed IR, and `pgsql-deparser` prints it. Converting to Kysely nodes took more code than the hand-written printer, and Kysely's node kinds are internal to a 0.x library, so they cannot be a stored plan format.
176
-
177
- ## How to apply
178
-
179
- 1. Spike, in `next/`:
180
- - print every allowlisted node type with `pgsql-deparser` and run it on local D1, counting the overrides needed;
181
- - run the conformance programs on local D1 in workerd;
182
- - measure how helpful the diagnostics are to an agent;
183
- - prove the `CAST` rule, the type encodings and `date_trunc` across daylight saving.
184
- 2. Settle #1196 from the spike's result.
185
- 3. The diagnostic codes are `SQL_SYNTAX`, `SQL_UNSUPPORTED`, `SQL_FUNCTION`, `SQL_RELATION`, `SQL_COLUMN`, `SQL_WRITE`, `SQL_SHAPE` and `SQL_TYPE` (fixed by the spike, no warning code), and are added to ADR-0032 decision 5's table.
186
- 4. Everything here ships in 0.2.0. The additions land in the order sequences, `numeric` columns, then the site time zone: a sequence is one system table, `numeric` is a boundary codec, and the time zone needs transition data generated and kept current.
187
-
188
- ## Implementation status
189
-
190
- Proposed.
191
-
192
- > **Amendment (spike, #1203, 2026-09-29):** The spike's findings are folded into decisions 2 to 5, 8 and 9 and How to apply 3. Changes: the four printer overrides and four AST rewrites; the 14 measured reserved names; `row_number()`-only window key; one-row upsert as a set op; hook rows always carry `id` and `version`, invisible before-hook rows fail with `CONFLICT`; time zone parity not claimed; a non-literal `CAST` to int is refused in favor of `round(x)` (replacing the earlier warning); relation positions as a hand-kept, type-bound list; the printed form of `search`; production D1 probed.
@@ -1,154 +0,0 @@
1
- # ADR-0035: SQL dialects — PostgreSQL syntax is Mantle SQL, a dialect runs it on one engine
2
-
3
- **Status:** Accepted for 0.2.0. Amends ADR-0032 decisions 6 and 12, ADR-0033, and ADR-0034 decisions 2, 3, 5, 6, 7, 8 and 9. Amended by its PostgreSQL dialect amendment (#1293), [ADR-0036](0036-host-and-dialect.md) and [ADR-0037](0037-postgresql-is-the-reference-dialect.md).
4
-
5
- **Date:** 2026-09-30
6
-
7
- **Related:** ADR-0032, ADR-0033, ADR-0034
8
-
9
- ## Context
10
-
11
- ADR-0034 made manifests SQL and D1 the one engine: its decision 2 calls the dialect "SQLite semantics in the syntax PostgreSQL and SQLite share", and decision 6 gives the Store one executor. The syntax is already PostgreSQL's (`libpg-query` parses it), and conformance case 6 already holds D1 to PostgreSQL's results. What is missing is a boundary: the D1 subset, the SQLite rendering, policy injection and storage convergence are spread through Core, so no other engine can run a Mantle plan without a fork.
12
-
13
- A service that needs another engine should be able to add one. Mature SQL tools split the same way: SQLGlot and Apache Calcite parse to one tree and generate per dialect; Kysely's `Dialect` bundles a driver, a query compiler, an adapter and an introspector; SQLAlchemy ships a dialect compliance suite a third-party dialect must pass. Mantle adopts that shape. The open-source repository ships one dialect, D1, and the interface and test suite that let anyone write another; an enterprise PostgreSQL dialect is the first one written outside it.
14
-
15
- ## Decision
16
-
17
- ### 1. Mantle SQL is PostgreSQL syntax, pinned (amends ADR-0034 decision 2)
18
-
19
- - A View or Procedure is written in PostgreSQL syntax, and its canonical form is the parse tree of `libpg-query` 18, PostgreSQL 18's own parser. The parser version is part of the language: moving to another major is a deliberate Mantle version change, recorded in an amendment.
20
- - Its meaning is PostgreSQL's. A dialect either gives PostgreSQL's result for a construct or refuses it at compile time with a position in the source; it never approximates. (ADR-0034 conformance case 6 is this rule for D1.)
21
- - A manifest that one dialect accepts may be refused by another. The D1 dialect accepts the ADR-0034 subset; a PostgreSQL dialect can accept nearly all of PostgreSQL.
22
-
23
- ### 2. Mantle's own functions live in the `mantle` schema (amends ADR-0034 decision 9)
24
-
25
- - `search()`, `search_rank()`, `near()` and `distance()` become `mantle.search()`, `mantle.search_rank()`, `mantle.near()` and `mantle.distance()`, as `auth.uid()` and `auth.role()` already are. An unqualified call is PostgreSQL's function of that name, never Mantle's. 0.2.0 is unreleased, so there is no old spelling to keep.
26
- - A function is Mantle's exactly when its schema is `mantle` or `auth`. Each dialect lowers every `mantle.*` function it supports and refuses the rest with a position; the D1 dialect lowers all four to FTS5 and R*Tree (ADR-0034 decision 9), and a dialect may refuse them and leave authors to the engine's own syntax.
27
- - `auth.uid()` and `auth.role()` are required of every dialect: policy is written with them.
28
-
29
- ### 3. The dialect interface
30
-
31
- A dialect is an npm module with two entry points, so the parser stays out of the runtime bundle (ADR-0034 decision 3):
32
-
33
- - **Compile side** (`<dialect>/compile`, loaded only by the CLI):
34
- - `accepts(tree, context)`: every refusal, each with its source position. Context is the linked manifest set: declared Schemas and their fields, inputs, and surfaces.
35
- - `lower(tree, context)`: the dialect's statement payload for the plan, opaque to Core, with `mantle.*` calls lowered.
36
- - `outputs(tree, context)`: a View's row type for the typed `mantle.ts`, by ADR-0034's rule (an output that reads a Schema field unchanged has its type; any other output is `unknown`).
37
- - **Runtime side** (`<dialect>`, loaded by the host entry):
38
- - `executor`: a `StoreExecutor` that runs plan payloads and renders the Store's structured operations (`select`, `write`, `search`) to the engine.
39
- - `policy`: `"inject"`, where Mantle's policy rewriter adds visibility and ownership to every relation position (ADR-0034 decision 8), or `"native"`, where the engine enforces them (for example PostgreSQL row-level security) and the dialect writes that enforcement during convergence.
40
- - `converge(plan)`: ADR-0033's storage convergence in the engine's DDL, including the tables Mantle owns (the migration ledger, boot state, site and media).
41
- - `codec`: the Store's wire values. They are the same on every dialect (ADR-0034's timestamps, `numeric` and booleans), whatever the engine stores.
42
- - There are no capability flags. What a dialect cannot run, its compile side refuses.
43
- - Core keeps the Store API, the runtime, the policy rewriter as a library any `"inject"` dialect uses, and the interface's types. It holds no engine-specific code.
44
-
45
- ### 4. What every dialect gets before `accepts`
46
-
47
- The CLI front end is shared and dialect-free. It parses, links, and refuses what no dialect may run:
48
- - A View is one `SELECT` (with `WITH`). A Procedure is `SELECT`, `INSERT`, `UPDATE`, `DELETE` and `MERGE` statements, with `WITH` and `RETURNING`. DDL, `SET`/`RESET`, transaction control, `COPY`, `DO`, `CALL`, `LISTEN`/`NOTIFY` and `PREPARE` are refused.
49
- - Every relation anywhere in the tree (`FROM`, joins, `LATERAL`, and subqueries in the select list, `WHERE`, `HAVING` and `RETURNING`) is a declared Schema or a CTE of the same statement; Mantle's tables and the identity provider's are never named.
50
- - `input.<name>` is a declared input. The `mantle` and `auth` schemas hold only the functions of decision 2.
51
- - Functions that change session or server state, or reach outside the database, are refused whatever the dialect: `set_config` and `current_setting` of `mantle.*`, advisory locks, file and large-object access, `dblink`, backend signals and `pg_reload_conf`. A `"native"` dialect relies on this list, because a caller setting could otherwise be forged from SQL.
52
-
53
- ### 5. Choosing a dialect (amends ADR-0032 decision 12)
54
-
55
- - `mantle.config.json` version 2 gains `dialect`, an npm module name. Absent, it is the built-in D1 dialect, so existing projects do not change. There is no CLI flag and no `host` field.
56
- - The plan records the dialect's name and version, and both are part of the fingerprint. Boot refuses a plan compiled for another dialect. Cloud Control (ADR-0034 decision 7) accepts only D1 plans.
57
- - A dialect and a host are different things. The dialect is the engine and is a public interface; the host is the platform entry (a Worker, `Bun.serve`, scheduling, media), which stays an application-owned preset. The open-source generator writes the Cloudflare preset only (ADR-0032 decision 6); another host's preset belongs with whoever ships it.
58
-
59
- ### 6. The D1 dialect (amends ADR-0034 decisions 5, 6 and 8)
60
-
61
- - The built-in dialect, `@aotter/mantle/d1`. It is everything ADR-0034 describes for D1: the subset check, the IR and its validator, the SQLite rendering and codec, FTS5 and R*Tree for `mantle.*`, `"inject"` policy, and trigger-based convergence. These move out of Core into the dialect; behavior does not change.
62
- - `@aotter/mantle/cloudflare` keeps the D1 binding driver and `d1Storage`, now built on the dialect.
63
-
64
- ### 7. `StoreSelect.search` (new)
65
-
66
- - `StoreSelect` gains `search?: string`: rows whose declared `searchableFields` contain the text, or whose `id` is the text, under the caller's visibility like any `select`. Ordering stays `orderBy`. Each dialect's executor implements it; D1 uses its FTS5 trigram table, so Chinese substrings of three characters or more match, and a shorter query falls back to a scan.
67
- - Admin's collection search box sends `search` instead of building `like` conditions itself.
68
- - The manifest key is `searchableFields`; ADR-0034 decision 9 wrote `search`, and the plan stores it as `search`.
69
-
70
- ### 8. The dialect compliance suite
71
-
72
- - `@aotter/mantle/testing` becomes the dialect compliance suite: every ADR-0034 conformance case, the relation-position probe, the wire-value checks and the `StoreSelect.search` checks, each against a dialect's runtime side on a real engine, and the refusal cases against its compile side. A case whose feature a dialect refuses at compile time passes by that refusal.
73
- - A dialect is supported when it passes the suite. The D1 dialect runs it on local D1 in CI, as today.
74
-
75
- ### 9. The identity provider's SQL
76
-
77
- - `createMantleAuth` stops writing its own SQLite. What it still writes in SQL (members, invitations, consents, linked accounts, the bootstrap owner, its schema ledger) moves to Better Auth's own Kysely instance, which speaks every engine Better Auth supports. Auth then depends on Better Auth's adapters, not on a Mantle dialect.
78
-
79
- ## Consequences
80
-
81
- - Another engine is a module, not a fork, and it proves itself with the same suite D1 passes.
82
- - Core loses its SQLite code; the D1 dialect owns it. Mantle Cloud stays D1-only.
83
- - Manifests name Mantle's extensions explicitly (`mantle.search(...)`), and anything unqualified reads as PostgreSQL.
84
- - A plan is dialect-specific; moving a service to another engine is a recompile.
85
- - The interface is new public surface, versioned with the plan.
86
-
87
- ## Alternatives
88
-
89
- - **ISO or ANSI SQL as the canonical language.** There is no authoritative parser for it, and PostgreSQL is the implementation closest to it. Naming the standard would still mean choosing one vendor's parser.
90
- - **Substrait.** A cross-engine relational-plan standard, but it describes plans after planning, it is not authored, and neither D1 nor most transactional engines consume it; every dialect would still render SQL from it.
91
- - **Mantle's own neutral tree.** A new language to specify and teach; ADR-0034 left the JSON grammar for SQL for this reason.
92
- - **A `host` option in the open-source CLI.** A host is a platform preset, not an engine; making it a CLI option ties platform files to the generator. Rejected in favor of the dialect interface. *Superseded by ADR-0036: presets are written once and owned by the application, so the generator owns no platform file after the first run.*
93
- - **Bare `search()` and `near()`.** Shorter, but they read as PostgreSQL functions and can collide with an engine's or an extension's own.
94
-
95
- ## How to apply
96
-
97
- 1. This ADR, then the moves with no behavior change: the shared front end out of the SQL compiler, the D1 subset check, rendering, policy lowering and convergence into `@aotter/mantle/d1`, and the interface types.
98
- 2. `mantle.*` names, the dialect recorded in the plan, and `dialect` in the config.
99
- 3. `StoreSelect.search`, and Admin's search box on it.
100
- 4. `createMantleAuth`'s SQL onto Better Auth's Kysely instance.
101
- 5. The compliance suite over the dialect interface, run on the D1 dialect.
102
-
103
- ## Conformance cases
104
-
105
- 1. The shared front end refuses, with a position: DDL, `SET`, transaction control, `COPY`, `DO`, `set_config('mantle.…', …)`, a Mantle or identity-provider table in `FROM` and in a scalar subquery, an undeclared `input`, and an unknown `mantle.*` or `auth.*` function.
106
- 2. An unqualified `search(…)` is not Mantle's: the D1 dialect refuses it as an unsupported function, and `mantle.search(…)` behaves as ADR-0034 decision 9's `search` did.
107
- 3. A plan compiled for another dialect is refused at boot; a config without `dialect` compiles for D1.
108
- 4. `StoreSelect.search` on D1: a three-character Chinese substring matches, a two-character one falls back to a scan, another owner's rows are absent.
109
- 5. The D1 dialect passes the compliance suite on local D1, and every public barrel except the moved internals exports what it did before.
110
-
111
- ## Implementation status
112
-
113
- Proposed.
114
-
115
- > **Amendment (How to apply 1, 2026-09-30):** The move, and the names it changes. Behavior does not change.
116
- > - `@aotter/mantle` no longer exports `sqliteStorage`, `runMigrations`, `readStoreInstanceId` or `Migration`; `@aotter/mantle/d1` exports them unchanged. `@aotter/mantle/spec` no longer exports the D1 allowlist (`validateProgram`, `validateIr`, `KEYS_SRC`, `KEYS`, `BARE`, `ENUM`, `FUNCS`, `TRUNC_UNITS`, `EXTRACT_FIELDS`, `MAX_RADIUS_M`, `MAX_NEAR_K`, `SQLITE_ONLY_KEYWORDS`, `SYSTEM`). `@aotter/mantle/d1/compile` exports `validateProgram` as `accepts`, and the runtime reaches the same validator as the dialect's `check`, which throws the first refusal instead of returning a list (D1 stops at the first).
117
- > - The shared front end (`compileSql`) calls D1's `accepts` directly until `dialect` in the config selects one (How to apply 2).
118
- > - `PreparedMantleStorage` gains `dialect`. Core calls four things on it: `check` (the IR validator, on every program), `lowering` (what the policy rewriter leaves to the engine: input and literal casts, `search`, `near` and the other Mantle functions, kept calls, subquery links, new ids, and extra wrapper columns such as D1's `_rid`), `bind` (the binds the lowering adds) and `codec`. These types stay internal until How to apply 5 makes the interface public. `name`, `version` and `policy` arrive with the plan's dialect record in How to apply 2.
119
- > - Still to move: `auth` calls `runMigrations` and `readStoreInstanceId` (How to apply 4), `@aotter/mantle/testing` reaches D1 internals (How to apply 5), and Store's TTL sweep pages on D1's `_rid` column.
120
-
121
- > **Amendment (How to apply 2, 2026-09-30):** The names, the plan record and the config key.
122
- > - Mantle's functions are spelled `mantle.search`, `mantle.search_rank`, `mantle.near` and `mantle.distance` everywhere: manifests, the D1 allowlist and its lowering. An unqualified `search(…)` is refused as an unsupported function.
123
- > - The plan records `dialect: { name, version }`, inside the fingerprint. Its version is 6 for all of 0.2.0: the plan version changes only between released formats (0.1.x shipped 5), never within an unreleased one, because no plan of an unreleased shape exists to refuse. Development had moved it to 7 and 8; both are gone. The D1 dialect is `{ name: "@aotter/mantle/d1", version: "1" }`; its version changes when what a D1 plan means changes. `dialect` moves from `PreparedMantleStorage` to `MantleStorageAdapter`, and the runtime's `MantleDialect` gains `name` and `version`, so boot compares them with the plan before it converges anything and refuses a mismatch with `PLAN_FINGERPRINT_MISMATCH`, as it refuses another plan version.
124
- > - `@aotter/mantle/d1/compile` exports `name`, `version` and `accepts`. `@aotter/mantle/spec` exports `SqlDialect`, the compile side's type, and `compileSql`, `compileLinkedPlan` and `compilePlan` take one as their last argument, D1 when omitted.
125
- > - `mantle.config.json` version 2 takes an optional `dialect`, a package name (never a path). `mantle generate` resolves `<dialect>/compile` from the project with `require.resolve`, so the package's `exports` must give it a `default` (or `require`) condition, imports it and compiles with it; absent, or `@aotter/mantle/d1`, it is the built-in dialect. The config's other keys are unchanged.
126
- > - The shared front end refuses decision 4's list before `accepts`: statements other than `SELECT`, `INSERT`, `UPDATE`, `DELETE` and `MERGE`; a relation that is not a declared Schema or a CTE of the statement, or that names a schema; an undeclared `input.<name>`; a `mantle.*` or `auth.*` function that decision 2 does not define; and the session, server and outside-access functions (`set_config` and `current_setting` of a `mantle.*` setting or of a name that is not a literal, advisory locks, file and large-object access, `dblink`, backend signals, `pg_reload_conf`, `pg_notify`, sequences, and the functions that run SQL text: `query_to_xml` and its kin, `ts_stat`, `ts_rewrite`); `SELECT … INTO`. Function names are compared as PostgreSQL resolves them (a catalog prefix and `pg_catalog.` dropped); a relation that names a CTE in scope, by PostgreSQL's scoping, is tagged `cte`.
127
- > - Lowering stays on the runtime side: Store builds its JSON queries at run time (and `StoreSelect.search`, How to apply 3), so they need it there. The compile side's `lower` and `outputs` are not built; `viewOutputs` reads a View's row type for every dialect.
128
-
129
-
130
- > **Amendment (How to apply 4, 2026-09-30):** Decision 9 as built. Better Auth does not expose its Kysely instance, and reaching it would add a dependency (`@better-auth/kysely-adapter`) for a handful of statements, so `createMantleAuth` does not use Kysely:
131
- > - Its tables come from Better Auth's own `getMigrations(...).runMigrations()`; the `_mantle_migrations` ledger row for them is gone. A digest of Better Auth's table definitions in `_mantle_boot_state` (`auth-schema`) lets a prepared database skip the introspection, so a warm isolate reads one row. Better Auth's statements are not idempotent, so an isolate that races another retries (up to five times) until the other has finished. Mantle adds one index, `user_role_idx`, in portable SQL.
132
- > - Revoking a consent deletes the consent and revokes its tokens in one batch first, so no new code is issued for it without a prompt; then its pending authorization codes are found and deleted through Better Auth's adapter (`findMany` paged past the rows it keeps, `deleteMany`), which reads the JSON value in code instead of `json_extract`.
133
- > - What Better Auth's API has no call for (the bootstrap owner's guarded promotion, member paging, the invite guard, linked accounts, consents and the MCP grant check) stays one statement each over the `DatabaseDriver`, in portable SQL: camelCase names and `"user"` quoted, binds numbered, a write's count read from `RETURNING`, no engine functions. The two guarded writes stay single statements, which SQLite and D1 serialize, so their guards hold there; on an engine with concurrent writers (PostgreSQL under READ COMMITTED) that engine's driver must run them serializable, or two first sign-ups could both become owner.
134
- > - The session cache's namespace (`_mantle_boot_state`'s instance id) is read by auth itself. `@aotter/mantle/d1` no longer exports `runMigrations`, `readStoreInstanceId` or `Migration`; it exports `sqliteStorage` only. `auth` no longer reaches `d1`.
135
-
136
- > **Amendment (How to apply 5, 2026-09-30):** The compliance suite over the dialect interface.
137
- > - `runStorageConformance({ create, compile })`: `create` returns, per case, a fresh database as `{ storage, driver, cleanup }`, where `storage` is the dialect's `MantleStorageAdapter` (its runtime side: `prepare` converges the fixture Schemas and returns the executor, and `dialect` carries the check, lowering and codec) and `driver` is the same database for the fixture's own seeding and reads, in plain SQL over the storage layout of ADR-0033, with typed values (timestamps, numerics, JSON) through the dialect's codec. `prepare` receives a whole `RuntimePlan` for the fixture Schemas. `compile` is the dialect's compile side, D1 when omitted. A corpus item the compile side refuses as unsupported (`SQL_UNSUPPORTED`, `SQL_FUNCTION`, `SQL_TYPE`) passes by that refusal, and the check names it; any other refusal, and a refusal in any other case, fails.
138
- > - The generic cases are requisition, stock, report View, before hook, policy (the relation-position probe), search and places, the printer corpus (rows, not SQL text) and Store (including `StoreSelect.search`). What depends on how D1 spells or stores things (the printed SQL, SQLite's query plan, FTS5's trigram floor, D1's `meta.changes`, the storage encodings of the types case, and that D1 accepts the whole corpus) is D1's own test, `test/d1/dialect.test.ts`. `testing` no longer reaches `d1`.
139
- > - **Not yet dialect-neutral: computed outputs.** Store decodes a View's output column only when it reads a Schema field unchanged; a computed typed value (`now()`, `date_trunc`, a numeric literal, a `CAST` to bool) reaches the caller as the engine stores it. So the corpus rows that compute such values, and the whole types case (integer division, exact numerics, the interval boundary, `round`, `date_trunc` and `extract` across daylight saving), expect D1's encodings, and the types case runs only in D1's test. Typing each output column in the compile side and decoding it in Store is the prerequisite for a second dialect; with it, the types case's View checks return to the generic suite and only its storage reads stay in D1's test.
140
-
141
- > **Amendment (PostgreSQL dialect, #1293, 2026-10-02):** The second dialect ships in this repository, not outside it: `@aotter/mantle/postgres` and `@aotter/mantle/postgres/compile`. This amends the Context's "an enterprise PostgreSQL dialect is the first one written outside it"; decision 5's "Cloud Control accepts only D1 plans" stands for now. A consumer service behind Cloudflare Hyperdrive wants PostgreSQL from day one, and a dialect inside the repository is the one the compliance suite keeps honest.
142
- > - **What it accepts** (*replaced by ADR-0037: the PostgreSQL dialect runs the reference profile, and D1 the base subset*): D1's subset (decision 6) less SQLite's own functions (`typeof`, `hex`, `json_extract`, `json_set`, `json_insert`, `json_remove`), refused with a position. A PostgreSQL manifest therefore compiles for D1 too. `mantle.near`, `mantle.distance` and `mantle.search_rank` are lowered without an extension (a range and a haversine; an occurrence count instead of bm25).
143
- > - **Values:** columns have native types. The executor asks node-postgres for every value as text and decodes it by the column's type OID, so computed outputs are typed wire values, which is the prerequisite How to apply 5 named, for this dialect. The printer corpus therefore accepts, per item, D1's encoding or the typed wire values (`typedRows`).
144
- > - **Core:** the `now` and `cutoff` binds and the TTL sweep's bind go through `codec.encode("timestamptz", …)` (the identity on D1), and `PolicyLowering.system` lets a dialect type `now()`'s bind (PostgreSQL cannot infer `$1 - interval '1 hour'`). D1's output is unchanged.
145
- > - **Concurrency:** every write batch is one `SERIALIZABLE` transaction, retried on 40001/40P01, which is the "engine's driver must run them serializable" that How to apply 4 asked for, for auth's guarded writes too (`pgDatabaseDriver`, `pgPool` for Better Auth).
146
- > - **Driver:** structural node-postgres types; `connect` opens a client per operation, as Workers and Hyperdrive need. Statements are sent one at a time; a pipelining driver is the upgrade if round trips show.
147
- > - **Same results as D1 where Mantle decides them:**
148
- > - Text columns use `COLLATE "C"`.
149
- > - A default NULL order is stated as Core pages Views: first ascending, last descending.
150
- > - Every transaction pins `DateStyle`, `IntervalStyle`, `extra_float_digits` and `TimeZone`.
151
- > - Reads run in read-only transactions, so Hyperdrive's cache never answers them.
152
- >
153
- > Elsewhere the meaning is PostgreSQL's (`LIKE` case, division by zero, `->>` returning text).
154
- > - **Not yet:** site settings and media (D1 only), a trigram or GiST index behind `searchableFields` and `format: geo`, and `mantle generate --check`'s storage dry run (D1 only).
@@ -1,65 +0,0 @@
1
- # ADR-0036: Host and dialect are the two axes of a project
2
-
3
- **Status:** Accepted for 0.2.0. Amends ADR-0035 decision 5 and replaces its rejected alternative "a `host` option in the open-source CLI". Amended by [ADR-0038](0038-bun-native-host.md).
4
-
5
- **Date:** 2026-10-02
6
-
7
- **Related:** ADR-0032 decision 6, ADR-0035, #1296
8
-
9
- ## Context
10
-
11
- ADR-0035 made the SQL engine a dialect module, but left the CLI with one preset: Cloudflare over D1. A service that wants
12
- PostgreSQL behind Hyperdrive wrote its composition by hand, and the CLI rejected a `host` key as a 0.1.x config. ADR-0035
13
- rejected a `host` option because it "ties platform files to the generator". Two facts change that: the preset is already
14
- written once and owned by the application (ADR-0032 decision 6), so the generator owns no platform file after the first
15
- run; and a second built-in dialect exists, so "which engine on which platform" is a real choice.
16
-
17
- ## Decision
18
-
19
- ### 1. Two axes
20
-
21
- - `host`: where the service runs. `cloudflare` (the default) or `none`. A Bun host (`bun`) is added by its own ADR amendment
22
- with `@aotter/mantle/bun`.
23
- - `dialect`: the SQL engine. `sqlite` (alias `d1`, the default), `postgres`, or a dialect package (ADR-0035 decision 5).
24
- - The driver follows from the pair (D1 binding, Hyperdrive and `pg`, ...); it is not a third option.
25
- - The host never enters the plan or its fingerprint. The dialect does, as ADR-0035 decision 5 says. The SQLite dialect keeps
26
- recording `@aotter/mantle/d1`, so the rename changes no existing plan.
27
-
28
- ### 2. Chosen once
29
-
30
- - `mantle generate --host <host> --dialect <name>` writes both into `mantle.config.json` on the first run, and the preset
31
- for the pair if one exists.
32
- - A rerun that asks for another host or dialect is refused (exit 2), as another identity is: `src/service.ts` is the
33
- application's, and another engine is a data move. The config is changed deliberately.
34
-
35
- ### 3. Presets per pair
36
-
37
- | | `cloudflare` | `none` |
38
- |---|---|---|
39
- | `sqlite` | the D1 preset | plan and types only |
40
- | `postgres` | the Hyperdrive preset: `postgresStorage`, `pgPool` and `pgDatabaseDriver` over a client per operation; a `hyperdrive` binding with a placeholder id and a `localConnectionString` | plan and types only |
41
- | a package | plan and types only | plan and types only |
42
-
43
- - `host: none` is the escape hatch for any platform the presets do not cover (ChatGPT Sites keeps using the Cloudflare
44
- preset with `identity: custom`): the application calls `createMantle` with a storage adapter itself.
45
- - The Cloudflare cron gate applies to host `cloudflare` only.
46
- - A pair's packages are checked like a feature's (`pg` for `postgres` on `cloudflare`).
47
- - Generate warns, never writes, when `wrangler.jsonc` lacks the pair's binding, or still holds the Hyperdrive placeholder.
48
-
49
- ## Consequences
50
-
51
- - PostgreSQL on Cloudflare is one flag, and its preset is tested end to end (typecheck, and a Worker booted against
52
- PostgreSQL through Hyperdrive's local connection).
53
- - The 0.1.x detection is `version: 1`, no longer any `host` key.
54
- - `--check --database`'s storage dry run stays the SQLite dialect's.
55
-
56
- ## Alternatives
57
-
58
- - **A third `driver` axis.** Every built-in pair has one sensible driver; a third choice is configuration without a use.
59
- - **Host in the plan.** A plan runs the same on any host; recording it would make a host move a recompile for nothing.
60
- - **Renaming the recorded dialect to `@aotter/mantle/sqlite`.** Every existing plan would stop booting for a name.
61
-
62
- ## Implementation status
63
-
64
- Implemented in #1296: the axes, the aliases, the Hyperdrive preset, `host: none`. The Bun host (`host: bun`, both dialects)
65
- is ADR-0038, which amends decisions 1 and 3.
@@ -1,125 +0,0 @@
1
- # ADR-0037: PostgreSQL is the reference dialect; D1 runs a subset
2
-
3
- **Status:** Accepted for 0.2.0. Amends ADR-0034 decisions 2 and 8 and ADR-0035 decisions 1, 4 and 6, and replaces the
4
- PostgreSQL dialect amendment's "What it accepts".
5
-
6
- **Date:** 2026-10-02
7
-
8
- **Related:** ADR-0014 (Cloud and tenants), ADR-0034, ADR-0035, ADR-0036, #1293
9
-
10
- ## Context
11
-
12
- ADR-0035 decision 1 made Mantle SQL PostgreSQL's syntax and meaning, and said a PostgreSQL dialect "can accept nearly all of
13
- PostgreSQL". The PostgreSQL dialect shipped as D1's subset less SQLite's functions, so a PostgreSQL manifest also compiled for
14
- D1. That kept engines interchangeable, but it held services that chose PostgreSQL to SQLite's limits: no `WITH`, no window
15
- frames, no `FILTER`, no jsonb operators. A View that needed one rule in many places (a plan's visible window, for example)
16
- had to repeat it.
17
-
18
- Services that pick PostgreSQL pick it for good (Swolhalla runs on PostgreSQL from day one). The subset should be D1's
19
- limitation, not every dialect's.
20
-
21
- Two kinds of author write Mantle SQL, and the allowlist means something different to each:
22
- - **A self-hosted service** (enterprise, Swolhalla): the author also operates the database and can reach it directly. The
23
- allowlist does not stop malice there; it stops mistakes, above all SQL (often written by an AI) that would read another
24
- member's rows.
25
- - **Mantle Cloud:** tenants are third parties. Today each tenant has its own D1 and its own Workers for Platforms script, and
26
- the tenant's `ref` handlers run in that script with the raw `DB` binding (aotter/mantle-home `apps/control/src/deploy/provider.ts`).
27
- Isolation between tenants is the separate database, not the allowlist. A PostgreSQL cell shared by thousands of tenants
28
- behind one Hyperdrive config (one connection string, one role) cannot isolate tenants that way.
29
-
30
- ## Decision
31
-
32
- ### 1. One reference allowlist, PostgreSQL's
33
-
34
- - Mantle SQL's allowlist lives in Core (`src/core/sql/allowlist.ts`): the walker and two profiles, **base** (what every
35
- dialect runs, ADR-0034's subset) and **reference** (base plus decision 2). The PostgreSQL dialect accepts the reference
36
- profile. The D1 dialect accepts base.
37
- - A construct D1 refuses but the reference accepts is refused with the reason "needs the PostgreSQL dialect", so an author
38
- knows it is an engine limit, not a mistake.
39
- - The allowlist stays closed on every dialect. "PostgreSQL first" means a larger closed list, never "anything PostgreSQL
40
- parses": PostgreSQL's catalog has thousands of functions, and one that runs SQL text (`query_to_xml`) or reads files
41
- bypasses every policy.
42
- - Each construct added to the reference profile lands with: the walker's rule, the policy rewriter's handling (a new relation
43
- position has a probe in the compliance suite, ADR-0034 decision 8), a compliance case on PostgreSQL, and a D1 refusal test.
44
-
45
- ### 2. The reference profile, first wave
46
-
47
- | Construct | Rule |
48
- |---|---|
49
- | `WITH` and `WITH RECURSIVE` | Every CTE body is a `SELECT`. A data-modifying CTE (`WITH x AS (DELETE …)`) is refused. Each Schema read inside a body is wrapped like any other (relation position `cte`); a reference to the CTE is not. A reference is a CTE only by PostgreSQL's scope (a body sees its earlier siblings, every sibling under `RECURSIVE`); the allowlist and the rewriter both check that scope at runtime, because a `cte` tag on any other name would make PostgreSQL read the table, or the catalog view, of that name unwrapped. |
50
- | `UNION`, `UNION ALL`, `INTERSECT`, `EXCEPT` | Inside a CTE body or a subquery only, never a View's own top-level `SELECT`, because Core's paging and deterministic order act on that `SELECT`. Each branch is wrapped (position `setop`). |
51
- | `DISTINCT ON` | Inside a CTE body or a subquery only, for the same reason: Core's paging rewrites the top-level order, which decides which row `DISTINCT ON` keeps. |
52
- | `LATERAL` subqueries | `JOIN LATERAL (…) x ON …` or `, LATERAL (…) x`. The subquery is wrapped as any FROM subquery. |
53
- | Window frames | `ROWS` and `RANGE` with literal offsets; functions `avg`, `min`, `max`, `lag`, `lead`, `first_value`, `last_value` and `dense_rank` gain `OVER`. |
54
- | Aggregates | `FILTER (WHERE …)`, `ORDER BY` inside an aggregate, `string_agg`. |
55
- | jsonb | Operators `->`, `#>`, `#>>`, `@>`, `<@`, `?`, `?|`, `?&`; `jsonb_build_object`, `jsonb_build_array`, `jsonb_strip_nulls`, `jsonb_agg`, `jsonb_object_agg`, `to_jsonb`, `jsonb_typeof`; casts to `jsonb`. |
56
- | Text | `ILIKE`, `NOT ILIKE`, and the regular-expression operators `~`, `~*`, `!~`, `!~*`; `split_part`. |
57
- | Numbers | `greatest`, `least`, `floor`, `ceil`, `sqrt`, `power`. |
58
- | Time | `AT TIME ZONE`; `date_trunc` adds `minute` and `quarter`; `extract` adds `minute`, `quarter`, `week`, `isoyear`, `isodow`, `doy` and `epoch`. |
59
- | Casts | A cast of any expression to `int4`, `int8`, `numeric(p, s)`, `date` or `timestamptz` (D1 keeps its literal-only rule, which exists because SQLite truncates and stores time as integers). A bare text literal compared with a date-time, date or boolean column is PostgreSQL's cast, so the D1 refusal of it does not apply. |
60
-
61
- Still refused everywhere: data-modifying CTEs, set-returning functions in FROM other than `json_each`, `generate_series`,
62
- `FOR UPDATE`, `OFFSET`, `RIGHT` and `FULL` joins, and every function in ADR-0035 decision 4's list. Each needs its own
63
- amendment.
64
-
65
- ### 3. A View may read another View
66
-
67
- - A View's or a Procedure's `FROM` may name an **internal** View (`surface: internal`) that declares no `input` and no `requires`, by its name
68
- with `-` written `_` (`free-window` is `free_window`). A Schema of the same name keeps it: the name reads the Schema.
69
- - The compiler inlines the referenced View's compiled `SELECT` as a `FROM` subquery before the dialect sees the tree. Policy
70
- and every check then apply to it as to any subquery. Nothing reaches the runtime that a hand-written subquery could not.
71
- - References are resolved in dependency order; a cycle is a compile error.
72
- - On every dialect. This is how a rule used by many Views is written once.
73
-
74
- ### 4. A narrowing hook
75
-
76
- - `postgresStorage` and `sqliteStorage` take `restrict?: (plan, context) => readonly SqlDiagnostic[]`. Core runs it on every
77
- program's IR after the dialect's own check, at runtime (ADR-0035: the runtime never trusts an IR). Since the SQL compile
78
- cache, an accepted verdict is cached with the compiled program, so `restrict` runs again only for a program Core compiles anew. It can only refuse.
79
- - It is for an operator that runs other people's plans. A self-hosted service does not set it.
80
-
81
- ### 5. Every PostgreSQL transaction has a statement timeout
82
-
83
- - The PostgreSQL driver pins `statement_timeout` with `SET LOCAL` in every transaction, as it pins `DateStyle` and `TimeZone`:
84
- 10 seconds unless `postgresStorage({ statementTimeoutMs })` says otherwise. A recursive CTE or a regular expression that runs
85
- away ends there.
86
- - A database role used by Mantle is not a superuser and holds no file or server privilege (`pg_read_server_files`,
87
- `pg_execute_server_program`). The handbook says so; Mantle does not check.
88
-
89
- ### 6. Mantle Cloud's boundary
90
-
91
- - **D1 (today):** the tenant's database is the isolation unit, so the tenant's code may hold its binding, as it does.
92
- - **PostgreSQL (when Cloud adds it):** the cell's connection never enters a tenant script. The platform owns the Hyperdrive
93
- binding and runs a Store service the tenant script calls (as it calls `MAIL` and `MEDIA`). The service validates every IR
94
- with the dialect, then a Cloud `restrict` profile, then the policy rewriter, and runs each transaction as the tenant with
95
- `SET LOCAL ROLE` and the tenant's `search_path`. The cell role is a member of every tenant role; a tenant role holds only its
96
- schema. The allowlist is then a real boundary, and PostgreSQL's privileges are the second one.
97
- - The Cloud profile and the Store service are aotter/mantle-home's to build; Core provides decision 4.
98
-
99
- ## Consequences
100
-
101
- - A PostgreSQL manifest may no longer compile for D1. Moving from PostgreSQL to D1 can need a rewrite; moving from D1 to
102
- PostgreSQL still needs none.
103
- - The reference profile grows by amendment, one construct at a time, each with its probe.
104
- - Swolhalla's free-plan window is one internal View every other View reads.
105
-
106
- ## Alternatives
107
-
108
- - **Accept everything PostgreSQL parses and deny a list of dangerous functions.** A denylist is never complete: an extension,
109
- a new catalog function or a server upgrade adds one. Rejected.
110
- - **A Schema-level visibility predicate** (a second `scope`, injected by the rewriter). It solves the repeated window, but only
111
- for row filters; View references solve it and every other shared rule.
112
- - **Native row-level security on PostgreSQL** (ADR-0035 decision 3's `policy: "native"`). The right second layer for Cloud
113
- (decision 6); a larger change than this ADR needs.
114
-
115
- ## Conformance cases
116
-
117
- 1. Each decision 2 construct gives PostgreSQL's result on the PostgreSQL dialect, and D1 refuses it with "needs the
118
- PostgreSQL dialect".
119
- 2. The relation-position probe covers `cte` and `setop`, and a Schema read inside a recursive CTE, a `UNION` branch and a
120
- `LATERAL` subquery never shows another owner's rows. An IR whose `cte` tag names a relation outside PostgreSQL's CTE
121
- scope (the CTE's own body, a later sibling, a catalog view) is refused at runtime.
122
- 3. A View's top-level `UNION` or `DISTINCT ON`, and a data-modifying CTE, are refused with a position.
123
- 4. A View reads an internal View; the reference to a View with an input, a public View or a cycle is refused.
124
- 5. A `restrict` that refuses a program stops it at runtime with its diagnostic.
125
- 6. A statement past `statement_timeout` fails with `RESOURCE_UNAVAILABLE`, and nothing is written.