@aotter/mantle 0.0.11-alpha.62 → 0.0.11-alpha.64
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 +96 -11
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +52 -0
- package/dist/cli.js.map +1 -0
- package/dist/generate.d.ts +2 -0
- package/dist/generate.d.ts.map +1 -0
- package/dist/generate.js +181 -0
- package/dist/generate.js.map +1 -0
- package/dist/harness-cli.d.ts +3 -0
- package/dist/harness-cli.d.ts.map +1 -0
- package/dist/harness-cli.js +209 -0
- package/dist/harness-cli.js.map +1 -0
- package/dist/runtime-testing.d.ts +2 -0
- package/dist/runtime-testing.d.ts.map +1 -0
- package/dist/runtime-testing.js +2 -0
- package/dist/runtime-testing.js.map +1 -0
- package/dist/skills.d.ts +2 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skills.js +80 -0
- package/dist/skills.js.map +1 -0
- package/dist/update.d.ts +2 -0
- package/dist/update.d.ts.map +1 -0
- package/dist/update.js +387 -0
- package/dist/update.js.map +1 -0
- package/docs/adapter-guide.md +8 -0
- package/docs/adr/0001-four-atom-manifest-model.md +6 -7
- package/docs/adr/0007-ai-as-primary-author.md +100 -138
- package/docs/adr/0008-structured-diagnostic-shape.md +79 -99
- package/docs/adr/0009-consumer-supplied-manifests.md +101 -228
- package/docs/adr/0012-views-as-public-rest.md +43 -15
- package/docs/adr/0014-auth-better-auth-and-multi-tenant-mcp.md +43 -17
- package/docs/adr/0018-core-starters-repository-boundary.md +155 -0
- package/docs/adr/README.md +8 -6
- package/docs/cloudflare-low-level-composition.md +94 -0
- package/docs/design-atoms.md +59 -57
- package/docs/design-references/editorial-blog-2026-05-05.md +7 -7
- package/docs/labels.md +1 -1
- package/docs/media-uploads.md +1 -1
- package/docs/performance-harness.md +104 -0
- package/docs/release-process.md +156 -523
- package/docs/schema-indexes.md +14 -1
- package/package.json +16 -6
- package/skills/README.md +20 -16
- package/skills/develop/SKILL.md +42 -4
- package/skills/install/SKILL.md +16 -2
- package/skills/plugin/SKILL.md +1 -1
- package/skills/provision/SKILL.md +1 -1
- package/skills/theme/SKILL.md +12 -10
- package/skills/update/SKILL.md +31 -19
- package/skills/customize-design/SKILL.md +0 -215
- package/skills/extend/SKILL.md +0 -257
package/README.md
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Umbrella entry for the Mantle SDK — a manifest-driven CMS for Cloudflare Workers, built around a 4-atom YAML model (Schema / View / Procedure / Trigger) where agents write config and the runtime carries the complexity.
|
|
4
4
|
|
|
5
|
-
>
|
|
5
|
+
> Mantle is prerelease software. Use this package's `package.json` as the exact
|
|
6
|
+
> installed version; APIs may change between prereleases until v0.1.0.
|
|
6
7
|
|
|
7
8
|
## Install
|
|
8
9
|
|
|
@@ -20,6 +21,7 @@ Adopters install this one package and import from subpaths. Sub-packages remain
|
|
|
20
21
|
|---|---|
|
|
21
22
|
| `@aotter/mantle/spec` (or root) | Manifest grammar, validators, JSON-Schema→Zod, diagnostic catalog (no env / no IO) |
|
|
22
23
|
| `@aotter/mantle/runtime` | Hexagonal runtime: domain ports, use cases, infrastructure helpers (no adapter deps) |
|
|
24
|
+
| `@aotter/mantle/runtime/testing` | Node-only crowded SQLite planner and HTTP sampling helpers |
|
|
23
25
|
| `@aotter/mantle/cloudflare` | Cloudflare Workers adapter — D1, KV, R2, Better Auth, MCP via `@cloudflare/workers-oauth-provider` |
|
|
24
26
|
| `@aotter/mantle/admin-ui` | Pre-built React 19 admin SPA bundle |
|
|
25
27
|
|
|
@@ -29,6 +31,84 @@ import { createCmsRuntime } from "@aotter/mantle/runtime";
|
|
|
29
31
|
import { mountServerEndpoints } from "@aotter/mantle/cloudflare";
|
|
30
32
|
```
|
|
31
33
|
|
|
34
|
+
The package also installs `mantle` and `mantle-harness`:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pnpm exec mantle generate
|
|
38
|
+
pnpm exec mantle generate --check
|
|
39
|
+
pnpm exec mantle skills
|
|
40
|
+
pnpm exec mantle skills --check
|
|
41
|
+
pnpm exec mantle update --ref <immutable-starter-ref>
|
|
42
|
+
pnpm exec mantle-harness indexes --require-public
|
|
43
|
+
pnpm exec mantle-harness http --base-url http://127.0.0.1:8787 --route page=/en/example
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`mantle generate` validates the YAML under `./manifests`, then writes the
|
|
47
|
+
parsed manifest module and handler declarations to `.mantle/generated/`.
|
|
48
|
+
It does not sync skills, update packages, style, provision, or deploy.
|
|
49
|
+
When manifests declare Views, the generated `site.ts` also exports
|
|
50
|
+
`bindMantleSite(runtime)`: its `views` keys, params and returned rows come from
|
|
51
|
+
those manifests, while diagnostics still come directly from `executeView`.
|
|
52
|
+
Dynamic `runtime.viewsByName` access remains available for low-level code.
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
const site = bindMantleSite(runtime);
|
|
56
|
+
const notes = await site.views["published-notes"]();
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`mantle skills` explicitly copies the installed package's `develop`, `plugin`,
|
|
60
|
+
`theme`, and `update` skills to matching `.agent/skills/mantle-*` and
|
|
61
|
+
`.claude/skills/mantle-*` paths. Both tool layouts receive identical bytes;
|
|
62
|
+
`--check` detects drift without writing. Manifest generation never rewrites
|
|
63
|
+
agent instructions.
|
|
64
|
+
|
|
65
|
+
`mantle update` compares the recorded source bundle, a target bundle, and the
|
|
66
|
+
local project, then writes `.mantle/update-report.json`. It never applies the
|
|
67
|
+
diff. Configure `.mantle/features.json` `registry.bundleBaseUrl` with a URL
|
|
68
|
+
containing `{ref}`, or pass `--bundle-base-url` for the alpha.63 bridge. The
|
|
69
|
+
report carries the only supported metadata migration; review and apply it
|
|
70
|
+
after porting selected upstream changes.
|
|
71
|
+
|
|
72
|
+
## Conventional Cloudflare Worker
|
|
73
|
+
|
|
74
|
+
The normal Worker entry delegates Core-owned assembly to the SDK:
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import { createMantleWorker } from "@aotter/mantle/cloudflare";
|
|
78
|
+
import { manifest } from "../.mantle/generated/site.js";
|
|
79
|
+
|
|
80
|
+
export default createMantleWorker({ manifest });
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`createMantleWorker` owns conventional D1/KV/assets bindings, Auth, Admin,
|
|
84
|
+
manifest REST/HTTP routes, OAuth, MCP, cache safety, and rejection-safe
|
|
85
|
+
per-isolate boot. Use its single `extend` seam for application handlers and
|
|
86
|
+
new Hono routes; use the public low-level exports when the deployment does not
|
|
87
|
+
fit the conventional binding or lifecycle contract.
|
|
88
|
+
|
|
89
|
+
Extensions may add routes but may not replace Core surfaces. These paths are
|
|
90
|
+
reserved:
|
|
91
|
+
|
|
92
|
+
- `/admin` and `/admin/*`
|
|
93
|
+
- `/api/auth` and `/api/auth/*`
|
|
94
|
+
- `/api/views` and `/api/views/*`
|
|
95
|
+
- `/oauth` and `/oauth/*`
|
|
96
|
+
- `/mcp` and `/mcp/*`
|
|
97
|
+
- `/.well-known/oauth*`
|
|
98
|
+
- `/favicon.svg`
|
|
99
|
+
- global `*` and `/*` handlers
|
|
100
|
+
|
|
101
|
+
A custom Auth factory's `basePath` and exact manifest-owned method/path pairs
|
|
102
|
+
are also reserved at assembly. Static literal conflicts fail TypeScript during
|
|
103
|
+
the consumer build. Computed paths cannot be proven statically, so the facade
|
|
104
|
+
checks Hono's assembled route table and fails closed before serving requests.
|
|
105
|
+
There is no standard-route override option.
|
|
106
|
+
|
|
107
|
+
For an uncommon deployment that must own the top-level assembly, use the
|
|
108
|
+
embedded [`docs/cloudflare-low-level-composition.md`](docs/cloudflare-low-level-composition.md)
|
|
109
|
+
fixture. It composes the same public primitives without importing package
|
|
110
|
+
internals or rebuilding Mantle's adapters.
|
|
111
|
+
|
|
32
112
|
## Getting started
|
|
33
113
|
|
|
34
114
|
Give the [Mantle repo](https://github.com/aotter/mantle) to a coding agent or
|
|
@@ -39,20 +119,23 @@ materializes a local project, and verifies it before any provider work.
|
|
|
39
119
|
|
|
40
120
|
[Mantle landing](https://mantle.tools) uses the same bundles and continues
|
|
41
121
|
through private GitHub repo creation, Cloudflare deployment, and optional paid
|
|
42
|
-
hosted auth. Generated repos
|
|
43
|
-
package for repo-local use.
|
|
122
|
+
hosted auth. Generated repos project Core-owned `mantle:*` skills from their
|
|
123
|
+
installed package for repo-local use.
|
|
44
124
|
|
|
45
125
|
## Agent marketplace install
|
|
46
126
|
|
|
47
127
|
Install the Mantle Core skill bundle before working on generated repos:
|
|
48
128
|
|
|
129
|
+
Replace `<installed-version>` with the exact version from this package's
|
|
130
|
+
`package.json`. Do not point a versioned consumer at a mutable branch.
|
|
131
|
+
|
|
49
132
|
```bash
|
|
50
133
|
# Claude Code
|
|
51
|
-
/plugin marketplace add aotter/mantle
|
|
134
|
+
/plugin marketplace add aotter/mantle@v<installed-version>
|
|
52
135
|
/plugin install mantle@mantle
|
|
53
136
|
|
|
54
137
|
# Codex
|
|
55
|
-
codex plugin marketplace add aotter/mantle --ref
|
|
138
|
+
codex plugin marketplace add aotter/mantle --ref v<installed-version>
|
|
56
139
|
codex plugin add mantle@mantle
|
|
57
140
|
```
|
|
58
141
|
|
|
@@ -97,6 +180,8 @@ The `mantle-runtime` package never imports Cloudflare-specific types — adapter
|
|
|
97
180
|
Queue wiring, retry/DLQ, idempotency, and delivery guarantees)
|
|
98
181
|
- `node_modules/@aotter/mantle/docs/schema-indexes.md` (ordered composite
|
|
99
182
|
JSON-field indexes, D1 query plans, and the safe Procedure SQL helper)
|
|
183
|
+
- `node_modules/@aotter/mantle/docs/performance-harness.md` (crowded SQLite,
|
|
184
|
+
Wrangler-local D1, cache HIT/MISS, and coding-agent guardrails)
|
|
100
185
|
- `node_modules/@aotter/mantle/docs/adr/`
|
|
101
186
|
- `node_modules/@aotter/mantle/skills/develop/SKILL.md`
|
|
102
187
|
- `node_modules/@aotter/mantle/skills/plugin/SKILL.md`
|
|
@@ -104,12 +189,12 @@ The `mantle-runtime` package never imports Cloudflare-specific types — adapter
|
|
|
104
189
|
- `node_modules/@aotter/mantle/skills/update/SKILL.md`
|
|
105
190
|
- `node_modules/@aotter/mantle/skills/install/SKILL.md`
|
|
106
191
|
- `node_modules/@aotter/mantle/skills/provision/SKILL.md`
|
|
107
|
-
- [
|
|
108
|
-
- [
|
|
109
|
-
- [
|
|
110
|
-
- [
|
|
111
|
-
- [
|
|
112
|
-
- [
|
|
192
|
+
- [4-atom manifest model (ADR-0001)](docs/adr/0001-four-atom-manifest-model.md)
|
|
193
|
+
- [API and MCP authorization](docs/api-mcp-authorization.md)
|
|
194
|
+
- [Deferred lifecycle Queues](docs/deferred-lifecycle-queues.md)
|
|
195
|
+
- [Schema indexes on D1](docs/schema-indexes.md)
|
|
196
|
+
- [Release process](docs/release-process.md)
|
|
197
|
+
- [Source repository](https://github.com/aotter/mantle)
|
|
113
198
|
- [Issues](https://github.com/aotter/mantle/issues)
|
|
114
199
|
|
|
115
200
|
## License
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { argv, stderr, stdout } from "node:process";
|
|
3
|
+
import { runEmitOpenapi, runEmitTypes, runIntrospect, runValidate, } from "@aotter/mantle-spec/cli";
|
|
4
|
+
import { runGenerate } from "./generate.js";
|
|
5
|
+
import { runSkills } from "./skills.js";
|
|
6
|
+
import { runUpdate } from "./update.js";
|
|
7
|
+
async function main() {
|
|
8
|
+
const command = argv[2];
|
|
9
|
+
if (!command || command === "--help" || command === "-h") {
|
|
10
|
+
stdout.write(`mantle - SDK authoring CLI
|
|
11
|
+
|
|
12
|
+
Usage: mantle <subcommand> [options]
|
|
13
|
+
|
|
14
|
+
Subcommands:
|
|
15
|
+
generate Compile manifests and handler types
|
|
16
|
+
skills Project version-matched Core skills
|
|
17
|
+
update Compare local work with provision bundles
|
|
18
|
+
validate Static manifest + handler-source validation
|
|
19
|
+
introspect Dump parsed manifest tree as JSON
|
|
20
|
+
emit-openapi Emit OpenAPI 3.1 from Triggers + Views
|
|
21
|
+
emit-types Emit TypeScript declarations from manifests
|
|
22
|
+
`);
|
|
23
|
+
return command ? 0 : 2;
|
|
24
|
+
}
|
|
25
|
+
const rest = argv.slice(3);
|
|
26
|
+
switch (command) {
|
|
27
|
+
case "generate":
|
|
28
|
+
return runGenerate(rest);
|
|
29
|
+
case "skills":
|
|
30
|
+
return runSkills(rest);
|
|
31
|
+
case "update":
|
|
32
|
+
return runUpdate(rest);
|
|
33
|
+
case "validate":
|
|
34
|
+
return runValidate(rest);
|
|
35
|
+
case "introspect":
|
|
36
|
+
return runIntrospect(rest);
|
|
37
|
+
case "emit-openapi":
|
|
38
|
+
return runEmitOpenapi(rest);
|
|
39
|
+
case "emit-types":
|
|
40
|
+
return runEmitTypes(rest);
|
|
41
|
+
default:
|
|
42
|
+
stderr.write(`Unknown subcommand: ${command}\n`);
|
|
43
|
+
return 2;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
main().then((code) => {
|
|
47
|
+
process.exitCode = code;
|
|
48
|
+
}, (error) => {
|
|
49
|
+
stderr.write(`internal error: ${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
|
|
50
|
+
process.exitCode = 2;
|
|
51
|
+
});
|
|
52
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EACL,cAAc,EACd,YAAY,EACZ,aAAa,EACb,WAAW,GACZ,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACxB,IAAI,CAAC,OAAO,IAAI,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACzD,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;CAYhB,CAAC,CAAC;QACC,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzB,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3B,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,UAAU;YACb,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;QAC3B,KAAK,QAAQ;YACX,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;QACzB,KAAK,QAAQ;YACX,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC;QACzB,KAAK,UAAU;YACb,OAAO,WAAW,CAAC,IAAI,CAAC,CAAC;QAC3B,KAAK,YAAY;YACf,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;QAC7B,KAAK,cAAc;YACjB,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC;QAC9B,KAAK,YAAY;YACf,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;QAC5B;YACE,MAAM,CAAC,KAAK,CAAC,uBAAuB,OAAO,IAAI,CAAC,CAAC;YACjD,OAAO,CAAC,CAAC;IACb,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,IAAI,CACT,CAAC,IAAI,EAAE,EAAE;IACP,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;AAC1B,CAAC,EACD,CAAC,KAAK,EAAE,EAAE;IACR,MAAM,CAAC,KAAK,CAAC,mBAAmB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3G,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"AAoBA,wBAAsB,WAAW,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA0C7E"}
|
package/dist/generate.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { cwd, stderr, stdout } from "node:process";
|
|
4
|
+
import { parseArgs } from "node:util";
|
|
5
|
+
import { EmitTypesUseCase, ValidateManifestsUseCase, } from "@aotter/mantle-spec";
|
|
6
|
+
import { loadManifestsFromRoot } from "@aotter/mantle-spec/cli";
|
|
7
|
+
export async function runGenerate(rawArgs) {
|
|
8
|
+
let options;
|
|
9
|
+
try {
|
|
10
|
+
const parsed = parseGenerateArgs(rawArgs);
|
|
11
|
+
if (parsed === null) {
|
|
12
|
+
printHelp();
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
options = parsed;
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
stderr.write(`${message(error)}\n`);
|
|
19
|
+
return 2;
|
|
20
|
+
}
|
|
21
|
+
const loaded = await loadManifestsFromRoot(options.manifests);
|
|
22
|
+
const validation = ValidateManifestsUseCase.run({
|
|
23
|
+
manifests: loaded.manifests,
|
|
24
|
+
filePaths: loaded.filePaths,
|
|
25
|
+
});
|
|
26
|
+
const errors = [...loaded.parseErrors, ...validation.diagnostics]
|
|
27
|
+
.filter((diagnostic) => diagnostic.severity === "error");
|
|
28
|
+
if (errors.length > 0) {
|
|
29
|
+
for (const error of errors) {
|
|
30
|
+
stderr.write(`${error.code} ${error.path}: ${error.message}\n`);
|
|
31
|
+
}
|
|
32
|
+
return 1;
|
|
33
|
+
}
|
|
34
|
+
const output = resolve(cwd(), options.output);
|
|
35
|
+
const files = new Map([
|
|
36
|
+
[join(output, "site.ts"), emitManifestModule(loaded.manifests, options.namespace)],
|
|
37
|
+
[join(output, "types.d.ts"), emitTypes(loaded.manifests, options.namespace)],
|
|
38
|
+
]);
|
|
39
|
+
let stale = false;
|
|
40
|
+
for (const [path, source] of files) {
|
|
41
|
+
stale = !(await syncText(path, source, options.check)) || stale;
|
|
42
|
+
}
|
|
43
|
+
if (stale && options.check) {
|
|
44
|
+
stderr.write("Mantle generated files are stale; run `mantle generate`.\n");
|
|
45
|
+
return 1;
|
|
46
|
+
}
|
|
47
|
+
return 0;
|
|
48
|
+
}
|
|
49
|
+
function parseGenerateArgs(rawArgs) {
|
|
50
|
+
const { values } = parseArgs({
|
|
51
|
+
args: [...rawArgs],
|
|
52
|
+
options: {
|
|
53
|
+
manifests: { type: "string" },
|
|
54
|
+
output: { type: "string", short: "o" },
|
|
55
|
+
namespace: { type: "string" },
|
|
56
|
+
check: { type: "boolean" },
|
|
57
|
+
help: { type: "boolean", short: "h" },
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
if (values.help)
|
|
61
|
+
return null;
|
|
62
|
+
const namespace = values.namespace ?? "MantleSite";
|
|
63
|
+
if (!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(namespace)) {
|
|
64
|
+
throw new Error(`--namespace must be a TypeScript identifier; got ${JSON.stringify(namespace)}`);
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
manifests: values.manifests ?? "./manifests",
|
|
68
|
+
output: values.output ?? ".mantle/generated",
|
|
69
|
+
namespace,
|
|
70
|
+
check: values.check === true,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function printHelp() {
|
|
74
|
+
stdout.write(`mantle generate — compile manifests and handler types
|
|
75
|
+
|
|
76
|
+
Usage: mantle generate [options]
|
|
77
|
+
|
|
78
|
+
Options:
|
|
79
|
+
--manifests <dir> Manifest root (default: ./manifests)
|
|
80
|
+
-o, --output <dir> Generated root (default: .mantle/generated)
|
|
81
|
+
--namespace <name> Generated type namespace (default: MantleSite)
|
|
82
|
+
--check Fail without writing when output is stale
|
|
83
|
+
-h, --help This help
|
|
84
|
+
`);
|
|
85
|
+
}
|
|
86
|
+
function emitManifestModule(manifests, namespace) {
|
|
87
|
+
const views = [];
|
|
88
|
+
manifests.forEach((manifest, index) => {
|
|
89
|
+
if (manifest.kind === "View")
|
|
90
|
+
views.push({ manifest, index });
|
|
91
|
+
});
|
|
92
|
+
const notice = "// Generated by `mantle generate`. Do not edit by hand.";
|
|
93
|
+
const specImport = 'import type { Manifest } from "@aotter/mantle/spec";';
|
|
94
|
+
const declaration = `export const manifest = ${JSON.stringify(manifests, null, 2)} as const satisfies readonly Manifest[];`;
|
|
95
|
+
if (views.length === 0)
|
|
96
|
+
return [notice, specImport, "", declaration, ""].join("\n");
|
|
97
|
+
return [
|
|
98
|
+
notice,
|
|
99
|
+
'import type { CmsRuntime, HandlerContext } from "@aotter/mantle/runtime";',
|
|
100
|
+
specImport,
|
|
101
|
+
'import type * as MantleGenerated from "./types.js";',
|
|
102
|
+
"",
|
|
103
|
+
declaration,
|
|
104
|
+
"",
|
|
105
|
+
"export interface MantleViewOptions {",
|
|
106
|
+
" readonly page?: number;",
|
|
107
|
+
" readonly show?: number;",
|
|
108
|
+
" readonly ctx?: HandlerContext;",
|
|
109
|
+
"}",
|
|
110
|
+
"",
|
|
111
|
+
"export function bindMantleSite(runtime: CmsRuntime) {",
|
|
112
|
+
" return {",
|
|
113
|
+
" views: {",
|
|
114
|
+
...views.flatMap(({ manifest: view, index }) => {
|
|
115
|
+
const id = tsId(view.metadata.name);
|
|
116
|
+
const requiredParams = (view.spec.params?.required?.length ?? 0) > 0;
|
|
117
|
+
const requestType = view.spec.params
|
|
118
|
+
? `MantleViewOptions & { readonly params${requiredParams ? "" : "?"}: MantleGenerated.${namespace}.ViewParams_${id} }`
|
|
119
|
+
: "MantleViewOptions";
|
|
120
|
+
return [
|
|
121
|
+
` ${JSON.stringify(view.metadata.name)}: (request: ${requestType}${requiredParams ? "" : " = {}"}) =>`,
|
|
122
|
+
` runtime.executeView.execute<MantleGenerated.${namespace}.ViewRow_${id}>({`,
|
|
123
|
+
` view: manifest[${index}],`,
|
|
124
|
+
" ctx: request.ctx,",
|
|
125
|
+
" options: {",
|
|
126
|
+
...(view.spec.params ? [" params: request.params,"] : []),
|
|
127
|
+
" page: request.page,",
|
|
128
|
+
" show: request.show,",
|
|
129
|
+
" },",
|
|
130
|
+
" }),",
|
|
131
|
+
];
|
|
132
|
+
}),
|
|
133
|
+
" },",
|
|
134
|
+
" } as const;",
|
|
135
|
+
"}",
|
|
136
|
+
"",
|
|
137
|
+
].join("\n");
|
|
138
|
+
}
|
|
139
|
+
function emitTypes(manifests, namespace) {
|
|
140
|
+
const generated = EmitTypesUseCase.run({ manifests, namespace }).source
|
|
141
|
+
.replace("Generated by `mantle emit-types`", "Generated by `mantle generate`");
|
|
142
|
+
const procedures = manifests.filter((manifest) => manifest.kind === "Procedure" && manifest.spec.handler.kind === "ref");
|
|
143
|
+
if (procedures.length === 0)
|
|
144
|
+
return generated;
|
|
145
|
+
const handlers = new Map();
|
|
146
|
+
for (const procedure of procedures) {
|
|
147
|
+
const name = tsId(procedure.metadata.name);
|
|
148
|
+
const ref = procedure.spec.handler.kind === "ref" ? procedure.spec.handler.ref : "";
|
|
149
|
+
const types = handlers.get(ref) ?? { inputs: [], outputs: [] };
|
|
150
|
+
types.inputs.push(`${namespace}.ProcInput_${name}`);
|
|
151
|
+
types.outputs.push(`${namespace}.ProcOutput_${name}`);
|
|
152
|
+
handlers.set(ref, types);
|
|
153
|
+
}
|
|
154
|
+
return [
|
|
155
|
+
'import type { HandlerFn } from "@aotter/mantle/runtime";',
|
|
156
|
+
"",
|
|
157
|
+
generated.trimEnd(),
|
|
158
|
+
"",
|
|
159
|
+
"export type MantleHandlers<Env = unknown> = {",
|
|
160
|
+
...[...handlers].map(([ref, types]) => ` readonly ${JSON.stringify(ref)}: HandlerFn<${types.inputs.join(" | ")}, ${types.outputs.join(" | ")}, Env>;`),
|
|
161
|
+
"};",
|
|
162
|
+
"",
|
|
163
|
+
].join("\n");
|
|
164
|
+
}
|
|
165
|
+
function tsId(name) {
|
|
166
|
+
return name.replace(/[^a-zA-Z0-9_$]+/g, "_");
|
|
167
|
+
}
|
|
168
|
+
async function syncText(path, expected, check) {
|
|
169
|
+
const current = await readFile(path, "utf8").catch(() => null);
|
|
170
|
+
if (current === expected)
|
|
171
|
+
return true;
|
|
172
|
+
if (check)
|
|
173
|
+
return false;
|
|
174
|
+
await mkdir(dirname(path), { recursive: true });
|
|
175
|
+
await writeFile(path, expected, "utf8");
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
function message(error) {
|
|
179
|
+
return error instanceof Error ? error.message : String(error);
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=generate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../src/generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness-cli.d.ts","sourceRoot":"","sources":["../src/harness-cli.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { argv, stderr, stdout } from "node:process";
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
import { ValidateManifestsUseCase, } from "@aotter/mantle-spec";
|
|
5
|
+
import { loadManifestsFromRoot } from "@aotter/mantle-spec/cli";
|
|
6
|
+
import { benchmarkHttpRoutes, inspectIndexCoverage, } from "@aotter/mantle-runtime/testing";
|
|
7
|
+
async function main() {
|
|
8
|
+
const command = argv[2];
|
|
9
|
+
if (!command || command === "--help" || command === "-h") {
|
|
10
|
+
printHelp();
|
|
11
|
+
return command ? 0 : 2;
|
|
12
|
+
}
|
|
13
|
+
if (command === "indexes")
|
|
14
|
+
return runIndexes(argv.slice(3));
|
|
15
|
+
if (command === "http")
|
|
16
|
+
return runHttp(argv.slice(3));
|
|
17
|
+
stderr.write(`Unknown subcommand: ${command}\n`);
|
|
18
|
+
return 2;
|
|
19
|
+
}
|
|
20
|
+
async function runIndexes(rawArgs) {
|
|
21
|
+
let values;
|
|
22
|
+
try {
|
|
23
|
+
({ values } = parseArgs({
|
|
24
|
+
args: [...rawArgs],
|
|
25
|
+
options: {
|
|
26
|
+
manifests: { type: "string" },
|
|
27
|
+
rows: { type: "string" },
|
|
28
|
+
require: { type: "string", multiple: true },
|
|
29
|
+
"require-public": { type: "boolean" },
|
|
30
|
+
format: { type: "string" },
|
|
31
|
+
help: { type: "boolean", short: "h" },
|
|
32
|
+
},
|
|
33
|
+
}));
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
stderr.write(`${message(error)}\n`);
|
|
37
|
+
return 2;
|
|
38
|
+
}
|
|
39
|
+
if (values.help) {
|
|
40
|
+
printIndexesHelp();
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
const format = outputFormat(values.format);
|
|
44
|
+
const loaded = await loadManifestsFromRoot(values.manifests ?? "./manifests");
|
|
45
|
+
const validation = ValidateManifestsUseCase.run({
|
|
46
|
+
manifests: loaded.manifests,
|
|
47
|
+
filePaths: loaded.filePaths,
|
|
48
|
+
});
|
|
49
|
+
const errors = [...loaded.parseErrors, ...validation.diagnostics]
|
|
50
|
+
.filter((diagnostic) => diagnostic.severity === "error");
|
|
51
|
+
if (errors.length > 0) {
|
|
52
|
+
emitErrors(errors, format);
|
|
53
|
+
return 1;
|
|
54
|
+
}
|
|
55
|
+
if (loaded.manifests.length === 0) {
|
|
56
|
+
stderr.write(`No manifests found under ${values.manifests ?? "./manifests"}\n`);
|
|
57
|
+
return 2;
|
|
58
|
+
}
|
|
59
|
+
const rows = values.rows === undefined ? undefined : Number(values.rows);
|
|
60
|
+
if (rows !== undefined && (!Number.isFinite(rows) || rows <= 0)) {
|
|
61
|
+
stderr.write("--rows must be a positive number\n");
|
|
62
|
+
return 2;
|
|
63
|
+
}
|
|
64
|
+
const report = await inspectIndexCoverage(loaded.manifests, {
|
|
65
|
+
rowsPerSchema: rows,
|
|
66
|
+
requirePublic: values["require-public"] === true,
|
|
67
|
+
requiredViews: values.require ?? [],
|
|
68
|
+
});
|
|
69
|
+
emitIndexReport(report, format);
|
|
70
|
+
return report.summary.requiredFailures > 0 ? 1 : 0;
|
|
71
|
+
}
|
|
72
|
+
async function runHttp(rawArgs) {
|
|
73
|
+
let values;
|
|
74
|
+
try {
|
|
75
|
+
({ values } = parseArgs({
|
|
76
|
+
args: [...rawArgs],
|
|
77
|
+
options: {
|
|
78
|
+
route: { type: "string", multiple: true },
|
|
79
|
+
"base-url": { type: "string" },
|
|
80
|
+
rounds: { type: "string" },
|
|
81
|
+
warmup: { type: "string" },
|
|
82
|
+
format: { type: "string" },
|
|
83
|
+
help: { type: "boolean", short: "h" },
|
|
84
|
+
},
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
stderr.write(`${message(error)}\n`);
|
|
89
|
+
return 2;
|
|
90
|
+
}
|
|
91
|
+
if (values.help) {
|
|
92
|
+
printHttpHelp();
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
if (!values.route || values.route.length === 0) {
|
|
96
|
+
stderr.write("http requires at least one --route name=/path-or-url\n");
|
|
97
|
+
return 2;
|
|
98
|
+
}
|
|
99
|
+
const format = outputFormat(values.format);
|
|
100
|
+
const baseUrl = (values["base-url"] ?? "").replace(/\/$/, "");
|
|
101
|
+
const targets = values.route.map((raw) => {
|
|
102
|
+
const separator = raw.indexOf("=");
|
|
103
|
+
if (separator < 1)
|
|
104
|
+
throw new Error(`invalid --route ${JSON.stringify(raw)}`);
|
|
105
|
+
const name = raw.slice(0, separator);
|
|
106
|
+
const path = raw.slice(separator + 1);
|
|
107
|
+
return { name, url: path.startsWith("/") ? `${baseUrl}${path}` : path };
|
|
108
|
+
});
|
|
109
|
+
if (targets.some(({ url }) => !/^https?:\/\//.test(url))) {
|
|
110
|
+
stderr.write("route URLs must be absolute, or use --base-url with /paths\n");
|
|
111
|
+
return 2;
|
|
112
|
+
}
|
|
113
|
+
let report;
|
|
114
|
+
try {
|
|
115
|
+
report = await benchmarkHttpRoutes({
|
|
116
|
+
targets,
|
|
117
|
+
rounds: numericOption(values.rounds, "--rounds"),
|
|
118
|
+
warmup: numericOption(values.warmup, "--warmup"),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
stderr.write(`${message(error)}\n`);
|
|
123
|
+
return 1;
|
|
124
|
+
}
|
|
125
|
+
emitHttpReport(report, format);
|
|
126
|
+
return 0;
|
|
127
|
+
}
|
|
128
|
+
function emitIndexReport(report, format) {
|
|
129
|
+
if (format === "json") {
|
|
130
|
+
stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
for (const path of report.paths) {
|
|
134
|
+
const status = path.required ? path.passed ? "PASS" : "FAIL" : "ADVISORY";
|
|
135
|
+
const detail = path.findings.length > 0
|
|
136
|
+
? path.findings.join("; ")
|
|
137
|
+
: path.usedIndexes.join(", ") || "planner found no named index";
|
|
138
|
+
stdout.write(`${status} ${path.view}: ${detail}\n`);
|
|
139
|
+
}
|
|
140
|
+
for (const view of report.summary.missingRequiredViews) {
|
|
141
|
+
stdout.write(`FAIL ${view}: required View not found\n`);
|
|
142
|
+
}
|
|
143
|
+
stdout.write(`views=${report.summary.views} required=${report.summary.required} ` +
|
|
144
|
+
`failures=${report.summary.requiredFailures} rows/schema=${report.rowsPerSchema}\n`);
|
|
145
|
+
}
|
|
146
|
+
function emitHttpReport(report, format) {
|
|
147
|
+
if (format === "json") {
|
|
148
|
+
stdout.write(`${JSON.stringify(report, null, 2)}\n`);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
for (const result of report.results) {
|
|
152
|
+
const queries = result.queryCount ? ` queries.p95=${result.queryCount.p95}` : "";
|
|
153
|
+
const rows = result.rowsRead ? ` rows_read.p95=${result.rowsRead.p95}` : "";
|
|
154
|
+
stdout.write(`${result.name}: p50=${result.timingMs.p50.toFixed(2)}ms ` +
|
|
155
|
+
`p95=${result.timingMs.p95.toFixed(2)}ms${queries}${rows}\n`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function emitErrors(errors, format) {
|
|
159
|
+
if (format === "json")
|
|
160
|
+
stdout.write(`${JSON.stringify({ errors }, null, 2)}\n`);
|
|
161
|
+
else
|
|
162
|
+
for (const error of errors)
|
|
163
|
+
stderr.write(`${error.code} ${error.path}: ${error.message}\n`);
|
|
164
|
+
}
|
|
165
|
+
function outputFormat(raw) {
|
|
166
|
+
if (raw === undefined)
|
|
167
|
+
return stdout.isTTY ? "text" : "json";
|
|
168
|
+
if (raw === "json" || raw === "text")
|
|
169
|
+
return raw;
|
|
170
|
+
throw new Error(`--format must be text or json; got ${JSON.stringify(raw)}`);
|
|
171
|
+
}
|
|
172
|
+
function numericOption(raw, name) {
|
|
173
|
+
if (raw === undefined)
|
|
174
|
+
return undefined;
|
|
175
|
+
const value = Number(raw);
|
|
176
|
+
if (!Number.isFinite(value) || value < 0)
|
|
177
|
+
throw new Error(`${name} must be a non-negative number`);
|
|
178
|
+
return value;
|
|
179
|
+
}
|
|
180
|
+
function message(error) {
|
|
181
|
+
return error instanceof Error ? error.message : String(error);
|
|
182
|
+
}
|
|
183
|
+
function printHelp() {
|
|
184
|
+
stdout.write(`mantle-harness — measured performance checks\n\n` +
|
|
185
|
+
`Usage: mantle-harness <indexes|http> [options]\n\n` +
|
|
186
|
+
` indexes Execute compiled Views in crowded SQLite and inspect plans\n` +
|
|
187
|
+
` http Sample a running Worker and report p50/p95 + metric headers\n`);
|
|
188
|
+
}
|
|
189
|
+
function printIndexesHelp() {
|
|
190
|
+
stdout.write(`Usage: mantle-harness indexes [options]\n\n` +
|
|
191
|
+
` --manifests <dir> Manifest root (default: ./manifests)\n` +
|
|
192
|
+
` --rows <n> Deterministic rows per Schema (default: 2000)\n` +
|
|
193
|
+
` --require <view> Fail when this View lacks its access path; repeatable\n` +
|
|
194
|
+
` --require-public Apply the gate to public Views\n` +
|
|
195
|
+
` --format <fmt> text or json\n`);
|
|
196
|
+
}
|
|
197
|
+
function printHttpHelp() {
|
|
198
|
+
stdout.write(`Usage: mantle-harness http [options]\n\n` +
|
|
199
|
+
` --base-url <url> Prefix for route paths\n` +
|
|
200
|
+
` --route <name=url> Route label and path/URL; repeatable\n` +
|
|
201
|
+
` --rounds <n> Measured requests per route (default: 20)\n` +
|
|
202
|
+
` --warmup <n> Warmup requests per route (default: 2)\n` +
|
|
203
|
+
` --format <fmt> text or json\n`);
|
|
204
|
+
}
|
|
205
|
+
main().then((code) => { process.exitCode = code; }, (error) => {
|
|
206
|
+
stderr.write(`${message(error)}\n`);
|
|
207
|
+
process.exitCode = 2;
|
|
208
|
+
});
|
|
209
|
+
//# sourceMappingURL=harness-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness-cli.js","sourceRoot":"","sources":["../src/harness-cli.ts"],"names":[],"mappings":"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"}
|