@aotter/mantle 0.2.0-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 +180 -45
- 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/{spec → build/spec}/domain/model/ManifestGrammar.d.ts +30 -43
- package/dist/{spec → build/spec}/domain/model/RuntimePlan.d.ts +77 -3
- package/dist/{spec → build/spec}/domain/model/SqlIr.d.ts +39 -6
- package/dist/build/spec/domain/model/UserFields.d.ts +21 -0
- package/dist/{spec → build/spec}/domain/service/PlanFingerprint.d.ts +4 -1
- package/dist/{spec → build/spec}/kernel/diagnostic.d.ts +1 -30
- 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/{spec/domain/service/CloudflareCron.d.ts → kernel/cron.d.ts} +0 -1
- package/dist/{spec/domain/service/CloudflareCron.js → kernel/cron.js} +1 -6
- 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/{auth/emailTemplates.js → kernel/email.js} +13 -2
- 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/{cloudflare/r2Media.d.ts → kernel/r2-media.d.ts} +4 -5
- 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/{core/site.d.ts → kernel/site-types.d.ts} +38 -9
- 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 -37
- package/dist/testing/index.js +1 -43
- 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 -16
- 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/{reference-service → app-shell}/tsconfig.json +6 -2
- 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 +186 -108
- package/docs/handbook/cloudflare/chatgpt-sites.md +5 -112
- package/docs/handbook/cloudflare/deploy-and-operate.md +59 -87
- package/docs/handbook/cloudflare/media-r2.md +61 -82
- package/docs/handbook/cloudflare/service-entry.md +220 -119
- package/docs/handbook/concepts/authorization.md +10 -117
- package/docs/handbook/concepts/four-atoms.md +9 -92
- package/docs/handbook/concepts/lifecycle-and-locales.md +9 -80
- package/docs/handbook/concepts/mcp-and-agents.md +24 -116
- package/docs/handbook/concepts/procedures-and-triggers.md +5 -162
- package/docs/handbook/concepts/runtime-and-adapters.md +15 -183
- package/docs/handbook/concepts/views.md +10 -109
- package/docs/handbook/examples/hub.md +2 -18
- package/docs/handbook/guides/adapter-guide.md +11 -0
- package/docs/handbook/guides/admin-ui.md +113 -136
- package/docs/handbook/guides/agent-setup.md +32 -27
- 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 +210 -100
- package/docs/handbook/navigation.json +176 -30
- package/docs/handbook/reference/admin-descriptors.md +53 -0
- package/docs/handbook/reference/authorization.md +44 -52
- package/docs/handbook/reference/describe.md +56 -0
- package/docs/handbook/reference/diagnostics.md +19 -77
- package/docs/handbook/reference/features.md +45 -53
- package/docs/handbook/reference/manifest.md +6 -69
- package/docs/handbook/reference/procedure.md +11 -115
- package/docs/handbook/reference/schema.md +81 -172
- package/docs/handbook/reference/site-config.md +5 -65
- package/docs/handbook/reference/sql.md +64 -0
- package/docs/handbook/reference/surface.md +396 -93
- package/docs/handbook/reference/trigger.md +62 -89
- package/docs/handbook/reference/view.md +40 -158
- package/docs/handbook/releases/index.md +198 -12
- package/docs/handbook/start/agents.md +45 -0
- package/docs/handbook/start/overview.md +9 -56
- package/docs/handbook/start/project-and-cli.md +51 -131
- package/docs/handbook/start/quickstart-worker.md +38 -115
- package/docs/skills/develop/SKILL.md +77 -121
- package/docs/skills/integrate/SKILL.md +37 -84
- package/docs/skills/media-gc/SKILL.md +21 -8
- package/docs/skills/provision/SKILL.md +31 -87
- package/docs/skills/update/SKILL.md +20 -34
- package/docs/source/scripts/postgres-adapter.ts +101 -0
- package/docs/upgrade-0.1-to-0.2.md +26 -10
- package/package.json +120 -112
- package/skills/README.md +67 -0
- package/skills/mantle/SKILL.md +76 -0
- package/dist/admin/consent.d.ts +0 -17
- package/dist/admin/consent.d.ts.map +0 -1
- package/dist/admin/consent.js +0 -17
- package/dist/admin/consent.js.map +0 -1
- package/dist/admin/createAdminSurface.d.ts +0 -22
- package/dist/admin/createAdminSurface.d.ts.map +0 -1
- package/dist/admin/createAdminSurface.js +0 -589
- package/dist/admin/createAdminSurface.js.map +0 -1
- package/dist/admin/developerConsole.d.ts +0 -264
- package/dist/admin/developerConsole.d.ts.map +0 -1
- package/dist/admin/developerConsole.js +0 -136
- package/dist/admin/developerConsole.js.map +0 -1
- package/dist/admin/identity.d.ts +0 -62
- package/dist/admin/identity.d.ts.map +0 -1
- package/dist/admin/identity.js +0 -7
- package/dist/admin/identity.js.map +0 -1
- package/dist/admin/index.d.ts +0 -4
- package/dist/admin/index.d.ts.map +0 -1
- package/dist/admin/index.js +0 -4
- package/dist/admin/index.js.map +0 -1
- package/dist/admin/procedureFlow.d.ts +0 -25
- package/dist/admin/procedureFlow.d.ts.map +0 -1
- package/dist/admin/procedureFlow.js +0 -154
- package/dist/admin/procedureFlow.js.map +0 -1
- package/dist/auth/ConsoleEmailSender.d.ts +0 -15
- package/dist/auth/ConsoleEmailSender.d.ts.map +0 -1
- package/dist/auth/ConsoleEmailSender.js +0 -19
- package/dist/auth/ConsoleEmailSender.js.map +0 -1
- package/dist/auth/appleClientSecret.d.ts +0 -75
- package/dist/auth/appleClientSecret.d.ts.map +0 -1
- package/dist/auth/appleClientSecret.js +0 -116
- package/dist/auth/appleClientSecret.js.map +0 -1
- package/dist/auth/buildAuth.d.ts +0 -4565
- package/dist/auth/buildAuth.d.ts.map +0 -1
- package/dist/auth/buildAuth.js +0 -307
- package/dist/auth/buildAuth.js.map +0 -1
- package/dist/auth/callerResolver.d.ts +0 -48
- package/dist/auth/callerResolver.d.ts.map +0 -1
- package/dist/auth/callerResolver.js +0 -49
- package/dist/auth/callerResolver.js.map +0 -1
- package/dist/auth/createAuthRoutes.d.ts +0 -22
- package/dist/auth/createAuthRoutes.d.ts.map +0 -1
- package/dist/auth/createAuthRoutes.js +0 -128
- package/dist/auth/createAuthRoutes.js.map +0 -1
- package/dist/auth/createMantleAuth.d.ts +0 -3
- package/dist/auth/createMantleAuth.d.ts.map +0 -1
- package/dist/auth/createMantleAuth.js +0 -483
- package/dist/auth/createMantleAuth.js.map +0 -1
- package/dist/auth/db.d.ts +0 -17
- package/dist/auth/db.d.ts.map +0 -1
- package/dist/auth/db.js +0 -24
- package/dist/auth/db.js.map +0 -1
- package/dist/auth/emailTemplates.d.ts +0 -7
- package/dist/auth/emailTemplates.d.ts.map +0 -1
- package/dist/auth/emailTemplates.js.map +0 -1
- package/dist/auth/index.d.ts +0 -9
- package/dist/auth/index.d.ts.map +0 -1
- package/dist/auth/index.js +0 -7
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/methods.d.ts +0 -717
- package/dist/auth/methods.d.ts.map +0 -1
- package/dist/auth/methods.js +0 -321
- package/dist/auth/methods.js.map +0 -1
- package/dist/auth/oauthTokens.d.ts +0 -24
- package/dist/auth/oauthTokens.d.ts.map +0 -1
- package/dist/auth/oauthTokens.js +0 -146
- package/dist/auth/oauthTokens.js.map +0 -1
- package/dist/auth/setupIncomplete.d.ts +0 -16
- package/dist/auth/setupIncomplete.d.ts.map +0 -1
- package/dist/auth/setupIncomplete.js +0 -50
- package/dist/auth/setupIncomplete.js.map +0 -1
- package/dist/auth/types.d.ts +0 -440
- package/dist/auth/types.d.ts.map +0 -1
- package/dist/auth/types.js +0 -10
- package/dist/auth/types.js.map +0 -1
- package/dist/bun/index.d.ts +0 -65
- package/dist/bun/index.d.ts.map +0 -1
- package/dist/bun/index.js +0 -130
- package/dist/bun/index.js.map +0 -1
- package/dist/cli/emitModule.d.ts +0 -7
- package/dist/cli/emitModule.d.ts.map +0 -1
- package/dist/cli/emitModule.js +0 -127
- package/dist/cli/emitModule.js.map +0 -1
- package/dist/cli/generate.d.ts +0 -8
- package/dist/cli/generate.d.ts.map +0 -1
- package/dist/cli/generate.js +0 -355
- package/dist/cli/generate.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 -21
- package/dist/cli/main.js.map +0 -1
- package/dist/cli/preset.d.ts +0 -18
- package/dist/cli/preset.d.ts.map +0 -1
- package/dist/cli/preset.js +0 -352
- package/dist/cli/preset.js.map +0 -1
- package/dist/cloudflare/index.d.ts +0 -21
- package/dist/cloudflare/index.d.ts.map +0 -1
- package/dist/cloudflare/index.js +0 -14
- package/dist/cloudflare/index.js.map +0 -1
- package/dist/cloudflare/r2Media.d.ts.map +0 -1
- package/dist/cloudflare/r2Media.js +0 -69
- package/dist/cloudflare/r2Media.js.map +0 -1
- package/dist/core/caller.d.ts +0 -35
- package/dist/core/caller.d.ts.map +0 -1
- package/dist/core/caller.js +0 -3
- package/dist/core/caller.js.map +0 -1
- package/dist/core/createMantle.d.ts +0 -22
- package/dist/core/createMantle.d.ts.map +0 -1
- package/dist/core/createMantle.js +0 -117
- package/dist/core/createMantle.js.map +0 -1
- package/dist/core/dialect.d.ts +0 -41
- package/dist/core/dialect.d.ts.map +0 -1
- package/dist/core/dialect.js +0 -7
- package/dist/core/dialect.js.map +0 -1
- package/dist/core/driver.d.ts +0 -17
- package/dist/core/driver.d.ts.map +0 -1
- package/dist/core/driver.js +0 -2
- package/dist/core/driver.js.map +0 -1
- package/dist/core/email.d.ts +0 -17
- package/dist/core/email.d.ts.map +0 -1
- package/dist/core/email.js +0 -2
- package/dist/core/email.js.map +0 -1
- package/dist/core/index.d.ts +0 -16
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -16
- package/dist/core/index.js.map +0 -1
- package/dist/core/invocation.d.ts +0 -66
- package/dist/core/invocation.d.ts.map +0 -1
- package/dist/core/invocation.js +0 -3
- package/dist/core/invocation.js.map +0 -1
- package/dist/core/runtime/auth.d.ts +0 -9
- package/dist/core/runtime/auth.d.ts.map +0 -1
- package/dist/core/runtime/auth.js +0 -39
- package/dist/core/runtime/auth.js.map +0 -1
- package/dist/core/runtime/createRuntime.d.ts +0 -23
- package/dist/core/runtime/createRuntime.d.ts.map +0 -1
- package/dist/core/runtime/createRuntime.js +0 -214
- package/dist/core/runtime/createRuntime.js.map +0 -1
- package/dist/core/runtime/verifyPlan.d.ts +0 -34
- package/dist/core/runtime/verifyPlan.d.ts.map +0 -1
- package/dist/core/runtime/verifyPlan.js +0 -301
- package/dist/core/runtime/verifyPlan.js.map +0 -1
- package/dist/core/service.d.ts +0 -45
- package/dist/core/service.d.ts.map +0 -1
- package/dist/core/service.js +0 -2
- package/dist/core/service.js.map +0 -1
- package/dist/core/site.d.ts.map +0 -1
- package/dist/core/site.js +0 -2
- package/dist/core/site.js.map +0 -1
- package/dist/core/siteConfig.d.ts +0 -5
- package/dist/core/siteConfig.d.ts.map +0 -1
- package/dist/core/siteConfig.js +0 -24
- package/dist/core/siteConfig.js.map +0 -1
- package/dist/core/sql/allowlist.d.ts +0 -65
- package/dist/core/sql/allowlist.d.ts.map +0 -1
- package/dist/core/sql/allowlist.js +0 -705
- package/dist/core/sql/allowlist.js.map +0 -1
- package/dist/core/sql/ast.d.ts +0 -24
- package/dist/core/sql/ast.d.ts.map +0 -1
- package/dist/core/sql/ast.js +0 -32
- package/dist/core/sql/ast.js.map +0 -1
- package/dist/core/sql/compile.d.ts +0 -50
- package/dist/core/sql/compile.d.ts.map +0 -1
- package/dist/core/sql/compile.js +0 -48
- package/dist/core/sql/compile.js.map +0 -1
- package/dist/core/sql/policy.d.ts +0 -121
- package/dist/core/sql/policy.d.ts.map +0 -1
- package/dist/core/sql/policy.js +0 -379
- package/dist/core/sql/policy.js.map +0 -1
- package/dist/core/sql/positions.d.ts +0 -30
- package/dist/core/sql/positions.d.ts.map +0 -1
- package/dist/core/sql/positions.js +0 -22
- package/dist/core/sql/positions.js.map +0 -1
- package/dist/core/sql/run.d.ts +0 -76
- package/dist/core/sql/run.d.ts.map +0 -1
- package/dist/core/sql/run.js +0 -267
- package/dist/core/sql/run.js.map +0 -1
- package/dist/core/store/createStore.d.ts +0 -49
- package/dist/core/store/createStore.d.ts.map +0 -1
- package/dist/core/store/createStore.js +0 -227
- package/dist/core/store/createStore.js.map +0 -1
- package/dist/core/store/cursor.d.ts +0 -4
- package/dist/core/store/cursor.d.ts.map +0 -1
- package/dist/core/store/cursor.js +0 -22
- package/dist/core/store/cursor.js.map +0 -1
- package/dist/core/store/json.d.ts +0 -80
- package/dist/core/store/json.d.ts.map +0 -1
- package/dist/core/store/json.js +0 -342
- package/dist/core/store/json.js.map +0 -1
- package/dist/core/store.d.ts +0 -160
- package/dist/core/store.d.ts.map +0 -1
- package/dist/core/store.js +0 -2
- package/dist/core/store.js.map +0 -1
- package/dist/core/wire.d.ts +0 -20
- package/dist/core/wire.d.ts.map +0 -1
- package/dist/core/wire.js +0 -84
- package/dist/core/wire.js.map +0 -1
- package/dist/core/withCaller.d.ts +0 -16
- package/dist/core/withCaller.d.ts.map +0 -1
- package/dist/core/withCaller.js +0 -29
- package/dist/core/withCaller.js.map +0 -1
- package/dist/d1/adapter.d.ts +0 -12
- package/dist/d1/adapter.d.ts.map +0 -1
- package/dist/d1/adapter.js +0 -23
- package/dist/d1/adapter.js.map +0 -1
- package/dist/d1/codec.d.ts +0 -14
- package/dist/d1/codec.d.ts.map +0 -1
- package/dist/d1/codec.js +0 -136
- package/dist/d1/codec.js.map +0 -1
- package/dist/d1/compile/index.d.ts +0 -9
- package/dist/d1/compile/index.d.ts.map +0 -1
- package/dist/d1/compile/index.js +0 -9
- package/dist/d1/compile/index.js.map +0 -1
- package/dist/d1/dialect.d.ts +0 -4
- package/dist/d1/dialect.d.ts.map +0 -1
- package/dist/d1/dialect.js +0 -13
- package/dist/d1/dialect.js.map +0 -1
- package/dist/d1/executor.d.ts +0 -13
- package/dist/d1/executor.d.ts.map +0 -1
- package/dist/d1/executor.js +0 -91
- package/dist/d1/executor.js.map +0 -1
- package/dist/d1/index.d.ts +0 -6
- package/dist/d1/index.d.ts.map +0 -1
- package/dist/d1/index.js +0 -6
- package/dist/d1/index.js.map +0 -1
- package/dist/d1/lower.d.ts +0 -8
- package/dist/d1/lower.d.ts.map +0 -1
- package/dist/d1/lower.js +0 -167
- package/dist/d1/lower.js.map +0 -1
- package/dist/d1/media.d.ts +0 -5
- package/dist/d1/media.d.ts.map +0 -1
- package/dist/d1/media.js +0 -157
- package/dist/d1/media.js.map +0 -1
- package/dist/d1/migrations.d.ts +0 -12
- package/dist/d1/migrations.d.ts.map +0 -1
- package/dist/d1/migrations.js +0 -111
- package/dist/d1/migrations.js.map +0 -1
- package/dist/d1/print.d.ts +0 -28
- package/dist/d1/print.d.ts.map +0 -1
- package/dist/d1/print.js +0 -54
- package/dist/d1/print.js.map +0 -1
- package/dist/d1/site.d.ts +0 -17
- package/dist/d1/site.d.ts.map +0 -1
- package/dist/d1/site.js +0 -63
- package/dist/d1/site.js.map +0 -1
- package/dist/d1/storage.d.ts +0 -34
- package/dist/d1/storage.d.ts.map +0 -1
- package/dist/d1/storage.js +0 -288
- package/dist/d1/storage.js.map +0 -1
- package/dist/d1/tz.d.ts +0 -21
- package/dist/d1/tz.d.ts.map +0 -1
- package/dist/d1/tz.js +0 -54
- package/dist/d1/tz.js.map +0 -1
- package/dist/d1/validator.d.ts +0 -10
- package/dist/d1/validator.d.ts.map +0 -1
- package/dist/d1/validator.js +0 -33
- package/dist/d1/validator.js.map +0 -1
- package/dist/mcp/apps.d.ts +0 -43
- package/dist/mcp/apps.d.ts.map +0 -1
- package/dist/mcp/apps.js +0 -57
- package/dist/mcp/apps.js.map +0 -1
- package/dist/mcp/catalog.d.ts +0 -55
- package/dist/mcp/catalog.d.ts.map +0 -1
- package/dist/mcp/catalog.js +0 -81
- package/dist/mcp/catalog.js.map +0 -1
- package/dist/mcp/createMcpSurface.d.ts +0 -34
- package/dist/mcp/createMcpSurface.d.ts.map +0 -1
- package/dist/mcp/createMcpSurface.js +0 -150
- package/dist/mcp/createMcpSurface.js.map +0 -1
- package/dist/mcp/index.d.ts +0 -4
- package/dist/mcp/index.d.ts.map +0 -1
- package/dist/mcp/index.js +0 -4
- package/dist/mcp/index.js.map +0 -1
- package/dist/postgres/adapter.d.ts +0 -20
- package/dist/postgres/adapter.d.ts.map +0 -1
- package/dist/postgres/adapter.js +0 -44
- package/dist/postgres/adapter.js.map +0 -1
- package/dist/postgres/codec.d.ts +0 -13
- package/dist/postgres/codec.d.ts.map +0 -1
- package/dist/postgres/codec.js +0 -110
- package/dist/postgres/codec.js.map +0 -1
- package/dist/postgres/compile/index.d.ts +0 -9
- package/dist/postgres/compile/index.d.ts.map +0 -1
- package/dist/postgres/compile/index.js +0 -9
- package/dist/postgres/compile/index.js.map +0 -1
- package/dist/postgres/driver.d.ts +0 -92
- package/dist/postgres/driver.d.ts.map +0 -1
- package/dist/postgres/driver.js +0 -110
- package/dist/postgres/driver.js.map +0 -1
- package/dist/postgres/executor.d.ts +0 -20
- package/dist/postgres/executor.d.ts.map +0 -1
- package/dist/postgres/executor.js +0 -69
- package/dist/postgres/executor.js.map +0 -1
- package/dist/postgres/index.d.ts +0 -7
- package/dist/postgres/index.d.ts.map +0 -1
- package/dist/postgres/index.js +0 -7
- package/dist/postgres/index.js.map +0 -1
- package/dist/postgres/lower.d.ts +0 -6
- package/dist/postgres/lower.d.ts.map +0 -1
- package/dist/postgres/lower.js +0 -157
- package/dist/postgres/lower.js.map +0 -1
- package/dist/postgres/print.d.ts +0 -11
- package/dist/postgres/print.d.ts.map +0 -1
- package/dist/postgres/print.js +0 -121
- package/dist/postgres/print.js.map +0 -1
- package/dist/postgres/storage.d.ts +0 -19
- package/dist/postgres/storage.d.ts.map +0 -1
- package/dist/postgres/storage.js +0 -201
- package/dist/postgres/storage.js.map +0 -1
- package/dist/postgres/textRows.d.ts +0 -10
- package/dist/postgres/textRows.d.ts.map +0 -1
- package/dist/postgres/textRows.js +0 -44
- package/dist/postgres/textRows.js.map +0 -1
- package/dist/postgres/validator.d.ts +0 -12
- package/dist/postgres/validator.d.ts.map +0 -1
- package/dist/postgres/validator.js +0 -46
- package/dist/postgres/validator.js.map +0 -1
- package/dist/spec/domain/index.d.ts +0 -3
- package/dist/spec/domain/index.d.ts.map +0 -1
- package/dist/spec/domain/index.js +0 -3
- package/dist/spec/domain/index.js.map +0 -1
- package/dist/spec/domain/model/ContentState.d.ts +0 -8
- package/dist/spec/domain/model/ContentState.d.ts.map +0 -1
- package/dist/spec/domain/model/ContentState.js +0 -7
- package/dist/spec/domain/model/ContentState.js.map +0 -1
- package/dist/spec/domain/model/Entry.d.ts +0 -29
- package/dist/spec/domain/model/Entry.d.ts.map +0 -1
- package/dist/spec/domain/model/Entry.js +0 -16
- package/dist/spec/domain/model/Entry.js.map +0 -1
- package/dist/spec/domain/model/Locale.d.ts +0 -30
- package/dist/spec/domain/model/Locale.d.ts.map +0 -1
- package/dist/spec/domain/model/Locale.js +0 -33
- package/dist/spec/domain/model/Locale.js.map +0 -1
- package/dist/spec/domain/model/ManifestGrammar.d.ts.map +0 -1
- package/dist/spec/domain/model/ManifestGrammar.js +0 -149
- package/dist/spec/domain/model/ManifestGrammar.js.map +0 -1
- package/dist/spec/domain/model/MediaMimeAccept.d.ts +0 -55
- package/dist/spec/domain/model/MediaMimeAccept.d.ts.map +0 -1
- package/dist/spec/domain/model/MediaMimeAccept.js +0 -90
- package/dist/spec/domain/model/MediaMimeAccept.js.map +0 -1
- package/dist/spec/domain/model/RuntimePlan.d.ts.map +0 -1
- package/dist/spec/domain/model/RuntimePlan.js +0 -4
- package/dist/spec/domain/model/RuntimePlan.js.map +0 -1
- package/dist/spec/domain/model/SiteConfig.d.ts +0 -173
- package/dist/spec/domain/model/SiteConfig.d.ts.map +0 -1
- package/dist/spec/domain/model/SiteConfig.js +0 -13
- package/dist/spec/domain/model/SiteConfig.js.map +0 -1
- package/dist/spec/domain/model/SqlIr.d.ts.map +0 -1
- package/dist/spec/domain/model/SqlIr.js +0 -95
- package/dist/spec/domain/model/SqlIr.js.map +0 -1
- package/dist/spec/domain/model/index.d.ts +0 -14
- package/dist/spec/domain/model/index.d.ts.map +0 -1
- package/dist/spec/domain/model/index.js +0 -14
- package/dist/spec/domain/model/index.js.map +0 -1
- package/dist/spec/domain/service/CloudflareCron.d.ts.map +0 -1
- package/dist/spec/domain/service/CloudflareCron.js.map +0 -1
- package/dist/spec/domain/service/CrossSchemaChecker.d.ts +0 -34
- package/dist/spec/domain/service/CrossSchemaChecker.d.ts.map +0 -1
- package/dist/spec/domain/service/CrossSchemaChecker.js +0 -114
- package/dist/spec/domain/service/CrossSchemaChecker.js.map +0 -1
- package/dist/spec/domain/service/EntryDataValidator.d.ts +0 -56
- package/dist/spec/domain/service/EntryDataValidator.d.ts.map +0 -1
- package/dist/spec/domain/service/EntryDataValidator.js +0 -88
- package/dist/spec/domain/service/EntryDataValidator.js.map +0 -1
- package/dist/spec/domain/service/JsonSchemaToZod.d.ts +0 -29
- package/dist/spec/domain/service/JsonSchemaToZod.d.ts.map +0 -1
- package/dist/spec/domain/service/JsonSchemaToZod.js +0 -156
- package/dist/spec/domain/service/JsonSchemaToZod.js.map +0 -1
- package/dist/spec/domain/service/LifecycleStateMachine.d.ts +0 -75
- package/dist/spec/domain/service/LifecycleStateMachine.d.ts.map +0 -1
- package/dist/spec/domain/service/LifecycleStateMachine.js +0 -76
- package/dist/spec/domain/service/LifecycleStateMachine.js.map +0 -1
- package/dist/spec/domain/service/LocaleCanonicalizer.d.ts +0 -29
- package/dist/spec/domain/service/LocaleCanonicalizer.d.ts.map +0 -1
- package/dist/spec/domain/service/LocaleCanonicalizer.js +0 -96
- package/dist/spec/domain/service/LocaleCanonicalizer.js.map +0 -1
- package/dist/spec/domain/service/ManifestFieldChecks.d.ts +0 -60
- package/dist/spec/domain/service/ManifestFieldChecks.d.ts.map +0 -1
- package/dist/spec/domain/service/ManifestFieldChecks.js +0 -116
- package/dist/spec/domain/service/ManifestFieldChecks.js.map +0 -1
- package/dist/spec/domain/service/ManifestGraphValidator.d.ts +0 -15
- package/dist/spec/domain/service/ManifestGraphValidator.d.ts.map +0 -1
- package/dist/spec/domain/service/ManifestGraphValidator.js +0 -225
- package/dist/spec/domain/service/ManifestGraphValidator.js.map +0 -1
- package/dist/spec/domain/service/ManifestLinker.d.ts +0 -45
- package/dist/spec/domain/service/ManifestLinker.d.ts.map +0 -1
- package/dist/spec/domain/service/ManifestLinker.js +0 -92
- package/dist/spec/domain/service/ManifestLinker.js.map +0 -1
- package/dist/spec/domain/service/ManifestLocaleTrimmer.d.ts +0 -16
- package/dist/spec/domain/service/ManifestLocaleTrimmer.d.ts.map +0 -1
- package/dist/spec/domain/service/ManifestLocaleTrimmer.js +0 -76
- package/dist/spec/domain/service/ManifestLocaleTrimmer.js.map +0 -1
- package/dist/spec/domain/service/ManifestParser.d.ts +0 -49
- package/dist/spec/domain/service/ManifestParser.d.ts.map +0 -1
- package/dist/spec/domain/service/ManifestParser.js +0 -203
- package/dist/spec/domain/service/ManifestParser.js.map +0 -1
- package/dist/spec/domain/service/ManifestPartition.d.ts +0 -9
- package/dist/spec/domain/service/ManifestPartition.d.ts.map +0 -1
- package/dist/spec/domain/service/ManifestPartition.js +0 -19
- package/dist/spec/domain/service/ManifestPartition.js.map +0 -1
- package/dist/spec/domain/service/ManifestPathDiagnoser.d.ts +0 -33
- package/dist/spec/domain/service/ManifestPathDiagnoser.d.ts.map +0 -1
- package/dist/spec/domain/service/ManifestPathDiagnoser.js +0 -43
- package/dist/spec/domain/service/ManifestPathDiagnoser.js.map +0 -1
- package/dist/spec/domain/service/ManifestSourceSpans.d.ts +0 -10
- package/dist/spec/domain/service/ManifestSourceSpans.d.ts.map +0 -1
- package/dist/spec/domain/service/ManifestSourceSpans.js +0 -76
- package/dist/spec/domain/service/ManifestSourceSpans.js.map +0 -1
- package/dist/spec/domain/service/McpToolNaming.d.ts +0 -25
- package/dist/spec/domain/service/McpToolNaming.d.ts.map +0 -1
- package/dist/spec/domain/service/McpToolNaming.js +0 -50
- package/dist/spec/domain/service/McpToolNaming.js.map +0 -1
- package/dist/spec/domain/service/PlanFingerprint.d.ts.map +0 -1
- package/dist/spec/domain/service/PlanFingerprint.js +0 -14
- package/dist/spec/domain/service/PlanFingerprint.js.map +0 -1
- package/dist/spec/domain/service/ProcedureViewSpecChecks.d.ts +0 -4
- package/dist/spec/domain/service/ProcedureViewSpecChecks.d.ts.map +0 -1
- package/dist/spec/domain/service/ProcedureViewSpecChecks.js +0 -211
- package/dist/spec/domain/service/ProcedureViewSpecChecks.js.map +0 -1
- package/dist/spec/domain/service/SchemaAdminUiChecker.d.ts +0 -42
- package/dist/spec/domain/service/SchemaAdminUiChecker.d.ts.map +0 -1
- package/dist/spec/domain/service/SchemaAdminUiChecker.js +0 -289
- package/dist/spec/domain/service/SchemaAdminUiChecker.js.map +0 -1
- package/dist/spec/domain/service/SchemaIndexChecker.d.ts +0 -33
- package/dist/spec/domain/service/SchemaIndexChecker.d.ts.map +0 -1
- package/dist/spec/domain/service/SchemaIndexChecker.js +0 -256
- package/dist/spec/domain/service/SchemaIndexChecker.js.map +0 -1
- package/dist/spec/domain/service/SchemaSearchChecker.d.ts +0 -11
- package/dist/spec/domain/service/SchemaSearchChecker.d.ts.map +0 -1
- package/dist/spec/domain/service/SchemaSearchChecker.js +0 -78
- package/dist/spec/domain/service/SchemaSearchChecker.js.map +0 -1
- package/dist/spec/domain/service/SchemaSpecChecks.d.ts +0 -31
- package/dist/spec/domain/service/SchemaSpecChecks.d.ts.map +0 -1
- package/dist/spec/domain/service/SchemaSpecChecks.js +0 -445
- package/dist/spec/domain/service/SchemaSpecChecks.js.map +0 -1
- package/dist/spec/domain/service/SiteDefaultsValidator.d.ts +0 -39
- package/dist/spec/domain/service/SiteDefaultsValidator.d.ts.map +0 -1
- package/dist/spec/domain/service/SiteDefaultsValidator.js +0 -194
- package/dist/spec/domain/service/SiteDefaultsValidator.js.map +0 -1
- package/dist/spec/domain/service/SqlClassify.d.ts +0 -19
- package/dist/spec/domain/service/SqlClassify.d.ts.map +0 -1
- package/dist/spec/domain/service/SqlClassify.js +0 -42
- package/dist/spec/domain/service/SqlClassify.js.map +0 -1
- package/dist/spec/domain/service/SqlRefusal.d.ts +0 -16
- package/dist/spec/domain/service/SqlRefusal.d.ts.map +0 -1
- package/dist/spec/domain/service/SqlRefusal.js +0 -20
- package/dist/spec/domain/service/SqlRefusal.js.map +0 -1
- package/dist/spec/domain/service/SqlTypes.d.ts +0 -40
- package/dist/spec/domain/service/SqlTypes.d.ts.map +0 -1
- package/dist/spec/domain/service/SqlTypes.js +0 -110
- package/dist/spec/domain/service/SqlTypes.js.map +0 -1
- package/dist/spec/domain/service/StaffRoleHierarchy.d.ts +0 -3
- package/dist/spec/domain/service/StaffRoleHierarchy.d.ts.map +0 -1
- package/dist/spec/domain/service/StaffRoleHierarchy.js +0 -19
- package/dist/spec/domain/service/StaffRoleHierarchy.js.map +0 -1
- package/dist/spec/domain/service/TriggerGraphChecks.d.ts +0 -16
- package/dist/spec/domain/service/TriggerGraphChecks.d.ts.map +0 -1
- package/dist/spec/domain/service/TriggerGraphChecks.js +0 -337
- package/dist/spec/domain/service/TriggerGraphChecks.js.map +0 -1
- package/dist/spec/domain/service/TriggerSpecChecks.d.ts +0 -4
- package/dist/spec/domain/service/TriggerSpecChecks.d.ts.map +0 -1
- package/dist/spec/domain/service/TriggerSpecChecks.js +0 -89
- package/dist/spec/domain/service/TriggerSpecChecks.js.map +0 -1
- package/dist/spec/domain/service/ValidatedAdminUiProjection.d.ts +0 -11
- package/dist/spec/domain/service/ValidatedAdminUiProjection.d.ts.map +0 -1
- package/dist/spec/domain/service/ValidatedAdminUiProjection.js +0 -26
- package/dist/spec/domain/service/ValidatedAdminUiProjection.js.map +0 -1
- package/dist/spec/domain/service/ViewAdminUiChecker.d.ts +0 -14
- package/dist/spec/domain/service/ViewAdminUiChecker.d.ts.map +0 -1
- package/dist/spec/domain/service/ViewAdminUiChecker.js +0 -53
- package/dist/spec/domain/service/ViewAdminUiChecker.js.map +0 -1
- package/dist/spec/domain/service/index.d.ts +0 -24
- package/dist/spec/domain/service/index.d.ts.map +0 -1
- package/dist/spec/domain/service/index.js +0 -24
- package/dist/spec/domain/service/index.js.map +0 -1
- package/dist/spec/index.d.ts +0 -10
- package/dist/spec/index.d.ts.map +0 -1
- package/dist/spec/index.js +0 -12
- package/dist/spec/index.js.map +0 -1
- package/dist/spec/infrastructure/cli/parseArgsError.d.ts +0 -16
- package/dist/spec/infrastructure/cli/parseArgsError.d.ts.map +0 -1
- package/dist/spec/infrastructure/cli/parseArgsError.js +0 -34
- package/dist/spec/infrastructure/cli/parseArgsError.js.map +0 -1
- package/dist/spec/infrastructure/index.d.ts +0 -2
- package/dist/spec/infrastructure/index.d.ts.map +0 -1
- package/dist/spec/infrastructure/index.js +0 -2
- package/dist/spec/infrastructure/index.js.map +0 -1
- package/dist/spec/infrastructure/sql/PgQueryParser.d.ts +0 -18
- package/dist/spec/infrastructure/sql/PgQueryParser.d.ts.map +0 -1
- package/dist/spec/infrastructure/sql/PgQueryParser.js +0 -17
- package/dist/spec/infrastructure/sql/PgQueryParser.js.map +0 -1
- package/dist/spec/infrastructure/sql/compilePlan.d.ts +0 -37
- package/dist/spec/infrastructure/sql/compilePlan.d.ts.map +0 -1
- package/dist/spec/infrastructure/sql/compilePlan.js +0 -282
- package/dist/spec/infrastructure/sql/compilePlan.js.map +0 -1
- package/dist/spec/infrastructure/sql/compileSql.d.ts +0 -35
- package/dist/spec/infrastructure/sql/compileSql.d.ts.map +0 -1
- package/dist/spec/infrastructure/sql/compileSql.js +0 -92
- package/dist/spec/infrastructure/sql/compileSql.js.map +0 -1
- package/dist/spec/infrastructure/sql/frontEnd.d.ts +0 -8
- package/dist/spec/infrastructure/sql/frontEnd.d.ts.map +0 -1
- package/dist/spec/infrastructure/sql/frontEnd.js +0 -100
- package/dist/spec/infrastructure/sql/frontEnd.js.map +0 -1
- package/dist/spec/infrastructure/sql/index.d.ts +0 -4
- package/dist/spec/infrastructure/sql/index.d.ts.map +0 -1
- package/dist/spec/infrastructure/sql/index.js +0 -4
- package/dist/spec/infrastructure/sql/index.js.map +0 -1
- package/dist/spec/kernel/diagnostic.d.ts.map +0 -1
- package/dist/spec/kernel/diagnostic.js +0 -296
- package/dist/spec/kernel/diagnostic.js.map +0 -1
- package/dist/spec/kernel/index.d.ts +0 -8
- package/dist/spec/kernel/index.d.ts.map +0 -1
- package/dist/spec/kernel/index.js +0 -8
- package/dist/spec/kernel/index.js.map +0 -1
- package/dist/spec/usecase/EmitTypes.d.ts +0 -22
- package/dist/spec/usecase/EmitTypes.d.ts.map +0 -1
- package/dist/spec/usecase/EmitTypes.js +0 -182
- package/dist/spec/usecase/EmitTypes.js.map +0 -1
- package/dist/spec/usecase/ValidateManifestsUseCase.d.ts +0 -8
- package/dist/spec/usecase/ValidateManifestsUseCase.d.ts.map +0 -1
- package/dist/spec/usecase/ValidateManifestsUseCase.js +0 -101
- package/dist/spec/usecase/ValidateManifestsUseCase.js.map +0 -1
- package/dist/spec/usecase/dto/ValidateManifestsRequest.d.ts +0 -27
- package/dist/spec/usecase/dto/ValidateManifestsRequest.d.ts.map +0 -1
- package/dist/spec/usecase/dto/ValidateManifestsRequest.js +0 -2
- package/dist/spec/usecase/dto/ValidateManifestsRequest.js.map +0 -1
- package/dist/spec/usecase/dto/ValidateManifestsResponse.d.ts +0 -14
- package/dist/spec/usecase/dto/ValidateManifestsResponse.d.ts.map +0 -1
- package/dist/spec/usecase/dto/ValidateManifestsResponse.js +0 -2
- package/dist/spec/usecase/dto/ValidateManifestsResponse.js.map +0 -1
- package/dist/spec/usecase/dto/index.d.ts +0 -3
- package/dist/spec/usecase/dto/index.d.ts.map +0 -1
- package/dist/spec/usecase/dto/index.js +0 -3
- package/dist/spec/usecase/dto/index.js.map +0 -1
- package/dist/spec/usecase/index.d.ts +0 -10
- package/dist/spec/usecase/index.d.ts.map +0 -1
- package/dist/spec/usecase/index.js +0 -10
- package/dist/spec/usecase/index.js.map +0 -1
- package/dist/testing/cases/before-hook.d.ts +0 -4
- package/dist/testing/cases/before-hook.d.ts.map +0 -1
- package/dist/testing/cases/before-hook.js +0 -71
- package/dist/testing/cases/before-hook.js.map +0 -1
- package/dist/testing/cases/corpus.d.ts +0 -12
- package/dist/testing/cases/corpus.d.ts.map +0 -1
- package/dist/testing/cases/corpus.js +0 -91
- package/dist/testing/cases/corpus.js.map +0 -1
- package/dist/testing/cases/policy.d.ts +0 -74
- package/dist/testing/cases/policy.d.ts.map +0 -1
- package/dist/testing/cases/policy.js +0 -142
- package/dist/testing/cases/policy.js.map +0 -1
- package/dist/testing/cases/printer.d.ts +0 -4
- package/dist/testing/cases/printer.d.ts.map +0 -1
- package/dist/testing/cases/printer.js +0 -32
- package/dist/testing/cases/printer.js.map +0 -1
- package/dist/testing/cases/report-view.d.ts +0 -5
- package/dist/testing/cases/report-view.d.ts.map +0 -1
- package/dist/testing/cases/report-view.js +0 -33
- package/dist/testing/cases/report-view.js.map +0 -1
- package/dist/testing/cases/requisition.d.ts +0 -4
- package/dist/testing/cases/requisition.d.ts.map +0 -1
- package/dist/testing/cases/requisition.js +0 -38
- package/dist/testing/cases/requisition.js.map +0 -1
- package/dist/testing/cases/search-places.d.ts +0 -4
- package/dist/testing/cases/search-places.d.ts.map +0 -1
- package/dist/testing/cases/search-places.js +0 -60
- package/dist/testing/cases/search-places.js.map +0 -1
- package/dist/testing/cases/stock.d.ts +0 -4
- package/dist/testing/cases/stock.d.ts.map +0 -1
- package/dist/testing/cases/stock.js +0 -35
- package/dist/testing/cases/stock.js.map +0 -1
- package/dist/testing/cases/store.d.ts +0 -4
- package/dist/testing/cases/store.d.ts.map +0 -1
- package/dist/testing/cases/store.js +0 -100
- package/dist/testing/cases/store.js.map +0 -1
- package/dist/testing/harness.d.ts +0 -94
- package/dist/testing/harness.d.ts.map +0 -1
- package/dist/testing/harness.js +0 -168
- package/dist/testing/harness.js.map +0 -1
- package/dist/testing/index.d.ts.map +0 -1
- package/dist/testing/index.js.map +0 -1
- package/dist/testing/report.d.ts +0 -15
- package/dist/testing/report.d.ts.map +0 -1
- package/dist/testing/report.js +0 -22
- package/dist/testing/report.js.map +0 -1
- package/dist/web/createRestSurface.d.ts +0 -7
- package/dist/web/createRestSurface.d.ts.map +0 -1
- package/dist/web/createRestSurface.js +0 -39
- package/dist/web/createRestSurface.js.map +0 -1
- package/dist/web/index.d.ts +0 -2
- package/dist/web/index.d.ts.map +0 -1
- package/dist/web/index.js +0 -2
- package/dist/web/index.js.map +0 -1
- 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 -919
- 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 -244
- 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/0029-mcp-apps-interaction-contracts.md +0 -324
- package/docs/adr/0030-store.md +0 -40
- package/docs/adr/0031-host-cloud-core-contract.md +0 -25
- package/docs/adr/0032-store-centric-core-and-service-contract.md +0 -361
- package/docs/adr/0033-storage-converges-to-the-plan.md +0 -92
- package/docs/adr/0034-store-is-authored-as-sql.md +0 -192
- package/docs/adr/0035-sql-dialects.md +0 -154
- package/docs/adr/0036-host-and-dialect.md +0 -65
- package/docs/adr/0037-postgresql-is-the-reference-dialect.md +0 -124
- package/docs/adr/0038-bun-native-host.md +0 -63
- package/docs/adr/README.md +0 -96
- 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 -48
- package/docs/adr/adr-lite-909-admin-ui-kit.md +0 -37
- package/docs/examples/commerce-inventory.md +0 -481
- package/docs/examples/commerce.md +0 -254
- package/docs/examples/guarded-api.md +0 -238
- package/docs/examples/intake-hooks.md +0 -237
- package/docs/examples/intake.md +0 -127
- package/docs/examples/legal-documents.md +0 -218
- package/docs/examples/procurement.md +0 -215
- package/docs/examples/publication.md +0 -211
- package/docs/examples/reference-service/.mantle/generated/mantle.ts +0 -174
- package/docs/examples/reference-service/.mantle/generated/plan.json +0 -1936
- package/docs/examples/reference-service/README.md +0 -33
- package/docs/examples/reference-service/manifests/catalog.yaml +0 -103
- package/docs/examples/reference-service/manifests/orders.yaml +0 -120
- package/docs/examples/reference-service/mantle.config.json +0 -1
- package/docs/examples/reference-service/package.json +0 -27
- package/docs/examples/reference-service/smoke.mjs +0 -156
- package/docs/examples/reference-service/src/handlers.ts +0 -36
- package/docs/examples/reference-service/src/index.ts +0 -33
- package/docs/examples/reference-service/src/service.ts +0 -78
- package/docs/examples/reference-service/wrangler.jsonc +0 -26
- package/docs/examples/reservation.md +0 -142
- package/docs/skills/develop/mcp-app.md +0 -79
- /package/docs/examples/{reference-service → app-shell}/.dev.vars.example +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { userReferences } from "../domain/userReferences.js";
|
|
2
|
+
/** Selected application bindings: compiled checks/native SQL; only the app depends on Admin adapters. */
|
|
3
|
+
import { isPrimaryCollection } from "../build/compiler.js";
|
|
4
|
+
import { enumOptions } from "../build/compiler.js";
|
|
5
|
+
import { databaseImport, isSqlite, literal as q } from "../domain/entry.js";
|
|
6
|
+
import { conversions, authLines } from "../domain/input.js";
|
|
7
|
+
import { recipesOf } from "../domain/recipes.js";
|
|
8
|
+
import { boundaryType, conversion, serverOwned } from "../domain/columns.js";
|
|
9
|
+
import { adminOrder } from "../domain/adminOrder.js";
|
|
10
|
+
import { emitValidation } from "./validation.js";
|
|
11
|
+
const scalar = (type) => ["text", "integer", "int4", "int8", "real", "float8", "bool", "date", "timestamptz"].includes(type ?? "");
|
|
12
|
+
const wire = (fields, sqlite) => {
|
|
13
|
+
const columns = fields.flatMap(([name, type]) => conversion(name, type, sqlite));
|
|
14
|
+
const geo = fields.filter(([, type]) => type === "geo").map(([field]) => `row[${q(field)}]=row[${q(field + "_lat")}] == null || row[${q(field + "_lng")}] == null ? null : {lat:row[${q(field + "_lat")}],lng:row[${q(field + "_lng")}]};delete row[${q(field + "_lat")}];delete row[${q(field + "_lng")}];`);
|
|
15
|
+
return `(raw:Row):Row=>{const row=${columns.length ? `wireRows([raw],${q(columns)})[0]!` : geo.length ? "{...raw}" : "raw"};${geo.join("")}return row;}`;
|
|
16
|
+
};
|
|
17
|
+
/** Core's titled string choices are enum checks; constrained or general oneOf remains refused. */
|
|
18
|
+
function adminProperty(property) {
|
|
19
|
+
const choices = enumOptions(property);
|
|
20
|
+
if (!property.oneOf || property.enum || !choices || !property.oneOf.every(branch => Object.entries(branch).every(([key, value]) => key === "const" || key === "title" || key === "type" && value === "string")) || new Set(choices.map(c => c.value)).size !== choices.length)
|
|
21
|
+
return property;
|
|
22
|
+
const { oneOf, ...base } = property;
|
|
23
|
+
return { ...base, enum: choices.map(c => c.value) };
|
|
24
|
+
}
|
|
25
|
+
function checks(s, full) {
|
|
26
|
+
const properties = Object.fromEntries(Object.entries(s.schema.properties ?? {}).filter(([name]) => name.toLowerCase() !== s.scope && s.fields[name.toLowerCase()] !== "geo").map(([name, property]) => [name, adminProperty(property)]));
|
|
27
|
+
return { ...s.schema, properties, required: full ? (s.schema.required ?? []).filter(name => Object.hasOwn(properties, name) && !(s.userScopes ?? []).some(u => u.column === name.toLowerCase())) : [], additionalProperties: false };
|
|
28
|
+
}
|
|
29
|
+
const allowed = (requires, path) => {
|
|
30
|
+
const lines = authLines(requires, path);
|
|
31
|
+
return lines.length ? `(caller:Caller)=>{try{${lines.join("")}return true;}catch{return false;}}` : "(_caller:Caller)=>true";
|
|
32
|
+
};
|
|
33
|
+
/** Share repeated compiler SQL constants; generated modules evaluate no decoder or kernel at import. */
|
|
34
|
+
function sqlConstants(value) {
|
|
35
|
+
const counts = new Map();
|
|
36
|
+
const visit = (v) => { if (typeof v === "string" && v.length > 80)
|
|
37
|
+
counts.set(v, (counts.get(v) ?? 0) + 1);
|
|
38
|
+
else if (Array.isArray(v))
|
|
39
|
+
v.forEach(visit);
|
|
40
|
+
else if (v && typeof v === "object")
|
|
41
|
+
Object.values(v).forEach(visit); };
|
|
42
|
+
visit(value);
|
|
43
|
+
const pool = new Map([...counts].filter(([, count]) => count > 1).map(([text], n) => [text, `sql${n}`]));
|
|
44
|
+
const literal = (v) => typeof v === "string" ? pool.get(v) ?? q(v) : Array.isArray(v) ? "[" + v.map(literal).join(",") + "]" : v && typeof v === "object" ? "{" + Object.entries(v).map(([name, child]) => `${name === "__proto__" ? `[${q(name)}]` : q(name)}:${literal(child)}`).join(",") + "}" : q(v);
|
|
45
|
+
return { code: literal(value), constants: [...pool].map(([text, name]) => `const ${name}=${q(text)};`) };
|
|
46
|
+
}
|
|
47
|
+
export function emitAdminBindings(input, refuse) {
|
|
48
|
+
if (!input.admin)
|
|
49
|
+
return {};
|
|
50
|
+
const { plan, lowered, target } = input, sqlite = isSqlite(target), refs = Object.values(plan.procedures).some(p => "ref" in p.handler), files = {};
|
|
51
|
+
const user = userReferences(plan, sqlite);
|
|
52
|
+
const imports = [...(user.used ? [user.code, 'import {userBinds} from "@aotter/mantle/user-fields";'] : []), databaseImport(target), 'import {wireRows,type Caller,type Row} from "@aotter/mantle/contracts";', 'import {deny,isAdmin,isUser} from "@aotter/mantle/contracts";', 'import {invalid} from "@aotter/mantle/surface";', 'import type {Handlers} from "./generated.js";', 'import {bootstrap,allCollections} from "./admin-descriptors.js";', 'import type {View,Operation} from "@aotter/mantle-admin/server";', 'import type {EntrySchema} from "@aotter/mantle-admin/server/entries";'];
|
|
53
|
+
imports.push('import {nativePage,nativeStatistics,nativeText} from "@aotter/mantle-admin/server/native";', `import * as D from "@aotter/mantle/dialect/${sqlite ? "sqlite" : "postgres"}";`, `import {read,procedure} from "@aotter/mantle/driver/${target === "bun-sqlite" ? "bun-sqlite" : target === "cloudflare-d1" ? "d1" : "postgres"}";`, `const adapter={read,procedure,values:${sqlite ? (user.used ? "{...D,...USER_VALUES}" : "D") : `{...D,${user.used ? "...USER_VALUES," : ""}timestamp:(v:Parameters<typeof D.timestamp>[0])=>{if(typeof v==="string"&&/^0000-/.test(v.trim()))invalid("PostgreSQL timestamps require a nonzero year.","admin/input");return D.timestamp(v);},date:(v:string)=>{if(/^0000-/.test(v.trim()))invalid("PostgreSQL dates require a nonzero year.","admin/input");return D.date(v);}}`},param:D.param,escapeLike:D.escapeLike,sqlite:${sqlite}} as const;`);
|
|
54
|
+
const schemas = [], views = [], adminViews = [], operations = [], pageSpecs = [];
|
|
55
|
+
for (const [n, s] of Object.values(plan.schemas).entries()) {
|
|
56
|
+
const schemaPath = `schemas/${s.name}/admin`, declared = Object.keys(s.fields).filter(f => f !== s.scope), writable = declared.filter(f => scalar(s.fields[f]) || s.fields[f] === "json");
|
|
57
|
+
// readOnly properties are server-maintained: values() pins them to their default, and they have no Admin UPDATE.
|
|
58
|
+
const server = Object.fromEntries(writable.filter(f => serverOwned(s.schema, f)).map(f => [f, Object.entries(s.schema.properties ?? {}).find(([k]) => k.toLowerCase() === f)?.[1]?.default ?? null]));
|
|
59
|
+
// Experimental geo collections remain readable; edits require a declared Procedure.
|
|
60
|
+
const validators = emitValidation({ views: {}, procedures: { full: { input: checks(s, true) }, partial: { input: checks(s, false) } } }, (path, message) => refuse(schemaPath + "/" + path, message));
|
|
61
|
+
for (const mode of ["full", "partial"]) {
|
|
62
|
+
const name = `validation/admin/${encodeURIComponent(s.name)}-${mode}.ts`;
|
|
63
|
+
files[name] = validators[`validation/procedures/${mode}.ts`].replaceAll(`procedures/${mode}/input`, schemaPath + "/input");
|
|
64
|
+
imports.push(`import {validate as ${mode}${n}} from "./${name.replace(/\.ts$/, ".js")}";`);
|
|
65
|
+
}
|
|
66
|
+
const names = Object.fromEntries(writable.map(f => [s.names[f] ?? f, f])), allNames = { ...names, id: "id", version: "version", createdAt: "created_at", updatedAt: "updated_at", authorId: "author_id", ...(s.publishing ? { status: "status", publishedAt: "published_at" } : {}) };
|
|
67
|
+
const temporal = writable.filter(f => ["date", "timestamptz"].includes(s.fields[f])).map(f => s.names[f] ?? f);
|
|
68
|
+
const yearZero = sqlite ? "" : `for(const key of ${q(temporal)})if(typeof data[key]==="string"&&/^0000-/.test(data[key].trim()))invalid("PostgreSQL dates require a nonzero year.",${q(schemaPath)});`;
|
|
69
|
+
const coercers = Object.entries(allNames).filter(([, f]) => scalar(s.fields[f] ?? (f === "version" ? "integer" : "text"))).map(([name, f]) => {
|
|
70
|
+
const type = s.fields[f] ?? (f === "version" ? "integer" : "text");
|
|
71
|
+
const value = type === "bool" ? `raw === "true" ? true : raw === "false" ? false : fail("Expected true or false.")` : ["integer", "int4", "int8", "real", "float8"].includes(type) ? `number(raw,${["integer", "int4", "int8"].includes(type)})` : `raw`;
|
|
72
|
+
return `case ${q(name)}:return {column:${q(f)},value:${value}};`;
|
|
73
|
+
});
|
|
74
|
+
const order = adminOrder(s), orderNames = Object.fromEntries(Object.keys(order).map(f => [f === "updated_at" ? "updatedAt" : s.names[f] ?? f, f]));
|
|
75
|
+
const parent = s.translates && plan.schemas[s.translates.parent.toLowerCase()];
|
|
76
|
+
const inherited = parent ? Object.keys(parent.fields).filter(f => f !== parent.scope && !Object.hasOwn(s.fields, f)) : [];
|
|
77
|
+
const rowNames = { ...(parent ? parent.names : {}), ...s.names };
|
|
78
|
+
const rowFields = [...declared.map(f => [f, s.fields[f]]), ...inherited.map(f => [f, parent && parent.fields[f]]), ...["version"].map(f => [f, "integer"])];
|
|
79
|
+
const named = `(raw:Row):Row=>{const row=row${n}(raw);return Object.fromEntries(Object.entries(row).map(([key,value])=>[Object.hasOwn(fieldNames${n},key)?fieldNames${n}[key as keyof typeof fieldNames${n}]:key,value]));}`;
|
|
80
|
+
const entrySpec = `entrySpecs[${q(s.name)}]`;
|
|
81
|
+
if (!input.adminEntries?.[s.name]) {
|
|
82
|
+
refuse(schemaPath, "Missing compiler-authorized entry queries and Procedures.");
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const defaults = Object.fromEntries(Object.entries(checks(s, true).properties ?? {}).flatMap(([key, p]) => p.default !== undefined ? [[key, p.default]] : []));
|
|
86
|
+
const primary = isPrimaryCollection(s, Object.values(plan.schemas));
|
|
87
|
+
const schemaCode = `{
|
|
88
|
+
name:${q(s.name)},primary:${primary},descriptor:allCollections[${q(s.name)}],publishing:${!!s.publishing},readOnly:${s.schema.readOnly === true || declared.some(f => s.fields[f] === "geo")},fields:names${n},defaults:${q(defaults)},
|
|
89
|
+
binding:${entrySpec},
|
|
90
|
+
query:query${n},validate:(data,full)=>{const checked=Object.fromEntries(Object.entries(data).filter(([key,v])=>v!==null||${q(s.schema.required ?? [])}.includes(key)));(full?full${n}:partial${n})(checked);${sqlite ? "" : "nativeText(data);"}${yearZero}return data;},
|
|
91
|
+
values:values${n},row:${named},
|
|
92
|
+
${sqlite ? "" : "native:nativeText,"}
|
|
93
|
+
${s.publishing ? `transition:async(db,caller,verb,id,expectedVersion)=>{const run=await ({publish:()=>import("./procedures/${encodeURIComponent(s.name + ".publish")}.js"),unpublish:()=>import("./procedures/${encodeURIComponent(s.name + ".unpublish")}.js"),archive:()=>import("./procedures/${encodeURIComponent(s.name + ".archive")}.js")})[verb]();const version=wireRows([{version:expectedVersion}],[["version","int"]])[0]!.version;return run.default(db,caller,{id,expectedVersion:version} as Parameters<typeof run.default>[2]);},` : ""}
|
|
94
|
+
}`;
|
|
95
|
+
schemas.push(schemaCode);
|
|
96
|
+
files[`admin/entries-${encodeURIComponent(s.name)}.ts`] = `import {invalid} from "@aotter/mantle/surface";\nimport {wireRows,type Row} from "@aotter/mantle/contracts";\nimport type {EntryPageQuery} from "@aotter/mantle-admin/server/entries";\nimport {entriesQuery,scalarNumber,nativeText} from "@aotter/mantle-admin/server/native";\nconst fail=(message:string):never=>invalid(message,${q(schemaPath)});\nconst number=(raw:string,integer:boolean)=>scalarNumber(raw,integer,${q(schemaPath)});\nimport * as D from "@aotter/mantle/dialect/${sqlite ? "sqlite" : "postgres"}";\nexport const names=${q(names)} as const;\nfunction encode(column:string,value:unknown):unknown{if(value==null)return value;switch(column){${[...writable, ...["created_at", "updated_at", ...(s.publishing ? ["published_at"] : [])]].map(f => { const type = s.fields[f] ?? "timestamptz"; return type === "date" || type === "timestamptz" ? `case ${q(f)}:return D.${type === "date" ? "date" : "timestamp"}(value as string);` : type === "json" ? `case ${q(f)}:return JSON.stringify(value);` : sqlite && type === "bool" ? `case ${q(f)}:return Number(value);` : ""; }).join("")}default:return value;}}\nconst server:Row=${q(server)};\n// Server-maintained (readOnly) fields: create stores their default, an edit drops them (the console echoes whole records).\nexport const values=(data:Row,patch=false):Row=>Object.fromEntries(Object.entries(data).flatMap(([key,value])=>{const column=names[key as keyof typeof names];return Object.hasOwn(server,column)?patch?[]:[[column,encode(column,server[column])]]:[[column,encode(column,value)]];}));\nexport const row=${wire(rowFields, sqlite)};\nfunction coerce(name:string,raw:string):{column:string;value:string|number|boolean}{${sqlite ? "" : "nativeText(raw);" + (temporal.length ? "if(" + q(temporal) + ".includes(name)&&/^0000-/.test(raw.trim()))fail(\"PostgreSQL dates require a nonzero year.\");" : "")}switch(name){${coercers.join("")}default:return fail("Unknown scalar filter field.");}}\nimport {validate as checkFilter} from "../validation/admin/${encodeURIComponent(s.name)}-partial.js";\nfunction field(name:string,raw:string){const f=coerce(name,raw);if(Object.hasOwn(names,name))checkFilter({[name]:f.value});return {...f,value:encode(f.column,f.value) as string|number|boolean};}\nexport const query=(params:URLSearchParams):EntryPageQuery|null=>entriesQuery(params,{path:${q(schemaPath)},orderFields:${q(orderNames)},publishing:${!!s.publishing},sqlite:${sqlite},field});\n`;
|
|
97
|
+
imports.push(`const fieldNames${n}=${q(rowNames)} as const;`);
|
|
98
|
+
imports.push(`import {names as names${n},row as row${n},query as query${n},values as values${n}} from "./admin/entries-${encodeURIComponent(s.name)}.js";`);
|
|
99
|
+
}
|
|
100
|
+
for (const [name, v] of Object.entries(plan.views).filter(([, v]) => v.surface !== "internal")) {
|
|
101
|
+
const n = views.length, encoded = encodeURIComponent(name), converted = conversions(v.input?.properties, (lowered.views[name]?.public ?? lowered.views[name]?.caller)?.binds ?? [], target);
|
|
102
|
+
imports.push(`import {query as queryView${n}} from "./validation/views/${encoded}.js";`);
|
|
103
|
+
const rename = Object.fromEntries(Object.entries(v.columns ?? {}).map(([key, col]) => [key, key === col.field ? plan.schemas[col.schema].names[col.field] ?? key : key]));
|
|
104
|
+
imports.push(`const viewNames${n}=${q(rename)} as const;`);
|
|
105
|
+
const pageData = input.adminPages?.[name];
|
|
106
|
+
// A supplied page map omits only Views its producer already refused (at `views/<name>` or `views/<name>/admin`).
|
|
107
|
+
if (!pageData) {
|
|
108
|
+
if (!input.adminPages)
|
|
109
|
+
refuse(`views/${name}/admin`, "Admin list was not generated: no compiler-authorized matching pages were supplied for this View.");
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
const kinds = (v.uiSchema?.list ?? {});
|
|
113
|
+
const filters = Object.fromEntries((kinds.filterFields ?? []).map(field => {
|
|
114
|
+
const lineage = v.columns?.[field] ?? v.columns?.[field.toLowerCase()], schema = lineage && plan.schemas[lineage.schema];
|
|
115
|
+
return [field, adminProperty(schema?.schema.properties?.[schema.names[lineage.field] ?? lineage.field] ?? { type: "string" })];
|
|
116
|
+
}));
|
|
117
|
+
const filterChecks = emitValidation({ procedures: { filters: { input: { type: "object", properties: filters, additionalProperties: false } } }, views: {} }, (path, msg) => refuse(`views/${name}/admin/` + path, msg));
|
|
118
|
+
files[`validation/admin/view-${encoded}.ts`] = filterChecks["validation/procedures/filters.ts"];
|
|
119
|
+
imports.push(`import {validate as filters${n}} from "./validation/admin/view-${encoded}.js";`);
|
|
120
|
+
const filterTransforms = Object.keys(filters).flatMap(field => { const col = v.columns?.[field] ?? v.columns?.[field.toLowerCase()], type = col && plan.schemas[col.schema]?.fields[col.field]; const convert = type === "date" && sqlite ? "encodeDate" : type === "timestamptz" && sqlite ? "encodeTimestamptz" : type === "bool" && sqlite ? "Number" : undefined; return convert ? [`if(Object.hasOwn(filters,${q(field)}))filters[${q(field)}]=${convert}(filters[${q(field)}] as ${type === "bool" ? "boolean" : "string"});`] : []; });
|
|
121
|
+
if (filterTransforms.some(t => t.includes("encode")))
|
|
122
|
+
imports.push('import {encodeDate,encodeTimestamptz} from "@aotter/mantle/scalars";');
|
|
123
|
+
const filterReads = Object.entries(filters).map(([field, s]) => { const type = [s.type].flat().find(t => t && t !== "null"); return `if(params.has(${q("filter." + field)})&¶ms.get(${q("filter." + field)})!=="")filters[${q(field)}]=${type === "boolean" ? `params.get(${q("filter." + field)})==="true"?true:params.get(${q("filter." + field)})==="false"?false:invalid("Expected true or false.",${q("views/" + name)})` : ["number", "integer"].includes(type ?? "") ? `Number(params.get(${q("filter." + field)}))` : `params.get(${q("filter." + field)})!`};`; });
|
|
124
|
+
const cursorKinds = (input.paging?.[name]?.types ?? []).map(type => type === "bool" ? "bool" : type === "integer" || type === "int8" ? "int" : type === "int4" ? "int4" : type.startsWith("numeric(") ? "numeric" : type === "real" || type === "float8" ? "float" : type === "date" ? "date" : type === "timestamptz" ? "timestamp" : "text");
|
|
125
|
+
const modes = Object.fromEntries(Object.entries({ caller: pageData.caller, trusted: pageData.trusted }).map(([mode, p]) => [mode, { ...p, binds: recipesOf(p, Object.keys(v.input?.properties ?? {}), message => refuse(`views/${name}/admin`, message)) }]));
|
|
126
|
+
pageSpecs.push(`const viewPage${n}=${q({ path: "views/" + name, cap: v.stmts[0]?.SelectStmt.limitCount?.A_Const?.ival?.ival ?? 500, cursorKinds, ...modes })} as const;`);
|
|
127
|
+
imports.push(`const allowsView${n}=${allowed(v.requires, `views/${name}`)};`);
|
|
128
|
+
if (v.surface === "admin")
|
|
129
|
+
adminViews.push(`view${n}`);
|
|
130
|
+
views.push(`{${user.used ? `check:(caller)=>{${authLines(undefined, `views/${name}`, pageData.caller.binds, sqlite).join("")}},` : ""}name:${q(name)},allows:allowsView${n},query:(params)=>{const result=queryView${n}(params),filters:Record<string,unknown>=Object.create(null);${filterReads.join("")}filters${n}(filters);${filterTransforms.join("")}${sqlite ? "" : "nativeText(result.input);nativeText(filters);"}${kinds.searchFields?.length ? `const search=params.get("search")?.trim();` : ""}return {...result,match:{filters${kinds.searchFields?.length ? ",...(search?{search}:{})" : ""}}};},page:(db,caller,input,paging)=>{deny(caller,allowsView${n}(caller),${q("views/" + name)});return nativePage(viewPage${n},adapter,db,caller,input,paging);},${converted ? `convert:${converted},` : ""}row:(raw)=>{const row=(${wire((input.viewKeys[name] ?? []).map(key => [key, boundaryType(plan, name, key)]), sqlite)})(raw);return Object.fromEntries(Object.entries(row).map(([key,value])=>[Object.hasOwn(viewNames${n},key)?viewNames${n}[key as keyof typeof viewNames${n}]:key,value]));}}`);
|
|
131
|
+
}
|
|
132
|
+
for (const [name, p] of Object.entries(plan.procedures).filter(([name]) => Object.values(plan.triggers).some(t => t.procedure === name && t.source.kind === "mcp" && t.source.surface === "admin"))) {
|
|
133
|
+
const n = operations.length, ref = "ref" in p.handler, encoded = encodeURIComponent(name), converted = conversions(p.input?.properties, lowered.procedures[name]?.caller?.flatMap(s => s.binds) ?? [], target);
|
|
134
|
+
imports.push(`import {validate as operation${n}} from "./validation/procedures/${encoded}.js";`);
|
|
135
|
+
operations.push(`{${input.description.targets.find(t => t._meta.id === `procedure:${name}`)?._meta.readOnly ? "readOnly:true," : ""}${user.used || p.trustedOnly ? `check:(caller)=>{${authLines(undefined, `procedures/${name}`, lowered.procedures[name]?.caller?.flatMap(s => s.binds), sqlite, p.trustedOnly).join("")}},` : ""}name:${q(name)},allows:${allowed(p.requires, `procedures/${name}`)},validate:operation${n},${converted ? `convert:${converted},` : ""}run:${ref ? `async(db,caller,input)=>(await import("./generated.js")).store(db,caller,{handlers:options.handlers}).procedures[${q(name)}](input)` : `async(db,caller,input)=>(await import("./procedures/${encoded}.js")).default(db,caller,input)`}}`);
|
|
136
|
+
}
|
|
137
|
+
const entryData = sqlConstants(input.adminEntries);
|
|
138
|
+
imports.push(...views.map((view, n) => `const view${n}=${view} satisfies View<Database>;`), ...pageSpecs, ...entryData.constants, `const entrySpecs=${entryData.code} as const;`);
|
|
139
|
+
imports.push(`export const statisticsView=(db:Database,caller:Caller,collection:keyof typeof entrySpecs,args:{from:number;to:number;bucketMs:number})=>nativeStatistics(entrySpecs,adapter,db,caller,collection,args);`);
|
|
140
|
+
const metadataGuards = [...Object.entries(plan.views).map(([name, v]) => `case ${q("view:" + name)}: return (${allowed(v.requires, `views/${name}`)})(caller);`), ...Object.entries(plan.procedures).map(([name, p]) => `case ${q("procedure:" + name)}: return (${allowed(p.requires, `procedures/${name}`)})(caller);`), ...Object.values(plan.schemas).filter(s => s.publishing).flatMap(s => ["publish", "unpublish", "archive"].map(verb => `case ${q("procedure:" + s.name + "." + verb)}: return isAdmin(caller);`))];
|
|
141
|
+
files["admin-bindings.ts"] = `${imports.filter(Boolean).join("\n")}\nexport function adminBindings${refs ? "<const H extends Handlers>(options:{handlers:H & Record<Exclude<keyof H,keyof Handlers>,never>})" : "(_options?:{handlers?:Handlers})"}{\nreturn {metadata:{...bootstrap,accessTargets:()=>import("./access-targets.js").then(m=>m.targets),${plan.access ? `userFields:${q(plan.access.userFields)} as const,` : ""}allows:(target:import("@aotter/mantle/contracts").Target,caller:Caller)=>{switch(target.kind+":"+target.name){${metadataGuards.join("")}default:return target.kind==="schema";}}},adapter,schemas:[${schemas.join(",\n")}] satisfies readonly EntrySchema<Database>[],views:[${adminViews.join(",")}],developerViews:[${views.map((_, n) => `view${n}`).join(",")}],operations:[${operations.join(",\n")}] satisfies readonly Operation<Database,${refs ? "Handlers" : "never"}>[]};\n}\n`;
|
|
142
|
+
return files;
|
|
143
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/** `admin-client.ts`: the types Admin's data hooks bind to, for the application's browser-side `admin.tsx`. */
|
|
2
|
+
import { BUILT_IN_NAV_GROUPS, mcpTools } from "../build/compiler.js";
|
|
3
|
+
import { q } from "../domain/entry.js";
|
|
4
|
+
/**
|
|
5
|
+
* The compatibility test of the application's Admin MCP App (`node --test generated/admin-mcp-app.check.mjs`): it loads the App
|
|
6
|
+
* `mantle bundle` built in the official MCP Apps host and fails on a network request, a console error or an exception. It needs
|
|
7
|
+
* `playwright-core` (a devDependency) and Chrome: `npx playwright-core install chromium`, or `MANTLE_TEST_CHROMIUM=<executable>`.
|
|
8
|
+
* Node strips the types of `admin-descriptors.ts` (Node 22.18 or newer).
|
|
9
|
+
*/
|
|
10
|
+
const MCP_APP_TEST = `import { existsSync } from "node:fs";
|
|
11
|
+
import { test } from "node:test";
|
|
12
|
+
import { checkMcpApp } from "@aotter/mantle-admin/testing";
|
|
13
|
+
import { mcpAppCatalogues } from "./admin-descriptors.ts";
|
|
14
|
+
|
|
15
|
+
// \`mantle bundle <entry> dist\` writes the App here; MANTLE_MCP_APP_HTML names another file
|
|
16
|
+
const html = process.env.MANTLE_MCP_APP_HTML ?? "dist/client/admin/mcp-app.html";
|
|
17
|
+
|
|
18
|
+
test("the Admin MCP App works in an MCP host", { timeout: 300_000 }, async () => {
|
|
19
|
+
if (!existsSync(html)) throw new Error(\`\${html} is missing: run \\\`npm run build\\\` first.\`);
|
|
20
|
+
await checkMcpApp({ catalogue: mcpAppCatalogues.admin, html });
|
|
21
|
+
});
|
|
22
|
+
`;
|
|
23
|
+
/** A Schema, View input or Procedure input as a closed object type; one that is only a `$ref` stays open. */
|
|
24
|
+
const closed = (typeOf, schema) => !schema ? "{}" : schema.properties || schema.type === "object" && !schema["$ref"] ? typeOf({ ...schema, additionalProperties: false }) : "{ readonly [key: string]: unknown }";
|
|
25
|
+
/**
|
|
26
|
+
* Types are what the routes take and return, not the Store's rows: an entry's `data` keeps declared field names, an input is
|
|
27
|
+
* what the route validates, a View row is its wire row under the names the browser route gives its columns (an MCP App's
|
|
28
|
+
* `tools/call` returns the SQL names; the hooks rename them with `rowNames`), with `true` when it is an admin MCP tool, else null, which
|
|
29
|
+
* types `pages[].mcp.renders` (types only; nothing ships). The file imports `generated/*` as types only, so nothing of the
|
|
30
|
+
* Worker enters the browser bundle, and it is refused in the Worker's startup graph (`mantle bundle`).
|
|
31
|
+
*/
|
|
32
|
+
export function emitAdminClient(plan, typeOf) {
|
|
33
|
+
const tools = mcpTools(plan, "admin"), hasTool = (kind, source) => tools.some(t => t.kind === kind && t.source === source);
|
|
34
|
+
const views = Object.entries(plan.views).filter(([, v]) => v.surface === "admin").sort(([a], [b]) => a < b ? -1 : 1);
|
|
35
|
+
const operations = Object.entries(plan.procedures).filter(([name]) => hasTool("procedure", name)).sort(([a], [b]) => a < b ? -1 : 1);
|
|
36
|
+
const schemas = Object.values(plan.schemas).sort((a, b) => a.name < b.name ? -1 : 1);
|
|
37
|
+
// the scope column belongs to the caller, so an entry's data has no such field
|
|
38
|
+
const dataOf = (s) => {
|
|
39
|
+
const scope = s.scope ? s.names[s.scope] ?? s.scope : undefined, { [scope ?? ""]: _scope, ...properties } = s.schema.properties ?? {};
|
|
40
|
+
// a draft of a publishing collection is only partly validated, so none of its fields is certain to be there
|
|
41
|
+
const required = s.publishing ? [] : s.schema.required?.filter(f => f !== scope);
|
|
42
|
+
const schema = { ...s.schema, properties, ...(required ? { required } : {}) };
|
|
43
|
+
return s.translates ? typeOf(schema) : closed(typeOf, schema);
|
|
44
|
+
};
|
|
45
|
+
// the names the browser route gives a View's columns where they differ from the SQL output names, as it applies them
|
|
46
|
+
const renames = views.map(([, v]) => Object.fromEntries(Object.entries(v.columns ?? {}).flatMap(([key, c]) => {
|
|
47
|
+
const named = key === c.field ? plan.schemas[c.schema].names[c.field] ?? key : key;
|
|
48
|
+
return named !== key ? [[key, named]] : [];
|
|
49
|
+
})));
|
|
50
|
+
// every sidebar group an admin Schema or View places an item in; `defineAdmin` must declare the ones Admin does not have
|
|
51
|
+
// (the generate-time check of `uiSchema.nav.group` is this type)
|
|
52
|
+
const placed = (ui) => { const group = ui?.["nav"]?.group; return typeof group === "string" ? [group] : []; };
|
|
53
|
+
const used = [...new Set([...schemas.flatMap(s => placed(s.uiSchema)), ...views.flatMap(([, v]) => placed(v.uiSchema))])].sort();
|
|
54
|
+
const custom = used.filter(group => !BUILT_IN_NAV_GROUPS.has(group));
|
|
55
|
+
const union = (names) => names.length ? names.map(name => q(name)).join(" | ") : "never";
|
|
56
|
+
// whether an admin View is an MCP tool, which a page declared for an MCP App (`pages[].mcp.renders`) must have
|
|
57
|
+
const toolOf = (name) => hasTool("view", name) || null;
|
|
58
|
+
const rows = views.map(([name], n) => `import type { WireRow as View${n}Wire } from "./views/${encodeURIComponent(name)}.js";`);
|
|
59
|
+
const sql = operations.some(([, p]) => "sql" in p.handler);
|
|
60
|
+
return { "admin-mcp-app.check.mjs": MCP_APP_TEST, "admin-client.ts": [
|
|
61
|
+
"// Browser only: import this from src/admin.tsx, never from the Worker (`mantle bundle` refuses it there).",
|
|
62
|
+
'import type { AdminMeta } from "@aotter/mantle-admin/app";',
|
|
63
|
+
'import { createAdminHooks } from "@aotter/mantle-admin/hooks";',
|
|
64
|
+
...(sql ? ['import type { Output } from "@aotter/mantle/contracts";'] : []),
|
|
65
|
+
...rows,
|
|
66
|
+
"",
|
|
67
|
+
"type Renamed<Row, Names extends { readonly [from: string]: string }> = { [K in keyof Row as K extends keyof Names ? Names[K] : K]: Row[K] };",
|
|
68
|
+
...views.map((_, n) => `type View${n}Row = Renamed<View${n}Wire, ${q(renames[n])}>;`),
|
|
69
|
+
"",
|
|
70
|
+
"/** Every sidebar group the manifest places an item in. */",
|
|
71
|
+
`export type ManifestNavGroup = ${union(used)};`,
|
|
72
|
+
"",
|
|
73
|
+
"/** The input and row of each admin View, the `data` of each collection's entries, and the input and output of each admin operation. */",
|
|
74
|
+
"export interface AppAdminTypes {",
|
|
75
|
+
` readonly views: { ${views.map(([name, v], n) => `readonly ${q(name)}: { readonly input: ${closed(typeOf, v.input)}; readonly row: View${n}Row; readonly mcp: ${q(toolOf(name))} }`).join("; ")} };`,
|
|
76
|
+
` readonly collections: { ${schemas.map(s => `readonly ${q(s.name)}: { readonly data: ${dataOf(s)} }`).join("; ")} };`,
|
|
77
|
+
` readonly operations: { ${operations.map(([name, p]) => `readonly ${q(name)}: { readonly input: ${closed(typeOf, p.input)}; readonly output: ${"sql" in p.handler ? "Output" : "unknown"} }`).join("; ")} };`,
|
|
78
|
+
` readonly navGroups: ${union(custom)};`,
|
|
79
|
+
"}",
|
|
80
|
+
"",
|
|
81
|
+
"/** Pass to `defineAdmin(admin)`: the column names a View's rows carry in the browser, for an MCP App to match. */",
|
|
82
|
+
`export const admin: AdminMeta<AppAdminTypes> = { rowNames: ${q(Object.fromEntries(views.flatMap(([name], n) => Object.keys(renames[n]).length ? [[name, renames[n]]] : [])))} };`,
|
|
83
|
+
"",
|
|
84
|
+
"export const { useView, useEntries, useEntry, useOperation, useCollectionTotal, useMe, useBadges } = createAdminHooks<AppAdminTypes>();",
|
|
85
|
+
"",
|
|
86
|
+
].join("\n") };
|
|
87
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/** Build-time projections only; generated exports are static, independently tree-shakable data. */
|
|
2
|
+
import { isPrimaryCollection, mcpTools, mcpToolNameSegment, toolTitle, collectionOf, developerConsole, rowPreconditions, appCatalog, entrySchema } from "../build/compiler.js";
|
|
3
|
+
import { q } from "../domain/entry.js";
|
|
4
|
+
import { advertised } from "./validation.js";
|
|
5
|
+
import { publishingAnnotations, publishingInput, publishingTransitions } from "./publishing.js";
|
|
6
|
+
import { versioned } from "./tool-version.js";
|
|
7
|
+
export function emitAdminDescriptors({ plan, admin = false }, diagnostics) {
|
|
8
|
+
const schemaList = Object.values(plan.schemas);
|
|
9
|
+
const placed = [...schemaList.map(s => ["schemas/" + s.name, s.uiSchema, s]), ...Object.entries(plan.views).map(([name, v]) => ["views/" + name, v.uiSchema, null])];
|
|
10
|
+
for (const [path, ui, s] of placed) {
|
|
11
|
+
const nav = (ui?.["nav"] ?? {}), group = nav["group"];
|
|
12
|
+
// a child folded under its parent, or a translation on its parent's language tabs, has no sidebar entry to place
|
|
13
|
+
if (s && !isPrimaryCollection(s, schemaList))
|
|
14
|
+
for (const key of ["group", "order", "hidden"])
|
|
15
|
+
if (nav[key] !== undefined)
|
|
16
|
+
diagnostics.push({ code: "SCHEMA_UI_INVALID", path: `${path}/uiSchema/nav/${key}`, message: s.translates ? `Schema '${s.name}' has no sidebar entry to place: it is a translation, shown on its parent's language tabs.` : `Schema '${s.name}' has no sidebar entry to place: it is folded under its parent${collectionOf(s, schemaList).parent?.parentField === "id" ? "; nav.standalone: true lists it in the sidebar." : " and opens from its parent's workbench (standalone needs a required id reference)."}` });
|
|
17
|
+
}
|
|
18
|
+
if (diagnostics.length)
|
|
19
|
+
return {};
|
|
20
|
+
const schemas = Object.values(plan.schemas);
|
|
21
|
+
const allCollections = Object.fromEntries(schemas.map(s => [s.name, { ...collectionOf(s, schemas), ...(admin ? { scopeField: s.scope ? s.names[s.scope] ?? s.scope : null, exportFields: Object.keys(s.fields).filter(f => f !== s.scope && s.fields[f] !== "geo").map(f => s.names[f] ?? f) } : {}) }]));
|
|
22
|
+
const viewNames = Object.create(null);
|
|
23
|
+
const views = Object.entries(plan.views).filter(([, v]) => v.surface === "admin").map(([name, v]) => {
|
|
24
|
+
const columns = Object.fromEntries(Object.entries(v.columns ?? {}).map(([key, column]) => {
|
|
25
|
+
const schema = plan.schemas[column.schema], field = schema.names[column.field] ?? column.field;
|
|
26
|
+
const output = key === column.field ? field : key;
|
|
27
|
+
(viewNames[name] ??= Object.create(null))[key] = output;
|
|
28
|
+
return [output, { schema: schema.name, field }];
|
|
29
|
+
}));
|
|
30
|
+
const list = (v.uiSchema?.list ?? {});
|
|
31
|
+
return { name, title: v.title ?? null, description: v.description ?? null, input: v.input ?? null, list: { columns: list.columns ?? [], searchFields: list.searchFields ?? [], filterFields: list.filterFields ?? [] }, columns, ...(v.uiSchema?.nav ? { nav: v.uiSchema.nav } : {}) };
|
|
32
|
+
});
|
|
33
|
+
const adminTools = mcpTools(plan, "admin"), toolNames = new Set(adminTools.map(t => t.name));
|
|
34
|
+
const operations = adminTools.filter(t => t.kind === "procedure").map(t => {
|
|
35
|
+
const p = plan.procedures[t.source];
|
|
36
|
+
const preconditions = p.target && "sql" in p.handler ? rowPreconditions(p.handler.sql.stmts, p.target.schema, p.target.id, plan.schemas[p.target.schema.toLowerCase()]?.schema ?? {}) : [];
|
|
37
|
+
return { ...(preconditions.length ? { preconditions } : {}), name: t.source, title: p.title ?? null, description: p.description ?? null, input: p.input, uiSchema: p.uiSchema ?? null, interactions: p.target ? [{ collection: p.target.schema, bind: [{ input: p.target.id, field: "id" }], ...(p.target.version ? { version: p.target.version } : {}), mutates: true }] : [] };
|
|
38
|
+
});
|
|
39
|
+
const authorizations = { views: Object.fromEntries(views.map(v => [v.name, plan.views[v.name].requires ?? null])), procedures: Object.fromEntries(Object.entries(plan.procedures).map(([name, p]) => [name, p.requires ?? null])) };
|
|
40
|
+
const adminCatalogue = appCatalog(plan, "admin");
|
|
41
|
+
const catalogues = { public: appCatalog(plan, "public"), admin: { views: Object.fromEntries(Object.entries(adminCatalogue.views).map(([name, v]) => [name, { ...v, actions: [...v.actions] }])), actions: { ...adminCatalogue.actions } } };
|
|
42
|
+
const snapshot = developerConsole(plan);
|
|
43
|
+
const webmcp = { tools: adminTools.map(({ name, source, kind, title, description, inputSchema, outputSchema, annotations }) => ({ target: { kind, name: source }, ...versioned({ name, ...(title ? { title: (kind === "view" ? plan.views[source] : plan.procedures[source]).title ?? title } : {}), ...advertised(inputSchema, (kind === "view" ? plan.views[source] : plan.procedures[source]).description ?? description), ...(outputSchema ? { outputSchema } : {}), ...(annotations ? { annotations } : {}) }) })), routes: Object.fromEntries(adminTools.flatMap(t => {
|
|
44
|
+
if (t.kind === "view")
|
|
45
|
+
return [[t.name, { path: "/admin/views/" + encodeURIComponent(t.source) }]];
|
|
46
|
+
const target = plan.procedures[t.source].target;
|
|
47
|
+
return target ? [[t.name, { path: "/admin/c/" + encodeURIComponent(plan.schemas[target.schema.toLowerCase()]?.name ?? target.schema), entry: true }]] : [];
|
|
48
|
+
})) };
|
|
49
|
+
// These are the actual generated transitions, not authored ref handlers or SQL IR.
|
|
50
|
+
for (const schema of schemas.filter(s => s.publishing))
|
|
51
|
+
for (const [verb] of publishingTransitions) {
|
|
52
|
+
const name = schema.name + "." + verb, tool = mcpToolNameSegment(verb + "_" + schema.name);
|
|
53
|
+
if (toolNames.has(tool)) {
|
|
54
|
+
diagnostics.push({ code: "GENERATE_UNSUPPORTED", path: "schemas/" + schema.name, message: "Generated publishing tool '" + tool + "' conflicts with an admin tool." });
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
toolNames.add(tool);
|
|
58
|
+
const action = { capability: tool, inputSchema: publishingInput, bind: [{ input: "id", field: "id" }], version: "expectedVersion", mutates: true };
|
|
59
|
+
catalogues.admin.actions[tool] = action;
|
|
60
|
+
for (const t of adminTools.filter(t => t.kind === "view"))
|
|
61
|
+
if (entrySchema(plan, plan.views[t.source]) === schema.name.toLowerCase())
|
|
62
|
+
catalogues.admin.views[t.name].actions.push(tool);
|
|
63
|
+
authorizations.procedures[name] = { auth: { all: ["ctx.admin"] } };
|
|
64
|
+
const description = verb + " an entry in " + schema.name + ".";
|
|
65
|
+
webmcp.tools.push({ target: { kind: "procedure", name }, ...versioned({ name: tool, title: toolTitle(verb + "_" + schema.name), description, inputSchema: publishingInput, annotations: publishingAnnotations(verb) }) });
|
|
66
|
+
webmcp.routes[tool] = { path: "/admin/c/" + encodeURIComponent(schema.name), entry: true };
|
|
67
|
+
snapshot.interfaces.callable.push({ kind: "procedure", name: tool, target: name, surface: "admin", audience: "admin", title: null, description, input: publishingInput, output: null, trigger: null });
|
|
68
|
+
}
|
|
69
|
+
const data = { allCollections, views, operations, fieldNames: Object.fromEntries(schemas.map(s => [s.name, s.names])), viewNames, authorizations, developerConsole: snapshot, mcpAppCatalogues: catalogues, webmcp };
|
|
70
|
+
return { "admin-descriptors.ts": "// Generated static Admin metadata. Import only the exports the application uses.\n" + literals(data) + "\nexport const collections = [" + schemas.filter(s => !s.translates).map(s => "allCollections[" + q(s.name) + "]").join(",") + "] as const;\nexport const bootstrap = {collections, allCollections, operations, views, webmcp, developerConsole} as const;\n" };
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Each export as a JSON literal; a subtree of 40 or more bytes that would be printed more than once is printed once, as a
|
|
74
|
+
* module-private constant the exports reference (a bundler keeps only those an imported export reaches).
|
|
75
|
+
*/
|
|
76
|
+
function literals(exports) {
|
|
77
|
+
const data = JSON.parse(q(exports)), count = new Map(), hoisted = new Map(), constants = [];
|
|
78
|
+
const each = (value, visit) => { if (value && typeof value === "object")
|
|
79
|
+
for (const child of Object.values(value))
|
|
80
|
+
if (child && typeof child === "object")
|
|
81
|
+
visit(q(child), child); };
|
|
82
|
+
const tally = (json, value, by = 1) => { if (json.length >= 40)
|
|
83
|
+
count.set(json, (count.get(json) ?? 0) + by); each(value, (json, child) => tally(json, child, by)); };
|
|
84
|
+
for (const value of Object.values(data))
|
|
85
|
+
each(value, tally);
|
|
86
|
+
// Longest first: once a subtree is printed once, what it contains occurs (copies - 1) times fewer per occurrence in it.
|
|
87
|
+
for (const json of [...count.keys()].sort((a, b) => b.length - a.length)) {
|
|
88
|
+
const copies = count.get(json);
|
|
89
|
+
if (copies > 1) {
|
|
90
|
+
hoisted.set(json, "");
|
|
91
|
+
each(JSON.parse(json), (inner, child) => tally(inner, child, 1 - copies));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
let named = 0;
|
|
95
|
+
const print = (value) => !value || typeof value !== "object" ? q(value) : Array.isArray(value) ? "[" + value.map(reference).join(",") + "]" : "{" + Object.entries(value).map(([key, child]) => (key === "__proto__" ? "[" + q(key) + "]" : q(key)) + ":" + reference(child)).join(",") + "}";
|
|
96
|
+
const reference = (value) => {
|
|
97
|
+
const json = q(value);
|
|
98
|
+
if (hoisted.get(json) === "") {
|
|
99
|
+
const name = "$" + named++;
|
|
100
|
+
hoisted.set(json, name);
|
|
101
|
+
constants.push("const " + name + " = " + print(value) + " as const;");
|
|
102
|
+
}
|
|
103
|
+
return hoisted.get(json) ?? print(value);
|
|
104
|
+
};
|
|
105
|
+
const lines = Object.entries(data).map(([name, value]) => "export const " + name + " = " + print(value) + " as const;");
|
|
106
|
+
return [...constants, ...lines].join("\n");
|
|
107
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { userReferences } from "../domain/userReferences.js";
|
|
2
|
+
/** Canonical lowered programs become ordinary target-specific TypeScript, never a runtime plan. */
|
|
3
|
+
import { parseNumeric, tableOutputs } from "../build/compiler.js";
|
|
4
|
+
import { boundaryType, nativeType, outputType, wireType } from "../domain/columns.js";
|
|
5
|
+
import { databaseImport, driverFor, entry, exportName, generatedFiles, isSqlite as sqlite, q } from "../domain/entry.js";
|
|
6
|
+
import { authLines as auth } from "../domain/input.js";
|
|
7
|
+
import { recipesOf } from "../domain/recipes.js";
|
|
8
|
+
import { emitTtl } from "./ttl.js";
|
|
9
|
+
import { emitPublishing } from "./publishing.js";
|
|
10
|
+
import { emitStores } from "./stores.js";
|
|
11
|
+
import { emitPaging } from "./paging.js";
|
|
12
|
+
import { emitWeb } from "./web.js";
|
|
13
|
+
import { emitMcp } from "./mcp.js";
|
|
14
|
+
import { emitValidation } from "./validation.js";
|
|
15
|
+
import { refuseDeclarations } from "./refusals.js";
|
|
16
|
+
import { emitHandlers } from "./handlers.js";
|
|
17
|
+
import { emitAdminDescriptors } from "./adminDescriptors.js";
|
|
18
|
+
import { emitAdminClient } from "./adminClient.js";
|
|
19
|
+
import { emitSite } from "./site.js";
|
|
20
|
+
import { emitTranslations } from "./translations.js";
|
|
21
|
+
import { emitAdminBindings } from "./adminBindings.js";
|
|
22
|
+
import { emitRest } from "./rest.js";
|
|
23
|
+
const typeOf = (s) => {
|
|
24
|
+
if (!s)
|
|
25
|
+
return "unknown";
|
|
26
|
+
if (s.nullable === true)
|
|
27
|
+
return `${typeOf({ ...s, nullable: false })} | null`;
|
|
28
|
+
if (s.enum)
|
|
29
|
+
return s.enum.map(v => q(v)).join(" | ") || "never";
|
|
30
|
+
if (s.const !== undefined)
|
|
31
|
+
return q(s.const);
|
|
32
|
+
if (Array.isArray(s.type))
|
|
33
|
+
return s.type.map(type => typeOf({ ...s, type })).join(" | ") || "never";
|
|
34
|
+
switch (s.type) {
|
|
35
|
+
case "string": return "string";
|
|
36
|
+
case "integer":
|
|
37
|
+
case "number": return "number";
|
|
38
|
+
case "boolean": return "boolean";
|
|
39
|
+
case "null": return "null";
|
|
40
|
+
case "array": return `ReadonlyArray<${Array.isArray(s.items) ? "unknown" : typeOf(s.items)}>`;
|
|
41
|
+
case "object": return `{ ${Object.entries(s.properties ?? {}).map(([key, child]) => `readonly ${q(key)}${s.required?.includes(key) ? "" : "?"}: ${typeOf(child)};`).join(" ")} ${s.additionalProperties !== false ? "readonly [key: string]: unknown;" : ""} }`;
|
|
42
|
+
default: return "unknown";
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
export function generate(input) {
|
|
46
|
+
const { target, plan, lowered, viewKeys, newId, site, admin, paging } = input;
|
|
47
|
+
const diagnostics = [];
|
|
48
|
+
refuseDeclarations({ plan }, diagnostics);
|
|
49
|
+
const refuse = (path, message) => { diagnostics.push({ code: "GENERATE_UNSUPPORTED", path, message }); };
|
|
50
|
+
const isSqlite = sqlite(target);
|
|
51
|
+
const user = userReferences(plan, isSqlite);
|
|
52
|
+
const expected = isSqlite ? "@aotter/mantle/d1" : "@aotter/mantle/postgres";
|
|
53
|
+
if (lowered.dialect.name !== expected || plan.dialect.name !== expected)
|
|
54
|
+
refuse("target", `Target '${target}' needs canonical '${expected}' compilation and lowering.`);
|
|
55
|
+
const driver = driverFor(target);
|
|
56
|
+
const queryInputType = (schema, statements) => {
|
|
57
|
+
if (!schema?.properties)
|
|
58
|
+
return typeOf(schema);
|
|
59
|
+
const binds = statements.flatMap(s => s.binds).filter(b => b.k === "input");
|
|
60
|
+
const properties = Object.entries(schema.properties).map(([name, field]) => {
|
|
61
|
+
const bind = binds.find(b => b.k === "input" && name.toLowerCase() === String(b.name).toLowerCase());
|
|
62
|
+
if (!bind || bind.k !== "input")
|
|
63
|
+
return `readonly ${q(name)}${schema.required?.includes(name) ? "" : "?"}: ${typeOf(field)};`;
|
|
64
|
+
const type = String(bind.type);
|
|
65
|
+
const driverType = type === "json" ? typeOf(field) : type === "date" ? "string" : type === "timestamptz" ? "string | Date" : isSqlite
|
|
66
|
+
? type === "bool" || parseNumeric(type) ? "number" : typeOf(field)
|
|
67
|
+
: parseNumeric(type) ? "number | string" : typeOf(field);
|
|
68
|
+
const nullable = field.nullable === true || Array.isArray(field.type) && field.type.includes("null") || !schema.required?.includes(name);
|
|
69
|
+
// D1 cannot bind undefined. Bound fields are explicit, null represents absence.
|
|
70
|
+
return `readonly ${q(name)}: ${driverType}${nullable ? " | null" : ""};`;
|
|
71
|
+
});
|
|
72
|
+
return `{ ${properties.join(" ")} ${schema.additionalProperties !== false ? "readonly [key:string]: unknown;" : ""} }`;
|
|
73
|
+
};
|
|
74
|
+
const inputFields = (schema, path) => {
|
|
75
|
+
const fields = Object.keys(schema?.properties ?? {});
|
|
76
|
+
if (new Set(fields.map(field => field.toLowerCase())).size !== fields.length)
|
|
77
|
+
refuse(path, "Input properties must have unique case-insensitive names. Rename input properties to be unique without regard to case.");
|
|
78
|
+
return fields;
|
|
79
|
+
};
|
|
80
|
+
// The dialect functions the bind recipes call, so a bundle carries only those (`binds` takes this object).
|
|
81
|
+
const values = new Set();
|
|
82
|
+
/** A statement as a constant: its text and how to bind it. */
|
|
83
|
+
const step = (s, path, fields, row = false) => {
|
|
84
|
+
const recipes = recipesOf(s, fields, message => refuse(path, message));
|
|
85
|
+
for (const r of recipes) {
|
|
86
|
+
if (r.k === "now" || r.k === "cutoff")
|
|
87
|
+
values.add(r.k);
|
|
88
|
+
else if (r.k === "input" && r.type)
|
|
89
|
+
values.add(r.type === "date" ? "date" : "timestamp");
|
|
90
|
+
}
|
|
91
|
+
return `{ sql: ${q(s.sql)}, binds: ${q(recipes)}${row ? ", row: true" : ""} }`;
|
|
92
|
+
};
|
|
93
|
+
const declarations = [], views = [], procedures = [], refProcedures = [];
|
|
94
|
+
const entries = {};
|
|
95
|
+
const base = "@aotter/mantle/";
|
|
96
|
+
const refNames = emitHandlers(plan, target !== "cloudflare-d1", typeOf, declarations, refProcedures);
|
|
97
|
+
const hasHandlers = refNames.length > 0;
|
|
98
|
+
for (const [index, [name, view]] of Object.entries(plan.views).sort().entries()) {
|
|
99
|
+
const path = `views/${name}`, fn = `view${index}`;
|
|
100
|
+
const modes = lowered.views[name];
|
|
101
|
+
const mode = view.surface === "public" ? "public" : "caller";
|
|
102
|
+
const c = modes?.[mode], trusted = modes?.trusted;
|
|
103
|
+
if (!c || (mode === "caller" && !trusted)) {
|
|
104
|
+
refuse(path, "Every reachable visibility mode must have canonical lowered SQL.");
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const keys = Object.hasOwn(viewKeys, name) ? viewKeys[name] : undefined;
|
|
108
|
+
if (!keys || new Set(keys).size !== keys.length) {
|
|
109
|
+
refuse(path, "Dynamic or repeated View outputs need an explicit generated row contract. Give each SELECT output a unique explicit alias.");
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
const output = [], direct = tableOutputs(view, plan.schemas);
|
|
113
|
+
for (const key of keys) {
|
|
114
|
+
// A table column read unchanged keeps its NOT NULL (and gives a native column such as `id` its type); anything else may be NULL.
|
|
115
|
+
const type = outputType(plan, name, key) ?? direct[key]?.type;
|
|
116
|
+
// Declared timestamps and dates arrive formatted by the SQL itself (domain/wireScalars).
|
|
117
|
+
output.push(`readonly ${q(key)}: ${nativeType(type, isSqlite, direct[key]?.notNull)};`);
|
|
118
|
+
}
|
|
119
|
+
const fieldNames = inputFields(view.input, path + "/input");
|
|
120
|
+
const callerStep = step(c, path, fieldNames), trustedStep = mode === "caller" ? step(trusted, path, fieldNames) : callerStep;
|
|
121
|
+
declarations.push(`export type View${index}Input = ${queryInputType(view.input ?? { type: "object", additionalProperties: false }, [c, ...(trusted ? [trusted] : [])])};`, `export type View${index}Row = { ${output.join(" ")} };`, `export type View${index}WireRow = { ${keys.map(key => `readonly ${q(key)}: ${boundaryType(plan, name, key) ? wireType(boundaryType(plan, name, key), direct[key]?.notNull) : `View${index}Row[${q(key)}]`};`).join(" ")} };`, `const ${fn}Caller = ${callerStep} as const;`, ...(trustedStep !== callerStep ? [`const ${fn}Trusted = ${trustedStep} as const;`] : []), `async function ${fn}(db: ${isSqlite ? "Database" : "Unsafe"}, caller: Caller, raw: View${index}Input): Promise<View${index}Row[]> {`, ...auth(view.requires, path), ...(user.used ? [' USER.modeOf(caller);'] : []), ` const m = ${trustedStep !== callerStep ? `${user.used ? 'USER.modeOf(caller) === "trusted"' : 'caller.kind === "system"'} ? ${fn}Trusted : ` : ""}${fn}Caller;`, ` return DRIVER.read(db, ${user.used ? "USER.scoped(m.sql, caller)" : "m.sql"}, binds(D, m.binds, caller, raw));`, "}");
|
|
122
|
+
views.push(`[${q(name)}]: ${fn}`);
|
|
123
|
+
declarations.push(`export { ${fn} as ${exportName("view", name)} };`);
|
|
124
|
+
entries[`views/${encodeURIComponent(name)}.ts`] = entry("view", name, `View${index}Input as Input, View${index}Row as Row, View${index}WireRow as WireRow`);
|
|
125
|
+
}
|
|
126
|
+
for (const [index, [name, procedure]] of Object.entries(plan.procedures).sort().entries()) {
|
|
127
|
+
const path = `procedures/${name}`, fn = `procedure${index}`;
|
|
128
|
+
if (!("sql" in procedure.handler))
|
|
129
|
+
continue;
|
|
130
|
+
const modes = lowered.procedures[name];
|
|
131
|
+
if (!modes?.caller || !modes.trusted) {
|
|
132
|
+
refuse(path, "Both caller and trusted SQL must be lowered.");
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if ([...modes.caller, ...modes.trusted].some(s => s.publish || s.schema && plan.schemas[s.schema]?.publishing))
|
|
136
|
+
refuse(path, "A SQL Procedure cannot write a publishing Schema: create and edit its rows from a ref handler through the Store (`ctx.store.collection(...)`), and change status with the generated `<schema>.publish` / `.unpublish` / `.archive` transitions.");
|
|
137
|
+
const fieldNames = inputFields(procedure.input, path + "/input");
|
|
138
|
+
const steps = (statements) => `[${statements.map(s => step(s, path, fieldNames, s.kind === "row")).join(", ")}] as const`;
|
|
139
|
+
const same = steps(modes.caller) === steps(modes.trusted);
|
|
140
|
+
declarations.push(`export type Procedure${index}Input = ${queryInputType(procedure.input, [...modes.caller, ...modes.trusted])};`, `const ${fn}Caller = ${steps(modes.caller)};`, ...(same ? [] : [`const ${fn}Trusted = ${steps(modes.trusted)};`]), `async function ${fn}(db: Database, caller: Caller, raw: Procedure${index}Input): Promise<Output> {`, ...(modes.caller.some(s => s.kind !== "read") ? [` if ("authenticatedAs" in caller && caller.authenticatedAs === "snapshot") (await import("@aotter/mantle/host-caller")).checkFresh(caller, false, ${q(path)});`] : []), ...auth(procedure.requires, path), ...(user.used ? [' USER.modeOf(caller);'] : []), ...(procedure.trustedOnly ? [` deny(caller, USER.modeOf(caller) === "trusted", ${q(path)});`] : []), ` return { results: await DRIVER.procedure(db, bound(D, ${user.used ? "USER.scopedAll(" : ""}${same ? "" : `${user.used ? 'USER.modeOf(caller) === "trusted"' : 'caller.kind === "system"'} ? ${fn}Trusted : `}${fn}Caller${user.used ? ", caller)" : ""}, caller, raw), ${q(path)}) };`, "}");
|
|
141
|
+
procedures.push(`[${q(name)}]: ${fn}`);
|
|
142
|
+
declarations.push(`export { ${fn} as ${exportName("procedure", name)} };`);
|
|
143
|
+
entries[`procedures/${encodeURIComponent(name)}.ts`] = entry("procedure", name, `Procedure${index}Input as Input`, `export type { Output } from "${base}contracts";\n`);
|
|
144
|
+
}
|
|
145
|
+
emitTtl(plan, isSqlite, declarations, procedures, entries, refuse);
|
|
146
|
+
emitPublishing(plan, isSqlite, declarations, procedures, entries, values, refuse);
|
|
147
|
+
const stores = emitStores(plan.schemas, isSqlite, newId, refuse, hasHandlers);
|
|
148
|
+
const surfaces = { ...emitPaging(plan, lowered, target, refuse, paging), ...emitPaging(plan, input.wireLowered ?? lowered, target, refuse, paging, true), ...emitValidation(plan, refuse), ...emitRest(plan, lowered, target, input.description), ...emitWeb(plan, lowered, target), ...emitMcp(plan, lowered, target, input.description, refuse, !!site), ...emitAdminDescriptors({ plan, admin }, diagnostics), ...emitAdminBindings(input, refuse), ...(admin ? emitAdminClient(plan, typeOf) : {}), ...emitSite(target, site, refuse, Object.keys(plan.schemas)), ...emitTranslations(plan, target) };
|
|
149
|
+
if (diagnostics.length)
|
|
150
|
+
return { ok: false, diagnostics };
|
|
151
|
+
const storeProcedures = hasHandlers ? "storeProcedures" : "procedures";
|
|
152
|
+
const code = [...(Object.keys(plan.access?.userFields ?? {}).length ? [`export const userFields = ${q(plan.access.userFields)} as const;`] : []), ...declarations, `export const views = { ${views.join(", ")} };`, `export const procedures = { ${procedures.join(", ")} };`, ...(stores ? [
|
|
153
|
+
`export type Tables = ${stores.tables};`, `const RULES = ${stores.rules} as const;`,
|
|
154
|
+
...(hasHandlers ? [`const storeProcedures = { ${[...procedures, ...refProcedures].join(", ")} };`] : []),
|
|
155
|
+
`const initStore = () => createStore<Database, Tables, typeof DRIVER, { views: typeof views; procedures: typeof ${storeProcedures} }${hasHandlers ? ", { handlers: Handlers }" : ""}>(${user.used ? "{...DIALECT.dialect, ...USER_VALUES}" : "DIALECT.dialect"}, DRIVER, RULES, ${stores.facts}, { views, procedures: ${storeProcedures} });`,
|
|
156
|
+
`let makeStore: ReturnType<typeof initStore>;`,
|
|
157
|
+
`export function store${hasHandlers ? "<const H extends Handlers>" : ""}(db: Database, caller: Caller${hasHandlers ? ", options: { handlers: H & Record<Exclude<keyof H, keyof Handlers>, never> }" : ", _options?: { handlers?: Handlers }"}): ReturnType<typeof makeStore> { return (makeStore ??= initStore())(db, caller${hasHandlers ? ", options" : ""}); }`,
|
|
158
|
+
] : [])].join("\n");
|
|
159
|
+
const dialect = `${base}dialect/${isSqlite ? "sqlite" : "postgres"}`;
|
|
160
|
+
const contracts = [...(target.endsWith("postgres") ? ["type Postgres as Database", ...(views.length ? ["type Unsafe"] : [])] : []), "type Caller", ...(hasHandlers ? ["ContractError"] : []), ...(/^ deny\(/m.test(code) ? ["deny", ...(/\bisAdmin\(/.test(code) ? ["isAdmin"] : []), ...(/\bisUser\(/.test(code) ? ["isUser"] : [])] : []), ...(procedures.length ? ["type Output"] : [])];
|
|
161
|
+
const dbType = isSqlite ? databaseImport(target) : "";
|
|
162
|
+
return { ok: true, refProcedures: refNames, files: generatedFiles({ ...surfaces, ...entries, "generated.ts": ["// Generated native application SQL. No runtime plan or interpreter.", user.code, dbType, `import { ${contracts.join(", ")} } from "${base}contracts";`,
|
|
163
|
+
...(values.size || stores ? [`import * as DIALECT from "${dialect}";`] : []), `import * as DRIVER from "${base}driver/${driver}";`, ...((names => names.length ? [`import { ${names.join(", ")} } from "${base}store";`] : [])([...(stores ? ["createStore"] : []), ...(hasHandlers && target !== "cloudflare-d1" ? ["handlerTransaction"] : [])])),
|
|
164
|
+
`import { ${procedures.length ? "binds, bound" : "binds"} } from "${base}binds";`,
|
|
165
|
+
`const D = { ${[...values].sort().map(v => `${v}: DIALECT.${v}`).concat(user.values ? [user.values] : []).join(", ")} };`, code].filter(Boolean).join("\n") + "\n" }) };
|
|
166
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { authLines as auth } from "../domain/input.js";
|
|
2
|
+
import { q } from "../domain/entry.js";
|
|
3
|
+
export function emitHandlers(plan, interactive, typeOf, declarations, procedures) {
|
|
4
|
+
const refs = Object.entries(plan.procedures).sort().map(([name, procedure], index) => ({ name, procedure, index })).filter(({ procedure }) => "ref" in procedure.handler);
|
|
5
|
+
// An empty contract keeps app wiring (`handlers: Handlers = {}`) identical whether or not any ref Procedure exists.
|
|
6
|
+
if (!refs.length) {
|
|
7
|
+
declarations.push("export interface Handlers {}");
|
|
8
|
+
return [];
|
|
9
|
+
}
|
|
10
|
+
declarations.push('export type HandlerStore = Pick<ReturnType<typeof makeStore>, "collection" | "views" | "procedures">;',
|
|
11
|
+
// D1 has no interactive transactions, so its handlers get no `transaction`: using one there fails typecheck.
|
|
12
|
+
`export interface HandlerContext { readonly caller: Caller; readonly db: Database; readonly store: HandlerStore;${interactive ? " readonly transaction: <R>(fn: (ctx: { readonly store: HandlerStore; readonly db: Database }) => Promise<R>) => Promise<R>;" : ""} }`, "export interface Handlers {", ...refs.map(({ name, index }) => ` readonly [${q(name)}]: (ctx: HandlerContext, input: Procedure${index}Input) => Promise<Procedure${index}Output>;`), "}");
|
|
13
|
+
for (const { name, procedure, index } of refs) {
|
|
14
|
+
const path = `procedures/${name}`, fn = `procedure${index}`;
|
|
15
|
+
declarations.push(`export type Procedure${index}Input = ${typeOf(procedure.input ?? { type: "object", additionalProperties: false })};`, `export type Procedure${index}Output = ${typeOf(procedure.output)};`, `async function ${fn}(db: Database, caller: Caller, raw: Procedure${index}Input, context: { handlers: Handlers; store: HandlerContext["store"] }): Promise<Procedure${index}Output> {`, ` if ("authenticatedAs" in caller && caller.authenticatedAs === "snapshot") (await import("@aotter/mantle/host-caller")).checkFresh(caller, false, ${q(path)});`, ...auth(procedure.requires, path), " const handlers = context?.handlers;", ` const handler = handlers && Object.hasOwn(handlers, ${q(name)}) ? handlers[${q(name)}] : undefined;`, ` if (!handler) throw new ContractError("HANDLER_NOT_REGISTERED", "Procedure handler is not registered.", ${q(path)});`,
|
|
16
|
+
// TODO #1470: REST/MCP use shared generated validators at the boundary; bare calls stay typed.
|
|
17
|
+
` return handler({ caller, db, store: context.store${interactive ? ", transaction: handlerTransaction(context.store, db)" : ""} }, raw);`, "}");
|
|
18
|
+
procedures.push(`[${q(name)}]: ${fn}`);
|
|
19
|
+
}
|
|
20
|
+
return refs.map(({ name }) => name);
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { emitValidation } from "./validation.js";
|
|
2
|
+
import { mediaDefinitions } from "../domain/generated-tools.js";
|
|
3
|
+
export { mediaDefinitions };
|
|
4
|
+
/** `definitions` are the versioned media tools, computed once by the MCP emitter. */
|
|
5
|
+
export function emitMcpMedia(definitions, refuse) {
|
|
6
|
+
const inputs = Object.fromEntries(definitions.map(tool => [tool.name, { input: tool.inputSchema }]));
|
|
7
|
+
const checks = Object.fromEntries(Object.entries(emitValidation({ views: {}, procedures: inputs }, refuse)).map(([path, code]) => [path.replace("validation/procedures/", "validation/media/"), code]));
|
|
8
|
+
const invoke = { policy: 'async (db,caller) => ({purposes:(await site(db,caller).read()).media.purposes})', create: '(db,caller,input:Record<string,unknown>) => site(db,caller).media(storage()).createUpload(input)', commit: '(db,caller,input:Record<string,unknown>) => site(db,caller).media(storage()).commitUpload(input.uploadGroupId as string,input)', list: '(db,caller,input:Record<string,unknown>) => site(db,caller).media(storage()).list(input)', get: '(db,caller,input:Record<string,unknown>) => site(db,caller).media(storage()).get(input.id as string)', update: '(db,caller,input:Record<string,unknown>) => site(db,caller).media(storage()).update(input.id as string,input)', delete: '(db,caller,input:Record<string,unknown>) => site(db,caller).media(storage()).delete(input.id as string)' };
|
|
9
|
+
return { ...checks, "mcp-media.ts": `import { site } from "./site.js";
|
|
10
|
+
import type { MediaStorage } from "@aotter/mantle/site";
|
|
11
|
+
import type { Tool } from "@aotter/mantle/mcp";
|
|
12
|
+
${definitions.map((tool, i) => `import { validate as v${i} } from "./validation/media/${tool.name}.js";`).join("\n")}
|
|
13
|
+
export function mediaTools<Handlers = never>(storage: () => MediaStorage): Tool<Parameters<typeof site>[0], Handlers>[] { return [
|
|
14
|
+
${definitions.map(({ action, ...tool }, i) => `{...${JSON.stringify({ ...tool, ...(tool.annotations.readOnlyHint ? { readOnly: true } : {}) })},surface:"admin",closed:true,validate:v${i},run:${invoke[action]}}`).join(",\n")}
|
|
15
|
+
]; }
|
|
16
|
+
` };
|
|
17
|
+
}
|