@aotter/mantle 0.1.3-alpha.5 → 0.1.3
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 +11 -3
- package/dist/cli/main.d.ts +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +3 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/skills.js +1 -1
- package/dist/cli/skills.js.map +1 -1
- package/dist/codegen/emitMantleModule.d.ts +8 -2
- package/dist/codegen/emitMantleModule.d.ts.map +1 -1
- package/dist/codegen/emitMantleModule.js +42 -12
- package/dist/codegen/emitMantleModule.js.map +1 -1
- package/docs/adr/0014-auth-better-auth-and-multi-tenant-mcp.md +2 -1
- package/docs/agent-prompts.md +6 -5
- package/docs/consumer-onboarding-audit.md +65 -0
- package/docs/handbook/cloudflare/authentication.md +16 -0
- package/docs/handbook/cloudflare/bindings.md +5 -3
- package/docs/handbook/cloudflare/deploy-and-operate.md +4 -0
- package/docs/handbook/concepts/mcp-and-agents.md +1 -1
- package/docs/handbook/concepts/runtime-and-adapters.md +1 -1
- package/docs/handbook/concepts/views.md +8 -7
- package/docs/handbook/guides/admin-ui.md +135 -0
- package/docs/handbook/guides/agent-setup.md +96 -0
- package/docs/handbook/guides/typed-queries.md +161 -0
- package/docs/handbook/navigation.json +24 -14
- 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 +2 -2
- package/docs/handbook/reference/view.md +8 -3
- package/docs/handbook/releases/index.md +45 -1
- package/docs/handbook/start/overview.md +52 -0
- package/docs/handbook/start/project-and-cli.md +2 -2
- package/docs/handbook/start/quickstart-worker.md +8 -3
- package/docs/performance-harness.md +7 -0
- package/docs/spec-only-host-adoption.md +1 -1
- package/package.json +17 -17
- package/skills/README.md +5 -1
- package/skills/develop/SKILL.md +19 -2
- package/skills/install/SKILL.md +23 -3
- package/skills/plugin/SKILL.md +17 -5
- package/skills/theme/SKILL.md +8 -1
- package/skills/update/SKILL.md +7 -2
|
@@ -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,96 @@
|
|
|
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 --skill install
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The installer selects the repository's `install` skill. Read its printed
|
|
16
|
+
installation path. In a project-local Codex installation that is
|
|
17
|
+
`.agents/skills/install/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
|
+
|
|
36
|
+
Then read:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
node_modules/@aotter/mantle/skills/install/SKILL.md
|
|
40
|
+
node_modules/@aotter/mantle/docs/handbook/start/overview.md
|
|
41
|
+
node_modules/@aotter/mantle/docs/handbook/reference/features.md
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
These files are in the npm tarball. They are the version-matched authority,
|
|
45
|
+
including when the bootstrap skill came from a different Git ref. Every
|
|
46
|
+
`docs/...` path in the skill resolves under the installed package, not under
|
|
47
|
+
`.agents/skills/install/`. Keep using that SDK's docs for host examples and CLI
|
|
48
|
+
behavior. No local `mantle` binary is available before package installation.
|
|
49
|
+
|
|
50
|
+
## 3. Project the ongoing workflows
|
|
51
|
+
|
|
52
|
+
From the application root, after installing the SDK:
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
pnpm exec mantle --help
|
|
56
|
+
pnpm exec mantle skills
|
|
57
|
+
pnpm exec mantle skills --check
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
| Artifact | What you get |
|
|
61
|
+
|---|---|
|
|
62
|
+
| `.agents/skills/mantle-{develop,plugin,theme,update}/SKILL.md` | The installed package's four project-scoped workflows. |
|
|
63
|
+
| `.claude/skills/mantle-{develop,plugin,theme,update}/SKILL.md` | Identical bytes for Claude compatibility. |
|
|
64
|
+
| `node_modules/@aotter/mantle/skills/` | All seven shipped skills, including opt-in `install`, `provision` and `media-gc`. |
|
|
65
|
+
| `node_modules/@aotter/mantle/docs/` | Handbook and examples matched to the package. |
|
|
66
|
+
|
|
67
|
+
`mantle skills` overwrites these four generated projections. Keep project-specific
|
|
68
|
+
instructions elsewhere. `--check` does not write: exit 0 means they match,
|
|
69
|
+
1 means missing/stale projections, and 2 means a command/package error.
|
|
70
|
+
`mantle generate` does not project skills. Projection does not remove an older
|
|
71
|
+
bootstrap `install` or legacy `.agent/skills` copy; use the version-matched
|
|
72
|
+
project skills for ongoing work.
|
|
73
|
+
|
|
74
|
+
## 4. Complete and verify the application
|
|
75
|
+
|
|
76
|
+
Follow a [tutorial](../start/overview.md#start-with-your-integration), then run
|
|
77
|
+
its generation, validation, TypeScript checks and actual local route probes.
|
|
78
|
+
Successful skill installation proves only that the instructions were copied.
|
|
79
|
+
It does not prove a server, login, Admin assets or MCP connection works.
|
|
80
|
+
|
|
81
|
+
| Symptom | Cause and next step |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `skills/install/SKILL.md` is missing | That is source provenance. Read the installer's destination instead. |
|
|
84
|
+
| `docs/...` is missing after `skills add` | The skill does not carry the handbook. Install the pinned SDK and read its embedded docs. |
|
|
85
|
+
| `mantle` is missing | Install local `@aotter/mantle`; run its binary through the project package manager. |
|
|
86
|
+
| `MANIFEST_ROOT_NOT_FOUND` | Author manifests in the configured directory; `generate` is not a scaffold command. |
|
|
87
|
+
| `mantle skills --check` exits 1 | Run `mantle skills`, then read the refreshed project skill. |
|
|
88
|
+
| No projected provision/media-gc skill | These are intentionally opt-in. Read their installed package files when the task calls for them. |
|
|
89
|
+
| A documented feature fails on an older release | Use that release's docs or explicitly upgrade; changing a skill does not change Runtime. |
|
|
90
|
+
|
|
91
|
+
## Source
|
|
92
|
+
|
|
93
|
+
- [Bootstrap install skill](../../../skills/install/SKILL.md)
|
|
94
|
+
- [Projection implementation](../../../packages/mantle/src/cli/skills.ts)
|
|
95
|
+
- [Package file list](../../../packages/mantle/package.json)
|
|
96
|
+
- [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)
|
|
@@ -4,12 +4,21 @@
|
|
|
4
4
|
{
|
|
5
5
|
"text": "Start here",
|
|
6
6
|
"items": [
|
|
7
|
+
{ "text": "Handbook overview", "link": "/start/overview" },
|
|
7
8
|
{ "text": "Project layout and the CLI loop", "link": "/start/project-and-cli" },
|
|
8
9
|
{ "text": "Quickstart: a minimal Worker", "link": "/start/quickstart-worker" },
|
|
9
10
|
{ "text": "Quickstart: local Admin (opt-in)", "link": "/start/quickstart-admin" },
|
|
10
11
|
{ "text": "When the host is ChatGPT Sites", "link": "/sites/index" }
|
|
11
12
|
]
|
|
12
13
|
},
|
|
14
|
+
{
|
|
15
|
+
"text": "Task guides",
|
|
16
|
+
"items": [
|
|
17
|
+
{ "text": "Agent installation and handoff", "link": "/guides/agent-setup" },
|
|
18
|
+
{ "text": "Typed queries and internal Views", "link": "/guides/typed-queries" },
|
|
19
|
+
{ "text": "Customize Admin from manifests", "link": "/guides/admin-ui" }
|
|
20
|
+
]
|
|
21
|
+
},
|
|
13
22
|
{
|
|
14
23
|
"text": "Concepts",
|
|
15
24
|
"items": [
|
|
@@ -22,6 +31,21 @@
|
|
|
22
31
|
{ "text": "Runtime pipeline and adapters", "link": "/concepts/runtime-and-adapters" }
|
|
23
32
|
]
|
|
24
33
|
},
|
|
34
|
+
{
|
|
35
|
+
"text": "Reference",
|
|
36
|
+
"items": [
|
|
37
|
+
{ "text": "Manifest feature table", "link": "/reference/features" },
|
|
38
|
+
{ "text": "Manifest envelope", "link": "/reference/manifest" },
|
|
39
|
+
{ "text": "Schema", "link": "/reference/schema" },
|
|
40
|
+
{ "text": "View", "link": "/reference/view" },
|
|
41
|
+
{ "text": "Procedure", "link": "/reference/procedure" },
|
|
42
|
+
{ "text": "Trigger", "link": "/reference/trigger" },
|
|
43
|
+
{ "text": "Authorization requirements", "link": "/reference/authorization" },
|
|
44
|
+
{ "text": "Site defaults and site_config", "link": "/reference/site-config" },
|
|
45
|
+
{ "text": "Diagnostic codes", "link": "/reference/diagnostics" },
|
|
46
|
+
{ "text": "HTTP, MCP, CLI and packages", "link": "/reference/surface" }
|
|
47
|
+
]
|
|
48
|
+
},
|
|
25
49
|
{
|
|
26
50
|
"text": "ChatGPT Sites",
|
|
27
51
|
"items": [
|
|
@@ -60,20 +84,6 @@
|
|
|
60
84
|
{ "text": "Guarded API access", "link": "/examples/guarded-api" }
|
|
61
85
|
]
|
|
62
86
|
},
|
|
63
|
-
{
|
|
64
|
-
"text": "Reference",
|
|
65
|
-
"items": [
|
|
66
|
-
{ "text": "Manifest envelope", "link": "/reference/manifest" },
|
|
67
|
-
{ "text": "Schema", "link": "/reference/schema" },
|
|
68
|
-
{ "text": "View", "link": "/reference/view" },
|
|
69
|
-
{ "text": "Procedure", "link": "/reference/procedure" },
|
|
70
|
-
{ "text": "Trigger", "link": "/reference/trigger" },
|
|
71
|
-
{ "text": "Authorization requirements", "link": "/reference/authorization" },
|
|
72
|
-
{ "text": "Site defaults and site_config", "link": "/reference/site-config" },
|
|
73
|
-
{ "text": "Diagnostic codes", "link": "/reference/diagnostics" },
|
|
74
|
-
{ "text": "HTTP, MCP, CLI and packages", "link": "/reference/surface" }
|
|
75
|
-
]
|
|
76
|
-
},
|
|
77
87
|
{
|
|
78
88
|
"text": "Releases",
|
|
79
89
|
"items": [
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Manifest capability table mapping authoring goals to Schema, View, Procedure and Trigger fields, generated APIs and Admin behavior.
|
|
3
|
+
---
|
|
4
|
+
# Manifest feature reference
|
|
5
|
+
|
|
6
|
+
All paths below are relative to the atom's `spec`. The envelope is always
|
|
7
|
+
`apiVersion`, `kind`, `metadata.name`, `spec`. Features compose from these four
|
|
8
|
+
atoms; there is no separate Form, Workflow or UI manifest kind. See the
|
|
9
|
+
[envelope reference](./manifest.md) for naming and unknown-key rules.
|
|
10
|
+
|
|
11
|
+
## Capability table
|
|
12
|
+
|
|
13
|
+
| Goal | Atom and fields | Runtime / surface effect | Contract |
|
|
14
|
+
|---|---|---|---|
|
|
15
|
+
| Define stored business data | Schema `schema` | Validated fields; storage adapter prepares the Schema. Generated entry types follow the JSON Schema subset. | [Schema](./schema.md) |
|
|
16
|
+
| Choose draft publishing or live records | Schema `lifecycle` | `publishing` has draft/publish transitions; `operational` creates live records. Admin workflow follows this choice. | [Lifecycle](../concepts/lifecycle-and-locales.md) |
|
|
17
|
+
| Label fields and collections | Schema `title`, `description`, property `title`, `description` | Localized Admin labels/help. Does not rename data keys. | [LocalizedText](./manifest.md#localizedtext) |
|
|
18
|
+
| Make Procedure-managed records | Schema `schema.readOnly` | Disables generic authoring writes; declared Procedures still work. | [Read-only collections](./schema.md#root-readonly-true) |
|
|
19
|
+
| Find and constrain records | Schema `indexes`, `uniqueIndexes`, `searchableFields` | Native access paths, uniqueness and declared substring-search fields. Search fields do not create indexes. | [Indexes](./schema.md#indexes) |
|
|
20
|
+
| Translate or relate records | Schema `localized`, `translates`; property `x-mantle-ref` | Locale rows, joined translations, relation controls and folded child collections. | [Schema](./schema.md), [Admin guide](../guides/admin-ui.md) |
|
|
21
|
+
| Stamp trusted values | Property `x-mantle-bind` | Runtime stamps identity/time; generic agent inputs exclude bound fields and Admin shows them read-only. | [Binding](./schema.md#x-mantle-bind) |
|
|
22
|
+
| Adjust collection inputs and list | Schema `uiSchema.fields`, `.list`, `.nav` | Textareas, operational columns/tabs, standalone child navigation. No CSS or component injection. | [Admin guide](../guides/admin-ui.md) |
|
|
23
|
+
| Query one Schema portably | View `from`, `fields`, `filter`, `orderBy`, `limit`, `params` | Named query with generated typed params and projected rows. | [View](./view.md), [typed queries](../guides/typed-queries.md) |
|
|
24
|
+
| Join or aggregate in SQLite | View `sql`, `params`, `limit` | One bound SELECT; requires a SQLite-capable adapter. Generated row type is `unknown`. | [SQL Views](./view.md#sql) |
|
|
25
|
+
| Choose read visibility | View `surface` | `public`: public REST/MCP; `staff`: Admin reports/staff MCP; `internal`: host binding only. Transports require host composition. | [Surfaces](./view.md#surfaces) |
|
|
26
|
+
| Authorize a query or action | View / Procedure `requires.auth`, `requires.guard` | Runtime checks verified caller context and optional guard. Visibility and UI metadata do not grant access. | [Authorization](./authorization.md) |
|
|
27
|
+
| Filter by caller identity | View `filter` with `$ctx.user: id` | Declarative equality filter; requires user auth and a left-prefix index. | [Identity filters](./view.md#value-forms) |
|
|
28
|
+
| Cache anonymous published reads | View `cache.sharedMaxAge` | Eligible public declarative publishing reads receive shared HTTP cache policy when the host configures cache scope. | [View cache](../concepts/views.md#shared-response-cache) |
|
|
29
|
+
| Configure a report | Staff View `title`, `uiSchema.list` | Ordered report/CSV columns, server-side search and exact filters. | [View list](./view.md#uischemalist) |
|
|
30
|
+
| Define an action | Procedure `input`, `output`, `handler` | Typed input/output; builtin mutation or registered host handler. A Procedure does not create an HTTP route by itself. | [Procedure](./procedure.md) |
|
|
31
|
+
| Put an action in Admin | Procedure `uiSchema.collectionAction`, `.fields`; input `x-mantle-ref`; qualifying Trigger | Collection/row actions and forms; eligible standalone operations appear under Operations. | [Admin guide](../guides/admin-ui.md) |
|
|
32
|
+
| Describe an agent action | Procedure `title`, `description`, `mcp` | Tool descriptions and behavior annotations; enforcement remains in runtime authorization/validation. | [Procedure](./procedure.md) |
|
|
33
|
+
| Expose an HTTP action | Trigger `source: { kind: http, method, path }`, `target.procedure` | Handler on the declared `/api/` path through supporting host adapters. | [HTTP Trigger](./trigger.md#http-source) |
|
|
34
|
+
| Expose an agent action | Trigger `source: { kind: mcp, surface }`, `target.procedure` | Public or staff MCP tool; Procedure authorization still applies. | [Trigger](./trigger.md) |
|
|
35
|
+
| React to content lifecycle | Trigger `source: { kind: lifecycle, schema, on, errorPolicy }`, `target.procedure` | Invokes the action on selected lifecycle events. Deferred execution needs host support. | [Hooks](../concepts/procedures-and-triggers.md) |
|
|
36
|
+
|
|
37
|
+
## Where manifest control ends
|
|
38
|
+
|
|
39
|
+
Manifests describe data, callable behavior and supported presentation metadata.
|
|
40
|
+
They do not declare arbitrary React components, visitor routes, page layouts,
|
|
41
|
+
CSS, provider credentials or deployment resources. Those belong to application
|
|
42
|
+
source and optional host packages. For an Admin change, consult the
|
|
43
|
+
[rendering map](../guides/admin-ui.md) before deciding that custom UI is needed.
|
|
44
|
+
|
|
45
|
+
The pipeline is source → parse → link → compile → prepare storage → bind
|
|
46
|
+
runtime. `mantle generate` projects the plan and types; it does not start a
|
|
47
|
+
server. Programmatic `emitMantleModule({ plan })` also accepts an already
|
|
48
|
+
compiled plan; see [typed queries](../guides/typed-queries.md).
|
|
49
|
+
|
|
50
|
+
## Source
|
|
51
|
+
|
|
52
|
+
- [Manifest grammar](../../../packages/mantle-spec/src/domain/model/ManifestGrammar.ts)
|
|
53
|
+
- [Admin UI validation](../../../packages/mantle-spec/src/domain/service/SchemaAdminUiChecker.ts)
|
|
54
|
+
- [Type generation](../../../packages/mantle-spec/src/usecase/EmitTypesUseCase.ts)
|
|
55
|
+
- [Runtime binding generation](../../../packages/mantle/src/codegen/emitMantleModule.ts)
|
|
@@ -5,6 +5,8 @@ description: Envelope fields, unknown-key policy, multi-document YAML, Localized
|
|
|
5
5
|
|
|
6
6
|
This page covers the rules that apply to every Manifest document before kind-specific validation runs. Read it once; the four atom pages ([Schema](./schema.md), [View](./view.md), [Procedure](./procedure.md), [Trigger](./trigger.md)) assume it. Diagnostic codes named here are catalogued in [Diagnostics](./diagnostics.md).
|
|
7
7
|
|
|
8
|
+
For a task-to-field table covering all four atoms, see the [Manifest feature reference](./features.md). For the resulting console, see [Customize Admin](../guides/admin-ui.md).
|
|
9
|
+
|
|
8
10
|
## Envelope
|
|
9
11
|
|
|
10
12
|
Every document is a YAML mapping with exactly four top-level keys.
|
|
@@ -37,7 +39,7 @@ The parser rejects keys outside the shipped grammar at every level it knows. The
|
|
|
37
39
|
| `/` | `apiVersion`, `kind`, `metadata`, `spec` |
|
|
38
40
|
| `/metadata` | `name` |
|
|
39
41
|
| `/spec` (Schema) | `title`, `description`, `schema`, `uiSchema`, `uniqueIndexes`, `indexes`, `searchableFields`, `localized`, `translates`, `lifecycle` |
|
|
40
|
-
| `/spec` (View) | `title`, `uiSchema`, `from`, `sql`, `surface`, `requires`, `filter`, `fields`, `orderBy`, `limit`, `params` |
|
|
42
|
+
| `/spec` (View) | `title`, `uiSchema`, `from`, `sql`, `surface`, `cache`, `requires`, `filter`, `fields`, `orderBy`, `limit`, `params` |
|
|
41
43
|
| `/spec` (Procedure) | `title`, `description`, `requires`, `input`, `uiSchema`, `output`, `handler`, `mcp` |
|
|
42
44
|
| `/spec` (Trigger) | `source`, `target` |
|
|
43
45
|
| `/spec/translates` | `parent`, `on` |
|
|
@@ -164,7 +164,7 @@ Closed Admin-only roots: `fields`, `list`, `nav`. Nested keys are closed too. Un
|
|
|
164
164
|
| `fields.<field>.widget` | Only `textarea`. The field must be a top-level property with a string type (`string` or `[string, null]`). |
|
|
165
165
|
| `list.filterField` | Operational Schemas only. A declared property with a non-empty string `enum` that is the first field of some `indexes` or `uniqueIndexes` tuple. Admin renders the enum as sidebar links and list tabs. |
|
|
166
166
|
| `list.primaryField` | Operational Schemas only. A non-empty top-level scalar property; rendered as the linked leading column. |
|
|
167
|
-
| `list.columns` | Operational Schemas only. Top-level properties, no repeats and not repeating `primaryField`; structured values render as compact JSON. |
|
|
167
|
+
| `list.columns` | Operational Schemas only. Top-level properties or native entry columns, no repeats and not repeating `primaryField`; structured values render as compact JSON. |
|
|
168
168
|
| `nav.standalone` | Boolean. `true` also emits a main Admin Nav list entry with a **parent autocomplete filter**. It does not unfold: required `x-mantle-ref` children still compose under the parent. Omit or `false` means fold-only (discover via the parent-entry workbench). Rejected on top-level Schemas, `translates` children, and Schemas with no eligible required-ref parent. |
|
|
169
169
|
| `nav.parentField` | Allowed only with `standalone: true`. Names a required `x-mantle-ref` field used as the parent filter. One eligible required ref is inferred; more than one requires an explicit `parentField`. Do not rely on property-order heuristics when multiple refs exist. |
|
|
170
170
|
|
|
@@ -97,7 +97,7 @@ Tool names are the mangled `metadata.name`: lower-cased, with `-` replaced by `_
|
|
|
97
97
|
|
|
98
98
|
| Tool | Surface | Registered when |
|
|
99
99
|
|---|---|---|
|
|
100
|
-
| `query_view_<segment>` | The View's own `surface` | One per
|
|
100
|
+
| `query_view_<segment>` | The View's own `surface` | One per public or staff View; internal Views have no tool. `annotations.readOnlyHint` is `true`; the input schema is the View's `params.properties` plus `page` and `show`. |
|
|
101
101
|
| `<procedure_segment>` | The MCP Trigger's `surface` | One per `mcp` Trigger. `annotations` carry what Core can prove (`readOnlyHint: false` for every builtin handler, `destructiveHint: true` for `op: delete`, `idempotentHint: true` when an input carries `x-mcp-hint: idempotency-key`) plus whatever the Procedure declares under `spec.mcp`; `ref` handlers get nothing inferred beyond the idempotency key. Generic authoring, lifecycle and media tools are `readOnlyHint: false`; `delete_entry` is also `destructiveHint: true`. |
|
|
102
102
|
| `<procedure segment>` | The Trigger's `surface` | One per `Trigger.source.kind: mcp`. A Procedure with no MCP Trigger is not exposed. |
|
|
103
103
|
| `request_publish` | staff | Always. Rejected at call time for an operational Schema. |
|
|
@@ -165,7 +165,7 @@ The umbrella installs Spec and Runtime only. Web, Admin, Auth, Admin UI, Bun, Ve
|
|
|
165
165
|
| `@aotter/mantle-spec` | `/spec` | Manifest grammar, parser, validators, JSON Schema to zod, site-config contract, diagnostic catalog. No environment, no IO. |
|
|
166
166
|
| `@aotter/mantle-runtime` | `/runtime` | Hexagonal runtime: domain ports, use cases, MCP catalog, storage helpers. No adapter dependencies. |
|
|
167
167
|
| — | `/runtime/testing` | Node-only crowded-SQLite planner and HTTP sampling helpers used by `mantle-harness`. |
|
|
168
|
-
| — | `/codegen` | The pure linked-manifests to typed-module emitter, with no IO. |
|
|
168
|
+
| — | `/codegen` | The pure linked-manifests or compiled-plan to typed-module emitter, with no IO. |
|
|
169
169
|
| `@aotter/mantle-web` | `/web` | HTML, Markdown, `llms.txt`, sitemap, SEO and preview composition. No routes, no platform dependencies. |
|
|
170
170
|
| `@aotter/mantle-admin` | `/admin` | Admin API, auth route mounting, OAuth pages, static-asset composition. |
|
|
171
171
|
| `@aotter/mantle-auth` | `/auth` | Host-neutral Better Auth identity, staff roles, and OAuth 2.1 / MCP authorization. Adapters own IP headers and storage bindings. |
|
|
@@ -3,7 +3,7 @@ description: View field reference — declarative and SQL forms, filter AST, par
|
|
|
3
3
|
---
|
|
4
4
|
# View
|
|
5
5
|
|
|
6
|
-
A View is a named read-only query over Schemas. It is the only atom that needs no [Trigger](./trigger.md):
|
|
6
|
+
A View is a named read-only query over Schemas. It is the only atom that needs no [Trigger](./trigger.md): `surface: public` or `staff` exposes it on supported transports; `internal` keeps it host-only. This page is the field-level contract; the concepts are in [Views](../concepts/views.md) and [The four atoms](../concepts/four-atoms.md). Envelope rules are in [Manifest envelope and conventions](./manifest.md), and every diagnostic code named here is catalogued in [Diagnostics](./diagnostics.md).
|
|
7
7
|
|
|
8
8
|
## Fields
|
|
9
9
|
|
|
@@ -13,7 +13,7 @@ A View is a named read-only query over Schemas. It is the only atom that needs n
|
|
|
13
13
|
| `uiSchema` | object | no | — | Only on `surface: staff`; only the key `list`. Violations are `VIEW_UI_INVALID`. |
|
|
14
14
|
| `from` | string | exactly one of `from` / `sql` | — | Name of a declared Schema (`VIEW_FROM_UNKNOWN_SCHEMA`). The declarative form. |
|
|
15
15
|
| `sql` | string | exactly one of `from` / `sql` | — | One SQLite `SELECT`. See [`sql`](#sql). |
|
|
16
|
-
| `surface` | `public` \| `staff` | yes | — | Decides where the View mounts. See [Surfaces](#surfaces). |
|
|
16
|
+
| `surface` | `public` \| `staff` \| `internal` | yes | — | Decides where the View mounts. See [Surfaces](#surfaces). |
|
|
17
17
|
| `cache` | `{ sharedMaxAge }` | no | — | Anonymous REST shared-cache hint. `sharedMaxAge` is an integer from 1 to 86400. Only an unguarded, declarative public View over a publishing Schema may declare it. |
|
|
18
18
|
| `requires` | AuthorizationRequirements | no | — | `auth.all` predicates plus one optional `guard.procedure`. See [Authorization](./authorization.md). |
|
|
19
19
|
| `filter` | FilterAst | no | — | `from` form only. See [Filter AST](#filter-ast). |
|
|
@@ -154,7 +154,7 @@ One statement, read-only, compiled and bound by the runtime.
|
|
|
154
154
|
Bound params are passed as positional values; caller input is never interpolated into the statement. SQLite JSON functions are available, so `json_each` and `json_extract` can unnest and project array or object members of `data` — the SQL example above does both.
|
|
155
155
|
|
|
156
156
|
> **Warning**
|
|
157
|
-
> `sql` Views are native SQLite.
|
|
157
|
+
> `sql` Views are native SQLite. `mantle validate` prepares each statement against an empty SQLite database containing only the declared Schema tables; an undeclared table, syntax error or unknown column is `INVALID_MANIFEST_ENVELOPE` at `/spec/sql`. Programmatic validation runs the same check when the host supplies `sqlViewSandbox`; without that port it is deferred to the host's admission gate. On a storage adapter that does not support the native dialect the View fails at prepare time with `VIEW_DIALECT_UNSUPPORTED`, naming the dialects that adapter does support.
|
|
158
158
|
|
|
159
159
|
## `params`
|
|
160
160
|
|
|
@@ -205,6 +205,11 @@ Admin applies search and filters before pagination, rejecting a search term or f
|
|
|
205
205
|
|---|---|---|---|
|
|
206
206
|
| `public` | `GET /api/views/<name>`, plus a catalog at `GET /api/views` | `query_view_<segment>` on `/mcp` | Also mounted at `GET /admin/api/views/<name>` and `/export` behind the staff gate |
|
|
207
207
|
| `staff` | `GET /admin/api/views/<name>` and `/admin/api/views/<name>/export` — not mounted publicly | `query_view_<segment>` on `/mcp/staff` | Report sidebar |
|
|
208
|
+
| `internal` | Not mounted | Not mounted | Not listed or mounted |
|
|
209
|
+
|
|
210
|
+
For a complete generated-binding example, see [Typed queries](../guides/typed-queries.md).
|
|
211
|
+
|
|
212
|
+
An `internal` View remains in the compiled plan for host code to call through `MantleRuntime.executeView`. It is an exposure policy, not an authorization bypass: `requires` and guards still evaluate against the `ctx` supplied by the host. Shared HTTP caching is invalid because no adapter owns an HTTP response for the View.
|
|
208
213
|
|
|
209
214
|
A `public` declarative View over a `publishing` Schema reads **published rows only**, on every transport. The runtime adds `status = published` to the compiled query whether or not the filter spells it out; writing it is allowed and redundant, and comparing `status` to any other value is rejected at validate time (`VIEW_PUBLIC_STATUS_INVALID`). Staff Views see every status. `operational` Schemas create rows as `published`, so nothing is added. SQL Views (`spec.sql`) are the author's own statement and receive no injected predicate. Decision record: ADR-0025.
|
|
210
215
|
|