@aotter/mantle 0.1.0-alpha.1 → 0.1.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/README.md +105 -26
  2. package/dist/admin.d.ts +2 -0
  3. package/dist/admin.d.ts.map +1 -0
  4. package/dist/admin.js +2 -0
  5. package/dist/admin.js.map +1 -0
  6. package/dist/bun.d.ts +2 -0
  7. package/dist/bun.d.ts.map +1 -0
  8. package/dist/bun.js +2 -0
  9. package/dist/bun.js.map +1 -0
  10. package/dist/cli/create.d.ts +2 -0
  11. package/dist/cli/create.d.ts.map +1 -0
  12. package/dist/cli/create.js +243 -0
  13. package/dist/cli/create.js.map +1 -0
  14. package/dist/cli/generate.d.ts.map +1 -0
  15. package/dist/cli/generate.js +101 -0
  16. package/dist/cli/generate.js.map +1 -0
  17. package/dist/cli/harness.d.ts +3 -0
  18. package/dist/cli/harness.d.ts.map +1 -0
  19. package/dist/{harness-cli.js → cli/harness.js} +13 -8
  20. package/dist/cli/harness.js.map +1 -0
  21. package/dist/cli/main.d.ts +3 -0
  22. package/dist/cli/main.d.ts.map +1 -0
  23. package/dist/{cli.js → cli/main.js} +6 -8
  24. package/dist/cli/main.js.map +1 -0
  25. package/dist/cli/skills.d.ts +3 -0
  26. package/dist/cli/skills.d.ts.map +1 -0
  27. package/dist/{skills.js → cli/skills.js} +51 -6
  28. package/dist/cli/skills.js.map +1 -0
  29. package/dist/cli/update.d.ts.map +1 -0
  30. package/dist/{update.js → cli/update.js} +72 -46
  31. package/dist/cli/update.js.map +1 -0
  32. package/dist/codegen/emitMantleModule.d.ts +16 -0
  33. package/dist/codegen/emitMantleModule.d.ts.map +1 -0
  34. package/dist/codegen/emitMantleModule.js +217 -0
  35. package/dist/codegen/emitMantleModule.js.map +1 -0
  36. package/dist/codegen.d.ts +2 -0
  37. package/dist/codegen.d.ts.map +1 -0
  38. package/dist/codegen.js +2 -0
  39. package/dist/codegen.js.map +1 -0
  40. package/dist/provision/renderProvisionBundle.d.ts +70 -0
  41. package/dist/provision/renderProvisionBundle.d.ts.map +1 -0
  42. package/dist/provision/renderProvisionBundle.js +367 -0
  43. package/dist/provision/renderProvisionBundle.js.map +1 -0
  44. package/dist/provision.d.ts +2 -0
  45. package/dist/provision.d.ts.map +1 -0
  46. package/dist/provision.js +2 -0
  47. package/dist/provision.js.map +1 -0
  48. package/dist/vercel-libsql.d.ts +2 -0
  49. package/dist/vercel-libsql.d.ts.map +1 -0
  50. package/dist/vercel-libsql.js +2 -0
  51. package/dist/vercel-libsql.js.map +1 -0
  52. package/dist/vercel.d.ts +2 -0
  53. package/dist/vercel.d.ts.map +1 -0
  54. package/dist/vercel.js +2 -0
  55. package/dist/vercel.js.map +1 -0
  56. package/dist/web.d.ts +2 -0
  57. package/dist/web.d.ts.map +1 -0
  58. package/dist/web.js +2 -0
  59. package/dist/web.js.map +1 -0
  60. package/docs/adapter-guide.md +94 -47
  61. package/docs/adr/0001-four-atom-manifest-model.md +48 -307
  62. package/docs/adr/0002-closed-enums-for-bindings.md +6 -15
  63. package/docs/adr/0007-ai-as-primary-author.md +6 -4
  64. package/docs/adr/0008-structured-diagnostic-shape.md +2 -2
  65. package/docs/adr/0009-consumer-supplied-manifests.md +15 -9
  66. package/docs/adr/0010-locale-and-translates.md +13 -8
  67. package/docs/adr/0011-adapter-port-spec.md +29 -21
  68. package/docs/adr/0012-views-as-public-rest.md +5 -9
  69. package/docs/adr/0014-auth-better-auth-and-multi-tenant-mcp.md +124 -43
  70. package/docs/adr/0018-core-starters-repository-boundary.md +22 -1
  71. package/docs/adr/0019-sealed-manifest-runtime-pipeline.md +204 -0
  72. package/docs/adr/README.md +16 -14
  73. package/docs/api-mcp-authorization.md +28 -42
  74. package/docs/assets/mantle-admin-operations.png +0 -0
  75. package/docs/assets/mantle-hero.jpg +0 -0
  76. package/docs/auth-hosting-model.md +15 -11
  77. package/docs/cloudflare-low-level-composition.md +30 -18
  78. package/docs/deferred-lifecycle-queues.md +20 -38
  79. package/docs/design-atoms.md +155 -401
  80. package/docs/labels.md +5 -3
  81. package/docs/media-uploads.md +9 -2
  82. package/docs/migration-0.1.2.md +45 -0
  83. package/docs/performance-harness.md +7 -6
  84. package/docs/release-process.md +86 -25
  85. package/docs/schema-indexes.md +1 -1
  86. package/docs/sealed-pipeline-ownership.md +100 -0
  87. package/package.json +84 -14
  88. package/skills/README.md +39 -7
  89. package/skills/develop/SKILL.md +31 -17
  90. package/skills/install/SKILL.md +26 -25
  91. package/skills/media-gc/SKILL.md +85 -0
  92. package/skills/plugin/SKILL.md +2 -1
  93. package/skills/provision/SKILL.md +24 -2
  94. package/skills/theme/SKILL.md +11 -1
  95. package/skills/update/SKILL.md +1 -0
  96. package/dist/cli.d.ts +0 -3
  97. package/dist/cli.d.ts.map +0 -1
  98. package/dist/cli.js.map +0 -1
  99. package/dist/generate.d.ts.map +0 -1
  100. package/dist/generate.js +0 -181
  101. package/dist/generate.js.map +0 -1
  102. package/dist/harness-cli.d.ts +0 -3
  103. package/dist/harness-cli.d.ts.map +0 -1
  104. package/dist/harness-cli.js.map +0 -1
  105. package/dist/skills.d.ts +0 -2
  106. package/dist/skills.d.ts.map +0 -1
  107. package/dist/skills.js.map +0 -1
  108. package/dist/update.d.ts.map +0 -1
  109. package/dist/update.js.map +0 -1
  110. /package/dist/{generate.d.ts → cli/generate.d.ts} +0 -0
  111. /package/dist/{update.d.ts → cli/update.d.ts} +0 -0
