vantris 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared/constants.ts","../src/shared/errors.ts","../src/utils/fs.ts","../src/utils/paths.ts","../src/config/load.ts","../src/config/resolve.ts","../src/html/parse.ts","../src/html/detect.ts","../src/html/client.ts","../src/server/websocket.ts","../src/server/mime.ts","../src/server/transform.ts","../src/server/static.ts","../src/server/index.ts","../src/shared/logger.ts","../src/shared/context.ts","../src/shared/watcher.ts","../src/commands/support.ts","../src/commands/dev.ts","../src/build/index.ts","../src/commands/build.ts","../src/preview/index.ts","../src/commands/preview.ts","../src/commands/index.ts","../src/cli/help.ts","../src/cli/run.ts"],"names":["dev","extname","resolve","relative","readFile"],"mappings":"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","file":"chunk-OFLPPG2U.js","sourcesContent":["/** Product name, used in CLI banners and logs. */\nexport const APP_NAME = \"vantris\";\n\n/** Current Vantris version. Kept in sync with package.json at release time. */\nexport const VERSION = \"0.2.0\";\n\n/** The HTML entry filename Vantris looks for at the project root. */\nexport const HTML_ENTRY_FILENAME = \"index.html\";\n\n/** Default directory values, relative to the project root. */\nexport const DEFAULTS = {\n root: \".\",\n rootDir: \"./src\",\n publicDir: \"./public\",\n outDir: \"./dist\",\n} as const;\n\n/** Default dev-server options. */\nexport const DEV_DEFAULTS = {\n port: 3000,\n host: \"localhost\",\n} as const;\n\n/**\n * Message the dev server pushes over the WebSocket to ask the client to\n * reload. A typed string (rather than an empty frame) keeps room for richer\n * HMR messages in v1.x without breaking the v0.2 client.\n */\nexport const RELOAD_MESSAGE = \"reload\";\n\n/** Config filenames Vantris will look for, in priority order. */\nexport const CONFIG_FILENAMES = [\n \"vantris.config.ts\",\n \"vantris.config.js\",\n \"vantris.config.mjs\",\n] as const;\n","/**\n * Base class for all errors thrown intentionally by Vantris. The CLI layer can\n * recognise these and render them cleanly (without a stack trace), while\n * unexpected errors keep their full trace.\n */\nexport class VantrisError extends Error {\n override readonly name: string = \"VantrisError\";\n\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n }\n}\n\n/** Thrown when configuration is missing, malformed, or fails to load. */\nexport class ConfigError extends VantrisError {\n override readonly name = \"ConfigError\";\n}\n\n/** Thrown when the project's HTML entry cannot be found. */\nexport class HtmlEntryError extends VantrisError {\n override readonly name = \"HtmlEntryError\";\n}\n\n/** Thrown for functionality declared but not yet implemented in this version. */\nexport class NotImplementedError extends VantrisError {\n override readonly name = \"NotImplementedError\";\n}\n\n/** Narrowing helper. */\nexport function isVantrisError(error: unknown): error is VantrisError {\n return error instanceof VantrisError;\n}\n","import { mkdir, readFile, stat } from \"node:fs/promises\";\n\n/** Returns `true` if `path` exists and is a regular file. */\nexport async function isFile(path: string): Promise<boolean> {\n try {\n return (await stat(path)).isFile();\n } catch {\n return false;\n }\n}\n\n/** Reads a UTF-8 text file. */\nexport function readTextFile(path: string): Promise<string> {\n return readFile(path, \"utf8\");\n}\n\n/** Creates a directory (and any missing parents) if it does not exist. */\nexport async function ensureDir(path: string): Promise<void> {\n await mkdir(path, { recursive: true });\n}\n","import { isAbsolute, resolve } from \"node:path\";\n\n/**\n * Resolves `target` against `base`, returning an absolute path.\n * Absolute targets are returned untouched.\n */\nexport function resolveFrom(base: string, target: string): string {\n return isAbsolute(target) ? target : resolve(base, target);\n}\n","import { pathToFileURL } from \"node:url\";\nimport type { Config, ConfigInput } from \"../types/config.js\";\nimport type { Logger } from \"../types/logger.js\";\nimport { CONFIG_FILENAMES } from \"../shared/constants.js\";\nimport { ConfigError } from \"../shared/errors.js\";\nimport { isFile } from \"../utils/fs.js\";\nimport { resolveFrom } from \"../utils/paths.js\";\n\nexport interface LoadConfigOptions {\n /** Directory to search for a config file. */\n cwd: string;\n /** Logger for diagnostics. */\n logger: Logger;\n /** Explicit config file path; bypasses filename discovery. */\n configFile?: string;\n}\n\nexport interface LoadedConfig {\n /** Parsed configuration. Empty object when no config file is present. */\n config: Config;\n /** Absolute path of the file that was loaded, or `null` when none. */\n file: string | null;\n}\n\n/**\n * Locates and loads a `vantris.config.*` file from `cwd`.\n *\n * The actual module evaluation is isolated here so the loading strategy\n * (native TS stripping today; a bundled loader such as esbuild/jiti later)\n * can change without affecting any caller. A missing config is not an error —\n * defaults take over downstream.\n */\nexport async function loadConfig(\n options: LoadConfigOptions,\n): Promise<LoadedConfig> {\n const { cwd, logger } = options;\n\n const file = options.configFile\n ? resolveFrom(cwd, options.configFile)\n : await findConfigFile(cwd);\n\n if (!file) {\n logger.debug(\"No config file found; using defaults.\");\n return { config: {}, file: null };\n }\n\n logger.debug(`Loading config from ${file}`);\n const config = await importConfig(file);\n return { config, file };\n}\n\n/** Returns the first existing config file in {@link CONFIG_FILENAMES}. */\nasync function findConfigFile(cwd: string): Promise<string | null> {\n for (const name of CONFIG_FILENAMES) {\n const candidate = resolveFrom(cwd, name);\n if (await isFile(candidate)) return candidate;\n }\n return null;\n}\n\n/**\n * Imports a config module and normalises its export to a {@link Config}.\n * Relies on the Node runtime's native TypeScript support for `.ts` files.\n */\nasync function importConfig(file: string): Promise<Config> {\n let mod: { default?: unknown };\n try {\n // Cache-bust so repeated loads (e.g. a future config-watch mode) re-read.\n const url = `${pathToFileURL(file).href}?t=${Date.now()}`;\n mod = (await import(url)) as { default?: unknown };\n } catch (cause) {\n throw new ConfigError(`Failed to load config file: ${file}`, { cause });\n }\n\n const exported = mod.default;\n if (exported === undefined) {\n throw new ConfigError(\n `Config file \"${file}\" has no default export. ` +\n `Export your config with \\`export default defineConfig({ ... })\\`.`,\n );\n }\n\n return normalise(exported as ConfigInput, file);\n}\n\n/** Resolves a {@link ConfigInput} (object or factory) into a {@link Config}. */\nasync function normalise(\n input: ConfigInput,\n file: string,\n): Promise<Config> {\n const value = typeof input === \"function\" ? await input() : input;\n\n if (value === null || typeof value !== \"object\") {\n throw new ConfigError(\n `Config file \"${file}\" must export an object (or a function returning one).`,\n );\n }\n\n return value;\n}\n","import type { Config } from \"../types/config.js\";\nimport type {\n ResolvedConfig,\n ResolvedDevConfig,\n} from \"../types/config-resolved.js\";\nimport type { ResolvedPaths } from \"../types/paths.js\";\nimport { DEFAULTS, DEV_DEFAULTS } from \"../shared/constants.js\";\nimport { resolveFrom } from \"../utils/paths.js\";\n\n/**\n * Applies defaults to a raw {@link Config} and resolves every directory to an\n * absolute path. This is the single source of truth for default values and\n * path resolution — no other module should re-derive these.\n *\n * @param raw User configuration (after loading; may be empty).\n * @param cwd Working directory the invocation started from.\n * @param configFile Absolute path of the loaded config file, or `null`.\n */\nexport function resolveConfig(\n raw: Config,\n cwd: string,\n configFile: string | null = null,\n): ResolvedConfig {\n const root = resolveFrom(cwd, raw.root ?? DEFAULTS.root);\n\n const paths: ResolvedPaths = {\n root,\n rootDir: resolveFrom(root, raw.rootDir ?? DEFAULTS.rootDir),\n publicDir: resolveFrom(root, raw.publicDir ?? DEFAULTS.publicDir),\n outDir: resolveFrom(root, raw.outDir ?? DEFAULTS.outDir),\n };\n\n const dev: ResolvedDevConfig = {\n port: raw.dev?.port ?? DEV_DEFAULTS.port,\n host: raw.dev?.host ?? DEV_DEFAULTS.host,\n };\n\n return { raw, paths, dev, configFile };\n}\n","import type { HtmlEntry, HtmlModuleScript } from \"../types/html.js\";\n\n/** Matches `<script ... type=\"module\" ... src=\"...\">` tags (any attr order). */\nconst SCRIPT_TAG = /<script\\b[^>]*>/gi;\nconst TYPE_MODULE = /\\btype\\s*=\\s*[\"']module[\"']/i;\nconst SRC_ATTR = /\\bsrc\\s*=\\s*[\"']([^\"']+)[\"']/i;\n\n/**\n * Parses raw HTML into an {@link HtmlEntry}, extracting `<script type=\"module\">`\n * `src` references.\n *\n * The analysis is intentionally regex-light rather than a full DOM parse: in\n * dev we only need to know the module entry points. This module is the single,\n * isolated home for HTML analysis, so it can grow toward a real parser (for\n * HMR boundaries, plugin transforms, virtual modules) without touching callers.\n */\nexport function parseHtml(file: string, html: string): HtmlEntry {\n const scripts: HtmlModuleScript[] = [];\n\n for (const [tag] of html.matchAll(SCRIPT_TAG)) {\n if (!TYPE_MODULE.test(tag)) continue;\n const src = SRC_ATTR.exec(tag)?.[1];\n if (src) scripts.push({ src });\n }\n\n return { file, html, scripts };\n}\n","import type { HtmlEntry } from \"../types/html.js\";\nimport { HTML_ENTRY_FILENAME } from \"../shared/constants.js\";\nimport { isFile, readTextFile } from \"../utils/fs.js\";\nimport { resolveFrom } from \"../utils/paths.js\";\nimport { parseHtml } from \"./parse.js\";\n\n/**\n * Locates the project's `index.html` entry at `root`.\n *\n * @returns The parsed {@link HtmlEntry}, or `null` if no entry exists.\n */\nexport async function detectHtmlEntry(root: string): Promise<HtmlEntry | null> {\n const file = resolveFrom(root, HTML_ENTRY_FILENAME);\n if (!(await isFile(file))) return null;\n\n const html = await readTextFile(file);\n return parseHtml(file, html);\n}\n","/**\n * The dev-only live-reload client, injected into the served HTML.\n *\n * v0.2.0 does a full page reload on any change. The WebSocket URL is derived\n * from `location.host` so it works regardless of how the host is addressed\n * (`localhost`, `127.0.0.1`, LAN IP). The message payload is ignored for now;\n * v1.x will branch on it to drive HMR instead of a full reload.\n */\nexport const DEV_CLIENT_SCRIPT = `<script type=\"module\">\n // Injected by Vantris dev server — live reload (full page).\n const connect = () => {\n const ws = new WebSocket(\"ws://\" + location.host);\n ws.addEventListener(\"message\", () => location.reload());\n // Reconnect if the dev server restarts.\n ws.addEventListener(\"close\", () => setTimeout(connect, 1000));\n };\n connect();\n</script>`;\n\n/**\n * Injects {@link DEV_CLIENT_SCRIPT} into an HTML document.\n *\n * The script is placed just before `</head>` when present, otherwise before\n * `</body>`, otherwise appended — so it loads before user modules without\n * requiring a well-formed document.\n */\nexport function injectDevClient(html: string): string {\n if (html.includes(\"</head>\")) {\n return html.replace(\"</head>\", `${DEV_CLIENT_SCRIPT}\\n</head>`);\n }\n if (html.includes(\"</body>\")) {\n return html.replace(\"</body>\", `${DEV_CLIENT_SCRIPT}\\n</body>`);\n }\n return `${html}\\n${DEV_CLIENT_SCRIPT}`;\n}\n","import type { Server as HttpServer } from \"node:http\";\nimport { WebSocket, WebSocketServer } from \"ws\";\nimport type { Logger } from \"../types/logger.js\";\nimport { RELOAD_MESSAGE } from \"../shared/constants.js\";\n\n/** Handle over the live-reload WebSocket channel. */\nexport interface ReloadSocket {\n /** Pushes a reload signal to every connected client. */\n broadcastReload(): void;\n /** Number of currently connected clients. */\n readonly clientCount: number;\n /** Closes the WebSocket server and all connections. */\n close(): Promise<void>;\n}\n\nexport interface ReloadSocketOptions {\n /** The HTTP server to share the port with (handles the WS upgrade). */\n server: HttpServer;\n logger: Logger;\n}\n\n/**\n * Attaches a live-reload WebSocket server to an existing HTTP server so the\n * client (injected into the HTML) and the server share a single port.\n *\n * The protocol is intentionally one-way and trivial in v0.2.0: the server\n * pushes {@link RELOAD_MESSAGE} and the client does a full page reload. v1.x\n * will replace this with a richer, bidirectional HMR channel — only this\n * module changes.\n */\nexport function createReloadSocket(options: ReloadSocketOptions): ReloadSocket {\n const { server, logger } = options;\n const wss = new WebSocketServer({ server });\n const clients = new Set<WebSocket>();\n\n wss.on(\"connection\", (socket) => {\n clients.add(socket);\n socket.on(\"close\", () => clients.delete(socket));\n socket.on(\"error\", () => clients.delete(socket));\n });\n\n wss.on(\"error\", (error) => {\n logger.error(`websocket error: ${error.message}`);\n });\n\n return {\n broadcastReload() {\n for (const socket of clients) {\n if (socket.readyState === WebSocket.OPEN) {\n socket.send(RELOAD_MESSAGE);\n }\n }\n },\n get clientCount() {\n return clients.size;\n },\n close() {\n return new Promise((resolveClose) => {\n for (const socket of clients) socket.terminate();\n clients.clear();\n wss.close(() => resolveClose());\n });\n },\n };\n}\n","import { extname } from \"node:path\";\n\n/**\n * Minimal extension → MIME type map for the dev server. Transpiled `.ts`/`.tsx`\n * files are served as JavaScript (see {@link contentTypeFor}). This stays small\n * on purpose; a full asset pipeline is out of scope for v0.2.0.\n */\nconst MIME_TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".txt\": \"text/plain; charset=utf-8\",\n \".map\": \"application/json; charset=utf-8\",\n};\n\nconst JAVASCRIPT = \"text/javascript; charset=utf-8\";\n\n/**\n * Resolves the `Content-Type` for a file path.\n *\n * @param file Absolute or relative file path.\n * @param transpiled When `true`, the file is served as JavaScript regardless\n * of its source extension (e.g. a transpiled `.ts`).\n */\nexport function contentTypeFor(file: string, transpiled = false): string {\n if (transpiled) return JAVASCRIPT;\n return MIME_TYPES[extname(file).toLowerCase()] ?? \"application/octet-stream\";\n}\n","import { extname } from \"node:path\";\nimport { transform, type Loader } from \"esbuild\";\n\n/** Extensions handled by the on-the-fly TypeScript/JSX transpiler. */\nconst TRANSPILE_EXTENSIONS = new Set([\".ts\", \".tsx\", \".mts\", \".cts\", \".jsx\"]);\n\n/** Whether a file path should be transpiled before being served. */\nexport function shouldTranspile(file: string): boolean {\n return TRANSPILE_EXTENSIONS.has(extname(file).toLowerCase());\n}\n\n/** Maps a file extension to the matching esbuild loader. */\nfunction loaderFor(file: string): Loader {\n switch (extname(file).toLowerCase()) {\n case \".tsx\":\n return \"tsx\";\n case \".jsx\":\n return \"jsx\";\n default:\n return \"ts\";\n }\n}\n\n/**\n * Transpiles a single TypeScript/JSX module to browser-ready ESM using esbuild.\n *\n * This is a **transform only** — no bundling, no resolution, no production\n * optimisation (those belong to the build system in a later version). Import\n * specifiers are left untouched; the dev server resolves them per request.\n * An inline source map is emitted so the browser maps back to the original.\n */\nexport async function transpile(code: string, file: string): Promise<string> {\n const result = await transform(code, {\n loader: loaderFor(file),\n format: \"esm\",\n target: \"es2022\",\n sourcemap: \"inline\",\n sourcefile: file,\n });\n return result.code;\n}\n","import { readFile } from \"node:fs/promises\";\nimport { extname, join, resolve, sep } from \"node:path\";\nimport { isFile } from \"../utils/fs.js\";\nimport { contentTypeFor } from \"./mime.js\";\nimport { shouldTranspile, transpile } from \"./transform.js\";\n\n/** Extensions tried when a request has no extension (bare module imports). */\nconst RESOLVE_EXTENSIONS = [\".ts\", \".tsx\", \".mts\", \".js\", \".mjs\", \".jsx\"];\n\n/** A resolved, ready-to-serve asset. */\nexport interface LoadedAsset {\n /** Response body — text for transpiled/HTML, bytes for binary assets. */\n body: string | Uint8Array;\n /** Resolved `Content-Type`. */\n contentType: string;\n /** `true` when the asset is an HTML document. */\n isHtml: boolean;\n}\n\nexport interface StaticLoaderOptions {\n /** Project root — base for resolving root-relative request paths. */\n root: string;\n /**\n * Source directory. Only files **inside** this directory are reachable via\n * root-relative paths (e.g. `/src/main.ts`). This is what keeps\n * `node_modules`, `package.json`, lockfiles, and config files unreachable.\n */\n rootDir: string;\n /** Public directory whose contents are served at `/` (Vite-style). */\n publicDir: string;\n}\n\n/**\n * Creates a per-request asset loader for the dev server.\n *\n * The serveable surface is an **allowlist** — only the source tree (`rootDir`)\n * and the public directory are exposed; nothing else under the project root is\n * reachable. Files are read fresh on every call so edits show up on reload, and\n * TypeScript/JSX is transpiled on the fly.\n *\n * @returns A function resolving a pathname to a {@link LoadedAsset}, or `null`\n * when nothing matches (or the path is outside the allowlist).\n */\nexport function createStaticLoader(options: StaticLoaderOptions) {\n const root = resolve(options.root);\n const rootDir = resolve(options.rootDir);\n const publicDir = resolve(options.publicDir);\n\n return async function loadAsset(\n pathname: string,\n ): Promise<LoadedAsset | null> {\n const relative = decodeURIComponent(pathname).replace(/^\\/+/, \"\");\n if (!relative) return null;\n\n // 1. Source files: resolved against the root but confined to `rootDir`,\n // so only the source subtree (e.g. `/src/*`) is ever served.\n const source = await resolveConfined(root, rootDir, relative);\n if (source) return readAsset(source);\n\n // 2. Public assets: served at `/` (e.g. `/favicon.svg`).\n const asset = await resolveConfined(publicDir, publicDir, relative);\n if (asset) return readAsset(asset);\n\n return null;\n };\n}\n\n/**\n * Resolves `relative` against `base`, trying extension candidates, and returns\n * the file only if it lands inside `confine` (the allowlist boundary). This\n * single check rejects both path traversal (`..`) and anything outside the\n * permitted directories.\n */\nasync function resolveConfined(\n base: string,\n confine: string,\n relative: string,\n): Promise<string | null> {\n const target = resolve(join(base, relative));\n if (target !== confine && !target.startsWith(confine + sep)) {\n return null;\n }\n\n if (await isFile(target)) return target;\n\n if (!extname(target)) {\n for (const ext of RESOLVE_EXTENSIONS) {\n const candidate = `${target}${ext}`;\n if (await isFile(candidate)) return candidate;\n }\n }\n return null;\n}\n\n/** Reads a file, transpiling it when needed, and resolves its content type. */\nasync function readAsset(file: string): Promise<LoadedAsset> {\n const ext = extname(file).toLowerCase();\n const isHtml = ext === \".html\";\n\n if (shouldTranspile(file)) {\n const source = await readFile(file, \"utf8\");\n return {\n body: await transpile(source, file),\n contentType: contentTypeFor(file, true),\n isHtml: false,\n };\n }\n\n if (isHtml) {\n return {\n body: await readFile(file, \"utf8\"),\n contentType: contentTypeFor(file),\n isHtml: true,\n };\n }\n\n return {\n body: await readFile(file),\n contentType: contentTypeFor(file),\n isHtml: false,\n };\n}\n","import { createServer, type Server as HttpServer } from \"node:http\";\nimport { readFile } from \"node:fs/promises\";\nimport { H3, getRequestURL, toNodeHandler } from \"h3\";\nimport type { H3Event } from \"h3\";\nimport type { Context } from \"../types/context.js\";\nimport type { HtmlEntry } from \"../types/html.js\";\nimport { injectDevClient } from \"../html/index.js\";\nimport { createReloadSocket, type ReloadSocket } from \"./websocket.js\";\nimport { createStaticLoader } from \"./static.js\";\n\n/** Options for {@link startDevServer}. */\nexport interface DevServerOptions {\n ctx: Context;\n /** The detected HTML entry, when present. */\n entry: HtmlEntry | null;\n}\n\n/** A running dev server. */\nexport interface DevServerHandle {\n /** Address the server is listening on, e.g. `http://localhost:3000/`. */\n readonly url: string;\n readonly host: string;\n readonly port: number;\n /** Pushes a full-page reload to every connected browser. */\n broadcastReload(): void;\n /** Stops the HTTP and WebSocket servers. */\n close(): Promise<void>;\n}\n\nconst HTML_HEADERS = {\n \"content-type\": \"text/html; charset=utf-8\",\n \"cache-control\": \"no-cache\",\n} as const;\n\n/**\n * Starts the H3-based development server.\n *\n * Responsibilities are split across the `server` module: this file owns the\n * HTTP routing (H3) and lifecycle, {@link createStaticLoader} owns file\n * resolution + transpilation, and {@link createReloadSocket} owns live reload.\n * The HTTP and WebSocket servers share a single port.\n */\nexport async function startDevServer(\n options: DevServerOptions,\n): Promise<DevServerHandle> {\n const { ctx, entry } = options;\n const { paths, dev } = ctx.config;\n\n const loadAsset = createStaticLoader({\n root: paths.root,\n rootDir: paths.rootDir,\n publicDir: paths.publicDir,\n });\n const entryFile = entry?.file ?? null;\n\n const app = new H3();\n const handler = async (event: H3Event) => {\n const { pathname } = getRequestURL(event);\n\n // 1. A real file on disk (transpiled if it's TypeScript/JSX).\n const asset = await loadAsset(pathname);\n if (asset) {\n if (asset.isHtml) {\n return new Response(injectDevClient(asset.body as string), {\n headers: HTML_HEADERS,\n });\n }\n return new Response(asset.body, {\n headers: { \"content-type\": asset.contentType, \"cache-control\": \"no-cache\" },\n });\n }\n\n // 2. Anything else falls back to the HTML entry. Root files\n // (package.json, configs, node_modules, …) are never read — they are\n // outside the served allowlist — so the client only ever gets index.html.\n if (entryFile) {\n const html = await readFile(entryFile, \"utf8\");\n return new Response(injectDevClient(html), { headers: HTML_HEADERS });\n }\n\n // 3. No HTML entry exists yet.\n return new Response(`404 Not Found: ${pathname}`, {\n status: 404,\n headers: { \"content-type\": \"text/plain; charset=utf-8\" },\n });\n };\n\n app.all(\"/\", handler);\n app.all(\"/**\", handler);\n\n const server: HttpServer = createServer(toNodeHandler(app));\n const reload: ReloadSocket = createReloadSocket({ server, logger: ctx.logger });\n\n await listen(server, dev.port, dev.host);\n\n const url = `http://${dev.host}:${dev.port}/`;\n\n return {\n url,\n host: dev.host,\n port: dev.port,\n broadcastReload: () => reload.broadcastReload(),\n async close() {\n await reload.close();\n await new Promise<void>((resolveClose, reject) => {\n server.close((err) => (err ? reject(err) : resolveClose()));\n });\n },\n };\n}\n\n/** Promisified `server.listen` with error propagation. */\nfunction listen(server: HttpServer, port: number, host: string): Promise<void> {\n return new Promise((resolveListen, reject) => {\n const onError = (err: NodeJS.ErrnoException) => {\n server.removeListener(\"error\", onError);\n reject(\n err.code === \"EADDRINUSE\"\n ? new Error(`Port ${port} is already in use.`)\n : err,\n );\n };\n server.once(\"error\", onError);\n server.listen(port, host, () => {\n server.removeListener(\"error\", onError);\n resolveListen();\n });\n });\n}\n","import type { Logger } from \"../types/logger.js\";\nimport { APP_NAME } from \"./constants.js\";\n\nexport interface LoggerOptions {\n /** When `false`, `debug` calls are dropped. @default false */\n verbose?: boolean;\n /** Sink for output. Defaults to the console; overridable for tests. */\n sink?: Pick<Console, \"log\" | \"warn\" | \"error\">;\n}\n\nconst prefix = `[${APP_NAME}]`;\n\n/**\n * Creates the default console-backed {@link Logger}.\n *\n * The sink is injectable so tests can capture output, and verbosity is a\n * construction-time concern rather than a global flag.\n */\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const { verbose = false, sink = console } = options;\n\n return {\n info(message) {\n sink.log(`${prefix} ${message}`);\n },\n warn(message) {\n sink.warn(`${prefix} ${message}`);\n },\n error(message) {\n sink.error(`${prefix} ${message}`);\n },\n debug(message) {\n if (verbose) sink.log(`${prefix} ${message}`);\n },\n };\n}\n","import type { Context } from \"../types/context.js\";\nimport type { Logger } from \"../types/logger.js\";\nimport { loadConfig } from \"../config/load.js\";\nimport { resolveConfig } from \"../config/resolve.js\";\n\nexport interface CreateContextOptions {\n /** Working directory the command was invoked from. */\n cwd: string;\n /** Injected logger. */\n logger: Logger;\n /** Optional explicit config file path. */\n configFile?: string;\n}\n\n/**\n * Builds the {@link Context} shared by every command: it loads the user config,\n * applies defaults, resolves paths, and bundles the injected services.\n *\n * Centralising construction here means commands never reach for global state —\n * everything they need arrives through the returned context.\n */\nexport async function createContext(\n options: CreateContextOptions,\n): Promise<Context> {\n const { cwd, logger } = options;\n\n const loaded = await loadConfig({\n cwd,\n logger,\n ...(options.configFile !== undefined\n ? { configFile: options.configFile }\n : {}),\n });\n\n const config = resolveConfig(loaded.config, cwd, loaded.file);\n\n return { cwd, config, logger };\n}\n","import { watch, type FSWatcher } from \"chokidar\";\nimport type { Logger } from \"../types/logger.js\";\n\n/** A change reported by the {@link Watcher}. */\nexport interface WatchEvent {\n /** What happened to the file. */\n kind: \"add\" | \"change\" | \"unlink\";\n /** Absolute path of the affected file. */\n file: string;\n}\n\nexport interface WatcherOptions {\n /** Directory tree to watch (typically `rootDir`). */\n dir: string;\n logger: Logger;\n /** Called on every relevant filesystem change. */\n onChange: (event: WatchEvent) => void;\n}\n\n/** A running filesystem watcher. */\nexport interface Watcher {\n /** Stops watching and releases OS resources. */\n close(): Promise<void>;\n}\n\n/**\n * Watches a directory tree and reports file changes.\n *\n * This is the single home for filesystem watching — the dev server depends on\n * the {@link Watcher} interface, not on chokidar, so the backing implementation\n * can change (or gain HMR-oriented metadata) without rippling outward.\n */\nexport function createWatcher(options: WatcherOptions): Watcher {\n const { dir, logger, onChange } = options;\n\n const watcher: FSWatcher = watch(dir, {\n ignoreInitial: true,\n persistent: true,\n ignored: (path) =>\n path.includes(\"node_modules\") || /(^|[/\\\\])\\.[^/\\\\]/.test(path),\n });\n\n const emit = (kind: WatchEvent[\"kind\"]) => (file: string) => {\n logger.debug(`watch ${kind}: ${file}`);\n onChange({ kind, file });\n };\n\n watcher\n .on(\"add\", emit(\"add\"))\n .on(\"change\", emit(\"change\"))\n .on(\"unlink\", emit(\"unlink\"))\n .on(\"error\", (error) =>\n logger.error(`watcher error: ${(error as Error).message}`),\n );\n\n return {\n close: () => watcher.close(),\n };\n}\n","import { relative } from \"node:path\";\nimport type { Context } from \"../types/context.js\";\nimport type { HtmlEntry } from \"../types/html.js\";\nimport { detectHtmlEntry } from \"../html/index.js\";\nimport { ensureDir } from \"../utils/fs.js\";\n\n/** Renders a path relative to the project root for tidy log output. */\nfunction rel(ctx: Context, target: string): string {\n return relative(ctx.config.paths.root, target) || \".\";\n}\n\n/**\n * Logs the resolved configuration and detects the HTML entry — the shared\n * preamble every command runs before delegating to its (future) engine.\n *\n * @returns The detected HTML entry, or `null` when none exists.\n */\nexport async function inspectProject(ctx: Context): Promise<HtmlEntry | null> {\n const { paths, configFile } = ctx.config;\n\n ctx.logger.info(\n `config: ${configFile ? rel(ctx, configFile) : \"defaults (no config file)\"}`,\n );\n ctx.logger.info(`rootDir: ${rel(ctx, paths.rootDir)}`);\n ctx.logger.info(`publicDir: ${rel(ctx, paths.publicDir)}`);\n ctx.logger.info(`outDir: ${rel(ctx, paths.outDir)}`);\n\n const entry = await detectHtmlEntry(paths.root);\n if (entry) {\n ctx.logger.info(`html entry: ${rel(ctx, entry.file)}`);\n } else {\n ctx.logger.warn(\n \"no index.html found at the project root; nothing to serve yet.\",\n );\n }\n\n return entry;\n}\n\n/** Ensures the given directories exist, creating them as needed. */\nexport async function prepareDirectories(\n ctx: Context,\n dirs: readonly string[],\n): Promise<void> {\n for (const dir of dirs) {\n await ensureDir(dir);\n ctx.logger.debug(`prepared directory: ${dir}`);\n }\n}\n","import { relative } from \"node:path\";\nimport type { Command } from \"../types/command.js\";\nimport { startDevServer } from \"../server/index.js\";\nimport { createWatcher } from \"../shared/watcher.js\";\nimport { inspectProject, prepareDirectories } from \"./support.js\";\n\n/** Coalesce a burst of filesystem events into a single reload. */\nconst RELOAD_DEBOUNCE_MS = 50;\n\n/**\n * `vantris dev` — start the development server.\n *\n * Runtime flow: load config (via context) → inspect project → init dev server\n * (HTTP + WebSocket) → start the file watcher → trigger live reload on change.\n * Runs until interrupted (Ctrl-C), then shuts everything down cleanly.\n */\nexport const dev: Command = {\n name: \"dev\",\n description: \"Start the development server\",\n async run(ctx) {\n const { root, rootDir, publicDir } = ctx.config.paths;\n await prepareDirectories(ctx, [rootDir, publicDir]);\n\n const entry = await inspectProject(ctx);\n\n const server = await startDevServer({ ctx, entry });\n ctx.logger.info(`ready — dev server running at ${server.url}`);\n\n let timer: NodeJS.Timeout | undefined;\n const watcher = createWatcher({\n dir: rootDir,\n logger: ctx.logger,\n onChange: ({ kind, file }) => {\n ctx.logger.info(`${kind}: ${relative(root, file)} — reloading`);\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => server.broadcastReload(), RELOAD_DEBOUNCE_MS);\n },\n });\n\n await waitForShutdown();\n\n ctx.logger.info(\"shutting down…\");\n if (timer) clearTimeout(timer);\n await watcher.close();\n await server.close();\n },\n};\n\n/** Resolves when the process receives an interrupt/terminate signal. */\nfunction waitForShutdown(): Promise<void> {\n return new Promise((resolve) => {\n const onSignal = () => {\n process.removeListener(\"SIGINT\", onSignal);\n process.removeListener(\"SIGTERM\", onSignal);\n resolve();\n };\n process.once(\"SIGINT\", onSignal);\n process.once(\"SIGTERM\", onSignal);\n });\n}\n","import type { Context } from \"../types/context.js\";\nimport type { HtmlEntry } from \"../types/html.js\";\n\n/** Options handed to the build pipeline. */\nexport interface BuildOptions {\n ctx: Context;\n /** The detected HTML entry, when present. */\n entry: HtmlEntry | null;\n}\n\n/**\n * Produces a production build into `outDir`.\n *\n * Reserved for a future version (planned: Rolldown for bundling, esbuild for\n * transforms). The seam exists now so `commands/build` can already delegate\n * here; only this file changes when the engine is implemented.\n */\nexport async function runBuild(options: BuildOptions): Promise<void> {\n const { ctx } = options;\n ctx.logger.info(\n \"build is not implemented in v0.1.0 (planned: Rolldown + esbuild).\",\n );\n}\n","import type { Command } from \"../types/command.js\";\nimport { runBuild } from \"../build/index.js\";\nimport { inspectProject, prepareDirectories } from \"./support.js\";\n\n/** `vantris build` — produce a production build. */\nexport const build: Command = {\n name: \"build\",\n description: \"Build the project for production\",\n async run(ctx) {\n const { rootDir, publicDir, outDir } = ctx.config.paths;\n await prepareDirectories(ctx, [rootDir, publicDir, outDir]);\n\n const entry = await inspectProject(ctx);\n await runBuild({ ctx, entry });\n },\n};\n","import type { Context } from \"../types/context.js\";\n\n/** Options handed to the preview server. */\nexport interface PreviewOptions {\n ctx: Context;\n}\n\n/**\n * Serves a previously produced production build from `outDir`.\n *\n * Reserved for a future version (planned: a static server over the build\n * output). The seam exists now so `commands/preview` can already delegate\n * here; only this file changes when the engine is implemented.\n */\nexport async function runPreview(options: PreviewOptions): Promise<void> {\n const { ctx } = options;\n ctx.logger.info(\n \"preview is not implemented in v0.1.0 (planned: static server over outDir).\",\n );\n}\n","import type { Command } from \"../types/command.js\";\nimport { runPreview } from \"../preview/index.js\";\nimport { inspectProject, prepareDirectories } from \"./support.js\";\n\n/** `vantris preview` — serve a production build locally. */\nexport const preview: Command = {\n name: \"preview\",\n description: \"Locally preview a production build\",\n async run(ctx) {\n await prepareDirectories(ctx, [ctx.config.paths.outDir]);\n\n await inspectProject(ctx);\n await runPreview({ ctx });\n },\n};\n","import type { Command } from \"../types/command.js\";\nimport { dev } from \"./dev.js\";\nimport { build } from \"./build.js\";\nimport { preview } from \"./preview.js\";\n\n/**\n * The command registry. The CLI routes purely against this map, so adding a\n * command is a one-line registration here plus its module — no CLI changes.\n */\nexport const commands: Readonly<Record<string, Command>> = {\n [dev.name]: dev,\n [build.name]: build,\n [preview.name]: preview,\n};\n\nexport type CommandName = keyof typeof commands;\n\nexport { dev, build, preview };\n","import { commands } from \"../commands/index.js\";\nimport { APP_NAME, VERSION } from \"../shared/constants.js\";\n\n/** Builds the help text listing every registered command. */\nexport function helpText(): string {\n const lines = [\n `${APP_NAME} v${VERSION} — a modern bundler for JavaScript/TypeScript`,\n \"\",\n \"Usage:\",\n ` ${APP_NAME} <command> [options]`,\n \"\",\n \"Commands:\",\n ];\n\n const width = Math.max(...Object.keys(commands).map((n) => n.length));\n for (const command of Object.values(commands)) {\n lines.push(` ${command.name.padEnd(width)} ${command.description}`);\n }\n\n lines.push(\n \"\",\n \"Options:\",\n \" -h, --help Show this help\",\n \" -v, --version Show the version number\",\n );\n\n return lines.join(\"\\n\");\n}\n\n/** Builds the version line. */\nexport function versionText(): string {\n return `${APP_NAME} v${VERSION}`;\n}\n","import type { Logger } from \"../types/logger.js\";\nimport { commands } from \"../commands/index.js\";\nimport { createContext } from \"../shared/context.js\";\nimport { createLogger } from \"../shared/logger.js\";\nimport { helpText, versionText } from \"./help.js\";\n\nexport interface RunOptions {\n /** Working directory; defaults to `process.cwd()`. */\n cwd?: string;\n /** Logger override, primarily for tests. */\n logger?: Logger;\n}\n\n/** Process exit codes used by the CLI. */\nexport const enum ExitCode {\n Ok = 0,\n Error = 1,\n}\n\n/**\n * Parses arguments and routes to a command. This is the entire CLI surface:\n * it owns argument handling and dispatch only — never command behaviour, which\n * lives behind the {@link commands} registry.\n *\n * @returns A process exit code.\n */\nexport async function run(\n argv: readonly string[],\n options: RunOptions = {},\n): Promise<ExitCode> {\n const verbose = argv.includes(\"--verbose\") || argv.includes(\"--debug\");\n const logger = options.logger ?? createLogger({ verbose });\n const cwd = options.cwd ?? process.cwd();\n\n const [first, ...rest] = argv.filter((arg) => !isGlobalFlag(arg));\n\n if (!first || first === \"--help\" || first === \"-h\" || first === \"help\") {\n logger.info(helpText());\n return ExitCode.Ok;\n }\n\n if (first === \"--version\" || first === \"-v\") {\n logger.info(versionText());\n return ExitCode.Ok;\n }\n\n const command = commands[first];\n if (!command) {\n logger.error(`Unknown command: \"${first}\"`);\n logger.info(helpText());\n return ExitCode.Error;\n }\n\n const ctx = await createContext({ cwd, logger });\n await command.run(ctx, rest);\n return ExitCode.Ok;\n}\n\n/** Flags handled by the runner itself rather than passed to commands. */\nfunction isGlobalFlag(arg: string): boolean {\n return arg === \"--verbose\" || arg === \"--debug\";\n}\n"]}
package/dist/cli/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { run, createLogger, isVantrisError } from '../chunk-PSXNP5S5.js';
2
+ import { run, createLogger, isVantrisError } from '../chunk-OFLPPG2U.js';
3
3
 
