@aotter/mantle 0.1.5-alpha.1 → 0.2.0-alpha.10

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 (495) hide show
  1. package/README.md +166 -298
  2. package/dist/auth/adapter.d.ts +32 -0
  3. package/dist/auth/adapter.js +288 -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 +155 -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 +63 -0
  13. package/dist/auth/oauth.js +217 -0
  14. package/dist/auth/resource-seeds.js +10 -0
  15. package/dist/auth/routes.d.ts +32 -0
  16. package/dist/auth/routes.js +226 -0
  17. package/dist/build/compiler.d.ts +721 -0
  18. package/dist/build/compiler.js +7029 -0
  19. package/dist/build/spec/domain/model/ManifestGrammar.d.ts +439 -0
  20. package/dist/build/spec/domain/model/RuntimePlan.d.ts +168 -0
  21. package/dist/build/spec/domain/model/SqlIr.d.ts +129 -0
  22. package/dist/build/spec/domain/model/UserFields.d.ts +21 -0
  23. package/dist/build/spec/domain/service/PlanFingerprint.d.ts +7 -0
  24. package/dist/build/spec/kernel/diagnostic.d.ts +108 -0
  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 +57 -0
  29. package/dist/domain/describe/chunk-ZVXBGP7Y.js +424 -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 +19 -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 +230 -0
  42. package/dist/domain/recipes.js +24 -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 +188 -0
  50. package/dist/infrastructure/cli.js +118 -0
  51. package/dist/infrastructure/generate.d.ts +12 -0
  52. package/dist/infrastructure/generate.js +189 -0
  53. package/dist/infrastructure/generateAuth.d.ts +8 -0
  54. package/dist/infrastructure/generateAuth.js +74 -0
  55. package/dist/infrastructure/help.js +60 -0
  56. package/dist/infrastructure/init.js +54 -0
  57. package/dist/infrastructure/inputs.js +41 -0
  58. package/dist/infrastructure/mounts.js +25 -0
  59. package/dist/infrastructure/wrangler.js +109 -0
  60. package/dist/kernel/authorization.d.ts +4 -0
  61. package/dist/kernel/authorization.js +16 -0
  62. package/dist/kernel/binds.d.ts +60 -0
  63. package/dist/kernel/binds.js +49 -0
  64. package/dist/kernel/caller-identity.d.ts +24 -0
  65. package/dist/kernel/caller-identity.js +22 -0
  66. package/dist/kernel/contract-error.d.ts +12 -0
  67. package/dist/kernel/contract-error.js +14 -0
  68. package/dist/kernel/contracts.d.ts +143 -0
  69. package/dist/kernel/contracts.js +97 -0
  70. package/dist/kernel/cron.d.ts +1 -0
  71. package/dist/kernel/cron.js +58 -0
  72. package/dist/kernel/dialect/common.d.ts +38 -0
  73. package/dist/kernel/dialect/common.js +6 -0
  74. package/dist/kernel/dialect/postgres.d.ts +16 -0
  75. package/dist/kernel/dialect/postgres.js +18 -0
  76. package/dist/kernel/dialect/sqlite.d.ts +20 -0
  77. package/dist/kernel/dialect/sqlite.js +34 -0
  78. package/dist/kernel/drain.d.ts +5 -0
  79. package/dist/kernel/drain.js +35 -0
  80. package/dist/kernel/driver/bun-sqlite.d.ts +19 -0
  81. package/dist/kernel/driver/bun-sqlite.js +77 -0
  82. package/dist/kernel/driver/d1.d.ts +24 -0
  83. package/dist/kernel/driver/d1.js +22 -0
  84. package/dist/kernel/driver/postgres.d.ts +25 -0
  85. package/dist/kernel/driver/postgres.js +99 -0
  86. package/dist/kernel/driver/transaction-context.d.ts +10 -0
  87. package/dist/kernel/driver/transaction-context.js +29 -0
  88. package/dist/kernel/email.d.ts +28 -0
  89. package/dist/kernel/email.js +38 -0
  90. package/dist/kernel/host-access.d.ts +10 -0
  91. package/dist/kernel/host-access.js +65 -0
  92. package/dist/kernel/host-caller.d.ts +39 -0
  93. package/dist/kernel/host-caller.js +56 -0
  94. package/dist/kernel/json-body.d.ts +4 -0
  95. package/dist/kernel/json-body.js +44 -0
  96. package/dist/kernel/mcp-apps.d.ts +69 -0
  97. package/dist/kernel/mcp-apps.js +40 -0
  98. package/dist/kernel/mcp-call.d.ts +5 -0
  99. package/dist/kernel/mcp-call.js +25 -0
  100. package/dist/kernel/mcp-handler.js +371 -0
  101. package/dist/kernel/mcp.d.ts +110 -0
  102. package/dist/kernel/mcp.js +50 -0
  103. package/dist/kernel/media.d.ts +27 -0
  104. package/dist/kernel/media.js +216 -0
  105. package/dist/kernel/paging.d.ts +55 -0
  106. package/dist/kernel/paging.js +95 -0
  107. package/dist/kernel/publishing.d.ts +4 -0
  108. package/dist/kernel/publishing.js +16 -0
  109. package/dist/kernel/r2-media.d.ts +42 -0
  110. package/dist/kernel/r2-media.js +78 -0
  111. package/dist/kernel/rest-dispatch.js +38 -0
  112. package/dist/kernel/rest-router.js +64 -0
  113. package/dist/kernel/rest.d.ts +58 -0
  114. package/dist/kernel/rest.js +41 -0
  115. package/dist/kernel/scalars.d.ts +6 -0
  116. package/dist/kernel/scalars.js +44 -0
  117. package/dist/kernel/search.js +5 -0
  118. package/dist/kernel/site-types.d.ts +146 -0
  119. package/dist/kernel/site-types.js +1 -0
  120. package/dist/kernel/site.d.ts +39 -0
  121. package/dist/kernel/site.js +32 -0
  122. package/dist/kernel/store.d.ts +175 -0
  123. package/dist/kernel/store.js +269 -0
  124. package/dist/kernel/surface.d.ts +10 -0
  125. package/dist/kernel/surface.js +19 -0
  126. package/dist/kernel/sweep.d.ts +17 -0
  127. package/dist/kernel/sweep.js +27 -0
  128. package/dist/kernel/translations.d.ts +1 -0
  129. package/dist/kernel/translations.js +13 -0
  130. package/dist/kernel/user-caller.d.ts +31 -0
  131. package/dist/kernel/user-caller.js +67 -0
  132. package/dist/kernel/user-field-name.js +3 -0
  133. package/dist/kernel/user-fields.d.ts +35 -0
  134. package/dist/kernel/user-fields.js +81 -0
  135. package/dist/kernel/validation.d.ts +15 -0
  136. package/dist/kernel/validation.js +54 -0
  137. package/dist/kernel/web-gateway.js +68 -0
  138. package/dist/kernel/web-head.js +15 -0
  139. package/dist/kernel/web-index.js +40 -0
  140. package/dist/kernel/web-response.js +8 -0
  141. package/dist/kernel/web.d.ts +77 -0
  142. package/dist/kernel/web.js +124 -0
  143. package/dist/kernel/where.js +27 -0
  144. package/dist/testing/index.d.ts +1 -0
  145. package/dist/testing/index.js +1 -0
  146. package/dist/usecase/adminBindings.js +143 -0
  147. package/dist/usecase/adminClient.js +87 -0
  148. package/dist/usecase/adminDescriptors.js +107 -0
  149. package/dist/usecase/generate.js +166 -0
  150. package/dist/usecase/handlers.js +21 -0
  151. package/dist/usecase/mcp-media.js +17 -0
  152. package/dist/usecase/mcp.js +100 -0
  153. package/dist/usecase/paging.js +71 -0
  154. package/dist/usecase/publishing.js +63 -0
  155. package/dist/usecase/refusals.js +27 -0
  156. package/dist/usecase/rest.js +54 -0
  157. package/dist/usecase/search.js +7 -0
  158. package/dist/usecase/site.js +39 -0
  159. package/dist/usecase/stores.js +64 -0
  160. package/dist/usecase/tool-version.js +9 -0
  161. package/dist/usecase/translations.js +78 -0
  162. package/dist/usecase/ttl.js +20 -0
  163. package/dist/usecase/validation.js +241 -0
  164. package/dist/usecase/web.js +23 -0
  165. package/docs/examples/README.md +39 -18
  166. package/docs/examples/app-shell/.dev.vars.example +4 -0
  167. package/docs/examples/app-shell/README.md +121 -0
  168. package/docs/examples/app-shell/accept.mjs +91 -0
  169. package/docs/examples/app-shell/gitignore +7 -0
  170. package/docs/examples/app-shell/package.json +43 -0
  171. package/docs/examples/app-shell/pnpm-workspace.yaml +8 -0
  172. package/docs/examples/app-shell/smoke-kit.mjs +168 -0
  173. package/docs/examples/app-shell/src/auth.ts +58 -0
  174. package/docs/examples/app-shell/src/handlers.ts +5 -0
  175. package/docs/examples/app-shell/src/index.ts +4 -0
  176. package/docs/examples/app-shell/src/routes.ts +14 -0
  177. package/docs/examples/app-shell/src/schedule.ts +8 -0
  178. package/docs/examples/app-shell/src/service.ts +70 -0
  179. package/docs/examples/app-shell/src/sign-in.ts +41 -0
  180. package/docs/examples/app-shell/src/signup.ts +8 -0
  181. package/docs/examples/app-shell/tsconfig.json +26 -0
  182. package/docs/examples/app-shell/worker-configuration.d.ts +22 -0
  183. package/docs/examples/app-shell/wrangler.jsonc +62 -0
  184. package/docs/examples/club-events/README.md +65 -0
  185. package/docs/examples/club-events/manifests/club-events.yaml +247 -0
  186. package/docs/examples/club-events/smoke.mjs +127 -0
  187. package/docs/examples/club-events/src/handlers.ts +25 -0
  188. package/docs/examples/club-events/src/signup.ts +9 -0
  189. package/docs/examples/generated-web/README.md +78 -0
  190. package/docs/examples/generated-web/posts.yaml +38 -0
  191. package/docs/examples/generated-web/seed.sql +6 -0
  192. package/docs/examples/generated-web/src/worker.ts +43 -0
  193. package/docs/examples/generated-web/tsconfig.json +8 -0
  194. package/docs/examples/generated-web/wrangler.jsonc +8 -0
  195. package/docs/examples/purchasing/.dev.vars.example +6 -0
  196. package/docs/examples/purchasing/README.md +99 -0
  197. package/docs/examples/purchasing/manifests/purchasing.yaml +374 -0
  198. package/docs/examples/purchasing/seed.sql +4 -0
  199. package/docs/examples/purchasing/smoke.mjs +191 -0
  200. package/docs/examples/purchasing/src/admin.tsx +13 -0
  201. package/docs/examples/purchasing/src/handlers.ts +33 -0
  202. package/docs/examples/purchasing/src/notify.ts +29 -0
  203. package/docs/examples/purchasing/src/requests-page.ts +57 -0
  204. package/docs/examples/purchasing/src/routes.ts +53 -0
  205. package/docs/examples/purchasing/src/schedule.ts +31 -0
  206. package/docs/examples/purchasing/src/signup.ts +5 -0
  207. package/docs/examples/purchasing/src/supplier.ts +32 -0
  208. package/docs/examples/purchasing/wrangler.jsonc +69 -0
  209. package/docs/examples/recipes/README.md +60 -0
  210. package/docs/examples/recipes/manifests/recipes.yaml +75 -0
  211. package/docs/examples/recipes/smoke.mjs +102 -0
  212. package/docs/examples/recipes/src/media.ts +13 -0
  213. package/docs/examples/recipes/src/pages.ts +99 -0
  214. package/docs/examples/recipes/src/routes.ts +71 -0
  215. package/docs/examples/recipes/src/site-config.ts +12 -0
  216. package/docs/examples/recipes/wrangler.jsonc +74 -0
  217. package/docs/handbook/cloudflare/authentication.md +180 -322
  218. package/docs/handbook/cloudflare/chatgpt-sites.md +5 -23
  219. package/docs/handbook/cloudflare/deploy-and-operate.md +55 -77
  220. package/docs/handbook/cloudflare/media-r2.md +61 -205
  221. package/docs/handbook/cloudflare/service-entry.md +239 -0
  222. package/docs/handbook/concepts/authorization.md +10 -107
  223. package/docs/handbook/concepts/four-atoms.md +9 -168
  224. package/docs/handbook/concepts/lifecycle-and-locales.md +9 -132
  225. package/docs/handbook/concepts/mcp-and-agents.md +24 -121
  226. package/docs/handbook/concepts/procedures-and-triggers.md +5 -217
  227. package/docs/handbook/concepts/runtime-and-adapters.md +15 -169
  228. package/docs/handbook/concepts/views.md +10 -185
  229. package/docs/handbook/examples/hub.md +3 -8
  230. package/docs/handbook/guides/adapter-guide.md +11 -0
  231. package/docs/handbook/guides/admin-ui.md +115 -133
  232. package/docs/handbook/guides/agent-setup.md +64 -74
  233. package/docs/handbook/guides/agent-workflow-acceptance.md +232 -0
  234. package/docs/handbook/guides/email.md +86 -0
  235. package/docs/handbook/guides/local-testing.md +40 -0
  236. package/docs/handbook/guides/mcp-apps.md +560 -0
  237. package/docs/handbook/guides/native-admin.md +566 -0
  238. package/docs/handbook/guides/native-execution.md +133 -0
  239. package/docs/handbook/guides/oauth.md +219 -0
  240. package/docs/handbook/guides/postgres-adapters.md +56 -0
  241. package/docs/handbook/guides/public-pages.md +87 -0
  242. package/docs/handbook/guides/size-and-startup.md +9 -0
  243. package/docs/handbook/guides/sql-patterns.md +266 -0
  244. package/docs/handbook/guides/typed-queries.md +211 -107
  245. package/docs/handbook/navigation.json +176 -55
  246. package/docs/handbook/reference/admin-descriptors.md +53 -0
  247. package/docs/handbook/reference/authorization.md +39 -266
  248. package/docs/handbook/reference/describe.md +56 -0
  249. package/docs/handbook/reference/diagnostics.md +19 -186
  250. package/docs/handbook/reference/features.md +45 -55
  251. package/docs/handbook/reference/manifest.md +6 -129
  252. package/docs/handbook/reference/procedure.md +11 -303
  253. package/docs/handbook/reference/schema.md +64 -240
  254. package/docs/handbook/reference/site-config.md +5 -218
  255. package/docs/handbook/reference/sql.md +64 -0
  256. package/docs/handbook/reference/surface.md +392 -201
  257. package/docs/handbook/reference/trigger.md +56 -192
  258. package/docs/handbook/reference/view.md +24 -243
  259. package/docs/handbook/releases/index.md +244 -77
  260. package/docs/handbook/start/agents.md +45 -0
  261. package/docs/handbook/start/overview.md +9 -48
  262. package/docs/handbook/start/project-and-cli.md +51 -104
  263. package/docs/handbook/start/quickstart-worker.md +43 -178
  264. package/docs/skills/develop/SKILL.md +79 -249
  265. package/docs/skills/integrate/SKILL.md +39 -50
  266. package/docs/skills/media-gc/SKILL.md +34 -10
  267. package/docs/skills/provision/SKILL.md +36 -186
  268. package/docs/skills/update/SKILL.md +23 -38
  269. package/docs/source/scripts/postgres-adapter.ts +101 -0
  270. package/docs/upgrade-0.1-to-0.2.md +227 -0
  271. package/package.json +120 -131
  272. package/skills/README.md +48 -108
  273. package/skills/mantle/SKILL.md +76 -0
  274. package/dist/admin-ui.d.ts +0 -2
  275. package/dist/admin-ui.d.ts.map +0 -1
  276. package/dist/admin-ui.js +0 -2
  277. package/dist/admin-ui.js.map +0 -1
  278. package/dist/admin.d.ts +0 -2
  279. package/dist/admin.d.ts.map +0 -1
  280. package/dist/admin.js +0 -2
  281. package/dist/admin.js.map +0 -1
  282. package/dist/auth.d.ts +0 -2
  283. package/dist/auth.d.ts.map +0 -1
  284. package/dist/auth.js +0 -2
  285. package/dist/auth.js.map +0 -1
  286. package/dist/bun.d.ts +0 -2
  287. package/dist/bun.d.ts.map +0 -1
  288. package/dist/bun.js +0 -2
  289. package/dist/bun.js.map +0 -1
  290. package/dist/cli/generate-cloudflare.d.ts +0 -7
  291. package/dist/cli/generate-cloudflare.d.ts.map +0 -1
  292. package/dist/cli/generate-cloudflare.js +0 -123
  293. package/dist/cli/generate-cloudflare.js.map +0 -1
  294. package/dist/cli/generate-project.d.ts +0 -25
  295. package/dist/cli/generate-project.d.ts.map +0 -1
  296. package/dist/cli/generate-project.js +0 -282
  297. package/dist/cli/generate-project.js.map +0 -1
  298. package/dist/cli/generate-sites.d.ts +0 -8
  299. package/dist/cli/generate-sites.d.ts.map +0 -1
  300. package/dist/cli/generate-sites.js +0 -273
  301. package/dist/cli/generate-sites.js.map +0 -1
  302. package/dist/cli/generate.d.ts +0 -20
  303. package/dist/cli/generate.d.ts.map +0 -1
  304. package/dist/cli/generate.js +0 -299
  305. package/dist/cli/generate.js.map +0 -1
  306. package/dist/cli/harness.d.ts +0 -3
  307. package/dist/cli/harness.d.ts.map +0 -1
  308. package/dist/cli/harness.js +0 -214
  309. package/dist/cli/harness.js.map +0 -1
  310. package/dist/cli/main.d.ts +0 -3
  311. package/dist/cli/main.d.ts.map +0 -1
  312. package/dist/cli/main.js +0 -77
  313. package/dist/cli/main.js.map +0 -1
  314. package/dist/cli/skills.d.ts +0 -3
  315. package/dist/cli/skills.d.ts.map +0 -1
  316. package/dist/cli/skills.js +0 -128
  317. package/dist/cli/skills.js.map +0 -1
  318. package/dist/cloudflare.d.ts +0 -2
  319. package/dist/cloudflare.d.ts.map +0 -1
  320. package/dist/cloudflare.js +0 -2
  321. package/dist/cloudflare.js.map +0 -1
  322. package/dist/codegen/emitMantleModule.d.ts +0 -22
  323. package/dist/codegen/emitMantleModule.d.ts.map +0 -1
  324. package/dist/codegen/emitMantleModule.js +0 -291
  325. package/dist/codegen/emitMantleModule.js.map +0 -1
  326. package/dist/codegen.d.ts +0 -2
  327. package/dist/codegen.d.ts.map +0 -1
  328. package/dist/codegen.js +0 -2
  329. package/dist/codegen.js.map +0 -1
  330. package/dist/runtime-testing.d.ts +0 -2
  331. package/dist/runtime-testing.d.ts.map +0 -1
  332. package/dist/runtime-testing.js +0 -2
  333. package/dist/runtime-testing.js.map +0 -1
  334. package/dist/runtime.d.ts +0 -2
  335. package/dist/runtime.d.ts.map +0 -1
  336. package/dist/runtime.js +0 -2
  337. package/dist/runtime.js.map +0 -1
  338. package/dist/spec.d.ts +0 -2
  339. package/dist/spec.d.ts.map +0 -1
  340. package/dist/spec.js +0 -2
  341. package/dist/spec.js.map +0 -1
  342. package/dist/vercel-libsql.d.ts +0 -2
  343. package/dist/vercel-libsql.d.ts.map +0 -1
  344. package/dist/vercel-libsql.js +0 -2
  345. package/dist/vercel-libsql.js.map +0 -1
  346. package/dist/vercel.d.ts +0 -2
  347. package/dist/vercel.d.ts.map +0 -1
  348. package/dist/vercel.js +0 -2
  349. package/dist/vercel.js.map +0 -1
  350. package/dist/web.d.ts +0 -2
  351. package/dist/web.d.ts.map +0 -1
  352. package/dist/web.js +0 -2
  353. package/dist/web.js.map +0 -1
  354. package/docs/adapter-guide.md +0 -222
  355. package/docs/adr/0001-four-atom-manifest-model.md +0 -440
  356. package/docs/adr/0002-closed-enums-for-bindings.md +0 -253
  357. package/docs/adr/0007-ai-as-primary-author.md +0 -473
  358. package/docs/adr/0008-structured-diagnostic-shape.md +0 -338
  359. package/docs/adr/0009-consumer-supplied-manifests.md +0 -149
  360. package/docs/adr/0010-locale-and-translates.md +0 -453
  361. package/docs/adr/0011-adapter-port-spec.md +0 -281
  362. package/docs/adr/0012-views-as-public-rest.md +0 -161
  363. package/docs/adr/0013-agent-provisioned-consumer-projects.md +0 -154
  364. package/docs/adr/0014-auth-better-auth-and-multi-tenant-mcp.md +0 -900
  365. package/docs/adr/0016-site-semantic-layer.md +0 -70
  366. package/docs/adr/0017-media-multi-variant-agent-side-optimization.md +0 -181
  367. package/docs/adr/0018-core-starters-repository-boundary.md +0 -179
  368. package/docs/adr/0019-sealed-manifest-runtime-pipeline.md +0 -240
  369. package/docs/adr/0020-builtin-handler-contracts-and-matched-upsert.md +0 -199
  370. package/docs/adr/0021-retire-starter-scaffolding.md +0 -30
  371. package/docs/adr/0022-caller-observed-version-occ.md +0 -212
  372. package/docs/adr/0023-port-failure-contract.md +0 -69
  373. package/docs/adr/0024-manifest-native-schema-tables.md +0 -264
  374. package/docs/adr/0025-reserved-native-columns-and-published-only-public-views.md +0 -105
  375. package/docs/adr/0026-progressive-generate.md +0 -36
  376. package/docs/adr/0027-scheduled-procedure-triggers.md +0 -31
  377. package/docs/adr/0028-schema-ttl-expiry.md +0 -33
  378. package/docs/adr/README.md +0 -81
  379. package/docs/adr/adr-lite-803-request-diagnostics.md +0 -38
  380. package/docs/adr/adr-lite-808-route-readiness.md +0 -47
  381. package/docs/adr/adr-lite-809-bounded-public-content.md +0 -71
  382. package/docs/adr/adr-lite-812-native-parity.md +0 -150
  383. package/docs/adr/adr-lite-823-home-statistics.md +0 -64
  384. package/docs/adr/adr-lite-842-mcp-authoring.md +0 -30
  385. package/docs/adr/adr-lite-845-frontend-client.md +0 -38
  386. package/docs/adr/adr-lite-861-admin-webmcp.md +0 -42
  387. package/docs/adr/adr-lite-909-admin-ui-kit.md +0 -37
  388. package/docs/agent-prompts.md +0 -64
  389. package/docs/api-mcp-authorization.md +0 -5
  390. package/docs/assets/mantle-admin-developer.png +0 -0
  391. package/docs/assets/mantle-admin-operations.png +0 -0
  392. package/docs/assets/mantle-hero.jpg +0 -0
  393. package/docs/auth-hosting-model.md +0 -166
  394. package/docs/cloudflare-low-level-composition.md +0 -5
  395. package/docs/consumer-onboarding-audit.md +0 -65
  396. package/docs/deferred-lifecycle-queues.md +0 -5
  397. package/docs/design-atoms.md +0 -16
  398. package/docs/design-references/editorial-blog-2026-05-05.md +0 -218
  399. package/docs/direct-authoring.md +0 -5
  400. package/docs/examples/builtin-commerce.md +0 -269
  401. package/docs/examples/builtin-intake.md +0 -143
  402. package/docs/examples/builtin-legal-documents.md +0 -189
  403. package/docs/examples/builtin-procurement.md +0 -241
  404. package/docs/examples/builtin-publication.md +0 -241
  405. package/docs/examples/builtin-reservation.md +0 -149
  406. package/docs/examples/cf-primitives-commerce-inventory.md +0 -809
  407. package/docs/examples/cf-primitives-guarded-api.md +0 -429
  408. package/docs/examples/cf-primitives-intake-hooks.md +0 -319
  409. package/docs/examples/host-chatgpt-sites/.openai/hosting.json +0 -1
  410. package/docs/examples/host-chatgpt-sites/README.md +0 -70
  411. package/docs/examples/host-chatgpt-sites/drizzle/0000_sites_users.sql +0 -8
  412. package/docs/examples/host-chatgpt-sites/drizzle/0001_mantle.sql +0 -294
  413. package/docs/examples/host-chatgpt-sites/drizzle/0002_article_cover.sql +0 -5
  414. package/docs/examples/host-chatgpt-sites/drizzle/0003_store_instance_id.sql +0 -1
  415. package/docs/examples/host-chatgpt-sites/drizzle/0004_mantle.sql +0 -10
  416. package/docs/examples/host-chatgpt-sites/drizzle/0005_mantle.sql +0 -24
  417. package/docs/examples/host-chatgpt-sites/drizzle/meta/_journal.json +0 -1
  418. package/docs/examples/host-chatgpt-sites/drizzle/meta/mantle-state.json +0 -60
  419. package/docs/examples/host-chatgpt-sites/manifests/site.yaml +0 -27
  420. package/docs/examples/host-chatgpt-sites/package.json +0 -1
  421. package/docs/examples/host-chatgpt-sites/public/site.css +0 -1
  422. package/docs/examples/host-chatgpt-sites/scripts/build.mjs +0 -13
  423. package/docs/examples/host-chatgpt-sites/scripts/check.mjs +0 -101
  424. package/docs/examples/host-chatgpt-sites/scripts/migration.mjs +0 -43
  425. package/docs/examples/host-chatgpt-sites/src/chatgpt-auth.ts +0 -66
  426. package/docs/examples/host-chatgpt-sites/src/index.ts +0 -46
  427. package/docs/examples/host-chatgpt-sites/src/mcp.ts +0 -49
  428. package/docs/examples/host-chatgpt-sites/src/media.ts +0 -109
  429. package/docs/examples/host-chatgpt-sites/src/r2-lab.ts +0 -38
  430. package/docs/examples/host-chatgpt-sites/src/storage-fingerprint.json +0 -1
  431. package/docs/examples/host-chatgpt-sites/src/web.ts +0 -35
  432. package/docs/examples/host-chatgpt-sites/tsconfig.json +0 -1
  433. package/docs/examples/host-chatgpt-sites/wrangler.jsonc +0 -10
  434. package/docs/examples/host-local-admin-otp/.dev.vars.example +0 -3
  435. package/docs/examples/host-local-admin-otp/README.md +0 -80
  436. package/docs/examples/host-local-admin-otp/ensure-dev-vars.mjs +0 -5
  437. package/docs/examples/host-local-admin-otp/manifests/site.yaml +0 -25
  438. package/docs/examples/host-local-admin-otp/package.json +0 -29
  439. package/docs/examples/host-local-admin-otp/public/.gitkeep +0 -1
  440. package/docs/examples/host-local-admin-otp/smoke.mjs +0 -141
  441. package/docs/examples/host-local-admin-otp/src/index.ts +0 -54
  442. package/docs/examples/host-local-admin-otp/tsconfig.json +0 -17
  443. package/docs/examples/host-local-admin-otp/wrangler.jsonc +0 -23
  444. package/docs/examples/host-minimal-worker/README.md +0 -41
  445. package/docs/examples/host-minimal-worker/manifests/site.yaml +0 -25
  446. package/docs/examples/host-minimal-worker/package.json +0 -26
  447. package/docs/examples/host-minimal-worker/smoke.mjs +0 -23
  448. package/docs/examples/host-minimal-worker/src/index.ts +0 -4
  449. package/docs/examples/host-minimal-worker/tsconfig.json +0 -17
  450. package/docs/examples/host-minimal-worker/wrangler.jsonc +0 -22
  451. package/docs/handbook/chatgpt-sites/equipment-checkout.md +0 -231
  452. package/docs/handbook/chatgpt-sites/generated-app.md +0 -84
  453. package/docs/handbook/chatgpt-sites/host-reference.md +0 -113
  454. package/docs/handbook/chatgpt-sites/index.md +0 -133
  455. package/docs/handbook/cloudflare/bindings.md +0 -291
  456. package/docs/handbook/cloudflare/conventional-worker.md +0 -166
  457. package/docs/handbook/cloudflare/deferred-hooks-queues.md +0 -170
  458. package/docs/handbook/cloudflare/low-level-composition.md +0 -169
  459. package/docs/handbook/cloudflare/public-web.md +0 -144
  460. package/docs/handbook/cloudflare/site-chrome.md +0 -75
  461. package/docs/handbook/examples/commerce-transaction.md +0 -11
  462. package/docs/handbook/examples/commerce.md +0 -11
  463. package/docs/handbook/examples/guarded-api.md +0 -10
  464. package/docs/handbook/examples/intake-form.md +0 -12
  465. package/docs/handbook/examples/intake-hooks.md +0 -11
  466. package/docs/handbook/examples/legal-documents.md +0 -10
  467. package/docs/handbook/examples/procurement-approvals.md +0 -10
  468. package/docs/handbook/examples/publication.md +0 -10
  469. package/docs/handbook/examples/reservation.md +0 -10
  470. package/docs/handbook/start/quickstart-admin.md +0 -52
  471. package/docs/labels.md +0 -71
  472. package/docs/media-uploads.md +0 -5
  473. package/docs/migration-0.1.2.md +0 -13
  474. package/docs/performance-harness.md +0 -228
  475. package/docs/release-process.md +0 -244
  476. package/docs/schema-indexes.md +0 -5
  477. package/docs/sealed-pipeline-ownership.md +0 -101
  478. package/docs/skills/plugin/SKILL.md +0 -132
  479. package/docs/skills/theme/SKILL.md +0 -77
  480. package/docs/spec-only-host-adoption.md +0 -157
  481. package/docs/transaction-patterns.md +0 -5
  482. package/skills/develop/SKILL.md +0 -258
  483. package/skills/install/SKILL.md +0 -112
  484. package/skills/integrate/SKILL.md +0 -60
  485. package/skills/media-gc/SKILL.md +0 -85
  486. package/skills/plugin/SKILL.md +0 -132
  487. package/skills/provision/SKILL.md +0 -194
  488. package/skills/theme/SKILL.md +0 -77
  489. package/skills/update/SKILL.md +0 -51
  490. package/templates/chatgpt-sites/auth.ts +0 -66
  491. package/templates/chatgpt-sites/build.mjs +0 -14
  492. package/templates/chatgpt-sites/env.ts +0 -1
  493. package/templates/chatgpt-sites/mcp.ts +0 -48
  494. package/templates/chatgpt-sites/public-mcp.ts +0 -29
  495. package/templates/chatgpt-sites/smoke-local.mjs +0 -20
