@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.
- package/README.md +166 -298
- package/dist/auth/adapter.d.ts +32 -0
- package/dist/auth/adapter.js +288 -0
- package/dist/auth/admin.d.ts +3 -0
- package/dist/auth/admin.js +21 -0
- package/dist/auth/caller.d.ts +86 -0
- package/dist/auth/caller.js +155 -0
- package/dist/auth/hardening.d.ts +24 -0
- package/dist/auth/hardening.js +40 -0
- package/dist/auth/identity.d.ts +121 -0
- package/dist/auth/identity.js +203 -0
- package/dist/auth/oauth.d.ts +63 -0
- package/dist/auth/oauth.js +217 -0
- package/dist/auth/resource-seeds.js +10 -0
- package/dist/auth/routes.d.ts +32 -0
- package/dist/auth/routes.js +226 -0
- package/dist/build/compiler.d.ts +721 -0
- package/dist/build/compiler.js +7029 -0
- package/dist/build/spec/domain/model/ManifestGrammar.d.ts +439 -0
- package/dist/build/spec/domain/model/RuntimePlan.d.ts +168 -0
- package/dist/build/spec/domain/model/SqlIr.d.ts +129 -0
- package/dist/build/spec/domain/model/UserFields.d.ts +21 -0
- package/dist/build/spec/domain/service/PlanFingerprint.d.ts +7 -0
- package/dist/build/spec/kernel/diagnostic.d.ts +108 -0
- package/dist/bun/assets.d.ts +2 -0
- package/dist/bun/assets.js +24 -0
- package/dist/domain/adminOrder.js +24 -0
- package/dist/domain/columns.js +57 -0
- package/dist/domain/describe/chunk-ZVXBGP7Y.js +424 -0
- package/dist/domain/describe/index.d.ts +58 -0
- package/dist/domain/describe/index.js +115 -0
- package/dist/domain/describe/target-hash.d.ts +8 -0
- package/dist/domain/describe/target-hash.js +12 -0
- package/dist/domain/describe/targets.d.ts +40 -0
- package/dist/domain/entry.js +33 -0
- package/dist/domain/generated-tools.js +19 -0
- package/dist/domain/generation.d.ts +16 -0
- package/dist/domain/generation.js +1 -0
- package/dist/domain/input.js +17 -0
- package/dist/domain/model.js +1 -0
- package/dist/domain/paging.js +230 -0
- package/dist/domain/recipes.js +24 -0
- package/dist/domain/userReferences.js +5 -0
- package/dist/domain/wireScalars.js +47 -0
- package/dist/infrastructure/adminEntries.js +153 -0
- package/dist/infrastructure/adminPaging.js +72 -0
- package/dist/infrastructure/artifacts.js +71 -0
- package/dist/infrastructure/authSchema.js +83 -0
- package/dist/infrastructure/bundle.js +188 -0
- package/dist/infrastructure/cli.js +118 -0
- package/dist/infrastructure/generate.d.ts +12 -0
- package/dist/infrastructure/generate.js +189 -0
- package/dist/infrastructure/generateAuth.d.ts +8 -0
- package/dist/infrastructure/generateAuth.js +74 -0
- package/dist/infrastructure/help.js +60 -0
- package/dist/infrastructure/init.js +54 -0
- package/dist/infrastructure/inputs.js +41 -0
- package/dist/infrastructure/mounts.js +25 -0
- package/dist/infrastructure/wrangler.js +109 -0
- package/dist/kernel/authorization.d.ts +4 -0
- package/dist/kernel/authorization.js +16 -0
- package/dist/kernel/binds.d.ts +60 -0
- package/dist/kernel/binds.js +49 -0
- package/dist/kernel/caller-identity.d.ts +24 -0
- package/dist/kernel/caller-identity.js +22 -0
- package/dist/kernel/contract-error.d.ts +12 -0
- package/dist/kernel/contract-error.js +14 -0
- package/dist/kernel/contracts.d.ts +143 -0
- package/dist/kernel/contracts.js +97 -0
- package/dist/kernel/cron.d.ts +1 -0
- package/dist/kernel/cron.js +58 -0
- package/dist/kernel/dialect/common.d.ts +38 -0
- package/dist/kernel/dialect/common.js +6 -0
- package/dist/kernel/dialect/postgres.d.ts +16 -0
- package/dist/kernel/dialect/postgres.js +18 -0
- package/dist/kernel/dialect/sqlite.d.ts +20 -0
- package/dist/kernel/dialect/sqlite.js +34 -0
- package/dist/kernel/drain.d.ts +5 -0
- package/dist/kernel/drain.js +35 -0
- package/dist/kernel/driver/bun-sqlite.d.ts +19 -0
- package/dist/kernel/driver/bun-sqlite.js +77 -0
- package/dist/kernel/driver/d1.d.ts +24 -0
- package/dist/kernel/driver/d1.js +22 -0
- package/dist/kernel/driver/postgres.d.ts +25 -0
- package/dist/kernel/driver/postgres.js +99 -0
- package/dist/kernel/driver/transaction-context.d.ts +10 -0
- package/dist/kernel/driver/transaction-context.js +29 -0
- package/dist/kernel/email.d.ts +28 -0
- package/dist/kernel/email.js +38 -0
- package/dist/kernel/host-access.d.ts +10 -0
- package/dist/kernel/host-access.js +65 -0
- package/dist/kernel/host-caller.d.ts +39 -0
- package/dist/kernel/host-caller.js +56 -0
- package/dist/kernel/json-body.d.ts +4 -0
- package/dist/kernel/json-body.js +44 -0
- package/dist/kernel/mcp-apps.d.ts +69 -0
- package/dist/kernel/mcp-apps.js +40 -0
- package/dist/kernel/mcp-call.d.ts +5 -0
- package/dist/kernel/mcp-call.js +25 -0
- package/dist/kernel/mcp-handler.js +371 -0
- package/dist/kernel/mcp.d.ts +110 -0
- package/dist/kernel/mcp.js +50 -0
- package/dist/kernel/media.d.ts +27 -0
- package/dist/kernel/media.js +216 -0
- package/dist/kernel/paging.d.ts +55 -0
- package/dist/kernel/paging.js +95 -0
- package/dist/kernel/publishing.d.ts +4 -0
- package/dist/kernel/publishing.js +16 -0
- package/dist/kernel/r2-media.d.ts +42 -0
- package/dist/kernel/r2-media.js +78 -0
- package/dist/kernel/rest-dispatch.js +38 -0
- package/dist/kernel/rest-router.js +64 -0
- package/dist/kernel/rest.d.ts +58 -0
- package/dist/kernel/rest.js +41 -0
- package/dist/kernel/scalars.d.ts +6 -0
- package/dist/kernel/scalars.js +44 -0
- package/dist/kernel/search.js +5 -0
- package/dist/kernel/site-types.d.ts +146 -0
- package/dist/kernel/site-types.js +1 -0
- package/dist/kernel/site.d.ts +39 -0
- package/dist/kernel/site.js +32 -0
- package/dist/kernel/store.d.ts +175 -0
- package/dist/kernel/store.js +269 -0
- package/dist/kernel/surface.d.ts +10 -0
- package/dist/kernel/surface.js +19 -0
- package/dist/kernel/sweep.d.ts +17 -0
- package/dist/kernel/sweep.js +27 -0
- package/dist/kernel/translations.d.ts +1 -0
- package/dist/kernel/translations.js +13 -0
- package/dist/kernel/user-caller.d.ts +31 -0
- package/dist/kernel/user-caller.js +67 -0
- package/dist/kernel/user-field-name.js +3 -0
- package/dist/kernel/user-fields.d.ts +35 -0
- package/dist/kernel/user-fields.js +81 -0
- package/dist/kernel/validation.d.ts +15 -0
- package/dist/kernel/validation.js +54 -0
- package/dist/kernel/web-gateway.js +68 -0
- package/dist/kernel/web-head.js +15 -0
- package/dist/kernel/web-index.js +40 -0
- package/dist/kernel/web-response.js +8 -0
- package/dist/kernel/web.d.ts +77 -0
- package/dist/kernel/web.js +124 -0
- package/dist/kernel/where.js +27 -0
- package/dist/testing/index.d.ts +1 -0
- package/dist/testing/index.js +1 -0
- package/dist/usecase/adminBindings.js +143 -0
- package/dist/usecase/adminClient.js +87 -0
- package/dist/usecase/adminDescriptors.js +107 -0
- package/dist/usecase/generate.js +166 -0
- package/dist/usecase/handlers.js +21 -0
- package/dist/usecase/mcp-media.js +17 -0
- package/dist/usecase/mcp.js +100 -0
- package/dist/usecase/paging.js +71 -0
- package/dist/usecase/publishing.js +63 -0
- package/dist/usecase/refusals.js +27 -0
- package/dist/usecase/rest.js +54 -0
- package/dist/usecase/search.js +7 -0
- package/dist/usecase/site.js +39 -0
- package/dist/usecase/stores.js +64 -0
- package/dist/usecase/tool-version.js +9 -0
- package/dist/usecase/translations.js +78 -0
- package/dist/usecase/ttl.js +20 -0
- package/dist/usecase/validation.js +241 -0
- package/dist/usecase/web.js +23 -0
- package/docs/examples/README.md +39 -18
- package/docs/examples/app-shell/.dev.vars.example +4 -0
- package/docs/examples/app-shell/README.md +121 -0
- package/docs/examples/app-shell/accept.mjs +91 -0
- package/docs/examples/app-shell/gitignore +7 -0
- package/docs/examples/app-shell/package.json +43 -0
- package/docs/examples/app-shell/pnpm-workspace.yaml +8 -0
- package/docs/examples/app-shell/smoke-kit.mjs +168 -0
- package/docs/examples/app-shell/src/auth.ts +58 -0
- package/docs/examples/app-shell/src/handlers.ts +5 -0
- package/docs/examples/app-shell/src/index.ts +4 -0
- package/docs/examples/app-shell/src/routes.ts +14 -0
- package/docs/examples/app-shell/src/schedule.ts +8 -0
- package/docs/examples/app-shell/src/service.ts +70 -0
- package/docs/examples/app-shell/src/sign-in.ts +41 -0
- package/docs/examples/app-shell/src/signup.ts +8 -0
- package/docs/examples/app-shell/tsconfig.json +26 -0
- package/docs/examples/app-shell/worker-configuration.d.ts +22 -0
- package/docs/examples/app-shell/wrangler.jsonc +62 -0
- package/docs/examples/club-events/README.md +65 -0
- package/docs/examples/club-events/manifests/club-events.yaml +247 -0
- package/docs/examples/club-events/smoke.mjs +127 -0
- package/docs/examples/club-events/src/handlers.ts +25 -0
- package/docs/examples/club-events/src/signup.ts +9 -0
- package/docs/examples/generated-web/README.md +78 -0
- package/docs/examples/generated-web/posts.yaml +38 -0
- package/docs/examples/generated-web/seed.sql +6 -0
- package/docs/examples/generated-web/src/worker.ts +43 -0
- package/docs/examples/generated-web/tsconfig.json +8 -0
- package/docs/examples/generated-web/wrangler.jsonc +8 -0
- package/docs/examples/purchasing/.dev.vars.example +6 -0
- package/docs/examples/purchasing/README.md +99 -0
- package/docs/examples/purchasing/manifests/purchasing.yaml +374 -0
- package/docs/examples/purchasing/seed.sql +4 -0
- package/docs/examples/purchasing/smoke.mjs +191 -0
- package/docs/examples/purchasing/src/admin.tsx +13 -0
- package/docs/examples/purchasing/src/handlers.ts +33 -0
- package/docs/examples/purchasing/src/notify.ts +29 -0
- package/docs/examples/purchasing/src/requests-page.ts +57 -0
- package/docs/examples/purchasing/src/routes.ts +53 -0
- package/docs/examples/purchasing/src/schedule.ts +31 -0
- package/docs/examples/purchasing/src/signup.ts +5 -0
- package/docs/examples/purchasing/src/supplier.ts +32 -0
- package/docs/examples/purchasing/wrangler.jsonc +69 -0
- package/docs/examples/recipes/README.md +60 -0
- package/docs/examples/recipes/manifests/recipes.yaml +75 -0
- package/docs/examples/recipes/smoke.mjs +102 -0
- package/docs/examples/recipes/src/media.ts +13 -0
- package/docs/examples/recipes/src/pages.ts +99 -0
- package/docs/examples/recipes/src/routes.ts +71 -0
- package/docs/examples/recipes/src/site-config.ts +12 -0
- package/docs/examples/recipes/wrangler.jsonc +74 -0
- package/docs/handbook/cloudflare/authentication.md +180 -322
- package/docs/handbook/cloudflare/chatgpt-sites.md +5 -23
- package/docs/handbook/cloudflare/deploy-and-operate.md +55 -77
- package/docs/handbook/cloudflare/media-r2.md +61 -205
- package/docs/handbook/cloudflare/service-entry.md +239 -0
- package/docs/handbook/concepts/authorization.md +10 -107
- package/docs/handbook/concepts/four-atoms.md +9 -168
- package/docs/handbook/concepts/lifecycle-and-locales.md +9 -132
- package/docs/handbook/concepts/mcp-and-agents.md +24 -121
- package/docs/handbook/concepts/procedures-and-triggers.md +5 -217
- package/docs/handbook/concepts/runtime-and-adapters.md +15 -169
- package/docs/handbook/concepts/views.md +10 -185
- package/docs/handbook/examples/hub.md +3 -8
- package/docs/handbook/guides/adapter-guide.md +11 -0
- package/docs/handbook/guides/admin-ui.md +115 -133
- package/docs/handbook/guides/agent-setup.md +64 -74
- package/docs/handbook/guides/agent-workflow-acceptance.md +232 -0
- package/docs/handbook/guides/email.md +86 -0
- package/docs/handbook/guides/local-testing.md +40 -0
- package/docs/handbook/guides/mcp-apps.md +560 -0
- package/docs/handbook/guides/native-admin.md +566 -0
- package/docs/handbook/guides/native-execution.md +133 -0
- package/docs/handbook/guides/oauth.md +219 -0
- package/docs/handbook/guides/postgres-adapters.md +56 -0
- package/docs/handbook/guides/public-pages.md +87 -0
- package/docs/handbook/guides/size-and-startup.md +9 -0
- package/docs/handbook/guides/sql-patterns.md +266 -0
- package/docs/handbook/guides/typed-queries.md +211 -107
- package/docs/handbook/navigation.json +176 -55
- package/docs/handbook/reference/admin-descriptors.md +53 -0
- package/docs/handbook/reference/authorization.md +39 -266
- package/docs/handbook/reference/describe.md +56 -0
- package/docs/handbook/reference/diagnostics.md +19 -186
- package/docs/handbook/reference/features.md +45 -55
- package/docs/handbook/reference/manifest.md +6 -129
- package/docs/handbook/reference/procedure.md +11 -303
- package/docs/handbook/reference/schema.md +64 -240
- package/docs/handbook/reference/site-config.md +5 -218
- package/docs/handbook/reference/sql.md +64 -0
- package/docs/handbook/reference/surface.md +392 -201
- package/docs/handbook/reference/trigger.md +56 -192
- package/docs/handbook/reference/view.md +24 -243
- package/docs/handbook/releases/index.md +244 -77
- package/docs/handbook/start/agents.md +45 -0
- package/docs/handbook/start/overview.md +9 -48
- package/docs/handbook/start/project-and-cli.md +51 -104
- package/docs/handbook/start/quickstart-worker.md +43 -178
- package/docs/skills/develop/SKILL.md +79 -249
- package/docs/skills/integrate/SKILL.md +39 -50
- package/docs/skills/media-gc/SKILL.md +34 -10
- package/docs/skills/provision/SKILL.md +36 -186
- package/docs/skills/update/SKILL.md +23 -38
- package/docs/source/scripts/postgres-adapter.ts +101 -0
- package/docs/upgrade-0.1-to-0.2.md +227 -0
- package/package.json +120 -131
- package/skills/README.md +48 -108
- package/skills/mantle/SKILL.md +76 -0
- package/dist/admin-ui.d.ts +0 -2
- package/dist/admin-ui.d.ts.map +0 -1
- package/dist/admin-ui.js +0 -2
- package/dist/admin-ui.js.map +0 -1
- package/dist/admin.d.ts +0 -2
- package/dist/admin.d.ts.map +0 -1
- package/dist/admin.js +0 -2
- package/dist/admin.js.map +0 -1
- package/dist/auth.d.ts +0 -2
- package/dist/auth.d.ts.map +0 -1
- package/dist/auth.js +0 -2
- package/dist/auth.js.map +0 -1
- package/dist/bun.d.ts +0 -2
- package/dist/bun.d.ts.map +0 -1
- package/dist/bun.js +0 -2
- package/dist/bun.js.map +0 -1
- package/dist/cli/generate-cloudflare.d.ts +0 -7
- package/dist/cli/generate-cloudflare.d.ts.map +0 -1
- package/dist/cli/generate-cloudflare.js +0 -123
- package/dist/cli/generate-cloudflare.js.map +0 -1
- package/dist/cli/generate-project.d.ts +0 -25
- package/dist/cli/generate-project.d.ts.map +0 -1
- package/dist/cli/generate-project.js +0 -282
- package/dist/cli/generate-project.js.map +0 -1
- package/dist/cli/generate-sites.d.ts +0 -8
- package/dist/cli/generate-sites.d.ts.map +0 -1
- package/dist/cli/generate-sites.js +0 -273
- package/dist/cli/generate-sites.js.map +0 -1
- package/dist/cli/generate.d.ts +0 -20
- package/dist/cli/generate.d.ts.map +0 -1
- package/dist/cli/generate.js +0 -299
- package/dist/cli/generate.js.map +0 -1
- package/dist/cli/harness.d.ts +0 -3
- package/dist/cli/harness.d.ts.map +0 -1
- package/dist/cli/harness.js +0 -214
- package/dist/cli/harness.js.map +0 -1
- package/dist/cli/main.d.ts +0 -3
- package/dist/cli/main.d.ts.map +0 -1
- package/dist/cli/main.js +0 -77
- package/dist/cli/main.js.map +0 -1
- package/dist/cli/skills.d.ts +0 -3
- package/dist/cli/skills.d.ts.map +0 -1
- package/dist/cli/skills.js +0 -128
- package/dist/cli/skills.js.map +0 -1
- package/dist/cloudflare.d.ts +0 -2
- package/dist/cloudflare.d.ts.map +0 -1
- package/dist/cloudflare.js +0 -2
- package/dist/cloudflare.js.map +0 -1
- package/dist/codegen/emitMantleModule.d.ts +0 -22
- package/dist/codegen/emitMantleModule.d.ts.map +0 -1
- package/dist/codegen/emitMantleModule.js +0 -291
- package/dist/codegen/emitMantleModule.js.map +0 -1
- package/dist/codegen.d.ts +0 -2
- package/dist/codegen.d.ts.map +0 -1
- package/dist/codegen.js +0 -2
- package/dist/codegen.js.map +0 -1
- package/dist/runtime-testing.d.ts +0 -2
- package/dist/runtime-testing.d.ts.map +0 -1
- package/dist/runtime-testing.js +0 -2
- package/dist/runtime-testing.js.map +0 -1
- package/dist/runtime.d.ts +0 -2
- package/dist/runtime.d.ts.map +0 -1
- package/dist/runtime.js +0 -2
- package/dist/runtime.js.map +0 -1
- package/dist/spec.d.ts +0 -2
- package/dist/spec.d.ts.map +0 -1
- package/dist/spec.js +0 -2
- package/dist/spec.js.map +0 -1
- package/dist/vercel-libsql.d.ts +0 -2
- package/dist/vercel-libsql.d.ts.map +0 -1
- package/dist/vercel-libsql.js +0 -2
- package/dist/vercel-libsql.js.map +0 -1
- package/dist/vercel.d.ts +0 -2
- package/dist/vercel.d.ts.map +0 -1
- package/dist/vercel.js +0 -2
- package/dist/vercel.js.map +0 -1
- package/dist/web.d.ts +0 -2
- package/dist/web.d.ts.map +0 -1
- package/dist/web.js +0 -2
- package/dist/web.js.map +0 -1
- package/docs/adapter-guide.md +0 -222
- package/docs/adr/0001-four-atom-manifest-model.md +0 -440
- package/docs/adr/0002-closed-enums-for-bindings.md +0 -253
- package/docs/adr/0007-ai-as-primary-author.md +0 -473
- package/docs/adr/0008-structured-diagnostic-shape.md +0 -338
- package/docs/adr/0009-consumer-supplied-manifests.md +0 -149
- package/docs/adr/0010-locale-and-translates.md +0 -453
- package/docs/adr/0011-adapter-port-spec.md +0 -281
- package/docs/adr/0012-views-as-public-rest.md +0 -161
- package/docs/adr/0013-agent-provisioned-consumer-projects.md +0 -154
- package/docs/adr/0014-auth-better-auth-and-multi-tenant-mcp.md +0 -900
- package/docs/adr/0016-site-semantic-layer.md +0 -70
- package/docs/adr/0017-media-multi-variant-agent-side-optimization.md +0 -181
- package/docs/adr/0018-core-starters-repository-boundary.md +0 -179
- package/docs/adr/0019-sealed-manifest-runtime-pipeline.md +0 -240
- package/docs/adr/0020-builtin-handler-contracts-and-matched-upsert.md +0 -199
- package/docs/adr/0021-retire-starter-scaffolding.md +0 -30
- package/docs/adr/0022-caller-observed-version-occ.md +0 -212
- package/docs/adr/0023-port-failure-contract.md +0 -69
- package/docs/adr/0024-manifest-native-schema-tables.md +0 -264
- package/docs/adr/0025-reserved-native-columns-and-published-only-public-views.md +0 -105
- package/docs/adr/0026-progressive-generate.md +0 -36
- package/docs/adr/0027-scheduled-procedure-triggers.md +0 -31
- package/docs/adr/0028-schema-ttl-expiry.md +0 -33
- package/docs/adr/README.md +0 -81
- package/docs/adr/adr-lite-803-request-diagnostics.md +0 -38
- package/docs/adr/adr-lite-808-route-readiness.md +0 -47
- package/docs/adr/adr-lite-809-bounded-public-content.md +0 -71
- package/docs/adr/adr-lite-812-native-parity.md +0 -150
- package/docs/adr/adr-lite-823-home-statistics.md +0 -64
- package/docs/adr/adr-lite-842-mcp-authoring.md +0 -30
- package/docs/adr/adr-lite-845-frontend-client.md +0 -38
- package/docs/adr/adr-lite-861-admin-webmcp.md +0 -42
- package/docs/adr/adr-lite-909-admin-ui-kit.md +0 -37
- package/docs/agent-prompts.md +0 -64
- package/docs/api-mcp-authorization.md +0 -5
- package/docs/assets/mantle-admin-developer.png +0 -0
- package/docs/assets/mantle-admin-operations.png +0 -0
- package/docs/assets/mantle-hero.jpg +0 -0
- package/docs/auth-hosting-model.md +0 -166
- package/docs/cloudflare-low-level-composition.md +0 -5
- package/docs/consumer-onboarding-audit.md +0 -65
- package/docs/deferred-lifecycle-queues.md +0 -5
- package/docs/design-atoms.md +0 -16
- package/docs/design-references/editorial-blog-2026-05-05.md +0 -218
- package/docs/direct-authoring.md +0 -5
- package/docs/examples/builtin-commerce.md +0 -269
- package/docs/examples/builtin-intake.md +0 -143
- package/docs/examples/builtin-legal-documents.md +0 -189
- package/docs/examples/builtin-procurement.md +0 -241
- package/docs/examples/builtin-publication.md +0 -241
- package/docs/examples/builtin-reservation.md +0 -149
- package/docs/examples/cf-primitives-commerce-inventory.md +0 -809
- package/docs/examples/cf-primitives-guarded-api.md +0 -429
- package/docs/examples/cf-primitives-intake-hooks.md +0 -319
- package/docs/examples/host-chatgpt-sites/.openai/hosting.json +0 -1
- package/docs/examples/host-chatgpt-sites/README.md +0 -70
- package/docs/examples/host-chatgpt-sites/drizzle/0000_sites_users.sql +0 -8
- package/docs/examples/host-chatgpt-sites/drizzle/0001_mantle.sql +0 -294
- package/docs/examples/host-chatgpt-sites/drizzle/0002_article_cover.sql +0 -5
- package/docs/examples/host-chatgpt-sites/drizzle/0003_store_instance_id.sql +0 -1
- package/docs/examples/host-chatgpt-sites/drizzle/0004_mantle.sql +0 -10
- package/docs/examples/host-chatgpt-sites/drizzle/0005_mantle.sql +0 -24
- package/docs/examples/host-chatgpt-sites/drizzle/meta/_journal.json +0 -1
- package/docs/examples/host-chatgpt-sites/drizzle/meta/mantle-state.json +0 -60
- package/docs/examples/host-chatgpt-sites/manifests/site.yaml +0 -27
- package/docs/examples/host-chatgpt-sites/package.json +0 -1
- package/docs/examples/host-chatgpt-sites/public/site.css +0 -1
- package/docs/examples/host-chatgpt-sites/scripts/build.mjs +0 -13
- package/docs/examples/host-chatgpt-sites/scripts/check.mjs +0 -101
- package/docs/examples/host-chatgpt-sites/scripts/migration.mjs +0 -43
- package/docs/examples/host-chatgpt-sites/src/chatgpt-auth.ts +0 -66
- package/docs/examples/host-chatgpt-sites/src/index.ts +0 -46
- package/docs/examples/host-chatgpt-sites/src/mcp.ts +0 -49
- package/docs/examples/host-chatgpt-sites/src/media.ts +0 -109
- package/docs/examples/host-chatgpt-sites/src/r2-lab.ts +0 -38
- package/docs/examples/host-chatgpt-sites/src/storage-fingerprint.json +0 -1
- package/docs/examples/host-chatgpt-sites/src/web.ts +0 -35
- package/docs/examples/host-chatgpt-sites/tsconfig.json +0 -1
- package/docs/examples/host-chatgpt-sites/wrangler.jsonc +0 -10
- package/docs/examples/host-local-admin-otp/.dev.vars.example +0 -3
- package/docs/examples/host-local-admin-otp/README.md +0 -80
- package/docs/examples/host-local-admin-otp/ensure-dev-vars.mjs +0 -5
- package/docs/examples/host-local-admin-otp/manifests/site.yaml +0 -25
- package/docs/examples/host-local-admin-otp/package.json +0 -29
- package/docs/examples/host-local-admin-otp/public/.gitkeep +0 -1
- package/docs/examples/host-local-admin-otp/smoke.mjs +0 -141
- package/docs/examples/host-local-admin-otp/src/index.ts +0 -54
- package/docs/examples/host-local-admin-otp/tsconfig.json +0 -17
- package/docs/examples/host-local-admin-otp/wrangler.jsonc +0 -23
- package/docs/examples/host-minimal-worker/README.md +0 -41
- package/docs/examples/host-minimal-worker/manifests/site.yaml +0 -25
- package/docs/examples/host-minimal-worker/package.json +0 -26
- package/docs/examples/host-minimal-worker/smoke.mjs +0 -23
- package/docs/examples/host-minimal-worker/src/index.ts +0 -4
- package/docs/examples/host-minimal-worker/tsconfig.json +0 -17
- package/docs/examples/host-minimal-worker/wrangler.jsonc +0 -22
- package/docs/handbook/chatgpt-sites/equipment-checkout.md +0 -231
- package/docs/handbook/chatgpt-sites/generated-app.md +0 -84
- package/docs/handbook/chatgpt-sites/host-reference.md +0 -113
- package/docs/handbook/chatgpt-sites/index.md +0 -133
- package/docs/handbook/cloudflare/bindings.md +0 -291
- package/docs/handbook/cloudflare/conventional-worker.md +0 -166
- package/docs/handbook/cloudflare/deferred-hooks-queues.md +0 -170
- package/docs/handbook/cloudflare/low-level-composition.md +0 -169
- package/docs/handbook/cloudflare/public-web.md +0 -144
- package/docs/handbook/cloudflare/site-chrome.md +0 -75
- package/docs/handbook/examples/commerce-transaction.md +0 -11
- package/docs/handbook/examples/commerce.md +0 -11
- package/docs/handbook/examples/guarded-api.md +0 -10
- package/docs/handbook/examples/intake-form.md +0 -12
- package/docs/handbook/examples/intake-hooks.md +0 -11
- package/docs/handbook/examples/legal-documents.md +0 -10
- package/docs/handbook/examples/procurement-approvals.md +0 -10
- package/docs/handbook/examples/publication.md +0 -10
- package/docs/handbook/examples/reservation.md +0 -10
- package/docs/handbook/start/quickstart-admin.md +0 -52
- package/docs/labels.md +0 -71
- package/docs/media-uploads.md +0 -5
- package/docs/migration-0.1.2.md +0 -13
- package/docs/performance-harness.md +0 -228
- package/docs/release-process.md +0 -244
- package/docs/schema-indexes.md +0 -5
- package/docs/sealed-pipeline-ownership.md +0 -101
- package/docs/skills/plugin/SKILL.md +0 -132
- package/docs/skills/theme/SKILL.md +0 -77
- package/docs/spec-only-host-adoption.md +0 -157
- package/docs/transaction-patterns.md +0 -5
- package/skills/develop/SKILL.md +0 -258
- package/skills/install/SKILL.md +0 -112
- package/skills/integrate/SKILL.md +0 -60
- package/skills/media-gc/SKILL.md +0 -85
- package/skills/plugin/SKILL.md +0 -132
- package/skills/provision/SKILL.md +0 -194
- package/skills/theme/SKILL.md +0 -77
- package/skills/update/SKILL.md +0 -51
- package/templates/chatgpt-sites/auth.ts +0 -66
- package/templates/chatgpt-sites/build.mjs +0 -14
- package/templates/chatgpt-sites/env.ts +0 -1
- package/templates/chatgpt-sites/mcp.ts +0 -48
- package/templates/chatgpt-sites/public-mcp.ts +0 -29
- package/templates/chatgpt-sites/smoke-local.mjs +0 -20
|
@@ -1,213 +1,77 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Trigger field reference — http, mcp, lifecycle and schedule sources, routing rules, and delivery semantics.
|
|
3
|
-
---
|
|
4
1
|
# Trigger
|
|
5
2
|
|
|
6
|
-
A Trigger binds one source to one [Procedure](./procedure.md). Every external surface for a write — an HTTP endpoint, an MCP tool, an entry-lifecycle hook — is a Trigger, and there is no other way to expose a Procedure. This page is the field-level contract; the concepts are in [Procedures and Triggers](../concepts/procedures-and-triggers.md). Envelope rules are in [Manifest envelope and conventions](./manifest.md), and diagnostic codes are catalogued in [Diagnostics](./diagnostics.md).
|
|
7
|
-
|
|
8
|
-
## Fields
|
|
9
|
-
|
|
10
|
-
`spec` accepts exactly two keys.
|
|
11
|
-
|
|
12
|
-
| Field | Type | Required | Rules |
|
|
13
|
-
|---|---|---|---|
|
|
14
|
-
| `source` | mapping | yes | Discriminated by `kind`; the accepted sibling keys depend on it. |
|
|
15
|
-
| `target` | `{ procedure }` | yes | Only the key `procedure`, naming a declared Procedure (`TRIGGER_TARGET_PROCEDURE_UNKNOWN`). |
|
|
16
|
-
|
|
17
|
-
| `source.kind` | Other keys | Binds |
|
|
18
|
-
|---|---|---|
|
|
19
|
-
| `http` | `method`, `path` | One REST endpoint under `/api/`. |
|
|
20
|
-
| `mcp` | `surface` | One tool on `/mcp` or `/mcp/staff`. |
|
|
21
|
-
| `lifecycle` | `schema`, `on`, `errorPolicy` | Entry-writer hooks on one Schema. |
|
|
22
|
-
| `schedule` | `cron`, optional `enabled` | A Cloudflare Cron Trigger calling one Procedure. |
|
|
23
|
-
|
|
24
|
-
An unknown `kind`, a missing `kind`, or a key that does not belong to the chosen kind is `INVALID_MANIFEST_ENVELOPE`. One Procedure may carry several Triggers — that is how the same handler becomes an HTTP endpoint and an MCP tool without duplicating logic.
|
|
25
|
-
|
|
26
|
-
## `schedule` source
|
|
27
|
-
|
|
28
3
|
```yaml
|
|
29
|
-
apiVersion: cms.mantle.aotter.net/
|
|
4
|
+
apiVersion: cms.mantle.aotter.net/v2
|
|
5
|
+
kind: Schema
|
|
6
|
+
metadata: { name: tickets }
|
|
7
|
+
spec:
|
|
8
|
+
title: Tickets
|
|
9
|
+
lifecycle: operational
|
|
10
|
+
schema: { type: object, required: [closed], properties: { closed: { type: boolean } } }
|
|
11
|
+
---
|
|
12
|
+
apiVersion: cms.mantle.aotter.net/v2
|
|
13
|
+
kind: Procedure
|
|
14
|
+
metadata: { name: close-ticket }
|
|
15
|
+
spec:
|
|
16
|
+
requires: { auth: { all: [ctx.admin] } }
|
|
17
|
+
input: { type: object, required: [id, version], properties: { id: { type: string }, version: { type: integer } }, additionalProperties: false }
|
|
18
|
+
output: { type: object }
|
|
19
|
+
handler: { sql: 'UPDATE tickets SET closed=true WHERE id=input.id AND version=input.version RETURNING id,closed' }
|
|
20
|
+
---
|
|
21
|
+
apiVersion: cms.mantle.aotter.net/v2
|
|
30
22
|
kind: Trigger
|
|
31
|
-
metadata: { name:
|
|
23
|
+
metadata: { name: close-ticket-http }
|
|
32
24
|
spec:
|
|
33
|
-
source: { kind:
|
|
34
|
-
target: { procedure:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
`cron` is a five-field Cloudflare UTC expression (minute, hour, day, month, weekday). Each field accepts `*`, a number, a range, comma-separated values, or `*/step` / `start-end/step`. Weekdays are **1 = Sunday through 7 = Saturday**; use `2-6` for Monday–Friday. Month and weekday names and provider-specific extensions are outside this subset. `enabled` defaults to `true`; a disabled schedule remains in the compiled plan but never invokes its Procedure. The target Procedure must accept `{}` as input (`SCHEDULE_INPUT_INVALID`) and have no user/staff authorization requirements (`SCHEDULE_AUTH_INVALID`). The schedule creates no public HTTP or MCP route.
|
|
38
|
-
|
|
39
|
-
On Cloudflare, add each enabled expression to `wrangler.jsonc` under `triggers.crons` and export the `scheduled` method returned by `createMantleWorker`. Mantle does not provision the provider trigger. A disabled expression still registered in Wrangler is ignored; an expression absent from the Mantle plan fails visibly. If the Worker also owns unrelated cron tasks, route those expressions in the application's `scheduled` export. Multiple Mantle Triggers may share one expression and run in Trigger-name order; all run even if an earlier one fails, then the event reports failure.
|
|
40
|
-
|
|
41
|
-
Handlers receive `ctx.schedule` with `id`, `trigger`, `cron`, and `scheduledTime` (Unix milliseconds). The stable ID is `${trigger}:${scheduledTime}`. The caller is always `user: null`, `staff: null`, with no credential metadata; normal Procedure guards still apply. Cloudflare executes cron events in UTC, but its Cron Trigger documentation does not promise automatic retries. Duplicate/manual replay is still possible, so use `ctx.schedule.id` as an idempotency key for writes. A failure rejects the scheduled event; exactly-once execution is not promised. Bun, Vercel, and ChatGPT Sites do not register schedules and reject enabled schedules at boot or generation.
|
|
42
|
-
|
|
43
|
-
Cloudflare's default D1 composition records each attempt under that stable run ID. The owner-only Developer Console shows declared schedules even before the first run, separately from recent observations; Wrangler registration is **not observed** by Core. Records include scheduled/start/finish times, status, attempt, duration, a diagnostic code or generic handler-error summary, and optional sweep counts. A started attempt with no finish record says **Completion not observed**, not success. Inputs, outputs, exception text, credentials and secrets are not stored. The default history retains 30 days, hides older rows on reads, and prunes them during later runs (at most once per day per runtime instance). If observation start fails, the Procedure is skipped and the scheduled event rejects; if recording completion fails, the event also rejects. Use the stable ID to make replay safe. If the host supplies custom storage without a durable observation store, the Console says **Unavailable**; it never reports a missing record as success.
|
|
44
|
-
|
|
45
|
-
## `http` source
|
|
46
|
-
|
|
47
|
-
```yaml
|
|
48
|
-
apiVersion: cms.mantle.aotter.net/v1
|
|
25
|
+
source: { kind: http, method: POST, path: '/api/tickets/{id}/close' }
|
|
26
|
+
target: { procedure: close-ticket }
|
|
27
|
+
---
|
|
28
|
+
apiVersion: cms.mantle.aotter.net/v2
|
|
49
29
|
kind: Trigger
|
|
50
|
-
metadata:
|
|
51
|
-
name: inventory-level-http
|
|
30
|
+
metadata: { name: close-ticket-mcp }
|
|
52
31
|
spec:
|
|
53
|
-
source:
|
|
54
|
-
|
|
55
|
-
method: PUT
|
|
56
|
-
path: /api/inventory/{sku}/level
|
|
57
|
-
target:
|
|
58
|
-
procedure: sync-inventory-level
|
|
32
|
+
source: { kind: mcp, surface: admin }
|
|
33
|
+
target: { procedure: close-ticket }
|
|
59
34
|
```
|
|
60
35
|
|
|
61
|
-
|
|
62
|
-
|---|---|
|
|
63
|
-
| `method` | `POST`, `PUT`, `PATCH` or `DELETE`. |
|
|
64
|
-
| `path` | Non-empty string starting with `/`. OpenAPI `{param}` syntax for path params. No optional segments. |
|
|
65
|
-
|
|
66
|
-
`GET` is deliberately absent. Reads are [Views](./view.md), which mount themselves from `surface` and need no Trigger at all; a Procedure is a write.
|
|
67
|
-
|
|
68
|
-
### Path rules
|
|
36
|
+
The target names a declared Procedure. `http` sources use POST/PUT/PATCH/DELETE and an `/api/` path. Path parameters bind to corresponding declared input fields and override JSON-body values. The generated REST module retains the Procedure's authorization and validates boundary input.
|
|
69
37
|
|
|
70
|
-
|
|
71
|
-
|---|---|---|
|
|
72
|
-
| parse | `path` starts with `/`. | `INVALID_MANIFEST_ENVELOPE` |
|
|
73
|
-
| validate | `path` starts with `/api/`, so adapters can route public pages and Procedure endpoints without ambiguity. | `TRIGGER_PATH_INVALID` |
|
|
74
|
-
| validate | `(method, path)` is unique across every `http` Trigger. | `TRIGGER_PATH_COLLISION`, naming the Trigger that claimed it first. |
|
|
75
|
-
| boot | `path` falls outside the adapter's reserved prefixes. | `TRIGGER_PATH_INVALID` |
|
|
38
|
+
An MCP source is `{ kind: mcp, surface: public }` or admin. The selected MCP module exposes the Procedure as a snake-case tool with its description, [tool hints](procedure.md#mcp-tool-hints) and requires checks.
|
|
76
39
|
|
|
77
|
-
|
|
40
|
+
By default, pair every HTTP Trigger with an MCP Trigger so the same operation is reachable by the user's AI. `mantle generate` warns when a Procedure has HTTP exposure but no MCP exposure, suggesting `surface: admin` for an admin-only Procedure and `public` otherwise. Triggers still decide every Procedure surface: intentional asymmetric exposure is allowed and generation succeeds.
|
|
78
41
|
|
|
79
|
-
|
|
42
|
+
Lifecycle and schedule sources are rejected at generation with `GENERATE_UNSUPPORTED`, including disabled schedules. Use an app-owned handler or scheduler. For signed webhooks, verify the original raw Request in the app and call a generated Procedure with validated input; do not route it through a JSON boundary before signature verification.
|
|
80
43
|
|
|
81
|
-
|
|
82
|
-
|---|---|
|
|
83
|
-
| Path params | Each `{param}` binds to the identically named field on the target Procedure's `input`, which must declare it. |
|
|
84
|
-
| Precedence | The invocation merges the body first and the path params second, so **the path wins** over a same-named body field. |
|
|
85
|
-
| Trailing slash | `/api/posts` and `/api/posts/` are the same route; the root `/` is preserved. |
|
|
86
|
-
| Percent-encoding | Each request segment is decoded once, so `/api/by%2Dtag` matches the literal `/api/by-tag`. Malformed encoding such as `%GG` is a routing miss (404), not a 500. |
|
|
87
|
-
| Body | Must be a JSON object. Anything else is `INPUT_VALIDATION_FAILED` (400) with *HTTP Trigger request body must be a JSON object*. A body over 1 MiB is the same code at 413. |
|
|
88
|
-
| Empty body | A `DELETE`, or any request without a JSON content type, is treated as `{}` — bind those inputs through path params. |
|
|
44
|
+
## Input rules
|
|
89
45
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
46
|
+
The admin MCP tool below lists `reason` and `closed` without the rules, and its
|
|
47
|
+
description ends "'reason' is required when 'closed' is false."; a call with
|
|
48
|
+
`closed: false` and no `reason` fails with `INPUT_VALIDATION_FAILED` at
|
|
49
|
+
`procedures/set-ticket/input/reason` (the error path is
|
|
50
|
+
`procedures/<name>/input/<field>`). See [surface contracts](surface.md) for the
|
|
51
|
+
supported rules.
|
|
93
52
|
|
|
94
53
|
```yaml
|
|
95
|
-
apiVersion: cms.mantle.aotter.net/
|
|
96
|
-
kind:
|
|
97
|
-
metadata:
|
|
98
|
-
name: approve-purchase-order-mcp
|
|
54
|
+
apiVersion: cms.mantle.aotter.net/v2
|
|
55
|
+
kind: Procedure
|
|
56
|
+
metadata: { name: set-ticket }
|
|
99
57
|
spec:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
`surface` is **discovery only**. It decides which tools appear in `tools/list` on which endpoint; it authorizes nothing. The target Procedure's `requires.auth.all` predicates and its optional guard are re-evaluated on every `tools/call` against the authenticated caller, exactly as they are over HTTP. A `public`-surface Procedure that requires `ctx.staff` is discoverable on `/mcp` and will still be denied there.
|
|
113
|
-
|
|
114
|
-
The tool name is derived from the **Procedure's** `metadata.name`, not the Trigger's: lower-cased, with `-` replaced by `_`. Only one Trigger may claim a given `(surface, tool name)` pair; a second is `MCP_TOOL_NAME_COLLISION`. The same code also fires when the mangled name hits a reserved generic tool name or prefix, or a Schema's or another Procedure's segment — see [Reserved names](./manifest.md#reserved-names). A Procedure exposed this way should carry `spec.description`; a missing one is the `MCP_TOOL_DESCRIPTION_MISSING` warning, because the catalog's generated fallback tells an agent nothing about when to call the tool. A write tool that requires `expectedVersion` also needs a View on the same surface that exposes that collection's `version`; otherwise the tool is listed but uncallable, and validation warns with `MCP_TOOL_INPUT_UNREACHABLE`.
|
|
115
|
-
|
|
116
|
-
The tool carries the Procedure's `title` and `description`, with a short authorization summary appended to the description. `output` is not surfaced; MCP clients infer the response shape from the `tools/call` result. See [MCP and agents](../concepts/mcp-and-agents.md).
|
|
117
|
-
|
|
118
|
-
## `lifecycle` source
|
|
119
|
-
|
|
120
|
-
```yaml
|
|
121
|
-
apiVersion: cms.mantle.aotter.net/v1
|
|
58
|
+
description: Open or close a ticket.
|
|
59
|
+
input:
|
|
60
|
+
type: object
|
|
61
|
+
required: [id, closed]
|
|
62
|
+
properties: { id: { type: string }, closed: { type: boolean }, reason: { type: string, maxLength: 200 } }
|
|
63
|
+
additionalProperties: false
|
|
64
|
+
if: { properties: { closed: { const: false } }, required: [closed] }
|
|
65
|
+
then: { required: [reason] }
|
|
66
|
+
output: { type: object }
|
|
67
|
+
handler: { sql: 'UPDATE tickets SET closed=input.closed WHERE id=input.id RETURNING id,closed' }
|
|
68
|
+
---
|
|
69
|
+
apiVersion: cms.mantle.aotter.net/v2
|
|
122
70
|
kind: Trigger
|
|
123
|
-
metadata:
|
|
124
|
-
name: 010-verify-purchase-token
|
|
71
|
+
metadata: { name: set-ticket-mcp }
|
|
125
72
|
spec:
|
|
126
|
-
source:
|
|
127
|
-
|
|
128
|
-
schema: purchase-orders
|
|
129
|
-
on: [before_create]
|
|
130
|
-
errorPolicy: abort
|
|
131
|
-
target:
|
|
132
|
-
procedure: verify-purchase-token
|
|
73
|
+
source: { kind: mcp, surface: admin }
|
|
74
|
+
target: { procedure: set-ticket }
|
|
133
75
|
```
|
|
134
76
|
|
|
135
|
-
|
|
136
|
-
|---|---|---|---|---|
|
|
137
|
-
| `schema` | string | yes | — | A declared Schema (`LIFECYCLE_SCHEMA_UNKNOWN`). |
|
|
138
|
-
| `on` | `LifecycleHook[]` | yes | — | Non-empty; every entry from the closed list below. |
|
|
139
|
-
| `errorPolicy` | `abort` \| `continue` | no | `abort` for `before_*`, `continue` for `after_*` | See below. |
|
|
140
|
-
|
|
141
|
-
`errorPolicy: abort` is rejected at parse time when **any** `after_*` hook appears in `on`: an `after_*` hook runs once the response has already been sent, so an abort could never reach the caller. Split the `after_*` hooks into their own Trigger, or declare `continue`.
|
|
142
|
-
|
|
143
|
-
> **Info**
|
|
144
|
-
> `Schema.spec.lifecycle` (`publishing` / `operational`) is a different domain that shares the word. That setting governs which states an entry may be in; a lifecycle Trigger governs what fires around a mutation. See [Schema](./schema.md#lifecycle).
|
|
145
|
-
|
|
146
|
-
### Hooks
|
|
147
|
-
|
|
148
|
-
| Hook | Fires |
|
|
149
|
-
|---|---|
|
|
150
|
-
| `before_create` | Before the insert. |
|
|
151
|
-
| `after_create` | After the insert. |
|
|
152
|
-
| `before_update` | Before an update **or** any status transition whose target is not `published` — this includes unpublish and archive. |
|
|
153
|
-
| `after_update` | After an update or such a transition. |
|
|
154
|
-
| `before_delete` | Before the delete. |
|
|
155
|
-
| `after_delete` | After the delete, only when a row was actually removed. |
|
|
156
|
-
| `before_publish` | Before a transition to `published`. |
|
|
157
|
-
| `after_publish` | After a transition to `published`. |
|
|
158
|
-
|
|
159
|
-
There are no unpublish-specific or archive-specific hooks. Do not read `before_update` / `after_update` as edit-only.
|
|
160
|
-
|
|
161
|
-
### Error policy
|
|
162
|
-
|
|
163
|
-
| Phase | Default | Behavior |
|
|
164
|
-
|---|---|---|
|
|
165
|
-
| `before_*` | `abort` | A throwing hook cancels the surrounding mutation and the caller receives the hook's own diagnostic. A hook that rejects a write on purpose raises `LIFECYCLE_HOOK_REJECTED` (409). Under `continue` the failure is logged and the mutation proceeds. |
|
|
166
|
-
| `after_*` | `continue` | The committed mutation stands. On the inline or `waitUntil` path a failure is logged and swallowed. With a deferred dispatcher wired in, the failure reaches the delivery adapter so its at-least-once retry and dead-letter policy can run. Neither path ever rolls back. |
|
|
167
|
-
|
|
168
|
-
### Handler input and `ctx.event`
|
|
169
|
-
|
|
170
|
-
Hook input is phase-specific.
|
|
171
|
-
|
|
172
|
-
| Phase | Handler input |
|
|
173
|
-
|---|---|
|
|
174
|
-
| `before_*` | The original **pre-projection** Procedure input, so a hook can read side-channel fields the row never stores — a CAPTCHA token, a client nonce. It falls back to the row's `data` when there is no caller input. |
|
|
175
|
-
| `after_*` | The persisted `entry.data` only. Deferred envelopes deliberately never carry arbitrary request input. |
|
|
176
|
-
|
|
177
|
-
Every hook handler also receives `ctx.event`:
|
|
178
|
-
|
|
179
|
-
| Field | Value |
|
|
180
|
-
|---|---|
|
|
181
|
-
| `id` | Stable event id, unchanged across enqueue fallback and deferred retries. |
|
|
182
|
-
| `trigger` | The firing Trigger's `metadata.name`. |
|
|
183
|
-
| `hook` | The hook name. |
|
|
184
|
-
| `schema` | The watched Schema name. |
|
|
185
|
-
| `entry` | `null` only on `before_create`; the pre-mutation row for the other `before_*` hooks; the persisted post-mutation row for every `after_*`. |
|
|
186
|
-
|
|
187
|
-
Deferred handlers key on `${ctx.event.id}:${ctx.event.trigger}`. See [Procedure](./procedure.md#conflicts-and-idempotency).
|
|
188
|
-
|
|
189
|
-
### Ordering and coverage
|
|
190
|
-
|
|
191
|
-
When several lifecycle Triggers bind the same `(schema, hook)`, they fire **alphabetically by `Trigger.metadata.name`**. Choose names that sort the way you want them to run — the `010-`, `020-` convention exists for exactly this, and the code generator handles the leading digits.
|
|
192
|
-
|
|
193
|
-
Hooks are wired through a repository decorator that wraps the single entry-writer chokepoint, so **Staff MCP, Admin and builtin Procedure writes all fire the same hooks**. There is no write path that bypasses them.
|
|
194
|
-
|
|
195
|
-
For deferred `after_*` delivery, the ordered Trigger-name list is captured into one versioned envelope carrying the persisted row and a small identity snapshot. Every captured Trigger runs before a failure is reported back, so a retry may replay Triggers that already succeeded — hence the idempotency key. Queue acceptance is not transactional with the entry write, the `waitUntil` fallback is best-effort, and exactly-once is not promised. See [Deferred hooks on Queues](../cloudflare/deferred-hooks-queues.md).
|
|
196
|
-
|
|
197
|
-
## Source
|
|
198
|
-
|
|
199
|
-
- [`packages/mantle-spec/src/domain/model/ManifestGrammar.ts`](../../../packages/mantle-spec/src/domain/model/ManifestGrammar.ts)
|
|
200
|
-
- [`packages/mantle-spec/src/domain/service/ManifestParser.ts`](../../../packages/mantle-spec/src/domain/service/ManifestParser.ts)
|
|
201
|
-
- [`packages/mantle-spec/src/domain/service/ManifestGraphValidator.ts`](../../../packages/mantle-spec/src/domain/service/ManifestGraphValidator.ts)
|
|
202
|
-
- [`packages/mantle-spec/src/domain/service/McpToolNaming.ts`](../../../packages/mantle-spec/src/domain/service/McpToolNaming.ts)
|
|
203
|
-
- [`packages/mantle-runtime/src/domain/service/PathMatcher.ts`](../../../packages/mantle-runtime/src/domain/service/PathMatcher.ts)
|
|
204
|
-
- [`packages/mantle-runtime/src/domain/service/TriggerIndex.ts`](../../../packages/mantle-runtime/src/domain/service/TriggerIndex.ts)
|
|
205
|
-
- [`packages/mantle-runtime/src/usecase/lifecycle/RunLifecycleHooksUseCase.ts`](../../../packages/mantle-runtime/src/usecase/lifecycle/RunLifecycleHooksUseCase.ts)
|
|
206
|
-
- [`packages/mantle-runtime/src/infrastructure/persistence/LifecycleHookingEntryRepository.ts`](../../../packages/mantle-runtime/src/infrastructure/persistence/LifecycleHookingEntryRepository.ts)
|
|
207
|
-
- [`packages/mantle-runtime/src/domain/port/DeferredHookDispatcher.ts`](../../../packages/mantle-runtime/src/domain/port/DeferredHookDispatcher.ts)
|
|
208
|
-
- [`packages/mantle-runtime/src/infrastructure/http/createMantleRequestHandler.ts`](../../../packages/mantle-runtime/src/infrastructure/http/createMantleRequestHandler.ts)
|
|
209
|
-
- [`packages/mantle-runtime/src/infrastructure/http/readJsonBody.ts`](../../../packages/mantle-runtime/src/infrastructure/http/readJsonBody.ts)
|
|
210
|
-
- [`packages/mantle-runtime/src/usecase/boot/ValidateBootUseCase.ts`](../../../packages/mantle-runtime/src/usecase/boot/ValidateBootUseCase.ts)
|
|
211
|
-
- [`packages/mantle/src/codegen/emitMantleModule.ts`](../../../packages/mantle/src/codegen/emitMantleModule.ts)
|
|
212
|
-
- [`packages/adapters/cloudflare/src/worker/createMantleWorker.ts`](../../../packages/adapters/cloudflare/src/worker/createMantleWorker.ts)
|
|
213
|
-
- [`packages/adapters/cloudflare/src/mount/mountMcp.ts`](../../../packages/adapters/cloudflare/src/mount/mountMcp.ts)
|
|
77
|
+
See [surfaces](surface.md) for mounted paths, error mapping and origin checks.
|
|
@@ -1,263 +1,44 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: View field reference — declarative and SQL forms, filter AST, params, pagination, REST and MCP surfaces, and every diagnostic they raise.
|
|
3
|
-
---
|
|
4
1
|
# View
|
|
5
2
|
|
|
6
|
-
A View
|
|
3
|
+
A View requires `surface: public | admin | internal` and one `sql` SELECT. Optional keys include title, description, input, requires, restrict, uiSchema (admin only), and cache. The app imports its generated typed function and supplies a native handle, verified Caller and driver-ready input; a JSON input (an array read by `json_each(input.ids)`) takes its authored array or object, which the generated query serializes.
|
|
7
4
|
|
|
8
|
-
##
|
|
5
|
+
## SQL
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
|---|---|---|---|---|
|
|
12
|
-
| `title` | LocalizedText | no | Title-Cased `metadata.name` | Admin report label. Non-empty string or locale map. |
|
|
13
|
-
| `uiSchema` | object | no | — | Only on `surface: staff`; only the key `list`. Violations are `VIEW_UI_INVALID`. |
|
|
14
|
-
| `from` | string | exactly one of `from` / `sql` | — | Name of a declared Schema (`VIEW_FROM_UNKNOWN_SCHEMA`). The declarative form. |
|
|
15
|
-
| `sql` | string | exactly one of `from` / `sql` | — | One SQLite `SELECT`. See [`sql`](#sql). |
|
|
16
|
-
| `surface` | `public` \| `staff` \| `internal` | yes | — | Decides where the View mounts. See [Surfaces](#surfaces). |
|
|
17
|
-
| `cache` | `{ sharedMaxAge }` | no | — | Anonymous REST shared-cache hint. `sharedMaxAge` is an integer from 1 to 86400. Only an unguarded, declarative public View over a publishing Schema may declare it. |
|
|
18
|
-
| `requires` | AuthorizationRequirements | no | — | `auth.all` predicates plus one optional `guard.procedure`. See [Authorization](./authorization.md). |
|
|
19
|
-
| `filter` | FilterAst | no | — | `from` form only. See [Filter AST](#filter-ast). |
|
|
20
|
-
| `fields` | `string[]` | no | every column | `from` form only. Projection. Not shape-validated by the parser. |
|
|
21
|
-
| `orderBy` | `{ field, direction? }[]` | no | `[]` | `from` form only. `direction` defaults to `asc`. |
|
|
22
|
-
| `limit` | number | no | 50 at runtime | `from` and `sql`. Not shape-validated by the parser; clamped at request time. |
|
|
23
|
-
| `params` | JSON Schema | no | — | `type: object` with `properties`. Reserved: `page`, `show`, `cursor`. |
|
|
7
|
+
PostgreSQL syntax is parsed and checked at generation. Reads may reference declared Schemas, CTEs and reusable internal Views; no auth/system tables or arbitrary external relations. The compiler adds scope, TTL, publication and translation-parent visibility at every relation. SQL policy is not injected at request time.
|
|
24
8
|
|
|
25
|
-
|
|
9
|
+
The SQL each dialect accepts, for Views and Procedures alike, is listed in [the SQL reference](sql.md); [SQL patterns](../guides/sql-patterns.md) shows the common ones. Unsupported SQL fails with a source position; generation is the authority for each target.
|
|
26
10
|
|
|
27
|
-
|
|
11
|
+
`*` and `t.*` expand to the Schema's declared fields only. Select `id`, `version`, `created_at` and `updated_at` by name when a client needs them (a write's `expectedVersion`, a detail link, keyset paging).
|
|
28
12
|
|
|
29
|
-
|
|
30
|
-
apiVersion: cms.mantle.aotter.net/v1
|
|
31
|
-
kind: View
|
|
32
|
-
metadata:
|
|
33
|
-
name: my-support-requests
|
|
34
|
-
spec:
|
|
35
|
-
title: { en: My support requests, "zh-TW": 我的客服請求 }
|
|
36
|
-
surface: public
|
|
37
|
-
from: support-requests
|
|
38
|
-
requires:
|
|
39
|
-
auth:
|
|
40
|
-
all: [ctx.user]
|
|
41
|
-
fields: [id, ticketNumber, subject, requestStatus, submittedAt]
|
|
42
|
-
filter:
|
|
43
|
-
and:
|
|
44
|
-
- eq: { field: submittedBy, value: { "$ctx.user": "id" } }
|
|
45
|
-
- eq: { field: requestStatus, value: { $param: requestStatus } }
|
|
46
|
-
orderBy:
|
|
47
|
-
- { field: submittedAt, direction: desc }
|
|
48
|
-
limit: 100
|
|
49
|
-
params:
|
|
50
|
-
type: object
|
|
51
|
-
required: [requestStatus]
|
|
52
|
-
properties:
|
|
53
|
-
requestStatus: { type: string, enum: [open, waiting, closed] }
|
|
54
|
-
```
|
|
13
|
+
OFFSET, arbitrary functions/relations, DDL and transaction control are not a read escape hatch. Use keyset paging. Select latitude/longitude explicitly instead of native geo projections.
|
|
55
14
|
|
|
56
|
-
|
|
15
|
+
## Restrict
|
|
57
16
|
|
|
58
|
-
|
|
17
|
+
`restrict` narrows one target by Schema: `restrict: { orders: "region IN auth.user('region')" }`. Each key is a Schema the SQL reads; each value uses the [scope](schema.md#field-scope) grammar, and a `= auth.uid()` term only on `author_id` or that Schema's own owner column. The effective rule is the Schema's scope AND the restrict. `{ all: true }` never lifts a restrict term: such a caller is refused with `AUTH_DENIED`. A View or Procedure that reads a restricted View carries that View's restrict too, so composing never widens it. A View with `restrict` cannot use a shared cache.
|
|
59
18
|
|
|
60
|
-
|
|
61
|
-
spec:
|
|
62
|
-
surface: public
|
|
63
|
-
from: published-notes
|
|
64
|
-
cache: { sharedMaxAge: 3600 }
|
|
65
|
-
```
|
|
19
|
+
## Search and totals
|
|
66
20
|
|
|
67
|
-
|
|
21
|
+
`mantle.search(<alias>, <text>)` matches the Schema's declared `searchableFields`, and `mantle.search_rank(<alias>)`
|
|
22
|
+
orders by relevance; qualify both with `mantle.`. An optional search reads
|
|
23
|
+
`WHERE p.active AND (input.q IS NULL OR mantle.search(p, input.q))`, and a ranked one
|
|
24
|
+
`WHERE mantle.search(p, input.q) ORDER BY mantle.search_rank(p), p.id` (see `examples/reference-service` `catalog.yaml`
|
|
25
|
+
for cursor paging over the rank).
|
|
68
26
|
|
|
69
|
-
|
|
27
|
+
Views using `mantle.search`, Store search and Admin list search share the dialect search: SQLite/D1 use FTS for queries of 3 or more characters (shorter queries use LIKE); PostgreSQL uses ILIKE over the declared fields and scans by default. A View does not make PostgreSQL search faster. For large PostgreSQL tables, the application's agent adds trigram indexes in a migration, which ILIKE then uses with no code change:
|
|
70
28
|
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
metadata:
|
|
75
|
-
name: order-lines-by-status
|
|
76
|
-
spec:
|
|
77
|
-
title: Order lines by status
|
|
78
|
-
surface: staff
|
|
79
|
-
sql: |
|
|
80
|
-
SELECT o._mantle_id AS orderId,
|
|
81
|
-
o.orderNumber AS orderNumber,
|
|
82
|
-
json_extract(line.value, '$.sku') AS sku,
|
|
83
|
-
json_extract(line.value, '$.quantity') AS quantity
|
|
84
|
-
FROM orders AS o
|
|
85
|
-
JOIN json_each(o.lines) AS line
|
|
86
|
-
WHERE o.orderStatus = :orderStatus
|
|
87
|
-
ORDER BY o.orderNumber ASC
|
|
88
|
-
params:
|
|
89
|
-
type: object
|
|
90
|
-
required: [orderStatus]
|
|
91
|
-
properties:
|
|
92
|
-
orderStatus: { type: string, enum: [paid, shipped, cancelled] }
|
|
93
|
-
limit: 200
|
|
94
|
-
uiSchema:
|
|
95
|
-
list:
|
|
96
|
-
columns: [orderNumber, sku, quantity]
|
|
97
|
-
searchFields: [orderNumber, sku]
|
|
98
|
-
filterFields: [sku]
|
|
29
|
+
```sql
|
|
30
|
+
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
|
31
|
+
CREATE INDEX articles_title_trgm ON articles USING gin (title gin_trgm_ops);
|
|
99
32
|
```
|
|
100
33
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
`filter` is a tree. Every node is an object with **exactly one** key: a comparison operator, or `and` / `or`.
|
|
104
|
-
|
|
105
|
-
| Key | Shape | Rules |
|
|
106
|
-
|---|---|---|
|
|
107
|
-
| `eq`, `gt`, `gte`, `lt`, `lte` | `{ field, value }` | Only those two keys. `field` is a non-empty string. `value` must be present; `null` is a legal value. |
|
|
108
|
-
| `and`, `or` | array of nodes | Non-empty. Nests to any depth. |
|
|
109
|
-
|
|
110
|
-
Any other key, a node with zero or several keys, an array node, or an empty `and` / `or` is `INVALID_MANIFEST_ENVELOPE` at the node's pointer.
|
|
111
|
-
|
|
112
|
-
### Value forms
|
|
113
|
-
|
|
114
|
-
| Form | Written as | Rules |
|
|
115
|
-
|---|---|---|
|
|
116
|
-
| Literal | `value: published` | Any JSON scalar, including `null`. Compared as written. |
|
|
117
|
-
| Param reference | `value: { $param: locale }` | The name must be declared under `params.properties` (`VIEW_FILTER_PARAM_REF_UNKNOWN`, also raised when no `params` is declared at all or the name is empty) and listed in `params.required` (`VIEW_FILTER_PARAM_REF_NOT_REQUIRED`). |
|
|
118
|
-
| Caller identity | `value: { "$ctx.user": "id" }` | The sentinel is closed: exactly one key, the literal string `id`, and only under `eq`. Anything else is `VIEW_FILTER_CTX_USER_REF_INVALID`. |
|
|
119
|
-
|
|
120
|
-
The identity sentinel carries two further graph-level obligations, checked once `from` resolves:
|
|
121
|
-
|
|
122
|
-
| Rule | Diagnostic |
|
|
123
|
-
|---|---|
|
|
124
|
-
| The View declares `ctx.user` in `requires.auth.all`. | `VIEW_FILTER_CTX_USER_REF_REQUIRES_AUTH` at `/spec/requires/auth/all` |
|
|
125
|
-
| The compared field is the leftmost field of some `uniqueIndexes` or `indexes` tuple on the source Schema. | `VIEW_FILTER_CTX_USER_REF_REQUIRES_INDEX` |
|
|
126
|
-
|
|
127
|
-
Provider claims and platform identities are deliberately out of reach; `id` is the only bindable identity value.
|
|
128
|
-
|
|
129
|
-
### Graph-level field checks
|
|
130
|
-
|
|
131
|
-
For a `from` View, the valid field names are the top-level keys of the Schema's `properties` plus the [reserved entry columns](./schema.md#reserved-entry-columns). Unknown names are rejected per site:
|
|
132
|
-
|
|
133
|
-
| Location | Diagnostic |
|
|
134
|
-
|---|---|
|
|
135
|
-
| `filter.<op>.field` | `VIEW_FILTER_FIELD_NOT_IN_SCHEMA` |
|
|
136
|
-
| `fields[i]`, `orderBy[i].field` | `VIEW_FIELD_NOT_IN_SCHEMA` |
|
|
137
|
-
| `uiSchema.list.<key>[i]` | `VIEW_UI_INVALID` |
|
|
138
|
-
| `from` itself | `VIEW_FROM_UNKNOWN_SCHEMA` (no further field checks run) |
|
|
139
|
-
|
|
140
|
-
None of these run for a `sql` View — its output columns are whatever the `SELECT` produces.
|
|
141
|
-
|
|
142
|
-
## `sql`
|
|
143
|
-
|
|
144
|
-
One statement, read-only, compiled and bound by the runtime.
|
|
145
|
-
|
|
146
|
-
| Rule | Effect |
|
|
147
|
-
|---|---|
|
|
148
|
-
| The trimmed text matches `/^select\b/i` and contains no `;`. | Otherwise `INVALID_MANIFEST_ENVELOPE` at `/spec/sql`: `View.spec.sql must be one SELECT statement without a semicolon`. |
|
|
149
|
-
| Every `:name` occurrence is declared in `params.properties`. | `VIEW_FILTER_PARAM_REF_UNKNOWN` |
|
|
150
|
-
| Every `:name` occurrence is listed in `params.required`. | `VIEW_FILTER_PARAM_REF_NOT_REQUIRED` |
|
|
151
|
-
| `filter`, `fields` and `orderBy` are absent. | `INVALID_MANIFEST_ENVELOPE` at `/spec/<key>` |
|
|
152
|
-
| Tables are Schema names. | Each Schema is exposed as a logical table reconciled at boot. Names containing `-` must be double-quoted: `FROM "post-translations"`. |
|
|
153
|
-
|
|
154
|
-
Bound params are passed as positional values; caller input is never interpolated into the statement. SQLite JSON functions are available, so `json_each` and `json_extract` can unnest and project array or object members of `data` — the SQL example above does both.
|
|
155
|
-
|
|
156
|
-
> **Warning**
|
|
157
|
-
> `sql` Views are native SQLite. `mantle validate` prepares each statement against an empty SQLite database containing only the declared Schema tables; an undeclared table, syntax error or unknown column is `INVALID_MANIFEST_ENVELOPE` at `/spec/sql`. Programmatic validation runs the same check when the host supplies `sqlViewSandbox`; without that port it is deferred to the host's admission gate. On a storage adapter that does not support the native dialect the View fails at prepare time with `VIEW_DIALECT_UNSUPPORTED`, naming the dialects that adapter does support.
|
|
158
|
-
|
|
159
|
-
## `params`
|
|
160
|
-
|
|
161
|
-
`params` declares the caller-supplied query shape and is walked by the [JSON Schema subset](./schema.md#json-schema-subset) validator.
|
|
162
|
-
|
|
163
|
-
| Rule | Diagnostic |
|
|
164
|
-
|---|---|
|
|
165
|
-
| A non-array object. | `VIEW_PARAMS_INVALID_SHAPE` at `/spec/params` |
|
|
166
|
-
| `type: "object"`. | `VIEW_PARAMS_INVALID_SHAPE` at `/spec/params/type` |
|
|
167
|
-
| `properties` is declared and is an object. | `VIEW_PARAMS_INVALID_SHAPE` at `/spec/params/properties` |
|
|
168
|
-
| No property named `page`, `show` or `cursor`. | `VIEW_PARAMS_RESERVED_NAME` |
|
|
169
|
-
|
|
170
|
-
The runtime owns those three names for pagination, which is why they cannot be redeclared. Rename the domain param (`pageSize`, `showArchived`).
|
|
171
|
-
|
|
172
|
-
## `orderBy`, `fields` and `limit`
|
|
173
|
-
|
|
174
|
-
`orderBy` is an array of objects accepting only `field` and `direction`. A non-array value, a non-object entry, a missing or empty `field`, or a `direction` other than `asc` / `desc` is `VIEW_ORDERBY_INVALID` at the offending pointer; an unrecognized key inside an entry is `INVALID_MANIFEST_ENVELOPE`.
|
|
175
|
-
|
|
176
|
-
`fields` and `limit` receive **no shape validation in the parser**. A `fields` value that is not an array of strings, or a `limit` that is not a number, is not reported as a diagnostic — it fails later, at graph validation or at request time. Declare them as documented.
|
|
177
|
-
|
|
178
|
-
`limit` is a per-View cap, and the runtime clamps around it on every call:
|
|
179
|
-
|
|
180
|
-
| Input | Result |
|
|
181
|
-
|---|---|
|
|
182
|
-
| `limit` missing, non-numeric, non-finite or `<= 0` | Cap is 50. |
|
|
183
|
-
| `limit` valid | Cap is `min(floor(limit), 500)`. 500 is the hard ceiling for any single round-trip. |
|
|
184
|
-
| `?show=` missing or not a positive finite number | Page size is the cap. |
|
|
185
|
-
| `?show=` valid | Page size is `min(floor(show), cap)`. |
|
|
186
|
-
| `?page=` missing or below 1 | Page 1. |
|
|
187
|
-
|
|
188
|
-
## `uiSchema.list`
|
|
189
|
-
|
|
190
|
-
Admin presentation for `surface: staff` Views. Declaring `uiSchema` on a public View is `VIEW_UI_INVALID`, as is any root key other than `list` or any key inside `list` other than the three below.
|
|
191
|
-
|
|
192
|
-
| Key | Meaning |
|
|
193
|
-
|---|---|
|
|
194
|
-
| `columns` | Ordered columns for the Admin report table and the default CSV column set. |
|
|
195
|
-
| `searchFields` | Output fields the Admin substring search box covers. |
|
|
196
|
-
| `filterFields` | Output fields offered as exact-match filters (`?filter.<field>=`). |
|
|
197
|
-
|
|
198
|
-
Each is an array of non-empty strings with no duplicates within the key. The characters `"`, `\` and NUL are rejected in a field name. The names are **View output field names** — SQL aliases for a `sql` View; for a `from` View they are additionally checked against the Schema's properties plus reserved columns.
|
|
199
|
-
|
|
200
|
-
Admin applies search and filters before pagination, rejecting a search term or filter value longer than 200 characters and any `filter.<field>` key that is not a declared `filterFields` entry. `GET /admin/api/views/<name>/export` streams the same query as CSV covering every matching row, not only the visible page; its columns come from `uiSchema.list.columns`, falling back to `spec.fields` and then to the union of keys in the returned rows.
|
|
201
|
-
|
|
202
|
-
## Surfaces
|
|
203
|
-
|
|
204
|
-
| `surface` | REST | MCP tool | Admin |
|
|
205
|
-
|---|---|---|---|
|
|
206
|
-
| `public` | `GET /api/views/<name>`, plus a catalog at `GET /api/views` | `query_view_<segment>` on `/mcp` | Also mounted at `GET /admin/api/views/<name>` and `/export` behind the staff gate |
|
|
207
|
-
| `staff` | `GET /admin/api/views/<name>` and `/admin/api/views/<name>/export` — not mounted publicly | `query_view_<segment>` on `/mcp/staff` | Report sidebar |
|
|
208
|
-
| `internal` | Not mounted | Not mounted | Not listed or mounted |
|
|
209
|
-
|
|
210
|
-
For a complete generated-binding example, see [Typed queries](../guides/typed-queries.md).
|
|
211
|
-
|
|
212
|
-
An `internal` View remains in the compiled plan for host code to call through `MantleRuntime.executeView`. It is an exposure policy, not an authorization bypass: `requires` and guards still evaluate against the `ctx` supplied by the host. Shared HTTP caching is invalid because no adapter owns an HTTP response for the View.
|
|
213
|
-
|
|
214
|
-
A `public` declarative View over a `publishing` Schema reads **published rows only**, on every transport. The runtime adds `status = published` to the compiled query whether or not the filter spells it out; writing it is allowed and redundant, and comparing `status` to any other value is rejected at validate time (`VIEW_PUBLIC_STATUS_INVALID`). Staff Views see every status. `operational` Schemas create rows as `published`, so nothing is added. SQL Views (`spec.sql`) are the author's own statement and receive no injected predicate. Decision record: ADR-0025.
|
|
215
|
-
|
|
216
|
-
`<segment>` is `metadata.name` lower-cased with `-` replaced by `_`. Two Views that mangle to the same segment collide with `MCP_TOOL_NAME_COLLISION`. Admin also serves the manifest listing `GET /admin/api/views-manifest`. Surface choice is visibility, not authorization: `requires` still gates every call on both transports. See [Surfaces](./surface.md) and [MCP and agents](../concepts/mcp-and-agents.md).
|
|
217
|
-
|
|
218
|
-
The MCP `inputSchema` is `params.properties` plus `page` and `show` as optional numbers, carrying `params.required` through unchanged; the tool is annotated `readOnlyHint: true`.
|
|
219
|
-
|
|
220
|
-
## REST contract
|
|
221
|
-
|
|
222
|
-
Pagination uses the two reserved knobs, `?page=` (1-indexed) and `?show=`. The response envelope is:
|
|
223
|
-
|
|
224
|
-
```json
|
|
225
|
-
{ "ok": true, "data": { "rows": [], "page": 1, "show": 20, "hasMore": true } }
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
`hasMore` is the lazy form — `rows.length === show`. There is no COUNT query and no `LIMIT n+1` probe, so a final page that exactly fills `show` reports `hasMore: true` and the next page comes back empty.
|
|
229
|
-
|
|
230
|
-
A failure returns `{ ok: false, diagnostic }` with the diagnostic's mapped status. Static `requires.auth` runs before parameter validation, so an unauthorized caller never learns the parameter shape; a `guard` Procedure runs after validation and authorizes the whole query rather than filtering rows.
|
|
231
|
-
|
|
232
|
-
### Param coercion
|
|
34
|
+
Store keeps `find`/`first` search and `count`. `count` scans every matching row; for large tables or frequently shown totals, use an internal View with indexed predicates or avoid exact totals. Aggregates still scan matching rows. See [Store reads](../guides/typed-queries.md#store-reads-and-writes).
|
|
233
35
|
|
|
234
|
-
|
|
36
|
+
## Results and paging
|
|
235
37
|
|
|
236
|
-
|
|
237
|
-
|---|---|---|
|
|
238
|
-
| `string`, or `type` omitted | Used as-is. | — |
|
|
239
|
-
| `integer` | `parseInt(raw, 10)` | The round-trip does not equal the trimmed input, so `"1.5"` and `"1abc"` fail. |
|
|
240
|
-
| `number` | `Number(raw)` | The result is not finite. |
|
|
241
|
-
| `boolean` | `"true"` / `"false"` | Any other text. |
|
|
242
|
-
| `enum` (with any of the above) | Coerced by `type` first, then checked for membership. | The coerced value is not in `enum`. |
|
|
243
|
-
| anything else | — | Unsupported on the REST surface. |
|
|
38
|
+
Each SELECT output needs a unique static name. Unquoted SQL identifiers fold to lower case; use an explicit quoted alias to preserve case (`r.reqStatus AS "reqStatus"`). Generation warns when an unaliased direct declared field would use its lower-case storage name. Declared-column lineage supplies generated types; computed outputs remain native/unknown, except a top-level output that is a JSON document by construction (a JSON aggregate or builder, a scalar subquery of one, or a `COALESCE` of those; see [SQL patterns](../guides/sql-patterns.md#a-row-with-its-children-in-one-read)), which is typed JSON. An output is non-null (`string`, not `string | null`) only when it reads unchanged a column its table declares NOT NULL (`id`, `version`, `created_at`, `updated_at`, a publishing `status`, or a [required](schema.md#fields-and-storage) field of an operational Schema) directly or through FROM subqueries; the right side of a LEFT JOIN, an aggregate, a column beside an aggregate without GROUP BY, a CTE and an expression stay nullable. SQL formats declared date-time/date outputs, while computed timestamps retain driver values. See [native execution](../guides/native-execution.md).
|
|
244
39
|
|
|
245
|
-
|
|
40
|
+
Bare `views/<encoded-name>.ts` returns row arrays. Proved pageable exposed/internal Views also receive native `paged/views/*`, returning `{ rows, nextCursor? }`. Selected REST/MCP boundaries use separate `paged/wire/views/*` SQL when declared integers require exact transport projections; bare modules also export `WireRow`. Indexed ordering after fixed equality prefixes ([index prefixes](schema.md#index-prefixes-for-paged-views)), non-null typed keys, complete groups and singleton joins/lookups are checked at generation. Unsupported internal paging retains its bare View; exposure requires a supported page contract. Aggregates still scan/group their sources: inspect EXPLAIN.
|
|
246
41
|
|
|
247
|
-
|
|
42
|
+
Publishing Schema fields may be NULL in drafts even when required, so public View paging cannot order by them. `published_at` is accepted by Store ordering but rejected as a View paging key. Use `ORDER BY id`, or keep the business date in an operational Schema as an indexed, required non-null field.
|
|
248
43
|
|
|
249
|
-
|
|
250
|
-
- [`packages/mantle-spec/src/domain/service/ManifestParser.ts`](../../../packages/mantle-spec/src/domain/service/ManifestParser.ts)
|
|
251
|
-
- [`packages/mantle-spec/src/domain/service/ManifestGraphValidator.ts`](../../../packages/mantle-spec/src/domain/service/ManifestGraphValidator.ts)
|
|
252
|
-
- [`packages/mantle-spec/src/domain/service/SchemaAdminUiChecker.ts`](../../../packages/mantle-spec/src/domain/service/SchemaAdminUiChecker.ts)
|
|
253
|
-
- [`packages/mantle-spec/src/domain/service/McpToolNaming.ts`](../../../packages/mantle-spec/src/domain/service/McpToolNaming.ts)
|
|
254
|
-
- [`packages/mantle-runtime/src/usecase/view/ExecuteViewUseCase.ts`](../../../packages/mantle-runtime/src/usecase/view/ExecuteViewUseCase.ts)
|
|
255
|
-
- [`packages/mantle-runtime/src/domain/service/ViewParamCoercer.ts`](../../../packages/mantle-runtime/src/domain/service/ViewParamCoercer.ts)
|
|
256
|
-
- [`packages/mantle-runtime/src/domain/service/Pagination.ts`](../../../packages/mantle-runtime/src/domain/service/Pagination.ts)
|
|
257
|
-
- [`packages/mantle-runtime/src/domain/service/CallableCapabilityProjector.ts`](../../../packages/mantle-runtime/src/domain/service/CallableCapabilityProjector.ts)
|
|
258
|
-
- [`packages/mantle-runtime/src/infrastructure/http/createMantleRequestHandler.ts`](../../../packages/mantle-runtime/src/infrastructure/http/createMantleRequestHandler.ts)
|
|
259
|
-
- [`packages/mantle-runtime/src/infrastructure/storage/SqliteViewCompiler.ts`](../../../packages/mantle-runtime/src/infrastructure/storage/SqliteViewCompiler.ts)
|
|
260
|
-
- [`packages/mantle-runtime/src/infrastructure/storage/SqliteMantleStorageAdapter.ts`](../../../packages/mantle-runtime/src/infrastructure/storage/SqliteMantleStorageAdapter.ts)
|
|
261
|
-
- [`packages/mantle-runtime/src/usecase/boot/ValidateBootUseCase.ts`](../../../packages/mantle-runtime/src/usecase/boot/ValidateBootUseCase.ts)
|
|
262
|
-
- [`packages/mantle-admin/src/mountMantleAdmin.ts`](../../../packages/mantle-admin/src/mountMantleAdmin.ts)
|
|
263
|
-
- [`packages/adapters/cloudflare/src/mount/mountRuntimeEndpoints.ts`](../../../packages/adapters/cloudflare/src/mount/mountRuntimeEndpoints.ts)
|
|
44
|
+
Internal Views have no public route/tool. Public and admin Views use selected REST/MCP/Admin bindings. `uiSchema.list` selects admin search/filter/display metadata; `uiSchema.nav.group/order/hidden` places an admin View in the sidebar ([sidebar](../guides/native-admin.md#sidebar)). See [surfaces](surface.md) for validation, paging and wire conversions and [typed queries](../guides/typed-queries.md) for a complete example.
|