@aotter/mantle 0.1.0-alpha.3 → 0.1.0-alpha.4
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 +40 -3
- package/dist/generate.d.ts.map +1 -1
- package/dist/generate.js +30 -2
- package/dist/generate.js.map +1 -1
- package/docs/auth-hosting-model.md +10 -6
- package/docs/design-atoms.md +67 -22
- package/package.json +5 -5
- package/skills/develop/SKILL.md +12 -9
- package/skills/provision/SKILL.md +18 -2
- package/skills/theme/SKILL.md +9 -0
package/README.md
CHANGED
|
@@ -43,8 +43,10 @@ pnpm exec mantle-harness indexes --require-public
|
|
|
43
43
|
pnpm exec mantle-harness http --base-url http://127.0.0.1:8787 --route page=/en/example
|
|
44
44
|
```
|
|
45
45
|
|
|
46
|
-
`mantle generate` validates `./manifests/site.yaml`,
|
|
47
|
-
parsed manifest module and handler declarations to `.mantle/generated
|
|
46
|
+
`mantle generate` validates `./manifests/site.yaml`, writes the
|
|
47
|
+
parsed manifest module and handler declarations to `.mantle/generated/`, and
|
|
48
|
+
copies the version-matched Admin SPA to `public/_mantle/admin/` for the
|
|
49
|
+
platform's static asset service. `--check` verifies both outputs.
|
|
48
50
|
It does not sync skills, update packages, style, provision, or deploy.
|
|
49
51
|
When manifests declare Views or Procedures, the generated `site.ts` also exports
|
|
50
52
|
`bindMantleSite(runtime)`: its `views` and `procedures` keys, inputs, and outputs
|
|
@@ -91,16 +93,25 @@ per-isolate boot. Use its single `extend` seam for application handlers and
|
|
|
91
93
|
new Hono routes; use the public low-level exports when the deployment does not
|
|
92
94
|
fit the conventional binding or lifecycle contract.
|
|
93
95
|
|
|
96
|
+
Conventional Auth requires an explicit `MANTLE_AUTH_MODE`: `self-managed`
|
|
97
|
+
uses the site's GitHub OAuth credentials, while `hosted` uses a same-origin
|
|
98
|
+
Mantle Hosted Auth PKCE client. Missing, invalid, partial, or mixed-mode
|
|
99
|
+
configuration keeps public routes available but returns `503 setup_incomplete`
|
|
100
|
+
from Auth-owned private routes. Pass `auth: (env) => Auth` only when the site
|
|
101
|
+
needs to replace this conventional factory; Core still owns the Auth routes.
|
|
102
|
+
The exact bindings and validation rules are in the
|
|
103
|
+
[Cloudflare adapter README](../adapters/cloudflare/README.md#conventional-auth).
|
|
104
|
+
|
|
94
105
|
Extensions may add routes but may not replace Core surfaces. These paths are
|
|
95
106
|
reserved:
|
|
96
107
|
|
|
97
108
|
- `/admin` and `/admin/*`
|
|
109
|
+
- `/_mantle` and `/_mantle/*`
|
|
98
110
|
- `/api/auth` and `/api/auth/*`
|
|
99
111
|
- `/api/views` and `/api/views/*`
|
|
100
112
|
- `/oauth` and `/oauth/*`
|
|
101
113
|
- `/mcp` and `/mcp/*`
|
|
102
114
|
- `/.well-known/oauth*`
|
|
103
|
-
- `/favicon.svg`
|
|
104
115
|
- global `*` and `/*` handlers
|
|
105
116
|
|
|
106
117
|
A custom Auth factory's `basePath` and exact manifest-owned method/path pairs
|
|
@@ -109,6 +120,32 @@ the consumer build. Computed paths cannot be proven statically, so the facade
|
|
|
109
120
|
checks Hono's assembled route table and fails closed before serving requests.
|
|
110
121
|
There is no standard-route override option.
|
|
111
122
|
|
|
123
|
+
Cloudflare projects expose that generated Admin bundle and the site's own
|
|
124
|
+
frontend assets through one native binding:
|
|
125
|
+
|
|
126
|
+
```toml
|
|
127
|
+
[assets]
|
|
128
|
+
directory = "./public"
|
|
129
|
+
binding = "ASSETS"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Declare browser, Admin, and MCP identity once. Multiple renditions are allowed;
|
|
133
|
+
keep SVG as the source and add PNG renditions when a target MCP client requires
|
|
134
|
+
the baseline raster formats:
|
|
135
|
+
|
|
136
|
+
```ts
|
|
137
|
+
siteDefaults: {
|
|
138
|
+
icons: [
|
|
139
|
+
{ src: "/site-icon.png", mimeType: "image/png", sizes: ["64x64"] },
|
|
140
|
+
{ src: "/site-icon.svg", mimeType: "image/svg+xml", sizes: ["any"] },
|
|
141
|
+
],
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Keep both files in the project's `public/` directory. They are one site
|
|
146
|
+
identity reused by browser favicons, Admin chrome, and MCP `serverInfo.icons`;
|
|
147
|
+
PNG is the compatibility rendition and SVG remains the editable source.
|
|
148
|
+
|
|
112
149
|
For an uncommon deployment that must own the top-level assembly, use the
|
|
113
150
|
embedded [`docs/cloudflare-low-level-composition.md`](docs/cloudflare-low-level-composition.md)
|
|
114
151
|
fixture. It composes the same public primitives without importing package
|
package/dist/generate.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAqBA,wBAAsB,WAAW,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA6C7E"}
|
package/dist/generate.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
1
|
+
import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
2
3
|
import { dirname, join, resolve } from "node:path";
|
|
3
4
|
import { cwd, stderr, stdout } from "node:process";
|
|
4
5
|
import { parseArgs } from "node:util";
|
|
@@ -40,6 +41,9 @@ export async function runGenerate(rawArgs) {
|
|
|
40
41
|
for (const [path, source] of files) {
|
|
41
42
|
stale = !(await syncText(path, source, options.check)) || stale;
|
|
42
43
|
}
|
|
44
|
+
const adminSource = dirname(fileURLToPath(import.meta.resolve("@aotter/mantle-admin-ui/index.html")));
|
|
45
|
+
const adminTarget = resolve(cwd(), "public/_mantle/admin");
|
|
46
|
+
stale = !(await syncAdminAssets(adminSource, adminTarget, options.check)) || stale;
|
|
43
47
|
if (stale && options.check) {
|
|
44
48
|
stderr.write("Mantle generated files are stale; run `mantle generate`.\n");
|
|
45
49
|
return 1;
|
|
@@ -79,7 +83,7 @@ Options:
|
|
|
79
83
|
--manifests <dir> Directory containing site.yaml (default: ./manifests)
|
|
80
84
|
-o, --output <dir> Generated root (default: .mantle/generated)
|
|
81
85
|
--namespace <name> Generated type namespace (default: MantleSite)
|
|
82
|
-
--check Fail without writing when
|
|
86
|
+
--check Fail without writing when generated code or Admin assets are stale
|
|
83
87
|
-h, --help This help
|
|
84
88
|
`);
|
|
85
89
|
}
|
|
@@ -192,6 +196,30 @@ async function syncText(path, expected, check) {
|
|
|
192
196
|
await writeFile(path, expected, "utf8");
|
|
193
197
|
return true;
|
|
194
198
|
}
|
|
199
|
+
async function syncAdminAssets(source, target, check) {
|
|
200
|
+
const sourceFiles = (await listFiles(source)).filter((path) => !path.startsWith("server."));
|
|
201
|
+
const targetFiles = await listFiles(target).catch(() => []);
|
|
202
|
+
const current = sourceFiles.length === targetFiles.length
|
|
203
|
+
&& sourceFiles.every((path, index) => path === targetFiles[index])
|
|
204
|
+
&& (await Promise.all(sourceFiles.map(async (path) => (await readFile(join(source, path))).equals(await readFile(join(target, path)))))).every(Boolean);
|
|
205
|
+
if (current || check)
|
|
206
|
+
return current;
|
|
207
|
+
await rm(target, { recursive: true, force: true });
|
|
208
|
+
for (const path of sourceFiles) {
|
|
209
|
+
const destination = join(target, path);
|
|
210
|
+
await mkdir(dirname(destination), { recursive: true });
|
|
211
|
+
await writeFile(destination, await readFile(join(source, path)));
|
|
212
|
+
}
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
async function listFiles(root, prefix = "") {
|
|
216
|
+
const entries = await readdir(join(root, prefix), { withFileTypes: true });
|
|
217
|
+
const files = await Promise.all(entries.map((entry) => {
|
|
218
|
+
const path = join(prefix, entry.name);
|
|
219
|
+
return entry.isDirectory() ? listFiles(root, path) : [path];
|
|
220
|
+
}));
|
|
221
|
+
return files.flat().sort();
|
|
222
|
+
}
|
|
195
223
|
function message(error) {
|
|
196
224
|
return error instanceof Error ? error.message : String(error);
|
|
197
225
|
}
|
package/dist/generate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,8 +5,10 @@ basic login. The split is:
|
|
|
5
5
|
|
|
6
6
|
- **Mantle SDK** gives every generated site the primitives needed to
|
|
7
7
|
run its own auth.
|
|
8
|
-
- **Mantle
|
|
9
|
-
self-hosted
|
|
8
|
+
- **Mantle's conventional Cloudflare adapter** runs the generated site's
|
|
9
|
+
selected self-hosted or Mantle Platform hosted client configuration.
|
|
10
|
+
- **Mantle starters** declare the mode and provider placeholders that landing
|
|
11
|
+
or the site owner completes.
|
|
10
12
|
- **Mantle Platform** can sell hosted identity, provider setup, email,
|
|
11
13
|
and billing convenience for site owners who do not want to operate
|
|
12
14
|
those pieces.
|
|
@@ -117,10 +119,12 @@ Landing can probe Platform staff/session state, but provisioning's
|
|
|
117
119
|
GitHub OAuth token is still Landing-owned unless a separate token
|
|
118
120
|
handoff design is introduced.
|
|
119
121
|
|
|
120
|
-
The
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
The conventional hosted-auth client wiring belongs in Core's Cloudflare
|
|
123
|
+
adapter. Starters declare its environment bindings; landing supplies an
|
|
124
|
+
allocated client. A site can still replace Auth construction through
|
|
125
|
+
`createMantleWorker({ auth })` when it needs a different curated identity
|
|
126
|
+
design. Core continues to own the normalized manifest/runtime credential
|
|
127
|
+
vocabulary (`ctx.user`, `ctx.staff`, `ctx.auth`) and guard orchestration.
|
|
124
128
|
|
|
125
129
|
## API and MCP Authorization
|
|
126
130
|
|
package/docs/design-atoms.md
CHANGED
|
@@ -139,6 +139,18 @@ and be the first field of an `indexes` or `uniqueIndexes` tuple. Admin reuses
|
|
|
139
139
|
the enum for sidebar links and list tabs; Staff MCP uses declared Views for
|
|
140
140
|
richer query capabilities instead of reading UI configuration.
|
|
141
141
|
|
|
142
|
+
Operational list data is also explicit: `uiSchema.list.primaryField` names the
|
|
143
|
+
linked leading value and `uiSchema.list.columns` names the remaining scalar
|
|
144
|
+
columns. Without them Admin shows only platform metadata. Form-only choices use
|
|
145
|
+
`uiSchema.fields.<field>.widget: textarea`; rich content remains declared with
|
|
146
|
+
`x-mcp-hint: markdown|html|richtext`. Neither setting changes runtime or MCP
|
|
147
|
+
input validation.
|
|
148
|
+
|
|
149
|
+
A staff-operable Procedure may declare `uiSchema.collectionAction: orders` to
|
|
150
|
+
appear as an action in that collection's Admin header. The target must be an
|
|
151
|
+
existing Schema. This binding is Admin-only; the Procedure input, authorization,
|
|
152
|
+
runtime handler, and MCP exposure remain unchanged.
|
|
153
|
+
|
|
142
154
|
**`spec.localized: bool`** (default `false`, ADR-0010) — opt-in per
|
|
143
155
|
Schema. Localized Schemas store locale in `data.locale`; non-localized
|
|
144
156
|
Schemas reject `data.locale` writes. Site config must declare the set
|
|
@@ -179,6 +191,13 @@ The modes are **per-Schema and mix freely** within a site. There is no
|
|
|
179
191
|
site-wide lifecycle setting; one Schema can be `publishing` while another
|
|
180
192
|
is `operational`.
|
|
181
193
|
|
|
194
|
+
**Root `schema.readOnly: true`** — standard JSON Schema annotation for a
|
|
195
|
+
Procedure-managed collection. Admin and Staff MCP keep list/detail access and
|
|
196
|
+
declared row Procedures, but suppress and reject generic create, update,
|
|
197
|
+
status-change, and delete operations. Trusted Procedure handlers may still use
|
|
198
|
+
the runtime write use cases to maintain the projection. Put this on operational
|
|
199
|
+
mirrors and audit rows whose authority lives outside generic authoring.
|
|
200
|
+
|
|
182
201
|
**Property-level extensions** (JSON Schema vendor keywords, all optional):
|
|
183
202
|
|
|
184
203
|
These are the standard `x-` prefix that JSON Schema reserves for
|
|
@@ -238,6 +257,12 @@ Declare a single-field `indexes` entry for the ref field (for example,
|
|
|
238
257
|
`indexes: [[authorId]]`) when reverse lookups must stay bounded. Mantle adds
|
|
239
258
|
the native entry-order columns to that access path.
|
|
240
259
|
|
|
260
|
+
On a Procedure input property, the Admin also uses `x-mantle-ref` to expose
|
|
261
|
+
that Procedure in the referenced collection row's three-dot menu. It locks
|
|
262
|
+
the referenced value to the selected row and infers the remaining form from
|
|
263
|
+
the Procedure input schema. The value comes from a same-named Schema property,
|
|
264
|
+
then a lone single-field unique index, and finally the entry `id`.
|
|
265
|
+
|
|
241
266
|
**Example**:
|
|
242
267
|
```yaml
|
|
243
268
|
authorId:
|
|
@@ -257,7 +282,9 @@ Descriptive hint for AI agents and admin UI widgets. The string is
|
|
|
257
282
|
accepted as free-form for forward compatibility, but conventional
|
|
258
283
|
values (`markdown`, `richtext`, `code`, `media`, `media-image`,
|
|
259
284
|
`media-video`, `media-file`) tell consumers how to render or generate
|
|
260
|
-
the field's value.
|
|
285
|
+
the field's value. `idempotency-key` asks the Admin to generate and hide a
|
|
286
|
+
stable UUID for one form invocation; other callers must generate one and reuse
|
|
287
|
+
it when retrying the same operation.
|
|
261
288
|
|
|
262
289
|
**Examples** (from the publication/blog starter manifests):
|
|
263
290
|
```yaml
|
|
@@ -285,10 +312,11 @@ UNIQUE (slug, locale));`
|
|
|
285
312
|
|
|
286
313
|
### 2. `View` — the read surface (auto-exposed by surface)
|
|
287
314
|
|
|
288
|
-
A named,
|
|
289
|
-
|
|
290
|
-
`
|
|
291
|
-
|
|
315
|
+
A named, read-only SQL query over Schemas. Every Schema is available to SQL as
|
|
316
|
+
a logical table named after `Schema.metadata.name`; storage internals stay
|
|
317
|
+
hidden. No Trigger is required. `surface` is required: `surface: public` mounts
|
|
318
|
+
at `GET /api/views/<name>` and becomes `query_view_<name>` on `/mcp`, while
|
|
319
|
+
`surface: staff` mounts at `GET /admin/api/views/<name>` behind the
|
|
292
320
|
staff gate and appears only on `/mcp/staff`. See ADR-0012 for the full design
|
|
293
321
|
rationale.
|
|
294
322
|
|
|
@@ -297,34 +325,35 @@ apiVersion: cms.mantle.aotter.net/v1
|
|
|
297
325
|
kind: View
|
|
298
326
|
metadata: { name: recent-published }
|
|
299
327
|
spec:
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
328
|
+
surface: public
|
|
329
|
+
sql: |
|
|
330
|
+
SELECT id, title, slug, locale, publishedAt, updatedAt
|
|
331
|
+
FROM posts
|
|
332
|
+
WHERE status = 'published'
|
|
333
|
+
ORDER BY updatedAt DESC
|
|
306
334
|
limit: 20
|
|
307
335
|
```
|
|
308
336
|
|
|
309
337
|
**Param-driven Views** declare `spec.params` (a JSON Schema with
|
|
310
|
-
`type: object`);
|
|
311
|
-
|
|
338
|
+
`type: object`); SQL references required properties as named `:params`. The
|
|
339
|
+
runtime validates and binds them; it never interpolates caller values:
|
|
312
340
|
|
|
313
341
|
```yaml
|
|
314
342
|
apiVersion: cms.mantle.aotter.net/v1
|
|
315
343
|
kind: View
|
|
316
344
|
metadata: { name: posts-by-locale }
|
|
317
345
|
spec:
|
|
318
|
-
|
|
346
|
+
surface: public
|
|
347
|
+
sql: |
|
|
348
|
+
SELECT id, slug, locale, title, updatedAt
|
|
349
|
+
FROM post-translations
|
|
350
|
+
WHERE status = 'published' AND locale = :locale
|
|
351
|
+
ORDER BY slug ASC
|
|
319
352
|
params:
|
|
320
353
|
type: object
|
|
321
354
|
properties:
|
|
322
355
|
locale: { type: string }
|
|
323
356
|
required: [locale]
|
|
324
|
-
filter:
|
|
325
|
-
and:
|
|
326
|
-
- eq: { field: status, value: published }
|
|
327
|
-
- eq: { field: locale, value: { $param: locale } }
|
|
328
357
|
limit: 100
|
|
329
358
|
```
|
|
330
359
|
|
|
@@ -334,6 +363,22 @@ names — `page` / `show` / `cursor` — must NOT appear in
|
|
|
334
363
|
`spec.params.properties` (the parser rejects with
|
|
335
364
|
`VIEW_PARAMS_RESERVED_NAME`).
|
|
336
365
|
|
|
366
|
+
Staff report lists may opt into the Admin's standard columns, substring
|
|
367
|
+
search, and exact filters without changing the public REST/MCP contract:
|
|
368
|
+
|
|
369
|
+
```yaml
|
|
370
|
+
uiSchema:
|
|
371
|
+
list:
|
|
372
|
+
columns: [orderNumber, customerName, orderStatus]
|
|
373
|
+
searchFields: [orderNumber, customerName, customerEmail]
|
|
374
|
+
filterFields: [orderStatus]
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
These names are SQL output aliases. The Admin applies search and filters
|
|
378
|
+
before pagination and carries them into
|
|
379
|
+
`GET /admin/api/views/<name>/export`; the CSV contains all matching rows,
|
|
380
|
+
not only the visible page.
|
|
381
|
+
|
|
337
382
|
Views may declare the same `requires.auth.all` predicates and optional
|
|
338
383
|
`requires.guard.procedure` as Procedures. Static auth runs before parameter
|
|
339
384
|
validation; the guard receives validated params and authorizes the whole
|
|
@@ -349,10 +394,10 @@ Response envelope:
|
|
|
349
394
|
`hasMore` is the lazy form: `rows.length === show` ⇒ `true`. No COUNT
|
|
350
395
|
query, no `LIMIT n+1` probe.
|
|
351
396
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
397
|
+
The previous `from` / `fields` / `filter` / `orderBy` declarative form remains
|
|
398
|
+
accepted for existing manifests. New Views should use one `SELECT`; writes,
|
|
399
|
+
multiple statements, semicolons, and combining SQL with the legacy clauses are
|
|
400
|
+
rejected.
|
|
356
401
|
|
|
357
402
|
**Postgres analogue**: `CREATE VIEW recent_published AS SELECT ...
|
|
358
403
|
FROM posts WHERE status = 'published' ORDER BY updated_at DESC LIMIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aotter/mantle",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.4",
|
|
4
4
|
"description": "Umbrella entry for @aotter/mantle. Adopters install this one package and import from subpaths: /spec, /runtime, /cloudflare, /admin-ui. Sub-packages remain individually installable on npm for tooling and adapter authors.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://mantle.tools/",
|
|
@@ -55,10 +55,10 @@
|
|
|
55
55
|
"README.md"
|
|
56
56
|
],
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@aotter/mantle-admin-ui": "0.1.0-alpha.
|
|
59
|
-
"@aotter/mantle-
|
|
60
|
-
"@aotter/mantle-spec": "0.1.0-alpha.
|
|
61
|
-
"@aotter/mantle-
|
|
58
|
+
"@aotter/mantle-admin-ui": "0.1.0-alpha.4",
|
|
59
|
+
"@aotter/mantle-cloudflare": "0.1.0-alpha.4",
|
|
60
|
+
"@aotter/mantle-spec": "0.1.0-alpha.4",
|
|
61
|
+
"@aotter/mantle-runtime": "0.1.0-alpha.4"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"@cloudflare/workers-oauth-provider": "^0.8.2",
|
package/skills/develop/SKILL.md
CHANGED
|
@@ -107,9 +107,11 @@ the atoms cannot express the behavior.
|
|
|
107
107
|
besides `locale` and the join field.
|
|
108
108
|
- Parallel locale blocks must keep field names, option values, step IDs, and
|
|
109
109
|
result keys identical; translate display strings only.
|
|
110
|
-
- `siteDefaults.origin` and `siteDefaults.
|
|
111
|
-
boot-synced.
|
|
112
|
-
|
|
110
|
+
- `siteDefaults.origin`, `siteDefaults.locales`, and `siteDefaults.icons` are
|
|
111
|
+
code-owned and boot-synced. The icon list is shared by browser favicons,
|
|
112
|
+
Admin chrome, and MCP `serverInfo.icons`; keep its static files under
|
|
113
|
+
`public/`. Brand, title, and description seed once, then change through site
|
|
114
|
+
settings.
|
|
113
115
|
- When changing an existing collection from `[slug]` to `[slug, locale]`,
|
|
114
116
|
boot with a Mantle version that reconciles obsolete unique indexes and test
|
|
115
117
|
the same slug in two locales. Do not patch D1 manually.
|
|
@@ -135,12 +137,13 @@ teaching the project Mantle internals.
|
|
|
135
137
|
|
|
136
138
|
## Auth Composition
|
|
137
139
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
140
|
+
Conventional Cloudflare projects declare `MANTLE_AUTH_MODE=hosted` or
|
|
141
|
+
`self-managed`; Core owns that standard Auth composition and rejects partial
|
|
142
|
+
or mixed bindings. Preserve the explicit mode recorded in launch state and
|
|
143
|
+
Worker config, keep provider secrets out of source, and do not infer a mode
|
|
144
|
+
from whichever credentials happen to be present. A repo with an explicit
|
|
145
|
+
`createMantleWorker({ auth })` override owns that custom composition; follow
|
|
146
|
+
its handoff instead of replacing it with the conventional factory.
|
|
144
147
|
|
|
145
148
|
## Performance Loop
|
|
146
149
|
|
|
@@ -62,6 +62,9 @@ directly; boot syncs its canonical origin from `PUBLIC_ORIGIN`.
|
|
|
62
62
|
hosted allocation and client configuration. Mantle Platform operates the
|
|
63
63
|
identity provider; do not ask the user for a per-site GitHub OAuth App.
|
|
64
64
|
|
|
65
|
+
Configure only the selected mode. Core deliberately rejects partial or mixed
|
|
66
|
+
hosted/self-managed bindings with `503 setup_incomplete`.
|
|
67
|
+
|
|
65
68
|
Do not claim that hosted auth can attach to an arbitrary local repo unless the
|
|
66
69
|
current Mantle landing flow explicitly supplies that handoff.
|
|
67
70
|
|
|
@@ -78,11 +81,15 @@ For the exact boundary, read
|
|
|
78
81
|
|
|
79
82
|
2. Put non-secret values in `wrangler.toml`:
|
|
80
83
|
|
|
84
|
+
- `MANTLE_AUTH_MODE = "self-managed"`
|
|
81
85
|
- `PUBLIC_ORIGIN`
|
|
82
86
|
- `GITHUB_CLIENT_ID`
|
|
83
87
|
- `ADMIN_GITHUB_LOGIN`
|
|
84
88
|
- correct Worker `name`
|
|
85
89
|
|
|
90
|
+
Remove `MANTLE_HOSTED_AUTH_ISSUER` and `MANTLE_HOSTED_AUTH_CLIENT_ID` if they
|
|
91
|
+
were present for a hosted allocation.
|
|
92
|
+
|
|
86
93
|
3. Keep the Client Secret out of chat. Prefer a Cloudflare connector for
|
|
87
94
|
secrets; otherwise use hidden shell input:
|
|
88
95
|
|
|
@@ -108,8 +115,17 @@ pnpm deploy
|
|
|
108
115
|
## Hosted Auth
|
|
109
116
|
|
|
110
117
|
Follow the landing handoff and generated client configuration. Hosted
|
|
111
|
-
configuration remains in landing-managed Cloudflare Worker bindings
|
|
112
|
-
|
|
118
|
+
configuration remains in landing-managed Cloudflare Worker bindings. Verify:
|
|
119
|
+
|
|
120
|
+
- `MANTLE_AUTH_MODE = "hosted"`;
|
|
121
|
+
- `MANTLE_HOSTED_AUTH_ISSUER` is the HTTPS root issuer;
|
|
122
|
+
- `MANTLE_HOSTED_AUTH_CLIENT_ID` is the same-origin `/clients/<id>` URL;
|
|
123
|
+
- `PUBLIC_ORIGIN` and `ADMIN_GITHUB_LOGIN` are set;
|
|
124
|
+
- `BETTER_AUTH_SECRET` exists as a Worker secret;
|
|
125
|
+
- `GITHUB_CLIENT_ID` and `GITHUB_CLIENT_SECRET` are absent.
|
|
126
|
+
|
|
127
|
+
Hosted clients use PKCE and have no client secret. Do not write secrets into
|
|
128
|
+
`wrangler.toml`.
|
|
113
129
|
|
|
114
130
|
Verify that admin sign-in redirects to Mantle Hosted Auth and Staff MCP
|
|
115
131
|
authenticates, then skip the self-hosted flow.
|
package/skills/theme/SKILL.md
CHANGED
|
@@ -26,6 +26,11 @@ tokens, or recipes, but the skill contract is Core-owned.
|
|
|
26
26
|
its `:root` and `.dark` values; runtime components inherit those variables.
|
|
27
27
|
- `components/` is the runtime-facing component surface when present.
|
|
28
28
|
`src/web/` is project-owned composition; put new sections there.
|
|
29
|
+
- `public/site-icon.svg` and `public/site-icon.png` are one site identity.
|
|
30
|
+
Keep both listed in `src/mantle/config.ts > siteDefaults.icons`: PNG first as
|
|
31
|
+
the 64x64 compatibility rendition, then SVG as the editable `any` size source.
|
|
32
|
+
The same list drives browser favicons, Admin chrome, and MCP
|
|
33
|
+
`serverInfo.icons`; do not edit generated files under `public/_mantle/`.
|
|
29
34
|
- If the project includes a vendored UI reference palette, treat it as
|
|
30
35
|
offline source material and provenance, not runtime source. Copy only a
|
|
31
36
|
needed primitive or block into the project's runtime directories, or
|
|
@@ -35,6 +40,10 @@ tokens, or recipes, but the skill contract is Core-owned.
|
|
|
35
40
|
## Work
|
|
36
41
|
|
|
37
42
|
- Use existing tokens, CSS, components, and installed dependencies first.
|
|
43
|
+
- When replacing the site mark, regenerate PNG from the same SVG artwork so
|
|
44
|
+
every surface presents the same identity. Check it at the Admin's 28px slot
|
|
45
|
+
in both light and dark themes; a single high-contrast rendition is preferred
|
|
46
|
+
over theme-specific variants unless the artwork genuinely needs both.
|
|
38
47
|
- For a standard hero image, set the section's `image: { src, alt }`; use
|
|
39
48
|
`showImage: false` for text-only hero/content blocks. Put non-image media in
|
|
40
49
|
a project-owned section.
|