@@ -1,104 +1,82 @@
1
1
  ---
2
- description: Production checklist, the check loop, deploy and post-deploy probes, day-to-day content operations, and version pins.
2
+ description: Install schema explicitly, migrate before deploying, and operate a native Worker.
3
3
  ---
4
4
  # Deploy and operate
5
5
 
6
- This page is the production checklist for a Mantle Worker on Cloudflare: what to pin and configure, which checks to run before `wrangler deploy`, how to verify a deployment, how content is operated afterwards, and how to move versions.
6
+ Run the same generation command with `--check`, typecheck the application and test its selected routes before deploying. Keep generated TypeScript, SQL and Wrangler edits committed; keep bundle `dist/` untracked. The app owns the database, auth secrets, trusted origin and assets.
7
7
 
8
- ## Before the first deploy
8
+ ## Public fetch routing
9
9
 
10
- - Pin every `@aotter/mantle*` package to one exact version and commit the lockfile. Install with `pnpm install --frozen-lockfile` (or `npm ci`) from then on. See [Project and CLI](../start/project-and-cli.md).
11
- - Set `PUBLIC_ORIGIN` to the real HTTPS origin, without a trailing slash. It drives canonical URLs, `.md` mirrors, `llms.txt`, the MCP resource and the OAuth callback. If a static documentation build also emits absolute URLs, give it the same value.
12
- - Set the production D1 `database_id` (and `account_id` if your deployment needs it) in `wrangler.jsonc`. A local `database_name` is not a production identifier, and local D1 is not production data.
13
- - Choose production Auth: a generated CF app uses `MANTLE_AUTH_MODE=self-managed` or `hosted` with `ADMIN_GITHUB_LOGIN` and the matching provider credentials. Local `local-otp` works only on loopback. If you author your own Worker Auth factory, replace console email delivery with a real `EmailSender`. Store secrets with `wrangler secret put`. See [Authentication](./authentication.md).
14
- - Keep `compatibility_flags: ["nodejs_compat", "global_fetch_strictly_public"]`.
15
- - Enable observability:
10
+ Workers use `compatibility_flags: ["nodejs_compat", "global_fetch_strictly_public"]`.
11
+ The public-fetch flag routes native `fetch` through Cloudflare's public Internet
12
+ boundary. OAuth verification needs it to fetch JWKS on the service's own public
13
+ hostname; CIMD also requires this boundary for client metadata. `nodejs_compat`
14
+ alone does not establish it.
16
15
 
