@storybook-astro/framework 1.0.2 → 1.1.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/dist/{chunk-7GHEQUPV.js → chunk-POHTFYST.js} +46 -8
- package/dist/chunk-POHTFYST.js.map +1 -0
- package/dist/chunk-T7NWIO5S.js +220 -0
- package/dist/chunk-T7NWIO5S.js.map +1 -0
- package/dist/{chunk-C5OH4VBR.js → chunk-V76WSNSP.js} +124 -47
- package/dist/chunk-V76WSNSP.js.map +1 -0
- package/dist/{chunk-KSDXET2L.js → chunk-VPJDFGB5.js} +444 -60
- package/dist/chunk-VPJDFGB5.js.map +1 -0
- package/dist/index.d.ts +19 -9
- package/dist/index.js +10 -3
- package/dist/index.js.map +1 -1
- package/dist/middleware.js +57 -39
- package/dist/middleware.js.map +1 -1
- package/dist/node/index.d.ts +10 -0
- package/dist/node/index.js +10 -0
- package/dist/node/index.js.map +1 -0
- package/dist/preset.d.ts +1 -1
- package/dist/preset.js +3 -3
- package/dist/testing.js +12 -64
- package/dist/testing.js.map +1 -1
- package/dist/{types-CHTsRtA7.d.ts → types-Cvor6Tyi.d.ts} +21 -5
- package/dist/{viteStorybookAstroMiddlewarePlugin-NP2E52IC.js → viteStorybookAstroMiddlewarePlugin-2EFKTECT.js} +2 -2
- package/dist/vitest/global-setup.js +42 -0
- package/dist/vitest/global-setup.js.map +1 -0
- package/dist/vitest/index.js +20 -3
- package/dist/vitest/index.js.map +1 -1
- package/package.json +13 -5
- package/src/index.ts +21 -1
- package/src/lib/sanitization.ts +104 -0
- package/src/middleware.ts +76 -44
- package/src/node/index.ts +7 -0
- package/src/preset.ts +75 -15
- package/src/renderer/renderer-dev.ts +82 -0
- package/src/renderer/renderer-server.test.ts +101 -0
- package/src/renderer/renderer-server.ts +135 -0
- package/src/renderer/renderer-static.ts +62 -0
- package/src/rules.test.ts +89 -18
- package/src/rules.ts +67 -18
- package/src/server/index.ts +111 -0
- package/src/testing/renderer-daemon.ts +10 -1
- package/src/types.ts +25 -5
- package/src/virtual.d.ts +37 -0
- package/src/vite/astroFilesVirtualModulePlugin.ts +36 -0
- package/src/vite/createVirtualModulePlugin.ts +3 -3
- package/src/vite/storybookAstroRulesConfigVirtualModulePlugin.ts +37 -0
- package/src/vite/storybookAstroSanitizationConfigVirtualModulePlugin.ts +21 -0
- package/src/vite/storybookAstroServerAuthConfigVirtualModulePlugin.test.ts +71 -0
- package/src/vite/storybookAstroServerAuthConfigVirtualModulePlugin.ts +42 -0
- package/src/vitePluginAstroBuildPrerender.ts +50 -51
- package/src/vitePluginAstroBuildServer.ts +289 -0
- package/src/vitePluginAstroIntegrationOptsFallback.ts +25 -0
- package/src/viteStorybookAstroMiddlewarePlugin.ts +40 -8
- package/src/viteStorybookAstroRendererPlugin.ts +45 -0
- package/src/vitest/config.ts +45 -4
- package/src/vitest/global-setup.ts +45 -0
- package/dist/chunk-7GHEQUPV.js.map +0 -1
- package/dist/chunk-C5OH4VBR.js.map +0 -1
- package/dist/chunk-KSDXET2L.js.map +0 -1
- package/dist/middleware.d.ts +0 -26
- package/src/msw-helpers.ts +0 -1
- package/src/msw.ts +0 -58
- /package/dist/{viteStorybookAstroMiddlewarePlugin-NP2E52IC.js.map → viteStorybookAstroMiddlewarePlugin-2EFKTECT.js.map} +0 -0
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
// src/viteStorybookAstroMiddlewarePlugin.ts
|
|
6
6
|
import { createRequire } from "module";
|
|
7
7
|
import { fileURLToPath } from "url";
|
|
8
|
-
import { createServer } from "vite";
|
|
8
|
+
import { createServer, createLogger } from "vite";
|
|
9
9
|
|
|
10
10
|
// src/vite/createVirtualModulePlugin.ts
|
|
11
11
|
function createVirtualModulePlugin(options) {
|
|
@@ -159,13 +159,33 @@ function vitePluginAstroFontsFallback() {
|
|
|
159
159
|
};
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
+
// src/vitePluginAstroIntegrationOptsFallback.ts
|
|
163
|
+
var OPTS_STUB = "export default {}";
|
|
164
|
+
var VIRTUAL_IDS = ["astro:react:opts", "astro:preact:opts"];
|
|
165
|
+
function vitePluginAstroIntegrationOptsFallback() {
|
|
166
|
+
const resolvedIds = new Map(VIRTUAL_IDS.map((id) => [id, `\0${id}`]));
|
|
167
|
+
const resolvedIdSet = new Set(resolvedIds.values());
|
|
168
|
+
return {
|
|
169
|
+
name: "storybook-astro-integration-opts-fallback",
|
|
170
|
+
enforce: "pre",
|
|
171
|
+
resolveId(id) {
|
|
172
|
+
return resolvedIds.get(id);
|
|
173
|
+
},
|
|
174
|
+
load(id) {
|
|
175
|
+
if (resolvedIdSet.has(id)) {
|
|
176
|
+
return { code: OPTS_STUB };
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
162
182
|
// src/vitePluginAstroVueFallback.ts
|
|
163
183
|
var VUE_APP_STUB = `
|
|
164
184
|
export const setup = () => {};
|
|
165
185
|
`;
|
|
166
|
-
var
|
|
186
|
+
var VIRTUAL_IDS2 = ["virtual:astro:vue-app", "virtual:@astrojs/vue/app"];
|
|
167
187
|
function vitePluginAstroVueFallback() {
|
|
168
|
-
const resolvedIds = new Map(
|
|
188
|
+
const resolvedIds = new Map(VIRTUAL_IDS2.map((id) => [id, "\0" + id]));
|
|
169
189
|
const resolvedIdSet = new Set(resolvedIds.values());
|
|
170
190
|
return {
|
|
171
191
|
name: "storybook-astro-vue-fallback",
|
|
@@ -291,14 +311,13 @@ async function vitePluginStorybookAstroMiddleware(options) {
|
|
|
291
311
|
const vitePlugin = {
|
|
292
312
|
name: "storybook-astro-middleware-plugin",
|
|
293
313
|
async configureServer(server) {
|
|
294
|
-
viteServer = await createViteServer(options.integrations, resolveFrom);
|
|
314
|
+
viteServer = await createViteServer(options.integrations ?? [], resolveFrom);
|
|
295
315
|
const storyRulesConfigFilePath = resolveRulesConfigFilePath(options.storyRules, resolveFrom);
|
|
296
316
|
const filePath = fileURLToPath(new URL("./middleware", import.meta.url));
|
|
297
317
|
const middleware = await viteServer.ssrLoadModule(filePath, {
|
|
298
318
|
fixStacktrace: true
|
|
299
319
|
});
|
|
300
320
|
const createHandler = () => middleware.handlerFactory(options.integrations ?? [], {
|
|
301
|
-
mode: "development",
|
|
302
321
|
sanitization: options.sanitization,
|
|
303
322
|
rulesConfigFilePath: storyRulesConfigFilePath,
|
|
304
323
|
resolveRulesConfigModule: () => loadRulesConfigModule(viteServer, storyRulesConfigFilePath),
|
|
@@ -362,8 +381,19 @@ async function vitePluginStorybookAstroMiddleware(options) {
|
|
|
362
381
|
}
|
|
363
382
|
};
|
|
364
383
|
}
|
|
384
|
+
function createSsrServerLogger() {
|
|
385
|
+
const logger = createLogger();
|
|
386
|
+
const originalWarn = logger.warn.bind(logger);
|
|
387
|
+
logger.warn = (msg, options) => {
|
|
388
|
+
if (msg.includes("Missing pages directory") || msg.includes("points to missing source files") || msg.includes("Failed to load source map for")) {
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
originalWarn(msg, options);
|
|
392
|
+
};
|
|
393
|
+
return logger;
|
|
394
|
+
}
|
|
365
395
|
async function createViteServer(integrations, resolveFrom = process.cwd()) {
|
|
366
|
-
const { getViteConfig } = await importAstroConfig(resolveFrom);
|
|
396
|
+
const { getViteConfig, passthroughImageService } = await importAstroConfig(resolveFrom);
|
|
367
397
|
const safeIntegrations = integrations ?? [];
|
|
368
398
|
const projectAstroResolutionPlugin = createProjectAstroResolutionPlugin(resolveFrom);
|
|
369
399
|
const config = await getViteConfig(
|
|
@@ -372,16 +402,22 @@ async function createViteServer(integrations, resolveFrom = process.cwd()) {
|
|
|
372
402
|
configFile: false,
|
|
373
403
|
integrations: await Promise.all(
|
|
374
404
|
safeIntegrations.map((integration) => integration.loadIntegration(resolveFrom))
|
|
375
|
-
)
|
|
405
|
+
),
|
|
406
|
+
// Use the passthrough image service so nested components that use <Image>
|
|
407
|
+
// from astro:assets render as plain <img> tags without triggering image
|
|
408
|
+
// optimization (which fails in the Storybook SSR context).
|
|
409
|
+
image: { service: passthroughImageService() }
|
|
376
410
|
}
|
|
377
411
|
)({ mode: "development", command: "serve" });
|
|
378
412
|
const viteServer = await createServer({
|
|
379
413
|
configFile: false,
|
|
380
414
|
...config,
|
|
415
|
+
customLogger: createSsrServerLogger(),
|
|
381
416
|
plugins: [
|
|
382
417
|
projectAstroResolutionPlugin,
|
|
383
418
|
// Fallbacks must come first to intercept before Astro's plugins
|
|
384
419
|
vitePluginAstroFontsFallback(),
|
|
420
|
+
vitePluginAstroIntegrationOptsFallback(),
|
|
385
421
|
vitePluginAstroVueFallback(),
|
|
386
422
|
vitePluginAstroRoutesFallback(),
|
|
387
423
|
...config.plugins?.filter(Boolean) ?? [],
|
|
@@ -428,7 +464,9 @@ async function loadRulesConfigModule(viteServer, configFilePath) {
|
|
|
428
464
|
|
|
429
465
|
export {
|
|
430
466
|
createVirtualModulePlugin,
|
|
467
|
+
viteAstroContainerRenderersPlugin,
|
|
431
468
|
vitePluginAstroFontsFallback,
|
|
469
|
+
vitePluginAstroIntegrationOptsFallback,
|
|
432
470
|
vitePluginAstroVueFallback,
|
|
433
471
|
vitePluginAstroRoutesFallback,
|
|
434
472
|
ssrLoadModuleWithFsFallback,
|
|
@@ -436,4 +474,4 @@ export {
|
|
|
436
474
|
vitePluginStorybookAstroMiddleware,
|
|
437
475
|
createViteServer
|
|
438
476
|
};
|
|
439
|
-
//# sourceMappingURL=chunk-
|
|
477
|
+
//# sourceMappingURL=chunk-POHTFYST.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/viteStorybookAstroMiddlewarePlugin.ts","../src/vite/createVirtualModulePlugin.ts","../src/viteAstroContainerRenderersPlugin.ts","../src/vitePluginAstroFontsFallback.ts","../src/vitePluginAstroIntegrationOptsFallback.ts","../src/vitePluginAstroVueFallback.ts","../src/vitePluginAstroRoutesFallback.ts","../src/lib/ssr-load-module-with-fs-fallback.ts","../src/rules-options.ts"],"sourcesContent":["import { createRequire } from 'node:module';\nimport { fileURLToPath } from 'node:url';\nimport type { ServerResponse } from 'node:http';\nimport { createServer, createLogger, type Connect, type PluginOption, type ViteDevServer } from 'vite';\nimport type { RenderRequestMessage, RenderResponseMessage } from '@storybook-astro/renderer/types';\nimport type { FrameworkOptions } from './types.ts';\nimport type { Integration } from './integrations/index.ts';\nimport { importAstroConfig } from './importAstroConfig.ts';\nimport { viteAstroContainerRenderersPlugin } from './viteAstroContainerRenderersPlugin.ts';\nimport { vitePluginAstroFontsFallback } from './vitePluginAstroFontsFallback.ts';\nimport { vitePluginAstroIntegrationOptsFallback } from './vitePluginAstroIntegrationOptsFallback.ts';\nimport { vitePluginAstroVueFallback } from './vitePluginAstroVueFallback.ts';\nimport { vitePluginAstroRoutesFallback } from './vitePluginAstroRoutesFallback.ts';\nimport { ssrLoadModuleWithFsFallback } from './lib/ssr-load-module-with-fs-fallback.ts';\nimport { resolveRulesConfigFilePath } from './rules-options.ts';\n\nexport async function vitePluginStorybookAstroMiddleware(options: FrameworkOptions) {\n // The internal Vite server is created lazily inside configureServer (dev-only).\n // During builds, configureServer never fires, so no server is created.\n let viteServer: ViteDevServer | null = null;\n\n const resolveFrom = options.resolveFrom ?? process.cwd();\n\n const vitePlugin = {\n name: 'storybook-astro-middleware-plugin',\n async configureServer(server) {\n viteServer = await createViteServer(options.integrations ?? [], resolveFrom);\n const storyRulesConfigFilePath = resolveRulesConfigFilePath(options.storyRules, resolveFrom);\n\n const filePath = fileURLToPath(new URL('./middleware', import.meta.url));\n const middleware = await viteServer.ssrLoadModule(filePath, {\n fixStacktrace: true\n });\n\n const createHandler = () => middleware.handlerFactory(options.integrations ?? [], {\n sanitization: options.sanitization,\n rulesConfigFilePath: storyRulesConfigFilePath,\n resolveRulesConfigModule: () =>\n loadRulesConfigModule(viteServer!, storyRulesConfigFilePath),\n loadModule: (id: string) =>\n ssrLoadModuleWithFsFallback(viteServer!, id, {\n fixStacktrace: true\n })\n });\n\n let handlerPromise = createHandler();\n\n const resetHandler = () => {\n handlerPromise = createHandler();\n };\n\n server.watcher.on('add', resetHandler);\n server.watcher.on('change', resetHandler);\n server.watcher.on('unlink', resetHandler);\n\n server.ws.on('astro:render:request', async (data: RenderRequestMessage['data']) => {\n try {\n const handler = await handlerPromise;\n const html = await handler(data);\n\n server.ws.send('astro:render:response', {\n html,\n id: data.id\n } satisfies RenderResponseMessage['data']);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : String(err);\n const errorStack = err instanceof Error ? err.stack : '';\n\n console.error('[storybook-astro] Render error:', errorMessage);\n if (errorStack) {console.error(errorStack);}\n server.ws.send('astro:render:response', {\n id: data.id,\n html:\n '<div style=\"background: #d73838; padding: 12px; color: #f0f0f0; font-family: monospace; border-radius: 4px\">' +\n '<strong>Error rendering Astro component</strong><br/>' +\n '<pre style=\"white-space: pre-wrap; margin-top: 8px; font-size: 12px\">' +\n errorMessage.replace(/</g, '<').replace(/>/g, '>') +\n '</pre></div>'\n } satisfies RenderResponseMessage['data']);\n }\n });\n }\n } satisfies PluginOption;\n\n // Create asset serving plugin (only active in dev when viteServer exists)\n const assetServingPlugin = {\n name: 'storybook-astro-assets',\n configureServer(server: ViteDevServer) {\n server.middlewares.use('/_image', (req: Connect.IncomingMessage, res: ServerResponse, next: Connect.NextFunction) => {\n if (!viteServer) {\n next();\n\n return;\n }\n // Forward the request to the Astro vite server\n viteServer.middlewares.handle(req, res, (err?: unknown) => {\n if (err) {\n console.error('Asset serving error:', err);\n next();\n }\n });\n });\n }\n };\n\n // The extracted CSS plugins from Astro's internal Vite server cause Vue SFC\n // <style> blocks to be double-processed (once by these plugins, once by\n // Storybook's built-in CSS plugins), resulting in PostCSS errors.\n //\n // Solution: Don't extract Astro's CSS plugins. Storybook's built-in CSS\n // plugins handle both Vue styles AND Astro style sub-modules (which are\n // standard CSS imports like `Component.astro?astro&type=style&index=0&lang.css`).\n //\n // The Astro internal server's CSS plugins are only needed for SSR rendering\n // within that server - they don't need to be shared with Storybook's server.\n return {\n vitePlugin,\n viteConfig: {\n plugins: [\n assetServingPlugin\n ].filter(Boolean)\n }\n };\n}\n\n/**\n * Creates a Vite logger that silences known benign warnings emitted by Astro's\n * Vite plugin in the SSR server context:\n * - \"Missing pages directory\" — Storybook and test contexts have no src/pages.\n * - \"points to missing source files\" — Sourcemap gaps in the `entities` package.\n */\nfunction createSsrServerLogger() {\n const logger = createLogger();\n const originalWarn = logger.warn.bind(logger);\n\n logger.warn = (msg, options) => {\n if (\n msg.includes('Missing pages directory') ||\n msg.includes('points to missing source files') ||\n msg.includes('Failed to load source map for')\n ) {\n return;\n }\n\n originalWarn(msg, options);\n };\n\n return logger;\n}\n\nexport async function createViteServer(integrations: Integration[], resolveFrom = process.cwd()) {\n const { getViteConfig, passthroughImageService } = await importAstroConfig(resolveFrom);\n const safeIntegrations = integrations ?? [];\n const projectAstroResolutionPlugin = createProjectAstroResolutionPlugin(resolveFrom);\n\n const config = await getViteConfig(\n { root: resolveFrom },\n {\n configFile: false,\n integrations: await Promise.all(\n safeIntegrations.map((integration) => integration.loadIntegration(resolveFrom))\n ),\n // Use the passthrough image service so nested components that use <Image>\n // from astro:assets render as plain <img> tags without triggering image\n // optimization (which fails in the Storybook SSR context).\n image: { service: passthroughImageService() }\n }\n )({ mode: 'development', command: 'serve' });\n\n const viteServer = await createServer({\n configFile: false,\n ...config,\n customLogger: createSsrServerLogger(),\n plugins: [\n projectAstroResolutionPlugin,\n // Fallbacks must come first to intercept before Astro's plugins\n vitePluginAstroFontsFallback(),\n vitePluginAstroIntegrationOptsFallback(),\n vitePluginAstroVueFallback(),\n vitePluginAstroRoutesFallback(),\n ...(config.plugins?.filter(Boolean) ?? []),\n viteAstroContainerRenderersPlugin(safeIntegrations)\n ]\n });\n\n // Initialize the server's plugin container to ensure all plugins are ready.\n // Without this, some plugins (like vite:css) may have uninitialized state\n // when ssrLoadModule is called.\n await viteServer.pluginContainer.buildStart({});\n\n return viteServer;\n}\n\nfunction createProjectAstroResolutionPlugin(resolveFrom: string): PluginOption {\n const require = createRequire(import.meta.url);\n\n return {\n name: 'storybook-astro:resolve-project-astro',\n enforce: 'pre',\n resolveId(id: string) {\n if (id !== 'astro' && !id.startsWith('astro/')) {\n return null;\n }\n\n try {\n return require.resolve(id, {\n paths: [resolveFrom]\n });\n } catch {\n return null;\n }\n }\n } satisfies PluginOption;\n}\n\nasync function loadRulesConfigModule(viteServer: ViteDevServer, configFilePath?: string) {\n if (!configFilePath) {\n return undefined;\n }\n\n try {\n return await ssrLoadModuleWithFsFallback(viteServer, configFilePath, {\n fixStacktrace: true\n });\n } catch (error) {\n const reason = error instanceof Error ? error.message : String(error);\n\n throw new Error(\n `Unable to load framework.options.storyRules config module at ${configFilePath}: ${reason}`\n );\n }\n}\n","import type { Plugin } from 'vite';\n\ntype CreateVirtualModulePluginOptions = {\n pluginName: string;\n virtualModuleId: string;\n load: (id: string) => string | Promise<string> | undefined;\n};\n\nexport function createVirtualModulePlugin(options: CreateVirtualModulePluginOptions): Plugin {\n const resolvedVirtualModuleId = `\\0${options.virtualModuleId}`;\n\n return {\n name: options.pluginName,\n resolveId(id) {\n if (id === options.virtualModuleId) {\n return resolvedVirtualModuleId;\n }\n },\n async load(id) {\n if (id === resolvedVirtualModuleId) {\n return options.load(id);\n }\n }\n } satisfies Plugin;\n}\n","import type { Integration } from './integrations/index.ts';\nimport { createVirtualModulePlugin } from './vite/createVirtualModulePlugin.ts';\n\ntype PluginOptions = {\n mode?: 'development' | 'production';\n staticModuleMap?: Record<string, string>;\n};\n\nexport function viteAstroContainerRenderersPlugin(\n integrations: Integration[],\n options: PluginOptions = {}\n) {\n const safeIntegrations = integrations ?? [];\n const mode = options.mode ?? 'development';\n const staticModuleMap = options.staticModuleMap ?? {};\n\n return createVirtualModulePlugin({\n pluginName: 'storybook-astro:container-renderers',\n virtualModuleId: 'virtual:astro-container-renderers',\n load() {\n const importStatements = buildImportStatements(safeIntegrations);\n const clientResolvers =\n mode === 'development'\n ? safeIntegrations\n .filter((integration) => typeof integration.resolveClient === 'function')\n .map((integration) =>\n integration.resolveClient.toString().replace(/^resolveClient/, 'function')\n )\n .join(',\\n')\n : '';\n\n return `\n ${importStatements}\n\n export function addRenderers(container) {\n ${safeIntegrations.map((integration) => buildServerRenderer(integration) + '\\n' + buildClientRenderer(integration)).join('\\n')}\n }\n\n const staticClientModules = ${JSON.stringify(staticModuleMap, null, 2)};\n\n const clientModulesResolvers = [\n ${clientResolvers}\n ];\n\n export function resolveClientModules(specifier) {\n if (Object.hasOwn(staticClientModules, specifier)) {\n return staticClientModules[specifier];\n }\n\n const normalizedSpecifier = specifier.replace(/\\\\\\\\/g, '/').replace(/\\\\?.*$/, '');\n\n if (Object.hasOwn(staticClientModules, normalizedSpecifier)) {\n return staticClientModules[normalizedSpecifier];\n }\n\n for (const resolver of clientModulesResolvers) {\n const resolution = resolver(specifier);\n\n if (resolution) {\n return resolution;\n }\n }\n }\n `;\n }\n });\n}\n\nfunction buildImportStatements(integrations: Integration[]) {\n return integrations\n .filter((integration) => integration.renderer.server)\n .map(\n (integration) =>\n `import ${integration.name}Renderer from '${integration.renderer.server?.entrypoint}';`\n )\n .join('\\n');\n}\n\nfunction buildServerRenderer(integration: Integration) {\n const serverRenderer = integration.renderer.server;\n\n if (!serverRenderer) {\n return '';\n }\n\n if (integration.name === 'solid') {\n return `\n container.addServerRenderer({\n name: '${serverRenderer.name}',\n renderer: {\n ...${integration.name}Renderer,\n name: '${serverRenderer.name}'\n }\n });\n `;\n }\n\n return `\n container.addServerRenderer({\n name: '${serverRenderer.name}',\n renderer: ${integration.name}Renderer\n });\n `;\n}\n\nfunction buildClientRenderer(integration: Integration) {\n const clientRenderer = integration.renderer.client;\n\n if (clientRenderer) {\n return `\n container.addClientRenderer({\n name: '${clientRenderer.name}',\n entrypoint: '${clientRenderer.entrypoint}'\n });\n `;\n }\n\n return '';\n}\n","import type { Plugin } from 'vite';\n\nconst FONTS_RUNTIME_STUB = `\nexport const fontData = {};\nexport function createGetFontData(fontsMod) {\n return fontsMod?.fontDataByCssVariable ?? {};\n}\n`;\n\nconst FONTS_INTERNAL_STUB = `\nexport const componentDataByCssVariable = new Map();\nexport const fontDataByCssVariable = {};\n`;\n\n/**\n * Provides fallback resolution for Astro's font-related virtual modules\n * and package import paths in Storybook's SSR Vite server.\n *\n * In Astro 6, the `astro:assets` virtual module depends on font-related\n * modules through virtual modules and a bare `astro/assets/fonts/runtime`\n * import. In the Storybook SSR context:\n *\n * 1. The fonts plugin's filter-based `resolveId` may not trigger for\n * the virtual module IDs.\n * 2. A Vite transform rewrites the `astro:assets` module to import\n * `createGetFontData` from `astro/assets/fonts/runtime` (without\n * `.js`), which fails against Astro's package.json exports map.\n * 3. The `createGetFontData` function is injected by a runtime Vite\n * transform that doesn't run in our SSR context.\n *\n * This plugin stubs all three font module paths with no-op exports,\n * since Storybook doesn't need Astro's font system.\n */\nexport function vitePluginAstroFontsFallback(): Plugin {\n const VIRTUAL_ID = 'virtual:astro:assets/fonts/internal';\n const RUNTIME_VIRTUAL_ID = 'virtual:astro:assets/fonts/runtime';\n const RESOLVED_VIRTUAL_ID = '\\0' + VIRTUAL_ID;\n const RESOLVED_RUNTIME_VIRTUAL_ID = '\\0' + RUNTIME_VIRTUAL_ID;\n const RESOLVED_FONTS_RUNTIME_ID = '\\0storybook:astro-fonts-runtime';\n\n return {\n name: 'storybook-astro-fonts-fallback',\n // Must run before vite:resolve to intercept virtual modules\n // before Vite tries to resolve them as Node package imports\n enforce: 'pre',\n\n resolveId(id) {\n if (id === VIRTUAL_ID) {\n return RESOLVED_VIRTUAL_ID;\n }\n if (id === RUNTIME_VIRTUAL_ID) {\n return RESOLVED_RUNTIME_VIRTUAL_ID;\n }\n // Intercept the bare package import (without .js) and the .js variant\n if (id === 'astro/assets/fonts/runtime' || id === 'astro/assets/fonts/runtime.js') {\n return RESOLVED_FONTS_RUNTIME_ID;\n }\n },\n\n load(id) {\n if (id === RESOLVED_VIRTUAL_ID) {\n return { code: FONTS_INTERNAL_STUB };\n }\n if (id === RESOLVED_RUNTIME_VIRTUAL_ID || id === RESOLVED_FONTS_RUNTIME_ID) {\n return { code: FONTS_RUNTIME_STUB };\n }\n }\n };\n}\n","import type { Plugin } from 'vite';\n\nconst OPTS_STUB = 'export default {}';\n\nconst VIRTUAL_IDS = ['astro:react:opts', 'astro:preact:opts'];\n\nexport function vitePluginAstroIntegrationOptsFallback(): Plugin {\n const resolvedIds = new Map(VIRTUAL_IDS.map((id) => [id, `\\0${id}`]));\n const resolvedIdSet = new Set(resolvedIds.values());\n\n return {\n name: 'storybook-astro-integration-opts-fallback',\n enforce: 'pre',\n\n resolveId(id) {\n return resolvedIds.get(id);\n },\n\n load(id) {\n if (resolvedIdSet.has(id)) {\n return { code: OPTS_STUB };\n }\n }\n };\n}\n","import type { Plugin } from 'vite';\n\nconst VUE_APP_STUB = `\nexport const setup = () => {};\n`;\n\n// Different versions of @astrojs/vue use different virtual module names\nconst VIRTUAL_IDS = ['virtual:astro:vue-app', 'virtual:@astrojs/vue/app'];\n\n/**\n * Provides fallback resolution for @astrojs/vue's virtual module\n * in Storybook's SSR Vite server.\n *\n * @astrojs/vue's server.js imports a virtual module to get a setup function\n * for configuring the Vue app instance. The virtual module name varies by version:\n * - v6.0.0-beta.1: \"virtual:astro:vue-app\"\n * - Later versions: \"virtual:@astrojs/vue/app\"\n *\n * The Vite plugin that normally creates this virtual module may not run in\n * Storybook's SSR context, so this plugin stubs it with a no-op setup function\n * (the default behavior when no appEntrypoint is configured).\n */\nexport function vitePluginAstroVueFallback(): Plugin {\n const resolvedIds = new Map(VIRTUAL_IDS.map((id) => [id, '\\0' + id]));\n const resolvedIdSet = new Set(resolvedIds.values());\n\n return {\n name: 'storybook-astro-vue-fallback',\n // Must run before vite:resolve to intercept virtual modules\n // before Vite tries to resolve them as Node package imports\n enforce: 'pre',\n\n resolveId(id) {\n const resolved = resolvedIds.get(id);\n\n if (resolved) {\n return resolved;\n }\n },\n\n load(id) {\n if (resolvedIdSet.has(id)) {\n return { code: VUE_APP_STUB };\n }\n }\n };\n}\n","import type { Plugin } from 'vite';\n\nconst ROUTES_STUB = `\nexport const routes = [];\n`;\n\n/**\n * Provides fallback resolution for Astro's routes virtual module\n * in Storybook's SSR Vite server.\n *\n * In Astro 6, the manifest and app entrypoints import from \"virtual:astro:routes\"\n * to get route data. In Storybook's context, there are no routes, so this plugin\n * stubs the virtual module with an empty routes array.\n */\nexport function vitePluginAstroRoutesFallback(): Plugin {\n const VIRTUAL_ID = 'virtual:astro:routes';\n const RESOLVED_VIRTUAL_ID = '\\0' + VIRTUAL_ID;\n\n return {\n name: 'storybook-astro-routes-fallback',\n // Must run before vite:resolve to intercept virtual modules\n // before Vite tries to resolve them as Node package imports\n enforce: 'pre',\n\n resolveId(id) {\n if (id === VIRTUAL_ID) {\n return RESOLVED_VIRTUAL_ID;\n }\n },\n\n load(id) {\n if (id === RESOLVED_VIRTUAL_ID) {\n return { code: ROUTES_STUB };\n }\n }\n };\n}\n","import type { ViteDevServer } from 'vite';\n\ntype SsrLoadModuleOptions = {\n fixStacktrace?: boolean;\n};\n\nexport async function ssrLoadModuleWithFsFallback<TModule = unknown>(\n viteServer: Pick<ViteDevServer, 'ssrLoadModule'>,\n id: string,\n options?: SsrLoadModuleOptions\n) {\n const ids = [id];\n\n if (id.startsWith('/') && !id.startsWith('/@fs/')) {\n ids.push(`/@fs${id}`);\n }\n\n let lastError: unknown;\n\n for (const candidate of ids) {\n try {\n return await viteServer.ssrLoadModule(candidate, options) as TModule;\n } catch (error) {\n lastError = error;\n }\n }\n\n throw lastError;\n}\n","import { existsSync, statSync } from 'node:fs';\nimport { extname, resolve } from 'node:path';\n\nexport type StoryRulesOptions =\n | string\n | {\n configFile: string;\n };\n\nexport function resolveRulesConfigFilePath(\n options?: StoryRulesOptions,\n resolveFrom = process.cwd()\n): string | undefined {\n if (options === undefined) {\n return undefined;\n }\n\n const configFile = normalizeConfigFileOption(options);\n const resolvedConfigFilePath = resolve(resolveFrom, configFile);\n const normalizedConfigFilePath = resolveConfigFilePath(resolvedConfigFilePath);\n\n if (!normalizedConfigFilePath) {\n throw new Error(\n `framework.options.storyRules config file was not found: ${resolvedConfigFilePath}. ` +\n 'Provide an existing path in framework.options.storyRules.'\n );\n }\n\n return normalizedConfigFilePath;\n}\n\nfunction normalizeConfigFileOption(options: StoryRulesOptions): string {\n const configFile =\n typeof options === 'string'\n ? options\n : typeof options === 'object' && options !== null\n ? options.configFile\n : undefined;\n\n if (typeof configFile !== 'string') {\n throw new Error(\n 'framework.options.storyRules must be either a string path or an object with a string configFile.'\n );\n }\n\n const normalizedConfigFile = configFile.trim();\n\n if (!normalizedConfigFile) {\n throw new Error('framework.options.storyRules config file path cannot be empty.');\n }\n\n return normalizedConfigFile;\n}\n\nfunction resolveConfigFilePath(filePath: string): string | undefined {\n if (existsSync(filePath)) {\n const fileStats = statSync(filePath);\n\n if (fileStats.isFile()) {\n return filePath;\n }\n }\n\n if (extname(filePath)) {\n return undefined;\n }\n\n const extensions = ['.ts', '.mts', '.cts', '.js', '.mjs', '.cjs'];\n\n for (const extension of extensions) {\n const candidateFilePath = `${filePath}${extension}`;\n\n if (existsSync(candidateFilePath)) {\n return candidateFilePath;\n }\n }\n\n for (const extension of extensions) {\n const candidateFilePath = resolve(filePath, `index${extension}`);\n\n if (existsSync(candidateFilePath)) {\n return candidateFilePath;\n }\n }\n\n return undefined;\n}\n"],"mappings":"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","names":["VIRTUAL_IDS","require"]}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createViteServer,
|
|
3
|
+
ssrLoadModuleWithFsFallback
|
|
4
|
+
} from "./chunk-POHTFYST.js";
|
|
5
|
+
import {
|
|
6
|
+
resolveTestingIntegrationsForRoot
|
|
7
|
+
} from "./chunk-4SWPVM6R.js";
|
|
8
|
+
|
|
9
|
+
// src/testing/renderer-daemon.ts
|
|
10
|
+
import { createServer as createHttpServer } from "http";
|
|
11
|
+
import { existsSync } from "fs";
|
|
12
|
+
import { fileURLToPath } from "url";
|
|
13
|
+
|
|
14
|
+
// src/testing/working-directory.ts
|
|
15
|
+
var workingDirectoryLock = Promise.resolve();
|
|
16
|
+
async function runWithWorkingDirectory(dir, fn) {
|
|
17
|
+
const previousLock = workingDirectoryLock;
|
|
18
|
+
let releaseLock;
|
|
19
|
+
workingDirectoryLock = new Promise((resolve) => {
|
|
20
|
+
releaseLock = resolve;
|
|
21
|
+
});
|
|
22
|
+
await previousLock;
|
|
23
|
+
const previousCwd = process.cwd();
|
|
24
|
+
try {
|
|
25
|
+
if (previousCwd !== dir) {
|
|
26
|
+
process.chdir(dir);
|
|
27
|
+
}
|
|
28
|
+
return await fn();
|
|
29
|
+
} finally {
|
|
30
|
+
if (process.cwd() !== previousCwd) {
|
|
31
|
+
process.chdir(previousCwd);
|
|
32
|
+
}
|
|
33
|
+
releaseLock();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/testing/renderer-daemon.ts
|
|
38
|
+
var RENDER_PATH = "/render";
|
|
39
|
+
var TESTING_RENDERER_DAEMON_URL_ENV = "STORYBOOK_ASTRO_TESTING_RENDERER_DAEMON_URL";
|
|
40
|
+
async function readJsonBody(request) {
|
|
41
|
+
const chunks = [];
|
|
42
|
+
for await (const chunk of request) {
|
|
43
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
44
|
+
}
|
|
45
|
+
if (chunks.length === 0) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
return JSON.parse(Buffer.concat(chunks).toString("utf-8"));
|
|
49
|
+
}
|
|
50
|
+
function createBadRequest(message) {
|
|
51
|
+
const error = new Error(message);
|
|
52
|
+
error.statusCode = 400;
|
|
53
|
+
return error;
|
|
54
|
+
}
|
|
55
|
+
function assertRenderPayload(payload) {
|
|
56
|
+
if (!payload || typeof payload !== "object") {
|
|
57
|
+
throw createBadRequest("Invalid render payload.");
|
|
58
|
+
}
|
|
59
|
+
const record = payload;
|
|
60
|
+
if (typeof record.resolveFrom !== "string" || record.resolveFrom.length === 0) {
|
|
61
|
+
throw createBadRequest("Missing render payload field: resolveFrom.");
|
|
62
|
+
}
|
|
63
|
+
if (typeof record.component !== "string" || record.component.length === 0) {
|
|
64
|
+
throw createBadRequest("Missing render payload field: component.");
|
|
65
|
+
}
|
|
66
|
+
if ("args" in record && typeof record.args !== "undefined" && (typeof record.args !== "object" || record.args === null || Array.isArray(record.args))) {
|
|
67
|
+
throw createBadRequest("Render payload field args must be an object when provided.");
|
|
68
|
+
}
|
|
69
|
+
if ("slots" in record && typeof record.slots !== "undefined" && (typeof record.slots !== "object" || record.slots === null || Array.isArray(record.slots))) {
|
|
70
|
+
throw createBadRequest("Render payload field slots must be an object when provided.");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function getErrorStatusCode(error) {
|
|
74
|
+
if (error && typeof error === "object" && "statusCode" in error) {
|
|
75
|
+
const statusCode = error.statusCode;
|
|
76
|
+
if (typeof statusCode === "number" && Number.isInteger(statusCode) && statusCode >= 400) {
|
|
77
|
+
return statusCode;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return 500;
|
|
81
|
+
}
|
|
82
|
+
async function startTestingRendererDaemon() {
|
|
83
|
+
const viteServerPromises = /* @__PURE__ */ new Map();
|
|
84
|
+
const renderHandlerPromises = /* @__PURE__ */ new Map();
|
|
85
|
+
async function getViteServer(resolveFrom) {
|
|
86
|
+
if (!viteServerPromises.has(resolveFrom)) {
|
|
87
|
+
const integrations = resolveTestingIntegrationsForRoot(resolveFrom);
|
|
88
|
+
viteServerPromises.set(
|
|
89
|
+
resolveFrom,
|
|
90
|
+
runWithWorkingDirectory(resolveFrom, () => createViteServer(integrations, resolveFrom))
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
return viteServerPromises.get(resolveFrom);
|
|
94
|
+
}
|
|
95
|
+
async function getRenderHandler(resolveFrom) {
|
|
96
|
+
if (!renderHandlerPromises.has(resolveFrom)) {
|
|
97
|
+
renderHandlerPromises.set(resolveFrom, (async () => {
|
|
98
|
+
const integrations = resolveTestingIntegrationsForRoot(resolveFrom);
|
|
99
|
+
const viteServer = await getViteServer(resolveFrom);
|
|
100
|
+
const middlewareSrcPath = fileURLToPath(new URL("../middleware.ts", import.meta.url));
|
|
101
|
+
const middlewareModulePath = existsSync(middlewareSrcPath) ? middlewareSrcPath : fileURLToPath(new URL("./middleware.js", import.meta.url));
|
|
102
|
+
const middleware = await runWithWorkingDirectory(
|
|
103
|
+
resolveFrom,
|
|
104
|
+
() => viteServer.ssrLoadModule(middlewareModulePath, {
|
|
105
|
+
fixStacktrace: true
|
|
106
|
+
})
|
|
107
|
+
);
|
|
108
|
+
return middleware.handlerFactory(integrations, {
|
|
109
|
+
loadModule: (id) => ssrLoadModuleWithFsFallback(viteServer, id, {
|
|
110
|
+
fixStacktrace: true
|
|
111
|
+
})
|
|
112
|
+
});
|
|
113
|
+
})());
|
|
114
|
+
}
|
|
115
|
+
return renderHandlerPromises.get(resolveFrom);
|
|
116
|
+
}
|
|
117
|
+
const server = createHttpServer(async (request, response) => {
|
|
118
|
+
response.setHeader("Access-Control-Allow-Origin", "*");
|
|
119
|
+
response.setHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
|
|
120
|
+
response.setHeader("Access-Control-Allow-Headers", "content-type");
|
|
121
|
+
if (request.method === "OPTIONS") {
|
|
122
|
+
response.statusCode = 204;
|
|
123
|
+
response.end();
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (request.method !== "POST" || request.url !== RENDER_PATH) {
|
|
127
|
+
response.statusCode = 404;
|
|
128
|
+
response.end();
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
const payload = await readJsonBody(request);
|
|
133
|
+
assertRenderPayload(payload);
|
|
134
|
+
const handler = await getRenderHandler(payload.resolveFrom);
|
|
135
|
+
const html = await handler({
|
|
136
|
+
component: payload.component,
|
|
137
|
+
args: payload.args,
|
|
138
|
+
slots: payload.slots
|
|
139
|
+
});
|
|
140
|
+
response.statusCode = 200;
|
|
141
|
+
response.setHeader("content-type", "application/json");
|
|
142
|
+
response.end(JSON.stringify({ html }));
|
|
143
|
+
} catch (error) {
|
|
144
|
+
const statusCode = getErrorStatusCode(error);
|
|
145
|
+
response.statusCode = statusCode;
|
|
146
|
+
response.setHeader("content-type", "application/json");
|
|
147
|
+
response.end(JSON.stringify({
|
|
148
|
+
error: error instanceof Error ? error.message : String(error)
|
|
149
|
+
}));
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
await new Promise((resolve, reject) => {
|
|
153
|
+
server.once("error", reject);
|
|
154
|
+
server.listen(0, "127.0.0.1", () => {
|
|
155
|
+
server.off("error", reject);
|
|
156
|
+
resolve();
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
const address = server.address();
|
|
160
|
+
if (!address || typeof address === "string") {
|
|
161
|
+
throw new Error("Failed to start Storybook Astro testing renderer daemon.");
|
|
162
|
+
}
|
|
163
|
+
const url = `http://127.0.0.1:${address.port}${RENDER_PATH}`;
|
|
164
|
+
return {
|
|
165
|
+
url,
|
|
166
|
+
close: async () => {
|
|
167
|
+
await Promise.all(
|
|
168
|
+
[...viteServerPromises.values()].map(async (viteServerPromise) => {
|
|
169
|
+
const viteServer = await viteServerPromise;
|
|
170
|
+
await viteServer.close();
|
|
171
|
+
})
|
|
172
|
+
);
|
|
173
|
+
await new Promise((resolve, reject) => {
|
|
174
|
+
server.close((error) => {
|
|
175
|
+
if (error) {
|
|
176
|
+
reject(error);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
resolve();
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
function getTestingRendererDaemonUrl() {
|
|
186
|
+
const value = process.env[TESTING_RENDERER_DAEMON_URL_ENV];
|
|
187
|
+
if (!value || value.length === 0) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
return value;
|
|
191
|
+
}
|
|
192
|
+
async function renderViaTestingRendererDaemon(payload) {
|
|
193
|
+
const daemonUrl = getTestingRendererDaemonUrl();
|
|
194
|
+
if (!daemonUrl) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
const response = await fetch(daemonUrl, {
|
|
198
|
+
method: "POST",
|
|
199
|
+
headers: {
|
|
200
|
+
"content-type": "application/json"
|
|
201
|
+
},
|
|
202
|
+
body: JSON.stringify(payload)
|
|
203
|
+
});
|
|
204
|
+
const parsed = await response.json();
|
|
205
|
+
if (!response.ok) {
|
|
206
|
+
throw new Error(parsed.error ?? `Renderer daemon returned ${response.status}.`);
|
|
207
|
+
}
|
|
208
|
+
if (typeof parsed.html !== "string") {
|
|
209
|
+
throw new Error("Renderer daemon returned an invalid payload.");
|
|
210
|
+
}
|
|
211
|
+
return parsed.html;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export {
|
|
215
|
+
runWithWorkingDirectory,
|
|
216
|
+
TESTING_RENDERER_DAEMON_URL_ENV,
|
|
217
|
+
startTestingRendererDaemon,
|
|
218
|
+
renderViaTestingRendererDaemon
|
|
219
|
+
};
|
|
220
|
+
//# sourceMappingURL=chunk-T7NWIO5S.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/testing/renderer-daemon.ts","../src/testing/working-directory.ts"],"sourcesContent":["import { createServer as createHttpServer } from 'node:http';\nimport type { IncomingMessage } from 'node:http';\nimport { existsSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport type { ViteDevServer } from 'vite';\nimport { createViteServer } from '../viteStorybookAstroMiddlewarePlugin.ts';\nimport { resolveTestingIntegrationsForRoot } from './integration-config.ts';\nimport { runWithWorkingDirectory } from './working-directory.ts';\nimport { ssrLoadModuleWithFsFallback } from '../lib/ssr-load-module-with-fs-fallback.ts';\n\nconst RENDER_PATH = '/render';\n\nexport const TESTING_RENDERER_DAEMON_URL_ENV = 'STORYBOOK_ASTRO_TESTING_RENDERER_DAEMON_URL';\n\ntype RenderPayload = {\n resolveFrom: string;\n component: string;\n args?: Record<string, unknown>;\n slots?: Record<string, unknown>;\n};\n\ntype RenderHandler = (data: {\n component: string;\n args?: Record<string, unknown>;\n slots?: Record<string, unknown>;\n}) => Promise<string>;\n\ntype RunningDaemon = {\n url: string;\n close: () => Promise<void>;\n};\n\nasync function readJsonBody(request: IncomingMessage) {\n const chunks: Buffer[] = [];\n\n for await (const chunk of request) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n\n if (chunks.length === 0) {\n return null;\n }\n\n return JSON.parse(Buffer.concat(chunks).toString('utf-8')) as unknown;\n}\n\nfunction createBadRequest(message: string) {\n const error = new Error(message);\n\n (error as Error & { statusCode?: number }).statusCode = 400;\n\n return error;\n}\n\nfunction assertRenderPayload(payload: unknown): asserts payload is RenderPayload {\n if (!payload || typeof payload !== 'object') {\n throw createBadRequest('Invalid render payload.');\n }\n\n const record = payload as Record<string, unknown>;\n\n if (typeof record.resolveFrom !== 'string' || record.resolveFrom.length === 0) {\n throw createBadRequest('Missing render payload field: resolveFrom.');\n }\n\n if (typeof record.component !== 'string' || record.component.length === 0) {\n throw createBadRequest('Missing render payload field: component.');\n }\n\n if (\n 'args' in record &&\n typeof record.args !== 'undefined' &&\n (typeof record.args !== 'object' || record.args === null || Array.isArray(record.args))\n ) {\n throw createBadRequest('Render payload field args must be an object when provided.');\n }\n\n if (\n 'slots' in record &&\n typeof record.slots !== 'undefined' &&\n (typeof record.slots !== 'object' || record.slots === null || Array.isArray(record.slots))\n ) {\n throw createBadRequest('Render payload field slots must be an object when provided.');\n }\n}\n\nfunction getErrorStatusCode(error: unknown) {\n if (error && typeof error === 'object' && 'statusCode' in error) {\n const statusCode = (error as { statusCode?: unknown }).statusCode;\n\n if (typeof statusCode === 'number' && Number.isInteger(statusCode) && statusCode >= 400) {\n return statusCode;\n }\n }\n\n return 500;\n}\n\nexport async function startTestingRendererDaemon(): Promise<RunningDaemon> {\n // One daemon process serves all Vitest workers; cache is keyed by project root.\n const viteServerPromises = new Map<string, Promise<ViteDevServer>>();\n const renderHandlerPromises = new Map<string, Promise<RenderHandler>>();\n\n async function getViteServer(resolveFrom: string) {\n if (!viteServerPromises.has(resolveFrom)) {\n const integrations = resolveTestingIntegrationsForRoot(resolveFrom);\n\n viteServerPromises.set(\n resolveFrom,\n runWithWorkingDirectory(resolveFrom, () => createViteServer(integrations, resolveFrom))\n );\n }\n\n return viteServerPromises.get(resolveFrom)!;\n }\n\n async function getRenderHandler(resolveFrom: string) {\n if (!renderHandlerPromises.has(resolveFrom)) {\n renderHandlerPromises.set(resolveFrom, (async () => {\n const integrations = resolveTestingIntegrationsForRoot(resolveFrom);\n const viteServer = await getViteServer(resolveFrom);\n // In the workspace this file is src/testing/renderer-daemon.ts so\n // '../middleware.ts' resolves to src/middleware.ts (Vite handles .ts).\n // When compiled by tsup, this code lands in a dist/chunk-*.js file so\n // '../middleware.ts' would resolve to framework/middleware.ts which does\n // not exist; fall back to './middleware.js' (sibling in dist/).\n const middlewareSrcPath = fileURLToPath(new URL('../middleware.ts', import.meta.url));\n const middlewareModulePath = existsSync(middlewareSrcPath)\n ? middlewareSrcPath\n : fileURLToPath(new URL('./middleware.js', import.meta.url));\n const middleware = await runWithWorkingDirectory(resolveFrom, () =>\n viteServer.ssrLoadModule(middlewareModulePath, {\n fixStacktrace: true\n })\n );\n\n return middleware.handlerFactory(integrations, {\n loadModule: (id: string) =>\n ssrLoadModuleWithFsFallback(viteServer, id, {\n fixStacktrace: true\n })\n }) as Promise<RenderHandler>;\n })());\n }\n\n return renderHandlerPromises.get(resolveFrom)!;\n }\n\n const server = createHttpServer(async (request, response) => {\n // Allow cross-origin requests from browser-like test environments (e.g. happy-dom).\n response.setHeader('Access-Control-Allow-Origin', '*');\n response.setHeader('Access-Control-Allow-Methods', 'POST, OPTIONS');\n response.setHeader('Access-Control-Allow-Headers', 'content-type');\n\n if (request.method === 'OPTIONS') {\n response.statusCode = 204;\n response.end();\n\n return;\n }\n\n if (request.method !== 'POST' || request.url !== RENDER_PATH) {\n response.statusCode = 404;\n response.end();\n\n return;\n }\n\n try {\n const payload = await readJsonBody(request);\n\n assertRenderPayload(payload);\n\n const handler = await getRenderHandler(payload.resolveFrom);\n const html = await handler({\n component: payload.component,\n args: payload.args,\n slots: payload.slots\n });\n\n response.statusCode = 200;\n response.setHeader('content-type', 'application/json');\n response.end(JSON.stringify({ html }));\n } catch (error) {\n const statusCode = getErrorStatusCode(error);\n\n response.statusCode = statusCode;\n response.setHeader('content-type', 'application/json');\n response.end(JSON.stringify({\n error: error instanceof Error ? error.message : String(error)\n }));\n }\n });\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject);\n server.listen(0, '127.0.0.1', () => {\n server.off('error', reject);\n resolve();\n });\n });\n\n const address = server.address();\n\n if (!address || typeof address === 'string') {\n throw new Error('Failed to start Storybook Astro testing renderer daemon.');\n }\n\n const url = `http://127.0.0.1:${address.port}${RENDER_PATH}`;\n\n return {\n url,\n close: async () => {\n await Promise.all(\n [...viteServerPromises.values()].map(async (viteServerPromise) => {\n const viteServer = await viteServerPromise;\n\n await viteServer.close();\n })\n );\n\n await new Promise<void>((resolve, reject) => {\n server.close((error) => {\n if (error) {\n reject(error);\n\n return;\n }\n\n resolve();\n });\n });\n }\n };\n}\n\nexport function getTestingRendererDaemonUrl() {\n const value = process.env[TESTING_RENDERER_DAEMON_URL_ENV];\n\n if (!value || value.length === 0) {\n return null;\n }\n\n return value;\n}\n\nexport async function renderViaTestingRendererDaemon(payload: RenderPayload) {\n const daemonUrl = getTestingRendererDaemonUrl();\n\n if (!daemonUrl) {\n // Daemon is optional so local in-worker rendering can still be used as fallback.\n return null;\n }\n\n // eslint-disable-next-line n/no-unsupported-features/node-builtins\n const response = await fetch(daemonUrl, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json'\n },\n body: JSON.stringify(payload)\n });\n\n const parsed = (await response.json()) as {\n html?: string;\n error?: string;\n };\n\n if (!response.ok) {\n throw new Error(parsed.error ?? `Renderer daemon returned ${response.status}.`);\n }\n\n if (typeof parsed.html !== 'string') {\n throw new Error('Renderer daemon returned an invalid payload.');\n }\n\n return parsed.html;\n}\n","let workingDirectoryLock: Promise<void> = Promise.resolve();\n\nexport async function runWithWorkingDirectory<T>(dir: string, fn: () => Promise<T>) {\n const previousLock = workingDirectoryLock;\n let releaseLock!: () => void;\n\n workingDirectoryLock = new Promise<void>((resolve) => {\n releaseLock = resolve;\n });\n\n await previousLock;\n\n const previousCwd = process.cwd();\n\n try {\n if (previousCwd !== dir) {\n process.chdir(dir);\n }\n\n return await fn();\n } finally {\n if (process.cwd() !== previousCwd) {\n process.chdir(previousCwd);\n }\n\n releaseLock();\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -16,24 +16,64 @@ async function selectStoryRules(input) {
|
|
|
16
16
|
if (typeof use !== "function") {
|
|
17
17
|
throw new Error('Each story rule "use" entry must be a function.');
|
|
18
18
|
}
|
|
19
|
-
await use({
|
|
20
|
-
mode: input.mode,
|
|
19
|
+
const cleanup = await use({
|
|
21
20
|
story,
|
|
22
|
-
msw: {
|
|
23
|
-
use: (...handlers) => {
|
|
24
|
-
selection.mswHandlers.push(...handlers);
|
|
25
|
-
}
|
|
26
|
-
},
|
|
27
21
|
mock: (specifier, replacement) => {
|
|
28
22
|
const normalizedSpecifier = normalizeMockSpecifier(specifier);
|
|
29
23
|
const normalizedReplacement = normalizeMockReplacement(replacement, input.configFilePath);
|
|
30
24
|
selection.moduleMocks.set(normalizedSpecifier, normalizedReplacement);
|
|
31
25
|
}
|
|
32
26
|
});
|
|
27
|
+
if (cleanup !== void 0) {
|
|
28
|
+
if (typeof cleanup !== "function") {
|
|
29
|
+
throw new Error('Story rule "use" must return either nothing or a cleanup function.');
|
|
30
|
+
}
|
|
31
|
+
selection.cleanups.push(cleanup);
|
|
32
|
+
}
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
return selection;
|
|
36
36
|
}
|
|
37
|
+
async function withStoryRuleCleanups(cleanups, callback) {
|
|
38
|
+
let result;
|
|
39
|
+
let callbackError;
|
|
40
|
+
try {
|
|
41
|
+
result = await callback();
|
|
42
|
+
} catch (error) {
|
|
43
|
+
callbackError = error;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
await runStoryRuleCleanups(cleanups);
|
|
47
|
+
} catch (cleanupError) {
|
|
48
|
+
if (callbackError) {
|
|
49
|
+
throw new AggregateError(
|
|
50
|
+
[callbackError, cleanupError],
|
|
51
|
+
"Story rule execution and cleanup both failed."
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
throw cleanupError;
|
|
55
|
+
}
|
|
56
|
+
if (callbackError) {
|
|
57
|
+
throw callbackError;
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
async function runStoryRuleCleanups(cleanups) {
|
|
62
|
+
const errors = [];
|
|
63
|
+
for (let index = cleanups.length - 1; index >= 0; index -= 1) {
|
|
64
|
+
try {
|
|
65
|
+
await cleanups[index]();
|
|
66
|
+
} catch (error) {
|
|
67
|
+
errors.push(error);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (errors.length === 1) {
|
|
71
|
+
throw errors[0];
|
|
72
|
+
}
|
|
73
|
+
if (errors.length > 1) {
|
|
74
|
+
throw new AggregateError(errors, "Story rule cleanup failed.");
|
|
75
|
+
}
|
|
76
|
+
}
|
|
37
77
|
function normalizeRulesConfig(configModule) {
|
|
38
78
|
const configExport = getRulesConfigExport(configModule);
|
|
39
79
|
if (configExport === void 0 || configExport === null) {
|
|
@@ -176,7 +216,7 @@ function slugify(input) {
|
|
|
176
216
|
function createEmptySelection() {
|
|
177
217
|
return {
|
|
178
218
|
moduleMocks: /* @__PURE__ */ new Map(),
|
|
179
|
-
|
|
219
|
+
cleanups: []
|
|
180
220
|
};
|
|
181
221
|
}
|
|
182
222
|
function toPosixPath(input) {
|
|
@@ -314,6 +354,16 @@ function sanitizeRenderPayload(payload, options) {
|
|
|
314
354
|
slots: sanitizedSlots
|
|
315
355
|
};
|
|
316
356
|
}
|
|
357
|
+
function serializeSanitizationOptions(options) {
|
|
358
|
+
if (!options) {
|
|
359
|
+
return "undefined";
|
|
360
|
+
}
|
|
361
|
+
assertNoFunctions(options.sanitizeHtml, "framework.options.sanitization.sanitizeHtml");
|
|
362
|
+
const state = {
|
|
363
|
+
seen: /* @__PURE__ */ new WeakSet()
|
|
364
|
+
};
|
|
365
|
+
return serializeValue(options, "framework.options.sanitization", state);
|
|
366
|
+
}
|
|
317
367
|
function mergeSanitizeHtmlOptions(userOptions) {
|
|
318
368
|
const merged = {
|
|
319
369
|
...DEFAULT_SANITIZE_HTML_OPTIONS,
|
|
@@ -397,6 +447,68 @@ function matchesPathPattern(path, pattern) {
|
|
|
397
447
|
const patternSegments = pattern.split(".");
|
|
398
448
|
return matchSegments(pathSegments, patternSegments);
|
|
399
449
|
}
|
|
450
|
+
function serializeValue(value, path, state) {
|
|
451
|
+
if (value === null) {
|
|
452
|
+
return "null";
|
|
453
|
+
}
|
|
454
|
+
if (value === void 0) {
|
|
455
|
+
return "undefined";
|
|
456
|
+
}
|
|
457
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
458
|
+
return JSON.stringify(value);
|
|
459
|
+
}
|
|
460
|
+
if (value instanceof RegExp) {
|
|
461
|
+
return value.toString();
|
|
462
|
+
}
|
|
463
|
+
if (Array.isArray(value)) {
|
|
464
|
+
const serializedItems = value.map(
|
|
465
|
+
(item, index) => serializeValue(item, `${path}[${index}]`, state)
|
|
466
|
+
);
|
|
467
|
+
return `[${serializedItems.join(", ")}]`;
|
|
468
|
+
}
|
|
469
|
+
if (isRecord2(value)) {
|
|
470
|
+
if (state.seen.has(value)) {
|
|
471
|
+
throw new Error(`${path} contains a circular reference.`);
|
|
472
|
+
}
|
|
473
|
+
state.seen.add(value);
|
|
474
|
+
const serializedEntries = Object.entries(value).filter(([, nestedValue]) => nestedValue !== void 0).map(([key, nestedValue]) => {
|
|
475
|
+
const serializedNestedValue = serializeValue(nestedValue, `${path}.${key}`, state);
|
|
476
|
+
return `${JSON.stringify(key)}: ${serializedNestedValue}`;
|
|
477
|
+
});
|
|
478
|
+
return `{ ${serializedEntries.join(", ")} }`;
|
|
479
|
+
}
|
|
480
|
+
throw new Error(
|
|
481
|
+
`${path} contains an unsupported value of type ${typeof value}. Only plain objects, arrays, primitives, and regular expressions are supported.`
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
function assertNoFunctions(value, path) {
|
|
485
|
+
const state = {
|
|
486
|
+
seen: /* @__PURE__ */ new WeakSet()
|
|
487
|
+
};
|
|
488
|
+
assertNoFunctionsRecursive(value, path, state);
|
|
489
|
+
}
|
|
490
|
+
function assertNoFunctionsRecursive(value, path, state) {
|
|
491
|
+
if (typeof value === "function") {
|
|
492
|
+
throw new Error(
|
|
493
|
+
`${path} cannot contain functions. Function-valued sanitization hooks are not supported in framework options.`
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
if (Array.isArray(value)) {
|
|
497
|
+
value.forEach((item, index) => {
|
|
498
|
+
assertNoFunctionsRecursive(item, `${path}[${index}]`, state);
|
|
499
|
+
});
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
if (isRecord2(value)) {
|
|
503
|
+
if (state.seen.has(value)) {
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
state.seen.add(value);
|
|
507
|
+
Object.entries(value).forEach(([key, nestedValue]) => {
|
|
508
|
+
assertNoFunctionsRecursive(nestedValue, `${path}.${key}`, state);
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
}
|
|
400
512
|
function matchSegments(pathSegments, patternSegments) {
|
|
401
513
|
if (patternSegments.length === 0) {
|
|
402
514
|
return pathSegments.length === 0;
|
|
@@ -444,49 +556,14 @@ function resolveStoryModuleMock(specifier) {
|
|
|
444
556
|
return moduleMockStorage.getStore()?.get(specifier);
|
|
445
557
|
}
|
|
446
558
|
|
|
447
|
-
// src/msw.ts
|
|
448
|
-
import { setupServer } from "msw/node";
|
|
449
|
-
var defaultListenOptions = {
|
|
450
|
-
onUnhandledRequest: "bypass"
|
|
451
|
-
};
|
|
452
|
-
async function applyMswHandlers(handlers) {
|
|
453
|
-
const state = getMswState();
|
|
454
|
-
if (state.pendingUpdate) {
|
|
455
|
-
await state.pendingUpdate;
|
|
456
|
-
}
|
|
457
|
-
const updatePromise = syncMswHandlers(handlers, state);
|
|
458
|
-
state.pendingUpdate = updatePromise;
|
|
459
|
-
try {
|
|
460
|
-
await updatePromise;
|
|
461
|
-
} finally {
|
|
462
|
-
state.pendingUpdate = void 0;
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
async function syncMswHandlers(handlers, state) {
|
|
466
|
-
if (!state.server) {
|
|
467
|
-
state.server = setupServer();
|
|
468
|
-
state.server.listen(defaultListenOptions);
|
|
469
|
-
}
|
|
470
|
-
state.server.resetHandlers(...handlers);
|
|
471
|
-
}
|
|
472
|
-
function getMswState() {
|
|
473
|
-
const globalState = globalThis;
|
|
474
|
-
if (!globalState.__storybookAstroMswState__) {
|
|
475
|
-
globalState.__storybookAstroMswState__ = {
|
|
476
|
-
server: void 0,
|
|
477
|
-
pendingUpdate: void 0
|
|
478
|
-
};
|
|
479
|
-
}
|
|
480
|
-
return globalState.__storybookAstroMswState__;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
559
|
export {
|
|
484
560
|
defineStoryRules,
|
|
485
561
|
selectStoryRules,
|
|
562
|
+
withStoryRuleCleanups,
|
|
486
563
|
resolveSanitizationOptions,
|
|
487
564
|
sanitizeRenderPayload,
|
|
565
|
+
serializeSanitizationOptions,
|
|
488
566
|
withStoryModuleMocks,
|
|
489
|
-
resolveStoryModuleMock
|
|
490
|
-
applyMswHandlers
|
|
567
|
+
resolveStoryModuleMock
|
|
491
568
|
};
|
|
492
|
-
//# sourceMappingURL=chunk-
|
|
569
|
+
//# sourceMappingURL=chunk-V76WSNSP.js.map
|