@impetik/xeer-mcp 0.2.18 → 0.2.20
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 +2 -2
- package/dist/server.js +4 -1
- package/package.json +2 -2
- package/vendor/spec/actions.d.ts +10 -5
- package/vendor/spec/actions.js +23 -8
- package/vendor/spec/diagnostics.js +95 -11
- package/vendor/spec/editor-settings.d.ts +26 -0
- package/vendor/spec/editor-settings.js +33 -0
- package/vendor/spec/import-policy.d.ts +168 -18
- package/vendor/spec/import-policy.js +284 -56
- package/vendor/spec/index.d.ts +2 -0
- package/vendor/spec/index.js +2 -0
- package/vendor/spec/schema.d.ts +5 -1
- package/vendor/spec/schema.js +57 -6
- package/vendor/spec/template-distribution.d.ts +101 -0
- package/vendor/spec/template-distribution.js +158 -0
- package/vendor/spec/template.d.ts +54 -6
- package/vendor/spec/template.js +34 -14
- package/vendor/spec/tunnel.d.ts +3 -0
- package/vendor/spec/tunnel.js +18 -0
- package/vendor/spec/type-check-profile.d.ts +65 -4
- package/vendor/spec/type-check-profile.js +144 -12
- package/vendor/spec/types.d.ts +49 -11
- package/vendor/spec/types.js +24 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const TEMPLATE_DISTRIBUTION_CATALOG_FORMAT: "xeer.template-distribution-catalog.v0";
|
|
3
|
+
export declare const TEMPLATE_DISTRIBUTION_CATALOG_SCHEMA_URL: "https://docs.xeer.run/template-distribution-catalog-v0.schema.json";
|
|
4
|
+
/** Exact semantic version: no range operator, no `v` prefix, no wildcard. */
|
|
5
|
+
export declare const EXACT_VERSION_PATTERN: string;
|
|
6
|
+
export declare const TEMPLATE_ARCHIVE_CHECKSUM_PATTERN: "^sha256:[a-f0-9]{64}$";
|
|
7
|
+
/**
|
|
8
|
+
* One published template. The authored metadata is copied verbatim from `template.json`; everything
|
|
9
|
+
* else is produced by the release job that packed, deployed, and verified this exact artifact.
|
|
10
|
+
*
|
|
11
|
+
* `platformVersion` is the `@impetik/xeer` release the artifact was built and verified against, and
|
|
12
|
+
* it is pinned exactly rather than as a range so a consumer reproduces the template's inputs. It may
|
|
13
|
+
* trail the catalog's own `platformVersion`: when a template fails to republish, the catalog keeps
|
|
14
|
+
* serving that template's last-known-good entry instead of dropping it. It is never ahead of the
|
|
15
|
+
* catalog, because an entry cannot be built from a release the catalog has not reached.
|
|
16
|
+
*/
|
|
17
|
+
export declare const templateDistributionEntrySchema: z.ZodObject<{
|
|
18
|
+
previewUrl: z.ZodString;
|
|
19
|
+
platformVersion: z.ZodString;
|
|
20
|
+
artifactVersion: z.ZodString;
|
|
21
|
+
sourceArchive: z.ZodObject<{
|
|
22
|
+
url: z.ZodString;
|
|
23
|
+
sha256: z.ZodString;
|
|
24
|
+
}, z.core.$strict>;
|
|
25
|
+
author: z.ZodObject<{
|
|
26
|
+
name: z.ZodString;
|
|
27
|
+
url: z.ZodOptional<z.ZodString>;
|
|
28
|
+
}, z.core.$strict>;
|
|
29
|
+
capabilities: z.ZodArray<z.ZodEnum<{
|
|
30
|
+
database: "database";
|
|
31
|
+
storage: "storage";
|
|
32
|
+
}>>;
|
|
33
|
+
requiredSecrets: z.ZodArray<z.ZodObject<{
|
|
34
|
+
name: z.ZodString;
|
|
35
|
+
description: z.ZodString;
|
|
36
|
+
}, z.core.$strict>>;
|
|
37
|
+
previewAppId: z.ZodString;
|
|
38
|
+
screenshots: z.ZodArray<z.ZodObject<{
|
|
39
|
+
url: z.ZodString;
|
|
40
|
+
alt: z.ZodString;
|
|
41
|
+
}, z.core.$strict>>;
|
|
42
|
+
title: z.ZodString;
|
|
43
|
+
description: z.ZodString;
|
|
44
|
+
category: z.ZodString;
|
|
45
|
+
tags: z.ZodArray<z.ZodString>;
|
|
46
|
+
keyHighlights: z.ZodArray<z.ZodString>;
|
|
47
|
+
id: z.ZodString;
|
|
48
|
+
}, z.core.$strict>;
|
|
49
|
+
export type TemplateDistributionEntryV0 = z.infer<typeof templateDistributionEntrySchema>;
|
|
50
|
+
/**
|
|
51
|
+
* Versioned distribution catalog published atomically after a platform release. Entries are keyed by
|
|
52
|
+
* template id, sorted by codepoint so a regenerated catalog is byte-stable, and a template with no
|
|
53
|
+
* successful publication is simply absent. Quarantine and failure reporting stay in the release
|
|
54
|
+
* pipeline; the catalog only ever describes artifacts that were verified.
|
|
55
|
+
*/
|
|
56
|
+
export declare const templateDistributionCatalogSchema: z.ZodObject<{
|
|
57
|
+
format: z.ZodLiteral<"xeer.template-distribution-catalog.v0">;
|
|
58
|
+
platformVersion: z.ZodString;
|
|
59
|
+
generatedAt: z.ZodISODateTime;
|
|
60
|
+
templates: z.ZodArray<z.ZodObject<{
|
|
61
|
+
previewUrl: z.ZodString;
|
|
62
|
+
platformVersion: z.ZodString;
|
|
63
|
+
artifactVersion: z.ZodString;
|
|
64
|
+
sourceArchive: z.ZodObject<{
|
|
65
|
+
url: z.ZodString;
|
|
66
|
+
sha256: z.ZodString;
|
|
67
|
+
}, z.core.$strict>;
|
|
68
|
+
author: z.ZodObject<{
|
|
69
|
+
name: z.ZodString;
|
|
70
|
+
url: z.ZodOptional<z.ZodString>;
|
|
71
|
+
}, z.core.$strict>;
|
|
72
|
+
capabilities: z.ZodArray<z.ZodEnum<{
|
|
73
|
+
database: "database";
|
|
74
|
+
storage: "storage";
|
|
75
|
+
}>>;
|
|
76
|
+
requiredSecrets: z.ZodArray<z.ZodObject<{
|
|
77
|
+
name: z.ZodString;
|
|
78
|
+
description: z.ZodString;
|
|
79
|
+
}, z.core.$strict>>;
|
|
80
|
+
previewAppId: z.ZodString;
|
|
81
|
+
screenshots: z.ZodArray<z.ZodObject<{
|
|
82
|
+
url: z.ZodString;
|
|
83
|
+
alt: z.ZodString;
|
|
84
|
+
}, z.core.$strict>>;
|
|
85
|
+
title: z.ZodString;
|
|
86
|
+
description: z.ZodString;
|
|
87
|
+
category: z.ZodString;
|
|
88
|
+
tags: z.ZodArray<z.ZodString>;
|
|
89
|
+
keyHighlights: z.ZodArray<z.ZodString>;
|
|
90
|
+
id: z.ZodString;
|
|
91
|
+
}, z.core.$strict>>;
|
|
92
|
+
}, z.core.$strict>;
|
|
93
|
+
export type TemplateDistributionCatalogV0 = z.infer<typeof templateDistributionCatalogSchema>;
|
|
94
|
+
/**
|
|
95
|
+
* Orders two exact semantic versions by precedence. Build metadata is ignored and a prerelease sorts
|
|
96
|
+
* before its own release, so `1.0.0-rc.1 < 1.0.0`. Inputs must already satisfy `EXACT_VERSION_PATTERN`.
|
|
97
|
+
*/
|
|
98
|
+
export declare function compareExactVersions(left: string, right: string): number;
|
|
99
|
+
export declare const templateDistributionCatalogJsonSchema: Readonly<Record<string, unknown>>;
|
|
100
|
+
export declare function parseTemplateDistributionEntry(value: unknown): TemplateDistributionEntryV0;
|
|
101
|
+
export declare function parseTemplateDistributionCatalog(value: unknown): TemplateDistributionCatalogV0;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { checkTemplateMetadataUniqueness, templateAltTextSchema, templateIdentityShape, templateMetadataShape, templateSlugSchema, } from './template.js';
|
|
3
|
+
export const TEMPLATE_DISTRIBUTION_CATALOG_FORMAT = 'xeer.template-distribution-catalog.v0';
|
|
4
|
+
export const TEMPLATE_DISTRIBUTION_CATALOG_SCHEMA_URL = 'https://docs.xeer.run/template-distribution-catalog-v0.schema.json';
|
|
5
|
+
/** Exact semantic version: no range operator, no `v` prefix, no wildcard. */
|
|
6
|
+
export const EXACT_VERSION_PATTERN = '^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)'
|
|
7
|
+
+ '(?:-(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*)?'
|
|
8
|
+
+ '(?:\\+[0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*)?$';
|
|
9
|
+
export const TEMPLATE_ARCHIVE_CHECKSUM_PATTERN = '^sha256:[a-f0-9]{64}$';
|
|
10
|
+
const exactVersion = z.string().regex(new RegExp(EXACT_VERSION_PATTERN, 'u'), 'must be an exact semantic version, not a range');
|
|
11
|
+
const httpsUrl = z.string().url().refine((value) => URL.parse(value)?.protocol === 'https:', 'must be an absolute https URL');
|
|
12
|
+
const archiveChecksum = z.string().regex(new RegExp(TEMPLATE_ARCHIVE_CHECKSUM_PATTERN, 'u'), 'must be a sha256: digest with 64 lowercase hexadecimal characters');
|
|
13
|
+
const distributedScreenshotSchema = z.strictObject({
|
|
14
|
+
url: httpsUrl,
|
|
15
|
+
alt: templateAltTextSchema,
|
|
16
|
+
});
|
|
17
|
+
const sourceArchiveSchema = z.strictObject({
|
|
18
|
+
url: httpsUrl,
|
|
19
|
+
sha256: archiveChecksum,
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* One published template. The authored metadata is copied verbatim from `template.json`; everything
|
|
23
|
+
* else is produced by the release job that packed, deployed, and verified this exact artifact.
|
|
24
|
+
*
|
|
25
|
+
* `platformVersion` is the `@impetik/xeer` release the artifact was built and verified against, and
|
|
26
|
+
* it is pinned exactly rather than as a range so a consumer reproduces the template's inputs. It may
|
|
27
|
+
* trail the catalog's own `platformVersion`: when a template fails to republish, the catalog keeps
|
|
28
|
+
* serving that template's last-known-good entry instead of dropping it. It is never ahead of the
|
|
29
|
+
* catalog, because an entry cannot be built from a release the catalog has not reached.
|
|
30
|
+
*/
|
|
31
|
+
export const templateDistributionEntrySchema = z.strictObject({
|
|
32
|
+
id: templateSlugSchema,
|
|
33
|
+
...templateMetadataShape,
|
|
34
|
+
screenshots: z.array(distributedScreenshotSchema).min(1).max(8),
|
|
35
|
+
...templateIdentityShape,
|
|
36
|
+
/** Live preview served by the first-party deployment of `previewAppId`, verified during release. */
|
|
37
|
+
previewUrl: httpsUrl,
|
|
38
|
+
platformVersion: exactVersion,
|
|
39
|
+
/** Release version of the template artifact itself, independent of the platform version. */
|
|
40
|
+
artifactVersion: exactVersion,
|
|
41
|
+
sourceArchive: sourceArchiveSchema,
|
|
42
|
+
}).superRefine(checkTemplateMetadataUniqueness);
|
|
43
|
+
/**
|
|
44
|
+
* Versioned distribution catalog published atomically after a platform release. Entries are keyed by
|
|
45
|
+
* template id, sorted by codepoint so a regenerated catalog is byte-stable, and a template with no
|
|
46
|
+
* successful publication is simply absent. Quarantine and failure reporting stay in the release
|
|
47
|
+
* pipeline; the catalog only ever describes artifacts that were verified.
|
|
48
|
+
*/
|
|
49
|
+
export const templateDistributionCatalogSchema = z.strictObject({
|
|
50
|
+
format: z.literal(TEMPLATE_DISTRIBUTION_CATALOG_FORMAT),
|
|
51
|
+
/** Platform release this catalog was published for; individual entries may still trail it. */
|
|
52
|
+
platformVersion: exactVersion,
|
|
53
|
+
generatedAt: z.iso.datetime(),
|
|
54
|
+
templates: z.array(templateDistributionEntrySchema).min(1).max(512),
|
|
55
|
+
}).superRefine((catalog, ctx) => {
|
|
56
|
+
const previewIdentities = new Map();
|
|
57
|
+
for (const [index, entry] of catalog.templates.entries()) {
|
|
58
|
+
const previous = catalog.templates[index - 1];
|
|
59
|
+
if (previous?.id === entry.id) {
|
|
60
|
+
ctx.addIssue({ code: 'custom', path: ['templates', index, 'id'], message: 'template id is declared twice' });
|
|
61
|
+
}
|
|
62
|
+
else if (previous && entry.id < previous.id) {
|
|
63
|
+
ctx.addIssue({ code: 'custom', path: ['templates', index, 'id'], message: 'templates must be sorted by id' });
|
|
64
|
+
}
|
|
65
|
+
const owner = previewIdentities.get(entry.previewAppId);
|
|
66
|
+
if (owner !== undefined) {
|
|
67
|
+
ctx.addIssue({
|
|
68
|
+
code: 'custom',
|
|
69
|
+
path: ['templates', index, 'previewAppId'],
|
|
70
|
+
message: `previewAppId is declared twice; templates[${owner}] already claims it`,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
previewIdentities.set(entry.previewAppId, index);
|
|
74
|
+
if (compareExactVersions(entry.platformVersion, catalog.platformVersion) > 0) {
|
|
75
|
+
ctx.addIssue({
|
|
76
|
+
code: 'custom',
|
|
77
|
+
path: ['templates', index, 'platformVersion'],
|
|
78
|
+
message: 'must not be newer than the catalog platform version',
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
const identifiers = (prerelease) => (prerelease === '' ? [] : prerelease.split('.'));
|
|
84
|
+
/**
|
|
85
|
+
* Orders two exact semantic versions by precedence. Build metadata is ignored and a prerelease sorts
|
|
86
|
+
* before its own release, so `1.0.0-rc.1 < 1.0.0`. Inputs must already satisfy `EXACT_VERSION_PATTERN`.
|
|
87
|
+
*/
|
|
88
|
+
export function compareExactVersions(left, right) {
|
|
89
|
+
const split = (version) => {
|
|
90
|
+
const withoutBuild = version.split('+', 1)[0];
|
|
91
|
+
const dash = withoutBuild.indexOf('-');
|
|
92
|
+
const core = dash === -1 ? withoutBuild : withoutBuild.slice(0, dash);
|
|
93
|
+
return {
|
|
94
|
+
core: core.split('.').map(Number),
|
|
95
|
+
prerelease: identifiers(dash === -1 ? '' : withoutBuild.slice(dash + 1)),
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
const a = split(left);
|
|
99
|
+
const b = split(right);
|
|
100
|
+
for (let index = 0; index < 3; index += 1) {
|
|
101
|
+
if (a.core[index] !== b.core[index])
|
|
102
|
+
return (a.core[index] ?? 0) < (b.core[index] ?? 0) ? -1 : 1;
|
|
103
|
+
}
|
|
104
|
+
if (a.prerelease.length === 0 || b.prerelease.length === 0) {
|
|
105
|
+
if (a.prerelease.length === b.prerelease.length)
|
|
106
|
+
return 0;
|
|
107
|
+
return a.prerelease.length === 0 ? 1 : -1;
|
|
108
|
+
}
|
|
109
|
+
for (let index = 0; index < Math.max(a.prerelease.length, b.prerelease.length); index += 1) {
|
|
110
|
+
const one = a.prerelease[index];
|
|
111
|
+
const other = b.prerelease[index];
|
|
112
|
+
if (one === undefined || other === undefined)
|
|
113
|
+
return one === undefined ? -1 : 1;
|
|
114
|
+
if (one === other)
|
|
115
|
+
continue;
|
|
116
|
+
const numeric = /^\d+$/u;
|
|
117
|
+
if (numeric.test(one) && numeric.test(other))
|
|
118
|
+
return Number(one) < Number(other) ? -1 : 1;
|
|
119
|
+
if (numeric.test(one) !== numeric.test(other))
|
|
120
|
+
return numeric.test(one) ? -1 : 1;
|
|
121
|
+
return one < other ? -1 : 1;
|
|
122
|
+
}
|
|
123
|
+
return 0;
|
|
124
|
+
}
|
|
125
|
+
const generatedCatalogJsonSchema = z.toJSONSchema(templateDistributionCatalogSchema);
|
|
126
|
+
const generatedProperties = generatedCatalogJsonSchema.properties;
|
|
127
|
+
export const templateDistributionCatalogJsonSchema = Object.freeze({
|
|
128
|
+
...generatedCatalogJsonSchema,
|
|
129
|
+
$id: TEMPLATE_DISTRIBUTION_CATALOG_SCHEMA_URL,
|
|
130
|
+
title: 'Xeer template distribution catalog v0',
|
|
131
|
+
description: 'Released, verified template artifacts a consumer can download, verify, and deploy.',
|
|
132
|
+
properties: {
|
|
133
|
+
...generatedProperties,
|
|
134
|
+
format: {
|
|
135
|
+
...generatedProperties.format,
|
|
136
|
+
description: `Distribution protocol discriminator; exactly ${TEMPLATE_DISTRIBUTION_CATALOG_FORMAT}.`,
|
|
137
|
+
},
|
|
138
|
+
platformVersion: {
|
|
139
|
+
...generatedProperties.platformVersion,
|
|
140
|
+
description: 'Exact @impetik/xeer release this catalog was published for.',
|
|
141
|
+
},
|
|
142
|
+
generatedAt: {
|
|
143
|
+
...generatedProperties.generatedAt,
|
|
144
|
+
description: 'UTC instant the release job assembled this catalog.',
|
|
145
|
+
},
|
|
146
|
+
templates: {
|
|
147
|
+
...generatedProperties.templates,
|
|
148
|
+
description: 'Verified entries sorted by template id; an entry may trail the catalog platform version.',
|
|
149
|
+
uniqueItems: true,
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
export function parseTemplateDistributionEntry(value) {
|
|
154
|
+
return templateDistributionEntrySchema.parse(value);
|
|
155
|
+
}
|
|
156
|
+
export function parseTemplateDistributionCatalog(value) {
|
|
157
|
+
return templateDistributionCatalogSchema.parse(value);
|
|
158
|
+
}
|
|
@@ -1,18 +1,55 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
/** Catalog identifier shape shared by template directory names and categories. */
|
|
5
|
+
export declare const templateSlugSchema: z.ZodString;
|
|
6
|
+
/** Alt text carried by a gallery image in either the source or the distribution catalog. */
|
|
7
|
+
export declare const templateAltTextSchema: z.ZodString;
|
|
8
|
+
/**
|
|
9
|
+
* Presentation metadata an author writes once and both catalogs repeat verbatim. Spread it ahead of
|
|
10
|
+
* the gallery so the source manifest and a distribution entry keep the same field order.
|
|
11
|
+
*/
|
|
12
|
+
export declare const templateMetadataShape: {
|
|
7
13
|
title: z.ZodString;
|
|
8
14
|
description: z.ZodString;
|
|
9
15
|
category: z.ZodString;
|
|
10
16
|
tags: z.ZodArray<z.ZodString>;
|
|
11
17
|
keyHighlights: z.ZodArray<z.ZodString>;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
};
|
|
19
|
+
/** Attribution, capability, and preview identity metadata that follows the gallery in both catalogs. */
|
|
20
|
+
export declare const templateIdentityShape: {
|
|
21
|
+
author: z.ZodObject<{
|
|
22
|
+
name: z.ZodString;
|
|
23
|
+
url: z.ZodOptional<z.ZodString>;
|
|
24
|
+
}, z.core.$strict>;
|
|
25
|
+
capabilities: z.ZodArray<z.ZodEnum<{
|
|
26
|
+
database: "database";
|
|
27
|
+
storage: "storage";
|
|
28
|
+
}>>;
|
|
29
|
+
requiredSecrets: z.ZodArray<z.ZodObject<{
|
|
30
|
+
name: z.ZodString;
|
|
31
|
+
description: z.ZodString;
|
|
15
32
|
}, z.core.$strict>>;
|
|
33
|
+
previewAppId: z.ZodString;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Rejects facets an author repeated inside one template. Distribution entries reuse it so a
|
|
37
|
+
* duplicate reads identically whether it is caught at authoring time or at release time; the
|
|
38
|
+
* gallery is keyed by `path` in the source catalog and by `url` once screenshots are uploaded.
|
|
39
|
+
*/
|
|
40
|
+
export declare function checkTemplateMetadataUniqueness(metadata: {
|
|
41
|
+
readonly tags: readonly string[];
|
|
42
|
+
readonly keyHighlights: readonly string[];
|
|
43
|
+
readonly screenshots: readonly {
|
|
44
|
+
readonly path?: string;
|
|
45
|
+
readonly url?: string;
|
|
46
|
+
}[];
|
|
47
|
+
readonly capabilities: readonly string[];
|
|
48
|
+
readonly requiredSecrets: readonly {
|
|
49
|
+
readonly name: string;
|
|
50
|
+
}[];
|
|
51
|
+
}, ctx: z.RefinementCtx): void;
|
|
52
|
+
export declare const templateManifestSchema: z.ZodObject<{
|
|
16
53
|
author: z.ZodObject<{
|
|
17
54
|
name: z.ZodString;
|
|
18
55
|
url: z.ZodOptional<z.ZodString>;
|
|
@@ -26,6 +63,17 @@ export declare const templateManifestSchema: z.ZodObject<{
|
|
|
26
63
|
description: z.ZodString;
|
|
27
64
|
}, z.core.$strict>>;
|
|
28
65
|
previewAppId: z.ZodString;
|
|
66
|
+
screenshots: z.ZodArray<z.ZodObject<{
|
|
67
|
+
path: z.ZodString;
|
|
68
|
+
alt: z.ZodString;
|
|
69
|
+
}, z.core.$strict>>;
|
|
70
|
+
title: z.ZodString;
|
|
71
|
+
description: z.ZodString;
|
|
72
|
+
category: z.ZodString;
|
|
73
|
+
tags: z.ZodArray<z.ZodString>;
|
|
74
|
+
keyHighlights: z.ZodArray<z.ZodString>;
|
|
75
|
+
$schema: z.ZodOptional<z.ZodString>;
|
|
76
|
+
format: z.ZodLiteral<"xeer.template.v0">;
|
|
29
77
|
}, z.core.$strict>;
|
|
30
78
|
export type TemplateManifestV0 = z.infer<typeof templateManifestSchema>;
|
|
31
79
|
export declare const templateManifestJsonSchema: Readonly<Record<string, unknown>>;
|
package/vendor/spec/template.js
CHANGED
|
@@ -5,7 +5,8 @@ export const TEMPLATE_MANIFEST_SCHEMA_URL = 'https://docs.xeer.run/template-v0.s
|
|
|
5
5
|
const trimmed = (maximum) => z.string().min(1).max(maximum)
|
|
6
6
|
.refine((value) => value === value.trim(), 'must not have leading or trailing whitespace')
|
|
7
7
|
.refine((value) => !/[\u0000-\u001f\u007f]/u.test(value), 'must not contain control characters');
|
|
8
|
-
|
|
8
|
+
/** Catalog identifier shape shared by template directory names and categories. */
|
|
9
|
+
export const templateSlugSchema = z.string().regex(/^[a-z][a-z0-9-]{1,62}$/u, 'must be a lowercase slug between 2 and 63 characters');
|
|
9
10
|
const environmentName = z.string().regex(/^[A-Z][A-Z0-9_]{0,63}$/u, 'must be an uppercase environment variable name');
|
|
10
11
|
const appId = z.string().regex(/^app_[A-Za-z0-9_-]{8,96}$/u, 'must be a valid Xeer appId');
|
|
11
12
|
const screenshotPath = z.string().regex(/^screenshots\/(?:[A-Za-z0-9][A-Za-z0-9._-]*\/)*[A-Za-z0-9][A-Za-z0-9._-]*\.(?:avif|jpe?g|png|webp)$/u, 'must be a repository-local AVIF, JPEG, PNG, or WebP path under screenshots/');
|
|
@@ -17,24 +18,36 @@ const requiredSecretSchema = z.strictObject({
|
|
|
17
18
|
name: environmentName,
|
|
18
19
|
description: trimmed(200),
|
|
19
20
|
});
|
|
21
|
+
/** Alt text carried by a gallery image in either the source or the distribution catalog. */
|
|
22
|
+
export const templateAltTextSchema = trimmed(200);
|
|
20
23
|
const screenshotSchema = z.strictObject({
|
|
21
24
|
path: screenshotPath,
|
|
22
|
-
alt:
|
|
25
|
+
alt: templateAltTextSchema,
|
|
23
26
|
});
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
/**
|
|
28
|
+
* Presentation metadata an author writes once and both catalogs repeat verbatim. Spread it ahead of
|
|
29
|
+
* the gallery so the source manifest and a distribution entry keep the same field order.
|
|
30
|
+
*/
|
|
31
|
+
export const templateMetadataShape = {
|
|
27
32
|
title: trimmed(120),
|
|
28
33
|
description: trimmed(300),
|
|
29
|
-
category:
|
|
34
|
+
category: templateSlugSchema,
|
|
30
35
|
tags: z.array(trimmed(40)).min(1).max(16),
|
|
31
36
|
keyHighlights: z.array(trimmed(120)).min(1).max(8),
|
|
32
|
-
|
|
37
|
+
};
|
|
38
|
+
/** Attribution, capability, and preview identity metadata that follows the gallery in both catalogs. */
|
|
39
|
+
export const templateIdentityShape = {
|
|
33
40
|
author: authorSchema,
|
|
34
41
|
capabilities: z.array(z.enum(CAPABILITIES)).max(CAPABILITIES.length),
|
|
35
42
|
requiredSecrets: z.array(requiredSecretSchema).max(16),
|
|
36
43
|
previewAppId: appId,
|
|
37
|
-
}
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Rejects facets an author repeated inside one template. Distribution entries reuse it so a
|
|
47
|
+
* duplicate reads identically whether it is caught at authoring time or at release time; the
|
|
48
|
+
* gallery is keyed by `path` in the source catalog and by `url` once screenshots are uploaded.
|
|
49
|
+
*/
|
|
50
|
+
export function checkTemplateMetadataUniqueness(metadata, ctx) {
|
|
38
51
|
const unique = (values, path, label) => {
|
|
39
52
|
const seen = new Set();
|
|
40
53
|
for (const [index, value] of values.entries()) {
|
|
@@ -45,12 +58,19 @@ export const templateManifestSchema = z.strictObject({
|
|
|
45
58
|
seen.add(normalized);
|
|
46
59
|
}
|
|
47
60
|
};
|
|
48
|
-
unique(
|
|
49
|
-
unique(
|
|
50
|
-
unique(
|
|
51
|
-
unique(
|
|
52
|
-
unique(
|
|
53
|
-
}
|
|
61
|
+
unique(metadata.tags, 'tags', 'tag');
|
|
62
|
+
unique(metadata.keyHighlights, 'keyHighlights', 'highlight');
|
|
63
|
+
unique(metadata.screenshots.map((screenshot) => screenshot.path ?? screenshot.url ?? ''), 'screenshots', 'screenshot');
|
|
64
|
+
unique(metadata.capabilities, 'capabilities', 'capability');
|
|
65
|
+
unique(metadata.requiredSecrets.map((secret) => secret.name), 'requiredSecrets', 'secret');
|
|
66
|
+
}
|
|
67
|
+
export const templateManifestSchema = z.strictObject({
|
|
68
|
+
$schema: z.string().url().optional(),
|
|
69
|
+
format: z.literal(TEMPLATE_FORMAT),
|
|
70
|
+
...templateMetadataShape,
|
|
71
|
+
screenshots: z.array(screenshotSchema).min(1).max(8),
|
|
72
|
+
...templateIdentityShape,
|
|
73
|
+
}).superRefine(checkTemplateMetadataUniqueness);
|
|
54
74
|
const generatedTemplateManifestJsonSchema = z.toJSONSchema(templateManifestSchema);
|
|
55
75
|
const generatedProperties = generatedTemplateManifestJsonSchema.properties;
|
|
56
76
|
export const templateManifestJsonSchema = Object.freeze({
|
package/vendor/spec/tunnel.d.ts
CHANGED
|
@@ -7,6 +7,9 @@ export declare const TUNNEL_TICKET_HEADER: "x-xeer-tunnel-ticket";
|
|
|
7
7
|
export declare const TUNNEL_CONTROL_HEADER: "x-xeer-tunnel-control";
|
|
8
8
|
export declare const TUNNEL_SHARED_HEADER: "x-xeer-shared-dev";
|
|
9
9
|
export declare const TUNNEL_SHARED_HOST_HEADER: "x-xeer-shared-host";
|
|
10
|
+
/** Builder-only routes that a public shared-dev tunnel must hide at the relay boundary. */
|
|
11
|
+
export declare const TUNNEL_SHARED_BLOCKED_PREFIXES: readonly ["/__admin", "/__xeer/admin", "/__xeer/manifest", "/__xeer/state", "/__xeer/logs", "/__xeer/export", "/__xeer/import", "/__open-in-editor", "/_xeer/auth/sign-in", "/_xeer/auth/sign-out", "/__vite", "/__inspect"];
|
|
12
|
+
export declare function tunnelSharedPathBlocked(pathname: string): boolean;
|
|
10
13
|
export declare const TUNNEL_PROFILES: readonly ["shared-dev", "raw-http"];
|
|
11
14
|
export type TunnelProfile = (typeof TUNNEL_PROFILES)[number];
|
|
12
15
|
export declare const TUNNEL_BINARY_HEADER_BYTES = 12;
|
package/vendor/spec/tunnel.js
CHANGED
|
@@ -7,6 +7,24 @@ export const TUNNEL_TICKET_HEADER = 'x-xeer-tunnel-ticket';
|
|
|
7
7
|
export const TUNNEL_CONTROL_HEADER = 'x-xeer-tunnel-control';
|
|
8
8
|
export const TUNNEL_SHARED_HEADER = 'x-xeer-shared-dev';
|
|
9
9
|
export const TUNNEL_SHARED_HOST_HEADER = 'x-xeer-shared-host';
|
|
10
|
+
/** Builder-only routes that a public shared-dev tunnel must hide at the relay boundary. */
|
|
11
|
+
export const TUNNEL_SHARED_BLOCKED_PREFIXES = Object.freeze([
|
|
12
|
+
'/__admin',
|
|
13
|
+
'/__xeer/admin',
|
|
14
|
+
'/__xeer/manifest',
|
|
15
|
+
'/__xeer/state',
|
|
16
|
+
'/__xeer/logs',
|
|
17
|
+
'/__xeer/export',
|
|
18
|
+
'/__xeer/import',
|
|
19
|
+
'/__open-in-editor',
|
|
20
|
+
'/_xeer/auth/sign-in',
|
|
21
|
+
'/_xeer/auth/sign-out',
|
|
22
|
+
'/__vite',
|
|
23
|
+
'/__inspect',
|
|
24
|
+
]);
|
|
25
|
+
export function tunnelSharedPathBlocked(pathname) {
|
|
26
|
+
return TUNNEL_SHARED_BLOCKED_PREFIXES.some((prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`));
|
|
27
|
+
}
|
|
10
28
|
export const TUNNEL_PROFILES = ['shared-dev', 'raw-http'];
|
|
11
29
|
export const TUNNEL_BINARY_HEADER_BYTES = 12;
|
|
12
30
|
export const TUNNEL_MAX_FRAME_PAYLOAD = 65_536;
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* `"react-jsx"`, `lib` without the `lib.`/`.d.ts` affixes), which is what
|
|
17
17
|
* `ts.convertCompilerOptionsFromJson` reads.
|
|
18
18
|
*/
|
|
19
|
+
import { type ClientRuntimeProvider, type EntrypointTypesSource } from './import-policy.js';
|
|
19
20
|
export declare const PLATFORM_TYPE_CHECK_COMPILER_OPTIONS: Readonly<{
|
|
20
21
|
readonly allowJs: true;
|
|
21
22
|
readonly allowArbitraryExtensions: true;
|
|
@@ -35,15 +36,71 @@ export declare const PLATFORM_TYPE_CHECK_COMPILER_OPTIONS: Readonly<{
|
|
|
35
36
|
readonly verbatimModuleSyntax: true;
|
|
36
37
|
}>;
|
|
37
38
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
39
|
+
* One editor mapping the platform generates a file for: the specifier an application writes, the
|
|
40
|
+
* classified anchor entrypoint whose declarations answer it, where those declarations live, and the
|
|
41
|
+
* module inside the platform package the row points at.
|
|
42
|
+
*
|
|
43
|
+
* The shim generator in the CLI package consumes exactly this. Everything it needs beyond the row is
|
|
44
|
+
* resolution — turning a types source into a file on disk — which is why the row carries the fact
|
|
45
|
+
* and not the path.
|
|
46
|
+
*/
|
|
47
|
+
export interface EditorResolutionRow {
|
|
48
|
+
readonly specifier: string;
|
|
49
|
+
readonly entrypoint: string;
|
|
50
|
+
readonly types: Exclude<EntrypointTypesSource, {
|
|
51
|
+
kind: 'none';
|
|
52
|
+
}>;
|
|
53
|
+
/** Relative to the platform package's `dist/`, without an extension. */
|
|
54
|
+
readonly module: string;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Every renderer mapping one provider's editor needs, derived from the family descriptor.
|
|
58
|
+
*
|
|
59
|
+
* Two rules, and both are the descriptor's rather than anyone's memory. **Completeness**: every
|
|
60
|
+
* specifier the import policy admits from the renderer family gets a row, alias keys included,
|
|
61
|
+
* because the policy is what decides whether an application may write the import and this table is
|
|
62
|
+
* what decides whether its editor can read it. Five hand-kept rows against twelve admitted
|
|
63
|
+
* specifiers is how `react-dom/server` came to be a clean `xeer check` beside a TS2307 in the same
|
|
64
|
+
* file, and ten unmapped `preact/*` entrypoints were the same defect one provider over (#277).
|
|
65
|
+
* **Honesty**: an entrypoint whose declarations exist nowhere gets no row, so both tools refuse it
|
|
66
|
+
* by construction — `scheduler` and `react-dom/profiling` under React, `preact/compat/scheduler` and
|
|
67
|
+
* the two `compat/server` spellings under Preact. A row inventing types for one of those would make
|
|
68
|
+
* an editor accept what `xeer check` rejects, which is the same divergence pointed the other way.
|
|
69
|
+
*/
|
|
70
|
+
export declare function rendererEditorRows(provider: ClientRuntimeProvider): readonly EditorResolutionRow[];
|
|
71
|
+
/**
|
|
72
|
+
* The editor's resolution table for one UI provider — the `paths` block of a scaffolded
|
|
73
|
+
* `tsconfig.json`.
|
|
41
74
|
*
|
|
42
75
|
* Not part of {@link PLATFORM_TYPE_CHECK_COMPILER_OPTIONS}: the platform check answers the same
|
|
43
76
|
* question through its module-resolution host instead, so this is the editor's half of one rule
|
|
44
77
|
* rather than a second rule.
|
|
78
|
+
*
|
|
79
|
+
* Every target is a module *inside* the installed platform package, because both renderers are
|
|
80
|
+
* platform-sourced: applications never declare them, and only a path inside the installed package
|
|
81
|
+
* resolves under npm hoisting and pnpm strictness alike. One rule binds a row to the file it names —
|
|
82
|
+
* a mapping rewrites *every* matching specifier in the program, including the ones written in the
|
|
83
|
+
* file it points at, so the file a row names may never import that row's own specifier. It would
|
|
84
|
+
* resolve back onto itself and answer with an empty module: an editor with no renderer types at all.
|
|
85
|
+
* The generator in the CLI package is what keeps that true, and `editor-resolution.test.ts` there
|
|
86
|
+
* type-checks a scaffolded project through its own `tsconfig.json` to prove it.
|
|
87
|
+
*
|
|
88
|
+
* Keys are sorted, so the file's bytes depend on which rows exist rather than on the order two
|
|
89
|
+
* declarations happen to be written in.
|
|
90
|
+
*/
|
|
91
|
+
export declare function tsconfigPathsFor(provider: ClientRuntimeProvider): Readonly<Record<string, readonly string[]>>;
|
|
92
|
+
/**
|
|
93
|
+
* The editor mappings a `tsconfig.json` carries under the **Preact** provider: the React-family
|
|
94
|
+
* names an application may write, aliased onto the platform's `preact/compat` surface, and Preact's
|
|
95
|
+
* own admitted entrypoints, which an application may equally write and whose editor rows were
|
|
96
|
+
* missing until #277.
|
|
45
97
|
*/
|
|
46
98
|
export declare const REACT_COMPAT_TSCONFIG_PATHS: Readonly<Record<string, readonly string[]>>;
|
|
99
|
+
/**
|
|
100
|
+
* The same mappings under the **React** provider, pointed at the renderer itself rather than at a
|
|
101
|
+
* compatibility layer — which is the whole point of selecting the provider.
|
|
102
|
+
*/
|
|
103
|
+
export declare const REACT_PROVIDER_TSCONFIG_PATHS: Readonly<Record<string, readonly string[]>>;
|
|
47
104
|
/**
|
|
48
105
|
* The files an application's `tsconfig.json` type-checks: sources, TypeScript tests, and the
|
|
49
106
|
* generated contract.
|
|
@@ -63,5 +120,9 @@ export declare const APPLICATION_TSCONFIG_INCLUDE: readonly string[];
|
|
|
63
120
|
* bytes. Serialized here rather than returned as an object because "the file the editor reads" is
|
|
64
121
|
* what has to match, and two callers stringifying the same object with different options would
|
|
65
122
|
* produce two different files.
|
|
123
|
+
*
|
|
124
|
+
* The provider changes `paths` and nothing else. Every rule the platform enforces is identical
|
|
125
|
+
* across providers — the choice is about which renderer a name resolves to, never about how strictly
|
|
126
|
+
* the code is judged — and the default keeps a Preact application's file byte-for-byte what it was.
|
|
66
127
|
*/
|
|
67
|
-
export declare function applicationTsconfigDocument(): string;
|
|
128
|
+
export declare function applicationTsconfigDocument(provider?: ClientRuntimeProvider): string;
|