@aotter/mantle 0.1.0-alpha.9 → 0.1.2-alpha.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 +38 -38
- package/dist/cli/generate.d.ts +10 -1
- package/dist/cli/generate.d.ts.map +1 -1
- package/dist/cli/generate.js +49 -4
- package/dist/cli/generate.js.map +1 -1
- package/dist/cli/main.js +0 -8
- package/dist/cli/main.js.map +1 -1
- package/dist/codegen/emitMantleModule.js +8 -0
- package/dist/codegen/emitMantleModule.js.map +1 -1
- package/docs/adapter-guide.md +23 -26
- package/docs/adr/0008-structured-diagnostic-shape.md +7 -2
- package/docs/adr/0010-locale-and-translates.md +14 -16
- package/docs/adr/0011-adapter-port-spec.md +2 -1
- package/docs/adr/0014-auth-better-auth-and-multi-tenant-mcp.md +100 -0
- package/docs/adr/0018-core-starters-repository-boundary.md +3 -0
- package/docs/adr/0019-sealed-manifest-runtime-pipeline.md +38 -2
- package/docs/adr/0020-builtin-handler-contracts-and-matched-upsert.md +199 -0
- package/docs/adr/0021-retire-starter-scaffolding.md +30 -0
- package/docs/adr/0022-caller-observed-version-occ.md +212 -0
- package/docs/adr/0023-port-failure-contract.md +69 -0
- package/docs/adr/0024-manifest-native-schema-tables.md +260 -0
- package/docs/adr/README.md +19 -3
- package/docs/adr/adr-lite-803-request-diagnostics.md +38 -0
- package/docs/adr/adr-lite-808-route-readiness.md +47 -0
- package/docs/adr/adr-lite-809-bounded-public-content.md +71 -0
- package/docs/adr/adr-lite-812-native-parity.md +150 -0
- package/docs/adr/adr-lite-823-home-statistics.md +64 -0
- package/docs/adr/adr-lite-842-mcp-authoring.md +30 -0
- package/docs/adr/adr-lite-861-admin-webmcp.md +42 -0
- package/docs/adr/adr-lite-909-admin-ui-kit.md +37 -0
- package/docs/api-mcp-authorization.md +3 -664
- package/docs/auth-hosting-model.md +4 -4
- package/docs/cloudflare-low-level-composition.md +3 -104
- package/docs/deferred-lifecycle-queues.md +2 -243
- package/docs/design-atoms.md +16 -796
- package/docs/direct-authoring.md +5 -0
- package/docs/examples/minimal-worker/README.md +37 -0
- package/docs/examples/minimal-worker/manifests/site.yaml +25 -0
- package/docs/examples/minimal-worker/package.json +26 -0
- package/docs/examples/minimal-worker/smoke.mjs +23 -0
- package/docs/examples/minimal-worker/src/index.ts +4 -0
- package/docs/examples/minimal-worker/tsconfig.json +17 -0
- package/docs/examples/minimal-worker/wrangler.jsonc +22 -0
- package/docs/handbook/cloudflare/authentication.md +167 -0
- package/docs/handbook/cloudflare/bindings.md +236 -0
- package/docs/handbook/cloudflare/conventional-worker.md +162 -0
- package/docs/handbook/cloudflare/deferred-hooks-queues.md +171 -0
- package/docs/handbook/cloudflare/deploy-and-operate.md +105 -0
- package/docs/handbook/cloudflare/low-level-composition.md +169 -0
- package/docs/handbook/cloudflare/media-r2.md +216 -0
- package/docs/handbook/cloudflare/public-web.md +144 -0
- package/docs/handbook/concepts/authorization.md +116 -0
- package/docs/handbook/concepts/four-atoms.md +173 -0
- package/docs/handbook/concepts/lifecycle-and-locales.md +142 -0
- package/docs/handbook/concepts/mcp-and-agents.md +109 -0
- package/docs/handbook/concepts/procedures-and-triggers.md +221 -0
- package/docs/handbook/concepts/runtime-and-adapters.md +177 -0
- package/docs/handbook/concepts/views.md +191 -0
- package/docs/handbook/examples/commerce-transaction.md +813 -0
- package/docs/handbook/examples/guarded-api.md +427 -0
- package/docs/handbook/examples/intake-form.md +319 -0
- package/docs/handbook/examples/legal-documents.md +218 -0
- package/docs/handbook/examples/procurement-approvals.md +240 -0
- package/docs/handbook/examples/publication.md +240 -0
- package/docs/handbook/examples/reservation.md +220 -0
- package/docs/handbook/navigation.json +63 -0
- package/docs/handbook/reference/authorization.md +295 -0
- package/docs/handbook/reference/diagnostics.md +183 -0
- package/docs/handbook/reference/manifest.md +132 -0
- package/docs/handbook/reference/procedure.md +263 -0
- package/docs/handbook/reference/schema.md +250 -0
- package/docs/handbook/reference/site-config.md +233 -0
- package/docs/handbook/reference/surface.md +207 -0
- package/docs/handbook/reference/trigger.md +193 -0
- package/docs/handbook/reference/view.md +256 -0
- package/docs/handbook/start/project-and-cli.md +122 -0
- package/docs/handbook/start/quickstart-worker.md +193 -0
- package/docs/labels.md +3 -1
- package/docs/media-uploads.md +3 -184
- package/docs/migration-0.1.2.md +60 -3
- package/docs/performance-harness.md +127 -10
- package/docs/release-process.md +85 -231
- package/docs/schema-indexes.md +3 -180
- package/docs/sealed-pipeline-ownership.md +6 -5
- package/docs/spec-only-host-adoption.md +158 -0
- package/docs/transaction-patterns.md +5 -0
- package/package.json +21 -25
- package/skills/README.md +4 -4
- package/skills/develop/SKILL.md +23 -28
- package/skills/install/SKILL.md +55 -147
- package/skills/provision/SKILL.md +4 -3
- package/skills/theme/SKILL.md +6 -6
- package/skills/update/SKILL.md +32 -68
- package/dist/cli/create.d.ts +0 -2
- package/dist/cli/create.d.ts.map +0 -1
- package/dist/cli/create.js +0 -243
- package/dist/cli/create.js.map +0 -1
- package/dist/cli/update.d.ts +0 -2
- package/dist/cli/update.d.ts.map +0 -1
- package/dist/cli/update.js +0 -413
- package/dist/cli/update.js.map +0 -1
- package/dist/provision/renderProvisionBundle.d.ts +0 -70
- package/dist/provision/renderProvisionBundle.d.ts.map +0 -1
- package/dist/provision/renderProvisionBundle.js +0 -367
- package/dist/provision/renderProvisionBundle.js.map +0 -1
- package/dist/provision.d.ts +0 -2
- package/dist/provision.d.ts.map +0 -1
- package/dist/provision.js +0 -2
- package/dist/provision.js.map +0 -1
package/docs/media-uploads.md
CHANGED
|
@@ -1,186 +1,5 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Media uploads
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
`create_media_upload` and `commit_media_upload`. This is an optional
|
|
5
|
-
post-launch feature for sites that use the Cloudflare adapter and need
|
|
6
|
-
staff-managed images or files.
|
|
3
|
+
This guide moved into the handbook: [`docs/handbook/cloudflare/media-r2.md`](handbook/cloudflare/media-r2.md).
|
|
7
4
|
|
|
8
|
-
|
|
9
|
-
require billing or a credit card, so landing and the blank starter do not
|
|
10
|
-
provision it by default.
|
|
11
|
-
|
|
12
|
-
## When To Enable
|
|
13
|
-
|
|
14
|
-
Enable this after the site already has:
|
|
15
|
-
|
|
16
|
-
- a working Cloudflare Worker deploy;
|
|
17
|
-
- staff auth configured;
|
|
18
|
-
- a real need for staff or an agent to upload images/files.
|
|
19
|
-
|
|
20
|
-
Use Claude Code, Codex, Cursor, or another local/non-sandboxed coding
|
|
21
|
-
agent for media maintenance. Claude Cowork often cannot complete this
|
|
22
|
-
flow because the final upload is a direct HTTP PUT to
|
|
23
|
-
`*.r2.cloudflarestorage.com`.
|
|
24
|
-
|
|
25
|
-
## How It Works
|
|
26
|
-
|
|
27
|
-
The upload flow is deliberately split:
|
|
28
|
-
|
|
29
|
-
1. The agent calls Staff MCP `create_media_upload` with purpose, variant
|
|
30
|
-
metadata, byte sizes, and mime types.
|
|
31
|
-
2. Mantle returns signed upload URLs and required headers.
|
|
32
|
-
3. The agent reads the local/chat attachment bytes and PUTs them directly
|
|
33
|
-
to R2.
|
|
34
|
-
4. The agent calls `commit_media_upload`.
|
|
35
|
-
|
|
36
|
-
Do not pass image bytes or base64 payloads through MCP tool arguments.
|
|
37
|
-
The Worker validates policy; the agent runtime performs file processing
|
|
38
|
-
and upload.
|
|
39
|
-
|
|
40
|
-
## Cloudflare Setup
|
|
41
|
-
|
|
42
|
-
Create a bucket and public read URL:
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
wrangler r2 bucket create <project>-media
|
|
46
|
-
wrangler r2 bucket dev-url enable <project>-media
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
In the Cloudflare dashboard, create an R2 S3 API token:
|
|
50
|
-
|
|
51
|
-
1. Open **R2**.
|
|
52
|
-
2. Open **Manage R2 API Tokens**.
|
|
53
|
-
3. Create an Object Read & Write token.
|
|
54
|
-
4. Copy the Access Key ID and Secret Access Key.
|
|
55
|
-
|
|
56
|
-
The R2 binding alone cannot issue presigned PUT URLs; Mantle also needs
|
|
57
|
-
these S3-compatible credentials.
|
|
58
|
-
|
|
59
|
-
## `wrangler.toml`
|
|
60
|
-
|
|
61
|
-
```toml
|
|
62
|
-
[vars]
|
|
63
|
-
R2_ACCOUNT_ID = "<account-id>"
|
|
64
|
-
MEDIA_PUBLIC_URL_BASE = "https://pub-<hash>.r2.dev"
|
|
65
|
-
|
|
66
|
-
[[r2_buckets]]
|
|
67
|
-
binding = "MEDIA_BUCKET"
|
|
68
|
-
bucket_name = "<project>-media"
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Set secrets:
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
wrangler secret put R2_ACCESS_KEY_ID
|
|
75
|
-
wrangler secret put R2_SECRET_ACCESS_KEY
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
## `src/mantle/config.ts`
|
|
79
|
-
|
|
80
|
-
```ts
|
|
81
|
-
import { R2MediaStorage, type MantleCloudflareConfig } from "@aotter/mantle/cloudflare";
|
|
82
|
-
import { AwsClient } from "aws4fetch";
|
|
83
|
-
|
|
84
|
-
export interface Env {
|
|
85
|
-
readonly MEDIA_BUCKET?: R2Bucket;
|
|
86
|
-
readonly R2_ACCOUNT_ID?: string;
|
|
87
|
-
readonly R2_ACCESS_KEY_ID?: string;
|
|
88
|
-
readonly R2_SECRET_ACCESS_KEY?: string;
|
|
89
|
-
readonly MEDIA_PUBLIC_URL_BASE?: string;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function buildMediaStorage(env: Env): MantleCloudflareConfig["bindings"]["mediaStorage"] {
|
|
93
|
-
if (
|
|
94
|
-
!env.MEDIA_BUCKET ||
|
|
95
|
-
!env.R2_ACCOUNT_ID ||
|
|
96
|
-
!env.R2_ACCESS_KEY_ID ||
|
|
97
|
-
!env.R2_SECRET_ACCESS_KEY ||
|
|
98
|
-
!env.MEDIA_PUBLIC_URL_BASE
|
|
99
|
-
) {
|
|
100
|
-
return undefined;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const s3 = new AwsClient({
|
|
104
|
-
accessKeyId: env.R2_ACCESS_KEY_ID,
|
|
105
|
-
secretAccessKey: env.R2_SECRET_ACCESS_KEY,
|
|
106
|
-
region: "auto",
|
|
107
|
-
service: "s3",
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
return new R2MediaStorage(
|
|
111
|
-
env.MEDIA_BUCKET,
|
|
112
|
-
s3,
|
|
113
|
-
`https://<project>-media.${env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,
|
|
114
|
-
env.MEDIA_PUBLIC_URL_BASE,
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
Then wire it into the CMS config:
|
|
120
|
-
|
|
121
|
-
```ts
|
|
122
|
-
siteDefaults: {
|
|
123
|
-
media: {
|
|
124
|
-
purposes: [
|
|
125
|
-
{
|
|
126
|
-
name: "page-image",
|
|
127
|
-
required: ["image/jpeg,image/png", "image/webp", "image/avif"],
|
|
128
|
-
maxBytes: {
|
|
129
|
-
"image/jpeg": 5_000_000,
|
|
130
|
-
"image/png": 5_000_000,
|
|
131
|
-
"image/webp": 3_000_000,
|
|
132
|
-
"image/avif": 2_000_000,
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
],
|
|
136
|
-
},
|
|
137
|
-
},
|
|
138
|
-
bindings: {
|
|
139
|
-
mediaStorage: buildMediaStorage(env),
|
|
140
|
-
},
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
`required` is slot-based. The example above declares three slots:
|
|
144
|
-
|
|
145
|
-
- slot 0: choose exactly one fallback mime, preserving the source
|
|
146
|
-
semantics (`image/jpeg` for opaque photos, `image/png` when alpha must
|
|
147
|
-
be preserved);
|
|
148
|
-
- slot 1: include a WebP variant;
|
|
149
|
-
- slot 2: include an AVIF variant.
|
|
150
|
-
|
|
151
|
-
This models the ADR-0017 multi-variant `<picture>` shape. If a site wants
|
|
152
|
-
a simpler single-variant upload for a narrow purpose, it may declare one
|
|
153
|
-
slot such as `["image/jpeg,image/png,image/webp,image/gif"]`; in that
|
|
154
|
-
case, the agent chooses exactly one mime from the comma-separated list and
|
|
155
|
-
must not upload one variant per listed mime.
|
|
156
|
-
|
|
157
|
-
## Tool Visibility
|
|
158
|
-
|
|
159
|
-
The Staff MCP media tools are registered only when both are true:
|
|
160
|
-
|
|
161
|
-
- `bindings.mediaStorage` is set;
|
|
162
|
-
- `siteDefaults.media.purposes` contains at least one purpose.
|
|
163
|
-
|
|
164
|
-
If either side is missing, `create_media_upload` and
|
|
165
|
-
`commit_media_upload` will not appear in `tools/list`.
|
|
166
|
-
|
|
167
|
-
## Agent Guidance
|
|
168
|
-
|
|
169
|
-
For image maintenance, prefer Claude Code or another coding agent that can
|
|
170
|
-
read local files, process images, and make outbound PUT requests to R2.
|
|
171
|
-
Avoid Claude Cowork for this workflow; use a non-sandboxed agent instead.
|
|
172
|
-
|
|
173
|
-
Preserve source semantics:
|
|
174
|
-
|
|
175
|
-
- photos may use JPEG/WebP variants;
|
|
176
|
-
- transparent logos must keep alpha;
|
|
177
|
-
- animated GIFs must stay animated;
|
|
178
|
-
- do not silently flatten, resize, or recompress user assets without
|
|
179
|
-
asking.
|
|
180
|
-
|
|
181
|
-
## Cleanup
|
|
182
|
-
|
|
183
|
-
Run the version-matched `media-gc` skill when an upload reached R2 but was
|
|
184
|
-
never committed. It audits first and removes only stale objects without
|
|
185
|
-
`committedAt` metadata after explicit operator confirmation. Do not use an R2
|
|
186
|
-
lifecycle rule: committed and uncommitted media share the same purpose prefix.
|
|
5
|
+
The handbook ships inside the `@aotter/mantle` package under `node_modules/@aotter/mantle/docs/handbook/` and describes the installed release.
|
package/docs/migration-0.1.2.md
CHANGED
|
@@ -1,4 +1,60 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Leaving the legacy alpha.17 launch line
|
|
2
|
+
|
|
3
|
+
0.1.0-alpha.17 remains immutable and is the final version for existing Landing
|
|
4
|
+
and Starters. Those repositories/tags/bundle URLs remain available. Staying on
|
|
5
|
+
that version requires no migration. No stable 0.1.0 release is planned.
|
|
6
|
+
|
|
7
|
+
The new line removes `mantle create`, the Starter bundle `mantle update`
|
|
8
|
+
command, and `@aotter/mantle/provision`. There are no aliases or replacement
|
|
9
|
+
scaffold commands. `generate`, `validate`, `emit-openapi` and `skills` remain.
|
|
10
|
+
Generation and runtime Web rendering retain their existing responsibilities.
|
|
11
|
+
|
|
12
|
+
To upgrade an existing application:
|
|
13
|
+
|
|
14
|
+
1. Read its installed version, lockfile, entry, scripts and provider bindings;
|
|
15
|
+
keep unrelated work safe in the normal git workflow.
|
|
16
|
+
2. Pin the selected SDK packages to the intended exact new release and update
|
|
17
|
+
the lockfile through the package manager. Review required peer upgrades.
|
|
18
|
+
3. Remove scripts invoking the retired scaffolder/bundle updater. If application
|
|
19
|
+
code imports the provision renderer, remain on alpha.17 until that host's
|
|
20
|
+
provisioning design is migrated explicitly; do not replace it with a
|
|
21
|
+
handwritten remote-code loader.
|
|
22
|
+
4. Retain application source and all Worker/D1/KV identity, origins, auth mode,
|
|
23
|
+
secrets and legacy `.mantle` metadata. Those files are not templates to
|
|
24
|
+
replace or evidence that new Starter tags must exist.
|
|
25
|
+
5. Run the installed `mantle generate`, `generate --check`, `skills`,
|
|
26
|
+
`skills --check`, `validate`, and the project's TypeScript/tests. Test local
|
|
27
|
+
routes and configured authorization before considering deployment.
|
|
28
|
+
|
|
29
|
+
## Native Schema-table storage reset
|
|
30
|
+
|
|
31
|
+
The 0.1.2 pre-beta line replaces the generic `entries` JSON table with one
|
|
32
|
+
native SQLite/D1 table per Manifest Schema. Mantle's row envelope uses
|
|
33
|
+
`_mantle_id`, `_mantle_status`, `_mantle_version`, `_mantle_author_id`,
|
|
34
|
+
`_mantle_created_at`, and `_mantle_updated_at`; authored fields keep their exact
|
|
35
|
+
names as native columns. The old generated columns, projection views and
|
|
36
|
+
compatibility repository were removed.
|
|
37
|
+
|
|
38
|
+
This is intentionally a storage-format break before beta. Reset and
|
|
39
|
+
re-bootstrap development or internal-alpha content databases that contain the
|
|
40
|
+
old `entries` layout. Move required data manually outside Mantle and Control;
|
|
41
|
+
there is no product migration workflow for this unreleased format. Automatic
|
|
42
|
+
artifacts cover initial and additive changes only. Removed columns and tables
|
|
43
|
+
remain physically present so the previous Worker can still run. Renames, type
|
|
44
|
+
changes and data transforms require the same manual rebuild. The pre-beta Cloud
|
|
45
|
+
path does not accept or execute destructive SQL.
|
|
46
|
+
|
|
47
|
+
Row APIs are now Schema-qualified. `EntryRepository.get` and
|
|
48
|
+
`EntryReader.readById` accept `{ collection, id }`; Admin entry detail and
|
|
49
|
+
mutation routes require `?collection=<schema>`, and generic MCP entry tools
|
|
50
|
+
require `collection`. Generated `entries.<schema>` bindings supply it for you.
|
|
51
|
+
|
|
52
|
+
A new project follows [direct authoring](direct-authoring.md). Templates and
|
|
53
|
+
provider setup are not hidden inside `generate`. Future Builder/landing-next
|
|
54
|
+
provisioning is a separate decision; this change does not migrate those hosts.
|
|
55
|
+
|
|
56
|
+
## Earlier alpha.7 compatibility changes
|
|
57
|
+
|
|
2
58
|
|
|
3
59
|
0.1.2 removes the temporary full-site compatibility stack. Mantle Core is now
|
|
4
60
|
an embeddable parse → link → compile → prepare → bind pipeline; Web, Admin,
|
|
@@ -41,5 +97,6 @@ Intentional behavior changes:
|
|
|
41
97
|
|
|
42
98
|
This alpha changes the Better Auth D1 schema, including required account
|
|
43
99
|
issuer identity and OAuth resource/client tables. Reset and re-bootstrap a
|
|
44
|
-
pre-1.7 alpha auth database; do not guess an issuer backfill.
|
|
45
|
-
|
|
100
|
+
pre-1.7 alpha auth database; do not guess an issuer backfill. Reset old generic
|
|
101
|
+
content storage as described above and move required data manually outside
|
|
102
|
+
Mantle.
|
|
@@ -31,7 +31,7 @@ must not query Mantle-owned tables outside the selected storage adapter.
|
|
|
31
31
|
the Worker. Cache keys are version-local, so a deploy starts with no stale
|
|
32
32
|
response from the previous Worker version.
|
|
33
33
|
- Successful publishing-content and site-setting writes purge the shared
|
|
34
|
-
|
|
34
|
+
deployment-scoped public Cache-Tag through Cloudflare's native cache API. Operational
|
|
35
35
|
records and immutable assets stay outside that invalidation boundary.
|
|
36
36
|
- Do not cache every repository read. Cross-isolate correctness for editable
|
|
37
37
|
data wins unless a read has a measured hot-path contract and explicit
|
|
@@ -50,7 +50,7 @@ pnpm exec mantle-harness indexes --require account-members --format json
|
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
Without `--require-public` or `--require`, findings are advisory. A required
|
|
53
|
-
path fails on
|
|
53
|
+
path fails on a required Schema-table scan, a temporary ORDER BY B-tree, or a
|
|
54
54
|
data-field predicate/order that does not use a declared Schema index.
|
|
55
55
|
Projection alone does not require an index. `mantle validate` remains a pure
|
|
56
56
|
correctness check; no performance grammar or manifest atom was added.
|
|
@@ -75,12 +75,14 @@ Timing always reports p50/p95/max. A test-only Worker wrapper may also return
|
|
|
75
75
|
`x-mantle-query-count` and `x-mantle-rows-read`; those become distributions in
|
|
76
76
|
the same report. Do not expose these diagnostic headers in production.
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
routing, View execution, and origin
|
|
80
|
-
row fixtures and gates row-read
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
78
|
+
The path-scoped Cloudflare benchmark workflow runs `pnpm bench:wrangler`
|
|
79
|
+
against real Wrangler-local D1, Worker HTTP routing, View execution, and origin
|
|
80
|
+
page rendering. It compares 100 and 10,000 row fixtures and gates row-read
|
|
81
|
+
scaling plus endpoint query budgets, not absolute milliseconds. It is separate
|
|
82
|
+
from the required repository checks so an unrelated dependency or docs PR does
|
|
83
|
+
not fail on the platform harness. Wrangler-local does not emulate the new
|
|
84
|
+
entrypoint Workers Cache, so cache hits are a deployment-level smoke check
|
|
85
|
+
rather than a fabricated local metric.
|
|
84
86
|
|
|
85
87
|
## Seven findings: measured disposition
|
|
86
88
|
|
|
@@ -90,8 +92,8 @@ diagnostic, while query/row counts are the stable assertions.
|
|
|
90
92
|
| Finding | Disposition |
|
|
91
93
|
|---|---|
|
|
92
94
|
| Public cache hits read D1 first | Removed from Worker code. Cloudflare's entrypoint Workers Cache runs before the Worker; Core has no inner render cache. |
|
|
93
|
-
| Slug/locale reads bypass
|
|
94
|
-
| OFFSET pagination |
|
|
95
|
+
| Slug/locale reads bypass Schema indexes | Fixed by the shared schema-aware entry-read boundary over native columns. A 10,000-row page MISS measured 2 queries / 5 rows read. |
|
|
96
|
+
| OFFSET pagination | Retained only where the View/Admin contract explicitly uses it, with a 500-row response cap. Public content lists and discovery now use forward keyset pages; they are not covered by the old 500-row claim. |
|
|
95
97
|
| Admin substring search scans | Accepted only for the authenticated Admin collection browser, with a 500-row response cap. Large/search-heavy sites should add a purpose-shaped indexed View or dedicated search service; do not expose this scan publicly. |
|
|
96
98
|
| Published list/sitemap/llms paths lack system indexes | Fixed with measured partial indexes for published global, locale, collection, and collection+locale ordering. The 100-row and 10,000-row API runs both measured 1 query / 20 rows read. |
|
|
97
99
|
| Page MISS waits for cache write-back | Removed. Origin rendering returns directly; Workers Cache owns response storage outside the Worker. |
|
|
@@ -102,3 +104,118 @@ not patterns for new public APIs. Re-measure before widening either scope.
|
|
|
102
104
|
|
|
103
105
|
See also [Schema indexes](./schema-indexes.md) and the official Cloudflare
|
|
104
106
|
[D1 index guidance](https://developers.cloudflare.com/d1/best-practices/use-indexes/).
|
|
107
|
+
|
|
108
|
+
### Prepared database, new Worker state
|
|
109
|
+
|
|
110
|
+
The Wrangler fixture resets its in-isolate runtime after seeding while retaining
|
|
111
|
+
D1. The first public page has a four-statement budget (fingerprint, lazy locale,
|
|
112
|
+
site settings, entry); subsequent origin pages have a two-statement budget.
|
|
113
|
+
This is a new application state in the same workerd isolate, not a measurement
|
|
114
|
+
of module startup CPU or an entrypoint cache HIT. Locale caching is enabled by
|
|
115
|
+
a successful preparation fingerprint; editable settings and media policy still
|
|
116
|
+
read the canonical database on every call.
|
|
117
|
+
|
|
118
|
+
### HTTP Trigger routing
|
|
119
|
+
|
|
120
|
+
The portable request handler indexes Trigger paths by method and segments once.
|
|
121
|
+
Literal and wildcard branches retain sealed-plan order, including encoded literal
|
|
122
|
+
collisions that an outer router may select differently. Each request decodes its
|
|
123
|
+
segments once and invokes the original Trigger identity through the same runtime.
|
|
124
|
+
The 1/10/100/1,000-route regression uses four segment lookups at every size;
|
|
125
|
+
overlapping wildcard shapes can visit multiple branches, pruned by route rank.
|
|
126
|
+
The HTTP microbench and workerd harness include the same route-count axis.
|
|
127
|
+
Workerd wall times include I/O and are not CPU measurements or a fixed-ms CI gate.
|
|
128
|
+
|
|
129
|
+
### Public content pages and discovery (#809)
|
|
130
|
+
|
|
131
|
+
| Surface | Canonical read / continuation |
|
|
132
|
+
|---|---|
|
|
133
|
+
| Collection HTML and collection Markdown | 50 entries by default, forward `cursor`; visible Next link plus HTTP `Link: rel="next"`. |
|
|
134
|
+
| Locale and root llms.txt | One canonical page, default 50 entries; root expands that page across configured locales in memory. Shared entries are not reread once per locale. Follow the body/HTTP continuation link. |
|
|
135
|
+
| Sitemap part | Up to 2,000 entries, with only declared path fields (built-in resolver: `slug`). A small site returns a urlset directly; a larger site returns a sitemap index linking every part. |
|
|
136
|
+
| Sitemap index | Walks metadata pages to derive exact part cursors; O(N) metadata work on an index MISS, with one page resident at a time. It is not a constant-work list endpoint. |
|
|
137
|
+
|
|
138
|
+
`EntryReader.readPublishedPage` caps returned data JSON at 1 MiB and 2,000 rows.
|
|
139
|
+
One oversized entry is returned alone to make progress. SQLite applies the byte
|
|
140
|
+
budget before transferring/parsing JSON in the Worker; one extra candidate
|
|
141
|
+
identifies continuation. A localized + shared page merges two indexed ranges
|
|
142
|
+
inside the same statement. The original `readPublished` remains an explicit
|
|
143
|
+
unbounded read unless its caller supplies a limit.
|
|
144
|
+
|
|
145
|
+
Translation lists resolve at most one newest published parent per join value,
|
|
146
|
+
then resolve media once for the bounded list. Parent payloads and media metadata
|
|
147
|
+
are additional input; the 1 MiB budget describes the canonical child page, not
|
|
148
|
+
arbitrary template output or total Worker heap. Custom renderers own their output
|
|
149
|
+
size. IndexedDB keeps identical page semantics but currently scans its local
|
|
150
|
+
collection; this is not a claim of bounded IndexedDB storage I/O.
|
|
151
|
+
|
|
152
|
+
The real SQLite fixture matrix covers 100/10,000/50,000 published rows, 64 B/4 KiB
|
|
153
|
+
bodies, and 1/3/10 locales. At limit 20, every case transfers 21 candidate rows;
|
|
154
|
+
4 KiB body data occupies 87,003–87,129 bytes, independent of collection size.
|
|
155
|
+
Complete llms traversal uses 2/200/1,000 statements at the default 50-row page
|
|
156
|
+
size, independent of locale count. Sitemap and llms URL sets match, including
|
|
157
|
+
275,000 URLs for 50,000 mixed localized/shared rows across 10 locales.
|
|
158
|
+
|
|
159
|
+
Run `pnpm --filter @aotter/mantle-cloudflare exec vitest run
|
|
160
|
+
test/public-content-scaling.test.ts` to emit JSON transfer sizes and traversal
|
|
161
|
+
CPU/wall/RSS diagnostics. These are Node + SQLite + assertions, including the
|
|
162
|
+
fixture database and URL-validation set; RSS is a process high-water mark, not
|
|
163
|
+
per-request Worker peak memory. Worker CPU, true cache HIT/MISS and placement
|
|
164
|
+
measurements belong to the matched native/full-stack harness (#812).
|
|
165
|
+
|
|
166
|
+
The workerd smoke also measures public list, llms and sitemap. The first two
|
|
167
|
+
use two warm statements (settings + page) and bounded D1 work. Sitemap index
|
|
168
|
+
queries and rows-read scale with the number of metadata parts; this explicit
|
|
169
|
+
cost preserves complete discovery instead of silently dropping URLs.
|
|
170
|
+
|
|
171
|
+
### Request diagnostics (version 1, test/performance only)
|
|
172
|
+
|
|
173
|
+
Import `runWithRequestDiagnostics`, `instrumentD1`, `instrumentKv` and
|
|
174
|
+
`instrumentR2` from `@aotter/mantle-cloudflare/testing`. Wrap native bindings once
|
|
175
|
+
before handing the same D1 object to Auth and Runtime. Open the request context
|
|
176
|
+
outside the complete facade fetch, and pass binding-presence flags matching the
|
|
177
|
+
instrumented fixture. The observer receives one response-time record; it never
|
|
178
|
+
receives request headers, tokens, proofs, user IDs, SQL, parameters, tool arguments,
|
|
179
|
+
object keys or response content. Sync/async observer failure cannot change the
|
|
180
|
+
original response or exception. The library emits no diagnostic headers or logs.
|
|
181
|
+
|
|
182
|
+
Records distinguish HTTP outcome from JSON-RPC result/error/tool-error. They
|
|
183
|
+
include actual in-isolate arrivals, inclusive OAuth/DPoP, role, runtime, catalog,
|
|
184
|
+
dispatcher construction and dispatch wall spans. Unreached phases are null.
|
|
185
|
+
Shared KV loads charge native I/O once to the initiating request; waiters record
|
|
186
|
+
wait duration and the same hit/miss/repair/error source. Boot publication has a
|
|
187
|
+
separate counter. The original rejected shared load remains retryable.
|
|
188
|
+
|
|
189
|
+
D1 statements and binding calls are separate: a batch is one call and N attempted
|
|
190
|
+
statements. Failed attempts count. `exec` uses the provider's count; unavailable
|
|
191
|
+
counts stay in `unknownStatementCalls`, never a semicolon parser. `first(column)`
|
|
192
|
+
and `raw` preserve native behavior and do not silently execute `all` to manufacture
|
|
193
|
+
metadata. Their absent metadata is null. Rows/duration are sums of available
|
|
194
|
+
metadata, and `metadataStatements` identifies coverage; incomplete coverage is
|
|
195
|
+
not a full-workload total. Serialized binding results are measured bytes, not a
|
|
196
|
+
claim about bytes on the provider's wire. Existing D1DatabaseDriver observers can
|
|
197
|
+
request metadata for first-row reads when a fixture explicitly chooses that mode.
|
|
198
|
+
|
|
199
|
+
KV bytes identify UTF-8, buffer or reserialized JSON sources. R2 payload bytes
|
|
200
|
+
remain unknown for an unconsumed/partly consumed GET. A successful PUT of that exact
|
|
201
|
+
native GET stream confirms the transferred body size on both operations. Streams
|
|
202
|
+
are never wrapped or buffered for diagnostics, preserving R2's native known-length
|
|
203
|
+
contract. `byteSamples` distinguishes known payload samples from the operation
|
|
204
|
+
count. Metadata/list response serialization is labeled separately from object
|
|
205
|
+
payload. R2 coverage is head/get/put/delete/list, not multipart-upload instrumentation.
|
|
206
|
+
|
|
207
|
+
Snapshots freeze at response creation; outstanding/deferred operations remain
|
|
208
|
+
visible through `inFlight` and metadata coverage and cannot rewrite a published
|
|
209
|
+
record. `totalMs` excludes the subsequent test-only JSON-RPC response inspection,
|
|
210
|
+
delivery and deferred work. CPU, TTFB, full-body duration and heap must be measured
|
|
211
|
+
separately. Worker wall clocks advance on I/O and are not a CPU timer; use the
|
|
212
|
+
[official CPU profiler](https://developers.cloudflare.com/workers/observability/dev-tools/cpu-usage/).
|
|
213
|
+
Measure diagnostics off/on overhead with the same workload before interpreting
|
|
214
|
+
small latency differences.
|
|
215
|
+
|
|
216
|
+
### Matched native facade controls (#812)
|
|
217
|
+
|
|
218
|
+
`pnpm bench:wrangler` now also runs the native parity smoke. The full
|
|
219
|
+
`pnpm bench:parity` matrix adds real Auth/MCP, cold workerd processes, R2,
|
|
220
|
+
TTFB/full-body timing and CPU/heap evidence. See
|
|
221
|
+
[the controls, gates and reproducible commands](./adr/adr-lite-812-native-parity.md).
|