@@ -2,20 +2,24 @@
2
2
 
3
3
  This guide is the fresh-developer entry point for implementing a new mantle platform adapter.
4
4
 
5
- Read this with [ADR-0011](adr/0011-adapter-port-spec.md). The source of truth for TypeScript shapes is `packages/mantle-runtime/src/domain/port/`.
5
+ Read this with [ADR-0019](adr/0019-sealed-manifest-runtime-pipeline.md). The source of truth for TypeScript shapes is `packages/mantle-runtime/src/domain/port/`.
6
6
 
7
7
  Adapter packages live under `packages/adapters/<platform>/` using a plural `adapters` bucket. The npm package names stay unchanged, for example `@aotter/mantle-cloudflare`. Keep adapters in this monorepo until the runtime/spec API is stable enough that coordinated releases across separate repositories would not create version skew for starters.
8
8
 
9
- ## Required runtime ports
9
+ ## Required storage boundary
10
10
 
11
- A first-run adapter must implement exactly these two runtime ports:
11
+ A storage adapter prepares one `RuntimePlan` into semantic ports:
12
12
 
13
13
  | Contract | Source | Cloudflare example |
14
14
  |---|---|---|
15
- | `DatabaseDriver` plus `PreparedStatement` and `MigrationRunner` | `packages/mantle-runtime/src/domain/port/DatabaseDriver.ts` | `packages/adapters/cloudflare/src/bindings/D1DatabaseDriver.ts` |
16
- | `AssetServer` | `packages/mantle-runtime/src/domain/port/AssetServer.ts` | `packages/adapters/cloudflare/src/bindings/AssetsAssetServer.ts` |
15
+ | `MantleStorageAdapter` / `PreparedMantleStorage` | `packages/mantle-runtime/src/domain/port/MantleStorageAdapter.ts` | `SqliteMantleStorageAdapter` over `D1DatabaseDriver` |
16
+ | `EntryRepository & EntryReader` | Existing semantic content ports | `DatabaseEntryRepository` supplied by the SQLite adapter |
17
+ | `ViewQueryExecutor` | `packages/mantle-runtime/src/domain/port/ViewQueryExecutor.ts` | `SqliteViewQueryExecutor` |
17
18
 
