@impetik/xeer-mcp 0.2.29 → 0.2.32
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 +7 -4
- package/dist/dev-session.d.ts +4 -0
- package/package.json +2 -2
- package/vendor/spec/actions.d.ts +62 -7
- package/vendor/spec/actions.js +67 -19
- package/vendor/spec/admin-sql.js +7 -2
- package/vendor/spec/diagnostics.d.ts +1 -1
- package/vendor/spec/diagnostics.js +17 -4
- package/vendor/spec/framework-config.d.ts +35 -0
- package/vendor/spec/framework-config.js +49 -2
- package/vendor/spec/index.d.ts +1 -0
- package/vendor/spec/index.js +1 -0
- package/vendor/spec/platform-grants.d.ts +25 -0
- package/vendor/spec/platform-grants.js +14 -0
- package/vendor/spec/route.js +1 -0
- package/vendor/spec/scaffold-names.d.ts +23 -1
- package/vendor/spec/scaffold-names.js +18 -1
- package/vendor/spec/template-distribution.d.ts +26 -0
- package/vendor/spec/template-distribution.js +41 -3
- package/vendor/spec/template.d.ts +13 -0
- package/vendor/spec/template.js +36 -1
package/README.md
CHANGED
|
@@ -63,7 +63,7 @@ The generated registry is the complete MCP tool and exclusion surface:
|
|
|
63
63
|
| `xeer_check` | `check` | `author` / `operator` | Validate a project and report structured diagnostics. | `directory?`: `string` | `read-source`<br>`write-generated` | writes; idempotent; reversible; non-destructive | `project-relative` | `xeer.command.v0` | none |
|
|
64
64
|
| `xeer_build` | `build` | `author` / `operator` | Build and verify a content-addressed project artifact. | `directory?`: `string` | `read-source`<br>`write-generated`<br>`run-local` | writes; idempotent; reversible; non-destructive | `project-relative` | `xeer.command.v0` | none |
|
|
65
65
|
| `xeer_test` | `test` | `author` / `operator` | Run the project test suite and record review evidence. | `directory?`: `string`<br>`timeoutMilliseconds?`: `integer` [1000..1800000] | `read-source`<br>`write-generated`<br>`run-local`<br>`write-state` | writes; idempotent; reversible; non-destructive | `project-relative` | `xeer.dev.v0` | none |
|
|
66
|
-
| `xeer_new` | `new` | `author` / `operator` | Create a new project from a supported scaffold. | `directory`: `string`<br>`template?`: `string`<br>`framework?`: `sveltekit`<br>`ui?`: `preact` / `react` | `write-source`<br>`network-read` | writes; non-idempotent; reversible; non-destructive | `project-relative` | `xeer.command.v0` | none |
|
|
66
|
+
| `xeer_new` | `new` | `author` / `operator` | Create a new project from a supported scaffold. | `directory`: `string`<br>`template?`: `string`<br>`framework?`: `sveltekit` / `astro`<br>`ui?`: `preact` / `react` | `write-source`<br>`network-read` | writes; non-idempotent; reversible; non-destructive | `project-relative` | `xeer.command.v0` | none |
|
|
67
67
|
| `xeer_agent_context` | `agent.context` | `author` / `operator` | Read normalized project facts, operations, diagnostics, tests, and safe next actions. | `directory?`: `string` | `read-source` | read-only; idempotent; reversible; non-destructive | `project-relative` | `xeer.agent-context.v0` | none |
|
|
68
68
|
| `xeer_docs_search` | `docs.search` | `author` / `operator` | Search the installed-version Xeer documentation index. | `query`: `string`<br>`limit?`: `integer` [1..20]; default `5` | none | read-only; idempotent; reversible; non-destructive | `none` | `xeer.docs-search.v0` | none |
|
|
69
69
|
| `xeer_doctor` | `doctor` | `author` / `operator` | Diagnose the toolchain and generated project state. | `directory?`: `string` | `read-source`<br>`write-generated` | writes; idempotent; reversible; non-destructive | `project-relative` | `xeer.command.v0` | none |
|
|
@@ -76,11 +76,12 @@ The generated registry is the complete MCP tool and exclusion surface:
|
|
|
76
76
|
| `xeer_dev_stop` | `dev.stop` | `author` / `operator` | Stop a local development session and release its lease. | `sessionId?`: `string`<br>`cursor?`: `integer` [0..9007199254740991]; default `0` | `run-local` | writes; idempotent; reversible; non-destructive | `none` | `xeer.dev.v0` | none |
|
|
77
77
|
| `xeer_diagnostics` | `diagnostics` | `author` / `operator` | Explain one emitted diagnostic code. | `code`: `string` | none | read-only; idempotent; reversible; non-destructive | `none` | `xeer.command.v0` | none |
|
|
78
78
|
|
|
79
|
-
**CLI actions intentionally excluded from MCP (
|
|
79
|
+
**CLI actions intentionally excluded from MCP (39).**
|
|
80
80
|
|
|
81
81
|
| CLI action | Action | Summary | Effects | Safety | Path policy | Output | Why no MCP tool |
|
|
82
82
|
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
83
|
-
| `xeer init` | `init` | Initialize Xeer in an existing SvelteKit project. | `read-source`<br>`write-source`<br>`run-local`<br>`network-read` | writes; idempotent; reversible; non-destructive | `project-relative` | `xeer.command.v0` | Not exposed through MCP v0; use the CLI deliberately. |
|
|
83
|
+
| `xeer init` | `init` | Initialize Xeer in an existing SvelteKit or Astro project. | `read-source`<br>`write-source`<br>`run-local`<br>`network-read` | writes; idempotent; reversible; non-destructive | `project-relative` | `xeer.command.v0` | Not exposed through MCP v0; use the CLI deliberately. |
|
|
84
|
+
| `xeer bootstrap` | `bootstrap` | Open owner-only EmDash setup for a deployed Astro project. | `read-source`<br>`network-read`<br>`network-write` | writes; non-idempotent; reversible; non-destructive | `project-relative` | `xeer.command.v0` | Not exposed through MCP v0; use the CLI deliberately. |
|
|
84
85
|
| `xeer agent setup` | `agent.setup` | Install or verify project-confined agent adapters. | `read-source`<br>`write-source` | writes; idempotent; reversible; non-destructive | `project-relative` | `xeer.command.v0` | Not exposed through MCP v0; use the CLI deliberately. |
|
|
85
86
|
| `xeer deploy` | `deploy` | Build and deploy a project artifact. | `read-source`<br>`write-generated`<br>`run-local`<br>`network-read`<br>`network-write`<br>`production-change` | writes; non-idempotent; reversible; non-destructive | `project-relative` | `xeer.command.v0` | MCP exposes a separate preview-only deploy action; direct production deploy stays CLI-only. |
|
|
86
87
|
| `xeer promote` | `promote` | Promote a preview artifact to production. | `network-read`<br>`network-write`<br>`production-change` | writes; non-idempotent; reversible; non-destructive | `project-or-url` | `xeer.command.v0` | MCP promotion is a separate action available only when the server starts in operator profile. |
|
|
@@ -115,7 +116,9 @@ The generated registry is the complete MCP tool and exclusion surface:
|
|
|
115
116
|
| `xeer actions` | `actions` | Print the machine-readable action and safety catalogue. | none | read-only; idempotent; reversible; non-destructive | `none` | `xeer.command.v0` | Not exposed through MCP v0; use the CLI deliberately. |
|
|
116
117
|
| `xeer db tables` | `db.tables` | List the tables of a running application database. | `read-state` | read-only; idempotent; reversible; non-destructive | `project-relative` | `xeer.command.v0` | Not exposed through MCP v0; use the CLI deliberately. |
|
|
117
118
|
| `xeer db schema` | `db.schema` | Print the declared schema of a running application database. | `read-state` | read-only; idempotent; reversible; non-destructive | `project-relative` | `xeer.command.v0` | Not exposed through MCP v0; use the CLI deliberately. |
|
|
118
|
-
| `xeer db exec` | `db.exec` | Run
|
|
119
|
+
| `xeer db exec` | `db.exec` | Run SQL against a running or deployed application database. | `read-state`<br>`write-state`<br>`network-read`<br>`network-write` | writes; non-idempotent; irreversible; destructive | `project-relative` | `xeer.command.v0` | Destructive state replacement requires an explicit CLI invocation. |
|
|
120
|
+
| `xeer db bookmark` | `db.bookmark` | Print the current Time Travel bookmark of a deployed application database. | `network-read` | read-only; idempotent; reversible; non-destructive | `project-relative` | `xeer.command.v0` | Not exposed through MCP v0; use the CLI deliberately. |
|
|
121
|
+
| `xeer db restore` | `db.restore` | Restore a deployed application database to a bookmark or a time. | `network-write`<br>`write-state` | writes; non-idempotent; reversible; destructive | `project-relative` | `xeer.command.v0` | Destructive state replacement requires an explicit CLI invocation. |
|
|
119
122
|
<!-- xeer-action-reference:end -->
|
|
120
123
|
|
|
121
124
|
Every tool returns `{ protocol: "xeer.mcp-result.v0", action, ok, result?, error? }` both as
|
package/dist/dev-session.d.ts
CHANGED
|
@@ -25,6 +25,10 @@ export type DevSessionStatus = 'starting' | 'ready' | 'compile_failed' | 'stoppe
|
|
|
25
25
|
*/
|
|
26
26
|
export interface PreviewUrls {
|
|
27
27
|
url: string;
|
|
28
|
+
/** A framework project's framework, `sveltekit` or `astro`; absent for a Xeer application. */
|
|
29
|
+
framework?: string;
|
|
30
|
+
/** An EmDash project's local admin, on `localhost` because passkeys refuse an IP address. */
|
|
31
|
+
adminUrl?: string;
|
|
28
32
|
healthUrl?: string;
|
|
29
33
|
inspectorUrl?: string;
|
|
30
34
|
debugUrl?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@impetik/xeer-mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.32",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Model Context Protocol server for Xeer project context, diagnostics, scaffold, check, test, dev, build, and preview deployment.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
49
49
|
"zod": "^4.0.10",
|
|
50
|
-
"@impetik/xeer": "0.2.
|
|
50
|
+
"@impetik/xeer": "0.2.32"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/node": "^24.1.0"
|
package/vendor/spec/actions.d.ts
CHANGED
|
@@ -194,7 +194,7 @@ declare const actions: readonly [{
|
|
|
194
194
|
readonly command: readonly ["new"];
|
|
195
195
|
readonly summary: "Create a new project from a supported scaffold.";
|
|
196
196
|
readonly description: string;
|
|
197
|
-
readonly usage: readonly ["new [directory] [--template <id>] [--framework sveltekit] [--ui preact|react] [--json]"];
|
|
197
|
+
readonly usage: readonly ["new [directory] [--template <id>] [--framework sveltekit|astro] [--ui preact|react] [--json]"];
|
|
198
198
|
readonly helpOrder: 30;
|
|
199
199
|
readonly outputProtocol: "xeer.command.v0";
|
|
200
200
|
readonly effects: readonly ["write-source", "network-read"];
|
|
@@ -218,7 +218,7 @@ declare const actions: readonly [{
|
|
|
218
218
|
readonly framework: {
|
|
219
219
|
readonly description: string;
|
|
220
220
|
readonly type: "string";
|
|
221
|
-
readonly enum: readonly ["sveltekit"];
|
|
221
|
+
readonly enum: readonly ["sveltekit", "astro"];
|
|
222
222
|
};
|
|
223
223
|
readonly ui: {
|
|
224
224
|
readonly description: string;
|
|
@@ -237,7 +237,7 @@ declare const actions: readonly [{
|
|
|
237
237
|
}, {
|
|
238
238
|
readonly id: "init";
|
|
239
239
|
readonly command: readonly ["init"];
|
|
240
|
-
readonly summary: "Initialize Xeer in an existing SvelteKit project.";
|
|
240
|
+
readonly summary: "Initialize Xeer in an existing SvelteKit or Astro project.";
|
|
241
241
|
readonly description: string;
|
|
242
242
|
readonly usage: readonly ["init [directory] [--dry-run] [--json]"];
|
|
243
243
|
readonly helpOrder: 32;
|
|
@@ -252,6 +252,24 @@ declare const actions: readonly [{
|
|
|
252
252
|
readonly cli: true;
|
|
253
253
|
readonly mcpExclusion: "Not exposed through MCP v0; use the CLI deliberately.";
|
|
254
254
|
};
|
|
255
|
+
}, {
|
|
256
|
+
readonly id: "bootstrap";
|
|
257
|
+
readonly command: readonly ["bootstrap"];
|
|
258
|
+
readonly summary: "Open owner-only EmDash setup for a deployed Astro project.";
|
|
259
|
+
readonly description: string;
|
|
260
|
+
readonly usage: readonly ["bootstrap [directory] [--environment prod|preview] [--control-url <url>] [--no-open] [--json]"];
|
|
261
|
+
readonly helpOrder: 51;
|
|
262
|
+
readonly outputProtocol: "xeer.command.v0";
|
|
263
|
+
readonly effects: readonly ["read-source", "network-read", "network-write"];
|
|
264
|
+
readonly idempotent: false;
|
|
265
|
+
readonly reversible: true;
|
|
266
|
+
readonly destructive: false;
|
|
267
|
+
readonly humanPrerequisites: readonly [string];
|
|
268
|
+
readonly pathPolicy: "project-relative";
|
|
269
|
+
readonly surfaces: {
|
|
270
|
+
readonly cli: true;
|
|
271
|
+
readonly mcpExclusion: "Not exposed through MCP v0; use the CLI deliberately.";
|
|
272
|
+
};
|
|
255
273
|
}, {
|
|
256
274
|
readonly id: "agent.setup";
|
|
257
275
|
readonly command: readonly ["agent", "setup"];
|
|
@@ -1247,15 +1265,52 @@ declare const actions: readonly [{
|
|
|
1247
1265
|
}, {
|
|
1248
1266
|
readonly id: "db.exec";
|
|
1249
1267
|
readonly command: readonly ["db", "exec"];
|
|
1250
|
-
readonly summary: "Run
|
|
1251
|
-
readonly
|
|
1268
|
+
readonly summary: "Run SQL against a running or deployed application database.";
|
|
1269
|
+
readonly description: string;
|
|
1270
|
+
readonly usage: readonly ["db exec [directory] <sql> [--state <dev|preview>] [--write] [--json]", "db exec [directory] <sql> --remote --environment <prod|preview> [--param <value>]... [--control-url <url>] [--json]", "db exec [directory] --remote --environment <prod|preview> --file <batch.json> [--control-url <url>] [--json]"];
|
|
1252
1271
|
readonly helpOrder: 340;
|
|
1253
1272
|
readonly outputProtocol: "xeer.command.v0";
|
|
1254
|
-
readonly effects: readonly ["read-state", "write-state"];
|
|
1273
|
+
readonly effects: readonly ["read-state", "write-state", "network-read", "network-write"];
|
|
1255
1274
|
readonly idempotent: false;
|
|
1256
1275
|
readonly reversible: false;
|
|
1276
|
+
readonly destructive: true;
|
|
1277
|
+
readonly humanPrerequisites: readonly ["Locally, a human must pass --write before any statement that modifies rows.", string];
|
|
1278
|
+
readonly pathPolicy: "project-relative";
|
|
1279
|
+
readonly surfaces: {
|
|
1280
|
+
readonly cli: true;
|
|
1281
|
+
readonly mcpExclusion: "Destructive state replacement requires an explicit CLI invocation.";
|
|
1282
|
+
};
|
|
1283
|
+
}, {
|
|
1284
|
+
readonly id: "db.bookmark";
|
|
1285
|
+
readonly command: readonly ["db", "bookmark"];
|
|
1286
|
+
readonly summary: "Print the current Time Travel bookmark of a deployed application database.";
|
|
1287
|
+
readonly description: string;
|
|
1288
|
+
readonly usage: readonly ["db bookmark [directory] --remote --environment <prod|preview> [--control-url <url>] [--json]"];
|
|
1289
|
+
readonly helpOrder: 345;
|
|
1290
|
+
readonly outputProtocol: "xeer.command.v0";
|
|
1291
|
+
readonly effects: readonly ["network-read"];
|
|
1292
|
+
readonly idempotent: true;
|
|
1293
|
+
readonly reversible: true;
|
|
1257
1294
|
readonly destructive: false;
|
|
1258
|
-
readonly humanPrerequisites: readonly [
|
|
1295
|
+
readonly humanPrerequisites: readonly [string];
|
|
1296
|
+
readonly pathPolicy: "project-relative";
|
|
1297
|
+
readonly surfaces: {
|
|
1298
|
+
readonly cli: true;
|
|
1299
|
+
readonly mcpExclusion: "Not exposed through MCP v0; use the CLI deliberately.";
|
|
1300
|
+
};
|
|
1301
|
+
}, {
|
|
1302
|
+
readonly id: "db.restore";
|
|
1303
|
+
readonly command: readonly ["db", "restore"];
|
|
1304
|
+
readonly summary: "Restore a deployed application database to a bookmark or a time.";
|
|
1305
|
+
readonly description: string;
|
|
1306
|
+
readonly usage: readonly ["db restore [directory] --remote --environment <prod|preview> --to <bookmark|time> [--control-url <url>] [--json]"];
|
|
1307
|
+
readonly helpOrder: 346;
|
|
1308
|
+
readonly outputProtocol: "xeer.command.v0";
|
|
1309
|
+
readonly effects: readonly ["network-write", "write-state"];
|
|
1310
|
+
readonly idempotent: false;
|
|
1311
|
+
readonly reversible: true;
|
|
1312
|
+
readonly destructive: true;
|
|
1313
|
+
readonly humanPrerequisites: readonly [string];
|
|
1259
1314
|
readonly pathPolicy: "project-relative";
|
|
1260
1315
|
readonly surfaces: {
|
|
1261
1316
|
readonly cli: true;
|
package/vendor/spec/actions.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** Stable protocol for the action catalogue consumed by CLI, MCP, and agent context surfaces. */
|
|
2
2
|
import { REVIEW_RECEIPT_ID_SOURCE } from './review.js';
|
|
3
|
-
import {
|
|
3
|
+
import { SCAFFOLDABLE_FRAMEWORK_NAMES } from './scaffold-names.js';
|
|
4
4
|
export const ACTION_REGISTRY_PROTOCOL = 'xeer.actions.v0';
|
|
5
5
|
export const XEER_MCP_PROFILES = ['author', 'operator'];
|
|
6
6
|
export const XEER_ARTIFACT_ID_PATTERN = '^sha256:[a-f0-9]{64}$';
|
|
@@ -17,7 +17,7 @@ export const XEER_CLI_COMMAND_GROUPS = Object.freeze([
|
|
|
17
17
|
{ command: 'state', summary: 'Inspect running application state or reset local state.' },
|
|
18
18
|
{ command: 'env', summary: 'Manage application environment values and secrets.' },
|
|
19
19
|
{ command: 'token', summary: 'Manage service builder tokens.' },
|
|
20
|
-
{ command: 'db', summary: 'Inspect and
|
|
20
|
+
{ command: 'db', summary: 'Inspect, query and restore a running or deployed application database.' },
|
|
21
21
|
]);
|
|
22
22
|
const NOT_EXPOSED_V0 = 'Not exposed through MCP v0; use the CLI deliberately.';
|
|
23
23
|
const HUMAN_IDENTITY = 'Human identity and project ownership decisions are not delegated through MCP.';
|
|
@@ -216,12 +216,14 @@ const actions = [
|
|
|
216
216
|
+ 'scaffold sign-in UI: every visitor already has a verified identity, and the generated README '
|
|
217
217
|
+ 'explains how to opt in to a persistent account. The four bundled starter names resolve '
|
|
218
218
|
+ 'offline and accept `--ui`; every other exact template id resolves through the public catalog '
|
|
219
|
-
+ 'and owns its renderer. `--
|
|
220
|
-
+ 'project
|
|
221
|
-
+ '
|
|
222
|
-
+ '
|
|
219
|
+
+ 'and owns its renderer. `--template emdash` is the bundled EmDash blog: a complete Astro '
|
|
220
|
+
+ 'framework project that resolves offline, declares `integration: "emdash"`, and refuses `--ui` '
|
|
221
|
+
+ 'with `XE3013`. `--framework sveltekit|astro` writes a plain framework project instead: the '
|
|
222
|
+
+ 'framework owns the renderer and the routes, Xeer owns `xeer.config.json` and the '
|
|
223
|
+
+ 'deployment, so `result.framework` replaces both fields, `--ui` does not apply and is '
|
|
224
|
+
+ 'refused with `XE3004`, and `--template` alongside it is `XE3005`. To adopt a framework '
|
|
223
225
|
+ 'project that already exists, use `xeer init` rather than this command.',
|
|
224
|
-
usage: ['new [directory] [--template <id>] [--framework sveltekit] [--ui preact|react] [--json]'],
|
|
226
|
+
usage: ['new [directory] [--template <id>] [--framework sveltekit|astro] [--ui preact|react] [--json]'],
|
|
225
227
|
helpOrder: 30,
|
|
226
228
|
outputProtocol: 'xeer.command.v0', effects: ['write-source', 'network-read'], idempotent: false,
|
|
227
229
|
reversible: true, destructive: false, humanPrerequisites: [], pathPolicy: 'project-relative',
|
|
@@ -235,15 +237,16 @@ const actions = [
|
|
|
235
237
|
type: 'string', description: 'Target directory, relative to the server root. Must be empty or absent.',
|
|
236
238
|
},
|
|
237
239
|
template: {
|
|
238
|
-
description: 'A bundled starter name
|
|
239
|
-
+ 'Bundled
|
|
240
|
+
description: 'A bundled starter name, the bundled emdash framework template, or an exact template '
|
|
241
|
+
+ 'catalog id. Defaults to notes. Bundled names resolve offline. Exclusive with framework, '
|
|
242
|
+
+ 'which is refused with XE3005.',
|
|
240
243
|
type: 'string',
|
|
241
244
|
},
|
|
242
245
|
framework: {
|
|
243
246
|
description: 'Scaffold a fresh project for this framework instead of a Xeer '
|
|
244
247
|
+ 'application: it declares xeer.config.json, owns its own renderer and routes, and '
|
|
245
248
|
+ 'delegates check, dev, test, and build to its package scripts. Exclusive with template and ui.',
|
|
246
|
-
type: 'string', enum:
|
|
249
|
+
type: 'string', enum: SCAFFOLDABLE_FRAMEWORK_NAMES,
|
|
247
250
|
},
|
|
248
251
|
ui: {
|
|
249
252
|
description: 'Which UI provider the written manifest selects. Defaults to preact, and '
|
|
@@ -257,7 +260,7 @@ const actions = [
|
|
|
257
260
|
},
|
|
258
261
|
},
|
|
259
262
|
{
|
|
260
|
-
id: 'init', command: ['init'], summary: 'Initialize Xeer in an existing SvelteKit project.',
|
|
263
|
+
id: 'init', command: ['init'], summary: 'Initialize Xeer in an existing SvelteKit or Astro project.',
|
|
261
264
|
description: 'Detects an existing SvelteKit project, runs Wrangler setup when Cloudflare is not '
|
|
262
265
|
+ 'configured, preserves the project\'s native dev/check/test/build scripts and application '
|
|
263
266
|
+ 'source, and creates the Xeer framework configuration. Use --dry-run to inspect the '
|
|
@@ -267,6 +270,19 @@ const actions = [
|
|
|
267
270
|
idempotent: true, reversible: true, destructive: false, humanPrerequisites: [],
|
|
268
271
|
pathPolicy: 'project-relative', surfaces: { cli: true, mcpExclusion: NOT_EXPOSED_V0 },
|
|
269
272
|
},
|
|
273
|
+
{
|
|
274
|
+
id: 'bootstrap', command: ['bootstrap'], summary: 'Open owner-only EmDash setup for a deployed Astro project.',
|
|
275
|
+
description: 'Verifies builder ownership, obtains a private setup grant, then polls the deployed '
|
|
276
|
+
+ 'site\x27s read-only `GET /_emdash/api/setup/status` for up to 240 seconds so a cold EmDash '
|
|
277
|
+
+ 'database can finish its migrations. A ready site returns `setup: "required"` with the private '
|
|
278
|
+
+ 'setup URL, or `setup: "complete"` with the admin URL once an owner exists. If the site is '
|
|
279
|
+
+ 'still initializing when the wait ends, the command exits 1 with `XE5135` and a '
|
|
280
|
+
+ '`readiness: "pending"` result naming the retry command. `--json` never opens a browser.',
|
|
281
|
+
usage: ['bootstrap [directory] [--environment prod|preview] [--control-url <url>] [--no-open] [--json]'],
|
|
282
|
+
helpOrder: 51, outputProtocol: 'xeer.command.v0', effects: ['read-source', 'network-read', 'network-write'],
|
|
283
|
+
idempotent: false, reversible: true, destructive: false, humanPrerequisites: [BUILDER_CREDENTIAL],
|
|
284
|
+
pathPolicy: 'project-relative', surfaces: { cli: true, mcpExclusion: NOT_EXPOSED_V0 },
|
|
285
|
+
},
|
|
270
286
|
{
|
|
271
287
|
id: 'agent.setup', command: ['agent', 'setup'],
|
|
272
288
|
summary: 'Install or verify project-confined agent adapters.',
|
|
@@ -755,16 +771,48 @@ const actions = [
|
|
|
755
771
|
{
|
|
756
772
|
// Not idempotent and not reversible, because `--write` admits UPDATE and DELETE and the action
|
|
757
773
|
// catalogue describes what an invocation may do rather than what a particular statement does.
|
|
758
|
-
//
|
|
759
|
-
//
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
774
|
+
// Destructive because `--remote` runs any SQL the owner sends, DDL included: on a deployed
|
|
775
|
+
// database the owner may do anything to their own data, and `db restore` is the undo.
|
|
776
|
+
id: 'db.exec', command: ['db', 'exec'], summary: 'Run SQL against a running or deployed application database.',
|
|
777
|
+
description: 'Locally (`--state`), runs one statement against a running `xeer dev` or `xeer preview`: '
|
|
778
|
+
+ 'reads by default, row writes with --write, and never DDL. With --remote it runs as the owner '
|
|
779
|
+
+ 'against the D1 database of a deployed framework project, in the --environment named (there is no '
|
|
780
|
+
+ 'default), through the control plane: any SQL, one statement or a --file batch (a JSON array of '
|
|
781
|
+
+ '{"sql","params"}) that runs as one transaction, so a failing statement rolls every statement '
|
|
782
|
+
+ 'back. Undo with `xeer db restore --remote`.',
|
|
783
|
+
usage: ['db exec [directory] <sql> [--state <dev|preview>] [--write] [--json]',
|
|
784
|
+
'db exec [directory] <sql> --remote --environment <prod|preview> [--param <value>]... [--control-url <url>] [--json]',
|
|
785
|
+
'db exec [directory] --remote --environment <prod|preview> --file <batch.json> [--control-url <url>] [--json]'],
|
|
786
|
+
helpOrder: 340,
|
|
787
|
+
outputProtocol: 'xeer.command.v0', effects: ['read-state', 'write-state', 'network-read', 'network-write'],
|
|
788
|
+
idempotent: false, reversible: false, destructive: true,
|
|
789
|
+
humanPrerequisites: ['Locally, a human must pass --write before any statement that modifies rows.',
|
|
790
|
+
BUILDER_CREDENTIAL],
|
|
766
791
|
pathPolicy: 'project-relative', surfaces: { cli: true, mcpExclusion: DESTRUCTIVE_STATE },
|
|
767
792
|
},
|
|
793
|
+
{
|
|
794
|
+
id: 'db.bookmark', command: ['db', 'bookmark'],
|
|
795
|
+
summary: 'Print the current Time Travel bookmark of a deployed application database.',
|
|
796
|
+
description: 'The bookmark names the database as it is now; `xeer db restore --remote --to <bookmark>` '
|
|
797
|
+
+ 'returns to it for 30 days (7 on the Workers Free plan).',
|
|
798
|
+
usage: ['db bookmark [directory] --remote --environment <prod|preview> [--control-url <url>] [--json]'], helpOrder: 345,
|
|
799
|
+
outputProtocol: 'xeer.command.v0', effects: ['network-read'], idempotent: true, reversible: true,
|
|
800
|
+
destructive: false, humanPrerequisites: [BUILDER_CREDENTIAL], pathPolicy: 'project-relative',
|
|
801
|
+
surfaces: { cli: true, mcpExclusion: NOT_EXPOSED_V0 },
|
|
802
|
+
},
|
|
803
|
+
{
|
|
804
|
+
// Reversible although destructive: the answer carries previousBookmark, and restoring to it
|
|
805
|
+
// brings back everything this restore discarded.
|
|
806
|
+
id: 'db.restore', command: ['db', 'restore'],
|
|
807
|
+
summary: 'Restore a deployed application database to a bookmark or a time.',
|
|
808
|
+
description: 'Replaces the whole database in --environment with its state at the bookmark or ISO time '
|
|
809
|
+
+ '(with a zone) given to --to. Every later write is discarded, including the owner writes; uploaded '
|
|
810
|
+
+ 'media, code and sessions are not touched. The previousBookmark in the result undoes the restore.',
|
|
811
|
+
usage: ['db restore [directory] --remote --environment <prod|preview> --to <bookmark|time> [--control-url <url>] [--json]'],
|
|
812
|
+
helpOrder: 346, outputProtocol: 'xeer.command.v0', effects: ['network-write', 'write-state'], idempotent: false,
|
|
813
|
+
reversible: true, destructive: true, humanPrerequisites: [BUILDER_CREDENTIAL], pathPolicy: 'project-relative',
|
|
814
|
+
surfaces: { cli: true, mcpExclusion: DESTRUCTIVE_STATE },
|
|
815
|
+
},
|
|
768
816
|
];
|
|
769
817
|
export const XEER_ACTIONS = Object.freeze(actions);
|
|
770
818
|
export function actionDefinition(id) {
|
package/vendor/spec/admin-sql.js
CHANGED
|
@@ -24,8 +24,13 @@
|
|
|
24
24
|
* change enforcement at all.
|
|
25
25
|
*/
|
|
26
26
|
import { ADMIN_PROTOCOL } from './admin.js';
|
|
27
|
-
/**
|
|
28
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Statements that only read. A strict allowlist of leading verbs: `WITH` and `EXPLAIN` are not here
|
|
29
|
+
* because the verb after them decides what they do — `WITH x AS (SELECT 1) UPDATE posts …` writes
|
|
30
|
+
* without `--write`, and `EXPLAIN PRAGMA ignore_check_constraints=ON` sets the pragma while the
|
|
31
|
+
* statement is prepared.
|
|
32
|
+
*/
|
|
33
|
+
const READ_VERBS = new Set(['SELECT', 'VALUES']);
|
|
29
34
|
const WRITE_VERBS = new Set(['INSERT', 'UPDATE', 'DELETE', 'REPLACE']);
|
|
30
35
|
/**
|
|
31
36
|
* Pragmas that only report. An allowlist rather than a denylist, because the case that must never
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* undocumented and a retired code cannot linger here.
|
|
14
14
|
*/
|
|
15
15
|
/** Where an agent observes a code, in the vocabulary of the CLI commands. */
|
|
16
|
-
export type DiagnosticSurface = 'any' | 'check' | 'build' | 'dev' | 'preview' | 'test' | 'new' | 'init' | 'agent' | 'doctor' | 'inspect' | 'state' | 'auth' | 'deploy' | 'deployments' | 'promote' | 'rollback' | 'disable' | 'enable' | 'delete' | 'link' | 'env' | 'token' | 'domains' | 'export' | 'import' | 'db';
|
|
16
|
+
export type DiagnosticSurface = 'any' | 'check' | 'build' | 'dev' | 'preview' | 'test' | 'new' | 'init' | 'agent' | 'doctor' | 'inspect' | 'state' | 'auth' | 'deploy' | 'deployments' | 'promote' | 'rollback' | 'disable' | 'enable' | 'delete' | 'link' | 'env' | 'bootstrap' | 'token' | 'domains' | 'export' | 'import' | 'db';
|
|
17
17
|
export interface DiagnosticFamily {
|
|
18
18
|
/** Numeric prefix the family owns, as it appears in a code. */
|
|
19
19
|
readonly prefix: string;
|
|
@@ -357,6 +357,12 @@ export const DIAGNOSTIC_DEFINITIONS = [
|
|
|
357
357
|
define('XE1841', 'The running server published no admin session secret, so its database surface is '
|
|
358
358
|
+ 'not reachable. The secret is minted per run and shared through the state lease.', 'Restart the server with a build that publishes one; a server older than this CLI does not.', ['db']),
|
|
359
359
|
define('XE1842', 'The server answered the database request with a protocol this CLI does not know.', 'The CLI and the running server are different versions. Restart the server from this checkout.', ['db']),
|
|
360
|
+
define('XE1843', 'The control plane refused, or did not complete, a `xeer db --remote` request.', 'Read `message` and `hint`: they carry the refusal verbatim. `sql_error` means the whole batch was '
|
|
361
|
+
+ 'rolled back; an unknown outcome means it may have been applied, so read before running writes again.', ['db']),
|
|
362
|
+
define('XE1844', 'The control plane returned a database response the CLI will not trust.', 'Retry the read; if it persists the control plane and CLI versions are incompatible.', ['db']),
|
|
363
|
+
define('XE1845', 'A `xeer db --remote` invocation is wrong: no --remote, no --environment, a --state '
|
|
364
|
+
+ 'alongside it, an unreadable --file, a bad --to, or no linked application.', 'Pass --remote --environment prod|preview in the project directory. A --file batch is a JSON array '
|
|
365
|
+
+ 'of {"sql","params"}; --to takes a bookmark or an ISO time with a zone.', ['db']),
|
|
360
366
|
define('XE1821', 'The export file could not be read or written.', 'Read `message`: usually a missing path or permissions. `--out` creates parent directories.', ['export', 'import']),
|
|
361
367
|
define('XE1822', 'The document is not a usable xeer.state-export.v0 export: wrong protocol, or it '
|
|
362
368
|
+ 'contradicts itself (counts, schema, or an encoded value).', 'Import the unmodified file `xeer export --out` produced. `detail.code` names the exact defect.', ['export', 'import']),
|
|
@@ -404,15 +410,16 @@ export const DIAGNOSTIC_DEFINITIONS = [
|
|
|
404
410
|
+ 'fix: wait out the advertised retry and read again. '
|
|
405
411
|
+ "Quote `detail.errorId` when correlating with the Worker's console output.", ['inspect', 'state', 'export']),
|
|
406
412
|
define('XE3001', 'xeer new could not scaffold the project — most often a non-empty target directory.', 'Choose an empty or non-existent directory.', ['new']),
|
|
407
|
-
define('XE3002', '`--template` named neither a bundled starter nor an exact id in the reachable catalog.', 'Check the exact catalog id, use a bundled
|
|
408
|
-
+ '
|
|
413
|
+
define('XE3002', '`--template` named neither a bundled starter nor an exact id in the reachable catalog.', 'Check the exact catalog id, use a bundled name (notes, todo, blog, personal-site, or the emdash '
|
|
414
|
+
+ 'framework template), or omit --template for the default. A plain framework scaffold is '
|
|
415
|
+
+ 'selected with `--framework`.', ['new']),
|
|
409
416
|
define('XE3003', '`--ui` named a UI provider that does not exist. Refused before the target '
|
|
410
417
|
+ 'directory is read, so nothing was written.', 'Use preact or react, or omit --ui for the default (preact). The choice is orthogonal to '
|
|
411
418
|
+ '--template for every Xeer application template: each scaffolds on either provider from the '
|
|
412
419
|
+ 'same client sources.', ['new']),
|
|
413
420
|
define('XE3004', '`--ui` was passed with `--framework`, and a framework renders through its own '
|
|
414
421
|
+ 'toolchain rather than through a Xeer UI provider. Refused before the target directory is '
|
|
415
|
-
+ 'read, so nothing was written.', 'Drop --ui.
|
|
422
|
+
+ 'read, so nothing was written.', 'Drop --ui. A framework project owns its renderer: it writes no client.runtime.provider to '
|
|
416
423
|
+ 'select, and no value of --ui would change a file it writes.', ['new']),
|
|
417
424
|
define('XE3005', '`--template` and `--framework` were passed together. They are two exclusive '
|
|
418
425
|
+ 'axes: one writes a Xeer application, the other a project Xeer runs rather than compiles. '
|
|
@@ -427,7 +434,8 @@ export const DIAGNOSTIC_DEFINITIONS = [
|
|
|
427
434
|
define('XE3010', 'The downloaded template archive does not match the catalog SHA-256.', 'Do not use the bytes. Repeat later or report the template artifact.', ['new']),
|
|
428
435
|
define('XE3011', 'The downloaded template archive contains unsafe or unsupported content.', 'Report the template artifact and choose another template.', ['new']),
|
|
429
436
|
define('XE3012', 'The extracted project root does not match the project metadata declared by the catalog.', 'Report the template artifact and choose another template.', ['new']),
|
|
430
|
-
define('XE3013', '`--ui` was passed with a
|
|
437
|
+
define('XE3013', '`--ui` was passed with a template that owns its renderer: a catalog template, or the '
|
|
438
|
+
+ 'bundled emdash framework template. Refused before the target directory is read, so nothing was written.', 'Drop --ui and create the template unchanged.', ['new']),
|
|
431
439
|
define('XE3101', 'Agent setup check found one or more generated files missing or stale. No files were written.', 'Run `xeer agent setup`, then repeat `xeer agent setup --check --json`.', ['agent']),
|
|
432
440
|
define('XE3102', 'Agent setup found a path owned by the user or another tool. The entire write was refused.', 'Move, rename, or deliberately remove the conflicting path; setup never overwrites an unowned file.', ['agent']),
|
|
433
441
|
define('XE3103', '`--target` named an agent adapter that Xeer does not support.', 'Use auto, agents, claude, codex, cursor, vscode, or mcp.', ['agent']),
|
|
@@ -509,6 +517,11 @@ export const DIAGNOSTIC_DEFINITIONS = [
|
|
|
509
517
|
+ 'entries have names or values a local run cannot load — so `ctx.env` is missing them.', 'Read `message`: it names the file and the exact problem — the shape to write is '
|
|
510
518
|
+ '{"format": "xeer.env-local.v0", "values": {"NAME": "value"}} with UPPER_SNAKE_CASE names '
|
|
511
519
|
+ 'and string values. `xeer env pull` writes the file correctly.', ['dev', 'preview', 'test']),
|
|
520
|
+
define('XE5135', 'xeer bootstrap could not confirm EmDash setup readiness within its fixed 240-second wait: '
|
|
521
|
+
+ 'the deployed site never answered `GET /_emdash/api/setup/status` with a ready response. A fresh '
|
|
522
|
+
+ 'database can take several minutes to run its migrations; no probe has a shorter deadline than what remains of that budget.', 'Wait for the site to finish initializing, then run the `retry` command from the result. The result '
|
|
523
|
+
+ 'carries `readiness: "pending"` and `retryable: true`; no setup URL was returned, and a retry obtains a '
|
|
524
|
+
+ 'fresh grant. Do not release a migration lock while initialization is still running.', ['bootstrap']),
|
|
512
525
|
define('XE5139', 'xeer env failed without a more specific code.', 'Read `message`; it is the underlying error verbatim.', ['env']),
|
|
513
526
|
define('XE5140', 'An `xeer deployments` invocation is wrong: an unusable --limit, or a directory that '
|
|
514
527
|
+ 'declares no app identity.', 'Read `message`. --limit takes a positive integer up to 200. In a directory with no appId, run '
|
|
@@ -1,18 +1,53 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export declare const FRAMEWORK_CONFIG_SCHEMA_URL: "https://docs.xeer.run/config-v0.schema.json";
|
|
3
3
|
export declare const FRAMEWORK_CONFIG_FORMAT: "xeer.config.v0";
|
|
4
|
+
/**
|
|
5
|
+
* What an EmDash deployment must bind. EmDash's own adapters fix the D1 and R2 binding names, its
|
|
6
|
+
* sign-in needs Astro's session KV, and its scheduled publishing needs the platform's one supported
|
|
7
|
+
* schedule. Stated once here so the config, the build, and the control plane refuse the same shape.
|
|
8
|
+
*/
|
|
9
|
+
export declare const EMDASH_DEPLOYMENT: Readonly<{
|
|
10
|
+
readonly framework: "astro";
|
|
11
|
+
readonly database: "DB";
|
|
12
|
+
readonly storage: "MEDIA";
|
|
13
|
+
readonly schedule: "* * * * *";
|
|
14
|
+
}>;
|
|
4
15
|
declare const frameworkConfigSchema: z.ZodObject<{
|
|
5
16
|
$schema: z.ZodOptional<z.ZodString>;
|
|
6
17
|
format: z.ZodLiteral<"xeer.config.v0">;
|
|
7
18
|
name: z.ZodString;
|
|
8
19
|
framework: z.ZodEnum<{
|
|
20
|
+
astro: "astro";
|
|
9
21
|
sveltekit: "sveltekit";
|
|
10
22
|
}>;
|
|
23
|
+
integration: z.ZodOptional<z.ZodEnum<{
|
|
24
|
+
emdash: "emdash";
|
|
25
|
+
}>>;
|
|
11
26
|
capabilities: z.ZodObject<{
|
|
12
27
|
auth: z.ZodOptional<z.ZodObject<{}, z.core.$strict>>;
|
|
28
|
+
database: z.ZodOptional<z.ZodObject<{}, z.core.$strict>>;
|
|
29
|
+
storage: z.ZodOptional<z.ZodObject<{}, z.core.$strict>>;
|
|
13
30
|
}, z.core.$strict>;
|
|
14
31
|
}, z.core.$strict>;
|
|
15
32
|
export type FrameworkConfigV0 = z.infer<typeof frameworkConfigSchema>;
|
|
16
33
|
export declare const frameworkConfigJsonSchema: Readonly<Record<string, unknown>>;
|
|
17
34
|
export declare function parseFrameworkConfig(value: unknown): FrameworkConfigV0;
|
|
35
|
+
declare const frameworkDeploymentSchema: z.ZodObject<{
|
|
36
|
+
framework: z.ZodOptional<z.ZodEnum<{
|
|
37
|
+
astro: "astro";
|
|
38
|
+
sveltekit: "sveltekit";
|
|
39
|
+
}>>;
|
|
40
|
+
integration: z.ZodOptional<z.ZodEnum<{
|
|
41
|
+
emdash: "emdash";
|
|
42
|
+
}>>;
|
|
43
|
+
bindings: z.ZodOptional<z.ZodObject<{
|
|
44
|
+
database: z.ZodOptional<z.ZodString>;
|
|
45
|
+
storage: z.ZodOptional<z.ZodString>;
|
|
46
|
+
session: z.ZodOptional<z.ZodString>;
|
|
47
|
+
}, z.core.$strict>>;
|
|
48
|
+
schedule: z.ZodOptional<z.ZodLiteral<"* * * * *">>;
|
|
49
|
+
}, z.core.$strip>;
|
|
50
|
+
export type FrameworkDeployment = z.infer<typeof frameworkDeploymentSchema>;
|
|
51
|
+
export type FrameworkBindings = NonNullable<FrameworkDeployment['bindings']>;
|
|
52
|
+
export declare function parseFrameworkDeployment(value: unknown): FrameworkDeployment;
|
|
18
53
|
export {};
|
|
@@ -1,16 +1,37 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { FRAMEWORK_NAMES } from './scaffold-names.js';
|
|
2
|
+
import { FRAMEWORK_NAMES, INTEGRATION_NAMES } from './scaffold-names.js';
|
|
3
3
|
export const FRAMEWORK_CONFIG_SCHEMA_URL = 'https://docs.xeer.run/config-v0.schema.json';
|
|
4
4
|
export const FRAMEWORK_CONFIG_FORMAT = 'xeer.config.v0';
|
|
5
|
+
/**
|
|
6
|
+
* What an EmDash deployment must bind. EmDash's own adapters fix the D1 and R2 binding names, its
|
|
7
|
+
* sign-in needs Astro's session KV, and its scheduled publishing needs the platform's one supported
|
|
8
|
+
* schedule. Stated once here so the config, the build, and the control plane refuse the same shape.
|
|
9
|
+
*/
|
|
10
|
+
export const EMDASH_DEPLOYMENT = Object.freeze({
|
|
11
|
+
framework: 'astro', database: 'DB', storage: 'MEDIA', schedule: '* * * * *',
|
|
12
|
+
});
|
|
13
|
+
function requireIntegrationFramework(value, context) {
|
|
14
|
+
if (value.integration === 'emdash' && value.framework !== 'astro') {
|
|
15
|
+
context.addIssue({ code: 'custom', message: 'The emdash integration requires the astro framework.' });
|
|
16
|
+
}
|
|
17
|
+
}
|
|
5
18
|
const frameworkConfigSchema = z.object({
|
|
6
19
|
$schema: z.string().url().optional(),
|
|
7
20
|
format: z.literal(FRAMEWORK_CONFIG_FORMAT),
|
|
8
21
|
name: z.string().regex(/^[a-z][a-z0-9-]{0,61}[a-z0-9]$/u),
|
|
9
22
|
framework: z.enum(FRAMEWORK_NAMES),
|
|
23
|
+
integration: z.enum(INTEGRATION_NAMES).optional(),
|
|
10
24
|
capabilities: z.object({
|
|
11
25
|
auth: z.object({}).strict().optional(),
|
|
26
|
+
database: z.object({}).strict().optional(),
|
|
27
|
+
storage: z.object({}).strict().optional(),
|
|
12
28
|
}).strict(),
|
|
13
|
-
}).strict()
|
|
29
|
+
}).strict().superRefine((value, context) => {
|
|
30
|
+
requireIntegrationFramework(value, context);
|
|
31
|
+
if (value.integration === 'emdash' && (!value.capabilities.database || !value.capabilities.storage)) {
|
|
32
|
+
context.addIssue({ code: 'custom', message: 'The emdash integration requires database and storage capabilities.' });
|
|
33
|
+
}
|
|
34
|
+
});
|
|
14
35
|
export const frameworkConfigJsonSchema = Object.freeze({
|
|
15
36
|
...z.toJSONSchema(frameworkConfigSchema),
|
|
16
37
|
$id: FRAMEWORK_CONFIG_SCHEMA_URL,
|
|
@@ -20,3 +41,29 @@ export const frameworkConfigJsonSchema = Object.freeze({
|
|
|
20
41
|
export function parseFrameworkConfig(value) {
|
|
21
42
|
return frameworkConfigSchema.parse(value);
|
|
22
43
|
}
|
|
44
|
+
const bindingName = z.string().regex(/^[A-Za-z_][A-Za-z0-9_]{0,62}$/u)
|
|
45
|
+
.refine((name) => !name.startsWith('XEER_') && !['ASSETS', 'XeerState'].includes(name), 'Binding names must not shadow platform bindings.');
|
|
46
|
+
const frameworkDeploymentSchema = z.object({
|
|
47
|
+
framework: z.enum(FRAMEWORK_NAMES).optional(),
|
|
48
|
+
integration: z.enum(INTEGRATION_NAMES).optional(),
|
|
49
|
+
bindings: z.object({ database: bindingName.optional(), storage: bindingName.optional(),
|
|
50
|
+
session: bindingName.optional() }).strict().optional(),
|
|
51
|
+
schedule: z.literal('* * * * *').optional(),
|
|
52
|
+
}).superRefine((value, context) => {
|
|
53
|
+
const names = Object.values(value.bindings ?? {});
|
|
54
|
+
if (new Set(names).size !== names.length)
|
|
55
|
+
context.addIssue({ code: 'custom', message: 'Binding names must be distinct.' });
|
|
56
|
+
if ((value.bindings !== undefined || value.schedule !== undefined) && value.framework !== 'astro') {
|
|
57
|
+
context.addIssue({ code: 'custom', message: 'Declared bindings and schedules require an Astro framework bundle.' });
|
|
58
|
+
}
|
|
59
|
+
requireIntegrationFramework(value, context);
|
|
60
|
+
if (value.integration === 'emdash' && (value.bindings?.database !== EMDASH_DEPLOYMENT.database
|
|
61
|
+
|| value.bindings.storage !== EMDASH_DEPLOYMENT.storage || value.bindings.session === undefined
|
|
62
|
+
|| value.schedule !== EMDASH_DEPLOYMENT.schedule)) {
|
|
63
|
+
context.addIssue({ code: 'custom', message: 'The emdash integration requires the DB database binding, the '
|
|
64
|
+
+ 'MEDIA storage binding, a session binding, and the * * * * * schedule.' });
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
export function parseFrameworkDeployment(value) {
|
|
68
|
+
return frameworkDeploymentSchema.parse(value);
|
|
69
|
+
}
|
package/vendor/spec/index.d.ts
CHANGED
package/vendor/spec/index.js
CHANGED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** Fixed by the endpoint, never selected by an incoming grant. */
|
|
2
|
+
export declare const PLATFORM_GRANTS: Readonly<{
|
|
3
|
+
inspector: Readonly<{
|
|
4
|
+
audience: "xeer-inspector";
|
|
5
|
+
maxTtlSeconds: 60;
|
|
6
|
+
}>;
|
|
7
|
+
scheduler: Readonly<{
|
|
8
|
+
audience: "xeer-scheduler";
|
|
9
|
+
maxTtlSeconds: 60;
|
|
10
|
+
}>;
|
|
11
|
+
bootstrap: Readonly<{
|
|
12
|
+
audience: "xeer-bootstrap";
|
|
13
|
+
maxTtlSeconds: 1800;
|
|
14
|
+
}>;
|
|
15
|
+
}>;
|
|
16
|
+
export type PlatformGrantScope = keyof typeof PLATFORM_GRANTS;
|
|
17
|
+
export type PlatformGrantEnvironment = 'production' | 'preview';
|
|
18
|
+
/** Includes cold framework migrations; four batches remain below a cron event's 15-minute lifetime. */
|
|
19
|
+
export declare const PLATFORM_SCHEDULE: Readonly<{
|
|
20
|
+
invocationDeadlineMs: 180000;
|
|
21
|
+
dispatchTimeoutMs: 185000;
|
|
22
|
+
leaseMs: 210000;
|
|
23
|
+
maxApplications: 20;
|
|
24
|
+
concurrency: 5;
|
|
25
|
+
}>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Fixed by the endpoint, never selected by an incoming grant. */
|
|
2
|
+
export const PLATFORM_GRANTS = Object.freeze({
|
|
3
|
+
inspector: Object.freeze({ audience: 'xeer-inspector', maxTtlSeconds: 60 }),
|
|
4
|
+
scheduler: Object.freeze({ audience: 'xeer-scheduler', maxTtlSeconds: 60 }),
|
|
5
|
+
bootstrap: Object.freeze({ audience: 'xeer-bootstrap', maxTtlSeconds: 1800 }),
|
|
6
|
+
});
|
|
7
|
+
/** Includes cold framework migrations; four batches remain below a cron event's 15-minute lifetime. */
|
|
8
|
+
export const PLATFORM_SCHEDULE = Object.freeze({
|
|
9
|
+
invocationDeadlineMs: 180_000,
|
|
10
|
+
dispatchTimeoutMs: 185_000,
|
|
11
|
+
leaseMs: 210_000,
|
|
12
|
+
maxApplications: 20,
|
|
13
|
+
concurrency: 5,
|
|
14
|
+
});
|
package/vendor/spec/route.js
CHANGED
|
@@ -13,6 +13,19 @@
|
|
|
13
13
|
*/
|
|
14
14
|
export declare const BUNDLED_TEMPLATES: readonly ["notes", "todo", "blog", "personal-site"];
|
|
15
15
|
export type BundledTemplateName = (typeof BUNDLED_TEMPLATES)[number];
|
|
16
|
+
/**
|
|
17
|
+
* The bundled framework templates: a complete framework project, written offline like the
|
|
18
|
+
* application starters above, but holding `xeer.config.json` and declaring which framework runs it.
|
|
19
|
+
*
|
|
20
|
+
* A template rather than a framework name because EmDash is an Astro application, not another
|
|
21
|
+
* runtime: `--template emdash` writes an Astro project whose config declares `framework: "astro"`
|
|
22
|
+
* and `integration: "emdash"`. Kept apart from {@link BUNDLED_TEMPLATES} because the two write
|
|
23
|
+
* different root contracts, and every application-only consumer of that list must stay narrow.
|
|
24
|
+
*/
|
|
25
|
+
export declare const BUNDLED_FRAMEWORK_TEMPLATES: Readonly<{
|
|
26
|
+
readonly emdash: "astro";
|
|
27
|
+
}>;
|
|
28
|
+
export type BundledFrameworkTemplateName = keyof typeof BUNDLED_FRAMEWORK_TEMPLATES;
|
|
16
29
|
/**
|
|
17
30
|
* The frameworks Xeer runs rather than compiles: a `xeer.config.json` beside a project whose own
|
|
18
31
|
* toolchain owns the renderer, the routes, and the build.
|
|
@@ -21,5 +34,14 @@ export type BundledTemplateName = (typeof BUNDLED_TEMPLATES)[number];
|
|
|
21
34
|
* and every later command dispatches on which one is present. `--framework` selects one for a fresh
|
|
22
35
|
* project; `xeer init` adopts an existing one; `xeer.config.json` declares which one a directory is.
|
|
23
36
|
*/
|
|
24
|
-
export declare const FRAMEWORK_NAMES: readonly ["sveltekit"];
|
|
37
|
+
export declare const FRAMEWORK_NAMES: readonly ["sveltekit", "astro"];
|
|
25
38
|
export type FrameworkName = (typeof FRAMEWORK_NAMES)[number];
|
|
39
|
+
export declare const SCAFFOLDABLE_FRAMEWORK_NAMES: readonly ["sveltekit", "astro"];
|
|
40
|
+
export type ScaffoldableFrameworkName = (typeof SCAFFOLDABLE_FRAMEWORK_NAMES)[number];
|
|
41
|
+
/**
|
|
42
|
+
* The integrations a framework project may declare on top of its framework. One today: EmDash, an
|
|
43
|
+
* Astro CMS whose deployment needs a fixed binding set and a computed site URL. Declared explicitly
|
|
44
|
+
* in `xeer.config.json`, never inferred from packages, routes, or resource names.
|
|
45
|
+
*/
|
|
46
|
+
export declare const INTEGRATION_NAMES: readonly ["emdash"];
|
|
47
|
+
export type IntegrationName = (typeof INTEGRATION_NAMES)[number];
|
|
@@ -12,6 +12,16 @@
|
|
|
12
12
|
* it names. Offline, deterministic, and resolved before any catalog request.
|
|
13
13
|
*/
|
|
14
14
|
export const BUNDLED_TEMPLATES = Object.freeze(['notes', 'todo', 'blog', 'personal-site']);
|
|
15
|
+
/**
|
|
16
|
+
* The bundled framework templates: a complete framework project, written offline like the
|
|
17
|
+
* application starters above, but holding `xeer.config.json` and declaring which framework runs it.
|
|
18
|
+
*
|
|
19
|
+
* A template rather than a framework name because EmDash is an Astro application, not another
|
|
20
|
+
* runtime: `--template emdash` writes an Astro project whose config declares `framework: "astro"`
|
|
21
|
+
* and `integration: "emdash"`. Kept apart from {@link BUNDLED_TEMPLATES} because the two write
|
|
22
|
+
* different root contracts, and every application-only consumer of that list must stay narrow.
|
|
23
|
+
*/
|
|
24
|
+
export const BUNDLED_FRAMEWORK_TEMPLATES = Object.freeze({ emdash: 'astro' });
|
|
15
25
|
/**
|
|
16
26
|
* The frameworks Xeer runs rather than compiles: a `xeer.config.json` beside a project whose own
|
|
17
27
|
* toolchain owns the renderer, the routes, and the build.
|
|
@@ -20,4 +30,11 @@ export const BUNDLED_TEMPLATES = Object.freeze(['notes', 'todo', 'blog', 'person
|
|
|
20
30
|
* and every later command dispatches on which one is present. `--framework` selects one for a fresh
|
|
21
31
|
* project; `xeer init` adopts an existing one; `xeer.config.json` declares which one a directory is.
|
|
22
32
|
*/
|
|
23
|
-
export const FRAMEWORK_NAMES = Object.freeze(['sveltekit']);
|
|
33
|
+
export const FRAMEWORK_NAMES = Object.freeze(['sveltekit', 'astro']);
|
|
34
|
+
export const SCAFFOLDABLE_FRAMEWORK_NAMES = Object.freeze(['sveltekit', 'astro']);
|
|
35
|
+
/**
|
|
36
|
+
* The integrations a framework project may declare on top of its framework. One today: EmDash, an
|
|
37
|
+
* Astro CMS whose deployment needs a fixed binding set and a computed site URL. Declared explicitly
|
|
38
|
+
* in `xeer.config.json`, never inferred from packages, routes, or resource names.
|
|
39
|
+
*/
|
|
40
|
+
export const INTEGRATION_NAMES = Object.freeze(['emdash']);
|
|
@@ -34,6 +34,15 @@ export declare const templateDistributionEntrySchema: z.ZodObject<{
|
|
|
34
34
|
url: z.ZodString;
|
|
35
35
|
sha256: z.ZodString;
|
|
36
36
|
}, z.core.$strict>;
|
|
37
|
+
admin: z.ZodOptional<z.ZodObject<{
|
|
38
|
+
path: z.ZodString;
|
|
39
|
+
signIn: z.ZodEnum<{
|
|
40
|
+
code: "code";
|
|
41
|
+
owner: "owner";
|
|
42
|
+
}>;
|
|
43
|
+
codeSecret: z.ZodOptional<z.ZodString>;
|
|
44
|
+
tasks: z.ZodString;
|
|
45
|
+
}, z.core.$strict>>;
|
|
37
46
|
author: z.ZodObject<{
|
|
38
47
|
name: z.ZodString;
|
|
39
48
|
url: z.ZodOptional<z.ZodString>;
|
|
@@ -63,8 +72,12 @@ export declare const templateDistributionEntrySchema: z.ZodObject<{
|
|
|
63
72
|
"xeer-application": "xeer-application";
|
|
64
73
|
}>;
|
|
65
74
|
framework: z.ZodOptional<z.ZodEnum<{
|
|
75
|
+
astro: "astro";
|
|
66
76
|
sveltekit: "sveltekit";
|
|
67
77
|
}>>;
|
|
78
|
+
integration: z.ZodOptional<z.ZodEnum<{
|
|
79
|
+
emdash: "emdash";
|
|
80
|
+
}>>;
|
|
68
81
|
}, z.core.$strict>>;
|
|
69
82
|
}, z.core.$strict>;
|
|
70
83
|
export type TemplateDistributionEntryV0 = z.infer<typeof templateDistributionEntrySchema>;
|
|
@@ -86,6 +99,15 @@ export declare const templateDistributionCatalogSchema: z.ZodObject<{
|
|
|
86
99
|
url: z.ZodString;
|
|
87
100
|
sha256: z.ZodString;
|
|
88
101
|
}, z.core.$strict>;
|
|
102
|
+
admin: z.ZodOptional<z.ZodObject<{
|
|
103
|
+
path: z.ZodString;
|
|
104
|
+
signIn: z.ZodEnum<{
|
|
105
|
+
code: "code";
|
|
106
|
+
owner: "owner";
|
|
107
|
+
}>;
|
|
108
|
+
codeSecret: z.ZodOptional<z.ZodString>;
|
|
109
|
+
tasks: z.ZodString;
|
|
110
|
+
}, z.core.$strict>>;
|
|
89
111
|
author: z.ZodObject<{
|
|
90
112
|
name: z.ZodString;
|
|
91
113
|
url: z.ZodOptional<z.ZodString>;
|
|
@@ -115,8 +137,12 @@ export declare const templateDistributionCatalogSchema: z.ZodObject<{
|
|
|
115
137
|
"xeer-application": "xeer-application";
|
|
116
138
|
}>;
|
|
117
139
|
framework: z.ZodOptional<z.ZodEnum<{
|
|
140
|
+
astro: "astro";
|
|
118
141
|
sveltekit: "sveltekit";
|
|
119
142
|
}>>;
|
|
143
|
+
integration: z.ZodOptional<z.ZodEnum<{
|
|
144
|
+
emdash: "emdash";
|
|
145
|
+
}>>;
|
|
120
146
|
}, z.core.$strict>>;
|
|
121
147
|
}, z.core.$strict>>;
|
|
122
148
|
}, z.core.$strict>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { FRAMEWORK_NAMES } from './scaffold-names.js';
|
|
3
|
-
import { checkTemplateMetadataUniqueness, templateAltTextSchema, templateIdentityShape, templateMetadataShape, templateSlugSchema, } from './template.js';
|
|
2
|
+
import { FRAMEWORK_NAMES, INTEGRATION_NAMES } from './scaffold-names.js';
|
|
3
|
+
import { checkTemplateMetadataUniqueness, templateAdminPathSchema, templateAdminTasksSchema, templateAltTextSchema, templateIdentityShape, templateMetadataShape, templateSlugSchema, } from './template.js';
|
|
4
4
|
export const TEMPLATE_DISTRIBUTION_CATALOG_FORMAT = 'xeer.template-distribution-catalog.v0';
|
|
5
5
|
export const TEMPLATE_DISTRIBUTION_CATALOG_SCHEMA_URL = 'https://docs.xeer.run/template-distribution-catalog-v0.schema.json';
|
|
6
6
|
/** Exact semantic version: no range operator, no `v` prefix, no wildcard. */
|
|
@@ -40,7 +40,12 @@ export const TEMPLATE_PROJECT_KINDS = ['xeer-application', 'framework'];
|
|
|
40
40
|
const templateProjectSchema = z.strictObject({
|
|
41
41
|
kind: z.enum(TEMPLATE_PROJECT_KINDS),
|
|
42
42
|
framework: z.enum(FRAMEWORK_NAMES).optional(),
|
|
43
|
+
/** Copied from the framework configuration; EmDash is the only integration, and it runs on Astro. */
|
|
44
|
+
integration: z.enum(INTEGRATION_NAMES).optional(),
|
|
43
45
|
}).superRefine((project, ctx) => {
|
|
46
|
+
if (project.integration === 'emdash' && project.framework !== 'astro') {
|
|
47
|
+
ctx.addIssue({ code: 'custom', path: ['integration'], message: 'the emdash integration runs on the astro framework' });
|
|
48
|
+
}
|
|
44
49
|
if ((project.framework !== undefined) === (project.kind === 'framework'))
|
|
45
50
|
return;
|
|
46
51
|
ctx.addIssue({
|
|
@@ -51,6 +56,17 @@ const templateProjectSchema = z.strictObject({
|
|
|
51
56
|
: `only a framework project names a framework; a ${project.kind} project does not`,
|
|
52
57
|
});
|
|
53
58
|
});
|
|
59
|
+
/**
|
|
60
|
+
* The Site admin an entry resolves to: an owner dashboard unlocked by one of the entry's invite codes
|
|
61
|
+
* (`code`), or EmDash's admin, which the owner opens through the platform's owner sign-in (`owner`).
|
|
62
|
+
* Authored in `template.json` for the first, derived from the EmDash integration for the second.
|
|
63
|
+
*/
|
|
64
|
+
const distributedAdminSchema = z.strictObject({
|
|
65
|
+
path: templateAdminPathSchema,
|
|
66
|
+
signIn: z.enum(['code', 'owner']),
|
|
67
|
+
codeSecret: z.string().optional(),
|
|
68
|
+
tasks: templateAdminTasksSchema,
|
|
69
|
+
});
|
|
54
70
|
/**
|
|
55
71
|
* One published template. The authored metadata is copied verbatim from `template.json`; everything
|
|
56
72
|
* else is produced by the release job that packed, deployed, and verified this exact artifact.
|
|
@@ -77,7 +93,29 @@ export const templateDistributionEntrySchema = z.strictObject({
|
|
|
77
93
|
/** Release version of the template artifact itself, independent of the platform version. */
|
|
78
94
|
artifactVersion: exactVersion,
|
|
79
95
|
sourceArchive: sourceArchiveSchema,
|
|
80
|
-
|
|
96
|
+
/** Absent for a template without an admin, and on every entry published before the field existed. */
|
|
97
|
+
admin: distributedAdminSchema.optional(),
|
|
98
|
+
}).superRefine((entry, ctx) => {
|
|
99
|
+
checkTemplateMetadataUniqueness(entry, ctx);
|
|
100
|
+
const { admin } = entry;
|
|
101
|
+
const emdash = entry.project?.integration === 'emdash';
|
|
102
|
+
if (emdash && admin?.signIn !== 'owner') {
|
|
103
|
+
ctx.addIssue({ code: 'custom', path: ['admin'], message: 'an emdash project carries the owner admin' });
|
|
104
|
+
}
|
|
105
|
+
if (!admin)
|
|
106
|
+
return;
|
|
107
|
+
if (admin.signIn === 'owner' && !emdash) {
|
|
108
|
+
ctx.addIssue({ code: 'custom', path: ['admin', 'signIn'], message: 'the owner sign-in belongs to an emdash project' });
|
|
109
|
+
}
|
|
110
|
+
if ((admin.codeSecret !== undefined) !== (admin.signIn === 'code')) {
|
|
111
|
+
ctx.addIssue({ code: 'custom', path: ['admin', 'codeSecret'],
|
|
112
|
+
message: 'a code admin names its codeSecret, and only a code admin does' });
|
|
113
|
+
}
|
|
114
|
+
else if (admin.codeSecret !== undefined && !entry.requiredSecrets.some((secret) => secret.name === admin.codeSecret)) {
|
|
115
|
+
ctx.addIssue({ code: 'custom', path: ['admin', 'codeSecret'],
|
|
116
|
+
message: 'admin codeSecret must name one of the entry requiredSecrets' });
|
|
117
|
+
}
|
|
118
|
+
});
|
|
81
119
|
/**
|
|
82
120
|
* Versioned distribution catalog published atomically after a platform release. Entries are keyed by
|
|
83
121
|
* template id, sorted by codepoint so a regenerated catalog is byte-stable, and a template with no
|
|
@@ -3,6 +3,13 @@ export declare const TEMPLATE_FORMAT: "xeer.template.v0";
|
|
|
3
3
|
export declare const TEMPLATE_MANIFEST_SCHEMA_URL: "https://docs.xeer.run/template-v0.schema.json";
|
|
4
4
|
/** Catalog identifier shape shared by template directory names and categories. */
|
|
5
5
|
export declare const templateSlugSchema: z.ZodString;
|
|
6
|
+
/**
|
|
7
|
+
* Where a template's own admin lives, relative to the site's origin: one absolute path, nothing that
|
|
8
|
+
* could leave the origin (`//host`) or carry a query or fragment.
|
|
9
|
+
*/
|
|
10
|
+
export declare const templateAdminPathSchema: z.ZodString;
|
|
11
|
+
/** What the owner does in the admin, shown next to its button: one short sentence. */
|
|
12
|
+
export declare const templateAdminTasksSchema: z.ZodString;
|
|
6
13
|
/** Alt text carried by a gallery image in either the source or the distribution catalog. */
|
|
7
14
|
export declare const templateAltTextSchema: z.ZodString;
|
|
8
15
|
/**
|
|
@@ -50,6 +57,12 @@ export declare function checkTemplateMetadataUniqueness(metadata: {
|
|
|
50
57
|
}[];
|
|
51
58
|
}, ctx: z.RefinementCtx): void;
|
|
52
59
|
export declare const templateManifestSchema: z.ZodObject<{
|
|
60
|
+
admin: z.ZodOptional<z.ZodObject<{
|
|
61
|
+
path: z.ZodOptional<z.ZodString>;
|
|
62
|
+
signIn: z.ZodOptional<z.ZodLiteral<"code">>;
|
|
63
|
+
codeSecret: z.ZodOptional<z.ZodString>;
|
|
64
|
+
tasks: z.ZodOptional<z.ZodString>;
|
|
65
|
+
}, z.core.$strict>>;
|
|
53
66
|
author: z.ZodObject<{
|
|
54
67
|
name: z.ZodString;
|
|
55
68
|
url: z.ZodOptional<z.ZodString>;
|
package/vendor/spec/template.js
CHANGED
|
@@ -18,6 +18,27 @@ const requiredSecretSchema = z.strictObject({
|
|
|
18
18
|
name: environmentName,
|
|
19
19
|
description: trimmed(200),
|
|
20
20
|
});
|
|
21
|
+
/**
|
|
22
|
+
* Where a template's own admin lives, relative to the site's origin: one absolute path, nothing that
|
|
23
|
+
* could leave the origin (`//host`) or carry a query or fragment.
|
|
24
|
+
*/
|
|
25
|
+
export const templateAdminPathSchema = z.string().max(200)
|
|
26
|
+
.regex(/^\/(?!\/)[^\s?#\\]*$/u, 'admin path must be a plain site path starting with one "/"');
|
|
27
|
+
/** What the owner does in the admin, shown next to its button: one short sentence. */
|
|
28
|
+
export const templateAdminTasksSchema = trimmed(140)
|
|
29
|
+
.regex(/^[^.!?]*(?:[.!?](?! )[^.!?]*)*\.$/u, 'admin tasks must be one short sentence ending in a full stop');
|
|
30
|
+
/**
|
|
31
|
+
* The Site admin a template offers. An application template authors all of it: the path of its owner
|
|
32
|
+
* dashboard, and the invite code (one of its `requiredSecrets`) that unlocks it. An EmDash template's
|
|
33
|
+
* admin is derived from its integration by the catalog, so there only `tasks` may be authored; which
|
|
34
|
+
* of the two applies is known only to the catalog generator, which reads the root contract.
|
|
35
|
+
*/
|
|
36
|
+
const templateAdminSchema = z.strictObject({
|
|
37
|
+
path: templateAdminPathSchema.optional(),
|
|
38
|
+
signIn: z.literal('code').optional(),
|
|
39
|
+
codeSecret: environmentName.optional(),
|
|
40
|
+
tasks: templateAdminTasksSchema.optional(),
|
|
41
|
+
});
|
|
21
42
|
/** Alt text carried by a gallery image in either the source or the distribution catalog. */
|
|
22
43
|
export const templateAltTextSchema = trimmed(200);
|
|
23
44
|
const screenshotSchema = z.strictObject({
|
|
@@ -70,7 +91,21 @@ export const templateManifestSchema = z.strictObject({
|
|
|
70
91
|
...templateMetadataShape,
|
|
71
92
|
screenshots: z.array(screenshotSchema).min(1).max(8),
|
|
72
93
|
...templateIdentityShape,
|
|
73
|
-
|
|
94
|
+
admin: templateAdminSchema.optional(),
|
|
95
|
+
}).superRefine((manifest, ctx) => {
|
|
96
|
+
checkTemplateMetadataUniqueness(manifest, ctx);
|
|
97
|
+
const { admin } = manifest;
|
|
98
|
+
if (!admin)
|
|
99
|
+
return;
|
|
100
|
+
const code = [admin.path, admin.signIn, admin.codeSecret];
|
|
101
|
+
if (code.some((value) => value !== undefined) && code.some((value) => value === undefined)) {
|
|
102
|
+
ctx.addIssue({ code: 'custom', path: ['admin'], message: 'admin needs path, signIn, and codeSecret together' });
|
|
103
|
+
}
|
|
104
|
+
if (admin.codeSecret !== undefined && !manifest.requiredSecrets.some((secret) => secret.name === admin.codeSecret)) {
|
|
105
|
+
ctx.addIssue({ code: 'custom', path: ['admin', 'codeSecret'],
|
|
106
|
+
message: 'admin codeSecret must name one of the template requiredSecrets' });
|
|
107
|
+
}
|
|
108
|
+
});
|
|
74
109
|
const generatedTemplateManifestJsonSchema = z.toJSONSchema(templateManifestSchema);
|
|
75
110
|
const generatedProperties = generatedTemplateManifestJsonSchema.properties;
|
|
76
111
|
export const templateManifestJsonSchema = Object.freeze({
|