@aotter/mantle 0.1.4 → 0.2.0-alpha.1
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 +39 -306
- package/dist/admin/consent.d.ts +17 -0
- package/dist/admin/consent.d.ts.map +1 -0
- package/dist/admin/consent.js +17 -0
- package/dist/admin/consent.js.map +1 -0
- package/dist/admin/createAdminSurface.d.ts +22 -0
- package/dist/admin/createAdminSurface.d.ts.map +1 -0
- package/dist/admin/createAdminSurface.js +589 -0
- package/dist/admin/createAdminSurface.js.map +1 -0
- package/dist/admin/developerConsole.d.ts +264 -0
- package/dist/admin/developerConsole.d.ts.map +1 -0
- package/dist/admin/developerConsole.js +136 -0
- package/dist/admin/developerConsole.js.map +1 -0
- package/dist/admin/identity.d.ts +62 -0
- package/dist/admin/identity.d.ts.map +1 -0
- package/dist/admin/identity.js +7 -0
- package/dist/admin/identity.js.map +1 -0
- package/dist/admin/index.d.ts +4 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +4 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/procedureFlow.d.ts +25 -0
- package/dist/admin/procedureFlow.d.ts.map +1 -0
- package/dist/admin/procedureFlow.js +154 -0
- package/dist/admin/procedureFlow.js.map +1 -0
- package/dist/auth/ConsoleEmailSender.d.ts +15 -0
- package/dist/auth/ConsoleEmailSender.d.ts.map +1 -0
- package/dist/auth/ConsoleEmailSender.js +19 -0
- package/dist/auth/ConsoleEmailSender.js.map +1 -0
- package/dist/auth/appleClientSecret.d.ts +75 -0
- package/dist/auth/appleClientSecret.d.ts.map +1 -0
- package/dist/auth/appleClientSecret.js +116 -0
- package/dist/auth/appleClientSecret.js.map +1 -0
- package/dist/auth/buildAuth.d.ts +4565 -0
- package/dist/auth/buildAuth.d.ts.map +1 -0
- package/dist/auth/buildAuth.js +307 -0
- package/dist/auth/buildAuth.js.map +1 -0
- package/dist/auth/callerResolver.d.ts +48 -0
- package/dist/auth/callerResolver.d.ts.map +1 -0
- package/dist/auth/callerResolver.js +49 -0
- package/dist/auth/callerResolver.js.map +1 -0
- package/dist/auth/createAuthRoutes.d.ts +22 -0
- package/dist/auth/createAuthRoutes.d.ts.map +1 -0
- package/dist/auth/createAuthRoutes.js +128 -0
- package/dist/auth/createAuthRoutes.js.map +1 -0
- package/dist/auth/createMantleAuth.d.ts +3 -0
- package/dist/auth/createMantleAuth.d.ts.map +1 -0
- package/dist/auth/createMantleAuth.js +483 -0
- package/dist/auth/createMantleAuth.js.map +1 -0
- package/dist/auth/db.d.ts +17 -0
- package/dist/auth/db.d.ts.map +1 -0
- package/dist/auth/db.js +24 -0
- package/dist/auth/db.js.map +1 -0
- package/dist/auth/emailTemplates.d.ts +7 -0
- package/dist/auth/emailTemplates.d.ts.map +1 -0
- package/dist/auth/emailTemplates.js +27 -0
- package/dist/auth/emailTemplates.js.map +1 -0
- package/dist/auth/index.d.ts +9 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +7 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/methods.d.ts +717 -0
- package/dist/auth/methods.d.ts.map +1 -0
- package/dist/auth/methods.js +321 -0
- package/dist/auth/methods.js.map +1 -0
- package/dist/auth/oauthTokens.d.ts +24 -0
- package/dist/auth/oauthTokens.d.ts.map +1 -0
- package/dist/auth/oauthTokens.js +146 -0
- package/dist/auth/oauthTokens.js.map +1 -0
- package/dist/auth/setupIncomplete.d.ts +16 -0
- package/dist/auth/setupIncomplete.d.ts.map +1 -0
- package/dist/auth/setupIncomplete.js +50 -0
- package/dist/auth/setupIncomplete.js.map +1 -0
- package/dist/auth/types.d.ts +440 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +10 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/bun/index.d.ts +65 -0
- package/dist/bun/index.d.ts.map +1 -0
- package/dist/bun/index.js +130 -0
- package/dist/bun/index.js.map +1 -0
- package/dist/cli/emitModule.d.ts +7 -0
- package/dist/cli/emitModule.d.ts.map +1 -0
- package/dist/cli/emitModule.js +127 -0
- package/dist/cli/emitModule.js.map +1 -0
- package/dist/cli/generate.d.ts +4 -16
- package/dist/cli/generate.d.ts.map +1 -1
- package/dist/cli/generate.js +332 -165
- package/dist/cli/generate.js.map +1 -1
- package/dist/cli/main.d.ts +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +15 -71
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/preset.d.ts +18 -0
- package/dist/cli/preset.d.ts.map +1 -0
- package/dist/cli/preset.js +352 -0
- package/dist/cli/preset.js.map +1 -0
- package/dist/cloudflare/index.d.ts +21 -0
- package/dist/cloudflare/index.d.ts.map +1 -0
- package/dist/cloudflare/index.js +14 -0
- package/dist/cloudflare/index.js.map +1 -0
- package/dist/cloudflare/r2Media.d.ts +43 -0
- package/dist/cloudflare/r2Media.d.ts.map +1 -0
- package/dist/cloudflare/r2Media.js +69 -0
- package/dist/cloudflare/r2Media.js.map +1 -0
- package/dist/core/caller.d.ts +35 -0
- package/dist/core/caller.d.ts.map +1 -0
- package/dist/core/caller.js +3 -0
- package/dist/core/caller.js.map +1 -0
- package/dist/core/createMantle.d.ts +22 -0
- package/dist/core/createMantle.d.ts.map +1 -0
- package/dist/core/createMantle.js +117 -0
- package/dist/core/createMantle.js.map +1 -0
- package/dist/core/dialect.d.ts +41 -0
- package/dist/core/dialect.d.ts.map +1 -0
- package/dist/core/dialect.js +7 -0
- package/dist/core/dialect.js.map +1 -0
- package/dist/core/driver.d.ts +17 -0
- package/dist/core/driver.d.ts.map +1 -0
- package/dist/core/driver.js +2 -0
- package/dist/core/driver.js.map +1 -0
- package/dist/core/email.d.ts +17 -0
- package/dist/core/email.d.ts.map +1 -0
- package/dist/core/email.js +2 -0
- package/dist/core/email.js.map +1 -0
- package/dist/core/index.d.ts +16 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +16 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/invocation.d.ts +66 -0
- package/dist/core/invocation.d.ts.map +1 -0
- package/dist/core/invocation.js +3 -0
- package/dist/core/invocation.js.map +1 -0
- package/dist/core/runtime/auth.d.ts +9 -0
- package/dist/core/runtime/auth.d.ts.map +1 -0
- package/dist/core/runtime/auth.js +39 -0
- package/dist/core/runtime/auth.js.map +1 -0
- package/dist/core/runtime/createRuntime.d.ts +23 -0
- package/dist/core/runtime/createRuntime.d.ts.map +1 -0
- package/dist/core/runtime/createRuntime.js +214 -0
- package/dist/core/runtime/createRuntime.js.map +1 -0
- package/dist/core/runtime/verifyPlan.d.ts +34 -0
- package/dist/core/runtime/verifyPlan.d.ts.map +1 -0
- package/dist/core/runtime/verifyPlan.js +301 -0
- package/dist/core/runtime/verifyPlan.js.map +1 -0
- package/dist/core/service.d.ts +45 -0
- package/dist/core/service.d.ts.map +1 -0
- package/dist/core/service.js +2 -0
- package/dist/core/service.js.map +1 -0
- package/dist/core/site.d.ts +117 -0
- package/dist/core/site.d.ts.map +1 -0
- package/dist/core/site.js +2 -0
- package/dist/core/site.js.map +1 -0
- package/dist/core/siteConfig.d.ts +5 -0
- package/dist/core/siteConfig.d.ts.map +1 -0
- package/dist/core/siteConfig.js +24 -0
- package/dist/core/siteConfig.js.map +1 -0
- package/dist/core/sql/allowlist.d.ts +65 -0
- package/dist/core/sql/allowlist.d.ts.map +1 -0
- package/dist/core/sql/allowlist.js +705 -0
- package/dist/core/sql/allowlist.js.map +1 -0
- package/dist/core/sql/ast.d.ts +24 -0
- package/dist/core/sql/ast.d.ts.map +1 -0
- package/dist/core/sql/ast.js +32 -0
- package/dist/core/sql/ast.js.map +1 -0
- package/dist/core/sql/compile.d.ts +50 -0
- package/dist/core/sql/compile.d.ts.map +1 -0
- package/dist/core/sql/compile.js +48 -0
- package/dist/core/sql/compile.js.map +1 -0
- package/dist/core/sql/policy.d.ts +121 -0
- package/dist/core/sql/policy.d.ts.map +1 -0
- package/dist/core/sql/policy.js +379 -0
- package/dist/core/sql/policy.js.map +1 -0
- package/dist/core/sql/positions.d.ts +30 -0
- package/dist/core/sql/positions.d.ts.map +1 -0
- package/dist/core/sql/positions.js +22 -0
- package/dist/core/sql/positions.js.map +1 -0
- package/dist/core/sql/run.d.ts +76 -0
- package/dist/core/sql/run.d.ts.map +1 -0
- package/dist/core/sql/run.js +267 -0
- package/dist/core/sql/run.js.map +1 -0
- package/dist/core/store/createStore.d.ts +49 -0
- package/dist/core/store/createStore.d.ts.map +1 -0
- package/dist/core/store/createStore.js +227 -0
- package/dist/core/store/createStore.js.map +1 -0
- package/dist/core/store/cursor.d.ts +4 -0
- package/dist/core/store/cursor.d.ts.map +1 -0
- package/dist/core/store/cursor.js +22 -0
- package/dist/core/store/cursor.js.map +1 -0
- package/dist/core/store/json.d.ts +80 -0
- package/dist/core/store/json.d.ts.map +1 -0
- package/dist/core/store/json.js +342 -0
- package/dist/core/store/json.js.map +1 -0
- package/dist/core/store.d.ts +160 -0
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/store.js +2 -0
- package/dist/core/store.js.map +1 -0
- package/dist/core/wire.d.ts +20 -0
- package/dist/core/wire.d.ts.map +1 -0
- package/dist/core/wire.js +84 -0
- package/dist/core/wire.js.map +1 -0
- package/dist/core/withCaller.d.ts +16 -0
- package/dist/core/withCaller.d.ts.map +1 -0
- package/dist/core/withCaller.js +29 -0
- package/dist/core/withCaller.js.map +1 -0
- package/dist/d1/adapter.d.ts +12 -0
- package/dist/d1/adapter.d.ts.map +1 -0
- package/dist/d1/adapter.js +23 -0
- package/dist/d1/adapter.js.map +1 -0
- package/dist/d1/codec.d.ts +14 -0
- package/dist/d1/codec.d.ts.map +1 -0
- package/dist/d1/codec.js +136 -0
- package/dist/d1/codec.js.map +1 -0
- package/dist/d1/compile/index.d.ts +9 -0
- package/dist/d1/compile/index.d.ts.map +1 -0
- package/dist/d1/compile/index.js +9 -0
- package/dist/d1/compile/index.js.map +1 -0
- package/dist/d1/dialect.d.ts +4 -0
- package/dist/d1/dialect.d.ts.map +1 -0
- package/dist/d1/dialect.js +13 -0
- package/dist/d1/dialect.js.map +1 -0
- package/dist/d1/executor.d.ts +13 -0
- package/dist/d1/executor.d.ts.map +1 -0
- package/dist/d1/executor.js +91 -0
- package/dist/d1/executor.js.map +1 -0
- package/dist/d1/index.d.ts +6 -0
- package/dist/d1/index.d.ts.map +1 -0
- package/dist/d1/index.js +6 -0
- package/dist/d1/index.js.map +1 -0
- package/dist/d1/lower.d.ts +8 -0
- package/dist/d1/lower.d.ts.map +1 -0
- package/dist/d1/lower.js +167 -0
- package/dist/d1/lower.js.map +1 -0
- package/dist/d1/media.d.ts +5 -0
- package/dist/d1/media.d.ts.map +1 -0
- package/dist/d1/media.js +157 -0
- package/dist/d1/media.js.map +1 -0
- package/dist/d1/migrations.d.ts +12 -0
- package/dist/d1/migrations.d.ts.map +1 -0
- package/dist/d1/migrations.js +111 -0
- package/dist/d1/migrations.js.map +1 -0
- package/dist/d1/print.d.ts +28 -0
- package/dist/d1/print.d.ts.map +1 -0
- package/dist/d1/print.js +54 -0
- package/dist/d1/print.js.map +1 -0
- package/dist/d1/site.d.ts +17 -0
- package/dist/d1/site.d.ts.map +1 -0
- package/dist/d1/site.js +63 -0
- package/dist/d1/site.js.map +1 -0
- package/dist/d1/storage.d.ts +34 -0
- package/dist/d1/storage.d.ts.map +1 -0
- package/dist/d1/storage.js +288 -0
- package/dist/d1/storage.js.map +1 -0
- package/dist/d1/tz.d.ts +21 -0
- package/dist/d1/tz.d.ts.map +1 -0
- package/dist/d1/tz.js +54 -0
- package/dist/d1/tz.js.map +1 -0
- package/dist/d1/validator.d.ts +10 -0
- package/dist/d1/validator.d.ts.map +1 -0
- package/dist/d1/validator.js +33 -0
- package/dist/d1/validator.js.map +1 -0
- package/dist/mcp/apps.d.ts +43 -0
- package/dist/mcp/apps.d.ts.map +1 -0
- package/dist/mcp/apps.js +57 -0
- package/dist/mcp/apps.js.map +1 -0
- package/dist/mcp/catalog.d.ts +55 -0
- package/dist/mcp/catalog.d.ts.map +1 -0
- package/dist/mcp/catalog.js +81 -0
- package/dist/mcp/catalog.js.map +1 -0
- package/dist/mcp/createMcpSurface.d.ts +34 -0
- package/dist/mcp/createMcpSurface.d.ts.map +1 -0
- package/dist/mcp/createMcpSurface.js +150 -0
- package/dist/mcp/createMcpSurface.js.map +1 -0
- package/dist/mcp/index.d.ts +4 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +4 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/postgres/adapter.d.ts +20 -0
- package/dist/postgres/adapter.d.ts.map +1 -0
- package/dist/postgres/adapter.js +44 -0
- package/dist/postgres/adapter.js.map +1 -0
- package/dist/postgres/codec.d.ts +13 -0
- package/dist/postgres/codec.d.ts.map +1 -0
- package/dist/postgres/codec.js +110 -0
- package/dist/postgres/codec.js.map +1 -0
- package/dist/postgres/compile/index.d.ts +9 -0
- package/dist/postgres/compile/index.d.ts.map +1 -0
- package/dist/postgres/compile/index.js +9 -0
- package/dist/postgres/compile/index.js.map +1 -0
- package/dist/postgres/driver.d.ts +92 -0
- package/dist/postgres/driver.d.ts.map +1 -0
- package/dist/postgres/driver.js +110 -0
- package/dist/postgres/driver.js.map +1 -0
- package/dist/postgres/executor.d.ts +20 -0
- package/dist/postgres/executor.d.ts.map +1 -0
- package/dist/postgres/executor.js +69 -0
- package/dist/postgres/executor.js.map +1 -0
- package/dist/postgres/index.d.ts +7 -0
- package/dist/postgres/index.d.ts.map +1 -0
- package/dist/postgres/index.js +7 -0
- package/dist/postgres/index.js.map +1 -0
- package/dist/postgres/lower.d.ts +6 -0
- package/dist/postgres/lower.d.ts.map +1 -0
- package/dist/postgres/lower.js +157 -0
- package/dist/postgres/lower.js.map +1 -0
- package/dist/postgres/print.d.ts +11 -0
- package/dist/postgres/print.d.ts.map +1 -0
- package/dist/postgres/print.js +121 -0
- package/dist/postgres/print.js.map +1 -0
- package/dist/postgres/storage.d.ts +19 -0
- package/dist/postgres/storage.d.ts.map +1 -0
- package/dist/postgres/storage.js +201 -0
- package/dist/postgres/storage.js.map +1 -0
- package/dist/postgres/textRows.d.ts +10 -0
- package/dist/postgres/textRows.d.ts.map +1 -0
- package/dist/postgres/textRows.js +44 -0
- package/dist/postgres/textRows.js.map +1 -0
- package/dist/postgres/validator.d.ts +12 -0
- package/dist/postgres/validator.d.ts.map +1 -0
- package/dist/postgres/validator.js +46 -0
- package/dist/postgres/validator.js.map +1 -0
- package/dist/spec/domain/index.d.ts +3 -0
- package/dist/spec/domain/index.d.ts.map +1 -0
- package/dist/spec/domain/index.js +3 -0
- package/dist/spec/domain/index.js.map +1 -0
- package/dist/spec/domain/model/ContentState.d.ts +8 -0
- package/dist/spec/domain/model/ContentState.d.ts.map +1 -0
- package/dist/spec/domain/model/ContentState.js +7 -0
- package/dist/spec/domain/model/ContentState.js.map +1 -0
- package/dist/spec/domain/model/Entry.d.ts +29 -0
- package/dist/spec/domain/model/Entry.d.ts.map +1 -0
- package/dist/spec/domain/model/Entry.js +16 -0
- package/dist/spec/domain/model/Entry.js.map +1 -0
- package/dist/spec/domain/model/Locale.d.ts +30 -0
- package/dist/spec/domain/model/Locale.d.ts.map +1 -0
- package/dist/spec/domain/model/Locale.js +33 -0
- package/dist/spec/domain/model/Locale.js.map +1 -0
- package/dist/spec/domain/model/ManifestGrammar.d.ts +452 -0
- package/dist/spec/domain/model/ManifestGrammar.d.ts.map +1 -0
- package/dist/spec/domain/model/ManifestGrammar.js +149 -0
- package/dist/spec/domain/model/ManifestGrammar.js.map +1 -0
- package/dist/spec/domain/model/MediaMimeAccept.d.ts +55 -0
- package/dist/spec/domain/model/MediaMimeAccept.d.ts.map +1 -0
- package/dist/spec/domain/model/MediaMimeAccept.js +90 -0
- package/dist/spec/domain/model/MediaMimeAccept.js.map +1 -0
- package/dist/spec/domain/model/RuntimePlan.d.ts +94 -0
- package/dist/spec/domain/model/RuntimePlan.d.ts.map +1 -0
- package/dist/spec/domain/model/RuntimePlan.js +4 -0
- package/dist/spec/domain/model/RuntimePlan.js.map +1 -0
- package/dist/spec/domain/model/SiteConfig.d.ts +173 -0
- package/dist/spec/domain/model/SiteConfig.d.ts.map +1 -0
- package/dist/spec/domain/model/SiteConfig.js +13 -0
- package/dist/spec/domain/model/SiteConfig.js.map +1 -0
- package/dist/spec/domain/model/SqlIr.d.ts +96 -0
- package/dist/spec/domain/model/SqlIr.d.ts.map +1 -0
- package/dist/spec/domain/model/SqlIr.js +95 -0
- package/dist/spec/domain/model/SqlIr.js.map +1 -0
- package/dist/spec/domain/model/index.d.ts +14 -0
- package/dist/spec/domain/model/index.d.ts.map +1 -0
- package/dist/spec/domain/model/index.js +14 -0
- package/dist/spec/domain/model/index.js.map +1 -0
- package/dist/spec/domain/service/CloudflareCron.d.ts +2 -0
- package/dist/spec/domain/service/CloudflareCron.d.ts.map +1 -0
- package/dist/spec/domain/service/CloudflareCron.js +63 -0
- package/dist/spec/domain/service/CloudflareCron.js.map +1 -0
- package/dist/spec/domain/service/CrossSchemaChecker.d.ts +34 -0
- package/dist/spec/domain/service/CrossSchemaChecker.d.ts.map +1 -0
- package/dist/spec/domain/service/CrossSchemaChecker.js +114 -0
- package/dist/spec/domain/service/CrossSchemaChecker.js.map +1 -0
- package/dist/spec/domain/service/EntryDataValidator.d.ts +56 -0
- package/dist/spec/domain/service/EntryDataValidator.d.ts.map +1 -0
- package/dist/spec/domain/service/EntryDataValidator.js +88 -0
- package/dist/spec/domain/service/EntryDataValidator.js.map +1 -0
- package/dist/spec/domain/service/JsonSchemaToZod.d.ts +29 -0
- package/dist/spec/domain/service/JsonSchemaToZod.d.ts.map +1 -0
- package/dist/spec/domain/service/JsonSchemaToZod.js +156 -0
- package/dist/spec/domain/service/JsonSchemaToZod.js.map +1 -0
- package/dist/spec/domain/service/LifecycleStateMachine.d.ts +75 -0
- package/dist/spec/domain/service/LifecycleStateMachine.d.ts.map +1 -0
- package/dist/spec/domain/service/LifecycleStateMachine.js +76 -0
- package/dist/spec/domain/service/LifecycleStateMachine.js.map +1 -0
- package/dist/spec/domain/service/LocaleCanonicalizer.d.ts +29 -0
- package/dist/spec/domain/service/LocaleCanonicalizer.d.ts.map +1 -0
- package/dist/spec/domain/service/LocaleCanonicalizer.js +96 -0
- package/dist/spec/domain/service/LocaleCanonicalizer.js.map +1 -0
- package/dist/spec/domain/service/ManifestFieldChecks.d.ts +60 -0
- package/dist/spec/domain/service/ManifestFieldChecks.d.ts.map +1 -0
- package/dist/spec/domain/service/ManifestFieldChecks.js +116 -0
- package/dist/spec/domain/service/ManifestFieldChecks.js.map +1 -0
- package/dist/spec/domain/service/ManifestGraphValidator.d.ts +15 -0
- package/dist/spec/domain/service/ManifestGraphValidator.d.ts.map +1 -0
- package/dist/spec/domain/service/ManifestGraphValidator.js +225 -0
- package/dist/spec/domain/service/ManifestGraphValidator.js.map +1 -0
- package/dist/spec/domain/service/ManifestLinker.d.ts +45 -0
- package/dist/spec/domain/service/ManifestLinker.d.ts.map +1 -0
- package/dist/spec/domain/service/ManifestLinker.js +92 -0
- package/dist/spec/domain/service/ManifestLinker.js.map +1 -0
- package/dist/spec/domain/service/ManifestLocaleTrimmer.d.ts +16 -0
- package/dist/spec/domain/service/ManifestLocaleTrimmer.d.ts.map +1 -0
- package/dist/spec/domain/service/ManifestLocaleTrimmer.js +76 -0
- package/dist/spec/domain/service/ManifestLocaleTrimmer.js.map +1 -0
- package/dist/spec/domain/service/ManifestParser.d.ts +49 -0
- package/dist/spec/domain/service/ManifestParser.d.ts.map +1 -0
- package/dist/spec/domain/service/ManifestParser.js +203 -0
- package/dist/spec/domain/service/ManifestParser.js.map +1 -0
- package/dist/spec/domain/service/ManifestPartition.d.ts +9 -0
- package/dist/spec/domain/service/ManifestPartition.d.ts.map +1 -0
- package/dist/spec/domain/service/ManifestPartition.js +19 -0
- package/dist/spec/domain/service/ManifestPartition.js.map +1 -0
- package/dist/spec/domain/service/ManifestPathDiagnoser.d.ts +33 -0
- package/dist/spec/domain/service/ManifestPathDiagnoser.d.ts.map +1 -0
- package/dist/spec/domain/service/ManifestPathDiagnoser.js +43 -0
- package/dist/spec/domain/service/ManifestPathDiagnoser.js.map +1 -0
- package/dist/spec/domain/service/ManifestSourceSpans.d.ts +10 -0
- package/dist/spec/domain/service/ManifestSourceSpans.d.ts.map +1 -0
- package/dist/spec/domain/service/ManifestSourceSpans.js +76 -0
- package/dist/spec/domain/service/ManifestSourceSpans.js.map +1 -0
- package/dist/spec/domain/service/McpToolNaming.d.ts +25 -0
- package/dist/spec/domain/service/McpToolNaming.d.ts.map +1 -0
- package/dist/spec/domain/service/McpToolNaming.js +50 -0
- package/dist/spec/domain/service/McpToolNaming.js.map +1 -0
- package/dist/spec/domain/service/PlanFingerprint.d.ts +4 -0
- package/dist/spec/domain/service/PlanFingerprint.d.ts.map +1 -0
- package/dist/spec/domain/service/PlanFingerprint.js +14 -0
- package/dist/spec/domain/service/PlanFingerprint.js.map +1 -0
- package/dist/spec/domain/service/ProcedureViewSpecChecks.d.ts +4 -0
- package/dist/spec/domain/service/ProcedureViewSpecChecks.d.ts.map +1 -0
- package/dist/spec/domain/service/ProcedureViewSpecChecks.js +211 -0
- package/dist/spec/domain/service/ProcedureViewSpecChecks.js.map +1 -0
- package/dist/spec/domain/service/SchemaAdminUiChecker.d.ts +42 -0
- package/dist/spec/domain/service/SchemaAdminUiChecker.d.ts.map +1 -0
- package/dist/spec/domain/service/SchemaAdminUiChecker.js +289 -0
- package/dist/spec/domain/service/SchemaAdminUiChecker.js.map +1 -0
- package/dist/spec/domain/service/SchemaIndexChecker.d.ts +33 -0
- package/dist/spec/domain/service/SchemaIndexChecker.d.ts.map +1 -0
- package/dist/spec/domain/service/SchemaIndexChecker.js +256 -0
- package/dist/spec/domain/service/SchemaIndexChecker.js.map +1 -0
- package/dist/spec/domain/service/SchemaSearchChecker.d.ts +11 -0
- package/dist/spec/domain/service/SchemaSearchChecker.d.ts.map +1 -0
- package/dist/spec/domain/service/SchemaSearchChecker.js +78 -0
- package/dist/spec/domain/service/SchemaSearchChecker.js.map +1 -0
- package/dist/spec/domain/service/SchemaSpecChecks.d.ts +31 -0
- package/dist/spec/domain/service/SchemaSpecChecks.d.ts.map +1 -0
- package/dist/spec/domain/service/SchemaSpecChecks.js +445 -0
- package/dist/spec/domain/service/SchemaSpecChecks.js.map +1 -0
- package/dist/spec/domain/service/SiteDefaultsValidator.d.ts +39 -0
- package/dist/spec/domain/service/SiteDefaultsValidator.d.ts.map +1 -0
- package/dist/spec/domain/service/SiteDefaultsValidator.js +194 -0
- package/dist/spec/domain/service/SiteDefaultsValidator.js.map +1 -0
- package/dist/spec/domain/service/SqlClassify.d.ts +19 -0
- package/dist/spec/domain/service/SqlClassify.d.ts.map +1 -0
- package/dist/spec/domain/service/SqlClassify.js +42 -0
- package/dist/spec/domain/service/SqlClassify.js.map +1 -0
- package/dist/spec/domain/service/SqlRefusal.d.ts +16 -0
- package/dist/spec/domain/service/SqlRefusal.d.ts.map +1 -0
- package/dist/spec/domain/service/SqlRefusal.js +20 -0
- package/dist/spec/domain/service/SqlRefusal.js.map +1 -0
- package/dist/spec/domain/service/SqlTypes.d.ts +40 -0
- package/dist/spec/domain/service/SqlTypes.d.ts.map +1 -0
- package/dist/spec/domain/service/SqlTypes.js +110 -0
- package/dist/spec/domain/service/SqlTypes.js.map +1 -0
- package/dist/spec/domain/service/StaffRoleHierarchy.d.ts +3 -0
- package/dist/spec/domain/service/StaffRoleHierarchy.d.ts.map +1 -0
- package/dist/spec/domain/service/StaffRoleHierarchy.js +19 -0
- package/dist/spec/domain/service/StaffRoleHierarchy.js.map +1 -0
- package/dist/spec/domain/service/TriggerGraphChecks.d.ts +16 -0
- package/dist/spec/domain/service/TriggerGraphChecks.d.ts.map +1 -0
- package/dist/spec/domain/service/TriggerGraphChecks.js +337 -0
- package/dist/spec/domain/service/TriggerGraphChecks.js.map +1 -0
- package/dist/spec/domain/service/TriggerSpecChecks.d.ts +4 -0
- package/dist/spec/domain/service/TriggerSpecChecks.d.ts.map +1 -0
- package/dist/spec/domain/service/TriggerSpecChecks.js +89 -0
- package/dist/spec/domain/service/TriggerSpecChecks.js.map +1 -0
- package/dist/spec/domain/service/ValidatedAdminUiProjection.d.ts +11 -0
- package/dist/spec/domain/service/ValidatedAdminUiProjection.d.ts.map +1 -0
- package/dist/spec/domain/service/ValidatedAdminUiProjection.js +26 -0
- package/dist/spec/domain/service/ValidatedAdminUiProjection.js.map +1 -0
- package/dist/spec/domain/service/ViewAdminUiChecker.d.ts +14 -0
- package/dist/spec/domain/service/ViewAdminUiChecker.d.ts.map +1 -0
- package/dist/spec/domain/service/ViewAdminUiChecker.js +53 -0
- package/dist/spec/domain/service/ViewAdminUiChecker.js.map +1 -0
- package/dist/spec/domain/service/index.d.ts +24 -0
- package/dist/spec/domain/service/index.d.ts.map +1 -0
- package/dist/spec/domain/service/index.js +24 -0
- package/dist/spec/domain/service/index.js.map +1 -0
- package/dist/spec/index.d.ts +10 -0
- package/dist/spec/index.d.ts.map +1 -0
- package/dist/spec/index.js +12 -0
- package/dist/spec/index.js.map +1 -0
- package/dist/spec/infrastructure/cli/parseArgsError.d.ts +16 -0
- package/dist/spec/infrastructure/cli/parseArgsError.d.ts.map +1 -0
- package/dist/spec/infrastructure/cli/parseArgsError.js +34 -0
- package/dist/spec/infrastructure/cli/parseArgsError.js.map +1 -0
- package/dist/spec/infrastructure/index.d.ts +2 -0
- package/dist/spec/infrastructure/index.d.ts.map +1 -0
- package/dist/spec/infrastructure/index.js +2 -0
- package/dist/spec/infrastructure/index.js.map +1 -0
- package/dist/spec/infrastructure/sql/PgQueryParser.d.ts +18 -0
- package/dist/spec/infrastructure/sql/PgQueryParser.d.ts.map +1 -0
- package/dist/spec/infrastructure/sql/PgQueryParser.js +17 -0
- package/dist/spec/infrastructure/sql/PgQueryParser.js.map +1 -0
- package/dist/spec/infrastructure/sql/compilePlan.d.ts +37 -0
- package/dist/spec/infrastructure/sql/compilePlan.d.ts.map +1 -0
- package/dist/spec/infrastructure/sql/compilePlan.js +282 -0
- package/dist/spec/infrastructure/sql/compilePlan.js.map +1 -0
- package/dist/spec/infrastructure/sql/compileSql.d.ts +35 -0
- package/dist/spec/infrastructure/sql/compileSql.d.ts.map +1 -0
- package/dist/spec/infrastructure/sql/compileSql.js +92 -0
- package/dist/spec/infrastructure/sql/compileSql.js.map +1 -0
- package/dist/spec/infrastructure/sql/frontEnd.d.ts +8 -0
- package/dist/spec/infrastructure/sql/frontEnd.d.ts.map +1 -0
- package/dist/spec/infrastructure/sql/frontEnd.js +100 -0
- package/dist/spec/infrastructure/sql/frontEnd.js.map +1 -0
- package/dist/spec/infrastructure/sql/index.d.ts +4 -0
- package/dist/spec/infrastructure/sql/index.d.ts.map +1 -0
- package/dist/spec/infrastructure/sql/index.js +4 -0
- package/dist/spec/infrastructure/sql/index.js.map +1 -0
- package/dist/spec/kernel/diagnostic.d.ts +137 -0
- package/dist/spec/kernel/diagnostic.d.ts.map +1 -0
- package/dist/spec/kernel/diagnostic.js +296 -0
- package/dist/spec/kernel/diagnostic.js.map +1 -0
- package/dist/spec/kernel/index.d.ts +8 -0
- package/dist/spec/kernel/index.d.ts.map +1 -0
- package/dist/spec/kernel/index.js +8 -0
- package/dist/spec/kernel/index.js.map +1 -0
- package/dist/spec/usecase/EmitTypes.d.ts +22 -0
- package/dist/spec/usecase/EmitTypes.d.ts.map +1 -0
- package/dist/spec/usecase/EmitTypes.js +182 -0
- package/dist/spec/usecase/EmitTypes.js.map +1 -0
- package/dist/spec/usecase/ValidateManifestsUseCase.d.ts +8 -0
- package/dist/spec/usecase/ValidateManifestsUseCase.d.ts.map +1 -0
- package/dist/spec/usecase/ValidateManifestsUseCase.js +101 -0
- package/dist/spec/usecase/ValidateManifestsUseCase.js.map +1 -0
- package/dist/spec/usecase/dto/ValidateManifestsRequest.d.ts +27 -0
- package/dist/spec/usecase/dto/ValidateManifestsRequest.d.ts.map +1 -0
- package/dist/spec/usecase/dto/ValidateManifestsRequest.js +2 -0
- package/dist/spec/usecase/dto/ValidateManifestsRequest.js.map +1 -0
- package/dist/spec/usecase/dto/ValidateManifestsResponse.d.ts +14 -0
- package/dist/spec/usecase/dto/ValidateManifestsResponse.d.ts.map +1 -0
- package/dist/spec/usecase/dto/ValidateManifestsResponse.js +2 -0
- package/dist/spec/usecase/dto/ValidateManifestsResponse.js.map +1 -0
- package/dist/spec/usecase/dto/index.d.ts +3 -0
- package/dist/spec/usecase/dto/index.d.ts.map +1 -0
- package/dist/spec/usecase/dto/index.js +3 -0
- package/dist/spec/usecase/dto/index.js.map +1 -0
- package/dist/spec/usecase/index.d.ts +10 -0
- package/dist/spec/usecase/index.d.ts.map +1 -0
- package/dist/spec/usecase/index.js +10 -0
- package/dist/spec/usecase/index.js.map +1 -0
- package/dist/testing/cases/before-hook.d.ts +4 -0
- package/dist/testing/cases/before-hook.d.ts.map +1 -0
- package/dist/testing/cases/before-hook.js +71 -0
- package/dist/testing/cases/before-hook.js.map +1 -0
- package/dist/testing/cases/corpus.d.ts +12 -0
- package/dist/testing/cases/corpus.d.ts.map +1 -0
- package/dist/testing/cases/corpus.js +91 -0
- package/dist/testing/cases/corpus.js.map +1 -0
- package/dist/testing/cases/policy.d.ts +74 -0
- package/dist/testing/cases/policy.d.ts.map +1 -0
- package/dist/testing/cases/policy.js +142 -0
- package/dist/testing/cases/policy.js.map +1 -0
- package/dist/testing/cases/printer.d.ts +4 -0
- package/dist/testing/cases/printer.d.ts.map +1 -0
- package/dist/testing/cases/printer.js +32 -0
- package/dist/testing/cases/printer.js.map +1 -0
- package/dist/testing/cases/report-view.d.ts +5 -0
- package/dist/testing/cases/report-view.d.ts.map +1 -0
- package/dist/testing/cases/report-view.js +33 -0
- package/dist/testing/cases/report-view.js.map +1 -0
- package/dist/testing/cases/requisition.d.ts +4 -0
- package/dist/testing/cases/requisition.d.ts.map +1 -0
- package/dist/testing/cases/requisition.js +38 -0
- package/dist/testing/cases/requisition.js.map +1 -0
- package/dist/testing/cases/search-places.d.ts +4 -0
- package/dist/testing/cases/search-places.d.ts.map +1 -0
- package/dist/testing/cases/search-places.js +60 -0
- package/dist/testing/cases/search-places.js.map +1 -0
- package/dist/testing/cases/stock.d.ts +4 -0
- package/dist/testing/cases/stock.d.ts.map +1 -0
- package/dist/testing/cases/stock.js +35 -0
- package/dist/testing/cases/stock.js.map +1 -0
- package/dist/testing/cases/store.d.ts +4 -0
- package/dist/testing/cases/store.d.ts.map +1 -0
- package/dist/testing/cases/store.js +100 -0
- package/dist/testing/cases/store.js.map +1 -0
- package/dist/testing/harness.d.ts +94 -0
- package/dist/testing/harness.d.ts.map +1 -0
- package/dist/testing/harness.js +168 -0
- package/dist/testing/harness.js.map +1 -0
- package/dist/testing/index.d.ts +37 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +43 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/report.d.ts +15 -0
- package/dist/testing/report.d.ts.map +1 -0
- package/dist/testing/report.js +22 -0
- package/dist/testing/report.js.map +1 -0
- package/dist/web/createRestSurface.d.ts +7 -0
- package/dist/web/createRestSurface.d.ts.map +1 -0
- package/dist/web/createRestSurface.js +39 -0
- package/dist/web/createRestSurface.js.map +1 -0
- package/dist/web/index.d.ts +2 -0
- package/dist/web/index.d.ts.map +1 -0
- package/dist/web/index.js +2 -0
- package/dist/web/index.js.map +1 -0
- package/docs/adr/0008-structured-diagnostic-shape.md +2 -2
- package/docs/adr/0011-adapter-port-spec.md +2 -2
- package/docs/adr/0014-auth-better-auth-and-multi-tenant-mcp.md +21 -2
- package/docs/adr/0019-sealed-manifest-runtime-pipeline.md +5 -1
- package/docs/adr/0021-retire-starter-scaffolding.md +1 -1
- package/docs/adr/0022-caller-observed-version-occ.md +1 -1
- package/docs/adr/0024-manifest-native-schema-tables.md +2 -2
- package/docs/adr/0026-progressive-generate.md +36 -0
- package/docs/adr/0027-scheduled-procedure-triggers.md +31 -0
- package/docs/adr/0028-schema-ttl-expiry.md +33 -0
- package/docs/adr/0029-mcp-apps-interaction-contracts.md +324 -0
- package/docs/adr/0030-store.md +40 -0
- package/docs/adr/0031-host-cloud-core-contract.md +25 -0
- package/docs/adr/0032-store-centric-core-and-service-contract.md +361 -0
- package/docs/adr/0033-storage-converges-to-the-plan.md +92 -0
- package/docs/adr/0034-store-is-authored-as-sql.md +192 -0
- package/docs/adr/0035-sql-dialects.md +154 -0
- package/docs/adr/0036-host-and-dialect.md +65 -0
- package/docs/adr/0037-postgresql-is-the-reference-dialect.md +124 -0
- package/docs/adr/0038-bun-native-host.md +63 -0
- package/docs/adr/README.md +26 -8
- package/docs/adr/adr-lite-861-admin-webmcp.md +6 -0
- package/docs/adr/adr-lite-909-admin-ui-kit.md +1 -1
- package/docs/examples/README.md +16 -18
- package/docs/examples/commerce-inventory.md +481 -0
- package/docs/examples/commerce.md +254 -0
- package/docs/examples/guarded-api.md +238 -0
- package/docs/examples/intake-hooks.md +237 -0
- package/docs/examples/intake.md +127 -0
- package/docs/examples/legal-documents.md +218 -0
- package/docs/examples/procurement.md +215 -0
- package/docs/examples/publication.md +211 -0
- package/docs/examples/reference-service/.dev.vars.example +4 -0
- package/docs/examples/reference-service/.mantle/generated/mantle.ts +174 -0
- package/docs/examples/reference-service/.mantle/generated/plan.json +1936 -0
- package/docs/examples/reference-service/README.md +33 -0
- package/docs/examples/reference-service/manifests/catalog.yaml +103 -0
- package/docs/examples/reference-service/manifests/orders.yaml +120 -0
- package/docs/examples/reference-service/mantle.config.json +1 -0
- package/docs/examples/reference-service/package.json +27 -0
- package/docs/examples/reference-service/smoke.mjs +156 -0
- package/docs/examples/reference-service/src/handlers.ts +36 -0
- package/docs/examples/reference-service/src/index.ts +33 -0
- package/docs/examples/reference-service/src/service.ts +78 -0
- package/docs/examples/{host-minimal-worker → reference-service}/tsconfig.json +7 -2
- package/docs/examples/reference-service/wrangler.jsonc +26 -0
- package/docs/examples/reservation.md +142 -0
- package/docs/handbook/cloudflare/authentication.md +96 -299
- package/docs/handbook/cloudflare/chatgpt-sites.md +104 -15
- package/docs/handbook/cloudflare/deploy-and-operate.md +77 -71
- package/docs/handbook/cloudflare/media-r2.md +64 -187
- package/docs/handbook/cloudflare/service-entry.md +138 -0
- package/docs/handbook/concepts/authorization.md +104 -94
- package/docs/handbook/concepts/four-atoms.md +68 -144
- package/docs/handbook/concepts/lifecycle-and-locales.md +62 -114
- package/docs/handbook/concepts/mcp-and-agents.md +112 -117
- package/docs/handbook/concepts/procedures-and-triggers.md +126 -181
- package/docs/handbook/concepts/runtime-and-adapters.md +177 -156
- package/docs/handbook/concepts/views.md +97 -173
- package/docs/handbook/examples/hub.md +17 -6
- package/docs/handbook/guides/admin-ui.md +101 -96
- package/docs/handbook/guides/agent-setup.md +56 -71
- package/docs/handbook/guides/typed-queries.md +105 -111
- package/docs/handbook/navigation.json +8 -32
- package/docs/handbook/reference/authorization.md +52 -271
- package/docs/handbook/reference/diagnostics.md +69 -173
- package/docs/handbook/reference/features.md +48 -50
- package/docs/handbook/reference/manifest.md +56 -116
- package/docs/handbook/reference/procedure.md +92 -229
- package/docs/handbook/reference/schema.md +156 -215
- package/docs/handbook/reference/site-config.md +58 -211
- package/docs/handbook/reference/surface.md +69 -181
- package/docs/handbook/reference/trigger.md +73 -162
- package/docs/handbook/reference/view.md +140 -241
- package/docs/handbook/releases/index.md +58 -22
- package/docs/handbook/start/overview.md +59 -48
- package/docs/handbook/start/project-and-cli.md +127 -116
- package/docs/handbook/start/quickstart-worker.md +102 -151
- package/docs/skills/develop/SKILL.md +114 -232
- package/docs/skills/develop/mcp-app.md +79 -0
- package/docs/skills/integrate/SKILL.md +96 -0
- package/docs/skills/media-gc/SKILL.md +21 -10
- package/docs/skills/provision/SKILL.md +68 -162
- package/docs/skills/update/SKILL.md +33 -34
- package/docs/upgrade-0.1-to-0.2.md +211 -0
- package/package.json +87 -105
- package/dist/admin-ui.d.ts +0 -2
- package/dist/admin-ui.d.ts.map +0 -1
- package/dist/admin-ui.js +0 -2
- package/dist/admin-ui.js.map +0 -1
- package/dist/admin.d.ts +0 -2
- package/dist/admin.d.ts.map +0 -1
- package/dist/admin.js +0 -2
- package/dist/admin.js.map +0 -1
- package/dist/auth.d.ts +0 -2
- package/dist/auth.d.ts.map +0 -1
- package/dist/auth.js +0 -2
- package/dist/auth.js.map +0 -1
- package/dist/bun.d.ts +0 -2
- package/dist/bun.d.ts.map +0 -1
- package/dist/bun.js +0 -2
- package/dist/bun.js.map +0 -1
- package/dist/cli/harness.d.ts +0 -3
- package/dist/cli/harness.d.ts.map +0 -1
- package/dist/cli/harness.js +0 -214
- package/dist/cli/harness.js.map +0 -1
- package/dist/cli/skills.d.ts +0 -3
- package/dist/cli/skills.d.ts.map +0 -1
- package/dist/cli/skills.js +0 -128
- package/dist/cli/skills.js.map +0 -1
- package/dist/cloudflare.d.ts +0 -2
- package/dist/cloudflare.d.ts.map +0 -1
- package/dist/cloudflare.js +0 -2
- package/dist/cloudflare.js.map +0 -1
- package/dist/codegen/emitMantleModule.d.ts +0 -22
- package/dist/codegen/emitMantleModule.d.ts.map +0 -1
- package/dist/codegen/emitMantleModule.js +0 -291
- package/dist/codegen/emitMantleModule.js.map +0 -1
- package/dist/codegen.d.ts +0 -2
- package/dist/codegen.d.ts.map +0 -1
- package/dist/codegen.js +0 -2
- package/dist/codegen.js.map +0 -1
- package/dist/runtime-testing.d.ts +0 -2
- package/dist/runtime-testing.d.ts.map +0 -1
- package/dist/runtime-testing.js +0 -2
- package/dist/runtime-testing.js.map +0 -1
- package/dist/runtime.d.ts +0 -2
- package/dist/runtime.d.ts.map +0 -1
- package/dist/runtime.js +0 -2
- package/dist/runtime.js.map +0 -1
- package/dist/spec.d.ts +0 -2
- package/dist/spec.d.ts.map +0 -1
- package/dist/spec.js +0 -2
- package/dist/spec.js.map +0 -1
- package/dist/vercel-libsql.d.ts +0 -2
- package/dist/vercel-libsql.d.ts.map +0 -1
- package/dist/vercel-libsql.js +0 -2
- package/dist/vercel-libsql.js.map +0 -1
- package/dist/vercel.d.ts +0 -2
- package/dist/vercel.d.ts.map +0 -1
- package/dist/vercel.js +0 -2
- package/dist/vercel.js.map +0 -1
- package/dist/web.d.ts +0 -2
- package/dist/web.d.ts.map +0 -1
- package/dist/web.js +0 -2
- package/dist/web.js.map +0 -1
- package/docs/adapter-guide.md +0 -222
- package/docs/agent-prompts.md +0 -102
- package/docs/api-mcp-authorization.md +0 -5
- package/docs/assets/mantle-admin-developer.png +0 -0
- package/docs/assets/mantle-admin-operations.png +0 -0
- package/docs/assets/mantle-hero.jpg +0 -0
- package/docs/auth-hosting-model.md +0 -166
- package/docs/cloudflare-low-level-composition.md +0 -5
- package/docs/consumer-onboarding-audit.md +0 -65
- package/docs/deferred-lifecycle-queues.md +0 -5
- package/docs/design-atoms.md +0 -16
- package/docs/design-references/editorial-blog-2026-05-05.md +0 -218
- package/docs/direct-authoring.md +0 -5
- package/docs/examples/builtin-commerce.md +0 -269
- package/docs/examples/builtin-intake.md +0 -143
- package/docs/examples/builtin-legal-documents.md +0 -189
- package/docs/examples/builtin-procurement.md +0 -241
- package/docs/examples/builtin-publication.md +0 -241
- package/docs/examples/builtin-reservation.md +0 -149
- package/docs/examples/cf-primitives-commerce-inventory.md +0 -809
- package/docs/examples/cf-primitives-guarded-api.md +0 -429
- package/docs/examples/cf-primitives-intake-hooks.md +0 -319
- package/docs/examples/host-chatgpt-sites/.openai/hosting.json +0 -1
- package/docs/examples/host-chatgpt-sites/README.md +0 -70
- package/docs/examples/host-chatgpt-sites/drizzle/0000_sites_users.sql +0 -8
- package/docs/examples/host-chatgpt-sites/drizzle/0001_mantle.sql +0 -294
- package/docs/examples/host-chatgpt-sites/drizzle/0002_article_cover.sql +0 -5
- package/docs/examples/host-chatgpt-sites/drizzle/0003_store_instance_id.sql +0 -1
- package/docs/examples/host-chatgpt-sites/drizzle/meta/_journal.json +0 -1
- package/docs/examples/host-chatgpt-sites/manifests/site.yaml +0 -27
- package/docs/examples/host-chatgpt-sites/package.json +0 -1
- package/docs/examples/host-chatgpt-sites/public/site.css +0 -1
- package/docs/examples/host-chatgpt-sites/scripts/build.mjs +0 -13
- package/docs/examples/host-chatgpt-sites/scripts/check.mjs +0 -101
- package/docs/examples/host-chatgpt-sites/scripts/migration.mjs +0 -9
- package/docs/examples/host-chatgpt-sites/src/chatgpt-auth.ts +0 -63
- package/docs/examples/host-chatgpt-sites/src/index.ts +0 -46
- package/docs/examples/host-chatgpt-sites/src/mcp.ts +0 -49
- package/docs/examples/host-chatgpt-sites/src/media.ts +0 -109
- package/docs/examples/host-chatgpt-sites/src/r2-lab.ts +0 -38
- package/docs/examples/host-chatgpt-sites/src/storage-fingerprint.json +0 -1
- package/docs/examples/host-chatgpt-sites/src/web.ts +0 -35
- package/docs/examples/host-chatgpt-sites/tsconfig.json +0 -1
- package/docs/examples/host-chatgpt-sites/wrangler.jsonc +0 -10
- package/docs/examples/host-local-admin-otp/.dev.vars.example +0 -3
- package/docs/examples/host-local-admin-otp/README.md +0 -80
- package/docs/examples/host-local-admin-otp/ensure-dev-vars.mjs +0 -5
- package/docs/examples/host-local-admin-otp/manifests/site.yaml +0 -25
- package/docs/examples/host-local-admin-otp/package.json +0 -29
- package/docs/examples/host-local-admin-otp/public/.gitkeep +0 -1
- package/docs/examples/host-local-admin-otp/smoke.mjs +0 -141
- package/docs/examples/host-local-admin-otp/src/index.ts +0 -54
- package/docs/examples/host-local-admin-otp/tsconfig.json +0 -17
- package/docs/examples/host-local-admin-otp/wrangler.jsonc +0 -23
- package/docs/examples/host-minimal-worker/README.md +0 -41
- package/docs/examples/host-minimal-worker/manifests/site.yaml +0 -25
- package/docs/examples/host-minimal-worker/package.json +0 -26
- package/docs/examples/host-minimal-worker/smoke.mjs +0 -23
- package/docs/examples/host-minimal-worker/src/index.ts +0 -4
- package/docs/examples/host-minimal-worker/wrangler.jsonc +0 -22
- package/docs/handbook/chatgpt-sites/equipment-checkout.md +0 -231
- package/docs/handbook/chatgpt-sites/host-reference.md +0 -113
- package/docs/handbook/chatgpt-sites/index.md +0 -123
- package/docs/handbook/cloudflare/bindings.md +0 -298
- package/docs/handbook/cloudflare/conventional-worker.md +0 -162
- package/docs/handbook/cloudflare/deferred-hooks-queues.md +0 -170
- package/docs/handbook/cloudflare/low-level-composition.md +0 -169
- package/docs/handbook/cloudflare/public-web.md +0 -144
- package/docs/handbook/cloudflare/site-chrome.md +0 -75
- package/docs/handbook/examples/commerce-transaction.md +0 -11
- package/docs/handbook/examples/commerce.md +0 -11
- package/docs/handbook/examples/guarded-api.md +0 -10
- package/docs/handbook/examples/intake-form.md +0 -12
- package/docs/handbook/examples/intake-hooks.md +0 -11
- package/docs/handbook/examples/legal-documents.md +0 -10
- package/docs/handbook/examples/procurement-approvals.md +0 -10
- package/docs/handbook/examples/publication.md +0 -10
- package/docs/handbook/examples/reservation.md +0 -10
- package/docs/handbook/start/quickstart-admin.md +0 -50
- package/docs/labels.md +0 -71
- package/docs/media-uploads.md +0 -5
- package/docs/migration-0.1.2.md +0 -13
- package/docs/performance-harness.md +0 -228
- package/docs/release-process.md +0 -244
- package/docs/schema-indexes.md +0 -5
- package/docs/sealed-pipeline-ownership.md +0 -101
- package/docs/skills/plugin/SKILL.md +0 -132
- package/docs/skills/theme/SKILL.md +0 -77
- package/docs/spec-only-host-adoption.md +0 -157
- package/docs/transaction-patterns.md +0 -5
- package/skills/README.md +0 -125
- package/skills/develop/SKILL.md +0 -250
- package/skills/install/SKILL.md +0 -149
- package/skills/media-gc/SKILL.md +0 -85
- package/skills/plugin/SKILL.md +0 -132
- package/skills/provision/SKILL.md +0 -194
- package/skills/theme/SKILL.md +0 -77
- package/skills/update/SKILL.md +0 -51
|
@@ -0,0 +1,705 @@
|
|
|
1
|
+
import { PG_GRAMMAR } from "../../spec/domain/model/SqlIr.js";
|
|
2
|
+
import { SqlRefusal } from "../../spec/domain/service/SqlRefusal.js";
|
|
3
|
+
import { intervalMicros, parseNumeric } from "../../spec/domain/service/SqlTypes.js";
|
|
4
|
+
/** node type -> the keys it may carry */
|
|
5
|
+
export const KEYS_SRC = {
|
|
6
|
+
SelectStmt: 'targetList fromClause whereClause groupClause havingClause sortClause limitCount distinctClause valuesLists limitOption op',
|
|
7
|
+
InsertStmt: 'relation cols selectStmt onConflictClause returningClause override',
|
|
8
|
+
UpdateStmt: 'relation targetList whereClause returningClause',
|
|
9
|
+
DeleteStmt: 'relation whereClause returningClause',
|
|
10
|
+
ReturningClause: 'exprs', ResTarget: 'name val', ColumnRef: 'fields', String: 'sval', A_Star: '',
|
|
11
|
+
A_Const: 'ival fval sval boolval isnull', A_Expr: 'kind name lexpr rexpr',
|
|
12
|
+
BoolExpr: 'boolop args', NullTest: 'arg nulltesttype', CaseExpr: 'arg args defresult', CaseWhen: 'expr result',
|
|
13
|
+
CoalesceExpr: 'args', TypeCast: 'arg typeName', TypeName: 'names typemod typmods',
|
|
14
|
+
FuncCall: 'funcname args agg_star agg_distinct over funcformat', WindowDef: 'partitionClause orderClause frameOptions',
|
|
15
|
+
SubLink: 'subLinkType testexpr subselect operName', SortBy: 'node sortby_dir sortby_nulls',
|
|
16
|
+
RangeVar: 'relname alias inh relpersistence mantle', Alias: 'aliasname', RangeSubselect: 'subquery alias',
|
|
17
|
+
RangeFunction: 'functions alias', JoinExpr: 'jointype larg rarg quals', List: 'items',
|
|
18
|
+
OnConflictClause: 'action infer targetList whereClause', InferClause: 'indexElems', IndexElem: 'name ordering nulls_ordering',
|
|
19
|
+
};
|
|
20
|
+
export const KEYS = Object.fromEntries(Object.entries(KEYS_SRC).map(([k, v]) => [k, new Set(v.split(' ').filter(Boolean))]));
|
|
21
|
+
/**
|
|
22
|
+
* Where a node may sit. The printers print whatever node a slot holds, and the policy rewriter wraps only a `RangeVar` in FROM, so
|
|
23
|
+
* the type of every child is checked against its slot: a `String` in FROM would print as a table read with no wrapper. A key not
|
|
24
|
+
* listed here is a scalar (a name, an enum, a flag) and must hold a string, number or boolean, never a node.
|
|
25
|
+
*/
|
|
26
|
+
const EXPR = 'ColumnRef A_Const A_Expr BoolExpr NullTest CaseExpr CoalesceExpr TypeCast FuncCall SubLink MinMaxExpr';
|
|
27
|
+
const FROM = 'RangeVar RangeSubselect RangeFunction JoinExpr';
|
|
28
|
+
const SLOTS_SRC = {
|
|
29
|
+
'SelectStmt.targetList': 'ResTarget', 'SelectStmt.fromClause': FROM, 'SelectStmt.whereClause': EXPR, 'SelectStmt.havingClause': EXPR,
|
|
30
|
+
'SelectStmt.groupClause': EXPR, 'SelectStmt.sortClause': 'SortBy', 'SelectStmt.limitCount': EXPR, 'SelectStmt.distinctClause': EXPR,
|
|
31
|
+
'SelectStmt.valuesLists': 'List', 'SelectStmt>List.items': EXPR,
|
|
32
|
+
'InsertStmt.cols': 'ResTarget', 'InsertStmt.selectStmt': 'SelectStmt', 'UpdateStmt.targetList': 'ResTarget', 'UpdateStmt.whereClause': EXPR,
|
|
33
|
+
'DeleteStmt.whereClause': EXPR, 'ReturningClause.exprs': 'ResTarget', 'ResTarget.val': EXPR,
|
|
34
|
+
'ColumnRef.fields': 'String A_Star', 'A_Expr.name': 'String', 'A_Expr.lexpr': EXPR, 'A_Expr.rexpr': `${EXPR} List`, 'A_Expr>List.items': EXPR,
|
|
35
|
+
'BoolExpr.args': EXPR, 'NullTest.arg': EXPR, 'CaseExpr.arg': EXPR, 'CaseExpr.args': 'CaseWhen', 'CaseExpr.defresult': EXPR,
|
|
36
|
+
'CaseWhen.expr': EXPR, 'CaseWhen.result': EXPR, 'CoalesceExpr.args': EXPR, 'TypeCast.arg': EXPR, 'TypeName.names': 'String', 'TypeName.typmods': 'A_Const',
|
|
37
|
+
'FuncCall.funcname': 'String', 'FuncCall.args': EXPR, 'FuncCall.agg_filter': EXPR, 'FuncCall.agg_order': 'SortBy',
|
|
38
|
+
'WindowDef.partitionClause': EXPR, 'WindowDef.orderClause': 'SortBy', 'WindowDef.startOffset': EXPR, 'WindowDef.endOffset': EXPR,
|
|
39
|
+
'SubLink.testexpr': EXPR, 'SubLink.subselect': 'SelectStmt', 'SubLink.operName': 'String', 'SortBy.node': EXPR,
|
|
40
|
+
'RangeSubselect.subquery': 'SelectStmt', 'RangeFunction.functions': 'List', 'RangeFunction>List.items': 'FuncCall',
|
|
41
|
+
'JoinExpr.larg': FROM, 'JoinExpr.rarg': FROM, 'JoinExpr.quals': EXPR,
|
|
42
|
+
'OnConflictClause.targetList': 'ResTarget', 'OnConflictClause.whereClause': EXPR, 'InferClause.indexElems': 'IndexElem',
|
|
43
|
+
'WithClause.ctes': 'CommonTableExpr', 'CommonTableExpr.ctequery': 'SelectStmt', 'CommonTableExpr.aliascolnames': 'String', 'MinMaxExpr.args': EXPR,
|
|
44
|
+
};
|
|
45
|
+
const SLOTS = new Map(Object.entries(SLOTS_SRC).map(([k, v]) => [k, new Set(v.split(' '))]));
|
|
46
|
+
/** keys (or `Type.key`) whose value is one node with the type key omitted (libpg-query prints nothing for it) */
|
|
47
|
+
export const BARE = { alias: 'Alias', typeName: 'TypeName', infer: 'InferClause', returningClause: 'ReturningClause', relation: 'RangeVar', over: 'WindowDef', onConflictClause: 'OnConflictClause', withClause: 'WithClause', 'SelectStmt.larg': 'SelectStmt', 'SelectStmt.rarg': 'SelectStmt' };
|
|
48
|
+
export const ENUM = {
|
|
49
|
+
'SelectStmt.op': ['SETOP_NONE'], 'SelectStmt.limitOption': ['LIMIT_OPTION_DEFAULT', 'LIMIT_OPTION_COUNT'],
|
|
50
|
+
'InsertStmt.override': ['OVERRIDING_NOT_SET'], 'RangeVar.inh': [true], 'RangeVar.relpersistence': ['p'], 'RangeVar.mantle': ['table', 'cte'],
|
|
51
|
+
'A_Expr.kind': ['AEXPR_OP', 'AEXPR_IN', 'AEXPR_LIKE', 'AEXPR_BETWEEN', 'AEXPR_NOT_BETWEEN', 'AEXPR_DISTINCT', 'AEXPR_NOT_DISTINCT', 'AEXPR_NULLIF'],
|
|
52
|
+
'BoolExpr.boolop': ['AND_EXPR', 'OR_EXPR', 'NOT_EXPR'], 'NullTest.nulltesttype': ['IS_NULL', 'IS_NOT_NULL'],
|
|
53
|
+
'SubLink.subLinkType': ['EXISTS_SUBLINK', 'EXPR_SUBLINK', 'ANY_SUBLINK'], 'JoinExpr.jointype': ['JOIN_INNER', 'JOIN_LEFT'],
|
|
54
|
+
'SortBy.sortby_dir': ['SORTBY_DEFAULT', 'SORTBY_ASC', 'SORTBY_DESC'], 'SortBy.sortby_nulls': ['SORTBY_NULLS_DEFAULT', 'SORTBY_NULLS_FIRST', 'SORTBY_NULLS_LAST'],
|
|
55
|
+
'FuncCall.funcformat': ['COERCE_EXPLICIT_CALL', 'COERCE_SQL_SYNTAX'],
|
|
56
|
+
'WindowDef.frameOptions': [1058], // 1058 = the default frame; any frame clause is refused
|
|
57
|
+
'OnConflictClause.action': ['ONCONFLICT_NOTHING', 'ONCONFLICT_UPDATE'], 'TypeName.typemod': [-1],
|
|
58
|
+
'IndexElem.ordering': ['SORTBY_DEFAULT'], 'IndexElem.nulls_ordering': ['SORTBY_NULLS_DEFAULT'],
|
|
59
|
+
};
|
|
60
|
+
// LIKE is an AEXPR_LIKE node, checked below; `~~` written as a plain operator prints as itself, which SQLite cannot parse
|
|
61
|
+
const OPS = new Set(['=', '<>', '!=', '<', '>', '<=', '>=', '+', '-', '*', '/', '%', '||', '->>']);
|
|
62
|
+
/** scalar and aggregate functions. `pg_catalog.` is stripped before the lookup. */
|
|
63
|
+
export const FUNCS = new Set([
|
|
64
|
+
'count', 'sum', 'min', 'max', 'avg', 'json_group_array', 'json_group_object', 'row_number', 'rank',
|
|
65
|
+
'lower', 'upper', 'length', 'abs', 'round', 'substr', 'replace', 'btrim', 'ltrim', 'rtrim', 'instr', 'typeof', 'hex', // btrim is what PostgreSQL parses trim(x) to
|
|
66
|
+
'json_extract', 'json_set', 'json_insert', 'json_remove', 'json_array_length',
|
|
67
|
+
'now', 'auth.uid', 'auth.role', 'date_trunc', 'extract', 'like_escape',
|
|
68
|
+
'mantle.search', 'mantle.search_rank', 'mantle.near', 'mantle.distance',
|
|
69
|
+
]);
|
|
70
|
+
const WINDOW = new Set(['row_number', 'rank', 'sum', 'count']);
|
|
71
|
+
/** functions that exist only with OVER */
|
|
72
|
+
const WINDOW_ONLY = new Set(['row_number', 'rank', 'dense_rank', 'lag', 'lead', 'first_value', 'last_value']);
|
|
73
|
+
const AGG = new Set(['count', 'sum', 'min', 'max', 'avg', 'json_group_array', 'json_group_object']);
|
|
74
|
+
export const TRUNC_UNITS = new Set(['hour', 'day', 'week', 'month', 'year']);
|
|
75
|
+
export const EXTRACT_FIELDS = new Set(['year', 'month', 'day', 'dow', 'hour']);
|
|
76
|
+
const CAST_TYPES = new Set(['text', 'int4', 'int8', 'float8', 'bool', 'timestamptz', 'date', 'numeric', 'interval']);
|
|
77
|
+
export const MAX_RADIUS_M = 50_000;
|
|
78
|
+
export const MAX_NEAR_K = 100;
|
|
79
|
+
/** The most nodes one program's IR may have. */
|
|
80
|
+
export const MAX_NODES = 2000;
|
|
81
|
+
const BASE_PROFILE = { name: 'base', keys: KEYS, enums: ENUM, ops: OPS, funcs: FUNCS, window: WINDOW, agg: AGG, trunc: TRUNC_UNITS, extract: EXTRACT_FIELDS, casts: CAST_TYPES };
|
|
82
|
+
// ---- ADR-0037 decision 2: the reference profile's additions --------------------------------------------------------------
|
|
83
|
+
const MORE_KEYS = {
|
|
84
|
+
SelectStmt: 'withClause larg rarg all', WithClause: 'ctes recursive', CommonTableExpr: 'ctename ctequery aliascolnames ctematerialized',
|
|
85
|
+
RangeSubselect: 'lateral', FuncCall: 'agg_filter agg_order', WindowDef: 'startOffset endOffset', MinMaxExpr: 'op args',
|
|
86
|
+
};
|
|
87
|
+
const MORE_ENUM = {
|
|
88
|
+
'SelectStmt.op': ['SETOP_UNION', 'SETOP_INTERSECT', 'SETOP_EXCEPT'], 'A_Expr.kind': ['AEXPR_ILIKE'],
|
|
89
|
+
'CommonTableExpr.ctematerialized': ['CTEMaterializeDefault', 'CTEMaterializeAlways', 'CTEMaterializeNever'], 'MinMaxExpr.op': ['IS_GREATEST', 'IS_LEAST'],
|
|
90
|
+
};
|
|
91
|
+
const MORE_OPS = ['->', '#>', '#>>', '@>', '<@', '?', '?|', '?&', '~', '~*', '!~', '!~*', '~~*', '!~~*'];
|
|
92
|
+
const MORE_WINDOW = ['avg', 'min', 'max', 'lag', 'lead', 'first_value', 'last_value', 'dense_rank'];
|
|
93
|
+
const MORE_AGG = ['string_agg', 'jsonb_agg', 'jsonb_object_agg'];
|
|
94
|
+
const MORE_FUNCS = [...MORE_WINDOW, ...MORE_AGG, 'jsonb_build_object', 'jsonb_build_array', 'jsonb_strip_nulls', 'to_jsonb', 'jsonb_typeof', 'split_part', 'floor', 'ceil', 'sqrt', 'power', 'timezone'];
|
|
95
|
+
/** frame bits a window may not set: GROUPS and every EXCLUDE (PostgreSQL's FRAMEOPTION_* in parsenodes.h) */
|
|
96
|
+
export const FRAME_REFUSED = 0x8 | 0x8000 | 0x10000 | 0x20000;
|
|
97
|
+
const union = (a, b) => new Set([...a, ...b]);
|
|
98
|
+
const REFERENCE_PROFILE = {
|
|
99
|
+
name: 'reference',
|
|
100
|
+
keys: Object.fromEntries([...new Set([...Object.keys(KEYS), ...Object.keys(MORE_KEYS)])].map((k) => [k, union(KEYS[k] ?? [], (MORE_KEYS[k] ?? '').split(' ').filter(Boolean))])),
|
|
101
|
+
// a frame is checked by its bits (check.WindowDef), not as one enum value
|
|
102
|
+
enums: Object.fromEntries([...new Set([...Object.keys(ENUM), ...Object.keys(MORE_ENUM)])].filter((k) => k !== 'WindowDef.frameOptions').map((k) => [k, [...(ENUM[k] ?? []), ...(MORE_ENUM[k] ?? [])]])),
|
|
103
|
+
ops: union(OPS, MORE_OPS), funcs: union(FUNCS, MORE_FUNCS), window: union(WINDOW, MORE_WINDOW), agg: union(AGG, MORE_AGG),
|
|
104
|
+
trunc: union(TRUNC_UNITS, ['minute', 'quarter']), extract: union(EXTRACT_FIELDS, ['minute', 'quarter', 'week', 'isoyear', 'isodow', 'doy', 'epoch']),
|
|
105
|
+
casts: union(CAST_TYPES, ['jsonb']),
|
|
106
|
+
};
|
|
107
|
+
export const PROFILES = { base: BASE_PROFILE, reference: REFERENCE_PROFILE };
|
|
108
|
+
/**
|
|
109
|
+
* Names that SQLite rejects unquoted while PostgreSQL's keyword list lets the printer emit them bare.
|
|
110
|
+
* Measured on local D1 by `cases/deparser.ts` (it fails if this list drifts from the measurement).
|
|
111
|
+
*/
|
|
112
|
+
export const SQLITE_ONLY_KEYWORDS = new Set([
|
|
113
|
+
'add', 'alter', 'autoincrement', 'commit', 'delete', 'drop', 'escape', 'index', 'insert', 'nothing', 'raise', 'set', 'transaction', 'update',
|
|
114
|
+
]);
|
|
115
|
+
export const SYSTEM = new Set(['version', 'status', 'author_id', 'created_at', 'updated_at']);
|
|
116
|
+
const sv = (list) => list.map((n) => n.String?.sval ?? (n.A_Star ? '*' : no('SQL_UNSUPPORTED', 'a name part that is not an identifier'))).join('.');
|
|
117
|
+
const fname = (n) => sv(n.funcname).replace(/^pg_catalog\./, '');
|
|
118
|
+
function no(code, message, offset, keyword) {
|
|
119
|
+
throw new SqlRefusal(code, message, offset, keyword);
|
|
120
|
+
}
|
|
121
|
+
/** structural refusals name a key or an enum value; these find the keyword in the source text (the AST carries no location for them) */
|
|
122
|
+
const KEYWORD = {
|
|
123
|
+
'SelectStmt.withClause': /\bWITH\b/i, 'InsertStmt.withClause': /\bWITH\b/i, 'UpdateStmt.withClause': /\bWITH\b/i, 'DeleteStmt.withClause': /\bWITH\b/i,
|
|
124
|
+
'SelectStmt.limitOffset': /\bOFFSET\b/i, 'SelectStmt.lockingClause': /\bFOR\s+(NO\s+KEY\s+)?(UPDATE|SHARE|KEY\s+SHARE)\b/i, 'SelectStmt.intoClause': /\bINTO\b/i,
|
|
125
|
+
'SelectStmt.op': /\b(UNION|INTERSECT|EXCEPT)\b/i, 'UpdateStmt.fromClause': /\bFROM\b/i, 'DeleteStmt.usingClause': /\bUSING\b/i,
|
|
126
|
+
'JoinExpr.jointype': /\b(RIGHT|FULL)\b/i, 'JoinExpr.isNatural': /\bNATURAL\b/i, 'JoinExpr.usingClause': /\bUSING\b/i,
|
|
127
|
+
'WindowDef.frameOptions': /\b(ROWS|RANGE|GROUPS)\b/i, 'A_Expr.kind': /\bILIKE\b/i, 'InferClause.conname': /\bON\s+CONSTRAINT\b/i,
|
|
128
|
+
'SelectStmt.distinctClause': /\bDISTINCT\s+ON\b/i, GroupingSet: /\bGROUPING\s+SETS\b/i,
|
|
129
|
+
};
|
|
130
|
+
/** first source offset found in a subtree, so a refusal about a key can still point somewhere */
|
|
131
|
+
function firstLoc(v) {
|
|
132
|
+
if (!v || typeof v !== 'object')
|
|
133
|
+
return undefined;
|
|
134
|
+
if (typeof v.location === 'number' && v.location >= 0)
|
|
135
|
+
return v.location;
|
|
136
|
+
for (const c of Array.isArray(v) ? v : Object.values(v)) {
|
|
137
|
+
const l = firstLoc(c);
|
|
138
|
+
if (l !== undefined)
|
|
139
|
+
return l;
|
|
140
|
+
}
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
/** Validate a program of statements under a profile. `stmts` are the `stmt` of each RawStmt; `locs` their offsets (CLI only). */
|
|
144
|
+
export function validateProgram(stmts, ctx, locs = [], profile = BASE_PROFILE) {
|
|
145
|
+
program(stmts, { ...ctx, p: profile, scope: [] }, locs);
|
|
146
|
+
}
|
|
147
|
+
function program(stmts, ctx, locs) {
|
|
148
|
+
if (!Array.isArray(stmts) || !stmts.length)
|
|
149
|
+
no('SQL_SHAPE', 'an empty program');
|
|
150
|
+
if (ctx.kind === 'view' && (stmts.length !== 1 || !stmts[0].SelectStmt))
|
|
151
|
+
no('SQL_SHAPE', 'a View is exactly one SELECT', locs[1]);
|
|
152
|
+
ctx = { ...ctx, known: knownColumns(stmts), cols: ctx.columns ?? schemaColumns(ctx.schemas) };
|
|
153
|
+
const w = { ctx, budget: { n: 0 } };
|
|
154
|
+
stmts.forEach((s, i) => {
|
|
155
|
+
const t = Object.keys(s)[0] ?? '';
|
|
156
|
+
const at = locs[i] ?? firstLoc(s);
|
|
157
|
+
if (!['SelectStmt', 'InsertStmt', 'UpdateStmt', 'DeleteStmt'].includes(t))
|
|
158
|
+
no('SQL_UNSUPPORTED', `statement ${t} is refused`, at);
|
|
159
|
+
if (t === 'SelectStmt' && ctx.kind !== 'view')
|
|
160
|
+
no('SQL_SHAPE', 'a Procedure statement is a write', at);
|
|
161
|
+
if (t !== 'SelectStmt' && ctx.kind === 'view')
|
|
162
|
+
no('SQL_SHAPE', 'a View is one SELECT', at);
|
|
163
|
+
walk(t, s[t], w, [t], at);
|
|
164
|
+
});
|
|
165
|
+
if (ctx.public)
|
|
166
|
+
publishedJoin(stmts, ctx);
|
|
167
|
+
}
|
|
168
|
+
/** every node of a tree with the given key, at any depth */
|
|
169
|
+
function* find(v, key) {
|
|
170
|
+
if (!v || typeof v !== 'object')
|
|
171
|
+
return;
|
|
172
|
+
for (const [k, c] of Object.entries(v)) {
|
|
173
|
+
if (k === key)
|
|
174
|
+
yield c;
|
|
175
|
+
yield* find(c, key);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/** What every program checked against these Schemas reads off them: computed once per plan by a caller that checks many. */
|
|
179
|
+
export function schemaColumns(schemas) {
|
|
180
|
+
const known = new Set();
|
|
181
|
+
const scopes = new Set();
|
|
182
|
+
const types = new Map();
|
|
183
|
+
for (const s of Object.values(schemas)) {
|
|
184
|
+
if (typeof s.scope === 'string')
|
|
185
|
+
scopes.add(s.scope.toLowerCase());
|
|
186
|
+
for (const [f, t] of Object.entries(s.fields)) {
|
|
187
|
+
(t === 'geo' ? [f, `${f}_lat`, `${f}_lng`] : [f]).forEach((c) => known.add(c));
|
|
188
|
+
types.set(f, types.has(f) && types.get(f) !== t ? null : t); // null: two Schemas disagree
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
return { known, scopes, types: new Map([...types].filter((e) => e[1] !== null)) };
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Every name a column may have beyond the declared fields (`SchemaColumns.known`, a geo field also as _lat and _lng): `id`, the
|
|
195
|
+
* system columns, json_each's, relation names and aliases, and every output name the program gives (ORDER BY and outer queries
|
|
196
|
+
* read them). A name outside both is a typo. Not per relation: a column of another table passes here.
|
|
197
|
+
*/
|
|
198
|
+
function knownColumns(stmts) {
|
|
199
|
+
const known = new Set(['id', 'key', 'value', 'type', 'atom', 'parent', 'fullkey', 'path', ...SYSTEM]);
|
|
200
|
+
for (const r of find(stmts, 'ResTarget'))
|
|
201
|
+
if (r.name)
|
|
202
|
+
known.add(String(r.name).toLowerCase());
|
|
203
|
+
for (const r of find(stmts, 'RangeVar'))
|
|
204
|
+
[r.relname, r.alias?.aliasname].forEach((a) => a && known.add(a.toLowerCase())); // mantle.search(<alias>, ...) names a relation
|
|
205
|
+
for (const c of find(stmts, 'CommonTableExpr'))
|
|
206
|
+
[c.ctename, ...(c.aliascolnames ?? []).map((x) => x.String?.sval)].forEach((a) => a && known.add(String(a).toLowerCase()));
|
|
207
|
+
return known;
|
|
208
|
+
}
|
|
209
|
+
/** ADR-0034 decision 8: a public View that joins a non-publishing Schema must tie it to a publishing one in a JOIN ... ON. */
|
|
210
|
+
function publishedJoin(stmts, ctx) {
|
|
211
|
+
// a CTE reference is not a relation: the Schemas its body reads are found where they are
|
|
212
|
+
const rels = [...find(stmts, 'RangeVar')].filter((r) => r.mantle !== 'cte').map((r) => ({
|
|
213
|
+
alias: (r.alias?.aliasname ?? r.relname).toLowerCase(),
|
|
214
|
+
publishing: !!ctx.schemas[r.relname.toLowerCase()]?.publishing,
|
|
215
|
+
}));
|
|
216
|
+
if (!rels.some((r) => r.publishing))
|
|
217
|
+
return;
|
|
218
|
+
const ons = [...find(stmts, 'JoinExpr')].map((j) => new Set([...find(j.quals, 'ColumnRef')].filter((c) => c.fields.length === 2).map((c) => c.fields[0].String.sval.toLowerCase())));
|
|
219
|
+
for (const r of rels)
|
|
220
|
+
if (!r.publishing && !ons.some((o) => o.has(r.alias) && rels.some((p) => p.publishing && o.has(p.alias))))
|
|
221
|
+
no('SQL_RELATION', `${r.alias} has no published state: a public View must join it to a publishing Schema in a JOIN ... ON`);
|
|
222
|
+
}
|
|
223
|
+
/** A node's keys and enum values against the profile. */
|
|
224
|
+
function shape(type, node, w, here) {
|
|
225
|
+
const keys = w.ctx.p.keys[type] ?? no('SQL_UNSUPPORTED', `${type} is not in the subset`, here, KEYWORD[type]);
|
|
226
|
+
for (const [k, v] of Object.entries(node)) {
|
|
227
|
+
if (k === 'location' || k === 'rexpr_list_start' || k === 'rexpr_list_end')
|
|
228
|
+
continue; // source positions, not structure
|
|
229
|
+
if (!keys.has(k))
|
|
230
|
+
no('SQL_UNSUPPORTED', `${type}.${k} is not in the subset`, firstLoc(v) ?? here, KEYWORD[`${type}.${k}`]);
|
|
231
|
+
const e = w.ctx.p.enums[`${type}.${k}`];
|
|
232
|
+
if (e && !e.includes(v))
|
|
233
|
+
no('SQL_UNSUPPORTED', `${type}.${k} = ${JSON.stringify(v)} is refused`, firstLoc(node) ?? here, KEYWORD[`${type}.${k}`]);
|
|
234
|
+
}
|
|
235
|
+
if (type === 'String' && node.sval !== undefined && typeof node.sval !== 'string')
|
|
236
|
+
no('SQL_SHAPE', 'a name is a string', here);
|
|
237
|
+
if (type === 'A_Const' && !constant(node))
|
|
238
|
+
no('SQL_UNSUPPORTED', 'a literal is one integer, numeric, string, boolean or NULL', firstLoc(node) ?? here);
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* A literal's value is printed as it is, so its type is checked here: the walker never descends into a literal, and a plan
|
|
242
|
+
* that reaches the runtime is untrusted. libpg-query omits a zero, a false and an empty string (`{ ival: {} }`).
|
|
243
|
+
*/
|
|
244
|
+
function constant(node) {
|
|
245
|
+
const own = Object.keys(node).filter((k) => k !== 'location');
|
|
246
|
+
if (own.length !== 1)
|
|
247
|
+
return false;
|
|
248
|
+
const [k] = own;
|
|
249
|
+
const v = node[k];
|
|
250
|
+
const only = (key, ok) => !!v && typeof v === 'object' && Object.keys(v).every((x) => x === key) && (!(key in v) || ok(v[key]));
|
|
251
|
+
switch (k) {
|
|
252
|
+
case 'ival': return only('ival', Number.isSafeInteger);
|
|
253
|
+
// the parser's Float: a point or exponent, or an integer past int32 (smaller ones are ival); never a sign the printers would
|
|
254
|
+
// print as `+2`, which SQLite reads as a column position in ORDER BY
|
|
255
|
+
// (one split of the digits, so the match is linear; and no longer than any number the parser writes)
|
|
256
|
+
case 'fval': return only('fval', (x) => typeof x === 'string' && x.length <= 64 && /^-?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][-+]?\d+)?$/.test(x) && (/[.eE]/.test(x) || Math.abs(Number(x)) >= 2 ** 31));
|
|
257
|
+
case 'sval': return only('sval', (x) => typeof x === 'string');
|
|
258
|
+
case 'boolval': return only('boolval', (x) => typeof x === 'boolean');
|
|
259
|
+
case 'isnull': return v === true;
|
|
260
|
+
default: return false;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/** Runs `f` with these CTE names in scope. */
|
|
264
|
+
function withScope(w, names, f) {
|
|
265
|
+
w.ctx.scope.push(new Set(names));
|
|
266
|
+
try {
|
|
267
|
+
f();
|
|
268
|
+
}
|
|
269
|
+
finally {
|
|
270
|
+
w.ctx.scope.pop();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function walk(type, node, w, path, loc) {
|
|
274
|
+
if (++w.budget.n > MAX_NODES)
|
|
275
|
+
no('SQL_SHAPE', 'statement too large', loc);
|
|
276
|
+
const here = typeof node.location === 'number' ? node.location : loc;
|
|
277
|
+
shape(type, node, w, here);
|
|
278
|
+
try {
|
|
279
|
+
check[type]?.(node, w.ctx, path, here);
|
|
280
|
+
}
|
|
281
|
+
catch (e) {
|
|
282
|
+
if (e instanceof SqlRefusal && e.offset === undefined && !e.keyword)
|
|
283
|
+
e.offset = here; // a helper (interval, numeric) refused without knowing where
|
|
284
|
+
throw e;
|
|
285
|
+
}
|
|
286
|
+
// PostgreSQL's CTE scope: a body sees its earlier siblings (every sibling under RECURSIVE); the SELECT's body sees them all
|
|
287
|
+
const wc = type === 'SelectStmt' ? node.withClause : undefined;
|
|
288
|
+
const names = (wc?.ctes ?? []).map((x) => String(x.CommonTableExpr?.ctename));
|
|
289
|
+
if (wc) {
|
|
290
|
+
shape('WithClause', wc, w, here);
|
|
291
|
+
if (wc.recursive !== undefined && typeof wc.recursive !== 'boolean')
|
|
292
|
+
no('SQL_UNSUPPORTED', 'WithClause.recursive is a flag', here);
|
|
293
|
+
(wc.ctes ?? []).forEach((x, j) => withScope(w, wc.recursive ? names : names.slice(0, j), () => child(x, w, [...path, 'WithClause'], 'ctes', here)));
|
|
294
|
+
}
|
|
295
|
+
// the Schema relations this statement reads directly, by alias: what a column reference in it can name (`jsonCompare`)
|
|
296
|
+
const rels = type === 'SelectStmt' || type === 'UpdateStmt' || type === 'DeleteStmt' ? relationsOf(node) : undefined;
|
|
297
|
+
if (rels)
|
|
298
|
+
(w.ctx.rels ??= []).push(rels);
|
|
299
|
+
try {
|
|
300
|
+
withScope(w, names, () => {
|
|
301
|
+
for (const [k, v] of Object.entries(node)) {
|
|
302
|
+
if (type === 'A_Const' || k === 'location' || k === 'rexpr_list_start' || k === 'rexpr_list_end' || (wc && k === 'withClause'))
|
|
303
|
+
continue;
|
|
304
|
+
const bare = BARE[`${type}.${k}`] ?? BARE[k];
|
|
305
|
+
const slot = bare || SLOTS.has(`${type}.${k}`) || (type === 'List' && k === 'items');
|
|
306
|
+
if (!slot) {
|
|
307
|
+
if (v !== null && typeof v === 'object')
|
|
308
|
+
no('SQL_UNSUPPORTED', `${type}.${k} is a value, not a node`, here);
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (v === null || typeof v !== 'object')
|
|
312
|
+
no('SQL_UNSUPPORTED', `${type}.${k} holds a node`, here);
|
|
313
|
+
if (bare)
|
|
314
|
+
walk(bare, v, w, [...path, bare], here);
|
|
315
|
+
else if (Array.isArray(v))
|
|
316
|
+
v.forEach((c) => child(c, w, path, k, here));
|
|
317
|
+
else
|
|
318
|
+
child(v, w, path, k, here);
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
}
|
|
322
|
+
finally {
|
|
323
|
+
if (rels)
|
|
324
|
+
w.ctx.rels.pop();
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
/** A statement's own Schema relations (FROM, its joins, an UPDATE or DELETE target), by alias; never a subquery or CTE. */
|
|
328
|
+
function relationsOf(node) {
|
|
329
|
+
const out = new Map();
|
|
330
|
+
const add = (n) => {
|
|
331
|
+
if (n?.JoinExpr)
|
|
332
|
+
return (add(n.JoinExpr.larg), add(n.JoinExpr.rarg));
|
|
333
|
+
const v = n?.RangeVar ?? n;
|
|
334
|
+
if (v?.mantle === 'table')
|
|
335
|
+
out.set(String(v.alias?.aliasname ?? v.relname).toLowerCase(), String(v.relname).toLowerCase());
|
|
336
|
+
};
|
|
337
|
+
for (const f of node.fromClause ?? [])
|
|
338
|
+
add(f);
|
|
339
|
+
add(node.relation);
|
|
340
|
+
return out;
|
|
341
|
+
}
|
|
342
|
+
function child(c, w, path, k, loc) {
|
|
343
|
+
const keys = Object.keys(c);
|
|
344
|
+
if (!keys.length) {
|
|
345
|
+
if (k === 'distinctClause' || (k === 'items' && path.at(-2) === 'RangeFunction'))
|
|
346
|
+
return; // `DISTINCT` is [{}]; a json_each coldeflist slot is {}
|
|
347
|
+
no('SQL_UNSUPPORTED', `an empty node in ${k}`, loc);
|
|
348
|
+
}
|
|
349
|
+
if (keys.length !== 1 || c[keys[0]] === null || typeof c[keys[0]] !== 'object')
|
|
350
|
+
no('SQL_UNSUPPORTED', 'a malformed node', loc);
|
|
351
|
+
const parent = path.at(-1);
|
|
352
|
+
const allowed = SLOTS.get(parent === 'List' ? `${path.at(-2)}>List.${k}` : `${parent}.${k}`);
|
|
353
|
+
if (w.ctx.p.keys[keys[0]] && !allowed?.has(keys[0]))
|
|
354
|
+
no('SQL_SHAPE', `${keys[0]} cannot stand in ${parent}.${k}`, loc); // an unknown type is shape()'s refusal
|
|
355
|
+
walk(keys[0], c[keys[0]], w, [...path, keys[0]], loc);
|
|
356
|
+
}
|
|
357
|
+
/** A cast's type: `t` or `pg_catalog.t`, read as the lowerings and printers read it (the last name part). */
|
|
358
|
+
const castType = (typeName) => {
|
|
359
|
+
const names = (typeName?.names ?? []).map((n) => n?.String?.sval);
|
|
360
|
+
const ok = names.every((x) => typeof x === 'string' && /^[a-z_][a-z0-9_]*$/.test(x)) && (names.length === 1 || (names.length === 2 && names[0] === 'pg_catalog'));
|
|
361
|
+
if (!ok)
|
|
362
|
+
no('SQL_TYPE', `a cast names one type: ${JSON.stringify(names)}`);
|
|
363
|
+
return names.at(-1);
|
|
364
|
+
};
|
|
365
|
+
const isConst = (n) => !!n?.A_Const;
|
|
366
|
+
const isInputRef = (n) => n?.ColumnRef?.fields?.length === 2 && n.ColumnRef.fields[0].String?.sval === 'input';
|
|
367
|
+
const check = {
|
|
368
|
+
RangeVar: (n, ctx, _p, at) => {
|
|
369
|
+
// the parser folds an unquoted name and the CLI writes only lower case: an `ARTICLES` would be one Schema to the checks and
|
|
370
|
+
// another to what keys hooks and publishing by the folded name, so a relation (a Schema or a CTE reference) is lower case
|
|
371
|
+
if (typeof n.relname !== 'string' || n.relname !== n.relname.toLowerCase())
|
|
372
|
+
no('SQL_RELATION', `${JSON.stringify(n.relname)}: a relation is named in lower case`, at);
|
|
373
|
+
const name = n.relname;
|
|
374
|
+
if (name.startsWith('_mantle') || name === 'input' || name === 'auth')
|
|
375
|
+
no('SQL_RELATION', `${name} is not a declared Schema`, at);
|
|
376
|
+
const reference = ctx.p.name === 'reference';
|
|
377
|
+
// a `cte` tag is honored only for a CTE in scope here (the runtime never trusts an IR's tags); base has no WITH at all
|
|
378
|
+
if (n.mantle === 'cte') {
|
|
379
|
+
if (reference && ctx.scope.some((s) => s.has(n.relname)))
|
|
380
|
+
return;
|
|
381
|
+
no('SQL_RELATION', `${name}: a cte reference is not defined in scope`, at);
|
|
382
|
+
}
|
|
383
|
+
if (!ctx.schemas[name])
|
|
384
|
+
no('SQL_RELATION', `${name} is not a declared Schema`, at);
|
|
385
|
+
if (n.mantle !== undefined && n.mantle !== 'table')
|
|
386
|
+
no('SQL_RELATION', `${name}: relation not name-resolved`, at);
|
|
387
|
+
if (n.alias && ['input', 'auth', 'excluded'].includes(n.alias.aliasname))
|
|
388
|
+
no('SQL_RELATION', `${n.alias.aliasname} is a reserved alias`, at);
|
|
389
|
+
if (!reference)
|
|
390
|
+
for (const ident of [name, n.alias?.aliasname])
|
|
391
|
+
if (ident && SQLITE_ONLY_KEYWORDS.has(ident))
|
|
392
|
+
no('SQL_UNSUPPORTED', `${ident} is an SQLite keyword: the printer would not quote it`, at);
|
|
393
|
+
},
|
|
394
|
+
ColumnRef: (n, ctx, _p, at) => {
|
|
395
|
+
const f = sv(n.fields), last = f.split('.').pop().toLowerCase();
|
|
396
|
+
if (n.fields.length > 2)
|
|
397
|
+
no('SQL_COLUMN', `${f}: at most alias.column`, at);
|
|
398
|
+
if (['rowid', 'oid', '_rowid_', '_rid'].includes(last))
|
|
399
|
+
no('SQL_COLUMN', `${last} is not addressable`, at);
|
|
400
|
+
if (ctx.cols.scopes.has(last))
|
|
401
|
+
no('SQL_COLUMN', `${f}: the scope column is not addressable`, at);
|
|
402
|
+
if (f.startsWith('input.') && !(last in ctx.inputs))
|
|
403
|
+
no('SQL_COLUMN', `${f} is not a declared input`, at);
|
|
404
|
+
if (ctx.p.name === 'base' && SQLITE_ONLY_KEYWORDS.has(last))
|
|
405
|
+
no('SQL_UNSUPPORTED', `${last} is an SQLite keyword: the printer would not quote it`, at);
|
|
406
|
+
if (last !== '*' && !f.startsWith('input.') && !ctx.known.has(last) && !ctx.cols.known.has(last))
|
|
407
|
+
no('SQL_COLUMN', `${f} is not a declared field`, at);
|
|
408
|
+
},
|
|
409
|
+
FuncCall: (n, ctx, path, at) => {
|
|
410
|
+
const f = fname(n);
|
|
411
|
+
if (f === 'json_each') {
|
|
412
|
+
if (path.at(-2) !== 'List' || path.at(-3) !== 'RangeFunction')
|
|
413
|
+
no('SQL_FUNCTION', 'json_each is only allowed in FROM', at);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
if (!ctx.p.funcs.has(f))
|
|
417
|
+
no('SQL_FUNCTION', `function ${f} is not on the allowlist`, at);
|
|
418
|
+
if (n.over && (ctx.kind !== 'view' || !ctx.p.window.has(f)))
|
|
419
|
+
no('SQL_FUNCTION', `window function ${f} is refused here`, at);
|
|
420
|
+
if (!n.over && WINDOW_ONLY.has(f))
|
|
421
|
+
no('SQL_FUNCTION', `${f}() is a window function: it needs OVER (...)`, at);
|
|
422
|
+
if ((f === 'lag' || f === 'lead') && n.args?.[1] && n.args[1].A_Const?.ival === undefined)
|
|
423
|
+
no('SQL_FUNCTION', `${f}'s offset is an integer literal`, at);
|
|
424
|
+
if ((n.agg_filter || n.agg_order) && !ctx.p.agg.has(f))
|
|
425
|
+
no('SQL_FUNCTION', `FILTER and ORDER BY belong to an aggregate, and ${f} is not one`, at);
|
|
426
|
+
const args = n.args ?? [];
|
|
427
|
+
const str = (a) => a?.A_Const?.sval?.sval;
|
|
428
|
+
switch (f) {
|
|
429
|
+
case 'like_escape':
|
|
430
|
+
if (path.at(-2) !== 'A_Expr' || args.length !== 2)
|
|
431
|
+
no('SQL_FUNCTION', 'like_escape is only the ESCAPE of a LIKE', at);
|
|
432
|
+
break;
|
|
433
|
+
case 'date_trunc':
|
|
434
|
+
if (args.length !== 2 || !ctx.p.trunc.has(str(args[0]) ?? ''))
|
|
435
|
+
no('SQL_TYPE', `date_trunc takes ${[...ctx.p.trunc].join(', ')} as a literal first argument`, at);
|
|
436
|
+
break;
|
|
437
|
+
case 'extract':
|
|
438
|
+
if (args.length !== 2 || !ctx.p.extract.has(str(args[0]) ?? ''))
|
|
439
|
+
no('SQL_TYPE', `extract takes ${[...ctx.p.extract].join(', ')}`, at);
|
|
440
|
+
break;
|
|
441
|
+
case 'now':
|
|
442
|
+
case 'auth.uid':
|
|
443
|
+
case 'auth.role':
|
|
444
|
+
if (args.length)
|
|
445
|
+
no('SQL_FUNCTION', `${f}() takes no arguments`, at);
|
|
446
|
+
break;
|
|
447
|
+
case 'mantle.search':
|
|
448
|
+
case 'mantle.search_rank':
|
|
449
|
+
if (args.length !== (f === 'mantle.search' ? 2 : 1) || args[0]?.ColumnRef?.fields?.length !== 1)
|
|
450
|
+
no('SQL_FUNCTION', f === 'mantle.search' ? 'mantle.search(<alias>, <query>)' : 'mantle.search_rank(<alias>)', at);
|
|
451
|
+
break;
|
|
452
|
+
case 'mantle.near':
|
|
453
|
+
case 'mantle.distance': {
|
|
454
|
+
const want = f === 'mantle.near' ? 4 : 3;
|
|
455
|
+
const fld = args[0]?.ColumnRef?.fields;
|
|
456
|
+
if (args.length !== want || fld?.length !== 2)
|
|
457
|
+
no('SQL_FUNCTION', `${f}(<alias>.<geo field>, lat, lng${f === 'mantle.near' ? ', meters' : ''})`, at);
|
|
458
|
+
for (const a of args.slice(1, 3))
|
|
459
|
+
if (!isConst(a) && !isInputRef(a))
|
|
460
|
+
no('SQL_FUNCTION', `${f}: latitude and longitude are a literal or input.<name>`, at);
|
|
461
|
+
if (f === 'mantle.near') {
|
|
462
|
+
const m = args[3]?.A_Const?.ival?.ival ?? args[3]?.A_Const?.fval?.fval;
|
|
463
|
+
if (m === undefined)
|
|
464
|
+
no('SQL_FUNCTION', 'mantle.near() needs a literal radius in meters', at);
|
|
465
|
+
if (Number(m) > MAX_RADIUS_M || Number(m) <= 0)
|
|
466
|
+
no('SQL_FUNCTION', `mantle.near() radius is at most ${MAX_RADIUS_M} m`, at);
|
|
467
|
+
}
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
if (ctx.p.agg.has(f) && n.args?.length === 0 && !n.agg_star)
|
|
472
|
+
no('SQL_FUNCTION', `${f} needs an argument`, at);
|
|
473
|
+
// the printers print these as written: `*` is count(*) only, DISTINCT one argument of an aggregate outside a window
|
|
474
|
+
if (n.agg_star && (f !== 'count' || args.length))
|
|
475
|
+
no('SQL_FUNCTION', `${f}(*) is refused: only count(*)`, at);
|
|
476
|
+
if (n.agg_distinct && (!ctx.p.agg.has(f) || args.length !== 1 || n.over))
|
|
477
|
+
no('SQL_FUNCTION', `DISTINCT is one argument of an aggregate, outside a window`, at);
|
|
478
|
+
},
|
|
479
|
+
A_Expr: (n, ctx, _p, at) => {
|
|
480
|
+
const op = sv(n.name);
|
|
481
|
+
// the printer joins what it is given: a missing operand or a one-bound BETWEEN would bind the policy predicate appended after it
|
|
482
|
+
const items = n.rexpr?.List?.items;
|
|
483
|
+
const range = n.kind === 'AEXPR_BETWEEN' || n.kind === 'AEXPR_NOT_BETWEEN';
|
|
484
|
+
if (!n.rexpr || (!n.lexpr && !(n.kind === 'AEXPR_OP' && (op === '-' || op === '+'))) || (range && items?.length !== 2) || (n.kind === 'AEXPR_IN' && !items?.length) || (!range && n.kind !== 'AEXPR_IN' && n.rexpr.List))
|
|
485
|
+
no('SQL_SHAPE', `a malformed ${op} expression`, at);
|
|
486
|
+
// the parser folds a sign into its number (`-2` is ival -2): a sign over a number constant is a resealed IR, and PostgreSQL
|
|
487
|
+
// folds `- -2` back into 2, a column position in ORDER BY and GROUP BY
|
|
488
|
+
if (n.kind === 'AEXPR_OP' && !n.lexpr && (op === '-' || op === '+') && (n.rexpr?.A_Const?.ival !== undefined || n.rexpr?.A_Const?.fval !== undefined))
|
|
489
|
+
no('SQL_SHAPE', `a sign over a number is that number: write ${op === '-' ? 'the negative constant' : 'the constant'}`, at);
|
|
490
|
+
if (ctx.p.name === 'base')
|
|
491
|
+
bareLiteralCompare(n, ctx, at); // PostgreSQL casts the literal to the column's type
|
|
492
|
+
jsonCompare(n, ctx, at);
|
|
493
|
+
if (n.kind === 'AEXPR_OP' && !ctx.p.ops.has(op))
|
|
494
|
+
no('SQL_UNSUPPORTED', `operator ${op} is refused`, at);
|
|
495
|
+
if (n.kind === 'AEXPR_IN' && !['=', '<>'].includes(op))
|
|
496
|
+
no('SQL_UNSUPPORTED', 'a bad IN', at);
|
|
497
|
+
if (n.kind === 'AEXPR_LIKE' && !['~~', '!~~'].includes(op))
|
|
498
|
+
no('SQL_UNSUPPORTED', 'ILIKE and regular expressions are refused', at, /\bILIKE\b/i);
|
|
499
|
+
if (n.kind === 'AEXPR_ILIKE' && !['~~*', '!~~*'].includes(op))
|
|
500
|
+
no('SQL_UNSUPPORTED', 'a bad ILIKE', at);
|
|
501
|
+
const esc = (x) => !!x?.FuncCall && fname(x.FuncCall) === 'like_escape';
|
|
502
|
+
if (esc(n.lexpr) || (esc(n.rexpr) && n.kind !== 'AEXPR_LIKE'))
|
|
503
|
+
no('SQL_FUNCTION', 'like_escape is only the ESCAPE of a LIKE', at);
|
|
504
|
+
},
|
|
505
|
+
TypeCast: (n, ctx, _p, at) => {
|
|
506
|
+
const t = castType(n.typeName);
|
|
507
|
+
if (!ctx.p.casts.has(t))
|
|
508
|
+
no('SQL_TYPE', `CAST to ${t} is refused`, at);
|
|
509
|
+
const lit = n.arg?.A_Const;
|
|
510
|
+
// the literal-only rules exist because SQLite truncates and stores time and decimals as integers; PostgreSQL casts any value
|
|
511
|
+
const base = ctx.p.name === 'base';
|
|
512
|
+
if (base && (t === 'int4' || t === 'int8') && !(lit?.ival || /^\s*-?\d+\s*$/.test(lit?.sval?.sval ?? 'x')))
|
|
513
|
+
no('SQL_TYPE', `CAST to ${t} takes an integer literal: SQLite truncates toward zero where PostgreSQL rounds. Write round(x)`, at);
|
|
514
|
+
// a type modifier is numeric's precision and scale, or one interval field (hour, minute, second) that truncates nothing; D1
|
|
515
|
+
// encodes nothing else (timestamptz(0) rounds on PostgreSQL, interval '90 minutes' hour truncates to an hour there)
|
|
516
|
+
// (intervalMicros reads a bare number in the field's unit and refuses any other field; one unit of the field divides the value)
|
|
517
|
+
const mods = n.typeName.typmods ?? [];
|
|
518
|
+
const typmod = mods[0]?.A_Const?.ival?.ival;
|
|
519
|
+
if (mods.length && t !== 'numeric' && !(t === 'interval' && mods.length === 1 && intervalMicros(lit?.sval?.sval ?? 'x', typmod) % intervalMicros('1', typmod) === 0))
|
|
520
|
+
no('SQL_TYPE', `CAST to ${t} takes no type modifier here, or one that truncates nothing`, at);
|
|
521
|
+
if (t === 'interval') {
|
|
522
|
+
if (!lit?.sval)
|
|
523
|
+
no('SQL_TYPE', 'an interval is a literal such as interval \'36 hours\'', at);
|
|
524
|
+
intervalMicros(lit.sval.sval, n.typeName.typmods?.[0]?.A_Const?.ival?.ival); // throws SQL_TYPE for calendar units
|
|
525
|
+
}
|
|
526
|
+
if (base && (t === 'timestamptz' || t === 'date') && !lit?.sval)
|
|
527
|
+
no('SQL_TYPE', `CAST to ${t} takes a literal (the compiler folds it to its integer encoding)`, at);
|
|
528
|
+
if (t === 'numeric') {
|
|
529
|
+
const [p, s] = (n.typeName.typmods ?? []).map((m) => m.A_Const?.ival?.ival ?? 0);
|
|
530
|
+
if (p === undefined)
|
|
531
|
+
no('SQL_TYPE', 'numeric needs (precision, scale)', at);
|
|
532
|
+
parseNumeric(`numeric(${p}, ${s})`);
|
|
533
|
+
if (base && !lit)
|
|
534
|
+
no('SQL_TYPE', 'CAST to numeric takes a literal: numeric columns are integer counts of the smallest unit', at);
|
|
535
|
+
}
|
|
536
|
+
},
|
|
537
|
+
ResTarget: (n, ctx, _p, at) => {
|
|
538
|
+
if (ctx.p.name === 'base' && n.name && SQLITE_ONLY_KEYWORDS.has(n.name))
|
|
539
|
+
no('SQL_UNSUPPORTED', `${n.name} is an SQLite keyword: the printer would not quote it`, at);
|
|
540
|
+
},
|
|
541
|
+
SubLink: (n, _c, _p, at) => {
|
|
542
|
+
if (n.subLinkType === 'ANY_SUBLINK' && n.operName && sv(n.operName) !== '=')
|
|
543
|
+
no('SQL_UNSUPPORTED', 'only IN (subquery)', at);
|
|
544
|
+
},
|
|
545
|
+
JoinExpr: (n, _c, _p, at) => {
|
|
546
|
+
if (!n.quals)
|
|
547
|
+
no('SQL_SHAPE', 'a JOIN needs ON', at, /\bCROSS\s+JOIN\b|\bJOIN\b/i);
|
|
548
|
+
},
|
|
549
|
+
RangeFunction: (n, _c, _p, at) => {
|
|
550
|
+
const fs = n.functions;
|
|
551
|
+
if (fs.length !== 1 || fs[0]?.List?.items?.length !== 2 || sv(fs[0].List.items[0].FuncCall?.funcname ?? []) !== 'json_each')
|
|
552
|
+
no('SQL_FUNCTION', 'only json_each() is allowed in FROM', at);
|
|
553
|
+
if (fs[0].List.items[0].FuncCall.args?.length !== 1)
|
|
554
|
+
no('SQL_FUNCTION', 'json_each takes one argument', at);
|
|
555
|
+
},
|
|
556
|
+
RangeSubselect: (n, _c, _p, at) => {
|
|
557
|
+
if (!n.alias)
|
|
558
|
+
no('SQL_SHAPE', 'a subquery in FROM needs an alias', at);
|
|
559
|
+
},
|
|
560
|
+
CommonTableExpr: (n, _c, _p, at) => {
|
|
561
|
+
if (!n.ctequery?.SelectStmt)
|
|
562
|
+
no('SQL_SHAPE', 'a CTE body is a SELECT: a write inside WITH is refused', at);
|
|
563
|
+
// the printer writes a CTE's name and its column names unquoted: each is a plain lower-case identifier
|
|
564
|
+
for (const name of [n.ctename, ...(n.aliascolnames ?? []).map((c) => c?.String?.sval)])
|
|
565
|
+
if (typeof name !== 'string' || !/^[a-z_][a-z0-9_]*$/.test(name))
|
|
566
|
+
no('SQL_SHAPE', `a CTE name is lower case, a plain identifier: ${JSON.stringify(name)}`, at);
|
|
567
|
+
},
|
|
568
|
+
BoolExpr: (n, _c, _p, at) => {
|
|
569
|
+
const k = (n.args ?? []).length;
|
|
570
|
+
if (n.boolop === 'NOT_EXPR' ? k !== 1 : k < 1)
|
|
571
|
+
no('SQL_SHAPE', `a malformed ${n.boolop}`, at);
|
|
572
|
+
},
|
|
573
|
+
WindowDef: (n, _c, _p, at) => {
|
|
574
|
+
if (n.frameOptions & FRAME_REFUSED)
|
|
575
|
+
no('SQL_UNSUPPORTED', 'GROUPS frames and EXCLUDE are refused', at, /\b(GROUPS|EXCLUDE)\b/i);
|
|
576
|
+
// an offset is a literal: rows as an integer, a RANGE over time as an interval literal
|
|
577
|
+
for (const o of [n.startOffset, n.endOffset])
|
|
578
|
+
if (o && !(o.A_Const?.ival !== undefined || (o.TypeCast?.arg?.A_Const?.sval && castType(o.TypeCast.typeName) === 'interval')))
|
|
579
|
+
no('SQL_SHAPE', 'a frame offset is a literal: an integer, or an interval such as interval \'6 days\'', at);
|
|
580
|
+
},
|
|
581
|
+
SelectStmt: (n, ctx, path, at) => {
|
|
582
|
+
const reference = ctx.p.name === 'reference';
|
|
583
|
+
// Core pages and orders a View's own SELECT (ADR-0037 decision 2), so what reshapes rows lives in a CTE or a subquery
|
|
584
|
+
const top = ctx.kind === 'view' && path.length === 1;
|
|
585
|
+
const distinctOn = !!n.distinctClause && (n.distinctClause.length !== 1 || Object.keys(n.distinctClause[0]).length > 0);
|
|
586
|
+
if (n.op && n.op !== 'SETOP_NONE' && top)
|
|
587
|
+
no('SQL_SHAPE', 'UNION, INTERSECT and EXCEPT go inside a WITH or a subquery: Core pages the View\'s own SELECT', at, /\b(UNION|INTERSECT|EXCEPT)\b/i);
|
|
588
|
+
if (n.limitCount && !n.sortClause)
|
|
589
|
+
no('SQL_SHAPE', 'LIMIT needs an ORDER BY', firstLoc(n.limitCount) ?? at);
|
|
590
|
+
if (distinctOn && (!reference || top))
|
|
591
|
+
no(reference ? 'SQL_SHAPE' : 'SQL_UNSUPPORTED', reference ? 'DISTINCT ON goes inside a WITH or a subquery: Core pages the View\'s own SELECT' : 'DISTINCT ON is refused', at, /\bDISTINCT\s+ON\b/i);
|
|
592
|
+
if (n.distinctClause && !distinctOn && n.sortClause)
|
|
593
|
+
no('SQL_SHAPE', 'DISTINCT with ORDER BY is refused: the appended id key would change what is distinct', at);
|
|
594
|
+
if (n.valuesLists && (path.at(-2) !== 'InsertStmt' || n.valuesLists.length !== 1))
|
|
595
|
+
no('SQL_SHAPE', 'VALUES is one row, in INSERT only', firstLoc(n.valuesLists) ?? at);
|
|
596
|
+
if ((n.fromClause ?? []).slice(1).some((f) => !f.RangeFunction && !(reference && f.RangeSubselect?.lateral)))
|
|
597
|
+
no('SQL_SHAPE', reference ? 'a comma join is refused (except json_each and LATERAL)' : 'a comma join is refused (except json_each)', at);
|
|
598
|
+
// mantle.near()/mantle.distance(): a query ordered by mantle.distance() needs a LIMIT of at most MAX_NEAR_K
|
|
599
|
+
const byDistance = JSON.stringify(n.sortClause ?? []).includes('"distance"');
|
|
600
|
+
if (byDistance) {
|
|
601
|
+
const k = n.limitCount?.A_Const?.ival?.ival;
|
|
602
|
+
if (k === undefined || k > MAX_NEAR_K)
|
|
603
|
+
no('SQL_SHAPE', `a query ordered by mantle.distance() needs a literal LIMIT of at most ${MAX_NEAR_K}`, firstLoc(n.sortClause) ?? at);
|
|
604
|
+
}
|
|
605
|
+
},
|
|
606
|
+
UpdateStmt: (n, ctx) => writeList(n.targetList, ctx, n.relation, false),
|
|
607
|
+
InsertStmt: (n, ctx, _p, at) => {
|
|
608
|
+
writeList(n.cols ?? no('SQL_WRITE', 'INSERT needs a column list', at), ctx, n.relation, true, n.selectStmt?.SelectStmt?.valuesLists?.[0]?.List?.items);
|
|
609
|
+
if (n.onConflictClause?.action === 'ONCONFLICT_UPDATE')
|
|
610
|
+
writeList(n.onConflictClause.targetList, ctx, n.relation, false);
|
|
611
|
+
},
|
|
612
|
+
};
|
|
613
|
+
/** Columns stored as integers that PostgreSQL compares with a string literal by casting it: the system timestamps and these types. */
|
|
614
|
+
const STORED_AS_NUMBER = new Set(['timestamptz', 'date', 'bool']);
|
|
615
|
+
const SYSTEM_TIMES = new Set(['created_at', 'updated_at']);
|
|
616
|
+
/** The type a column name has in every Schema that declares it, or undefined when none does or they disagree. */
|
|
617
|
+
function columnType(ctx, name) {
|
|
618
|
+
if (SYSTEM_TIMES.has(name))
|
|
619
|
+
return 'timestamptz';
|
|
620
|
+
return ctx.cols.types.get(name);
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* PostgreSQL reads `startsAt > '2020-01-01'` by casting the literal to the column's type; SQLite compares the stored integer with
|
|
624
|
+
* text and the condition is silently false. A bare string literal against a date-time, date or boolean column is refused.
|
|
625
|
+
*/
|
|
626
|
+
function bareLiteralCompare(n, ctx, at) {
|
|
627
|
+
const compares = n.kind === 'AEXPR_OP' ? ['=', '<>', '!=', '<', '>', '<=', '>='].includes(sv(n.name)) : ['AEXPR_IN', 'AEXPR_BETWEEN', 'AEXPR_NOT_BETWEEN', 'AEXPR_DISTINCT', 'AEXPR_NOT_DISTINCT'].includes(n.kind);
|
|
628
|
+
if (!compares)
|
|
629
|
+
return;
|
|
630
|
+
const typeOf = (x) => { const f = x?.ColumnRef?.fields; const name = f?.at(-1)?.String?.sval; return name && !(f.length === 2 && f[0].String?.sval === 'input') ? columnType(ctx, String(name).toLowerCase()) : undefined; };
|
|
631
|
+
const literals = (x) => (x?.List ? x.List.items.flatMap(literals) : x?.A_Const?.sval ? [x.A_Const.sval.sval] : []);
|
|
632
|
+
for (const [colSide, other] of [[n.lexpr, n.rexpr], [n.rexpr, n.lexpr]]) {
|
|
633
|
+
const type = typeOf(colSide);
|
|
634
|
+
if (!type || !STORED_AS_NUMBER.has(type))
|
|
635
|
+
continue;
|
|
636
|
+
const text = literals(other)[0];
|
|
637
|
+
if (text !== undefined)
|
|
638
|
+
no('SQL_TYPE', `'${text}' is text and the column is ${type}, which is stored as a number: ${type === 'bool' ? 'write true or false' : `write CAST('${text}' AS ${type})`}, or bind it as an input`, at);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* A json field compares as its stored text on SQLite and as jsonb on PostgreSQL (no jsonb < integer): either way not as the value
|
|
643
|
+
* the author meant, so a comparison of one is refused on every dialect. The field is the statement's own Schema column: named
|
|
644
|
+
* through its alias, or bare when exactly one of its Schema relations declares it.
|
|
645
|
+
*/
|
|
646
|
+
function jsonCompare(n, ctx, at) {
|
|
647
|
+
const compares = n.kind === 'AEXPR_OP' ? ['=', '<>', '!=', '<', '>', '<=', '>='].includes(sv(n.name)) : ['AEXPR_IN', 'AEXPR_BETWEEN', 'AEXPR_NOT_BETWEEN', 'AEXPR_DISTINCT', 'AEXPR_NOT_DISTINCT'].includes(n.kind);
|
|
648
|
+
const rels = ctx.rels?.at(-1);
|
|
649
|
+
if (!compares || !rels)
|
|
650
|
+
return;
|
|
651
|
+
for (const side of [n.lexpr, n.rexpr]) {
|
|
652
|
+
const f = side?.ColumnRef?.fields;
|
|
653
|
+
if (!f || f.length > 2 || !f.every((x) => x.String))
|
|
654
|
+
continue;
|
|
655
|
+
const name = String(f.at(-1).String.sval).toLowerCase();
|
|
656
|
+
const schemas = f.length === 2 ? [rels.get(String(f[0].String.sval).toLowerCase())].filter((s) => !!s)
|
|
657
|
+
: [...new Set(rels.values())].filter((s) => Object.hasOwn(ctx.schemas[s]?.fields ?? {}, name));
|
|
658
|
+
if (schemas.length === 1 && ctx.schemas[schemas[0]]?.fields[name] === 'json')
|
|
659
|
+
no('SQL_TYPE', `${f.at(-1).String.sval} is json: compare a value read with ->> (and CAST), or declare the field with one scalar type`, at);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
/** A write may not name the scope field or a system column; `id` is never writable on update, and on a scoped Schema never on insert. */
|
|
663
|
+
function writeList(list, ctx, rel, insert, values) {
|
|
664
|
+
const s = ctx.schemas[rel.relname.toLowerCase()];
|
|
665
|
+
for (const [i, { ResTarget: r }] of list.entries()) {
|
|
666
|
+
const at = firstLoc(r) ?? firstLoc(rel);
|
|
667
|
+
const name = String(r.name).toLowerCase();
|
|
668
|
+
const scopedId = insert && name === 'id' && s?.scope;
|
|
669
|
+
if (name === s?.scope?.toLowerCase() || SYSTEM.has(name) || (!insert && name === 'id') || scopedId)
|
|
670
|
+
no('SQL_WRITE', `${r.name} is filled by Mantle and cannot be written${scopedId ? ' (a scoped Schema generates its ids)' : ''}`, at);
|
|
671
|
+
const cols = Object.entries(s?.fields ?? {}).flatMap(([f, t]) => (t === 'geo' ? [`${f}_lat`, `${f}_lng`] : [f]));
|
|
672
|
+
if (name !== 'id' && !cols.includes(name))
|
|
673
|
+
no('SQL_WRITE', `${rel.relname} has no field ${r.name}`, at);
|
|
674
|
+
// a bare text literal in a column stored as a number: SQLite's STRICT table would fail it at run time, so refuse it here
|
|
675
|
+
const type = s?.fields[name];
|
|
676
|
+
const literal = (insert ? values?.[i] : r.val)?.A_Const?.sval?.sval;
|
|
677
|
+
if (ctx.p.name === 'base' && literal !== undefined && type && !['text', 'json'].includes(type) && !/^-?\d+(\.\d+)?$/.test(literal))
|
|
678
|
+
no('SQL_TYPE', `'${literal}' is text and ${r.name} is ${type}: write CAST('${literal}' AS ${type === 'integer' ? 'int8' : type === 'real' ? 'float8' : type}), or bind it as an input`, at);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
/** A `SqlRefusal` as a `SqlDiagnostic`, without a source position (the runtime has no source text). */
|
|
682
|
+
function refusalToDiagnostic(e) {
|
|
683
|
+
return { code: e.code, message: e.message };
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* The runtime's check of a plan's IR: the grammar version, then the exact allowlist.
|
|
687
|
+
* Returns no diagnostics when the plan is acceptable, otherwise the first refusal.
|
|
688
|
+
* Also the check for IR built by handler code. Never throws for bad input.
|
|
689
|
+
*/
|
|
690
|
+
export function validateIr(plan, ctx, profile = BASE_PROFILE) {
|
|
691
|
+
try {
|
|
692
|
+
if (plan?.grammar !== PG_GRAMMAR)
|
|
693
|
+
no("SQL_UNSUPPORTED", `plan was compiled with PostgreSQL grammar ${plan?.grammar}, this runtime reads ${PG_GRAMMAR}`);
|
|
694
|
+
validateProgram(plan.stmts, ctx, [], profile);
|
|
695
|
+
return [];
|
|
696
|
+
}
|
|
697
|
+
catch (e) {
|
|
698
|
+
if (e instanceof SqlRefusal)
|
|
699
|
+
return [refusalToDiagnostic(e)];
|
|
700
|
+
// Hand-built IR can be malformed in ways the allowlist does not anticipate (null, wrong types).
|
|
701
|
+
// Refusing is the only safe answer.
|
|
702
|
+
return [{ code: "SQL_UNSUPPORTED", message: `malformed IR: ${e instanceof Error ? e.message : String(e)}` }];
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
//# sourceMappingURL=allowlist.js.map
|