18
- The runtime must not import platform types such as `D1Database`, `KVNamespace`, Cloudflare `Fetcher`, Netlify request objects, Postgres pools, or adapter SDK types. Those live in adapter packages.
19
+ `DatabaseDriver` is only the reusable SQLite/D1 implementation seam. A
20
+ PostgreSQL, MongoDB, or application-owned-table adapter implements the semantic
21
+ ports directly; it does not emulate D1 and needs no mapping DSL. Platform types
22
+ such as `D1Database`, Postgres pools, and Mongo clients remain in adapter code.
19
23
 
20
24
  ## Optional capabilities
21
25
 
@@ -26,7 +30,7 @@ Optional ports are enabled only when a feature needs them:
26
30
  | `MediaStorage` | `packages/mantle-runtime/src/domain/port/MediaStorage.ts` | The adapter exposes admin/MCP media upload flows. |
27
31
  | `DeferredHookDispatcher` | `packages/mantle-runtime/src/domain/port/DeferredHookDispatcher.ts` | The adapter wants at-least-once queue delivery for `after_*` lifecycle hooks. |
28
32
 
29
- Test seams such as `Clock` and `IdGenerator` are injectable through `createCmsRuntime`, but normal adapters do not need custom implementations.
33
+ Test seams such as `Clock` and `IdGenerator` are injectable through `createMantleRuntime`, but normal adapters do not need custom implementations.
30
34
 
31
35
  Deferred delivery is an optional, versioned wire contract. Queue acceptance is
32
36
  not atomic with the entry write; adapters must preserve the supplied event id,
@@ -35,37 +39,72 @@ to their retry mechanism, and document poison-message/DLQ behavior. See
35
39
  [Deferred lifecycle hooks on Cloudflare Queues](deferred-lifecycle-queues.md)
36
40
  for the reference implementation and exact guarantees.
37
41
 
38
- ## Runtime boot
42
+ ## Storage preparation
39
43
 
40
- Adapters compose the runtime through `createCmsRuntime`:
44
+ Compile before deployment preparation, then pass only the sealed plan:
41
45
 
42
46
  ```ts
43
- import { createCmsRuntime } from "@aotter/mantle-runtime";
44
-
45
- const runtime = createCmsRuntime({
46
- manifests,
47
+ import {
48
+ bootMantleRuntime,
49
+ SqliteMantleStorageAdapter,
50
+ } from "@aotter/mantle-runtime";
51
+
52
+ const storage = new SqliteMantleStorageAdapter(db, siteDefaults);
53
+ const runtime = await bootMantleRuntime({
54
+ plan,
55
+ storage,
47
56
  handlers,
48
- templates,
49
- siteDefaults,
50
- db,
51
- assets,
52
- publicPathResolver,
53
- mediaStorage,
54
- deferredHookDispatcher,
57
+ ports,
58
+ deployment: {
59
+ reservedHttpPathPrefixes: selectedCapabilities.flatMap(
60
+ (capability) => capability.reservedHttpPathPrefixes,
61
+ ),
62
+ },
55
63
  });
64
+ ```
65
+
66
+ `bootMantleRuntime` performs one attempt and derives Procedure readiness from
67
+ the supplied handlers. The platform adapter remains responsible for lazy boot,
68
+ promise caching, retry policy, and teardown.
56
69
 
