@agimon-ai/doompi-style-system 0.0.1-alpha.100
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/LICENSE +21 -0
- package/README.md +53 -0
- package/dist/apiContracts.cjs +118 -0
- package/dist/apiContracts.cjs.map +1 -0
- package/dist/apiContracts.d.mts +52 -0
- package/dist/apiContracts.d.mts.map +1 -0
- package/dist/apiContracts.mjs +113 -0
- package/dist/apiContracts.mjs.map +1 -0
- package/dist/cli.cjs +242 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.mts +4 -0
- package/dist/cli.d.mts.map +1 -0
- package/dist/cli.mjs +239 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/designCheck-7P9r9ijq.mjs +475 -0
- package/dist/designCheck-7P9r9ijq.mjs.map +1 -0
- package/dist/designCheck-zx4PsRvE.cjs +495 -0
- package/dist/designCheck-zx4PsRvE.cjs.map +1 -0
- package/dist/extensions/pi.cjs +94 -0
- package/dist/extensions/pi.cjs.map +1 -0
- package/dist/extensions/pi.d.mts +5 -0
- package/dist/extensions/pi.d.mts.map +1 -0
- package/dist/extensions/pi.mjs +87 -0
- package/dist/extensions/pi.mjs.map +1 -0
- package/dist/extensions/server.cjs +136 -0
- package/dist/extensions/server.cjs.map +1 -0
- package/dist/extensions/server.d.mts +5 -0
- package/dist/extensions/server.d.mts.map +1 -0
- package/dist/extensions/server.mjs +131 -0
- package/dist/extensions/server.mjs.map +1 -0
- package/dist/extensions/web.mjs +942 -0
- package/dist/extensions/web.mjs.map +1 -0
- package/dist/index.cjs +8 -0
- package/dist/index.d.mts +171 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +3 -0
- package/dist/rolldown-runtime-VH7oDXx4.cjs +28 -0
- package/dist/storyPreview-D-hGhlig.cjs +371 -0
- package/dist/storyPreview-D-hGhlig.cjs.map +1 -0
- package/dist/storyPreview-Dhejqhos.mjs +357 -0
- package/dist/storyPreview-Dhejqhos.mjs.map +1 -0
- package/package.json +132 -0
- package/skills/design-workflow/SKILL.md +84 -0
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.cjs");
|
|
2
|
+
let node_crypto = require("node:crypto");
|
|
3
|
+
let node_fs = require("node:fs");
|
|
4
|
+
let node_path = require("node:path");
|
|
5
|
+
node_path = require_rolldown_runtime.__toESM(node_path, 1);
|
|
6
|
+
let node_os = require("node:os");
|
|
7
|
+
node_os = require_rolldown_runtime.__toESM(node_os, 1);
|
|
8
|
+
let _agimon_ai_style_system = require("@agimon-ai/style-system");
|
|
9
|
+
//#region src/services/storyPreview/index.ts
|
|
10
|
+
const STORY_FILE_PATTERN = /\.stories\.(?:js|jsx|ts|tsx)$/u;
|
|
11
|
+
const STORY_EXPORT_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
12
|
+
const PNG_SIGNATURE = Buffer.from([
|
|
13
|
+
137,
|
|
14
|
+
80,
|
|
15
|
+
78,
|
|
16
|
+
71,
|
|
17
|
+
13,
|
|
18
|
+
10,
|
|
19
|
+
26,
|
|
20
|
+
10
|
|
21
|
+
]);
|
|
22
|
+
const MAX_IMAGE_BYTES = 2097152;
|
|
23
|
+
const MAX_IMAGE_DIMENSION = 1600;
|
|
24
|
+
const NON_STORY_EXPORTS = /* @__PURE__ */ new Set([
|
|
25
|
+
"afterAll",
|
|
26
|
+
"afterEach",
|
|
27
|
+
"argTypes",
|
|
28
|
+
"beforeAll",
|
|
29
|
+
"beforeEach",
|
|
30
|
+
"component",
|
|
31
|
+
"decorators",
|
|
32
|
+
"excludeStories",
|
|
33
|
+
"globals",
|
|
34
|
+
"includeStories",
|
|
35
|
+
"loaders",
|
|
36
|
+
"meta",
|
|
37
|
+
"parameters",
|
|
38
|
+
"render",
|
|
39
|
+
"tags"
|
|
40
|
+
]);
|
|
41
|
+
function isContained(root, candidate) {
|
|
42
|
+
const relative = node_path.default.relative(root, candidate);
|
|
43
|
+
return relative === "" || !relative.startsWith(`..${node_path.default.sep}`) && relative !== ".." && !node_path.default.isAbsolute(relative);
|
|
44
|
+
}
|
|
45
|
+
function stripComments(source) {
|
|
46
|
+
let output = "";
|
|
47
|
+
let quote;
|
|
48
|
+
let escaped = false;
|
|
49
|
+
for (let index = 0; index < source.length; index += 1) {
|
|
50
|
+
const character = source[index];
|
|
51
|
+
const next = source[index + 1];
|
|
52
|
+
if (quote !== void 0) {
|
|
53
|
+
output += character === "\n" ? "\n" : " ";
|
|
54
|
+
if (escaped) escaped = false;
|
|
55
|
+
else if (character === "\\") escaped = true;
|
|
56
|
+
else if (character === quote) quote = void 0;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (character === "\"" || character === "'" || character === "`") {
|
|
60
|
+
quote = character;
|
|
61
|
+
output += " ";
|
|
62
|
+
} else if (character === "/" && next === "/") {
|
|
63
|
+
output += " ";
|
|
64
|
+
index += 2;
|
|
65
|
+
while (index < source.length && source[index] !== "\n") {
|
|
66
|
+
output += " ";
|
|
67
|
+
index += 1;
|
|
68
|
+
}
|
|
69
|
+
if (index < source.length) output += "\n";
|
|
70
|
+
} else if (character === "/" && next === "*") {
|
|
71
|
+
output += " ";
|
|
72
|
+
index += 2;
|
|
73
|
+
while (index < source.length && !(source[index - 1] === "*" && source[index] === "/")) {
|
|
74
|
+
output += source[index] === "\n" ? "\n" : " ";
|
|
75
|
+
index += 1;
|
|
76
|
+
}
|
|
77
|
+
} else output += character;
|
|
78
|
+
}
|
|
79
|
+
return output;
|
|
80
|
+
}
|
|
81
|
+
function storyLabel(source, clean, exportName) {
|
|
82
|
+
const escapedExport = exportName.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
83
|
+
const declaration = new RegExp(`\\bexport\\s+(?:const|let|var)\\s+${escapedExport}\\b[^=]*=\\s*\\{`, "u");
|
|
84
|
+
const match = clean.match(declaration);
|
|
85
|
+
if (match === null || match.index === void 0) return void 0;
|
|
86
|
+
const opening = clean.indexOf("{", match.index);
|
|
87
|
+
let depth = 0;
|
|
88
|
+
for (let index = opening; index < clean.length; index += 1) if (clean[index] === "{") depth += 1;
|
|
89
|
+
else if (clean[index] === "}") {
|
|
90
|
+
depth -= 1;
|
|
91
|
+
if (depth === 0) {
|
|
92
|
+
const label = source.slice(opening, index).match(/\bname\s*:\s*(['"])(.*?)\1/u)?.[2]?.trim();
|
|
93
|
+
return label === "" ? void 0 : label;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** Extracts named CSF candidates without evaluating workspace source. */
|
|
98
|
+
function extractStoryExports(source) {
|
|
99
|
+
const names = [];
|
|
100
|
+
const seen = /* @__PURE__ */ new Set();
|
|
101
|
+
const add = (name) => {
|
|
102
|
+
if (name === "default" || NON_STORY_EXPORTS.has(name) || seen.has(name)) return;
|
|
103
|
+
seen.add(name);
|
|
104
|
+
names.push(name);
|
|
105
|
+
};
|
|
106
|
+
const clean = stripComments(source);
|
|
107
|
+
for (const match of clean.matchAll(/\bexport\s+(?:async\s+)?(?:const|let|var|function|class)\s+([A-Za-z_$][A-Za-z0-9_$]*)/gu)) add(match[1]);
|
|
108
|
+
for (const match of clean.matchAll(/\bexport\s*\{([^}]*)\}/gu)) for (const item of match[1].split(",")) {
|
|
109
|
+
const name = (item.trim().split(/\s+as\s+/u).at(-1) ?? "").trim();
|
|
110
|
+
if (/^[A-Za-z_$][A-Za-z0-9_$]*$/u.test(name)) add(name);
|
|
111
|
+
}
|
|
112
|
+
return names.map((exportName) => {
|
|
113
|
+
const label = storyLabel(source, clean, exportName);
|
|
114
|
+
return label === void 0 ? { exportName } : {
|
|
115
|
+
exportName,
|
|
116
|
+
label
|
|
117
|
+
};
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
async function exists(filePath) {
|
|
121
|
+
try {
|
|
122
|
+
await node_fs.promises.stat(filePath);
|
|
123
|
+
return true;
|
|
124
|
+
} catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function relativeWorkspacePath(root, candidate) {
|
|
129
|
+
const relative = node_path.default.relative(root, candidate).split(node_path.default.sep).join("/");
|
|
130
|
+
return relative === "" ? "." : relative;
|
|
131
|
+
}
|
|
132
|
+
const defaultDependencies = {
|
|
133
|
+
loadConfig: _agimon_ai_style_system.getAppDesignSystemConfig,
|
|
134
|
+
createBundler(_config) {
|
|
135
|
+
return (0, _agimon_ai_style_system.createDefaultBundlerService)();
|
|
136
|
+
},
|
|
137
|
+
createRenderer(config, appPath) {
|
|
138
|
+
return new _agimon_ai_style_system.ComponentRendererService(config, appPath);
|
|
139
|
+
},
|
|
140
|
+
rendererTemporaryRoot: () => node_path.default.join(node_os.default.tmpdir(), "style-system"),
|
|
141
|
+
createHandle: node_crypto.randomUUID
|
|
142
|
+
};
|
|
143
|
+
function pngCrc(data) {
|
|
144
|
+
let crc = 4294967295;
|
|
145
|
+
for (const byte of data) {
|
|
146
|
+
crc ^= byte;
|
|
147
|
+
for (let bit = 0; bit < 8; bit += 1) crc = crc >>> 1 ^ (crc & 1 ? 3988292384 : 0);
|
|
148
|
+
}
|
|
149
|
+
return (crc ^ 4294967295) >>> 0;
|
|
150
|
+
}
|
|
151
|
+
function pngDimensions(image) {
|
|
152
|
+
if (image.length < PNG_SIGNATURE.length || !image.subarray(0, PNG_SIGNATURE.length).equals(PNG_SIGNATURE)) throw new Error("Style-system returned an invalid PNG image");
|
|
153
|
+
let offset = PNG_SIGNATURE.length;
|
|
154
|
+
let width = 0;
|
|
155
|
+
let height = 0;
|
|
156
|
+
let chunks = 0;
|
|
157
|
+
let hasImageData = false;
|
|
158
|
+
let hasEnd = false;
|
|
159
|
+
while (offset < image.length) {
|
|
160
|
+
if (image.length - offset < 12) throw new Error("Style-system returned an invalid PNG image");
|
|
161
|
+
const length = image.readUInt32BE(offset);
|
|
162
|
+
const end = offset + 12 + length;
|
|
163
|
+
if (end > image.length) throw new Error("Style-system returned an invalid PNG image");
|
|
164
|
+
const type = image.toString("ascii", offset + 4, offset + 8);
|
|
165
|
+
if (!/^[A-Za-z]{4}$/u.test(type)) throw new Error("Style-system returned an invalid PNG image");
|
|
166
|
+
if (image.readUInt32BE(end - 4) !== pngCrc(image.subarray(offset + 4, end - 4))) throw new Error("Style-system returned an invalid PNG image");
|
|
167
|
+
if (chunks === 0) {
|
|
168
|
+
if (type !== "IHDR" || length !== 13) throw new Error("Style-system returned an invalid PNG image");
|
|
169
|
+
width = image.readUInt32BE(offset + 8);
|
|
170
|
+
height = image.readUInt32BE(offset + 12);
|
|
171
|
+
} else if (type === "IHDR") throw new Error("Style-system returned an invalid PNG image");
|
|
172
|
+
if (type === "IDAT") hasImageData = true;
|
|
173
|
+
if (type === "IEND") {
|
|
174
|
+
if (length !== 0 || end !== image.length) throw new Error("Style-system returned an invalid PNG image");
|
|
175
|
+
hasEnd = true;
|
|
176
|
+
}
|
|
177
|
+
chunks += 1;
|
|
178
|
+
offset = end;
|
|
179
|
+
}
|
|
180
|
+
if (!hasImageData || !hasEnd) throw new Error("Style-system returned an invalid PNG image");
|
|
181
|
+
if (width === 0 || height === 0 || width > MAX_IMAGE_DIMENSION || height > MAX_IMAGE_DIMENSION) throw new Error("Style-system returned PNG dimensions outside the supported range");
|
|
182
|
+
return {
|
|
183
|
+
width,
|
|
184
|
+
height
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
/** Owns disposable static story-preview artifacts for one trusted workspace. */
|
|
188
|
+
var StoryPreviewService = class {
|
|
189
|
+
root;
|
|
190
|
+
dependencies;
|
|
191
|
+
artifacts = /* @__PURE__ */ new Map();
|
|
192
|
+
constructor(workspaceRoot, dependencies = {}) {
|
|
193
|
+
this.root = node_path.default.resolve(workspaceRoot);
|
|
194
|
+
this.dependencies = {
|
|
195
|
+
...defaultDependencies,
|
|
196
|
+
...dependencies
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
async metadata(input) {
|
|
200
|
+
const root = await node_fs.promises.realpath(this.root);
|
|
201
|
+
const storyPath = await this.resolveContainedPath(root, input.storyPath, "storyPath");
|
|
202
|
+
if (!STORY_FILE_PATTERN.test(storyPath)) throw new Error("storyPath must name a .stories.js, .stories.jsx, .stories.ts, or .stories.tsx file");
|
|
203
|
+
const project = await this.resolveProject(root, storyPath, input.appPath);
|
|
204
|
+
const source = await node_fs.promises.readFile(storyPath, "utf8");
|
|
205
|
+
return {
|
|
206
|
+
storyPath: relativeWorkspacePath(root, storyPath),
|
|
207
|
+
appPath: relativeWorkspacePath(root, project.path),
|
|
208
|
+
projectResolution: project.resolution,
|
|
209
|
+
exports: extractStoryExports(source)
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
async resolveProject(root, storyPath, requestedPath) {
|
|
213
|
+
if (requestedPath !== void 0 && requestedPath.trim() !== "") return {
|
|
214
|
+
path: await this.resolveContainedPath(root, requestedPath, "appPath"),
|
|
215
|
+
resolution: "explicit"
|
|
216
|
+
};
|
|
217
|
+
let directory = node_path.default.dirname(storyPath);
|
|
218
|
+
let packagePath;
|
|
219
|
+
while (isContained(root, directory)) {
|
|
220
|
+
if (await exists(node_path.default.join(directory, "style-system.config.yaml"))) return {
|
|
221
|
+
path: directory,
|
|
222
|
+
resolution: "config"
|
|
223
|
+
};
|
|
224
|
+
if (packagePath === void 0 && await exists(node_path.default.join(directory, "package.json"))) packagePath = directory;
|
|
225
|
+
if (directory === root) break;
|
|
226
|
+
directory = node_path.default.dirname(directory);
|
|
227
|
+
}
|
|
228
|
+
return packagePath === void 0 ? {
|
|
229
|
+
path: root,
|
|
230
|
+
resolution: "workspace"
|
|
231
|
+
} : {
|
|
232
|
+
path: packagePath,
|
|
233
|
+
resolution: "package"
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
async exactStory(root, storyPath, storyExport) {
|
|
237
|
+
if (!extractStoryExports(await node_fs.promises.readFile(storyPath, "utf8")).some((entry) => entry.exportName === storyExport)) throw new Error(`Story export "${storyExport}" was not found in ${relativeWorkspacePath(root, storyPath)}.`);
|
|
238
|
+
const index = new _agimon_ai_style_system.StoriesIndexService({
|
|
239
|
+
workspaceRoot: root,
|
|
240
|
+
storyFiles: [storyPath],
|
|
241
|
+
searchRoots: []
|
|
242
|
+
});
|
|
243
|
+
await index.initialize();
|
|
244
|
+
const component = index.getAllComponents().find((entry) => node_path.default.resolve(entry.filePath) === storyPath);
|
|
245
|
+
if (component === void 0) throw new Error("The requested story file could not be indexed.");
|
|
246
|
+
return component;
|
|
247
|
+
}
|
|
248
|
+
async build(input) {
|
|
249
|
+
if (!STORY_EXPORT_PATTERN.test(input.storyExport)) throw new Error("storyExport must be an exact JavaScript named export");
|
|
250
|
+
const root = await node_fs.promises.realpath(this.root);
|
|
251
|
+
const appPath = await this.resolveContainedPath(root, input.appPath, "appPath");
|
|
252
|
+
const storyPath = await this.resolveContainedPath(root, input.storyPath, "storyPath");
|
|
253
|
+
if (!STORY_FILE_PATTERN.test(storyPath)) throw new Error("storyPath must name a .stories.js, .stories.jsx, .stories.ts, or .stories.tsx file");
|
|
254
|
+
await this.exactStory(root, storyPath, input.storyExport);
|
|
255
|
+
const [source, config] = await Promise.all([node_fs.promises.readFile(storyPath, "utf8"), this.dependencies.loadConfig(appPath)]);
|
|
256
|
+
const bundler = this.dependencies.createBundler(config);
|
|
257
|
+
let artifactDirectory;
|
|
258
|
+
try {
|
|
259
|
+
const rendered = await bundler.prerenderComponent({
|
|
260
|
+
componentPath: storyPath,
|
|
261
|
+
storyName: input.storyExport,
|
|
262
|
+
args: input.args,
|
|
263
|
+
darkMode: input.darkMode,
|
|
264
|
+
appPath,
|
|
265
|
+
themePath: config.themeProvider,
|
|
266
|
+
cssFiles: config.cssFiles,
|
|
267
|
+
rootComponent: config.rootComponent,
|
|
268
|
+
unistylesConfig: config.unistylesConfig
|
|
269
|
+
});
|
|
270
|
+
const htmlPath = await node_fs.promises.realpath(rendered.htmlFilePath);
|
|
271
|
+
const candidateDirectory = node_path.default.dirname(htmlPath);
|
|
272
|
+
const temporaryRoot = node_path.default.join(appPath, ".tmp");
|
|
273
|
+
if (candidateDirectory === temporaryRoot || !isContained(temporaryRoot, candidateDirectory)) throw new Error("Style-system returned a preview artifact outside the project temporary directory");
|
|
274
|
+
artifactDirectory = candidateDirectory;
|
|
275
|
+
const handle = this.dependencies.createHandle();
|
|
276
|
+
const html = await node_fs.promises.readFile(htmlPath, "utf8");
|
|
277
|
+
this.artifacts.set(handle, { directory: artifactDirectory });
|
|
278
|
+
return {
|
|
279
|
+
handle,
|
|
280
|
+
html,
|
|
281
|
+
storyPath: relativeWorkspacePath(root, storyPath),
|
|
282
|
+
storyExport: input.storyExport,
|
|
283
|
+
sourceSha256: (0, node_crypto.createHash)("sha256").update(source).digest("hex")
|
|
284
|
+
};
|
|
285
|
+
} catch (reason) {
|
|
286
|
+
if (artifactDirectory !== void 0) await node_fs.promises.rm(artifactDirectory, {
|
|
287
|
+
recursive: true,
|
|
288
|
+
force: true
|
|
289
|
+
});
|
|
290
|
+
throw reason;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/** Renders a fresh source-backed PNG. This does not preserve transient iframe interaction state. */
|
|
294
|
+
async exportImage(input) {
|
|
295
|
+
if (!STORY_EXPORT_PATTERN.test(input.storyExport)) throw new Error("storyExport must be an exact JavaScript named export");
|
|
296
|
+
const root = await node_fs.promises.realpath(this.root);
|
|
297
|
+
const appPath = await this.resolveContainedPath(root, input.appPath, "appPath");
|
|
298
|
+
const storyPath = await this.resolveContainedPath(root, input.storyPath, "storyPath");
|
|
299
|
+
if (!STORY_FILE_PATTERN.test(storyPath)) throw new Error("storyPath must name a .stories.js, .stories.jsx, .stories.ts, or .stories.tsx file");
|
|
300
|
+
const [source, config] = await Promise.all([node_fs.promises.readFile(storyPath, "utf8"), this.dependencies.loadConfig(appPath)]);
|
|
301
|
+
const renderer = this.dependencies.createRenderer(config, appPath);
|
|
302
|
+
let ownedImagePath;
|
|
303
|
+
try {
|
|
304
|
+
const component = await this.exactStory(root, storyPath, input.storyExport);
|
|
305
|
+
const rendered = await renderer.renderComponent(component, {
|
|
306
|
+
storyName: input.storyExport,
|
|
307
|
+
darkMode: input.darkMode
|
|
308
|
+
});
|
|
309
|
+
const [renderedImagePath, imageRoot] = await Promise.all([node_fs.promises.realpath(rendered.imagePath), node_fs.promises.realpath(this.dependencies.rendererTemporaryRoot())]);
|
|
310
|
+
if (renderedImagePath === imageRoot || !isContained(imageRoot, renderedImagePath)) throw new Error("Style-system returned an image artifact outside its temporary directory");
|
|
311
|
+
const imageStat = await node_fs.promises.stat(renderedImagePath);
|
|
312
|
+
if (!imageStat.isFile()) throw new Error("Style-system returned a non-regular PNG image");
|
|
313
|
+
ownedImagePath = renderedImagePath;
|
|
314
|
+
if (imageStat.size > MAX_IMAGE_BYTES) throw new Error("Style-system returned an oversized PNG image");
|
|
315
|
+
const image = await node_fs.promises.readFile(renderedImagePath);
|
|
316
|
+
if (image.length !== imageStat.size) throw new Error("Style-system PNG changed while it was being read");
|
|
317
|
+
const { width, height } = pngDimensions(image);
|
|
318
|
+
return {
|
|
319
|
+
data: image.toString("base64"),
|
|
320
|
+
mimeType: "image/png",
|
|
321
|
+
captureId: this.dependencies.createHandle(),
|
|
322
|
+
width,
|
|
323
|
+
height,
|
|
324
|
+
storyPath: relativeWorkspacePath(root, storyPath),
|
|
325
|
+
storyExport: input.storyExport,
|
|
326
|
+
sourceSha256: (0, node_crypto.createHash)("sha256").update(source).digest("hex")
|
|
327
|
+
};
|
|
328
|
+
} finally {
|
|
329
|
+
try {
|
|
330
|
+
if (ownedImagePath !== void 0) await node_fs.promises.rm(ownedImagePath, { force: true });
|
|
331
|
+
} finally {
|
|
332
|
+
await renderer.dispose();
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
async dispose(handle) {
|
|
337
|
+
const artifact = this.artifacts.get(handle);
|
|
338
|
+
if (artifact === void 0) return false;
|
|
339
|
+
this.artifacts.delete(handle);
|
|
340
|
+
await node_fs.promises.rm(artifact.directory, {
|
|
341
|
+
recursive: true,
|
|
342
|
+
force: true
|
|
343
|
+
});
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
async disposeAll() {
|
|
347
|
+
await Promise.all([...this.artifacts.keys()].map((handle) => this.dispose(handle)));
|
|
348
|
+
}
|
|
349
|
+
async resolveContainedPath(root, inputPath, field) {
|
|
350
|
+
if (inputPath.trim() === "") throw new Error(`${field} is required`);
|
|
351
|
+
const candidate = node_path.default.isAbsolute(inputPath) ? inputPath : node_path.default.resolve(root, inputPath);
|
|
352
|
+
const canonical = await node_fs.promises.realpath(candidate);
|
|
353
|
+
if (!isContained(root, canonical)) throw new Error(`${field} must remain inside the workspace root`);
|
|
354
|
+
return canonical;
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
//#endregion
|
|
358
|
+
Object.defineProperty(exports, "StoryPreviewService", {
|
|
359
|
+
enumerable: true,
|
|
360
|
+
get: function() {
|
|
361
|
+
return StoryPreviewService;
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
Object.defineProperty(exports, "extractStoryExports", {
|
|
365
|
+
enumerable: true,
|
|
366
|
+
get: function() {
|
|
367
|
+
return extractStoryExports;
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
//# sourceMappingURL=storyPreview-D-hGhlig.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storyPreview-D-hGhlig.cjs","names":["path","fs","getAppDesignSystemConfig","createDefaultBundlerService","ComponentRendererService","os","randomUUID","StoriesIndexService","createHash"],"sources":["../src/services/storyPreview/index.ts"],"sourcesContent":["import { createHash, randomUUID } from 'node:crypto';\nimport { promises as fs } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\n\nimport {\n ComponentRendererService,\n createDefaultBundlerService,\n getAppDesignSystemConfig,\n StoriesIndexService,\n type BaseBundlerService,\n type DesignSystemConfig,\n} from '@agimon-ai/style-system';\n\nimport type { StoryPreviewExport, StoryPreviewMetadataRequest, StoryPreviewMetadataView } from '../../types/previewApi';\nimport type {\n StoryPreviewBuildInput,\n StoryPreviewBuildResult,\n StoryPreviewImageResult,\n StoryPreviewServiceDependencies,\n} from './type';\n\nconst STORY_FILE_PATTERN = /\\.stories\\.(?:js|jsx|ts|tsx)$/u;\nconst STORY_EXPORT_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;\nconst PNG_SIGNATURE = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);\nconst MAX_IMAGE_BYTES = 2 * 1024 * 1024;\nconst MAX_IMAGE_DIMENSION = 1600;\nconst NON_STORY_EXPORTS = new Set([\n 'afterAll',\n 'afterEach',\n 'argTypes',\n 'beforeAll',\n 'beforeEach',\n 'component',\n 'decorators',\n 'excludeStories',\n 'globals',\n 'includeStories',\n 'loaders',\n 'meta',\n 'parameters',\n 'render',\n 'tags',\n]);\n\ninterface OwnedArtifact {\n directory: string;\n}\n\nfunction isContained(root: string, candidate: string): boolean {\n const relative = path.relative(root, candidate);\n return relative === '' || (!relative.startsWith(`..${path.sep}`) && relative !== '..' && !path.isAbsolute(relative));\n}\n\nfunction stripComments(source: string): string {\n let output = '';\n let quote: \"'\" | '\"' | '`' | undefined;\n let escaped = false;\n for (let index = 0; index < source.length; index += 1) {\n const character = source[index];\n const next = source[index + 1];\n if (quote !== undefined) {\n output += character === '\\n' ? '\\n' : ' ';\n if (escaped) escaped = false;\n else if (character === '\\\\') escaped = true;\n else if (character === quote) quote = undefined;\n continue;\n }\n if (character === '\"' || character === \"'\" || character === '`') {\n quote = character;\n output += ' ';\n } else if (character === '/' && next === '/') {\n output += ' ';\n index += 2;\n while (index < source.length && source[index] !== '\\n') {\n output += ' ';\n index += 1;\n }\n if (index < source.length) output += '\\n';\n } else if (character === '/' && next === '*') {\n output += ' ';\n index += 2;\n while (index < source.length && !(source[index - 1] === '*' && source[index] === '/')) {\n output += source[index] === '\\n' ? '\\n' : ' ';\n index += 1;\n }\n } else output += character;\n }\n return output;\n}\n\nfunction storyLabel(source: string, clean: string, exportName: string): string | undefined {\n const escapedExport = exportName.replace(/[.*+?^${}()|[\\]\\\\]/gu, '\\\\$&');\n const declaration = new RegExp(`\\\\bexport\\\\s+(?:const|let|var)\\\\s+${escapedExport}\\\\b[^=]*=\\\\s*\\\\{`, 'u');\n const match = clean.match(declaration);\n if (match === null || match.index === undefined) return undefined;\n const opening = clean.indexOf('{', match.index);\n let depth = 0;\n for (let index = opening; index < clean.length; index += 1) {\n if (clean[index] === '{') depth += 1;\n else if (clean[index] === '}') {\n depth -= 1;\n if (depth === 0) {\n const label = source\n .slice(opening, index)\n .match(/\\bname\\s*:\\s*(['\"])(.*?)\\1/u)?.[2]\n ?.trim();\n return label === '' ? undefined : label;\n }\n }\n }\n return undefined;\n}\n\n/** Extracts named CSF candidates without evaluating workspace source. */\nexport function extractStoryExports(source: string): readonly StoryPreviewExport[] {\n const names: string[] = [];\n const seen = new Set<string>();\n const add = (name: string): void => {\n if (name === 'default' || NON_STORY_EXPORTS.has(name) || seen.has(name)) return;\n seen.add(name);\n names.push(name);\n };\n const clean = stripComments(source);\n const declarations = /\\bexport\\s+(?:async\\s+)?(?:const|let|var|function|class)\\s+([A-Za-z_$][A-Za-z0-9_$]*)/gu;\n for (const match of clean.matchAll(declarations)) add(match[1]!);\n const lists = /\\bexport\\s*\\{([^}]*)\\}/gu;\n for (const match of clean.matchAll(lists)) {\n for (const item of match[1]!.split(',')) {\n const parts = item.trim().split(/\\s+as\\s+/u);\n const name = (parts.at(-1) ?? '').trim();\n if (/^[A-Za-z_$][A-Za-z0-9_$]*$/u.test(name)) add(name);\n }\n }\n return names.map((exportName) => {\n const label = storyLabel(source, clean, exportName);\n return label === undefined ? { exportName } : { exportName, label };\n });\n}\n\nasync function exists(filePath: string): Promise<boolean> {\n try {\n await fs.stat(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction relativeWorkspacePath(root: string, candidate: string): string {\n const relative = path.relative(root, candidate).split(path.sep).join('/');\n return relative === '' ? '.' : relative;\n}\n\nconst defaultDependencies: StoryPreviewServiceDependencies = {\n loadConfig: getAppDesignSystemConfig,\n createBundler(_config: DesignSystemConfig): BaseBundlerService {\n return createDefaultBundlerService();\n },\n createRenderer(config, appPath) {\n return new ComponentRendererService(config, appPath);\n },\n rendererTemporaryRoot: () => path.join(os.tmpdir(), 'style-system'),\n createHandle: randomUUID,\n};\n\nfunction pngCrc(data: Buffer): number {\n let crc = 0xffffffff;\n for (const byte of data) {\n crc ^= byte;\n for (let bit = 0; bit < 8; bit += 1) crc = (crc >>> 1) ^ (crc & 1 ? 0xedb88320 : 0);\n }\n return (crc ^ 0xffffffff) >>> 0;\n}\n\nfunction pngDimensions(image: Buffer): { width: number; height: number } {\n if (image.length < PNG_SIGNATURE.length || !image.subarray(0, PNG_SIGNATURE.length).equals(PNG_SIGNATURE)) {\n throw new Error('Style-system returned an invalid PNG image');\n }\n let offset = PNG_SIGNATURE.length;\n let width = 0;\n let height = 0;\n let chunks = 0;\n let hasImageData = false;\n let hasEnd = false;\n while (offset < image.length) {\n if (image.length - offset < 12) throw new Error('Style-system returned an invalid PNG image');\n const length = image.readUInt32BE(offset);\n const end = offset + 12 + length;\n if (end > image.length) throw new Error('Style-system returned an invalid PNG image');\n const type = image.toString('ascii', offset + 4, offset + 8);\n if (!/^[A-Za-z]{4}$/u.test(type)) throw new Error('Style-system returned an invalid PNG image');\n if (image.readUInt32BE(end - 4) !== pngCrc(image.subarray(offset + 4, end - 4))) {\n throw new Error('Style-system returned an invalid PNG image');\n }\n if (chunks === 0) {\n if (type !== 'IHDR' || length !== 13) throw new Error('Style-system returned an invalid PNG image');\n width = image.readUInt32BE(offset + 8);\n height = image.readUInt32BE(offset + 12);\n } else if (type === 'IHDR') throw new Error('Style-system returned an invalid PNG image');\n if (type === 'IDAT') hasImageData = true;\n if (type === 'IEND') {\n if (length !== 0 || end !== image.length) throw new Error('Style-system returned an invalid PNG image');\n hasEnd = true;\n }\n chunks += 1;\n offset = end;\n }\n if (!hasImageData || !hasEnd) throw new Error('Style-system returned an invalid PNG image');\n if (width === 0 || height === 0 || width > MAX_IMAGE_DIMENSION || height > MAX_IMAGE_DIMENSION) {\n throw new Error('Style-system returned PNG dimensions outside the supported range');\n }\n return { width, height };\n}\n\n/** Owns disposable static story-preview artifacts for one trusted workspace. */\nexport class StoryPreviewService {\n private readonly root: string;\n private readonly dependencies: StoryPreviewServiceDependencies;\n private readonly artifacts = new Map<string, OwnedArtifact>();\n\n constructor(workspaceRoot: string, dependencies: Partial<StoryPreviewServiceDependencies> = {}) {\n this.root = path.resolve(workspaceRoot);\n this.dependencies = { ...defaultDependencies, ...dependencies };\n }\n\n async metadata(input: StoryPreviewMetadataRequest): Promise<StoryPreviewMetadataView> {\n const root = await fs.realpath(this.root);\n const storyPath = await this.resolveContainedPath(root, input.storyPath, 'storyPath');\n if (!STORY_FILE_PATTERN.test(storyPath))\n throw new Error('storyPath must name a .stories.js, .stories.jsx, .stories.ts, or .stories.tsx file');\n const project = await this.resolveProject(root, storyPath, input.appPath);\n const source = await fs.readFile(storyPath, 'utf8');\n return {\n storyPath: relativeWorkspacePath(root, storyPath),\n appPath: relativeWorkspacePath(root, project.path),\n projectResolution: project.resolution,\n exports: extractStoryExports(source),\n };\n }\n\n private async resolveProject(\n root: string,\n storyPath: string,\n requestedPath: string | undefined,\n ): Promise<{ path: string; resolution: StoryPreviewMetadataView['projectResolution'] }> {\n if (requestedPath !== undefined && requestedPath.trim() !== '') {\n return { path: await this.resolveContainedPath(root, requestedPath, 'appPath'), resolution: 'explicit' };\n }\n let directory = path.dirname(storyPath);\n let packagePath: string | undefined;\n while (isContained(root, directory)) {\n if (await exists(path.join(directory, 'style-system.config.yaml'))) {\n return { path: directory, resolution: 'config' };\n }\n if (packagePath === undefined && (await exists(path.join(directory, 'package.json')))) packagePath = directory;\n if (directory === root) break;\n directory = path.dirname(directory);\n }\n return packagePath === undefined\n ? { path: root, resolution: 'workspace' }\n : { path: packagePath, resolution: 'package' };\n }\n\n private async exactStory(root: string, storyPath: string, storyExport: string) {\n const source = await fs.readFile(storyPath, 'utf8');\n if (!extractStoryExports(source).some((entry) => entry.exportName === storyExport)) {\n throw new Error(`Story export \"${storyExport}\" was not found in ${relativeWorkspacePath(root, storyPath)}.`);\n }\n const index = new StoriesIndexService({ workspaceRoot: root, storyFiles: [storyPath], searchRoots: [] });\n await index.initialize();\n const component = index.getAllComponents().find((entry) => path.resolve(entry.filePath) === storyPath);\n if (component === undefined) throw new Error('The requested story file could not be indexed.');\n return component;\n }\n\n async build(input: StoryPreviewBuildInput): Promise<StoryPreviewBuildResult> {\n if (!STORY_EXPORT_PATTERN.test(input.storyExport)) {\n throw new Error('storyExport must be an exact JavaScript named export');\n }\n\n const root = await fs.realpath(this.root);\n const appPath = await this.resolveContainedPath(root, input.appPath, 'appPath');\n const storyPath = await this.resolveContainedPath(root, input.storyPath, 'storyPath');\n if (!STORY_FILE_PATTERN.test(storyPath))\n throw new Error('storyPath must name a .stories.js, .stories.jsx, .stories.ts, or .stories.tsx file');\n await this.exactStory(root, storyPath, input.storyExport);\n\n const [source, config] = await Promise.all([fs.readFile(storyPath, 'utf8'), this.dependencies.loadConfig(appPath)]);\n const bundler = this.dependencies.createBundler(config);\n let artifactDirectory: string | undefined;\n try {\n const rendered = await bundler.prerenderComponent({\n componentPath: storyPath,\n storyName: input.storyExport,\n args: input.args,\n darkMode: input.darkMode,\n appPath,\n themePath: config.themeProvider,\n cssFiles: config.cssFiles,\n rootComponent: config.rootComponent,\n unistylesConfig: config.unistylesConfig,\n });\n\n const htmlPath = await fs.realpath(rendered.htmlFilePath);\n const candidateDirectory = path.dirname(htmlPath);\n const temporaryRoot = path.join(appPath, '.tmp');\n if (candidateDirectory === temporaryRoot || !isContained(temporaryRoot, candidateDirectory)) {\n throw new Error('Style-system returned a preview artifact outside the project temporary directory');\n }\n artifactDirectory = candidateDirectory;\n\n const handle = this.dependencies.createHandle();\n const html = await fs.readFile(htmlPath, 'utf8');\n this.artifacts.set(handle, { directory: artifactDirectory });\n return {\n handle,\n html,\n storyPath: relativeWorkspacePath(root, storyPath),\n storyExport: input.storyExport,\n sourceSha256: createHash('sha256').update(source).digest('hex'),\n };\n } catch (reason) {\n if (artifactDirectory !== undefined) await fs.rm(artifactDirectory, { recursive: true, force: true });\n throw reason;\n }\n }\n\n /** Renders a fresh source-backed PNG. This does not preserve transient iframe interaction state. */\n async exportImage(input: StoryPreviewBuildInput): Promise<StoryPreviewImageResult> {\n if (!STORY_EXPORT_PATTERN.test(input.storyExport)) {\n throw new Error('storyExport must be an exact JavaScript named export');\n }\n const root = await fs.realpath(this.root);\n const appPath = await this.resolveContainedPath(root, input.appPath, 'appPath');\n const storyPath = await this.resolveContainedPath(root, input.storyPath, 'storyPath');\n if (!STORY_FILE_PATTERN.test(storyPath))\n throw new Error('storyPath must name a .stories.js, .stories.jsx, .stories.ts, or .stories.tsx file');\n\n const [source, config] = await Promise.all([fs.readFile(storyPath, 'utf8'), this.dependencies.loadConfig(appPath)]);\n const renderer = this.dependencies.createRenderer(config, appPath);\n let ownedImagePath: string | undefined;\n try {\n const component = await this.exactStory(root, storyPath, input.storyExport);\n const rendered = await renderer.renderComponent(component, {\n storyName: input.storyExport,\n darkMode: input.darkMode,\n });\n const [renderedImagePath, imageRoot] = await Promise.all([\n fs.realpath(rendered.imagePath),\n fs.realpath(this.dependencies.rendererTemporaryRoot()),\n ]);\n if (renderedImagePath === imageRoot || !isContained(imageRoot, renderedImagePath)) {\n throw new Error('Style-system returned an image artifact outside its temporary directory');\n }\n const imageStat = await fs.stat(renderedImagePath);\n if (!imageStat.isFile()) throw new Error('Style-system returned a non-regular PNG image');\n ownedImagePath = renderedImagePath;\n if (imageStat.size > MAX_IMAGE_BYTES) throw new Error('Style-system returned an oversized PNG image');\n const image = await fs.readFile(renderedImagePath);\n if (image.length !== imageStat.size) throw new Error('Style-system PNG changed while it was being read');\n const { width, height } = pngDimensions(image);\n return {\n data: image.toString('base64'),\n mimeType: 'image/png',\n captureId: this.dependencies.createHandle(),\n width,\n height,\n storyPath: relativeWorkspacePath(root, storyPath),\n storyExport: input.storyExport,\n sourceSha256: createHash('sha256').update(source).digest('hex'),\n };\n } finally {\n try {\n if (ownedImagePath !== undefined) await fs.rm(ownedImagePath, { force: true });\n } finally {\n await renderer.dispose();\n }\n }\n }\n\n async dispose(handle: string): Promise<boolean> {\n const artifact = this.artifacts.get(handle);\n if (artifact === undefined) return false;\n this.artifacts.delete(handle);\n await fs.rm(artifact.directory, { recursive: true, force: true });\n return true;\n }\n\n async disposeAll(): Promise<void> {\n await Promise.all([...this.artifacts.keys()].map((handle) => this.dispose(handle)));\n }\n\n private async resolveContainedPath(root: string, inputPath: string, field: string): Promise<string> {\n if (inputPath.trim() === '') throw new Error(`${field} is required`);\n const candidate = path.isAbsolute(inputPath) ? inputPath : path.resolve(root, inputPath);\n const canonical = await fs.realpath(candidate);\n if (!isContained(root, canonical)) throw new Error(`${field} must remain inside the workspace root`);\n return canonical;\n }\n}\n\nexport type {\n StoryPreviewBuildInput,\n StoryPreviewBuildResult,\n StoryPreviewImageResult,\n StoryPreviewRenderer,\n StoryPreviewServiceDependencies,\n} from './type';\n"],"mappings":"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"}
|