@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
@@ -0,0 +1,90 @@
1
+ # Purchasing
2
+
3
+ An internal purchase-request workflow. Any signed-in employee submits a request against a department budget. An admin
4
+ approves or rejects it, in Admin or through an AI agent on the admin MCP endpoint. Approval spends the budget and writes a
5
+ ledger row in one transaction. The app then orders from the supplier's API and waits for the supplier's signed callback
6
+ to mark the request confirmed. Requesters get an email on each decision, and a daily cron emails admins about requests
7
+ that have been waiting too long.
8
+
9
+ ## Capabilities shown
10
+
11
+ - **Status workflow with guarded transitions**: the write Procedures use
12
+ `UPDATE requests SET requestStatus = 'approved' ... WHERE id = input.id AND requestStatus = 'submitted'`. A match on
13
+ 0 rows is a `CONFLICT` (409). See `manifests/purchasing.yaml` (`approve-request-write`, `reject-request-write`,
14
+ `change-amount`, `mark-ordered`, `confirm-order`). The column is `requestStatus` because `status` is reserved for
15
+ publishing Schemas. `requests` and `ledger` set `readOnly: true`, so Admin's generic editor cannot bypass the state
16
+ machine (for example by moving an ordered request back to `submitted` and approving it again).
17
+ - **Admin-only operations**: `approve-request` and `reject-request` declare `requires: ctx.admin` and a `target`, so
18
+ Admin shows them as operations on a request. Their `kind: mcp, surface: admin` Triggers make them
19
+ `approve_request` / `reject_request` tools on `/mcp/admin`. They are not listed on `/mcp`.
20
+ - **Optimistic concurrency**: clients send `expectedVersion`, and the SQL matches `version = input.expectedVersion`.
21
+ If the requester changes the amount (`change-amount`, only their own request and only while it is `submitted`)
22
+ after an admin reviewed it, that admin's approval is a 409. When two admins approve the same version, one succeeds
23
+ and the other gets a 409.
24
+ - **Several writes in one transaction**: `approve-request-write` runs three statements as one program: the status
25
+ change, `UPDATE budgets SET remaining = remaining - ...` and `INSERT INTO ledger`. If the request would overspend,
26
+ `checks: ["remaining >= 0"]` on `budgets` rolls back all three. `src/handlers.ts` turns that failure into a 409.
27
+ - **External API + signed callback**: after the transaction commits, `src/supplier.ts` POSTs the order to
28
+ `env.SUPPLIER_API_URL` (request id as the idempotency key, 10 s timeout) and then sets the request to `ordered`.
29
+ If the supplier cannot be reached, the request stays `approved` and the daily cron retries it as a system caller
30
+ (`mark-ordered` has no `requires` for that reason, and no Trigger).
31
+ `src/routes.ts` serves `POST /callbacks/supplier`. It first checks an HMAC-SHA256 of the timestamp and the **raw**
32
+ body with `env.SUPPLIER_WEBHOOK_SECRET`, and only then parses the JSON. It then calls the generated `confirm-order`
33
+ Procedure as a `system` caller. No Trigger exposes that Procedure. The callback may arrive before `ordered` is
34
+ written, so `approved` is confirmed too. A replay of an applied callback answers 204 again.
35
+ - **Email + cron as app code**: `src/notify.ts` sends through an `EmailSender` from `@aotter/mantle/email`
36
+ (`ConsoleEmailSender` locally). `src/schedule.ts` uses `toCloudflareCron`, and its cron is listed in
37
+ `wrangler.jsonc`. The cron retries failed orders (internal View `approved-requests`) and sends the reminder
38
+ (internal View `stale-requests`) to admins who are not banned.
39
+ - Employees see only their own requests through `my-requests` (`restrict: { requests: "author_id = auth.uid()" }`).
40
+ - **Sidebar for the approver's day**: `src/admin.ts` declares an Approvals group (`navGroups`) above Admin's built-in
41
+ groups; `pending-requests` and `requests` move into it with `uiSchema.nav: { group, order }`.
42
+ - **A page only signed-in employees reach**: `src/requests-page.ts` serves `GET /requests`. An anonymous visitor gets a
43
+ 303 to the shell's `/sign-in?return=/requests` (`src/sign-in.ts`, email code, then back). Signed in, the table reads
44
+ `my-requests` as the visitor's own caller. The form keeps `action="/api/requests" method="post"`; a small script sends
45
+ its fields as JSON to that REST Trigger, so the manifest's validation, `requires` and origin check apply and app code
46
+ never hands request data to a Procedure. Unstyled on purpose. `src/signup.ts` lets only `@EMPLOYEE_DOMAIN` emails
47
+ create an account (`vars` in `wrangler.jsonc`).
48
+
49
+ Search for `AGENT:` to find what a real app must still provide: an email sender, the supplier's real API and signature
50
+ scheme.
51
+
52
+ ## Combine with
53
+
54
+ - Need members to own rows, prevent duplicates or cap capacity? Add club-events' `uniqueIndexes` and capacity `checks`.
55
+ - Need public pages, SEO or media for the approved items? Add recipes' publishing lifecycle and visitor pages.
56
+ - Need another approval flow? Copy the pattern: a ref Procedure (admin-only, side effects) that wraps a guarded SQL
57
+ write Procedure (one transaction).
58
+
59
+ ## Copy
60
+
61
+ ```sh
62
+ cp -R node_modules/@aotter/mantle/docs/examples/app-shell/. my-app/
63
+ cp -R node_modules/@aotter/mantle/docs/examples/purchasing/. my-app/
64
+ cd my-app && pnpm install && pnpm generate && pnpm types && pnpm check
65
+ cp .dev.vars.example .dev.vars # then set SUPPLIER_API_URL and SUPPLIER_WEBHOOK_SECRET
66
+ pnpm db:init && pnpm db:seed && pnpm dev
67
+ ```
68
+
69
+ ## What `pnpm smoke` proves
70
+
71
+ `smoke.mjs` starts a stand-in supplier API on a local port (which it can switch to 503) and passes its URL and the
72
+ webhook secret through `smoke(scenario, { vars })`. It then checks the following:
73
+
74
+ 1. Employees submit requests and see only their own. A department without a budget creates nothing.
75
+ 2. An employee gets 403 on the Admin operation. The approve and reject tools exist only on `/mcp/admin`, and the
76
+ internal write Procedures are on neither MCP surface.
77
+ 3. Rejecting through the admin MCP tool emails the requester. Approving that request afterwards, with its current
78
+ version, is a 409 because the `requestStatus` guard matches no row.
79
+ 4. Approving more than the department has left is a 409. The request stays `submitted`, and the budget and ledger are
80
+ unchanged.
81
+ 5. Admin's generic editor cannot change a request. Another employee cannot change its amount (409); the requester can,
82
+ and then approving the version the admin reviewed is a 409 that changes nothing.
83
+ 6. Two admins approve the same version at the same time: one gets 200 and the other 409. The budget is deducted and
84
+ the ledger row written once.
85
+ 7. Approval places exactly one supplier order, sets `ordered` and emails the requester.
86
+ 8. The admin MCP tool approves too. With the supplier down, approvals still commit and stay `approved`.
87
+ 9. A callback with a bad signature is a 401 and changes nothing. A correctly signed callback sets `confirmed`, also
88
+ while the request is still `approved`; a replay is 204; a wrong order id or a `submitted` request is 409.
89
+ 10. The daily cron places the failed order (`ordered`) and emails every admin about requests pending more than 3
90
+ days, and only about those.
@@ -0,0 +1,341 @@
1
+ # Internal purchase requests: employees submit, admins approve or reject, approval spends a department budget.
2
+ # requestStatus: submitted -> approved -> ordered -> confirmed, or submitted -> rejected.
3
+ apiVersion: cms.mantle.aotter.net/v2
4
+ kind: Schema
5
+ metadata: { name: budgets }
6
+ spec:
7
+ title: Budgets
8
+ lifecycle: operational
9
+ uniqueIndexes: [[department]]
10
+ # An approval that would overspend fails this check and the whole approval rolls back.
11
+ checks: ["remaining >= 0"]
12
+ uiSchema: { list: { primaryField: department, columns: [remaining] } }
13
+ schema:
14
+ type: object
15
+ additionalProperties: false
16
+ required: [department, remaining]
17
+ properties:
18
+ department: { type: string }
19
+ remaining: { type: integer }
20
+ ---
21
+ apiVersion: cms.mantle.aotter.net/v2
22
+ kind: Schema
23
+ metadata: { name: requests }
24
+ spec:
25
+ title: Purchase requests
26
+ lifecycle: operational
27
+ indexes: [[authorId, createdAt, id], [requestStatus, createdAt, id]]
28
+ # Sidebar: in the Approvals group (src/admin.ts), after the queue of requests waiting for a decision.
29
+ uiSchema: { list: { primaryField: title, columns: [department, amount, requestStatus], filterField: requestStatus }, nav: { group: approvals, order: 2 } }
30
+ schema:
31
+ type: object
32
+ # Admin reads requests but cannot edit them generically: a generic edit could move requestStatus back to
33
+ # 'submitted' and spend the budget twice. Every change goes through the guarded Procedures below.
34
+ readOnly: true
35
+ additionalProperties: false
36
+ required: [title, amount, department, requestStatus]
37
+ properties:
38
+ title: { type: string, minLength: 1 }
39
+ amount: { type: integer, minimum: 1 }
40
+ department: { type: string }
41
+ requestStatus: { type: string, enum: [submitted, approved, rejected, ordered, confirmed] }
42
+ supplierOrderId: { type: string }
43
+ ---
44
+ apiVersion: cms.mantle.aotter.net/v2
45
+ kind: Schema
46
+ metadata: { name: ledger }
47
+ spec:
48
+ title: Budget ledger
49
+ lifecycle: operational
50
+ indexes: [[createdAt, id]]
51
+ uiSchema: { list: { primaryField: department, columns: [amount, remainingAfter, requestId] } }
52
+ schema:
53
+ type: object
54
+ readOnly: true # written only by approve-request-write
55
+ additionalProperties: false
56
+ required: [requestId, department, amount, remainingAfter]
57
+ properties:
58
+ requestId: { type: string }
59
+ department: { type: string }
60
+ amount: { type: integer }
61
+ remainingAfter: { type: integer }
62
+ ---
63
+ # Employees see only the requests they submitted.
64
+ apiVersion: cms.mantle.aotter.net/v2
65
+ kind: View
66
+ metadata: { name: my-requests }
67
+ spec:
68
+ surface: public
69
+ requires: { auth: { all: [ctx.user] } }
70
+ restrict: { requests: "author_id = auth.uid()" }
71
+ sql: |
72
+ SELECT id, title, amount, department, requestStatus AS "requestStatus", version
73
+ FROM requests ORDER BY created_at DESC, id DESC
74
+ ---
75
+ apiVersion: cms.mantle.aotter.net/v2
76
+ kind: View
77
+ metadata: { name: pending-requests }
78
+ spec:
79
+ title: Pending purchase requests
80
+ surface: admin
81
+ requires: { auth: { all: [ctx.admin] } }
82
+ uiSchema: { nav: { group: approvals, order: 1 } }
83
+ sql: |
84
+ SELECT id, title, amount, department, version
85
+ FROM requests WHERE requestStatus = 'submitted' ORDER BY created_at, id
86
+ ---
87
+ # The daily reminder reads this from src/schedule.ts; no route or tool exposes it.
88
+ apiVersion: cms.mantle.aotter.net/v2
89
+ kind: View
90
+ metadata: { name: stale-requests }
91
+ spec:
92
+ surface: internal
93
+ input:
94
+ type: object
95
+ additionalProperties: false
96
+ required: [before]
97
+ properties:
98
+ before: { type: string, format: date-time }
99
+ sql: |
100
+ SELECT id, title, amount, department FROM requests
101
+ WHERE requestStatus = 'submitted' AND created_at < input.before
102
+ ORDER BY created_at, id LIMIT 100
103
+ ---
104
+ # Approved but not yet ordered (the supplier call failed): the cron retries these.
105
+ apiVersion: cms.mantle.aotter.net/v2
106
+ kind: View
107
+ metadata: { name: approved-requests }
108
+ spec:
109
+ surface: internal
110
+ sql: |
111
+ SELECT id, title, amount FROM requests WHERE requestStatus = 'approved'
112
+ ORDER BY created_at, id LIMIT 20
113
+ ---
114
+ # Selecting from budgets refuses a department that has no budget, so approval always has a budget row to deduct.
115
+ apiVersion: cms.mantle.aotter.net/v2
116
+ kind: Procedure
117
+ metadata: { name: submit-request }
118
+ spec:
119
+ title: Submit a purchase request
120
+ requires: { auth: { all: [ctx.user] } }
121
+ input:
122
+ type: object
123
+ additionalProperties: false
124
+ required: [title, amount, department]
125
+ properties:
126
+ title: { type: string, minLength: 1 }
127
+ amount: { type: integer, minimum: 1 }
128
+ department: { type: string }
129
+ output: { type: object }
130
+ handler:
131
+ sql: |
132
+ INSERT INTO requests (title, amount, department, requestStatus)
133
+ SELECT input.title, input.amount, b.department, 'submitted' FROM budgets b WHERE b.department = input.department
134
+ RETURNING id, version
135
+ ---
136
+ # The requester may change the amount while the request is still 'submitted'. The version moves on, so an admin
137
+ # approving the version they reviewed before the change gets a 409 and looks again.
138
+ apiVersion: cms.mantle.aotter.net/v2
139
+ kind: Procedure
140
+ metadata: { name: change-amount }
141
+ spec:
142
+ title: Change the amount of my request
143
+ requires: { auth: { all: [ctx.user] } }
144
+ restrict: { requests: "author_id = auth.uid()" }
145
+ input:
146
+ type: object
147
+ additionalProperties: false
148
+ required: [id, expectedVersion, amount]
149
+ properties:
150
+ id: { type: string }
151
+ expectedVersion: { type: integer }
152
+ amount: { type: integer, minimum: 1 }
153
+ output: { type: object }
154
+ handler:
155
+ sql: |
156
+ UPDATE requests SET amount = input.amount
157
+ WHERE id = input.id AND version = input.expectedVersion AND requestStatus = 'submitted'
158
+ RETURNING id, version
159
+ ---
160
+ # Admin-only. The ref handler runs the write below, then places the supplier order and emails the requester.
161
+ apiVersion: cms.mantle.aotter.net/v2
162
+ kind: Procedure
163
+ metadata: { name: approve-request }
164
+ spec:
165
+ title: Approve a purchase request
166
+ description: Approve a submitted request; deducts the department budget, records a ledger row and places the supplier order.
167
+ requires: { auth: { all: [ctx.admin] } }
168
+ target: { schema: requests, id: id, version: expectedVersion }
169
+ input:
170
+ type: object
171
+ additionalProperties: false
172
+ required: [id, expectedVersion]
173
+ properties:
174
+ id: { type: string }
175
+ expectedVersion: { type: integer }
176
+ output: { type: object }
177
+ handler: { ref: approve-request }
178
+ ---
179
+ # One program, one transaction. Statement 1 is the guarded transition: a stale version or a request that is no longer
180
+ # 'submitted' matches 0 rows -> CONFLICT (409). Statement 2 fails remaining >= 0 when over budget. Either failure rolls
181
+ # back all three statements.
182
+ apiVersion: cms.mantle.aotter.net/v2
183
+ kind: Procedure
184
+ metadata: { name: approve-request-write }
185
+ spec:
186
+ requires: { auth: { all: [ctx.admin] } }
187
+ input:
188
+ type: object
189
+ additionalProperties: false
190
+ required: [id, expectedVersion]
191
+ properties:
192
+ id: { type: string }
193
+ expectedVersion: { type: integer }
194
+ output: { type: object }
195
+ handler:
196
+ sql: |
197
+ UPDATE requests SET requestStatus = 'approved'
198
+ WHERE id = input.id AND version = input.expectedVersion AND requestStatus = 'submitted'
199
+ RETURNING id, title, amount, author_id AS "authorId";
200
+ UPDATE budgets SET remaining = remaining - (SELECT r.amount FROM requests r WHERE r.id = input.id)
201
+ WHERE department = (SELECT r.department FROM requests r WHERE r.id = input.id);
202
+ INSERT INTO ledger (requestId, department, amount, remainingAfter)
203
+ SELECT r.id, r.department, r.amount, b.remaining FROM requests r JOIN budgets b ON b.department = r.department
204
+ WHERE r.id = input.id
205
+ ---
206
+ apiVersion: cms.mantle.aotter.net/v2
207
+ kind: Procedure
208
+ metadata: { name: reject-request }
209
+ spec:
210
+ title: Reject a purchase request
211
+ requires: { auth: { all: [ctx.admin] } }
212
+ target: { schema: requests, id: id, version: expectedVersion }
213
+ input:
214
+ type: object
215
+ additionalProperties: false
216
+ required: [id, expectedVersion]
217
+ properties:
218
+ id: { type: string }
219
+ expectedVersion: { type: integer }
220
+ output: { type: object }
221
+ handler: { ref: reject-request }
222
+ ---
223
+ apiVersion: cms.mantle.aotter.net/v2
224
+ kind: Procedure
225
+ metadata: { name: reject-request-write }
226
+ spec:
227
+ requires: { auth: { all: [ctx.admin] } }
228
+ input:
229
+ type: object
230
+ additionalProperties: false
231
+ required: [id, expectedVersion]
232
+ properties:
233
+ id: { type: string }
234
+ expectedVersion: { type: integer }
235
+ output: { type: object }
236
+ handler:
237
+ sql: |
238
+ UPDATE requests SET requestStatus = 'rejected'
239
+ WHERE id = input.id AND version = input.expectedVersion AND requestStatus = 'submitted'
240
+ RETURNING id, title, author_id AS "authorId"
241
+ ---
242
+ # Called after the supplier accepted the order: by the approve handler (admin caller) and by the cron retry (system
243
+ # caller). System callers satisfy no `requires` predicate, so it has none; no Trigger exposes it.
244
+ apiVersion: cms.mantle.aotter.net/v2
245
+ kind: Procedure
246
+ metadata: { name: mark-ordered }
247
+ spec:
248
+ input:
249
+ type: object
250
+ additionalProperties: false
251
+ required: [id, supplierOrderId]
252
+ properties:
253
+ id: { type: string }
254
+ supplierOrderId: { type: string }
255
+ output: { type: object }
256
+ handler:
257
+ sql: |
258
+ UPDATE requests SET requestStatus = 'ordered', supplierOrderId = input.supplierOrderId
259
+ WHERE id = input.id AND requestStatus = 'approved'
260
+ RETURNING id
261
+ ---
262
+ # Called only by POST /callbacks/supplier (src/routes.ts) as a system caller after the signature checks out.
263
+ # The callback can arrive before mark-ordered ran, so 'approved' is accepted too.
264
+ # No Trigger exposes it; system callers satisfy no `requires` predicate, so it has none.
265
+ apiVersion: cms.mantle.aotter.net/v2
266
+ kind: Procedure
267
+ metadata: { name: confirm-order }
268
+ spec:
269
+ input:
270
+ type: object
271
+ additionalProperties: false
272
+ required: [id, supplierOrderId]
273
+ properties:
274
+ id: { type: string }
275
+ supplierOrderId: { type: string }
276
+ output: { type: object }
277
+ handler:
278
+ sql: |
279
+ UPDATE requests SET requestStatus = 'confirmed', supplierOrderId = input.supplierOrderId
280
+ WHERE id = input.id AND (
281
+ (requestStatus = 'ordered' AND supplierOrderId = input.supplierOrderId)
282
+ OR requestStatus = 'approved')
283
+ RETURNING id
284
+ ---
285
+ apiVersion: cms.mantle.aotter.net/v2
286
+ kind: Trigger
287
+ metadata: { name: submit-request-http }
288
+ spec:
289
+ source: { kind: http, method: POST, path: /api/requests }
290
+ target: { procedure: submit-request }
291
+ ---
292
+ apiVersion: cms.mantle.aotter.net/v2
293
+ kind: Trigger
294
+ metadata: { name: change-amount-http }
295
+ spec:
296
+ source: { kind: http, method: POST, path: '/api/requests/{id}/amount' }
297
+ target: { procedure: change-amount }
298
+ ---
299
+ # Admin MCP tools: an AI agent connected to /mcp/admin can approve or reject.
300
+ apiVersion: cms.mantle.aotter.net/v2
301
+ kind: Trigger
302
+ metadata: { name: approve-request-mcp }
303
+ spec:
304
+ source: { kind: mcp, surface: admin }
305
+ target: { procedure: approve-request }
306
+ ---
307
+ apiVersion: cms.mantle.aotter.net/v2
308
+ kind: Trigger
309
+ metadata: { name: reject-request-mcp }
310
+ spec:
311
+ source: { kind: mcp, surface: admin }
312
+ target: { procedure: reject-request }
313
+ ---
314
+ # Admins open a department's budget from the Budgets list header (operational collections have no generic create);
315
+ # adjusting `remaining` later is an ordinary Admin edit.
316
+ apiVersion: cms.mantle.aotter.net/v2
317
+ kind: Procedure
318
+ metadata: { name: open-budget }
319
+ spec:
320
+ title: Open a budget
321
+ description: Give a department a purchasing budget.
322
+ requires: { auth: { all: [ctx.admin] } }
323
+ uiSchema: { collectionAction: budgets }
324
+ input:
325
+ type: object
326
+ required: [department, remaining]
327
+ additionalProperties: false
328
+ properties:
329
+ department: { type: string, minLength: 1, maxLength: 100, title: Department }
330
+ remaining: { type: integer, minimum: 0, title: Budget }
331
+ output: { type: object }
332
+ handler:
333
+ sql: |
334
+ INSERT INTO budgets (department, remaining) VALUES (input.department, input.remaining) RETURNING id
335
+ ---
336
+ apiVersion: cms.mantle.aotter.net/v2
337
+ kind: Trigger
338
+ metadata: { name: open-budget-admin }
339
+ spec:
340
+ source: { kind: mcp, surface: admin }
341
+ target: { procedure: open-budget }
@@ -0,0 +1,4 @@
1
+ -- Department budgets (whole currency units). Admins edit them in Admin > Budgets.
2
+ INSERT INTO budgets (id, created_at, updated_at, department, remaining) VALUES
3
+ ('budget-engineering', 1767225600000000, 1767225600000000, 'Engineering', 5000),
4
+ ('budget-design', 1767225600000000, 1767225600000000, 'Design', 1000);
@@ -0,0 +1,171 @@
1
+ // Purchase requests end to end: submit, guarded transitions, admin-only approve/reject (Admin + admin MCP),
2
+ // optimistic concurrency, one-transaction approval with a budget check, supplier order + signed callback, emails, cron.
3
+ import assert from "node:assert/strict";
4
+ import { createHmac } from "node:crypto";
5
+ import { createServer } from "node:http";
6
+ import { smoke } from "./smoke-kit.mjs";
7
+
8
+ const SECRET = "local-supplier-secret", DAILY = "0 9 * * *", DAY_US = 86_400 * 1_000_000;
9
+
10
+ // A stand-in supplier API: accepts an order and answers with its order id, or 503 while `supplierDown`.
11
+ const received = [];
12
+ let supplierDown = false;
13
+ const supplier = createServer((request, response) => {
14
+ let body = "";
15
+ request.on("data", chunk => { body += chunk; });
16
+ request.on("end", () => {
17
+ if (supplierDown) return response.writeHead(503).end();
18
+ received.push({ ...JSON.parse(body), idempotencyKey: request.headers["idempotency-key"] });
19
+ response.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify({ orderId: `SUP-${received.length}` }));
20
+ });
21
+ });
22
+ await new Promise(resolve => supplier.listen(0, "127.0.0.1", resolve));
23
+
24
+ try {
25
+ await smoke(async ({ owner, call, mcp, signIn, sql, cron, waitForLog, step, logs }) => {
26
+ const query = sql;
27
+ const row = async id => (await query(`SELECT requeststatus AS status, version, supplierorderid AS "supplierOrderId" FROM requests WHERE id = '${id}'`))[0];
28
+ const statusAndOrder = async id => { const { status, supplierOrderId } = await row(id); return { status, supplierOrderId }; };
29
+ const remaining = async department => (await query(`SELECT remaining FROM budgets WHERE department = '${department}'`))[0].remaining;
30
+ const ledgerRows = () => query("SELECT requestid AS \"requestId\", amount, remainingafter AS \"remainingAfter\" FROM ledger");
31
+ const operation = (cookie, name, body) => call("POST", `/admin/api/operations/${name}`, { cookie, body });
32
+ const signed = (payload, secret = SECRET) => {
33
+ const body = JSON.stringify(payload), timestamp = String(Math.floor(Date.now() / 1000));
34
+ const signature = createHmac("sha256", secret).update(`${timestamp}.${body}`).digest("hex");
35
+ return call("POST", "/callbacks/supplier", { body, headers: { "x-supplier-timestamp": timestamp, "x-supplier-signature": signature } });
36
+ };
37
+
38
+ const admin = await signIn(owner), alice = await signIn("alice@example.test"), bob = await signIn("bob@example.test");
39
+ const carol = await signIn("carol@example.test");
40
+ await query(`UPDATE "user" SET role = 'admin' WHERE email = 'carol@example.test'`);
41
+ assert.equal((await call("GET", "/admin/api/me", { cookie: carol })).status, 200);
42
+
43
+ const submit = async (cookie, title, amount, department) => {
44
+ const response = await call("POST", "/api/requests", { cookie, body: { title, amount, department } });
45
+ assert.equal(response.status, 200, JSON.stringify(response.body));
46
+ return response.body.results[0][0]?.id;
47
+ };
48
+ assert.equal((await call("POST", "/api/requests", { body: { title: "Pens", amount: 5, department: "Design" } })).status, 401);
49
+ const laptop = await submit(alice, "Laptop", 1200, "Engineering");
50
+ const monitors = await submit(alice, "Monitors", 1500, "Design");
51
+ const chairs = await submit(alice, "Chairs", 300, "Design");
52
+ const desk = await submit(bob, "Desk", 400, "Engineering");
53
+ const projector = await submit(bob, "Projector", 600, "Engineering");
54
+ assert.equal(await submit(bob, "Rocket", 10, "Space"), undefined);
55
+ assert.equal((await query("SELECT count(*) AS n FROM requests"))[0].n, 5);
56
+ const mine = (await call("GET", "/api/views/my-requests", { cookie: alice })).body.rows;
57
+ assert.deepEqual(mine.map(r => r.title).sort(), ["Chairs", "Laptop", "Monitors"]);
58
+ assert.deepEqual((await call("GET", "/api/views/my-requests", { cookie: bob })).body.rows.map(r => r.title).sort(), ["Desk", "Projector"]);
59
+ step("employees submit requests (unknown department creates nothing) and see only their own");
60
+
61
+ // fetch follows the 303, so an anonymous visitor ends on the sign-in page.
62
+ assert.match((await call("GET", "/requests")).body, /<h1>Sign in<\/h1>/);
63
+ assert.match((await call("GET", "/sign-in?return=%2Frequests")).body, /sign-in\/email-otp/);
64
+ const page = (await call("GET", "/requests", { cookie: bob })).body;
65
+ assert.match(page, /Projector/); assert.doesNotMatch(page, /Laptop/); assert.match(page, /<option>Design<\/option>/);
66
+ // Writes go through the REST Trigger the page's form names, never through the page itself.
67
+ assert.match(page, /<form action="\/api\/requests" method="post"/);
68
+ assert.equal((await call("POST", "/requests", { cookie: bob })).status, 404);
69
+ assert.equal((await call("POST", "/api/requests", { cookie: bob, body: { title: "Pens", amount: 0, department: "Design" } })).status, 400);
70
+ step("the /requests page sends anonymous visitors to /sign-in, lists only the employee's own requests and submits to the REST Trigger");
71
+
72
+ assert.equal((await operation(admin, "open-budget", { department: "Marketing", remaining: 500 })).status, 200);
73
+ assert.equal((await operation(admin, "open-budget", { department: "Design", remaining: 1 })).status, 409);
74
+ assert.equal(await remaining("Marketing"), 500);
75
+ assert.equal((await operation(alice, "open-budget", { department: "Ops", remaining: 1 })).status, 403);
76
+ step("admins open a department budget from the Budgets list header (open-budget; a second one for the same department is 409); employees cannot");
77
+
78
+ const version = async id => (await row(id)).version;
79
+ assert.equal((await operation(alice, "approve-request", { id: laptop, expectedVersion: await version(laptop) })).status, 403);
80
+ const publicTools = (await mcp("/mcp", alice)).body.result.tools.map(t => t.name);
81
+ assert.ok(!publicTools.includes("approve_request") && !publicTools.includes("reject_request"), publicTools.join());
82
+ const adminTools = (await mcp("/mcp/admin", admin)).body.result.tools.map(t => t.name);
83
+ assert.ok(adminTools.includes("approve_request") && adminTools.includes("reject_request"), adminTools.join());
84
+ for (const hidden of ["confirm_order", "mark_ordered", "approve_request_write", "reject_request_write"])
85
+ assert.ok(!adminTools.includes(hidden) && !publicTools.includes(hidden), hidden);
86
+ step("approve/reject are admin-only: an employee gets 403 in Admin and the tools exist only on /mcp/admin");
87
+
88
+ const rejected = await mcp("/mcp/admin", admin, "reject_request", { id: chairs, expectedVersion: await version(chairs) });
89
+ assert.equal(rejected.body.result.isError, undefined, JSON.stringify(rejected.body));
90
+ assert.equal((await row(chairs)).status, "rejected");
91
+ await waitForLog(/purchasing\.rejected → alice@example\.test[\s\S]*?Rejected: Chairs/);
92
+ const guarded = await operation(admin, "approve-request", { id: chairs, expectedVersion: await version(chairs) });
93
+ assert.equal(guarded.status, 409, JSON.stringify(guarded.body));
94
+ assert.equal((await row(chairs)).status, "rejected");
95
+ step("admin MCP rejects (requester emailed); approving it with its current version is 409: WHERE requestStatus = 'submitted' matched 0 rows");
96
+
97
+ const overBudget = await operation(admin, "approve-request", { id: monitors, expectedVersion: await version(monitors) });
98
+ assert.equal(overBudget.status, 409, JSON.stringify(overBudget.body));
99
+ assert.match(overBudget.body.error.message, /budget cannot cover/);
100
+ assert.equal((await row(monitors)).status, "submitted");
101
+ assert.equal(await remaining("Design"), 1000);
102
+ assert.equal((await ledgerRows()).length, 0);
103
+ step("over budget: remaining >= 0 fails statement 2, so the status change and ledger insert roll back too");
104
+
105
+ const seen = await version(monitors); // the version the admin reviewed
106
+ const generic = await call("PATCH", `/admin/api/entries/${monitors}?collection=requests`, { cookie: admin, body: { expectedVersion: seen, data: { requestStatus: "approved" } } });
107
+ assert.ok(generic.status >= 400 && generic.status < 500, JSON.stringify(generic.body));
108
+ assert.deepEqual([(await row(monitors)).status, await version(monitors)], ["submitted", seen]);
109
+ const changeAmount = (cookie, expectedVersion) => call("POST", `/api/requests/${monitors}/amount`, { cookie, body: { expectedVersion, amount: 900 } });
110
+ assert.equal((await changeAmount(bob, seen)).status, 409);
111
+ const changed = await changeAmount(alice, seen);
112
+ assert.equal(changed.status, 200, JSON.stringify(changed.body));
113
+ assert.equal((await changeAmount(alice, seen)).status, 409);
114
+ const stale = await operation(admin, "approve-request", { id: monitors, expectedVersion: seen });
115
+ assert.equal(stale.status, 409, JSON.stringify(stale.body));
116
+ assert.equal((await row(monitors)).status, "submitted");
117
+ assert.equal(await remaining("Design"), 1000);
118
+ step("Admin cannot edit requests generically; once the requester changes the amount, approving the reviewed version is 409");
119
+
120
+ const lock = (await call("GET", "/api/views/my-requests", { cookie: alice })).body.rows.find(r => r.id === laptop).version;
121
+ const race = await Promise.all([admin, carol].map(cookie => operation(cookie, "approve-request", { id: laptop, expectedVersion: lock })));
122
+ assert.deepEqual(race.map(r => r.status).sort(), [200, 409], JSON.stringify(race.map(r => r.body)));
123
+ assert.equal(await remaining("Engineering"), 3800);
124
+ assert.deepEqual(await ledgerRows(), [{ requestId: laptop, amount: 1200, remainingAfter: 3800 }]);
125
+ step("two admins approve the same version at once: one 200, one 409; the budget and ledger change once");
126
+
127
+ assert.deepEqual(received, [{ reference: laptop, item: "Laptop", amount: 1200, idempotencyKey: laptop }]);
128
+ assert.deepEqual(await row(laptop), { status: "ordered", version: lock + 2, supplierOrderId: "SUP-1" });
129
+ await waitForLog(/purchasing\.approved → alice@example\.test[\s\S]*?Approved: Laptop/);
130
+ step("approval places the supplier order (status 'ordered') and emails the requester");
131
+
132
+ supplierDown = true;
133
+ const viaAi = await mcp("/mcp/admin", admin, "approve_request", { id: desk, expectedVersion: await version(desk) });
134
+ assert.equal(viaAi.body.result.isError, undefined, JSON.stringify(viaAi.body));
135
+ assert.equal((await operation(carol, "approve-request", { id: projector, expectedVersion: await version(projector) })).status, 200);
136
+ assert.deepEqual([(await row(desk)).status, (await row(projector)).status], ["approved", "approved"]);
137
+ assert.equal(await remaining("Engineering"), 2800);
138
+ await waitForLog(/purchasing\.approved → bob@example\.test[\s\S]*?Approved: Desk/);
139
+ step("the admin MCP tool approves too; with the supplier down, approvals still commit and stay 'approved'");
140
+
141
+ assert.equal((await signed({ reference: laptop, orderId: "SUP-1" }, "wrong-secret")).status, 401);
142
+ const tampered = await call("POST", "/callbacks/supplier", { body: JSON.stringify({ reference: laptop, orderId: "SUP-1" }),
143
+ headers: { "x-supplier-timestamp": String(Math.floor(Date.now() / 1000)), "x-supplier-signature": "0".repeat(64) } });
144
+ assert.equal(tampered.status, 401);
145
+ assert.equal((await row(laptop)).status, "ordered");
146
+ assert.equal((await signed({ reference: laptop, orderId: "SUP-9" })).status, 409);
147
+ assert.equal((await signed({ reference: laptop, orderId: "SUP-1" })).status, 204);
148
+ assert.equal((await row(laptop)).status, "confirmed");
149
+ assert.equal((await signed({ reference: laptop, orderId: "SUP-1" })).status, 204);
150
+ assert.equal((await signed({ reference: monitors, orderId: "SUP-1" })).status, 409);
151
+ // The callback can beat mark-ordered: an 'approved' request is confirmed and keeps the supplier's order id.
152
+ assert.equal((await signed({ reference: desk, orderId: "SUP-EARLY" })).status, 204);
153
+ assert.deepEqual(await statusAndOrder(desk), { status: "confirmed", supplierOrderId: "SUP-EARLY" });
154
+ step("supplier callback: bad signatures are 401 with no change; a signed one confirms (also before 'ordered'); a replay is 204; a wrong order id or a submitted request is 409");
155
+
156
+ const late = await submit(bob, "Whiteboard", 150, "Engineering");
157
+ await query(`UPDATE requests SET created_at = created_at - ${4 * DAY_US} WHERE id = '${late}'`);
158
+ const before = logs().length;
159
+ supplierDown = false;
160
+ assert.equal(await cron(DAILY), 200);
161
+ for (const to of [owner, "carol@example.test"])
162
+ await waitForLog(new RegExp(`purchasing\\.reminder → ${to.replace(/[.+]/g, "\\$&")}[\\s\\S]*?Whiteboard`));
163
+ const reminder = logs().slice(before);
164
+ assert.ok(!reminder.includes("Monitors"), "a request submitted today is not in the reminder");
165
+ assert.deepEqual(received.map(order => order.reference), [laptop, projector]);
166
+ assert.deepEqual(await statusAndOrder(projector), { status: "ordered", supplierOrderId: "SUP-2" });
167
+ step("daily cron retries the failed supplier order (system caller) and emails every admin about requests pending more than 3 days, and only those");
168
+ }, { vars: { EMPLOYEE_DOMAIN: "example.test", SUPPLIER_API_URL: `http://127.0.0.1:${supplier.address().port}/orders`, SUPPLIER_WEBHOOK_SECRET: SECRET } });
169
+ } finally {
170
+ supplier.close();
171
+ }
@@ -0,0 +1,12 @@
1
+ import type { AdminExtension, AdminNavGroup } from "@aotter/mantle-admin/server/extensions";
2
+
3
+ /**
4
+ * Admin presentation, read by `mantle generate --admin-extensions src/admin.ts` (no runtime code).
5
+ * The approver's daily work gets its own sidebar group above Admin's built-in ones (content 10, operations 20,
6
+ * reports 30; More stays last); manifests place `pending-requests` and `requests` in it with `uiSchema.nav`.
7
+ * AGENT: add groups for how the staff work; titles take one string or a { locale: text } map.
8
+ */
9
+ export const navGroups: AdminNavGroup[] = [
10
+ { id: "approvals", title: { en: "Approvals", "zh-TW": "簽核" }, order: 5 },
11
+ ];
12
+ export const adminExtensions: AdminExtension[] = [];
@@ -0,0 +1,33 @@
1
+ import { ContractError } from "@aotter/mantle/contracts";
2
+ import type { Handlers } from "../generated/generated.js";
3
+ import { notifyUser } from "./notify.js";
4
+ import { placeOrder } from "./supplier.js";
5
+
6
+ type Decided = { id: string; title: string; amount: number; authorId: string };
7
+
8
+ export const handlers: Handlers = {
9
+ "approve-request": async ({ store }, input) => {
10
+ let decided: Decided;
11
+ try {
12
+ // One transaction: the guarded status change, the budget deduction and the ledger row.
13
+ decided = (await store.procedures["approve-request-write"](input)).results[0]![0] as Decided;
14
+ } catch (error) {
15
+ // The declared budget check is a business refusal, not a server error. Nothing was written.
16
+ // The approval's only Schema check is the budget one.
17
+ if (error instanceof ContractError && error.code === "CONFLICT" && error.message.startsWith("A check of the Schema failed"))
18
+ throw new ContractError("CONFLICT", "The department budget cannot cover this request.", "procedures/approve-request");
19
+ throw error;
20
+ }
21
+ // After commit: nothing below may turn the committed approval into an error response.
22
+ const ordered = await placeOrder(store, decided);
23
+ await notifyUser(decided.authorId, `Approved: ${decided.title}`,
24
+ `Your purchase request "${decided.title}" was approved${ordered ? " and ordered from the supplier" : ""}.`, "purchasing.approved");
25
+ return { id: decided.id, requestStatus: ordered ? "ordered" : "approved" };
26
+ },
27
+ "reject-request": async ({ store }, input) => {
28
+ const decided = (await store.procedures["reject-request-write"](input)).results[0]![0] as Decided;
29
+ await notifyUser(decided.authorId, `Rejected: ${decided.title}`,
30
+ `Your purchase request "${decided.title}" was rejected.`, "purchasing.rejected");
31
+ return { id: decided.id, requestStatus: "rejected" };
32
+ },
33
+ };