57
- await runtime.bootInit();
70
+ Hosts that need work between preparation and binding may keep the same stages
71
+ public and explicit:
72
+
73
+ ```ts
74
+ const prepared = await prepareDeployment(plan, storage, {
75
+ handlerNames: Object.keys(handlers ?? {}),
76
+ });
77
+ const runtime = createMantleRuntime({ prepared, handlers, ports });
58
78
  ```
59
79
 
60
- `bootInit()` runs canonical migrations, seeds `siteDefaults`, and validates the manifest set. Call it once before serving CMS traffic. The Cloudflare adapter's reference pattern is `packages/adapters/cloudflare/src/mount/bootRuntimeOnce.ts`.
80
+ The prepared revision carries its exact plan, but exposes both `plan` and
81
+ `storage`; it seals the pairing invariant rather than hiding low-level host
82
+ capabilities. Omit `handlerNames` only for a read-only embedding that never
83
+ dispatches Procedures.
61
84
 
62
- Use purpose-shaped runtime surfaces for canonical data: `runtime.entryReader`
63
- applies Schema index declarations, locale semantics, and the public `Entry`
64
- projection; `runtime.siteConfig` owns site settings. `runtime.db` remains only
65
- for source compatibility and is deprecated. An adapter that owns additional
66
- tables should retain the `DatabaseDriver` it injected instead of reaching back
67
- through the assembled runtime. Authoring continues through the pre-wired
68
- content use cases.
85
+ The official SQLite adapter runs canonical migrations, defaults, indexes, and
86
+ schema-View reconciliation, and skips mutation for an unchanged revision. A
87
+ custom adapter owns its own preparation and returns application-owned semantic
88
+ ports. Unsupported native View dialects fail before the adapter mutates state.
89
+
90
+ ### Bun embedding
91
+
92
+ `@aotter/mantle-bun` is the minimal SQLite reference: pass an application-owned
93
+ `bun:sqlite` `Database` and a compiled `RuntimePlan` to `createBunMantle()`.
94
+ Its `handle()` returns `null` for sibling routes and a Web-standard `Response`
95
+ for manifest-declared public Views and HTTP Triggers. The host owns
96
+ `Bun.serve`, database shutdown, authentication, and CSRF policy; the adapter
97
+ prepares the semantic revision once and retries only after failed preparation.
98
+
99
+ ### Vercel Functions embedding
100
+
101
+ `@aotter/mantle-vercel` accepts a compiled plan plus any application-owned
102
+ `MantleStorageAdapter` and reuses the same public View/HTTP Trigger transport as
103
+ Bun. It maps deferred work to Vercel Functions `waitUntil` and otherwise leaves
104
+ the Web Handler, auth/CSRF, and route composition to the application. The
105
+ optional `/libsql` subpath adapts a caller-owned remote Turso/libSQL client to
106
+ the canonical SQLite chain; the default entry has no database-vendor policy.
107
+ Vercel's read-only filesystem and writable `/tmp` are never durable state.
69
108
 
70
109
  ## HTTP and MCP surfaces
71
110
 
@@ -73,9 +112,10 @@ The runtime is a library, not an HTTP server. A new adapter must mount equivalen
73
112
 
74
113
  | Surface | Adapter responsibility | Cloudflare reference |
75
114
  |---|---|---|
