@wojciechpiskorz/astroix 0.0.26 → 0.0.28

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/chrome.js CHANGED
@@ -59530,16 +59530,17 @@ eJ.replaceSync($q), document.adoptedStyleSheets = [...document.adoptedStyleSheet
59530
59530
  //#endregion
59531
59531
  //#region src/client/entry.tsx
59532
59532
  var tJ = new Le();
59533
- function nJ() {
59534
- let e = document.getElementById("astroix-root");
59535
- if (e === null) throw Error("astroix: #astroix-root is missing from the chrome document");
59536
- let t = e.shadowRoot ?? e.attachShadow({ mode: "open" });
59537
- t.adoptedStyleSheets = [...t.adoptedStyleSheets, eJ], (0, Qt.createRoot)(t).render(/* @__PURE__ */ (0, g.jsx)(h.StrictMode, { children: /* @__PURE__ */ (0, g.jsx)(y, {
59533
+ function nJ(e) {
59534
+ let t = document.getElementById("astroix-root");
59535
+ if (t === null) throw Error("astroix: #astroix-root is missing from the chrome document");
59536
+ t.dataset.astroixChromeMode = e;
59537
+ let n = t.shadowRoot ?? t.attachShadow({ mode: "open" });
59538
+ n.adoptedStyleSheets = [...n.adoptedStyleSheets, eJ], (0, Qt.createRoot)(n).render(/* @__PURE__ */ (0, g.jsx)(h.StrictMode, { children: /* @__PURE__ */ (0, g.jsx)(y, {
59538
59539
  client: tJ,
59539
59540
  children: /* @__PURE__ */ (0, g.jsx)(Qq, {})
59540
59541
  }) }));
59541
59542
  }
59542
59543
  //#endregion
59543
59544
  //#region src/client/chrome.tsx
59544
- nJ();
59545
+ nJ("prebuilt");
59545
59546
  //#endregion
package/dist/index.js CHANGED
@@ -130,13 +130,10 @@ async function handleRoutes(_req, res, _url, ctx) {
130
130
  }
131
131
 
132
132
  // src/node/source-mode.ts
133
- import { existsSync } from "fs";
133
+ import { existsSync, realpathSync } from "fs";
134
134
  import { fileURLToPath, URL as NodeURL } from "url";
135
- var candidates = [
136
- fileURLToPath(new NodeURL("../../src/client/entry.tsx", import.meta.url)),
137
- fileURLToPath(new NodeURL("../src/client/entry.tsx", import.meta.url))
138
- ];
139
- var clientEntryPath = candidates.find((path) => existsSync(path)) ?? null;
135
+ var candidate = fileURLToPath(new NodeURL("../src/client/entry.tsx", import.meta.url));
136
+ var clientEntryPath = existsSync(candidate) ? realpathSync(candidate) : null;
140
137
  var chromeArtifactPath = fileURLToPath(
141
138
  new NodeURL("./chrome.js", import.meta.url)
142
139
  );
@@ -755,7 +752,7 @@ async function loadCollectionSchema(ctx, name) {
755
752
  });
756
753
  }
757
754
  function findContentConfigPath(srcDir) {
758
- const candidates2 = [
755
+ const candidates = [
759
756
  ["content.config.mjs", "content.config.js", "content.config.mts", "content.config.ts"].map(
760
757
  (name) => join2(srcDir, name)
761
758
  ),
@@ -763,7 +760,7 @@ function findContentConfigPath(srcDir) {
763
760
  (name) => join2(srcDir, "content", name)
764
761
  )
765
762
  ].flat();
766
- return candidates2.find((candidate) => existsSync3(candidate)) ?? null;
763
+ return candidates.find((candidate2) => existsSync3(candidate2)) ?? null;
767
764
  }
768
765
 
769
766
  // src/node/document-request.ts
@@ -1085,7 +1082,7 @@ function astroixVitePlugin(options) {
1085
1082
  if (id !== VIRTUAL_CHROME_ID) return null;
1086
1083
  if (clientEntryPath !== null) {
1087
1084
  return `import { mountChrome } from '/@fs${clientEntryPath}';
1088
- mountChrome();
1085
+ mountChrome('source');
1089
1086
  `;
1090
1087
  }
1091
1088
  if (!existsSync4(chromeArtifactPath)) {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/node/index.ts","../src/node/api.ts","../src/node/routes.ts","../src/node/source-mode.ts","../src/node/tailwind-guard.ts","../src/node/vite-plugin.ts","../src/node/chrome-html.ts","../src/node/chrome-reload-shield.ts","../src/node/content.ts","../src/core/form-tree.ts","../src/node/rest.ts","../src/core/indexer.ts","../src/core/splice-writer.ts","../src/node/document-request.ts","../src/node/route-enumeration.ts","../src/node/content-signal.ts","../src/node/paginate.ts","../src/node/watch-sync.ts"],"sourcesContent":["import { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport tailwindcss from '@tailwindcss/vite';\nimport react from '@vitejs/plugin-react';\nimport type { AstroIntegration } from 'astro';\nimport type { Plugin as VitePlugin } from 'vite';\nimport { captureRoutes, type RoutesState } from './routes';\nimport { clientEntryPath, isSourceMode } from './source-mode';\nimport { hostRegistersTailwind } from './tailwind-guard';\nimport { astroixVitePlugin } from './vite-plugin';\n\n/**\n * Canvas script injected into every dev page (the chrome document itself is\n * never Astro-rendered, so this only ever runs inside host pages). It decides\n * on its own whether it is the builder canvas: inside the iframe\n * (`window.parent !== window`) with `?builder=0`, it hides Astro's dev\n * toolbar — the toolbar stays available on normal page loads (spec #2).\n */\nconst CANVAS_SCRIPT = `if (window.parent !== window && new URLSearchParams(location.search).get('builder') === '0') {\n const style = document.createElement('style');\n style.textContent = 'astro-dev-toolbar{display:none!important}';\n document.head.append(style);\n}\n`;\n\n/**\n * Astroix — dev-only visual builder integration.\n *\n * In dev: the astroix Vite plugin serves the builder chrome over every\n * top-level URL (default-on) with the `?builder=0` escape hatch, and the\n * virtual chrome module delivers the app (source mode in this checkout per\n * ADR-0001; the prebuilt bundle lands with the chrome packaging slice).\n * Any other command registers nothing — the dev-only guarantee.\n */\nfunction astroix(): AstroIntegration {\n // Routes captured from the hook below and served at `GET /__astroix/routes`\n // (spec Impl #13). Lives on the integration instance so both hooks —\n // the writer and the plugin that serves the state — share one container\n // across dev restarts (restarts re-run the routes hook on the same instance).\n // The background enumeration (`route-enumeration.ts`) fills `renders` into\n // it and watches the captures through `onCapture` (#119).\n const routesState: RoutesState = { current: [], captured: [] };\n return {\n name: 'astroix',\n hooks: {\n 'astro:routes:resolved': ({ routes }) => {\n captureRoutes(routesState, routes);\n },\n 'astro:config:setup': ({ config, command, updateConfig, injectScript, logger }) => {\n if (command !== 'dev') return;\n\n // The resolved config turns dir strings into URLs (trailing slash included) —\n // the plugin wants clean paths.\n const plugins: VitePlugin[] = [\n astroixVitePlugin({ srcDir: fileURLToPath(config.srcDir), routes: routesState }),\n ];\n // The chrome sources live outside the host root and are served via\n // /@fs, which has two consequences fixed below: (a) deps discovered\n // from /@fs files resolve against the importer's location, so `react`\n // can enter the optimizer from two paths and mount twice (Invalid\n // hook call) — dedupe pins every resolution to the host root's React,\n // which in the dev checkout is our own 19; (b) HMR re-fetches carry a\n // `?t=` timestamp that misses the import-chain fs exemption — the\n // checkout root joins the allow list so chrome modules always serve.\n let vitePatch: {\n plugins: VitePlugin[];\n resolve?: { dedupe: string[] };\n server?: { fs: { allow: string[] } };\n } = { plugins };\n\n if (isSourceMode()) {\n // ADR-0001 source mode: chrome from this checkout's source, with\n // fast-refresh scoped to chrome files only (host code untouched).\n const clientDir = dirname(clientEntryPath ?? '');\n // compiler: true = React Compiler via oxc (stack #4: no manual memoization).\n plugins.push(\n ...react({\n include: new RegExp(`^${escapeRegExp(clientDir)}/.*\\\\.tsx?$`),\n compiler: true,\n }),\n );\n if (hostRegistersTailwind(config.vite)) {\n logger.info('host already registers @tailwindcss/vite — reusing it for the chrome');\n } else {\n plugins.push(...tailwindcss());\n }\n vitePatch = {\n plugins,\n resolve: { dedupe: ['react', 'react-dom'] },\n server: { fs: { allow: [dirname(dirname(clientDir))] } },\n };\n }\n\n updateConfig({ vite: vitePatch });\n injectScript('page', CANVAS_SCRIPT);\n },\n },\n };\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replaceAll(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport default astroix;\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { ViteDevServer } from 'vite';\nimport type { RoutesState } from './routes';\n\nconst API_PREFIX = '/__astroix';\n\n/** The shared server context every `/__astroix` handler may touch. */\nexport interface ApiContext {\n server: ViteDevServer;\n /** Absolute project root (Vite root) — the confinement root for file paths. */\n root: string;\n /** Absolute Astro src dir (css/astro sources to index, content config). */\n srcDir: string;\n /** Routes captured by the integration's `astro:routes:resolved` hook. */\n routes: RoutesState;\n}\n\n/**\n * One endpoint of the builder API. `path` is mount-relative (connect strips\n * the `/__astroix` prefix, so `GET /__astroix/index` arrives as `/index`).\n * A handler answers its request fully or throws — it never calls `next()`.\n */\nexport interface ApiHandler {\n method: 'GET' | 'POST';\n path: string;\n handle(req: IncomingMessage, res: ServerResponse, url: URL, ctx: ApiContext): Promise<void>;\n}\n\nexport interface ApiOptions {\n root: string;\n srcDir: string;\n routes: RoutesState;\n /** Endpoint handlers, contributed by the owning modules (rest, content, routes). */\n handlers: readonly ApiHandler[];\n}\n\n/**\n * Registers the chrome↔node contract on the Vite connect middleware\n * (core-reuse §2 — like core's `/_astro/status`, not Astro app middleware):\n * one `/__astroix` mount dispatching over a handler table keyed by\n * `method + path`, so the same-origin invariant is structural (checked once,\n * in the dispatcher) instead of conventional (per registrar). Handlers are\n * contributed by the owning modules — see each module for its endpoints.\n *\n * Same-origin only: a browser `sec-fetch-site` header that is not\n * same-origin/none is rejected (T2).\n */\nexport function registerApiEndpoints(server: ViteDevServer, options: ApiOptions): void {\n const table = new Map(\n options.handlers.map((handler) => [handlerKey(handler.method, handler.path), handler]),\n );\n // Two modules registering the same route would silently shadow — fail at\n // boot instead of at request time.\n if (table.size !== options.handlers.length) {\n throw new Error('astroix: duplicate route in the /__astroix handler table');\n }\n const ctx: ApiContext = {\n server,\n root: options.root,\n srcDir: options.srcDir,\n routes: options.routes,\n };\n server.middlewares.use(API_PREFIX, (req, res, next) => {\n void dispatchApi(req, res, next, table, ctx);\n });\n}\n\nasync function dispatchApi(\n req: IncomingMessage,\n res: ServerResponse,\n next: (err?: unknown) => void,\n table: ReadonlyMap<string, ApiHandler>,\n ctx: ApiContext,\n): Promise<void> {\n try {\n if (isCrossOriginTraffic(req)) {\n json(res, 403, { error: 'cross-origin builder traffic is not allowed' });\n return;\n }\n const url = new URL(req.url ?? '/', 'http://astroix.internal');\n // The middleware is mounted at /__astroix (connect strips the prefix),\n // so GET /__astroix/index arrives as /index.\n const handler = table.get(handlerKey(req.method ?? '', url.pathname));\n if (handler === undefined) {\n next();\n return;\n }\n await handler.handle(req, res, url, ctx);\n } catch (error) {\n next(error instanceof Error ? error : new Error(String(error)));\n }\n}\n\nfunction handlerKey(method: string, path: string): string {\n return `${method} ${path}`;\n}\n\n/**\n * The builder endpoints serve same-origin chrome traffic only: a browser\n * `sec-fetch-site` header that is not same-origin/none means cross-origin\n * (T2). Enforced once, by the `/__astroix` dispatcher.\n */\nexport function isCrossOriginTraffic(req: IncomingMessage): boolean {\n const secFetchSite = req.headers['sec-fetch-site'];\n return (\n typeof secFetchSite === 'string' && secFetchSite !== 'same-origin' && secFetchSite !== 'none'\n );\n}\n\nexport function json(res: ServerResponse, status: number, body: unknown): void {\n res.statusCode = status;\n res.setHeader('content-type', 'application/json; charset=utf-8');\n res.end(JSON.stringify(body));\n}\n\nconst MAX_BODY_BYTES = 1_000_000;\n\n/** The shared JSON body reader for the POST endpoints (capped, rejects bad JSON). */\nexport function readJsonBody(req: IncomingMessage): Promise<unknown> {\n return new Promise((resolveBody, reject) => {\n const chunks: Buffer[] = [];\n let size = 0;\n req.on('data', (chunk: Buffer) => {\n size += chunk.length;\n if (size > MAX_BODY_BYTES) {\n reject(new Error('request body too large'));\n req.destroy();\n return;\n }\n chunks.push(chunk);\n });\n req.on('end', () => {\n try {\n resolveBody(JSON.parse(Buffer.concat(chunks).toString('utf8')));\n } catch {\n reject(new Error('request body is not valid JSON'));\n }\n });\n req.on('error', reject);\n });\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { IntegrationResolvedRoute } from 'astro';\nimport type { RouteInfo } from '../core/route-resolver';\nimport { type ApiContext, type ApiHandler, json } from './api';\n\n/**\n * Shared container between the `astro:routes:resolved` hook (writer) and the\n * REST layer (reader). The hook's sync projection lands in `current`\n * immediately; `renders` is filled into it later by the background\n * enumeration pass (`route-enumeration.ts`) — `GET /__astroix/routes` never\n * awaits that pass (#119).\n */\nexport interface RoutesState {\n /** The served payload — the sync hook projection, `renders` merged in place. */\n current: RouteInfo[];\n /**\n * The hook's raw capture — the enumeration's input (entrypoint,\n * `isPrerendered`, params). Replaced whole on every hook run.\n */\n captured: readonly IntegrationResolvedRoute[];\n /**\n * Fired by `captureRoutes` on every hook capture with whether the served\n * projection changed (preserved `renders` aside); set by the enumeration\n * registration, which owns the server handles (latest server wins across\n * dev restarts — the integration instance persists).\n */\n onCapture?: (changed: boolean) => void;\n}\n\n/**\n * Projects hook routes to the `RouteInfo` contract of `src/core/route-resolver`\n * (single source of truth per the core-first ruling on PR #77): page routes\n * only — the resolver's contract filters out `endpoint`/`redirect`/`fallback`\n * types and Astro-core `internal`-origin routes (e.g. the dev server-islands\n * route `/_server-islands/[name]`, which would otherwise resolve as a\n * same-shape candidate and navigate to a 404, #109) — with Astro's own\n * `segments` parse carried along, deep-copied so no live core object is held\n * between hook runs. `rendering` rides from the hook's `isPrerendered` —\n * free and synchronous (#119); `renders` is not projected here: enumeration\n * owns it.\n */\nexport function toRouteInfos(routes: readonly IntegrationResolvedRoute[]): RouteInfo[] {\n return routes.flatMap((route) => {\n if (!isProjectPageRoute(route)) return [];\n return [\n {\n pattern: route.pattern,\n segments: route.segments.map((segment) => segment.map((part) => ({ ...part }))),\n params: [...route.params],\n rendering: route.isPrerendered ? 'prerendered' : 'on-demand',\n },\n ];\n });\n}\n\n/**\n * The routes-payload membership rule — the same filter the enumeration pass\n * applies over the raw capture, so served patterns and enumerated patterns\n * can never drift.\n */\nexport function isProjectPageRoute(route: IntegrationResolvedRoute): boolean {\n return route.type === 'page' && route.origin !== 'internal';\n}\n\n/**\n * The `astro:routes:resolved` writer: replaces the raw capture, reprojects\n * `current`, and preserves already-enumerated `renders` by pattern — a\n * re-capture with unchanged routes leaves the served payload byte-identical\n * (no push), and a stale `renders` can only keep a candidate alive through\n * the ms-scale window until the next pass re-verifies it, never fire the\n * marker wrongly (unknown never fires, #119's silent-never-wrong).\n */\nexport function captureRoutes(\n state: RoutesState,\n routes: readonly IntegrationResolvedRoute[],\n): void {\n state.captured = routes;\n const previous = new Map(state.current.map((info) => [info.pattern, info.renders]));\n const next = toRouteInfos(routes).map((info) => {\n const renders = previous.get(info.pattern);\n return renders === undefined ? info : { ...info, renders };\n });\n const changed = !samePayload(next, state.current);\n state.current = next;\n state.onCapture?.(changed);\n}\n\n/**\n * Merges enumeration results into the served payload: an entry sets `renders`\n * (a `[]` is knowably-dead truth, not unknown), a missing entry means the\n * route's enumeration did not positively succeed — `renders` comes off.\n * Returns whether the payload changed (the caller's push signal).\n */\nexport function applyRenders(\n state: RoutesState,\n renders: ReadonlyMap<string, ReadonlyArray<string>>,\n): boolean {\n let changed = false;\n state.current = state.current.map((info) => {\n const values = renders.get(info.pattern);\n if (values === undefined) {\n if (info.renders !== undefined) changed = true;\n return { ...info, renders: undefined };\n }\n if (samePayload(values, info.renders)) return info;\n changed = true;\n return { ...info, renders: [...values] };\n });\n return changed;\n}\n\n/** Payload equality over the projection's small JSON shape (stable key order). */\nfunction samePayload(a: unknown, b: unknown): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n}\n\n/**\n * `GET /__astroix/routes` — the routes array captured from\n * `astro:routes:resolved` (re-runs on route changes via dev restarts).\n * Served synchronously from the container: the background enumeration fills\n * `renders` into the same array slots, and its completion pushes the\n * `astroix:routes-changed` WS event so the chrome refetches (#119). A\n * routing concern, not a content one: the concept grows from here — the\n * resolver (#69) and the overrides-file naming both key on route patterns.\n */\nexport const routesHandlers: readonly ApiHandler[] = [\n { method: 'GET', path: '/routes', handle: handleRoutes },\n];\n\nasync function handleRoutes(\n _req: IncomingMessage,\n res: ServerResponse,\n _url: URL,\n ctx: ApiContext,\n): Promise<void> {\n json(res, 200, ctx.routes.current);\n}\n","import { existsSync } from 'node:fs';\nimport { fileURLToPath, URL as NodeURL } from 'node:url';\n\n/**\n * Dev-checkout detection for the ADR-0001 mode switch: the chrome client\n * sources exist next to the integration only when the package runs from this\n * repo (an installed package ships no `src/`). Two candidate depths because\n * this module executes from `src/node/` during development and from the\n * bundled `dist/index.js` at runtime. `URL` comes from `node:url` because\n * happy-dom (unit tests) patches the global `URL` with its own class, which\n * `fileURLToPath` rejects.\n */\nconst candidates = [\n fileURLToPath(new NodeURL('../../src/client/entry.tsx', import.meta.url)),\n fileURLToPath(new NodeURL('../src/client/entry.tsx', import.meta.url)),\n];\n\nexport const clientEntryPath: string | null = candidates.find((path) => existsSync(path)) ?? null;\n\n/**\n * The prebuilt chrome bundle (ADR-0001): a self-contained ESM shipped inside\n * `dist/`. Served by the virtual chrome module when the dev-checkout sources\n * are absent — the consumer-facing delivery mode.\n */\nexport const chromeArtifactPath: string = fileURLToPath(\n new NodeURL('./chrome.js', import.meta.url),\n);\n\nexport function isSourceMode(): boolean {\n return clientEntryPath !== null;\n}\n","import type { AstroUserConfig } from 'astro';\n\n/**\n * Guard: skip our Tailwind plugin when the host already registered one.\n * The `@tailwindcss/vite` factory returns an array whose plugin names start\n * with `@tailwindcss/vite:` (verified on 4.x) — that prefix is the check.\n */\nexport function hostRegistersTailwind(viteConfig: AstroUserConfig['vite']): boolean {\n const seen = new Set<string>();\n const walk = (input: unknown): void => {\n if (Array.isArray(input)) {\n for (const entry of input) walk(entry);\n return;\n }\n if (!input || typeof input !== 'object') return;\n const plugin = input as { name?: unknown };\n if (typeof plugin.name === 'string') seen.add(plugin.name);\n };\n walk(viteConfig?.plugins);\n for (const name of seen) {\n if (name.startsWith('@tailwindcss/vite')) return true;\n }\n return false;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { Plugin, ViteDevServer } from 'vite';\nimport { registerApiEndpoints } from './api';\nimport { chromeHtml } from './chrome-html';\nimport { registerChromeReloadShield } from './chrome-reload-shield';\nimport { contentHandlers } from './content';\nimport { isDocumentRequest } from './document-request';\nimport { restHandlers } from './rest';\nimport { registerRouteEnumeration } from './route-enumeration';\nimport { type RoutesState, routesHandlers } from './routes';\nimport { chromeArtifactPath, clientEntryPath } from './source-mode';\nimport { registerFileSync } from './watch-sync';\n\nexport const VIRTUAL_CHROME_ID = 'virtual:astroix/chrome';\n\nexport interface AstroixPluginOptions {\n /** Absolute Astro src dir with the sources to index; defaults to `<root>/src`. */\n srcDir?: string;\n /** Routes captured by the integration's `astro:routes:resolved` hook, served at `/__astroix/routes`. */\n routes: RoutesState;\n}\n\n/**\n * The astroix Vite plugin: default-on chrome over every top-level dev URL.\n * The middleware is registered in the body of `configureServer` (pre-internal)\n * because Astro's dev handler lives in a post-hook and never calls `next()` —\n * this is the only position that sees every request (core-reuse §1). The\n * chrome HTML passes through `server.transformIndexHtml` (the plugin hook\n * never fires for Astro pages, the server API does) which injects the Vite\n * client and the plugin-react preamble.\n */\nexport function astroixVitePlugin(options: AstroixPluginOptions): Plugin {\n return {\n name: 'astroix',\n configureServer(server: ViteDevServer) {\n server.middlewares.use((req, res, next) => {\n void (async () => {\n try {\n const url = req.url ?? '/';\n if (\n !isDocumentRequest({ method: req.method ?? 'GET', url, accept: req.headers.accept })\n ) {\n next();\n return;\n }\n const html = await server.transformIndexHtml(url, chromeHtml());\n res.statusCode = 200;\n res.setHeader('content-type', 'text/html; charset=utf-8');\n res.end(html);\n } catch (error) {\n next(error instanceof Error ? error : new Error(String(error)));\n }\n })();\n });\n const srcDir = options.srcDir ?? join(server.config.root, 'src');\n registerApiEndpoints(server, {\n root: server.config.root,\n srcDir,\n routes: options.routes,\n handlers: [...restHandlers, ...contentHandlers, ...routesHandlers],\n });\n // the background getStaticPaths pass — fills `renders` into the routes\n // payload and pushes `astroix:routes-changed` when it lands (#119)\n registerRouteEnumeration(server, {\n root: server.config.root,\n srcDir,\n routes: options.routes,\n });\n registerFileSync(server, { root: server.config.root, srcDir });\n registerChromeReloadShield(server);\n },\n resolveId(id) {\n // The HTML references `/virtual:astroix/chrome`; imports may use the bare id.\n if (id === VIRTUAL_CHROME_ID || id === `/${VIRTUAL_CHROME_ID}`) {\n return VIRTUAL_CHROME_ID;\n }\n return null;\n },\n load(id) {\n if (id !== VIRTUAL_CHROME_ID) return null;\n if (clientEntryPath !== null) {\n // ADR-0001 source mode: the chrome loads from this checkout's source,\n // so the host dev server transforms it (fast-refresh, Tailwind).\n return `import { mountChrome } from '/@fs${clientEntryPath}';\\nmountChrome();\\n`;\n }\n // ADR-0001 prebuilt mode: serve the shipped bundle — a self-contained\n // ESM with react, the compiled CSS and CodeMirror inside, so foreign\n // hosts resolve none of our chrome dependencies. Missing artifact =\n // broken package build; fail loudly, never silently (ADR-0001).\n if (!existsSync(chromeArtifactPath)) {\n throw new Error(\n 'astroix: prebuilt chrome bundle is missing from the package build (expected dist/chrome.js)',\n );\n }\n return readFileSync(chromeArtifactPath, 'utf8');\n },\n };\n}\n","/**\n * The chrome document shell: a mount point and the virtual-module reference.\n * Layout lives inside the shadow root (React app); the document only resets\n * geometry so the shadow host can fill the viewport.\n */\nexport function chromeHtml(): string {\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>astroix builder</title>\n <style>\n html, body { margin: 0; height: 100%; }\n #astroix-root { display: block; height: 100vh; }\n </style>\n </head>\n <body>\n <div id=\"astroix-root\"></div>\n <script type=\"module\" src=\"/virtual:astroix/chrome\"></script>\n </body>\n</html>`;\n}\n","import type { ViteDevServer } from 'vite';\n\n/**\n * The chrome's full-reload shield (spec #13/#74): Astro's content sync\n * broadcasts a vite `full-reload` to every connected page — the canvas\n * iframe is one (it reloads exactly as Astro intends, the live preview), but\n * so is the chrome, whose in-memory session (open tab, active entry, dirty\n * draft) a reload would destroy on every write pause. The chrome announces\n * itself over the hot channel; the shield reroutes `full-reload` broadcasts\n * around announced clients only — every other page (canvas, the host\n * developer's own tabs) keeps Astro's behavior untouched. Custom events and\n * module updates flow to everyone as before; a vite whose internals move\n * past this seam degrades to today's behavior (the chrome reloads).\n */\n\n/** The public slice of vite's per-socket client wrapper the shield consumes. */\ninterface HotClient {\n send: (payload: unknown) => void;\n /** WebSocket readyState — 1 is OPEN; sends on dead sockets throw. */\n socket: { readyState: number };\n}\n\n/** The structural slice of vite's ws wrapper (`server.ws`/`server.hot`). */\ninterface HotChannel {\n // the wrapper accepts both a payload object and the (event, data) custom form\n send: (payload: unknown, ...rest: unknown[]) => void;\n on: (event: string, handler: (data: unknown, client: HotClient) => void) => void;\n clients: Set<HotClient>;\n}\n\nexport function registerChromeReloadShield(server: ViteDevServer): void {\n const channel = server.ws as unknown as HotChannel;\n const chromeClients = new Set<HotClient>();\n\n channel.on('astroix:chrome', (_data, client) => {\n // prune clients whose socket left the channel (chrome reloads/remounts)\n // while adding the announcer — dev scale makes this cheap, not urgent\n for (const known of chromeClients) {\n if (!channel.clients.has(known)) chromeClients.delete(known);\n }\n chromeClients.add(client);\n });\n\n const broadcast = channel.send.bind(channel);\n channel.send = (payload: unknown, ...rest: unknown[]) => {\n if (\n typeof payload === 'object' &&\n (payload as { type?: string } | null)?.type === 'full-reload'\n ) {\n // vite's own broadcast only sends to OPEN sockets — a send on a dying\n // one throws, and the throw would kill whatever pipeline called us\n // (astro's content sync wedges mid-flight); skip exactly like vite,\n // and never let a stray send failure escape either\n for (const client of channel.clients) {\n if (chromeClients.has(client) || client.socket.readyState !== 1) continue;\n try {\n client.send(payload);\n } catch {\n // the socket died between the check and the send — its page\n // reconnects and reloads on the next broadcast\n }\n }\n return;\n }\n broadcast(payload, ...rest);\n };\n}\n","import { existsSync } from 'node:fs';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { join } from 'node:path';\nimport { z } from 'astro/zod';\nimport { createServerModuleRunner } from 'vite';\nimport type { CollectionEntryRecord, CollectionRecord } from '../core/collections';\nimport {\n type IssueLike,\n toIssueRecords,\n type ValidationIssueRecord,\n walkSchemaFields,\n} from '../core/form-tree';\nimport { type ApiContext, type ApiHandler, json, readJsonBody } from './api';\nimport { writeGuarded } from './rest';\n\n/** The content endpoints: read-side (core-reuse §3) and the auto-write (Impl #9). */\nexport const contentHandlers: readonly ApiHandler[] = [\n { method: 'GET', path: '/collections', handle: handleCollections },\n { method: 'GET', path: '/content-schema', handle: handleContentSchema },\n { method: 'POST', path: '/content-validate', handle: handleContentValidate },\n { method: 'POST', path: '/content-write', handle: handleContentWrite },\n];\n\n/**\n * `GET /__astroix/collections` — collections + entries through core's own\n * `astro:content` module: parsed `data`, `body`, `filePath` per entry, plus\n * schema presence from the content config. **Stateless doctrine**: a fresh\n * module runner per request, no module held between requests — core clears\n * its caches on invalidation, so anything we cache would go stale. Raw entry\n * bytes go through the root-confined `GET /__astroix/file` (rest.ts).\n */\nasync function handleCollections(\n _req: IncomingMessage,\n res: ServerResponse,\n _url: URL,\n ctx: ApiContext,\n): Promise<void> {\n const payload = await withContentConfig(ctx, async (runner, configModule) => {\n const contentModule = (await runner.import('astro:content')) as RawContentModule;\n return assembleCollectionsPayload(configModule, contentModule);\n });\n json(res, 200, payload);\n}\n\n/**\n * The stateless-doctrine sequence every content endpoint starts with: one\n * fresh module runner per request (nothing held between requests — core\n * clears its caches on invalidation), importing the user's content config\n * as the runner evaluates it. The runner closes when `use` settles: its\n * transport pins a `send` listener on the ssr hot channel, and a fresh\n * runner per request leaks one listener each otherwise (#146).\n */\nasync function withContentConfig<T>(\n ctx: ApiContext,\n use: (\n runner: ReturnType<typeof createServerModuleRunner>,\n configModule: RawContentConfig | null,\n ) => Promise<T>,\n): Promise<T> {\n const runner = createServerModuleRunner(ctx.server.environments.ssr);\n try {\n const configPath = findContentConfigPath(ctx.srcDir);\n const configModule =\n configPath === null ? null : ((await runner.import(configPath)) as RawContentConfig);\n return await use(runner, configModule);\n } finally {\n // teardown of dev-only listener noise must not mask the endpoint's result\n await runner.close().catch(() => {});\n }\n}\n\n/** The user's `content.config` module as the runner evaluates it. */\nexport interface RawContentConfig {\n collections?: unknown;\n}\n\n/** `astro:content` as the runner evaluates it — only the surface this module consumes. */\nexport interface RawContentModule {\n getCollection?: (name: string) => Promise<unknown[]>;\n}\n\n/**\n * Joins the config's collection definitions (names, schema presence) with\n * core's `getCollection` results. Deterministic: collections and entries are\n * name/id-sorted regardless of store iteration order.\n */\nexport async function assembleCollectionsPayload(\n configModule: RawContentConfig | null,\n contentModule: RawContentModule,\n): Promise<CollectionRecord[]> {\n const definitions = toDefinitionMap(configModule?.collections);\n const collections: CollectionRecord[] = [];\n for (const name of Object.keys(definitions).sort()) {\n const entries = await loadEntries(contentModule, name);\n collections.push({ name, hasSchema: definitions[name]?.schema !== undefined, entries });\n }\n return collections;\n}\n\n/** `Record<string, { schema?: unknown }>` or an empty record — never throws on a malformed config. */\nfunction toDefinitionMap(collections: unknown): Record<string, { schema?: unknown }> {\n if (typeof collections !== 'object' || collections === null) return {};\n const definitions: Record<string, { schema?: unknown }> = {};\n for (const [name, definition] of Object.entries(collections)) {\n if (typeof definition === 'object' && definition !== null) {\n definitions[name] = definition as { schema?: unknown };\n }\n }\n return definitions;\n}\n\nasync function loadEntries(\n contentModule: RawContentModule,\n name: string,\n): Promise<CollectionEntryRecord[]> {\n const raw = (await contentModule.getCollection?.(name)) ?? [];\n return (\n raw\n .filter(\n (entry): entry is { id: string; filePath?: unknown; data?: unknown; body?: unknown } =>\n typeof entry === 'object' &&\n entry !== null &&\n typeof (entry as { id?: unknown }).id === 'string',\n )\n .map((entry) => ({\n id: entry.id,\n filePath: typeof entry.filePath === 'string' ? entry.filePath : null,\n data: entry.data ?? null,\n body: typeof entry.body === 'string' ? entry.body : null,\n }))\n // Code-unit order, like the collection-name sort above — localeCompare\n // follows process collation, which can order ids per machine.\n .sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))\n );\n}\n\n/**\n * `GET /__astroix/content-schema?collection=<name>` — the collection's schema\n * walked into the JSON field tree the chrome renders widgets from (#72).\n * Schema-less collections and non-object roots degrade to a root raw field:\n * every collection opens in the builder regardless of its schema's shape.\n */\nasync function handleContentSchema(\n _req: IncomingMessage,\n res: ServerResponse,\n url: URL,\n ctx: ApiContext,\n): Promise<void> {\n const loaded = await loadCollectionSchema(ctx, url.searchParams.get('collection'));\n if (loaded === null) {\n json(res, 400, { error: 'collection query parameter is missing or unknown' });\n return;\n }\n const fields = walkSchemaFields(loaded.resolved.schema, {\n isImage: (schema) => loaded.resolved.imageStubs.has(schema as object),\n });\n json(res, 200, { collection: loaded.name, fields });\n}\n\n/**\n * `POST /__astroix/content-validate?collection=<name>` — safeParse of the\n * chrome's draft against the same schema instance the form was generated\n * from (the repo-mapping doctrine: no parallel schema reconstruction\n * client-side). Advisory only: issues render inline and never gate anything\n * (US12) — this slice has no write to gate.\n */\nasync function handleContentValidate(\n req: IncomingMessage,\n res: ServerResponse,\n url: URL,\n ctx: ApiContext,\n): Promise<void> {\n const loaded = await loadCollectionSchema(ctx, url.searchParams.get('collection'));\n if (loaded === null) {\n json(res, 400, { error: 'collection query parameter is missing or unknown' });\n return;\n }\n let data: unknown;\n try {\n data = await readJsonBody(req);\n } catch (error) {\n json(res, 400, { error: error instanceof Error ? error.message : 'unreadable body' });\n return;\n }\n const issues = await validateDraft(loaded.resolved.schema, data);\n json(res, 200, { ok: issues.length === 0, issues });\n}\n\n/** Minimal structural surface of a zod schema's async parse. */\ninterface AsyncSafeParse {\n safeParseAsync?: (\n input: unknown,\n ) => Promise<{ success: true } | { success: false; error: { issues: readonly IssueLike[] } }>;\n}\n\n/**\n * `POST /__astroix/content-write` — the content auto-write's whole-file write\n * (spec Impl #9): the chrome serializes the entry (core's entry-writer) and\n * posts the full bytes with the hash of the baseline it serialized from.\n * `writeGuarded` owns the shared hash-guard skeleton (Impl #10).\n */\nasync function handleContentWrite(\n req: IncomingMessage,\n res: ServerResponse,\n _url: URL,\n ctx: ApiContext,\n): Promise<void> {\n let body: unknown;\n try {\n body = await readJsonBody(req);\n } catch (error) {\n json(res, 400, { error: error instanceof Error ? error.message : 'unreadable body' });\n return;\n }\n const { file, contents, expected } = parseWriteBody(body);\n if (file === null || contents === null) {\n json(res, 400, { error: 'expected { file, contents }' });\n return;\n }\n await writeGuarded(res, ctx, file, expected, () => contents);\n}\n\nfunction parseWriteBody(body: unknown): {\n file: string | null;\n contents: string | null;\n expected: string | null;\n} {\n if (body === null || typeof body !== 'object') {\n return { file: null, contents: null, expected: null };\n }\n const { file, contents, expected } = body as Record<string, unknown>;\n return {\n file: typeof file === 'string' ? file : null,\n contents: typeof contents === 'string' ? contents : null,\n expected: typeof expected === 'string' ? expected : null,\n };\n}\n\n/**\n * Runs safeParseAsync and projects the issues. A schema that cannot parse\n * under introspection validates as clean — validation is advisory, and a\n * throwing parse must not 500 the typing loop.\n */\nexport async function validateDraft(\n schema: unknown,\n data: unknown,\n): Promise<ValidationIssueRecord[]> {\n const parse = (schema as AsyncSafeParse | null)?.safeParseAsync;\n if (parse === undefined) return [];\n try {\n const result = await parse.call(schema, data);\n return result.success ? [] : toIssueRecords(result.error.issues);\n } catch {\n return [];\n }\n}\n\n/** A collection schema resolved for walking: the instance plus our image stubs. */\nexport interface ResolvedCollectionSchema {\n schema: unknown;\n imageStubs: Set<object>;\n}\n\n/** Astro's function-schema service bag — only the `image` seam is consumed. */\ntype SchemaFunction = (services: { image: () => unknown }) => unknown;\n\n/**\n * Resolves a collection's schema out of the evaluated content config:\n * static schemas pass through; function schemas (astro's `({ image }) => …`\n * form) are called once with our own image stubs — `z.any()` instances whose\n * Set membership the walker reads through the injected `isImage` predicate.\n * The real `image()` is `z.string().transform(...)` with a Vite-bound\n * resolver, unwalkable and indistinguishable from user transforms — the\n * permissive stub keeps safeParse off read-only fields while marking them.\n * A function schema that throws under introspection degrades to no schema\n * (the raw-field root) — every collection still opens.\n */\nexport function resolveCollectionSchema(\n configModule: RawContentConfig | null,\n name: string,\n): ResolvedCollectionSchema | null {\n const definition = toDefinitionMap(configModule?.collections)[name];\n if (definition === undefined) return null;\n const imageStubs = new Set<object>();\n const raw = definition.schema;\n if (typeof raw !== 'function') return { schema: raw ?? null, imageStubs };\n try {\n const schema = (raw as SchemaFunction)({ image: () => imageStub(imageStubs) });\n return { schema, imageStubs };\n } catch {\n return { schema: null, imageStubs };\n }\n}\n\nfunction imageStub(stubs: Set<object>): unknown {\n // fresh instance per call — membership never collides with a user's z.any()\n const stub = z.any();\n stubs.add(stub);\n return stub;\n}\n\n/** Fresh-runner schema load shared by the schema and validate endpoints. */\nasync function loadCollectionSchema(\n ctx: ApiContext,\n name: string | null,\n): Promise<{ name: string; resolved: ResolvedCollectionSchema } | null> {\n if (name === null) return null;\n return withContentConfig(ctx, async (_runner, configModule) => {\n const resolved = resolveCollectionSchema(configModule, name);\n return resolved === null ? null : { name, resolved };\n });\n}\n\n/**\n * The content config path, mirroring core's search order\n * (`src/content.config.{mjs,js,mts,ts}`, then the legacy `src/content/config.*`).\n */\nexport function findContentConfigPath(srcDir: string): string | null {\n const candidates = [\n ['content.config.mjs', 'content.config.js', 'content.config.mts', 'content.config.ts'].map(\n (name) => join(srcDir, name),\n ),\n ['config.ts', 'config.js', 'config.mjs', 'config.mts'].map((name) =>\n join(srcDir, 'content', name),\n ),\n ].flat();\n return candidates.find((candidate) => existsSync(candidate)) ?? null;\n}\n","/**\n * The schema def-walk (spec Impl #4, #72): a pure, structural walk over a\n * zod 4 schema's `_zod.def` tree producing the JSON field tree the chrome\n * renders widgets from. Structural on purpose — the walked instance comes\n * from the project's own zod through the module runner, and nothing here\n * instanceof-checks against a second zod copy (\"no instanceof hell\", ticket\n * #72). `z.toJSONSchema()` is deliberately not used: it loses zod-specific\n * shapes (astro's `image()`, function schemas, wrappers) that the walk reads\n * directly.\n */\n\n/** A leaf widget kind. `image` renders read-only metadata (picker deferred). */\nexport type PrimitiveKind = 'string' | 'number' | 'boolean' | 'enum' | 'image';\n\n/** The `enum` options as declared (strings, or numbers via nativeEnum). */\nexport type EnumOptions = (string | number)[];\n\ninterface NodeBase {\n /** Dotted path into the entry's data (`cta.label`); `''` = the whole frontmatter. */\n path: string;\n /** Last path segment, human-facing. */\n label: string;\n /** False when any optional/nullable/default wrapper was peeled. */\n required: boolean;\n /** The schema's `defaultValue` when present (zod fills it into `entry.data` too). */\n initial?: unknown;\n}\n\nexport interface StringFieldNode extends NodeBase {\n kind: 'string';\n}\nexport interface NumberFieldNode extends NodeBase {\n kind: 'number';\n}\nexport interface BooleanFieldNode extends NodeBase {\n kind: 'boolean';\n}\nexport interface EnumFieldNode extends NodeBase {\n kind: 'enum';\n options: EnumOptions;\n}\n/** Read-only `src`/`width`/`height` from `entry.data`; the value round-trips untouched. */\nexport interface ImageFieldNode extends NodeBase {\n kind: 'image';\n}\n/** Array of primitives → repeatable rows; anything else walks to a raw field. */\nexport interface ArrayFieldNode extends NodeBase {\n kind: 'array';\n item: { kind: 'string' | 'number' | 'boolean' | 'enum'; options?: EnumOptions };\n}\n/** Nested object → fieldset. */\nexport interface GroupFieldNode extends NodeBase {\n kind: 'group';\n children: FormFieldNode[];\n}\n/**\n * The raw field (glossary): a clearly-marked textarea holding that subtree's\n * YAML — the convention resolving every unsupported schema node (unions,\n * transforms/pipes, records, dates, literals…): every schema opens in the\n * builder, odd fields stay editable, just widgetless.\n */\nexport interface RawFieldNode extends NodeBase {\n kind: 'raw';\n /** The zod def type that fell through the mapping. */\n reason: string;\n}\n\nexport type FormFieldNode =\n | StringFieldNode\n | NumberFieldNode\n | BooleanFieldNode\n | EnumFieldNode\n | ImageFieldNode\n | ArrayFieldNode\n | GroupFieldNode\n | RawFieldNode;\n\nexport interface WalkOptions {\n /**\n * Recognizes astro's `image()` schemas. Astro injects `image()` into\n * function schemas (`schema: ({ image }) => …`) and its real form is\n * `z.string().transform(...)` — indistinguishable from any user transform.\n * The server-side resolver substitutes its own stub instances and passes\n * their membership here; by default nothing is an image.\n */\n isImage?: (schema: unknown) => boolean;\n}\n\n/** One zod issue as served to the chrome (`POST /__astroix/content-validate`). */\nexport interface ValidationIssueRecord {\n /** Dotted path into the draft (`cta.label`, `tags.0`); `''` = the root. */\n path: string;\n code: string;\n message: string;\n}\n\n/** The structural slice of a zod issue `toIssueRecords` consumes. */\nexport interface IssueLike {\n path?: readonly PropertyKey[];\n code?: unknown;\n message: unknown;\n}\n\n/** Maps zod's issues to the served records — structural (path keys join by code unit). */\nexport function toIssueRecords(issues: Iterable<IssueLike>): ValidationIssueRecord[] {\n const records: ValidationIssueRecord[] = [];\n for (const issue of issues) {\n const path = (issue.path ?? [])\n .filter((key): key is string | number => typeof key === 'string' || typeof key === 'number')\n .join('.');\n records.push({\n path,\n code: typeof issue.code === 'string' ? issue.code : 'unknown',\n message: typeof issue.message === 'string' ? issue.message : String(issue.message),\n });\n }\n return records;\n}\n\n/**\n * Walks a collection schema into the field tree. The root is expected to be\n * an object (astro's frontmatter shape) — its children come back; any other\n * root (or no schema at all) degrades to a single root raw field, so every\n * collection opens in the builder regardless of its schema's shape.\n */\nexport function walkSchemaFields(schema: unknown, options: WalkOptions = {}): FormFieldNode[] {\n const root = walkNode(schema, '', 'frontmatter', options);\n return root.kind === 'group' ? root.children : [root];\n}\n\n/**\n * Dotted paths of the image-kind fields — the auto-write's never-touch list:\n * the draft carries zod output (ImageMetadata) there, while the frontmatter\n * value round-trips byte-identical (spec Impl #4). Arrays can't hide images\n * (their items are primitives), so only groups recurse.\n */\nexport function collectImagePaths(fields: readonly FormFieldNode[]): string[] {\n const paths: string[] = [];\n for (const field of fields) {\n if (field.kind === 'image') paths.push(field.path);\n else if (field.kind === 'group') paths.push(...collectImagePaths(field.children));\n }\n return paths;\n}\n\ninterface Peeled {\n schema: unknown;\n required: boolean;\n initial: unknown;\n hasInitial: boolean;\n}\n\n/** Peels the widget-neutral wrappers, collecting optionality and defaults. */\nfunction peelWrappers(schema: unknown): Peeled {\n let peeled: Peeled = { schema, required: true, initial: undefined, hasInitial: false };\n for (let guard = 0; guard < 32; guard += 1) {\n const def = zodDef(peeled.schema);\n if (def === null) break;\n if (def.type === 'optional' || def.type === 'nullable') {\n peeled = { ...peeled, schema: def.innerType, required: false };\n continue;\n }\n if (def.type === 'default') {\n peeled = {\n schema: def.innerType,\n required: false,\n initial: def.defaultValue,\n hasInitial: def.defaultValue !== undefined,\n };\n continue;\n }\n if (def.type === 'readonly' || def.type === 'catch') {\n peeled = { ...peeled, schema: def.innerType };\n continue;\n }\n break;\n }\n return peeled;\n}\n\nfunction walkNode(\n schema: unknown,\n path: string,\n label: string,\n options: WalkOptions,\n): FormFieldNode {\n const peeled = peelWrappers(schema);\n const base = {\n path,\n label,\n required: peeled.required,\n ...(peeled.hasInitial ? { initial: peeled.initial } : {}),\n };\n\n if (options.isImage?.(peeled.schema)) {\n return { kind: 'image', ...base };\n }\n\n const def = zodDef(peeled.schema);\n if (def?.type === undefined) {\n return { kind: 'raw', reason: 'unwalkable', ...base };\n }\n\n switch (def.type) {\n case 'string':\n return { kind: 'string', ...base };\n case 'number':\n return { kind: 'number', ...base };\n case 'boolean':\n return { kind: 'boolean', ...base };\n case 'enum':\n return {\n kind: 'enum',\n options: Object.values((def.entries ?? {}) as Record<string, string | number>),\n ...base,\n };\n case 'object': {\n const shape = def.shape;\n if (typeof shape !== 'object' || shape === null) {\n return { kind: 'raw', reason: def.type, ...base };\n }\n const children = Object.entries(shape).map(([key, child]) =>\n walkNode(child, path === '' ? key : `${path}.${key}`, key, options),\n );\n return { kind: 'group', children, ...base };\n }\n case 'array': {\n const item = peelWrappers(def.element);\n const itemDef = zodDef(item.schema);\n const itemTypeEnum = itemDef?.type;\n const itemKind =\n itemTypeEnum === 'string' ||\n itemTypeEnum === 'number' ||\n itemTypeEnum === 'boolean' ||\n itemTypeEnum === 'enum'\n ? itemTypeEnum\n : null;\n if (itemKind === null) {\n return {\n kind: 'raw',\n reason: `${def.type}<${itemTypeEnum ?? 'unknown'}>`,\n ...base,\n };\n }\n return {\n kind: 'array',\n item: {\n kind: itemKind,\n ...(itemTypeEnum === 'enum'\n ? {\n options: Object.values((itemDef?.entries ?? {}) as Record<string, string | number>),\n }\n : {}),\n },\n ...base,\n };\n }\n default:\n // union, record, literal, date, pipe (transforms), intersection, tuple,\n // lazy, any, unknown… — the raw-field convention's whole catalogue\n return { kind: 'raw', reason: def.type, ...base };\n }\n}\n\n/**\n * The structural slice of a zod 4 `_zod.def` the walk consumes — typed to\n * keep the switch narrow; every field is optional because defs are open.\n */\ninterface ZodDef {\n type?: string;\n innerType?: unknown;\n defaultValue?: unknown;\n entries?: Record<string, unknown>;\n shape?: Record<string, unknown>;\n element?: unknown;\n}\n\n/** `_zod.def` when present, else null — zod 4's structural contract. */\nfunction zodDef(schema: unknown): ZodDef | null {\n if (typeof schema !== 'object' || schema === null) return null;\n const holder = (schema as { _zod?: { def?: unknown } })._zod;\n if (typeof holder !== 'object' || holder === null) return null;\n if (typeof holder.def !== 'object' || holder.def === null) return null;\n return holder.def as ZodDef;\n}\n","import { createHash } from 'node:crypto';\nimport { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { join, relative, resolve, sep } from 'node:path';\nimport postcss from 'postcss';\nimport type { ViteDevServer } from 'vite';\nimport { buildCssIndex, type SourceFile } from '../core/indexer';\nimport type { IndexPayloadRecord } from '../core/matcher';\nimport { SpliceRangeError, spliceText } from '../core/splice-writer';\nimport { type ApiContext, type ApiHandler, json, readJsonBody } from './api';\n\n/** The css endpoints: the index payload, root-confined file reads, disk splices. */\nexport const restHandlers: readonly ApiHandler[] = [\n // The bare mount serves the index payload too (connect hands it as `/`).\n { method: 'GET', path: '/', handle: handleIndex },\n { method: 'GET', path: '/index', handle: handleIndex },\n { method: 'GET', path: '/file', handle: handleFile },\n { method: 'POST', path: '/edit', handle: handleEdit },\n];\n\nasync function handleIndex(\n _req: IncomingMessage,\n res: ServerResponse,\n _url: URL,\n ctx: ApiContext,\n): Promise<void> {\n const payload = await buildIndexPayload(collectSources(ctx.srcDir), (file, blockIndex) =>\n resolveCompiledCss(ctx.server, ctx.root, file, blockIndex),\n );\n // Payload paths are project-relative; the join worked in absolute space.\n json(\n res,\n 200,\n payload.map((record) => ({ ...record, file: toRelative(ctx.root, record.file) })),\n );\n}\n\n// File content for the editor pane — a dedicated endpoint (not payload\n// fields) so contents are fresh exactly when a rule is opened and the\n// payload stays small. Same root confinement as the edit endpoint.\nasync function handleFile(\n _req: IncomingMessage,\n res: ServerResponse,\n url: URL,\n ctx: ApiContext,\n): Promise<void> {\n const file = url.searchParams.get('file');\n const absPath = file === null ? null : safeResolve(ctx.root, file);\n if (file === null || absPath === null || !existsSync(absPath)) {\n json(res, 400, { error: `file is missing or outside the project root: ${file ?? ''}` });\n return;\n }\n json(res, 200, { file, contents: readFileSync(absPath, 'utf8') });\n}\n\nasync function handleEdit(\n req: IncomingMessage,\n res: ServerResponse,\n _url: URL,\n ctx: ApiContext,\n): Promise<void> {\n let body: unknown;\n try {\n body = await readJsonBody(req);\n } catch (error) {\n json(res, 400, { error: error instanceof Error ? error.message : 'unreadable body' });\n return;\n }\n const { file, range, replacement, expected } = parseEditBody(body);\n if (file === null || range === null || replacement === null) {\n json(res, 400, { error: 'expected { file, range: { start, end }, replacement }' });\n return;\n }\n await writeGuarded(res, ctx, file, expected, (disk) =>\n spliceText(disk, { start: range[0], end: range[1], replacement }),\n );\n}\n\n/**\n * The hash-guarded write skeleton both write endpoints share (Impl #10):\n * root confinement, the missing-file taxonomy, then the optimistic `expected`\n * sha256 check — a mismatch means the file changed on disk under the chrome's\n * debounce (IDE/agent edit), so refuse and hand back the current bytes for a\n * one-roundtrip reload. `produce` computes the next bytes from the disk\n * truth; a `SpliceRangeError` maps to the 400 taxonomy, anything else throws\n * on through the dispatcher.\n */\nexport async function writeGuarded(\n res: ServerResponse,\n ctx: ApiContext,\n file: string,\n expected: string | null,\n produce: (disk: string) => string,\n): Promise<void> {\n const absPath = safeResolve(ctx.root, file);\n if (absPath === null) {\n json(res, 400, { error: `file is outside the project root: ${file}` });\n return;\n }\n if (!existsSync(absPath)) {\n json(res, 400, { error: `file is missing: ${file}` });\n return;\n }\n const disk = readFileSync(absPath, 'utf8');\n if (expected !== null && sha256(disk) !== expected) {\n json(res, 409, { error: 'file changed on disk', contents: disk });\n return;\n }\n try {\n writeFileSync(absPath, produce(disk));\n } catch (error) {\n if (error instanceof SpliceRangeError) {\n json(res, 400, { error: error.message });\n return;\n }\n throw error;\n }\n json(res, 200, { ok: true });\n}\n\n/** Supplies the compiled css of a scoped style module, or null when absent. */\nexport type CompiledCssResolver = (file: string, styleBlockIndex: number) => Promise<string | null>;\n\n/**\n * The module-graph hybrid join: static records plus effective selectors for\n * scoped rules. Scoped records of one style block correlate with the compiled\n * rules of module `{file}.astro?astro&type=style&index={N}` in rule order; a\n * block with no compiled module (not loaded on the current route, or a rule\n * count mismatch) stays listed without an effective selector — the liveness\n * line of v1.\n */\nexport async function buildIndexPayload(\n sources: SourceFile[],\n resolveCompiledCss: CompiledCssResolver,\n): Promise<IndexPayloadRecord[]> {\n const payload: IndexPayloadRecord[] = buildCssIndex(sources).map((record) => ({\n ...record,\n effectiveSelector: null,\n }));\n\n const blocks = new Map<string, { file: string; styleBlockIndex: number; positions: number[] }>();\n payload.forEach((record, position) => {\n if (!record.scoped || record.styleBlockIndex === null) return;\n const key = `${record.file}\\u0000${record.styleBlockIndex}`;\n const block = blocks.get(key) ?? {\n file: record.file,\n styleBlockIndex: record.styleBlockIndex,\n positions: [],\n };\n block.positions.push(position);\n blocks.set(key, block);\n });\n\n for (const block of blocks.values()) {\n const css = await resolveCompiledCss(block.file, block.styleBlockIndex);\n if (css === null) continue;\n const selectors = compiledSelectors(css);\n block.positions.forEach((position, ruleOrder) => {\n const effectiveSelector = selectors[ruleOrder];\n const record = payload[position];\n if (effectiveSelector !== undefined && record !== undefined) {\n record.effectiveSelector = effectiveSelector;\n }\n });\n }\n return payload;\n}\n\n/** Selectors of the compiled css in rule order — the join's correlation key. */\nexport function compiledSelectors(css: string): string[] {\n const selectors: string[] = [];\n postcss.parse(css).walkRules((rule) => {\n selectors.push(rule.selector);\n });\n return selectors;\n}\n\n/** Pulls the css text out of a dev-transformed css module's code. */\nexport function extractCssFromModuleCode(code: string): string | null {\n const match = code.match(/__vite__css = (\"(?:[^\"\\\\]|\\\\.)*\")/);\n if (match?.[1] === undefined) return null;\n try {\n return JSON.parse(match[1]) as string;\n } catch {\n return null;\n }\n}\n\nasync function resolveCompiledCss(\n server: ViteDevServer,\n root: string,\n file: string,\n styleBlockIndex: number,\n): Promise<string | null> {\n const moduleUrl = `/${toRelative(root, file)}?astro&type=style&index=${styleBlockIndex}&lang.css`;\n const module = await server.environments.client.moduleGraph.getModuleByUrl(moduleUrl);\n const code = module?.transformResult?.code;\n if (code === undefined || code === null) return null;\n return extractCssFromModuleCode(code);\n}\n\n/** Walks `src/**` collecting the css/astro sources the indexer consumes. */\nexport function collectSources(srcDir: string): SourceFile[] {\n if (!existsSync(srcDir)) return [];\n const sources: SourceFile[] = [];\n const walk = (dir: string): void => {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.name.startsWith('.') || entry.name === 'node_modules') continue;\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n walk(full);\n } else if (entry.name.endsWith('.css') || entry.name.endsWith('.astro')) {\n sources.push({ file: full, contents: readFileSync(full, 'utf8') });\n }\n }\n };\n walk(srcDir);\n return sources;\n}\n\n/** Project-relative posix path — also the file id used by the sync events. */\nexport function toRelative(root: string, file: string): string {\n return relative(root, file).split(sep).join('/');\n}\n\n/** The confinement check every file-touching endpoint shares (content.ts too). */\nexport function safeResolve(root: string, file: string): string | null {\n const absPath = resolve(root, file);\n if (absPath !== root && !absPath.startsWith(`${root}${sep}`)) return null;\n return absPath;\n}\n\nfunction parseEditBody(body: unknown): {\n file: string | null;\n range: [number, number] | null;\n replacement: string | null;\n expected: string | null;\n} {\n if (body === null || typeof body !== 'object') {\n return { file: null, range: null, replacement: null, expected: null };\n }\n const { file, range, replacement, expected } = body as Record<string, unknown>;\n const validRange =\n typeof range === 'object' &&\n range !== null &&\n typeof (range as Record<string, unknown>).start === 'number' &&\n typeof (range as Record<string, unknown>).end === 'number'\n ? ([(range as Record<string, unknown>).start, (range as Record<string, unknown>).end] as [\n number,\n number,\n ])\n : null;\n return {\n file: typeof file === 'string' ? file : null,\n range: validRange,\n replacement: typeof replacement === 'string' ? replacement : null,\n expected: typeof expected === 'string' ? expected : null,\n };\n}\n\n/** sha256 hex — the optimistic-write guard's currency, shared with content.ts. */\nexport function sha256(text: string): string {\n return createHash('sha256').update(text).digest('hex');\n}\n","import { extractStylesSync } from '@astrojs/compiler-binding';\nimport postcss from 'postcss';\n\n/** A project CSS source to index: path + raw contents. No IO happens here. */\nexport interface SourceFile {\n file: string;\n contents: string;\n}\n\n/**\n * One rule from the edit-truth index. The range is in character offsets of\n * `file` and covers the rule from its selector through the closing brace\n * (end-exclusive) — the splice-writer edits inside these bounds.\n */\nexport interface CssRuleRecord {\n /** Selector text verbatim from source (source space — no cid synthesis here). */\n selector: string;\n file: string;\n range: { start: number; end: number };\n /**\n * One-based line of the rule's selector in `file`, derived from the range\n * at index time (the indexer holds the contents) — the rule list shows it.\n */\n line: number;\n /** Condition of the nearest `@media` ancestor, or null at the top level. */\n media: string | null;\n /** True for rules from a scoped `<style>` block (the compiler applies the cid). */\n scoped: boolean;\n /**\n * Zero-based style-block index correlating with the module-graph module id\n * `{file}.astro?astro&type=style&index={N}` — the join key for the index\n * payload. Null when the block is not in the module graph (`is:inline`).\n */\n styleBlockIndex: number | null;\n}\n\ninterface BlockMeta {\n scoped: boolean;\n styleBlockIndex: number | null;\n baseOffset: number;\n}\n\nconst STYLE_TAG = /<style\\b[^>]*>([\\s\\S]*?)<\\/style>/g;\n\n/**\n * The indexer: scans project CSS sources into the edit-truth index\n * (selector → file, source range, media condition). Dev generates no CSS\n * sourcemaps, so this static scan is the only mapping to what's on disk —\n * and the only one that sees `is:inline` blocks.\n */\nexport function buildCssIndex(sources: SourceFile[]): CssRuleRecord[] {\n const records: CssRuleRecord[] = [];\n for (const source of sources) {\n const fileRecords = source.file.endsWith('.css')\n ? indexStylesheet(source.file, source.contents, {\n scoped: false,\n styleBlockIndex: null,\n baseOffset: 0,\n })\n : source.file.endsWith('.astro')\n ? indexAstroStyles(source.file, source.contents)\n : [];\n // Lines derive from absolute offsets against the whole file — the .astro\n // blocks were parsed as substrings but carry absolute ranges.\n for (const record of fileRecords) {\n records.push({ ...record, line: lineAt(source.contents, record.range.start) });\n }\n }\n return records;\n}\n\n/** One-based line number of a character offset. */\nfunction lineAt(contents: string, offset: number): number {\n let line = 1;\n for (let i = 0; i < offset && i < contents.length; i++) {\n if (contents[i] === '\\n') line += 1;\n }\n return line;\n}\n\nfunction indexStylesheet(\n file: string,\n css: string,\n meta: BlockMeta,\n): Omit<CssRuleRecord, 'line'>[] {\n const records: Omit<CssRuleRecord, 'line'>[] = [];\n postcss.parse(css).walkRules((rule) => {\n const start = rule.source?.start;\n const end = rule.source?.end;\n if (start === undefined || end === undefined) return;\n records.push({\n selector: rule.selector,\n file,\n range: { start: start.offset + meta.baseOffset, end: end.offset + meta.baseOffset },\n media: nearestMediaCondition(rule),\n scoped: meta.scoped,\n styleBlockIndex: meta.styleBlockIndex,\n });\n });\n return records;\n}\n\nfunction indexAstroStyles(file: string, source: string): Omit<CssRuleRecord, 'line'>[] {\n const records: Omit<CssRuleRecord, 'line'>[] = [];\n // extractStylesSync returns only blocks the compiler would process —\n // `is:inline` (and expression-attribute blocks) never make it there, so the\n // raw tag scan is the edit-truth pass and the compiler blocks supply the\n // module-graph index.\n const processed = extractStylesSync(source);\n let next = 0;\n\n for (const match of source.matchAll(STYLE_TAG)) {\n const content = match[1];\n if (content === undefined) continue;\n const openTag = match[0].slice(0, match[0].indexOf('>') + 1);\n const contentStart = match.index + openTag.length;\n\n const compilerBlock = processed[next];\n if (compilerBlock !== undefined && compilerBlock.content === content) {\n next += 1;\n records.push(\n ...indexStylesheet(file, content, {\n scoped: compilerBlock.attrs['is:global'] === undefined,\n styleBlockIndex: compilerBlock.index,\n baseOffset: contentStart,\n }),\n );\n } else {\n records.push(\n ...indexStylesheet(file, content, {\n scoped: false,\n styleBlockIndex: null,\n baseOffset: contentStart,\n }),\n );\n }\n }\n return records;\n}\n\nfunction nearestMediaCondition(node: postcss.Node): string | null {\n for (let parent = node.parent; parent !== undefined; parent = parent.parent) {\n if (parent.type !== 'atrule') continue;\n const atRule = parent as postcss.AtRule;\n if (atRule.name === 'media') {\n return atRule.params;\n }\n }\n return null;\n}\n","/**\n * A single text edit: replace the half-open range `[start, end)` of the file\n * content with `replacement`. Zero-length ranges insert purely. The editor\n * debounces and sends one edit at a time — this is the only write primitive.\n */\nexport interface SpliceEdit {\n start: number;\n end: number;\n replacement: string;\n}\n\n/** Thrown for ranges that do not fit the content — never produces partial output. */\nexport class SpliceRangeError extends Error {\n constructor(start: number, end: number, contentLength: number) {\n super(`Invalid splice range [${start}, ${end}) for content of length ${contentLength}`);\n this.name = 'SpliceRangeError';\n }\n}\n\n/**\n * The splice-writer primitive: (content, range, replacement) → new content.\n * Text-splice only — never reprints the file. Every byte outside the replaced\n * range stays identical, so formatting, comments and agent conventions\n * survive and the git diff is minimal.\n */\nexport function spliceText(content: string, edit: SpliceEdit): string {\n const { start, end, replacement } = edit;\n if (\n !Number.isInteger(start) ||\n !Number.isInteger(end) ||\n start < 0 ||\n end > content.length ||\n start > end\n ) {\n throw new SpliceRangeError(start, end, content.length);\n }\n return content.slice(0, start) + replacement + content.slice(end);\n}\n\n/**\n * Append a rule at EOF with exactly one added line, regardless of whether the\n * original ends with a newline (no accidental blank runs; the file's\n * trailing-newline convention is preserved).\n */\nexport function appendRule(content: string, rule: string): string {\n if (content === '') {\n return rule;\n }\n const endsWithNewline = content.endsWith('\\n');\n const body = endsWithNewline ? content : `${content}\\n`;\n return `${body}${rule}${endsWithNewline ? '\\n' : ''}`;\n}\n","/**\n * Is this request a top-level document navigation the builder should wrap?\n * Deliberately conservative: anything asset-like, internal to Vite/Astro, or\n * carrying an explicit `builder` param falls through to the host.\n */\nexport function isDocumentRequest(input: {\n method: string;\n url: string;\n accept?: string | undefined;\n}): boolean {\n if (input.method !== 'GET' && input.method !== 'HEAD') return false;\n if (!(input.accept ?? '').includes('text/html')) return false;\n\n let url: URL;\n try {\n url = new URL(input.url, 'http://astroix.internal');\n } catch {\n return false;\n }\n if (url.searchParams.has('builder')) return false;\n\n const { pathname } = url;\n if (\n pathname.startsWith('/@') ||\n pathname.startsWith('/__') ||\n pathname.startsWith('/_astro') ||\n pathname.startsWith('/virtual:')\n ) {\n return false;\n }\n // A dot in the last path segment reads as an asset (`home.css`, `foo.png`).\n if (/(^|\\/)[^/]*\\.[a-zA-Z0-9]+$/.test(pathname)) return false;\n return true;\n}\n","import { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { IntegrationResolvedRoute, PaginateFunction } from 'astro';\nimport { createServerModuleRunner, type ViteDevServer } from 'vite';\nimport {\n createContentSignalClassifier,\n createLoaderCommitClassifier,\n pushToChrome,\n} from './content-signal';\nimport { generatePaginateFunction } from './paginate';\nimport { applyRenders, isProjectPageRoute, type RoutesState } from './routes';\n\n/**\n * The background `getStaticPaths` enumeration (#119, research #118): mirrors\n * core's dev recipe — load each prerendered single-param page route's\n * entrypoint in the ssr environment, call its\n * `getStaticPaths({ paginate, routePattern })`, collect the rendered param\n * values into the routes payload's `renders`.\n *\n * Freshness rides the codebase's stateless-doctrine runner (content.ts): a\n * NEW `createServerModuleRunner` per pass, nothing held between passes —\n * and closed when the pass settles, because each runner's transport pins a\n * `send` listener on the ssr hot channel (#146). The long-lived\n * `environments.ssr.runner` cannot serve this pass — its cached\n * module bindings never see content commits (verified live on astro@7.2.7:\n * after a content edit, a direct `runner.import('astro:content')` keeps\n * returning the old entries forever, while dev requests go fresh through\n * per-request runners; the module-identity memo from the research's\n * RouteCache mirroring is therefore not just unnecessary here — on the\n * shared runner it is wrong). A fresh runner re-evaluates against the\n * module graph's transform cache: route edits are seen (vite invalidated\n * the transform), content commits are seen (the evaluation reads live\n * data), warm passes stay ms-scale.\n *\n * Cadence: debounced (400 ms), lazy (boot + hook captures + srcDir content\n * signals), never blocking a request. Content file events race the loader's\n * data commit (verified: a pass right after the event reads the previous\n * commit), so a content signal re-runs the pass twice more, 2 s apart —\n * loader commits slower than ~4 s degrade to the next real event, the same\n * stale-window class dev renders have before the loader syncs.\n *\n * Failure containment per route: try/catch + a 5 s timeout → that route's\n * `renders` comes off the payload (unknown — consumers degrade to the shape\n * premise, the marker never fires on unknown). The served endpoint never\n * awaits any of this; completion pushes `astroix:routes-changed` when the\n * payload actually moved.\n *\n * This subscription is also where `astroix:content-synced` is pushed\n * (#133): astro's own content event rides the ssr environment's hot channel\n * and never reaches the client chrome (verified live on astro@7.2.7), so\n * the chrome's collections/schema caches have no other external-edit\n * invalidation. Both the shared srcDir content signal and the loader's\n * data-store write (the post-commit half — the loader debounces the store\n * write 500 ms) push immediately, labeled with the leg that fired (#155) —\n * the chrome, not a server-side grace, sequences the loader leg's refetch\n * after the canvas's post-commit full-reload render (see\n * synced-invalidation.ts on the client side).\n */\n\nconst DEBOUNCE_MS = 400;\nconst CONTENT_FOLLOWUP_MS = 2_000;\nconst CONTENT_FOLLOWUPS = 2;\nconst ROUTE_TIMEOUT_MS = 5_000;\n\n/** A `getStaticPaths` module as the ssr runner hands it over. */\ntype StaticPathsModule = {\n getStaticPaths?: (options: {\n paginate: PaginateFunction;\n routePattern: string;\n }) => Promise<unknown> | unknown;\n};\n\n/** The param values a `getStaticPaths` result actually renders — first occurrence order, non-strings skipped (paginate's first page carries `undefined`). */\nexport function extractRenders(\n staticPaths: Iterable<{ params: Record<string, unknown> }>,\n paramKey: string,\n): string[] {\n const seen = new Set<string>();\n for (const staticPath of staticPaths) {\n const value = staticPath.params[paramKey];\n if (typeof value === 'string') seen.add(value);\n }\n return [...seen];\n}\n\nexport function registerRouteEnumeration(\n server: ViteDevServer,\n options: { root: string; srcDir: string; routes: RoutesState },\n): void {\n const isContentSignal = createContentSignalClassifier(options);\n const isLoaderCommit = createLoaderCommitClassifier(options.root);\n const results = new Map<string, readonly string[]>();\n let timer: ReturnType<typeof setTimeout> | null = null;\n let running = false;\n let rerun = false;\n let contentFollowups = 0;\n\n const push = (): void => {\n pushToChrome(server, 'astroix:routes-changed');\n };\n\n const schedule = (delay = DEBOUNCE_MS): void => {\n if (timer !== null) return;\n timer = setTimeout(() => {\n timer = null;\n void runPass();\n }, delay);\n };\n\n // Every hook capture re-arms a pass (route edits invalidate transforms,\n // the fresh runner sees them) and pushes when the served projection\n // changed — the chrome's ROUTES_KEY cache has no other invalidation.\n const onCapture = (changed: boolean): void => {\n if (changed) push();\n schedule();\n };\n\n // The content signal (shared classification, content-signal.ts): a srcDir\n // file event that is neither a captured route entrypoint (the fresh\n // runner already reads those as transformed) nor css is treated as\n // content moving — the pass re-runs now and twice more to out-wait the\n // loader's data commit. Both that signal and the loader's store write\n // push `astroix:content-synced` labeled with their leg (see the module\n // doc); the store write re-arms nothing — the enumeration cadence is\n // #119's, unchanged.\n const onFileEvent = (file: string): void => {\n if (isLoaderCommit(file)) {\n pushToChrome(server, 'astroix:content-synced', 'loader');\n return;\n }\n if (!isContentSignal(file)) return;\n pushToChrome(server, 'astroix:content-synced', 'srcdir');\n contentFollowups = CONTENT_FOLLOWUPS;\n schedule();\n };\n for (const event of ['add', 'change', 'unlink'] as const) {\n server.watcher.on(event, onFileEvent);\n }\n\n const runPass = async (): Promise<void> => {\n if (running) {\n rerun = true;\n return;\n }\n running = true;\n let runner: ReturnType<typeof createServerModuleRunner> | null = null;\n try {\n runner = createServerModuleRunner(server.environments.ssr);\n for (const route of options.routes.captured) {\n if (!isEnumeratable(route)) continue;\n const entryUrl = pathToFileURL(join(options.root, route.entrypoint)).href;\n try {\n const mod = (await withTimeout(\n runner.import(entryUrl),\n ROUTE_TIMEOUT_MS,\n )) as StaticPathsModule;\n const staticPaths = await withTimeout(callGetStaticPaths(mod, route), ROUTE_TIMEOUT_MS);\n results.set(route.pattern, extractRenders(staticPaths, paramKeyOf(route)));\n } catch {\n results.delete(route.pattern); // unknown — never a wrong `renders`\n }\n }\n } catch {\n // the pass itself must never reject in the background; route-level\n // failures were already contained above\n } finally {\n // close() drops the transport's `send` listener (one leaked per pass\n // otherwise, #146); cleanup failure must not reject the background pass\n await runner?.close().catch(() => {});\n running = false;\n }\n if (applyRenders(options.routes, results)) push();\n if (contentFollowups > 0) {\n // the loader's data commit may still be in flight — read again after\n // it, until the follow-ups run out\n contentFollowups -= 1;\n schedule(CONTENT_FOLLOWUP_MS);\n } else if (rerun) {\n rerun = false;\n schedule();\n }\n };\n\n options.routes.onCapture = onCapture;\n // Boot: arm the first pass. No push to replay — a pre-registration capture\n // predates the server listening, so no client could have missed it; every\n // capture after registration arrives as a real onCapture call.\n onCapture(false);\n}\n\n/** Prerendered single-param page routes are the payload's `renders` space — the resolver's participating shapes, minus on-demand (its `getStaticPaths` is dead code). */\nfunction isEnumeratable(route: IntegrationResolvedRoute): boolean {\n return isProjectPageRoute(route) && route.isPrerendered && route.params.length === 1;\n}\n\n/** The `getStaticPaths` params key for a rest param drops the dots (`...slug` → `slug`). */\nfunction paramKeyOf(route: IntegrationResolvedRoute): string {\n return route.params[0]?.replace(/^\\.\\.\\./, '') ?? '';\n}\n\nasync function callGetStaticPaths(mod: StaticPathsModule, route: IntegrationResolvedRoute) {\n const getStaticPaths = mod.getStaticPaths;\n if (typeof getStaticPaths !== 'function') {\n // core throws GetStaticPathsRequired for this project shape at render —\n // enumeration contains it the same way: unknown, not an error\n throw new Error(`route module has no getStaticPaths: ${route.entrypoint}`);\n }\n const result = await getStaticPaths({\n paginate: generatePaginateFunction(route),\n routePattern: route.pattern,\n });\n return result as Iterable<{ params: Record<string, unknown> }>;\n}\n\nfunction withTimeout<T>(work: Promise<T>, ms: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`timed out after ${ms}ms`)), ms);\n work.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error: unknown) => {\n clearTimeout(timer);\n reject(error instanceof Error ? error : new Error(String(error)));\n },\n );\n });\n}\n","import { sep } from 'node:path';\nimport type { ViteDevServer } from 'vite';\nimport { toRelative } from './rest';\nimport type { RoutesState } from './routes';\n\n/**\n * A dir path as posix with the trailing slash stripped, so the `startsWith`\n * joins below match astro's URL-form dirs (a windows-style or suffixed path\n * would never match). watch-sync.ts carries the same idiom for its own dirs.\n */\nfunction toPosixDir(dir: string): string {\n return dir.split(sep).join('/').replace(/\\/+$/, '');\n}\n\n/**\n * The content signal, shared (#133): the one classification every watcher\n * subscriber that needs \"content may have moved\" consumes — today the\n * enumeration re-arm (route-enumeration.ts, #119) and the\n * `astroix:content-synced` push — so the predicate cannot drift between\n * them. A srcDir file event that is neither a captured route entrypoint\n * (route edits reach the enumeration pass as transforms) nor css\n * (watch-sync's territory). add/unlink matter as much as change (entries\n * are created and deleted, not only edited).\n */\nexport interface ContentSignalScope {\n root: string;\n srcDir: string;\n routes: RoutesState;\n}\n\nexport function createContentSignalClassifier(\n scope: ContentSignalScope,\n): (file: string) => boolean {\n const srcDir = toPosixDir(scope.srcDir);\n return (file: string): boolean => {\n // the prefix check runs in absolute space (srcDir is absolute — a\n // relative path would never match); the entrypoint check in relative\n // space (entrypoints are root-relative)\n const norm = file.split(sep).join('/');\n if (!norm.startsWith(`${srcDir}/`)) return false;\n if (norm.endsWith('.css')) return false;\n const rel = toRelative(scope.root, file);\n return !scope.routes.captured.some((route) => route.entrypoint === rel);\n };\n}\n\n/**\n * The loader's commit signal (#133): astro's dev data store lives at\n * `<root>/.astro/data-store.json` (dev always uses the dot-astro dir; the\n * chunked form lands under `.astro/data-store/`), and astro itself adds it\n * to `server.watcher` — its add/change events fire exactly when the content\n * layer wrote the store, the same instant core invalidates its own\n * data-store module. The srcDir classification fires pre-commit: the\n * loader's store write is debounced 500 ms (SAVE_DEBOUNCE_MS,\n * mutable-data-store.js on astro@7.2.7), so a chrome refetch on that\n * signal alone races the commit and loses ~always — `astroix:content-synced`\n * needs this post-commit leg to mean \"synced\". Internals seam: the store\n * path is not public API — if astro ever moves it, this predicate goes\n * quiet and the push degrades to the srcDir signal (a slower refresh,\n * never a break).\n */\nexport function createLoaderCommitClassifier(root: string): (file: string) => boolean {\n const storePrefix = `${toPosixDir(root)}/.astro/`;\n return (file: string): boolean => {\n const norm = file.split(sep).join('/');\n return norm === `${storePrefix}data-store.json` || norm.startsWith(`${storePrefix}data-store/`);\n };\n}\n\n/**\n * Which watcher leg a `astroix:content-synced` push carries (#155): the\n * srcDir signal fires pre-commit (the loader's store write is debounced\n * 500 ms), the loader's data-store write is the post-commit leg. The label\n * is the whole payload — the chrome sequences on it: only the loader leg's\n * refetch races the canvas's post-commit full-reload render (verified live\n * on astro@7.2.7: the re-render and a concurrent fresh-runner evaluation\n * leave the canvas serving the pre-commit store for good), so the chrome\n * holds that leg's invalidation until its canvas-load signal proves the\n * reload's render served, while the srcDir leg — whose refetch lands well\n * before the reload — invalidates immediately. The server stays dumb about\n * timing; it only says which signal fired.\n */\nexport type ContentSyncLeg = 'srcdir' | 'loader';\n\n/**\n * The no-audience guard this file's pushers share (routes push, #119;\n * content-synced push, #133 — watch-sync's older `file-changed` push\n * predates it): with no connected client nobody holds a stale cache key,\n * and vite accumulates a send listener per early send, which trips its\n * EventEmitter warning.\n */\nexport function pushToChrome(server: ViteDevServer, event: 'astroix:routes-changed'): void;\nexport function pushToChrome(\n server: ViteDevServer,\n event: 'astroix:content-synced',\n leg: ContentSyncLeg,\n): void;\nexport function pushToChrome(\n server: ViteDevServer,\n event: 'astroix:routes-changed' | 'astroix:content-synced',\n leg?: ContentSyncLeg,\n): void {\n if (server.ws.clients.size === 0) return;\n server.ws.send(event, event === 'astroix:content-synced' ? { leg } : {});\n}\n","import type { IntegrationResolvedRoute, PaginateFunction } from 'astro';\n\n/**\n * Vendored from astro@7.2.7 `dist/core/render/paginate.js`\n * (`generatePaginateFunction`) — core does not export it through the\n * `astro/runtime/*` wildcard, and `getStaticPaths` receives it as an\n * argument, so the enumeration pass must supply its own. Core semantics are\n * pinned by `paginate.test.ts`, which runs this against core's own\n * implementation over the same inputs. The one adaptation: core builds the\n * generator from `routeMatch.segments` + trailingSlash; the hook's\n * `IntegrationResolvedRoute.generate` already IS that generator closure.\n * The cast mirrors core's own (`callGetStaticPaths` casts for the same\n * reason): the public `PaginateFunction` is a user-facing generic\n * convenience our structural implementation satisfies.\n */\n\n/** The options object `paginate(data, args)` accepts (core's `PaginateOptions`, structurally). */\ninterface PaginateArgs {\n pageSize?: number;\n params?: Record<string, string | undefined>;\n props?: Record<string, unknown>;\n format?: (url: string) => string;\n}\n\nexport function generatePaginateFunction(route: IntegrationResolvedRoute): PaginateFunction {\n function paginateUtility(data: readonly unknown[], args: PaginateArgs = {}): unknown[] {\n const { pageSize: _pageSize, params: _params, props: _props, format: _format } = args;\n const pageSize = _pageSize || 10;\n const paramName = 'page';\n const additionalParams = _params || {};\n const additionalProps = _props || {};\n const formatUrl = _format || ((url: string) => url);\n let includesFirstPageNumber: boolean;\n if (route.params.includes(`...${paramName}`)) {\n includesFirstPageNumber = false;\n } else if (route.params.includes(`${paramName}`)) {\n includesFirstPageNumber = true;\n } else {\n throw new Error(\n `[paginate] page number param \\`${paramName}\\` not found. If you are using the paginate() helper, your route must include a [${paramName}] or [...${paramName}] param.`,\n );\n }\n const lastPage = Math.max(1, Math.ceil(data.length / pageSize));\n return [...Array(lastPage).keys()].map((num) => {\n const pageNum = num + 1;\n const start = pageSize === Number.POSITIVE_INFINITY ? 0 : (pageNum - 1) * pageSize;\n const end = Math.min(start + pageSize, data.length);\n const params = {\n ...additionalParams,\n [paramName]: includesFirstPageNumber || pageNum > 1 ? String(pageNum) : undefined,\n };\n const current = formatUrl(addRouteBase(route.generate({ ...params })));\n const next =\n pageNum === lastPage\n ? undefined\n : formatUrl(addRouteBase(route.generate({ ...params, page: String(pageNum + 1) })));\n const prev =\n pageNum === 1\n ? undefined\n : formatUrl(\n addRouteBase(\n route.generate({\n ...params,\n page:\n !includesFirstPageNumber && pageNum - 1 === 1 ? undefined : String(pageNum - 1),\n }),\n ),\n );\n const first =\n pageNum === 1\n ? undefined\n : formatUrl(\n addRouteBase(\n route.generate({ ...params, page: includesFirstPageNumber ? '1' : undefined }),\n ),\n );\n const last =\n pageNum === lastPage\n ? undefined\n : formatUrl(addRouteBase(route.generate({ ...params, page: String(lastPage) })));\n return {\n params,\n props: {\n ...additionalProps,\n page: {\n data: data.slice(start, end),\n start,\n end: end - 1,\n size: pageSize,\n total: data.length,\n currentPage: pageNum,\n lastPage,\n url: { current, next, prev, first, last },\n },\n },\n };\n });\n }\n return paginateUtility as PaginateFunction;\n}\n\n/** Core's `joinPaths(base, path)` + empty→`/`, for the dev base we run under. */\nfunction addRouteBase(path: string): string {\n const joined = `/${path.replace(/^\\/+/, '')}`;\n return joined === '' ? '/' : joined;\n}\n","import { sep } from 'node:path';\nimport type { ViteDevServer } from 'vite';\nimport { toRelative } from './rest';\n\n/**\n * The file→chrome half of the sync (spec #13): the host watcher is the only\n * FS subscriber; css/astro changes under the project's src dir are debounced\n * per file and pushed to the chrome as `astroix:file-changed` over the Vite\n * WebSocket — the same channel Astro uses for its own events. The chrome\n * refetches content/payload on receipt; its own writes echo back as no-ops\n * (content compare client-side).\n */\nexport function registerFileSync(\n server: ViteDevServer,\n options: { root: string; srcDir: string },\n): void {\n // astro hands srcDir as a URL that keeps a trailing slash — strip it or\n // the startsWith filter below never matches\n const srcDir = options.srcDir.split(sep).join('/').replace(/\\/+$/, '');\n const pending = new Map<string, ReturnType<typeof setTimeout>>();\n\n const push = (file: string): void => {\n const timer = pending.get(file);\n if (timer !== undefined) clearTimeout(timer);\n pending.set(\n file,\n setTimeout(() => {\n pending.delete(file);\n server.ws.send('astroix:file-changed', { file: toRelative(options.root, file) });\n }, 100),\n );\n };\n\n const isWatchedSource = (file: string): boolean => {\n const norm = file.split(sep).join('/');\n if (!norm.startsWith(`${srcDir}/`)) return false;\n return norm.endsWith('.css') || norm.endsWith('.astro');\n };\n\n // `add` matters too: IDE atomic saves (write temp + rename) can surface as\n // add instead of change depending on the editor\n server.watcher.on('change', (file) => {\n if (isWatchedSource(file)) push(file);\n });\n server.watcher.on('add', (file) => {\n if (isWatchedSource(file)) push(file);\n });\n}\n"],"mappings":"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","names":["fileURLToPath","existsSync","readFileSync","join","existsSync","join","existsSync","postcss","existsSync","resolveCompiledCss","postcss","candidates","join","existsSync","join","createServerModuleRunner","sep","sep","createServerModuleRunner","join","resolve","sep","sep","join","existsSync","readFileSync","fileURLToPath"]}
1
+ {"version":3,"sources":["../src/node/index.ts","../src/node/api.ts","../src/node/routes.ts","../src/node/source-mode.ts","../src/node/tailwind-guard.ts","../src/node/vite-plugin.ts","../src/node/chrome-html.ts","../src/node/chrome-reload-shield.ts","../src/node/content.ts","../src/core/form-tree.ts","../src/node/rest.ts","../src/core/indexer.ts","../src/core/splice-writer.ts","../src/node/document-request.ts","../src/node/route-enumeration.ts","../src/node/content-signal.ts","../src/node/paginate.ts","../src/node/watch-sync.ts"],"sourcesContent":["import { dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport tailwindcss from '@tailwindcss/vite';\nimport react from '@vitejs/plugin-react';\nimport type { AstroIntegration } from 'astro';\nimport type { Plugin as VitePlugin } from 'vite';\nimport { captureRoutes, type RoutesState } from './routes';\nimport { clientEntryPath, isSourceMode } from './source-mode';\nimport { hostRegistersTailwind } from './tailwind-guard';\nimport { astroixVitePlugin } from './vite-plugin';\n\n/**\n * Canvas script injected into every dev page (the chrome document itself is\n * never Astro-rendered, so this only ever runs inside host pages). It decides\n * on its own whether it is the builder canvas: inside the iframe\n * (`window.parent !== window`) with `?builder=0`, it hides Astro's dev\n * toolbar — the toolbar stays available on normal page loads (spec #2).\n */\nconst CANVAS_SCRIPT = `if (window.parent !== window && new URLSearchParams(location.search).get('builder') === '0') {\n const style = document.createElement('style');\n style.textContent = 'astro-dev-toolbar{display:none!important}';\n document.head.append(style);\n}\n`;\n\n/**\n * Astroix — dev-only visual builder integration.\n *\n * In dev: the astroix Vite plugin serves the builder chrome over every\n * top-level URL (default-on) with the `?builder=0` escape hatch, and the\n * virtual chrome module delivers the app (source mode in this checkout per\n * ADR-0001; the prebuilt bundle lands with the chrome packaging slice).\n * Any other command registers nothing — the dev-only guarantee.\n */\nfunction astroix(): AstroIntegration {\n // Routes captured from the hook below and served at `GET /__astroix/routes`\n // (spec Impl #13). Lives on the integration instance so both hooks —\n // the writer and the plugin that serves the state — share one container\n // across dev restarts (restarts re-run the routes hook on the same instance).\n // The background enumeration (`route-enumeration.ts`) fills `renders` into\n // it and watches the captures through `onCapture` (#119).\n const routesState: RoutesState = { current: [], captured: [] };\n return {\n name: 'astroix',\n hooks: {\n 'astro:routes:resolved': ({ routes }) => {\n captureRoutes(routesState, routes);\n },\n 'astro:config:setup': ({ config, command, updateConfig, injectScript, logger }) => {\n if (command !== 'dev') return;\n\n // The resolved config turns dir strings into URLs (trailing slash included) —\n // the plugin wants clean paths.\n const plugins: VitePlugin[] = [\n astroixVitePlugin({ srcDir: fileURLToPath(config.srcDir), routes: routesState }),\n ];\n // The chrome sources live outside the host root and are served via\n // /@fs, which has two consequences fixed below: (a) deps discovered\n // from /@fs files resolve against the importer's location, so `react`\n // can enter the optimizer from two paths and mount twice (Invalid\n // hook call) — dedupe pins every resolution to the host root's React,\n // which in the dev checkout is our own 19; (b) HMR re-fetches carry a\n // `?t=` timestamp that misses the import-chain fs exemption — the\n // checkout root joins the allow list so chrome modules always serve.\n let vitePatch: {\n plugins: VitePlugin[];\n resolve?: { dedupe: string[] };\n server?: { fs: { allow: string[] } };\n } = { plugins };\n\n if (isSourceMode()) {\n // ADR-0001 source mode: chrome from this checkout's source, with\n // fast-refresh scoped to chrome files only (host code untouched).\n const clientDir = dirname(clientEntryPath ?? '');\n // compiler: true = React Compiler via oxc (stack #4: no manual memoization).\n plugins.push(\n ...react({\n include: new RegExp(`^${escapeRegExp(clientDir)}/.*\\\\.tsx?$`),\n compiler: true,\n }),\n );\n if (hostRegistersTailwind(config.vite)) {\n logger.info('host already registers @tailwindcss/vite — reusing it for the chrome');\n } else {\n plugins.push(...tailwindcss());\n }\n vitePatch = {\n plugins,\n resolve: { dedupe: ['react', 'react-dom'] },\n server: { fs: { allow: [dirname(dirname(clientDir))] } },\n };\n }\n\n updateConfig({ vite: vitePatch });\n injectScript('page', CANVAS_SCRIPT);\n },\n },\n };\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replaceAll(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport default astroix;\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { ViteDevServer } from 'vite';\nimport type { RoutesState } from './routes';\n\nconst API_PREFIX = '/__astroix';\n\n/** The shared server context every `/__astroix` handler may touch. */\nexport interface ApiContext {\n server: ViteDevServer;\n /** Absolute project root (Vite root) — the confinement root for file paths. */\n root: string;\n /** Absolute Astro src dir (css/astro sources to index, content config). */\n srcDir: string;\n /** Routes captured by the integration's `astro:routes:resolved` hook. */\n routes: RoutesState;\n}\n\n/**\n * One endpoint of the builder API. `path` is mount-relative (connect strips\n * the `/__astroix` prefix, so `GET /__astroix/index` arrives as `/index`).\n * A handler answers its request fully or throws — it never calls `next()`.\n */\nexport interface ApiHandler {\n method: 'GET' | 'POST';\n path: string;\n handle(req: IncomingMessage, res: ServerResponse, url: URL, ctx: ApiContext): Promise<void>;\n}\n\nexport interface ApiOptions {\n root: string;\n srcDir: string;\n routes: RoutesState;\n /** Endpoint handlers, contributed by the owning modules (rest, content, routes). */\n handlers: readonly ApiHandler[];\n}\n\n/**\n * Registers the chrome↔node contract on the Vite connect middleware\n * (core-reuse §2 — like core's `/_astro/status`, not Astro app middleware):\n * one `/__astroix` mount dispatching over a handler table keyed by\n * `method + path`, so the same-origin invariant is structural (checked once,\n * in the dispatcher) instead of conventional (per registrar). Handlers are\n * contributed by the owning modules — see each module for its endpoints.\n *\n * Same-origin only: a browser `sec-fetch-site` header that is not\n * same-origin/none is rejected (T2).\n */\nexport function registerApiEndpoints(server: ViteDevServer, options: ApiOptions): void {\n const table = new Map(\n options.handlers.map((handler) => [handlerKey(handler.method, handler.path), handler]),\n );\n // Two modules registering the same route would silently shadow — fail at\n // boot instead of at request time.\n if (table.size !== options.handlers.length) {\n throw new Error('astroix: duplicate route in the /__astroix handler table');\n }\n const ctx: ApiContext = {\n server,\n root: options.root,\n srcDir: options.srcDir,\n routes: options.routes,\n };\n server.middlewares.use(API_PREFIX, (req, res, next) => {\n void dispatchApi(req, res, next, table, ctx);\n });\n}\n\nasync function dispatchApi(\n req: IncomingMessage,\n res: ServerResponse,\n next: (err?: unknown) => void,\n table: ReadonlyMap<string, ApiHandler>,\n ctx: ApiContext,\n): Promise<void> {\n try {\n if (isCrossOriginTraffic(req)) {\n json(res, 403, { error: 'cross-origin builder traffic is not allowed' });\n return;\n }\n const url = new URL(req.url ?? '/', 'http://astroix.internal');\n // The middleware is mounted at /__astroix (connect strips the prefix),\n // so GET /__astroix/index arrives as /index.\n const handler = table.get(handlerKey(req.method ?? '', url.pathname));\n if (handler === undefined) {\n next();\n return;\n }\n await handler.handle(req, res, url, ctx);\n } catch (error) {\n next(error instanceof Error ? error : new Error(String(error)));\n }\n}\n\nfunction handlerKey(method: string, path: string): string {\n return `${method} ${path}`;\n}\n\n/**\n * The builder endpoints serve same-origin chrome traffic only: a browser\n * `sec-fetch-site` header that is not same-origin/none means cross-origin\n * (T2). Enforced once, by the `/__astroix` dispatcher.\n */\nexport function isCrossOriginTraffic(req: IncomingMessage): boolean {\n const secFetchSite = req.headers['sec-fetch-site'];\n return (\n typeof secFetchSite === 'string' && secFetchSite !== 'same-origin' && secFetchSite !== 'none'\n );\n}\n\nexport function json(res: ServerResponse, status: number, body: unknown): void {\n res.statusCode = status;\n res.setHeader('content-type', 'application/json; charset=utf-8');\n res.end(JSON.stringify(body));\n}\n\nconst MAX_BODY_BYTES = 1_000_000;\n\n/** The shared JSON body reader for the POST endpoints (capped, rejects bad JSON). */\nexport function readJsonBody(req: IncomingMessage): Promise<unknown> {\n return new Promise((resolveBody, reject) => {\n const chunks: Buffer[] = [];\n let size = 0;\n req.on('data', (chunk: Buffer) => {\n size += chunk.length;\n if (size > MAX_BODY_BYTES) {\n reject(new Error('request body too large'));\n req.destroy();\n return;\n }\n chunks.push(chunk);\n });\n req.on('end', () => {\n try {\n resolveBody(JSON.parse(Buffer.concat(chunks).toString('utf8')));\n } catch {\n reject(new Error('request body is not valid JSON'));\n }\n });\n req.on('error', reject);\n });\n}\n","import type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { IntegrationResolvedRoute } from 'astro';\nimport type { RouteInfo } from '../core/route-resolver';\nimport { type ApiContext, type ApiHandler, json } from './api';\n\n/**\n * Shared container between the `astro:routes:resolved` hook (writer) and the\n * REST layer (reader). The hook's sync projection lands in `current`\n * immediately; `renders` is filled into it later by the background\n * enumeration pass (`route-enumeration.ts`) — `GET /__astroix/routes` never\n * awaits that pass (#119).\n */\nexport interface RoutesState {\n /** The served payload — the sync hook projection, `renders` merged in place. */\n current: RouteInfo[];\n /**\n * The hook's raw capture — the enumeration's input (entrypoint,\n * `isPrerendered`, params). Replaced whole on every hook run.\n */\n captured: readonly IntegrationResolvedRoute[];\n /**\n * Fired by `captureRoutes` on every hook capture with whether the served\n * projection changed (preserved `renders` aside); set by the enumeration\n * registration, which owns the server handles (latest server wins across\n * dev restarts — the integration instance persists).\n */\n onCapture?: (changed: boolean) => void;\n}\n\n/**\n * Projects hook routes to the `RouteInfo` contract of `src/core/route-resolver`\n * (single source of truth per the core-first ruling on PR #77): page routes\n * only — the resolver's contract filters out `endpoint`/`redirect`/`fallback`\n * types and Astro-core `internal`-origin routes (e.g. the dev server-islands\n * route `/_server-islands/[name]`, which would otherwise resolve as a\n * same-shape candidate and navigate to a 404, #109) — with Astro's own\n * `segments` parse carried along, deep-copied so no live core object is held\n * between hook runs. `rendering` rides from the hook's `isPrerendered` —\n * free and synchronous (#119); `renders` is not projected here: enumeration\n * owns it.\n */\nexport function toRouteInfos(routes: readonly IntegrationResolvedRoute[]): RouteInfo[] {\n return routes.flatMap((route) => {\n if (!isProjectPageRoute(route)) return [];\n return [\n {\n pattern: route.pattern,\n segments: route.segments.map((segment) => segment.map((part) => ({ ...part }))),\n params: [...route.params],\n rendering: route.isPrerendered ? 'prerendered' : 'on-demand',\n },\n ];\n });\n}\n\n/**\n * The routes-payload membership rule — the same filter the enumeration pass\n * applies over the raw capture, so served patterns and enumerated patterns\n * can never drift.\n */\nexport function isProjectPageRoute(route: IntegrationResolvedRoute): boolean {\n return route.type === 'page' && route.origin !== 'internal';\n}\n\n/**\n * The `astro:routes:resolved` writer: replaces the raw capture, reprojects\n * `current`, and preserves already-enumerated `renders` by pattern — a\n * re-capture with unchanged routes leaves the served payload byte-identical\n * (no push), and a stale `renders` can only keep a candidate alive through\n * the ms-scale window until the next pass re-verifies it, never fire the\n * marker wrongly (unknown never fires, #119's silent-never-wrong).\n */\nexport function captureRoutes(\n state: RoutesState,\n routes: readonly IntegrationResolvedRoute[],\n): void {\n state.captured = routes;\n const previous = new Map(state.current.map((info) => [info.pattern, info.renders]));\n const next = toRouteInfos(routes).map((info) => {\n const renders = previous.get(info.pattern);\n return renders === undefined ? info : { ...info, renders };\n });\n const changed = !samePayload(next, state.current);\n state.current = next;\n state.onCapture?.(changed);\n}\n\n/**\n * Merges enumeration results into the served payload: an entry sets `renders`\n * (a `[]` is knowably-dead truth, not unknown), a missing entry means the\n * route's enumeration did not positively succeed — `renders` comes off.\n * Returns whether the payload changed (the caller's push signal).\n */\nexport function applyRenders(\n state: RoutesState,\n renders: ReadonlyMap<string, ReadonlyArray<string>>,\n): boolean {\n let changed = false;\n state.current = state.current.map((info) => {\n const values = renders.get(info.pattern);\n if (values === undefined) {\n if (info.renders !== undefined) changed = true;\n return { ...info, renders: undefined };\n }\n if (samePayload(values, info.renders)) return info;\n changed = true;\n return { ...info, renders: [...values] };\n });\n return changed;\n}\n\n/** Payload equality over the projection's small JSON shape (stable key order). */\nfunction samePayload(a: unknown, b: unknown): boolean {\n return JSON.stringify(a) === JSON.stringify(b);\n}\n\n/**\n * `GET /__astroix/routes` — the routes array captured from\n * `astro:routes:resolved` (re-runs on route changes via dev restarts).\n * Served synchronously from the container: the background enumeration fills\n * `renders` into the same array slots, and its completion pushes the\n * `astroix:routes-changed` WS event so the chrome refetches (#119). A\n * routing concern, not a content one: the concept grows from here — the\n * resolver (#69) and the overrides-file naming both key on route patterns.\n */\nexport const routesHandlers: readonly ApiHandler[] = [\n { method: 'GET', path: '/routes', handle: handleRoutes },\n];\n\nasync function handleRoutes(\n _req: IncomingMessage,\n res: ServerResponse,\n _url: URL,\n ctx: ApiContext,\n): Promise<void> {\n json(res, 200, ctx.routes.current);\n}\n","import { existsSync, realpathSync } from 'node:fs';\nimport { fileURLToPath, URL as NodeURL } from 'node:url';\n\n/**\n * Dev-checkout detection for the ADR-0001 mode switch: the chrome client\n * sources sit as a sibling of the running `dist/` — true for this repo's\n * checkout and for the src-ful staging (`.astroix-local-src`, whose `src` is\n * a symlink to the repo's), false for the publish-shaped staging\n * (`.astroix-local`, dist-only) and for every consumer install (no `src/`\n * ships). This module executes from the bundled `dist/index.js` at runtime.\n * `URL` comes from `node:url` because happy-dom (unit tests) patches the\n * global `URL` with its own class, which `fileURLToPath` rejects.\n *\n * The sibling depth is load-bearing (#150): an earlier two-depth candidate\n * (`../../src/client/entry.tsx`) leaked source mode into the dist-only\n * staging — node realpath-resolves the module through the per-file symlink\n * install to `.astroix-local/dist/index.js`, and the reach-through then hit\n * the repo's own `src/`, so the main lane silently kept serving chrome\n * source instead of exercising the publish-shaped artifact it links.\n */\nconst candidate = fileURLToPath(new NodeURL('../src/client/entry.tsx', import.meta.url));\n\n/**\n * The served entry, resolved to its real path: the src-staging's `src` is a\n * symlink, and every downstream consumer (the `/@fs` URL, `server.fs.allow`,\n * the `plugin-react` include regex) must operate on the repo path it points\n * at — the class of symlink-vs-realpath edge this detection sits on.\n */\nexport const clientEntryPath: string | null = existsSync(candidate)\n ? realpathSync(candidate)\n : null;\n\n/**\n * The prebuilt chrome bundle (ADR-0001): a self-contained ESM shipped inside\n * `dist/`. Served by the virtual chrome module when the dev-checkout sources\n * are absent — the consumer-facing delivery mode.\n */\nexport const chromeArtifactPath: string = fileURLToPath(\n new NodeURL('./chrome.js', import.meta.url),\n);\n\nexport function isSourceMode(): boolean {\n return clientEntryPath !== null;\n}\n","import type { AstroUserConfig } from 'astro';\n\n/**\n * Guard: skip our Tailwind plugin when the host already registered one.\n * The `@tailwindcss/vite` factory returns an array whose plugin names start\n * with `@tailwindcss/vite:` (verified on 4.x) — that prefix is the check.\n */\nexport function hostRegistersTailwind(viteConfig: AstroUserConfig['vite']): boolean {\n const seen = new Set<string>();\n const walk = (input: unknown): void => {\n if (Array.isArray(input)) {\n for (const entry of input) walk(entry);\n return;\n }\n if (!input || typeof input !== 'object') return;\n const plugin = input as { name?: unknown };\n if (typeof plugin.name === 'string') seen.add(plugin.name);\n };\n walk(viteConfig?.plugins);\n for (const name of seen) {\n if (name.startsWith('@tailwindcss/vite')) return true;\n }\n return false;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { Plugin, ViteDevServer } from 'vite';\nimport { registerApiEndpoints } from './api';\nimport { chromeHtml } from './chrome-html';\nimport { registerChromeReloadShield } from './chrome-reload-shield';\nimport { contentHandlers } from './content';\nimport { isDocumentRequest } from './document-request';\nimport { restHandlers } from './rest';\nimport { registerRouteEnumeration } from './route-enumeration';\nimport { type RoutesState, routesHandlers } from './routes';\nimport { chromeArtifactPath, clientEntryPath } from './source-mode';\nimport { registerFileSync } from './watch-sync';\n\nexport const VIRTUAL_CHROME_ID = 'virtual:astroix/chrome';\n\nexport interface AstroixPluginOptions {\n /** Absolute Astro src dir with the sources to index; defaults to `<root>/src`. */\n srcDir?: string;\n /** Routes captured by the integration's `astro:routes:resolved` hook, served at `/__astroix/routes`. */\n routes: RoutesState;\n}\n\n/**\n * The astroix Vite plugin: default-on chrome over every top-level dev URL.\n * The middleware is registered in the body of `configureServer` (pre-internal)\n * because Astro's dev handler lives in a post-hook and never calls `next()` —\n * this is the only position that sees every request (core-reuse §1). The\n * chrome HTML passes through `server.transformIndexHtml` (the plugin hook\n * never fires for Astro pages, the server API does) which injects the Vite\n * client and the plugin-react preamble.\n */\nexport function astroixVitePlugin(options: AstroixPluginOptions): Plugin {\n return {\n name: 'astroix',\n configureServer(server: ViteDevServer) {\n server.middlewares.use((req, res, next) => {\n void (async () => {\n try {\n const url = req.url ?? '/';\n if (\n !isDocumentRequest({ method: req.method ?? 'GET', url, accept: req.headers.accept })\n ) {\n next();\n return;\n }\n const html = await server.transformIndexHtml(url, chromeHtml());\n res.statusCode = 200;\n res.setHeader('content-type', 'text/html; charset=utf-8');\n res.end(html);\n } catch (error) {\n next(error instanceof Error ? error : new Error(String(error)));\n }\n })();\n });\n const srcDir = options.srcDir ?? join(server.config.root, 'src');\n registerApiEndpoints(server, {\n root: server.config.root,\n srcDir,\n routes: options.routes,\n handlers: [...restHandlers, ...contentHandlers, ...routesHandlers],\n });\n // the background getStaticPaths pass — fills `renders` into the routes\n // payload and pushes `astroix:routes-changed` when it lands (#119)\n registerRouteEnumeration(server, {\n root: server.config.root,\n srcDir,\n routes: options.routes,\n });\n registerFileSync(server, { root: server.config.root, srcDir });\n registerChromeReloadShield(server);\n },\n resolveId(id) {\n // The HTML references `/virtual:astroix/chrome`; imports may use the bare id.\n if (id === VIRTUAL_CHROME_ID || id === `/${VIRTUAL_CHROME_ID}`) {\n return VIRTUAL_CHROME_ID;\n }\n return null;\n },\n load(id) {\n if (id !== VIRTUAL_CHROME_ID) return null;\n if (clientEntryPath !== null) {\n // ADR-0001 source mode: the chrome loads from this checkout's source,\n // so the host dev server transforms it (fast-refresh, Tailwind). The\n // mode discriminator rides the mount call so each e2e lane can pin\n // the delivery mode it boots (#150).\n return `import { mountChrome } from '/@fs${clientEntryPath}';\\nmountChrome('source');\\n`;\n }\n // ADR-0001 prebuilt mode: serve the shipped bundle — a self-contained\n // ESM with react, the compiled CSS and CodeMirror inside, so foreign\n // hosts resolve none of our chrome dependencies. Missing artifact =\n // broken package build; fail loudly, never silently (ADR-0001).\n if (!existsSync(chromeArtifactPath)) {\n throw new Error(\n 'astroix: prebuilt chrome bundle is missing from the package build (expected dist/chrome.js)',\n );\n }\n return readFileSync(chromeArtifactPath, 'utf8');\n },\n };\n}\n","/**\n * The chrome document shell: a mount point and the virtual-module reference.\n * Layout lives inside the shadow root (React app); the document only resets\n * geometry so the shadow host can fill the viewport.\n */\nexport function chromeHtml(): string {\n return `<!doctype html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\" />\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <title>astroix builder</title>\n <style>\n html, body { margin: 0; height: 100%; }\n #astroix-root { display: block; height: 100vh; }\n </style>\n </head>\n <body>\n <div id=\"astroix-root\"></div>\n <script type=\"module\" src=\"/virtual:astroix/chrome\"></script>\n </body>\n</html>`;\n}\n","import type { ViteDevServer } from 'vite';\n\n/**\n * The chrome's full-reload shield (spec #13/#74): Astro's content sync\n * broadcasts a vite `full-reload` to every connected page — the canvas\n * iframe is one (it reloads exactly as Astro intends, the live preview), but\n * so is the chrome, whose in-memory session (open tab, active entry, dirty\n * draft) a reload would destroy on every write pause. The chrome announces\n * itself over the hot channel; the shield reroutes `full-reload` broadcasts\n * around announced clients only — every other page (canvas, the host\n * developer's own tabs) keeps Astro's behavior untouched. Custom events and\n * module updates flow to everyone as before; a vite whose internals move\n * past this seam degrades to today's behavior (the chrome reloads).\n */\n\n/** The public slice of vite's per-socket client wrapper the shield consumes. */\ninterface HotClient {\n send: (payload: unknown) => void;\n /** WebSocket readyState — 1 is OPEN; sends on dead sockets throw. */\n socket: { readyState: number };\n}\n\n/** The structural slice of vite's ws wrapper (`server.ws`/`server.hot`). */\ninterface HotChannel {\n // the wrapper accepts both a payload object and the (event, data) custom form\n send: (payload: unknown, ...rest: unknown[]) => void;\n on: (event: string, handler: (data: unknown, client: HotClient) => void) => void;\n clients: Set<HotClient>;\n}\n\nexport function registerChromeReloadShield(server: ViteDevServer): void {\n const channel = server.ws as unknown as HotChannel;\n const chromeClients = new Set<HotClient>();\n\n channel.on('astroix:chrome', (_data, client) => {\n // prune clients whose socket left the channel (chrome reloads/remounts)\n // while adding the announcer — dev scale makes this cheap, not urgent\n for (const known of chromeClients) {\n if (!channel.clients.has(known)) chromeClients.delete(known);\n }\n chromeClients.add(client);\n });\n\n const broadcast = channel.send.bind(channel);\n channel.send = (payload: unknown, ...rest: unknown[]) => {\n if (\n typeof payload === 'object' &&\n (payload as { type?: string } | null)?.type === 'full-reload'\n ) {\n // vite's own broadcast only sends to OPEN sockets — a send on a dying\n // one throws, and the throw would kill whatever pipeline called us\n // (astro's content sync wedges mid-flight); skip exactly like vite,\n // and never let a stray send failure escape either\n for (const client of channel.clients) {\n if (chromeClients.has(client) || client.socket.readyState !== 1) continue;\n try {\n client.send(payload);\n } catch {\n // the socket died between the check and the send — its page\n // reconnects and reloads on the next broadcast\n }\n }\n return;\n }\n broadcast(payload, ...rest);\n };\n}\n","import { existsSync } from 'node:fs';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { join } from 'node:path';\nimport { z } from 'astro/zod';\nimport { createServerModuleRunner } from 'vite';\nimport type { CollectionEntryRecord, CollectionRecord } from '../core/collections';\nimport {\n type IssueLike,\n toIssueRecords,\n type ValidationIssueRecord,\n walkSchemaFields,\n} from '../core/form-tree';\nimport { type ApiContext, type ApiHandler, json, readJsonBody } from './api';\nimport { writeGuarded } from './rest';\n\n/** The content endpoints: read-side (core-reuse §3) and the auto-write (Impl #9). */\nexport const contentHandlers: readonly ApiHandler[] = [\n { method: 'GET', path: '/collections', handle: handleCollections },\n { method: 'GET', path: '/content-schema', handle: handleContentSchema },\n { method: 'POST', path: '/content-validate', handle: handleContentValidate },\n { method: 'POST', path: '/content-write', handle: handleContentWrite },\n];\n\n/**\n * `GET /__astroix/collections` — collections + entries through core's own\n * `astro:content` module: parsed `data`, `body`, `filePath` per entry, plus\n * schema presence from the content config. **Stateless doctrine**: a fresh\n * module runner per request, no module held between requests — core clears\n * its caches on invalidation, so anything we cache would go stale. Raw entry\n * bytes go through the root-confined `GET /__astroix/file` (rest.ts).\n */\nasync function handleCollections(\n _req: IncomingMessage,\n res: ServerResponse,\n _url: URL,\n ctx: ApiContext,\n): Promise<void> {\n const payload = await withContentConfig(ctx, async (runner, configModule) => {\n const contentModule = (await runner.import('astro:content')) as RawContentModule;\n return assembleCollectionsPayload(configModule, contentModule);\n });\n json(res, 200, payload);\n}\n\n/**\n * The stateless-doctrine sequence every content endpoint starts with: one\n * fresh module runner per request (nothing held between requests — core\n * clears its caches on invalidation), importing the user's content config\n * as the runner evaluates it. The runner closes when `use` settles: its\n * transport pins a `send` listener on the ssr hot channel, and a fresh\n * runner per request leaks one listener each otherwise (#146).\n */\nasync function withContentConfig<T>(\n ctx: ApiContext,\n use: (\n runner: ReturnType<typeof createServerModuleRunner>,\n configModule: RawContentConfig | null,\n ) => Promise<T>,\n): Promise<T> {\n const runner = createServerModuleRunner(ctx.server.environments.ssr);\n try {\n const configPath = findContentConfigPath(ctx.srcDir);\n const configModule =\n configPath === null ? null : ((await runner.import(configPath)) as RawContentConfig);\n return await use(runner, configModule);\n } finally {\n // teardown of dev-only listener noise must not mask the endpoint's result\n await runner.close().catch(() => {});\n }\n}\n\n/** The user's `content.config` module as the runner evaluates it. */\nexport interface RawContentConfig {\n collections?: unknown;\n}\n\n/** `astro:content` as the runner evaluates it — only the surface this module consumes. */\nexport interface RawContentModule {\n getCollection?: (name: string) => Promise<unknown[]>;\n}\n\n/**\n * Joins the config's collection definitions (names, schema presence) with\n * core's `getCollection` results. Deterministic: collections and entries are\n * name/id-sorted regardless of store iteration order.\n */\nexport async function assembleCollectionsPayload(\n configModule: RawContentConfig | null,\n contentModule: RawContentModule,\n): Promise<CollectionRecord[]> {\n const definitions = toDefinitionMap(configModule?.collections);\n const collections: CollectionRecord[] = [];\n for (const name of Object.keys(definitions).sort()) {\n const entries = await loadEntries(contentModule, name);\n collections.push({ name, hasSchema: definitions[name]?.schema !== undefined, entries });\n }\n return collections;\n}\n\n/** `Record<string, { schema?: unknown }>` or an empty record — never throws on a malformed config. */\nfunction toDefinitionMap(collections: unknown): Record<string, { schema?: unknown }> {\n if (typeof collections !== 'object' || collections === null) return {};\n const definitions: Record<string, { schema?: unknown }> = {};\n for (const [name, definition] of Object.entries(collections)) {\n if (typeof definition === 'object' && definition !== null) {\n definitions[name] = definition as { schema?: unknown };\n }\n }\n return definitions;\n}\n\nasync function loadEntries(\n contentModule: RawContentModule,\n name: string,\n): Promise<CollectionEntryRecord[]> {\n const raw = (await contentModule.getCollection?.(name)) ?? [];\n return (\n raw\n .filter(\n (entry): entry is { id: string; filePath?: unknown; data?: unknown; body?: unknown } =>\n typeof entry === 'object' &&\n entry !== null &&\n typeof (entry as { id?: unknown }).id === 'string',\n )\n .map((entry) => ({\n id: entry.id,\n filePath: typeof entry.filePath === 'string' ? entry.filePath : null,\n data: entry.data ?? null,\n body: typeof entry.body === 'string' ? entry.body : null,\n }))\n // Code-unit order, like the collection-name sort above — localeCompare\n // follows process collation, which can order ids per machine.\n .sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0))\n );\n}\n\n/**\n * `GET /__astroix/content-schema?collection=<name>` — the collection's schema\n * walked into the JSON field tree the chrome renders widgets from (#72).\n * Schema-less collections and non-object roots degrade to a root raw field:\n * every collection opens in the builder regardless of its schema's shape.\n */\nasync function handleContentSchema(\n _req: IncomingMessage,\n res: ServerResponse,\n url: URL,\n ctx: ApiContext,\n): Promise<void> {\n const loaded = await loadCollectionSchema(ctx, url.searchParams.get('collection'));\n if (loaded === null) {\n json(res, 400, { error: 'collection query parameter is missing or unknown' });\n return;\n }\n const fields = walkSchemaFields(loaded.resolved.schema, {\n isImage: (schema) => loaded.resolved.imageStubs.has(schema as object),\n });\n json(res, 200, { collection: loaded.name, fields });\n}\n\n/**\n * `POST /__astroix/content-validate?collection=<name>` — safeParse of the\n * chrome's draft against the same schema instance the form was generated\n * from (the repo-mapping doctrine: no parallel schema reconstruction\n * client-side). Advisory only: issues render inline and never gate anything\n * (US12) — this slice has no write to gate.\n */\nasync function handleContentValidate(\n req: IncomingMessage,\n res: ServerResponse,\n url: URL,\n ctx: ApiContext,\n): Promise<void> {\n const loaded = await loadCollectionSchema(ctx, url.searchParams.get('collection'));\n if (loaded === null) {\n json(res, 400, { error: 'collection query parameter is missing or unknown' });\n return;\n }\n let data: unknown;\n try {\n data = await readJsonBody(req);\n } catch (error) {\n json(res, 400, { error: error instanceof Error ? error.message : 'unreadable body' });\n return;\n }\n const issues = await validateDraft(loaded.resolved.schema, data);\n json(res, 200, { ok: issues.length === 0, issues });\n}\n\n/** Minimal structural surface of a zod schema's async parse. */\ninterface AsyncSafeParse {\n safeParseAsync?: (\n input: unknown,\n ) => Promise<{ success: true } | { success: false; error: { issues: readonly IssueLike[] } }>;\n}\n\n/**\n * `POST /__astroix/content-write` — the content auto-write's whole-file write\n * (spec Impl #9): the chrome serializes the entry (core's entry-writer) and\n * posts the full bytes with the hash of the baseline it serialized from.\n * `writeGuarded` owns the shared hash-guard skeleton (Impl #10).\n */\nasync function handleContentWrite(\n req: IncomingMessage,\n res: ServerResponse,\n _url: URL,\n ctx: ApiContext,\n): Promise<void> {\n let body: unknown;\n try {\n body = await readJsonBody(req);\n } catch (error) {\n json(res, 400, { error: error instanceof Error ? error.message : 'unreadable body' });\n return;\n }\n const { file, contents, expected } = parseWriteBody(body);\n if (file === null || contents === null) {\n json(res, 400, { error: 'expected { file, contents }' });\n return;\n }\n await writeGuarded(res, ctx, file, expected, () => contents);\n}\n\nfunction parseWriteBody(body: unknown): {\n file: string | null;\n contents: string | null;\n expected: string | null;\n} {\n if (body === null || typeof body !== 'object') {\n return { file: null, contents: null, expected: null };\n }\n const { file, contents, expected } = body as Record<string, unknown>;\n return {\n file: typeof file === 'string' ? file : null,\n contents: typeof contents === 'string' ? contents : null,\n expected: typeof expected === 'string' ? expected : null,\n };\n}\n\n/**\n * Runs safeParseAsync and projects the issues. A schema that cannot parse\n * under introspection validates as clean — validation is advisory, and a\n * throwing parse must not 500 the typing loop.\n */\nexport async function validateDraft(\n schema: unknown,\n data: unknown,\n): Promise<ValidationIssueRecord[]> {\n const parse = (schema as AsyncSafeParse | null)?.safeParseAsync;\n if (parse === undefined) return [];\n try {\n const result = await parse.call(schema, data);\n return result.success ? [] : toIssueRecords(result.error.issues);\n } catch {\n return [];\n }\n}\n\n/** A collection schema resolved for walking: the instance plus our image stubs. */\nexport interface ResolvedCollectionSchema {\n schema: unknown;\n imageStubs: Set<object>;\n}\n\n/** Astro's function-schema service bag — only the `image` seam is consumed. */\ntype SchemaFunction = (services: { image: () => unknown }) => unknown;\n\n/**\n * Resolves a collection's schema out of the evaluated content config:\n * static schemas pass through; function schemas (astro's `({ image }) => …`\n * form) are called once with our own image stubs — `z.any()` instances whose\n * Set membership the walker reads through the injected `isImage` predicate.\n * The real `image()` is `z.string().transform(...)` with a Vite-bound\n * resolver, unwalkable and indistinguishable from user transforms — the\n * permissive stub keeps safeParse off read-only fields while marking them.\n * A function schema that throws under introspection degrades to no schema\n * (the raw-field root) — every collection still opens.\n */\nexport function resolveCollectionSchema(\n configModule: RawContentConfig | null,\n name: string,\n): ResolvedCollectionSchema | null {\n const definition = toDefinitionMap(configModule?.collections)[name];\n if (definition === undefined) return null;\n const imageStubs = new Set<object>();\n const raw = definition.schema;\n if (typeof raw !== 'function') return { schema: raw ?? null, imageStubs };\n try {\n const schema = (raw as SchemaFunction)({ image: () => imageStub(imageStubs) });\n return { schema, imageStubs };\n } catch {\n return { schema: null, imageStubs };\n }\n}\n\nfunction imageStub(stubs: Set<object>): unknown {\n // fresh instance per call — membership never collides with a user's z.any()\n const stub = z.any();\n stubs.add(stub);\n return stub;\n}\n\n/** Fresh-runner schema load shared by the schema and validate endpoints. */\nasync function loadCollectionSchema(\n ctx: ApiContext,\n name: string | null,\n): Promise<{ name: string; resolved: ResolvedCollectionSchema } | null> {\n if (name === null) return null;\n return withContentConfig(ctx, async (_runner, configModule) => {\n const resolved = resolveCollectionSchema(configModule, name);\n return resolved === null ? null : { name, resolved };\n });\n}\n\n/**\n * The content config path, mirroring core's search order\n * (`src/content.config.{mjs,js,mts,ts}`, then the legacy `src/content/config.*`).\n */\nexport function findContentConfigPath(srcDir: string): string | null {\n const candidates = [\n ['content.config.mjs', 'content.config.js', 'content.config.mts', 'content.config.ts'].map(\n (name) => join(srcDir, name),\n ),\n ['config.ts', 'config.js', 'config.mjs', 'config.mts'].map((name) =>\n join(srcDir, 'content', name),\n ),\n ].flat();\n return candidates.find((candidate) => existsSync(candidate)) ?? null;\n}\n","/**\n * The schema def-walk (spec Impl #4, #72): a pure, structural walk over a\n * zod 4 schema's `_zod.def` tree producing the JSON field tree the chrome\n * renders widgets from. Structural on purpose — the walked instance comes\n * from the project's own zod through the module runner, and nothing here\n * instanceof-checks against a second zod copy (\"no instanceof hell\", ticket\n * #72). `z.toJSONSchema()` is deliberately not used: it loses zod-specific\n * shapes (astro's `image()`, function schemas, wrappers) that the walk reads\n * directly.\n */\n\n/** A leaf widget kind. `image` renders read-only metadata (picker deferred). */\nexport type PrimitiveKind = 'string' | 'number' | 'boolean' | 'enum' | 'image';\n\n/** The `enum` options as declared (strings, or numbers via nativeEnum). */\nexport type EnumOptions = (string | number)[];\n\ninterface NodeBase {\n /** Dotted path into the entry's data (`cta.label`); `''` = the whole frontmatter. */\n path: string;\n /** Last path segment, human-facing. */\n label: string;\n /** False when any optional/nullable/default wrapper was peeled. */\n required: boolean;\n /** The schema's `defaultValue` when present (zod fills it into `entry.data` too). */\n initial?: unknown;\n}\n\nexport interface StringFieldNode extends NodeBase {\n kind: 'string';\n}\nexport interface NumberFieldNode extends NodeBase {\n kind: 'number';\n}\nexport interface BooleanFieldNode extends NodeBase {\n kind: 'boolean';\n}\nexport interface EnumFieldNode extends NodeBase {\n kind: 'enum';\n options: EnumOptions;\n}\n/** Read-only `src`/`width`/`height` from `entry.data`; the value round-trips untouched. */\nexport interface ImageFieldNode extends NodeBase {\n kind: 'image';\n}\n/** Array of primitives → repeatable rows; anything else walks to a raw field. */\nexport interface ArrayFieldNode extends NodeBase {\n kind: 'array';\n item: { kind: 'string' | 'number' | 'boolean' | 'enum'; options?: EnumOptions };\n}\n/** Nested object → fieldset. */\nexport interface GroupFieldNode extends NodeBase {\n kind: 'group';\n children: FormFieldNode[];\n}\n/**\n * The raw field (glossary): a clearly-marked textarea holding that subtree's\n * YAML — the convention resolving every unsupported schema node (unions,\n * transforms/pipes, records, dates, literals…): every schema opens in the\n * builder, odd fields stay editable, just widgetless.\n */\nexport interface RawFieldNode extends NodeBase {\n kind: 'raw';\n /** The zod def type that fell through the mapping. */\n reason: string;\n}\n\nexport type FormFieldNode =\n | StringFieldNode\n | NumberFieldNode\n | BooleanFieldNode\n | EnumFieldNode\n | ImageFieldNode\n | ArrayFieldNode\n | GroupFieldNode\n | RawFieldNode;\n\nexport interface WalkOptions {\n /**\n * Recognizes astro's `image()` schemas. Astro injects `image()` into\n * function schemas (`schema: ({ image }) => …`) and its real form is\n * `z.string().transform(...)` — indistinguishable from any user transform.\n * The server-side resolver substitutes its own stub instances and passes\n * their membership here; by default nothing is an image.\n */\n isImage?: (schema: unknown) => boolean;\n}\n\n/** One zod issue as served to the chrome (`POST /__astroix/content-validate`). */\nexport interface ValidationIssueRecord {\n /** Dotted path into the draft (`cta.label`, `tags.0`); `''` = the root. */\n path: string;\n code: string;\n message: string;\n}\n\n/** The structural slice of a zod issue `toIssueRecords` consumes. */\nexport interface IssueLike {\n path?: readonly PropertyKey[];\n code?: unknown;\n message: unknown;\n}\n\n/** Maps zod's issues to the served records — structural (path keys join by code unit). */\nexport function toIssueRecords(issues: Iterable<IssueLike>): ValidationIssueRecord[] {\n const records: ValidationIssueRecord[] = [];\n for (const issue of issues) {\n const path = (issue.path ?? [])\n .filter((key): key is string | number => typeof key === 'string' || typeof key === 'number')\n .join('.');\n records.push({\n path,\n code: typeof issue.code === 'string' ? issue.code : 'unknown',\n message: typeof issue.message === 'string' ? issue.message : String(issue.message),\n });\n }\n return records;\n}\n\n/**\n * Walks a collection schema into the field tree. The root is expected to be\n * an object (astro's frontmatter shape) — its children come back; any other\n * root (or no schema at all) degrades to a single root raw field, so every\n * collection opens in the builder regardless of its schema's shape.\n */\nexport function walkSchemaFields(schema: unknown, options: WalkOptions = {}): FormFieldNode[] {\n const root = walkNode(schema, '', 'frontmatter', options);\n return root.kind === 'group' ? root.children : [root];\n}\n\n/**\n * Dotted paths of the image-kind fields — the auto-write's never-touch list:\n * the draft carries zod output (ImageMetadata) there, while the frontmatter\n * value round-trips byte-identical (spec Impl #4). Arrays can't hide images\n * (their items are primitives), so only groups recurse.\n */\nexport function collectImagePaths(fields: readonly FormFieldNode[]): string[] {\n const paths: string[] = [];\n for (const field of fields) {\n if (field.kind === 'image') paths.push(field.path);\n else if (field.kind === 'group') paths.push(...collectImagePaths(field.children));\n }\n return paths;\n}\n\ninterface Peeled {\n schema: unknown;\n required: boolean;\n initial: unknown;\n hasInitial: boolean;\n}\n\n/** Peels the widget-neutral wrappers, collecting optionality and defaults. */\nfunction peelWrappers(schema: unknown): Peeled {\n let peeled: Peeled = { schema, required: true, initial: undefined, hasInitial: false };\n for (let guard = 0; guard < 32; guard += 1) {\n const def = zodDef(peeled.schema);\n if (def === null) break;\n if (def.type === 'optional' || def.type === 'nullable') {\n peeled = { ...peeled, schema: def.innerType, required: false };\n continue;\n }\n if (def.type === 'default') {\n peeled = {\n schema: def.innerType,\n required: false,\n initial: def.defaultValue,\n hasInitial: def.defaultValue !== undefined,\n };\n continue;\n }\n if (def.type === 'readonly' || def.type === 'catch') {\n peeled = { ...peeled, schema: def.innerType };\n continue;\n }\n break;\n }\n return peeled;\n}\n\nfunction walkNode(\n schema: unknown,\n path: string,\n label: string,\n options: WalkOptions,\n): FormFieldNode {\n const peeled = peelWrappers(schema);\n const base = {\n path,\n label,\n required: peeled.required,\n ...(peeled.hasInitial ? { initial: peeled.initial } : {}),\n };\n\n if (options.isImage?.(peeled.schema)) {\n return { kind: 'image', ...base };\n }\n\n const def = zodDef(peeled.schema);\n if (def?.type === undefined) {\n return { kind: 'raw', reason: 'unwalkable', ...base };\n }\n\n switch (def.type) {\n case 'string':\n return { kind: 'string', ...base };\n case 'number':\n return { kind: 'number', ...base };\n case 'boolean':\n return { kind: 'boolean', ...base };\n case 'enum':\n return {\n kind: 'enum',\n options: Object.values((def.entries ?? {}) as Record<string, string | number>),\n ...base,\n };\n case 'object': {\n const shape = def.shape;\n if (typeof shape !== 'object' || shape === null) {\n return { kind: 'raw', reason: def.type, ...base };\n }\n const children = Object.entries(shape).map(([key, child]) =>\n walkNode(child, path === '' ? key : `${path}.${key}`, key, options),\n );\n return { kind: 'group', children, ...base };\n }\n case 'array': {\n const item = peelWrappers(def.element);\n const itemDef = zodDef(item.schema);\n const itemTypeEnum = itemDef?.type;\n const itemKind =\n itemTypeEnum === 'string' ||\n itemTypeEnum === 'number' ||\n itemTypeEnum === 'boolean' ||\n itemTypeEnum === 'enum'\n ? itemTypeEnum\n : null;\n if (itemKind === null) {\n return {\n kind: 'raw',\n reason: `${def.type}<${itemTypeEnum ?? 'unknown'}>`,\n ...base,\n };\n }\n return {\n kind: 'array',\n item: {\n kind: itemKind,\n ...(itemTypeEnum === 'enum'\n ? {\n options: Object.values((itemDef?.entries ?? {}) as Record<string, string | number>),\n }\n : {}),\n },\n ...base,\n };\n }\n default:\n // union, record, literal, date, pipe (transforms), intersection, tuple,\n // lazy, any, unknown… — the raw-field convention's whole catalogue\n return { kind: 'raw', reason: def.type, ...base };\n }\n}\n\n/**\n * The structural slice of a zod 4 `_zod.def` the walk consumes — typed to\n * keep the switch narrow; every field is optional because defs are open.\n */\ninterface ZodDef {\n type?: string;\n innerType?: unknown;\n defaultValue?: unknown;\n entries?: Record<string, unknown>;\n shape?: Record<string, unknown>;\n element?: unknown;\n}\n\n/** `_zod.def` when present, else null — zod 4's structural contract. */\nfunction zodDef(schema: unknown): ZodDef | null {\n if (typeof schema !== 'object' || schema === null) return null;\n const holder = (schema as { _zod?: { def?: unknown } })._zod;\n if (typeof holder !== 'object' || holder === null) return null;\n if (typeof holder.def !== 'object' || holder.def === null) return null;\n return holder.def as ZodDef;\n}\n","import { createHash } from 'node:crypto';\nimport { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { join, relative, resolve, sep } from 'node:path';\nimport postcss from 'postcss';\nimport type { ViteDevServer } from 'vite';\nimport { buildCssIndex, type SourceFile } from '../core/indexer';\nimport type { IndexPayloadRecord } from '../core/matcher';\nimport { SpliceRangeError, spliceText } from '../core/splice-writer';\nimport { type ApiContext, type ApiHandler, json, readJsonBody } from './api';\n\n/** The css endpoints: the index payload, root-confined file reads, disk splices. */\nexport const restHandlers: readonly ApiHandler[] = [\n // The bare mount serves the index payload too (connect hands it as `/`).\n { method: 'GET', path: '/', handle: handleIndex },\n { method: 'GET', path: '/index', handle: handleIndex },\n { method: 'GET', path: '/file', handle: handleFile },\n { method: 'POST', path: '/edit', handle: handleEdit },\n];\n\nasync function handleIndex(\n _req: IncomingMessage,\n res: ServerResponse,\n _url: URL,\n ctx: ApiContext,\n): Promise<void> {\n const payload = await buildIndexPayload(collectSources(ctx.srcDir), (file, blockIndex) =>\n resolveCompiledCss(ctx.server, ctx.root, file, blockIndex),\n );\n // Payload paths are project-relative; the join worked in absolute space.\n json(\n res,\n 200,\n payload.map((record) => ({ ...record, file: toRelative(ctx.root, record.file) })),\n );\n}\n\n// File content for the editor pane — a dedicated endpoint (not payload\n// fields) so contents are fresh exactly when a rule is opened and the\n// payload stays small. Same root confinement as the edit endpoint.\nasync function handleFile(\n _req: IncomingMessage,\n res: ServerResponse,\n url: URL,\n ctx: ApiContext,\n): Promise<void> {\n const file = url.searchParams.get('file');\n const absPath = file === null ? null : safeResolve(ctx.root, file);\n if (file === null || absPath === null || !existsSync(absPath)) {\n json(res, 400, { error: `file is missing or outside the project root: ${file ?? ''}` });\n return;\n }\n json(res, 200, { file, contents: readFileSync(absPath, 'utf8') });\n}\n\nasync function handleEdit(\n req: IncomingMessage,\n res: ServerResponse,\n _url: URL,\n ctx: ApiContext,\n): Promise<void> {\n let body: unknown;\n try {\n body = await readJsonBody(req);\n } catch (error) {\n json(res, 400, { error: error instanceof Error ? error.message : 'unreadable body' });\n return;\n }\n const { file, range, replacement, expected } = parseEditBody(body);\n if (file === null || range === null || replacement === null) {\n json(res, 400, { error: 'expected { file, range: { start, end }, replacement }' });\n return;\n }\n await writeGuarded(res, ctx, file, expected, (disk) =>\n spliceText(disk, { start: range[0], end: range[1], replacement }),\n );\n}\n\n/**\n * The hash-guarded write skeleton both write endpoints share (Impl #10):\n * root confinement, the missing-file taxonomy, then the optimistic `expected`\n * sha256 check — a mismatch means the file changed on disk under the chrome's\n * debounce (IDE/agent edit), so refuse and hand back the current bytes for a\n * one-roundtrip reload. `produce` computes the next bytes from the disk\n * truth; a `SpliceRangeError` maps to the 400 taxonomy, anything else throws\n * on through the dispatcher.\n */\nexport async function writeGuarded(\n res: ServerResponse,\n ctx: ApiContext,\n file: string,\n expected: string | null,\n produce: (disk: string) => string,\n): Promise<void> {\n const absPath = safeResolve(ctx.root, file);\n if (absPath === null) {\n json(res, 400, { error: `file is outside the project root: ${file}` });\n return;\n }\n if (!existsSync(absPath)) {\n json(res, 400, { error: `file is missing: ${file}` });\n return;\n }\n const disk = readFileSync(absPath, 'utf8');\n if (expected !== null && sha256(disk) !== expected) {\n json(res, 409, { error: 'file changed on disk', contents: disk });\n return;\n }\n try {\n writeFileSync(absPath, produce(disk));\n } catch (error) {\n if (error instanceof SpliceRangeError) {\n json(res, 400, { error: error.message });\n return;\n }\n throw error;\n }\n json(res, 200, { ok: true });\n}\n\n/** Supplies the compiled css of a scoped style module, or null when absent. */\nexport type CompiledCssResolver = (file: string, styleBlockIndex: number) => Promise<string | null>;\n\n/**\n * The module-graph hybrid join: static records plus effective selectors for\n * scoped rules. Scoped records of one style block correlate with the compiled\n * rules of module `{file}.astro?astro&type=style&index={N}` in rule order; a\n * block with no compiled module (not loaded on the current route, or a rule\n * count mismatch) stays listed without an effective selector — the liveness\n * line of v1.\n */\nexport async function buildIndexPayload(\n sources: SourceFile[],\n resolveCompiledCss: CompiledCssResolver,\n): Promise<IndexPayloadRecord[]> {\n const payload: IndexPayloadRecord[] = buildCssIndex(sources).map((record) => ({\n ...record,\n effectiveSelector: null,\n }));\n\n const blocks = new Map<string, { file: string; styleBlockIndex: number; positions: number[] }>();\n payload.forEach((record, position) => {\n if (!record.scoped || record.styleBlockIndex === null) return;\n const key = `${record.file}\\u0000${record.styleBlockIndex}`;\n const block = blocks.get(key) ?? {\n file: record.file,\n styleBlockIndex: record.styleBlockIndex,\n positions: [],\n };\n block.positions.push(position);\n blocks.set(key, block);\n });\n\n for (const block of blocks.values()) {\n const css = await resolveCompiledCss(block.file, block.styleBlockIndex);\n if (css === null) continue;\n const selectors = compiledSelectors(css);\n block.positions.forEach((position, ruleOrder) => {\n const effectiveSelector = selectors[ruleOrder];\n const record = payload[position];\n if (effectiveSelector !== undefined && record !== undefined) {\n record.effectiveSelector = effectiveSelector;\n }\n });\n }\n return payload;\n}\n\n/** Selectors of the compiled css in rule order — the join's correlation key. */\nexport function compiledSelectors(css: string): string[] {\n const selectors: string[] = [];\n postcss.parse(css).walkRules((rule) => {\n selectors.push(rule.selector);\n });\n return selectors;\n}\n\n/** Pulls the css text out of a dev-transformed css module's code. */\nexport function extractCssFromModuleCode(code: string): string | null {\n const match = code.match(/__vite__css = (\"(?:[^\"\\\\]|\\\\.)*\")/);\n if (match?.[1] === undefined) return null;\n try {\n return JSON.parse(match[1]) as string;\n } catch {\n return null;\n }\n}\n\nasync function resolveCompiledCss(\n server: ViteDevServer,\n root: string,\n file: string,\n styleBlockIndex: number,\n): Promise<string | null> {\n const moduleUrl = `/${toRelative(root, file)}?astro&type=style&index=${styleBlockIndex}&lang.css`;\n const module = await server.environments.client.moduleGraph.getModuleByUrl(moduleUrl);\n const code = module?.transformResult?.code;\n if (code === undefined || code === null) return null;\n return extractCssFromModuleCode(code);\n}\n\n/** Walks `src/**` collecting the css/astro sources the indexer consumes. */\nexport function collectSources(srcDir: string): SourceFile[] {\n if (!existsSync(srcDir)) return [];\n const sources: SourceFile[] = [];\n const walk = (dir: string): void => {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.name.startsWith('.') || entry.name === 'node_modules') continue;\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n walk(full);\n } else if (entry.name.endsWith('.css') || entry.name.endsWith('.astro')) {\n sources.push({ file: full, contents: readFileSync(full, 'utf8') });\n }\n }\n };\n walk(srcDir);\n return sources;\n}\n\n/** Project-relative posix path — also the file id used by the sync events. */\nexport function toRelative(root: string, file: string): string {\n return relative(root, file).split(sep).join('/');\n}\n\n/** The confinement check every file-touching endpoint shares (content.ts too). */\nexport function safeResolve(root: string, file: string): string | null {\n const absPath = resolve(root, file);\n if (absPath !== root && !absPath.startsWith(`${root}${sep}`)) return null;\n return absPath;\n}\n\nfunction parseEditBody(body: unknown): {\n file: string | null;\n range: [number, number] | null;\n replacement: string | null;\n expected: string | null;\n} {\n if (body === null || typeof body !== 'object') {\n return { file: null, range: null, replacement: null, expected: null };\n }\n const { file, range, replacement, expected } = body as Record<string, unknown>;\n const validRange =\n typeof range === 'object' &&\n range !== null &&\n typeof (range as Record<string, unknown>).start === 'number' &&\n typeof (range as Record<string, unknown>).end === 'number'\n ? ([(range as Record<string, unknown>).start, (range as Record<string, unknown>).end] as [\n number,\n number,\n ])\n : null;\n return {\n file: typeof file === 'string' ? file : null,\n range: validRange,\n replacement: typeof replacement === 'string' ? replacement : null,\n expected: typeof expected === 'string' ? expected : null,\n };\n}\n\n/** sha256 hex — the optimistic-write guard's currency, shared with content.ts. */\nexport function sha256(text: string): string {\n return createHash('sha256').update(text).digest('hex');\n}\n","import { extractStylesSync } from '@astrojs/compiler-binding';\nimport postcss from 'postcss';\n\n/** A project CSS source to index: path + raw contents. No IO happens here. */\nexport interface SourceFile {\n file: string;\n contents: string;\n}\n\n/**\n * One rule from the edit-truth index. The range is in character offsets of\n * `file` and covers the rule from its selector through the closing brace\n * (end-exclusive) — the splice-writer edits inside these bounds.\n */\nexport interface CssRuleRecord {\n /** Selector text verbatim from source (source space — no cid synthesis here). */\n selector: string;\n file: string;\n range: { start: number; end: number };\n /**\n * One-based line of the rule's selector in `file`, derived from the range\n * at index time (the indexer holds the contents) — the rule list shows it.\n */\n line: number;\n /** Condition of the nearest `@media` ancestor, or null at the top level. */\n media: string | null;\n /** True for rules from a scoped `<style>` block (the compiler applies the cid). */\n scoped: boolean;\n /**\n * Zero-based style-block index correlating with the module-graph module id\n * `{file}.astro?astro&type=style&index={N}` — the join key for the index\n * payload. Null when the block is not in the module graph (`is:inline`).\n */\n styleBlockIndex: number | null;\n}\n\ninterface BlockMeta {\n scoped: boolean;\n styleBlockIndex: number | null;\n baseOffset: number;\n}\n\nconst STYLE_TAG = /<style\\b[^>]*>([\\s\\S]*?)<\\/style>/g;\n\n/**\n * The indexer: scans project CSS sources into the edit-truth index\n * (selector → file, source range, media condition). Dev generates no CSS\n * sourcemaps, so this static scan is the only mapping to what's on disk —\n * and the only one that sees `is:inline` blocks.\n */\nexport function buildCssIndex(sources: SourceFile[]): CssRuleRecord[] {\n const records: CssRuleRecord[] = [];\n for (const source of sources) {\n const fileRecords = source.file.endsWith('.css')\n ? indexStylesheet(source.file, source.contents, {\n scoped: false,\n styleBlockIndex: null,\n baseOffset: 0,\n })\n : source.file.endsWith('.astro')\n ? indexAstroStyles(source.file, source.contents)\n : [];\n // Lines derive from absolute offsets against the whole file — the .astro\n // blocks were parsed as substrings but carry absolute ranges.\n for (const record of fileRecords) {\n records.push({ ...record, line: lineAt(source.contents, record.range.start) });\n }\n }\n return records;\n}\n\n/** One-based line number of a character offset. */\nfunction lineAt(contents: string, offset: number): number {\n let line = 1;\n for (let i = 0; i < offset && i < contents.length; i++) {\n if (contents[i] === '\\n') line += 1;\n }\n return line;\n}\n\nfunction indexStylesheet(\n file: string,\n css: string,\n meta: BlockMeta,\n): Omit<CssRuleRecord, 'line'>[] {\n const records: Omit<CssRuleRecord, 'line'>[] = [];\n postcss.parse(css).walkRules((rule) => {\n const start = rule.source?.start;\n const end = rule.source?.end;\n if (start === undefined || end === undefined) return;\n records.push({\n selector: rule.selector,\n file,\n range: { start: start.offset + meta.baseOffset, end: end.offset + meta.baseOffset },\n media: nearestMediaCondition(rule),\n scoped: meta.scoped,\n styleBlockIndex: meta.styleBlockIndex,\n });\n });\n return records;\n}\n\nfunction indexAstroStyles(file: string, source: string): Omit<CssRuleRecord, 'line'>[] {\n const records: Omit<CssRuleRecord, 'line'>[] = [];\n // extractStylesSync returns only blocks the compiler would process —\n // `is:inline` (and expression-attribute blocks) never make it there, so the\n // raw tag scan is the edit-truth pass and the compiler blocks supply the\n // module-graph index.\n const processed = extractStylesSync(source);\n let next = 0;\n\n for (const match of source.matchAll(STYLE_TAG)) {\n const content = match[1];\n if (content === undefined) continue;\n const openTag = match[0].slice(0, match[0].indexOf('>') + 1);\n const contentStart = match.index + openTag.length;\n\n const compilerBlock = processed[next];\n if (compilerBlock !== undefined && compilerBlock.content === content) {\n next += 1;\n records.push(\n ...indexStylesheet(file, content, {\n scoped: compilerBlock.attrs['is:global'] === undefined,\n styleBlockIndex: compilerBlock.index,\n baseOffset: contentStart,\n }),\n );\n } else {\n records.push(\n ...indexStylesheet(file, content, {\n scoped: false,\n styleBlockIndex: null,\n baseOffset: contentStart,\n }),\n );\n }\n }\n return records;\n}\n\nfunction nearestMediaCondition(node: postcss.Node): string | null {\n for (let parent = node.parent; parent !== undefined; parent = parent.parent) {\n if (parent.type !== 'atrule') continue;\n const atRule = parent as postcss.AtRule;\n if (atRule.name === 'media') {\n return atRule.params;\n }\n }\n return null;\n}\n","/**\n * A single text edit: replace the half-open range `[start, end)` of the file\n * content with `replacement`. Zero-length ranges insert purely. The editor\n * debounces and sends one edit at a time — this is the only write primitive.\n */\nexport interface SpliceEdit {\n start: number;\n end: number;\n replacement: string;\n}\n\n/** Thrown for ranges that do not fit the content — never produces partial output. */\nexport class SpliceRangeError extends Error {\n constructor(start: number, end: number, contentLength: number) {\n super(`Invalid splice range [${start}, ${end}) for content of length ${contentLength}`);\n this.name = 'SpliceRangeError';\n }\n}\n\n/**\n * The splice-writer primitive: (content, range, replacement) → new content.\n * Text-splice only — never reprints the file. Every byte outside the replaced\n * range stays identical, so formatting, comments and agent conventions\n * survive and the git diff is minimal.\n */\nexport function spliceText(content: string, edit: SpliceEdit): string {\n const { start, end, replacement } = edit;\n if (\n !Number.isInteger(start) ||\n !Number.isInteger(end) ||\n start < 0 ||\n end > content.length ||\n start > end\n ) {\n throw new SpliceRangeError(start, end, content.length);\n }\n return content.slice(0, start) + replacement + content.slice(end);\n}\n\n/**\n * Append a rule at EOF with exactly one added line, regardless of whether the\n * original ends with a newline (no accidental blank runs; the file's\n * trailing-newline convention is preserved).\n */\nexport function appendRule(content: string, rule: string): string {\n if (content === '') {\n return rule;\n }\n const endsWithNewline = content.endsWith('\\n');\n const body = endsWithNewline ? content : `${content}\\n`;\n return `${body}${rule}${endsWithNewline ? '\\n' : ''}`;\n}\n","/**\n * Is this request a top-level document navigation the builder should wrap?\n * Deliberately conservative: anything asset-like, internal to Vite/Astro, or\n * carrying an explicit `builder` param falls through to the host.\n */\nexport function isDocumentRequest(input: {\n method: string;\n url: string;\n accept?: string | undefined;\n}): boolean {\n if (input.method !== 'GET' && input.method !== 'HEAD') return false;\n if (!(input.accept ?? '').includes('text/html')) return false;\n\n let url: URL;\n try {\n url = new URL(input.url, 'http://astroix.internal');\n } catch {\n return false;\n }\n if (url.searchParams.has('builder')) return false;\n\n const { pathname } = url;\n if (\n pathname.startsWith('/@') ||\n pathname.startsWith('/__') ||\n pathname.startsWith('/_astro') ||\n pathname.startsWith('/virtual:')\n ) {\n return false;\n }\n // A dot in the last path segment reads as an asset (`home.css`, `foo.png`).\n if (/(^|\\/)[^/]*\\.[a-zA-Z0-9]+$/.test(pathname)) return false;\n return true;\n}\n","import { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { IntegrationResolvedRoute, PaginateFunction } from 'astro';\nimport { createServerModuleRunner, type ViteDevServer } from 'vite';\nimport {\n createContentSignalClassifier,\n createLoaderCommitClassifier,\n pushToChrome,\n} from './content-signal';\nimport { generatePaginateFunction } from './paginate';\nimport { applyRenders, isProjectPageRoute, type RoutesState } from './routes';\n\n/**\n * The background `getStaticPaths` enumeration (#119, research #118): mirrors\n * core's dev recipe — load each prerendered single-param page route's\n * entrypoint in the ssr environment, call its\n * `getStaticPaths({ paginate, routePattern })`, collect the rendered param\n * values into the routes payload's `renders`.\n *\n * Freshness rides the codebase's stateless-doctrine runner (content.ts): a\n * NEW `createServerModuleRunner` per pass, nothing held between passes —\n * and closed when the pass settles, because each runner's transport pins a\n * `send` listener on the ssr hot channel (#146). The long-lived\n * `environments.ssr.runner` cannot serve this pass — its cached\n * module bindings never see content commits (verified live on astro@7.2.7:\n * after a content edit, a direct `runner.import('astro:content')` keeps\n * returning the old entries forever, while dev requests go fresh through\n * per-request runners; the module-identity memo from the research's\n * RouteCache mirroring is therefore not just unnecessary here — on the\n * shared runner it is wrong). A fresh runner re-evaluates against the\n * module graph's transform cache: route edits are seen (vite invalidated\n * the transform), content commits are seen (the evaluation reads live\n * data), warm passes stay ms-scale.\n *\n * Cadence: debounced (400 ms), lazy (boot + hook captures + srcDir content\n * signals), never blocking a request. Content file events race the loader's\n * data commit (verified: a pass right after the event reads the previous\n * commit), so a content signal re-runs the pass twice more, 2 s apart —\n * loader commits slower than ~4 s degrade to the next real event, the same\n * stale-window class dev renders have before the loader syncs.\n *\n * Failure containment per route: try/catch + a 5 s timeout → that route's\n * `renders` comes off the payload (unknown — consumers degrade to the shape\n * premise, the marker never fires on unknown). The served endpoint never\n * awaits any of this; completion pushes `astroix:routes-changed` when the\n * payload actually moved.\n *\n * This subscription is also where `astroix:content-synced` is pushed\n * (#133): astro's own content event rides the ssr environment's hot channel\n * and never reaches the client chrome (verified live on astro@7.2.7), so\n * the chrome's collections/schema caches have no other external-edit\n * invalidation. Both the shared srcDir content signal and the loader's\n * data-store write (the post-commit half — the loader debounces the store\n * write 500 ms) push immediately, labeled with the leg that fired (#155) —\n * the chrome, not a server-side grace, sequences the loader leg's refetch\n * after the canvas's post-commit full-reload render (see\n * synced-invalidation.ts on the client side).\n */\n\nconst DEBOUNCE_MS = 400;\nconst CONTENT_FOLLOWUP_MS = 2_000;\nconst CONTENT_FOLLOWUPS = 2;\nconst ROUTE_TIMEOUT_MS = 5_000;\n\n/** A `getStaticPaths` module as the ssr runner hands it over. */\ntype StaticPathsModule = {\n getStaticPaths?: (options: {\n paginate: PaginateFunction;\n routePattern: string;\n }) => Promise<unknown> | unknown;\n};\n\n/** The param values a `getStaticPaths` result actually renders — first occurrence order, non-strings skipped (paginate's first page carries `undefined`). */\nexport function extractRenders(\n staticPaths: Iterable<{ params: Record<string, unknown> }>,\n paramKey: string,\n): string[] {\n const seen = new Set<string>();\n for (const staticPath of staticPaths) {\n const value = staticPath.params[paramKey];\n if (typeof value === 'string') seen.add(value);\n }\n return [...seen];\n}\n\nexport function registerRouteEnumeration(\n server: ViteDevServer,\n options: { root: string; srcDir: string; routes: RoutesState },\n): void {\n const isContentSignal = createContentSignalClassifier(options);\n const isLoaderCommit = createLoaderCommitClassifier(options.root);\n const results = new Map<string, readonly string[]>();\n let timer: ReturnType<typeof setTimeout> | null = null;\n let running = false;\n let rerun = false;\n let contentFollowups = 0;\n\n const push = (): void => {\n pushToChrome(server, 'astroix:routes-changed');\n };\n\n const schedule = (delay = DEBOUNCE_MS): void => {\n if (timer !== null) return;\n timer = setTimeout(() => {\n timer = null;\n void runPass();\n }, delay);\n };\n\n // Every hook capture re-arms a pass (route edits invalidate transforms,\n // the fresh runner sees them) and pushes when the served projection\n // changed — the chrome's ROUTES_KEY cache has no other invalidation.\n const onCapture = (changed: boolean): void => {\n if (changed) push();\n schedule();\n };\n\n // The content signal (shared classification, content-signal.ts): a srcDir\n // file event that is neither a captured route entrypoint (the fresh\n // runner already reads those as transformed) nor css is treated as\n // content moving — the pass re-runs now and twice more to out-wait the\n // loader's data commit. Both that signal and the loader's store write\n // push `astroix:content-synced` labeled with their leg (see the module\n // doc); the store write re-arms nothing — the enumeration cadence is\n // #119's, unchanged.\n const onFileEvent = (file: string): void => {\n if (isLoaderCommit(file)) {\n pushToChrome(server, 'astroix:content-synced', 'loader');\n return;\n }\n if (!isContentSignal(file)) return;\n pushToChrome(server, 'astroix:content-synced', 'srcdir');\n contentFollowups = CONTENT_FOLLOWUPS;\n schedule();\n };\n for (const event of ['add', 'change', 'unlink'] as const) {\n server.watcher.on(event, onFileEvent);\n }\n\n const runPass = async (): Promise<void> => {\n if (running) {\n rerun = true;\n return;\n }\n running = true;\n let runner: ReturnType<typeof createServerModuleRunner> | null = null;\n try {\n runner = createServerModuleRunner(server.environments.ssr);\n for (const route of options.routes.captured) {\n if (!isEnumeratable(route)) continue;\n const entryUrl = pathToFileURL(join(options.root, route.entrypoint)).href;\n try {\n const mod = (await withTimeout(\n runner.import(entryUrl),\n ROUTE_TIMEOUT_MS,\n )) as StaticPathsModule;\n const staticPaths = await withTimeout(callGetStaticPaths(mod, route), ROUTE_TIMEOUT_MS);\n results.set(route.pattern, extractRenders(staticPaths, paramKeyOf(route)));\n } catch {\n results.delete(route.pattern); // unknown — never a wrong `renders`\n }\n }\n } catch {\n // the pass itself must never reject in the background; route-level\n // failures were already contained above\n } finally {\n // close() drops the transport's `send` listener (one leaked per pass\n // otherwise, #146); cleanup failure must not reject the background pass\n await runner?.close().catch(() => {});\n running = false;\n }\n if (applyRenders(options.routes, results)) push();\n if (contentFollowups > 0) {\n // the loader's data commit may still be in flight — read again after\n // it, until the follow-ups run out\n contentFollowups -= 1;\n schedule(CONTENT_FOLLOWUP_MS);\n } else if (rerun) {\n rerun = false;\n schedule();\n }\n };\n\n options.routes.onCapture = onCapture;\n // Boot: arm the first pass. No push to replay — a pre-registration capture\n // predates the server listening, so no client could have missed it; every\n // capture after registration arrives as a real onCapture call.\n onCapture(false);\n}\n\n/** Prerendered single-param page routes are the payload's `renders` space — the resolver's participating shapes, minus on-demand (its `getStaticPaths` is dead code). */\nfunction isEnumeratable(route: IntegrationResolvedRoute): boolean {\n return isProjectPageRoute(route) && route.isPrerendered && route.params.length === 1;\n}\n\n/** The `getStaticPaths` params key for a rest param drops the dots (`...slug` → `slug`). */\nfunction paramKeyOf(route: IntegrationResolvedRoute): string {\n return route.params[0]?.replace(/^\\.\\.\\./, '') ?? '';\n}\n\nasync function callGetStaticPaths(mod: StaticPathsModule, route: IntegrationResolvedRoute) {\n const getStaticPaths = mod.getStaticPaths;\n if (typeof getStaticPaths !== 'function') {\n // core throws GetStaticPathsRequired for this project shape at render —\n // enumeration contains it the same way: unknown, not an error\n throw new Error(`route module has no getStaticPaths: ${route.entrypoint}`);\n }\n const result = await getStaticPaths({\n paginate: generatePaginateFunction(route),\n routePattern: route.pattern,\n });\n return result as Iterable<{ params: Record<string, unknown> }>;\n}\n\nfunction withTimeout<T>(work: Promise<T>, ms: number): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(() => reject(new Error(`timed out after ${ms}ms`)), ms);\n work.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (error: unknown) => {\n clearTimeout(timer);\n reject(error instanceof Error ? error : new Error(String(error)));\n },\n );\n });\n}\n","import { sep } from 'node:path';\nimport type { ViteDevServer } from 'vite';\nimport { toRelative } from './rest';\nimport type { RoutesState } from './routes';\n\n/**\n * A dir path as posix with the trailing slash stripped, so the `startsWith`\n * joins below match astro's URL-form dirs (a windows-style or suffixed path\n * would never match). watch-sync.ts carries the same idiom for its own dirs.\n */\nfunction toPosixDir(dir: string): string {\n return dir.split(sep).join('/').replace(/\\/+$/, '');\n}\n\n/**\n * The content signal, shared (#133): the one classification every watcher\n * subscriber that needs \"content may have moved\" consumes — today the\n * enumeration re-arm (route-enumeration.ts, #119) and the\n * `astroix:content-synced` push — so the predicate cannot drift between\n * them. A srcDir file event that is neither a captured route entrypoint\n * (route edits reach the enumeration pass as transforms) nor css\n * (watch-sync's territory). add/unlink matter as much as change (entries\n * are created and deleted, not only edited).\n */\nexport interface ContentSignalScope {\n root: string;\n srcDir: string;\n routes: RoutesState;\n}\n\nexport function createContentSignalClassifier(\n scope: ContentSignalScope,\n): (file: string) => boolean {\n const srcDir = toPosixDir(scope.srcDir);\n return (file: string): boolean => {\n // the prefix check runs in absolute space (srcDir is absolute — a\n // relative path would never match); the entrypoint check in relative\n // space (entrypoints are root-relative)\n const norm = file.split(sep).join('/');\n if (!norm.startsWith(`${srcDir}/`)) return false;\n if (norm.endsWith('.css')) return false;\n const rel = toRelative(scope.root, file);\n return !scope.routes.captured.some((route) => route.entrypoint === rel);\n };\n}\n\n/**\n * The loader's commit signal (#133): astro's dev data store lives at\n * `<root>/.astro/data-store.json` (dev always uses the dot-astro dir; the\n * chunked form lands under `.astro/data-store/`), and astro itself adds it\n * to `server.watcher` — its add/change events fire exactly when the content\n * layer wrote the store, the same instant core invalidates its own\n * data-store module. The srcDir classification fires pre-commit: the\n * loader's store write is debounced 500 ms (SAVE_DEBOUNCE_MS,\n * mutable-data-store.js on astro@7.2.7), so a chrome refetch on that\n * signal alone races the commit and loses ~always — `astroix:content-synced`\n * needs this post-commit leg to mean \"synced\". Internals seam: the store\n * path is not public API — if astro ever moves it, this predicate goes\n * quiet and the push degrades to the srcDir signal (a slower refresh,\n * never a break).\n */\nexport function createLoaderCommitClassifier(root: string): (file: string) => boolean {\n const storePrefix = `${toPosixDir(root)}/.astro/`;\n return (file: string): boolean => {\n const norm = file.split(sep).join('/');\n return norm === `${storePrefix}data-store.json` || norm.startsWith(`${storePrefix}data-store/`);\n };\n}\n\n/**\n * Which watcher leg a `astroix:content-synced` push carries (#155): the\n * srcDir signal fires pre-commit (the loader's store write is debounced\n * 500 ms), the loader's data-store write is the post-commit leg. The label\n * is the whole payload — the chrome sequences on it: only the loader leg's\n * refetch races the canvas's post-commit full-reload render (verified live\n * on astro@7.2.7: the re-render and a concurrent fresh-runner evaluation\n * leave the canvas serving the pre-commit store for good), so the chrome\n * holds that leg's invalidation until its canvas-load signal proves the\n * reload's render served, while the srcDir leg — whose refetch lands well\n * before the reload — invalidates immediately. The server stays dumb about\n * timing; it only says which signal fired.\n */\nexport type ContentSyncLeg = 'srcdir' | 'loader';\n\n/**\n * The no-audience guard this file's pushers share (routes push, #119;\n * content-synced push, #133 — watch-sync's older `file-changed` push\n * predates it): with no connected client nobody holds a stale cache key,\n * and vite accumulates a send listener per early send, which trips its\n * EventEmitter warning.\n */\nexport function pushToChrome(server: ViteDevServer, event: 'astroix:routes-changed'): void;\nexport function pushToChrome(\n server: ViteDevServer,\n event: 'astroix:content-synced',\n leg: ContentSyncLeg,\n): void;\nexport function pushToChrome(\n server: ViteDevServer,\n event: 'astroix:routes-changed' | 'astroix:content-synced',\n leg?: ContentSyncLeg,\n): void {\n if (server.ws.clients.size === 0) return;\n server.ws.send(event, event === 'astroix:content-synced' ? { leg } : {});\n}\n","import type { IntegrationResolvedRoute, PaginateFunction } from 'astro';\n\n/**\n * Vendored from astro@7.2.7 `dist/core/render/paginate.js`\n * (`generatePaginateFunction`) — core does not export it through the\n * `astro/runtime/*` wildcard, and `getStaticPaths` receives it as an\n * argument, so the enumeration pass must supply its own. Core semantics are\n * pinned by `paginate.test.ts`, which runs this against core's own\n * implementation over the same inputs. The one adaptation: core builds the\n * generator from `routeMatch.segments` + trailingSlash; the hook's\n * `IntegrationResolvedRoute.generate` already IS that generator closure.\n * The cast mirrors core's own (`callGetStaticPaths` casts for the same\n * reason): the public `PaginateFunction` is a user-facing generic\n * convenience our structural implementation satisfies.\n */\n\n/** The options object `paginate(data, args)` accepts (core's `PaginateOptions`, structurally). */\ninterface PaginateArgs {\n pageSize?: number;\n params?: Record<string, string | undefined>;\n props?: Record<string, unknown>;\n format?: (url: string) => string;\n}\n\nexport function generatePaginateFunction(route: IntegrationResolvedRoute): PaginateFunction {\n function paginateUtility(data: readonly unknown[], args: PaginateArgs = {}): unknown[] {\n const { pageSize: _pageSize, params: _params, props: _props, format: _format } = args;\n const pageSize = _pageSize || 10;\n const paramName = 'page';\n const additionalParams = _params || {};\n const additionalProps = _props || {};\n const formatUrl = _format || ((url: string) => url);\n let includesFirstPageNumber: boolean;\n if (route.params.includes(`...${paramName}`)) {\n includesFirstPageNumber = false;\n } else if (route.params.includes(`${paramName}`)) {\n includesFirstPageNumber = true;\n } else {\n throw new Error(\n `[paginate] page number param \\`${paramName}\\` not found. If you are using the paginate() helper, your route must include a [${paramName}] or [...${paramName}] param.`,\n );\n }\n const lastPage = Math.max(1, Math.ceil(data.length / pageSize));\n return [...Array(lastPage).keys()].map((num) => {\n const pageNum = num + 1;\n const start = pageSize === Number.POSITIVE_INFINITY ? 0 : (pageNum - 1) * pageSize;\n const end = Math.min(start + pageSize, data.length);\n const params = {\n ...additionalParams,\n [paramName]: includesFirstPageNumber || pageNum > 1 ? String(pageNum) : undefined,\n };\n const current = formatUrl(addRouteBase(route.generate({ ...params })));\n const next =\n pageNum === lastPage\n ? undefined\n : formatUrl(addRouteBase(route.generate({ ...params, page: String(pageNum + 1) })));\n const prev =\n pageNum === 1\n ? undefined\n : formatUrl(\n addRouteBase(\n route.generate({\n ...params,\n page:\n !includesFirstPageNumber && pageNum - 1 === 1 ? undefined : String(pageNum - 1),\n }),\n ),\n );\n const first =\n pageNum === 1\n ? undefined\n : formatUrl(\n addRouteBase(\n route.generate({ ...params, page: includesFirstPageNumber ? '1' : undefined }),\n ),\n );\n const last =\n pageNum === lastPage\n ? undefined\n : formatUrl(addRouteBase(route.generate({ ...params, page: String(lastPage) })));\n return {\n params,\n props: {\n ...additionalProps,\n page: {\n data: data.slice(start, end),\n start,\n end: end - 1,\n size: pageSize,\n total: data.length,\n currentPage: pageNum,\n lastPage,\n url: { current, next, prev, first, last },\n },\n },\n };\n });\n }\n return paginateUtility as PaginateFunction;\n}\n\n/** Core's `joinPaths(base, path)` + empty→`/`, for the dev base we run under. */\nfunction addRouteBase(path: string): string {\n const joined = `/${path.replace(/^\\/+/, '')}`;\n return joined === '' ? '/' : joined;\n}\n","import { sep } from 'node:path';\nimport type { ViteDevServer } from 'vite';\nimport { toRelative } from './rest';\n\n/**\n * The file→chrome half of the sync (spec #13): the host watcher is the only\n * FS subscriber; css/astro changes under the project's src dir are debounced\n * per file and pushed to the chrome as `astroix:file-changed` over the Vite\n * WebSocket — the same channel Astro uses for its own events. The chrome\n * refetches content/payload on receipt; its own writes echo back as no-ops\n * (content compare client-side).\n */\nexport function registerFileSync(\n server: ViteDevServer,\n options: { root: string; srcDir: string },\n): void {\n // astro hands srcDir as a URL that keeps a trailing slash — strip it or\n // the startsWith filter below never matches\n const srcDir = options.srcDir.split(sep).join('/').replace(/\\/+$/, '');\n const pending = new Map<string, ReturnType<typeof setTimeout>>();\n\n const push = (file: string): void => {\n const timer = pending.get(file);\n if (timer !== undefined) clearTimeout(timer);\n pending.set(\n file,\n setTimeout(() => {\n pending.delete(file);\n server.ws.send('astroix:file-changed', { file: toRelative(options.root, file) });\n }, 100),\n );\n };\n\n const isWatchedSource = (file: string): boolean => {\n const norm = file.split(sep).join('/');\n if (!norm.startsWith(`${srcDir}/`)) return false;\n return norm.endsWith('.css') || norm.endsWith('.astro');\n };\n\n // `add` matters too: IDE atomic saves (write temp + rename) can surface as\n // add instead of change depending on the editor\n server.watcher.on('change', (file) => {\n if (isWatchedSource(file)) push(file);\n });\n server.watcher.on('add', (file) => {\n if (isWatchedSource(file)) push(file);\n });\n}\n"],"mappings":"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","names":["fileURLToPath","existsSync","readFileSync","join","existsSync","join","existsSync","postcss","existsSync","resolveCompiledCss","postcss","join","candidate","existsSync","join","createServerModuleRunner","sep","sep","createServerModuleRunner","join","resolve","sep","sep","join","existsSync","readFileSync","fileURLToPath"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wojciechpiskorz/astroix",
3
- "version": "0.0.26",
3
+ "version": "0.0.28",
4
4
  "description": "Dev-only Astro 7 integration — a visual builder for Content Collections content and repo-mapped CSS",
5
5
  "type": "module",
6
6
  "license": "MIT",