@aotter/mantle 0.1.2-alpha.6 → 0.1.2
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 +15 -10
- package/dist/cli/generate.d.ts +9 -0
- package/dist/cli/generate.d.ts.map +1 -1
- package/dist/cli/generate.js +40 -1
- package/dist/cli/generate.js.map +1 -1
- package/dist/cli/main.d.ts +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +37 -9
- package/dist/cli/main.js.map +1 -1
- package/docs/adapter-guide.md +6 -1
- package/docs/adr/adr-lite-845-frontend-client.md +38 -0
- package/docs/agent-prompts.md +91 -0
- package/docs/api-mcp-authorization.md +1 -1
- package/docs/auth-hosting-model.md +1 -1
- package/docs/examples/README.md +22 -0
- package/docs/examples/builtin-commerce.md +269 -0
- package/docs/examples/builtin-intake.md +143 -0
- package/docs/examples/builtin-legal-documents.md +189 -0
- package/docs/examples/builtin-procurement.md +241 -0
- package/docs/examples/builtin-publication.md +241 -0
- package/docs/examples/builtin-reservation.md +149 -0
- package/docs/examples/cf-primitives-commerce-inventory.md +809 -0
- package/docs/examples/cf-primitives-guarded-api.md +429 -0
- package/docs/examples/cf-primitives-intake-hooks.md +319 -0
- package/docs/examples/host-chatgpt-sites/.openai/hosting.json +1 -0
- package/docs/examples/host-chatgpt-sites/README.md +53 -0
- package/docs/examples/host-chatgpt-sites/drizzle/0000_sites_users.sql +8 -0
- package/docs/examples/host-chatgpt-sites/drizzle/0001_mantle.sql +294 -0
- package/docs/examples/host-chatgpt-sites/drizzle/0002_article_cover.sql +5 -0
- package/docs/examples/host-chatgpt-sites/drizzle/meta/_journal.json +1 -0
- package/docs/examples/host-chatgpt-sites/manifests/site.yaml +27 -0
- package/docs/examples/host-chatgpt-sites/package.json +1 -0
- package/docs/examples/host-chatgpt-sites/public/site.css +1 -0
- package/docs/examples/host-chatgpt-sites/scripts/build.mjs +12 -0
- package/docs/examples/host-chatgpt-sites/scripts/check.mjs +99 -0
- package/docs/examples/host-chatgpt-sites/scripts/migration.mjs +9 -0
- package/docs/examples/host-chatgpt-sites/src/chatgpt-auth.ts +63 -0
- package/docs/examples/host-chatgpt-sites/src/index.ts +46 -0
- package/docs/examples/host-chatgpt-sites/src/mcp.ts +49 -0
- package/docs/examples/host-chatgpt-sites/src/media.ts +109 -0
- package/docs/examples/host-chatgpt-sites/src/r2-lab.ts +38 -0
- package/docs/examples/host-chatgpt-sites/src/storage-fingerprint.json +1 -0
- package/docs/examples/host-chatgpt-sites/src/web.ts +35 -0
- package/docs/examples/host-chatgpt-sites/tsconfig.json +1 -0
- package/docs/examples/host-chatgpt-sites/wrangler.jsonc +10 -0
- package/docs/examples/host-local-admin-otp/.dev.vars.example +3 -0
- package/docs/examples/host-local-admin-otp/README.md +70 -0
- package/docs/examples/host-local-admin-otp/ensure-dev-vars.mjs +5 -0
- package/docs/examples/host-local-admin-otp/package.json +29 -0
- package/docs/examples/host-local-admin-otp/public/.gitkeep +1 -0
- package/docs/examples/host-local-admin-otp/smoke.mjs +141 -0
- package/docs/examples/host-local-admin-otp/src/index.ts +54 -0
- package/docs/examples/host-local-admin-otp/wrangler.jsonc +23 -0
- package/docs/examples/{minimal-worker → host-minimal-worker}/README.md +9 -5
- package/docs/examples/host-minimal-worker/manifests/site.yaml +25 -0
- package/docs/examples/{minimal-worker → host-minimal-worker}/package.json +3 -3
- package/docs/examples/host-minimal-worker/tsconfig.json +17 -0
- package/docs/handbook/cloudflare/authentication.md +17 -2
- package/docs/handbook/cloudflare/bindings.md +9 -7
- package/docs/handbook/cloudflare/chatgpt-sites.md +29 -0
- package/docs/handbook/cloudflare/conventional-worker.md +3 -3
- package/docs/handbook/cloudflare/deferred-hooks-queues.md +0 -1
- package/docs/handbook/cloudflare/deploy-and-operate.md +14 -20
- package/docs/handbook/cloudflare/media-r2.md +2 -2
- package/docs/handbook/cloudflare/public-web.md +1 -1
- package/docs/handbook/cloudflare/site-chrome.md +75 -0
- package/docs/handbook/concepts/authorization.md +2 -2
- package/docs/handbook/concepts/four-atoms.md +2 -2
- package/docs/handbook/concepts/lifecycle-and-locales.md +1 -1
- package/docs/handbook/concepts/mcp-and-agents.md +1 -1
- 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 +2 -2
- package/docs/handbook/examples/commerce-transaction.md +4 -806
- package/docs/handbook/examples/commerce.md +11 -0
- package/docs/handbook/examples/guarded-api.md +3 -420
- package/docs/handbook/examples/hub.md +10 -0
- package/docs/handbook/examples/intake-form.md +6 -313
- package/docs/handbook/examples/intake-hooks.md +11 -0
- package/docs/handbook/examples/legal-documents.md +3 -211
- package/docs/handbook/examples/procurement-approvals.md +3 -233
- package/docs/handbook/examples/publication.md +3 -233
- package/docs/handbook/examples/reservation.md +3 -213
- package/docs/handbook/navigation.json +17 -2
- package/docs/handbook/reference/authorization.md +1 -1
- package/docs/handbook/reference/procedure.md +2 -2
- package/docs/handbook/reference/schema.md +3 -3
- package/docs/handbook/reference/site-config.md +5 -16
- package/docs/handbook/reference/surface.md +3 -7
- package/docs/handbook/sites/equipment-checkout.md +231 -0
- package/docs/handbook/sites/host-reference.md +113 -0
- package/docs/handbook/sites/index.md +111 -0
- package/docs/handbook/start/project-and-cli.md +22 -14
- package/docs/handbook/start/quickstart-admin.md +239 -0
- package/docs/handbook/start/quickstart-worker.md +22 -23
- package/docs/migration-0.1.2.md +26 -0
- package/docs/release-process.md +92 -7
- package/docs/sealed-pipeline-ownership.md +2 -2
- package/docs/spec-only-host-adoption.md +3 -4
- package/docs/transaction-patterns.md +2 -2
- package/package.json +15 -15
- package/skills/README.md +18 -2
- package/skills/develop/SKILL.md +32 -23
- package/skills/install/SKILL.md +50 -11
- package/skills/provision/SKILL.md +21 -5
- /package/docs/examples/{minimal-worker → host-local-admin-otp}/manifests/site.yaml +0 -0
- /package/docs/examples/{minimal-worker → host-local-admin-otp}/tsconfig.json +0 -0
- /package/docs/examples/{minimal-worker → host-minimal-worker}/smoke.mjs +0 -0
- /package/docs/examples/{minimal-worker → host-minimal-worker}/src/index.ts +0 -0
- /package/docs/examples/{minimal-worker → host-minimal-worker}/wrangler.jsonc +0 -0
|
@@ -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
|
|
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).
|
|
7
7
|
|
|
8
8
|
## When to enable it
|
|
9
9
|
|
|
@@ -31,7 +31,7 @@ wrangler r2 bucket dev-url enable <project>-media
|
|
|
31
31
|
|
|
32
32
|
Then create an R2 S3 API token in the dashboard: open **R2**, open **Manage R2 API Tokens**, create an **Object Read & Write** token, and copy the Access Key ID and Secret Access Key.
|
|
33
33
|
|
|
34
|
-
The R2 binding alone cannot issue presigned `PUT` URLs: presigning is an S3-protocol operation, so
|
|
34
|
+
The R2 binding alone cannot issue presigned `PUT` URLs: presigning is an S3-protocol operation, so this **direct-to-R2 adapter** needs these credentials in addition to the binding. This is not a requirement of Mantle's `MediaStorage` port: a host may return an authenticated same-origin Worker `PUT` URL instead. Media tools appear whenever `mediaStorage` and a media purpose are bound, regardless of which transport the adapter uses.
|
|
35
35
|
|
|
36
36
|
## Wrangler configuration
|
|
37
37
|
|
|
@@ -75,7 +75,7 @@ export default createMantleWorker<Env>({
|
|
|
75
75
|
});
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
Templates return complete HTML strings; the renderer prepends the doctype. Escape every value you interpolate.
|
|
78
|
+
Templates return complete HTML strings; the renderer prepends the doctype. Escape every value you interpolate. Analytics, pixels and verification tags are host chrome — add them in the template or on Cloudflare. See [Site chrome](./site-chrome.md).
|
|
79
79
|
|
|
80
80
|
## Template signatures
|
|
81
81
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Host-owned site chrome — Cloudflare-first analytics, verification, robots, and what still belongs in mantle-web.
|
|
3
|
+
---
|
|
4
|
+
# Site chrome
|
|
5
|
+
|
|
6
|
+
Core `siteConfig` is deployment identity: locales, brand, title, description, origin, icons and media. Visitor analytics, pixels, search-engine verification tokens, `ads.txt` and similar chrome are **host responsibility**. Admin Settings does not accept tracking IDs, and `@aotter/mantle-web` does not inject vendor snippets from `siteConfig`.
|
|
7
|
+
|
|
8
|
+
Cloudflare-native platform capabilities are the first-class place for chrome that the zone already covers. Do not invent a parallel “CDN settings center” inside Mantle.
|
|
9
|
+
|
|
10
|
+
## Why Core does not inject
|
|
11
|
+
|
|
12
|
+
A headless runtime that rewrites the first `</head>` (or prepends to `<body>`) on a composed HTML string assumes one frontend shape: a complete SSR document that Core is allowed to mutate after the fact. Hosts are not one shape.
|
|
13
|
+
|
|
14
|
+
Frontends are plural. A Mantle consumer may serve SSR full HTML documents, a Vite/React (or other) SPA, a Worker plus static assets, Cloudflare Pages, or a custom wrapper that already owns `<html>`. Only the first of those even has a complete document string a runtime could splice into — and even then the attach point is the host template, not Core.
|
|
15
|
+
|
|
16
|
+
SPA, client-routed and hydration hosts attach analytics in **their own entry**: GTM or Zaraz, the app bootstrap, or Cloudflare Web Analytics. They do not expect Runtime or `mantle-web` to parse an HTML string and splice tags into it.
|
|
17
|
+
|
|
18
|
+
Silent injection from `siteConfig` would be a surprising side effect for any host that did not opt into “I emit a full document and you may rewrite it.” Core must not pretend to know every frontend’s attach point.
|
|
19
|
+
|
|
20
|
+
Therefore tracking and verification stay **host chrome**. Core `siteConfig` is not a tag-manager. The tables below say where to put chrome.
|
|
21
|
+
|
|
22
|
+
## Two layers
|
|
23
|
+
|
|
24
|
+
| Concern | Prefer | Usually still app / mantle-web |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| `robots.txt`, simple redirects, some `/.well-known` files, Cloudflare Web Analytics | **Cloudflare-native** | — |
|
|
27
|
+
| Dynamic sitemap (grows with content), `llms.txt`, SEO `.md` mirrors | — | Application mount or `@aotter/mantle-web` composition, then serve publicly |
|
|
28
|
+
|
|
29
|
+
Turning on Cloudflare Web Analytics is **not** the same as having an indexable sitemap or `llms.txt`. Analytics answers “who visited”; discovery files answer “what can a crawler or agent list”. Keep those jobs on the layer that owns the data.
|
|
30
|
+
|
|
31
|
+
Cloud tenant UX for ads.txt / robots / sitemap tools lives on the host product. Core stays injection-free.
|
|
32
|
+
|
|
33
|
+
## Cloudflare-first install
|
|
34
|
+
|
|
35
|
+
Use the dashboard, Wrangler, or an agent that can edit Worker / Pages config. None of these paths write Core Admin fields.
|
|
36
|
+
|
|
37
|
+
### Analytics
|
|
38
|
+
|
|
39
|
+
Prefer **Cloudflare Web Analytics** (and Zaraz when you need a tag manager) for first-party traffic measurement. Enable it on the zone; no Core `siteConfig` key is required.
|
|
40
|
+
|
|
41
|
+
To add GA4 or Meta Pixel:
|
|
42
|
+
|
|
43
|
+
1. Add the provider through **Cloudflare Zaraz** (recommended on a CF zone), or
|
|
44
|
+
2. Emit the vendor snippet from **your** entry/list templates in `@aotter/mantle-web`, or from a host HTML wrapper.
|
|
45
|
+
|
|
46
|
+
Do not put Measurement IDs or Pixel IDs in `siteDefaults`. Core does not persist or inject them.
|
|
47
|
+
|
|
48
|
+
### Search Console and Bing verification
|
|
49
|
+
|
|
50
|
+
Verify ownership with a host-owned method. On Cloudflare, prefer in this order:
|
|
51
|
+
|
|
52
|
+
1. **DNS TXT** at the zone apex (Search Console and Bing Webmaster both accept this).
|
|
53
|
+
2. **Cloudflare-managed HTML** via Zaraz or a small Worker / Pages header rewrite that adds `<meta name="google-site-verification">` / Bing equivalent.
|
|
54
|
+
3. A **static verification file** at `/` or `/.well-known/` served from `public/` / the `ASSETS` binding.
|
|
55
|
+
|
|
56
|
+
HTML-tag verification belongs in the host template `<head>`, not in Core Settings.
|
|
57
|
+
|
|
58
|
+
### robots.txt, redirects, well-known
|
|
59
|
+
|
|
60
|
+
Serve a static `robots.txt` from assets, or use Cloudflare Redirect Rules / Transform Rules / a tiny Worker route. `mountPublicRoutes` also emits `GET /robots.txt` (`Allow: /` plus the sitemap URL) when you opt into public pages — that is an application mount, not a Core Admin setting. See [Public web](./public-web.md).
|
|
61
|
+
|
|
62
|
+
Simple path redirects and most `/.well-known` files (including verification and `security.txt`) belong on the same Cloudflare-native layer.
|
|
63
|
+
|
|
64
|
+
## What still belongs in the app
|
|
65
|
+
|
|
66
|
+
Dynamic **sitemap** and **`llms.txt`** grow with published content. Compose them with `@aotter/mantle-web` (`composeSitemap`, `composeLlmsTxt`) and mount the public URLs, or implement the same contract in the application. Cloudflare Web Analytics does not generate those files.
|
|
67
|
+
|
|
68
|
+
SEO `.md` mirrors are likewise application / `mantle-web` composition. Details: [Public web](./public-web.md) and [Site config](../reference/site-config.md).
|
|
69
|
+
|
|
70
|
+
## Source
|
|
71
|
+
|
|
72
|
+
- [`packages/mantle-spec/src/domain/model/SiteConfig.ts`](../../../packages/mantle-spec/src/domain/model/SiteConfig.ts)
|
|
73
|
+
- [`packages/mantle-web/src/service/HtmlRenderer.ts`](../../../packages/mantle-web/src/service/HtmlRenderer.ts)
|
|
74
|
+
- [`docs/handbook/reference/site-config.md`](../reference/site-config.md)
|
|
75
|
+
- [`docs/handbook/cloudflare/public-web.md`](./public-web.md)
|
|
@@ -3,7 +3,7 @@ description: One authorization pipeline for REST, MCP and Admin — identity kin
|
|
|
3
3
|
---
|
|
4
4
|
# Authorization
|
|
5
5
|
|
|
6
|
-
Mantle has one authorization pipeline. A manifest HTTP Trigger, a View over REST, an MCP `tools/call` and an Admin operation all reach the same evaluator, so a rule written once holds on every surface. This page explains the model; the exact `requires` grammar is in the [authorization reference](../reference/authorization.md), and a worked ladder of four access levels is in [Guarded API access](
|
|
6
|
+
Mantle has one authorization pipeline. A manifest HTTP Trigger, a View over REST, an MCP `tools/call` and an Admin operation all reach the same evaluator, so a rule written once holds on every surface. This page explains the model; the exact `requires` grammar is in the [authorization reference](../reference/authorization.md), and a worked ladder of four access levels is in [Guarded API access](../../examples/cf-primitives-guarded-api.md).
|
|
7
7
|
|
|
8
8
|
## The fixed order
|
|
9
9
|
|
|
@@ -104,7 +104,7 @@ An MCP `tools/call` runs the identical evaluator, in the identical order, with t
|
|
|
104
104
|
## Related
|
|
105
105
|
|
|
106
106
|
- [Authorization requirements](../reference/authorization.md) — the `requires` shape, predicate forms, guard rules, OpenAPI projection.
|
|
107
|
-
- [Guarded API access](
|
|
107
|
+
- [Guarded API access](../../examples/cf-primitives-guarded-api.md) — a full resolver, guards and the REST/MCP outcome tables.
|
|
108
108
|
- [Reads: Views, REST and MCP](./views.md) — the `$ctx.user` identity-View sentinel.
|
|
109
109
|
- [Authentication](../cloudflare/authentication.md) — sessions, first owner, role management routes.
|
|
110
110
|
|
|
@@ -26,9 +26,9 @@ The consequence for authors: a Procedure that has no Trigger is unreachable from
|
|
|
26
26
|
|
|
27
27
|
## The composition rule
|
|
28
28
|
|
|
29
|
-
Anything more domain-shaped than these four is not an atom. A Form, Membership, Email, Webhook, Workflow or ScheduledJob is a composition of Schemas, Views, Procedures and Triggers plus your own TypeScript.
|
|
29
|
+
Anything more domain-shaped than these four is not an atom. A Form, Membership, Email, Webhook, Workflow or ScheduledJob is a composition of Schemas, Views, Procedures and Triggers plus your own TypeScript. A fifth kind would recreate the same overlap: authors would have to decide whether a contact form was a Form, a Workflow or an Email.
|
|
30
30
|
|
|
31
|
-
If you find yourself wanting
|
|
31
|
+
If you find yourself wanting another kind, sketch the same thing as a composition of the four first. Almost always it works.
|
|
32
32
|
|
|
33
33
|
## The Manifest envelope
|
|
34
34
|
|
|
@@ -129,7 +129,7 @@ The parent holds what every language shares and stays non-localized. The child s
|
|
|
129
129
|
|
|
130
130
|
When you keep parallel locale rows in step, translate display strings only. Field names, option values, step identifiers and result keys must stay identical across locales, or the same View and the same MCP tool stop describing the same thing.
|
|
131
131
|
|
|
132
|
-
The full worked version of this pattern, with a locale-parameterized public View and its REST response, is [Publication](
|
|
132
|
+
The full worked version of this pattern, with a locale-parameterized public View and its REST response, is [Publication](../../examples/builtin-publication.md).
|
|
133
133
|
|
|
134
134
|
## Source
|
|
135
135
|
|
|
@@ -33,7 +33,7 @@ Procedures are never exposed on their own. A Procedure becomes a tool only throu
|
|
|
33
33
|
|
|
34
34
|
## The OAuth model
|
|
35
35
|
|
|
36
|
-
The Cloudflare adapter runs one Better Auth 1.7 instance for staff identity, authorization, consent, client registration and MCP resource verification. Client identity is CIMD-first — the MCP 2026-07-28 Client ID Metadata Document profile, which is why the Worker needs the `global_fetch_strictly_public` flag to fetch client metadata across the public Internet boundary
|
|
36
|
+
The Cloudflare adapter runs one Better Auth 1.7 instance for staff identity, authorization, consent, client registration and MCP resource verification. Client identity is CIMD-first — the MCP 2026-07-28 Client ID Metadata Document profile, which is why the Worker needs the `global_fetch_strictly_public` flag to fetch client metadata across the public Internet boundary. Unauthenticated Dynamic Client Registration remains available as a bounded path with a 90-day default lifetime for clients that do not present CIMD. One non-colon scope, `mcp`, is advertised in `scopes_supported`, because clients such as claude.ai reject colon-shaped scopes; per-surface enforcement then happens server-side, not through scope strings. Authorization is session-bound: the JWT's originating Better Auth session must still exist and be unexpired, so signing out of Admin also ends that session's MCP access, and a refresh token is not an independent authorization. Unauthenticated requests to either mount answer `401` with a `WWW-Authenticate` challenge pointing at the RFC 9728 protected-resource metadata document served under the auth mount. Authorization endpoints live under `/api/auth/oauth2/*` and are discovered from the advertised metadata, never hard-coded.
|
|
37
37
|
|
|
38
38
|
## Connecting a local client
|
|
39
39
|
|
|
@@ -209,7 +209,7 @@ What each piece is doing:
|
|
|
209
209
|
- `submittedAt` is stamped by the runtime, so it is absent from the Procedure input and from Staff MCP authoring tools.
|
|
210
210
|
- Adding `{ kind: mcp, surface: public }` as a fourth Trigger would publish the same Procedure as an agent tool without touching a handler.
|
|
211
211
|
|
|
212
|
-
Register the two `ref` keys in the project's handlers map, then run the check loop from [Project layout and the CLI loop](../start/project-and-cli.md). The complete version with real Turnstile and email handlers is [Intake
|
|
212
|
+
Register the two `ref` keys in the project's handlers map, then run the check loop from [Project layout and the CLI loop](../start/project-and-cli.md). The complete version with real Turnstile and email handlers is [Intake Turnstile and email hooks](../../examples/cf-primitives-intake-hooks.md). The Builder-safe Manifest without those hooks is [Intake form](../../examples/builtin-intake.md).
|
|
213
213
|
|
|
214
214
|
## Source
|
|
215
215
|
|
|
@@ -112,7 +112,7 @@ Bun, with the server and SQLite handle staying yours:
|
|
|
112
112
|
|
|
113
113
|
```ts
|
|
114
114
|
import { Database } from "bun:sqlite";
|
|
115
|
-
import { createBunMantle } from "@aotter/mantle-bun";
|
|
115
|
+
import { createBunMantle } from "@aotter/mantle-bun"; // experimental
|
|
116
116
|
|
|
117
117
|
const database = new Database("app.sqlite");
|
|
118
118
|
const mantle = createBunMantle({ plan, database, handlers });
|
|
@@ -128,7 +128,7 @@ Vercel Functions, with storage injected:
|
|
|
128
128
|
|
|
129
129
|
```ts
|
|
130
130
|
import { SqliteMantleStorageAdapter } from "@aotter/mantle-runtime";
|
|
131
|
-
import { createVercelMantle } from "@aotter/mantle-vercel";
|
|
131
|
+
import { createVercelMantle } from "@aotter/mantle-vercel"; // experimental
|
|
132
132
|
import { LibsqlDatabaseDriver } from "@aotter/mantle-vercel/libsql";
|
|
133
133
|
|
|
134
134
|
const mantle = createVercelMantle({
|
|
@@ -47,7 +47,7 @@ A View can filter to the calling user's own rows with the closed sentinel `{ "$c
|
|
|
47
47
|
2. The View must require a signed-in user: `ctx.user` in `requires.auth.all` — otherwise `VIEW_FILTER_CTX_USER_REF_REQUIRES_AUTH`.
|
|
48
48
|
3. The compared field must be the leftmost field of a declared index on the source Schema — otherwise `VIEW_FILTER_CTX_USER_REF_REQUIRES_INDEX`.
|
|
49
49
|
|
|
50
|
-
This is a filter, not a row-level policy engine. `requires` authorizes the whole query; it does not inject per-row visibility predicates. Membership, payment and entitlement checks belong in a guard Procedure. See [Procurement approvals](
|
|
50
|
+
This is a filter, not a row-level policy engine. `requires` authorizes the whole query; it does not inject per-row visibility predicates. Membership, payment and entitlement checks belong in a guard Procedure. See [Procurement approvals](../../examples/builtin-procurement.md).
|
|
51
51
|
|
|
52
52
|
## Shared response cache
|
|
53
53
|
|
|
@@ -176,7 +176,7 @@ spec:
|
|
|
176
176
|
limit: 200
|
|
177
177
|
```
|
|
178
178
|
|
|
179
|
-
`tags` is an array property, so `json_each` unnests it and one request appears once per tag. The runtime wraps the whole statement as a subquery before applying pagination, which is why Admin's search and filters attach to the SQL output aliases — `tag` is a real filterable column even though no Schema property is named `tag`. See [Commerce
|
|
179
|
+
`tags` is an array property, so `json_each` unnests it and one request appears once per tag. The runtime wraps the whole statement as a subquery before applying pagination, which is why Admin's search and filters attach to the SQL output aliases — `tag` is a real filterable column even though no Schema property is named `tag`. See [Commerce inventory](../../examples/cf-primitives-commerce-inventory.md) for the same technique over order lines.
|
|
180
180
|
|
|
181
181
|
## Source
|
|
182
182
|
|