kitfly 0.1.2 → 0.2.0
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/CHANGELOG.md +34 -0
- package/README.md +63 -16
- package/VERSION +1 -1
- package/dist/_raw/content/deployment/preflight.md +134 -0
- package/dist/_raw/content/deployment/recipes/aws-s3.md +128 -0
- package/dist/_raw/content/deployment/recipes/cloudflare-pages.md +73 -0
- package/dist/_raw/content/deployment/recipes/cloudflare-r2.md +156 -0
- package/dist/_raw/content/deployment/recipes/fly-io.md +57 -0
- package/dist/_raw/content/deployment/recipes/github-pages.md +112 -0
- package/dist/_raw/content/deployment/recipes/netlify.md +99 -0
- package/dist/_raw/content/deployment/recipes/vercel.md +88 -0
- package/dist/_raw/content/deployment/secrets-and-env-vars.md +75 -0
- package/dist/_raw/content/deployment.md +128 -0
- package/dist/_raw/content/guide/approaches.md +182 -0
- package/dist/_raw/content/guide/features.md +121 -0
- package/dist/_raw/content/guide/getting-started.md +112 -0
- package/dist/_raw/content/guide/kitfly-overview.md +209 -0
- package/dist/_raw/content/reference/configuration.md +259 -0
- package/dist/_raw/content/reference/design-catalog.md +167 -0
- package/dist/_raw/content/reference/environment-variables.md +66 -0
- package/dist/_raw/content/reference/glossary.md +92 -0
- package/dist/_raw/content/reference/key-concepts.md +118 -0
- package/dist/_raw/content/reference/plugins.md +220 -0
- package/dist/_raw/content/reference/structure.md +166 -0
- package/dist/_raw/content/reference.md +19 -0
- package/dist/_raw/content/templates/crucible.md +192 -0
- package/dist/_raw/content/templates/handbook.md +83 -0
- package/dist/_raw/content/templates/minimal.md +138 -0
- package/dist/_raw/content/templates/overview.md +187 -0
- package/dist/_raw/content/templates/pipeline.md +151 -0
- package/dist/_raw/content/templates/productbook.md +187 -0
- package/dist/_raw/content/templates/runbook.md +193 -0
- package/dist/_raw/content/templates/servicebook.md +163 -0
- package/dist/_raw/docs/decisions/ADR-0001-minimalist-site-code.md +118 -0
- package/dist/_raw/docs/decisions/ADR-0002-ai-accessibility.md +153 -0
- package/dist/_raw/docs/decisions/ADR-0003-single-file-bundle.md +93 -0
- package/dist/_raw/docs/decisions/ADR-0004-bun-runtime.md +98 -0
- package/dist/_raw/docs/decisions/ADR-0005-plugin-contract-and-distribution.md +110 -0
- package/dist/_raw/docs/decisions/DDR-0001-viewport-locked-layout.md +111 -0
- package/dist/_raw/docs/decisions/DDR-0002-theme-system.md +131 -0
- package/dist/_raw/docs/decisions/DDR-0003-bounded-logo-slot.md +106 -0
- package/dist/_raw/docs/decisions/DDR-0004-slides-rendering-model.md +113 -0
- package/dist/_raw/docs/decisions/DDR-0005-deterministic-layout-boundary.md +107 -0
- package/dist/_raw/docs/userguide/cli/build.md +85 -0
- package/dist/_raw/docs/userguide/cli/bundle.md +81 -0
- package/dist/_raw/docs/userguide/cli/dev.md +92 -0
- package/dist/_raw/docs/userguide/cli/init.md +116 -0
- package/dist/_raw/docs/userguide/cli/servers.md +69 -0
- package/dist/_raw/docs/userguide/cli/stop.md +76 -0
- package/dist/_raw/docs/userguide/cli/update.md +78 -0
- package/dist/_raw/docs/userguide/cli/version.md +65 -0
- package/dist/_raw/docs/userguide/cli.md +34 -0
- package/dist/_raw/docs/userguide/sharing.md +94 -0
- package/dist/_raw/schemas/plugin-schemas-notes.md +71 -0
- package/dist/_raw/schemas.md +42 -0
- package/dist/assets/brand/kitfly-favicon-32.png +0 -0
- package/dist/assets/brand/kitfly-icon-64.png +0 -0
- package/dist/assets/brand/kitfly-logo-128.png +0 -0
- package/dist/assets/brand/kitfly-logo-512.png +0 -0
- package/dist/assets/brand/kitfly-logo.svg +12132 -0
- package/dist/assets/brand/kitfly-neon-128.png +0 -0
- package/dist/assets/brand/kitfly-neon-192.png +0 -0
- package/dist/assets/brand/kitfly-neon-256.png +0 -0
- package/dist/assets/brand/kitfly-neon.png +0 -0
- package/dist/assets/brand/palette.md +75 -0
- package/dist/content/deployment/index.html +11 -0
- package/dist/content/deployment/preflight.html +418 -0
- package/dist/content/deployment/recipes/aws-s3.html +421 -0
- package/dist/content/deployment/recipes/cloudflare-pages.html +372 -0
- package/dist/content/deployment/recipes/cloudflare-r2.html +443 -0
- package/dist/content/deployment/recipes/fly-io.html +356 -0
- package/dist/content/deployment/recipes/github-pages.html +414 -0
- package/dist/content/deployment/recipes/index.html +11 -0
- package/dist/content/deployment/recipes/netlify.html +394 -0
- package/dist/content/deployment/recipes/vercel.html +382 -0
- package/dist/content/deployment/secrets-and-env-vars.html +380 -0
- package/dist/content/deployment.html +426 -0
- package/dist/content/guide/approaches.html +501 -0
- package/dist/content/guide/features.html +436 -0
- package/dist/content/guide/getting-started.html +403 -0
- package/dist/content/guide/index.html +11 -0
- package/dist/content/guide/kitfly-overview.html +544 -0
- package/dist/content/index.html +11 -0
- package/dist/content/reference/configuration.html +580 -0
- package/dist/content/reference/design-catalog.html +449 -0
- package/dist/content/reference/environment-variables.html +367 -0
- package/dist/content/reference/glossary.html +368 -0
- package/dist/content/reference/index.html +11 -0
- package/dist/content/reference/key-concepts.html +399 -0
- package/dist/content/reference/plugins.html +491 -0
- package/dist/content/reference/structure.html +463 -0
- package/dist/content/reference.html +334 -0
- package/dist/content/templates/crucible.html +546 -0
- package/dist/content/templates/handbook.html +405 -0
- package/dist/content/templates/index.html +11 -0
- package/dist/content/templates/minimal.html +447 -0
- package/dist/content/templates/overview.html +558 -0
- package/dist/content/templates/pipeline.html +494 -0
- package/dist/content/templates/productbook.html +540 -0
- package/dist/content/templates/runbook.html +543 -0
- package/dist/content/templates/servicebook.html +523 -0
- package/dist/content-index.json +540 -0
- package/dist/docs/decisions/ADR-0001-minimalist-site-code.html +491 -0
- package/dist/docs/decisions/ADR-0002-ai-accessibility.html +434 -0
- package/dist/docs/decisions/ADR-0003-single-file-bundle.html +412 -0
- package/dist/docs/decisions/ADR-0004-bun-runtime.html +409 -0
- package/dist/docs/decisions/ADR-0005-plugin-contract-and-distribution.html +402 -0
- package/dist/docs/decisions/DDR-0001-viewport-locked-layout.html +459 -0
- package/dist/docs/decisions/DDR-0002-theme-system.html +452 -0
- package/dist/docs/decisions/DDR-0003-bounded-logo-slot.html +423 -0
- package/dist/docs/decisions/DDR-0004-slides-rendering-model.html +399 -0
- package/dist/docs/decisions/DDR-0005-deterministic-layout-boundary.html +422 -0
- package/dist/docs/decisions/index.html +11 -0
- package/dist/docs/userguide/cli/build.html +408 -0
- package/dist/docs/userguide/cli/bundle.html +419 -0
- package/dist/docs/userguide/cli/dev.html +428 -0
- package/dist/docs/userguide/cli/index.html +11 -0
- package/dist/docs/userguide/cli/init.html +436 -0
- package/dist/docs/userguide/cli/servers.html +393 -0
- package/dist/docs/userguide/cli/stop.html +408 -0
- package/dist/docs/userguide/cli/update.html +406 -0
- package/dist/docs/userguide/cli/version.html +406 -0
- package/dist/docs/userguide/cli.html +386 -0
- package/dist/docs/userguide/index.html +11 -0
- package/dist/docs/userguide/sharing.html +465 -0
- package/dist/index.html +387 -0
- package/dist/llms.txt +18 -0
- package/dist/provenance.json +7 -0
- package/dist/schemas/index.html +11 -0
- package/dist/schemas/plugin-registry.schema.html +327 -0
- package/dist/schemas/plugin-schemas-notes.html +364 -0
- package/dist/schemas/plugin.schema.html +327 -0
- package/dist/schemas/plugins.schema.html +327 -0
- package/dist/schemas/v0/common.schema.html +386 -0
- package/dist/schemas/v0/index.html +11 -0
- package/dist/schemas/v0/plugin-registry.schema.html +547 -0
- package/dist/schemas/v0/plugin.schema.html +497 -0
- package/dist/schemas/v0/plugins.schema.html +406 -0
- package/dist/schemas/v0/site.schema.html +541 -0
- package/dist/schemas/v0/theme.schema.html +615 -0
- package/dist/schemas.html +351 -0
- package/dist/styles.css +1262 -0
- package/package.json +4 -2
- package/plugins-dist/callouts.css +32 -0
- package/plugins-dist/callouts.js +46 -0
- package/plugins-dist/slides-visuals.css +224 -0
- package/plugins-dist/slides-visuals.js +598 -0
- package/registry/plugins.yaml +35 -0
- package/schemas/README.md +10 -0
- package/schemas/plugin-registry.schema.json +5 -0
- package/schemas/plugin-schemas-notes.md +71 -0
- package/schemas/plugin.schema.json +5 -0
- package/schemas/plugins.schema.json +5 -0
- package/schemas/v0/common.schema.json +64 -0
- package/schemas/v0/plugin-registry.schema.json +225 -0
- package/schemas/v0/plugin.schema.json +175 -0
- package/schemas/v0/plugins.schema.json +84 -0
- package/schemas/v0/site.schema.json +56 -9
- package/schemas/v0/theme.schema.json +105 -22
- package/scripts/build.ts +155 -3
- package/scripts/bundle.ts +258 -95
- package/scripts/dev.ts +203 -1
- package/src/__tests__/build.test.ts +158 -1
- package/src/__tests__/bundle.test.ts +31 -0
- package/src/__tests__/cli.test.ts +14 -3
- package/src/__tests__/fixtures/fences/slides-visuals/invalid/bad-list-indent.md +5 -0
- package/src/__tests__/fixtures/fences/slides-visuals/invalid/blank-line.md +5 -0
- package/src/__tests__/fixtures/fences/slides-visuals/invalid/compare-object-items.md +9 -0
- package/src/__tests__/fixtures/fences/slides-visuals/invalid/indented-fence.md +4 -0
- package/src/__tests__/fixtures/fences/slides-visuals/invalid/stat-grid-missing-fields.md +5 -0
- package/src/__tests__/fixtures/fences/slides-visuals/invalid/unknown-type.md +3 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/compare.md +10 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/comparison-table.md +14 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/funnel.md +7 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/kpi.md +5 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/layer-cake.md +6 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/pyramid.md +6 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/quadrant-grid.md +8 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/scorecard.md +13 -0
- package/src/__tests__/fixtures/fences/slides-visuals/valid/stat-grid.md +8 -0
- package/src/__tests__/init.test.ts +35 -0
- package/src/__tests__/plugin-loader.test.ts +221 -0
- package/src/__tests__/shared.test.ts +428 -0
- package/src/__tests__/slides-visuals-fence-contract.test.ts +28 -0
- package/src/__tests__/slides-visuals-runtime-regressions.bun.test.ts +114 -0
- package/src/__tests__/styles.test.ts +35 -0
- package/src/cli.ts +9 -4
- package/src/plugin-loader.ts +245 -0
- package/src/shared.ts +614 -7
- package/src/site/styles.css +331 -0
- package/src/site/template.html +66 -5
- package/src/templates/deck.ts +186 -0
- package/src/templates/driver.ts +11 -1
- package/src/templates/minimal.ts +1 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { basename, dirname, join } from "node:path";
|
|
4
|
+
import { ENGINE_ROOT } from "./engine.ts";
|
|
5
|
+
import { exists, parseYaml, validatePath } from "./shared.ts";
|
|
6
|
+
|
|
7
|
+
export class PluginNetworkError extends Error {}
|
|
8
|
+
export class PluginIntegrityError extends Error {}
|
|
9
|
+
export class PluginPolicyError extends Error {}
|
|
10
|
+
export class PluginConfigError extends Error {}
|
|
11
|
+
|
|
12
|
+
export type PluginInjections = {
|
|
13
|
+
head: string;
|
|
14
|
+
bodyEnd: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export type KitflyMode = "docs" | "slides";
|
|
18
|
+
|
|
19
|
+
type RegistryAssetChecksums = {
|
|
20
|
+
js?: string;
|
|
21
|
+
css?: string;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
type RegistryAssets = {
|
|
25
|
+
js?: string;
|
|
26
|
+
css?: string;
|
|
27
|
+
assetSha256: RegistryAssetChecksums;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
type RegistryPlugin = {
|
|
31
|
+
name: string;
|
|
32
|
+
description: string;
|
|
33
|
+
version: string;
|
|
34
|
+
contract: string;
|
|
35
|
+
kitfly: string;
|
|
36
|
+
license: string;
|
|
37
|
+
verified: boolean;
|
|
38
|
+
modes?: KitflyMode[];
|
|
39
|
+
assets: RegistryAssets;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
type PluginRegistry = {
|
|
43
|
+
version: number;
|
|
44
|
+
updated: string;
|
|
45
|
+
baseUrl: string;
|
|
46
|
+
plugins: Record<string, RegistryPlugin>;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
type CanonicalPluginRef = {
|
|
50
|
+
id: string;
|
|
51
|
+
version: string;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const PLUGIN_ID_RE = /^[a-z][a-z0-9-]*$/;
|
|
55
|
+
const SEMVER_RE =
|
|
56
|
+
/^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
57
|
+
|
|
58
|
+
function parseCanonicalRef(spec: string): CanonicalPluginRef | null {
|
|
59
|
+
const at = spec.lastIndexOf("@");
|
|
60
|
+
if (at <= 0) return null;
|
|
61
|
+
const id = spec.slice(0, at).trim();
|
|
62
|
+
const version = spec.slice(at + 1).trim();
|
|
63
|
+
if (!id || !version) return null;
|
|
64
|
+
if (!PLUGIN_ID_RE.test(id) || id.length > 40) return null;
|
|
65
|
+
if (!SEMVER_RE.test(version)) return null;
|
|
66
|
+
return { id, version };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function sha256Hex(data: Uint8Array): string {
|
|
70
|
+
return createHash("sha256").update(data).digest("hex");
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function requiredSha256Hex(expected: string, context: string): string {
|
|
74
|
+
if (!expected.startsWith("sha256:")) {
|
|
75
|
+
throw new PluginConfigError(`${context}: expected sha256:<hex>, got ${expected}`);
|
|
76
|
+
}
|
|
77
|
+
const hex = expected.slice("sha256:".length);
|
|
78
|
+
if (!/^[0-9a-f]{64}$/i.test(hex)) {
|
|
79
|
+
throw new PluginConfigError(`${context}: invalid sha256 hex`);
|
|
80
|
+
}
|
|
81
|
+
return hex.toLowerCase();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function templateBaseUrl(url: string, baseUrl: string): string {
|
|
85
|
+
const token = "${" + "baseUrl}";
|
|
86
|
+
return url.replaceAll(token, baseUrl);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function fetchTextOrThrow(url: string): Promise<string> {
|
|
90
|
+
if (!/^https?:\/\//.test(url)) {
|
|
91
|
+
throw new PluginConfigError(`Unsupported URL scheme: ${url}`);
|
|
92
|
+
}
|
|
93
|
+
let res: Response;
|
|
94
|
+
try {
|
|
95
|
+
res = await fetch(url);
|
|
96
|
+
} catch (e) {
|
|
97
|
+
throw new PluginNetworkError(`Failed to fetch ${url}: ${String(e)}`);
|
|
98
|
+
}
|
|
99
|
+
if (!res.ok)
|
|
100
|
+
throw new PluginNetworkError(`Failed to fetch ${url}: ${res.status} ${res.statusText}`);
|
|
101
|
+
return res.text();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function readLocalTextOrThrow(root: string, relOrAbs: string): Promise<string> {
|
|
105
|
+
const rel = relOrAbs.replace(/^\//, "");
|
|
106
|
+
const fsPath = validatePath(root, ".", rel, true);
|
|
107
|
+
if (!fsPath) throw new PluginConfigError(`Invalid local plugin asset path: ${relOrAbs}`);
|
|
108
|
+
return readFile(fsPath, "utf-8");
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function fetchWithSha256Cache(
|
|
112
|
+
cacheFile: string,
|
|
113
|
+
url: string,
|
|
114
|
+
expectedSha256Hex: string,
|
|
115
|
+
assetRoot: string,
|
|
116
|
+
): Promise<string> {
|
|
117
|
+
if (!/^https?:\/\//.test(url)) {
|
|
118
|
+
const text = await readLocalTextOrThrow(assetRoot, url);
|
|
119
|
+
const actual = sha256Hex(new TextEncoder().encode(text));
|
|
120
|
+
if (actual !== expectedSha256Hex) {
|
|
121
|
+
throw new PluginIntegrityError(
|
|
122
|
+
`CHECKSUM MISMATCH for ${url}\n expected: ${expectedSha256Hex}\n got: ${actual}`,
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
return text;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (await exists(cacheFile)) {
|
|
129
|
+
const cached = await readFile(cacheFile);
|
|
130
|
+
if (sha256Hex(cached) === expectedSha256Hex) return cached.toString("utf-8");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const text = await fetchTextOrThrow(url);
|
|
134
|
+
const bytes = new TextEncoder().encode(text);
|
|
135
|
+
const actual = sha256Hex(bytes);
|
|
136
|
+
if (actual !== expectedSha256Hex) {
|
|
137
|
+
throw new PluginIntegrityError(
|
|
138
|
+
`CHECKSUM MISMATCH for ${url}\n expected: ${expectedSha256Hex}\n got: ${actual}`,
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
await mkdir(dirname(cacheFile), { recursive: true });
|
|
143
|
+
await writeFile(cacheFile, text, "utf-8");
|
|
144
|
+
return text;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export async function loadPluginRegistry(registryPath: string): Promise<PluginRegistry> {
|
|
148
|
+
const raw = await readFile(registryPath, "utf-8");
|
|
149
|
+
const parsed = parseYaml(raw) as unknown as PluginRegistry;
|
|
150
|
+
if (!parsed || typeof parsed !== "object") throw new PluginConfigError("Invalid plugin registry");
|
|
151
|
+
if (typeof parsed.baseUrl !== "string")
|
|
152
|
+
throw new PluginConfigError("Invalid plugin registry shape");
|
|
153
|
+
if (!parsed.plugins || typeof parsed.plugins !== "object") {
|
|
154
|
+
throw new PluginConfigError("Invalid plugin registry shape");
|
|
155
|
+
}
|
|
156
|
+
return parsed;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export async function loadPluginInjections(opts: {
|
|
160
|
+
root: string;
|
|
161
|
+
mode?: KitflyMode;
|
|
162
|
+
registryPath?: string;
|
|
163
|
+
configPath?: string;
|
|
164
|
+
cacheDir?: string;
|
|
165
|
+
allowUntrusted?: boolean;
|
|
166
|
+
}): Promise<PluginInjections> {
|
|
167
|
+
const configPath = opts.configPath ?? join(opts.root, "kitfly.plugins.yaml");
|
|
168
|
+
const cacheDir = opts.cacheDir ?? join(opts.root, "node_modules", ".kitfly-plugins");
|
|
169
|
+
const allowUntrusted = opts.allowUntrusted ?? false;
|
|
170
|
+
const mode: KitflyMode = opts.mode ?? "docs";
|
|
171
|
+
|
|
172
|
+
if (!(await exists(configPath))) return { head: "", bodyEnd: "" };
|
|
173
|
+
|
|
174
|
+
const engineRegistryPath = join(ENGINE_ROOT, "registry", "plugins.yaml");
|
|
175
|
+
const siteRegistryPath = join(opts.root, "registry", "plugins.yaml");
|
|
176
|
+
const hasSiteRegistry = await exists(siteRegistryPath);
|
|
177
|
+
const registryPath =
|
|
178
|
+
opts.registryPath ?? (hasSiteRegistry ? siteRegistryPath : engineRegistryPath);
|
|
179
|
+
const assetRoot = hasSiteRegistry ? opts.root : ENGINE_ROOT;
|
|
180
|
+
|
|
181
|
+
if (!(await exists(registryPath)))
|
|
182
|
+
throw new PluginConfigError(`Missing registry: ${registryPath}`);
|
|
183
|
+
|
|
184
|
+
const registry = await loadPluginRegistry(registryPath);
|
|
185
|
+
const config = parseYaml(await readFile(configPath, "utf-8")) as Record<string, unknown>;
|
|
186
|
+
const plugins = Array.isArray(config.plugins) ? config.plugins : [];
|
|
187
|
+
|
|
188
|
+
let head = "";
|
|
189
|
+
let bodyEnd = "";
|
|
190
|
+
|
|
191
|
+
for (const entry of plugins) {
|
|
192
|
+
if (typeof entry !== "string") {
|
|
193
|
+
if (allowUntrusted) {
|
|
194
|
+
throw new PluginPolicyError("Third-party plugin objects are not supported yet");
|
|
195
|
+
}
|
|
196
|
+
throw new PluginPolicyError("Third-party plugins require --allow-untrusted");
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const ref = parseCanonicalRef(entry);
|
|
200
|
+
if (!ref) throw new PluginConfigError(`Invalid plugin ref: ${entry}`);
|
|
201
|
+
const reg = registry.plugins?.[ref.id];
|
|
202
|
+
if (!reg) throw new PluginConfigError(`Plugin not in registry: ${ref.id}`);
|
|
203
|
+
if (reg.version !== ref.version) {
|
|
204
|
+
throw new PluginConfigError(
|
|
205
|
+
`Plugin ${ref.id} version mismatch: ${ref.version} != ${reg.version}`,
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (Array.isArray(reg.modes)) {
|
|
210
|
+
if (reg.modes.length === 0) continue;
|
|
211
|
+
if (!reg.modes.includes(mode)) continue;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const assets = reg.assets;
|
|
215
|
+
const pluginCacheDir = join(cacheDir, `${ref.id}@${ref.version}`);
|
|
216
|
+
|
|
217
|
+
if (assets.css) {
|
|
218
|
+
const url = templateBaseUrl(assets.css, registry.baseUrl);
|
|
219
|
+
const expected = requiredSha256Hex(
|
|
220
|
+
assets.assetSha256.css ?? "",
|
|
221
|
+
`${ref.id}: assetSha256.css`,
|
|
222
|
+
);
|
|
223
|
+
const css = await fetchWithSha256Cache(
|
|
224
|
+
join(pluginCacheDir, basename(url)),
|
|
225
|
+
url,
|
|
226
|
+
expected,
|
|
227
|
+
assetRoot,
|
|
228
|
+
);
|
|
229
|
+
head += `\n<style data-kitfly-plugin="${ref.id}@${ref.version}">\n${css}\n</style>\n`;
|
|
230
|
+
}
|
|
231
|
+
if (assets.js) {
|
|
232
|
+
const url = templateBaseUrl(assets.js, registry.baseUrl);
|
|
233
|
+
const expected = requiredSha256Hex(assets.assetSha256.js ?? "", `${ref.id}: assetSha256.js`);
|
|
234
|
+
const js = await fetchWithSha256Cache(
|
|
235
|
+
join(pluginCacheDir, basename(url)),
|
|
236
|
+
url,
|
|
237
|
+
expected,
|
|
238
|
+
assetRoot,
|
|
239
|
+
);
|
|
240
|
+
bodyEnd += `\n<script data-kitfly-plugin="${ref.id}@${ref.version}">\n${js}\n</script>\n`;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return { head, bodyEnd };
|
|
245
|
+
}
|