@aotter/mantle 0.1.5-alpha.1 → 0.2.0-alpha.2
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 +592 -0
- package/dist/admin/createAdminSurface.js.map +1 -0
- package/dist/admin/developerConsole.d.ts +266 -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 +38 -0
- package/dist/admin/procedureFlow.d.ts.map +1 -0
- package/dist/admin/procedureFlow.js +188 -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 +129 -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 +508 -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 +318 -262
- 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 +353 -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/0022-caller-observed-version-occ.md +1 -1
- package/docs/adr/0024-manifest-native-schema-tables.md +2 -2
- package/docs/adr/0027-scheduled-procedure-triggers.md +1 -1
- package/docs/adr/0028-schema-ttl-expiry.md +3 -3
- 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 +23 -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 +119 -311
- 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 -163
- 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 -33
- package/docs/handbook/reference/authorization.md +52 -271
- package/docs/handbook/reference/diagnostics.md +69 -178
- package/docs/handbook/reference/features.md +48 -50
- package/docs/handbook/reference/manifest.md +56 -116
- package/docs/handbook/reference/procedure.md +91 -279
- package/docs/handbook/reference/schema.md +154 -239
- package/docs/handbook/reference/site-config.md +58 -211
- package/docs/handbook/reference/surface.md +69 -181
- package/docs/handbook/reference/trigger.md +72 -181
- package/docs/handbook/reference/view.md +140 -241
- package/docs/handbook/releases/index.md +58 -77
- package/docs/handbook/start/overview.md +59 -51
- package/docs/handbook/start/project-and-cli.md +132 -105
- package/docs/handbook/start/quickstart-worker.md +102 -160
- package/docs/skills/develop/SKILL.md +114 -240
- package/docs/skills/develop/mcp-app.md +79 -0
- package/docs/skills/integrate/SKILL.md +83 -47
- 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 -106
- package/dist/admin-ui.d.ts +0 -2
- package/dist/admin-ui.d.ts.map +0 -1
- package/dist/admin-ui.js +0 -2
- package/dist/admin-ui.js.map +0 -1
- package/dist/admin.d.ts +0 -2
- package/dist/admin.d.ts.map +0 -1
- package/dist/admin.js +0 -2
- package/dist/admin.js.map +0 -1
- package/dist/auth.d.ts +0 -2
- package/dist/auth.d.ts.map +0 -1
- package/dist/auth.js +0 -2
- package/dist/auth.js.map +0 -1
- package/dist/bun.d.ts +0 -2
- package/dist/bun.d.ts.map +0 -1
- package/dist/bun.js +0 -2
- package/dist/bun.js.map +0 -1
- package/dist/cli/generate-cloudflare.d.ts +0 -7
- package/dist/cli/generate-cloudflare.d.ts.map +0 -1
- package/dist/cli/generate-cloudflare.js +0 -123
- package/dist/cli/generate-cloudflare.js.map +0 -1
- package/dist/cli/generate-project.d.ts +0 -25
- package/dist/cli/generate-project.d.ts.map +0 -1
- package/dist/cli/generate-project.js +0 -282
- package/dist/cli/generate-project.js.map +0 -1
- package/dist/cli/generate-sites.d.ts +0 -8
- package/dist/cli/generate-sites.d.ts.map +0 -1
- package/dist/cli/generate-sites.js +0 -273
- package/dist/cli/generate-sites.js.map +0 -1
- package/dist/cli/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 -64
- package/docs/api-mcp-authorization.md +0 -5
- package/docs/assets/mantle-admin-developer.png +0 -0
- package/docs/assets/mantle-admin-operations.png +0 -0
- package/docs/assets/mantle-hero.jpg +0 -0
- package/docs/auth-hosting-model.md +0 -166
- package/docs/cloudflare-low-level-composition.md +0 -5
- package/docs/consumer-onboarding-audit.md +0 -65
- package/docs/deferred-lifecycle-queues.md +0 -5
- package/docs/design-atoms.md +0 -16
- package/docs/design-references/editorial-blog-2026-05-05.md +0 -218
- package/docs/direct-authoring.md +0 -5
- package/docs/examples/builtin-commerce.md +0 -269
- package/docs/examples/builtin-intake.md +0 -143
- package/docs/examples/builtin-legal-documents.md +0 -189
- package/docs/examples/builtin-procurement.md +0 -241
- package/docs/examples/builtin-publication.md +0 -241
- package/docs/examples/builtin-reservation.md +0 -149
- package/docs/examples/cf-primitives-commerce-inventory.md +0 -809
- package/docs/examples/cf-primitives-guarded-api.md +0 -429
- package/docs/examples/cf-primitives-intake-hooks.md +0 -319
- package/docs/examples/host-chatgpt-sites/.openai/hosting.json +0 -1
- package/docs/examples/host-chatgpt-sites/README.md +0 -70
- package/docs/examples/host-chatgpt-sites/drizzle/0000_sites_users.sql +0 -8
- package/docs/examples/host-chatgpt-sites/drizzle/0001_mantle.sql +0 -294
- package/docs/examples/host-chatgpt-sites/drizzle/0002_article_cover.sql +0 -5
- package/docs/examples/host-chatgpt-sites/drizzle/0003_store_instance_id.sql +0 -1
- package/docs/examples/host-chatgpt-sites/drizzle/0004_mantle.sql +0 -10
- package/docs/examples/host-chatgpt-sites/drizzle/0005_mantle.sql +0 -24
- package/docs/examples/host-chatgpt-sites/drizzle/meta/_journal.json +0 -1
- package/docs/examples/host-chatgpt-sites/drizzle/meta/mantle-state.json +0 -60
- package/docs/examples/host-chatgpt-sites/manifests/site.yaml +0 -27
- package/docs/examples/host-chatgpt-sites/package.json +0 -1
- package/docs/examples/host-chatgpt-sites/public/site.css +0 -1
- package/docs/examples/host-chatgpt-sites/scripts/build.mjs +0 -13
- package/docs/examples/host-chatgpt-sites/scripts/check.mjs +0 -101
- package/docs/examples/host-chatgpt-sites/scripts/migration.mjs +0 -43
- package/docs/examples/host-chatgpt-sites/src/chatgpt-auth.ts +0 -66
- package/docs/examples/host-chatgpt-sites/src/index.ts +0 -46
- package/docs/examples/host-chatgpt-sites/src/mcp.ts +0 -49
- package/docs/examples/host-chatgpt-sites/src/media.ts +0 -109
- package/docs/examples/host-chatgpt-sites/src/r2-lab.ts +0 -38
- package/docs/examples/host-chatgpt-sites/src/storage-fingerprint.json +0 -1
- package/docs/examples/host-chatgpt-sites/src/web.ts +0 -35
- package/docs/examples/host-chatgpt-sites/tsconfig.json +0 -1
- package/docs/examples/host-chatgpt-sites/wrangler.jsonc +0 -10
- package/docs/examples/host-local-admin-otp/.dev.vars.example +0 -3
- package/docs/examples/host-local-admin-otp/README.md +0 -80
- package/docs/examples/host-local-admin-otp/ensure-dev-vars.mjs +0 -5
- package/docs/examples/host-local-admin-otp/manifests/site.yaml +0 -25
- package/docs/examples/host-local-admin-otp/package.json +0 -29
- package/docs/examples/host-local-admin-otp/public/.gitkeep +0 -1
- package/docs/examples/host-local-admin-otp/smoke.mjs +0 -141
- package/docs/examples/host-local-admin-otp/src/index.ts +0 -54
- package/docs/examples/host-local-admin-otp/tsconfig.json +0 -17
- package/docs/examples/host-local-admin-otp/wrangler.jsonc +0 -23
- package/docs/examples/host-minimal-worker/README.md +0 -41
- package/docs/examples/host-minimal-worker/manifests/site.yaml +0 -25
- package/docs/examples/host-minimal-worker/package.json +0 -26
- package/docs/examples/host-minimal-worker/smoke.mjs +0 -23
- package/docs/examples/host-minimal-worker/src/index.ts +0 -4
- package/docs/examples/host-minimal-worker/wrangler.jsonc +0 -22
- package/docs/handbook/chatgpt-sites/equipment-checkout.md +0 -231
- package/docs/handbook/chatgpt-sites/generated-app.md +0 -84
- package/docs/handbook/chatgpt-sites/host-reference.md +0 -113
- package/docs/handbook/chatgpt-sites/index.md +0 -133
- package/docs/handbook/cloudflare/bindings.md +0 -291
- package/docs/handbook/cloudflare/conventional-worker.md +0 -166
- package/docs/handbook/cloudflare/deferred-hooks-queues.md +0 -170
- package/docs/handbook/cloudflare/low-level-composition.md +0 -169
- package/docs/handbook/cloudflare/public-web.md +0 -144
- package/docs/handbook/cloudflare/site-chrome.md +0 -75
- package/docs/handbook/examples/commerce-transaction.md +0 -11
- package/docs/handbook/examples/commerce.md +0 -11
- package/docs/handbook/examples/guarded-api.md +0 -10
- package/docs/handbook/examples/intake-form.md +0 -12
- package/docs/handbook/examples/intake-hooks.md +0 -11
- package/docs/handbook/examples/legal-documents.md +0 -10
- package/docs/handbook/examples/procurement-approvals.md +0 -10
- package/docs/handbook/examples/publication.md +0 -10
- package/docs/handbook/examples/reservation.md +0 -10
- package/docs/handbook/start/quickstart-admin.md +0 -52
- package/docs/labels.md +0 -71
- package/docs/media-uploads.md +0 -5
- package/docs/migration-0.1.2.md +0 -13
- package/docs/performance-harness.md +0 -228
- package/docs/release-process.md +0 -244
- package/docs/schema-indexes.md +0 -5
- package/docs/sealed-pipeline-ownership.md +0 -101
- package/docs/skills/plugin/SKILL.md +0 -132
- package/docs/skills/theme/SKILL.md +0 -77
- package/docs/spec-only-host-adoption.md +0 -157
- package/docs/transaction-patterns.md +0 -5
- package/skills/README.md +0 -127
- package/skills/develop/SKILL.md +0 -258
- package/skills/install/SKILL.md +0 -112
- package/skills/integrate/SKILL.md +0 -60
- package/skills/media-gc/SKILL.md +0 -85
- package/skills/plugin/SKILL.md +0 -132
- package/skills/provision/SKILL.md +0 -194
- package/skills/theme/SKILL.md +0 -77
- package/skills/update/SKILL.md +0 -51
- package/templates/chatgpt-sites/auth.ts +0 -66
- package/templates/chatgpt-sites/build.mjs +0 -14
- package/templates/chatgpt-sites/env.ts +0 -1
- package/templates/chatgpt-sites/mcp.ts +0 -48
- package/templates/chatgpt-sites/public-mcp.ts +0 -29
- package/templates/chatgpt-sites/smoke-local.mjs +0 -20
|
@@ -0,0 +1,592 @@
|
|
|
1
|
+
import { requiredEnumStates } from "./procedureFlow.js";
|
|
2
|
+
/**
|
|
3
|
+
* The Admin surface (ADR-0032 decisions 8 and 9): the staff JSON API under `{basePath}/api` and the SPA shell under `{basePath}`.
|
|
4
|
+
* Every API route needs a staff caller. Reads and runs go through `store.as(caller)` and `invokeProcedure`, so Admin sees what the
|
|
5
|
+
* caller's scope sees and nothing wider. Routes of an `AdminIdentity` facet that is absent do not exist.
|
|
6
|
+
*/
|
|
7
|
+
import { makeDiagnostic, redactForWire } from "../spec/kernel/index.js";
|
|
8
|
+
import { MCP_HINT_KEYWORD, STAFF_ROLES, isMediaMcpHint, isStaffRole, meetsRole, enumOptions, resolveMantleRef, mcpTools } from "../spec/domain/index.js";
|
|
9
|
+
import { evaluateAuthAll } from "../core/index.js";
|
|
10
|
+
import { siteConfigOf } from "../core/siteConfig.js";
|
|
11
|
+
import { coerce, failure, json, match, readJsonObject, viewQuery, wireError } from "../core/wire.js";
|
|
12
|
+
import { decodeMemberCursor } from "./consent.js";
|
|
13
|
+
import { developerConsole } from "./developerConsole.js";
|
|
14
|
+
const NO_STORE = { "cache-control": "no-store" };
|
|
15
|
+
const P = "admin";
|
|
16
|
+
const bad = (message) => wireError("INPUT_VALIDATION_FAILED", message, P);
|
|
17
|
+
const propsOf = (s) => (s.properties ?? {});
|
|
18
|
+
/** A role denial names the minimum role, so the SPA can say who may do it. */
|
|
19
|
+
const denied = (role, message) => json({ error: redactForWire(makeDiagnostic({ code: "AUTH_DENIED", phase: "runtime", severity: "error", path: P, expected: `${role} role or higher`, message })), minimumRole: role }, 403, NO_STORE);
|
|
20
|
+
/** What the SPA lists and edits for one Schema; a translation's parent is the entry sharing its `on`. */
|
|
21
|
+
function collectionOf(s, schemas) {
|
|
22
|
+
const names = new Set(schemas.filter((x) => !x.translates).map((x) => x.name));
|
|
23
|
+
const props = propsOf(s.schema);
|
|
24
|
+
const required = new Set(s.schema.required ?? []);
|
|
25
|
+
const ui = (s.uiSchema ?? {});
|
|
26
|
+
const list = ui["list"] ?? {};
|
|
27
|
+
const nav = ui["nav"];
|
|
28
|
+
const filterField = list["filterField"];
|
|
29
|
+
// a required reference is composition: the child sits under its parent, an `id` reference first, else one by a unique field
|
|
30
|
+
const refs = Object.keys(props).filter((f) => required.has(f) && names.has(resolveMantleRef(props[f])?.schema ?? ""));
|
|
31
|
+
const byId = refs.find((f) => resolveMantleRef(props[f]).field === "id");
|
|
32
|
+
const parentField = byId ?? refs[0];
|
|
33
|
+
// a standalone list's parent picker scopes by the parent's entry id, so only an `id` reference composes there (the checker agrees)
|
|
34
|
+
const navField = nav?.["standalone"] === true ? nav["parentField"] ?? byId : undefined;
|
|
35
|
+
const navParent = navField ? resolveMantleRef(props[navField]) : null;
|
|
36
|
+
const children = schemas.filter((c) => c.translates?.parent === s.name);
|
|
37
|
+
return {
|
|
38
|
+
name: s.name, title: s.title ?? s.name, description: s.description ?? null,
|
|
39
|
+
lifecycle: s.publishing ? "publishing" : "operational",
|
|
40
|
+
parent: s.translates ? { collection: s.translates.parent, parentField: s.translates.on, childField: s.translates.on }
|
|
41
|
+
: parentField ? { collection: resolveMantleRef(props[parentField]).schema, parentField: resolveMantleRef(props[parentField]).field, childField: parentField } : null,
|
|
42
|
+
hasTranslations: children.length > 0, localized: s.localized === true || !!s.translates, translates: s.translates ?? null,
|
|
43
|
+
schema: s.schema, uiSchema: s.uiSchema ?? null,
|
|
44
|
+
mediaFields: [s, ...children].flatMap((x) => Object.entries(propsOf(x.schema)).flatMap(([name, p]) => (isMediaMcpHint(p[MCP_HINT_KEYWORD]) ? [{ name, hint: p[MCP_HINT_KEYWORD] }] : []))),
|
|
45
|
+
// the plan lower-cases index columns; `names` maps them back to the declared spelling
|
|
46
|
+
sortableFields: [...new Set([...(s.unique ?? []), ...(s.indexes ?? [])].map((i) => s.names[i[0]] ?? i[0]).filter((f) => required.has(f)))],
|
|
47
|
+
filter: filterField ? { field: filterField, values: enumOptions(props[filterField])?.map((o) => o.value) ?? [] } : null,
|
|
48
|
+
list: { primaryField: list["primaryField"] ?? null, columns: list["columns"] ?? [] },
|
|
49
|
+
nav: navField && navParent ? { standalone: true, parentField: navField, parentCollection: navParent.schema } : null,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/** The settings page's fields and their longest value; the old surface had no limit. */
|
|
53
|
+
const SETTINGS = { brand: 80, title: 200, description: 1000 };
|
|
54
|
+
/** A committed asset with its primary variant lifted, so the library grid renders without deriving it. */
|
|
55
|
+
const settingsOf = ({ brand, title, description }) => ({ brand, title, description });
|
|
56
|
+
function mediaItem(a) {
|
|
57
|
+
const primary = a.variants.find((v) => v.role === "primary") ?? a.variants[0];
|
|
58
|
+
return { id: a.id, variants: a.variants, primaryUrl: primary?.publicUrl ?? null, mime: primary?.mimeType ?? null, byteSize: primary?.byteSize ?? null, alt: a.alt ?? null, caption: a.caption ?? null, createdAt: a.createdAt };
|
|
59
|
+
}
|
|
60
|
+
/** Store's native columns: `data` never sets them (status moves by publish and unpublish). */
|
|
61
|
+
const NATIVE = ["id", "status", "version", "createdAt", "updatedAt", "authorId"];
|
|
62
|
+
/** Store keeps microseconds; the Admin wire keeps the old milliseconds. */
|
|
63
|
+
const ms = (iso) => (typeof iso === "string" ? Date.parse(iso) : null);
|
|
64
|
+
/** RFC 4180 quoting, and a text that a spreadsheet would run as a formula gets a leading `'`. */
|
|
65
|
+
function csvCell(v) {
|
|
66
|
+
const t = v === null || v === undefined ? "" : typeof v === "object" ? JSON.stringify(v) : String(v);
|
|
67
|
+
const safe = typeof v === "string" && /^[\s\u0000-\u001f]*[=+@-]|^[\t\r]/u.test(t) ? `'${t}` : t;
|
|
68
|
+
return /[",\r\n]/.test(safe) ? `"${safe.replace(/"/g, '""')}"` : safe;
|
|
69
|
+
}
|
|
70
|
+
/** Every page as one CSV download. The first page is read before answering, so a bad query is a JSON error, not a broken file. */
|
|
71
|
+
async function csv(name, read, columnsOf, cell) {
|
|
72
|
+
let page = await read();
|
|
73
|
+
const columns = columnsOf(page.rows);
|
|
74
|
+
const line = (xs) => `${xs.map(csvCell).join(",")}\r\n`;
|
|
75
|
+
async function* lines() {
|
|
76
|
+
yield `\uFEFF${line(columns)}`;
|
|
77
|
+
for (;;) {
|
|
78
|
+
yield page.rows.map((r) => line(columns.map((c) => cell(r, c)))).join("");
|
|
79
|
+
if (!page.nextCursor)
|
|
80
|
+
return;
|
|
81
|
+
page = await read(page.nextCursor);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const it = lines();
|
|
85
|
+
const enc = new TextEncoder();
|
|
86
|
+
const body = new ReadableStream({
|
|
87
|
+
async pull(c) {
|
|
88
|
+
try {
|
|
89
|
+
const n = await it.next();
|
|
90
|
+
if (n.done)
|
|
91
|
+
c.close();
|
|
92
|
+
else
|
|
93
|
+
c.enqueue(enc.encode(n.value));
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
// the status line is gone once a page has streamed: end the download as failed, and leave a trace
|
|
97
|
+
console.error("[mantle admin] export failed mid-stream", e);
|
|
98
|
+
c.error(e);
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
async cancel() { await it.return(undefined); },
|
|
102
|
+
});
|
|
103
|
+
return new Response(body, { headers: { "content-type": "text/csv; charset=utf-8", "content-disposition": `attachment; filename="${name}.csv"`, ...NO_STORE } });
|
|
104
|
+
}
|
|
105
|
+
export function createAdminSurface(runtime, options) {
|
|
106
|
+
const base = options.basePath.replace(/\/+$/, "");
|
|
107
|
+
// the SPA is built for /admin: its chunks, its API calls and its links name that path
|
|
108
|
+
if (options.assets && base !== "/admin")
|
|
109
|
+
throw new Error(`createAdminSurface: the Admin SPA (assets) is served at /admin only, not '${options.basePath}'.`);
|
|
110
|
+
const { plan } = runtime;
|
|
111
|
+
const { directory, roles } = options.identity ?? {};
|
|
112
|
+
const schemas = Object.values(plan.schemas);
|
|
113
|
+
const projected = new Map(schemas.map((s) => [s, collectionOf(s, schemas)]));
|
|
114
|
+
const projection = (s) => projected.get(s);
|
|
115
|
+
const collections = schemas.filter((s) => !s.translates).map(projection);
|
|
116
|
+
const staffProcedures = [...new Set(Object.values(plan.triggers).flatMap((t) => (t.source.kind === "mcp" && t.source.surface === "staff" ? [t.procedure] : [])))];
|
|
117
|
+
const sees = (requires, caller) => evaluateAuthAll(requires, caller, P) === null;
|
|
118
|
+
const operations = (caller) => staffProcedures.filter((name) => sees(plan.procedures[name].requires, caller)).map((name) => {
|
|
119
|
+
const p = plan.procedures[name];
|
|
120
|
+
const requiredStates = p.target && "sql" in p.handler ? requiredEnumStates(p.handler.sql.stmts, p.target.schema, plan.schemas[p.target.schema.toLowerCase()]?.schema ?? {}) : [];
|
|
121
|
+
return {
|
|
122
|
+
...(requiredStates.length ? { requiredStates } : {}),
|
|
123
|
+
name, title: p.title ?? null, description: p.description ?? null, input: p.input, uiSchema: p.uiSchema ?? null,
|
|
124
|
+
interactions: p.target ? [{ collection: p.target.schema, bind: [{ input: p.target.id, field: "id" }], ...(p.target.version ? { version: p.target.version } : {}), mutates: true }] : [],
|
|
125
|
+
};
|
|
126
|
+
});
|
|
127
|
+
const staffView = (name, caller) => {
|
|
128
|
+
const v = plan.views[name];
|
|
129
|
+
// a View the caller cannot see is not there for them, so its name and its rule cannot be probed
|
|
130
|
+
if (!v || v.surface !== "staff" || !sees(v.requires, caller))
|
|
131
|
+
throw wireError("NOT_FOUND", `no staff View '${name}'`, P);
|
|
132
|
+
return v;
|
|
133
|
+
};
|
|
134
|
+
const views = (caller) => Object.entries(plan.views).filter(([, v]) => v.surface === "staff" && sees(v.requires, caller)).map(([name, v]) => {
|
|
135
|
+
const list = (v.uiSchema?.["list"] ?? {});
|
|
136
|
+
// `columns`: the output that reads a Schema field unchanged, so Admin labels and formats it as that field; named as the rows and the
|
|
137
|
+
// JSON Schema name them, not by the plan's lower-cased keys
|
|
138
|
+
const columns = Object.fromEntries(Object.entries(v.columns ?? {}).map(([k, c]) => {
|
|
139
|
+
const s = plan.schemas[c.schema];
|
|
140
|
+
const field = s.names?.[c.field] ?? c.field;
|
|
141
|
+
return [k === c.field ? field : k, { schema: s.name, field }];
|
|
142
|
+
}));
|
|
143
|
+
return { name, title: v.title ?? null, description: v.description ?? null, input: v.input ?? null, list: { columns: list["columns"] ?? [], searchFields: list["searchFields"] ?? [], filterFields: list["filterFields"] ?? [] }, columns };
|
|
144
|
+
});
|
|
145
|
+
// `search` and `filter.<output>` from the query string, for the outputs the View's uiSchema.list declares (ADR-0032 decision 5).
|
|
146
|
+
// A filter value is coerced to the field the output reads, as a View's input is.
|
|
147
|
+
const viewMatch = (v, q) => {
|
|
148
|
+
const list = (v.uiSchema?.["list"] ?? {});
|
|
149
|
+
const search = q.get("search")?.trim();
|
|
150
|
+
const filters = {};
|
|
151
|
+
for (const f of list["filterFields"] ?? []) {
|
|
152
|
+
const raw = q.get(`filter.${f}`);
|
|
153
|
+
if (raw === null || raw === "")
|
|
154
|
+
continue;
|
|
155
|
+
const c = v.columns?.[f] ?? v.columns?.[f.toLowerCase()];
|
|
156
|
+
const schema = c ? propsOf(plan.schemas[c.schema].schema)[plan.schemas[c.schema].names?.[c.field] ?? c.field] : undefined;
|
|
157
|
+
filters[f] = coerce(raw, schema, `filter.${f}`, P);
|
|
158
|
+
}
|
|
159
|
+
return { ...(search && list["searchFields"]?.length ? { search } : {}), ...(Object.keys(filters).length ? { filters } : {}) };
|
|
160
|
+
};
|
|
161
|
+
// a custom directory may return more than it declares: only the declared fields reach the wire
|
|
162
|
+
const staffInfo = ({ id, email, name, role, githubLogin, emailVerified, createdAt }) => ({ id, email, name, role, githubLogin, emailVerified, createdAt });
|
|
163
|
+
const memberInfo = ({ id, email, name, emailVerified, createdAt }) => ({ id, email, name, emailVerified, createdAt });
|
|
164
|
+
const site = async (url) => {
|
|
165
|
+
const { origin, ...config } = runtime.site ? await runtime.site.read() : siteConfigOf([]);
|
|
166
|
+
// boot refuses a bad origin; a row edited by hand still must not take /site down
|
|
167
|
+
const publicUrl = URL.canParse(origin) ? origin : url.origin;
|
|
168
|
+
const at = (p) => (p ? new URL(p, publicUrl).href : null);
|
|
169
|
+
const mcp = options.site?.mcpEndpoints;
|
|
170
|
+
// what this deployment turned on, so the console does not offer a page that can only answer 501
|
|
171
|
+
// creation statistics are a storage capability 0.2.0 storage does not have (the route answers 501)
|
|
172
|
+
const capabilities = { siteSettings: runtime.site !== undefined, media: !!library, invitationEmail: !!roles?.sendStaffInvitation, statistics: false };
|
|
173
|
+
return { ...config, publicUrl, mcpEndpoints: { public: at(mcp?.public), staff: at(mcp?.staff) }, capabilities };
|
|
174
|
+
};
|
|
175
|
+
const library = options.media && runtime.site?.media(options.media);
|
|
176
|
+
const media = () => {
|
|
177
|
+
if (!library)
|
|
178
|
+
throw wireError("MEDIA_NOT_CONFIGURED", "Media is not enabled on this deployment: give the storage adapter site defaults and createAdminSurface a MediaStorage.", P);
|
|
179
|
+
return library;
|
|
180
|
+
};
|
|
181
|
+
const me = async (caller) => {
|
|
182
|
+
const u = await directory?.getUser?.(caller.subject);
|
|
183
|
+
return { userId: caller.subject, role: caller.role, login: u ? u.githubLogin || u.name || u.email || null : null, image: u?.image ?? null };
|
|
184
|
+
};
|
|
185
|
+
// the staff MCP surface's tools (its default locale), each with its page: a Procedure's target Schema, or the View
|
|
186
|
+
const staffTools = mcpTools(plan, "staff");
|
|
187
|
+
const staffTool = new Map(staffTools.map((t) => [t.name, t]));
|
|
188
|
+
const webmcp = {
|
|
189
|
+
tools: staffTools.map(({ name, title, description, inputSchema, outputSchema, annotations }) => ({ name, ...(title ? { title } : {}), description, inputSchema, ...(outputSchema ? { outputSchema } : {}), ...(annotations ? { annotations } : {}) })),
|
|
190
|
+
routes: Object.fromEntries(staffTools.flatMap((t) => {
|
|
191
|
+
if (t.kind === "view")
|
|
192
|
+
return [[t.name, { path: `${base}/views/${encodeURIComponent(t.source)}` }]];
|
|
193
|
+
const target = plan.procedures[t.source].target;
|
|
194
|
+
return target ? [[t.name, { path: `${base}/c/${encodeURIComponent(plan.schemas[target.schema.toLowerCase()]?.name ?? target.schema)}`, entry: true }]] : [];
|
|
195
|
+
})),
|
|
196
|
+
};
|
|
197
|
+
let developer;
|
|
198
|
+
// ---- entries: every read and write is the caller's own Store, so a scoped Schema shows the caller's rows only (G2b)
|
|
199
|
+
const schemaOf = (name) => {
|
|
200
|
+
if (typeof name !== "string" || !name)
|
|
201
|
+
throw bad("a `collection` naming a Schema is required");
|
|
202
|
+
const s = Object.hasOwn(plan.schemas, name.toLowerCase()) ? plan.schemas[name.toLowerCase()] : undefined;
|
|
203
|
+
if (!s)
|
|
204
|
+
throw wireError("NOT_FOUND", `no collection '${name}'`, P);
|
|
205
|
+
return s;
|
|
206
|
+
};
|
|
207
|
+
// root `readOnly: true` keeps generic authoring off a Schema its Procedures maintain
|
|
208
|
+
const writable = (s) => {
|
|
209
|
+
if (s.schema.readOnly === true)
|
|
210
|
+
throw wireError("CONFLICT", `Schema '${s.name}' is read-only on generic authoring surfaces; use its declared Procedures.`, P);
|
|
211
|
+
};
|
|
212
|
+
const dataOf = (body) => {
|
|
213
|
+
const d = body["data"] ?? {};
|
|
214
|
+
if (typeof d !== "object" || d === null || Array.isArray(d))
|
|
215
|
+
throw bad("`data` must be an object");
|
|
216
|
+
const native = Object.keys(d).find((k) => NATIVE.includes(k));
|
|
217
|
+
if (native)
|
|
218
|
+
throw bad(`\`data\` may not set '${native}': status moves by publish and unpublish, and Store owns the rest`);
|
|
219
|
+
return d;
|
|
220
|
+
};
|
|
221
|
+
const current = async (store, s, id) => {
|
|
222
|
+
const [row] = (await store.select({ from: s.name, where: { id }, limit: 1 })).rows;
|
|
223
|
+
if (!row)
|
|
224
|
+
throw wireError("NOT_FOUND", `no ${s.name} entry '${id}'`, P);
|
|
225
|
+
return row;
|
|
226
|
+
};
|
|
227
|
+
const entryOf = (s, row) => {
|
|
228
|
+
const { id, status, version, createdAt: _c, updatedAt, authorId: _a, ...data } = row;
|
|
229
|
+
return { id: String(id), collection: s.name, locale: typeof data["locale"] === "string" ? data["locale"] : null, status: status ?? null, version, data, updated_at: ms(updatedAt) };
|
|
230
|
+
};
|
|
231
|
+
const titleOf = (s, data) => {
|
|
232
|
+
const props = propsOf(s.schema);
|
|
233
|
+
const key = [projection(s).list.primaryField, "title", "name", "slug", ...(s.schema.required ?? []).filter((f) => [props[f]?.["type"]].flat().includes("string"))]
|
|
234
|
+
.find((k) => k && typeof data[k] === "string" && data[k] !== "");
|
|
235
|
+
return key ? data[key] : null;
|
|
236
|
+
};
|
|
237
|
+
const listQuery = (s, q) => {
|
|
238
|
+
if (q.get("cursor_direction") === "backward")
|
|
239
|
+
throw bad("entries page forward only: keep the cursors already seen to go back");
|
|
240
|
+
const where = [];
|
|
241
|
+
const status = q.get("status");
|
|
242
|
+
if (s.publishing && status && status !== "all")
|
|
243
|
+
where.push({ status });
|
|
244
|
+
for (const k of ["filter", "scope"]) {
|
|
245
|
+
const field = q.get(`${k}_field`), value = q.get(`${k}_value`);
|
|
246
|
+
if (!field !== !value)
|
|
247
|
+
throw bad(`${k}_field and ${k}_value go together`);
|
|
248
|
+
if (field)
|
|
249
|
+
where.push({ [field]: coerce(value, propsOf(s.schema)[field], field, P) });
|
|
250
|
+
}
|
|
251
|
+
const search = q.get("search")?.trim();
|
|
252
|
+
return { from: s.name, ...(where.length ? { where: { and: where } } : {}), ...(search ? { search } : {}), orderBy: { [q.get("sort") || "updatedAt"]: q.get("direction") === "asc" ? "asc" : "desc" } };
|
|
253
|
+
};
|
|
254
|
+
const everyPage = async (store, q) => {
|
|
255
|
+
const rows = [];
|
|
256
|
+
let cursor;
|
|
257
|
+
do {
|
|
258
|
+
const page = await store.select({ ...q, ...(cursor ? { cursor } : {}) });
|
|
259
|
+
rows.push(...page.rows);
|
|
260
|
+
cursor = page.nextCursor;
|
|
261
|
+
} while (cursor);
|
|
262
|
+
return rows;
|
|
263
|
+
};
|
|
264
|
+
/** Each row's translation locales: a second select per translation Schema, `in` the page's keys, in chunks under the bind limit. */
|
|
265
|
+
const localesOf = async (store, s, rows) => {
|
|
266
|
+
const out = new Map(rows.map((r) => [String(r["id"]), new Set()]));
|
|
267
|
+
for (const t of schemas.filter((x) => x.translates?.parent === s.name && x.fields["locale"])) {
|
|
268
|
+
const on = t.translates.on;
|
|
269
|
+
const keys = [...new Set(rows.map((r) => r[on]).filter((v) => v !== null && v !== undefined && v !== ""))];
|
|
270
|
+
const byKey = new Map();
|
|
271
|
+
for (let i = 0; i < keys.length; i += 50) {
|
|
272
|
+
for (const tr of await everyPage(store, { from: t.name, columns: [on, "locale"], where: { [on]: { in: keys.slice(i, i + 50) } }, limit: 500 })) {
|
|
273
|
+
if (typeof tr["locale"] === "string")
|
|
274
|
+
byKey.set(tr[on], (byKey.get(tr[on]) ?? new Set()).add(tr["locale"]));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
for (const r of rows)
|
|
278
|
+
for (const l of byKey.get(r[on]) ?? [])
|
|
279
|
+
out.get(String(r["id"])).add(l);
|
|
280
|
+
}
|
|
281
|
+
return out;
|
|
282
|
+
};
|
|
283
|
+
const list = async (caller, q) => {
|
|
284
|
+
const s = schemaOf(q.get("collection"));
|
|
285
|
+
const store = runtime.store.as(caller);
|
|
286
|
+
const limit = q.get("limit");
|
|
287
|
+
const cursor = q.get("cursor");
|
|
288
|
+
const page = await store.select({ ...listQuery(s, q), ...(limit ? { limit: coerce(limit, { type: "integer" }, "limit", P) } : {}), ...(cursor ? { cursor } : {}) });
|
|
289
|
+
const locales = await localesOf(store, s, page.rows);
|
|
290
|
+
const ui = projection(s).list;
|
|
291
|
+
const preview = [...(ui.primaryField ? [ui.primaryField] : []), ...ui.columns];
|
|
292
|
+
return {
|
|
293
|
+
items: page.rows.map((row) => {
|
|
294
|
+
const e = entryOf(s, row);
|
|
295
|
+
return {
|
|
296
|
+
id: e.id, collection: s.name, locale: e.locale, status: e.status, version: e.version, title: s.publishing ? titleOf(s, e.data) : null, updated_at: e.updated_at,
|
|
297
|
+
translation_locales: [...locales.get(e.id)],
|
|
298
|
+
...(!s.publishing && preview.length ? { data_preview: Object.fromEntries(preview.map((f) => [f, row[f] ?? null])) } : {}),
|
|
299
|
+
};
|
|
300
|
+
}),
|
|
301
|
+
// forward only: Store pages one way, so the client keeps the cursors it has seen (G5)
|
|
302
|
+
next_cursor: page.nextCursor ?? null,
|
|
303
|
+
};
|
|
304
|
+
};
|
|
305
|
+
/** The editor's payload: the entry, its parent, and the related sections (translations, and Schemas that reference it by id or a unique field). */
|
|
306
|
+
const editor = async (store, s, row) => {
|
|
307
|
+
const join = (v) => (v === undefined || v === "" ? null : v);
|
|
308
|
+
const up = projection(s).parent;
|
|
309
|
+
const upValue = up ? join(row[up.childField]) : null;
|
|
310
|
+
const parentSchema = up && upValue !== null ? schemaOf(up.collection) : undefined;
|
|
311
|
+
const [parent] = parentSchema ? (await store.select({ from: parentSchema.name, where: { [up.parentField]: upValue }, limit: 1 })).rows : [];
|
|
312
|
+
const rels = [
|
|
313
|
+
...(s.translates ? [{ t: s, kind: "translation", parentField: s.translates.on, childField: s.translates.on }] : []),
|
|
314
|
+
...schemas.filter((c) => c !== s).flatMap((c) => c.translates?.parent === s.name
|
|
315
|
+
? [{ t: c, kind: "translation", parentField: c.translates.on, childField: c.translates.on }]
|
|
316
|
+
: Object.entries(propsOf(c.schema)).flatMap(([f, p]) => { const ref = resolveMantleRef(p); return ref?.schema === s.name ? [{ t: c, kind: "field", parentField: ref.field, childField: f }] : []; })),
|
|
317
|
+
];
|
|
318
|
+
const related = await Promise.all(rels.map(async ({ t, kind, parentField, childField }) => {
|
|
319
|
+
const parentValue = join(row[parentField]);
|
|
320
|
+
const rows = parentValue === null ? [] : (await store.select({ from: t.name, where: { [childField]: parentValue }, limit: 50 })).rows;
|
|
321
|
+
return { collection: projection(t), relationship: { kind, parentField, childField, parentValue }, entries: rows.map((r) => entryOf(t, r)) };
|
|
322
|
+
}));
|
|
323
|
+
return {
|
|
324
|
+
collection: projection(s), entry: entryOf(s, row),
|
|
325
|
+
parentEntryId: parent ? String(parent["id"]) : null, parentEntryTitle: parent ? titleOf(parentSchema, entryOf(parentSchema, parent).data) ?? String(parent["id"]) : null,
|
|
326
|
+
related,
|
|
327
|
+
};
|
|
328
|
+
};
|
|
329
|
+
const move = (status) => async ({ caller, params: { id }, url }) => {
|
|
330
|
+
const s = schemaOf(url.searchParams.get("collection"));
|
|
331
|
+
writable(s);
|
|
332
|
+
const store = runtime.store.as(caller);
|
|
333
|
+
await current(store, s, id);
|
|
334
|
+
// the lifecycle, a publish's completeness and a translation's parent-first rule are Store's (ADR-0032 decision 1)
|
|
335
|
+
await store.write([{ update: s.name, set: { status }, where: { id: id } }]);
|
|
336
|
+
return editor(store, s, await current(store, s, id));
|
|
337
|
+
};
|
|
338
|
+
const routes = [
|
|
339
|
+
{ method: "GET", path: "/me", role: "contributor", run: ({ caller }) => me(caller) },
|
|
340
|
+
{
|
|
341
|
+
method: "GET", path: "/bootstrap", role: "contributor", run: async ({ caller, url, url: { searchParams: q } }) => ({
|
|
342
|
+
me: await me(caller), site: await site(url), collections, operations: operations(caller), views: views(caller), webmcp,
|
|
343
|
+
// the first page of the collection the SPA opens on
|
|
344
|
+
...(q.get("collection") ? { entries: await list(caller, q) } : {}),
|
|
345
|
+
}),
|
|
346
|
+
},
|
|
347
|
+
{ method: "GET", path: "/collections", role: "contributor", run: async () => ({ collections }) },
|
|
348
|
+
{
|
|
349
|
+
// creation statistics are an optional storage capability that 0.2.0 storage does not have (G7); the SPA hides the card on 501
|
|
350
|
+
method: "GET", path: "/collections/{name}/statistics", role: "contributor", run: async ({ params: { name } }) => {
|
|
351
|
+
schemaOf(name);
|
|
352
|
+
return json({ error: { code: "STATISTICS_UNAVAILABLE", message: "Statistics are unavailable for this storage adapter." } }, 501, NO_STORE);
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
{ method: "GET", path: "/developer-console", role: "owner", run: async () => (developer ??= developerConsole(plan)) },
|
|
356
|
+
{ method: "GET", path: "/site", role: "contributor", run: ({ url }) => site(url) },
|
|
357
|
+
// the bytes go straight to the bucket: create, PUT each variant to its uploadUrl, commit
|
|
358
|
+
{ method: "POST", path: "/media/uploads", role: "editor", run: async ({ request }) => media().createUpload(await readJsonObject(request, P)) },
|
|
359
|
+
{ method: "POST", path: "/media/uploads/{groupId}/commit", role: "editor", run: async ({ request, params: { groupId } }) => media().commitUpload(groupId, await readJsonObject(request, P)) },
|
|
360
|
+
{
|
|
361
|
+
method: "GET", path: "/media", role: "editor", run: async ({ url: { searchParams: q } }) => {
|
|
362
|
+
const limit = q.get("limit");
|
|
363
|
+
// the callee first: an unconfigured library is 501 before the query is read
|
|
364
|
+
const r = await media().list({ ...(limit ? { limit: coerce(limit, { type: "integer" }, "limit", P) } : {}), ...(q.get("cursor") ? { cursor: q.get("cursor") } : {}), ...(q.get("search")?.trim() ? { search: q.get("search").trim() } : {}) });
|
|
365
|
+
return { items: r.rows.map(mediaItem), next_cursor: r.nextCursor ?? null };
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
{ method: "GET", path: "/media/{id}", role: "editor", run: async ({ params: { id } }) => mediaItem(await media().get(id)) },
|
|
369
|
+
{ method: "PATCH", path: "/media/{id}", role: "editor", run: async ({ request, params: { id } }) => mediaItem(await media().update(id, await readJsonObject(request, P))) },
|
|
370
|
+
{ method: "DELETE", path: "/media/{id}", role: "editor", run: async ({ params: { id } }) => media().delete(id) },
|
|
371
|
+
{ method: "GET", path: "/views-manifest", role: "contributor", run: async ({ caller }) => ({ views: views(caller) }) },
|
|
372
|
+
{
|
|
373
|
+
method: "GET", path: "/views/{name}", role: "contributor", run: ({ caller, params: { name }, url }) => runtime.store.as(caller).view(name, { ...viewQuery(name, staffView(name, caller), url.searchParams, P), ...viewMatch(staffView(name, caller), url.searchParams) }),
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
method: "GET", path: "/views/{name}/export", role: "contributor", run: ({ caller, params: { name }, url }) => {
|
|
377
|
+
const v = staffView(name, caller);
|
|
378
|
+
const { input } = viewQuery(name, v, url.searchParams, P);
|
|
379
|
+
const declared = (v.uiSchema?.["list"] ?? {})["columns"] ?? [];
|
|
380
|
+
const store = runtime.store.as(caller);
|
|
381
|
+
const matched = viewMatch(v, url.searchParams);
|
|
382
|
+
return csv(name, (cursor) => store.view(name, { input, ...matched, limit: 500, ...(cursor ? { cursor } : {}) }), (rows) => (declared.length ? declared : [...new Set(rows.flatMap((r) => Object.keys(r)))]), (row, c) => row[c]);
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
{ method: "GET", path: "/entries", role: "contributor", run: ({ caller, url }) => list(caller, url.searchParams) },
|
|
386
|
+
// before `/entries/{id}`, which has as many segments
|
|
387
|
+
{
|
|
388
|
+
method: "GET", path: "/entries/export", role: "contributor", run: ({ caller, url: { searchParams: q } }) => {
|
|
389
|
+
const s = schemaOf(q.get("collection"));
|
|
390
|
+
const query = listQuery(s, q);
|
|
391
|
+
const store = runtime.store.as(caller);
|
|
392
|
+
const columns = ["id", ...(s.publishing ? ["status"] : []), "version", "updated_at", ...Object.keys(propsOf(s.schema)).filter((f) => f.toLowerCase() !== s.scope && s.fields[f.toLowerCase()] !== "geo")];
|
|
393
|
+
return csv(s.name, (cursor) => store.select({ ...query, limit: 500, ...(cursor ? { cursor } : {}) }), () => columns, (row, c) => (c === "updated_at" ? ms(row["updatedAt"]) : row[c]));
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
method: "GET", path: "/entries/{id}", role: "contributor", run: async ({ caller, params: { id }, url }) => {
|
|
398
|
+
const s = schemaOf(url.searchParams.get("collection"));
|
|
399
|
+
const store = runtime.store.as(caller);
|
|
400
|
+
return editor(store, s, await current(store, s, id));
|
|
401
|
+
},
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
method: "POST", path: "/entries", role: "contributor", run: async ({ caller, request }) => {
|
|
405
|
+
const body = await readJsonObject(request, P);
|
|
406
|
+
const s = schemaOf(body["collection"]);
|
|
407
|
+
writable(s);
|
|
408
|
+
if (caller.role === "contributor" && !s.publishing)
|
|
409
|
+
return denied("editor", "Contributors can create drafts, not operational records.");
|
|
410
|
+
const store = runtime.store.as(caller);
|
|
411
|
+
const [r] = await store.write([{ insert: s.name, values: Object.fromEntries(Object.entries(dataOf(body)).filter(([, v]) => v !== null)) }]);
|
|
412
|
+
return editor(store, s, await current(store, s, r.id));
|
|
413
|
+
},
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
method: "PATCH", path: "/entries/{id}", role: "contributor", run: async ({ caller, params: { id }, request, url }) => {
|
|
417
|
+
const s = schemaOf(url.searchParams.get("collection"));
|
|
418
|
+
writable(s);
|
|
419
|
+
const store = runtime.store.as(caller);
|
|
420
|
+
const row = await current(store, s, id);
|
|
421
|
+
if (caller.role === "contributor" && (!s.publishing || row["status"] !== "draft"))
|
|
422
|
+
return denied("editor", "Contributors can edit drafts only.");
|
|
423
|
+
const body = await readJsonObject(request, P);
|
|
424
|
+
const lock = body["expectedVersion"];
|
|
425
|
+
if (typeof lock !== "number" || !Number.isSafeInteger(lock) || lock < 0)
|
|
426
|
+
throw bad("`expectedVersion` (the version the editor loaded) is required");
|
|
427
|
+
// the editor sends the whole entry back: a null it read stays as it is, so a draft's empty required field is no write
|
|
428
|
+
const set = Object.fromEntries(Object.entries(dataOf(body)).filter(([k, v]) => v !== null || row[k] != null));
|
|
429
|
+
if (Object.keys(set).length)
|
|
430
|
+
await store.write([{ update: s.name, set, where: { id: id }, lock }]);
|
|
431
|
+
return editor(store, s, await current(store, s, id));
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
{ method: "POST", path: "/entries/{id}/publish", role: "editor", run: move("published") },
|
|
435
|
+
{ method: "POST", path: "/entries/{id}/unpublish", role: "editor", run: move("draft") },
|
|
436
|
+
{
|
|
437
|
+
method: "DELETE", path: "/entries/{id}", role: "editor", run: async ({ caller, params: { id }, url }) => {
|
|
438
|
+
const s = schemaOf(url.searchParams.get("collection"));
|
|
439
|
+
writable(s);
|
|
440
|
+
const store = runtime.store.as(caller);
|
|
441
|
+
await current(store, s, id);
|
|
442
|
+
return (await store.write([{ delete: s.name, where: { id: id } }]))[0];
|
|
443
|
+
},
|
|
444
|
+
},
|
|
445
|
+
{ method: "GET", path: "/operations", role: "contributor", run: async ({ caller }) => ({ operations: operations(caller) }) },
|
|
446
|
+
{
|
|
447
|
+
method: "POST", path: "/operations/{name}", role: "contributor", run: async ({ caller, params: { name }, request }) => {
|
|
448
|
+
// an operation the caller cannot see is not there for them, so its name cannot be probed
|
|
449
|
+
if (!staffProcedures.includes(name) || !sees(plan.procedures[name].requires, caller))
|
|
450
|
+
throw wireError("NOT_FOUND", `no staff operation '${name}'`, P);
|
|
451
|
+
const input = await readJsonObject(request, P);
|
|
452
|
+
return { ok: true, output: await runtime.invokeProcedure({ procedure: name, input, caller, cause: { kind: "http", id: crypto.randomUUID() } }) };
|
|
453
|
+
},
|
|
454
|
+
},
|
|
455
|
+
];
|
|
456
|
+
// without the site tables the routes still answer, so Admin's Settings page can say what is missing
|
|
457
|
+
const siteStore = () => runtime.site ?? (() => { throw wireError("SITE_NOT_CONFIGURED", "Site settings need the site tables: give the storage adapter site defaults (d1Storage(db, { site })).", P); })();
|
|
458
|
+
routes.push({ method: "GET", path: "/site-settings", role: "owner", run: async () => settingsOf(await siteStore().read()) }, {
|
|
459
|
+
method: "PATCH", path: "/site-settings", role: "owner", run: async ({ request }) => {
|
|
460
|
+
const body = await readJsonObject(request, P);
|
|
461
|
+
const values = {};
|
|
462
|
+
for (const [k, max] of Object.entries(SETTINGS)) {
|
|
463
|
+
const v = body[k];
|
|
464
|
+
if (v === undefined)
|
|
465
|
+
continue;
|
|
466
|
+
if (typeof v !== "string" || v.length > max)
|
|
467
|
+
throw bad(`'${k}' must be a string of at most ${max} characters`);
|
|
468
|
+
values[k] = v;
|
|
469
|
+
}
|
|
470
|
+
return settingsOf(await siteStore().updateSettings(values));
|
|
471
|
+
},
|
|
472
|
+
});
|
|
473
|
+
routes.push({ method: "GET", path: "/webmcp", role: "contributor", run: async () => webmcp }, {
|
|
474
|
+
// a browser agent's tool call, run as `/mcp/staff` runs it: the same input, an `mcp` cause, the caller's own Store
|
|
475
|
+
method: "POST", path: "/webmcp/{tool}", role: "contributor", run: async ({ caller, params: { tool: name }, request }) => {
|
|
476
|
+
const tool = staffTool.get(name);
|
|
477
|
+
if (!tool)
|
|
478
|
+
throw wireError("NOT_FOUND", `no staff tool '${name}'`, P);
|
|
479
|
+
const input = await readJsonObject(request, P);
|
|
480
|
+
const cause = { kind: "mcp", id: crypto.randomUUID() };
|
|
481
|
+
if (tool.kind === "procedure")
|
|
482
|
+
return { output: await runtime.invokeProcedure({ procedure: tool.source, input, caller, cause }) };
|
|
483
|
+
const { limit, cursor, ...rest } = input;
|
|
484
|
+
return { output: await runtime.store.as(caller, cause).view(tool.source, { input: rest, ...(limit !== undefined ? { limit: limit } : {}), ...(cursor !== undefined ? { cursor: cursor } : {}) }) };
|
|
485
|
+
},
|
|
486
|
+
});
|
|
487
|
+
if (directory)
|
|
488
|
+
routes.push({ method: "GET", path: "/staff", role: "owner", run: async ({ request }) => ({ users: (await directory.listUsers(request)).map(staffInfo) }) }, {
|
|
489
|
+
method: "GET", path: "/members", role: "editor", run: async ({ url: { searchParams: q } }) => {
|
|
490
|
+
const limit = Number(q.get("limit") ?? 50);
|
|
491
|
+
const cursor = q.get("cursor") || undefined;
|
|
492
|
+
const search = q.get("search")?.trim() || undefined;
|
|
493
|
+
if (!Number.isInteger(limit) || limit < 1 || limit > 100 || (cursor && !decodeMemberCursor(cursor)) || (search?.length ?? 0) > 200)
|
|
494
|
+
throw bad("limit must be 1..100, the cursor one this list returned, and search at most 200 characters");
|
|
495
|
+
const r = await directory.listMembers({ limit, ...(search ? { search } : {}), ...(cursor ? { cursor } : {}), cursorDirection: q.get("cursor_direction") === "backward" ? "backward" : "forward" });
|
|
496
|
+
return { items: r.items.map(memberInfo), previous_cursor: r.previousCursor, next_cursor: r.nextCursor };
|
|
497
|
+
},
|
|
498
|
+
});
|
|
499
|
+
if (roles)
|
|
500
|
+
routes.push({
|
|
501
|
+
method: "PATCH", path: "/staff/{id}/role", role: "owner", run: async ({ caller, params: { id }, request }) => {
|
|
502
|
+
const { role } = await readJsonObject(request, P);
|
|
503
|
+
if (role !== null && !(typeof role === "string" && isStaffRole(role)))
|
|
504
|
+
throw bad(`role must be one of ${STAFF_ROLES.join(", ")}, or null to revoke`);
|
|
505
|
+
// demoting the only owner would lock everyone out of staff management
|
|
506
|
+
if (id === caller.subject)
|
|
507
|
+
throw wireError("AUTH_DENIED", "You cannot change your own role.", P);
|
|
508
|
+
if (!await roles.setUserRole(request, id, role))
|
|
509
|
+
throw wireError("NOT_FOUND", "no user with that id", P);
|
|
510
|
+
return { ok: true };
|
|
511
|
+
},
|
|
512
|
+
}, {
|
|
513
|
+
method: "POST", path: "/staff/invitations", role: "owner", run: async ({ caller, request }) => {
|
|
514
|
+
const body = await readJsonObject(request, P);
|
|
515
|
+
const email = typeof body["email"] === "string" ? body["email"].trim().toLowerCase() : "";
|
|
516
|
+
const role = body["role"];
|
|
517
|
+
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) || !(typeof role === "string" && isStaffRole(role)))
|
|
518
|
+
throw bad(`an invitation needs an email and a role in ${STAFF_ROLES.join(", ")}`);
|
|
519
|
+
const r = await roles.inviteUser(request, email, role);
|
|
520
|
+
if (r.kind === "exists") {
|
|
521
|
+
if (r.id === caller.subject)
|
|
522
|
+
throw wireError("AUTH_DENIED", "You cannot change your own role.", P);
|
|
523
|
+
await roles.setUserRole(request, r.id, role);
|
|
524
|
+
}
|
|
525
|
+
await roles.sendStaffInvitation?.(email, role);
|
|
526
|
+
return { ok: true, userId: r.id, emailSent: roles.sendStaffInvitation !== undefined };
|
|
527
|
+
},
|
|
528
|
+
}, {
|
|
529
|
+
method: "DELETE", path: "/staff/invitations/{id}", role: "owner", run: async ({ params: { id } }) => {
|
|
530
|
+
if (!await roles.revokeInvite(id))
|
|
531
|
+
throw wireError("CONFLICT", "Only an invitation nobody has signed in to can be revoked; clear an active user's role instead.", P);
|
|
532
|
+
return { ok: true };
|
|
533
|
+
},
|
|
534
|
+
});
|
|
535
|
+
const api = async (request, url, caller) => {
|
|
536
|
+
if (caller.kind === "anonymous")
|
|
537
|
+
throw wireError("UNAUTHENTICATED", "Sign in to use Admin.", P);
|
|
538
|
+
if (caller.kind !== "user" || caller.role === null)
|
|
539
|
+
throw wireError("AUTH_DENIED", "This account is not on the staff list.", P);
|
|
540
|
+
// Admin acts as the person: a token or key minted for something narrower (an MCP client, a script) is not a sign-in
|
|
541
|
+
if (caller.credential !== "session")
|
|
542
|
+
throw wireError("AUTH_DENIED", "Admin needs a signed-in session.", P);
|
|
543
|
+
const staff = caller;
|
|
544
|
+
for (const route of routes) {
|
|
545
|
+
const params = route.method === request.method ? match(`${base}/api${route.path}`, url.pathname) : null;
|
|
546
|
+
if (!params)
|
|
547
|
+
continue;
|
|
548
|
+
if (!meetsRole(staff.role, route.role))
|
|
549
|
+
return denied(route.role, `This needs the ${route.role} role.`);
|
|
550
|
+
const out = await route.run({ request, url, caller: staff, params });
|
|
551
|
+
return out instanceof Response ? out : json(out, 200, NO_STORE);
|
|
552
|
+
}
|
|
553
|
+
throw wireError("NOT_FOUND", "no such route", P);
|
|
554
|
+
};
|
|
555
|
+
const shell = async (request, rel) => {
|
|
556
|
+
// the path reaches `assets` as the client sent it, so a traversal or an encoded separator stops here
|
|
557
|
+
if (request.method !== "GET" || !options.assets || /(^|\/)\.\.(\/|$)|%2f|%5c|\\/i.test(rel))
|
|
558
|
+
throw wireError("NOT_FOUND", "no such route", P);
|
|
559
|
+
const file = rel.split("/").pop().includes(".") ? await options.assets(rel) : null;
|
|
560
|
+
// an unknown path is a client-side route (`/members/a.b@x.test` too), which the shell answers
|
|
561
|
+
const res = file ?? (rel.startsWith("assets/") ? null : await options.assets("index.html"));
|
|
562
|
+
if (!res)
|
|
563
|
+
throw wireError("NOT_FOUND", "no such route", P);
|
|
564
|
+
// every HTML page is the shell's but the preview, whatever path reached it (`//index.html`, an encoded name)
|
|
565
|
+
const headers = new Headers(res.headers);
|
|
566
|
+
headers.set("x-content-type-options", "nosniff");
|
|
567
|
+
// a built chunk's name carries its hash, so it never changes; a 304 is then never needed
|
|
568
|
+
if (file?.ok && rel.startsWith("assets/"))
|
|
569
|
+
headers.set("cache-control", "public, max-age=31536000, immutable");
|
|
570
|
+
if (file && (rel === "preview.html" || !/^text\/html\b/i.test(res.headers.get("content-type") ?? "")))
|
|
571
|
+
return new Response(res.body, { status: res.status, headers });
|
|
572
|
+
// appended, so a policy the asset already carries stays in force
|
|
573
|
+
headers.append("content-security-policy", "frame-ancestors 'none'");
|
|
574
|
+
headers.set("x-frame-options", "DENY");
|
|
575
|
+
headers.set("cache-control", "no-store");
|
|
576
|
+
return new Response(res.body, { status: res.status, headers });
|
|
577
|
+
};
|
|
578
|
+
return async (request, caller) => {
|
|
579
|
+
const url = new URL(request.url);
|
|
580
|
+
const rel = url.pathname.startsWith(`${base}/`) ? url.pathname.slice(base.length + 1) : url.pathname === base ? "" : null;
|
|
581
|
+
const isApi = rel !== null && (rel === "api" || rel.startsWith("api/"));
|
|
582
|
+
try {
|
|
583
|
+
if (rel === null)
|
|
584
|
+
throw wireError("NOT_FOUND", "no such route", P);
|
|
585
|
+
return isApi ? await api(request, url, caller) : await shell(request, rel);
|
|
586
|
+
}
|
|
587
|
+
catch (e) {
|
|
588
|
+
return failure(e, P, isApi ? NO_STORE : undefined);
|
|
589
|
+
}
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
//# sourceMappingURL=createAdminSurface.js.map
|