76
- | Public/admin HTTP endpoints | Route HTTP Triggers, View REST endpoints, admin SPA assets, and public render routes into runtime use cases. | `packages/adapters/cloudflare/src/mount/mountServerEndpoints.ts`, `mountPublicRoutes.ts` |
77
- | Auth endpoints | Own sign-in/session/OAuth metadata routes through the adapter's Better Auth integration. | `packages/adapters/cloudflare/src/auth/createAuth.ts`, `mountServerEndpoints.ts` |
78
- | MCP endpoints | Mount `/mcp/staff` and `/mcp` via `createOAuthProvider({ apiHandlers })`; the OAuth lib verifies bearer tokens against its KV grant store, then calls the matching apiHandler with `ctx.props` set. The adapter enforces the staff D1 role inside the apiHandler, then dispatches JSON-RPC. | `packages/adapters/cloudflare/src/mount/mountMcp.ts`, `oauth/oauthSingleton.ts`, `oauth/mountOAuth.ts` |
115
+ | Runtime HTTP endpoints | Route HTTP Triggers and public View REST endpoints into runtime use cases. | `packages/adapters/cloudflare/src/mount/mountRuntimeEndpoints.ts` |
116
+ | Optional Admin | Supply session/request context and assets to `mantle-admin`; mount only when selected. | `packages/adapters/cloudflare/src/mount/mountAdmin.ts` |
117
+ | Auth endpoints | Own sign-in/session/OAuth metadata through the adapter's Better Auth implementation selected by Admin/OAuth surfaces. | `packages/adapters/cloudflare/src/auth/createAuth.ts` |
118
+ | MCP endpoints | Mount `/mcp/staff` and `/mcp` behind one canonical protected resource. The adapter verifies Better Auth JWTs, normalizes the caller, re-reads the staff D1 role, then dispatches JSON-RPC. | `packages/adapters/cloudflare/src/mount/mountMcp.ts`, `auth/createAuth.ts` |
79
119
 
80
120
  Auth is not a runtime port. Per [ADR-0014](adr/0014-auth-better-auth-and-multi-tenant-mcp.md), the adapter owns Better Auth wiring and passes authenticated user/staff context into runtime dispatchers. Procedure handlers receive that data through `HandlerContext` in `packages/mantle-runtime/src/domain/model/HandlerContext.ts`.
81
121
 
@@ -93,7 +133,7 @@ Minimum HTTP behavior for a full adapter:
93
133
  - Route manifest HTTP Triggers to `runtime.invokeProcedure`.
94
134
  - Route `GET /api/views/<name>` to `runtime.executeView`.
95
135
  - Mount admin content APIs with session/role checks before calling runtime content use cases.
96
- - Serve admin SPA assets through `AssetServer`, with an SPA catchall for admin client-side routes.
136
+ - Serve selected Admin SPA assets through `AdminAssetServer`, with an SPA catchall for client-side routes.
97
137
  - Mount public render routes and markdown mirrors when the starter exposes public pages.
98
138
  - Translate runtime diagnostics and validation failures into stable HTTP JSON responses instead of throwing raw errors.
99
139
  - Evaluate target auth and dynamic guards through the runtime use cases; do
@@ -101,22 +141,27 @@ Minimum HTTP behavior for a full adapter:
101
141
 
102
142
  For the Cloudflare adapter, public rendering requires three matching consumer
103
143
  inputs: `mountPublicRoutes(...)` route declarations, a `TemplateRegistry`
104
- passed through `CmsConfig.templates`, and a `publicPathResolver` passed through
105
- `CmsConfig.publicPathResolver`. Omitting public routes is valid for a headless
144
+ passed through `MantleCloudflareConfig.templates`, and a `publicPathResolver`
145
+ passed through `MantleCloudflareConfig.publicPathResolver`. Omitting public routes is valid for a headless
106
146
  consumer; mounting every Schema automatically is not, because some collections
107
147
  are private even when they contain a slug.
108
148
 
149
+ `TemplateRegistry` and `createPublicPathResolver` come from
150
+ `@aotter/mantle-web`. Other adapters can call `createMantleWeb(runtime)` and map
151
+ its document operations into their own routing and cache conventions.
152
+
109
153
  ### HTTP cache contract
110
154
 
111
- The Cloudflare adapter is private by default. Consumers must export
112
- `createOAuthProvider(...)` as the Worker's top-level handler so its final
113
- response policy covers admin, auth, API, OAuth, MCP, redirects, and errors.
155
+ The Cloudflare adapter is private by default. Consumers must apply its final
156
+ cache policy after admin, auth, API, OAuth, MCP, application routes, redirects,
157
+ and errors.
114
158
  Those responses receive `Cache-Control: private, no-store`; Cloudflare-specific
115
159
  CDN cache overrides are removed.
116
160
 
117
161
  `mountPublicRoutes(...)` renders canonical D1 state and opts only successful HTML, markdown,
118
162
  `llms.txt`, and sitemap responses into the shared cache with
