@storybook-astro/framework 1.2.0 → 1.3.0-canary.1
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/dist/{base-IRZo3zgK.d.ts → base-DT67T5pi.d.ts} +1 -0
- package/dist/{chunk-T7NWIO5S.js → chunk-2EABPTOY.js} +5 -5
- package/dist/{chunk-PJEDXZVN.js → chunk-7YBE4TTI.js} +2 -1
- package/dist/chunk-7YBE4TTI.js.map +1 -0
- package/dist/{chunk-POHTFYST.js → chunk-AYYMNFI6.js} +104 -6
- package/dist/chunk-AYYMNFI6.js.map +1 -0
- package/dist/chunk-B5HHF6FC.js +116 -0
- package/dist/chunk-B5HHF6FC.js.map +1 -0
- package/dist/chunk-H3XZHW6Z.js +1402 -0
- package/dist/chunk-H3XZHW6Z.js.map +1 -0
- package/dist/{chunk-DNGQBPT7.js → chunk-PUTCAN6X.js} +5 -2
- package/dist/{chunk-DNGQBPT7.js.map → chunk-PUTCAN6X.js.map} +1 -1
- package/dist/{chunk-OUEDTRBO.js → chunk-TWAO2IQW.js} +229 -67
- package/dist/chunk-TWAO2IQW.js.map +1 -0
- package/dist/{chunk-4SWPVM6R.js → chunk-WUTCMEF5.js} +2 -2
- package/dist/index.d.ts +17 -7
- package/dist/index.js +6 -5
- package/dist/index.js.map +1 -1
- package/dist/integrations/index.d.ts +2 -1
- package/dist/integrations/index.js +1 -1
- package/dist/middleware.js +18 -131
- package/dist/middleware.js.map +1 -1
- package/dist/{types-C-jan6Px.d.ts → preset-BvgHg2of.d.ts} +8 -11
- package/dist/preset.d.ts +2 -10
- package/dist/preset.js +5 -4
- package/dist/renderer/renderer-dev.js +62 -0
- package/dist/renderer/renderer-dev.js.map +1 -0
- package/dist/renderer/renderer-server.js +92 -0
- package/dist/renderer/renderer-server.js.map +1 -0
- package/dist/renderer/renderer-static.js +54 -0
- package/dist/renderer/renderer-static.js.map +1 -0
- package/dist/testing.js +12 -11
- package/dist/testing.js.map +1 -1
- package/dist/{viteStorybookAstroMiddlewarePlugin-2EFKTECT.js → viteStorybookAstroMiddlewarePlugin-UB6ZLJ4B.js} +4 -3
- package/dist/vitest/global-setup.js +6 -5
- package/dist/vitest/global-setup.js.map +1 -1
- package/dist/vitest/index.d.ts +1 -1
- package/dist/vitest/index.js +3 -3
- package/package.json +14 -43
- package/src/astroImageService.ts +57 -0
- package/src/astroRenderHandler.ts +203 -0
- package/src/importAstroConfig.ts +1 -1
- package/src/index.ts +2 -0
- package/src/integrations/alpine.ts +1 -0
- package/src/integrations/base.ts +6 -0
- package/src/middleware.ts +29 -200
- package/src/module-mocks.ts +153 -5
- package/src/preset.ts +38 -8
- package/src/productionRenderRuntime.ts +187 -0
- package/src/rules.test.ts +52 -4
- package/src/rules.ts +54 -7
- package/src/server/index.ts +101 -31
- package/src/storyRulesRuntime.ts +34 -0
- package/src/storySsrVite.ts +240 -0
- package/src/types.ts +0 -9
- package/src/virtual.d.ts +17 -3
- package/src/vite/{astroFilesVirtualModulePlugin.ts → astroFilesPlugin.ts} +4 -4
- package/src/vite/sanitizeConfigPlugin.ts +18 -0
- package/src/vite/{storybookAstroServerAuthConfigVirtualModulePlugin.test.ts → serverAuthPlugin.test.ts} +7 -10
- package/src/vite/{storybookAstroServerAuthConfigVirtualModulePlugin.ts → serverAuthPlugin.ts} +6 -9
- package/src/vite/serverRuntimePlugin.ts +109 -0
- package/src/vite/{storybookAstroRulesConfigVirtualModulePlugin.ts → storyRulesPlugin.ts} +6 -7
- package/src/vite/{createVirtualModulePlugin.test.ts → virtualModulePlugin.test.ts} +5 -5
- package/src/vite/{createVirtualModulePlugin.ts → virtualModulePlugin.ts} +2 -2
- package/src/viteAstroContainerRenderersPlugin.ts +72 -2
- package/src/vitePluginAstroBuildPrerender.ts +75 -646
- package/src/vitePluginAstroBuildServer.ts +217 -165
- package/src/vitePluginAstroBuildShared.test.ts +87 -0
- package/src/vitePluginAstroBuildShared.ts +465 -0
- package/src/vitePluginStoryModuleMocks.ts +29 -0
- package/src/viteStorybookAstroMiddlewarePlugin.ts +8 -0
- package/src/viteStorybookAstroRendererPlugin.ts +13 -6
- package/src/viteStorybookRendererFallbackPlugin.ts +2 -2
- package/dist/chunk-OUEDTRBO.js.map +0 -1
- package/dist/chunk-PBISP7PA.js +0 -1137
- package/dist/chunk-PBISP7PA.js.map +0 -1
- package/dist/chunk-PJEDXZVN.js.map +0 -1
- package/dist/chunk-POHTFYST.js.map +0 -1
- package/dist/node/index.d.ts +0 -10
- package/dist/node/index.js +0 -10
- package/dist/node/index.js.map +0 -1
- package/src/vite/storybookAstroSanitizationConfigVirtualModulePlugin.ts +0 -21
- /package/dist/{chunk-T7NWIO5S.js.map → chunk-2EABPTOY.js.map} +0 -0
- /package/dist/{chunk-4SWPVM6R.js.map → chunk-WUTCMEF5.js.map} +0 -0
- /package/dist/{viteStorybookAstroMiddlewarePlugin-2EFKTECT.js.map → viteStorybookAstroMiddlewarePlugin-UB6ZLJ4B.js.map} +0 -0
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { access, copyFile, mkdir, readFile, readdir, stat } from 'node:fs/promises';
|
|
3
|
+
import { dirname, resolve } from 'node:path';
|
|
4
|
+
import type { Rollup } from 'vite';
|
|
5
|
+
import type { Integration } from './integrations/index.ts';
|
|
6
|
+
|
|
7
|
+
/** Resolves the shared virtual module ids used by both build pipelines. */
|
|
8
|
+
export function resolveVirtualBuildModuleId(id: string) {
|
|
9
|
+
if (id.startsWith('virtual:astro-static-module/')) {
|
|
10
|
+
return `\0${id}`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (id.startsWith('virtual:astro-component-module/')) {
|
|
14
|
+
return `\0${id}`;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Loads the virtual modules that stand in for tracked runtime and component entrypoints. */
|
|
19
|
+
export function loadVirtualBuildModule(id: string) {
|
|
20
|
+
if (id.startsWith('\0virtual:astro-static-module/')) {
|
|
21
|
+
const encodedSpecifier = id.replace('\0virtual:astro-static-module/', '');
|
|
22
|
+
const specifier = decodeURIComponent(encodedSpecifier);
|
|
23
|
+
|
|
24
|
+
if (isClientEntrypoint(specifier)) {
|
|
25
|
+
return [`export { default } from '${specifier}';`, `export * from '${specifier}';`].join(
|
|
26
|
+
'\n'
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return [`import '${specifier}';`, 'export default undefined;'].join('\n');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (id.startsWith('\0virtual:astro-component-module/')) {
|
|
34
|
+
const withoutPrefix = id.replace('\0virtual:astro-component-module/', '');
|
|
35
|
+
const encodedSpecifier = withoutPrefix.replace(/\?.*$/, '');
|
|
36
|
+
const specifier = decodeURIComponent(encodedSpecifier);
|
|
37
|
+
|
|
38
|
+
return [`export { default } from '${specifier}';`, `export * from '${specifier}';`].join('\n');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Emits build entrypoints for framework client runtimes that Astro stories may reference. */
|
|
43
|
+
export async function emitBuildEntrypoints(options: {
|
|
44
|
+
pluginContext: Rollup.PluginContext;
|
|
45
|
+
integrations: Integration[];
|
|
46
|
+
resolveFrom: string;
|
|
47
|
+
trackedSpecifiers: Set<string>;
|
|
48
|
+
staticEntrypointRefs: Map<string, string>;
|
|
49
|
+
}) {
|
|
50
|
+
const { pluginContext, integrations, resolveFrom } = options;
|
|
51
|
+
|
|
52
|
+
// Keep framework client entrypoints in the build so Astro islands can
|
|
53
|
+
// still hydrate after the preview iframe switches to built assets.
|
|
54
|
+
integrations.forEach((integration) => {
|
|
55
|
+
const entrypoint = integration.renderer.client?.entrypoint;
|
|
56
|
+
|
|
57
|
+
if (entrypoint) {
|
|
58
|
+
pluginContext.addWatchFile(entrypoint);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
options.trackedSpecifiers.forEach((specifier) => {
|
|
63
|
+
const fileReferenceId = pluginContext.emitFile({
|
|
64
|
+
type: 'chunk',
|
|
65
|
+
id: toStaticVirtualId(specifier),
|
|
66
|
+
name: createEntrypointName(resolveFrom, specifier)
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
options.staticEntrypointRefs.set(specifier, fileReferenceId);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Emits framework component entry chunks for one Astro component file used in the build graph. */
|
|
74
|
+
export async function emitHydratedComponentEntriesFromAstroFile(options: {
|
|
75
|
+
pluginContext: Rollup.PluginContext;
|
|
76
|
+
astroFilePath: string;
|
|
77
|
+
resolveFrom: string;
|
|
78
|
+
componentEntrypointRefs: Map<string, string>;
|
|
79
|
+
}) {
|
|
80
|
+
const hydratedComponentPaths = await collectHydratedComponentPaths(options.astroFilePath);
|
|
81
|
+
|
|
82
|
+
for (const resolvedImportPath of hydratedComponentPaths) {
|
|
83
|
+
|
|
84
|
+
if (options.componentEntrypointRefs.has(resolvedImportPath)) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const fileReferenceId = options.pluginContext.emitFile({
|
|
89
|
+
type: 'chunk',
|
|
90
|
+
id: toComponentChunkId(resolvedImportPath),
|
|
91
|
+
name: createEntrypointName(options.resolveFrom, resolvedImportPath)
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
options.componentEntrypointRefs.set(resolvedImportPath, fileReferenceId);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Collects the framework component files one Astro component hydrates in the browser. */
|
|
99
|
+
export async function collectHydratedComponentPaths(astroFilePath: string) {
|
|
100
|
+
// Only Astro components create islands, so only their framework imports
|
|
101
|
+
// need standalone client chunks in built Storybook output.
|
|
102
|
+
const localImportSpecifiers = await readLocalImportSpecifiers(astroFilePath);
|
|
103
|
+
const hydratedComponentPaths: string[] = [];
|
|
104
|
+
|
|
105
|
+
for (const specifier of localImportSpecifiers) {
|
|
106
|
+
const resolvedImportPath = await resolveLocalImportPath(astroFilePath, specifier);
|
|
107
|
+
|
|
108
|
+
if (!resolvedImportPath) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (
|
|
113
|
+
!isHydratableSourceFile(resolvedImportPath) ||
|
|
114
|
+
isNonHydratableSourceFile(resolvedImportPath)
|
|
115
|
+
) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Only .jsx/.tsx files go through toComponentVirtualId, which emits
|
|
120
|
+
// `export { default } from '<file>'`. A file with no default export
|
|
121
|
+
// crashes Rollup with '"default" is not exported'. Svelte/Vue SFCs are
|
|
122
|
+
// passed directly to their compilers, which generate the default export —
|
|
123
|
+
// checking their source for a literal `export default` would falsely
|
|
124
|
+
// exclude them.
|
|
125
|
+
if (/\.(jsx|tsx)$/.test(resolvedImportPath) && !(await hasDefaultExport(resolvedImportPath))) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
hydratedComponentPaths.push(resolvedImportPath);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return hydratedComponentPaths;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Collects framework client runtimes that must stay addressable after the preview is built. */
|
|
136
|
+
export function collectTrackedSpecifiers(integrations: Integration[]) {
|
|
137
|
+
const specifiers = new Set<string>([
|
|
138
|
+
'astro:scripts/page.js',
|
|
139
|
+
'astro:scripts/before-hydration.js'
|
|
140
|
+
]);
|
|
141
|
+
|
|
142
|
+
integrations.forEach((integration) => {
|
|
143
|
+
const entrypoint = integration.renderer.client?.entrypoint;
|
|
144
|
+
|
|
145
|
+
if (entrypoint) {
|
|
146
|
+
specifiers.add(entrypoint);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
return specifiers;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** Builds the browser module map used to rewrite source specifiers to built asset URLs. */
|
|
154
|
+
export function buildStaticModuleMap(
|
|
155
|
+
pluginContext: Rollup.PluginContext,
|
|
156
|
+
staticEntrypointRefs: Map<string, string>,
|
|
157
|
+
componentEntrypointRefs: Map<string, string>
|
|
158
|
+
) {
|
|
159
|
+
const map: Record<string, string> = {};
|
|
160
|
+
|
|
161
|
+
staticEntrypointRefs.forEach((fileReferenceId, specifier) => {
|
|
162
|
+
const fileName = pluginContext.getFileName(fileReferenceId);
|
|
163
|
+
|
|
164
|
+
if (fileName) {
|
|
165
|
+
map[specifier] = toPublicPath(fileName);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
componentEntrypointRefs.forEach((fileReferenceId, specifier) => {
|
|
170
|
+
const fileName = pluginContext.getFileName(fileReferenceId);
|
|
171
|
+
|
|
172
|
+
if (fileName) {
|
|
173
|
+
map[specifier] = toPublicPath(fileName);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
return map;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** Builds the stylesheet map for emitted framework component entry chunks. */
|
|
181
|
+
export function buildStaticCssMap(
|
|
182
|
+
pluginContext: Rollup.PluginContext,
|
|
183
|
+
bundle: Rollup.OutputBundle,
|
|
184
|
+
componentEntrypointRefs: Map<string, string>
|
|
185
|
+
) {
|
|
186
|
+
const map: Record<string, string[]> = {};
|
|
187
|
+
|
|
188
|
+
componentEntrypointRefs.forEach((fileReferenceId, specifier) => {
|
|
189
|
+
const fileName = pluginContext.getFileName(fileReferenceId);
|
|
190
|
+
const chunk = fileName ? (bundle[fileName] as Rollup.OutputChunk | undefined) : undefined;
|
|
191
|
+
const importedCss = Array.from(
|
|
192
|
+
(chunk?.viteMetadata?.importedCss ?? new Set<string>()).values()
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
if (importedCss.length > 0) {
|
|
196
|
+
map[specifier] = importedCss.map((cssFileName) => toPublicPath(cssFileName));
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
return map;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Normalizes one emitted file name to the relative public path used in built HTML. */
|
|
204
|
+
export function toPublicPath(fileName: string) {
|
|
205
|
+
return `./${fileName}`;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function stripQuery(input: string | undefined) {
|
|
209
|
+
return input?.replace(/\?.*$/, '');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** Converts a project file path into the stable path used inside the snapshot tree. */
|
|
213
|
+
export function relativePathFromRoot(resolveFrom: string, filePath: string) {
|
|
214
|
+
return filePath.slice(resolveFrom.length).replace(/^[/\\]+/, '');
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Copies one file or directory tree into the standalone runtime snapshot. */
|
|
218
|
+
export async function copyPath(sourcePath: string, targetPath: string): Promise<void> {
|
|
219
|
+
const sourceStats = await stat(sourcePath);
|
|
220
|
+
|
|
221
|
+
if (sourceStats.isDirectory()) {
|
|
222
|
+
await mkdir(targetPath, { recursive: true });
|
|
223
|
+
const entries = await readdir(sourcePath, { withFileTypes: true });
|
|
224
|
+
|
|
225
|
+
await Promise.all(
|
|
226
|
+
entries.map((entry) =>
|
|
227
|
+
copyPath(resolve(sourcePath, entry.name), resolve(targetPath, entry.name))
|
|
228
|
+
)
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
await mkdir(dirname(targetPath), { recursive: true });
|
|
235
|
+
await copyFile(sourcePath, targetPath);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** Maps an original source file path to its location inside the snapshot tree. */
|
|
239
|
+
export function buildSnapshotFilePath(
|
|
240
|
+
resolveFrom: string,
|
|
241
|
+
filePath: string,
|
|
242
|
+
snapshotDirName: string
|
|
243
|
+
) {
|
|
244
|
+
const normalizedResolveFrom = resolveFrom.replace(/\\/g, '/').replace(/\/$/, '');
|
|
245
|
+
const normalizedFilePath = filePath.replace(/\\/g, '/');
|
|
246
|
+
|
|
247
|
+
if (normalizedFilePath.startsWith(`${normalizedResolveFrom}/`)) {
|
|
248
|
+
return `${snapshotDirName}/${relativePathFromRoot(resolveFrom, filePath)}`.replace(/\\/g, '/');
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return `${snapshotDirName}/__external/${normalizedFilePath.replace(/^[/\\]+/, '')}`.replace(
|
|
252
|
+
/\\/g,
|
|
253
|
+
'/'
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/** Copies the source files and config files the standalone render server needs at runtime. */
|
|
258
|
+
export async function copyRuntimeSnapshot(options: {
|
|
259
|
+
resolveFrom: string;
|
|
260
|
+
snapshotRoot: string;
|
|
261
|
+
snapshotDirName: string;
|
|
262
|
+
astroComponents: string[];
|
|
263
|
+
storyRulesConfigFilePath?: string;
|
|
264
|
+
}) {
|
|
265
|
+
// The standalone render server still spins up a Vite SSR runtime, so it
|
|
266
|
+
// needs the exact source/config files that runtime will read from disk.
|
|
267
|
+
const runtimeInputFiles = new Set<string>([
|
|
268
|
+
...options.astroComponents,
|
|
269
|
+
...(options.storyRulesConfigFilePath ? [options.storyRulesConfigFilePath] : []),
|
|
270
|
+
...(await listRuntimeConfigFiles(options.resolveFrom))
|
|
271
|
+
]);
|
|
272
|
+
const copiedFiles = new Set<string>();
|
|
273
|
+
|
|
274
|
+
for (const runtimeInputFile of runtimeInputFiles) {
|
|
275
|
+
await copyLocalRuntimeDependencies(runtimeInputFile, options, copiedFiles);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/** Reports whether a JS/TS source file has a default export.
|
|
280
|
+
* Only call for .jsx/.tsx — Svelte and Vue SFCs have no literal `export default`
|
|
281
|
+
* in source, but their compilers generate one. On read error the file is kept,
|
|
282
|
+
* preserving prior behaviour rather than silently dropping a component.
|
|
283
|
+
*
|
|
284
|
+
* The regex scan is intentionally conservative: it can match inside comments
|
|
285
|
+
* or string literals, which produces a false-positive (file kept, Rollup crashes
|
|
286
|
+
* as before) rather than a false-negative (file silently dropped). */
|
|
287
|
+
async function hasDefaultExport(absPath: string) {
|
|
288
|
+
try {
|
|
289
|
+
const source = await readFile(absPath, 'utf-8');
|
|
290
|
+
|
|
291
|
+
return /export\s+default\b/.test(source) || /export\s*\{[^}]*\bdefault\b/.test(source);
|
|
292
|
+
} catch {
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function toStaticVirtualId(specifier: string) {
|
|
298
|
+
return `virtual:astro-static-module/${encodeURIComponent(specifier)}`;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function toComponentVirtualId(specifier: string) {
|
|
302
|
+
return `virtual:astro-component-module/${encodeURIComponent(specifier)}?component-wrapper`;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function toComponentChunkId(specifier: string) {
|
|
306
|
+
return /\.(svelte|vue)$/.test(specifier) ? specifier : toComponentVirtualId(specifier);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function createEntrypointName(resolveFrom: string, specifier: string) {
|
|
310
|
+
const normalizedResolveFrom = resolveFrom.replace(/\\/g, '/');
|
|
311
|
+
const normalizedSpecifier = specifier.replace(/\\/g, '/');
|
|
312
|
+
const relativeName = normalizedSpecifier.startsWith(`${normalizedResolveFrom}/`)
|
|
313
|
+
? normalizedSpecifier.slice(normalizedResolveFrom.length + 1)
|
|
314
|
+
: normalizedSpecifier.split('/').slice(-2).join('/');
|
|
315
|
+
const sanitizedName = relativeName.replace(/[^a-zA-Z0-9/_-]/g, '_').replace(/_+/g, '_');
|
|
316
|
+
const hash = createHash('sha1').update(normalizedSpecifier).digest('hex').slice(0, 8);
|
|
317
|
+
|
|
318
|
+
return `${sanitizedName}-${hash}`;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function isClientEntrypoint(specifier: string) {
|
|
322
|
+
return specifier.startsWith('@astrojs/') && specifier.endsWith('/client.js');
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function isHydratableSourceFile(input: string) {
|
|
326
|
+
return /\.(jsx|tsx|vue|svelte)$/.test(input);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function isNonHydratableSourceFile(input: string) {
|
|
330
|
+
return /\.stories\.[jt]sx?$|\.stories\.vue$|\.stories\.svelte$|\.(spec|test)\.[jt]sx?$/.test(
|
|
331
|
+
input
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** Finds project config files that the standalone render server may load through Vite. */
|
|
336
|
+
async function listRuntimeConfigFiles(resolveFrom: string) {
|
|
337
|
+
const candidates = [
|
|
338
|
+
'package.json',
|
|
339
|
+
'tsconfig.json',
|
|
340
|
+
'tsconfig.base.json',
|
|
341
|
+
'jsconfig.json',
|
|
342
|
+
'astro.config.mjs',
|
|
343
|
+
'astro.config.js',
|
|
344
|
+
'astro.config.ts',
|
|
345
|
+
'vite.config.js',
|
|
346
|
+
'vite.config.ts',
|
|
347
|
+
'svelte.config.js'
|
|
348
|
+
];
|
|
349
|
+
const existing: string[] = [];
|
|
350
|
+
|
|
351
|
+
await Promise.all(
|
|
352
|
+
candidates.map(async (candidate) => {
|
|
353
|
+
const filePath = resolve(resolveFrom, candidate);
|
|
354
|
+
|
|
355
|
+
try {
|
|
356
|
+
await access(filePath);
|
|
357
|
+
existing.push(filePath);
|
|
358
|
+
} catch {
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
})
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
return existing;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/** Copies one local source file and follows its local imports into the snapshot. */
|
|
368
|
+
async function copyLocalRuntimeDependencies(
|
|
369
|
+
sourcePath: string,
|
|
370
|
+
options: {
|
|
371
|
+
resolveFrom: string;
|
|
372
|
+
snapshotRoot: string;
|
|
373
|
+
snapshotDirName: string;
|
|
374
|
+
},
|
|
375
|
+
copiedFiles: Set<string>
|
|
376
|
+
) {
|
|
377
|
+
const normalizedSourcePath = sourcePath.replace(/\\/g, '/');
|
|
378
|
+
|
|
379
|
+
if (copiedFiles.has(normalizedSourcePath)) {
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
copiedFiles.add(normalizedSourcePath);
|
|
384
|
+
|
|
385
|
+
const snapshotRelativePath = buildSnapshotFilePath(
|
|
386
|
+
options.resolveFrom,
|
|
387
|
+
normalizedSourcePath,
|
|
388
|
+
options.snapshotDirName
|
|
389
|
+
);
|
|
390
|
+
|
|
391
|
+
await copyPath(
|
|
392
|
+
normalizedSourcePath,
|
|
393
|
+
resolve(dirname(options.snapshotRoot), snapshotRelativePath)
|
|
394
|
+
);
|
|
395
|
+
|
|
396
|
+
// Follow only local imports here. Package dependencies stay external and are
|
|
397
|
+
// resolved by Node/Vite from the deployed install, not copied into snapshot.
|
|
398
|
+
const localImportSpecifiers = await readLocalImportSpecifiers(normalizedSourcePath);
|
|
399
|
+
|
|
400
|
+
for (const specifier of localImportSpecifiers) {
|
|
401
|
+
const resolvedDependency = await resolveLocalImportPath(normalizedSourcePath, specifier);
|
|
402
|
+
|
|
403
|
+
if (!resolvedDependency) {
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
await copyLocalRuntimeDependencies(resolvedDependency, options, copiedFiles);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/** Reads local import specifiers from source files that can participate in the SSR runtime. */
|
|
412
|
+
async function readLocalImportSpecifiers(filePath: string) {
|
|
413
|
+
if (!/\.(astro|[cm]?[jt]sx?|vue|svelte)$/.test(filePath)) {
|
|
414
|
+
return [];
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const source = await readFile(filePath, 'utf-8');
|
|
418
|
+
const matches = source.matchAll(
|
|
419
|
+
/(?:import|export)\s+(?:[^'"`]*?\s+from\s+)?['"`]([^'"`]+)['"`]|import\(\s*['"`]([^'"`]+)['"`]\s*\)/g
|
|
420
|
+
);
|
|
421
|
+
|
|
422
|
+
return Array.from(matches, (match) => match[1] ?? match[2]).filter(
|
|
423
|
+
(specifier): specifier is string => Boolean(specifier) && specifier.startsWith('.')
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/** Resolves one relative import the same way the project source tree would on disk. */
|
|
428
|
+
async function resolveLocalImportPath(importerPath: string, specifier: string) {
|
|
429
|
+
const basePath = resolve(dirname(importerPath), specifier);
|
|
430
|
+
const candidates = [
|
|
431
|
+
basePath,
|
|
432
|
+
`${basePath}.ts`,
|
|
433
|
+
`${basePath}.tsx`,
|
|
434
|
+
`${basePath}.js`,
|
|
435
|
+
`${basePath}.jsx`,
|
|
436
|
+
`${basePath}.mjs`,
|
|
437
|
+
`${basePath}.cjs`,
|
|
438
|
+
`${basePath}.astro`,
|
|
439
|
+
`${basePath}.vue`,
|
|
440
|
+
`${basePath}.svelte`,
|
|
441
|
+
resolve(basePath, 'index.ts'),
|
|
442
|
+
resolve(basePath, 'index.tsx'),
|
|
443
|
+
resolve(basePath, 'index.js'),
|
|
444
|
+
resolve(basePath, 'index.jsx'),
|
|
445
|
+
resolve(basePath, 'index.mjs'),
|
|
446
|
+
resolve(basePath, 'index.cjs'),
|
|
447
|
+
resolve(basePath, 'index.astro'),
|
|
448
|
+
resolve(basePath, 'index.vue'),
|
|
449
|
+
resolve(basePath, 'index.svelte')
|
|
450
|
+
];
|
|
451
|
+
|
|
452
|
+
for (const candidate of candidates) {
|
|
453
|
+
try {
|
|
454
|
+
const candidateStats = await stat(candidate);
|
|
455
|
+
|
|
456
|
+
if (candidateStats.isFile()) {
|
|
457
|
+
return candidate.replace(/\\/g, '/');
|
|
458
|
+
}
|
|
459
|
+
} catch {
|
|
460
|
+
continue;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return undefined;
|
|
465
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { PluginOption } from 'vite';
|
|
2
|
+
import {
|
|
3
|
+
loadStoryInlineModule,
|
|
4
|
+
resolveStoryModuleMock,
|
|
5
|
+
STORYBOOK_ASTRO_INLINE_MODULE_PREFIX
|
|
6
|
+
} from './module-mocks.ts';
|
|
7
|
+
|
|
8
|
+
export function vitePluginStoryModuleMocks(): PluginOption {
|
|
9
|
+
return {
|
|
10
|
+
name: 'storybook-astro:story-module-mocks',
|
|
11
|
+
enforce: 'pre',
|
|
12
|
+
resolveId(id) {
|
|
13
|
+
if (id.startsWith(STORYBOOK_ASTRO_INLINE_MODULE_PREFIX)) {
|
|
14
|
+
return `\0${id}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const mockedModule = resolveStoryModuleMock(id);
|
|
18
|
+
|
|
19
|
+
if (mockedModule) {
|
|
20
|
+
return mockedModule;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return null;
|
|
24
|
+
},
|
|
25
|
+
load(id) {
|
|
26
|
+
return loadStoryInlineModule(id);
|
|
27
|
+
}
|
|
28
|
+
} satisfies PluginOption;
|
|
29
|
+
}
|
|
@@ -11,6 +11,7 @@ import { vitePluginAstroFontsFallback } from './vitePluginAstroFontsFallback.ts'
|
|
|
11
11
|
import { vitePluginAstroIntegrationOptsFallback } from './vitePluginAstroIntegrationOptsFallback.ts';
|
|
12
12
|
import { vitePluginAstroVueFallback } from './vitePluginAstroVueFallback.ts';
|
|
13
13
|
import { vitePluginAstroRoutesFallback } from './vitePluginAstroRoutesFallback.ts';
|
|
14
|
+
import { vitePluginStoryModuleMocks } from './vitePluginStoryModuleMocks.ts';
|
|
14
15
|
import { ssrLoadModuleWithFsFallback } from './lib/ssr-load-module-with-fs-fallback.ts';
|
|
15
16
|
import { resolveRulesConfigFilePath } from './rules-options.ts';
|
|
16
17
|
|
|
@@ -37,6 +38,9 @@ export async function vitePluginStorybookAstroMiddleware(options: FrameworkOptio
|
|
|
37
38
|
rulesConfigFilePath: storyRulesConfigFilePath,
|
|
38
39
|
resolveRulesConfigModule: () =>
|
|
39
40
|
loadRulesConfigModule(viteServer!, storyRulesConfigFilePath),
|
|
41
|
+
invalidateModuleGraph: () => {
|
|
42
|
+
viteServer?.moduleGraph.invalidateAll();
|
|
43
|
+
},
|
|
40
44
|
loadModule: (id: string) =>
|
|
41
45
|
ssrLoadModuleWithFsFallback(viteServer!, id, {
|
|
42
46
|
fixStacktrace: true
|
|
@@ -52,6 +56,9 @@ export async function vitePluginStorybookAstroMiddleware(options: FrameworkOptio
|
|
|
52
56
|
server.watcher.on('add', resetHandler);
|
|
53
57
|
server.watcher.on('change', resetHandler);
|
|
54
58
|
server.watcher.on('unlink', resetHandler);
|
|
59
|
+
viteServer.watcher.on('add', resetHandler);
|
|
60
|
+
viteServer.watcher.on('change', resetHandler);
|
|
61
|
+
viteServer.watcher.on('unlink', resetHandler);
|
|
55
62
|
|
|
56
63
|
server.ws.on('astro:render:request', async (data: RenderRequestMessage['data']) => {
|
|
57
64
|
try {
|
|
@@ -178,6 +185,7 @@ export async function createViteServer(integrations: Integration[], resolveFrom
|
|
|
178
185
|
vitePluginAstroIntegrationOptsFallback(),
|
|
179
186
|
vitePluginAstroVueFallback(),
|
|
180
187
|
vitePluginAstroRoutesFallback(),
|
|
188
|
+
vitePluginStoryModuleMocks(),
|
|
181
189
|
...(config.plugins?.filter(Boolean) ?? []),
|
|
182
190
|
viteAstroContainerRenderersPlugin(safeIntegrations)
|
|
183
191
|
]
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
1
2
|
import type { RenderMode, ServerBuildOptions } from './types.ts';
|
|
2
|
-
import {
|
|
3
|
+
import { createVirtualModule } from './vite/virtualModulePlugin.ts';
|
|
3
4
|
|
|
4
|
-
const
|
|
5
|
+
const rendererDevModulePath = fileURLToPath(new URL('./renderer/renderer-dev.js', import.meta.url));
|
|
6
|
+
const rendererStaticModulePath = fileURLToPath(new URL('./renderer/renderer-static.js', import.meta.url));
|
|
7
|
+
const rendererServerModulePath = fileURLToPath(new URL('./renderer/renderer-server.js', import.meta.url));
|
|
5
8
|
|
|
6
9
|
export function viteStorybookAstroRendererPlugin(options: {
|
|
7
10
|
mode: 'development' | 'production';
|
|
@@ -13,20 +16,20 @@ export function viteStorybookAstroRendererPlugin(options: {
|
|
|
13
16
|
const isProduction = options.mode === 'production';
|
|
14
17
|
const isStaticMode = options.renderMode === 'static';
|
|
15
18
|
|
|
16
|
-
return
|
|
19
|
+
return createVirtualModule({
|
|
17
20
|
pluginName,
|
|
18
21
|
virtualModuleId,
|
|
19
22
|
load() {
|
|
20
23
|
if (!isProduction) {
|
|
21
|
-
return `export * from
|
|
24
|
+
return `export * from ${JSON.stringify(normalizePath(rendererDevModulePath))};`;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
if (isStaticMode) {
|
|
25
|
-
return `export * from
|
|
28
|
+
return `export * from ${JSON.stringify(normalizePath(rendererStaticModulePath))};`;
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
return [
|
|
29
|
-
`import { createServerRenderer } from
|
|
32
|
+
`import { createServerRenderer } from ${JSON.stringify(normalizePath(rendererServerModulePath))};`,
|
|
30
33
|
`const renderer = createServerRenderer(${JSON.stringify(
|
|
31
34
|
{
|
|
32
35
|
serverUrl: options.server?.serverUrl,
|
|
@@ -43,3 +46,7 @@ export function viteStorybookAstroRendererPlugin(options: {
|
|
|
43
46
|
}
|
|
44
47
|
});
|
|
45
48
|
}
|
|
49
|
+
|
|
50
|
+
function normalizePath(value: string) {
|
|
51
|
+
return value.replace(/\\/g, '/');
|
|
52
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Integration } from './integrations/index.ts';
|
|
2
|
-
import {
|
|
2
|
+
import { createVirtualModule } from './vite/virtualModulePlugin.ts';
|
|
3
3
|
|
|
4
4
|
export function viteStorybookRendererFallbackPlugin(integrations: Integration[]) {
|
|
5
5
|
const safeIntegrations = integrations ?? [];
|
|
6
6
|
|
|
7
|
-
return
|
|
7
|
+
return createVirtualModule({
|
|
8
8
|
pluginName: 'storybook-renderer-fallback',
|
|
9
9
|
virtualModuleId: 'virtual:storybook-renderer-fallback',
|
|
10
10
|
load() {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/rules.ts","../src/lib/passthrough-image-service.ts","../src/lib/sanitization.ts","../src/module-mocks.ts"],"sourcesContent":["import { dirname, isAbsolute, resolve } from 'node:path';\nimport type { RenderStoryInput } from './types.ts';\n\nexport type StoryRuleCleanup = () => void | Promise<void>;\ntype StoryRuleUseResult = void | StoryRuleCleanup | Promise<void | StoryRuleCleanup>;\n\nexport type StoryRuleUseContext = {\n story: StoryRuleStory;\n mock: (specifier: string, replacement: string) => void;\n};\n\nexport type StoryRuleUse = (context: StoryRuleUseContext) => StoryRuleUseResult;\n\nexport type StoryRule = {\n match: string | string[];\n use: StoryRuleUse | StoryRuleUse[];\n};\n\nexport type StoryRulesConfig = {\n rules: StoryRule[];\n};\n\nexport type StoryRuleStory = {\n id: string;\n title?: string;\n name?: string;\n keys: string[];\n};\n\nexport type StoryRuleSelectionInput = {\n configModule: unknown;\n configFilePath?: string;\n story?: RenderStoryInput;\n};\n\nexport type StoryRuleSelection = {\n moduleMocks: Map<string, string>;\n cleanups: StoryRuleCleanup[];\n};\n\ntype MutableStoryRuleSelection = {\n moduleMocks: Map<string, string>;\n cleanups: StoryRuleCleanup[];\n};\n\nexport function defineStoryRules(config: StoryRulesConfig): StoryRulesConfig {\n return config;\n}\n\nexport async function selectStoryRules(\n input: StoryRuleSelectionInput\n): Promise<StoryRuleSelection> {\n const config = normalizeRulesConfig(input.configModule);\n const story = normalizeStory(input.story);\n const selection = createEmptySelection();\n\n for (const rule of config.rules) {\n if (!isStoryRuleMatch(rule.match, story)) {\n continue;\n }\n\n const uses = Array.isArray(rule.use) ? rule.use : [rule.use];\n\n for (const use of uses) {\n if (typeof use !== 'function') {\n throw new Error('Each story rule \"use\" entry must be a function.');\n }\n\n const cleanup = await use({\n story,\n mock: (specifier, replacement) => {\n const normalizedSpecifier = normalizeMockSpecifier(specifier);\n const normalizedReplacement = normalizeMockReplacement(replacement, input.configFilePath);\n\n selection.moduleMocks.set(normalizedSpecifier, normalizedReplacement);\n }\n });\n\n if (cleanup !== undefined) {\n if (typeof cleanup !== 'function') {\n throw new Error('Story rule \"use\" must return either nothing or a cleanup function.');\n }\n\n selection.cleanups.push(cleanup);\n }\n }\n }\n\n return selection;\n}\n\nexport async function withStoryRuleCleanups<T>(\n cleanups: StoryRuleCleanup[],\n callback: () => Promise<T>\n): Promise<T> {\n let result: T | undefined;\n let callbackError: unknown;\n\n try {\n result = await callback();\n } catch (error) {\n callbackError = error;\n }\n\n try {\n await runStoryRuleCleanups(cleanups);\n } catch (cleanupError) {\n if (callbackError) {\n throw new AggregateError(\n [callbackError, cleanupError],\n 'Story rule execution and cleanup both failed.'\n );\n }\n\n throw cleanupError;\n }\n\n if (callbackError) {\n throw callbackError;\n }\n\n return result as T;\n}\n\nexport async function runStoryRuleCleanups(cleanups: StoryRuleCleanup[]): Promise<void> {\n const errors: unknown[] = [];\n\n for (let index = cleanups.length - 1; index >= 0; index -= 1) {\n try {\n await cleanups[index]();\n } catch (error) {\n errors.push(error);\n }\n }\n\n if (errors.length === 1) {\n throw errors[0];\n }\n\n if (errors.length > 1) {\n throw new AggregateError(errors, 'Story rule cleanup failed.');\n }\n}\n\nfunction normalizeRulesConfig(configModule: unknown): StoryRulesConfig {\n const configExport = getRulesConfigExport(configModule);\n\n if (configExport === undefined || configExport === null) {\n return {\n rules: []\n };\n }\n\n if (!isRecord(configExport)) {\n throw new Error(\n 'Story rules config must export an object with a \"rules\" array via a default export or named export.'\n );\n }\n\n const rules = configExport.rules;\n\n if (rules === undefined) {\n return {\n rules: []\n };\n }\n\n if (!Array.isArray(rules)) {\n throw new Error('Story rules config \"rules\" must be an array.');\n }\n\n return {\n rules: rules as StoryRule[]\n };\n}\n\nfunction getRulesConfigExport(configModule: unknown): unknown {\n if (!isRecord(configModule)) {\n return configModule;\n }\n\n if ('default' in configModule && configModule.default !== undefined) {\n return configModule.default;\n }\n\n if ('rules' in configModule) {\n return {\n rules: configModule.rules\n };\n }\n\n return undefined;\n}\n\nfunction normalizeStory(story?: RenderStoryInput): StoryRuleStory {\n const id = normalizeStoryId(story?.id);\n const title = normalizeOptionalString(story?.title);\n const name = normalizeOptionalString(story?.name);\n const keys = Array.from(resolveStoryKeys({ id, title, name }));\n\n return {\n id,\n title,\n name,\n keys\n };\n}\n\nfunction resolveStoryKeys(story: { id: string; title?: string; name?: string }) {\n const keys = new Set<string>();\n\n keys.add('');\n\n const storyId = story.id;\n const idPath = storyId ? storyId.replaceAll('--', '/') : '';\n\n if (storyId) {\n keys.add(storyId);\n keys.add(`/story/${storyId}`);\n }\n\n if (idPath) {\n keys.add(idPath);\n keys.add(`/story/${idPath}`);\n }\n\n const titlePath = story.title\n ? story.title\n .split('/')\n .map((segment) => slugify(segment))\n .filter(Boolean)\n .join('/')\n : '';\n\n const storyNamePath = story.name ? slugify(story.name) : '';\n\n if (titlePath && storyNamePath) {\n const composedPath = `${titlePath}/${storyNamePath}`;\n\n keys.add(composedPath);\n keys.add(`/story/${composedPath}`);\n }\n\n return keys;\n}\n\nfunction isStoryRuleMatch(match: string | string[], story: StoryRuleStory): boolean {\n const patterns = Array.isArray(match) ? match : [match];\n\n return patterns.some((pattern) => {\n if (typeof pattern !== 'string') {\n throw new Error('Story rule \"match\" must be a string or an array of strings.');\n }\n\n const normalizedPattern = pattern.trim();\n\n if (!normalizedPattern) {\n throw new Error('Story rule \"match\" cannot be empty.');\n }\n\n return story.keys.some((key) => isWildcardMatch(normalizedPattern, key));\n });\n}\n\nfunction isWildcardMatch(pattern: string, candidate: string): boolean {\n const escapedPattern = escapeRegExp(pattern).replaceAll('*', '.*');\n const regex = new RegExp(`^${escapedPattern}$`);\n\n return regex.test(candidate);\n}\n\nfunction normalizeStoryId(id?: string): string {\n const value = normalizeOptionalString(id) ?? '';\n\n if (!value) {\n return '';\n }\n\n return value.startsWith('/story/') ? value.slice('/story/'.length) : value;\n}\n\nfunction normalizeOptionalString(value: unknown): string | undefined {\n if (typeof value !== 'string') {\n return undefined;\n }\n\n const normalizedValue = value.trim();\n\n return normalizedValue || undefined;\n}\n\nfunction normalizeMockSpecifier(value: unknown): string {\n if (typeof value !== 'string') {\n throw new Error('Story rule mock specifier must be a string.');\n }\n\n const normalizedValue = value.trim();\n\n if (!normalizedValue) {\n throw new Error('Story rule mock specifier cannot be empty.');\n }\n\n return normalizedValue;\n}\n\nfunction normalizeMockReplacement(value: unknown, configFilePath?: string): string {\n if (typeof value !== 'string') {\n throw new Error('Story rule mock replacement must be a string.');\n }\n\n const normalizedValue = value.trim();\n\n if (!normalizedValue) {\n throw new Error('Story rule mock replacement cannot be empty.');\n }\n\n if (isAbsolute(normalizedValue)) {\n return toPosixPath(normalizedValue);\n }\n\n if (normalizedValue.startsWith('.')) {\n if (!configFilePath) {\n throw new Error(\n 'Story rule mock replacement uses a relative path, but rules config path is unavailable.'\n );\n }\n\n return toPosixPath(resolve(dirname(configFilePath), normalizedValue));\n }\n\n return normalizedValue;\n}\n\nfunction slugify(input: string): string {\n return input\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\nfunction createEmptySelection(): MutableStoryRuleSelection {\n return {\n moduleMocks: new Map(),\n cleanups: []\n };\n}\n\nfunction toPosixPath(input: string): string {\n return input.replaceAll('\\\\', '/');\n}\n\nfunction escapeRegExp(input: string) {\n return input.replace(/[|\\\\{}()[\\]^$+?.]/g, '\\\\$&');\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n return !Array.isArray(value);\n}\n","/**\n * Install a passthrough image service on `globalThis.astroAsset.imageService`.\n *\n * AstroContainer has no image service configuration API, and the default\n * `getConfiguredImageService()` tries to dynamically import \"virtual:image-service\"\n * which fails in astro6/Vite 7's module runner. Even when it succeeds (astro5),\n * the noop service still routes through /_image?href=... URLs that the Storybook\n * dev server cannot serve.\n *\n * Pre-populating `globalThis.astroAsset.imageService` bypasses the dynamic import\n * entirely — `getConfiguredImageService()` checks this global first and returns\n * it without going through the broken virtual module. Our service returns the\n * direct /@fs/... Vite URL from the ImageMetadata object, which Vite can serve\n * as a static asset in the browser; in static (build-time prerender) mode the\n * URL ends up being rewritten to a content-hashed Rollup asset.\n *\n * This must be called on the same Node process that hosts AstroContainer,\n * before `container.renderToString()` is invoked.\n */\nexport function installPassthroughImageService() {\n if (!globalThis.astroAsset) {\n (globalThis as Record<string, unknown>).astroAsset = {};\n }\n\n (globalThis.astroAsset as Record<string, unknown>).imageService = {\n propertiesToHash: ['src'],\n validateOptions(options: Record<string, unknown>) {\n return options;\n },\n getURL(options: { src: unknown }) {\n const src = options.src;\n\n if (\n src != null &&\n typeof src === 'object' &&\n 'src' in src &&\n typeof (src as Record<string, unknown>).src === 'string'\n ) {\n // ImageMetadata object — return the /@fs/... Vite URL directly\n return (src as Record<string, unknown>).src as string;\n }\n\n return typeof src === 'string' ? src : '';\n },\n getHTMLAttributes(options: Record<string, unknown>) {\n const {\n src,\n width,\n height,\n format: _format,\n quality: _quality,\n densities: _densities,\n widths: _widths,\n formats: _formats,\n layout: _layout,\n priority: _priority,\n fit: _fit,\n position: _position,\n background: _background,\n ...attrs\n } = options;\n const srcObj = src != null && typeof src === 'object' ? (src as Record<string, unknown>) : null;\n\n return {\n ...attrs,\n width: width ?? srcObj?.width,\n height: height ?? srcObj?.height,\n loading: (attrs.loading as string | undefined) ?? 'lazy',\n decoding: (attrs.decoding as string | undefined) ?? 'async'\n };\n },\n getSrcSet() {\n return [];\n }\n };\n}\n","import sanitizeHtml from 'sanitize-html';\nimport type { IOptions } from 'sanitize-html';\n\ntype SanitizationPayload = {\n args: Record<string, unknown>;\n slots: Record<string, unknown>;\n};\n\nexport type SanitizationOptions = {\n enabled?: boolean;\n args?: string[];\n slots?: string[];\n sanitizeHtml?: IOptions;\n};\n\nexport type ResolvedSanitizationOptions = {\n enabled: boolean;\n args: string[];\n slots: string[];\n sanitizeHtml: IOptions;\n};\n\nconst DEFAULT_SANITIZE_HTML_OPTIONS: IOptions = {\n allowedTags: [\n 'a',\n 'abbr',\n 'b',\n 'blockquote',\n 'br',\n 'caption',\n 'cite',\n 'code',\n 'col',\n 'colgroup',\n 'dd',\n 'details',\n 'dfn',\n 'div',\n 'dl',\n 'dt',\n 'em',\n 'figcaption',\n 'figure',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'hr',\n 'i',\n 'img',\n 'kbd',\n 'li',\n 'mark',\n 'ol',\n 'p',\n 'pre',\n 'q',\n 'rp',\n 'rt',\n 'ruby',\n 's',\n 'samp',\n 'small',\n 'span',\n 'strong',\n 'sub',\n 'summary',\n 'sup',\n 'table',\n 'tbody',\n 'td',\n 'tfoot',\n 'th',\n 'thead',\n 'time',\n 'tr',\n 'u',\n 'ul',\n 'var',\n 'wbr'\n ],\n allowedAttributes: {\n '*': [\n 'aria-describedby',\n 'aria-hidden',\n 'aria-label',\n 'aria-labelledby',\n 'class',\n 'id',\n 'lang',\n 'role',\n 'title'\n ],\n a: ['href', 'name', 'target', 'rel'],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height', 'loading', 'decoding'],\n td: ['colspan', 'rowspan'],\n th: ['colspan', 'rowspan', 'scope'],\n time: ['datetime']\n },\n allowedSchemes: ['http', 'https', 'mailto', 'tel', 'data'],\n allowedSchemesByTag: {\n a: ['http', 'https', 'mailto', 'tel'],\n img: ['http', 'https', 'data']\n },\n allowedSchemesAppliedToAttributes: ['href', 'src', 'cite', 'srcset'],\n allowProtocolRelative: false,\n disallowedTagsMode: 'discard',\n enforceHtmlBoundary: true,\n parseStyleAttributes: false\n};\n\nexport function resolveSanitizationOptions(options?: SanitizationOptions): ResolvedSanitizationOptions {\n if (!options) {\n return {\n enabled: true,\n args: [],\n slots: ['**'],\n sanitizeHtml: mergeSanitizeHtmlOptions()\n };\n }\n\n const enabled = options.enabled ?? true;\n const args = normalizePathList(options.args, 'framework.options.sanitization.args');\n const slots =\n options.slots === undefined\n ? ['**']\n : normalizePathList(options.slots, 'framework.options.sanitization.slots');\n\n return {\n enabled,\n args,\n slots,\n sanitizeHtml: mergeSanitizeHtmlOptions(options.sanitizeHtml)\n };\n}\n\nexport function sanitizeRenderPayload(\n payload: SanitizationPayload,\n options: ResolvedSanitizationOptions\n): SanitizationPayload {\n if (!options.enabled) {\n return payload;\n }\n\n const sanitizedArgs =\n options.args.length > 0\n ? sanitizeRecord(payload.args, options.args, options.sanitizeHtml)\n : payload.args;\n\n const sanitizedSlots =\n options.slots.length > 0\n ? sanitizeRecord(payload.slots, options.slots, options.sanitizeHtml)\n : payload.slots;\n\n return {\n args: sanitizedArgs,\n slots: sanitizedSlots\n };\n}\n\nexport function serializeSanitizationOptions(options?: SanitizationOptions): string {\n if (!options) {\n return 'undefined';\n }\n\n assertNoFunctions(options.sanitizeHtml, 'framework.options.sanitization.sanitizeHtml');\n\n const state = {\n seen: new WeakSet<object>()\n };\n\n return serializeValue(options, 'framework.options.sanitization', state);\n}\n\nfunction mergeSanitizeHtmlOptions(userOptions?: IOptions): IOptions {\n const merged: IOptions = {\n ...DEFAULT_SANITIZE_HTML_OPTIONS,\n ...userOptions\n };\n\n if (\n isRecord(DEFAULT_SANITIZE_HTML_OPTIONS.allowedAttributes) &&\n isRecord(userOptions?.allowedAttributes)\n ) {\n merged.allowedAttributes = {\n ...DEFAULT_SANITIZE_HTML_OPTIONS.allowedAttributes,\n ...userOptions.allowedAttributes\n };\n }\n\n if (isRecord(userOptions?.allowedClasses)) {\n merged.allowedClasses = {\n ...(isRecord(DEFAULT_SANITIZE_HTML_OPTIONS.allowedClasses)\n ? DEFAULT_SANITIZE_HTML_OPTIONS.allowedClasses\n : {}),\n ...userOptions.allowedClasses\n };\n }\n\n if (isRecord(userOptions?.allowedStyles)) {\n merged.allowedStyles = {\n ...(isRecord(DEFAULT_SANITIZE_HTML_OPTIONS.allowedStyles)\n ? DEFAULT_SANITIZE_HTML_OPTIONS.allowedStyles\n : {}),\n ...userOptions.allowedStyles\n };\n }\n\n return merged;\n}\n\nfunction normalizePathList(value: unknown, path: string): string[] {\n if (value === undefined) {\n return [];\n }\n\n if (!Array.isArray(value)) {\n throw new Error(`${path} must be an array of dot-path patterns.`);\n }\n\n const unique = new Set<string>();\n\n value.forEach((entry, index) => {\n if (typeof entry !== 'string') {\n throw new Error(`${path}[${index}] must be a string.`);\n }\n\n const normalized = entry.trim();\n\n if (!normalized) {\n throw new Error(`${path}[${index}] cannot be an empty string.`);\n }\n\n unique.add(normalized);\n });\n\n return Array.from(unique);\n}\n\nfunction sanitizeRecord(\n record: Record<string, unknown>,\n patterns: string[],\n options: IOptions\n): Record<string, unknown> {\n const sanitized: Record<string, unknown> = {};\n\n Object.entries(record).forEach(([key, value]) => {\n sanitized[key] = sanitizeValue(value, key, patterns, options);\n });\n\n return sanitized;\n}\n\nfunction sanitizeValue(\n value: unknown,\n currentPath: string,\n patterns: string[],\n options: IOptions\n): unknown {\n if (typeof value === 'string') {\n if (shouldSanitizePath(currentPath, patterns)) {\n return sanitizeHtml(value, options);\n }\n\n return value;\n }\n\n if (Array.isArray(value)) {\n return value.map((item, index) => {\n const nextPath = `${currentPath}.${index}`;\n\n return sanitizeValue(item, nextPath, patterns, options);\n });\n }\n\n if (isRecord(value)) {\n const sanitized: Record<string, unknown> = {};\n\n Object.entries(value).forEach(([key, nestedValue]) => {\n const nextPath = `${currentPath}.${key}`;\n\n sanitized[key] = sanitizeValue(nestedValue, nextPath, patterns, options);\n });\n\n return sanitized;\n }\n\n return value;\n}\n\nfunction shouldSanitizePath(path: string, patterns: string[]): boolean {\n return patterns.some((pattern) => matchesPathPattern(path, pattern));\n}\n\nfunction matchesPathPattern(path: string, pattern: string): boolean {\n const pathSegments = path.split('.');\n const patternSegments = pattern.split('.');\n\n return matchSegments(pathSegments, patternSegments);\n}\n\nfunction serializeValue(value: unknown, path: string, state: { seen: WeakSet<object> }): string {\n if (value === null) {\n return 'null';\n }\n\n if (value === undefined) {\n return 'undefined';\n }\n\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return JSON.stringify(value);\n }\n\n if (value instanceof RegExp) {\n return value.toString();\n }\n\n if (Array.isArray(value)) {\n const serializedItems = value.map((item, index) =>\n serializeValue(item, `${path}[${index}]`, state)\n );\n\n return `[${serializedItems.join(', ')}]`;\n }\n\n if (isRecord(value)) {\n if (state.seen.has(value)) {\n throw new Error(`${path} contains a circular reference.`);\n }\n\n state.seen.add(value);\n\n const serializedEntries = Object.entries(value)\n .filter(([, nestedValue]) => nestedValue !== undefined)\n .map(([key, nestedValue]) => {\n const serializedNestedValue = serializeValue(nestedValue, `${path}.${key}`, state);\n\n return `${JSON.stringify(key)}: ${serializedNestedValue}`;\n });\n\n return `{ ${serializedEntries.join(', ')} }`;\n }\n\n throw new Error(\n `${path} contains an unsupported value of type ${typeof value}. ` +\n 'Only plain objects, arrays, primitives, and regular expressions are supported.'\n );\n}\n\nfunction assertNoFunctions(value: unknown, path: string): void {\n const state = {\n seen: new WeakSet<object>()\n };\n\n assertNoFunctionsRecursive(value, path, state);\n}\n\nfunction assertNoFunctionsRecursive(\n value: unknown,\n path: string,\n state: { seen: WeakSet<object> }\n): void {\n if (typeof value === 'function') {\n throw new Error(\n `${path} cannot contain functions. ` +\n 'Function-valued sanitization hooks are not supported in framework options.'\n );\n }\n\n if (Array.isArray(value)) {\n value.forEach((item, index) => {\n assertNoFunctionsRecursive(item, `${path}[${index}]`, state);\n });\n\n return;\n }\n\n if (isRecord(value)) {\n if (state.seen.has(value)) {\n return;\n }\n\n state.seen.add(value);\n\n Object.entries(value).forEach(([key, nestedValue]) => {\n assertNoFunctionsRecursive(nestedValue, `${path}.${key}`, state);\n });\n }\n}\n\nfunction matchSegments(pathSegments: string[], patternSegments: string[]): boolean {\n if (patternSegments.length === 0) {\n return pathSegments.length === 0;\n }\n\n const [patternHead, ...patternTail] = patternSegments;\n\n if (patternHead === '**') {\n if (patternTail.length === 0) {\n return true;\n }\n\n for (let index = 0; index <= pathSegments.length; index += 1) {\n const remainingPath = pathSegments.slice(index);\n\n if (matchSegments(remainingPath, patternTail)) {\n return true;\n }\n }\n\n return false;\n }\n\n if (pathSegments.length === 0) {\n return false;\n }\n\n const [pathHead, ...pathTail] = pathSegments;\n\n if (patternHead === '*' || patternHead === pathHead) {\n return matchSegments(pathTail, patternTail);\n }\n\n return false;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n if (typeof value !== 'object' || value === null) {\n return false;\n }\n\n if (Array.isArray(value) || value instanceof RegExp) {\n return false;\n }\n\n const prototype = Object.getPrototypeOf(value);\n\n return prototype === Object.prototype || prototype === null;\n}\n","import { AsyncLocalStorage } from 'node:async_hooks';\n\nexport type StoryModuleMocks = Map<string, string>;\n\nconst moduleMockStorage = new AsyncLocalStorage<StoryModuleMocks>();\n\nexport async function withStoryModuleMocks<T>(\n moduleMocks: StoryModuleMocks,\n callback: () => Promise<T>\n): Promise<T> {\n return moduleMockStorage.run(moduleMocks, callback);\n}\n\nexport function resolveStoryModuleMock(specifier: string): string | undefined {\n return moduleMockStorage.getStore()?.get(specifier);\n}\n"],"mappings":"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","names":["isRecord"]}
|