4
4
  // src/cli/index.ts
5
5
  async function main() {
package/dist/index.d.ts CHANGED
@@ -6,6 +6,27 @@
6
6
  * single extension point through which future versions will grow (plugins,
7
7
  * build options, HMR, server tuning, …) without breaking existing configs.
8
8
  */
9
+ /**
10
+ * Development server options.
11
+ *
12
+ * Extension point for the dev server. v0.2.0 exposes only `port` and `host`;
13
+ * future versions will add HMR, proxy, HTTPS, and middleware hooks here
14
+ * without breaking existing configs.
15
+ */
16
+ interface DevConfig {
17
+ /**
18
+ * Port the dev server listens on.
19
+ *
20
+ * @default 3000
21
+ */
22
+ port?: number;
23
+ /**
24
+ * Host the dev server binds to.
25
+ *
26
+ * @default "localhost"
27
+ */
28
+ host?: string;
29
+ }
9
30
  interface Config {
10
31
  /**
11
32
  * Project root. Resolved relative to the current working directory.
@@ -33,6 +54,10 @@ interface Config {
33
54
  * @default "./dist"
34
55
  */
35
56
  outDir?: string;
57
+ /**
58
+ * Development server options. See {@link DevConfig}.
59
+ */
60
+ dev?: DevConfig;
36
61
  }
37
62
  /**
38
63
  * A factory form of {@link Config}. Supporting a function (sync or async)
@@ -119,6 +144,11 @@ interface ResolvedPaths {
119
144
  outDir: string;
120
145
  }
121
146
 
147
+ /** Dev-server options after defaults have been applied (no optionals). */
148
+ interface ResolvedDevConfig {
149
+ readonly port: number;
150
+ readonly host: string;
151
+ }
122
152
  /**
123
153
  * A {@link Config} after defaults have been applied and paths resolved.
124
154
  *
@@ -131,6 +161,8 @@ interface ResolvedConfig {
131
161
  readonly raw: Config;
132
162
  /** Absolute paths derived from the configuration. */
133
163
  readonly paths: ResolvedPaths;
164
+ /** Resolved dev-server options. */
165
+ readonly dev: ResolvedDevConfig;
134
166
  /** Absolute path of the config file that was loaded, if any. */
135
167
  readonly configFile: string | null;
136
168
  }