119
- `Cache-Control: public, max-age=0, s-maxage=300`. The top-level policy preserves
163
+ `Cache-Control: public, max-age=0, s-maxage=300` and the site-level
164
+ `Cache-Tag: mantle-public`. The top-level policy preserves
120
165
  that opt-in only for anonymous `GET`/`HEAD` responses with status 200, explicit
121
166
  shared freshness, no request `Cookie` or `Authorization`, and no response
122
167
  `Set-Cookie`. It also varies public responses by `Cookie` and `Authorization`.
@@ -124,7 +169,10 @@ shared freshness, no request `Cookie` or `Authorization`, and no response
124
169
  A starter-level Workers Cache may therefore store only responses that still
125
170
  meet that exact public contract. It must bypass credentialed/cookie requests
126
171
  and must never infer cacheability from a URL prefix. Cache entries remain
127
- version-local; cross-version caching is outside this contract.
172
+ version-local; cross-version caching is outside this contract. Successful
173
+ publishing-content and site-setting mutations purge `mantle-public` through
174
+ Cloudflare's native cache API. Operational records and immutable assets do not
175
+ purge the public render cache.
128
176
 
129
177
  Minimum auth/MCP behavior:
130
178
 
@@ -142,20 +190,19 @@ Minimum auth/MCP behavior:
142
190
 
143
191
  ## Static assets
144
192
 
145
- `AssetServer` is required because every adapter must have a strategy for serving the prebuilt admin UI from `@aotter/mantle-admin-ui`. The adapter may serve those files from platform assets, a static publish directory, object storage plus CDN, or a filesystem bundle. Return `null` from `AssetServer.fetch()` when a specific asset is not found so the adapter can fall back to the admin SPA catchall.
193
+ `AdminAssetServer` belongs to optional `@aotter/mantle-admin`. Headless Core
194
+ storage preparation and binding do not accept or require a static asset port.
146
195
 
147
196
  ## Implementation checklist
148
197
 
149
- - [ ] Implement `DatabaseDriver`, including canonical migration tracking.
150
- - [ ] Implement `AssetServer` for the admin UI assets.
151
- - [ ] Compose `createCmsRuntime` with manifests, handlers, templates, site defaults, and required ports.
152
- - [ ] Call `bootInit()` before serving CMS traffic.
198
+ - [ ] Implement `MantleStorageAdapter` returning existing semantic ports, or reuse `SqliteMantleStorageAdapter` with an already-owned handle.
199
+ - [ ] Call `bootMantleRuntime()` once per semantic revision, or explicitly prepare before binding.
153
200
  - [ ] Mount HTTP Trigger and View REST surfaces.
154
201
  - [ ] Mount admin/public render routes and admin SPA assets.
155
202
  - [ ] Provide adapter-owned Better Auth wiring and session helpers.
156
203
  - [ ] Normalize session/OAuth and any consumer credential seam into
157
204
  `HandlerContext.auth`; never put raw credentials in runtime context.
158
- - [ ] Mount `/mcp/staff` and `/mcp` via the platform's OAuth provider lib (Cloudflare adapter uses `@cloudflare/workers-oauth-provider` at top level). Enforce staff D1 role inside the apiHandler.
205
+ - [ ] Mount `/mcp/staff` and `/mcp` behind one resource-bound token verifier. Enforce the live staff role inside the apiHandler.
159
206
  - [ ] Preserve the HTTP cache contract: private by default; explicit anonymous 200 `GET`/`HEAD` public opt-in only.
160
207
  - [ ] Prove one guarded target has identical REST/MCP outcomes, including
161
208
  mutable revocation on the next call.
@@ -170,4 +217,4 @@ Minimum auth/MCP behavior:
170
217
  - Do not add API-key, personal-token, transaction, billing, or entitlement
171
218
  repositories to Core. They are consumer state behind the adapter resolver
172
219
  and guard Procedure.
173
- - Do not add a second canonical migration chain for a new adapter. The runtime owns canonical migrations; adapters execute them through `DatabaseDriver.migrations`.
220
+ - Do not generalize `DatabaseDriver` for PostgreSQL/MongoDB or add a mapping DSL. Implement semantic ports; SQLite/D1 alone reuse the canonical SQL chain.