17
- ```jsonc
18
- "observability": { "enabled": true, "logs": { "head_sampling_rate": 1 } },
19
- "upload_source_maps": true
20
- ```
21
-
22
- ## The check loop
16
+ `mantle generate cloudflare-*` adds these flags without replacing other flags,
17
+ including in environments with their own `compatibility_flags` array. The same
18
+ command with `--check` refuses missing flags without writing. JSON/JSONC configs
19
+ are updated; TOML receives manual-edit instructions. Keep both flags in every
20
+ TOML environment override. An explicit `global_fetch_private_origin` is preserved
21
+ for applications without OAuth/CIMD, but conflicts with selected OAuth/CIMD auth
22
+ and with the public-fetch flag: generation refuses that config without rewriting
23
+ it. Such applications must use public routing for their OAuth/CIMD transport.
23
24
 
24
- Run the project's `check` script before every deploy. The minimal reference chains:
25
+ After deployment, complete a real OAuth sign-in and use the resulting bearer
26
+ for MCP `initialize` and `tools/list`. Local development and cookie-only Admin
27
+ checks do not verify production public-hostname routing.
25
28
 
26
- ```sh
27
- mantle generate && mantle generate --check && mantle validate \
28
- && mantle skills && mantle skills --check && tsc --noEmit && node smoke.mjs
29
- ```
30
-
31
- Add tests and the frontend build where the project has them, then confirm index coverage for every public View:
29
+ ## Install and change schemas
32
30
 
