@aotter/mantle 0.2.0-alpha.8 → 0.2.0
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 +26 -3
- package/dist/auth/adapter.js +10 -34
- package/dist/auth/admin.js +2 -5
- package/dist/auth/caller.js +0 -27
- package/dist/auth/consent.js +100 -0
- package/dist/auth/hardening.js +0 -7
- package/dist/auth/identity.js +0 -11
- package/dist/auth/oauth.js +0 -32
- package/dist/auth/resource-seeds.js +0 -2
- package/dist/auth/route-http.js +33 -0
- package/dist/auth/routes.js +8 -153
- package/dist/build/compiler.d.ts +19 -609
- package/dist/build/compiler.js +3 -6896
- package/dist/build/spec/domain/model/SqlIr.d.ts +2 -0
- package/dist/build/spec/domain/model/UserFields.d.ts +1 -0
- package/dist/bun/assets.js +0 -2
- package/dist/domain/adminOrder.js +0 -2
- package/dist/domain/columns.js +7 -20
- package/dist/domain/describe/chunk-SGMRVDGE.js +1 -0
- package/dist/domain/describe/index.js +1 -115
- package/dist/domain/describe/target-hash.js +1 -12
- package/dist/domain/entry.js +0 -14
- package/dist/domain/generated-tools.js +0 -1
- package/dist/domain/input.js +0 -2
- package/dist/domain/paging.js +0 -17
- package/dist/domain/recipes.js +10 -7
- package/dist/domain/userReferences.js +0 -1
- package/dist/domain/wireScalars.js +0 -6
- package/dist/infrastructure/adminEntries.js +10 -7
- package/dist/infrastructure/adminPaging.js +55 -57
- package/dist/infrastructure/artifacts.js +0 -4
- package/dist/infrastructure/authSchema.js +0 -9
- package/dist/infrastructure/bundle.js +17 -32
- package/dist/infrastructure/cli.js +25 -11
- package/dist/infrastructure/generate.js +18 -17
- package/dist/infrastructure/generateAuth.js +48 -5
- package/dist/infrastructure/help.js +55 -0
- package/dist/infrastructure/init.js +50 -0
- package/dist/infrastructure/inputs.js +0 -9
- package/dist/infrastructure/mounts.js +22 -0
- package/dist/infrastructure/wrangler.js +18 -9
- package/dist/kernel/authorization.js +0 -1
- package/dist/kernel/binds.d.ts +16 -7
- package/dist/kernel/binds.js +4 -10
- package/dist/kernel/caller-identity.d.ts +0 -3
- package/dist/kernel/caller-identity.js +0 -15
- package/dist/kernel/caller-mode.d.ts +4 -0
- package/dist/kernel/caller-mode.js +14 -0
- package/dist/kernel/contracts.d.ts +7 -11
- package/dist/kernel/contracts.js +8 -44
- package/dist/kernel/cron.js +0 -4
- package/dist/kernel/dialect/common.d.ts +0 -1
- package/dist/kernel/dialect/common.js +0 -3
- package/dist/kernel/dialect/postgres.js +0 -2
- package/dist/kernel/dialect/sqlite.js +1 -6
- package/dist/kernel/drain.js +2 -8
- package/dist/kernel/driver/bun-sqlite.js +0 -4
- package/dist/kernel/driver/d1.js +0 -1
- package/dist/kernel/driver/postgres.js +3 -17
- package/dist/kernel/driver/transaction-context.js +0 -1
- package/dist/kernel/email.js +0 -4
- package/dist/kernel/host-access.js +2 -3
- package/dist/kernel/host-caller.d.ts +1 -1
- package/dist/kernel/host-caller.js +3 -6
- package/dist/kernel/json-body.js +0 -2
- package/dist/kernel/mcp-apps.js +1 -6
- package/dist/kernel/mcp-call.js +0 -1
- package/dist/kernel/mcp-handler.js +3 -27
- package/dist/kernel/mcp.d.ts +5 -1
- package/dist/kernel/mcp.js +2 -6
- package/dist/kernel/media.js +0 -18
- package/dist/kernel/paging.js +1 -9
- package/dist/kernel/publishing.js +3 -4
- package/dist/kernel/r2-media.js +0 -7
- package/dist/kernel/rest-dispatch.js +0 -1
- package/dist/kernel/rest-router.js +2 -3
- package/dist/kernel/rest.js +0 -3
- package/dist/kernel/scalars.js +4 -11
- package/dist/kernel/search.js +0 -1
- package/dist/kernel/site.js +0 -2
- package/dist/kernel/store.d.ts +11 -1
- package/dist/kernel/store.js +21 -34
- package/dist/kernel/surface-failure.d.ts +10 -0
- package/dist/kernel/surface-failure.js +29 -0
- package/dist/kernel/surface.js +0 -3
- package/dist/kernel/sweep.js +0 -1
- package/dist/kernel/translations.js +0 -1
- package/dist/kernel/user-caller.js +2 -8
- package/dist/kernel/user-fields.d.ts +3 -2
- package/dist/kernel/user-fields.js +9 -9
- package/dist/kernel/validation.js +0 -8
- package/dist/kernel/web-gateway.js +0 -2
- package/dist/kernel/web-head.js +0 -1
- package/dist/kernel/web-index.js +39 -0
- package/dist/kernel/web-response.js +0 -1
- package/dist/kernel/web-serve.js +97 -0
- package/dist/kernel/web.d.ts +1 -1
- package/dist/kernel/web.js +10 -125
- package/dist/kernel/where.js +0 -6
- package/dist/usecase/adminBindings.js +30 -21
- package/dist/usecase/adminClient.js +0 -21
- package/dist/usecase/adminDescriptors.js +2 -9
- package/dist/usecase/generate.js +7 -12
- package/dist/usecase/handlers.js +0 -3
- package/dist/usecase/mcp-media.js +0 -1
- package/dist/usecase/mcp.js +0 -4
- package/dist/usecase/paging.js +1 -3
- package/dist/usecase/publishing.js +1 -5
- package/dist/usecase/rest.js +0 -1
- package/dist/usecase/site.js +0 -2
- package/dist/usecase/stores.js +4 -14
- package/dist/usecase/tool-version.js +0 -3
- package/dist/usecase/translations.js +0 -2
- package/dist/usecase/validation.js +8 -20
- package/docs/examples/README.md +13 -5
- package/docs/examples/app-shell/README.md +43 -8
- package/docs/examples/app-shell/accept.mjs +91 -0
- package/docs/examples/app-shell/gitignore +7 -0
- package/docs/examples/app-shell/package.json +7 -6
- package/docs/examples/app-shell/smoke-kit.mjs +29 -15
- package/docs/examples/app-shell/src/auth.ts +3 -2
- package/docs/examples/app-shell/src/routes.ts +6 -3
- package/docs/examples/app-shell/src/service.ts +4 -3
- package/docs/examples/club-events/README.md +7 -2
- package/docs/examples/club-events/manifests/club-events.yaml +22 -0
- package/docs/examples/club-events/smoke.mjs +7 -1
- package/docs/examples/club-events/src/handlers.ts +1 -1
- package/docs/examples/purchasing/README.md +12 -3
- package/docs/examples/purchasing/manifests/purchasing.yaml +36 -3
- package/docs/examples/purchasing/smoke.mjs +14 -0
- package/docs/examples/purchasing/src/handlers.ts +1 -1
- package/docs/examples/recipes/README.md +5 -3
- package/docs/handbook/cloudflare/authentication.md +21 -4
- package/docs/handbook/cloudflare/chatgpt-sites.md +4 -2
- package/docs/handbook/cloudflare/deploy-and-operate.md +24 -1
- package/docs/handbook/cloudflare/media-r2.md +2 -3
- package/docs/handbook/cloudflare/service-entry.md +17 -4
- package/docs/handbook/concepts/runtime-and-adapters.md +1 -1
- package/docs/handbook/examples/hub.md +1 -1
- package/docs/handbook/guides/agent-setup.md +15 -10
- package/docs/handbook/guides/agent-workflow-acceptance.md +232 -0
- package/docs/handbook/guides/local-testing.md +40 -0
- package/docs/handbook/guides/mcp-apps.md +78 -1
- package/docs/handbook/guides/native-admin.md +29 -6
- package/docs/handbook/guides/native-execution.md +5 -4
- package/docs/handbook/guides/oauth.md +58 -0
- package/docs/handbook/guides/public-pages.md +44 -4
- package/docs/handbook/guides/sql-patterns.md +266 -0
- package/docs/handbook/guides/typed-queries.md +173 -0
- package/docs/handbook/navigation.json +16 -0
- package/docs/handbook/reference/admin-descriptors.md +4 -1
- package/docs/handbook/reference/authorization.md +1 -1
- package/docs/handbook/reference/diagnostics.md +6 -1
- package/docs/handbook/reference/procedure.md +5 -5
- package/docs/handbook/reference/schema.md +10 -4
- package/docs/handbook/reference/sql.md +64 -0
- package/docs/handbook/reference/surface.md +11 -4
- package/docs/handbook/reference/trigger.md +9 -0
- package/docs/handbook/reference/view.md +11 -3
- package/docs/handbook/releases/index.md +27 -6
- package/docs/handbook/start/agents.md +45 -0
- package/docs/handbook/start/project-and-cli.md +15 -1
- package/docs/handbook/start/quickstart-worker.md +1 -1
- package/docs/skills/develop/SKILL.md +44 -16
- package/docs/skills/integrate/SKILL.md +4 -9
- package/docs/skills/provision/SKILL.md +15 -12
- package/docs/skills/update/SKILL.md +21 -18
- package/package.json +24 -4
- package/skills/README.md +1 -1
- package/skills/mantle/SKILL.md +48 -107
- package/dist/domain/describe/chunk-ZVXBGP7Y.js +0 -424
- package/docs/skills/develop/mcp-app.md +0 -39
- package/skills/.keep +0 -0
- package/skills/mantle/references/local-testing.md +0 -15
- package/skills/mantle/references/web.md +0 -41
- package/skills/mantle/references/website.md +0 -49
|
@@ -38,7 +38,7 @@ A string `pattern` needs a `maxLength`: generation bounds each regex's backtrack
|
|
|
38
38
|
| object/array | JSON text | jsonb |
|
|
39
39
|
| geo | lat/lng columns, R*Tree | lat/lng columns |
|
|
40
40
|
|
|
41
|
-
System columns include id, version, created_at, updated_at and author_id; publishing adds status/published_at. Do not declare reserved fields. Manifest native column names in indexes use camelCase (`createdAt`); generated Store/SQL use storage names (`created_at`). Scope is omitted from returned rows.
|
|
41
|
+
System columns include id, version, created_at, updated_at and author_id; publishing adds status/published_at. Initial DDL declares a field NOT NULL when an `operational` Schema lists it in `required` and it does not allow null; `default` never does, and no column gets a DDL `DEFAULT` ([server-maintained fields](#admin-uischema)). Do not declare reserved fields. Manifest native column names in indexes use camelCase (`createdAt`); generated Store/SQL use storage names (`created_at`). Scope is omitted from returned rows.
|
|
42
42
|
|
|
43
43
|
Declared date/date-time outputs are SQL-formatted strings (`YYYY-MM-DD`, UTC ISO with six fractional digits). Computed timestamps remain native. Inputs and other output scalars follow [the native contract](../guides/native-execution.md). Date conversion through JS Date loses microseconds.
|
|
44
44
|
|
|
@@ -76,9 +76,11 @@ The runtime never creates, alters or checks tables. Initial DDL is for an empty
|
|
|
76
76
|
|
|
77
77
|
## Admin uiSchema
|
|
78
78
|
|
|
79
|
-
A property marked `readOnly: true` in the JSON Schema is server-maintained (a counter, a total): Admin's generic create stores its `default` whatever the input says, Admin edits ignore it, and only Procedures (or server code through the Store) change it afterwards. JSON Schema defaults are applied by Admin
|
|
79
|
+
A property marked `readOnly: true` in the JSON Schema is server-maintained (a counter, a total): Admin's generic create stores its `default` whatever the input says, Admin edits ignore it, and only Procedures (or server code through the Store) change it afterwards. JSON Schema defaults are applied by Admin's generic create only, not by the Store or the database: initial DDL emits no `DEFAULT` for a field, so server code through the Store and a SQL Procedure that inserts the row set the field themselves. A root `readOnly: true` makes the whole Schema read-only in Admin: a generic Admin write is refused with 403 `AUTH_DENIED` (not a 409 version conflict).
|
|
80
80
|
|
|
81
|
-
`
|
|
81
|
+
`default` does not make a column NOT NULL; `required` does (in an `operational` Schema). For a server-maintained value that is never NULL, list it in both, `required: [name, total]` with `total: {type: integer, readOnly: true, default: 0}`: initial DDL declares `total` NOT NULL, Store and View row types read it as `number` rather than `number | null`, Admin's create still fills the default when the client omits it, and the Store's insert type requires server code to pass it. Without `required` the column stays nullable, and an INSERT that omits it stores NULL. Adding `required` to an existing table is a [migration](../concepts/runtime-and-adapters.md#schema-installation-and-migrations): backfill NULLs, then add NOT NULL.
|
|
82
|
+
|
|
83
|
+
`fields.<name>.widget` selects a built-in control (`textarea`); `list.primaryField`, `list.columns` and enum `filterField` select list presentation (operational Schemas only; a publishing Schema's list shows its title field and status); `nav.parentField` chooses the parent a child folds under (required when two or more required `id` references exist) and `nav.standalone` lists the child in the sidebar; `nav.group/order/hidden` place it in the sidebar ([sidebar](../guides/native-admin.md#sidebar)). `list.columns` must not repeat `list.primaryField` or itself (`SCHEMA_UI_INVALID`). Generation validates these against declared fields/indexes. Components that render a field, cell or record aside are not manifest references: they live in `defineAdmin` ([customising Admin](../guides/native-admin.md#customising-admin)), and a manifest that still names one (`widget: <extension>/<contribution>`, `widget` `options`, `list.cells`, `panels`) is refused. JSON Schema root `schema.readOnly: true` disables generic Admin writes, not declared Procedures; `uiSchema.readOnly` is rejected with `SCHEMA_UI_INVALID`. `x-mantle-ref` relates a field to another Schema id or single-field unique field. It is not a foreign key: the database does not check that the referenced row exists, and deleting that row leaves the reference dangling. Check existence in the write (a JOIN or `EXISTS` in the Procedure) and guard deletes with `NOT EXISTS` ([SQL patterns](../guides/sql-patterns.md)).
|
|
82
84
|
|
|
83
85
|
See [Admin](../guides/admin-ui.md) and [diagnostics](diagnostics.md).
|
|
84
86
|
|
|
@@ -88,7 +90,11 @@ See [Admin](../guides/admin-ui.md) and [diagnostics](diagnostics.md).
|
|
|
88
90
|
|
|
89
91
|
A caller whose value for a field is `{ all: true }` drops that field's term only; the other terms still apply. Generated SQL holds one statement per target and selects the form for each caller at run time; values are always bound parameters. Neither roles nor the admin layer widen a field scope or a translation parent's visibility. A Schema whose `x-mantle-ref` points to a field-scoped Schema must carry the same scope terms.
|
|
90
92
|
|
|
91
|
-
For inserts, one allowed partition autofills a missing value; multiple values require an explicit allowed partition, and missing/empty values fail with `AUTH_DENIED`. Callers holding `{ all: true }` and system callers always provide an explicit partition. Procedure INSERT
|
|
93
|
+
For inserts, one allowed partition autofills a missing value; multiple values require an explicit allowed partition, and missing/empty values fail with `AUTH_DENIED`. Callers holding `{ all: true }` and system callers always provide an explicit partition. A Procedure `INSERT … VALUES` follows the same rule for user callers, checked before any SQL runs: leave the partition column out to autofill a caller's single value, or take it from an input declared with the column's own type (`VALUES (input.region, …)`) or a matching literal, which must be inside the caller's set; any other expression there is refused. A Procedure that callers holding several values or `{ all: true }` use, such as an Admin create action, takes the partition as an optional input. `INSERT … SELECT` into a field-scoped Schema, and an insert into a Schema the target `restrict`s, run only for system callers, which this check does not cover: they name the partition themselves; use the scoped Store for user writes there. The partition is never writable through SET, including upsert and native Admin patch. An excluded id behaves like a missing row: reads return not found; Store update/delete and row-classified Procedure UPDATE/DELETE affecting zero rows return HTTP 409 (`CONFLICT`). Native Admin's visible-row pre-read returns 404 for either id. SQLite binds a JSON array; PostgreSQL binds a quoted, escaped array. Public Views over field scope warn that anonymous callers are refused.
|
|
94
|
+
|
|
95
|
+
#### References to a scoped Schema
|
|
96
|
+
|
|
97
|
+
A non-null `x-mantle-ref` value that points to a scoped Schema (field or owner scope) must name a row of that Schema the caller can read, matched on `id` or on the object form's `field`, and that row must have the same value as the child for every scope field the two share (`ADR-0034`: a reference between scoped Schemas stays inside one owner or partition). A Store insert or update, a Procedure `INSERT … VALUES`, `UPDATE … SET` or `DO UPDATE SET`, and native Admin's generic create and patch check it in the same statement; a missing, unreadable or other-partition parent behaves like a missing row: a single-row statement returns HTTP 409 (`CONFLICT`), and an `ON CONFLICT` insert or a set update writes nothing for that row. A caller holding several values or `{ all: true }` can still not point a child in one partition at a parent in another. `INSERT … SELECT` that writes such a reference runs only for system callers. A caller's `UPDATE … SET` or `DO UPDATE SET` of such a reference takes no subquery, which could read the parent's columns as its own. Trusted writes (system callers, `runtime.store`) are not checked, like the other row rules. NULL is always allowed; deleting a parent does not touch its children.
|
|
92
98
|
|
|
93
99
|
## Reserved entry columns
|
|
94
100
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: The SQL that Views and Procedures accept on SQLite/D1 and on PostgreSQL, and what each refuses with which diagnostic.
|
|
3
|
+
---
|
|
4
|
+
# SQL accepted by each dialect
|
|
5
|
+
|
|
6
|
+
Views and Procedures share one allowlist with two profiles. SQLite and D1 run the base profile; PostgreSQL runs the
|
|
7
|
+
base profile plus the additions below. Anything not listed is refused at generation with a code (`SQL_UNSUPPORTED`,
|
|
8
|
+
`SQL_FUNCTION`, `SQL_SHAPE`, `SQL_TYPE`) and a source position, so generation is the authority for each target. For
|
|
9
|
+
worked examples see [SQL patterns](../guides/sql-patterns.md).
|
|
10
|
+
|
|
11
|
+
## Both dialects
|
|
12
|
+
|
|
13
|
+
| Area | Accepted |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| Statements | `SELECT`, `INSERT … VALUES` / `INSERT … SELECT`, `UPDATE … SET … WHERE`, `DELETE … WHERE`, each with `RETURNING`; `WITH` (non-recursive) on a `SELECT` |
|
|
16
|
+
| Upsert | `ON CONFLICT (<unique index columns>) DO NOTHING` / `DO UPDATE SET …`, with `excluded.<column>` |
|
|
17
|
+
| Joins | `INNER JOIN`, `LEFT JOIN`; a comma join only for a row source (`json_each`, or PostgreSQL's below) |
|
|
18
|
+
| Clauses | `WHERE`, `GROUP BY`, `HAVING`, `ORDER BY`, `LIMIT` |
|
|
19
|
+
| Predicates | `=`, `<>`, `!=`, `<`, `>`, `<=`, `>=`, `AND`, `OR`, `NOT`, `IS [NOT] NULL`, `IS [NOT] DISTINCT FROM`, `[NOT] BETWEEN`, `IN (list)`, `IN (subquery)`, `LIKE`, `[NOT] EXISTS (subquery)` |
|
|
20
|
+
| Expressions | `+ - * / %`, `\|\|`, `->>` (JSON field), `CASE`, `COALESCE`, `NULLIF`, scalar subqueries, `CAST(… AS text \| int4 \| int8 \| float8 \| bool \| timestamptz \| date \| numeric \| interval)` |
|
|
21
|
+
| Aggregates | `count`, `sum`, `min`, `max`, `avg` |
|
|
22
|
+
| Windows | `row_number()`, `rank()`, `sum()`, `count()` with `OVER (PARTITION BY … ORDER BY …)` and the default frame |
|
|
23
|
+
| Scalar functions | `lower`, `upper`, `length`, `abs`, `round`, `substr`, `replace`, `trim`, `ltrim`, `rtrim`, `instr` |
|
|
24
|
+
| Time | `now()`, `date_trunc('hour' \| 'day' \| 'week' \| 'month' \| 'year', …)`, `extract(year \| month \| day \| dow \| hour FROM …)` |
|
|
25
|
+
| Mantle | `auth.uid()`, `input.<name>`, `mantle.search`, `mantle.search_rank`, `mantle.near`, `mantle.distance` ([features](features.md)) |
|
|
26
|
+
|
|
27
|
+
## SQLite and D1 only
|
|
28
|
+
|
|
29
|
+
| Accepted | PostgreSQL instead |
|
|
30
|
+
| --- | --- |
|
|
31
|
+
| `json_each(<array>)` as a row source (`FROM json_each(input.items) j`, `j.value ->> 'field'`) | `jsonb_array_elements(…) AS j(value)` |
|
|
32
|
+
| `json_group_array`, `json_group_object` | `jsonb_agg`, `jsonb_object_agg` |
|
|
33
|
+
| `json_extract`, `json_set`, `json_insert`, `json_remove`, `json_array_length`; build an object with `json_set('{}', '$.k', v, …)` (`json_object` is refused) | `jsonb_build_object`, `jsonb_build_array` and the jsonb operators |
|
|
34
|
+
| `typeof`, `hex` | refused (`typeof` is SQLite's; PostgreSQL has `pg_typeof`) |
|
|
35
|
+
|
|
36
|
+
An integer `CAST` of anything but a literal is refused (`SQL_TYPE`): SQLite truncates where PostgreSQL rounds. Write
|
|
37
|
+
`round(x)`; `->>` already returns a JSON number as a number.
|
|
38
|
+
|
|
39
|
+
## PostgreSQL additions
|
|
40
|
+
|
|
41
|
+
| Area | Accepted |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| Set operations | `UNION [ALL]`, `INTERSECT`, `EXCEPT`, inside a `WITH` or a subquery (the View's own SELECT is the one that pages) |
|
|
44
|
+
| Relations | `LATERAL` subqueries, `WITH RECURSIVE`, `MATERIALIZED` / `NOT MATERIALIZED` CTEs |
|
|
45
|
+
| Row sources | `jsonb_array_elements`, `jsonb_array_elements_text`, `jsonb_each`, `jsonb_each_text`, with `WITH ORDINALITY` |
|
|
46
|
+
| Operators | `ILIKE`, `~`, `~*`, `!~`, `!~*`, jsonb `->`, `#>`, `#>>`, `@>`, `<@`, `?`, `?\|`, `?&` |
|
|
47
|
+
| Aggregates | `string_agg`, `jsonb_agg`, `jsonb_object_agg`, with `FILTER (WHERE …)` and `ORDER BY` inside the call |
|
|
48
|
+
| Windows | also `avg`, `min`, `max`, `lag`, `lead`, `first_value`, `last_value`, `dense_rank`; frames except `GROUPS` and `EXCLUDE` |
|
|
49
|
+
| Functions | `GREATEST`, `LEAST`, `floor`, `ceil`, `sqrt`, `power`, `split_part`, `timezone`, `jsonb_build_object`, `jsonb_build_array`, `jsonb_strip_nulls`, `to_jsonb`, `jsonb_typeof`, `CAST(… AS jsonb)` |
|
|
50
|
+
| Time | `date_trunc` also `'minute'`, `'quarter'`; `extract` also `minute`, `quarter`, `week`, `isoyear`, `isodow`, `doy`, `epoch` |
|
|
51
|
+
|
|
52
|
+
`jsonb_agg` of no rows is `NULL`: write `COALESCE(jsonb_agg(…), CAST('[]' AS jsonb))` for an empty array.
|
|
53
|
+
|
|
54
|
+
## Refused on every target
|
|
55
|
+
|
|
56
|
+
- `OFFSET`: page with the generated cursor (`limit`, `cursor`) instead.
|
|
57
|
+
- `RIGHT` and `FULL` joins, `UPDATE … FROM`, `DELETE … USING`, DDL and any function not listed.
|
|
58
|
+
- `DISTINCT` with `ORDER BY`: the paging key Mantle appends would change what is distinct; use `GROUP BY`.
|
|
59
|
+
- A program of more than 2000 syntax nodes.
|
|
60
|
+
|
|
61
|
+
Two write rules come from Mantle, not the dialect ([Procedure](procedure.md)). A row-classified `UPDATE`/`DELETE`
|
|
62
|
+
(`WHERE id = input.id …`) must change exactly one row, otherwise `CONFLICT`. A set form (`WHERE id IN (SELECT …)`,
|
|
63
|
+
`INSERT … SELECT`) may change none, so write a conditional write that may do nothing in that form. Scope, version,
|
|
64
|
+
timestamps and author columns are assigned by Mantle, never by your SQL.
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
snake-cased View names on each declared surface, and snake-cased Procedure
|
|
14
14
|
names per MCP Trigger. Its SDK loads only through a request-time dynamic import.
|
|
15
15
|
- HTTP/MCP Triggers declare exposure only. `mantle generate` refuses schedule
|
|
16
|
-
and lifecycle Triggers;
|
|
16
|
+
and lifecycle Triggers; host scheduling is a separate capability.
|
|
17
17
|
- Native Admin retains selected 0.2 paths and the console contracts; see
|
|
18
18
|
[Native Admin](../guides/native-admin.md) for app-mounted
|
|
19
19
|
`adminBindings()` and `entries(bindings.schemas, bindings.adapter)`.
|
|
@@ -25,6 +25,8 @@ challenges, JSON-RPC, web rendering, keyset paging) lives in the package's
|
|
|
25
25
|
`rest`, `mcp`, `web`, `paging` and `validation` kernel modules, so a runtime fix
|
|
26
26
|
ships as a package update instead of a regeneration.
|
|
27
27
|
|
|
28
|
+
Procedure surface selection follows the [HTTP/MCP pairing default and deliberate asymmetry exception](trigger.md); no surface is implied.
|
|
29
|
+
|
|
28
30
|
The generated `validation/views/<name>.ts` and
|
|
29
31
|
`validation/procedures/<name>.ts` export `validate(unknown)`. View validators
|
|
30
32
|
also export `query(URLSearchParams)` returning `{ input, limit?, cursor? }`.
|
|
@@ -219,7 +221,9 @@ must also mount Better Auth's `/.well-known/oauth-protected-resource/mcp`
|
|
|
219
221
|
metadata route. Auth challenges point to that route. Presented bearer credentials
|
|
220
222
|
need the `mcp` scope; cookie sessions use the same-origin mutation checks.
|
|
221
223
|
|
|
222
|
-
Generation emits `mcp.ts` only for a non-internal View or MCP Trigger.
|
|
224
|
+
Generation emits `mcp.ts` only for a non-internal View or MCP Trigger. Omitting
|
|
225
|
+
MCP remains a deliberate asymmetric choice; an HTTP-only Procedure still generates
|
|
226
|
+
successfully with the warning described in [Trigger](trigger.md). These
|
|
223
227
|
surfaces typecheck without the optional `@modelcontextprotocol/server` peer;
|
|
224
228
|
install the exact version declared in the installed SDK's `peerDependencies`.
|
|
225
229
|
The peer loads by dynamic import on the first matching `/mcp` request; if
|
|
@@ -229,7 +233,7 @@ surface its generated `publish_<schema>`, `unpublish_<schema>` and
|
|
|
229
233
|
`archive_<schema>` tools use the same snake-case naming rule, are admin-only
|
|
230
234
|
and take `{ id, expectedVersion }` through the shared generated validation.
|
|
231
235
|
|
|
232
|
-
`/mcp/admin` admits only admins: `isAdmin(caller)` must hold. Better Auth’s admin plugin `adminRoles` defines this layer (default `["admin"]`); the application supplies its verified Caller. MCP bodies are limited
|
|
236
|
+
`/mcp/admin` admits only admins: `isAdmin(caller)` must hold. It lists only admin-surface tools; public Views and Procedures stay on `/mcp`, and generation never copies them across. An admin's AI that changes records also needs admin Views to find them and read back the committed row and its version (search, detail), declared by the app; the [acceptance design audit](../guides/agent-workflow-acceptance.md#audit-mcp-tool-design-before-implementation) checks this. Better Auth’s admin plugin `adminRoles` defines this layer (default `["admin"]`); the application supplies its verified Caller. MCP bodies are limited
|
|
233
237
|
to 1 MiB (1,048,576 bytes). Resource metadata challenges use the origin of
|
|
234
238
|
`request.url`; behind a proxy, the app must pass a Request with its public
|
|
235
239
|
origin so the audience and metadata URL point to the client-visible service.
|
|
@@ -348,7 +352,10 @@ REST and MCP View pages expose declared JSON columns as JSON values and declared
|
|
|
348
352
|
boolean columns as booleans, including explicitly authored SQL aliases. SQLite
|
|
349
353
|
and D1 conversions are compiled into only the selected boundary pages;
|
|
350
354
|
PostgreSQL already-native JSON/boolean values pass through. SQL NULL stays null and absent
|
|
351
|
-
fields stay absent.
|
|
355
|
+
fields stay absent. A computed output that is a JSON document by construction
|
|
356
|
+
(`json_group_array`, `json_set`, `jsonb_agg`, `jsonb_build_object` and the like, a scalar
|
|
357
|
+
subquery of one, or a `COALESCE` of those) is converted like a declared JSON column, so it
|
|
358
|
+
is a JSON value on every target. Other expressions without declared column lineage stay native.
|
|
352
359
|
Malformed persisted JSON becomes a redacted internal failure. The conversion
|
|
353
360
|
adds no database operations and does not mutate native query rows.
|
|
354
361
|
|
|
@@ -24,12 +24,21 @@ metadata: { name: close-ticket-http }
|
|
|
24
24
|
spec:
|
|
25
25
|
source: { kind: http, method: POST, path: '/api/tickets/{id}/close' }
|
|
26
26
|
target: { procedure: close-ticket }
|
|
27
|
+
---
|
|
28
|
+
apiVersion: cms.mantle.aotter.net/v2
|
|
29
|
+
kind: Trigger
|
|
30
|
+
metadata: { name: close-ticket-mcp }
|
|
31
|
+
spec:
|
|
32
|
+
source: { kind: mcp, surface: admin }
|
|
33
|
+
target: { procedure: close-ticket }
|
|
27
34
|
```
|
|
28
35
|
|
|
29
36
|
The target names a declared Procedure. `http` sources use POST/PUT/PATCH/DELETE and an `/api/` path. Path parameters bind to corresponding declared input fields and override JSON-body values. The generated REST module retains the Procedure's authorization and validates boundary input.
|
|
30
37
|
|
|
31
38
|
An MCP source is `{ kind: mcp, surface: public }` or admin. The selected MCP module exposes the Procedure as a snake-case tool with its description, [tool hints](procedure.md#mcp-tool-hints) and requires checks.
|
|
32
39
|
|
|
40
|
+
By default, pair every HTTP Trigger with an MCP Trigger so the same operation is reachable by the user's AI. `mantle generate` warns when a Procedure has HTTP exposure but no MCP exposure, suggesting `surface: admin` for an admin-only Procedure and `public` otherwise. Triggers still decide every Procedure surface: intentional asymmetric exposure is allowed and generation succeeds.
|
|
41
|
+
|
|
33
42
|
Lifecycle and schedule sources are rejected at generation with `GENERATE_UNSUPPORTED`, including disabled schedules. Use an app-owned handler or scheduler. For signed webhooks, verify the original raw Request in the app and call a generated Procedure with validated input; do not route it through a JSON boundary before signature verification.
|
|
34
43
|
|
|
35
44
|
## Input rules
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
# View
|
|
2
2
|
|
|
3
|
-
A View requires `surface: public | admin | internal` and one `sql` SELECT. Optional keys include title, description, input, requires, restrict, uiSchema (admin only), and cache. The app imports its generated typed function and supplies a native handle, verified Caller and driver-ready input.
|
|
3
|
+
A View requires `surface: public | admin | internal` and one `sql` SELECT. Optional keys include title, description, input, requires, restrict, uiSchema (admin only), and cache. The app imports its generated typed function and supplies a native handle, verified Caller and driver-ready input; a JSON input (an array read by `json_each(input.ids)`) takes its authored array or object, which the generated query serializes.
|
|
4
4
|
|
|
5
5
|
## SQL
|
|
6
6
|
|
|
7
7
|
PostgreSQL syntax is parsed and checked at generation. Reads may reference declared Schemas, CTEs and reusable internal Views; no auth/system tables or arbitrary external relations. The compiler adds scope, TTL, publication and translation-parent visibility at every relation. SQL policy is not injected at request time.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
The SQL each dialect accepts, for Views and Procedures alike, is listed in [the SQL reference](sql.md); [SQL patterns](../guides/sql-patterns.md) shows the common ones. Unsupported SQL fails with a source position; generation is the authority for each target.
|
|
10
|
+
|
|
11
|
+
`*` and `t.*` expand to the Schema's declared fields only. Select `id`, `version`, `created_at` and `updated_at` by name when a client needs them (a write's `expectedVersion`, a detail link, keyset paging).
|
|
10
12
|
|
|
11
13
|
OFFSET, arbitrary functions/relations, DDL and transaction control are not a read escape hatch. Use keyset paging. Select latitude/longitude explicitly instead of native geo projections.
|
|
12
14
|
|
|
@@ -16,6 +18,12 @@ OFFSET, arbitrary functions/relations, DDL and transaction control are not a rea
|
|
|
16
18
|
|
|
17
19
|
## Search and totals
|
|
18
20
|
|
|
21
|
+
`mantle.search(<alias>, <text>)` matches the Schema's declared `searchableFields`, and `mantle.search_rank(<alias>)`
|
|
22
|
+
orders by relevance; qualify both with `mantle.`. An optional search reads
|
|
23
|
+
`WHERE p.active AND (input.q IS NULL OR mantle.search(p, input.q))`, and a ranked one
|
|
24
|
+
`WHERE mantle.search(p, input.q) ORDER BY mantle.search_rank(p), p.id` (see `examples/reference-service` `catalog.yaml`
|
|
25
|
+
for cursor paging over the rank).
|
|
26
|
+
|
|
19
27
|
Views using `mantle.search`, Store search and Admin list search share the dialect search: SQLite/D1 use FTS for queries of 3 or more characters (shorter queries use LIKE); PostgreSQL uses ILIKE over the declared fields and scans by default. A View does not make PostgreSQL search faster. For large PostgreSQL tables, the application's agent adds trigram indexes in a migration, which ILIKE then uses with no code change:
|
|
20
28
|
|
|
21
29
|
```sql
|
|
@@ -27,7 +35,7 @@ Store keeps `find`/`first` search and `count`. `count` scans every matching row;
|
|
|
27
35
|
|
|
28
36
|
## Results and paging
|
|
29
37
|
|
|
30
|
-
Each SELECT output needs a unique static name. Unquoted SQL identifiers fold to lower case; use an explicit quoted alias to preserve case (`r.reqStatus AS "reqStatus"`). Generation warns when an unaliased direct declared field would use its lower-case storage name. Declared-column lineage supplies generated types; computed outputs remain native/unknown. SQL formats declared date-time/date outputs, while computed timestamps retain driver values. See [native execution](../guides/native-execution.md).
|
|
38
|
+
Each SELECT output needs a unique static name. Unquoted SQL identifiers fold to lower case; use an explicit quoted alias to preserve case (`r.reqStatus AS "reqStatus"`). Generation warns when an unaliased direct declared field would use its lower-case storage name. Declared-column lineage supplies generated types; computed outputs remain native/unknown, except a top-level output that is a JSON document by construction (a JSON aggregate or builder, a scalar subquery of one, or a `COALESCE` of those; see [SQL patterns](../guides/sql-patterns.md#a-row-with-its-children-in-one-read)), which is typed JSON. An output is non-null (`string`, not `string | null`) only when it reads unchanged a column its table declares NOT NULL (`id`, `version`, `created_at`, `updated_at`, a publishing `status`, or a [required](schema.md#fields-and-storage) field of an operational Schema) directly or through FROM subqueries; the right side of a LEFT JOIN, an aggregate, a column beside an aggregate without GROUP BY, a CTE and an expression stay nullable. SQL formats declared date-time/date outputs, while computed timestamps retain driver values. See [native execution](../guides/native-execution.md).
|
|
31
39
|
|
|
32
40
|
Bare `views/<encoded-name>.ts` returns row arrays. Proved pageable exposed/internal Views also receive native `paged/views/*`, returning `{ rows, nextCursor? }`. Selected REST/MCP boundaries use separate `paged/wire/views/*` SQL when declared integers require exact transport projections; bare modules also export `WireRow`. Indexed ordering after fixed equality prefixes ([index prefixes](schema.md#index-prefixes-for-paged-views)), non-null typed keys, complete groups and singleton joins/lookups are checked at generation. Unsupported internal paging retains its bare View; exposure requires a supported page contract. Aggregates still scan/group their sources: inspect EXPLAIN.
|
|
33
41
|
|
|
@@ -15,15 +15,36 @@ From 0.2.0-alpha.7, Mantle publishes three packages together at one version:
|
|
|
15
15
|
and `@aotter/mantle-admin` (optional Admin server, SPA and MCP App).
|
|
16
16
|
Pin every package you use to the same exact version and upgrade them together.
|
|
17
17
|
|
|
18
|
-
## 0.2.0
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
## 0.2.0 (2026-10-19)
|
|
19
|
+
|
|
20
|
+
The first stable native 0.2 release compiles closed v2 manifests to SQL and
|
|
21
|
+
TypeScript for Bun SQLite/PostgreSQL and Cloudflare D1/PostgreSQL. It ships
|
|
22
|
+
three matching packages: Core, the pure UI kit and the optional application-built
|
|
23
|
+
Admin. Applications own routing, verified identity, database handles, migrations
|
|
24
|
+
and deployment; selected REST, MCP, public pages, publishing, translations and
|
|
25
|
+
media compose around the generated operations.
|
|
26
|
+
|
|
27
|
+
This is a breaking upgrade from 0.1.x: follow the [0.1-to-0.2 migration
|
|
28
|
+
guide](../../upgrade-0.1-to-0.2.md), use a new 0.2 database and explicitly move
|
|
29
|
+
data. From alpha.11, pin the three selected packages to 0.2.0, regenerate and
|
|
30
|
+
review owned output; the stable version commit changes release metadata and
|
|
31
|
+
documentation rather than adding another runtime API.
|
|
32
|
+
|
|
33
|
+
[GitHub release](https://github.com/aotter/mantle/releases/tag/v0.2.0) is the
|
|
34
|
+
complete change history. Known follow-ups remain tracked: [Admin/authoring
|
|
35
|
+
refinements](https://github.com/aotter/mantle/issues/1752), [production social
|
|
36
|
+
and magic-link recipe verification](https://github.com/aotter/mantle/issues/1273)
|
|
37
|
+
and [real Sites guide verification](https://github.com/aotter/mantle/issues/1272).
|
|
38
|
+
Those provider-specific paths are not claimed as verified by local OTP or
|
|
39
|
+
native-host tests.
|
|
40
|
+
|
|
41
|
+
### Upgrading to 0.2.0
|
|
21
42
|
|
|
22
43
|
Pin every selected `@aotter/mantle`, `@aotter/mantle-ui` and
|
|
23
|
-
`@aotter/mantle-admin` dependency to `0.2.0
|
|
44
|
+
`@aotter/mantle-admin` dependency to `0.2.0`, refresh the lockfile,
|
|
24
45
|
then regenerate and check the application's owned artifacts. Keep existing
|
|
25
46
|
production migrations application-owned; generated initial DDL is for an empty
|
|
26
|
-
database. This
|
|
47
|
+
database. This release includes breaking Admin authoring and paging changes.
|
|
27
48
|
|
|
28
49
|
1. **Build output and host configuration.** `mantle bundle` writes server
|
|
29
50
|
modules to `dist/worker` and static files to `dist/client`, including
|
|
@@ -112,7 +133,7 @@ Existing alpha.6 applications require a source migration:
|
|
|
112
133
|
application code. Review [authorization and Caller wiring](../concepts/runtime-and-adapters.md)
|
|
113
134
|
and regenerate all owned artifacts before running `generate --check`.
|
|
114
135
|
|
|
115
|
-
The [reference Worker](https://github.com/aotter/mantle/tree/v0.2.0
|
|
136
|
+
The [reference Worker](https://github.com/aotter/mantle/tree/v0.2.0/docs/examples/reference-service) and
|
|
116
137
|
[app shell](../../examples/app-shell/) demonstrate the current composition.
|
|
117
138
|
The following earlier-alpha notes are historical; the current handbook and
|
|
118
139
|
the native migration above supersede their runtime and CLI instructions.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: The entry point `mantle help` prints first: choose a complete app or generation only, use examples as references, accept before done.
|
|
3
|
+
---
|
|
4
|
+
# Build with an agent
|
|
5
|
+
|
|
6
|
+
`mantle help` prints this page. `mantle help <topic>` prints one handbook page and ends with the commands for its next page and for every page it links; run those to read further.
|
|
7
|
+
Topics are the handbook paths below (for example `guides/native-admin`) or their last segment when unique (`native-admin`).
|
|
8
|
+
The installed package's `docs/` is the source of every topic, so the text always matches the installed version.
|
|
9
|
+
|
|
10
|
+
## Choose how much Mantle owns
|
|
11
|
+
|
|
12
|
+
| You want | Do |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| A complete application | `mantle init [directory]`, then follow its `README.md`. It writes the app shell once: Better Auth email OTP with `admin` and `user`, the Admin console, MCP for both roles, REST, and a member `/sign-in` page. Existing files stop it; `--dry-run` lists what it would write. |
|
|
15
|
+
| Only typed SQL and bindings inside an app you already have | Skip `init`. Write manifests and run `mantle generate <target> <output-directory> <manifest>...`; see `mantle help project-and-cli` and `mantle help typed-queries`. |
|
|
16
|
+
|
|
17
|
+
`init` writes the `cloudflare-d1` shell, the default target. `bun-sqlite`, `bun-postgres` and `cloudflare-postgres`
|
|
18
|
+
generate the same bindings; their app entry is yours (`mantle help service-entry`).
|
|
19
|
+
|
|
20
|
+
`init` writes app code you then own; it never runs again. `generate` writes only `generated/` and Wrangler build keys,
|
|
21
|
+
and overwrites them on every run. When `generate` sees a selected surface (REST, MCP, Admin) whose generated module
|
|
22
|
+
the app entry (`--entry`) never imports, it warns and names the topic that shows the wiring.
|
|
23
|
+
|
|
24
|
+
## Build from a product brief
|
|
25
|
+
|
|
26
|
+
1. `mantle init`, install, then read the app's `README.md` and search for `AGENT:`.
|
|
27
|
+
2. Map the brief to the [four atoms](../concepts/four-atoms.md): Schemas, Views, Procedures, Triggers.
|
|
28
|
+
Decide what each role (`admin`, `user`) does on each surface: Admin, MCP, REST and any visitor pages.
|
|
29
|
+
3. For each need, find the pattern in `mantle help examples` (the **Combining** table) and read that example's
|
|
30
|
+
manifest and source. Examples are references: take the pattern into your own manifests; do not copy an example
|
|
31
|
+
directory into the app.
|
|
32
|
+
- Business rules (status transitions, approval thresholds, stock, guards, several rows that commit together)
|
|
33
|
+
belong in SQL Procedures, not in handler code around separate writes: `mantle help sql-patterns`, and
|
|
34
|
+
`mantle help sql` for the SQL each dialect accepts.
|
|
35
|
+
- Visitor pages (anything anonymous and indexable) follow `mantle help public-pages`: server-rendered HTML,
|
|
36
|
+
canonical and Open Graph tags, JSON-LD and an answer block on detail pages, Markdown alternates, `/sitemap.xml`,
|
|
37
|
+
`/robots.txt` and `/llms.txt`. A brief that names a site, shop or catalogue for visitors includes all of them.
|
|
38
|
+
4. `pnpm generate`, implement every handler it lists, `pnpm check`, then `pnpm smoke`.
|
|
39
|
+
5. Before reporting the app or a feature done, run [role-only acceptance](../guides/agent-workflow-acceptance.md)
|
|
40
|
+
(`mantle help agent-workflow-acceptance`). Scripted smoke is not acceptance. `pnpm accept` starts the app and hands
|
|
41
|
+
each role to a fresh evaluator as a URL that carries that role's session.
|
|
42
|
+
|
|
43
|
+
The first verified sign-in with `ADMIN_EMAIL` becomes the admin. Further administrators are added in Admin:
|
|
44
|
+
**More → Administrators** invites by email, and **More → Members** grants Admin to an existing member.
|
|
45
|
+
[Authentication](../cloudflare/authentication.md#identity-helpers) documents the same operations as an API.
|
|
@@ -12,13 +12,27 @@ description: Generation targets, CLI options and ownership of native application
|
|
|
12
12
|
| `wrangler.jsonc` | App configuration; generator maintains selected split-build keys |
|
|
13
13
|
| `dist/` | Disposable bundle output (`dist/worker`, `dist/client`); do not commit |
|
|
14
14
|
|
|
15
|
+
## Accept user-facing work
|
|
16
|
+
|
|
17
|
+
Before reporting any user-facing deliverable as done, run the installed
|
|
18
|
+
version's [independent acceptance
|
|
19
|
+
flow](../guides/agent-workflow-acceptance.md) with a fresh agent on the surface
|
|
20
|
+
its user uses. For MCP work, also run that guide's design audit before choosing
|
|
21
|
+
tool names or writing manifests/handlers.
|
|
22
|
+
|
|
15
23
|
## Commands
|
|
16
24
|
|
|
17
25
|
```sh
|
|
26
|
+
mantle help [topic] # these docs, one page at a time; start here
|
|
27
|
+
mantle init [directory] [--dry-run] # write the cloudflare-d1 app shell once; never overwrites
|
|
18
28
|
mantle generate <target> <output-directory> <manifest>... [options]
|
|
19
29
|
mantle bundle <entry> <outdir> [--assets <dir>]
|
|
20
30
|
```
|
|
21
31
|
|
|
32
|
+
`init` writes application code the app then owns. `generate` writes only generated output and Wrangler build keys,
|
|
33
|
+
on every run; after writing, it follows the `--entry` file's imports and warns for each selected REST, MCP or Admin
|
|
34
|
+
module the entry never imports.
|
|
35
|
+
|
|
22
36
|
| Target | Dialect | Handle |
|
|
23
37
|
| --- | --- | --- |
|
|
24
38
|
| `bun-sqlite` | sqlite | bun:sqlite Database |
|
|
@@ -37,7 +51,7 @@ Other handles may adapt to the same [structural driver contracts](../guides/adap
|
|
|
37
51
|
| `--wrangler <path>` | Existing JSONC/JSON/TOML config; default finds one or creates `wrangler.jsonc`. TOML receives manual-edit instructions. |
|
|
38
52
|
| `--entry <path>` | Worker source entry; default `src/worker.ts`. |
|
|
39
53
|
| `--outdir <path>` | Bundle output; default `dist`. The Worker goes to `<outdir>/worker`. Keep separate from source/generated files. |
|
|
40
|
-
| `--assets <path>` | With `--admin`: the static assets directory `mantle bundle` builds Admin into (`<assets>/admin`); default `<outdir>/client`. Written to Wrangler's `assets.directory`, and to the build command when not the default. |
|
|
54
|
+
| `--assets <path>` | With `--admin`: the static assets directory `mantle bundle` builds Admin into (`<assets>/admin`); default `<outdir>/client`. Written to Wrangler's `assets.directory`, and to the build command when not the default. New assets blocks default to `ASSETS`, Worker-first routing and no HTML rewriting; existing blocks keep their binding/routing. |
|
|
41
55
|
|
|
42
56
|
## Outputs
|
|
43
57
|
|
|
@@ -3,7 +3,7 @@ description: Generate a small native D1 service and mount an application-owned W
|
|
|
3
3
|
---
|
|
4
4
|
# Quickstart: a service on Workers
|
|
5
5
|
|
|
6
|
-
Create an application outside the SDK checkout. Install
|
|
6
|
+
Create an application outside the SDK checkout. Install stable `@aotter/mantle@0.2.0` exactly, TypeScript, Wrangler and Cloudflare Worker types; `node_modules/@aotter/mantle/docs/examples/app-shell/package.json` lists the versions this release is tested with. Read that installed version's handbook; this page describes the native 0.2.0 contract.
|
|
7
7
|
|
|
8
8
|
Save `manifests/tickets.yaml`:
|
|
9
9
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: develop
|
|
3
|
-
description: Work on an existing Mantle 0.2 project — manifests, SQL Views and Procedures, ref handlers, the service entry, surfaces, identity and
|
|
3
|
+
description: Work on an existing Mantle 0.2 project — manifests, SQL Views and Procedures, ref handlers, the service entry, surfaces, identity, MCP tool design and independent acceptance — using the installed package's contract.
|
|
4
4
|
metadata:
|
|
5
5
|
source: "@aotter/mantle"
|
|
6
6
|
sourcePath: docs/skills/develop/SKILL.md
|
|
@@ -12,28 +12,49 @@ metadata:
|
|
|
12
12
|
|
|
13
13
|
## Workflow
|
|
14
14
|
|
|
15
|
-
Read the installed SDK README
|
|
15
|
+
Read the installed SDK README, then follow the version-matched [project and CLI
|
|
16
|
+
workflow](../../handbook/start/project-and-cli.md) before editing.
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
resources; Better Auth’s admin plugin `adminRoles` defines the admin layer (default `["admin"]`); `ctx.admin` takes no role list ([authorization](../../handbook/cloudflare/authentication.md)).
|
|
22
|
-
|
|
23
|
-
Use the native Store/query/surface entries and app-owned fetch from the service composition guide.
|
|
18
|
+
Use the native Store/query/surface entries and app-owned fetch from the [service
|
|
19
|
+
composition guide](../../handbook/cloudflare/service-entry.md).
|
|
20
|
+
Pair every HTTP Trigger with an MCP Trigger by default; see [Trigger](../../handbook/reference/trigger.md)
|
|
21
|
+
for the generate warning and deliberate asymmetry exception.
|
|
24
22
|
Keep optional modules out of unused entry imports and auth dynamically loaded.
|
|
25
23
|
Run actual public/member/admin HTTP, MCP and UI scenarios; verify stored state,
|
|
26
24
|
visibility, OCC and restart persistence, not just a 200 response.
|
|
25
|
+
Before reporting any new app or feature as done, follow the [independent
|
|
26
|
+
acceptance guide](../../handbook/guides/agent-workflow-acceptance.md): write a
|
|
27
|
+
private rubric, then give one fresh agent per role (`admin`, `user`) only its
|
|
28
|
+
role and entry points, across every surface it uses. This is not limited to
|
|
29
|
+
MCP; if it was not run, say so explicitly and report the work as UNVERIFIED
|
|
30
|
+
rather than done. For MCP workflows, also run the guide's design audit before implementing
|
|
31
|
+
tools.
|
|
27
32
|
|
|
28
|
-
For native Admin, read the [current guide](../../handbook/guides/native-admin.md)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
use
|
|
33
|
+
For native Admin, read the [current guide](../../handbook/guides/native-admin.md):
|
|
34
|
+
the app builds Admin with `mantle bundle`. To customise pages, slots, hooks or
|
|
35
|
+
MCP-host-safe components, follow [Customising Admin](../../handbook/guides/native-admin.md#customising-admin).
|
|
36
|
+
Keep matching SDK, Admin and UI versions. Ref handlers retain caller-bound
|
|
37
|
+
`ctx.store`; generic Admin reads use shared generated View templates and writes
|
|
38
|
+
use native Procedure fragments.
|
|
34
39
|
Check actual member/Admin OTP, private scope/TTL/translation visibility, paging,
|
|
35
40
|
statistics, safe/exact OCC and no automatic retry after unknown 503 outcomes.
|
|
36
41
|
|
|
42
|
+
For application-owned MCP App entries and host checks, follow the [MCP Apps
|
|
43
|
+
guide](../../handbook/guides/mcp-apps.md).
|
|
44
|
+
|
|
45
|
+
Build a custom frontend with `App` from `@modelcontextprotocol/ext-apps`: register
|
|
46
|
+
`ontoolinput`/`ontoolresult` before `connect()`, and use `callServerTool` for
|
|
47
|
+
host-proxied calls. Keep protocol negotiation and message routing in the official
|
|
48
|
+
client; importing its types while writing a second `postMessage` bridge is
|
|
49
|
+
insufficient.
|
|
50
|
+
|
|
51
|
+
For Admin UI upgrades, follow the installed handbook's
|
|
52
|
+
[retained-page recipe](../../handbook/guides/mcp-apps.md#keep-old-conversations-working-after-an-upgrade).
|
|
53
|
+
Keep deployed snapshots in source/artifact storage and pass `previous` to
|
|
54
|
+
`adminMcpApps`; verify old conversations after a changed UI build without host
|
|
55
|
+
tool refresh, reconnection or cache clearing. Keep tool contracts compatible
|
|
56
|
+
through the declared retention window.
|
|
57
|
+
|
|
37
58
|
|
|
38
59
|
Place admin MCP Procedures in Admin deliberately: `spec.uiSchema.collectionAction:
|
|
39
60
|
<schema-name>` adds a collection-header action; `spec.target: { schema, id,
|
|
@@ -51,10 +72,17 @@ The runtime never creates, alters or checks tables. Boot and requests run no DDL
|
|
|
51
72
|
|
|
52
73
|
For the first install, apply generated `schema.sql`, including selected auth/site DDL, to an empty database. Apply selected seed SQL explicitly.
|
|
53
74
|
|
|
54
|
-
For every later schema change, the application's coding agent diffs the regenerated `schema.sql`, writes a migration with the host's native tool (`wrangler d1 migrations` or the app's PostgreSQL migration tool), rehearses it on a copy, and applies it before deploying the new code.
|
|
75
|
+
For every later schema change, the application's coding agent diffs the regenerated `schema.sql`, writes a migration with the host's native tool (`wrangler d1 migrations` or the app's PostgreSQL migration tool), rehearses it on a copy, and applies it before deploying the new code.
|
|
55
76
|
|
|
56
77
|
Destructive changes and type changes need explicit data migration. Mantle drops nothing. Initial `schema.sql` is not an upgrade script.
|
|
57
78
|
|
|
58
79
|
## Data paths
|
|
59
80
|
|
|
60
81
|
Writes use Store `insert` / `update` / `delete`, `batch`, `transaction`, or declared Procedures. Never use raw SQL writes: they bypass scope, TTL, publishing and system-column rules. For reads beyond an id lookup or simple AND filter (joins, aggregates, OR, reuse), declare an internal View so the SQL is reviewable and typed. Store `findById`, `find` and `first` remain suitable for handler lookups and embedding in an existing app. Ref handlers receive `ctx.store` bound to the same Caller and transaction.
|
|
82
|
+
|
|
83
|
+
For simple creates/partial updates, prefer Store-backed ref Procedures; keep
|
|
84
|
+
Procedure `requires`/generated input checks, use only allowed patch fields and
|
|
85
|
+
return safe business fields with the actual returned ID/version. Preserve
|
|
86
|
+
omitted fields and document null semantics. Retain SQL for atomic conditional
|
|
87
|
+
or related writes; D1 batches cannot consume an earlier result. Follow the
|
|
88
|
+
[Store write guidance](../../handbook/guides/typed-queries.md#prefer-store-backed-ref-procedures-for-simple-writes).
|
|
@@ -12,13 +12,8 @@ metadata:
|
|
|
12
12
|
|
|
13
13
|
## Workflow
|
|
14
14
|
|
|
15
|
-
Read the installed SDK README
|
|
16
|
-
|
|
17
|
-
Follow the installed [native generation and service workflow](../../handbook/cloudflare/service-entry.md)
|
|
18
|
-
with its [native contract](../../handbook/guides/native-execution.md) and [supported declarations](../../handbook/reference/features.md). Commit
|
|
19
|
-
all generated output, run the same generation command with `--check`, and keep
|
|
20
|
-
bundle `dist/` untracked. The app owns its verified Caller, handlers and native
|
|
21
|
-
resources; Better Auth’s admin plugin `adminRoles` defines the admin layer (default `["admin"]`); `ctx.admin` takes no role list ([authorization](../../handbook/cloudflare/authentication.md)).
|
|
15
|
+
Read the installed SDK README, then follow the version-matched [project and CLI
|
|
16
|
+
workflow](../../handbook/start/project-and-cli.md) before editing.
|
|
22
17
|
|
|
23
18
|
Keep the application router, database/pool, identity and frontend. Replace
|
|
24
19
|
Core consumers explicitly and compose only selected generated entries. Resolve
|
|
@@ -30,8 +25,8 @@ the configured OAuth resource row (see [OAuth](../../handbook/guides/oauth.md)).
|
|
|
30
25
|
Verify cutover with actual app tests.
|
|
31
26
|
|
|
32
27
|
Preserve the app router, verified identity and native resources. For selected
|
|
33
|
-
Admin
|
|
34
|
-
|
|
28
|
+
Admin, follow the [native guide](../../handbook/guides/native-admin.md) for its
|
|
29
|
+
application-built bundle and service composition.
|
|
35
30
|
Do not import old `/spec`, `/core` or runtime surface APIs. Review data/role
|
|
36
31
|
migrations explicitly; full cross-target int64 parity and automated transfer
|
|
37
32
|
are not this release's upgrade contract.
|
|
@@ -13,13 +13,8 @@ metadata:
|
|
|
13
13
|
|
|
14
14
|
## Workflow
|
|
15
15
|
|
|
16
|
-
Read the installed SDK README
|
|
17
|
-
|
|
18
|
-
Follow the installed [native generation and service workflow](../../handbook/cloudflare/service-entry.md)
|
|
19
|
-
with its [native contract](../../handbook/guides/native-execution.md) and [supported declarations](../../handbook/reference/features.md). Commit
|
|
20
|
-
all generated output, run the same generation command with `--check`, and keep
|
|
21
|
-
bundle `dist/` untracked. The app owns its verified Caller, handlers and native
|
|
22
|
-
resources; Better Auth’s admin plugin `adminRoles` defines the admin layer (default `["admin"]`); `ctx.admin` takes no role list ([authorization](../../handbook/cloudflare/authentication.md)).
|
|
16
|
+
Read the installed SDK README, then follow the version-matched [project and CLI
|
|
17
|
+
workflow](../../handbook/start/project-and-cli.md) before editing.
|
|
23
18
|
|
|
24
19
|
Deploy/create resources only within the user's authorization; reuse configured
|
|
25
20
|
host resources. Apply reviewed and rehearsed migrations before routing traffic;
|
|
@@ -30,12 +25,20 @@ as in [Workers assets and secrets](../../handbook/cloudflare/service-entry.md#wo
|
|
|
30
25
|
Keep the Workers [public-fetch flags](../../handbook/cloudflare/deploy-and-operate.md#public-fetch-routing),
|
|
31
26
|
including environment overrides; verify deployed MCP with a real OAuth bearer
|
|
32
27
|
(`initialize` and `tools/list`), not only a browser session cookie.
|
|
28
|
+
For MCP Apps, also follow [deployed host acceptance](../../handbook/guides/mcp-apps.md#verify-a-deployed-app-in-chatgpt):
|
|
29
|
+
compare the current resource URI and visibly verify a newly invoked render tool.
|
|
30
|
+
Archive deployed Admin pages using the guide's `previous` recipe and carry them
|
|
31
|
+
through clean builds. Test the same old conversation after changing the UI build,
|
|
32
|
+
without reconnecting, refreshing host tools or clearing caches. A deliberate tool
|
|
33
|
+
contract change has its own migration/host rediscovery step. OAuth renewal, `tools/call` success and a
|
|
34
|
+
local official-host replay do not establish that the deployed App rendered.
|
|
33
35
|
Bun uses native Database/SQL, an app server and scheduler. Verify admin sign-in
|
|
34
36
|
(role admin), denied access, public reads, a persisted write, MCP and selected UI.
|
|
35
37
|
Report artifact/resources/checks and keep rollback artifacts.
|
|
36
38
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
For ChatGPT Sites, follow [Mantle on ChatGPT Sites](../../handbook/cloudflare/chatgpt-sites.md).
|
|
40
|
+
|
|
41
|
+
The app builds Admin with `mantle bundle`; serve it as [Native
|
|
42
|
+
Admin](../../handbook/guides/native-admin.md) describes. Verify both member and
|
|
43
|
+
admin OTP/UI flows. Deployment of an authorized application does not authorize
|
|
44
|
+
SDK publication; a workspace preview remains a preview.
|
|
@@ -12,24 +12,27 @@ metadata:
|
|
|
12
12
|
|
|
13
13
|
## Workflow
|
|
14
14
|
|
|
15
|
-
Read the installed SDK README
|
|
15
|
+
Read the installed SDK README, then follow the version-matched [project and CLI
|
|
16
|
+
workflow](../../handbook/start/project-and-cli.md) before editing.
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
resources; Better Auth’s admin plugin `adminRoles` defines the admin layer (default `["admin"]`); `ctx.admin` takes no role list ([authorization](../../handbook/cloudflare/authentication.md)).
|
|
18
|
+
For 0.1.x, follow [Upgrade 0.1 to 0.2](../../upgrade-0.1-to-0.2.md): give the
|
|
19
|
+
0.2 service a new database and move data by export and import; never boot 0.2
|
|
20
|
+
against a 0.1.x database. Between 0.2 versions, apply reviewed migrations
|
|
21
|
+
rehearsed on a copy.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
installation instructions. Core-to-native replaces app imports/wiring; it is not
|
|
25
|
-
a package-only update. Preserve users, sessions, content and application code.
|
|
26
|
-
Review emitted SQL/policy diffs and rehearse explicit data-preserving schema/auth/role
|
|
27
|
-
migrations on a copy. Initial schema.sql never authorizes rebuilding production
|
|
28
|
-
tables. Verify auth/Admin/MCP/REST, locks and persistence before authorized cutover.
|
|
23
|
+
For the stable 0.2 line, pin every selected Mantle package to `0.2.0`; do not upgrade an existing application by following a moving dist-tag.
|
|
29
24
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
Pin exact target SDK/peer versions and read its release notes and Admin build
|
|
26
|
+
instructions. Core-to-native replaces app imports/wiring; it is not
|
|
27
|
+
a package-only update. For 0.2-to-0.2 updates, preserve users, sessions, content
|
|
28
|
+
and application code; review emitted SQL/policy diffs and rehearse explicit
|
|
29
|
+
data-preserving schema/auth/role migrations on a copy. Initial schema.sql never
|
|
30
|
+
authorizes rebuilding production tables. Verify auth/Admin/MCP/REST, locks and
|
|
31
|
+
persistence before authorized cutover.
|
|
32
|
+
|
|
33
|
+
Follow [Customising Admin](../../handbook/guides/native-admin.md#customising-admin)
|
|
34
|
+
for the current application-built Admin; old UI subpaths have no compatibility
|
|
35
|
+
aliases. Pin only actually published versions, or explicitly use a matching
|
|
36
|
+
workspace preview. Recheck member and Admin OTP, all affected native routes,
|
|
37
|
+
private field visibility, OCC and unknown outcomes. Do not publish a package as
|
|
38
|
+
part of an application dependency update.
|