@aotter/mantle 0.1.3-alpha.6 → 0.1.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 +5 -5
- package/dist/cli/main.d.ts +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +4 -2
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/skills.js +2 -2
- package/dist/cli/skills.js.map +1 -1
- package/docs/adr/0001-four-atom-manifest-model.md +3 -2
- package/docs/adr/0013-agent-provisioned-consumer-projects.md +4 -4
- package/docs/adr/0016-site-semantic-layer.md +5 -4
- package/docs/adr/0018-core-starters-repository-boundary.md +1 -1
- package/docs/adr/README.md +2 -2
- package/docs/agent-prompts.md +10 -8
- package/docs/assets/mantle-admin-developer.png +0 -0
- package/docs/consumer-onboarding-audit.md +65 -0
- package/docs/examples/README.md +1 -1
- package/docs/examples/host-chatgpt-sites/README.md +29 -12
- package/docs/examples/host-chatgpt-sites/drizzle/0003_store_instance_id.sql +1 -0
- package/docs/examples/host-chatgpt-sites/drizzle/meta/_journal.json +1 -1
- package/docs/examples/host-chatgpt-sites/public/site.css +1 -1
- package/docs/examples/host-chatgpt-sites/scripts/build.mjs +2 -1
- package/docs/examples/host-chatgpt-sites/scripts/check.mjs +2 -0
- package/docs/examples/host-chatgpt-sites/src/index.ts +1 -1
- package/docs/examples/host-chatgpt-sites/src/web.ts +1 -1
- package/docs/examples/host-minimal-worker/README.md +5 -5
- package/docs/handbook/{sites → chatgpt-sites}/equipment-checkout.md +1 -1
- package/docs/handbook/{sites → chatgpt-sites}/index.md +15 -3
- package/docs/handbook/cloudflare/authentication.md +16 -0
- package/docs/handbook/cloudflare/chatgpt-sites.md +6 -6
- package/docs/handbook/cloudflare/deploy-and-operate.md +3 -2
- package/docs/handbook/cloudflare/media-r2.md +2 -2
- package/docs/handbook/concepts/four-atoms.md +1 -1
- package/docs/handbook/concepts/lifecycle-and-locales.md +1 -1
- package/docs/handbook/concepts/mcp-and-agents.md +25 -5
- package/docs/handbook/concepts/procedures-and-triggers.md +1 -1
- package/docs/handbook/concepts/runtime-and-adapters.md +2 -2
- package/docs/handbook/concepts/views.md +9 -8
- package/docs/handbook/guides/admin-ui.md +135 -0
- package/docs/handbook/guides/agent-setup.md +97 -0
- package/docs/handbook/guides/typed-queries.md +161 -0
- package/docs/handbook/navigation.json +28 -18
- package/docs/handbook/reference/features.md +55 -0
- package/docs/handbook/reference/manifest.md +3 -1
- package/docs/handbook/reference/schema.md +1 -1
- package/docs/handbook/reference/surface.md +1 -1
- package/docs/handbook/reference/view.md +4 -2
- package/docs/handbook/releases/index.md +71 -2
- package/docs/handbook/start/overview.md +52 -0
- package/docs/handbook/start/project-and-cli.md +7 -7
- package/docs/handbook/start/quickstart-worker.md +8 -6
- package/docs/release-process.md +3 -2
- package/docs/sealed-pipeline-ownership.md +1 -1
- package/docs/skills/develop/SKILL.md +250 -0
- package/docs/skills/media-gc/SKILL.md +85 -0
- package/docs/skills/plugin/SKILL.md +132 -0
- package/docs/skills/provision/SKILL.md +194 -0
- package/docs/skills/theme/SKILL.md +77 -0
- package/docs/skills/update/SKILL.md +51 -0
- package/docs/spec-only-host-adoption.md +1 -1
- package/package.json +18 -18
- package/skills/README.md +30 -21
- package/skills/develop/SKILL.md +21 -4
- package/skills/install/SKILL.md +40 -8
- package/skills/media-gc/SKILL.md +2 -2
- package/skills/plugin/SKILL.md +19 -7
- package/skills/provision/SKILL.md +3 -3
- package/skills/theme/SKILL.md +10 -3
- package/skills/update/SKILL.md +9 -4
- package/skills/.keep +0 -0
- /package/docs/handbook/{sites → chatgpt-sites}/host-reference.md +0 -0
|
@@ -4,26 +4,26 @@ description: "Mantle on ChatGPT Sites now has its own integration guide."
|
|
|
4
4
|
# Mantle on ChatGPT Sites
|
|
5
5
|
|
|
6
6
|
ChatGPT Sites has a dedicated section in the Mantle handbook. Start with
|
|
7
|
-
[Mantle on ChatGPT Sites](../sites/index.md) for installation, supported
|
|
7
|
+
[Mantle on ChatGPT Sites](../chatgpt-sites/index.md) for installation, supported
|
|
8
8
|
capabilities, and your first published article. This page preserves earlier
|
|
9
9
|
links to the host checklist.
|
|
10
10
|
|
|
11
11
|
## First deployment
|
|
12
12
|
|
|
13
|
-
See [the host deployment checklist](../sites/host-reference.md#first-deployment).
|
|
13
|
+
See [the host deployment checklist](../chatgpt-sites/host-reference.md#first-deployment).
|
|
14
14
|
|
|
15
15
|
## Media with only an R2 binding
|
|
16
16
|
|
|
17
|
-
See [R2 media integration](../sites/host-reference.md#media-with-only-an-r2-binding).
|
|
17
|
+
See [R2 media integration](../chatgpt-sites/host-reference.md#media-with-only-an-r2-binding).
|
|
18
18
|
|
|
19
19
|
## Remote MCP is a separate gate
|
|
20
20
|
|
|
21
|
-
See [MCP support and authentication](../sites/host-reference.md#remote-mcp-is-a-separate-gate).
|
|
21
|
+
See [MCP support and authentication](../chatgpt-sites/host-reference.md#remote-mcp-is-a-separate-gate).
|
|
22
22
|
|
|
23
23
|
## Capability boundaries
|
|
24
24
|
|
|
25
|
-
See [host capability boundaries](../sites/host-reference.md#capability-boundaries).
|
|
25
|
+
See [host capability boundaries](../chatgpt-sites/host-reference.md#capability-boundaries).
|
|
26
26
|
|
|
27
27
|
## Source
|
|
28
28
|
|
|
29
|
-
See [integration sources](../sites/host-reference.md#source).
|
|
29
|
+
See [integration sources](../chatgpt-sites/host-reference.md#source).
|
|
@@ -47,7 +47,8 @@ wrangler deploy
|
|
|
47
47
|
|
|
48
48
|
## Post-deploy verification
|
|
49
49
|
|
|
50
|
-
Probe the deployed origin, not `wrangler dev
|
|
50
|
+
Probe the deployed origin, not `wrangler dev`. Run only the probes for surfaces
|
|
51
|
+
the application mounts and configures:
|
|
51
52
|
|
|
52
53
|
| Probe | Expect |
|
|
53
54
|
|---|---|
|
|
@@ -55,7 +56,7 @@ Probe the deployed origin, not `wrangler dev`:
|
|
|
55
56
|
| `GET /<locale>/<segment>/<slug>` and `GET /<locale>/<segment>/<slug>.md` | `200` HTML and Markdown for a published entry |
|
|
56
57
|
| `GET /llms.txt`, `GET /sitemap.xml`, `GET /robots.txt` | `200` |
|
|
57
58
|
| `GET /<locale>/<segment>/does-not-exist` | `404` from your `notFoundRenderer` |
|
|
58
|
-
| `
|
|
59
|
+
| `POST /mcp/staff` without credentials | `401` with `WWW-Authenticate`; `GET /mcp` is `405` |
|
|
59
60
|
| `GET /admin` | Sign-in page; sign in with the `ADMIN_GITHUB_LOGIN` account |
|
|
60
61
|
|
|
61
62
|
Then check the cache: a second anonymous `GET` of a public page should show `cf-cache-status: HIT`; publish a change in Admin and the next request should be a `MISS`. Sample latency with:
|
|
@@ -3,7 +3,7 @@ description: Enable staff media uploads on R2 — presigned PUT flow through Sta
|
|
|
3
3
|
---
|
|
4
4
|
# Media uploads with R2
|
|
5
5
|
|
|
6
|
-
R2-backed media is an optional post-launch capability for Workers whose staff or agents need to upload images and files. This page covers the native Cloudflare direct-to-R2 flow, the configuration it needs, how a Schema references an asset, what a commit costs, and how to clean up. For ChatGPT Sites with an R2 binding but no S3 credentials, use [the same-origin Worker flow](../sites/host-reference.md#media-with-only-an-r2-binding).
|
|
6
|
+
R2-backed media is an optional post-launch capability for Workers whose staff or agents need to upload images and files. This page covers the native Cloudflare direct-to-R2 flow, the configuration it needs, how a Schema references an asset, what a commit costs, and how to clean up. For ChatGPT Sites with an R2 binding but no S3 credentials, use [the same-origin Worker flow](../chatgpt-sites/host-reference.md#media-with-only-an-r2-binding).
|
|
7
7
|
|
|
8
8
|
## When to enable it
|
|
9
9
|
|
|
@@ -213,4 +213,4 @@ The full catalog is in [Diagnostic codes](../reference/diagnostics.md).
|
|
|
213
213
|
- [`packages/mantle-spec/src/domain/service/SiteDefaultsValidator.ts`](../../../packages/mantle-spec/src/domain/service/SiteDefaultsValidator.ts)
|
|
214
214
|
- [`packages/mantle-spec/src/kernel/diagnostic.ts`](../../../packages/mantle-spec/src/kernel/diagnostic.ts)
|
|
215
215
|
- [`packages/adapters/cloudflare/README.md`](../../../packages/adapters/cloudflare/README.md)
|
|
216
|
-
- [`skills/media-gc/SKILL.md`](
|
|
216
|
+
- [`docs/skills/media-gc/SKILL.md`](../../skills/media-gc/SKILL.md)
|
|
@@ -170,4 +170,4 @@ Postgres exposes roughly twenty-five object kinds; an application developer writ
|
|
|
170
170
|
- [`docs/adr/0012-views-as-public-rest.md`](../../../docs/adr/0012-views-as-public-rest.md)
|
|
171
171
|
- [`packages/mantle-spec/src/domain/model/ManifestGrammar.ts`](../../../packages/mantle-spec/src/domain/model/ManifestGrammar.ts)
|
|
172
172
|
- [`packages/mantle-spec/src/domain/service/ManifestParser.ts`](../../../packages/mantle-spec/src/domain/service/ManifestParser.ts)
|
|
173
|
-
- [`skills/develop/SKILL.md`](
|
|
173
|
+
- [`docs/skills/develop/SKILL.md`](../../skills/develop/SKILL.md)
|
|
@@ -139,4 +139,4 @@ The full worked version of this pattern, with a locale-parameterized public View
|
|
|
139
139
|
- [`packages/mantle-spec/src/domain/model/SiteConfig.ts`](../../../packages/mantle-spec/src/domain/model/SiteConfig.ts)
|
|
140
140
|
- [`packages/mantle-runtime/src/domain/service/io/EntryWriteGuard.ts`](../../../packages/mantle-runtime/src/domain/service/io/EntryWriteGuard.ts)
|
|
141
141
|
- [`packages/mantle-runtime/src/infrastructure/mcp/McpToolCatalog.ts`](../../../packages/mantle-runtime/src/infrastructure/mcp/McpToolCatalog.ts)
|
|
142
|
-
- [`skills/develop/SKILL.md`](
|
|
142
|
+
- [`docs/skills/develop/SKILL.md`](../../skills/develop/SKILL.md)
|
|
@@ -20,7 +20,7 @@ A tool name is derived from a manifest name by `mcpToolNameSegment`: lowercased,
|
|
|
20
20
|
|
|
21
21
|
| Tool | Produced by | Surface |
|
|
22
22
|
|---|---|---|
|
|
23
|
-
| `query_view_<segment>` |
|
|
23
|
+
| `query_view_<segment>` | Public or staff View (never internal) | The View's own `surface` |
|
|
24
24
|
| `create_draft_<schema>`, `update_draft_<schema>` | A Schema with `lifecycle: publishing` | Staff |
|
|
25
25
|
| `create_record_<schema>`, `update_record_<schema>` | A Schema with `lifecycle: operational` | Staff |
|
|
26
26
|
| `request_publish`, `unpublish_entry`, `archive_entry`, `delete_entry` | Present when an applicable Schema exists | Staff |
|
|
@@ -68,6 +68,25 @@ Only `status: published` entries appear anywhere in that set. Details are in [Pu
|
|
|
68
68
|
|
|
69
69
|
## WebMCP in the browser
|
|
70
70
|
|
|
71
|
+
### Admin: tools for the signed-in staff member
|
|
72
|
+
|
|
73
|
+
Admin UI registers staff tools in browsers supporting `document.modelContext`.
|
|
74
|
+
The catalog comes from `GET /admin/api/webmcp`; calls use
|
|
75
|
+
`POST /admin/api/mcp` with the current staff session. Server-side role checks,
|
|
76
|
+
Procedure authorization, and optimistic concurrency remain in force.
|
|
77
|
+
`admin_get_context` and `admin_navigate` add page context and navigation.
|
|
78
|
+
The WebMCP control appears after registration succeeds; unsupported browsers
|
|
79
|
+
can continue using the regular Admin UI.
|
|
80
|
+
|
|
81
|
+
Owners can explore application API documentation in Developer UI:
|
|
82
|
+
`/admin/dev/docs/api` for HTTP, `/admin/dev/docs/mcp` for remote MCP, and
|
|
83
|
+
`/admin/dev/docs/webmcp` for the Admin catalog and public-page capabilities.
|
|
84
|
+
These pages show projected definitions. Remote clients connect to the host's
|
|
85
|
+
advertised MCP endpoints using the authentication described above.
|
|
86
|
+
See the [Admin API guide](../../../packages/mantle-admin/README.md#admin-webmcp).
|
|
87
|
+
|
|
88
|
+
### Public pages: opt-in registration
|
|
89
|
+
|
|
71
90
|
`@aotter/mantle-web/webmcp` exposes public capabilities as tools inside a page, for browsers implementing the draft imperative WebMCP API. Importing the subpath has no side effect; registration starts only when `bindWebMcp()` is called.
|
|
72
91
|
|
|
73
92
|
```ts
|
|
@@ -78,7 +97,7 @@ const binding = await bindWebMcp();
|
|
|
78
97
|
binding.dispose();
|
|
79
98
|
```
|
|
80
99
|
|
|
81
|
-
It feature-detects `document.modelContext` and returns `{ supported: false }` on browsers without it.
|
|
100
|
+
It feature-detects `document.modelContext` and returns `{ supported: false }` on browsers without it. This public-page binding registers only public capabilities. Staff tools use the separate authenticated Admin integration above. Existing host tool names are inspected and skipped, never replaced. A server-backed page discovers the safe descriptors published at `GET /api/views` and calls the same-origin `GET /api/views/<name>` routes; a browser-local SPA passes `projectCallableCapabilities(plan, { surface: "public" })` and its own invoker. Procedure tools must still originate from an explicit public MCP Trigger, and invocation enters the runtime through that Trigger, so browser tools cannot bypass validation or authorization. See [Runtime pipeline and adapters](./runtime-and-adapters.md).
|
|
82
101
|
|
|
83
102
|
## Skills for your coding agent
|
|
84
103
|
|
|
@@ -91,11 +110,12 @@ pnpm exec mantle skills --check
|
|
|
91
110
|
|
|
92
111
|
This copies every skill the installed package marks `projection: project` — the develop skill among them — into matching `.agents/skills/mantle-*` and `.claude/skills/mantle-*` paths. Both layouts receive identical bytes; `--check` detects drift without writing. Skills that act destructively or target one platform stay out of that set and are opt-in. Manifest generation never rewrites agent instructions.
|
|
93
112
|
|
|
94
|
-
The
|
|
113
|
+
The bootstrap `mantle` skill is also available from the plugin marketplace.
|
|
114
|
+
The ongoing workflows come from the installed SDK through `mantle skills`:
|
|
95
115
|
|
|
96
116
|
```sh
|
|
97
117
|
# Canonical
|
|
98
|
-
npx skills add aotter/mantle
|
|
118
|
+
npx skills add aotter/mantle
|
|
99
119
|
|
|
100
120
|
# Claude Code — two separate prompts
|
|
101
121
|
/plugin marketplace add aotter/mantle
|
|
@@ -111,4 +131,4 @@ Never point a versioned project at a mutable branch. See [Project layout and the
|
|
|
111
131
|
- [`packages/mantle-web/README.md`](../../../packages/mantle-web/README.md)
|
|
112
132
|
- [`packages/mantle/README.md`](../../../packages/mantle/README.md)
|
|
113
133
|
- [`packages/adapters/cloudflare/README.md`](../../../packages/adapters/cloudflare/README.md)
|
|
114
|
-
- [`skills/develop/SKILL.md`](
|
|
134
|
+
- [`docs/skills/develop/SKILL.md`](../../skills/develop/SKILL.md)
|
|
@@ -218,4 +218,4 @@ Register the two `ref` keys in the project's handlers map, then run the check lo
|
|
|
218
218
|
- [`packages/mantle-spec/src/domain/model/ManifestGrammar.ts`](../../../packages/mantle-spec/src/domain/model/ManifestGrammar.ts)
|
|
219
219
|
- [`packages/mantle-runtime/src/domain/service/BuiltinProjector.ts`](../../../packages/mantle-runtime/src/domain/service/BuiltinProjector.ts)
|
|
220
220
|
- [`packages/mantle-runtime/src/infrastructure/http/createMantleRequestHandler.ts`](../../../packages/mantle-runtime/src/infrastructure/http/createMantleRequestHandler.ts)
|
|
221
|
-
- [`skills/develop/SKILL.md`](
|
|
221
|
+
- [`docs/skills/develop/SKILL.md`](../../skills/develop/SKILL.md)
|
|
@@ -51,7 +51,7 @@ const bound = bindMantle(runtime);
|
|
|
51
51
|
await bound.runtime.archive.execute({ id, ctx });
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
Generated property names are deterministic lower-camel identifiers; calls keep the authored wire names internally, and a collision is an error (`CODEGEN_IDENTIFIER_COLLISION`). Code generation is a pure projection: it never caches, retries, mounts routes or owns host lifecycle, and the typed API keeps its raw `runtime` so it hides nothing. Skipping generation is valid — call `runtime.executeView({ view: "published-notes" })` by name.
|
|
54
|
+
Generated property names are deterministic lower-camel identifiers; calls keep the authored wire names internally, and a collision is an error (`CODEGEN_IDENTIFIER_COLLISION`). The emitter accepts either `emitMantleModule({ linked })` or `emitMantleModule({ plan })` for hosts that already compiled the plan; see [Typed queries](../guides/typed-queries.md). Code generation is a pure projection: it never caches, retries, mounts routes or owns host lifecycle, and the typed API keeps its raw `runtime` so it hides nothing. Skipping generation is valid — call `runtime.executeView({ view: "published-notes" })` by name.
|
|
55
55
|
|
|
56
56
|
## Core, optional products, adapters
|
|
57
57
|
|
|
@@ -174,4 +174,4 @@ If a normal feature cannot be expressed through a purpose-shaped surface, treat
|
|
|
174
174
|
- [`packages/adapters/bun/README.md`](../../../packages/adapters/bun/README.md)
|
|
175
175
|
- [`packages/adapters/vercel/README.md`](../../../packages/adapters/vercel/README.md)
|
|
176
176
|
- [`packages/adapters/indexeddb/README.md`](../../../packages/adapters/indexeddb/README.md)
|
|
177
|
-
- [`skills/develop/SKILL.md`](
|
|
177
|
+
- [`docs/skills/develop/SKILL.md`](../../skills/develop/SKILL.md)
|
|
@@ -3,24 +3,25 @@ description: Views are the only public read surface — surfaces, declarative ve
|
|
|
3
3
|
---
|
|
4
4
|
# Reads: Views, REST and MCP
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
Views declare reusable queries and their transport visibility. This page explains why, how a View is shaped, and what it costs at query time. Field-level rules are in the [View reference](../reference/view.md).
|
|
7
7
|
|
|
8
8
|
## One read surface, not two
|
|
9
9
|
|
|
10
|
-
A View is a named, read-only query over Schemas.
|
|
10
|
+
A View is a named, read-only query over Schemas. Public and staff Views mount on supported transports with no [Trigger](./procedures-and-triggers.md) involved. Schemas are never publicly readable on their own.
|
|
11
11
|
|
|
12
12
|
Exposing collections directly — a `Schema.spec.expose.rest` flag, or a `GET /api/<collection>` shortcut — was considered and rejected. A Schema declares the storage shape. Its entries carry drafts, internal status, server-stamped fields and per-row data the author never intended to publish; `contact-messages` is the canonical example, where a direct collection route would be a privacy bug by default. A View already has the right semantics — a named query with explicit fields, filter, ordering and limit — so auto-exposing it only ratifies what the manifest already says.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Use `surface: internal` for a named query callable only by host code. It remains in the plan and generated bindings, but is absent from REST, MCP, WebMCP and Admin reports. Its `requires` and guards still run. See [Typed queries](../guides/typed-queries.md).
|
|
15
15
|
|
|
16
16
|
## Surfaces
|
|
17
17
|
|
|
18
|
-
`spec.surface` is required and closed to
|
|
18
|
+
`spec.surface` is required and closed to three values.
|
|
19
19
|
|
|
20
20
|
| `surface` | REST | MCP | Extra |
|
|
21
21
|
|---|---|---|---|
|
|
22
22
|
| `public` | `GET /api/views/<name>` | `query_view_<segment>` on `/mcp` | Listed by `GET /api/views` |
|
|
23
23
|
| `staff` | `GET /admin/api/views/<name>` | `query_view_<segment>` on `/mcp/staff` | `GET /admin/api/views/<name>/export`, Admin report sidebar |
|
|
24
|
+
| `internal` | None | None | Host calls through `executeView` or generated `views` bindings |
|
|
24
25
|
|
|
25
26
|
The adapter filters the View set before building each MCP dispatcher, so a guessed public tool call cannot reach a staff View. Surface decides transport visibility; `spec.requires` decides whether the verified caller may execute the View, on REST and MCP alike. See [Authorization](./authorization.md).
|
|
26
27
|
|
|
@@ -31,7 +32,7 @@ A View declares exactly one of `from` or `sql`; declaring both or neither is rej
|
|
|
31
32
|
- **`from`** names a Schema and pairs with `fields`, `filter`, `orderBy` and `limit`. The filter is a closed AST: `eq`, `gt`, `gte`, `lt`, `lte`, combined with `and` and `or`. Field-to-field comparison and arithmetic are not expressible.
|
|
32
33
|
- **`sql`** is a single `SELECT` with no semicolon. Every Schema is available as a logical table named after its `metadata.name`, with data properties projected as columns; quote names containing hyphens (`"post-translations"`). Combining `sql` with `fields`, `filter` or `orderBy` is rejected.
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
Use `from` for portable single-Schema queries, typed result rows and eligible public caching. Use `sql` for joins, aggregation or JSON expansion that the declarative form cannot express. SQL Views require a SQLite-capable adapter (`VIEW_DIALECT_UNSUPPORTED` otherwise), and generated SQL row types are `unknown`. The CLI validates SQL against an empty database of declared Schema tables; programmatic validation needs the `sqlViewSandbox` port for the same check. Exercise data-dependent behavior on your adapter or with `mantle-harness indexes`.
|
|
35
36
|
|
|
36
37
|
## Params
|
|
37
38
|
|
|
@@ -88,7 +89,7 @@ These names are output field names — SQL aliases for a `sql` View, Schema prop
|
|
|
88
89
|
|
|
89
90
|
## The MCP mirror
|
|
90
91
|
|
|
91
|
-
Every View is also a tool. The name is the View name lowercased with hyphens replaced by underscores, prefixed `query_view_`. Its input schema is `params.properties` plus `page` and `show`, and it is annotated `readOnlyHint: true`. One executor and one response shape serve REST and MCP, so an agent and a downstream service read exactly the same rows. See [MCP and agents](./mcp-and-agents.md).
|
|
92
|
+
Every public or staff View is also a tool on its matching MCP surface; internal Views are never tools. The name is the View name lowercased with hyphens replaced by underscores, prefixed `query_view_`. Its input schema is `params.properties` plus `page` and `show`, and it is annotated `readOnlyHint: true`. One executor and one response shape serve REST and MCP, so an agent and a downstream service read exactly the same rows. See [MCP and agents](./mcp-and-agents.md).
|
|
92
93
|
|
|
93
94
|
## Performance: declare the index the query needs
|
|
94
95
|
|
|
@@ -97,7 +98,7 @@ a native column. Declared `indexes` and `uniqueIndexes` become B-tree indexes
|
|
|
97
98
|
over those columns; Core-compiled projections, filters and ordering reference
|
|
98
99
|
the same columns directly.
|
|
99
100
|
|
|
100
|
-
Declare the **smallest ordered index justified by the measured path**, and respect SQLite's leftmost-prefix rule. Equality columns go first, the ordered column last. A public View over a publishing Schema always carries `status = published`, so its index leads with `status`: `[status, locale, publishedAt]` serves `WHERE status = ? AND locale = ?`, `… AND publishedAt > ?`, and `… ORDER BY publishedAt`. It does not serve `WHERE publishedAt > ?` alone, and `[publishedAt]` alone does not serve the published list — without planner statistics SQLite prefers the status equality and sorts in a temporary B-tree. If a second hot path needs a different leading field, that is a second index — not a reason to enumerate every permutation, since each index costs storage and slows every write.
|
|
101
|
+
Declare the **smallest ordered index justified by the measured path**, and respect SQLite's leftmost-prefix rule. Equality columns go first, the ordered column last. A public declarative View over a publishing Schema always carries `status = published`, so its index leads with `status`: `[status, locale, publishedAt]` serves `WHERE status = ? AND locale = ?`, `… AND publishedAt > ?`, and `… ORDER BY publishedAt`. It does not serve `WHERE publishedAt > ?` alone, and `[publishedAt]` alone does not serve the published list — without planner statistics SQLite prefers the status equality and sorts in a temporary B-tree. If a second hot path needs a different leading field, that is a second index — not a reason to enumerate every permutation, since each index costs storage and slows every write.
|
|
101
102
|
|
|
102
103
|
```sh
|
|
103
104
|
pnpm exec mantle-harness indexes --require-public --format text
|
|
@@ -188,4 +189,4 @@ spec:
|
|
|
188
189
|
- [`packages/mantle-runtime/src/infrastructure/storage/SqliteViewCompiler.ts`](../../../packages/mantle-runtime/src/infrastructure/storage/SqliteViewCompiler.ts)
|
|
189
190
|
- [`packages/mantle-runtime/src/infrastructure/http/createMantleRequestHandler.ts`](../../../packages/mantle-runtime/src/infrastructure/http/createMantleRequestHandler.ts)
|
|
190
191
|
- [`packages/adapters/cloudflare/src/mount/mountRuntimeEndpoints.ts`](../../../packages/adapters/cloudflare/src/mount/mountRuntimeEndpoints.ts)
|
|
191
|
-
- [`skills/develop/SKILL.md`](
|
|
192
|
+
- [`docs/skills/develop/SKILL.md`](../../skills/develop/SKILL.md)
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: How Schema, View, Procedure, Trigger and uiSchema become Admin forms, lists, navigation and actions, with a complete customization example.
|
|
3
|
+
---
|
|
4
|
+
# Customize the Admin console
|
|
5
|
+
|
|
6
|
+
Many Admin changes are manifest edits: labels, multiline inputs, operational
|
|
7
|
+
list columns and tabs, reports and action placement. Admin API derives
|
|
8
|
+
metadata from the compiled plan; the prebuilt SPA renders it. The host must
|
|
9
|
+
already mount Admin API, authentication and Admin assets — see the
|
|
10
|
+
[local Admin tutorial](../start/quickstart-admin.md).
|
|
11
|
+
|
|
12
|
+
## Manifest to rendered UI
|
|
13
|
+
|
|
14
|
+
| User request | Author this | What Admin renders / constraints |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| Rename a collection or explain a field | Schema `title` / `description`, property `title` / `description` | Localized labels and help. Property names and stored values stay unchanged. |
|
|
17
|
+
| Make a field required or an option list | JSON Schema `required`, `enum`, `type` | Required marker and type-derived control; enums become selects. These are data contracts, not styling flags. |
|
|
18
|
+
| Make a string multiline | Schema or Procedure `uiSchema.fields.<name>.widget: textarea` | Textarea for a top-level string field. `textarea` is the only supported explicit widget. |
|
|
19
|
+
| Edit Markdown or HTML | Property `x-mcp-hint: markdown` or `html` | Rich editor; these hints take precedence over `widget: textarea`. `richtext` currently uses a textarea. |
|
|
20
|
+
| Edit a timestamp or show money | `format: date-time` on a string; `x-mcp-hint: timestamp-ms` or `money-minor` on a number | Date/time controls or number preview. Money uses minor units divided by 100 and a sibling `currency` when present. |
|
|
21
|
+
| Reorder an operational record list | Schema `uiSchema.list.primaryField`, `.columns` | Linked leading data field, then ordered columns. Native columns such as `status` and `createdAt` are allowed in `columns`; `primaryField` must be a scalar data property. |
|
|
22
|
+
| Add business-state tabs | Schema `uiSchema.list.filterField` | Operational-only enum tabs/sidebar links. Field needs a string enum and a left-prefix index. |
|
|
23
|
+
| Search record contents | Schema `searchableFields` | Searches declared string fields plus entry id. This is substring search, not an index declaration. |
|
|
24
|
+
| Show related records | Required property `x-mantle-ref` | Eligible child collections fold into the parent's workbench; translation children use language tabs. |
|
|
25
|
+
| Also show a folded child in navigation | Schema `uiSchema.nav.standalone: true`, optional `parentField` | Adds its own list with parent filter, retaining the folded view. Multiple eligible parent refs require `parentField`; not allowed on translation children. |
|
|
26
|
+
| Add a read-only report and CSV | View `surface: staff`, `title`, `uiSchema.list` | Report navigation; `columns`, `searchFields`, `filterFields` use output names. Server filters before pagination; CSV includes all matches. |
|
|
27
|
+
| Add a list-level action | Eligible Procedure `uiSchema.collectionAction: <schema>` | Collection action with a form generated from Procedure `input`. |
|
|
28
|
+
| Add a row action | Eligible Procedure input property `x-mantle-ref: <schema>` | Row operation with prefilled reference. Selection uses a same-name Schema property, then a sole single-field unique index, otherwise entry `id`. |
|
|
29
|
+
| Make generic content editing read-only | Schema root `schema.readOnly: true` | Generic authoring writes are blocked; declared Procedures remain available. A disabled field is not an authorization rule. |
|
|
30
|
+
|
|
31
|
+
The data editor also handles booleans, numbers, objects and arrays from JSON
|
|
32
|
+
Schema. Bound fields (`x-mantle-bind`) display read-only because Runtime owns
|
|
33
|
+
the value. Media controls depend on the supported media schema and host media
|
|
34
|
+
policy; `uiSchema` alone cannot enable uploads.
|
|
35
|
+
|
|
36
|
+
Schema list presentation (`primaryField`, `columns`, `filterField`) is for
|
|
37
|
+
`lifecycle: operational`. Publishing collections keep the built-in publishing
|
|
38
|
+
workflow. For an alternate publishing table, define a staff View report.
|
|
39
|
+
|
|
40
|
+
## Example: an operational inbox
|
|
41
|
+
|
|
42
|
+
This complete source configures a collection and a separate staff report.
|
|
43
|
+
The collection filters by `ticketState`, not Mantle's native publishing status.
|
|
44
|
+
|
|
45
|
+
```yaml
|
|
46
|
+
apiVersion: cms.mantle.aotter.net/v1
|
|
47
|
+
kind: Schema
|
|
48
|
+
metadata:
|
|
49
|
+
name: support-tickets
|
|
50
|
+
spec:
|
|
51
|
+
title: { en: Support tickets, zh-TW: 客服工單 }
|
|
52
|
+
lifecycle: operational
|
|
53
|
+
schema:
|
|
54
|
+
type: object
|
|
55
|
+
additionalProperties: false
|
|
56
|
+
required: [subject, ticketState]
|
|
57
|
+
properties:
|
|
58
|
+
subject: { type: string, title: Subject }
|
|
59
|
+
details: { type: string, description: Include the steps to reproduce. }
|
|
60
|
+
ticketState: { type: string, enum: [open, waiting, closed] }
|
|
61
|
+
indexes: [[ticketState]]
|
|
62
|
+
searchableFields: [subject, details]
|
|
63
|
+
uiSchema:
|
|
64
|
+
fields:
|
|
65
|
+
details: { widget: textarea }
|
|
66
|
+
list:
|
|
67
|
+
primaryField: subject
|
|
68
|
+
columns: [ticketState, createdAt]
|
|
69
|
+
filterField: ticketState
|
|
70
|
+
---
|
|
71
|
+
apiVersion: cms.mantle.aotter.net/v1
|
|
72
|
+
kind: View
|
|
73
|
+
metadata:
|
|
74
|
+
name: support-report
|
|
75
|
+
spec:
|
|
76
|
+
title: Support report
|
|
77
|
+
surface: staff
|
|
78
|
+
from: support-tickets
|
|
79
|
+
fields: [id, subject, ticketState, createdAt]
|
|
80
|
+
uiSchema:
|
|
81
|
+
list:
|
|
82
|
+
columns: [subject, ticketState, createdAt]
|
|
83
|
+
searchFields: [subject]
|
|
84
|
+
filterFields: [ticketState]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The collection shows Subject first, State and Created at next, state tabs,
|
|
88
|
+
and a multiline Details editor. The report is a separate navigation entry
|
|
89
|
+
with its own search/filter configuration and CSV export. Schema `.list` and
|
|
90
|
+
View `.list` are different contracts; do not copy their keys between atoms.
|
|
91
|
+
|
|
92
|
+
## When a Procedure becomes a button
|
|
93
|
+
|
|
94
|
+
`uiSchema.collectionAction` alone does not expose a Procedure. Admin discovers
|
|
95
|
+
staff operations from either a staff MCP Trigger or an HTTP Trigger whose
|
|
96
|
+
Procedure requires `ctx.staff`. Runtime rechecks Procedure `requires` on
|
|
97
|
+
execution. Use the [Procedure reference](../reference/procedure.md#uischema)
|
|
98
|
+
for a complete action declaration.
|
|
99
|
+
|
|
100
|
+
An eligible operation with row bindings appears on those records. One with
|
|
101
|
+
`collectionAction` appears on that collection's list. Operations without either
|
|
102
|
+
appear in the standalone Operations screen. Row mutations use the observed
|
|
103
|
+
entry version for optimistic concurrency where the Procedure contract declares
|
|
104
|
+
`expectedVersion`; keep its input contract intact when adjusting presentation.
|
|
105
|
+
|
|
106
|
+
## Verify a change
|
|
107
|
+
|
|
108
|
+
1. Edit the application manifests, then run `mantle validate`, `mantle generate`
|
|
109
|
+
and `mantle generate --check` through the local package manager.
|
|
110
|
+
2. Restart/reload the host so Admin receives the new compiled plan. Check
|
|
111
|
+
`/admin/api/collections`, `/admin/api/views-manifest` or
|
|
112
|
+
`/admin/api/operations` in an authenticated session if the UI seems stale.
|
|
113
|
+
3. Open the affected list and editor: check labels, actual columns, filters,
|
|
114
|
+
form values and keyboard access. Verify a record after saving, and verify
|
|
115
|
+
report filters in CSV as well as the visible page.
|
|
116
|
+
|
|
117
|
+
`uiSchema` roots and supported nested keys are closed. Schema accepts `fields`,
|
|
118
|
+
`list`, `nav`; Procedure accepts `collectionAction`, `fields`; staff View accepts
|
|
119
|
+
`list`. They do not accept a custom layout, CSS, React component, arbitrary
|
|
120
|
+
widget name or permission policy. See [Schema](../reference/schema.md#uischema),
|
|
121
|
+
[View](../reference/view.md#uischemalist) and [Procedure](../reference/procedure.md#uischema).
|
|
122
|
+
|
|
123
|
+
For a new layout or unsupported widget, use application-owned UI against the
|
|
124
|
+
appropriate APIs or propose a change to the Admin UI package. Do not patch
|
|
125
|
+
`public/_mantle/admin/`: generation replaces those prebuilt assets. Visitor
|
|
126
|
+
frontend styles and the `theme` skill's site changes do not style Admin.
|
|
127
|
+
|
|
128
|
+
## Source
|
|
129
|
+
|
|
130
|
+
- [Admin UI contract validation](../../../packages/mantle-spec/src/domain/service/SchemaAdminUiChecker.ts)
|
|
131
|
+
- [Admin metadata and operation discovery](../../../packages/mantle-admin/src/mountMantleAdmin.ts)
|
|
132
|
+
- [Entry form renderer](../../../packages/mantle-admin-ui/src/features/content/entry-edit-view.tsx)
|
|
133
|
+
- [Collection renderer](../../../packages/mantle-admin-ui/src/features/content/collection-view.tsx)
|
|
134
|
+
- [Action renderer](../../../packages/mantle-admin-ui/src/features/content/row-operations.tsx)
|
|
135
|
+
- [Navigation rules](../../../packages/mantle-admin-ui/src/lib/collection-nav.ts)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Trace what npx skills add installs, hand off to the pinned SDK, project version-matched skills and diagnose missing or stale instructions.
|
|
3
|
+
---
|
|
4
|
+
# Install and verify agent instructions
|
|
5
|
+
|
|
6
|
+
There are two separate installations: an agent's bootstrap skill and the
|
|
7
|
+
application's SDK. Installing one does not install the other.
|
|
8
|
+
|
|
9
|
+
## 1. Install the bootstrap skill
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
npx skills add aotter/mantle
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The installer selects the repository's `mantle` skill. Read its printed
|
|
16
|
+
installation path. In a project-local Codex installation that is
|
|
17
|
+
`.agents/skills/mantle/SKILL.md`, not `skills/install/SKILL.md` (the latter is
|
|
18
|
+
its source-repository path). Other agent selections and global installation
|
|
19
|
+
can use different locations.
|
|
20
|
+
|
|
21
|
+
The command installs the selected brief; it does not materialize a Mantle
|
|
22
|
+
application, install `@aotter/mantle`, or copy `docs/`. The unqualified GitHub
|
|
23
|
+
source follows its default branch, not necessarily `develop` or the npm
|
|
24
|
+
version you intend to use. The skills installer's lock identifies the source
|
|
25
|
+
skill; it is not the application's dependency lockfile.
|
|
26
|
+
|
|
27
|
+
## 2. Select the SDK version, then read its own instructions
|
|
28
|
+
|
|
29
|
+
Use the version the project already pins, or resolve the requested npm channel
|
|
30
|
+
once and pin every selected `@aotter/mantle*` dependency to the same exact
|
|
31
|
+
version. `latest` and `alpha` can describe different capabilities. Resolve only
|
|
32
|
+
requirements the user has not provided: host, storage, public API/HTML, and
|
|
33
|
+
whether staff need Admin. Follow the bootstrap skill to install the selected
|
|
34
|
+
packages locally.
|
|
35
|
+
No matching `mantle-starters` tag or bundle is needed to create a project.
|
|
36
|
+
|
|
37
|
+
Then read:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
node_modules/@aotter/mantle/skills/install/SKILL.md
|
|
41
|
+
node_modules/@aotter/mantle/docs/handbook/start/overview.md
|
|
42
|
+
node_modules/@aotter/mantle/docs/handbook/reference/features.md
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
These files are in the npm tarball. They are the version-matched authority,
|
|
46
|
+
including when the bootstrap skill came from a different Git ref. Every
|
|
47
|
+
`docs/...` path in the skill resolves under the installed package, not under
|
|
48
|
+
`.agents/skills/mantle/`. Keep using that SDK's docs for host examples and CLI
|
|
49
|
+
behavior. No local `mantle` binary is available before package installation.
|
|
50
|
+
|
|
51
|
+
## 3. Project the ongoing workflows
|
|
52
|
+
|
|
53
|
+
From the application root, after installing the SDK:
|
|
54
|
+
|
|
55
|
+
```sh
|
|
56
|
+
pnpm exec mantle --help
|
|
57
|
+
pnpm exec mantle skills
|
|
58
|
+
pnpm exec mantle skills --check
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
| Artifact | What you get |
|
|
62
|
+
|---|---|
|
|
63
|
+
| `.agents/skills/mantle-{develop,plugin,theme,update}/SKILL.md` | The installed package's four project-scoped workflows. |
|
|
64
|
+
| `.claude/skills/mantle-{develop,plugin,theme,update}/SKILL.md` | Identical bytes for Claude compatibility. |
|
|
65
|
+
| `node_modules/@aotter/mantle/skills/` | All seven shipped skills, including opt-in `mantle`, `provision` and `media-gc`. |
|
|
66
|
+
| `node_modules/@aotter/mantle/docs/` | Handbook and examples matched to the package. |
|
|
67
|
+
|
|
68
|
+
`mantle skills` overwrites these four generated projections. Keep project-specific
|
|
69
|
+
instructions elsewhere. `--check` does not write: exit 0 means they match,
|
|
70
|
+
1 means missing/stale projections, and 2 means a command/package error.
|
|
71
|
+
`mantle generate` does not project skills. Projection does not remove an older
|
|
72
|
+
bootstrap `install` or legacy `.agent/skills` copy; use the version-matched
|
|
73
|
+
project skills for ongoing work.
|
|
74
|
+
|
|
75
|
+
## 4. Complete and verify the application
|
|
76
|
+
|
|
77
|
+
Follow a [tutorial](../start/overview.md#start-with-your-integration), then run
|
|
78
|
+
its generation, validation, TypeScript checks and actual local route probes.
|
|
79
|
+
Successful skill installation proves only that the instructions were copied.
|
|
80
|
+
It does not prove a server, login, Admin assets or MCP connection works.
|
|
81
|
+
|
|
82
|
+
| Symptom | Cause and next step |
|
|
83
|
+
|---|---|
|
|
84
|
+
| `skills/install/SKILL.md` is missing | That is source provenance. Read the installer's destination instead. |
|
|
85
|
+
| `docs/...` is missing after `skills add` | The skill does not carry the handbook. Install the pinned SDK and read its embedded docs. |
|
|
86
|
+
| `mantle` is missing | Install local `@aotter/mantle`; run its binary through the project package manager. |
|
|
87
|
+
| `MANIFEST_ROOT_NOT_FOUND` | Author manifests in the configured directory; `generate` is not a scaffold command. |
|
|
88
|
+
| `mantle skills --check` exits 1 | Run `mantle skills`, then read the refreshed project skill. |
|
|
89
|
+
| No projected provision/media-gc skill | These are intentionally opt-in. Read their installed package files when the task calls for them. |
|
|
90
|
+
| A documented feature fails on an older release | Use that release's docs or explicitly upgrade; changing a skill does not change Runtime. |
|
|
91
|
+
|
|
92
|
+
## Source
|
|
93
|
+
|
|
94
|
+
- [Bootstrap install skill](../../../skills/install/SKILL.md)
|
|
95
|
+
- [Projection implementation](../../../packages/mantle/src/cli/skills.ts)
|
|
96
|
+
- [Package file list](../../../packages/mantle/package.json)
|
|
97
|
+
- [Package docs and skills copying](../../../scripts/sync-package-docs.mjs)
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Generate and call typed Views, including internal-only queries, and choose indexed entry readers without confusing them with authorized public reads.
|
|
3
|
+
---
|
|
4
|
+
# Query from TypeScript
|
|
5
|
+
|
|
6
|
+
Use a **View** when a read needs declared params, projection, pagination or
|
|
7
|
+
`requires` authorization. Use an **entry reader** for trusted host code that
|
|
8
|
+
needs stored entries by a data field. Both are exposed by generated bindings;
|
|
9
|
+
only the View executes the declared View authorization contract.
|
|
10
|
+
|
|
11
|
+
## Declare an internal query
|
|
12
|
+
|
|
13
|
+
Save this complete source as `manifests/tickets.yaml`. The operational Schema
|
|
14
|
+
uses a business status field distinct from Mantle's native `status`.
|
|
15
|
+
|
|
16
|
+
```yaml
|
|
17
|
+
apiVersion: cms.mantle.aotter.net/v1
|
|
18
|
+
kind: Schema
|
|
19
|
+
metadata:
|
|
20
|
+
name: tickets
|
|
21
|
+
spec:
|
|
22
|
+
title: Tickets
|
|
23
|
+
lifecycle: operational
|
|
24
|
+
schema:
|
|
25
|
+
type: object
|
|
26
|
+
additionalProperties: false
|
|
27
|
+
required: [subject, ticketState]
|
|
28
|
+
properties:
|
|
29
|
+
subject: { type: string }
|
|
30
|
+
ticketState: { type: string, enum: [open, closed] }
|
|
31
|
+
indexes: [[ticketState]]
|
|
32
|
+
---
|
|
33
|
+
apiVersion: cms.mantle.aotter.net/v1
|
|
34
|
+
kind: View
|
|
35
|
+
metadata:
|
|
36
|
+
name: tickets-by-state
|
|
37
|
+
spec:
|
|
38
|
+
surface: internal
|
|
39
|
+
from: tickets
|
|
40
|
+
fields: [id, subject, ticketState]
|
|
41
|
+
filter:
|
|
42
|
+
eq: { field: ticketState, value: { $param: ticketState } }
|
|
43
|
+
params:
|
|
44
|
+
type: object
|
|
45
|
+
additionalProperties: false
|
|
46
|
+
required: [ticketState]
|
|
47
|
+
properties:
|
|
48
|
+
ticketState: { type: string, enum: [open, closed] }
|
|
49
|
+
limit: 50
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
pnpm exec mantle validate --no-source
|
|
54
|
+
pnpm exec mantle generate
|
|
55
|
+
pnpm exec mantle generate --check
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`internal` keeps this query out of REST routes, OpenAPI, MCP/WebMCP catalogs and
|
|
59
|
+
Admin reports. It remains in the plan and generated binding. It is not a
|
|
60
|
+
security bypass: adding `requires` evaluates the same authorization and guards
|
|
61
|
+
against the host-supplied `ctx` on every call. No `uiSchema` or shared HTTP
|
|
62
|
+
cache is allowed for an internal View.
|
|
63
|
+
|
|
64
|
+
## Bind and call
|
|
65
|
+
|
|
66
|
+
When the host already owns a prepared Runtime, bind it once where you need the
|
|
67
|
+
typed API. This function can live in `src/queries.ts`:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
import type { MantleRuntime } from "@aotter/mantle/runtime";
|
|
71
|
+
import { bindMantle } from "../.mantle/generated/mantle.js";
|
|
72
|
+
|
|
73
|
+
export async function openTickets(runtime: MantleRuntime) {
|
|
74
|
+
const mantle = bindMantle(runtime);
|
|
75
|
+
const result = await mantle.views.ticketsByState({
|
|
76
|
+
params: { ticketState: "open" },
|
|
77
|
+
page: 1,
|
|
78
|
+
show: 20,
|
|
79
|
+
});
|
|
80
|
+
if (!result.ok) throw new Error(result.diagnostic.message);
|
|
81
|
+
return result.result.rows;
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The runtime response uses `result` on success (`result.result.rows` above);
|
|
86
|
+
REST wraps those rows under `data` instead.
|
|
87
|
+
|
|
88
|
+
The wire name `tickets-by-state` becomes `ticketsByState`. Required params
|
|
89
|
+
make the request and `params` mandatory; invalid enum values are TypeScript
|
|
90
|
+
errors, and Runtime also validates actual inputs. `show` remains capped by
|
|
91
|
+
`limit`. For an authorized View, pass the verified caller context as `ctx`;
|
|
92
|
+
do not fabricate staff/user identities from request input.
|
|
93
|
+
|
|
94
|
+
A host without a Runtime can use generated `createMantle({ storage, handlers,
|
|
95
|
+
ports })`, which delegates one eager boot attempt and returns the typed
|
|
96
|
+
binding. Host code still owns connection lifetime and retries. See
|
|
97
|
+
[Runtime and adapters](../concepts/runtime-and-adapters.md).
|
|
98
|
+
|
|
99
|
+
## What is typed
|
|
100
|
+
|
|
101
|
+
| Query form | Generated shape | Limit |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| Declarative View | `Mantle.ViewParams_<name>` and `Mantle.ViewRow_<name>` | Projection follows `fields`; native columns have their native types. Data properties remain optional in the row type. |
|
|
104
|
+
| SQL View | Typed params; row type `unknown` | The generator does not infer SQL expressions or aliases. Narrow/validate rows in host code. |
|
|
105
|
+
| Entry field reader | `MantleEntry<Mantle.Entry_<schema>>` | The field must be a declared data property and the value a compatible string, number or boolean. Types do not prove an index exists. |
|
|
106
|
+
| Dynamic Runtime call | `runtime.executeView({ view, ctx, options })` | Useful without codegen; supplying a generic row type is the caller's assertion, not SQL validation. |
|
|
107
|
+
|
|
108
|
+
Without `fields`, a declarative View includes native entry columns and Schema
|
|
109
|
+
properties. Use explicit projections on exposed reads. Public declarative
|
|
110
|
+
Views over publishing Schemas inject `status = published`; internal/staff
|
|
111
|
+
Views and SQL statements do not. See [View reference](../reference/view.md).
|
|
112
|
+
|
|
113
|
+
## Indexed entry reads
|
|
114
|
+
|
|
115
|
+
For the Schema above:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
const rows = await mantle.entries.tickets.findManyByDataField({
|
|
119
|
+
field: "ticketState",
|
|
120
|
+
value: "open",
|
|
121
|
+
limit: 20,
|
|
122
|
+
});
|
|
123
|
+
// rows[n].data is the generated tickets data shape.
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
| Method | Returns | Options worth knowing |
|
|
127
|
+
|---|---|---|
|
|
128
|
+
| `readBySlug({ slug, locale?, status? })` | One entry or `null` | Use on a Schema with a slug field and an appropriate index. |
|
|
129
|
+
| `readByDataField({ field, value, locale?, status? })` | One entry or `null` | Equality on one data property. |
|
|
130
|
+
| `readByDataFieldIn({ field, values, latestPerValue?, locale?, status? })` | Entry array | Batch equality lookups; `latestPerValue` selects the newest match per value. |
|
|
131
|
+
| `findManyByDataField({ field, value, limit })` | Entry array | Bounded equality lookup across statuses; no `ctx`, `status` or `locale` option. |
|
|
132
|
+
|
|
133
|
+
These readers do not evaluate View `requires`, inject public visibility or
|
|
134
|
+
fire mutation hooks. In particular, `findManyByDataField` can return drafts.
|
|
135
|
+
Use a public View for untrusted callers; do not expose a raw reader as a public
|
|
136
|
+
route and assume the generated type authorizes it. Declare a measured index
|
|
137
|
+
whose leftmost field matches the lookup; do not scan an entire collection in
|
|
138
|
+
TypeScript to replace a field query.
|
|
139
|
+
|
|
140
|
+
## Generate from an existing plan
|
|
141
|
+
|
|
142
|
+
A build tool that already compiled a sealed plan can use the pure emitter:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { emitMantleModule } from "@aotter/mantle/codegen";
|
|
146
|
+
|
|
147
|
+
const emitted = emitMantleModule({ plan });
|
|
148
|
+
if (!emitted.ok) throw new Error(emitted.diagnostics.map(d => d.message).join("\n"));
|
|
149
|
+
// Write emitted.source to your generated module in the build step.
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Pass either `{ plan }` or `{ linked }`, never both. The plan form avoids
|
|
153
|
+
reparsing YAML and preserves the same generated types and entry/View/Procedure
|
|
154
|
+
bindings. The emitter does no I/O, asset copying, storage preparation or caching.
|
|
155
|
+
|
|
156
|
+
## Source
|
|
157
|
+
|
|
158
|
+
- [Binding generator](../../../packages/mantle/src/codegen/emitMantleModule.ts)
|
|
159
|
+
- [Type generator](../../../packages/mantle-spec/src/usecase/EmitTypesUseCase.ts)
|
|
160
|
+
- [Entry reader contract](../../../packages/mantle-runtime/src/domain/port/EntryReader.ts)
|
|
161
|
+
- [View execution](../../../packages/mantle-runtime/src/usecase/view/ExecuteViewUseCase.ts)
|