@astroscope/node 2.0.0 → 2.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/index.d.ts +1 -1
- package/dist/index.js +13 -12
- package/dist/index.js.map +1 -1
- package/dist/islands-middleware-entrypoint.js +1 -1
- package/dist/islands-runtime.iife.js +1 -0
- package/dist/islands.d.ts +1 -1
- package/dist/{prerendered-CpEAJN_q.js → prerendered-DVjzWNbW.js} +2 -2
- package/dist/{prerendered-CpEAJN_q.js.map → prerendered-DVjzWNbW.js.map} +1 -1
- package/dist/{route-store-DtY3uvLf.d.ts → route-store-CSYR4G5e.d.ts} +12 -4
- package/dist/route-store-CSYR4G5e.d.ts.map +1 -0
- package/dist/strip-build-paths-C6eb1QdG.js +63 -0
- package/dist/strip-build-paths-C6eb1QdG.js.map +1 -0
- package/dist/{transform-D8dIBGEr.js → transform-BqV8SOEm.js} +7 -3
- package/dist/transform-BqV8SOEm.js.map +1 -0
- package/package.json +1 -1
- package/dist/islands-runtime.d.ts +0 -1
- package/dist/islands-runtime.js +0 -113
- package/dist/islands-runtime.js.map +0 -1
- package/dist/route-store-DtY3uvLf.d.ts.map +0 -1
- package/dist/transform-D8dIBGEr.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { r as ExcludePattern } from "./excludes-BDiE3eyp.js";
|
|
2
2
|
import "./construct-BGlPfWMF.js";
|
|
3
|
-
import { c as IslandEmitter, i as registerIslandEmitter, l as IslandInfo, s as IslandEmission, t as getRequestRouteData } from "./route-store-
|
|
3
|
+
import { c as IslandEmitter, i as registerIslandEmitter, l as IslandInfo, s as IslandEmission, t as getRequestRouteData } from "./route-store-CSYR4G5e.js";
|
|
4
4
|
import { t as BootContext } from "./types-D0uMBi2M.js";
|
|
5
5
|
import { n as BootEventName, t as BootEventHandler } from "./events-u7J3ezJR.js";
|
|
6
6
|
import { AstroIntegration } from "astro";
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,6 @@ import fs, { readFileSync } from "node:fs";
|
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
11
|
import { parse } from "@astrojs/compiler-rs";
|
|
12
|
-
import { createHash } from "node:crypto";
|
|
13
12
|
import { Parser } from "acorn";
|
|
14
13
|
import MagicString from "magic-string";
|
|
15
14
|
//#region src/dev-mode/island-warmup.ts
|
|
@@ -582,9 +581,12 @@ const RESOLVED_ISLANDS_VIRTUAL_MODULE_ID = `\0virtual:@astroscope/node/islands-m
|
|
|
582
581
|
const MANIFEST_FILE_NAME = "islands-manifest.json";
|
|
583
582
|
/**
|
|
584
583
|
* Client-build side of island preloading: records the chunk import graph (direct
|
|
585
|
-
* static and dynamic edges per chunk),
|
|
586
|
-
* the
|
|
587
|
-
*
|
|
584
|
+
* static and dynamic edges per chunk), embeds the gate runtime source, and drops
|
|
585
|
+
* the manifest next to the server chunks — where the virtual module reads it back
|
|
586
|
+
* at runtime, mirroring the i18n manifest. The runtime is inlined into documents
|
|
587
|
+
* rather than shipped as an asset: an external module fetch would install the
|
|
588
|
+
* gates a round-trip after astro's own inline island machinery, losing the race
|
|
589
|
+
* it exists to win.
|
|
588
590
|
*
|
|
589
591
|
* The client build runs after the server build, so the SSR bundle can only carry
|
|
590
592
|
* code that reads the file lazily; in dev there is no manifest and the middleware
|
|
@@ -638,13 +640,10 @@ export { manifest };
|
|
|
638
640
|
...chunk.dynamicImports.length > 0 && { d: chunk.dynamicImports }
|
|
639
641
|
};
|
|
640
642
|
}
|
|
641
|
-
const runtimeSource = fs.readFileSync(new URL("./islands-runtime.js", import.meta.url), "utf-8").
|
|
642
|
-
|
|
643
|
-
const runtime = `${options.assetsDir}/islands-runtime.${hash}.js`;
|
|
644
|
-
fs.mkdirSync(path.join(outputOptions.dir, options.assetsDir), { recursive: true });
|
|
645
|
-
fs.writeFileSync(path.join(outputOptions.dir, options.assetsDir, `islands-runtime.${hash}.js`), runtimeSource);
|
|
643
|
+
const runtimeSource = fs.readFileSync(new URL("./islands-runtime.iife.js", import.meta.url), "utf-8").trim();
|
|
644
|
+
if (runtimeSource.toLowerCase().includes("<\/script")) throw new Error("islands gate runtime must not contain \"<\/script\"");
|
|
646
645
|
const manifest = {
|
|
647
|
-
|
|
646
|
+
runtimeSource,
|
|
648
647
|
chunks
|
|
649
648
|
};
|
|
650
649
|
const chunksDir = path.resolve(outputOptions.dir, "..", "server", "chunks");
|
|
@@ -893,7 +892,6 @@ function node(options = {}) {
|
|
|
893
892
|
...devMachinery,
|
|
894
893
|
...islandWarmup,
|
|
895
894
|
createIslandsManifestPlugin({
|
|
896
|
-
assetsDir: config.build.assets,
|
|
897
895
|
logger,
|
|
898
896
|
enabled: islandsEnabled
|
|
899
897
|
}),
|
|
@@ -987,12 +985,15 @@ function node(options = {}) {
|
|
|
987
985
|
if (islandsEnabled) {
|
|
988
986
|
const manifestPath = path.join(fileURLToPath(astroConfig.build.server), "chunks", "islands-manifest.json");
|
|
989
987
|
if (fs.existsSync(manifestPath)) {
|
|
990
|
-
const { transformPrerenderedHtml } = await import("./prerendered-
|
|
988
|
+
const { transformPrerenderedHtml } = await import("./prerendered-DVjzWNbW.js");
|
|
991
989
|
const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
|
|
992
990
|
const transformed = await transformPrerenderedHtml(fileURLToPath(astroConfig.build.client), manifest);
|
|
993
991
|
if (transformed > 0) logger.info(`island preloading applied to ${transformed} prerendered page(s)`);
|
|
994
992
|
}
|
|
995
993
|
}
|
|
994
|
+
const { stripBuildPaths } = await import("./strip-build-paths-C6eb1QdG.js");
|
|
995
|
+
const stripped = stripBuildPaths(fileURLToPath(astroConfig.build.server), fileURLToPath(astroConfig.root));
|
|
996
|
+
if (stripped > 0) logger.info(`build machine paths stripped from ${stripped} server file(s)`);
|
|
996
997
|
const { compressClientDir } = await import("./compress-B11aeRHQ.js");
|
|
997
998
|
await compressClientDir(fileURLToPath(astroConfig.build.client), logger);
|
|
998
999
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["walk"],"sources":["../src/dev-mode/island-warmup.ts","../src/dev-mode/serialize-error.ts","../src/dev-mode/scheduler.ts","../src/dev-mode/vite-env.ts","../src/dev-mode/ignored.ts","../src/dev-mode/watch.ts","../src/dev-mode/machinery.ts","../src/excludes/serialize.ts","../src/islands/manifest-plugin.ts","../src/tweaks/sourcemap.ts","../src/tweaks/strip-effects.ts","../src/integration/integration.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { parse } from '@astrojs/compiler-rs';\nimport type { Plugin, ViteDevServer } from 'vite';\n\n/**\n * Vite discovers island dependencies lazily: astro registers no client entries,\n * so a dep like radix is first seen when an island hydrates. The optimizer then\n * re-runs, bumps the `?v=` hash and every in-flight import gets a\n * \"504 Outdated Optimize Dep\" — hydration fails until the full reload.\n *\n * This plugin scans `.astro` sources for `client:*` components at config time,\n * puts their bare package imports into `optimizeDeps.include` (initial optimize\n * pass) and warms their local module graphs at server start (vite's\n * `preTransformRequests` crawls static imports recursively), so discovery\n * happens before a browser holds stale URLs.\n */\n\ninterface Logger {\n info(msg: string): void;\n debug(msg: string): void;\n}\n\nexport interface IslandImport {\n /** absolute path of the .astro file rendering the island */\n importer: string;\n /** import specifier of the hydrated component */\n specifier: string;\n}\n\ninterface AstNode {\n type: string;\n [key: string]: unknown;\n}\n\nfunction isAstNode(value: unknown): value is AstNode {\n return typeof value === 'object' && value !== null && typeof (value as AstNode).type === 'string';\n}\n\nfunction walk(node: unknown, visit: (node: AstNode) => void): void {\n if (Array.isArray(node)) {\n for (const item of node) walk(item, visit);\n\n return;\n }\n\n if (typeof node !== 'object' || node === null) return;\n\n if (isAstNode(node)) visit(node);\n\n for (const value of Object.values(node)) walk(value, visit);\n}\n\ninterface ImportDeclarationNode {\n importKind?: string | null;\n source?: { value?: unknown } | null;\n specifiers?: { importKind?: string | null; local?: { name?: unknown } | null }[] | null;\n}\n\n/** local binding name → import specifier, from the frontmatter program */\nfunction collectImports(program: unknown): Map<string, string> {\n const imports = new Map<string, string>();\n\n walk(program, (node) => {\n if (node.type !== 'ImportDeclaration') return;\n\n const decl = node as ImportDeclarationNode;\n\n if (decl.importKind === 'type') return;\n\n const specifier = typeof decl.source?.value === 'string' ? decl.source.value : undefined;\n\n if (!specifier) return;\n\n for (const spec of decl.specifiers ?? []) {\n if (spec.importKind === 'type') continue;\n\n if (typeof spec.local?.name === 'string') {\n imports.set(spec.local.name, specifier);\n }\n }\n });\n\n return imports;\n}\n\n/** the root identifier of a JSX tag: `Foo` → Foo, `Ns.Chart` → Ns */\nfunction tagRootIdentifier(name: unknown): string | undefined {\n let current = name;\n\n while (isAstNode(current) && current.type === 'JSXMemberExpression') {\n current = (current as unknown as { object?: unknown }).object;\n }\n\n if (isAstNode(current) && current.type === 'JSXIdentifier') {\n const identifier = current as unknown as { name?: unknown };\n\n return typeof identifier.name === 'string' ? identifier.name : undefined;\n }\n\n return undefined;\n}\n\nfunction hasClientDirective(attributes: unknown): boolean {\n if (!Array.isArray(attributes)) return false;\n\n return attributes.some((attr) => {\n if (!isAstNode(attr) || attr.type !== 'JSXAttribute') return false;\n\n const name = (attr as unknown as { name?: { name?: unknown } | null }).name;\n\n return typeof name?.name === 'string' && name.name.startsWith('client:');\n });\n}\n\n/**\n * Extract the import specifiers of all hydrated (`client:*`) components from\n * raw `.astro` source. Astro components can't hydrate, so `.astro` specifiers\n * are skipped; dynamic tags without a frontmatter import are invisible here.\n */\nexport function scanAstroSource(source: string): string[] {\n const { ast } = parse(source);\n const root = ast as { frontmatter?: { program?: unknown } | null; body?: unknown };\n\n const imports = collectImports(root.frontmatter?.program);\n\n if (imports.size === 0) return [];\n\n const specifiers = new Set<string>();\n\n walk(root.body, (node) => {\n if (node.type !== 'JSXOpeningElement') return;\n\n const element = node as unknown as { attributes?: unknown; name?: unknown };\n\n if (!hasClientDirective(element.attributes)) return;\n\n const rootName = tagRootIdentifier(element.name);\n\n if (!rootName || /^[a-z]/.test(rootName)) return;\n\n const specifier = imports.get(rootName);\n\n if (specifier && !specifier.endsWith('.astro')) {\n specifiers.add(specifier);\n }\n });\n\n return [...specifiers];\n}\n\n/** scan all `.astro` files under `srcDir` for hydrated components */\nexport async function scanProjectIslands(srcDir: string, logger: Logger): Promise<IslandImport[]> {\n const islands: IslandImport[] = [];\n\n let entries: fs.Dirent[];\n\n try {\n entries = await fs.promises.readdir(srcDir, { recursive: true, withFileTypes: true });\n } catch {\n return islands;\n }\n\n const files = entries\n .filter((entry) => entry.isFile() && entry.name.endsWith('.astro'))\n .map((entry) => path.join(entry.parentPath, entry.name));\n\n await Promise.all(\n files.map(async (file) => {\n try {\n const source = await fs.promises.readFile(file, 'utf8');\n\n for (const specifier of scanAstroSource(source)) {\n islands.push({ importer: file, specifier });\n }\n } catch (error) {\n // a file mid-edit or unreadable must not break the dev server\n logger.debug(`island scan skipped ${file}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }),\n );\n\n return islands;\n}\n\nfunction packageNameOf(specifier: string): string {\n const segments = specifier.split('/');\n\n return specifier.startsWith('@') ? segments.slice(0, 2).join('/') : (segments[0] ?? specifier);\n}\n\n/**\n * Bare package specifiers resolvable from the project's `node_modules` — these\n * go into `optimizeDeps.include`. Anything else (relative paths, tsconfig\n * aliases, hoisted workspace deps) is resolved through vite at server start;\n * misclassification is harmless, just slightly later discovery.\n */\nexport function selectBareSpecifiers(islands: IslandImport[], root: string): string[] {\n const bare = new Set<string>();\n\n for (const { specifier } of islands) {\n if (specifier.startsWith('.') || specifier.startsWith('/') || specifier.startsWith('#')) continue;\n\n if (fs.existsSync(path.join(root, 'node_modules', packageNameOf(specifier)))) {\n bare.add(specifier);\n }\n }\n\n return [...bare];\n}\n\nfunction toRequestUrl(id: string, root: string): string {\n const normalized = id.split(path.sep).join('/');\n const normalizedRoot = root.split(path.sep).join('/');\n\n return normalized.startsWith(`${normalizedRoot}/`) ? normalized.slice(normalizedRoot.length) : `/@fs/${normalized}`;\n}\n\nexport interface IslandWarmupOptions {\n root: string;\n srcDir: string;\n logger: Logger;\n}\n\nexport function createIslandWarmup(options: IslandWarmupOptions): Plugin {\n const { root, srcDir, logger } = options;\n\n let islands: IslandImport[] = [];\n\n const warmIslands = async (server: ViteDevServer, batch: IslandImport[], warmed: Set<string>): Promise<void> => {\n const env = server.environments.client;\n\n await Promise.all(\n batch.map(async ({ importer, specifier }) => {\n try {\n // resolving through vite also registers still-unknown bare deps with\n // the optimizer — discovery happens now, not at hydration time\n const resolved = await env.pluginContainer.resolveId(specifier, importer);\n\n if (!resolved || resolved.external) return;\n if (resolved.id.startsWith('\\0') || resolved.id.includes('node_modules')) return;\n if (warmed.has(resolved.id)) return;\n\n warmed.add(resolved.id);\n\n await env.warmupRequest(toRequestUrl(resolved.id, root));\n } catch {\n // warmup is best-effort; a broken component surfaces on request anyway\n }\n }),\n );\n };\n\n return {\n name: '@astroscope/node/island-warmup',\n\n async config() {\n islands = await scanProjectIslands(srcDir, logger);\n\n const include = selectBareSpecifiers(islands, root);\n\n if (islands.length > 0) {\n logger.info(`warming ${islands.length} island(s), pre-optimizing ${include.length} dependenc(ies)`);\n }\n\n return include.length > 0 ? { optimizeDeps: { include } } : undefined;\n },\n\n configureServer(server) {\n const warmed = new Set<string>();\n\n // the plugin container is not initialized until the server starts\n // listening — mirror vite's own warmup timing\n if (server.httpServer) {\n server.httpServer.once('listening', () => void warmIslands(server, islands, warmed));\n } else {\n void warmIslands(server, islands, warmed);\n }\n\n // islands added mid-session get discovered at save time instead of at\n // page load; new bare deps still re-optimize, but before hydration\n const onWatcherEvent = (file: string): void => {\n if (!file.endsWith('.astro') || !file.startsWith(srcDir)) return;\n\n void fs.promises\n .readFile(file, 'utf8')\n .then((source) => {\n const batch = scanAstroSource(source).map((specifier) => ({ importer: file, specifier }));\n\n return warmIslands(server, batch, warmed);\n })\n .catch(() => {});\n };\n\n server.watcher.on('add', onWatcherEvent);\n server.watcher.on('change', onWatcherEvent);\n },\n };\n}\n","export function serializeError(error: unknown): string {\n if (error instanceof Error) {\n return error.stack ?? error.message;\n }\n\n return JSON.stringify(error);\n}\n","import path from 'node:path';\nimport type { ViteDevServer } from 'vite';\nimport { serializeError } from './serialize-error.js';\n\ntype Logger = { info(msg: string): void; error(msg: string): void };\n\nconst FULL_RELOAD_UNKNOWN = '<unknown>';\n\n/**\n * Coordinates dev-server restarts: debounces bursts, chains a follow-up if\n * changes arrive mid-restart (vite's `ssrImport` reads disk at import time,\n * so changes during a restart would otherwise be missed), and logs once per\n * restart with what triggered it.\n *\n * One instance per integration, shared across restart-induced configureServer\n * reruns — chain coordination would be lost if recreated each time.\n */\nexport class RestartScheduler {\n private _inFlight = false;\n private _pending = false;\n private _debounceTimer: ReturnType<typeof setTimeout> | undefined;\n private _pendingBootDeps = new Set<string>();\n private _pendingFullReloads = new Set<string>();\n // set while a restart chain is running. the gate probes it (`isRestartPending`)\n // to short-circuit requests, and awaits it (`waitForRestart`) on readiness.\n private _runPromise: Promise<void> | undefined;\n // set when a restart attempt fails\n private _lastFailure: { message: string } | undefined;\n\n constructor(\n private readonly debounceMs: number,\n private readonly logger: Logger,\n ) {}\n\n // true from the moment a change is queued until the restart completes — covers\n // the debounce window too, so requests don't slip past the gate before _run starts.\n isRestartPending(): boolean {\n return !!this._runPromise || !!this._debounceTimer || !!this._lastFailure;\n }\n\n getLastFailure(): { message: string } | undefined {\n return this._lastFailure;\n }\n\n recordFailure(message: string): void {\n this._lastFailure = { message };\n }\n\n clearFailure(): void {\n this._lastFailure = undefined;\n }\n\n schedule(server: ViteDevServer, changedPath: string): void {\n this._pendingBootDeps.add(changedPath);\n this._scheduleRun(server);\n }\n\n scheduleFullReload(server: ViteDevServer, triggeredBy?: string): void {\n this._pendingFullReloads.add(triggeredBy ?? FULL_RELOAD_UNKNOWN);\n this._scheduleRun(server);\n }\n\n /**\n * Resolves when no restart is running. Loops to handle back-to-back restarts\n * (e.g. one chain ends and a queued debounce timer immediately fires a new\n * one). Never rejects, so a failed restart still releases the gate — caller\n * proceeds against the broken state rather than hanging forever.\n */\n async waitForRestart(): Promise<void> {\n while (this._runPromise) {\n try {\n await this._runPromise;\n } catch {\n // restart failed — release anyway\n }\n }\n }\n\n private _scheduleRun(server: ViteDevServer): void {\n clearTimeout(this._debounceTimer);\n this._debounceTimer = setTimeout(() => {\n this._debounceTimer = undefined;\n void this._run(server);\n }, this.debounceMs);\n }\n\n private async _run(server: ViteDevServer): Promise<void> {\n if (this._inFlight) {\n // loop driving the in-flight restart will pick up the next iteration.\n this._pending = true;\n\n return;\n }\n\n this._inFlight = true;\n\n let resolveRun!: () => void;\n\n this._runPromise = new Promise<void>((resolve) => {\n resolveRun = resolve;\n });\n\n try {\n do {\n this._pending = false;\n\n const bootDeps = [...this._pendingBootDeps].sort();\n const fullReloads = [...this._pendingFullReloads].sort();\n\n this._pendingBootDeps.clear();\n this._pendingFullReloads.clear();\n\n if (bootDeps.length > 0 || fullReloads.length > 0) {\n this.logger.info(this._formatReason(server, bootDeps, fullReloads));\n }\n\n try {\n await server.restart();\n } catch (error) {\n this.logger.error(`error during dev server restart: ${serializeError(error)}`);\n }\n } while (this._pending);\n } finally {\n this._inFlight = false;\n this._runPromise = undefined;\n resolveRun();\n }\n }\n\n private _formatReason(server: ViteDevServer, bootDeps: string[], fullReloads: string[]): string {\n const root = server.config.root;\n const rel = (p: string): string => path.relative(root, p) || p;\n const parts: string[] = [];\n\n if (bootDeps.length === 1) {\n parts.push(`boot dep changed: ${rel(bootDeps[0]!)}`);\n } else if (bootDeps.length > 1) {\n parts.push(`boot deps changed (${bootDeps.length}): ${bootDeps.map(rel).join(', ')}`);\n }\n\n if (fullReloads.length > 0) {\n const named = fullReloads.filter((p) => p !== FULL_RELOAD_UNKNOWN);\n\n if (named.length === 0) {\n parts.push('vite SSR full-reload');\n } else {\n parts.push(`vite SSR full-reload (triggered by ${named.map(rel).join(', ')})`);\n }\n }\n\n return `${parts.join(' + ')} — restarting dev server`;\n }\n}\n","import type { DevEnvironment, ViteDevServer } from 'vite';\n\ntype RunnableEnv = DevEnvironment & { runner: { import: (id: string) => Promise<unknown> } };\n\n/**\n * duck-typed runnable-env check. avoids `isRunnableDevEnvironment` which relies on\n * `instanceof RunnableDevEnvironment` — that breaks when the consumer and vite host\n * resolve to different vite installs (e.g. linked packages outside the workspace).\n */\nfunction isRunnable(env: DevEnvironment | undefined): env is RunnableEnv {\n return (\n !!env &&\n typeof (env as { runner?: unknown }).runner === 'object' &&\n typeof (env as RunnableEnv).runner.import === 'function'\n );\n}\n\n/**\n * resolve a runnable dev environment — prefers `ssr`, falls back to `astro`.\n * astro 6 exposes a separate `astro` environment when `ssr` isn't runnable\n * (see astro/core/constants.ts ASTRO_VITE_ENVIRONMENT_NAMES).\n */\nfunction getRunnableEnv(server: ViteDevServer): RunnableEnv {\n const ssr = server.environments['ssr'];\n\n if (isRunnable(ssr)) return ssr;\n\n const astro = server.environments['astro'];\n\n if (isRunnable(astro)) return astro;\n\n const names = Object.keys(server.environments);\n\n throw new Error(`no runnable dev environment found — available: ${names.join(', ')}`);\n}\n\n/**\n * load a module via the Vite Environment API.\n */\nexport async function ssrImport<T = Record<string, unknown>>(server: ViteDevServer, moduleId: string): Promise<T> {\n return getRunnableEnv(server).runner.import(moduleId) as Promise<T>;\n}\n\n/**\n * return the env whose `hot` channel should receive astro-targeted events.\n * astro listens on the env that backs its middleware runner.\n */\nexport function getAstroHotEnv(server: ViteDevServer): DevEnvironment | undefined {\n const ssr = server.environments['ssr'];\n\n if (isRunnable(ssr)) return ssr;\n\n const astro = server.environments['astro'];\n\n if (isRunnable(astro)) return astro;\n\n return undefined;\n}\n","export const ignoredSuffixes = [\n // type definitions\n '.d.ts',\n '.d.mts',\n '.d.cts',\n // images\n '.png',\n '.jpg',\n '.jpeg',\n '.gif',\n '.svg',\n '.webp',\n '.avif',\n '.ico',\n // fonts\n '.woff',\n '.woff2',\n '.ttf',\n '.otf',\n '.eot',\n // other static assets\n '.pdf',\n '.mp3',\n '.mp4',\n '.webm',\n '.ogg',\n '.wav',\n // data/config that boot typically doesn't import\n '.json',\n '.yaml',\n '.yml',\n '.toml',\n '.md',\n '.mdx',\n '.txt',\n // styles (handled by Vite's CSS HMR)\n '.css',\n '.scss',\n '.sass',\n '.less',\n];\n","import type { EventEmitter } from 'node:events';\nimport { readFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { HotPayload, ViteDevServer } from 'vite';\nimport { GEN_HEADER, getCurrentGeneration } from './generation.js';\nimport { ignoredSuffixes } from './ignored.js';\nimport type { RestartScheduler } from './scheduler.js';\nimport { getAstroHotEnv } from './vite-env.js';\n\nconst RESTART_HTML = readFileSync(fileURLToPath(new URL('./restart-page.html', import.meta.url)), 'utf8');\n\nexport function setupBootWatch(server: ViteDevServer, entries: string[], scheduler: RestartScheduler): void {\n const entryFilePaths = entries.map((entry) => path.resolve(server.config.root, entry));\n\n const runnableEnv = getAstroHotEnv(server);\n const bootModuleGraph = runnableEnv?.moduleGraph;\n\n const collectBootDependencies = (): Set<string> => {\n const deps = new Set<string>();\n const seen = new Set<string>();\n\n for (const entryFilePath of entryFilePaths) {\n const entryModules = bootModuleGraph?.getModulesByFile(entryFilePath);\n const entryModule = entryModules ? [...entryModules][0] : undefined;\n\n if (!entryModule) continue;\n\n const visit = (mod: typeof entryModule): void => {\n if (!mod?.file || seen.has(mod.file)) return;\n\n seen.add(mod.file);\n deps.add(mod.file);\n\n for (const imp of mod.importedModules) visit(imp);\n };\n\n visit(entryModule);\n }\n\n return deps;\n };\n\n const shouldIgnore = (filePath: string): boolean => {\n const p = filePath.toLowerCase();\n\n return ignoredSuffixes.some((suffix) => p.endsWith(suffix));\n };\n\n const onWatcherEvent = (changedPath: string): void => {\n if (shouldIgnore(changedPath)) return;\n\n const bootDeps = collectBootDependencies();\n\n if (!bootDeps.has(changedPath)) return;\n\n scheduler.schedule(server, changedPath);\n };\n\n server.watcher.on('change', onWatcherEvent);\n server.watcher.on('add', onWatcherEvent);\n server.watcher.on('unlink', onWatcherEvent);\n\n // ignore full-reloads emitted during server startup (dep optimization, port retries).\n let handleFullReloads = false;\n\n if (server.httpServer) {\n server.httpServer.once('listening', () => {\n handleFullReloads = true;\n });\n } else {\n // middleware mode — no httpServer, enable immediately\n handleFullReloads = true;\n }\n\n // SSR full-reloads come through the runnable env's hot channel and clear\n // its module runner's cache — onStartup needs to run again on a fresh server.\n const outsideEmitter = (runnableEnv?.hot as { api?: { outsideEmitter?: EventEmitter } } | undefined)?.api\n ?.outsideEmitter;\n\n if (outsideEmitter) {\n outsideEmitter.on('send', (payload: HotPayload) => {\n if (!handleFullReloads) return;\n if (payload.type !== 'full-reload') return;\n\n const triggeredBy = 'triggeredBy' in payload ? (payload.triggeredBy as string) : undefined;\n\n scheduler.scheduleFullReload(server, triggeredBy);\n });\n }\n}\n\nconst READINESS_PATH = '/__astroscope_boot_ready';\n\n/**\n * Gate requests: show 503 holding page during restart, readiness probe for the reload.\n */\nexport function installBootGate(\n server: Pick<ViteDevServer, 'middlewares'>,\n scheduler: Pick<RestartScheduler, 'waitForRestart' | 'isRestartPending' | 'getLastFailure'>,\n): void {\n const middlewares = server.middlewares as unknown as {\n stack: { route: string; handle: unknown }[];\n };\n\n // must be `stack.unshift`ed to land before astro's handler\n middlewares.stack.unshift({\n route: '',\n handle: (async (\n req: { url?: string },\n res: {\n writeHead: (status: number, headers: Record<string, string>) => void;\n end: (body?: string) => void;\n headersSent?: boolean;\n },\n next: (err?: unknown) => void,\n ) => {\n // readiness probe: holding page polls this. blocks until no restart is in\n // flight, then 204 on success / 503 + JSON error if last attempt failed.\n if (req.url === READINESS_PATH) {\n await scheduler.waitForRestart();\n\n if (res.headersSent) return;\n\n const failure = scheduler.getLastFailure();\n\n if (failure) {\n res.writeHead(503, { 'cache-control': 'no-store', 'content-type': 'application/json' });\n res.end(JSON.stringify({ error: failure.message }));\n\n return;\n }\n\n res.writeHead(204, { 'cache-control': 'no-store' });\n res.end();\n\n return;\n }\n\n if (isDevInternalPath(req.url)) {\n next();\n\n return;\n }\n\n // respond now; awaiting the restart would let vite destroy the socket mid-response.\n if (scheduler.isRestartPending()) {\n res.writeHead(503, {\n 'content-type': 'text/html; charset=utf-8',\n 'cache-control': 'no-store',\n 'retry-after': '1',\n });\n res.end(RESTART_HTML);\n\n return;\n }\n\n next();\n }) as never,\n });\n}\n\nfunction isDevInternalPath(url: string | undefined): boolean {\n if (!url) return false;\n\n return url.startsWith('/@') || url.startsWith('/__') || url.includes('/node_modules/');\n}\n\n/**\n * Stamp the current generation onto every incoming request so the runtime\n * Astro middleware can later detect whether the request belongs to a previous\n * (now torn-down) generation\n */\nexport function installGenStamp(server: Pick<ViteDevServer, 'middlewares'>): void {\n const middlewares = server.middlewares as unknown as {\n stack: { route: string; handle: unknown }[];\n };\n\n middlewares.stack.unshift({\n route: '',\n handle: ((req: { headers: Record<string, string> }, _res: unknown, next: () => void) => {\n req.headers[GEN_HEADER] = String(getCurrentGeneration());\n next();\n }) as never,\n });\n}\n","import type { AstroConfig } from 'astro';\nimport type { Plugin } from 'vite';\nimport { setBootContext } from '../lifecycle/context.js';\nimport { type BootModule, runShutdown, runStartup } from '../lifecycle/lifecycle.js';\nimport type { BootContext } from '../lifecycle/types.js';\nimport { clearNativeMounts } from '../server/native-mount.js';\nimport { incrementGeneration } from './generation.js';\nimport { RestartScheduler } from './scheduler.js';\nimport { serializeError } from './serialize-error.js';\nimport { ssrImport } from './vite-env.js';\nimport { installBootGate, installGenStamp, setupBootWatch } from './watch.js';\n\ninterface Logger {\n info(msg: string): void;\n warn(msg: string): void;\n error(msg: string): void;\n}\n\nexport interface DevMachineryOptions {\n /** boot file path relative to the project root; undefined = no boot module */\n entry: string | undefined;\n /** restart the dev server when watched dependencies change */\n watch: boolean;\n /** extra files (relative to the root) whose changes restart the dev server */\n watchEntries: string[];\n /** platform seams; runs each generation before the boot module starts */\n prepare: (importModule: <T = Record<string, unknown>>(id: string) => Promise<T>) => Promise<void>;\n logger: Logger;\n getConfig: () => AstroConfig | null;\n}\n\n/**\n * Resolve the default host and port from the Astro server config.\n * Falls back to `localhost:4321` when no config is provided.\n */\nfunction getServerDefaults(config: AstroConfig | null): { host: string; port: number } {\n return {\n host:\n typeof config?.server?.host === 'string'\n ? config.server.host\n : config?.server?.host === true\n ? '0.0.0.0'\n : 'localhost',\n port: config?.server?.port ?? 4321,\n };\n}\n\n/**\n * Build a dev-mode boot context from the running server's address,\n * falling back to Astro config defaults if the server isn't listening yet.\n */\nfunction resolveBootContext(\n server: { httpServer?: { address(): unknown } | null | undefined },\n config: AstroConfig | null,\n): BootContext {\n const addr = server.httpServer?.address();\n\n if (addr && typeof addr === 'object' && 'address' in addr && 'port' in addr) {\n const host =\n (addr as { address: string }).address === '::' || (addr as { address: string }).address === '0.0.0.0'\n ? 'localhost'\n : (addr as { address: string }).address;\n\n return { dev: true, host, port: (addr as { port: number }).port };\n }\n\n const { host, port } = getServerDefaults(config);\n\n return { dev: true, host, port };\n}\n\n/**\n * The dev-mode boot machinery: runs the platform seams and the boot lifecycle\n * per restart generation, restarts the dev server when watched dependencies\n * change, and gates requests behind a holding page during restarts.\n */\nexport function createDevMachinery(options: DevMachineryOptions): Plugin[] {\n const { entry, logger } = options;\n\n let hasStartupSucceededOnce = false;\n // run by the next configureServer before its startup so resources (ports,\n // sockets, locks) from the previous module are released first. idempotent.\n let priorShutdown: (() => Promise<void>) | undefined;\n // shared across restart-induced configureServer reruns\n const scheduler = options.watch ? new RestartScheduler(100, logger) : undefined;\n\n return [\n // gate plugin: enforce 'post' + returned-function so our `stack.unshift`\n // (in installBootGate / installGenStamp) lands at connect position 0,\n // ahead of astro's handler.\n {\n name: '@astroscope/node/dev-gate',\n enforce: 'post',\n\n configureServer(server) {\n if (!scheduler) return;\n\n return () => {\n // gen-stamp is unshifted last so it ends up at position 0:\n // every request gets a generation header before anything else,\n // including the gate's readiness probe.\n installBootGate(server, scheduler);\n installGenStamp(server);\n };\n },\n },\n\n // startup plugin: runs after all other configureServer hooks\n {\n name: '@astroscope/node/dev-startup',\n enforce: 'post',\n\n async configureServer(server) {\n incrementGeneration();\n\n // tear down the previous module first so its resources are released\n // before the new startup tries to claim them.\n if (priorShutdown) {\n await priorShutdown();\n priorShutdown = undefined;\n }\n\n const astroConfig = options.getConfig();\n const bootContext = resolveBootContext(server, astroConfig);\n let bootModule: BootModule | undefined;\n\n setBootContext(bootContext);\n\n try {\n await options.prepare((id) => ssrImport(server, id));\n\n bootModule = entry ? await ssrImport<BootModule>(server, `/${entry}`) : {};\n\n await runStartup(bootModule, bootContext);\n } catch (error) {\n logger.error(`Error running startup script: ${serializeError(error)}`);\n\n if (bootModule) {\n try {\n await runShutdown(bootModule, bootContext);\n } catch {\n // best-effort cleanup\n }\n }\n\n // restart failure: the gate can keep the holding\n // page up with an error message instead of dropping users onto a\n // half-broken old server.\n if (hasStartupSucceededOnce) {\n scheduler?.recordFailure(serializeError(error));\n\n throw error;\n }\n\n // initial failure: exit cleanly (mirrors the production server).\n process.exit(1);\n }\n\n hasStartupSucceededOnce = true;\n scheduler?.clearFailure();\n\n // capture so shutdown sees the same instance that started.\n const startedModule = bootModule;\n let shutdownDone = false;\n\n const shutdown = async (): Promise<void> => {\n if (shutdownDone) return;\n\n shutdownDone = true;\n\n try {\n await runShutdown(startedModule, resolveBootContext(server, options.getConfig()));\n } catch (error) {\n logger.error(`Error running shutdown script: ${serializeError(error)}`);\n }\n\n // the next generation's onStartup re-registers its mounts\n clearNativeMounts();\n };\n\n priorShutdown = shutdown;\n\n // sigint/sigterm path. also fires during restart but shutdown is idempotent.\n server.httpServer?.once('close', () => {\n void shutdown();\n });\n\n if (scheduler) {\n setupBootWatch(server, [...(entry ? [entry] : []), ...options.watchEntries], scheduler);\n }\n },\n },\n ];\n}\n","import type { ExcludePattern } from './excludes.js';\n\n/**\n * Serialize exclude patterns to JavaScript code for use in virtual modules.\n * Handles RegExp objects which JSON.stringify cannot serialize.\n */\nexport function serializeExcludePatterns(patterns: ExcludePattern[]): string {\n return `[${patterns.map((p) => ('pattern' in p ? `{ pattern: ${p.pattern.toString()} }` : JSON.stringify(p))).join(', ')}]`;\n}\n","import { createHash } from 'node:crypto';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport type { Plugin } from 'vite';\nimport type { IslandsManifest } from './types.js';\n\nexport const ISLANDS_VIRTUAL_MODULE_ID = 'virtual:@astroscope/node/islands-manifest';\n\nconst RESOLVED_ISLANDS_VIRTUAL_MODULE_ID = `\\0${ISLANDS_VIRTUAL_MODULE_ID}`;\n\nconst MANIFEST_FILE_NAME = 'islands-manifest.json';\n\nexport type IslandsManifestPluginOptions = {\n /** astro's `build.assets` directory name, e.g. `_astro` */\n assetsDir: string;\n logger: { warn: (message: string) => void };\n /** `islands: false` disables the preloading — no manifest is written and the virtual module resolves to null */\n enabled: boolean;\n};\n\n/**\n * Client-build side of island preloading: records the chunk import graph (direct\n * static and dynamic edges per chunk), writes the content-hashed gate runtime into\n * the client assets dir, and drops the manifest next to the server chunks — where\n * the virtual module reads it back at runtime, mirroring the i18n manifest.\n *\n * The client build runs after the server build, so the SSR bundle can only carry\n * code that reads the file lazily; in dev there is no manifest and the middleware\n * stays inert.\n */\nexport function createIslandsManifestPlugin(options: IslandsManifestPluginOptions): Plugin {\n let isBuild = false;\n\n return {\n name: '@astroscope/node/islands-manifest',\n\n configResolved(config) {\n isBuild = config.command === 'build';\n },\n\n resolveId(id) {\n if (id === ISLANDS_VIRTUAL_MODULE_ID) return RESOLVED_ISLANDS_VIRTUAL_MODULE_ID;\n },\n\n load(id) {\n if (id !== RESOLVED_ISLANDS_VIRTUAL_MODULE_ID) return;\n\n if (!isBuild || !options.enabled) {\n return 'export const manifest = null;';\n }\n\n // the manifest only exists after the client build — read it at runtime. astro\n // bundles middleware at the server root and service code under chunks/, so\n // probe both relative to wherever this module ended up\n return `\nimport { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\n\nconst dir = dirname(fileURLToPath(import.meta.url));\n\nlet manifest = null;\n\nfor (const candidate of [\n join(dir, '${MANIFEST_FILE_NAME}'),\n join(dir, 'chunks', '${MANIFEST_FILE_NAME}'),\n join(dir, '..', 'chunks', '${MANIFEST_FILE_NAME}'),\n]) {\n try {\n manifest = JSON.parse(readFileSync(candidate, 'utf-8'));\n break;\n } catch {\n manifest = null;\n }\n}\n\nexport { manifest };\n`;\n },\n\n writeBundle(outputOptions, bundle) {\n if (!options.enabled || this.environment.name !== 'client' || !outputOptions.dir) return;\n\n const chunks: IslandsManifest['chunks'] = {};\n\n for (const chunk of Object.values(bundle)) {\n if (chunk.type !== 'chunk') continue;\n\n chunks[chunk.fileName] = {\n ...(chunk.imports.length > 0 && { i: chunk.imports }),\n ...(chunk.dynamicImports.length > 0 && { d: chunk.dynamicImports }),\n };\n }\n\n // the sourcemap itself is not shipped, so the marker would 404 (and client\n // bundles are deliberately map-free, see tweaks/sourcemap.ts)\n const runtimeSource = fs\n .readFileSync(new URL('./islands-runtime.js', import.meta.url), 'utf-8')\n .replace(/^\\/\\/# sourceMappingURL=.*$/m, '')\n .trimEnd();\n const hash = createHash('sha256').update(runtimeSource).digest('hex').slice(0, 8);\n const runtime = `${options.assetsDir}/islands-runtime.${hash}.js`;\n\n fs.mkdirSync(path.join(outputOptions.dir, options.assetsDir), { recursive: true });\n fs.writeFileSync(path.join(outputOptions.dir, options.assetsDir, `islands-runtime.${hash}.js`), runtimeSource);\n\n const manifest: IslandsManifest = { runtime, chunks };\n const chunksDir = path.resolve(outputOptions.dir, '..', 'server', 'chunks');\n\n if (fs.existsSync(chunksDir)) {\n fs.writeFileSync(path.join(chunksDir, MANIFEST_FILE_NAME), JSON.stringify(manifest));\n } else {\n options.logger.warn(`server chunks directory not found, cannot write manifest to ${chunksDir}`);\n }\n },\n };\n}\n","import type { Plugin } from 'vite';\n\n/**\n * emit sourcemaps only for the SSR build. client bundles are left unmapped\n * so browsers can't fetch source via `//# sourceMappingURL=`.\n *\n * vite 7's `environments.ssr.build.sourcemap` looks cleaner but wholesale\n * replaces astro's SSR build defaults (including entry file naming), which\n * breaks the embedded dev boot machinery. using `isSsrBuild` keeps the\n * rest of astro's SSR config intact.\n */\nexport function ssrSourcemapPlugin(): Plugin {\n return {\n name: '@astroscope/node/tweaks/sourcemap',\n config(_config, { isSsrBuild }) {\n if (isSsrBuild) return { build: { sourcemap: true } };\n\n return {};\n },\n };\n}\n","import { Parser } from 'acorn';\nimport MagicString from 'magic-string';\nimport type { Plugin } from 'vite';\n\nconst HOOK_NAMES = new Set(['useEffect', 'useLayoutEffect', 'useInsertionEffect']);\nconst REACT_SOURCE = /^react(\\/.*)?$/;\nconst TRANSFORMABLE = /\\.(?:[mc]?[jt]sx?)$/;\nconst EMPTY_FN = '(()=>{})';\n\n/**\n * in SSR builds, react effect hooks never execute. emptying their callbacks\n * lets rolldown drop dead branches — including dynamic imports of client-only\n * libs (maplibre-gl, hls.js, etc.) — from the server bundle, which in turn\n * stops nft from tracing them at docker-image time.\n *\n * scope is deliberately narrow: first-party code only (no node_modules), only\n * in the SSR pass, and binding-aware (the React import must resolve to the\n * real react package). raw chunks where bundling has erased the binding are\n * left alone — that's NFT's domain, not ours.\n */\nexport function stripSsrEffectsPlugin(): Plugin {\n return {\n name: '@astroscope/node/tweaks/strip-effects',\n enforce: 'post',\n transform(code, id, options) {\n if (!options?.ssr) return null;\n if (id.includes('/node_modules/')) return null;\n\n const cleanId = id.split('?')[0] ?? id;\n\n if (!TRANSFORMABLE.test(cleanId)) return null;\n if (!code.includes('useEffect') && !code.includes('useLayoutEffect') && !code.includes('useInsertionEffect')) {\n return null;\n }\n\n let ast: any;\n\n try {\n ast = Parser.parse(code, {\n ecmaVersion: 'latest',\n sourceType: 'module',\n allowReturnOutsideFunction: true,\n allowAwaitOutsideFunction: true,\n allowImportExportEverywhere: true,\n allowHashBang: true,\n });\n } catch {\n return null;\n }\n\n const directHooks = new Set<string>();\n const namespaceHooks = new Set<string>();\n\n walk(ast, (node) => {\n if (node.type !== 'ImportDeclaration') return;\n\n const src = node.source?.value;\n\n if (typeof src !== 'string' || !REACT_SOURCE.test(src)) return;\n\n for (const spec of node.specifiers ?? []) {\n if (spec.type === 'ImportSpecifier') {\n const imported = spec.imported?.name ?? spec.imported?.value;\n\n if (HOOK_NAMES.has(imported)) directHooks.add(spec.local.name);\n } else if (spec.type === 'ImportDefaultSpecifier' || spec.type === 'ImportNamespaceSpecifier') {\n namespaceHooks.add(spec.local.name);\n }\n }\n });\n\n if (directHooks.size === 0 && namespaceHooks.size === 0) return null;\n\n const replacements: { start: number; end: number }[] = [];\n\n walk(ast, (node) => {\n if (node.type !== 'CallExpression' || !node.arguments?.length) return;\n\n const callee = node.callee;\n const isDirect = callee.type === 'Identifier' && directHooks.has(callee.name);\n const isMember =\n callee.type === 'MemberExpression' &&\n !callee.computed &&\n callee.object?.type === 'Identifier' &&\n namespaceHooks.has(callee.object.name) &&\n callee.property?.type === 'Identifier' &&\n HOOK_NAMES.has(callee.property.name);\n\n if (!isDirect && !isMember) return;\n\n const arg = node.arguments[0];\n\n replacements.push({ start: arg.start, end: arg.end });\n });\n\n if (replacements.length === 0) return null;\n\n const s = new MagicString(code);\n\n for (const { start, end } of replacements) {\n s.overwrite(start, end, EMPTY_FN);\n }\n\n return { code: s.toString(), map: s.generateMap({ hires: true }).toString() };\n },\n };\n}\n\nfunction walk(node: any, visit: (n: any) => void): void {\n if (!node || typeof node !== 'object') return;\n\n if (typeof node.type === 'string') visit(node);\n\n for (const key of Object.keys(node)) {\n const v = node[key];\n\n if (Array.isArray(v)) for (const item of v) walk(item, visit);\n else if (v && typeof v === 'object') walk(v, visit);\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { AstroConfig, AstroIntegration } from 'astro';\nimport { createIslandWarmup } from '../dev-mode/island-warmup.js';\nimport { createDevMachinery } from '../dev-mode/machinery.js';\nimport { type ExcludePattern, RECOMMENDED_EXCLUDES } from '../excludes/excludes.js';\nimport { serializeExcludePatterns } from '../excludes/serialize.js';\nimport { createIslandsManifestPlugin } from '../islands/manifest-plugin.js';\nimport type { IslandsManifest } from '../islands/types.js';\nimport { createRequestInstrumentation } from '../observability/instrument.js';\nimport { preparePlatform } from '../platform/prepare.js';\nimport { dispatchNativeMount } from '../server/native-mount.js';\nimport { ssrSourcemapPlugin } from '../tweaks/sourcemap.js';\nimport { stripSsrEffectsPlugin } from '../tweaks/strip-effects.js';\nimport type { NodeOptions, RuntimeOptions } from '../types.js';\n\nexport const CONFIG_VIRTUAL_MODULE_ID = 'virtual:@astroscope/node/config';\nexport const BOOT_VIRTUAL_MODULE_ID = 'virtual:@astroscope/node/boot';\nexport const CSRF_VIRTUAL_MODULE_ID = 'virtual:@astroscope/node/csrf';\nexport const CONFIG_ENTRY_VIRTUAL_MODULE_ID = 'virtual:@astroscope/node/config-entry';\nexport const INSTRUMENTATION_ENTRY_VIRTUAL_MODULE_ID = 'virtual:@astroscope/node/instrumentation-entry';\nexport const LOG_ENTRY_VIRTUAL_MODULE_ID = 'virtual:@astroscope/node/log-entry';\n\nconst RESOLVED_CONFIG_VIRTUAL_MODULE_ID = `\\0${CONFIG_VIRTUAL_MODULE_ID}`;\nconst RESOLVED_BOOT_VIRTUAL_MODULE_ID = `\\0${BOOT_VIRTUAL_MODULE_ID}`;\nconst RESOLVED_CSRF_VIRTUAL_MODULE_ID = `\\0${CSRF_VIRTUAL_MODULE_ID}`;\nconst RESOLVED_CONFIG_ENTRY_VIRTUAL_MODULE_ID = `\\0${CONFIG_ENTRY_VIRTUAL_MODULE_ID}`;\nconst RESOLVED_INSTRUMENTATION_ENTRY_VIRTUAL_MODULE_ID = `\\0${INSTRUMENTATION_ENTRY_VIRTUAL_MODULE_ID}`;\nconst RESOLVED_LOG_ENTRY_VIRTUAL_MODULE_ID = `\\0${LOG_ENTRY_VIRTUAL_MODULE_ID}`;\n\nconst SERVER_ENVIRONMENTS = ['ssr', 'prerender', 'astro'];\nconst DEFAULT_REQUEST_EXCLUDES: ExcludePattern[] = [...RECOMMENDED_EXCLUDES];\n\nfunction resolveHost(host: string | boolean | undefined): string {\n if (typeof host === 'string') return host;\n\n return host === true ? '0.0.0.0' : 'localhost';\n}\n\nfunction resolveBootEntry(root: string, entry: string | undefined): string | undefined {\n if (entry) {\n const abs = path.resolve(root, entry);\n\n if (!fs.existsSync(abs)) {\n throw new Error(`[@astroscope/node] boot entry not found: ${entry}`);\n }\n\n return abs;\n }\n\n for (const candidate of ['src/boot/index.ts', 'src/boot.ts']) {\n const abs = path.resolve(root, candidate);\n\n if (fs.existsSync(abs)) return abs;\n }\n\n return undefined;\n}\n\nfunction resolveSeam(root: string, candidate: string): string | undefined {\n const abs = path.resolve(root, candidate);\n\n return fs.existsSync(abs) ? abs : undefined;\n}\n\n/**\n * Node adapter for Astro with a first-class server entrypoint: the boot\n * lifecycle, module warmup, health probes, request logging and telemetry run\n * as plain code around `server.listen()` instead of being injected into the\n * build output.\n */\nexport default function node(options: NodeOptions = {}): AstroIntegration {\n const bootOptions = options.boot ?? {};\n const healthOptions = options.health ?? {};\n const csrfOptions = options.csrf ?? {};\n const islandsEnabled = options.islands !== false;\n const loggingOptions = options.logging ?? {};\n const telemetryOptions = options.telemetry ?? {};\n\n const loggingExclude = loggingOptions ? (loggingOptions.exclude ?? DEFAULT_REQUEST_EXCLUDES) : [];\n const telemetryExclude = telemetryOptions ? (telemetryOptions.exclude ?? DEFAULT_REQUEST_EXCLUDES) : [];\n\n let astroConfig: AstroConfig | null = null;\n let bootEntry: string | undefined;\n let configSeam: string | undefined;\n let instrumentationSeam: string | undefined;\n let logSeam: string | undefined;\n let isDev = false;\n\n return {\n name: '@astroscope/node',\n hooks: {\n 'astro:config:setup': ({ command, config, updateConfig, addMiddleware, logger }) => {\n isDev = command === 'dev';\n\n // route enrichment first so csrf-rejected requests still carry a route\n if (loggingOptions || telemetryOptions) {\n addMiddleware({ order: 'pre', entrypoint: '@astroscope/node/route-middleware' });\n }\n\n if (csrfOptions) {\n addMiddleware({ order: 'pre', entrypoint: '@astroscope/node/csrf-middleware' });\n }\n\n // registered after logging/csrf so its next() wraps the rendered response\n addMiddleware({ order: 'pre', entrypoint: '@astroscope/node/islands-middleware' });\n\n const root = fileURLToPath(config.root);\n const watch = bootOptions === false ? false : (bootOptions.watch ?? true);\n\n bootEntry = bootOptions === false ? undefined : resolveBootEntry(root, bootOptions.entry);\n configSeam = resolveSeam(root, 'src/config.ts');\n instrumentationSeam = resolveSeam(root, 'src/instrumentation.ts');\n logSeam = resolveSeam(root, 'src/log.ts');\n\n const relativeSeam = (abs: string | undefined) =>\n abs ? path.relative(root, abs).split(path.sep).join('/') : undefined;\n\n const devMachinery =\n command === 'dev' && bootOptions !== false\n ? createDevMachinery({\n entry: bootEntry ? path.relative(root, bootEntry) : undefined,\n watch,\n // instrumentation runs once per process — watching it would\n // restart generations that can't re-apply it\n watchEntries: [relativeSeam(configSeam), relativeSeam(logSeam)].filter(\n (entry): entry is string => !!entry,\n ),\n prepare: (importModule) =>\n preparePlatform({\n dev: true,\n telemetry:\n telemetryOptions && telemetryOptions.dev\n ? { prometheus: telemetryOptions.prometheus ?? {} }\n : false,\n seams: {\n ...(configSeam && { config: () => importModule(`/${relativeSeam(configSeam)}`) }),\n ...(instrumentationSeam && {\n instrumentation: () => importModule(`/${relativeSeam(instrumentationSeam)}`),\n }),\n ...(logSeam && { log: () => importModule(`/${relativeSeam(logSeam)}`) }),\n },\n }),\n logger,\n getConfig: () => astroConfig,\n })\n : [];\n\n if (command === 'dev' && bootOptions !== false && watch) {\n // catches errors thrown by stale (post-shutdown) requests so\n // they don't pollute the logs during dev-server restarts.\n addMiddleware({ entrypoint: '@astroscope/node/dev-middleware', order: 'pre' });\n }\n\n const islandWarmup =\n command === 'dev' ? [createIslandWarmup({ root, srcDir: fileURLToPath(config.srcDir), logger })] : [];\n\n const imageService = options.imageService ?? 'auto';\n const imageOff =\n imageService === 'off' ||\n (imageService === 'auto' && config.image.service.entrypoint === 'astro/assets/services/sharp');\n\n updateConfig({\n build: { redirects: false },\n // opinionated defaults: no trailing slashes, behind LB\n ...(config.trailingSlash === 'ignore' && { trailingSlash: 'never' as const }),\n security: {\n // assumed to run behind LB\n ...(!config.security.allowedDomains?.length && { allowedDomains: [{}] }),\n // the embedded csrf middleware replaces the built-in origin check\n ...(csrfOptions && { checkOrigin: false }),\n },\n image: {\n ...(imageOff && { service: { entrypoint: '@astroscope/node/image-service', config: {} } }),\n endpoint: {\n route: config.image.endpoint.route ?? '_image',\n entrypoint: imageOff\n ? '@astroscope/node/image-endpoint'\n : (config.image.endpoint.entrypoint ??\n (command === 'dev' ? 'astro/assets/endpoint/dev' : 'astro/assets/endpoint/node')),\n },\n },\n vite: {\n plugins: [\n ...devMachinery,\n ...islandWarmup,\n createIslandsManifestPlugin({ assetsDir: config.build.assets, logger, enabled: islandsEnabled }),\n ssrSourcemapPlugin(),\n stripSsrEffectsPlugin(),\n {\n name: '@astroscope/node',\n\n configEnvironment(environmentName: string) {\n if (SERVER_ENVIRONMENTS.includes(environmentName)) {\n return { resolve: { noExternal: ['@astroscope/node'] } };\n }\n },\n\n resolveId(id: string) {\n if (id === CONFIG_VIRTUAL_MODULE_ID) return RESOLVED_CONFIG_VIRTUAL_MODULE_ID;\n if (id === BOOT_VIRTUAL_MODULE_ID) return RESOLVED_BOOT_VIRTUAL_MODULE_ID;\n if (id === CSRF_VIRTUAL_MODULE_ID) return RESOLVED_CSRF_VIRTUAL_MODULE_ID;\n if (id === CONFIG_ENTRY_VIRTUAL_MODULE_ID) return RESOLVED_CONFIG_ENTRY_VIRTUAL_MODULE_ID;\n if (id === INSTRUMENTATION_ENTRY_VIRTUAL_MODULE_ID) {\n return RESOLVED_INSTRUMENTATION_ENTRY_VIRTUAL_MODULE_ID;\n }\n if (id === LOG_ENTRY_VIRTUAL_MODULE_ID) return RESOLVED_LOG_ENTRY_VIRTUAL_MODULE_ID;\n },\n\n load(id: string) {\n if (id === RESOLVED_CONFIG_VIRTUAL_MODULE_ID) {\n if (!astroConfig) throw new Error('[@astroscope/node] astro config not resolved yet');\n\n const runtimeOptions: Omit<RuntimeOptions, 'logging' | 'telemetry'> = {\n host: resolveHost(astroConfig.server.host),\n port: astroConfig.server.port ?? 4321,\n client: astroConfig.build.client.toString(),\n server: astroConfig.build.server.toString(),\n bodySizeLimit: options.bodySizeLimit ?? 1024 * 1024 * 1024,\n shutdownTimeout: options.shutdownTimeout ?? 10_000,\n health: healthOptions\n ? {\n ...(healthOptions.host !== undefined && { host: healthOptions.host }),\n ...(healthOptions.port !== undefined && { port: healthOptions.port }),\n ...(healthOptions.paths && { paths: healthOptions.paths }),\n }\n : false,\n };\n\n // exclude patterns may contain RegExp — serialized as code, not JSON\n const logging = loggingOptions\n ? `{ exclude: ${serializeExcludePatterns(loggingExclude)}, extended: ${JSON.stringify(\n loggingOptions.extended ?? false,\n )} }`\n : 'false';\n const telemetry = telemetryOptions\n ? `{ exclude: ${serializeExcludePatterns(telemetryExclude)}, prometheus: ${JSON.stringify(\n telemetryOptions.prometheus ?? {},\n )} }`\n : 'false';\n\n return `export const options = { ...${JSON.stringify(runtimeOptions)}, logging: ${logging}, telemetry: ${telemetry} };`;\n }\n\n if (id === RESOLVED_BOOT_VIRTUAL_MODULE_ID) {\n // re-export to avoid absolute path manifest leaks\n return bootEntry ? `export * from ${JSON.stringify(bootEntry)};` : 'export {};';\n }\n\n if (id === RESOLVED_CSRF_VIRTUAL_MODULE_ID) {\n return `export const excludePatterns = ${serializeExcludePatterns(csrfOptions ? (csrfOptions.exclude ?? []) : [])};`;\n }\n\n if (id === RESOLVED_CONFIG_ENTRY_VIRTUAL_MODULE_ID) {\n // side-effect import: @entwico/zod-conf validation runs at module load\n return configSeam ? `import ${JSON.stringify(configSeam)};\\nexport {};` : 'export {};';\n }\n\n if (id === RESOLVED_INSTRUMENTATION_ENTRY_VIRTUAL_MODULE_ID) {\n return instrumentationSeam ? `export * from ${JSON.stringify(instrumentationSeam)};` : 'export {};';\n }\n\n if (id === RESOLVED_LOG_ENTRY_VIRTUAL_MODULE_ID) {\n return logSeam\n ? `export { default } from ${JSON.stringify(logSeam)};`\n : 'export default undefined;';\n }\n },\n },\n ],\n },\n });\n },\n 'astro:server:setup': ({ server }) => {\n if (!isDev) return;\n\n const devLogging = loggingOptions && loggingOptions.dev;\n const devTelemetry = telemetryOptions && telemetryOptions.dev;\n\n const instrument =\n devLogging || devTelemetry\n ? createRequestInstrumentation({\n logging: devLogging ? { exclude: loggingExclude, extended: loggingOptions.extended ?? false } : false,\n telemetry: devTelemetry ? { exclude: telemetryExclude } : false,\n })\n : undefined;\n\n server.middlewares.use((req, res, next) => {\n const inner = (): void => {\n if (!dispatchNativeMount(req, res)) next();\n };\n\n if (instrument) {\n instrument(req, res, inner);\n } else {\n inner();\n }\n });\n },\n 'astro:config:done': ({ config, setAdapter }) => {\n astroConfig = config;\n\n setAdapter({\n name: '@astroscope/node',\n entrypointResolution: 'auto',\n serverEntrypoint: '@astroscope/node/server',\n previewEntrypoint: '@astroscope/node/preview',\n adapterFeatures: {\n buildOutput: 'server',\n middlewareMode: 'classic',\n },\n supportedAstroFeatures: {\n hybridOutput: 'stable',\n staticOutput: 'stable',\n serverOutput: 'stable',\n sharpImageService: 'stable',\n i18nDomains: 'experimental',\n envGetSecret: 'stable',\n },\n });\n },\n 'astro:build:done': async ({ logger }) => {\n if (!astroConfig) return;\n\n if (islandsEnabled) {\n // prerendered pages never pass through the middleware — rewrite them on\n // disk before compression, from the manifest the client build just wrote\n const manifestPath = path.join(fileURLToPath(astroConfig.build.server), 'chunks', 'islands-manifest.json');\n\n if (fs.existsSync(manifestPath)) {\n const { transformPrerenderedHtml } = await import('../islands/prerendered.js');\n const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8')) as IslandsManifest;\n const transformed = await transformPrerenderedHtml(fileURLToPath(astroConfig.build.client), manifest);\n\n if (transformed > 0) {\n logger.info(`island preloading applied to ${transformed} prerendered page(s)`);\n }\n }\n }\n\n const { compressClientDir } = await import('../compress/compress.js');\n\n await compressClientDir(fileURLToPath(astroConfig.build.client), logger);\n },\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AAmCA,SAAS,UAAU,OAAkC;CACnD,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,OAAQ,MAAkB,SAAS;AAC3F;AAEA,SAASA,OAAK,MAAe,OAAsC;CACjE,IAAI,MAAM,QAAQ,IAAI,GAAG;EACvB,KAAK,MAAM,QAAQ,MAAM,OAAK,MAAM,KAAK;EAEzC;CACF;CAEA,IAAI,OAAO,SAAS,YAAY,SAAS,MAAM;CAE/C,IAAI,UAAU,IAAI,GAAG,MAAM,IAAI;CAE/B,KAAK,MAAM,SAAS,OAAO,OAAO,IAAI,GAAG,OAAK,OAAO,KAAK;AAC5D;;AASA,SAAS,eAAe,SAAuC;CAC7D,MAAM,0BAAU,IAAI,IAAoB;CAExC,OAAK,UAAU,SAAS;EACtB,IAAI,KAAK,SAAS,qBAAqB;EAEvC,MAAM,OAAO;EAEb,IAAI,KAAK,eAAe,QAAQ;EAEhC,MAAM,YAAY,OAAO,KAAK,QAAQ,UAAU,WAAW,KAAK,OAAO,QAAQ,KAAA;EAE/E,IAAI,CAAC,WAAW;EAEhB,KAAK,MAAM,QAAQ,KAAK,cAAc,CAAC,GAAG;GACxC,IAAI,KAAK,eAAe,QAAQ;GAEhC,IAAI,OAAO,KAAK,OAAO,SAAS,UAC9B,QAAQ,IAAI,KAAK,MAAM,MAAM,SAAS;EAE1C;CACF,CAAC;CAED,OAAO;AACT;;AAGA,SAAS,kBAAkB,MAAmC;CAC5D,IAAI,UAAU;CAEd,OAAO,UAAU,OAAO,KAAK,QAAQ,SAAS,uBAC5C,UAAW,QAA4C;CAGzD,IAAI,UAAU,OAAO,KAAK,QAAQ,SAAS,iBAAiB;EAC1D,MAAM,aAAa;EAEnB,OAAO,OAAO,WAAW,SAAS,WAAW,WAAW,OAAO,KAAA;CACjE;AAGF;AAEA,SAAS,mBAAmB,YAA8B;CACxD,IAAI,CAAC,MAAM,QAAQ,UAAU,GAAG,OAAO;CAEvC,OAAO,WAAW,MAAM,SAAS;EAC/B,IAAI,CAAC,UAAU,IAAI,KAAK,KAAK,SAAS,gBAAgB,OAAO;EAE7D,MAAM,OAAQ,KAAyD;EAEvE,OAAO,OAAO,MAAM,SAAS,YAAY,KAAK,KAAK,WAAW,SAAS;CACzE,CAAC;AACH;;;;;;AAOA,SAAgB,gBAAgB,QAA0B;CACxD,MAAM,EAAE,QAAQ,MAAM,MAAM;CAC5B,MAAM,OAAO;CAEb,MAAM,UAAU,eAAe,KAAK,aAAa,OAAO;CAExD,IAAI,QAAQ,SAAS,GAAG,OAAO,CAAC;CAEhC,MAAM,6BAAa,IAAI,IAAY;CAEnC,OAAK,KAAK,OAAO,SAAS;EACxB,IAAI,KAAK,SAAS,qBAAqB;EAEvC,MAAM,UAAU;EAEhB,IAAI,CAAC,mBAAmB,QAAQ,UAAU,GAAG;EAE7C,MAAM,WAAW,kBAAkB,QAAQ,IAAI;EAE/C,IAAI,CAAC,YAAY,SAAS,KAAK,QAAQ,GAAG;EAE1C,MAAM,YAAY,QAAQ,IAAI,QAAQ;EAEtC,IAAI,aAAa,CAAC,UAAU,SAAS,QAAQ,GAC3C,WAAW,IAAI,SAAS;CAE5B,CAAC;CAED,OAAO,CAAC,GAAG,UAAU;AACvB;;AAGA,eAAsB,mBAAmB,QAAgB,QAAyC;CAChG,MAAM,UAA0B,CAAC;CAEjC,IAAI;CAEJ,IAAI;EACF,UAAU,MAAM,GAAG,SAAS,QAAQ,QAAQ;GAAE,WAAW;GAAM,eAAe;EAAK,CAAC;CACtF,QAAQ;EACN,OAAO;CACT;CAEA,MAAM,QAAQ,QACX,QAAQ,UAAU,MAAM,OAAO,KAAK,MAAM,KAAK,SAAS,QAAQ,CAAC,CAAC,CAClE,KAAK,UAAU,KAAK,KAAK,MAAM,YAAY,MAAM,IAAI,CAAC;CAEzD,MAAM,QAAQ,IACZ,MAAM,IAAI,OAAO,SAAS;EACxB,IAAI;GACF,MAAM,SAAS,MAAM,GAAG,SAAS,SAAS,MAAM,MAAM;GAEtD,KAAK,MAAM,aAAa,gBAAgB,MAAM,GAC5C,QAAQ,KAAK;IAAE,UAAU;IAAM;GAAU,CAAC;EAE9C,SAAS,OAAO;GAEd,OAAO,MAAM,uBAAuB,KAAK,IAAI,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,GAAG;EACvG;CACF,CAAC,CACH;CAEA,OAAO;AACT;AAEA,SAAS,cAAc,WAA2B;CAChD,MAAM,WAAW,UAAU,MAAM,GAAG;CAEpC,OAAO,UAAU,WAAW,GAAG,IAAI,SAAS,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,IAAK,SAAS,MAAM;AACtF;;;;;;;AAQA,SAAgB,qBAAqB,SAAyB,MAAwB;CACpF,MAAM,uBAAO,IAAI,IAAY;CAE7B,KAAK,MAAM,EAAE,eAAe,SAAS;EACnC,IAAI,UAAU,WAAW,GAAG,KAAK,UAAU,WAAW,GAAG,KAAK,UAAU,WAAW,GAAG,GAAG;EAEzF,IAAI,GAAG,WAAW,KAAK,KAAK,MAAM,gBAAgB,cAAc,SAAS,CAAC,CAAC,GACzE,KAAK,IAAI,SAAS;CAEtB;CAEA,OAAO,CAAC,GAAG,IAAI;AACjB;AAEA,SAAS,aAAa,IAAY,MAAsB;CACtD,MAAM,aAAa,GAAG,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG;CAC9C,MAAM,iBAAiB,KAAK,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG;CAEpD,OAAO,WAAW,WAAW,GAAG,eAAe,EAAE,IAAI,WAAW,MAAM,eAAe,MAAM,IAAI,QAAQ;AACzG;AAQA,SAAgB,mBAAmB,SAAsC;CACvE,MAAM,EAAE,MAAM,QAAQ,WAAW;CAEjC,IAAI,UAA0B,CAAC;CAE/B,MAAM,cAAc,OAAO,QAAuB,OAAuB,WAAuC;EAC9G,MAAM,MAAM,OAAO,aAAa;EAEhC,MAAM,QAAQ,IACZ,MAAM,IAAI,OAAO,EAAE,UAAU,gBAAgB;GAC3C,IAAI;IAGF,MAAM,WAAW,MAAM,IAAI,gBAAgB,UAAU,WAAW,QAAQ;IAExE,IAAI,CAAC,YAAY,SAAS,UAAU;IACpC,IAAI,SAAS,GAAG,WAAW,IAAI,KAAK,SAAS,GAAG,SAAS,cAAc,GAAG;IAC1E,IAAI,OAAO,IAAI,SAAS,EAAE,GAAG;IAE7B,OAAO,IAAI,SAAS,EAAE;IAEtB,MAAM,IAAI,cAAc,aAAa,SAAS,IAAI,IAAI,CAAC;GACzD,QAAQ,CAER;EACF,CAAC,CACH;CACF;CAEA,OAAO;EACL,MAAM;EAEN,MAAM,SAAS;GACb,UAAU,MAAM,mBAAmB,QAAQ,MAAM;GAEjD,MAAM,UAAU,qBAAqB,SAAS,IAAI;GAElD,IAAI,QAAQ,SAAS,GACnB,OAAO,KAAK,WAAW,QAAQ,OAAO,6BAA6B,QAAQ,OAAO,gBAAgB;GAGpG,OAAO,QAAQ,SAAS,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,IAAI,KAAA;EAC9D;EAEA,gBAAgB,QAAQ;GACtB,MAAM,yBAAS,IAAI,IAAY;GAI/B,IAAI,OAAO,YACT,OAAO,WAAW,KAAK,mBAAmB,KAAK,YAAY,QAAQ,SAAS,MAAM,CAAC;QAEnF,YAAiB,QAAQ,SAAS,MAAM;GAK1C,MAAM,kBAAkB,SAAuB;IAC7C,IAAI,CAAC,KAAK,SAAS,QAAQ,KAAK,CAAC,KAAK,WAAW,MAAM,GAAG;IAE1D,GAAQ,SACL,SAAS,MAAM,MAAM,CAAC,CACtB,MAAM,WAAW;KAChB,MAAM,QAAQ,gBAAgB,MAAM,CAAC,CAAC,KAAK,eAAe;MAAE,UAAU;MAAM;KAAU,EAAE;KAExF,OAAO,YAAY,QAAQ,OAAO,MAAM;IAC1C,CAAC,CAAC,CACD,YAAY,CAAC,CAAC;GACnB;GAEA,OAAO,QAAQ,GAAG,OAAO,cAAc;GACvC,OAAO,QAAQ,GAAG,UAAU,cAAc;EAC5C;CACF;AACF;;;AC1SA,SAAgB,eAAe,OAAwB;CACrD,IAAI,iBAAiB,OACnB,OAAO,MAAM,SAAS,MAAM;CAG9B,OAAO,KAAK,UAAU,KAAK;AAC7B;;;ACAA,MAAM,sBAAsB;;;;;;;;;;AAW5B,IAAa,mBAAb,MAA8B;CAaT;CACA;CAbnB,YAAoB;CACpB,WAAmB;CACnB;CACA,mCAA2B,IAAI,IAAY;CAC3C,sCAA8B,IAAI,IAAY;CAG9C;CAEA;CAEA,YACE,YACA,QACA;EAFiB,KAAA,aAAA;EACA,KAAA,SAAA;CAChB;CAIH,mBAA4B;EAC1B,OAAO,CAAC,CAAC,KAAK,eAAe,CAAC,CAAC,KAAK,kBAAkB,CAAC,CAAC,KAAK;CAC/D;CAEA,iBAAkD;EAChD,OAAO,KAAK;CACd;CAEA,cAAc,SAAuB;EACnC,KAAK,eAAe,EAAE,QAAQ;CAChC;CAEA,eAAqB;EACnB,KAAK,eAAe,KAAA;CACtB;CAEA,SAAS,QAAuB,aAA2B;EACzD,KAAK,iBAAiB,IAAI,WAAW;EACrC,KAAK,aAAa,MAAM;CAC1B;CAEA,mBAAmB,QAAuB,aAA4B;EACpE,KAAK,oBAAoB,IAAI,eAAe,mBAAmB;EAC/D,KAAK,aAAa,MAAM;CAC1B;;;;;;;CAQA,MAAM,iBAAgC;EACpC,OAAO,KAAK,aACV,IAAI;GACF,MAAM,KAAK;EACb,QAAQ,CAER;CAEJ;CAEA,aAAqB,QAA6B;EAChD,aAAa,KAAK,cAAc;EAChC,KAAK,iBAAiB,iBAAiB;GACrC,KAAK,iBAAiB,KAAA;GACtB,KAAU,KAAK,MAAM;EACvB,GAAG,KAAK,UAAU;CACpB;CAEA,MAAc,KAAK,QAAsC;EACvD,IAAI,KAAK,WAAW;GAElB,KAAK,WAAW;GAEhB;EACF;EAEA,KAAK,YAAY;EAEjB,IAAI;EAEJ,KAAK,cAAc,IAAI,SAAe,YAAY;GAChD,aAAa;EACf,CAAC;EAED,IAAI;GACF,GAAG;IACD,KAAK,WAAW;IAEhB,MAAM,WAAW,CAAC,GAAG,KAAK,gBAAgB,CAAC,CAAC,KAAK;IACjD,MAAM,cAAc,CAAC,GAAG,KAAK,mBAAmB,CAAC,CAAC,KAAK;IAEvD,KAAK,iBAAiB,MAAM;IAC5B,KAAK,oBAAoB,MAAM;IAE/B,IAAI,SAAS,SAAS,KAAK,YAAY,SAAS,GAC9C,KAAK,OAAO,KAAK,KAAK,cAAc,QAAQ,UAAU,WAAW,CAAC;IAGpE,IAAI;KACF,MAAM,OAAO,QAAQ;IACvB,SAAS,OAAO;KACd,KAAK,OAAO,MAAM,oCAAoC,eAAe,KAAK,GAAG;IAC/E;GACF,SAAS,KAAK;EAChB,UAAU;GACR,KAAK,YAAY;GACjB,KAAK,cAAc,KAAA;GACnB,WAAW;EACb;CACF;CAEA,cAAsB,QAAuB,UAAoB,aAA+B;EAC9F,MAAM,OAAO,OAAO,OAAO;EAC3B,MAAM,OAAO,MAAsB,KAAK,SAAS,MAAM,CAAC,KAAK;EAC7D,MAAM,QAAkB,CAAC;EAEzB,IAAI,SAAS,WAAW,GACtB,MAAM,KAAK,qBAAqB,IAAI,SAAS,EAAG,GAAG;OAC9C,IAAI,SAAS,SAAS,GAC3B,MAAM,KAAK,sBAAsB,SAAS,OAAO,KAAK,SAAS,IAAI,GAAG,CAAC,CAAC,KAAK,IAAI,GAAG;EAGtF,IAAI,YAAY,SAAS,GAAG;GAC1B,MAAM,QAAQ,YAAY,QAAQ,MAAM,MAAM,mBAAmB;GAEjE,IAAI,MAAM,WAAW,GACnB,MAAM,KAAK,sBAAsB;QAEjC,MAAM,KAAK,sCAAsC,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE,EAAE;EAEjF;EAEA,OAAO,GAAG,MAAM,KAAK,KAAK,EAAE;CAC9B;AACF;;;;;;;;AC/IA,SAAS,WAAW,KAAqD;CACvE,OACE,CAAC,CAAC,OACF,OAAQ,IAA6B,WAAW,YAChD,OAAQ,IAAoB,OAAO,WAAW;AAElD;;;;;;AAOA,SAAS,eAAe,QAAoC;CAC1D,MAAM,MAAM,OAAO,aAAa;CAEhC,IAAI,WAAW,GAAG,GAAG,OAAO;CAE5B,MAAM,QAAQ,OAAO,aAAa;CAElC,IAAI,WAAW,KAAK,GAAG,OAAO;CAE9B,MAAM,QAAQ,OAAO,KAAK,OAAO,YAAY;CAE7C,MAAM,IAAI,MAAM,kDAAkD,MAAM,KAAK,IAAI,GAAG;AACtF;;;;AAKA,eAAsB,UAAuC,QAAuB,UAA8B;CAChH,OAAO,eAAe,MAAM,CAAC,CAAC,OAAO,OAAO,QAAQ;AACtD;;;;;AAMA,SAAgB,eAAe,QAAmD;CAChF,MAAM,MAAM,OAAO,aAAa;CAEhC,IAAI,WAAW,GAAG,GAAG,OAAO;CAE5B,MAAM,QAAQ,OAAO,aAAa;CAElC,IAAI,WAAW,KAAK,GAAG,OAAO;AAGhC;;;ACzDA,MAAa,kBAAkB;CAE7B;CACA;CACA;CAEA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA;CACA;CACA;CACA;AACF;;;AC9BA,MAAM,eAAe,aAAa,cAAc,IAAI,IAAI,uBAAuB,YAAY,GAAG,CAAC,GAAG,MAAM;AAExG,SAAgB,eAAe,QAAuB,SAAmB,WAAmC;CAC1G,MAAM,iBAAiB,QAAQ,KAAK,UAAU,KAAK,QAAQ,OAAO,OAAO,MAAM,KAAK,CAAC;CAErF,MAAM,cAAc,eAAe,MAAM;CACzC,MAAM,kBAAkB,aAAa;CAErC,MAAM,gCAA6C;EACjD,MAAM,uBAAO,IAAI,IAAY;EAC7B,MAAM,uBAAO,IAAI,IAAY;EAE7B,KAAK,MAAM,iBAAiB,gBAAgB;GAC1C,MAAM,eAAe,iBAAiB,iBAAiB,aAAa;GACpE,MAAM,cAAc,eAAe,CAAC,GAAG,YAAY,CAAC,CAAC,KAAK,KAAA;GAE1D,IAAI,CAAC,aAAa;GAElB,MAAM,SAAS,QAAkC;IAC/C,IAAI,CAAC,KAAK,QAAQ,KAAK,IAAI,IAAI,IAAI,GAAG;IAEtC,KAAK,IAAI,IAAI,IAAI;IACjB,KAAK,IAAI,IAAI,IAAI;IAEjB,KAAK,MAAM,OAAO,IAAI,iBAAiB,MAAM,GAAG;GAClD;GAEA,MAAM,WAAW;EACnB;EAEA,OAAO;CACT;CAEA,MAAM,gBAAgB,aAA8B;EAClD,MAAM,IAAI,SAAS,YAAY;EAE/B,OAAO,gBAAgB,MAAM,WAAW,EAAE,SAAS,MAAM,CAAC;CAC5D;CAEA,MAAM,kBAAkB,gBAA8B;EACpD,IAAI,aAAa,WAAW,GAAG;EAI/B,IAAI,CAFa,wBAEL,CAAC,CAAC,IAAI,WAAW,GAAG;EAEhC,UAAU,SAAS,QAAQ,WAAW;CACxC;CAEA,OAAO,QAAQ,GAAG,UAAU,cAAc;CAC1C,OAAO,QAAQ,GAAG,OAAO,cAAc;CACvC,OAAO,QAAQ,GAAG,UAAU,cAAc;CAG1C,IAAI,oBAAoB;CAExB,IAAI,OAAO,YACT,OAAO,WAAW,KAAK,mBAAmB;EACxC,oBAAoB;CACtB,CAAC;MAGD,oBAAoB;CAKtB,MAAM,kBAAkB,aAAa,IAAA,EAAiE,KAClG;CAEJ,IAAI,gBACF,eAAe,GAAG,SAAS,YAAwB;EACjD,IAAI,CAAC,mBAAmB;EACxB,IAAI,QAAQ,SAAS,eAAe;EAEpC,MAAM,cAAc,iBAAiB,UAAW,QAAQ,cAAyB,KAAA;EAEjF,UAAU,mBAAmB,QAAQ,WAAW;CAClD,CAAC;AAEL;AAEA,MAAM,iBAAiB;;;;AAKvB,SAAgB,gBACd,QACA,WACM;CAMN,OAL2B,YAKf,MAAM,QAAQ;EACxB,OAAO;EACP,SAAS,OACP,KACA,KAKA,SACG;GAGH,IAAI,IAAI,QAAQ,gBAAgB;IAC9B,MAAM,UAAU,eAAe;IAE/B,IAAI,IAAI,aAAa;IAErB,MAAM,UAAU,UAAU,eAAe;IAEzC,IAAI,SAAS;KACX,IAAI,UAAU,KAAK;MAAE,iBAAiB;MAAY,gBAAgB;KAAmB,CAAC;KACtF,IAAI,IAAI,KAAK,UAAU,EAAE,OAAO,QAAQ,QAAQ,CAAC,CAAC;KAElD;IACF;IAEA,IAAI,UAAU,KAAK,EAAE,iBAAiB,WAAW,CAAC;IAClD,IAAI,IAAI;IAER;GACF;GAEA,IAAI,kBAAkB,IAAI,GAAG,GAAG;IAC9B,KAAK;IAEL;GACF;GAGA,IAAI,UAAU,iBAAiB,GAAG;IAChC,IAAI,UAAU,KAAK;KACjB,gBAAgB;KAChB,iBAAiB;KACjB,eAAe;IACjB,CAAC;IACD,IAAI,IAAI,YAAY;IAEpB;GACF;GAEA,KAAK;EACP;CACF,CAAC;AACH;AAEA,SAAS,kBAAkB,KAAkC;CAC3D,IAAI,CAAC,KAAK,OAAO;CAEjB,OAAO,IAAI,WAAW,IAAI,KAAK,IAAI,WAAW,KAAK,KAAK,IAAI,SAAS,gBAAgB;AACvF;;;;;;AAOA,SAAgB,gBAAgB,QAAkD;CAKhF,OAJ2B,YAIf,MAAM,QAAQ;EACxB,OAAO;EACP,UAAU,KAA0C,MAAe,SAAqB;GACtF,IAAI,QAAQ,cAAc,OAAO,qBAAqB,CAAC;GACvD,KAAK;EACP;CACF,CAAC;AACH;;;;;;;ACtJA,SAAS,kBAAkB,QAA4D;CACrF,OAAO;EACL,MACE,OAAO,QAAQ,QAAQ,SAAS,WAC5B,OAAO,OAAO,OACd,QAAQ,QAAQ,SAAS,OACvB,YACA;EACR,MAAM,QAAQ,QAAQ,QAAQ;CAChC;AACF;;;;;AAMA,SAAS,mBACP,QACA,QACa;CACb,MAAM,OAAO,OAAO,YAAY,QAAQ;CAExC,IAAI,QAAQ,OAAO,SAAS,YAAY,aAAa,QAAQ,UAAU,MAMrE,OAAO;EAAE,KAAK;EAAM,MAJjB,KAA6B,YAAY,QAAS,KAA6B,YAAY,YACxF,cACC,KAA6B;EAEV,MAAO,KAA0B;CAAK;CAGlE,MAAM,EAAE,MAAM,SAAS,kBAAkB,MAAM;CAE/C,OAAO;EAAE,KAAK;EAAM;EAAM;CAAK;AACjC;;;;;;AAOA,SAAgB,mBAAmB,SAAwC;CACzE,MAAM,EAAE,OAAO,WAAW;CAE1B,IAAI,0BAA0B;CAG9B,IAAI;CAEJ,MAAM,YAAY,QAAQ,QAAQ,IAAI,iBAAiB,KAAK,MAAM,IAAI,KAAA;CAEtE,OAAO,CAIL;EACE,MAAM;EACN,SAAS;EAET,gBAAgB,QAAQ;GACtB,IAAI,CAAC,WAAW;GAEhB,aAAa;IAIX,gBAAgB,QAAQ,SAAS;IACjC,gBAAgB,MAAM;GACxB;EACF;CACF,GAGA;EACE,MAAM;EACN,SAAS;EAET,MAAM,gBAAgB,QAAQ;GAC5B,oBAAoB;GAIpB,IAAI,eAAe;IACjB,MAAM,cAAc;IACpB,gBAAgB,KAAA;GAClB;GAGA,MAAM,cAAc,mBAAmB,QADnB,QAAQ,UAC6B,CAAC;GAC1D,IAAI;GAEJ,eAAe,WAAW;GAE1B,IAAI;IACF,MAAM,QAAQ,SAAS,OAAO,UAAU,QAAQ,EAAE,CAAC;IAEnD,aAAa,QAAQ,MAAM,UAAsB,QAAQ,IAAI,OAAO,IAAI,CAAC;IAEzE,MAAM,WAAW,YAAY,WAAW;GAC1C,SAAS,OAAO;IACd,OAAO,MAAM,iCAAiC,eAAe,KAAK,GAAG;IAErE,IAAI,YACF,IAAI;KACF,MAAM,YAAY,YAAY,WAAW;IAC3C,QAAQ,CAER;IAMF,IAAI,yBAAyB;KAC3B,WAAW,cAAc,eAAe,KAAK,CAAC;KAE9C,MAAM;IACR;IAGA,QAAQ,KAAK,CAAC;GAChB;GAEA,0BAA0B;GAC1B,WAAW,aAAa;GAGxB,MAAM,gBAAgB;GACtB,IAAI,eAAe;GAEnB,MAAM,WAAW,YAA2B;IAC1C,IAAI,cAAc;IAElB,eAAe;IAEf,IAAI;KACF,MAAM,YAAY,eAAe,mBAAmB,QAAQ,QAAQ,UAAU,CAAC,CAAC;IAClF,SAAS,OAAO;KACd,OAAO,MAAM,kCAAkC,eAAe,KAAK,GAAG;IACxE;IAGA,kBAAkB;GACpB;GAEA,gBAAgB;GAGhB,OAAO,YAAY,KAAK,eAAe;IACrC,SAAc;GAChB,CAAC;GAED,IAAI,WACF,eAAe,QAAQ,CAAC,GAAI,QAAQ,CAAC,KAAK,IAAI,CAAC,GAAI,GAAG,QAAQ,YAAY,GAAG,SAAS;EAE1F;CACF,CACF;AACF;;;;;;;AC3LA,SAAgB,yBAAyB,UAAoC;CAC3E,OAAO,IAAI,SAAS,KAAK,MAAO,aAAa,IAAI,cAAc,EAAE,QAAQ,SAAS,EAAE,MAAM,KAAK,UAAU,CAAC,CAAE,CAAC,CAAC,KAAK,IAAI,EAAE;AAC3H;ACAA,MAAM,qCAAqC;AAE3C,MAAM,qBAAqB;;;;;;;;;;;AAoB3B,SAAgB,4BAA4B,SAA+C;CACzF,IAAI,UAAU;CAEd,OAAO;EACL,MAAM;EAEN,eAAe,QAAQ;GACrB,UAAU,OAAO,YAAY;EAC/B;EAEA,UAAU,IAAI;GACZ,IAAI,OAAA,6CAAkC,OAAO;EAC/C;EAEA,KAAK,IAAI;GACP,IAAI,OAAO,oCAAoC;GAE/C,IAAI,CAAC,WAAW,CAAC,QAAQ,SACvB,OAAO;GAMT,OAAO;;;;;;;;;;eAUE,mBAAmB;yBACT,mBAAmB;+BACb,mBAAmB;;;;;;;;;;;;EAY9C;EAEA,YAAY,eAAe,QAAQ;GACjC,IAAI,CAAC,QAAQ,WAAW,KAAK,YAAY,SAAS,YAAY,CAAC,cAAc,KAAK;GAElF,MAAM,SAAoC,CAAC;GAE3C,KAAK,MAAM,SAAS,OAAO,OAAO,MAAM,GAAG;IACzC,IAAI,MAAM,SAAS,SAAS;IAE5B,OAAO,MAAM,YAAY;KACvB,GAAI,MAAM,QAAQ,SAAS,KAAK,EAAE,GAAG,MAAM,QAAQ;KACnD,GAAI,MAAM,eAAe,SAAS,KAAK,EAAE,GAAG,MAAM,eAAe;IACnE;GACF;GAIA,MAAM,gBAAgB,GACnB,aAAa,IAAI,IAAI,wBAAwB,YAAY,GAAG,GAAG,OAAO,CAAC,CACvE,QAAQ,gCAAgC,EAAE,CAAC,CAC3C,QAAQ;GACX,MAAM,OAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,aAAa,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC;GAChF,MAAM,UAAU,GAAG,QAAQ,UAAU,mBAAmB,KAAK;GAE7D,GAAG,UAAU,KAAK,KAAK,cAAc,KAAK,QAAQ,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;GACjF,GAAG,cAAc,KAAK,KAAK,cAAc,KAAK,QAAQ,WAAW,mBAAmB,KAAK,IAAI,GAAG,aAAa;GAE7G,MAAM,WAA4B;IAAE;IAAS;GAAO;GACpD,MAAM,YAAY,KAAK,QAAQ,cAAc,KAAK,MAAM,UAAU,QAAQ;GAE1E,IAAI,GAAG,WAAW,SAAS,GACzB,GAAG,cAAc,KAAK,KAAK,WAAW,kBAAkB,GAAG,KAAK,UAAU,QAAQ,CAAC;QAEnF,QAAQ,OAAO,KAAK,+DAA+D,WAAW;EAElG;CACF;AACF;;;;;;;;;;;;ACzGA,SAAgB,qBAA6B;CAC3C,OAAO;EACL,MAAM;EACN,OAAO,SAAS,EAAE,cAAc;GAC9B,IAAI,YAAY,OAAO,EAAE,OAAO,EAAE,WAAW,KAAK,EAAE;GAEpD,OAAO,CAAC;EACV;CACF;AACF;;;AChBA,MAAM,6BAAa,IAAI,IAAI;CAAC;CAAa;CAAmB;AAAoB,CAAC;AACjF,MAAM,eAAe;AACrB,MAAM,gBAAgB;AACtB,MAAM,WAAW;;;;;;;;;;;;AAajB,SAAgB,wBAAgC;CAC9C,OAAO;EACL,MAAM;EACN,SAAS;EACT,UAAU,MAAM,IAAI,SAAS;GAC3B,IAAI,CAAC,SAAS,KAAK,OAAO;GAC1B,IAAI,GAAG,SAAS,gBAAgB,GAAG,OAAO;GAE1C,MAAM,UAAU,GAAG,MAAM,GAAG,CAAC,CAAC,MAAM;GAEpC,IAAI,CAAC,cAAc,KAAK,OAAO,GAAG,OAAO;GACzC,IAAI,CAAC,KAAK,SAAS,WAAW,KAAK,CAAC,KAAK,SAAS,iBAAiB,KAAK,CAAC,KAAK,SAAS,oBAAoB,GACzG,OAAO;GAGT,IAAI;GAEJ,IAAI;IACF,MAAM,OAAO,MAAM,MAAM;KACvB,aAAa;KACb,YAAY;KACZ,4BAA4B;KAC5B,2BAA2B;KAC3B,6BAA6B;KAC7B,eAAe;IACjB,CAAC;GACH,QAAQ;IACN,OAAO;GACT;GAEA,MAAM,8BAAc,IAAI,IAAY;GACpC,MAAM,iCAAiB,IAAI,IAAY;GAEvC,KAAK,MAAM,SAAS;IAClB,IAAI,KAAK,SAAS,qBAAqB;IAEvC,MAAM,MAAM,KAAK,QAAQ;IAEzB,IAAI,OAAO,QAAQ,YAAY,CAAC,aAAa,KAAK,GAAG,GAAG;IAExD,KAAK,MAAM,QAAQ,KAAK,cAAc,CAAC,GACrC,IAAI,KAAK,SAAS,mBAAmB;KACnC,MAAM,WAAW,KAAK,UAAU,QAAQ,KAAK,UAAU;KAEvD,IAAI,WAAW,IAAI,QAAQ,GAAG,YAAY,IAAI,KAAK,MAAM,IAAI;IAC/D,OAAO,IAAI,KAAK,SAAS,4BAA4B,KAAK,SAAS,4BACjE,eAAe,IAAI,KAAK,MAAM,IAAI;GAGxC,CAAC;GAED,IAAI,YAAY,SAAS,KAAK,eAAe,SAAS,GAAG,OAAO;GAEhE,MAAM,eAAiD,CAAC;GAExD,KAAK,MAAM,SAAS;IAClB,IAAI,KAAK,SAAS,oBAAoB,CAAC,KAAK,WAAW,QAAQ;IAE/D,MAAM,SAAS,KAAK;IACpB,MAAM,WAAW,OAAO,SAAS,gBAAgB,YAAY,IAAI,OAAO,IAAI;IAC5E,MAAM,WACJ,OAAO,SAAS,sBAChB,CAAC,OAAO,YACR,OAAO,QAAQ,SAAS,gBACxB,eAAe,IAAI,OAAO,OAAO,IAAI,KACrC,OAAO,UAAU,SAAS,gBAC1B,WAAW,IAAI,OAAO,SAAS,IAAI;IAErC,IAAI,CAAC,YAAY,CAAC,UAAU;IAE5B,MAAM,MAAM,KAAK,UAAU;IAE3B,aAAa,KAAK;KAAE,OAAO,IAAI;KAAO,KAAK,IAAI;IAAI,CAAC;GACtD,CAAC;GAED,IAAI,aAAa,WAAW,GAAG,OAAO;GAEtC,MAAM,IAAI,IAAI,YAAY,IAAI;GAE9B,KAAK,MAAM,EAAE,OAAO,SAAS,cAC3B,EAAE,UAAU,OAAO,KAAK,QAAQ;GAGlC,OAAO;IAAE,MAAM,EAAE,SAAS;IAAG,KAAK,EAAE,YAAY,EAAE,OAAO,KAAK,CAAC,CAAC,CAAC,SAAS;GAAE;EAC9E;CACF;AACF;AAEA,SAAS,KAAK,MAAW,OAA+B;CACtD,IAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;CAEvC,IAAI,OAAO,KAAK,SAAS,UAAU,MAAM,IAAI;CAE7C,KAAK,MAAM,OAAO,OAAO,KAAK,IAAI,GAAG;EACnC,MAAM,IAAI,KAAK;EAEf,IAAI,MAAM,QAAQ,CAAC,GAAG,KAAK,MAAM,QAAQ,GAAG,KAAK,MAAM,KAAK;OACvD,IAAI,KAAK,OAAO,MAAM,UAAU,KAAK,GAAG,KAAK;CACpD;AACF;;;ACtGA,MAAa,2BAA2B;AACxC,MAAa,yBAAyB;AACtC,MAAa,yBAAyB;AACtC,MAAa,iCAAiC;AAC9C,MAAa,0CAA0C;AACvD,MAAa,8BAA8B;AAE3C,MAAM,oCAAoC,KAAK;AAC/C,MAAM,kCAAkC,KAAK;AAC7C,MAAM,kCAAkC,KAAK;AAC7C,MAAM,0CAA0C,KAAK;AACrD,MAAM,mDAAmD,KAAK;AAC9D,MAAM,uCAAuC,KAAK;AAElD,MAAM,sBAAsB;CAAC;CAAO;CAAa;AAAO;AACxD,MAAM,2BAA6C,CAAC,GAAG,oBAAoB;AAE3E,SAAS,YAAY,MAA4C;CAC/D,IAAI,OAAO,SAAS,UAAU,OAAO;CAErC,OAAO,SAAS,OAAO,YAAY;AACrC;AAEA,SAAS,iBAAiB,MAAc,OAA+C;CACrF,IAAI,OAAO;EACT,MAAM,MAAM,KAAK,QAAQ,MAAM,KAAK;EAEpC,IAAI,CAAC,GAAG,WAAW,GAAG,GACpB,MAAM,IAAI,MAAM,4CAA4C,OAAO;EAGrE,OAAO;CACT;CAEA,KAAK,MAAM,aAAa,CAAC,qBAAqB,aAAa,GAAG;EAC5D,MAAM,MAAM,KAAK,QAAQ,MAAM,SAAS;EAExC,IAAI,GAAG,WAAW,GAAG,GAAG,OAAO;CACjC;AAGF;AAEA,SAAS,YAAY,MAAc,WAAuC;CACxE,MAAM,MAAM,KAAK,QAAQ,MAAM,SAAS;CAExC,OAAO,GAAG,WAAW,GAAG,IAAI,MAAM,KAAA;AACpC;;;;;;;AAQA,SAAwB,KAAK,UAAuB,CAAC,GAAqB;CACxE,MAAM,cAAc,QAAQ,QAAQ,CAAC;CACrC,MAAM,gBAAgB,QAAQ,UAAU,CAAC;CACzC,MAAM,cAAc,QAAQ,QAAQ,CAAC;CACrC,MAAM,iBAAiB,QAAQ,YAAY;CAC3C,MAAM,iBAAiB,QAAQ,WAAW,CAAC;CAC3C,MAAM,mBAAmB,QAAQ,aAAa,CAAC;CAE/C,MAAM,iBAAiB,iBAAkB,eAAe,WAAW,2BAA4B,CAAC;CAChG,MAAM,mBAAmB,mBAAoB,iBAAiB,WAAW,2BAA4B,CAAC;CAEtG,IAAI,cAAkC;CACtC,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI,QAAQ;CAEZ,OAAO;EACL,MAAM;EACN,OAAO;GACL,uBAAuB,EAAE,SAAS,QAAQ,cAAc,eAAe,aAAa;IAClF,QAAQ,YAAY;IAGpB,IAAI,kBAAkB,kBACpB,cAAc;KAAE,OAAO;KAAO,YAAY;IAAoC,CAAC;IAGjF,IAAI,aACF,cAAc;KAAE,OAAO;KAAO,YAAY;IAAmC,CAAC;IAIhF,cAAc;KAAE,OAAO;KAAO,YAAY;IAAsC,CAAC;IAEjF,MAAM,OAAO,cAAc,OAAO,IAAI;IACtC,MAAM,QAAQ,gBAAgB,QAAQ,QAAS,YAAY,SAAS;IAEpE,YAAY,gBAAgB,QAAQ,KAAA,IAAY,iBAAiB,MAAM,YAAY,KAAK;IACxF,aAAa,YAAY,MAAM,eAAe;IAC9C,sBAAsB,YAAY,MAAM,wBAAwB;IAChE,UAAU,YAAY,MAAM,YAAY;IAExC,MAAM,gBAAgB,QACpB,MAAM,KAAK,SAAS,MAAM,GAAG,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,IAAI,KAAA;IAE7D,MAAM,eACJ,YAAY,SAAS,gBAAgB,QACjC,mBAAmB;KACjB,OAAO,YAAY,KAAK,SAAS,MAAM,SAAS,IAAI,KAAA;KACpD;KAGA,cAAc,CAAC,aAAa,UAAU,GAAG,aAAa,OAAO,CAAC,CAAC,CAAC,QAC7D,UAA2B,CAAC,CAAC,KAChC;KACA,UAAU,iBACR,gBAAgB;MACd,KAAK;MACL,WACE,oBAAoB,iBAAiB,MACjC,EAAE,YAAY,iBAAiB,cAAc,CAAC,EAAE,IAChD;MACN,OAAO;OACL,GAAI,cAAc,EAAE,cAAc,aAAa,IAAI,aAAa,UAAU,GAAG,EAAE;OAC/E,GAAI,uBAAuB,EACzB,uBAAuB,aAAa,IAAI,aAAa,mBAAmB,GAAG,EAC7E;OACA,GAAI,WAAW,EAAE,WAAW,aAAa,IAAI,aAAa,OAAO,GAAG,EAAE;MACxE;KACF,CAAC;KACH;KACA,iBAAiB;IACnB,CAAC,IACD,CAAC;IAEP,IAAI,YAAY,SAAS,gBAAgB,SAAS,OAGhD,cAAc;KAAE,YAAY;KAAmC,OAAO;IAAM,CAAC;IAG/E,MAAM,eACJ,YAAY,QAAQ,CAAC,mBAAmB;KAAE;KAAM,QAAQ,cAAc,OAAO,MAAM;KAAG;IAAO,CAAC,CAAC,IAAI,CAAC;IAEtG,MAAM,eAAe,QAAQ,gBAAgB;IAC7C,MAAM,WACJ,iBAAiB,SAChB,iBAAiB,UAAU,OAAO,MAAM,QAAQ,eAAe;IAElE,aAAa;KACX,OAAO,EAAE,WAAW,MAAM;KAE1B,GAAI,OAAO,kBAAkB,YAAY,EAAE,eAAe,QAAiB;KAC3E,UAAU;MAER,GAAI,CAAC,OAAO,SAAS,gBAAgB,UAAU,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAAE;MAEtE,GAAI,eAAe,EAAE,aAAa,MAAM;KAC1C;KACA,OAAO;MACL,GAAI,YAAY,EAAE,SAAS;OAAE,YAAY;OAAkC,QAAQ,CAAC;MAAE,EAAE;MACxF,UAAU;OACR,OAAO,OAAO,MAAM,SAAS,SAAS;OACtC,YAAY,WACR,oCACC,OAAO,MAAM,SAAS,eACtB,YAAY,QAAQ,8BAA8B;MACzD;KACF;KACA,MAAM,EACJ,SAAS;MACP,GAAG;MACH,GAAG;MACH,4BAA4B;OAAE,WAAW,OAAO,MAAM;OAAQ;OAAQ,SAAS;MAAe,CAAC;MAC/F,mBAAmB;MACnB,sBAAsB;MACtB;OACE,MAAM;OAEN,kBAAkB,iBAAyB;QACzC,IAAI,oBAAoB,SAAS,eAAe,GAC9C,OAAO,EAAE,SAAS,EAAE,YAAY,CAAC,kBAAkB,EAAE,EAAE;OAE3D;OAEA,UAAU,IAAY;QACpB,IAAI,OAAA,mCAAiC,OAAO;QAC5C,IAAI,OAAA,iCAA+B,OAAO;QAC1C,IAAI,OAAA,iCAA+B,OAAO;QAC1C,IAAI,OAAA,yCAAuC,OAAO;QAClD,IAAI,OAAA,kDACF,OAAO;QAET,IAAI,OAAA,sCAAoC,OAAO;OACjD;OAEA,KAAK,IAAY;QACf,IAAI,OAAO,mCAAmC;SAC5C,IAAI,CAAC,aAAa,MAAM,IAAI,MAAM,kDAAkD;SAEpF,MAAM,iBAAgE;UACpE,MAAM,YAAY,YAAY,OAAO,IAAI;UACzC,MAAM,YAAY,OAAO,QAAQ;UACjC,QAAQ,YAAY,MAAM,OAAO,SAAS;UAC1C,QAAQ,YAAY,MAAM,OAAO,SAAS;UAC1C,eAAe,QAAQ,iBAAiB;UACxC,iBAAiB,QAAQ,mBAAmB;UAC5C,QAAQ,gBACJ;WACE,GAAI,cAAc,SAAS,KAAA,KAAa,EAAE,MAAM,cAAc,KAAK;WACnE,GAAI,cAAc,SAAS,KAAA,KAAa,EAAE,MAAM,cAAc,KAAK;WACnE,GAAI,cAAc,SAAS,EAAE,OAAO,cAAc,MAAM;UAC1D,IACA;SACN;SAGA,MAAM,UAAU,iBACZ,cAAc,yBAAyB,cAAc,EAAE,cAAc,KAAK,UACxE,eAAe,YAAY,KAC7B,EAAE,MACF;SACJ,MAAM,YAAY,mBACd,cAAc,yBAAyB,gBAAgB,EAAE,gBAAgB,KAAK,UAC5E,iBAAiB,cAAc,CAAC,CAClC,EAAE,MACF;SAEJ,OAAO,+BAA+B,KAAK,UAAU,cAAc,EAAE,aAAa,QAAQ,eAAe,UAAU;QACrH;QAEA,IAAI,OAAO,iCAET,OAAO,YAAY,iBAAiB,KAAK,UAAU,SAAS,EAAE,KAAK;QAGrE,IAAI,OAAO,iCACT,OAAO,kCAAkC,yBAAyB,cAAe,YAAY,WAAW,CAAC,IAAK,CAAC,CAAC,EAAE;QAGpH,IAAI,OAAO,yCAET,OAAO,aAAa,UAAU,KAAK,UAAU,UAAU,EAAE,iBAAiB;QAG5E,IAAI,OAAO,kDACT,OAAO,sBAAsB,iBAAiB,KAAK,UAAU,mBAAmB,EAAE,KAAK;QAGzF,IAAI,OAAO,sCACT,OAAO,UACH,2BAA2B,KAAK,UAAU,OAAO,EAAE,KACnD;OAER;MACF;KACF,EACF;IACF,CAAC;GACH;GACA,uBAAuB,EAAE,aAAa;IACpC,IAAI,CAAC,OAAO;IAEZ,MAAM,aAAa,kBAAkB,eAAe;IACpD,MAAM,eAAe,oBAAoB,iBAAiB;IAE1D,MAAM,aACJ,cAAc,eACV,6BAA6B;KAC3B,SAAS,aAAa;MAAE,SAAS;MAAgB,UAAU,eAAe,YAAY;KAAM,IAAI;KAChG,WAAW,eAAe,EAAE,SAAS,iBAAiB,IAAI;IAC5D,CAAC,IACD,KAAA;IAEN,OAAO,YAAY,KAAK,KAAK,KAAK,SAAS;KACzC,MAAM,cAAoB;MACxB,IAAI,CAAC,oBAAoB,KAAK,GAAG,GAAG,KAAK;KAC3C;KAEA,IAAI,YACF,WAAW,KAAK,KAAK,KAAK;UAE1B,MAAM;IAEV,CAAC;GACH;GACA,sBAAsB,EAAE,QAAQ,iBAAiB;IAC/C,cAAc;IAEd,WAAW;KACT,MAAM;KACN,sBAAsB;KACtB,kBAAkB;KAClB,mBAAmB;KACnB,iBAAiB;MACf,aAAa;MACb,gBAAgB;KAClB;KACA,wBAAwB;MACtB,cAAc;MACd,cAAc;MACd,cAAc;MACd,mBAAmB;MACnB,aAAa;MACb,cAAc;KAChB;IACF,CAAC;GACH;GACA,oBAAoB,OAAO,EAAE,aAAa;IACxC,IAAI,CAAC,aAAa;IAElB,IAAI,gBAAgB;KAGlB,MAAM,eAAe,KAAK,KAAK,cAAc,YAAY,MAAM,MAAM,GAAG,UAAU,uBAAuB;KAEzG,IAAI,GAAG,WAAW,YAAY,GAAG;MAC/B,MAAM,EAAE,6BAA6B,MAAM,OAAO;MAClD,MAAM,WAAW,KAAK,MAAM,GAAG,aAAa,cAAc,OAAO,CAAC;MAClE,MAAM,cAAc,MAAM,yBAAyB,cAAc,YAAY,MAAM,MAAM,GAAG,QAAQ;MAEpG,IAAI,cAAc,GAChB,OAAO,KAAK,gCAAgC,YAAY,qBAAqB;KAEjF;IACF;IAEA,MAAM,EAAE,sBAAsB,MAAM,OAAO;IAE3C,MAAM,kBAAkB,cAAc,YAAY,MAAM,MAAM,GAAG,MAAM;GACzE;EACF;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["walk"],"sources":["../src/dev-mode/island-warmup.ts","../src/dev-mode/serialize-error.ts","../src/dev-mode/scheduler.ts","../src/dev-mode/vite-env.ts","../src/dev-mode/ignored.ts","../src/dev-mode/watch.ts","../src/dev-mode/machinery.ts","../src/excludes/serialize.ts","../src/islands/manifest-plugin.ts","../src/tweaks/sourcemap.ts","../src/tweaks/strip-effects.ts","../src/integration/integration.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { parse } from '@astrojs/compiler-rs';\nimport type { Plugin, ViteDevServer } from 'vite';\n\n/**\n * Vite discovers island dependencies lazily: astro registers no client entries,\n * so a dep like radix is first seen when an island hydrates. The optimizer then\n * re-runs, bumps the `?v=` hash and every in-flight import gets a\n * \"504 Outdated Optimize Dep\" — hydration fails until the full reload.\n *\n * This plugin scans `.astro` sources for `client:*` components at config time,\n * puts their bare package imports into `optimizeDeps.include` (initial optimize\n * pass) and warms their local module graphs at server start (vite's\n * `preTransformRequests` crawls static imports recursively), so discovery\n * happens before a browser holds stale URLs.\n */\n\ninterface Logger {\n info(msg: string): void;\n debug(msg: string): void;\n}\n\nexport interface IslandImport {\n /** absolute path of the .astro file rendering the island */\n importer: string;\n /** import specifier of the hydrated component */\n specifier: string;\n}\n\ninterface AstNode {\n type: string;\n [key: string]: unknown;\n}\n\nfunction isAstNode(value: unknown): value is AstNode {\n return typeof value === 'object' && value !== null && typeof (value as AstNode).type === 'string';\n}\n\nfunction walk(node: unknown, visit: (node: AstNode) => void): void {\n if (Array.isArray(node)) {\n for (const item of node) walk(item, visit);\n\n return;\n }\n\n if (typeof node !== 'object' || node === null) return;\n\n if (isAstNode(node)) visit(node);\n\n for (const value of Object.values(node)) walk(value, visit);\n}\n\ninterface ImportDeclarationNode {\n importKind?: string | null;\n source?: { value?: unknown } | null;\n specifiers?: { importKind?: string | null; local?: { name?: unknown } | null }[] | null;\n}\n\n/** local binding name → import specifier, from the frontmatter program */\nfunction collectImports(program: unknown): Map<string, string> {\n const imports = new Map<string, string>();\n\n walk(program, (node) => {\n if (node.type !== 'ImportDeclaration') return;\n\n const decl = node as ImportDeclarationNode;\n\n if (decl.importKind === 'type') return;\n\n const specifier = typeof decl.source?.value === 'string' ? decl.source.value : undefined;\n\n if (!specifier) return;\n\n for (const spec of decl.specifiers ?? []) {\n if (spec.importKind === 'type') continue;\n\n if (typeof spec.local?.name === 'string') {\n imports.set(spec.local.name, specifier);\n }\n }\n });\n\n return imports;\n}\n\n/** the root identifier of a JSX tag: `Foo` → Foo, `Ns.Chart` → Ns */\nfunction tagRootIdentifier(name: unknown): string | undefined {\n let current = name;\n\n while (isAstNode(current) && current.type === 'JSXMemberExpression') {\n current = (current as unknown as { object?: unknown }).object;\n }\n\n if (isAstNode(current) && current.type === 'JSXIdentifier') {\n const identifier = current as unknown as { name?: unknown };\n\n return typeof identifier.name === 'string' ? identifier.name : undefined;\n }\n\n return undefined;\n}\n\nfunction hasClientDirective(attributes: unknown): boolean {\n if (!Array.isArray(attributes)) return false;\n\n return attributes.some((attr) => {\n if (!isAstNode(attr) || attr.type !== 'JSXAttribute') return false;\n\n const name = (attr as unknown as { name?: { name?: unknown } | null }).name;\n\n return typeof name?.name === 'string' && name.name.startsWith('client:');\n });\n}\n\n/**\n * Extract the import specifiers of all hydrated (`client:*`) components from\n * raw `.astro` source. Astro components can't hydrate, so `.astro` specifiers\n * are skipped; dynamic tags without a frontmatter import are invisible here.\n */\nexport function scanAstroSource(source: string): string[] {\n const { ast } = parse(source);\n const root = ast as { frontmatter?: { program?: unknown } | null; body?: unknown };\n\n const imports = collectImports(root.frontmatter?.program);\n\n if (imports.size === 0) return [];\n\n const specifiers = new Set<string>();\n\n walk(root.body, (node) => {\n if (node.type !== 'JSXOpeningElement') return;\n\n const element = node as unknown as { attributes?: unknown; name?: unknown };\n\n if (!hasClientDirective(element.attributes)) return;\n\n const rootName = tagRootIdentifier(element.name);\n\n if (!rootName || /^[a-z]/.test(rootName)) return;\n\n const specifier = imports.get(rootName);\n\n if (specifier && !specifier.endsWith('.astro')) {\n specifiers.add(specifier);\n }\n });\n\n return [...specifiers];\n}\n\n/** scan all `.astro` files under `srcDir` for hydrated components */\nexport async function scanProjectIslands(srcDir: string, logger: Logger): Promise<IslandImport[]> {\n const islands: IslandImport[] = [];\n\n let entries: fs.Dirent[];\n\n try {\n entries = await fs.promises.readdir(srcDir, { recursive: true, withFileTypes: true });\n } catch {\n return islands;\n }\n\n const files = entries\n .filter((entry) => entry.isFile() && entry.name.endsWith('.astro'))\n .map((entry) => path.join(entry.parentPath, entry.name));\n\n await Promise.all(\n files.map(async (file) => {\n try {\n const source = await fs.promises.readFile(file, 'utf8');\n\n for (const specifier of scanAstroSource(source)) {\n islands.push({ importer: file, specifier });\n }\n } catch (error) {\n // a file mid-edit or unreadable must not break the dev server\n logger.debug(`island scan skipped ${file}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }),\n );\n\n return islands;\n}\n\nfunction packageNameOf(specifier: string): string {\n const segments = specifier.split('/');\n\n return specifier.startsWith('@') ? segments.slice(0, 2).join('/') : (segments[0] ?? specifier);\n}\n\n/**\n * Bare package specifiers resolvable from the project's `node_modules` — these\n * go into `optimizeDeps.include`. Anything else (relative paths, tsconfig\n * aliases, hoisted workspace deps) is resolved through vite at server start;\n * misclassification is harmless, just slightly later discovery.\n */\nexport function selectBareSpecifiers(islands: IslandImport[], root: string): string[] {\n const bare = new Set<string>();\n\n for (const { specifier } of islands) {\n if (specifier.startsWith('.') || specifier.startsWith('/') || specifier.startsWith('#')) continue;\n\n if (fs.existsSync(path.join(root, 'node_modules', packageNameOf(specifier)))) {\n bare.add(specifier);\n }\n }\n\n return [...bare];\n}\n\nfunction toRequestUrl(id: string, root: string): string {\n const normalized = id.split(path.sep).join('/');\n const normalizedRoot = root.split(path.sep).join('/');\n\n return normalized.startsWith(`${normalizedRoot}/`) ? normalized.slice(normalizedRoot.length) : `/@fs/${normalized}`;\n}\n\nexport interface IslandWarmupOptions {\n root: string;\n srcDir: string;\n logger: Logger;\n}\n\nexport function createIslandWarmup(options: IslandWarmupOptions): Plugin {\n const { root, srcDir, logger } = options;\n\n let islands: IslandImport[] = [];\n\n const warmIslands = async (server: ViteDevServer, batch: IslandImport[], warmed: Set<string>): Promise<void> => {\n const env = server.environments.client;\n\n await Promise.all(\n batch.map(async ({ importer, specifier }) => {\n try {\n // resolving through vite also registers still-unknown bare deps with\n // the optimizer — discovery happens now, not at hydration time\n const resolved = await env.pluginContainer.resolveId(specifier, importer);\n\n if (!resolved || resolved.external) return;\n if (resolved.id.startsWith('\\0') || resolved.id.includes('node_modules')) return;\n if (warmed.has(resolved.id)) return;\n\n warmed.add(resolved.id);\n\n await env.warmupRequest(toRequestUrl(resolved.id, root));\n } catch {\n // warmup is best-effort; a broken component surfaces on request anyway\n }\n }),\n );\n };\n\n return {\n name: '@astroscope/node/island-warmup',\n\n async config() {\n islands = await scanProjectIslands(srcDir, logger);\n\n const include = selectBareSpecifiers(islands, root);\n\n if (islands.length > 0) {\n logger.info(`warming ${islands.length} island(s), pre-optimizing ${include.length} dependenc(ies)`);\n }\n\n return include.length > 0 ? { optimizeDeps: { include } } : undefined;\n },\n\n configureServer(server) {\n const warmed = new Set<string>();\n\n // the plugin container is not initialized until the server starts\n // listening — mirror vite's own warmup timing\n if (server.httpServer) {\n server.httpServer.once('listening', () => void warmIslands(server, islands, warmed));\n } else {\n void warmIslands(server, islands, warmed);\n }\n\n // islands added mid-session get discovered at save time instead of at\n // page load; new bare deps still re-optimize, but before hydration\n const onWatcherEvent = (file: string): void => {\n if (!file.endsWith('.astro') || !file.startsWith(srcDir)) return;\n\n void fs.promises\n .readFile(file, 'utf8')\n .then((source) => {\n const batch = scanAstroSource(source).map((specifier) => ({ importer: file, specifier }));\n\n return warmIslands(server, batch, warmed);\n })\n .catch(() => {});\n };\n\n server.watcher.on('add', onWatcherEvent);\n server.watcher.on('change', onWatcherEvent);\n },\n };\n}\n","export function serializeError(error: unknown): string {\n if (error instanceof Error) {\n return error.stack ?? error.message;\n }\n\n return JSON.stringify(error);\n}\n","import path from 'node:path';\nimport type { ViteDevServer } from 'vite';\nimport { serializeError } from './serialize-error.js';\n\ntype Logger = { info(msg: string): void; error(msg: string): void };\n\nconst FULL_RELOAD_UNKNOWN = '<unknown>';\n\n/**\n * Coordinates dev-server restarts: debounces bursts, chains a follow-up if\n * changes arrive mid-restart (vite's `ssrImport` reads disk at import time,\n * so changes during a restart would otherwise be missed), and logs once per\n * restart with what triggered it.\n *\n * One instance per integration, shared across restart-induced configureServer\n * reruns — chain coordination would be lost if recreated each time.\n */\nexport class RestartScheduler {\n private _inFlight = false;\n private _pending = false;\n private _debounceTimer: ReturnType<typeof setTimeout> | undefined;\n private _pendingBootDeps = new Set<string>();\n private _pendingFullReloads = new Set<string>();\n // set while a restart chain is running. the gate probes it (`isRestartPending`)\n // to short-circuit requests, and awaits it (`waitForRestart`) on readiness.\n private _runPromise: Promise<void> | undefined;\n // set when a restart attempt fails\n private _lastFailure: { message: string } | undefined;\n\n constructor(\n private readonly debounceMs: number,\n private readonly logger: Logger,\n ) {}\n\n // true from the moment a change is queued until the restart completes — covers\n // the debounce window too, so requests don't slip past the gate before _run starts.\n isRestartPending(): boolean {\n return !!this._runPromise || !!this._debounceTimer || !!this._lastFailure;\n }\n\n getLastFailure(): { message: string } | undefined {\n return this._lastFailure;\n }\n\n recordFailure(message: string): void {\n this._lastFailure = { message };\n }\n\n clearFailure(): void {\n this._lastFailure = undefined;\n }\n\n schedule(server: ViteDevServer, changedPath: string): void {\n this._pendingBootDeps.add(changedPath);\n this._scheduleRun(server);\n }\n\n scheduleFullReload(server: ViteDevServer, triggeredBy?: string): void {\n this._pendingFullReloads.add(triggeredBy ?? FULL_RELOAD_UNKNOWN);\n this._scheduleRun(server);\n }\n\n /**\n * Resolves when no restart is running. Loops to handle back-to-back restarts\n * (e.g. one chain ends and a queued debounce timer immediately fires a new\n * one). Never rejects, so a failed restart still releases the gate — caller\n * proceeds against the broken state rather than hanging forever.\n */\n async waitForRestart(): Promise<void> {\n while (this._runPromise) {\n try {\n await this._runPromise;\n } catch {\n // restart failed — release anyway\n }\n }\n }\n\n private _scheduleRun(server: ViteDevServer): void {\n clearTimeout(this._debounceTimer);\n this._debounceTimer = setTimeout(() => {\n this._debounceTimer = undefined;\n void this._run(server);\n }, this.debounceMs);\n }\n\n private async _run(server: ViteDevServer): Promise<void> {\n if (this._inFlight) {\n // loop driving the in-flight restart will pick up the next iteration.\n this._pending = true;\n\n return;\n }\n\n this._inFlight = true;\n\n let resolveRun!: () => void;\n\n this._runPromise = new Promise<void>((resolve) => {\n resolveRun = resolve;\n });\n\n try {\n do {\n this._pending = false;\n\n const bootDeps = [...this._pendingBootDeps].sort();\n const fullReloads = [...this._pendingFullReloads].sort();\n\n this._pendingBootDeps.clear();\n this._pendingFullReloads.clear();\n\n if (bootDeps.length > 0 || fullReloads.length > 0) {\n this.logger.info(this._formatReason(server, bootDeps, fullReloads));\n }\n\n try {\n await server.restart();\n } catch (error) {\n this.logger.error(`error during dev server restart: ${serializeError(error)}`);\n }\n } while (this._pending);\n } finally {\n this._inFlight = false;\n this._runPromise = undefined;\n resolveRun();\n }\n }\n\n private _formatReason(server: ViteDevServer, bootDeps: string[], fullReloads: string[]): string {\n const root = server.config.root;\n const rel = (p: string): string => path.relative(root, p) || p;\n const parts: string[] = [];\n\n if (bootDeps.length === 1) {\n parts.push(`boot dep changed: ${rel(bootDeps[0]!)}`);\n } else if (bootDeps.length > 1) {\n parts.push(`boot deps changed (${bootDeps.length}): ${bootDeps.map(rel).join(', ')}`);\n }\n\n if (fullReloads.length > 0) {\n const named = fullReloads.filter((p) => p !== FULL_RELOAD_UNKNOWN);\n\n if (named.length === 0) {\n parts.push('vite SSR full-reload');\n } else {\n parts.push(`vite SSR full-reload (triggered by ${named.map(rel).join(', ')})`);\n }\n }\n\n return `${parts.join(' + ')} — restarting dev server`;\n }\n}\n","import type { DevEnvironment, ViteDevServer } from 'vite';\n\ntype RunnableEnv = DevEnvironment & { runner: { import: (id: string) => Promise<unknown> } };\n\n/**\n * duck-typed runnable-env check. avoids `isRunnableDevEnvironment` which relies on\n * `instanceof RunnableDevEnvironment` — that breaks when the consumer and vite host\n * resolve to different vite installs (e.g. linked packages outside the workspace).\n */\nfunction isRunnable(env: DevEnvironment | undefined): env is RunnableEnv {\n return (\n !!env &&\n typeof (env as { runner?: unknown }).runner === 'object' &&\n typeof (env as RunnableEnv).runner.import === 'function'\n );\n}\n\n/**\n * resolve a runnable dev environment — prefers `ssr`, falls back to `astro`.\n * astro 6 exposes a separate `astro` environment when `ssr` isn't runnable\n * (see astro/core/constants.ts ASTRO_VITE_ENVIRONMENT_NAMES).\n */\nfunction getRunnableEnv(server: ViteDevServer): RunnableEnv {\n const ssr = server.environments['ssr'];\n\n if (isRunnable(ssr)) return ssr;\n\n const astro = server.environments['astro'];\n\n if (isRunnable(astro)) return astro;\n\n const names = Object.keys(server.environments);\n\n throw new Error(`no runnable dev environment found — available: ${names.join(', ')}`);\n}\n\n/**\n * load a module via the Vite Environment API.\n */\nexport async function ssrImport<T = Record<string, unknown>>(server: ViteDevServer, moduleId: string): Promise<T> {\n return getRunnableEnv(server).runner.import(moduleId) as Promise<T>;\n}\n\n/**\n * return the env whose `hot` channel should receive astro-targeted events.\n * astro listens on the env that backs its middleware runner.\n */\nexport function getAstroHotEnv(server: ViteDevServer): DevEnvironment | undefined {\n const ssr = server.environments['ssr'];\n\n if (isRunnable(ssr)) return ssr;\n\n const astro = server.environments['astro'];\n\n if (isRunnable(astro)) return astro;\n\n return undefined;\n}\n","export const ignoredSuffixes = [\n // type definitions\n '.d.ts',\n '.d.mts',\n '.d.cts',\n // images\n '.png',\n '.jpg',\n '.jpeg',\n '.gif',\n '.svg',\n '.webp',\n '.avif',\n '.ico',\n // fonts\n '.woff',\n '.woff2',\n '.ttf',\n '.otf',\n '.eot',\n // other static assets\n '.pdf',\n '.mp3',\n '.mp4',\n '.webm',\n '.ogg',\n '.wav',\n // data/config that boot typically doesn't import\n '.json',\n '.yaml',\n '.yml',\n '.toml',\n '.md',\n '.mdx',\n '.txt',\n // styles (handled by Vite's CSS HMR)\n '.css',\n '.scss',\n '.sass',\n '.less',\n];\n","import type { EventEmitter } from 'node:events';\nimport { readFileSync } from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { HotPayload, ViteDevServer } from 'vite';\nimport { GEN_HEADER, getCurrentGeneration } from './generation.js';\nimport { ignoredSuffixes } from './ignored.js';\nimport type { RestartScheduler } from './scheduler.js';\nimport { getAstroHotEnv } from './vite-env.js';\n\nconst RESTART_HTML = readFileSync(fileURLToPath(new URL('./restart-page.html', import.meta.url)), 'utf8');\n\nexport function setupBootWatch(server: ViteDevServer, entries: string[], scheduler: RestartScheduler): void {\n const entryFilePaths = entries.map((entry) => path.resolve(server.config.root, entry));\n\n const runnableEnv = getAstroHotEnv(server);\n const bootModuleGraph = runnableEnv?.moduleGraph;\n\n const collectBootDependencies = (): Set<string> => {\n const deps = new Set<string>();\n const seen = new Set<string>();\n\n for (const entryFilePath of entryFilePaths) {\n const entryModules = bootModuleGraph?.getModulesByFile(entryFilePath);\n const entryModule = entryModules ? [...entryModules][0] : undefined;\n\n if (!entryModule) continue;\n\n const visit = (mod: typeof entryModule): void => {\n if (!mod?.file || seen.has(mod.file)) return;\n\n seen.add(mod.file);\n deps.add(mod.file);\n\n for (const imp of mod.importedModules) visit(imp);\n };\n\n visit(entryModule);\n }\n\n return deps;\n };\n\n const shouldIgnore = (filePath: string): boolean => {\n const p = filePath.toLowerCase();\n\n return ignoredSuffixes.some((suffix) => p.endsWith(suffix));\n };\n\n const onWatcherEvent = (changedPath: string): void => {\n if (shouldIgnore(changedPath)) return;\n\n const bootDeps = collectBootDependencies();\n\n if (!bootDeps.has(changedPath)) return;\n\n scheduler.schedule(server, changedPath);\n };\n\n server.watcher.on('change', onWatcherEvent);\n server.watcher.on('add', onWatcherEvent);\n server.watcher.on('unlink', onWatcherEvent);\n\n // ignore full-reloads emitted during server startup (dep optimization, port retries).\n let handleFullReloads = false;\n\n if (server.httpServer) {\n server.httpServer.once('listening', () => {\n handleFullReloads = true;\n });\n } else {\n // middleware mode — no httpServer, enable immediately\n handleFullReloads = true;\n }\n\n // SSR full-reloads come through the runnable env's hot channel and clear\n // its module runner's cache — onStartup needs to run again on a fresh server.\n const outsideEmitter = (runnableEnv?.hot as { api?: { outsideEmitter?: EventEmitter } } | undefined)?.api\n ?.outsideEmitter;\n\n if (outsideEmitter) {\n outsideEmitter.on('send', (payload: HotPayload) => {\n if (!handleFullReloads) return;\n if (payload.type !== 'full-reload') return;\n\n const triggeredBy = 'triggeredBy' in payload ? (payload.triggeredBy as string) : undefined;\n\n scheduler.scheduleFullReload(server, triggeredBy);\n });\n }\n}\n\nconst READINESS_PATH = '/__astroscope_boot_ready';\n\n/**\n * Gate requests: show 503 holding page during restart, readiness probe for the reload.\n */\nexport function installBootGate(\n server: Pick<ViteDevServer, 'middlewares'>,\n scheduler: Pick<RestartScheduler, 'waitForRestart' | 'isRestartPending' | 'getLastFailure'>,\n): void {\n const middlewares = server.middlewares as unknown as {\n stack: { route: string; handle: unknown }[];\n };\n\n // must be `stack.unshift`ed to land before astro's handler\n middlewares.stack.unshift({\n route: '',\n handle: (async (\n req: { url?: string },\n res: {\n writeHead: (status: number, headers: Record<string, string>) => void;\n end: (body?: string) => void;\n headersSent?: boolean;\n },\n next: (err?: unknown) => void,\n ) => {\n // readiness probe: holding page polls this. blocks until no restart is in\n // flight, then 204 on success / 503 + JSON error if last attempt failed.\n if (req.url === READINESS_PATH) {\n await scheduler.waitForRestart();\n\n if (res.headersSent) return;\n\n const failure = scheduler.getLastFailure();\n\n if (failure) {\n res.writeHead(503, { 'cache-control': 'no-store', 'content-type': 'application/json' });\n res.end(JSON.stringify({ error: failure.message }));\n\n return;\n }\n\n res.writeHead(204, { 'cache-control': 'no-store' });\n res.end();\n\n return;\n }\n\n if (isDevInternalPath(req.url)) {\n next();\n\n return;\n }\n\n // respond now; awaiting the restart would let vite destroy the socket mid-response.\n if (scheduler.isRestartPending()) {\n res.writeHead(503, {\n 'content-type': 'text/html; charset=utf-8',\n 'cache-control': 'no-store',\n 'retry-after': '1',\n });\n res.end(RESTART_HTML);\n\n return;\n }\n\n next();\n }) as never,\n });\n}\n\nfunction isDevInternalPath(url: string | undefined): boolean {\n if (!url) return false;\n\n return url.startsWith('/@') || url.startsWith('/__') || url.includes('/node_modules/');\n}\n\n/**\n * Stamp the current generation onto every incoming request so the runtime\n * Astro middleware can later detect whether the request belongs to a previous\n * (now torn-down) generation\n */\nexport function installGenStamp(server: Pick<ViteDevServer, 'middlewares'>): void {\n const middlewares = server.middlewares as unknown as {\n stack: { route: string; handle: unknown }[];\n };\n\n middlewares.stack.unshift({\n route: '',\n handle: ((req: { headers: Record<string, string> }, _res: unknown, next: () => void) => {\n req.headers[GEN_HEADER] = String(getCurrentGeneration());\n next();\n }) as never,\n });\n}\n","import type { AstroConfig } from 'astro';\nimport type { Plugin } from 'vite';\nimport { setBootContext } from '../lifecycle/context.js';\nimport { type BootModule, runShutdown, runStartup } from '../lifecycle/lifecycle.js';\nimport type { BootContext } from '../lifecycle/types.js';\nimport { clearNativeMounts } from '../server/native-mount.js';\nimport { incrementGeneration } from './generation.js';\nimport { RestartScheduler } from './scheduler.js';\nimport { serializeError } from './serialize-error.js';\nimport { ssrImport } from './vite-env.js';\nimport { installBootGate, installGenStamp, setupBootWatch } from './watch.js';\n\ninterface Logger {\n info(msg: string): void;\n warn(msg: string): void;\n error(msg: string): void;\n}\n\nexport interface DevMachineryOptions {\n /** boot file path relative to the project root; undefined = no boot module */\n entry: string | undefined;\n /** restart the dev server when watched dependencies change */\n watch: boolean;\n /** extra files (relative to the root) whose changes restart the dev server */\n watchEntries: string[];\n /** platform seams; runs each generation before the boot module starts */\n prepare: (importModule: <T = Record<string, unknown>>(id: string) => Promise<T>) => Promise<void>;\n logger: Logger;\n getConfig: () => AstroConfig | null;\n}\n\n/**\n * Resolve the default host and port from the Astro server config.\n * Falls back to `localhost:4321` when no config is provided.\n */\nfunction getServerDefaults(config: AstroConfig | null): { host: string; port: number } {\n return {\n host:\n typeof config?.server?.host === 'string'\n ? config.server.host\n : config?.server?.host === true\n ? '0.0.0.0'\n : 'localhost',\n port: config?.server?.port ?? 4321,\n };\n}\n\n/**\n * Build a dev-mode boot context from the running server's address,\n * falling back to Astro config defaults if the server isn't listening yet.\n */\nfunction resolveBootContext(\n server: { httpServer?: { address(): unknown } | null | undefined },\n config: AstroConfig | null,\n): BootContext {\n const addr = server.httpServer?.address();\n\n if (addr && typeof addr === 'object' && 'address' in addr && 'port' in addr) {\n const host =\n (addr as { address: string }).address === '::' || (addr as { address: string }).address === '0.0.0.0'\n ? 'localhost'\n : (addr as { address: string }).address;\n\n return { dev: true, host, port: (addr as { port: number }).port };\n }\n\n const { host, port } = getServerDefaults(config);\n\n return { dev: true, host, port };\n}\n\n/**\n * The dev-mode boot machinery: runs the platform seams and the boot lifecycle\n * per restart generation, restarts the dev server when watched dependencies\n * change, and gates requests behind a holding page during restarts.\n */\nexport function createDevMachinery(options: DevMachineryOptions): Plugin[] {\n const { entry, logger } = options;\n\n let hasStartupSucceededOnce = false;\n // run by the next configureServer before its startup so resources (ports,\n // sockets, locks) from the previous module are released first. idempotent.\n let priorShutdown: (() => Promise<void>) | undefined;\n // shared across restart-induced configureServer reruns\n const scheduler = options.watch ? new RestartScheduler(100, logger) : undefined;\n\n return [\n // gate plugin: enforce 'post' + returned-function so our `stack.unshift`\n // (in installBootGate / installGenStamp) lands at connect position 0,\n // ahead of astro's handler.\n {\n name: '@astroscope/node/dev-gate',\n enforce: 'post',\n\n configureServer(server) {\n if (!scheduler) return;\n\n return () => {\n // gen-stamp is unshifted last so it ends up at position 0:\n // every request gets a generation header before anything else,\n // including the gate's readiness probe.\n installBootGate(server, scheduler);\n installGenStamp(server);\n };\n },\n },\n\n // startup plugin: runs after all other configureServer hooks\n {\n name: '@astroscope/node/dev-startup',\n enforce: 'post',\n\n async configureServer(server) {\n incrementGeneration();\n\n // tear down the previous module first so its resources are released\n // before the new startup tries to claim them.\n if (priorShutdown) {\n await priorShutdown();\n priorShutdown = undefined;\n }\n\n const astroConfig = options.getConfig();\n const bootContext = resolveBootContext(server, astroConfig);\n let bootModule: BootModule | undefined;\n\n setBootContext(bootContext);\n\n try {\n await options.prepare((id) => ssrImport(server, id));\n\n bootModule = entry ? await ssrImport<BootModule>(server, `/${entry}`) : {};\n\n await runStartup(bootModule, bootContext);\n } catch (error) {\n logger.error(`Error running startup script: ${serializeError(error)}`);\n\n if (bootModule) {\n try {\n await runShutdown(bootModule, bootContext);\n } catch {\n // best-effort cleanup\n }\n }\n\n // restart failure: the gate can keep the holding\n // page up with an error message instead of dropping users onto a\n // half-broken old server.\n if (hasStartupSucceededOnce) {\n scheduler?.recordFailure(serializeError(error));\n\n throw error;\n }\n\n // initial failure: exit cleanly (mirrors the production server).\n process.exit(1);\n }\n\n hasStartupSucceededOnce = true;\n scheduler?.clearFailure();\n\n // capture so shutdown sees the same instance that started.\n const startedModule = bootModule;\n let shutdownDone = false;\n\n const shutdown = async (): Promise<void> => {\n if (shutdownDone) return;\n\n shutdownDone = true;\n\n try {\n await runShutdown(startedModule, resolveBootContext(server, options.getConfig()));\n } catch (error) {\n logger.error(`Error running shutdown script: ${serializeError(error)}`);\n }\n\n // the next generation's onStartup re-registers its mounts\n clearNativeMounts();\n };\n\n priorShutdown = shutdown;\n\n // sigint/sigterm path. also fires during restart but shutdown is idempotent.\n server.httpServer?.once('close', () => {\n void shutdown();\n });\n\n if (scheduler) {\n setupBootWatch(server, [...(entry ? [entry] : []), ...options.watchEntries], scheduler);\n }\n },\n },\n ];\n}\n","import type { ExcludePattern } from './excludes.js';\n\n/**\n * Serialize exclude patterns to JavaScript code for use in virtual modules.\n * Handles RegExp objects which JSON.stringify cannot serialize.\n */\nexport function serializeExcludePatterns(patterns: ExcludePattern[]): string {\n return `[${patterns.map((p) => ('pattern' in p ? `{ pattern: ${p.pattern.toString()} }` : JSON.stringify(p))).join(', ')}]`;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport type { Plugin } from 'vite';\nimport type { IslandsManifest } from './types.js';\n\nexport const ISLANDS_VIRTUAL_MODULE_ID = 'virtual:@astroscope/node/islands-manifest';\n\nconst RESOLVED_ISLANDS_VIRTUAL_MODULE_ID = `\\0${ISLANDS_VIRTUAL_MODULE_ID}`;\n\nconst MANIFEST_FILE_NAME = 'islands-manifest.json';\n\nexport type IslandsManifestPluginOptions = {\n logger: { warn: (message: string) => void };\n /** `islands: false` disables the preloading — no manifest is written and the virtual module resolves to null */\n enabled: boolean;\n};\n\n/**\n * Client-build side of island preloading: records the chunk import graph (direct\n * static and dynamic edges per chunk), embeds the gate runtime source, and drops\n * the manifest next to the server chunks — where the virtual module reads it back\n * at runtime, mirroring the i18n manifest. The runtime is inlined into documents\n * rather than shipped as an asset: an external module fetch would install the\n * gates a round-trip after astro's own inline island machinery, losing the race\n * it exists to win.\n *\n * The client build runs after the server build, so the SSR bundle can only carry\n * code that reads the file lazily; in dev there is no manifest and the middleware\n * stays inert.\n */\nexport function createIslandsManifestPlugin(options: IslandsManifestPluginOptions): Plugin {\n let isBuild = false;\n\n return {\n name: '@astroscope/node/islands-manifest',\n\n configResolved(config) {\n isBuild = config.command === 'build';\n },\n\n resolveId(id) {\n if (id === ISLANDS_VIRTUAL_MODULE_ID) return RESOLVED_ISLANDS_VIRTUAL_MODULE_ID;\n },\n\n load(id) {\n if (id !== RESOLVED_ISLANDS_VIRTUAL_MODULE_ID) return;\n\n if (!isBuild || !options.enabled) {\n return 'export const manifest = null;';\n }\n\n // the manifest only exists after the client build — read it at runtime. astro\n // bundles middleware at the server root and service code under chunks/, so\n // probe both relative to wherever this module ended up\n return `\nimport { readFileSync } from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\n\nconst dir = dirname(fileURLToPath(import.meta.url));\n\nlet manifest = null;\n\nfor (const candidate of [\n join(dir, '${MANIFEST_FILE_NAME}'),\n join(dir, 'chunks', '${MANIFEST_FILE_NAME}'),\n join(dir, '..', 'chunks', '${MANIFEST_FILE_NAME}'),\n]) {\n try {\n manifest = JSON.parse(readFileSync(candidate, 'utf-8'));\n break;\n } catch {\n manifest = null;\n }\n}\n\nexport { manifest };\n`;\n },\n\n writeBundle(outputOptions, bundle) {\n if (!options.enabled || this.environment.name !== 'client' || !outputOptions.dir) return;\n\n const chunks: IslandsManifest['chunks'] = {};\n\n for (const chunk of Object.values(bundle)) {\n if (chunk.type !== 'chunk') continue;\n\n chunks[chunk.fileName] = {\n ...(chunk.imports.length > 0 && { i: chunk.imports }),\n ...(chunk.dynamicImports.length > 0 && { d: chunk.dynamicImports }),\n };\n }\n\n const runtimeSource = fs.readFileSync(new URL('./islands-runtime.iife.js', import.meta.url), 'utf-8').trim();\n\n // the source goes verbatim into an inline script tag — a stray closing\n // sequence would truncate every page carrying deferred islands\n if (runtimeSource.toLowerCase().includes('</script')) {\n throw new Error('islands gate runtime must not contain \"</script\"');\n }\n\n const manifest: IslandsManifest = { runtimeSource, chunks };\n const chunksDir = path.resolve(outputOptions.dir, '..', 'server', 'chunks');\n\n if (fs.existsSync(chunksDir)) {\n fs.writeFileSync(path.join(chunksDir, MANIFEST_FILE_NAME), JSON.stringify(manifest));\n } else {\n options.logger.warn(`server chunks directory not found, cannot write manifest to ${chunksDir}`);\n }\n },\n };\n}\n","import type { Plugin } from 'vite';\n\n/**\n * emit sourcemaps only for the SSR build. client bundles are left unmapped\n * so browsers can't fetch source via `//# sourceMappingURL=`.\n *\n * vite 7's `environments.ssr.build.sourcemap` looks cleaner but wholesale\n * replaces astro's SSR build defaults (including entry file naming), which\n * breaks the embedded dev boot machinery. using `isSsrBuild` keeps the\n * rest of astro's SSR config intact.\n */\nexport function ssrSourcemapPlugin(): Plugin {\n return {\n name: '@astroscope/node/tweaks/sourcemap',\n config(_config, { isSsrBuild }) {\n if (isSsrBuild) return { build: { sourcemap: true } };\n\n return {};\n },\n };\n}\n","import { Parser } from 'acorn';\nimport MagicString from 'magic-string';\nimport type { Plugin } from 'vite';\n\nconst HOOK_NAMES = new Set(['useEffect', 'useLayoutEffect', 'useInsertionEffect']);\nconst REACT_SOURCE = /^react(\\/.*)?$/;\nconst TRANSFORMABLE = /\\.(?:[mc]?[jt]sx?)$/;\nconst EMPTY_FN = '(()=>{})';\n\n/**\n * in SSR builds, react effect hooks never execute. emptying their callbacks\n * lets rolldown drop dead branches — including dynamic imports of client-only\n * libs (maplibre-gl, hls.js, etc.) — from the server bundle, which in turn\n * stops nft from tracing them at docker-image time.\n *\n * scope is deliberately narrow: first-party code only (no node_modules), only\n * in the SSR pass, and binding-aware (the React import must resolve to the\n * real react package). raw chunks where bundling has erased the binding are\n * left alone — that's NFT's domain, not ours.\n */\nexport function stripSsrEffectsPlugin(): Plugin {\n return {\n name: '@astroscope/node/tweaks/strip-effects',\n enforce: 'post',\n transform(code, id, options) {\n if (!options?.ssr) return null;\n if (id.includes('/node_modules/')) return null;\n\n const cleanId = id.split('?')[0] ?? id;\n\n if (!TRANSFORMABLE.test(cleanId)) return null;\n if (!code.includes('useEffect') && !code.includes('useLayoutEffect') && !code.includes('useInsertionEffect')) {\n return null;\n }\n\n let ast: any;\n\n try {\n ast = Parser.parse(code, {\n ecmaVersion: 'latest',\n sourceType: 'module',\n allowReturnOutsideFunction: true,\n allowAwaitOutsideFunction: true,\n allowImportExportEverywhere: true,\n allowHashBang: true,\n });\n } catch {\n return null;\n }\n\n const directHooks = new Set<string>();\n const namespaceHooks = new Set<string>();\n\n walk(ast, (node) => {\n if (node.type !== 'ImportDeclaration') return;\n\n const src = node.source?.value;\n\n if (typeof src !== 'string' || !REACT_SOURCE.test(src)) return;\n\n for (const spec of node.specifiers ?? []) {\n if (spec.type === 'ImportSpecifier') {\n const imported = spec.imported?.name ?? spec.imported?.value;\n\n if (HOOK_NAMES.has(imported)) directHooks.add(spec.local.name);\n } else if (spec.type === 'ImportDefaultSpecifier' || spec.type === 'ImportNamespaceSpecifier') {\n namespaceHooks.add(spec.local.name);\n }\n }\n });\n\n if (directHooks.size === 0 && namespaceHooks.size === 0) return null;\n\n const replacements: { start: number; end: number }[] = [];\n\n walk(ast, (node) => {\n if (node.type !== 'CallExpression' || !node.arguments?.length) return;\n\n const callee = node.callee;\n const isDirect = callee.type === 'Identifier' && directHooks.has(callee.name);\n const isMember =\n callee.type === 'MemberExpression' &&\n !callee.computed &&\n callee.object?.type === 'Identifier' &&\n namespaceHooks.has(callee.object.name) &&\n callee.property?.type === 'Identifier' &&\n HOOK_NAMES.has(callee.property.name);\n\n if (!isDirect && !isMember) return;\n\n const arg = node.arguments[0];\n\n replacements.push({ start: arg.start, end: arg.end });\n });\n\n if (replacements.length === 0) return null;\n\n const s = new MagicString(code);\n\n for (const { start, end } of replacements) {\n s.overwrite(start, end, EMPTY_FN);\n }\n\n return { code: s.toString(), map: s.generateMap({ hires: true }).toString() };\n },\n };\n}\n\nfunction walk(node: any, visit: (n: any) => void): void {\n if (!node || typeof node !== 'object') return;\n\n if (typeof node.type === 'string') visit(node);\n\n for (const key of Object.keys(node)) {\n const v = node[key];\n\n if (Array.isArray(v)) for (const item of v) walk(item, visit);\n else if (v && typeof v === 'object') walk(v, visit);\n }\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { AstroConfig, AstroIntegration } from 'astro';\nimport { createIslandWarmup } from '../dev-mode/island-warmup.js';\nimport { createDevMachinery } from '../dev-mode/machinery.js';\nimport { type ExcludePattern, RECOMMENDED_EXCLUDES } from '../excludes/excludes.js';\nimport { serializeExcludePatterns } from '../excludes/serialize.js';\nimport { createIslandsManifestPlugin } from '../islands/manifest-plugin.js';\nimport type { IslandsManifest } from '../islands/types.js';\nimport { createRequestInstrumentation } from '../observability/instrument.js';\nimport { preparePlatform } from '../platform/prepare.js';\nimport { dispatchNativeMount } from '../server/native-mount.js';\nimport { ssrSourcemapPlugin } from '../tweaks/sourcemap.js';\nimport { stripSsrEffectsPlugin } from '../tweaks/strip-effects.js';\nimport type { NodeOptions, RuntimeOptions } from '../types.js';\n\nexport const CONFIG_VIRTUAL_MODULE_ID = 'virtual:@astroscope/node/config';\nexport const BOOT_VIRTUAL_MODULE_ID = 'virtual:@astroscope/node/boot';\nexport const CSRF_VIRTUAL_MODULE_ID = 'virtual:@astroscope/node/csrf';\nexport const CONFIG_ENTRY_VIRTUAL_MODULE_ID = 'virtual:@astroscope/node/config-entry';\nexport const INSTRUMENTATION_ENTRY_VIRTUAL_MODULE_ID = 'virtual:@astroscope/node/instrumentation-entry';\nexport const LOG_ENTRY_VIRTUAL_MODULE_ID = 'virtual:@astroscope/node/log-entry';\n\nconst RESOLVED_CONFIG_VIRTUAL_MODULE_ID = `\\0${CONFIG_VIRTUAL_MODULE_ID}`;\nconst RESOLVED_BOOT_VIRTUAL_MODULE_ID = `\\0${BOOT_VIRTUAL_MODULE_ID}`;\nconst RESOLVED_CSRF_VIRTUAL_MODULE_ID = `\\0${CSRF_VIRTUAL_MODULE_ID}`;\nconst RESOLVED_CONFIG_ENTRY_VIRTUAL_MODULE_ID = `\\0${CONFIG_ENTRY_VIRTUAL_MODULE_ID}`;\nconst RESOLVED_INSTRUMENTATION_ENTRY_VIRTUAL_MODULE_ID = `\\0${INSTRUMENTATION_ENTRY_VIRTUAL_MODULE_ID}`;\nconst RESOLVED_LOG_ENTRY_VIRTUAL_MODULE_ID = `\\0${LOG_ENTRY_VIRTUAL_MODULE_ID}`;\n\nconst SERVER_ENVIRONMENTS = ['ssr', 'prerender', 'astro'];\nconst DEFAULT_REQUEST_EXCLUDES: ExcludePattern[] = [...RECOMMENDED_EXCLUDES];\n\nfunction resolveHost(host: string | boolean | undefined): string {\n if (typeof host === 'string') return host;\n\n return host === true ? '0.0.0.0' : 'localhost';\n}\n\nfunction resolveBootEntry(root: string, entry: string | undefined): string | undefined {\n if (entry) {\n const abs = path.resolve(root, entry);\n\n if (!fs.existsSync(abs)) {\n throw new Error(`[@astroscope/node] boot entry not found: ${entry}`);\n }\n\n return abs;\n }\n\n for (const candidate of ['src/boot/index.ts', 'src/boot.ts']) {\n const abs = path.resolve(root, candidate);\n\n if (fs.existsSync(abs)) return abs;\n }\n\n return undefined;\n}\n\nfunction resolveSeam(root: string, candidate: string): string | undefined {\n const abs = path.resolve(root, candidate);\n\n return fs.existsSync(abs) ? abs : undefined;\n}\n\n/**\n * Node adapter for Astro with a first-class server entrypoint: the boot\n * lifecycle, module warmup, health probes, request logging and telemetry run\n * as plain code around `server.listen()` instead of being injected into the\n * build output.\n */\nexport default function node(options: NodeOptions = {}): AstroIntegration {\n const bootOptions = options.boot ?? {};\n const healthOptions = options.health ?? {};\n const csrfOptions = options.csrf ?? {};\n const islandsEnabled = options.islands !== false;\n const loggingOptions = options.logging ?? {};\n const telemetryOptions = options.telemetry ?? {};\n\n const loggingExclude = loggingOptions ? (loggingOptions.exclude ?? DEFAULT_REQUEST_EXCLUDES) : [];\n const telemetryExclude = telemetryOptions ? (telemetryOptions.exclude ?? DEFAULT_REQUEST_EXCLUDES) : [];\n\n let astroConfig: AstroConfig | null = null;\n let bootEntry: string | undefined;\n let configSeam: string | undefined;\n let instrumentationSeam: string | undefined;\n let logSeam: string | undefined;\n let isDev = false;\n\n return {\n name: '@astroscope/node',\n hooks: {\n 'astro:config:setup': ({ command, config, updateConfig, addMiddleware, logger }) => {\n isDev = command === 'dev';\n\n // route enrichment first so csrf-rejected requests still carry a route\n if (loggingOptions || telemetryOptions) {\n addMiddleware({ order: 'pre', entrypoint: '@astroscope/node/route-middleware' });\n }\n\n if (csrfOptions) {\n addMiddleware({ order: 'pre', entrypoint: '@astroscope/node/csrf-middleware' });\n }\n\n // registered after logging/csrf so its next() wraps the rendered response\n addMiddleware({ order: 'pre', entrypoint: '@astroscope/node/islands-middleware' });\n\n const root = fileURLToPath(config.root);\n const watch = bootOptions === false ? false : (bootOptions.watch ?? true);\n\n bootEntry = bootOptions === false ? undefined : resolveBootEntry(root, bootOptions.entry);\n configSeam = resolveSeam(root, 'src/config.ts');\n instrumentationSeam = resolveSeam(root, 'src/instrumentation.ts');\n logSeam = resolveSeam(root, 'src/log.ts');\n\n const relativeSeam = (abs: string | undefined) =>\n abs ? path.relative(root, abs).split(path.sep).join('/') : undefined;\n\n const devMachinery =\n command === 'dev' && bootOptions !== false\n ? createDevMachinery({\n entry: bootEntry ? path.relative(root, bootEntry) : undefined,\n watch,\n // instrumentation runs once per process — watching it would\n // restart generations that can't re-apply it\n watchEntries: [relativeSeam(configSeam), relativeSeam(logSeam)].filter(\n (entry): entry is string => !!entry,\n ),\n prepare: (importModule) =>\n preparePlatform({\n dev: true,\n telemetry:\n telemetryOptions && telemetryOptions.dev\n ? { prometheus: telemetryOptions.prometheus ?? {} }\n : false,\n seams: {\n ...(configSeam && { config: () => importModule(`/${relativeSeam(configSeam)}`) }),\n ...(instrumentationSeam && {\n instrumentation: () => importModule(`/${relativeSeam(instrumentationSeam)}`),\n }),\n ...(logSeam && { log: () => importModule(`/${relativeSeam(logSeam)}`) }),\n },\n }),\n logger,\n getConfig: () => astroConfig,\n })\n : [];\n\n if (command === 'dev' && bootOptions !== false && watch) {\n // catches errors thrown by stale (post-shutdown) requests so\n // they don't pollute the logs during dev-server restarts.\n addMiddleware({ entrypoint: '@astroscope/node/dev-middleware', order: 'pre' });\n }\n\n const islandWarmup =\n command === 'dev' ? [createIslandWarmup({ root, srcDir: fileURLToPath(config.srcDir), logger })] : [];\n\n const imageService = options.imageService ?? 'auto';\n const imageOff =\n imageService === 'off' ||\n (imageService === 'auto' && config.image.service.entrypoint === 'astro/assets/services/sharp');\n\n updateConfig({\n build: { redirects: false },\n // opinionated defaults: no trailing slashes, behind LB\n ...(config.trailingSlash === 'ignore' && { trailingSlash: 'never' as const }),\n security: {\n // assumed to run behind LB\n ...(!config.security.allowedDomains?.length && { allowedDomains: [{}] }),\n // the embedded csrf middleware replaces the built-in origin check\n ...(csrfOptions && { checkOrigin: false }),\n },\n image: {\n ...(imageOff && { service: { entrypoint: '@astroscope/node/image-service', config: {} } }),\n endpoint: {\n route: config.image.endpoint.route ?? '_image',\n entrypoint: imageOff\n ? '@astroscope/node/image-endpoint'\n : (config.image.endpoint.entrypoint ??\n (command === 'dev' ? 'astro/assets/endpoint/dev' : 'astro/assets/endpoint/node')),\n },\n },\n vite: {\n plugins: [\n ...devMachinery,\n ...islandWarmup,\n createIslandsManifestPlugin({ logger, enabled: islandsEnabled }),\n ssrSourcemapPlugin(),\n stripSsrEffectsPlugin(),\n {\n name: '@astroscope/node',\n\n configEnvironment(environmentName: string) {\n if (SERVER_ENVIRONMENTS.includes(environmentName)) {\n return { resolve: { noExternal: ['@astroscope/node'] } };\n }\n },\n\n resolveId(id: string) {\n if (id === CONFIG_VIRTUAL_MODULE_ID) return RESOLVED_CONFIG_VIRTUAL_MODULE_ID;\n if (id === BOOT_VIRTUAL_MODULE_ID) return RESOLVED_BOOT_VIRTUAL_MODULE_ID;\n if (id === CSRF_VIRTUAL_MODULE_ID) return RESOLVED_CSRF_VIRTUAL_MODULE_ID;\n if (id === CONFIG_ENTRY_VIRTUAL_MODULE_ID) return RESOLVED_CONFIG_ENTRY_VIRTUAL_MODULE_ID;\n if (id === INSTRUMENTATION_ENTRY_VIRTUAL_MODULE_ID) {\n return RESOLVED_INSTRUMENTATION_ENTRY_VIRTUAL_MODULE_ID;\n }\n if (id === LOG_ENTRY_VIRTUAL_MODULE_ID) return RESOLVED_LOG_ENTRY_VIRTUAL_MODULE_ID;\n },\n\n load(id: string) {\n if (id === RESOLVED_CONFIG_VIRTUAL_MODULE_ID) {\n if (!astroConfig) throw new Error('[@astroscope/node] astro config not resolved yet');\n\n const runtimeOptions: Omit<RuntimeOptions, 'logging' | 'telemetry'> = {\n host: resolveHost(astroConfig.server.host),\n port: astroConfig.server.port ?? 4321,\n client: astroConfig.build.client.toString(),\n server: astroConfig.build.server.toString(),\n bodySizeLimit: options.bodySizeLimit ?? 1024 * 1024 * 1024,\n shutdownTimeout: options.shutdownTimeout ?? 10_000,\n health: healthOptions\n ? {\n ...(healthOptions.host !== undefined && { host: healthOptions.host }),\n ...(healthOptions.port !== undefined && { port: healthOptions.port }),\n ...(healthOptions.paths && { paths: healthOptions.paths }),\n }\n : false,\n };\n\n // exclude patterns may contain RegExp — serialized as code, not JSON\n const logging = loggingOptions\n ? `{ exclude: ${serializeExcludePatterns(loggingExclude)}, extended: ${JSON.stringify(\n loggingOptions.extended ?? false,\n )} }`\n : 'false';\n const telemetry = telemetryOptions\n ? `{ exclude: ${serializeExcludePatterns(telemetryExclude)}, prometheus: ${JSON.stringify(\n telemetryOptions.prometheus ?? {},\n )} }`\n : 'false';\n\n return `export const options = { ...${JSON.stringify(runtimeOptions)}, logging: ${logging}, telemetry: ${telemetry} };`;\n }\n\n if (id === RESOLVED_BOOT_VIRTUAL_MODULE_ID) {\n // re-export to avoid absolute path manifest leaks\n return bootEntry ? `export * from ${JSON.stringify(bootEntry)};` : 'export {};';\n }\n\n if (id === RESOLVED_CSRF_VIRTUAL_MODULE_ID) {\n return `export const excludePatterns = ${serializeExcludePatterns(csrfOptions ? (csrfOptions.exclude ?? []) : [])};`;\n }\n\n if (id === RESOLVED_CONFIG_ENTRY_VIRTUAL_MODULE_ID) {\n // side-effect import: @entwico/zod-conf validation runs at module load\n return configSeam ? `import ${JSON.stringify(configSeam)};\\nexport {};` : 'export {};';\n }\n\n if (id === RESOLVED_INSTRUMENTATION_ENTRY_VIRTUAL_MODULE_ID) {\n return instrumentationSeam ? `export * from ${JSON.stringify(instrumentationSeam)};` : 'export {};';\n }\n\n if (id === RESOLVED_LOG_ENTRY_VIRTUAL_MODULE_ID) {\n return logSeam\n ? `export { default } from ${JSON.stringify(logSeam)};`\n : 'export default undefined;';\n }\n },\n },\n ],\n },\n });\n },\n 'astro:server:setup': ({ server }) => {\n if (!isDev) return;\n\n const devLogging = loggingOptions && loggingOptions.dev;\n const devTelemetry = telemetryOptions && telemetryOptions.dev;\n\n const instrument =\n devLogging || devTelemetry\n ? createRequestInstrumentation({\n logging: devLogging ? { exclude: loggingExclude, extended: loggingOptions.extended ?? false } : false,\n telemetry: devTelemetry ? { exclude: telemetryExclude } : false,\n })\n : undefined;\n\n server.middlewares.use((req, res, next) => {\n const inner = (): void => {\n if (!dispatchNativeMount(req, res)) next();\n };\n\n if (instrument) {\n instrument(req, res, inner);\n } else {\n inner();\n }\n });\n },\n 'astro:config:done': ({ config, setAdapter }) => {\n astroConfig = config;\n\n setAdapter({\n name: '@astroscope/node',\n entrypointResolution: 'auto',\n serverEntrypoint: '@astroscope/node/server',\n previewEntrypoint: '@astroscope/node/preview',\n adapterFeatures: {\n buildOutput: 'server',\n middlewareMode: 'classic',\n },\n supportedAstroFeatures: {\n hybridOutput: 'stable',\n staticOutput: 'stable',\n serverOutput: 'stable',\n sharpImageService: 'stable',\n i18nDomains: 'experimental',\n envGetSecret: 'stable',\n },\n });\n },\n 'astro:build:done': async ({ logger }) => {\n if (!astroConfig) return;\n\n if (islandsEnabled) {\n // prerendered pages never pass through the middleware — rewrite them on\n // disk before compression, from the manifest the client build just wrote\n const manifestPath = path.join(fileURLToPath(astroConfig.build.server), 'chunks', 'islands-manifest.json');\n\n if (fs.existsSync(manifestPath)) {\n const { transformPrerenderedHtml } = await import('../islands/prerendered.js');\n const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8')) as IslandsManifest;\n const transformed = await transformPrerenderedHtml(fileURLToPath(astroConfig.build.client), manifest);\n\n if (transformed > 0) {\n logger.info(`island preloading applied to ${transformed} prerendered page(s)`);\n }\n }\n }\n\n const { stripBuildPaths } = await import('../tweaks/strip-build-paths.js');\n const stripped = stripBuildPaths(fileURLToPath(astroConfig.build.server), fileURLToPath(astroConfig.root));\n\n if (stripped > 0) {\n logger.info(`build machine paths stripped from ${stripped} server file(s)`);\n }\n\n const { compressClientDir } = await import('../compress/compress.js');\n\n await compressClientDir(fileURLToPath(astroConfig.build.client), logger);\n },\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { n as log } from "./log-B69HEBvg.js";
|
|
2
2
|
import { t as getDocumentEmitters } from "./emitters-C20tjKLp.js";
|
|
3
3
|
import { t as getRequestRouteData } from "./route-store-DdxGePj2.js";
|
|
4
|
-
import { n as createPageTransformStream, t as createIslandsTransformer } from "./transform-
|
|
4
|
+
import { n as createPageTransformStream, t as createIslandsTransformer } from "./transform-BqV8SOEm.js";
|
|
5
5
|
import { manifest } from "virtual:@astroscope/node/islands-manifest";
|
|
6
6
|
//#region src/islands/middleware.ts
|
|
7
7
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(){let e=Symbol.for(`@astroscope/node.islandsRuntime`),t=globalThis,n=new Set,r=new Set,i=new Set,a=new Map,o;function s(e){for(let t of e){if(r.has(t))continue;r.add(t);let e=document.createElement(`link`);e.rel=`modulepreload`,e.setAttribute(`fetchpriority`,`low`),e.href=t,document.head.append(e)}}function c(e){if(n.has(e))return;n.add(e);let r=t.__islands__?.[e];if(!r)return;let a=Array.isArray(r)?r:r.l??[],o=Array.isArray(r)?[]:r.i??[];for(let e of o)i.has(e)||(i.add(e),import(e).catch(()=>void 0));s(a)}function l(e){try{return JSON.parse(e.getAttribute(`opts`)??``).value}catch{return}}function u(e,t){o??=new IntersectionObserver(e=>{for(let t of e)if(t.isIntersecting){let e=a.get(t.target);o.unobserve(t.target),a.delete(t.target),e&&c(e)}},{rootMargin:`100% 0px`}),a.set(e,t),o.observe(e)}function d(e){let r=e.getAttribute(`component-url`);if(!r||n.has(r)||!t.__islands__?.[r])return;let i=(e.getAttribute(`client`)??``).replace(/-x$/,``);if(i===`media`){let t=l(e);if(typeof t==`string`){let e=matchMedia(t);e.matches?c(r):e.addEventListener(`change`,()=>c(r),{once:!0});return}}if(i===`visible`){u(e,r);return}if(i===`load`||i===`only`){c(r);return}let a=l(e),o=typeof a==`object`&&a?a.timeout:void 0,s=()=>c(r);`requestIdleCallback`in window?requestIdleCallback(s,typeof o==`number`?{timeout:o}:void 0):setTimeout(s,typeof o==`number`?o:200)}function f(e){for(let t of e.querySelectorAll(`astro-island`))d(t)}t[e]||(t[e]=!0,f(document),new MutationObserver(e=>{for(let t of e)for(let e of t.addedNodes)e instanceof Element&&(e.localName===`astro-island`?d(e):f(e))}).observe(document.documentElement,{childList:!0,subtree:!0}))})();
|
package/dist/islands.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as DocumentEmission, c as IslandEmitter, i as registerIslandEmitter, l as IslandInfo, n as setRequestRouteData, o as DocumentEmitter, r as registerDocumentEmitter, s as IslandEmission, t as getRequestRouteData } from "./route-store-
|
|
1
|
+
import { a as DocumentEmission, c as IslandEmitter, i as registerIslandEmitter, l as IslandInfo, n as setRequestRouteData, o as DocumentEmitter, r as registerDocumentEmitter, s as IslandEmission, t as getRequestRouteData } from "./route-store-CSYR4G5e.js";
|
|
2
2
|
export { type DocumentEmission, type DocumentEmitter, type IslandEmission, type IslandEmitter, type IslandInfo, getRequestRouteData, registerDocumentEmitter, registerIslandEmitter, setRequestRouteData };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as createIslandsTransformer } from "./transform-
|
|
1
|
+
import { t as createIslandsTransformer } from "./transform-BqV8SOEm.js";
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
//#region src/islands/prerendered.ts
|
|
@@ -31,4 +31,4 @@ async function transformPrerenderedHtml(clientDir, manifest) {
|
|
|
31
31
|
//#endregion
|
|
32
32
|
export { transformPrerenderedHtml };
|
|
33
33
|
|
|
34
|
-
//# sourceMappingURL=prerendered-
|
|
34
|
+
//# sourceMappingURL=prerendered-DVjzWNbW.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prerendered-
|
|
1
|
+
{"version":3,"file":"prerendered-DVjzWNbW.js","names":[],"sources":["../src/islands/prerendered.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { createIslandsTransformer } from './transform.js';\nimport type { IslandsManifest } from './types.js';\n\nfunction* walkHtmlFiles(dir: string): Generator<string> {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const full = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n yield* walkHtmlFiles(full);\n } else if (entry.isFile() && entry.name.endsWith('.html')) {\n yield full;\n }\n }\n}\n\n/**\n * Prerendered pages never pass through the middleware — they get the same rewrite\n * once, at build time, before the client dir is compressed. Runs without a request\n * context, so registered emitters that need one contribute nothing here.\n */\nexport async function transformPrerenderedHtml(clientDir: string, manifest: IslandsManifest): Promise<number> {\n const transformer = createIslandsTransformer(manifest);\n let transformed = 0;\n\n for (const file of walkHtmlFiles(clientDir)) {\n const html = fs.readFileSync(file, 'utf-8');\n const rewriter = transformer.createDocumentRewriter();\n const result = rewriter.write(html) + (await rewriter.end());\n\n if (result !== html) {\n fs.writeFileSync(file, result);\n transformed++;\n }\n }\n\n return transformed;\n}\n"],"mappings":";;;;AAKA,UAAU,cAAc,KAAgC;CACtD,KAAK,MAAM,SAAS,GAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;EAChE,MAAM,OAAO,KAAK,KAAK,KAAK,MAAM,IAAI;EAEtC,IAAI,MAAM,YAAY,GACpB,OAAO,cAAc,IAAI;OACpB,IAAI,MAAM,OAAO,KAAK,MAAM,KAAK,SAAS,OAAO,GACtD,MAAM;CAEV;AACF;;;;;;AAOA,eAAsB,yBAAyB,WAAmB,UAA4C;CAC5G,MAAM,cAAc,yBAAyB,QAAQ;CACrD,IAAI,cAAc;CAElB,KAAK,MAAM,QAAQ,cAAc,SAAS,GAAG;EAC3C,MAAM,OAAO,GAAG,aAAa,MAAM,OAAO;EAC1C,MAAM,WAAW,YAAY,uBAAuB;EACpD,MAAM,SAAS,SAAS,MAAM,IAAI,IAAK,MAAM,SAAS,IAAI;EAE1D,IAAI,WAAW,MAAM;GACnB,GAAG,cAAc,MAAM,MAAM;GAC7B;EACF;CACF;CAEA,OAAO;AACT"}
|
|
@@ -19,12 +19,20 @@ type IslandInfo = {
|
|
|
19
19
|
* What an emitter contributes for one island. `links` are merged across emitters and
|
|
20
20
|
* either emitted as `<link rel="modulepreload">` tags (immediate directives) or
|
|
21
21
|
* registered on the preload global for the gate runtime (deferred directives).
|
|
22
|
-
* `
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* `imports` are data-module urls (safe to evaluate ahead of time, e.g. translation
|
|
23
|
+
* chunks) that the gate runtime eagerly `import()`s when a deferred island's
|
|
24
|
+
* directive fires — they land in the module loader cache so the component's own
|
|
25
|
+
* awaited import resolves instantly instead of fetching serially after the
|
|
26
|
+
* component graph evaluated; urls listed in both sets are registered as imports
|
|
27
|
+
* only. Immediate directives ignore `imports` — their hydration import fires right
|
|
28
|
+
* away and pulls the data modules itself. `html` is emitted right before the island
|
|
29
|
+
* tag regardless of directive — an inline script there is parsed strictly before
|
|
30
|
+
* the island connects, so it is the place for data the island's chunks read at
|
|
31
|
+
* execution time.
|
|
25
32
|
*/
|
|
26
33
|
type IslandEmission = {
|
|
27
34
|
links?: string[] | undefined;
|
|
35
|
+
imports?: string[] | undefined;
|
|
28
36
|
html?: string | undefined;
|
|
29
37
|
};
|
|
30
38
|
/**
|
|
@@ -66,4 +74,4 @@ declare function setRequestRouteData(request: Request, routeData: RouteData): vo
|
|
|
66
74
|
declare function getRequestRouteData(request: Request): RouteData | undefined;
|
|
67
75
|
//#endregion
|
|
68
76
|
export { DocumentEmission as a, IslandEmitter as c, registerIslandEmitter as i, IslandInfo as l, setRequestRouteData as n, DocumentEmitter as o, registerDocumentEmitter as r, IslandEmission as s, getRequestRouteData as t };
|
|
69
|
-
//# sourceMappingURL=route-store-
|
|
77
|
+
//# sourceMappingURL=route-store-CSYR4G5e.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-store-CSYR4G5e.d.ts","names":[],"sources":["../src/islands/types.ts","../src/islands/emitters.ts","../src/server/route-store.ts"],"mappings":";;;;;;;KAqBY;EACV;EACA;;EAEA;;EAEA;;EAEA;;;;;;;;;;;;;;;;;KAkBU;EACV;EACA;EACA;;;;;;KAOU,iBAAiB,QAAQ,YAAY,UAAU,2BAA2B;;;;KAK1E;EACV;EACA;;;;;;;KAQU,mBAAmB,SAAS,eAAe;;;;;;;;iBC3CvC,sBAAsB,SAAS;;;;;;;iBAc/B,wBAAwB,SAAS;;;iBCpBjC,oBAAoB,SAAS,SAAS,WAAW;iBAIjD,oBAAoB,SAAS,UAAU"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
//#region src/tweaks/strip-build-paths.ts
|
|
5
|
+
/**
|
|
6
|
+
* Stable stand-in for the build machine's project root in emitted server code.
|
|
7
|
+
* Only relative relationships matter at runtime (see `resolveClientDir`), so the
|
|
8
|
+
* value is never dereferenced — it just has to be consistent across the bundle.
|
|
9
|
+
*/
|
|
10
|
+
const ROOT_PLACEHOLDER = "/_astroscope";
|
|
11
|
+
const TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
12
|
+
".mjs",
|
|
13
|
+
".js",
|
|
14
|
+
".cjs",
|
|
15
|
+
".json",
|
|
16
|
+
".map"
|
|
17
|
+
]);
|
|
18
|
+
const HOISTED_STORE_RE = /(file:\/\/)?\/[^"'`\s]*?\/node_modules\/([^"'`\s]*)/g;
|
|
19
|
+
const MACHINE_PATH_RE = /(file:\/\/)?\/(?:Users|home)\/[^"'`\s]+/g;
|
|
20
|
+
function collectFiles(dir, out) {
|
|
21
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
22
|
+
const abs = path.join(dir, entry.name);
|
|
23
|
+
if (entry.isDirectory()) collectFiles(abs, out);
|
|
24
|
+
else if (TEXT_EXTENSIONS.has(path.extname(entry.name))) out.push(abs);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Replace the build machine's project root in the server build output with a
|
|
29
|
+
* stable placeholder.
|
|
30
|
+
*
|
|
31
|
+
* Astro serializes absolute `file://` config URLs (root, outDir, srcDir, ...)
|
|
32
|
+
* and absolute component module ids into the SSR manifest, and the compiled
|
|
33
|
+
* chunks and sourcemaps carry the same absolute paths. Shipping them makes the
|
|
34
|
+
* artifact irreproducible and leaks the developer's filesystem layout. The
|
|
35
|
+
* replacement is applied uniformly, so manifest keys keep matching the module
|
|
36
|
+
* ids embedded in chunks, and the server→client relative resolution keeps
|
|
37
|
+
* working.
|
|
38
|
+
*
|
|
39
|
+
* Returns the number of files rewritten.
|
|
40
|
+
*/
|
|
41
|
+
function stripBuildPaths(serverDir, root) {
|
|
42
|
+
const rootFsPosix = root.split(path.sep).join("/").replace(/\/+$/, "");
|
|
43
|
+
const rootUrl = pathToFileURL(rootFsPosix).href;
|
|
44
|
+
const files = [];
|
|
45
|
+
collectFiles(serverDir, files);
|
|
46
|
+
let rewritten = 0;
|
|
47
|
+
for (const file of files) {
|
|
48
|
+
const content = fs.readFileSync(file, "utf-8");
|
|
49
|
+
const replaced = content.replaceAll(rootUrl, `file://${ROOT_PLACEHOLDER}`).replaceAll(rootFsPosix, ROOT_PLACEHOLDER).replace(HOISTED_STORE_RE, (_, proto, suffix) => `${proto ?? ""}${ROOT_PLACEHOLDER}/node_modules/${suffix}`).replace(MACHINE_PATH_RE, (match, proto) => {
|
|
50
|
+
const rel = path.posix.relative(rootFsPosix, proto ? match.slice(proto.length) : match);
|
|
51
|
+
return `${proto ?? ""}${ROOT_PLACEHOLDER}/${rel}`;
|
|
52
|
+
});
|
|
53
|
+
if (replaced !== content) {
|
|
54
|
+
fs.writeFileSync(file, replaced);
|
|
55
|
+
rewritten++;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return rewritten;
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { stripBuildPaths };
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=strip-build-paths-C6eb1QdG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strip-build-paths-C6eb1QdG.js","names":[],"sources":["../src/tweaks/strip-build-paths.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\n/**\n * Stable stand-in for the build machine's project root in emitted server code.\n * Only relative relationships matter at runtime (see `resolveClientDir`), so the\n * value is never dereferenced — it just has to be consistent across the bundle.\n */\nexport const ROOT_PLACEHOLDER = '/_astroscope';\n\nconst TEXT_EXTENSIONS = new Set(['.mjs', '.js', '.cjs', '.json', '.map']);\n\n// absolute module ids pointing into a dependency store hoisted above the project\n// root (pnpm workspaces); the prefix before the first node_modules is collapsed,\n// the store-relative suffix keeps ids unique and matching. the greedy suffix\n// consumes the whole path token so a nested node_modules is not re-matched\nconst HOISTED_STORE_RE = /(file:\\/\\/)?\\/[^\"'`\\s]*?\\/node_modules\\/([^\"'`\\s]*)/g;\n\n// remaining machine paths outside the root and outside any store (workspace\n// siblings, linked package sources): rewritten relative to the root, which keeps\n// the mapping unique without shipping the home directory or the layout above root\nconst MACHINE_PATH_RE = /(file:\\/\\/)?\\/(?:Users|home)\\/[^\"'`\\s]+/g;\n\nfunction collectFiles(dir: string, out: string[]): void {\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const abs = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n collectFiles(abs, out);\n } else if (TEXT_EXTENSIONS.has(path.extname(entry.name))) {\n out.push(abs);\n }\n }\n}\n\n/**\n * Replace the build machine's project root in the server build output with a\n * stable placeholder.\n *\n * Astro serializes absolute `file://` config URLs (root, outDir, srcDir, ...)\n * and absolute component module ids into the SSR manifest, and the compiled\n * chunks and sourcemaps carry the same absolute paths. Shipping them makes the\n * artifact irreproducible and leaks the developer's filesystem layout. The\n * replacement is applied uniformly, so manifest keys keep matching the module\n * ids embedded in chunks, and the server→client relative resolution keeps\n * working.\n *\n * Returns the number of files rewritten.\n */\nexport function stripBuildPaths(serverDir: string, root: string): number {\n const rootFsPosix = root.split(path.sep).join('/').replace(/\\/+$/, '');\n const rootUrl = pathToFileURL(rootFsPosix).href;\n\n const files: string[] = [];\n\n collectFiles(serverDir, files);\n\n let rewritten = 0;\n\n for (const file of files) {\n const content = fs.readFileSync(file, 'utf-8');\n const replaced = content\n .replaceAll(rootUrl, `file://${ROOT_PLACEHOLDER}`)\n .replaceAll(rootFsPosix, ROOT_PLACEHOLDER)\n .replace(\n HOISTED_STORE_RE,\n (_, proto: string | undefined, suffix: string) => `${proto ?? ''}${ROOT_PLACEHOLDER}/node_modules/${suffix}`,\n )\n .replace(MACHINE_PATH_RE, (match, proto: string | undefined) => {\n const rel = path.posix.relative(rootFsPosix, proto ? match.slice(proto.length) : match);\n\n return `${proto ?? ''}${ROOT_PLACEHOLDER}/${rel}`;\n });\n\n if (replaced !== content) {\n fs.writeFileSync(file, replaced);\n rewritten++;\n }\n }\n\n return rewritten;\n}\n"],"mappings":";;;;;;;;;AASA,MAAa,mBAAmB;AAEhC,MAAM,kCAAkB,IAAI,IAAI;CAAC;CAAQ;CAAO;CAAQ;CAAS;AAAM,CAAC;AAMxE,MAAM,mBAAmB;AAKzB,MAAM,kBAAkB;AAExB,SAAS,aAAa,KAAa,KAAqB;CACtD,KAAK,MAAM,SAAS,GAAG,YAAY,KAAK,EAAE,eAAe,KAAK,CAAC,GAAG;EAChE,MAAM,MAAM,KAAK,KAAK,KAAK,MAAM,IAAI;EAErC,IAAI,MAAM,YAAY,GACpB,aAAa,KAAK,GAAG;OAChB,IAAI,gBAAgB,IAAI,KAAK,QAAQ,MAAM,IAAI,CAAC,GACrD,IAAI,KAAK,GAAG;CAEhB;AACF;;;;;;;;;;;;;;;AAgBA,SAAgB,gBAAgB,WAAmB,MAAsB;CACvE,MAAM,cAAc,KAAK,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,QAAQ,QAAQ,EAAE;CACrE,MAAM,UAAU,cAAc,WAAW,CAAC,CAAC;CAE3C,MAAM,QAAkB,CAAC;CAEzB,aAAa,WAAW,KAAK;CAE7B,IAAI,YAAY;CAEhB,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,UAAU,GAAG,aAAa,MAAM,OAAO;EAC7C,MAAM,WAAW,QACd,WAAW,SAAS,UAAU,kBAAkB,CAAC,CACjD,WAAW,aAAa,gBAAgB,CAAC,CACzC,QACC,mBACC,GAAG,OAA2B,WAAmB,GAAG,SAAS,KAAK,iBAAiB,gBAAgB,QACtG,CAAC,CACA,QAAQ,kBAAkB,OAAO,UAA8B;GAC9D,MAAM,MAAM,KAAK,MAAM,SAAS,aAAa,QAAQ,MAAM,MAAM,MAAM,MAAM,IAAI,KAAK;GAEtF,OAAO,GAAG,SAAS,KAAK,iBAAiB,GAAG;EAC9C,CAAC;EAEH,IAAI,aAAa,SAAS;GACxB,GAAG,cAAc,MAAM,QAAQ;GAC/B;EACF;CACF;CAEA,OAAO;AACT"}
|
|
@@ -139,9 +139,13 @@ function createIslandsTransformer(manifest) {
|
|
|
139
139
|
}
|
|
140
140
|
if (registeredComponents.has(componentUrl)) return { prepend: html || void 0 };
|
|
141
141
|
registeredComponents.add(componentUrl);
|
|
142
|
-
const runtime = runtimeInjected ? "" : `<script
|
|
142
|
+
const runtime = runtimeInjected ? "" : `<script>${manifest.runtimeSource}<\/script>`;
|
|
143
143
|
runtimeInjected = true;
|
|
144
|
-
|
|
144
|
+
const imports = [...new Set(emissions.flatMap((e) => e.imports ?? []))];
|
|
145
|
+
const importSet = new Set(imports);
|
|
146
|
+
const entry = { l: links.filter((url) => !importSet.has(url)) };
|
|
147
|
+
if (imports.length > 0) entry["i"] = imports;
|
|
148
|
+
return { prepend: runtime + `<script>(self.__islands__??={})[${jsonForScript(componentUrl)}]=${jsonForScript(entry)};<\/script>` + html || void 0 };
|
|
145
149
|
});
|
|
146
150
|
};
|
|
147
151
|
return { createDocumentRewriter };
|
|
@@ -188,4 +192,4 @@ function createPageTransformStream(options) {
|
|
|
188
192
|
//#endregion
|
|
189
193
|
export { createPageTransformStream as n, createIslandsTransformer as t };
|
|
190
194
|
|
|
191
|
-
//# sourceMappingURL=transform-
|
|
195
|
+
//# sourceMappingURL=transform-BqV8SOEm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform-BqV8SOEm.js","names":[],"sources":["../src/islands/graph.ts","../src/islands/rewriter.ts","../src/islands/transform.ts"],"sourcesContent":["import type { IslandsManifest } from './types.js';\n\n/**\n * Closure computation over the chunk import graph, memoized per manifest. The\n * manifest stores direct edges only — flattened closures repeat heavily across\n * entries and would bloat the JSON.\n */\nexport type ChunkGraph = {\n /** transitive static imports of a chunk, the chunk itself excluded */\n staticClosure(fileName: string): string[];\n /** transitive static + dynamic imports of a chunk, the chunk itself excluded */\n fullClosure(fileName: string): string[];\n has(fileName: string): boolean;\n};\n\nfunction createClosure(\n chunks: IslandsManifest['chunks'],\n edges: (entry: { i?: string[] | undefined; d?: string[] | undefined }) => string[],\n): (fileName: string) => string[] {\n const cache = new Map<string, string[]>();\n\n const walk = (fileName: string, result: Set<string>, visited: Set<string>): void => {\n if (visited.has(fileName)) {\n return;\n }\n\n visited.add(fileName);\n\n const entry = chunks[fileName];\n\n if (!entry) {\n return;\n }\n\n for (const dep of edges(entry)) {\n result.add(dep);\n walk(dep, result, visited);\n }\n };\n\n return (fileName) => {\n const cached = cache.get(fileName);\n\n if (cached) {\n return cached;\n }\n\n const result = new Set<string>();\n\n walk(fileName, result, new Set());\n result.delete(fileName);\n\n const list = [...result];\n\n cache.set(fileName, list);\n\n return list;\n };\n}\n\nexport function createChunkGraph(manifest: IslandsManifest): ChunkGraph {\n return {\n staticClosure: createClosure(manifest.chunks, (entry) => entry.i ?? []),\n fullClosure: createClosure(manifest.chunks, (entry) => [...(entry.i ?? []), ...(entry.d ?? [])]),\n has: (fileName) => fileName in manifest.chunks,\n };\n}\n","import { RewritingStream } from 'parse5-html-rewriting-stream';\n\n/**\n * Streaming HTML rewriter that finds `<astro-island …>` opening tags, hands their\n * attributes to a handler, and prepends the handler's html before the tag — the\n * tag itself is always re-emitted from its raw source, byte-verbatim.\n *\n * Tokenization is parse5's — the reference WHATWG implementation — so every\n * context where island markup is not actually an element to the browser\n * (comments, raw-text elements like `script`/`iframe`/`noscript`, doctypes,\n * quoted attribute values) is skipped by construction rather than by our own\n * spec-tracking; unmodified content passes through as raw source slices.\n * Attribute values arrive with the full entity set decoded.\n *\n * Closing tags are never touched: injection happens before the island's opening\n * tag precisely so the island's subtree — the hydration target — stays untouched.\n *\n * The test suite pins the behavior this package relies on, so a parse5 upgrade\n * that changes it fails here rather than degrading silently — same philosophy as\n * the astro compatibility surface.\n */\n\nexport type IslandTagRewrite = {\n /** html emitted immediately before the island opening tag */\n prepend?: string | undefined;\n};\n\nexport type IslandTagHandler = (attrs: Record<string, string>) => IslandTagRewrite | null;\n\nexport type IslandRewriter = {\n write(chunk: string): string;\n end(): Promise<string>;\n};\n\nconst ISLAND = 'astro-island';\n\nexport function encodeAttribute(value: string): string {\n return value.replace(/&/g, '&').replace(/\"/g, '"').replace(/</g, '<');\n}\n\nexport function createIslandRewriter(onIsland: IslandTagHandler): IslandRewriter {\n const stream = new RewritingStream();\n const out: string[] = [];\n\n stream.on('data', (chunk: string | Buffer) => {\n out.push(typeof chunk === 'string' ? chunk : chunk.toString());\n });\n\n stream.on('startTag', (tag, rawHtml) => {\n if (tag.tagName === ISLAND) {\n const attrs: Record<string, string> = {};\n\n for (const attr of tag.attrs) {\n attrs[attr.name] = attr.value;\n }\n\n const rewrite = onIsland(attrs);\n\n if (rewrite?.prepend) {\n stream.emitRaw(rewrite.prepend);\n }\n }\n\n stream.emitRaw(rawHtml);\n });\n\n const drain = (): string => out.splice(0).join('');\n\n return {\n // a transform stream with an attached data listener processes writes\n // synchronously, so each write can hand back its output right away\n write(chunk) {\n stream.write(chunk);\n\n return drain();\n },\n end() {\n return new Promise((resolve, reject) => {\n stream.once('error', reject);\n stream.end(() => resolve(drain()));\n });\n },\n };\n}\n","import type { APIContext } from 'astro';\nimport { log } from '../observability/log/index.js';\nimport { getIslandEmitters } from './emitters.js';\nimport { createChunkGraph } from './graph.js';\nimport { type IslandRewriter, createIslandRewriter, encodeAttribute } from './rewriter.js';\nimport type { IslandEmission, IslandInfo, IslandsManifest } from './types.js';\n\n/**\n * Turns the manifest into per-document rewriters: resolves each island's chunk\n * closures, collects emissions (the built-in preloader plus registered emitters),\n * and applies the emission policy —\n *\n * - immediate directives (`load`, `only`) get `<link rel=\"modulepreload\">` tags\n * before the tag, deduplicated per document; the browser's speculative preload\n * scanner acts on them from raw bytes, ahead of any script.\n * - deferred directives get an inline script before the first island per\n * component that registers `{l: links, i: imports}` on the preload global,\n * keyed by `component-url`; the gate runtime injects the links and eagerly\n * `import()`s the imports by the directive's own scheduling semantics. A script\n * rather than an attribute: it takes effect at parse time and its effect\n * survives the island element being removed — the island tag itself stays\n * untouched.\n *\n * The gate runtime is inlined once, before the first island that needs it, so\n * pages without deferred islands never carry it — and pages with them install\n * the gates at parse time, without an external fetch astro's inline island\n * machinery would always beat.\n */\n\n/** global registry of `{l, i}` entries per component-url, written by the transform, read by the gate runtime */\nexport const PRELOAD_GLOBAL = '__islands__';\n\nconst IMMEDIATE_DIRECTIVES = new Set(['load', 'only']);\n\n/** urls cannot contain `</script>`, but escape `<` anyway so no value ever can */\nfunction jsonForScript(value: unknown): string {\n return JSON.stringify(value).replace(/</g, '\\\\u003c');\n}\n\ntype ResolvedChunk = { prefix: string; fileName: string };\n\nexport type IslandsTransformer = {\n createDocumentRewriter(context?: APIContext | undefined): IslandRewriter;\n};\n\nexport function createIslandsTransformer(manifest: IslandsManifest): IslandsTransformer {\n const graph = createChunkGraph(manifest);\n const fileNames = Object.keys(manifest.chunks);\n const resolveCache = new Map<string, ResolvedChunk | null>();\n\n // islands carry public urls (base and asset prefix baked in), the manifest holds\n // dist-relative file names — match by suffix at a path boundary, so the observed\n // prefix maps closures and the runtime script back to public urls with no config\n const resolve = (url: string): ResolvedChunk | null => {\n const cached = resolveCache.get(url);\n\n if (cached !== undefined) {\n return cached;\n }\n\n let resolved: ResolvedChunk | null = null;\n\n for (const fileName of fileNames) {\n if (url.endsWith(fileName)) {\n const boundary = url.length - fileName.length;\n\n if (boundary === 0 || url[boundary - 1] === '/') {\n resolved = { prefix: url.slice(0, boundary), fileName };\n break;\n }\n }\n }\n\n resolveCache.set(url, resolved);\n\n return resolved;\n };\n\n const createDocumentRewriter = (context?: APIContext | undefined): IslandRewriter => {\n const emittedLinks = new Set<string>();\n const registeredComponents = new Set<string>();\n let runtimeInjected = false;\n\n return createIslandRewriter((attrs) => {\n const componentUrl = attrs['component-url'];\n\n if (!componentUrl) {\n return null;\n }\n\n const component = resolve(componentUrl);\n\n if (!component) {\n return null;\n }\n\n const rendererUrl = attrs['renderer-url'] || null;\n const renderer = rendererUrl ? resolve(rendererUrl) : null;\n\n const closureUrls = (closure: (fileName: string) => string[]): string[] => {\n const urls = new Set([componentUrl, ...closure(component.fileName).map((f) => component.prefix + f)]);\n\n if (rendererUrl) {\n urls.add(rendererUrl);\n\n for (const f of renderer ? closure(renderer.fileName) : []) {\n urls.add(renderer!.prefix + f);\n }\n }\n\n return [...urls];\n };\n\n const island: IslandInfo = {\n componentUrl,\n rendererUrl,\n client: attrs['client'] || null,\n staticClosure: closureUrls(graph.staticClosure),\n fullClosure: closureUrls(graph.fullClosure),\n };\n\n const emissions: IslandEmission[] = [{ links: island.staticClosure }];\n\n for (const emitter of getIslandEmitters()) {\n try {\n const emission = emitter(island, context);\n\n if (emission) {\n emissions.push(emission);\n }\n } catch (error) {\n // an emitter must never break the page — its contribution is dropped\n log.error({ err: error, componentUrl }, 'island emitter failed');\n }\n }\n\n const links = [...new Set(emissions.flatMap((e) => e.links ?? []))];\n const html = emissions.map((e) => e.html ?? '').join('');\n const directive = (island.client ?? '').replace(/-x$/, '');\n\n if (IMMEDIATE_DIRECTIVES.has(directive)) {\n const fresh = links.filter((url) => !emittedLinks.has(url));\n\n for (const url of fresh) {\n emittedLinks.add(url);\n }\n\n const prepend =\n html +\n fresh.map((url) => `<link rel=\"modulepreload\" fetchpriority=\"low\" href=\"${encodeAttribute(url)}\">`).join('');\n\n return { prepend: prepend || undefined };\n }\n\n if (registeredComponents.has(componentUrl)) {\n return { prepend: html || undefined };\n }\n\n registeredComponents.add(componentUrl);\n\n const runtime = runtimeInjected ? '' : `<script>${manifest.runtimeSource}</script>`;\n\n runtimeInjected = true;\n\n const imports = [...new Set(emissions.flatMap((e) => e.imports ?? []))];\n const importSet = new Set(imports);\n const entry: Record<string, string[]> = { l: links.filter((url) => !importSet.has(url)) };\n\n if (imports.length > 0) {\n entry['i'] = imports;\n }\n\n const register = `<script>(self.${PRELOAD_GLOBAL}??={})[${jsonForScript(componentUrl)}]=${jsonForScript(entry)};</script>`;\n\n return { prepend: runtime + register + html || undefined };\n });\n };\n\n return { createDocumentRewriter };\n}\n\nexport type PageTransformOptions = {\n /** the islands rewriter for this document, when preloading is on (prod with a manifest) */\n rewriter?: IslandRewriter | undefined;\n /** scripts inserted right after the opening `<head>` tag — buffers the response */\n heads: string[];\n /** script factories invoked after the rewriter finished, results appended at stream end */\n ends: (() => string | null)[];\n};\n\n/**\n * The single streaming pass over an html page response: chunks go through the\n * islands rewriter (when present), head content is inserted right after the\n * opening `<head>` tag (which requires buffering the whole document — head\n * content is dev-style delivery, where throughput is irrelevant), and end\n * factories run last, strictly after every island passed the rewriter.\n */\nexport function createPageTransformStream(options: PageTransformOptions): TransformStream<Uint8Array, Uint8Array> {\n const { rewriter, heads, ends } = options;\n const decoder = new TextDecoder();\n const encoder = new TextEncoder();\n const buffered = heads.length > 0 ? ([] as string[]) : null;\n\n const enqueue = (controller: TransformStreamDefaultController<Uint8Array>, text: string): void => {\n if (text) {\n controller.enqueue(encoder.encode(text));\n }\n };\n\n return new TransformStream({\n transform(chunk, controller) {\n let text = decoder.decode(chunk, { stream: true });\n\n if (rewriter) {\n text = rewriter.write(text);\n }\n\n if (buffered) {\n buffered.push(text);\n } else {\n enqueue(controller, text);\n }\n },\n async flush(controller) {\n let tail = decoder.decode();\n\n if (rewriter) {\n tail = (tail ? rewriter.write(tail) : '') + (await rewriter.end());\n }\n\n if (buffered) {\n const html = buffered.join('') + tail;\n // nothing but the doctype, comments and <html> can precede <head>, so the\n // first match cannot sit inside script raw text\n const head = /<head[^>]*>/i.exec(html);\n const at = head ? head.index + head[0].length : 0;\n\n enqueue(controller, html.slice(0, at) + heads.join('') + html.slice(at));\n } else {\n enqueue(controller, tail);\n }\n\n for (const end of ends) {\n try {\n enqueue(controller, end() ?? '');\n } catch (error) {\n // an emitter must never break the page — its contribution is dropped\n log.error({ err: error }, 'document emitter failed');\n }\n }\n },\n });\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astroscope/node",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Opinionated, cloud-friendly Node adapter for Astro: boot lifecycle, health probes, request logging, telemetry, CSRF and static serving run as plain code around server.listen()",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {}
|
package/dist/islands-runtime.js
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
//#region src/islands/runtime.ts
|
|
2
|
-
/**
|
|
3
|
-
* Gate runtime for deferred island preloading, shipped to the browser as a single
|
|
4
|
-
* self-contained module (keep this file import-free so tsdown cannot split it).
|
|
5
|
-
*
|
|
6
|
-
* The islands middleware registers each deferred island's preload urls on
|
|
7
|
-
* `self.__islands__`, keyed by component-url, via an inline script before the
|
|
8
|
-
* first island per component (`PRELOAD_GLOBAL` in `transform.ts` — keep in
|
|
9
|
-
* sync); the registration takes effect at parse time and outlives the island
|
|
10
|
-
* element itself. This script watches islands arrive — parsed, streamed, or
|
|
11
|
-
* swapped in by a client router — and injects `<link rel="modulepreload">` for
|
|
12
|
-
* a component when one of its islands is about to hydrate, replicating the
|
|
13
|
-
* *scheduling* of astro's client directives without touching their behavior:
|
|
14
|
-
*
|
|
15
|
-
* - `idle` (and any unknown directive): requestIdleCallback, honoring a timeout
|
|
16
|
-
* - `media`: matchMedia on the directive's own query
|
|
17
|
-
* - `visible`: IntersectionObserver on the island, with an expanded rootMargin so
|
|
18
|
-
* the fetch leads the hydration decision by roughly a viewport
|
|
19
|
-
*
|
|
20
|
-
* Islands beyond the first share their component's links through the registry, and
|
|
21
|
-
* whichever instance's gate fires first wins; injection is deduplicated per url and
|
|
22
|
-
* the browser deduplicates preloads against the module loader anyway.
|
|
23
|
-
*/
|
|
24
|
-
const INSTALLED = Symbol.for("@astroscope/node.islandsRuntime");
|
|
25
|
-
const scope = globalThis;
|
|
26
|
-
const fired = /* @__PURE__ */ new Set();
|
|
27
|
-
const injected = /* @__PURE__ */ new Set();
|
|
28
|
-
const observed = /* @__PURE__ */ new Map();
|
|
29
|
-
let observer;
|
|
30
|
-
function inject(urls) {
|
|
31
|
-
for (const url of urls) {
|
|
32
|
-
if (injected.has(url)) continue;
|
|
33
|
-
injected.add(url);
|
|
34
|
-
const link = document.createElement("link");
|
|
35
|
-
link.rel = "modulepreload";
|
|
36
|
-
link.setAttribute("fetchpriority", "low");
|
|
37
|
-
link.href = url;
|
|
38
|
-
document.head.append(link);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
function fire(componentUrl) {
|
|
42
|
-
if (fired.has(componentUrl)) return;
|
|
43
|
-
fired.add(componentUrl);
|
|
44
|
-
const links = scope.__islands__?.[componentUrl];
|
|
45
|
-
if (links) inject(links);
|
|
46
|
-
}
|
|
47
|
-
function directiveValue(el) {
|
|
48
|
-
try {
|
|
49
|
-
return JSON.parse(el.getAttribute("opts") ?? "").value;
|
|
50
|
-
} catch {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
function observe(el, componentUrl) {
|
|
55
|
-
observer ??= new IntersectionObserver((entries) => {
|
|
56
|
-
for (const entry of entries) if (entry.isIntersecting) {
|
|
57
|
-
const url = observed.get(entry.target);
|
|
58
|
-
observer.unobserve(entry.target);
|
|
59
|
-
observed.delete(entry.target);
|
|
60
|
-
if (url) fire(url);
|
|
61
|
-
}
|
|
62
|
-
}, { rootMargin: "100% 0px" });
|
|
63
|
-
observed.set(el, componentUrl);
|
|
64
|
-
observer.observe(el);
|
|
65
|
-
}
|
|
66
|
-
function gate(el) {
|
|
67
|
-
const componentUrl = el.getAttribute("component-url");
|
|
68
|
-
if (!componentUrl) return;
|
|
69
|
-
if (fired.has(componentUrl) || !scope.__islands__?.[componentUrl]) return;
|
|
70
|
-
const directive = (el.getAttribute("client") ?? "").replace(/-x$/, "");
|
|
71
|
-
if (directive === "media") {
|
|
72
|
-
const value = directiveValue(el);
|
|
73
|
-
if (typeof value === "string") {
|
|
74
|
-
const query = matchMedia(value);
|
|
75
|
-
if (query.matches) fire(componentUrl);
|
|
76
|
-
else query.addEventListener("change", () => fire(componentUrl), { once: true });
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
if (directive === "visible") {
|
|
81
|
-
observe(el, componentUrl);
|
|
82
|
-
return;
|
|
83
|
-
}
|
|
84
|
-
if (directive === "load" || directive === "only") {
|
|
85
|
-
fire(componentUrl);
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
const value = directiveValue(el);
|
|
89
|
-
const timeout = typeof value === "object" && value !== null ? value.timeout : void 0;
|
|
90
|
-
const run = () => fire(componentUrl);
|
|
91
|
-
if ("requestIdleCallback" in window) requestIdleCallback(run, typeof timeout === "number" ? { timeout } : void 0);
|
|
92
|
-
else setTimeout(run, typeof timeout === "number" ? timeout : 200);
|
|
93
|
-
}
|
|
94
|
-
function scan(root) {
|
|
95
|
-
for (const el of root.querySelectorAll("astro-island")) gate(el);
|
|
96
|
-
}
|
|
97
|
-
if (!scope[INSTALLED]) {
|
|
98
|
-
scope[INSTALLED] = true;
|
|
99
|
-
scan(document);
|
|
100
|
-
new MutationObserver((mutations) => {
|
|
101
|
-
for (const mutation of mutations) for (const node of mutation.addedNodes) if (node instanceof Element) {
|
|
102
|
-
if (node.localName === "astro-island") gate(node);
|
|
103
|
-
else scan(node);
|
|
104
|
-
}
|
|
105
|
-
}).observe(document.documentElement, {
|
|
106
|
-
childList: true,
|
|
107
|
-
subtree: true
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
//#endregion
|
|
111
|
-
export {};
|
|
112
|
-
|
|
113
|
-
//# sourceMappingURL=islands-runtime.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"islands-runtime.js","names":[],"sources":["../src/islands/runtime.ts"],"sourcesContent":["/**\n * Gate runtime for deferred island preloading, shipped to the browser as a single\n * self-contained module (keep this file import-free so tsdown cannot split it).\n *\n * The islands middleware registers each deferred island's preload urls on\n * `self.__islands__`, keyed by component-url, via an inline script before the\n * first island per component (`PRELOAD_GLOBAL` in `transform.ts` — keep in\n * sync); the registration takes effect at parse time and outlives the island\n * element itself. This script watches islands arrive — parsed, streamed, or\n * swapped in by a client router — and injects `<link rel=\"modulepreload\">` for\n * a component when one of its islands is about to hydrate, replicating the\n * *scheduling* of astro's client directives without touching their behavior:\n *\n * - `idle` (and any unknown directive): requestIdleCallback, honoring a timeout\n * - `media`: matchMedia on the directive's own query\n * - `visible`: IntersectionObserver on the island, with an expanded rootMargin so\n * the fetch leads the hydration decision by roughly a viewport\n *\n * Islands beyond the first share their component's links through the registry, and\n * whichever instance's gate fires first wins; injection is deduplicated per url and\n * the browser deduplicates preloads against the module loader anyway.\n */\n\n// a client-router swap after a deploy can pull in a second runtime under a new\n// hash — only the first install may observe, or every island would gate twice\nconst INSTALLED = Symbol.for('@astroscope/node.islandsRuntime');\nconst scope = globalThis as { [INSTALLED]?: boolean; __islands__?: Record<string, string[]> };\n\nconst fired = new Set<string>();\nconst injected = new Set<string>();\nconst observed = new Map<Element, string>();\n\nlet observer: IntersectionObserver | undefined;\n\nfunction inject(urls: string[]): void {\n for (const url of urls) {\n if (injected.has(url)) {\n continue;\n }\n\n injected.add(url);\n\n const link = document.createElement('link');\n\n link.rel = 'modulepreload';\n link.setAttribute('fetchpriority', 'low');\n link.href = url;\n\n document.head.append(link);\n }\n}\n\nfunction fire(componentUrl: string): void {\n if (fired.has(componentUrl)) {\n return;\n }\n\n fired.add(componentUrl);\n\n const links = scope.__islands__?.[componentUrl];\n\n if (links) {\n inject(links);\n }\n}\n\nfunction directiveValue(el: Element): unknown {\n try {\n return (JSON.parse(el.getAttribute('opts') ?? '') as { value?: unknown }).value;\n } catch {\n return undefined;\n }\n}\n\nfunction observe(el: Element, componentUrl: string): void {\n observer ??= new IntersectionObserver(\n (entries) => {\n for (const entry of entries) {\n if (entry.isIntersecting) {\n const url = observed.get(entry.target);\n\n observer!.unobserve(entry.target);\n observed.delete(entry.target);\n\n if (url) {\n fire(url);\n }\n }\n }\n },\n { rootMargin: '100% 0px' },\n );\n\n observed.set(el, componentUrl);\n observer.observe(el);\n}\n\nfunction gate(el: Element): void {\n const componentUrl = el.getAttribute('component-url');\n\n if (!componentUrl) {\n return;\n }\n\n if (fired.has(componentUrl) || !scope.__islands__?.[componentUrl]) {\n return;\n }\n\n const directive = (el.getAttribute('client') ?? '').replace(/-x$/, '');\n\n if (directive === 'media') {\n const value = directiveValue(el);\n\n if (typeof value === 'string') {\n const query = matchMedia(value);\n\n if (query.matches) {\n fire(componentUrl);\n } else {\n query.addEventListener('change', () => fire(componentUrl), { once: true });\n }\n\n return;\n }\n }\n\n if (directive === 'visible') {\n observe(el, componentUrl);\n\n return;\n }\n\n if (directive === 'load' || directive === 'only') {\n // immediate islands normally get server-emitted link tags instead; if one\n // carries gate data anyway, fire right away\n fire(componentUrl);\n\n return;\n }\n\n // idle, a malformed media query, and unknown directives\n const value = directiveValue(el);\n const timeout = typeof value === 'object' && value !== null ? (value as { timeout?: unknown }).timeout : undefined;\n const run = (): void => fire(componentUrl);\n\n if ('requestIdleCallback' in window) {\n requestIdleCallback(run, typeof timeout === 'number' ? { timeout } : undefined);\n } else {\n setTimeout(run, typeof timeout === 'number' ? timeout : 200);\n }\n}\n\nfunction scan(root: ParentNode): void {\n for (const el of root.querySelectorAll('astro-island')) {\n gate(el);\n }\n}\n\nif (!scope[INSTALLED]) {\n scope[INSTALLED] = true;\n\n scan(document);\n\n new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n for (const node of mutation.addedNodes) {\n if (node instanceof Element) {\n if (node.localName === 'astro-island') {\n gate(node);\n } else {\n scan(node);\n }\n }\n }\n }\n }).observe(document.documentElement, { childList: true, subtree: true });\n}\n\nexport {};\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"route-store-DtY3uvLf.d.ts","names":[],"sources":["../src/islands/types.ts","../src/islands/emitters.ts","../src/server/route-store.ts"],"mappings":";;;;;;;KAqBY;EACV;EACA;;EAEA;;EAEA;;EAEA;;;;;;;;;;KAWU;EACV;EACA;;;;;;KAOU,iBAAiB,QAAQ,YAAY,UAAU,2BAA2B;;;;KAK1E;EACV;EACA;;;;;;;KAQU,mBAAmB,SAAS,eAAe;;;;;;;;iBCnCvC,sBAAsB,SAAS;;;;;;;iBAc/B,wBAAwB,SAAS;;;iBCpBjC,oBAAoB,SAAS,SAAS,WAAW;iBAIjD,oBAAoB,SAAS,UAAU"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transform-D8dIBGEr.js","names":[],"sources":["../src/islands/graph.ts","../src/islands/rewriter.ts","../src/islands/transform.ts"],"sourcesContent":["import type { IslandsManifest } from './types.js';\n\n/**\n * Closure computation over the chunk import graph, memoized per manifest. The\n * manifest stores direct edges only — flattened closures repeat heavily across\n * entries and would bloat the JSON.\n */\nexport type ChunkGraph = {\n /** transitive static imports of a chunk, the chunk itself excluded */\n staticClosure(fileName: string): string[];\n /** transitive static + dynamic imports of a chunk, the chunk itself excluded */\n fullClosure(fileName: string): string[];\n has(fileName: string): boolean;\n};\n\nfunction createClosure(\n chunks: IslandsManifest['chunks'],\n edges: (entry: { i?: string[] | undefined; d?: string[] | undefined }) => string[],\n): (fileName: string) => string[] {\n const cache = new Map<string, string[]>();\n\n const walk = (fileName: string, result: Set<string>, visited: Set<string>): void => {\n if (visited.has(fileName)) {\n return;\n }\n\n visited.add(fileName);\n\n const entry = chunks[fileName];\n\n if (!entry) {\n return;\n }\n\n for (const dep of edges(entry)) {\n result.add(dep);\n walk(dep, result, visited);\n }\n };\n\n return (fileName) => {\n const cached = cache.get(fileName);\n\n if (cached) {\n return cached;\n }\n\n const result = new Set<string>();\n\n walk(fileName, result, new Set());\n result.delete(fileName);\n\n const list = [...result];\n\n cache.set(fileName, list);\n\n return list;\n };\n}\n\nexport function createChunkGraph(manifest: IslandsManifest): ChunkGraph {\n return {\n staticClosure: createClosure(manifest.chunks, (entry) => entry.i ?? []),\n fullClosure: createClosure(manifest.chunks, (entry) => [...(entry.i ?? []), ...(entry.d ?? [])]),\n has: (fileName) => fileName in manifest.chunks,\n };\n}\n","import { RewritingStream } from 'parse5-html-rewriting-stream';\n\n/**\n * Streaming HTML rewriter that finds `<astro-island …>` opening tags, hands their\n * attributes to a handler, and prepends the handler's html before the tag — the\n * tag itself is always re-emitted from its raw source, byte-verbatim.\n *\n * Tokenization is parse5's — the reference WHATWG implementation — so every\n * context where island markup is not actually an element to the browser\n * (comments, raw-text elements like `script`/`iframe`/`noscript`, doctypes,\n * quoted attribute values) is skipped by construction rather than by our own\n * spec-tracking; unmodified content passes through as raw source slices.\n * Attribute values arrive with the full entity set decoded.\n *\n * Closing tags are never touched: injection happens before the island's opening\n * tag precisely so the island's subtree — the hydration target — stays untouched.\n *\n * The test suite pins the behavior this package relies on, so a parse5 upgrade\n * that changes it fails here rather than degrading silently — same philosophy as\n * the astro compatibility surface.\n */\n\nexport type IslandTagRewrite = {\n /** html emitted immediately before the island opening tag */\n prepend?: string | undefined;\n};\n\nexport type IslandTagHandler = (attrs: Record<string, string>) => IslandTagRewrite | null;\n\nexport type IslandRewriter = {\n write(chunk: string): string;\n end(): Promise<string>;\n};\n\nconst ISLAND = 'astro-island';\n\nexport function encodeAttribute(value: string): string {\n return value.replace(/&/g, '&').replace(/\"/g, '"').replace(/</g, '<');\n}\n\nexport function createIslandRewriter(onIsland: IslandTagHandler): IslandRewriter {\n const stream = new RewritingStream();\n const out: string[] = [];\n\n stream.on('data', (chunk: string | Buffer) => {\n out.push(typeof chunk === 'string' ? chunk : chunk.toString());\n });\n\n stream.on('startTag', (tag, rawHtml) => {\n if (tag.tagName === ISLAND) {\n const attrs: Record<string, string> = {};\n\n for (const attr of tag.attrs) {\n attrs[attr.name] = attr.value;\n }\n\n const rewrite = onIsland(attrs);\n\n if (rewrite?.prepend) {\n stream.emitRaw(rewrite.prepend);\n }\n }\n\n stream.emitRaw(rawHtml);\n });\n\n const drain = (): string => out.splice(0).join('');\n\n return {\n // a transform stream with an attached data listener processes writes\n // synchronously, so each write can hand back its output right away\n write(chunk) {\n stream.write(chunk);\n\n return drain();\n },\n end() {\n return new Promise((resolve, reject) => {\n stream.once('error', reject);\n stream.end(() => resolve(drain()));\n });\n },\n };\n}\n","import type { APIContext } from 'astro';\nimport { log } from '../observability/log/index.js';\nimport { getIslandEmitters } from './emitters.js';\nimport { createChunkGraph } from './graph.js';\nimport { type IslandRewriter, createIslandRewriter, encodeAttribute } from './rewriter.js';\nimport type { IslandEmission, IslandInfo, IslandsManifest } from './types.js';\n\n/**\n * Turns the manifest into per-document rewriters: resolves each island's chunk\n * closures, collects emissions (the built-in preloader plus registered emitters),\n * and applies the emission policy —\n *\n * - immediate directives (`load`, `only`) get `<link rel=\"modulepreload\">` tags\n * before the tag, deduplicated per document; the browser's speculative preload\n * scanner acts on them from raw bytes, ahead of any script.\n * - deferred directives get an inline script before the first island per\n * component that registers the links on the preload global, keyed by\n * `component-url`; the gate runtime fires them by the directive's own\n * scheduling semantics. A script rather than an attribute: it takes effect at\n * parse time and its effect survives the island element being removed — the\n * island tag itself stays untouched.\n *\n * The gate runtime script is injected once, before the first island that needs it,\n * so pages without deferred islands never load it.\n */\n\n/** global registry of preload urls per component-url, written by the transform, read by the gate runtime */\nexport const PRELOAD_GLOBAL = '__islands__';\n\nconst IMMEDIATE_DIRECTIVES = new Set(['load', 'only']);\n\n/** urls cannot contain `</script>`, but escape `<` anyway so no value ever can */\nfunction jsonForScript(value: unknown): string {\n return JSON.stringify(value).replace(/</g, '\\\\u003c');\n}\n\ntype ResolvedChunk = { prefix: string; fileName: string };\n\nexport type IslandsTransformer = {\n createDocumentRewriter(context?: APIContext | undefined): IslandRewriter;\n};\n\nexport function createIslandsTransformer(manifest: IslandsManifest): IslandsTransformer {\n const graph = createChunkGraph(manifest);\n const fileNames = Object.keys(manifest.chunks);\n const resolveCache = new Map<string, ResolvedChunk | null>();\n\n // islands carry public urls (base and asset prefix baked in), the manifest holds\n // dist-relative file names — match by suffix at a path boundary, so the observed\n // prefix maps closures and the runtime script back to public urls with no config\n const resolve = (url: string): ResolvedChunk | null => {\n const cached = resolveCache.get(url);\n\n if (cached !== undefined) {\n return cached;\n }\n\n let resolved: ResolvedChunk | null = null;\n\n for (const fileName of fileNames) {\n if (url.endsWith(fileName)) {\n const boundary = url.length - fileName.length;\n\n if (boundary === 0 || url[boundary - 1] === '/') {\n resolved = { prefix: url.slice(0, boundary), fileName };\n break;\n }\n }\n }\n\n resolveCache.set(url, resolved);\n\n return resolved;\n };\n\n const createDocumentRewriter = (context?: APIContext | undefined): IslandRewriter => {\n const emittedLinks = new Set<string>();\n const registeredComponents = new Set<string>();\n let runtimeInjected = false;\n\n return createIslandRewriter((attrs) => {\n const componentUrl = attrs['component-url'];\n\n if (!componentUrl) {\n return null;\n }\n\n const component = resolve(componentUrl);\n\n if (!component) {\n return null;\n }\n\n const rendererUrl = attrs['renderer-url'] || null;\n const renderer = rendererUrl ? resolve(rendererUrl) : null;\n\n const closureUrls = (closure: (fileName: string) => string[]): string[] => {\n const urls = new Set([componentUrl, ...closure(component.fileName).map((f) => component.prefix + f)]);\n\n if (rendererUrl) {\n urls.add(rendererUrl);\n\n for (const f of renderer ? closure(renderer.fileName) : []) {\n urls.add(renderer!.prefix + f);\n }\n }\n\n return [...urls];\n };\n\n const island: IslandInfo = {\n componentUrl,\n rendererUrl,\n client: attrs['client'] || null,\n staticClosure: closureUrls(graph.staticClosure),\n fullClosure: closureUrls(graph.fullClosure),\n };\n\n const emissions: IslandEmission[] = [{ links: island.staticClosure }];\n\n for (const emitter of getIslandEmitters()) {\n try {\n const emission = emitter(island, context);\n\n if (emission) {\n emissions.push(emission);\n }\n } catch (error) {\n // an emitter must never break the page — its contribution is dropped\n log.error({ err: error, componentUrl }, 'island emitter failed');\n }\n }\n\n const links = [...new Set(emissions.flatMap((e) => e.links ?? []))];\n const html = emissions.map((e) => e.html ?? '').join('');\n const directive = (island.client ?? '').replace(/-x$/, '');\n\n if (IMMEDIATE_DIRECTIVES.has(directive)) {\n const fresh = links.filter((url) => !emittedLinks.has(url));\n\n for (const url of fresh) {\n emittedLinks.add(url);\n }\n\n const prepend =\n html +\n fresh.map((url) => `<link rel=\"modulepreload\" fetchpriority=\"low\" href=\"${encodeAttribute(url)}\">`).join('');\n\n return { prepend: prepend || undefined };\n }\n\n if (registeredComponents.has(componentUrl)) {\n return { prepend: html || undefined };\n }\n\n registeredComponents.add(componentUrl);\n\n const runtime = runtimeInjected\n ? ''\n : `<script type=\"module\" src=\"${encodeAttribute(component.prefix + manifest.runtime)}\"></script>`;\n\n runtimeInjected = true;\n\n const register = `<script>(self.${PRELOAD_GLOBAL}??={})[${jsonForScript(componentUrl)}]=${jsonForScript(links)};</script>`;\n\n return { prepend: runtime + register + html || undefined };\n });\n };\n\n return { createDocumentRewriter };\n}\n\nexport type PageTransformOptions = {\n /** the islands rewriter for this document, when preloading is on (prod with a manifest) */\n rewriter?: IslandRewriter | undefined;\n /** scripts inserted right after the opening `<head>` tag — buffers the response */\n heads: string[];\n /** script factories invoked after the rewriter finished, results appended at stream end */\n ends: (() => string | null)[];\n};\n\n/**\n * The single streaming pass over an html page response: chunks go through the\n * islands rewriter (when present), head content is inserted right after the\n * opening `<head>` tag (which requires buffering the whole document — head\n * content is dev-style delivery, where throughput is irrelevant), and end\n * factories run last, strictly after every island passed the rewriter.\n */\nexport function createPageTransformStream(options: PageTransformOptions): TransformStream<Uint8Array, Uint8Array> {\n const { rewriter, heads, ends } = options;\n const decoder = new TextDecoder();\n const encoder = new TextEncoder();\n const buffered = heads.length > 0 ? ([] as string[]) : null;\n\n const enqueue = (controller: TransformStreamDefaultController<Uint8Array>, text: string): void => {\n if (text) {\n controller.enqueue(encoder.encode(text));\n }\n };\n\n return new TransformStream({\n transform(chunk, controller) {\n let text = decoder.decode(chunk, { stream: true });\n\n if (rewriter) {\n text = rewriter.write(text);\n }\n\n if (buffered) {\n buffered.push(text);\n } else {\n enqueue(controller, text);\n }\n },\n async flush(controller) {\n let tail = decoder.decode();\n\n if (rewriter) {\n tail = (tail ? rewriter.write(tail) : '') + (await rewriter.end());\n }\n\n if (buffered) {\n const html = buffered.join('') + tail;\n // nothing but the doctype, comments and <html> can precede <head>, so the\n // first match cannot sit inside script raw text\n const head = /<head[^>]*>/i.exec(html);\n const at = head ? head.index + head[0].length : 0;\n\n enqueue(controller, html.slice(0, at) + heads.join('') + html.slice(at));\n } else {\n enqueue(controller, tail);\n }\n\n for (const end of ends) {\n try {\n enqueue(controller, end() ?? '');\n } catch (error) {\n // an emitter must never break the page — its contribution is dropped\n log.error({ err: error }, 'document emitter failed');\n }\n }\n },\n });\n}\n"],"mappings":"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"}
|