@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,40 @@
|
|
|
1
|
+
# ADR-0030: Store — one persistence object over one relational query AST
|
|
2
|
+
|
|
3
|
+
**Status:** Accepted (#1151). Runtime slices shipped in 0.1.5 alphas; the grammar slice, the storage port and the removal of the parallel paths are decided for 0.2.0 by [ADR-0032](0032-store-centric-core-and-service-contract.md). Manifest authoring is amended by [ADR-0034](0034-store-is-authored-as-sql.md).
|
|
4
|
+
|
|
5
|
+
**Date:** 2026-09-26
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
Entry persistence grew parallel paths: builtin-op use cases over `EntryRepository`, `ctx.writeAtomically` over `AtomicEntryWriter`, declarative Views with their own Filter AST, typed-query bindings, `runtime.entries` readers and the TTL sweeper. Each re-implements filters, OCC and SQL for every adapter, and the public vocabulary stops at id-addressed single rows. A consumer deleting one workout (swolhalla/swolhalla-mantle#15) expands it to two statements per row — about 51 queries for a small workout and 615 for a large one — or bypasses Mantle with raw SQL against Mantle-owned tables.
|
|
10
|
+
|
|
11
|
+
## Decision
|
|
12
|
+
|
|
13
|
+
**Store** is the single persistence object: `ctx.store` inside Procedures (bound to the caller) and `runtime.store` for trusted host code.
|
|
14
|
+
|
|
15
|
+
- Queries are a closed **relational AST with a JSON shape**: SQL vocabulary and semantics (`select`/`from`/`where`/`orderBy`, NULL, subqueries), never a SQL string. Adapters compile it; values are always bound and identifiers come only from the linked Schema, so row scope and OCC can be injected structurally later.
|
|
16
|
+
- Where grammar: `{ column: value }` is equality and sibling keys AND; `{ column: { eq, ne, gt, gte, lt, lte, like, in, notIn, isNull } }`; `and`/`or`/`not`; `in`/`notIn` accept a `{ select, from, where }` subquery. Columns are scalar Schema fields plus the native `id`, `status`, `version`, `createdAt`, `updatedAt`, `authorId`. `like` requires a string column, uses SQLite patterns and `\` as its escape character. `ne` follows SQL and excludes NULL.
|
|
17
|
+
- Rows are flat (native columns next to Schema fields; the parser forbids clashes). Pagination is keyset `limit` (1–500) / `cursor` over one scalar `orderBy` column with `id` as tie-breaker. Declared-required fields can still be NULL in storage (publishing drafts validate partially; added columns start NULL), so NULLs sort last in either direction and the cursor carries a NULL value; no row falls between pages. A cursor is bound to its Schema, column and direction. TTL-expired rows stay hidden everywhere, including subqueries (ADR-0028).
|
|
18
|
+
- `select` returns every lifecycle status: it is a trusted-handler read, not a public View. A Procedure exposed to callers must filter `status` itself (ADR-0025 applies to public Views only). `ne` and `not` follow SQL three-valued logic and exclude NULL; subqueries exclude NULL values so `notIn` behaves like its array form (a NULL left-hand value still matches `notIn` only when the list is empty, as in SQL). A `where` nests at most 16 levels and counts at most 256 objects, comparisons and subqueries in total. A Schema field named `and`, `or` or `not` cannot be filtered.
|
|
19
|
+
- Storage support is an optional `StoreReader` capability; absent support is `RESOURCE_UNAVAILABLE`. Invalid queries are `INPUT_VALIDATION_FAILED`. A statement binds at most 100 values (D1's limit) on every adapter.
|
|
20
|
+
- `store.view(name, options)` runs a named View with the caller's context; `store.id()` returns an entry id.
|
|
21
|
+
- Runtime validates and snapshots Store queries before calling a storage adapter, including nested set-delete filters. Storage adapters retain dialect-specific limits and SQL compilation. `sweepExpired` is host maintenance and rejects every caller-bound Procedure Store, including an anonymous caller.
|
|
22
|
+
- A Schema may declare one identity scope as `scope: { ownerId: "$ctx.user.id" }`, where the named field is a required scalar string and starts an index. Caller-bound Store reads and deletes structurally AND this predicate into every touched Schema, including subqueries. Insert fills the field and rejects a conflicting value; id-based update/delete check the row owner before hooks. A missing caller identity fails closed. `expect` counts affected rows after scope. `runtime.store` remains trusted and unscoped. Until declarative Views use Store IR, a declarative View over a scoped Schema must carry the same top-level identity predicate and auth gate. Native SQL Views remain a trusted escape hatch.
|
|
23
|
+
|
|
24
|
+
Delivery order (each a reviewed PR): (1) `select`, `view`, `id` — this ADR's first slice; (2) `store.write(ops)` with `insert`/`update`/`delete`, `lock` and `expect`, set-based deletes over live rows only, rejected on Schemas with per-row delete hooks and on publishing Schemas (published entries are protected), replacing `ctx.writeAtomically`; (3) manifest grammar (handler `ref | store`, View `select`, Schema `scope`) and removal of the parallel read paths, under grammar-revise.
|
|
25
|
+
|
|
26
|
+
## Consequences
|
|
27
|
+
|
|
28
|
+
- One compiler per dialect replaces per-path SQL generators as later slices land; the SQLite family (D1, Bun, libSQL) implements it first, IndexedDB fails closed until it opts in.
|
|
29
|
+
- Handlers get multi-Schema reads without raw SQL; Web and Admin keep `EntryReader` until the grammar slice.
|
|
30
|
+
- Breaking changes are limited to 0.1.5-alpha APIs until the grammar slice, which ships with a `mantle-update` codemod.
|
|
31
|
+
|
|
32
|
+
## Alternatives
|
|
33
|
+
|
|
34
|
+
MongoDB-flavoured operators (`deleteMany`, `$in`) were considered first and rejected: every backend is relational, document semantics (nested paths, missing versus null) mismatch SQLite, and SQL is the vocabulary agents know best. SQL strings cannot carry injected scope and locks without a parser. Extending `writeAtomically` alone would add a fifth path.
|
|
35
|
+
|
|
36
|
+
> **Amendment (ADR-0034):** Manifests now carry SQL, and the CLI's parser lowers it to this AST before it reaches any Worker. The Store API still takes no SQL string. The AST grows to what the SQL dialect needs (expressions, `CASE`, joins, aggregates, window functions, `RETURNING`, `ON CONFLICT`), and native SQL Views are no longer an escape hatch.
|
|
37
|
+
|
|
38
|
+
## New folder rationale
|
|
39
|
+
|
|
40
|
+
`usecase/store/` holds the Store facade that binds storage capability, the View executor and the id generator to one caller context; it has no storage or platform imports.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# ADR 0031: Cloud supplies the host Core pin
|
|
2
|
+
|
|
3
|
+
Status: Accepted for mantle-host protocol 2.
|
|
4
|
+
|
|
5
|
+
The backend artifact includes `sdkVersion` and `sdkRevision` in its hashed
|
|
6
|
+
bytes. The old host bundled a fixed Core revision. Cloud can run the previous
|
|
7
|
+
Core release, so a host built from current Core cannot assume its own revision
|
|
8
|
+
is the revision Cloud accepts. Asking only the backend upload grant is too
|
|
9
|
+
late: that grant requires the artifact hash first.
|
|
10
|
+
|
|
11
|
+
`save` now preflights the project and emits `cloud-host-contract` with the
|
|
12
|
+
project ID. Control returns `{ projectId, core: { version, revision }, protocol }`
|
|
13
|
+
from the deployed Cloud configuration. The script validates the project,
|
|
14
|
+
40-hex revision and protocol minimum before packing. It persists the pin and
|
|
15
|
+
backend hash together. Upload grants, HTTP responses and the frontend kit must
|
|
16
|
+
echo the same pin; a difference fails before another upload and requires a new
|
|
17
|
+
save. No static Core pin is shipped in the plugin. The script contacts only
|
|
18
|
+
the granted Cloud HTTP endpoints; the contract comes through the Cloud MCP
|
|
19
|
+
tool, like upload grants.
|
|
20
|
+
|
|
21
|
+
Protocol 2 changes the MCP save sequence and requires both Core version and
|
|
22
|
+
revision in `kit.json`. Control must provide the contract tool and pin echoes
|
|
23
|
+
before this host script is offered to users. A future change to the MCP
|
|
24
|
+
sequence, artifact bytes or validation meaning requires a protocol bump. A
|
|
25
|
+
new Core release using these same rules changes only the Cloud contract pin.
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
# ADR-0032: Store-centric Core, an application-owned service, and caller identity
|
|
2
|
+
|
|
3
|
+
**Status:** Accepted for 0.2.0 (#1188). Amends ADR-0014, ADR-0026, ADR-0027 and ADR-0030; storage evolution is decided separately in [ADR-0033](0033-storage-converges-to-the-plan.md). Decisions 1–5, 10 and 13 are amended by [ADR-0034](0034-store-is-authored-as-sql.md): manifests carry SQL, which the CLI compiles to the IR. Decisions 6 and 12 are amended by [ADR-0035](0035-sql-dialects.md).
|
|
4
|
+
|
|
5
|
+
**Date:** 2026-09-27
|
|
6
|
+
|
|
7
|
+
**Related:** #1151 (Store), #1152 (identity), #1156 (table namespace), #1150, #1189, ADR-0022, ADR-0023, ADR-0028, ADR-0031, aotter/mantle-home#201
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
`develop` (3b829e6) carries the first Store slices from ADR-0030, but six persistence paths still generate their own SQL: builtin ops (`EntryRepository`), `store.write` (`AtomicEntryWriter`), legacy Views (`SqliteViewCompiler`), select Views (`SqliteStoreQueryCompiler`), `runtime.entries` (`EntryReader`) and the TTL sweep (`sweepExpired`). Scope, TTL, OCC and hook rules are spread across them, and builtin ops, Admin/MCP CRUD, `EntryReader` and legacy Views ignore `Schema.spec.scope`.
|
|
12
|
+
|
|
13
|
+
The host boundary has the same problem in a different place:
|
|
14
|
+
|
|
15
|
+
- **Mantle owns the entry.** `createMantleWorker` owns the Worker and hands the application a restricted seam (`extend`, `getRuntime`, `MANTLE_RESERVED_PATH_PREFIXES`, `MantleExtensionApp`).
|
|
16
|
+
- **Mantle owns the user.** `0001-init` creates the twelve Better Auth tables on every SQLite database, even without `@aotter/mantle-auth`. `createMantleWorker` requires a full `MantleAuth`, `resolveCaller` calls `getUserRole`, and `mountMantleAdmin` depends on the Better Auth session shape. ChatGPT Sites fakes the Admin methods and hand-mounts Admin.
|
|
17
|
+
- **Cloudflare semantics sit in Core contracts.** ADR-0027 Triggers use Cloudflare's cron dialect and put a required `cloudflare` host in the plan; `HandlerContext.schedule` and `waitUntil` are documented as Cloudflare deliveries.
|
|
18
|
+
|
|
19
|
+
No 0.1.5 has been tagged, and the release is allowed to break grammar, so it ships as 0.2.0.
|
|
20
|
+
|
|
21
|
+
## Decision
|
|
22
|
+
|
|
23
|
+
Spec (the four atoms) compiles into a sealed `RuntimePlan`; Core executes it; everything else is built around Core.
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
application-owned service (MantleHandlers + one WinterTC fetch entry)
|
|
27
|
+
└─ Core: Trigger dispatch → View / Procedure → Store → StoreExecutor
|
|
28
|
+
└ ref → handlers (the only custom code)
|
|
29
|
+
createMantle(service, { storage }) → one fetch; the generated preset wires it into the host's entry
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 1. Store is the only path to Mantle-owned entry storage
|
|
33
|
+
|
|
34
|
+
Every entry read and write goes through `MantleStore` / `CallerStore` over the relational JSON IR of ADR-0030. Policies are **IR rewrites applied before storage**: caller scope (including subqueries), TTL visibility, published-only, and OCC (`lock` becomes a version predicate plus `expect: 1`). Storage implementations compile a dialect and apply atomic batches; nothing else.
|
|
35
|
+
|
|
36
|
+
- **Contract.** `select`, `view`, `write` and `id` on both types; `as(caller)` and `sweepExpired` on `MantleStore` only. `as` now takes a `Caller` (decision 7), not a `HandlerContext`.
|
|
37
|
+
- **Write ops** stay `insert | update | delete`, all or nothing. `StoreInsert` gains `onConflict?: "ignore" | { columns, update }` (#1151). `StoreUpdate` and `StoreDelete` both take any `where`, optional `lock` and optional `expect`.
|
|
38
|
+
- **Results.** A row op returns `{ id, version }`; a set op, or an insert ignored by `onConflict`, returns `{ affected }`. `StoreWriteResult` renames `deleted` to `affected`.
|
|
39
|
+
- **Errors** stay `DiagnosticError`: `INPUT_VALIDATION_FAILED`, `CONFLICT`, `RESOURCE_UNAVAILABLE`, `OUTCOME_UNKNOWN` (ADR-0023). `Diagnostic` gains `conflict?: { opIndex?: number; reason: "lock" | "expect" | "unique" }`. `opIndex` is best effort, because a D1 batch cannot report which statement failed.
|
|
40
|
+
- **Status changes** are `update` with `set: { status }`, validated by one domain service, `LifecycleStateMachine`, which owns drafts, publish, unpublish, archive and published protection. Its tests are ported from the `content-ops` suite before any legacy path is removed.
|
|
41
|
+
- **One cursor format.** Cursors are opaque, versioned and bound to `from`, the `orderBy` column and direction. The three formats in use today (`s:`, `st:`, `o:`) are removed.
|
|
42
|
+
- **Admin statistics** (`readCreationStatistics`) stay a narrow optional storage capability outside Store. Store does not grow aggregates for one Admin chart.
|
|
43
|
+
- **Translations.** Mantle Web resolves a locale with two Store selects (the base rows, then the translation rows for the requested and the site default locale) and merges them; the requested locale wins, then the default. Both reads are Store selects, so scope, TTL and published-only apply to each. `JoinedEntryReader` is removed and no read path grows around Store.
|
|
44
|
+
|
|
45
|
+
> **Amendment (ADR-0034):** `conflict.opIndex` is exact: count and guard checks inside the batch name their statement.
|
|
46
|
+
|
|
47
|
+
### 2. Row ops and set ops
|
|
48
|
+
|
|
49
|
+
A write op's `where` is classified **on the caller's `where`, before any policy rewrite**, so an injected scope predicate never changes the class.
|
|
50
|
+
|
|
51
|
+
- **Row op:** the top level of `where` pins `id` to one value, alone or ANDed with further conditions (`{ id, performedAt: { gte } }`). It affects at most one row, may carry `lock`, and fires per-row lifecycle hooks. A row op that matches nothing is re-read by id: a present row with another version is `CONFLICT` with reason `lock`; otherwise reason `expect`.
|
|
52
|
+
- **Set op:** any other `where`. It fires no hooks. `mantle validate` and Store reject it on a Schema with a per-row `before_*`/`after_*` Trigger for that operation and on a Schema whose published entries are protected.
|
|
53
|
+
- `Procedure.target` is inferred with the same rule: a program with exactly one row op whose `where` pins `id` to an input field gets that target; otherwise `target` is explicit, as today.
|
|
54
|
+
|
|
55
|
+
> **Amendment (ADR-0034):** Row and set ops are classified on the compiled statement, and the class decides only `target` inference and whether writing no row is `CONFLICT`. A set op calls after hooks with its rows; Schemas with a before hook for that operation, or with `publishing` lifecycle, still refuse it.
|
|
56
|
+
|
|
57
|
+
### 3. Lifecycle hooks and atomicity
|
|
58
|
+
|
|
59
|
+
- A lifecycle Trigger targets a Procedure whose handler is a `ref`. `mantle validate` rejects an inline Store program as a hook target.
|
|
60
|
+
- **`before_*` is a read-only check.** It receives a read-only `CallerStore` (as guard Procedures do today) and no `ctx.invoke`. It allows the mutation by returning and rejects it by throwing; it cannot rewrite the mutation in 0.2.0. A rejection or failure means nothing in the batch is applied: before hooks always fail closed. Hooks for a multi-op batch run in op order, and for one op in Trigger-name order, all before the batch applies. Each sees committed data only, never a sibling op. OCC at apply time still guards the race between the check and the commit. The contract forbids external mutations in a before hook; this limits what Mantle injects, not arbitrary user code.
|
|
61
|
+
- **`after_*` runs only after a successful commit.** A rollback emits nothing, a failure never changes the committed result, and a write the hook makes is a new `write` in a new transaction. The hook receives the mutation snapshot (the row and version at commit), not the latest row.
|
|
62
|
+
- **Delivery.** `LifecycleTriggerSource.errorPolicy` is removed: before hooks always fail closed, and an after hook cannot change a committed result. After hooks are best effort, as today: they run inline or through `waitUntil`, and `ctx.cause.id` is stable so a handler can deduplicate a replay. Reliable delivery (an outbox written in the same batch, at-least-once) is deferred until a consumer needs it; it is an additive Trigger key.
|
|
63
|
+
- **Retries.** External side effects sit outside Store atomicity. A retry after `OUTCOME_UNKNOWN` reconciles through client ids (`store.id()`) and versions: a replayed insert conflicts on its id, a replayed update on its lock.
|
|
64
|
+
- **Identity and depth.** Hooks run with the originating `Caller`; deferred deliveries rehydrate it from the event record. `MAX_INVOCATION_DEPTH = 8` counts the `cause` chain across hook chains and `ctx.invoke`; exceeding it fails with `INVOCATION_DEPTH_EXCEEDED`.
|
|
65
|
+
- An entitlement check for one action belongs in that Procedure's `requires.guard`. A before hook is for rules every path must obey, Admin, import and maintenance included.
|
|
66
|
+
- The Store hands mutations to a `LifecycleDispatcher` port (`before(mutations)`, `after(events)`) that the Trigger layer implements; Store never references Procedures. It replaces `LifecycleHookingEntryRepository`, `RunLifecycleHooksUseCase` and `DeferredHookDispatcher`.
|
|
67
|
+
|
|
68
|
+
> **Amendment (ADR-0034):** An after hook is called once per statement and Trigger with `ctx.cause.rows`. Before hooks keep row ops and OCC.
|
|
69
|
+
|
|
70
|
+
### 4. Storage port
|
|
71
|
+
|
|
72
|
+
`StoreReader` grows into **`StoreExecutor`**: `maxBindings`, `select(query)` and `apply(batch)` over validated IR only. Every executor implements the whole IR and applies a batch atomically, so there are no capability flags; the one Core validator reads `maxBindings` (100 on D1) and removes the duplicated `NATIVE_TYPES`, depth and node checks. `ViewQueryExecutor` shrinks to native SQL Views, the remaining escape hatch.
|
|
73
|
+
|
|
74
|
+
- `SqliteStoreExecutor` serves D1, Bun and libSQL, so libSQL gains writes.
|
|
75
|
+
- `MemoryStoreExecutor` is the reference implementation, the test fake (replacing `test/fakes/in-memory-store.ts`) and the base of the IndexedDB adapter, which keeps its own persistence and concurrency tests.
|
|
76
|
+
- `@aotter/mantle/testing` exports one conformance suite that runs against every executor.
|
|
77
|
+
|
|
78
|
+
The rewrite is built in `next/`, a private package beside the shipped ones (see `next/README.md`), and replaces them at the end.
|
|
79
|
+
|
|
80
|
+
> **Amendment (ADR-0034):** `SqliteStoreExecutor` is the only executor; `MemoryStoreExecutor` is removed, and so is `ViewQueryExecutor`, since every View compiles to IR. Conformance runs on local D1 inside workerd.
|
|
81
|
+
|
|
82
|
+
### 5. Grammar is the IR
|
|
83
|
+
|
|
84
|
+
`API_VERSION` becomes `cms.mantle.aotter.net/v2`, and `RUNTIME_PLAN_VERSION` becomes 6. A v1 manifest fails with the existing apiVersion diagnostic, whose suggestion names `mantle-update`. There is no legacy lowering layer.
|
|
85
|
+
|
|
86
|
+
- **Procedure handler** is `{ ref: <name> }` or `{ store: [<write ops>] }`. `kind`, `builtin`, `op`, `match` and `BUILTIN_OPS` are removed. Views read; Procedures write, so an inline program holds write ops only. Its output is `{ results }`, the `store.write` results in op order; `mantle validate` checks the declared `output` schema accepts that shape.
|
|
87
|
+
- **View** is `spec.select` or `spec.sql`. The top-level `from`/`filter`/`fields`/`orderBy`/`limit`, the Filter AST, `$param`, `{"$ctx.user": "id"}` and `VIEW_PARAMS_RESERVED` are removed. `spec.params` is renamed `spec.input`, matching the `$input` reference.
|
|
88
|
+
- **Value references** are one set everywhere: `$input.<path>`, `$ctx.user.id`, `$now` and `{ $literal: <value> }`.
|
|
89
|
+
- **Pagination.** REST, MCP and Admin page with `limit` and `cursor` only.
|
|
90
|
+
- Staff View `uiSchema.searchFields` and `filterFields` compile to `like` and `eq` conditions.
|
|
91
|
+
- A native SQL View may not target a scoped Schema (`VIEW_SQL_SCOPED_SCHEMA`); `VIEW_TTL_NATIVE_UNSAFE` stays.
|
|
92
|
+
- **Schedule Triggers** take a five-field POSIX cron in UTC (weekday 0 = Sunday). The plan no longer carries a required host. A service that wires schedules passes `schedules: true` to `createMantle`, and boot fails for any enabled schedule without it. `toCloudflareCron` in `@aotter/mantle/cloudflare` translates an expression for Wrangler.
|
|
93
|
+
- **Webhooks.** An HTTP Trigger does not receive the raw request body in 0.2.0. The service owns its HTTP entry (decision 6), so it verifies a signature there and calls `runtime.invokeProcedure`. A raw-body Trigger key is additive and can come later.
|
|
94
|
+
|
|
95
|
+
> **Amendment (ADR-0034):** The grammar is SQL and the plan is the IR. A View is `spec.sql`, one `SELECT`, and an inline Procedure is `handler: { sql }`; `spec.select`, `{ store }` and the `$`-prefixed value references are replaced by `input.<name>`, `auth.uid()`, `auth.role()` and `now()`. Every View gets scope and TTL injected, so `VIEW_SQL_SCOPED_SCHEMA` and `VIEW_TTL_NATIVE_UNSAFE` are removed.
|
|
96
|
+
|
|
97
|
+
### 6. The portable unit is an application-owned service
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
interface MantleService<Env = unknown> {
|
|
101
|
+
readonly handlers: MantleHandlers<Env>;
|
|
102
|
+
fetch(request: Request, env: Env, context: MantleServiceContext): Response | Promise<Response>;
|
|
103
|
+
}
|
|
104
|
+
interface MantleServiceContext {
|
|
105
|
+
readonly runtime: MantleRuntime;
|
|
106
|
+
waitUntil(promise: Promise<unknown>): void;
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
- `env` stays opaque. HTTP is the service's only Mantle ingress; schedules, deferred hooks, MCP and REST enter through Trigger atoms and surfaces.
|
|
111
|
+
- **One host-neutral entry, no per-host adapter.** Once the service is a WinterTC fetch, hosts differ only in the storage driver and in how their native entry is spelled. `@aotter/mantle` exports one function:
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
createMantle(service, { storage: (env) => MantleStorageAdapter, schedules?: boolean }): {
|
|
115
|
+
fetch(request: Request, env: Env, ctx?: { waitUntil(p: Promise<unknown>): void }): Promise<Response>;
|
|
116
|
+
invokeSchedule(cron: string, scheduledTime: number, env: Env, ctx?): Promise<void>;
|
|
117
|
+
runDeferredHook(message: unknown, env: Env, ctx?): Promise<void>;
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
It boots the runtime lazily from `storage(env)`, passes it to `service.fetch`, and turns a schedule or a deferred-hook message into a Trigger invocation. The host's entry is one to three lines of **generated, application-owned** preset code (`export default { fetch: m.fetch, scheduled: (e, env, ctx) => m.invokeSchedule(e.cron, e.scheduledTime, env, ctx) }` on Cloudflare, `Bun.serve({ fetch: m.fetch })` on Bun), so an application adds its own native handlers next to Mantle's and Core absorbs no platform event types.
|
|
122
|
+
- `createMantleWorker`, `createBunMantle` and `createVercelMantle` are removed; today `createBunMantle` and `createVercelMantle` are 62-line copies of the same lazy boot. The adapter subpaths keep only what is platform-specific: `@aotter/mantle/cloudflare` the D1 driver, the KV and R2 bindings and `toCloudflareCron`; `@aotter/mantle/bun` the `bun:sqlite` driver; `@aotter/mantle/vercel` the libSQL driver. ChatGPT Sites uses the Cloudflare preset with the custom identity.
|
|
123
|
+
- **`--host` is removed** (amends ADR-0026). Whenever the selection needs an entry (anything beyond `spec`, which stays host-free), `mantle generate` emits the Cloudflare preset: the entry above with `scheduled` wired, D1 storage, and the KV and R2 bindings. `host-minimal-worker` and `host-local-admin-otp` are its reference examples.
|
|
124
|
+
- **Other hosts are examples and drivers, not generator options.** ChatGPT Sites is the `host-chatgpt-sites` reference: an agent adapts the Cloudflare preset from it (Sites sign-in, R2 media, custom identity). `@aotter/mantle/bun` (`bun:sqlite`) and `@aotter/mantle/vercel` (libSQL) keep their drivers, marked experimental until a maintainer runs them end to end; they get no preset and no promised example. On any host, a capability the entry does not wire (schedules, for example) is refused at boot with a diagnostic, never skipped silently, and the author's coding agent bridges it.
|
|
125
|
+
- `BootMantleRuntimeArgs.supportsScheduledTriggers` becomes the `schedules` option above.
|
|
126
|
+
- Removed: `MANTLE_RESERVED_PATH_PREFIXES`, `MantleExtensionApp`, `extend`, `extend.mount` and `getRuntime`. `mantle generate` emits the standard composition as application-owned source: `src/service.ts`, `src/handlers.ts` and the host entry.
|
|
127
|
+
|
|
128
|
+
### 7. Handlers, invocation and capabilities
|
|
129
|
+
|
|
130
|
+
- The codegen `MantleHandlers` type lists exactly the plan's refs. `mantle validate` and boot check both directions: a plan ref without a handler is `HANDLER_NOT_REGISTERED` (existing), a handler the plan does not declare is `HANDLER_NOT_DECLARED`.
|
|
131
|
+
- A handler receives only `(input, ctx)`. The serializable part is an **`Invocation`**: `{ procedure, input, caller, cause }`. Every source (HTTP, MCP, schedule, lifecycle, internal) produces one, and `runtime.invokeProcedure(invocation)` runs auth → guard → input → handler → output for all of them. Only an `Invocation` ever crosses a wire.
|
|
132
|
+
- `HandlerContext` is `{ caller, cause, env, waitUntil, store, invoke }`. `user`, `staff`, `auth`, `event` and `schedule` are removed.
|
|
133
|
+
- **`InvocationCause`** is `{ kind: "http" | "mcp" | "schedule" | "lifecycle" | "internal", id, parent? }` plus kind-specific facts: `trigger`, `cron` and `scheduledTime` for schedules; `trigger`, `hook`, `schema` and the mutation snapshot for lifecycle. `id` is stable across retries.
|
|
134
|
+
- **`ctx.invoke(procedure, input)`** is the one Procedure-to-Procedure entry. It keeps the caller, chains `cause.parent`, and re-runs the target's auth and guard. There is no `getRuntime` closure.
|
|
135
|
+
|
|
136
|
+
### 8. Mantle never owns the user or the auth
|
|
137
|
+
|
|
138
|
+
A service keeps its existing users and auth. `@aotter/mantle/auth` is one optional producer of the caller identity.
|
|
139
|
+
|
|
140
|
+
- **`Caller`** (in `@aotter/mantle`) replaces `HandlerContext.user`, `.staff` and `.auth`:
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
type Caller =
|
|
144
|
+
| { readonly kind: "anonymous" }
|
|
145
|
+
| { readonly kind: "user"; readonly subject: string; readonly issuer?: string;
|
|
146
|
+
readonly role: StaffRole | null; readonly scopes: readonly string[];
|
|
147
|
+
readonly credential: CredentialKind; readonly credentialId: string | null; readonly clientId: string | null }
|
|
148
|
+
| { readonly kind: "system"; readonly reason: string };
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
- **Subject key.** `subject` is the application subject key: opaque, stable and unique within the service across every issuer. The resolver owns that uniqueness (mantle-auth uses its user row id; a resolver over several IdPs namespaces the id). `issuer` is informational. `$ctx.user.id`, `scope.ownerId` and `authorId` store the subject key, with no foreign key into any users table. Identity is never keyed by email.
|
|
152
|
+
- **One authentication boundary.** The service's entry resolves the caller once per request with a **`CallerResolver`**: `(request) => Promise<{ caller: Caller } | { invalid: true; challenge?: string }>`. An invalid credential is answered 401 before any surface runs and is never treated as anonymous. Only "no credential presented" is anonymous. Roles are resolved inside the resolver on every request.
|
|
153
|
+
- **Predicates.** `requires.auth` evaluates against the `Caller` only; the grammar is unchanged. `ctx.user` and `ctx.auth` require a user caller, `ctx.staff` a role in the list, `ctx.auth.scope` a scope. `STAFF_ROLES` is Admin's vocabulary: a custom resolver maps its own roles onto it or leaves `role` null and uses scopes and guards.
|
|
154
|
+
- **System caller.** `systemCaller(reason)` is exported for host code only; no wire can produce one. It satisfies no `requires.auth` predicate (so schedule targets still declare none, as ADR-0027) and bypasses caller scope and nothing else: lifecycle rules and TTL visibility apply, and expired rows are visible only to `sweepExpired`. Schedules and maintenance run as the system caller.
|
|
155
|
+
- **Policy origins.** Scope comes from the caller; published-only from the surface or atom (a public View over a publishing Schema); TTL and lifecycle always apply. `runtime.store` is host-level and unscoped, `runtime.store.as(caller)` binds per request, and `ctx.store` arrives bound.
|
|
156
|
+
- **Admin facets.** `@aotter/mantle/admin` defines `AdminIdentity`, whose members are all optional: `directory` (`getUser`, `listUsers`, `listMembers`), `roles` (`setUserRole`, `inviteUser`, `revokeInvite`, `sendStaffInvitation`) and `deleteUser`. Admin hides what is absent. Display names come from `directory`, never from a Store join.
|
|
157
|
+
- **mantle-auth** implements `CallerResolver`, `AdminIdentity` and the optional OAuth server routes. Account deletion is its `deleteUser` facet, so services stop running raw SQL against auth tables; a custom provider owns deletion for its own users. The MCP surface verifies nothing: it takes `authorizationServer` (a URL) for its 401 challenge and protected-resource metadata.
|
|
158
|
+
- **Core creates no auth tables.** The twelve Better Auth `CREATE`s and their indexes are removed from `0001-init`, which keeps its id, so migrated databases are unchanged. mantle-auth already migrates its own schema through Better Auth's `getMigrations`; that becomes the only source of auth DDL, and Core stops carrying a copy. mantle-auth refuses to start when an auth table name belongs to a Schema.
|
|
159
|
+
- **No identity** (anonymous callers only, no auth package, no auth tables) works and is tested. It is an explicit choice, never the default.
|
|
160
|
+
- **Existing services.** Mantle is added to a running service; it does not replace it. The service keeps its entry, users, auth, tables, routes and SSR. Mantle adds `_mantle_*` system tables, the Schemas it declares, and the product tables of the modules it selects. Data the service wants Mantle to manage (Admin, MCP, Store) moves into a Schema, one table at a time, by the data owner's choice. #1102's consumer skill carries that path.
|
|
161
|
+
|
|
162
|
+
### 9. Surfaces are Fetch functions
|
|
163
|
+
|
|
164
|
+
A surface is `(request: Request, caller: Caller) => Promise<Response>`, created with its base path:
|
|
165
|
+
|
|
166
|
+
| Surface | Factory | Package |
|
|
167
|
+
|---|---|---|
|
|
168
|
+
| MCP | `createMcpSurface(runtime, { basePath, authorizationServer? })` | `@aotter/mantle/mcp` |
|
|
169
|
+
| Admin | `createAdminSurface(runtime, { basePath, identity?, assets })` | `@aotter/mantle/admin` |
|
|
170
|
+
| REST Views | `createRestSurface(runtime, { basePath })` | `@aotter/mantle/web` |
|
|
171
|
+
| Web | `createWebSurface(runtime, { basePath, ... })` | `@aotter/mantle/web` |
|
|
172
|
+
|
|
173
|
+
Admin UI assets honour the base path. Hono may stay inside a package; it is no longer in any public signature. Mantle Web and Admin read through Store, and `EntryReader` is removed. A typed client for custom frontends is deferred; it is additive. The `@aotter/mantle/admin-ui/kit` re-export and `rowBindings` are removed (#1140).
|
|
174
|
+
|
|
175
|
+
### 10. Cloud verifies the plan; the user owns the entry
|
|
176
|
+
|
|
177
|
+
- `semanticFingerprint` becomes SHA-256; it now crosses a trust boundary, which its `ponytail:` comment named as the upgrade point. It is the "compiled plan fingerprint" aotter/mantle-home#201 records.
|
|
178
|
+
- `createMantleRuntime` accepts `expectedFingerprint` and refuses to boot on a mismatch (`PLAN_FINGERPRINT_MISMATCH`).
|
|
179
|
+
- `runtime.bootReport()` returns `MantleBootReport`: `{ fingerprint, coreVersion }`. Handler refs need no report because boot already refuses a mismatch; schedules are in the plan.
|
|
180
|
+
- Cloud's guarantee names two kinds of fact. **Platform-verified:** the Cloud-compiled plan, the pinned Core, storage matching the plan (ADR-0033) and the fingerprint handshake. **Service-reported:** the surfaces and mounts the service chose, which Cloud confirms only by probing them in smoke. A service that never boots the runtime has no manifest scope to guarantee, and smoke shows that.
|
|
181
|
+
- The plugin's Cloud helper script (decision 13) distinguishes a handlers-only artifact (today's closed module, host protocol 2 per ADR-0031) from a service-entry artifact, which is closed except for `@aotter/mantle*` externals that Cloud supplies at the pinned Core. The artifact field is `artifactKind: "handlers" | "service"`; service entries use host protocol 3. aotter/mantle-home reserves the field now and accepts service entries after Core 0.2.0, as its own issue.
|
|
182
|
+
|
|
183
|
+
> **Amendment (ADR-0034):** The guarantee is a Cloud-validated plan. The CLI compiles; Cloud validates the IR and never parses SQL; whether the IR matches its SQL source is service-reported. Host protocol 3 uploads the plan.
|
|
184
|
+
|
|
185
|
+
### 11. Table namespace
|
|
186
|
+
|
|
187
|
+
Tables that start with `_mantle_` are system tables: Mantle's internal state (the ledger, boot, Schema registry, schedule runs). They are Mantle's alone and the service does not touch them. Every other table Mantle or a Mantle module creates is a **product table** and keeps its name, just as Better Auth's tables keep theirs: `site_config`, `media_assets` and `pending_media_uploads` from Core, and Better Auth's own tables from mantle-auth. #1156 is decided by this rule: no rename. `sites_users` leaves `RESERVED_TABLES`, since ChatGPT Sites' identity is application-owned.
|
|
188
|
+
|
|
189
|
+
A product table that already exists without the ledger record of the Mantle migration that creates it is someone else's table: Core refuses to boot (`STORAGE_TABLE_NOT_OWNED`) instead of reading and writing it. mantle-auth applies the same rule to `user` and the other Better Auth tables.
|
|
190
|
+
|
|
191
|
+
### 12. `mantle generate` and identity
|
|
192
|
+
|
|
193
|
+
- With no `--features`, generate emits the full preset, including mantle-auth, which creates and owns its tables.
|
|
194
|
+
- `--features` stays a positive replacement list (ADR-0026). `mantle.config.json` and the CLI gain `identity: "mantle" | "custom" | "none"`, and identity is part of the positive selection: an explicit `--features` without `--identity` means `none`, and a selected feature that needs a caller identity (`admin`) then fails with the dependency diagnostic below. `custom` emits an application-owned `src/identity.ts` implementing `CallerResolver`.
|
|
195
|
+
- **Amends ADR-0026:** dependencies are no longer closed automatically. A missing dependency fails with `GENERATE_FEATURE_DEPENDENCY_MISSING`, and an omitted module is never re-added.
|
|
196
|
+
- Switching `identity` on a rerun is refused and never drops tables.
|
|
197
|
+
- Acceptance: the default works with users and auth whose tables mantle-auth owns; `custom` keeps the service's users and adds no auth tables; an explicit public service with `none` adds no auth package or tables; a valid positive selection generates, and a missing dependency is refused with a diagnostic.
|
|
198
|
+
|
|
199
|
+
### 13. Two npm packages and one plugin
|
|
200
|
+
|
|
201
|
+
Every Mantle package versions and releases together, so splitting by area buys nothing and costs a publish, a peer and a pin per package. 0.2.0 publishes two packages, split where the dependencies, the build and the audience actually differ: server and browser.
|
|
202
|
+
|
|
203
|
+
| Package | Contents |
|
|
204
|
+
|---|---|
|
|
205
|
+
| `@aotter/mantle` | Core at the root (Store, `createMantle`, `createMantleRuntime`); subpaths `/spec`, `/testing`, `/cloudflare`, `/bun`, `/vercel`, `/indexeddb`, `/auth`, `/admin`, `/mcp`, `/web`; the `mantle` CLI |
|
|
206
|
+
| `@aotter/mantle-ui` | `/controller`, `/kit` (including the sign-in card a service's own frontend can reuse), `/mcp-app`, and the prebuilt Admin SPA at `/admin` |
|
|
207
|
+
|
|
208
|
+
- Platform and heavy libraries (`better-auth`, `hono`, `@libsql/client`, the MCP SDK, React) are optional peers. A subpath that is not imported is never loaded, so Core still requires no Admin, Web, Auth or platform code; `check:boundaries` enforces this at module level instead of package level (amends ADR-0019's optional-package boundary).
|
|
209
|
+
- `@aotter/mantle` never imports `@aotter/mantle-ui`. The generated preset passes the Admin assets from `@aotter/mantle-ui/admin` to `createAdminSurface`.
|
|
210
|
+
- `@aotter/mantle-spec`, `-runtime`, `-cloudflare`, `-bun`, `-vercel`, `-indexeddb`, `-auth`, `-admin`, `-mcp` and `-web` fold into subpaths; `@aotter/mantle-admin-ui` folds into `@aotter/mantle-ui/admin`. `@aotter/mantle-host` was never published and is removed.
|
|
211
|
+
- **The plugin** (this repository's agent plugin) ships one `mantle` skill and helper scripts. Its configuration carries the Mantle Cloud MCP endpoint as an absolute URL, `https://cloud.mantle.tools/mcp`; aotter/mantle-home provides only that MCP. The helper scripts (`.mjs`) orchestrate the Cloud MCP sequence so an agent does less by hand, and keep the upload rules whose artifact bytes depend on the Core version (ADR-0031). The `mantle-host` name disappears; ADR-0031's protocol is the host protocol. Deploying anywhere else uses that host's own CLI, and the skill states that the user may always self-host: Mantle Cloud is one option, never a requirement.
|
|
212
|
+
|
|
213
|
+
> **Amendment (ADR-0034):** `/indexeddb` is removed, with no browser driver in 0.2.0. D1 test helpers live at `/cloudflare/testing`. The plugin's helper scripts compile with the project's installed `@aotter/mantle/spec` and bundle no parser.
|
|
214
|
+
|
|
215
|
+
## Conformance cases
|
|
216
|
+
|
|
217
|
+
The three contracts #1188 made ADR gates are accepted only with these cases, run against every `StoreExecutor` and the lifecycle layer:
|
|
218
|
+
|
|
219
|
+
1. **Atomicity and hooks.** A hook target with an inline program is rejected. A before hook has no write and no `invoke`; its rejection applies nothing in the batch. A concurrent write between a before check and the commit fails on OCC. A rollback emits no after event. An after-hook failure leaves the committed result. A replayed after event carries the same `ctx.cause.id`.
|
|
220
|
+
2. **Row-op classification.** `{ id }` and `{ id, performedAt: { gte } }` are row ops; `{ ownerId }` is a set op; a caller-scoped rewrite of `{ id }` stays a row op; `Procedure.target` inference agrees with Store in every case.
|
|
221
|
+
3. **Caller identity.** Two callers with the same upstream id from different issuers cannot read each other's scoped rows. An invalid credential is 401, never anonymous. The system caller bypasses scope but not TTL or lifecycle. A no-identity service boots with no auth package and no auth tables.
|
|
222
|
+
|
|
223
|
+
## Consequences
|
|
224
|
+
|
|
225
|
+
- **Net deletion** of about 3,200 lines: `DatabaseEntryRepository`, `LifecycleHookingEntryRepository`, `InvokeBuiltinUseCase`, `BuiltinProjector`, the content use cases and `AtomicEntryWriteUseCase`; the `EntryRepository`, `EntryReader`, `AtomicEntryWriter` and `ExpirySweeper` ports; the declarative part of `SqliteViewCompiler`; `IndexedDbEntryRepository` and `IndexedDbViewQueryExecutor`; `page`/`show`; the in-memory test fake; the twelve auth `CREATE`s in `0001-init`.
|
|
226
|
+
- **Breaking for every consumer:** grammar, the handler API, Worker composition and the pagination wire. The release ships the `mantle-update` codemod (builtin handlers to inline programs, Filter AST to `select`, `params` to `input`, `page`/`show` to `limit`/`cursor`, `extend` to the service preset) and old-to-new tables.
|
|
227
|
+
- **Main risk: lifecycle semantics.** They move into `LifecycleStateMachine` with their tests ported first.
|
|
228
|
+
- Cloud's promise changes from "Admin at /admin" to "the surfaces you declare work at the mounts you declare".
|
|
229
|
+
- A service with working users and auth keeps them. Fresh databases without mantle-auth get no auth tables; databases that have them are left alone.
|
|
230
|
+
|
|
231
|
+
## Alternatives
|
|
232
|
+
|
|
233
|
+
- **A legacy-lowering layer** that compiles builtin ops and the Filter AST into IR without a grammar change. Rejected: it keeps the code this release deletes.
|
|
234
|
+
- **A Worker-shaped artifact.** Rejected: it leaks the Worker name, the `fetch`/`scheduled`/`queue` export shape and `cloudflare:workers` into a host-agnostic contract.
|
|
235
|
+
- **One npm package per area** (today's fourteen). Rejected: they version together, so each split adds a publish, a peer and a pin without independent releases.
|
|
236
|
+
- **One adapter factory per host** (`createMantleWorker`, `createBunMantle`, `createVercelMantle`, each taking the service). Rejected: with a WinterTC service they would differ only in the storage driver and a few lines of entry spelling, which the driver package and the generated preset already carry.
|
|
237
|
+
- **A handler-host port with remote execution.** Deferred: the service already is the host. The serializable `Invocation` keeps remote execution possible.
|
|
238
|
+
- **Keeping a Mantle-owned Worker with extension seams.** Rejected: it limits custom frontends, SSR and webhooks, and duplicates Cloud-only assembly.
|
|
239
|
+
- **An identity port in Runtime, or auth tables in Core.** Rejected in #1152: Core only ever sees a resolved `Caller`.
|
|
240
|
+
- **Prefixing every Mantle-created table** (#1156). Rejected: the prefix marks system tables. Product tables follow the same rule as Better Auth's, and the ownership check in decision 11 covers the collision risk without a rename migration for live sessions and tokens.
|
|
241
|
+
- **Moving the Core auth DDL into mantle-auth as `mantle-auth:0001`** (#1152). Rejected: mantle-auth already derives it from Better Auth's own `getMigrations`, so a copy would be a second source of truth.
|
|
242
|
+
- **`errorPolicy: continue` on before hooks.** Removed: a before hook that fails open is an unchecked rule.
|
|
243
|
+
|
|
244
|
+
## How to apply
|
|
245
|
+
|
|
246
|
+
1. Land this ADR and ADR-0033, then build in this order: the three conformance contracts; Store and cross-executor conformance; cut every legacy path over and delete it; service, surfaces and identity; Cloud service-entry artifacts. Vercel and IndexedDB completion may trail.
|
|
247
|
+
2. **Keep proven host integrations as maintained examples, not Core contracts.** Core models no host's delivery workflow, but a working integration saves the next user the search. The reference examples of decision 6 are ported to the 0.2.0 contracts and rechecked when their host changes. For ChatGPT Sites that means Sites sign-in mapped to a `CallerResolver` and an `AdminIdentity` over `sites_users` (the 0.1.x `host-chatgpt-sites` example's `chatgpt-auth.ts`, whose `chatgpt:<sub>` id is already a namespaced subject key) and R2 behind the `MediaStorage` port (its `media.ts`). That example was removed with the 0.1.x packages; [Mantle on ChatGPT Sites](../handbook/cloudflare/chatgpt-sites.md) carries the 0.2.0 guide.
|
|
248
|
+
3. New code uses only the identifiers named here. A new public name needs an amendment to this ADR.
|
|
249
|
+
4. `mantle validate` diagnostics listed here are added with the grammar slice; the runtime codes with the Store and invocation slices.
|
|
250
|
+
|
|
251
|
+
## Amendments
|
|
252
|
+
|
|
253
|
+
- **2026-09-30, plan presentation metadata.** The sealed plan carries what Admin and the MCP surface show, as optional fields copied unchanged from the manifests: `PlanSchema.name` (the declared name; the map key is lower case), `title`, `description`, `uiSchema`, `localized`; `PlanView` and `PlanProcedure` gain `uiSchema` (and `title`, `description`). They change the fingerprint and nothing else: no Store, storage or policy behavior reads them. Without them `createAdminSurface` could not name a collection, and a tool would have no description.
|
|
254
|
+
- **2026-09-30, MCP tools come from Views and Procedures only.** `createMcpSurface(runtime, { basePath, surface, resourceMetadata?, apps? })` lists a tool for each Procedure bound by an `mcp` Trigger of its surface and each View of its surface; a Schema is never a tool. `store.view` checks the call's input against the View's input schema, as `invokeProcedure` does for a Procedure.
|
|
255
|
+
- **2026-09-30, site config and media.** Core's product tables are one optional runtime capability. `sqliteStorage(driver, { site })` and `d1Storage(db, { site })` take the service's `SiteDefaults`. With them, boot runs the canonical migrations and seeds or syncs `site_config`, the prepared storage returns it as `PreparedMantleStorage.site`, and the runtime carries it as `runtime.site: MantleSite`. Without them, the tables are not created and `runtime.site` is absent.
|
|
256
|
+
- `MantleSite` has `read()`, `updateSettings(SiteSettings)` and `media(storage: MediaStorage): MediaLibrary`.
|
|
257
|
+
- `MediaStorage` is the port with `createUpload`, `commitUpload` and `deleteObject`, which uses `MediaAsset`, `MediaVariant` and `MediaVariantRole`. `r2MediaStorage({ bucket, signer, endpoint, publicBase })` in `@aotter/mantle/cloudflare` implements it. `R2MediaStorageOptions` is its option type, and the host supplies the S3 signer.
|
|
258
|
+
- A `Migration` may name the product `tables` it creates. If one of those tables exists without the migration's ledger row, boot stops with `STORAGE_TABLE_NOT_OWNED`, as decision 11 says.
|
|
259
|
+
- The migration ids and DDL are 0.1.x's (`0001-init`, `0002-media-assets`, `0003-pending-media-uploads`). Ownership is proven by next's own `_mantle_migrations` ledger. Upgrading a 0.1.x database in place is a separate step that is not built yet: its legacy `_migrations` ledger is not backfilled, and its `_mantle_boot_state` has another shape.
|
|
260
|
+
- Hazard: a new migration id must not be purely numeric like `0004-…`, because 0.1.x ledgers already hold ids of that form.
|
|
261
|
+
- Uploads go to an upload-only key. Commit checks each object's type and size through the storage itself, then publishes it under a key that no upload URL reaches. A rejected group's objects are deleted.
|
|
262
|
+
- `createAdminSurface` gains `site?: { mcpEndpoints? }` and `media?: MediaStorage`. Without both `media` and `runtime.site`, every media route answers 501 `MEDIA_NOT_CONFIGURED`. Without `runtime.site`, `/site-settings` does not exist.
|
|
263
|
+
- `/site` drops the deprecated `mcpUrl` alias, and `mcpEndpoints` defaults to `null`, not `/mcp` and `/mcp/staff`. Both are deliberate: the service decides which surfaces it mounts.
|
|
264
|
+
- Per decision 11, `sites_users` leaves `RESERVED_TABLES`.
|
|
265
|
+
- **2026-09-30, staff MCP in Admin, the tool catalog, and the auth routes.**
|
|
266
|
+
- `mcpTools(plan, surface, locale?)` returns the `McpTool` list (name, title, description, inputSchema, outputSchema, annotations, `requires`, and the `kind` and `source` Procedure or View it comes from). `createMcpSurface` registers these, hides app-only tools from a client without UI support, and returns an `McpSurface`: the `Surface` plus the `tools` it registers for such a client, in its locale. It lives in `@aotter/mantle/spec` rather than `/mcp`, because `/admin` may not import `/mcp`: `check:boundaries` gives the MCP SDK one owner folder, and `/admin` reaches only `core` and `spec`.
|
|
267
|
+
- `createAdminSurface` gains `staffMcp?: McpSurface`, which the service builds with `createMcpSurface(runtime, { basePath: "{basePath}/api/mcp", surface: "staff" })`. Admin answers it at `{basePath}/api/mcp`, for any method, after Admin's own gate (session only, staff role). With it, `GET {basePath}/api/webmcp` returns `{ tools, routes }`, and bootstrap carries the same object as `webmcp` (null without it). `tools` is the projection of `staffMcp.tools` that `tools/list` returns, so locale and apps agree; nothing recomputes the catalog. `routes` maps a tool to `{basePath}/c/<target Schema>` (`entry: true`) when its Procedure declares `target`, and to `{basePath}/views/<name>` for a View. Any other tool has no route. An MCP client with a token uses a separate mount, `withCaller(resolver, createMcpSurface(runtime, { basePath: "/mcp/staff", surface: "staff", resourceMetadata }), { resourceMetadata })`, and that surface's own staff gate. `@better-auth/mcp` serves protected-resource metadata for the single `mcpResource` only, so `/mcp/staff` shares that audience and its `resourceMetadata` is the `/mcp` metadata URL (`/.well-known/oauth-protected-resource/mcp`), never a derived `/mcp/staff` one.
|
|
268
|
+
|
|
269
|
+
> **Amendment (Admin answers no MCP):** `staffMcp` and `{basePath}/api/mcp` are removed. `GET {basePath}/api/webmcp` and bootstrap's `webmcp` are always present and are `{ tools, routes }`, where `tools` is `mcpTools(plan, "staff")` in its default locale. The browser calls a tool with `POST {basePath}/api/webmcp/<tool>` and the input as the JSON body; Admin runs it as the staff surface does (the same input split, an `mcp` cause, the session caller) and answers `{ output }`. An `appOnly` tool is hidden from MCP clients only: in Admin the agent acts as the signed-in person. Staff MCP has one mount, `/mcp/staff`, which the preset mounts whenever it mounts `/mcp` and has an identity, and reports as `site.mcpEndpoints.staff`.
|
|
270
|
+
- `GET {basePath}/api/developer-console` is owner only. It returns `dataModel` (schemas, and non-internal Views with their IR as `sql: { grammar, stmts }`), `logic` (Procedures with `handler` as `{ ref }` or `{ sql }` IR, and triggers) and `operations`. `operations` holds `schedules` (`registration: "not-observed"`), `ttlPolicies` (`sweepObservation: "unavailable"`), `observationAvailability: "unavailable"` and empty `runs` and `latestRuns`: 0.2.0 has no run observation store. The 0.1 `graph` and `interfaces` projections are dropped; the console draws from the IR (ADR-0034).
|
|
271
|
+
- `GET {basePath}/api/collections/{name}/statistics` answers 404 for an unknown collection and 501 otherwise, with the wire code `STATISTICS_UNAVAILABLE` (not a `DiagnosticCode`), until a storage offers the decision 1 capability.
|
|
272
|
+
- `createAuthRoutes(auth: AuthRoutesAuth, options: AuthRoutesOptions)` (`{ resolver, connectedAppsPage? }`) in `@aotter/mantle/auth` is the service's auth entry. It returns `(request, context?) => Promise<Response | null>`, which is `null` for a path it does not own.
|
|
273
|
+
- It answers `GET {auth.basePath}/methods` itself.
|
|
274
|
+
- It hands the rest of `{auth.basePath}/*`, `/.well-known/oauth-authorization-server/*` and `/.well-known/oauth-protected-resource[/*]` to `auth.handler` without resolving a caller. Better Auth serves both metadata documents natively (`oauthProvider` and `@better-auth/mcp`), so Mantle writes none; the protected-resource document exists for the one `mcpResource`, at `/.well-known/oauth-protected-resource` and that resource's path.
|
|
275
|
+
- It runs `/oauth/consent[/data]` and `/oauth/consents[/data|/revoke]` behind `withCaller(resolver, …)`, so a cross-site session POST is refused there. Only a `session` credential may read, give or revoke a consent. The consent redirect is only what `completeOAuthConsent` returns, and one that does not parse, or is `javascript:`, `data:`, `vbscript:` or `blob:`, is 400.
|
|
276
|
+
- Admin is an optional subpath (decision 13), so `GET /oauth/consent` and `GET /oauth/consents` answer plain HTML pages. With Admin, `oauthProvider.consentPage` points at Admin's page, and `connectedAppsPage` redirects the list there.
|
|
277
|
+
- **2026-09-30, `mantle generate`, the plan file and the generated module** (decisions 6, 7, 12 and 13; ADR-0033 decision 3; ADR-0034 decision 7).
|
|
278
|
+
- **The bin.** `@aotter/mantle` declares one bin, `mantle` (`src/cli/main.ts`). Its commands are `generate` (with `--check`) and the manifest commands `validate`, `introspect`, `emit-openapi` and `emit-types`. `mantle-update` is a separate bin, added with the codemod. The entry is TypeScript, so the bin runs only once the swap builds the package; until then `runGenerate` is what tests exercise.
|
|
279
|
+
- **`mantle generate [--manifests <dir>] [--features <list>] [--identity <kind>]`.**
|
|
280
|
+
- It reads every `.yaml` and `.yml` file directly in the manifest directory (default `./manifests`) and runs parse, validate and `compileLinkedPlan`.
|
|
281
|
+
- It writes `.mantle/generated/plan.json` and `.mantle/generated/mantle.ts`, and writes `mantle.config.json` at the project root when the selection changes. It refuses (exit 2) to write through a symlinked `.mantle` or `.mantle/generated`.
|
|
282
|
+
- It reads only files, so a directory named `x.yaml` is not a manifest, and it names the manifest directory as it was given, never by its absolute path.
|
|
283
|
+
- It also writes the service preset once (amendment "the service preset" below); an application that already has `src/service.ts` keeps its own entry.
|
|
284
|
+
- **`plan.json`** is the one copy of the plan: `{ "sourceHash": <hex>, "plan": <RuntimePlan> }` as `compileLinkedPlan` returns it, with two-space indentation and a trailing newline. Its key order is deterministic, so identical input gives identical bytes, and it is not sorted: a JSON Schema's `properties` keep the order Admin and MCP show.
|
|
285
|
+
- `sourceHash` is ADR-0034 decision 7's source hash. It is the SHA-256 of the JSON array `[[name, text], …]` of the manifest files, sorted by file name, so the project's location never enters it. A text loses a leading BOM and has CRLF read as LF first, so a Windows checkout is the same source; `--check` compares generated files the same way. Host protocol 3 uploads this file.
|
|
286
|
+
- The hash sits beside the plan, not in it, so it is **not part of the fingerprint**. Reformatting a manifest changes `sourceHash`, but not the fingerprint Cloud and boot compare.
|
|
287
|
+
- **`mantle.ts`** imports `./plan.json` (`with { type: "json" }`) and exports:
|
|
288
|
+
- `plan` (the `RuntimePlan`, for `createMantle`) and `sourceHash`;
|
|
289
|
+
- the `emit-types` namespace `Mantle`;
|
|
290
|
+
- `Schemas`, `Views`, `ViewOptions` (`limit`, `cursor` and the View's `input`, required when the View requires any), and `Store` and `CallerStore` typed over them. `select` has one overload per Schema, and an insert's `values` or an update's `set` never names the scope field, which Store fills (ADR-0034 decision 8), or a native column. On a `publishing` Schema an insert is a draft, so its `values` are all optional, and an update's `set` may instead be `{ status: ContentState }` alone;
|
|
291
|
+
- `Handler<I, O, Env>`, whose `ctx.store` is that `CallerStore`, and `MantleHandlers<Env>`. `MantleHandlers` has exactly the plan's refs, so a missing or an extra handler is a `tsc` error; a plan without refs takes no handler. It stays assignable to Core's `MantleService.handlers` without a cast. Known limit: an extra ref is a `tsc` error only in an object literal typed as `MantleHandlers`; boot's `HANDLER_NOT_DECLARED` catches the rest.
|
|
292
|
+
|
|
293
|
+
`mantle.ts` imports only types, from `@aotter/mantle` and `@aotter/mantle/spec`.
|
|
294
|
+
- **`ViewRow_<name>`.**
|
|
295
|
+
- `viewOutputs(view, schemas)` in `@aotter/mantle/spec` reads a compiled `SELECT`'s outputs: an output's `AS` name, else its column's name, and `*` as the Schema's declared fields without the scope field. `compilePlan` records the outputs that read a Schema field unchanged as `PlanView.columns` (`{ <output>: { schema, field } }`, which changes the fingerprint).
|
|
296
|
+
- **`store.view` decodes those columns as `store.select` does** (booleans, JSON, timestamps, dates, numerics) and names an output that is the field's own name as declared (`e.startsAt AS startsAt` comes back as `startsAt`); another alias keeps its own name. An expression (`e.title || '!'`) keeps the storage encoding. Before this, every View row came back in the storage encoding with lower-case keys.
|
|
297
|
+
- The row type gives such a column its field's type, as `NonNullable<Entry_<schema>[<field>]> | null`, and any other output `unknown`. The row is `unknown` when an output has no name, or a `*` reads a subquery or `json_each`.
|
|
298
|
+
- `emitTypesFromManifests` gains the option `rows` (View name to row type), which the generator passes. `mantle emit-types` has no plan, so its rows stay `unknown`.
|
|
299
|
+
- **`mantle.config.json` v2** is `{ "version": 2, "identity": "mantle" | "custom" | "none", "features": [...] }`. `host` and `output` are removed. `features` is a subset of `mcp`, `admin`, `web`, in that order.
|
|
300
|
+
- `mcp` needs `@modelcontextprotocol/server` and `@modelcontextprotocol/ext-apps`.
|
|
301
|
+
- `admin` needs `@aotter/mantle-ui`, for the Admin SPA, and an identity other than `none`.
|
|
302
|
+
- `web` is `@aotter/mantle/web`. It needs no peer and today serves `createRestSurface`; `createWebSurface` is not ported yet.
|
|
303
|
+
- Identity `mantle` needs `better-auth`, `@better-auth/oauth-provider`, `@better-auth/mcp` and `@better-auth/cimd`, the packages `@aotter/mantle/auth` imports. Every selection needs `@aotter/mantle`.
|
|
304
|
+
|
|
305
|
+
Without a config or flags, the selection is identity `mantle` and every feature. An explicit `--features` without `--identity` means `none` (decision 12). A rerun keeps the saved identity, and asking for another one is refused (exit 2), never a table drop. A changed `--features` rewrites the config. The config is rewritten only when the selection (identity or features) changes, and keeps any other key it holds; a config with the same selection in another layout is not stale. A config that is not JSON, or not a JSON object, fails with exit 2 and names the file.
|
|
306
|
+
- **`GENERATE_FEATURE_DEPENDENCY_MISSING`** (validate phase) is raised for:
|
|
307
|
+
- a selected feature or identity whose package is not installed, found as `node_modules/<name>/package.json` from the project root upward (under Yarn PnP, by Node's resolution; elsewhere Node's resolution is not used, since it also follows `NODE_PATH`, which a bundler does not);
|
|
308
|
+
- `admin` with identity `none`.
|
|
309
|
+
|
|
310
|
+
The message carries the exact install command, chosen by the lockfile in the nearest directory that has one: `pnpm add`, `yarn add`, `bun add` or `npm install`. Generate fails before it writes anything. It never installs, never edits `package.json`, and never adds a feature back (amends ADR-0026).
|
|
311
|
+
- **`SCHEMA_NAME_CASE_COLLISION` and `FIELD_NAME_CASE_COLLISION`** (validate phase, in the graph validator, so `compilePlan` raises them too): two Schemas, or two fields of one Schema, whose names differ only by case. SQL resolves identifiers case-insensitively and the plan keys both by the lower-case name, so they would otherwise become one table or one column.
|
|
312
|
+
- **0.1.x input.** A `cms.mantle.aotter.net/v1` manifest fails with the parser's apiVersion diagnostic. A `mantle.config.json` with `version: 1` or a `host` fails with exit 2. Both messages name `mantle-update`.
|
|
313
|
+
- **`mantle generate --check [--database <file>]`** writes nothing. It exits 1 when `plan.json`, `mantle.ts` or `mantle.config.json` differs from what generate would write, or a dependency is missing.
|
|
314
|
+
- With `--database`, it also reads that database. The file is a SQLite file, such as Wrangler's local D1 under `.wrangler/state/v3/d1/`, opened read-only with `node:sqlite`, verified on Node 22.14 (it prints Node's experimental warning there). Node 22's `node:sqlite` binds only anonymous `?`, so the CLI's driver rewrites Core's numbered `?N` in order.
|
|
315
|
+
- The result comes from `planStorageChanges(driver, schemas, { fingerprint })` in Core's storage module, which shares convergence's one `diff` and applies nothing, and returns `{ skipped, sql, blocked, undeclared }`. `skipped` is a database that already booted this fingerprint, where boot applies nothing, and the check says so. Otherwise it prints the SQL: the system DDL (`IF NOT EXISTS`, only where Mantle never booted) and the Schema changes, with binds inlined as literals, so the SQL replays; or "nothing to do". The fingerprint and time zone rows are left to boot.
|
|
316
|
+
- Undeclared differences are printed as comments. A blocked difference is printed instead of any SQL and fails the check with exit 1. A database that cannot be read (missing, corrupt, locked, a directory) fails with exit 2 as `--database <file>: <reason>`.
|
|
317
|
+
- Without `--database`, no database is read. ADR-0034 decision 6's "`node:sqlite` is not used" concerns the storage test line, and still holds.
|
|
318
|
+
- **2026-09-30, the service preset, `toCloudflareCron` and the schedule gate** (decisions 5, 6, 8, 9 and 12).
|
|
319
|
+
- **Written once, then the application's.** `mantle generate` (not `--check`) writes each preset file that does not exist and never overwrites one; `--check` neither reads nor reports them. When `src/service.ts` already exists the application owns its composition and no preset file is written. `wrangler.jsonc` is skipped when any `wrangler.jsonc`, `wrangler.json` or `wrangler.toml` exists, and an existing `.gitignore` is left alone. `.mantle/generated` is not ignored: `--check` compares it, so it is committed.
|
|
320
|
+
- **The files.**
|
|
321
|
+
- `src/service.ts` exports `Env` and `mantle`, the `createMantle` result over the generated `plan`, `handlers`, `d1Storage(env.DB)` and `schedules: true`. Its `MantleService.fetch` mounts, in this order: the auth routes (identity `mantle`), Admin at `/admin` (feature `admin`), the public MCP surface at `/mcp` (feature `mcp`), and the REST surface at `/api`, which answers everything else. REST is always mounted; feature `web` selects nothing more until `createWebSurface` is ported (this replaces "`web` … serves `createRestSurface`" above). With `admin` and `mcp`, Admin also gets `staffMcp` at `/admin/api/mcp` and `site.mcpEndpoints` `{ public: "/mcp", staff: null }`.
|
|
322
|
+
|
|
323
|
+
> **Amendment (Admin answers no MCP):** with `mcp` and an identity, the preset mounts the staff surface at `/mcp/staff` (before `/mcp`, with the `/mcp` `resourceMetadata`) and Admin's `site.mcpEndpoints` is `{ public: "/mcp", staff: "/mcp/staff" }`; Admin gets no `staffMcp`.
|
|
324
|
+
- Identity `mantle`: `createMantleAuth` over `env.DB` (Better Auth's D1 dialect and `d1Driver`), email OTP through `ConsoleEmailSender`, `bootstrapOwner` by `ADMIN_EMAIL`, `ipAddressHeaders: ["cf-connecting-ip"]`, and an OAuth provider whose `mcpResource` is `{PUBLIC_ORIGIN}/mcp`; then `createCallerResolver` (with `jwtBearer` for that audience), `withCaller` around every surface, `createAuthRoutes`, and an `AdminIdentity` whose facets are the auth's own methods. Without `BETTER_AUTH_SECRET` and `ADMIN_EMAIL`, or when `PUBLIC_ORIGIN` is unset or is not a loopback `http:` origin (an unset value is never local: the request's `Origin` header is not evidence, so a forged loopback `Origin` prints no code), it uses `createSetupIncompleteAuth` instead, because codes printed to the log are for local development only; a deployed service replaces the sender and the method.
|
|
325
|
+
- Identity `custom`: `src/identity.ts` exports `resolveCaller: CallerResolver`, which throws until the application implements it, so a request fails loudly instead of running as anonymous. Admin gets no `identity`, so it hides the user facets.
|
|
326
|
+
- Identity `none`: every surface runs with the anonymous caller; no auth package is imported and no auth table is created.
|
|
327
|
+
- `src/handlers.ts` exports `handlers: MantleHandlers` with one stub per plan ref, each throwing `not implemented: <ref>`.
|
|
328
|
+
- `src/index.ts` is the Cloudflare entry: `fetch` and `scheduled`, no `queue` (no Core path produces a deferred-hook message). `scheduled` maps `controller.cron`, which Cloudflare spells as `wrangler.jsonc` does, back to the plan's POSIX expression through `toCloudflareCron` over `plan.triggers`, computed at module load from the enabled schedule Triggers, and calls `mantle.invokeSchedule` for each POSIX spelling that maps to it, so Triggers whose expressions differ but share one Cloudflare cron all run, and every failure is reported together in an `AggregateError`. A cron no Trigger maps to throws. Both handlers pass `{ waitUntil }` imported from `cloudflare:workers`, which is not bound to one request, so a handler's `ctx.waitUntil` never lands on another request's finished context (the open item "waitUntil captured per last request"). `env` is the isolate's, which Workers keeps the same for every request.
|
|
329
|
+
- `wrangler.jsonc`: `main: "src/index.ts"`, `compatibility_date: "2026-09-01"`, `compatibility_flags: ["nodejs_compat"]`, the D1 binding `DB`, and `triggers.crons` with `toCloudflareCron` of each enabled schedule Trigger, deduplicated. No R2 binding: media purposes live in the service's `SiteDefaults`, not in the plan, so generate cannot see them; an application that adds media adds the binding.
|
|
330
|
+
- `tsconfig.json` (`module: "ESNext"`, `moduleResolution: "Bundler"`, `resolveJsonModule`, `strict`, `types: ["@cloudflare/workers-types", "node"]`, since `nodejs_compat` serves the `node:` modules `/auth` imports), `.dev.vars.example` (identity `mantle`: `BETTER_AUTH_SECRET`, `PUBLIC_ORIGIN`, `ADMIN_EMAIL`) and `.gitignore` (`node_modules/`, `.wrangler/`, `.dev.vars`). The project installs `wrangler`, `@cloudflare/workers-types` and `@types/node` itself; generate does not check them.
|
|
331
|
+
- Admin gets no `assets` yet: its API answers and its SPA routes are 404 until `@aotter/mantle-ui/admin` exists (decision 13), which the preset will then pass.
|
|
332
|
+
- **`toCloudflareCron(cron: string): string`** in `@aotter/mantle/cloudflare`. Cloudflare numbers weekdays 1 (Sunday) to 7 (Saturday); POSIX 0 to 6. It adds one to every explicit weekday number (a single value, a list member, both ends of a range; a step is kept, so `1-5/2` becomes `2-6/2`), leaves `*` and weekday names (`SUN`–`SAT`) as written, and leaves the other four fields unchanged. It throws an `Error` naming the expression for what it cannot map faithfully: not five fields, a token that is not a number, name, `*`, range or step (`?`, `L`, `W`, `#`), weekday `7`, a weekday number past 6, a number with a leading zero (`01` and `1` would name one Cloudflare cron for two spellings), a value outside its field's range, a range that runs backwards (`5-1`), a name with a step (`MON/2`), a step below 1, and a day of month other than `*` together with a weekday other than `*`, where POSIX runs on either and Cloudflare's rule is not documented to match.
|
|
333
|
+
- Since the grammar has no rule across cron fields, generate (and `--check`) runs `toCloudflareCron` on every enabled schedule Trigger first, and a refusal fails with exit 1 as `Trigger <name>: <message>` before anything is written. Once `src/service.ts` exists the application owns it and `wrangler.jsonc`, so a plain `generate` only compares: it prints a `warning:` when `triggers.crons` differs from the plan's schedule Triggers or the selection changed, and writes neither file. `src/service.ts` is written last, so a preset write that failed (exit 2, `cannot write <path>`) is finished by the rerun.
|
|
334
|
+
- **The schedule cause.** A schedule's `cause.id` stays `<trigger>:<scheduledTime>`, so a replay of the same (Trigger, `scheduledTime`) carries the same id and a handler can deduplicate it.
|
|
335
|
+
- **`withCaller` moves to `@aotter/mantle`** (Core), with `WithCallerOptions`: it needs only a `CallerResolver` and a `Surface`, and `@aotter/mantle/auth` imports Better Auth, so a `custom` service that imported it from there bundled Better Auth. `/auth` no longer exports it.
|
|
336
|
+
- **The Worker never bundles the SQL compiler.** `core`, `cloudflare`, `web`, `auth`, `admin` and `mcp` import `spec/kernel` and `spec/domain`, never the `spec` barrel, whose `infrastructure/sql` re-export pulls `libpg-query` into a bundle even behind a dynamic import. `@aotter/mantle/spec` still exports `compilePlan`. A test bundles the generated entry (identity `mantle`, every feature) with esbuild and asserts no `libpg-query` input.
|
|
337
|
+
- **The schedule gate** replaces `check:schedule-cf` at the swap PR (until then the root `check` still runs the old script): it boots a generated preset under Wrangler's `unstable_startWorker`, fires `/cdn-cgi/local/scheduled` with the `wrangler.jsonc` spelling of the cron, and asserts the Trigger's Procedure ran once with `cause.kind: "schedule"`, and that a replay with the same `scheduledTime` carries the same `cause.id`.
|
|
338
|
+
- **2026-09-30, staff management goes through Better Auth's admin API** (decision 8). `createMantleAuth` already installs Better Auth's `admin` plugin with the staff roles as `adminRoles` and their access-control statements, yet `listUsers`, `setUserRole` and `inviteUser` wrote its tables in SQL, because the facet gave them no request to act as. They now take the signed-in owner's `Request` first, and `createMantleAuth` forwards its headers to `auth.api.listUsers` (`filterField: "role"`, `filterOperator: "in"`), `auth.api.setRole` and `auth.api.createUser`, so Better Auth authorizes the call with its own role statements, and its session store sees the change without a second path for a session cache:
|
|
339
|
+
- `AdminIdentity.directory.listUsers(request)`, `AdminIdentity.roles.setUserRole(request, userId, role)` and `AdminIdentity.roles.inviteUser(request, email, role)`; `MantleAuth` has the same signatures. Admin passes the request it is serving. `listUsers` still returns every staff user: Better Auth answers 100 unless given a limit, so a longer list is read again with its total as the limit.
|
|
340
|
+
- `setUserRole(request, userId, null)` stores Better Auth's default role `user`, which is not a staff role, instead of `NULL`; both read as "not staff" everywhere (`CallerResolver`, `listMembers`).
|
|
341
|
+
- Unchanged, because Better Auth has no call for them: `listMembers` (cursor paging that excludes every staff role; `listUsers` pages by offset and filters on one field), `getUser`, `listLinkedAccounts` and `unlinkAccount` for another user (`listUserAccounts` and `unlinkAccount` act on the session's own user), `revokeInvite` (one `DELETE` whose guard, no verified email and no linked account, holds in the same statement), and the OAuth consent calls. `deleteUser` stays headerless for a service's own code and always uses Better Auth's `internalAdapter.deleteUser`, which also clears cached sessions, instead of SQL when no session cache is configured.
|
|
342
|
+
- **2026-09-30, `@aotter/mantle/auth` exports its contract only.** Its values are `createMantleAuth`, `createSetupIncompleteAuth`, `createAuthRoutes`, what `callerResolver` exports, `ConsoleEmailSender` and `appleClientSecret`, with their types. The option builders (`buildGenericOAuthProviders`, `buildOAuthProviderOptions`, `buildSocialProviders`, `buildTrustedOriginsFor`, `guardGithubLoginProfile`, `hasEmailAuthSurface`, `hashEmailOtp`, `normalizeAuthBasePath`, `normalizeAuthResponseCookies`, `pickLocale`, `resolveClientIpHeaders`, `shouldPromoteToOwner`, `validateBootstrap`), the token helpers (`getProviderAccessTokenForRequest`, `mapRegisteredOAuthClient`, `verifyOAuthJwt`, `verifyOAuthJwtWithLocalJwks`), `STAFF_ROLES`, `STAFF_ROLE_SET` and the member cursors (`decodeMemberCursor`, `encodeMemberCursor`) were exported only for tests or for Admin, which has its own; `MantleAuth.getProviderAccessToken` still serves a service's own code. `isSetupIncompleteAuth` had no caller and is deleted.
|
|
343
|
+
- **2026-09-30, the `mantle` bin is one command, `generate`.** `validate`, `introspect`, `emit-openapi` and `emit-types` are removed: `generate` validates and compiles (`--check` is the gate that writes nothing and exits 1), `plan.json` is what `introspect` printed, and the generated `mantle.ts` holds every type `emit-types` wrote. `emit-openapi` had no caller. Its handler-source grep (`HANDLER_NOT_REGISTERED` as a warning) goes too: the typed `mantle.ts` makes a missing or extra handler a type error. `@aotter/mantle/spec` no longer exports `IntrospectManifestsUseCase`, `EmitOpenapiUseCase`, `EmitTypesUseCase` or their DTOs (`IntrospectManifestsRequest`, `IntrospectManifestsResponse`, `IntrospectedProcedure`, `IntrospectedSchema`, `IntrospectedTrigger`, `IntrospectedView`, `EmitOpenapiRequest`, `EmitOpenapiResponse`, `EmitTypesRequest`, `EmitTypesResponse`); `emitTypesFromManifests` stays, and `ValidateManifestsRequest` loses `handlerSource`.
|
|
344
|
+
- **2026-09-30, no `mantle-update` codemod; an upgrade guide for agents instead** (Consequences, and the amendment "`mantle generate`"). The codemod and its bin are not built. A 0.1.x project moves by hand, usually with a coding agent, following `docs/upgrade-0.1-to-0.2.md`, which ships in the package's `docs/`. The rewrites the codemod was to make (builtin handlers to SQL, the Filter AST and `params` to a View's SQL and `input`, `page`/`show` to `limit`/`cursor`, `ctx.event.entry` to a loop over `ctx.cause.rows`, Cloudflare cron to POSIX, `extend` to the service preset) are rows of that guide. A v1 manifest and a v1 `mantle.config.json` still fail as before; their messages name the guide instead of `mantle-update`.
|
|
345
|
+
- **2026-09-30, `x-mantle-bind` is refused** (ADR-0034 decision 8). In 0.1.x the keyword stamped a field on every write. 0.2.0 parsed and validated it, but no write path read it, so a field an author believed stamped took whatever the caller sent. The keyword is now refused on any Schema property, with a message naming the replacements: `Schema.spec.scope` for the caller's own field, and `auth.uid()` or `now()` in the Procedure's SQL for the rest. `@aotter/mantle/spec` no longer exports `MANTLE_BIND_VALUES` or `MantleBindValue`, and the diagnostic code `BIND_VALUE_NOT_IN_ENUM` is removed; `MANTLE_BIND_KEYWORD` stays, naming what is refused.
|
|
346
|
+
|
|
347
|
+
- **2026-10-01, the Admin console is `@aotter/mantle-ui/admin`, and Admin's wire reads the 0.2 plan** (decision 13, the swap's last step).
|
|
348
|
+
- **Package.** `@aotter/mantle-admin-ui` is removed. Its SPA builds into `@aotter/mantle-ui`'s `dist/admin/` (export `./admin/index.html`), with base `/admin/` instead of 0.1's `/_mantle/admin/`. The default site icons follow it to `/admin/favicon.*`. Removed with the package: its `/kit`, `kit.css` and `tokens.css` re-exports (the kit is `@aotter/mantle-ui/kit`), the shadcn `registry/auth-page.json` item, and the `systemTokensCss` export. 0.2.0 publishes two packages.
|
|
349
|
+
- **Serving.** With the admin feature, the Cloudflare preset binds `node_modules/@aotter/mantle-ui/dist/admin` as the Worker's static assets (`ASSETS`, `run_worker_first`, `html_handling: none`) and passes `createAdminSurface` an `assets` that fetches from it. Admin answers every `/admin` path; nothing is served at the files' bare paths.
|
|
350
|
+
- **Developer console.** `GET {base}/api/developer-console` is the snapshot the console reads: the data model, the logic with each audience, the HTTP and MCP interfaces, and a graph whose relations come from the IR (a View's sources, a Procedure's writes) and the plan. A View's query and an inline handler are `{ kind: "sql", statement }`, the SQL as authored; the IR stays on the server. The plan carries that text as `PlanView.source` and an inline handler's `source`, presentation metadata like `title`.
|
|
351
|
+
- **Views.** `/views-manifest` lists each staff View with `input`, `list.columns` and `columns`: each output that reads a Schema field unchanged, so Admin labels and formats it as that field. It also carries `list.searchFields` and `list.filterFields` (decision 5, below). The console pages Views by cursor only.
|
|
352
|
+
- **Settings.** `/site-settings` without the site tables answers 501 `SITE_NOT_CONFIGURED` (a new diagnostic code) instead of a bare 404.
|
|
353
|
+
- **Store.** A `null` for a field the Schema does not require clears it: it is stored as NULL, which is how Store reads an unset field, so a read-modify-write round trip validates. A `null` for a required field is still refused.
|
|
354
|
+
- **Search and filters (decision 5).** A staff View's `uiSchema.list.searchFields` and `filterFields` compile to conditions on its outputs, as decision 5 says; this replaces an earlier draft of this amendment that removed them, which was never decided. `store.view(name, { search, filters })` (`StoreViewOptions`) adds, around the View's own query and inside its paging, one `LIKE` per `searchFields` output, ORed, with the text's `%`, `_` and `\` escaped, and one `=` per `filters` entry, its value encoded as the output's Schema field. Store refuses a `search` on a View without `searchFields` and a filter on an output `filterFields` does not name (`INPUT_VALIDATION_FAILED`), so a request never chooses a column. Admin's `/views/{name}` and `/export` read `search` and `filter.<output>`, coercing a filter to the output's field type, and the console's search box and filters send them. `compilePlan` refuses a name the View's `SELECT` does not output (`VIEW_UI_INVALID`). These two keys are the one part of `uiSchema` that Store reads; the rest stays presentation only.
|
|
355
|
+
- **Not in 0.2.0 yet.** The ADR-0029 interaction tools (`read_entry`, `preview_entry`, View row actions) are not on `createMcpSurface`. The console keeps its optional row-action code, and the surface sends no row actions.
|
|
356
|
+
|
|
357
|
+
> **Amendment (MCP App catalog):** row actions reach an MCP App through the catalog `planApp` embeds in the App's HTML (ADR-0029 amendment), not through results; `read_entry` and `preview_entry` stay out, and a locked action reviews the row as listed.
|
|
358
|
+
|
|
359
|
+
## Implementation status
|
|
360
|
+
|
|
361
|
+
Proposed. Nothing in decisions 1–13 is implemented beyond the ADR-0030 slices already on `develop`.
|