@@ -146,17 +178,31 @@ interface ResolvedConfig {
146
178
  */
147
179
  declare function resolveConfig(raw: Config, cwd: string, configFile?: string | null): ResolvedConfig;
148
180
 
181
+ /**
182
+ * A `<script type="module">` reference discovered in the HTML entry.
183
+ *
184
+ * Only the `src` is captured in v0.2.0. The shape is deliberately an object
185
+ * (rather than a bare string) so later versions can attach resolved paths,
186
+ * inline contents, or transform metadata without breaking consumers.
187
+ */
188
+ interface HtmlModuleScript {
189
+ /** The `src` attribute value, exactly as authored (e.g. `/src/main.ts`). */
190
+ src: string;
191
+ }
149
192
  /**
150
193
  * The HTML entry point of a project, as discovered and parsed by the
151
- * `html` subsystem. Parsing is deliberately minimal in v0.1.0 only what is
152
- * needed to locate the entry — but the shape anticipates richer analysis
153
- * (script tags, module graph roots, asset references) in later versions.
194
+ * `html` subsystem. Parsing stays intentionally lightweightjust enough to
195
+ * locate the entry and its module scripts — but the shape anticipates richer
196
+ * analysis (asset references, injection points, module graph roots) in later
197
+ * versions on the road to HMR and plugin transforms.
154
198
  */
155
199
  interface HtmlEntry {
156
200
  /** Absolute path to the `index.html` file. */
157
201
  file: string;
158
202
  /** Raw HTML contents. */
159
203
  html: string;
204
+ /** Module scripts (`<script type="module" src=...>`) found in the entry. */
205
+ scripts: HtmlModuleScript[];
160
206
  }
161
207
 
162
208
  /**
@@ -167,32 +213,33 @@ interface HtmlEntry {
167
213
  declare function detectHtmlEntry(root: string): Promise<HtmlEntry | null>;
168
214
 
169
215
  /**
170
- * Parses raw HTML into an {@link HtmlEntry}.
216
+ * Parses raw HTML into an {@link HtmlEntry}, extracting `<script type="module">`
217
+ * `src` references.
171
218
  *
172
- * v0.1.0 keeps this intentionally minimal: it only wraps the file path and
173
- * contents. The function exists as the single, isolated home for HTML
174
- * analysis so later versions can grow it (extracting `<script type="module">`
175
- * entries, asset references, injection points for HMR) without scattering
176
- * parsing logic across the codebase.
219
+ * The analysis is intentionally regex-light rather than a full DOM parse: in
220
+ * dev we only need to know the module entry points. This module is the single,
221
+ * isolated home for HTML analysis, so it can grow toward a real parser (for
222
+ * HMR boundaries, plugin transforms, virtual modules) without touching callers.
177
223
  */
178
224
  declare function parseHtml(file: string, html: string): HtmlEntry;
179
225
 
180
- /** Current Vantris version. Kept in sync with package.json at release time. */
181
- declare const VERSION = "0.1.0";
182
-
183
- interface LoggerOptions {
184
- /** When `false`, `debug` calls are dropped. @default false */
185
- verbose?: boolean;
186
- /** Sink for output. Defaults to the console; overridable for tests. */
187
- sink?: Pick<Console, "log" | "warn" | "error">;
188
- }
189
226
  /**
190
- * Creates the default console-backed {@link Logger}.
227
+ * The dev-only live-reload client, injected into the served HTML.
191
228
  *
192
- * The sink is injectable so tests can capture output, and verbosity is a
193
- * construction-time concern rather than a global flag.
229
+ * v0.2.0 does a full page reload on any change. The WebSocket URL is derived
230
+ * from `location.host` so it works regardless of how the host is addressed
231
+ * (`localhost`, `127.0.0.1`, LAN IP). The message payload is ignored for now;
232
+ * v1.x will branch on it to drive HMR instead of a full reload.
194
233
  */
195
- declare function createLogger(options?: LoggerOptions): Logger;
234
+ declare const DEV_CLIENT_SCRIPT = "<script type=\"module\">\n // Injected by Vantris dev server \u2014 live reload (full page).\n const connect = () => {\n const ws = new WebSocket(\"ws://\" + location.host);\n ws.addEventListener(\"message\", () => location.reload());\n // Reconnect if the dev server restarts.\n ws.addEventListener(\"close\", () => setTimeout(connect, 1000));\n };\n connect();\n</script>";
235
+ /**
236
+ * Injects {@link DEV_CLIENT_SCRIPT} into an HTML document.
237
+ *
238
+ * The script is placed just before `</head>` when present, otherwise before
239
+ * `</body>`, otherwise appended — so it loads before user modules without
240
+ * requiring a well-formed document.
241
+ */
242
+ declare function injectDevClient(html: string): string;
196
243
 
197
244
  /**
198
245
  * The execution context threaded into every command.
@@ -210,6 +257,50 @@ interface Context {
210
257
  readonly logger: Logger;
211
258
  }
212
259
 
260
+ /** Options for {@link startDevServer}. */
261
+ interface DevServerOptions {
262
+ ctx: Context;
263
+ /** The detected HTML entry, when present. */
264
+ entry: HtmlEntry | null;
265
+ }
266
+ /** A running dev server. */
267
+ interface DevServerHandle {
268
+ /** Address the server is listening on, e.g. `http://localhost:3000/`. */
269
+ readonly url: string;
270
+ readonly host: string;
271
+ readonly port: number;
272
+ /** Pushes a full-page reload to every connected browser. */
273
+ broadcastReload(): void;
274
+ /** Stops the HTTP and WebSocket servers. */
275
+ close(): Promise<void>;
276
+ }
277
+ /**
278
+ * Starts the H3-based development server.
279
+ *
280
+ * Responsibilities are split across the `server` module: this file owns the
281
+ * HTTP routing (H3) and lifecycle, {@link createStaticLoader} owns file
282
+ * resolution + transpilation, and {@link createReloadSocket} owns live reload.
283
+ * The HTTP and WebSocket servers share a single port.
284
+ */
285
+ declare function startDevServer(options: DevServerOptions): Promise<DevServerHandle>;
286
+
287
+ /** Current Vantris version. Kept in sync with package.json at release time. */
288
+ declare const VERSION = "0.2.0";
289
+
290
+ interface LoggerOptions {
291
+ /** When `false`, `debug` calls are dropped. @default false */
292
+ verbose?: boolean;
293
+ /** Sink for output. Defaults to the console; overridable for tests. */
294
+ sink?: Pick<Console, "log" | "warn" | "error">;
295
+ }
296
+ /**
297
+ * Creates the default console-backed {@link Logger}.
298
+ *
299
+ * The sink is injectable so tests can capture output, and verbosity is a
300
+ * construction-time concern rather than a global flag.
301
+ */
302
+ declare function createLogger(options?: LoggerOptions): Logger;
303
+
213
304
  interface CreateContextOptions {
214
305
  /** Working directory the command was invoked from. */
215
306
  cwd: string;
@@ -227,6 +318,34 @@ interface CreateContextOptions {
227
318
  */
228
319
  declare function createContext(options: CreateContextOptions): Promise<Context>;
229
320
 
321
+ /** A change reported by the {@link Watcher}. */
322
+ interface WatchEvent {
323
+ /** What happened to the file. */
324
+ kind: "add" | "change" | "unlink";
325
+ /** Absolute path of the affected file. */
326
+ file: string;
327
+ }
328
+ interface WatcherOptions {
329
+ /** Directory tree to watch (typically `rootDir`). */
330
+ dir: string;
331
+ logger: Logger;
332
+ /** Called on every relevant filesystem change. */
333
+ onChange: (event: WatchEvent) => void;
334
+ }
335
+ /** A running filesystem watcher. */
336
+ interface Watcher {
337
+ /** Stops watching and releases OS resources. */
338
+ close(): Promise<void>;
339
+ }
340
+ /**
341
+ * Watches a directory tree and reports file changes.
342
+ *
343
+ * This is the single home for filesystem watching — the dev server depends on
344
+ * the {@link Watcher} interface, not on chokidar, so the backing implementation
345
+ * can change (or gain HMR-oriented metadata) without rippling outward.
346
+ */
347
+ declare function createWatcher(options: WatcherOptions): Watcher;
348
+
230
349
  /**
231
350
  * Base class for all errors thrown intentionally by Vantris. The CLI layer can
232
351
  * recognise these and render them cleanly (without a stack trace), while
@@ -296,4 +415,4 @@ declare const enum ExitCode {
296
415
  */
297
416
  declare function run(argv: readonly string[], options?: RunOptions): Promise<ExitCode>;
298
417
 
299
- export { type Command, type Config, ConfigError, type ConfigFn, type ConfigInput, type Context, type HtmlEntry, HtmlEntryError, type Logger, NotImplementedError, type ResolvedConfig, type ResolvedPaths, VERSION, VantrisError, commands, createContext, createLogger, defineConfig, detectHtmlEntry, isVantrisError, loadConfig, parseHtml, resolveConfig, run };
418
+ export { type Command, type Config, ConfigError, type ConfigFn, type ConfigInput, type Context, DEV_CLIENT_SCRIPT, type DevConfig, type DevServerHandle, type DevServerOptions, type HtmlEntry, HtmlEntryError, type HtmlModuleScript, type Logger, NotImplementedError, type ResolvedConfig, type ResolvedDevConfig, type ResolvedPaths, VERSION, VantrisError, type WatchEvent, type Watcher, type WatcherOptions, commands, createContext, createLogger, createWatcher, defineConfig, detectHtmlEntry, injectDevClient, isVantrisError, loadConfig, parseHtml, resolveConfig, run, startDevServer };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { ConfigError, HtmlEntryError, NotImplementedError, VERSION, VantrisError, commands, createContext, createLogger, detectHtmlEntry, isVantrisError, loadConfig, parseHtml, resolveConfig, run } from './chunk-PSXNP5S5.js';
1
+ export { ConfigError, DEV_CLIENT_SCRIPT, HtmlEntryError, NotImplementedError, VERSION, VantrisError, commands, createContext, createLogger, createWatcher, detectHtmlEntry, injectDevClient, isVantrisError, loadConfig, parseHtml, resolveConfig, run, startDevServer } from './chunk-OFLPPG2U.js';
2
2
 
3
3
  // src/config/define-config.ts
4
4
  function defineConfig(config) {
package/package.json CHANGED
@@ -1,10 +1,15 @@
1
1
  {
2
2
  "name": "vantris",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "A modern bundler for JavaScript/TypeScript",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
- "keywords": ["bundler", "build-tool", "dev-server", "typescript"],
7
+ "keywords": [
8
+ "bundler",
9
+ "build-tool",
10
+ "dev-server",
11
+ "typescript"
12
+ ],
8
13
  "bin": {
9
14
  "vantris": "dist/cli/index.js"
10
15
  },
@@ -17,7 +22,9 @@
17
22
  },
18
23
  "main": "./dist/index.js",
19
24
  "types": "./dist/index.d.ts",
20
- "files": ["dist"],
25
+ "files": [
26
+ "dist"
27
+ ],
21
28
  "engines": {
22
29
  "node": ">=20.11.0"
23
30
  },
@@ -29,6 +36,13 @@
29
36
  "prepublishOnly": "pnpm run build"
30
37
  },
31
38
  "devDependencies": {
39
+ "@types/ws": "^8.18.1",
32
40
  "tsup": "^8.3.5"
41
+ },
42
+ "dependencies": {
43
+ "chokidar": "^5.0.0",
44
+ "esbuild": "^0.28.1",
45
+ "h3": "2.0.1-rc.22",
46
+ "ws": "^8.21.0"
33
47
  }
34
48
  }