33
- ```sh
34
- pnpm exec mantle-harness indexes --require-public --format text
35
- ```
31
+ The runtime never creates, alters or checks tables. Boot and requests run no DDL, introspection or schema checks.
36
32
 
37
- A required path fails on a required Schema-table scan, a temporary sort or an unindexed data-field predicate. Then dry-run and deploy:
33
+ For the first install, apply generated `schema.sql`, including selected auth/site DDL, to an empty database. Apply selected seed SQL explicitly.
38
34
 
39
- This local SQLite check intentionally runs without planner statistics. Treat it
40
- as a conservative preflight; use post-deploy D1 metrics for production cost and
41
- latency claims.
35
+ For every later schema change, the application's coding agent diffs the regenerated `schema.sql`, writes a migration with the host's native tool (`wrangler d1 migrations` or the app's PostgreSQL migration tool), rehearses it on a copy, and applies it before deploying the new code.
42
36
 
43
- ```sh
44
- wrangler deploy --dry-run
45
- wrangler deploy
46
- ```
37
+ Destructive changes and type changes need explicit data migration. Mantle drops nothing. Initial `schema.sql` is not an upgrade script.
47
38
 
48
- ## Post-deploy verification
39
+ For D1, create a migration with `pnpm exec wrangler d1 migrations create <database> <name>`, review its SQL, then rehearse `pnpm exec wrangler d1 migrations apply <database> --local` against copied data. Apply the reviewed migrations to the target before `wrangler deploy`. Initial DDL may be placed in the first migration for a new database.
49
40
 
50
- Probe the deployed origin, not `wrangler dev`. Run only the probes for surfaces
51
- the application mounts and configures:
41
+ For PostgreSQL, use the app's migration tool and deployment credentials. Plan lock waits and long index builds there; request credentials need no DDL privileges. Configure session settings on the role/database as described in [native execution](../guides/native-execution.md#postgresql-settings). Hyperdrive query caching must be disabled for authority and mutation visibility.
52
42
 
53
- | Probe | Expect |
54
- |---|---|
55
- | `GET /api/views/<public-view>` | `200`, `{ "ok": true, "data": { "rows": [...] } }` |
56
- | `GET /<locale>/<segment>/<slug>` and `GET /<locale>/<segment>/<slug>.md` | `200` HTML and Markdown for a published entry |
57
- | `GET /llms.txt`, `GET /sitemap.xml`, `GET /robots.txt` | `200` |
58
- | `GET /<locale>/<segment>/does-not-exist` | `404` from your `notFoundRenderer` |
59
- | `POST /mcp/staff` without credentials | `401` with `WWW-Authenticate`; `GET /mcp` is `405` |
60
- | `GET /admin` | Sign-in page; sign in with the `ADMIN_GITHUB_LOGIN` account |
43
+ ## Latency placement and D1 read replication
61
44
 
62
- Then check the cache: a second anonymous `GET` of a public page should show `cf-cache-status: HIT`; publish a change in Admin and the next request should be a `MISS`. Sample latency with:
45
+ Measure these options against the application's real traffic; neither is a
46
+ default latency guarantee. [Smart Placement](https://developers.cloudflare.com/workers/configuration/placement/)
47
+ can move fetch execution closer to observed back-end services:
63
48
 
64
- ```sh
65
- pnpm exec mantle-harness http --base-url https://example.com \
66
- --route recent=/api/views/recent-posts --route page=/en/posts/hello --rounds 20 --warmup 2
49
+ ```jsonc
50
+ "placement": { "mode": "smart" }
67
51
  ```
68
52
 
69
- ## Operating content
70
-
71
- Sign in to Admin with a staff account. Publishing collections (`lifecycle: publishing`) follow draft, publish, verify:
53
+ For globally distributed, read-heavy D1 traffic, enable
54
+ [read replication](https://developers.cloudflare.com/d1/best-practices/read-replication/)
55
+ on the database and pass one request-scoped `env.DB.withSession(...)` handle to
56
+ the selected generated Views, Procedures and Store. Those D1 entry points accept
57
+ `D1DatabaseSession`. Without the Sessions API, queries continue to use the primary.
72
58
 
73
- 1. Create a draft with its title, slug, locale and body.
74
- 2. Publish (`editor` or above). The write purges the deployment-scoped public cache tag.
75
- 3. Open the public URL and its `.md` mirror. Drafts never appear on pages, mirrors, `llms.txt` or the sitemap; use `?preview=1` with a staff session to see one.
76
- 4. Unpublish removes the entry from every public surface; the Admin delete action and the Staff MCP `archive_entry` tool retire it.
59
+ Use `first-unconstrained` only when a replica snapshot is acceptable,
60
+ `first-primary` when the flow must start from the latest primary state, or carry
61
+ a bookmark between logical sessions for sequential consistency. Reuse the same
62
+ session within that logical flow; all writes still go to the primary. Keep fresh
63
+ authentication/authorization checks and mutation/read-after-write paths on their
64
+ required current-authority path rather than weakening them for replica latency.
77
65
 
78
- Operational collections (`lifecycle: operational`) have no publish step; records are edited in place and do not purge the public cache. The same operations are available to agents through Staff MCP; see [MCP and agents](../concepts/mcp-and-agents.md).
66
+ ## Operate
79
67
 
80
- Site settings split by owner. Brand, title and description seed once from `siteDefaults` and are then edited in Admin (`owner`); each edit purges the public cache. Origin, icons, locales and media purposes are code-owned and re-sync from `siteDefaults` on every boot, so change them in the Worker and redeploy. Analytics, pixels and search-engine verification are host chrome, not Core settings; see [Site chrome](./site-chrome.md) and [Site config](../reference/site-config.md).
68
+ Enable Workers Logs and traces in production. The top-level `observability.enabled` alone does not enable traces:
81
69
 
82
- ## Changing versions
83
-
84
- Pin every selected `@aotter/mantle*` package to one exact version and keep them together. This handbook describes the snapshot in this source tree; use the docs that ship with the version you install.
70
+ ```jsonc
71
+ "observability": {
72
+ "enabled": true,
73
+ "logs": { "enabled": true, "head_sampling_rate": 1 },
74
+ "traces": { "enabled": true, "head_sampling_rate": 0.01 }
75
+ }
76
+ ```
85
77
 
86
- 1. Pin the new exact release for every selected package and update the lockfile through the package manager; review peer ranges.
87
- 2. Keep application source, Worker/D1/KV identity, origins, auth mode and secrets.
88
- 3. Run `mantle generate`, `generate --check`, `skills`, `skills --check`, `validate`, typecheck and tests.
89
- 4. Test local routes and authorization, then deploy.
78
+ Auth configuration and production email delivery are app-owned; follow [authentication](authentication.md). Keep secrets in the platform's secret store. With `secrets.required`, `wrangler deploy` refuses to upload while a required secret is unset: set them with `wrangler secret put` (or pass `--secrets-file` on the first deploy). Serve the selected Admin assets through the [native Admin](../guides/native-admin.md) shell contract.
90
79
 
91
- Each Manifest Schema is a native table. Safe additive storage changes deploy online. Destructive changes — including any `uniqueIndexes` tuple add, remove, reorder or rewrite — are rejected; rebuild the instance and move required data outside Mantle. There is no in-product data-move workflow.
80
+ Scheduling is app-owned. Wire generated system-only TTL sweeps into `scheduled()` and configure Wrangler crons explicitly. Bound each invocation and retain a cursor if work remains; see [TTL maintenance](../guides/native-execution.md#ttl-maintenance). Expired rows remain stored and hold unique keys until removed.
92
81
 
93
- ## Source
94
- - [`packages/mantle/README.md`](../../../packages/mantle/README.md)
95
- - [`packages/adapters/cloudflare/README.md`](../../../packages/adapters/cloudflare/README.md)
96
- - [`docs/direct-authoring.md`](../../../docs/direct-authoring.md)
97
- - [`docs/performance-harness.md`](../../../docs/performance-harness.md)
98
- - [`docs/examples/host-minimal-worker/README.md`](../../../docs/examples/host-minimal-worker/README.md)
99
- - [`docs/examples/host-minimal-worker/package.json`](../../../docs/examples/host-minimal-worker/package.json)
100
- - [`docs/examples/host-minimal-worker/wrangler.jsonc`](../../../docs/examples/host-minimal-worker/wrangler.jsonc)
101
- - [`docs/examples/host-minimal-worker/smoke.mjs`](../../../docs/examples/host-minimal-worker/smoke.mjs)
102
- - [`packages/mantle-spec/src/domain/model/SiteConfig.ts`](../../../packages/mantle-spec/src/domain/model/SiteConfig.ts)
103
- - [`packages/mantle-admin/src/mountMantleAdmin.ts`](../../../packages/mantle-admin/src/mountMantleAdmin.ts)
104
- - [`packages/adapters/cloudflare/src/oauth/cachePolicy.ts`](../../../packages/adapters/cloudflare/src/oauth/cachePolicy.ts)
82
+ After deployment, verify public and protected reads, member/admin sign-in, a persisted write, stale OCC and selected MCP/Admin/web routes. An `OUTCOME_UNKNOWN` write may have committed; reconcile before deciding what to do next and never retry automatically.
@@ -1,216 +1,72 @@
1
- ---
2
- description: Enable staff media uploads on R2 — presigned PUT flow through Staff MCP, media purposes, wrangler config, commit cost and cleanup.
3
- ---
4
- # Media uploads with R2
1
+ # Optional site settings and media
5
2
 
6
- R2-backed media is an optional post-launch capability for Workers whose staff or agents need to upload images and files. This page covers the native Cloudflare direct-to-R2 flow, the configuration it needs, how a Schema references an asset, what a commit costs, and how to clean up. For ChatGPT Sites with an R2 binding but no S3 credentials, use [the same-origin Worker flow](../chatgpt-sites/host-reference.md#media-with-only-an-r2-binding).
3
+ Declare a TypeScript `siteDefaults` object using the 0.2 `SiteDefaults` shape and
4
+ pass it to generation, or use `mantle generate ... --site ./site-config.ts`.
5
+ Apply the emitted `schema.sql` to a new database; apply idempotent `site-seed.sql`
6
+ on subsequent deployments to seed only absent operator fields. Import `site` from the generated
7
+ `site` module; call `site(db, verifiedCaller).read()`, `.updateSettings({brand,title,
8
+ description})`, or `.media(storage)` to access the library. Construction runs no
9
+ queries, migrations, seeds, or storage work. The library accepts verified admin
10
+ Callers of any credential kind; the Admin handler must additionally keep its
11
+ cookie-session-only gate and the shared session-mutation origin check. The optional module is absent from
12
+ a Worker that does not import it.
7
13
 
8
- ## When to enable it
9
-
10
- Turn this on only after the site already has a working deploy, staff auth configured, and a real need for staff-managed media. R2 setup may require billing, so it is deliberately not part of the first-deploy path. Everything on this page is inert until the bucket, credentials and at least one media purpose all exist.
11
-
12
- Media maintenance also needs an agent that can read local files, process images and make outbound `PUT` requests to `*.r2.cloudflarestorage.com`. A sandboxed agent without egress cannot finish the flow.
13
-
14
- ## The upload flow
15
-
16
- ```txt
17
- 1. create_media_upload staff MCP -> purpose, variants, mime types, byte sizes
18
- 2. Mantle -> signed upload URLs + required headers
19
- 3. agent or browser -> PUT bytes directly to R2
20
- 4. commit_media_upload staff MCP -> validate, stamp, save the asset row
21
- ```
22
-
23
- Bytes travel from the agent to R2 over a signed URL; the Worker sees policy, not payload. Never pass image bytes or base64 payloads through MCP tool arguments — the tool dispatchers count streamed JSON bytes and return `413` above the 1 MiB control-plane limit. The Worker validates; the agent runtime does the file work.
24
-
25
- ## Cloudflare setup
26
-
27
- ```sh
28
- wrangler r2 bucket create <project>-media
29
- wrangler r2 bucket dev-url enable <project>-media
30
- ```
31
-
32
- Then create an R2 S3 API token in the dashboard: open **R2**, open **Manage R2 API Tokens**, create an **Object Read & Write** token, and copy the Access Key ID and Secret Access Key.
33
-
34
- The R2 binding alone cannot issue presigned `PUT` URLs: presigning is an S3-protocol operation, so this **direct-to-R2 adapter** needs these credentials in addition to the binding. This is not a requirement of Mantle's `MediaStorage` port: a host may return an authenticated same-origin Worker `PUT` URL instead. Media tools appear whenever `mediaStorage` and a media purpose are bound, regardless of which transport the adapter uses.
35
-
36
- ## Wrangler configuration
37
-
38
- ```toml
39
- [vars]
40
- R2_ACCOUNT_ID = "<account-id>"
41
- MEDIA_PUBLIC_URL_BASE = "https://pub-<hash>.r2.dev"
42
-
43
- [[r2_buckets]]
44
- binding = "MEDIA_BUCKET"
45
- bucket_name = "<project>-media"
46
- ```
47
-
48
- A `wrangler.jsonc` project writes the same binding as an `"r2_buckets"` array; see [Bindings and primitives](./bindings.md#r2-media-bucket-optional) for the JSON form and the matching `Env` fields.
49
-
50
- ```sh
51
- wrangler secret put R2_ACCESS_KEY_ID
52
- wrangler secret put R2_SECRET_ACCESS_KEY
53
- ```
54
-
55
- `MEDIA_PUBLIC_URL_BASE` is the origin public URLs are built from — the `r2.dev` development URL, or a custom domain in production. `R2_ACCOUNT_ID` builds the S3 endpoint, which is a different host from the public one.
56
-
57
- ## Wiring `R2MediaStorage`
58
-
59
- Build the adapter from `env`, returning `undefined` when any part is missing so a half-configured environment degrades to no media rather than failing to boot:
14
+ Each media purpose in `siteDefaults.media.purposes` lists mime **slots** and a byte cap per full mime type:
60
15
 
61
16
  ```ts
62
- import { R2MediaStorage } from "@aotter/mantle/cloudflare";
63
- import { AwsClient } from "aws4fetch";
64
-
65
- function buildMediaStorage(env: Env) {
66
- if (
67
- !env.MEDIA_BUCKET ||
68
- !env.R2_ACCOUNT_ID ||
69
- !env.R2_ACCESS_KEY_ID ||
70
- !env.R2_SECRET_ACCESS_KEY ||
71
- !env.MEDIA_PUBLIC_URL_BASE
72
- ) {
73
- return undefined;
74
- }
75
-
76
- const s3 = new AwsClient({
77
- accessKeyId: env.R2_ACCESS_KEY_ID,
78
- secretAccessKey: env.R2_SECRET_ACCESS_KEY,
79
- region: "auto",
80
- service: "s3",
81
- });
82
-
83
- return new R2MediaStorage(
84
- env.MEDIA_BUCKET,
85
- s3,
86
- `https://<project>-media.${env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,
87
- env.MEDIA_PUBLIC_URL_BASE,
88
- );
89
- }
17
+ { name: "cover", required: ["image/jpeg,image/png,image/webp"], maxBytes: { "image/jpeg": 5_000_000, "image/png": 5_000_000, "image/webp": 5_000_000 } }
90
18
  ```
91
19
 
92
- Pass it through the `bindings` hook, spreading the conventional set:
93
-
94
- ```ts
95
- export default createMantleWorker<Env>({
96
- plan,
97
- bindings: (env, conventional) => ({
98
- ...conventional,
99
- mediaStorage: buildMediaStorage(env),
100
- }),
101
- });
102
- ```
20
+ `required` entries use `<input accept>` grammar (full mime, comma list, or a subtype shorthand such as `webp`);
21
+ `maxBytes` must cover every mime the slots allow, keyed by the full mime type.
103
22
 
104
- `aws4fetch` is an application dependency; the adapter takes the signing client rather than embedding one. See [The conventional Worker](./conventional-worker.md#a-bindings-hook).
105
-
106
- ## Declaring media purposes
107
-
108
- A purpose is the upload policy: which variants an asset must have, and how large each may be.
23
+ Applications own their R2 binding, public bucket URL and S3 credentials; the SDK
24
+ package does not manage them. Import `r2MediaStorage` from `@aotter/mantle/media/r2`:
109
25
 
110
26
  ```ts
111
- siteDefaults: {
112
- media: {
113
- purposes: [
114
- {
115
- name: "page-image",
116
- required: ["image/jpeg,image/png", "image/webp", "image/avif"],
117
- maxBytes: {
118
- "image/jpeg": 5_000_000,
119
- "image/png": 5_000_000,
120
- "image/webp": 3_000_000,
121
- "image/avif": 2_000_000,
122
- },
123
- },
124
- ],
125
- },
126
- },
127
- ```
128
-
129
- `required` is slot-based, in the grammar of an `<input accept>` list. The example declares three slots: slot 0 takes exactly one fallback mime preserving source semantics (`image/jpeg` for opaque photos, `image/png` when alpha must survive), slot 1 a WebP variant, slot 2 an AVIF variant. That models a multi-variant `<picture>`. A narrower purpose may declare a single slot such as `["image/jpeg,image/png,image/webp,image/gif"]`, in which case the agent picks exactly one mime from that list and must not upload one variant per listed mime.
130
-
131
- Purpose names are slugs (`^[a-z0-9]+(-[a-z0-9]+)*$`), every slot must be non-empty, slots may not overlap on a mime, and every `maxBytes` key must be a mime some slot accepts with a positive value. Violations fail at boot. SVG uploads are rejected unless the Worker sets `mediaAllowSvg`. See [Site defaults and site_config](../reference/site-config.md).
132
-
133
- The runtime emits the policy summary into the `create_media_upload` tool description, so an agent reads the contract straight from `tools/list` without an extra round trip.
134
-
135
- ## Tool visibility
136
-
137
- `create_media_upload` and `commit_media_upload` are registered only when **both** hold:
138
-
139
- - `bindings.mediaStorage` is set;
140
- - `siteDefaults.media.purposes` contains at least one purpose.
141
-
142
- If either is missing the tools never appear in `tools/list`. That is the intended diagnostic: an agent that cannot see the tools is looking at a deployment where media is not configured, not at a permissions problem. A call that reaches a runtime without media storage answers `MEDIA_NOT_CONFIGURED`.
143
-
144
- ## Referencing an asset from a Schema
145
-
146
- Entries store asset ids, not URLs. Mark the field with both existing v0.1 grammar extensions:
147
-
148
- ```yaml
149
- apiVersion: cms.mantle.aotter.net/v1
150
- kind: Schema
151
- metadata:
152
- name: pages
153
- spec:
154
- title: Pages
155
- schema:
156
- type: object
157
- additionalProperties: false
158
- required: [slug, title]
159
- properties:
160
- slug: { type: string, pattern: "^[a-z0-9-]+$" }
161
- title: { type: string, minLength: 1 }
162
- coverAssetId:
163
- type: string
164
- x-mantle-ref: media_assets
165
- x-mcp-hint: media-image
27
+ const storage = r2MediaStorage({
28
+ bucket: env.MEDIA,
29
+ endpoint: "https://bucket.account.r2.cloudflarestorage.com",
30
+ publicBase: "https://media.example.com",
31
+ signer, // app-owned SigV4 signer: sign(url, {method:"PUT",aws:{signQuery:true,service:"s3"}})
32
+ });
33
+ const media = site(db, caller).media(storage);
34
+ const upload = await media.createUpload({
35
+ filename: "cover.jpg", purpose: "cover",
36
+ variants: [{mimeType:"image/jpeg",byteSize:1234,role:"primary"}]
37
+ });
38
+ // Client PUTs bytes directly to upload.capabilities[i].uploadUrl,
39
+ // with its requiredHeaders. Never send the bytes through Mantle.
40
+ const asset = await media.commitUpload(upload.uploadGroupId);
166
41
  ```
167
42
 
168
- `x-mantle-ref: media_assets` marks the string as an id in the media asset collection, which is what makes Admin show a media picker instead of a text box. `x-mcp-hint: media-image` tells an MCP client the field expects an image asset. Neither key is validated as a foreign key; they are informational. At render time, resolve ids to their variants with `runtime.media.resolve(id)` or `resolveMany(ids)`, which batches a render pass into one database round trip. No new manifest keys are involved; see [Schema](../reference/schema.md).
169
-
170
- ## What a commit costs
171
-
172
- R2 has no metadata-only patch. To stamp `committedAt`, `role`, `uploadGroupId` and the filename markers, Mantle streams each uploaded object through a `GET` and a `PUT`. So a successful N-variant commit performs N `GET`s and N `PUT`s and rewrites the sum of the variant sizes.
173
-
174
- - Commits validate the bundle shape before any I/O.
175
- - Variants are processed in batches of at most three; a batch settles before the next starts or an error returns.
176
- - A mime or size failure cancels the unused `GET` stream; a failed `PUT` also attempts cancellation while preserving the original error.
177
- - The asset row is saved only after every variant succeeds. All-or-nothing.
178
-
179
- Parallelism reduces waiting, not operation count or bytes. Keep variant counts and byte caps deliberate. A partial R2 failure leaves the pending D1 record in place so the commit can be retried before it expires; already stamped objects stay stamped.
180
-
181
- ## Cleanup
182
-
183
- An upload can reach R2 and never be committed — an interrupted agent, a rejected commit. Remove those objects with the version-matched `media-gc` skill. It is opt-in and deliberately not projected into a repository by `mantle skills`, because it deletes remote objects.
184
-
185
- Its posture is audit first, delete only what an operator confirmed. It treats an object as a candidate only when it is over 24 hours old, has no `committedAt` custom metadata, and matches the exact key layout `<purpose>/<group>/(primary|alternate|fallback).<ext>` for a purpose this project declares. It reports account, bucket, prefixes, cutoff, counts, bytes and a digest of the candidate set without printing keys or URLs; on confirmation it re-runs the same audit and stops if anything changed.
186
-
187
- > **Do not use an R2 lifecycle rule**
188
- > Committed and uncommitted media share the same purpose prefix, so an age-based rule deletes live assets. After a pending record expires, partially stamped orphans require an operator audit against D1 references: a missing pending record does not mean an object is unused.
189
-
190
- ## Diagnostics
191
-
192
- | Code | HTTP | Raised when |
193
- |---|---|---|
194
- | `MEDIA_NOT_CONFIGURED` | 501 | No `mediaStorage` port is bound on this deployment |
195
- | `MEDIA_PURPOSE_REJECTED` | 400 | The requested purpose is not declared; the declared set is returned so an agent can self-correct |
196
- | `MEDIA_MIME_REJECTED` | 400 | A mime outside `image/png`, `image/jpeg`, `image/webp`, `image/avif`, `image/gif` |
197
- | `MEDIA_SIZE_EXCEEDED` | 400 | A declared byte size exceeds its cap |
198
- | `MEDIA_SVG_REJECTED` | 400 | An SVG was offered while SVG is not allowed; object storage does not sanitize SVG payloads |
199
- | `MEDIA_VARIANTS_INCOMPLETE` | 400 | The bundle misses a mime the purpose requires; the missing set is returned |
200
- | `MEDIA_VARIANT_SIZE_EXCEEDED` | 400 | One variant exceeds the cap declared for its mime |
201
- | `MEDIA_VARIANTS_SUSPICIOUS_SIZE` | 400 | A modern variant is larger than its fallback (AVIF above JPEG), so it looks unoptimized |
202
- | `MEDIA_ASSET_NOT_FOUND` | 404 | No `media_assets` row matches the id |
203
- | `MEDIA_UPLOAD_EXPIRED` | 410 | The upload capability's TTL elapsed, or it was never created |
204
- | `MEDIA_OBJECT_NOT_FOUND` | 409 | A variant's bytes were never PUT before commit |
205
-
206
- The full catalog is in [Diagnostic codes](../reference/diagnostics.md).
207
-
208
- ## Source
209
- - [`docs/media-uploads.md`](../../../docs/media-uploads.md)
210
- - [`docs/adr/0017-media-multi-variant-agent-side-optimization.md`](../../../docs/adr/0017-media-multi-variant-agent-side-optimization.md)
211
- - [`packages/mantle-runtime/src/domain/port/MediaStorage.ts`](../../../packages/mantle-runtime/src/domain/port/MediaStorage.ts)
212
- - [`packages/mantle-runtime/src/domain/port/MediaAssetRepository.ts`](../../../packages/mantle-runtime/src/domain/port/MediaAssetRepository.ts)
213
- - [`packages/mantle-spec/src/domain/service/SiteDefaultsValidator.ts`](../../../packages/mantle-spec/src/domain/service/SiteDefaultsValidator.ts)
214
- - [`packages/mantle-spec/src/kernel/diagnostic.ts`](../../../packages/mantle-spec/src/kernel/diagnostic.ts)
215
- - [`packages/adapters/cloudflare/README.md`](../../../packages/adapters/cloudflare/README.md)
216
- - [`docs/skills/media-gc/SKILL.md`](../../skills/media-gc/SKILL.md)
43
+ An existing S3 signer (for example an application already using aws4fetch) fits
44
+ this port. This package adds no AWS SDK. The signer must return a SigV4
45
+ query-signed PUT URL and preserve `X-Amz-Expires`; never give its credentials to
46
+ the client. Configure bucket CORS to allow PUT from the application's origins
47
+ and the returned Content-Type header. Serve the `committed/` prefix on the public domain; these keys differ from 0.2's `{purpose}/{group}/{role}` keys. Keep `uploads/` private/unserved on the
48
+ public domain and add a bucket lifecycle rule for abandoned upload keys.
49
+
50
+ Commit checks every object's MIME and size, then rechecks the exact GET
51
+ response used for the copy. Public keys cannot be reached by an upload URL. Each commit attempt has a separate
52
+ public-key UUID, while the asset id remains the upload-group UUID. A concurrent
53
+ loser can neither overwrite nor remove the winner's objects. After SQL selects
54
+ the durable asset, the losing attempt removes only its own unselected copies.
55
+ Upload sources remain until the database commit succeeds, so an uncertain DB
56
+ write can be reconciled/retried with the same UUID. Failed object deletion keeps
57
+ the media row; retry the same id. An upload group expires after 15 minutes. Asset `createdAt` is the upload-group creation time (epoch milliseconds), not the later commit time.
58
+ No R2 upload or deployment is performed by generation.
59
+
60
+ A positively identified native rollback deletes only that attempt's copied
61
+ objects. Plain/network failures lack rollback evidence, retain copies, and return
62
+ `OUTCOME_UNKNOWN`, including a lost D1 batch response.
63
+ An uncertain native write preserves copies, because they may belong to the
64
+ durable winning row. If SQL durability or unselected-copy cleanup returns `OUTCOME_UNKNOWN`, reconcile
65
+ storage with the durable `media_assets.variants` keys. Attempt-isolated copies
66
+ may remain after an uncertain outcome; never delete the winning asset's keys or
67
+ expire all `committed/` objects indiscriminately. The group UUID remains the
68
+ reconciliation and retry id.
69
+
70
+ Admin's `media` option takes a `MediaStorage` value, so build it where `env` is available (for example once per
71
+ Worker in the fetch handler). Uploads use presigned S3 PUT URLs: `wrangler dev --local` has an R2 binding but no S3
72
+ endpoint, so test the upload flow against a real bucket; local tests can cover everything up to the signed URL.