cindel 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +675 -0
- package/README.md +546 -0
- package/dist/client/file-loader.d.ts +24 -0
- package/dist/client/file-loader.d.ts.map +1 -0
- package/dist/client/hmr-client.d.ts +185 -0
- package/dist/client/hmr-client.d.ts.map +1 -0
- package/dist/client.d.ts +3 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.iife.js +2232 -0
- package/dist/client.iife.js.map +7 -0
- package/dist/client.iife.min.js +2 -0
- package/dist/client.iife.min.js.map +7 -0
- package/dist/client.js +2221 -0
- package/dist/client.js.map +7 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1142 -0
- package/dist/index.js.map +7 -0
- package/dist/server/file-watcher.d.ts +93 -0
- package/dist/server/file-watcher.d.ts.map +1 -0
- package/dist/server/hmr-server.d.ts +378 -0
- package/dist/server/hmr-server.d.ts.map +1 -0
- package/dist/server/routes.d.ts +2 -0
- package/dist/server/routes.d.ts.map +1 -0
- package/dist/server/ws-proxy.d.ts +5 -0
- package/dist/server/ws-proxy.d.ts.map +1 -0
- package/dist/shared/constants.d.ts +24 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/logger.d.ts +39 -0
- package/dist/shared/logger.d.ts.map +1 -0
- package/dist/shared/utils.d.ts +13 -0
- package/dist/shared/utils.d.ts.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/server/file-watcher.js", "../src/shared/utils.js", "../src/shared/constants.js", "../src/server/hmr-server.js", "../src/shared/logger.js", "../src/server/routes.js", "../src/server/ws-proxy.js"],
|
|
4
|
+
"sourcesContent": ["import chokidar from 'chokidar';\nimport chalk from 'chalk';\nimport path from 'path';\nimport { matchGlob } from '../shared/utils.js';\nimport { WATCHER_CONFIG } from '../shared/constants.js';\n\n/**\n * @typedef {Object} FileWatcherOptions\n * @property {string[]} paths - Paths or glob patterns to watch (from project root)\n * @property {string[]} [ignore] - Glob patterns to ignore (from project root)\n * @property {string[]} [extensions] - File extensions to watch\n * @property {import('../shared/logger.js').Logger} logger - Logger instance from HMR server\n * @property {(path: string) => void} [onChange] - Called when file changes\n * @property {(path: string) => void} [onAdd] - Called when file is added\n * @property {(path: string) => void} [onRemove] - Called when file is removed\n * @property {(path: string) => void} [onAddDir] - Called when directory is added\n * @property {(path: string) => void} [onRemoveDir] - Called when directory is removed\n * @property {() => void} [onReady] - Called when watcher is ready\n * @property {boolean} [logFiles=false] - Log watched files during initialization\n */\n\n/** File watcher using chokidar with picomatch glob filtering */\nexport class FileWatcher {\n constructor(options) {\n this.paths = options.paths || [];\n this.ignorePatterns = options.ignore || [];\n this.extensions = options.extensions || [];\n this.onChange = options.onChange || (() => { });\n this.onAdd = options.onAdd || (() => { });\n this.onRemove = options.onRemove || (() => { });\n this.onAddDir = options.onAddDir || (() => { });\n this.onRemoveDir = options.onRemoveDir || (() => { });\n this.onReady = options.onReady || (() => { });\n this.logFiles = options.logFiles || false;\n\n this.logger = options.logger;\n this.watcher = null;\n\n /**\n * Incrementally maintained set of watched files.\n * Avoids rescanning chokidar's full watched map on every /files request.\n * @type {Set<string>}\n */\n this._watchedFiles = new Set();\n\n // Only used during initialization for file logging\n this.isInitializing = true;\n this.loggedFiles = new Set();\n }\n\n shouldIgnore(filePath, stats) {\n const normalized = this.normalizePath(filePath);\n\n // Always allow directories to be traversed (unless they match ignore patterns)\n if (stats && stats.isDirectory()) {\n return matchGlob(normalized, this.ignorePatterns);\n }\n\n if (matchGlob(normalized, this.ignorePatterns)) {\n this.logFile(filePath, true, 'ignored pattern');\n return true;\n }\n\n if (stats && stats.isFile() && !this.isWatchableFile(normalized, this.extensions)) {\n this.logFile(filePath, true, 'non-watchable extension');\n return true;\n }\n\n if (stats && stats.isFile()) {\n this.logFile(filePath, false);\n }\n\n return false;\n }\n\n normalizePath(filePath) {\n return path.relative('.', filePath).replace(/\\\\/g, '/');\n }\n\n isWatchableFile(filePath, extensions) {\n const ext = path.extname(filePath).toLowerCase();\n return extensions.includes(ext);\n }\n\n logFile(filePath, ignored, reason = '') {\n if (!this.logFiles || !this.isInitializing) return;\n\n const normalized = this.normalizePath(filePath);\n if (this.loggedFiles.has(normalized)) return;\n\n this.loggedFiles.add(normalized);\n this.logger.logInitFile(normalized, ignored, reason);\n }\n\n getWatchedFiles() {\n return Array.from(this._watchedFiles);\n }\n\n logWatchedDirectories() {\n if (!this.logFiles || !this.watcher) return;\n\n const watched = this.watcher.getWatched();\n const watchRoots = this.paths.map(p => this.normalizePath(p));\n const relevantDirs = new Set();\n\n for (const [dir, files] of Object.entries(watched)) {\n const normalized = this.normalizePath(dir);\n\n const isWithinWatchRoot = watchRoots.some(root =>\n normalized === root || normalized.startsWith(root + '/')\n );\n\n if (!isWithinWatchRoot || normalized === '.') continue;\n\n const hasWatchableFiles = files.some(file => {\n const fullPath = `${dir}/${file}`.replace(/\\\\/g, '/');\n const normalizedFile = this.normalizePath(fullPath);\n return this.isWatchableFile(normalizedFile, this.extensions) &&\n !matchGlob(normalizedFile, this.ignorePatterns);\n });\n\n if (hasWatchableFiles) {\n // Add the directory's full normalized path and every ancestor up to\n // (but not including) the watch root so the printed tree is complete.\n relevantDirs.add(normalized);\n for (const root of watchRoots) {\n if (normalized.startsWith(root + '/')) {\n // Walk up the ancestors between root and this dir\n const parts = normalized.substring(root.length + 1).split('/');\n let ancestor = root;\n for (const part of parts.slice(0, -1)) {\n ancestor = `${ancestor}/${part}`;\n relevantDirs.add(ancestor);\n }\n break;\n }\n }\n }\n }\n\n const sortedDirs = Array.from(relevantDirs).sort();\n if (sortedDirs.length === 0) return;\n\n console.log(chalk.cyan(`\\n${this.logger.symbols.watch} Watching directories:`));\n sortedDirs.forEach(dir => {\n console.log(chalk.green(` ${this.logger.symbols.success} ${dir}`));\n });\n }\n\n async start() {\n if (this.watcher) {\n this.logger.warning('Watcher already started');\n return;\n }\n\n if (this.paths.length === 0) {\n this.logger.warning('No paths to watch');\n return;\n }\n\n this.logger.watcherStart(this.paths);\n this.isInitializing = true;\n\n this.watcher = chokidar.watch(this.paths, {\n ...WATCHER_CONFIG,\n ignored: (filePath, stats) => this.shouldIgnore(filePath, stats)\n });\n\n this.watcher\n .on('change', (filePath) => {\n const normalized = this.normalizePath(filePath);\n this.onChange(normalized);\n })\n .on('add', (filePath) => {\n const normalized = this.normalizePath(filePath);\n this._watchedFiles.add(normalized);\n this.onAdd(normalized);\n })\n .on('unlink', (filePath) => {\n const normalized = this.normalizePath(filePath);\n this._watchedFiles.delete(normalized);\n this.onRemove(normalized);\n })\n .on('addDir', (dirPath) => {\n const normalized = this.normalizePath(dirPath);\n this.onAddDir(normalized);\n })\n .on('unlinkDir', (dirPath) => {\n const normalized = this.normalizePath(dirPath);\n this.onRemoveDir(normalized);\n })\n .on('error', (error) => {\n this.logger.error(`Watcher error: ${error.message}`);\n })\n .on('ready', () => {\n this.isInitializing = false;\n this.loggedFiles.clear();\n\n // Populate the incremental cache from chokidar's initial scan,\n // since add events were suppressed by ignoreInitial during startup.\n const watched = this.watcher.getWatched();\n const watchRoots = this.paths.map(p => this.normalizePath(p));\n\n let actualFileCount = 0;\n let actualDirCount = 0;\n\n for (const [dir, files] of Object.entries(watched)) {\n const normalized = this.normalizePath(dir);\n\n const isWithinWatchRoot = watchRoots.some(root =>\n normalized === root || normalized.startsWith(root + '/')\n );\n\n if (!isWithinWatchRoot || normalized === '.') continue;\n\n let hasWatchableFiles = false;\n for (const file of files) {\n const fullPath = `${dir}/${file}`.replace(/\\\\/g, '/');\n const normalizedFile = this.normalizePath(fullPath);\n if (this.isWatchableFile(normalizedFile, this.extensions) &&\n !matchGlob(normalizedFile, this.ignorePatterns)) {\n this._watchedFiles.add(normalizedFile);\n actualFileCount++;\n hasWatchableFiles = true;\n }\n }\n\n if (hasWatchableFiles) actualDirCount++;\n }\n\n this.logWatchedDirectories();\n\n console.log(chalk.green(`\\n${this.logger.symbols.watch} Chokidar is ready`));\n console.log(chalk.cyan(`${this.logger.symbols.watch} Watching ${actualFileCount} files across ${actualDirCount} ${actualDirCount === 1 ? 'directory' : 'directories'}\\n`));\n\n if (actualFileCount === 0) {\n this.logger.watcherNoFiles(this.paths, this.extensions);\n }\n\n this.onReady();\n });\n\n return new Promise(resolve => {\n this.watcher.on('ready', resolve);\n });\n }\n\n async stop() {\n if (this.watcher) {\n await this.watcher.close();\n this.watcher = null;\n this._watchedFiles.clear();\n }\n }\n}", "import picomatch from 'picomatch';\n\n// Cache compiled matchers so same patterns aren't recompiled on every call\nconst matcherCache = new Map();\n\nexport function matchGlob(file, patterns) {\n return patterns.some(pattern => {\n if (!matcherCache.has(pattern)) matcherCache.set(pattern, picomatch(pattern));\n return matcherCache.get(pattern)(file);\n });\n}\n\nexport function formatTime() {\n return new Date().toLocaleTimeString('en-US', {\n hour12: false,\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit'\n });\n}\n\nexport function getBrowserFromUA(userAgent) {\n if (!userAgent) return 'Unknown';\n\n if (userAgent.includes('Chrome/')) return 'Chrome';\n if (userAgent.includes('Firefox/')) return 'Firefox';\n if (userAgent.includes('Safari/') && !userAgent.includes('Chrome/')) return 'Safari';\n if (userAgent.includes('Edge/')) return 'Edge';\n if (userAgent.includes('Opera/') || userAgent.includes('OPR/')) return 'Opera';\n\n return 'Unknown';\n}\n\nexport function getFileName(path) {\n return path.split('/').pop();\n}\n\nexport function getFilePath(path) {\n const parts = path.split('/');\n parts.pop();\n return parts.join('/') || '.';\n}\n\nexport function normalizeUrl(url) {\n return url.endsWith('/') ? url : url + '/';\n}\n\nexport function normalizeProxyPath(path, defaultPath) {\n return (path || defaultPath).replace(/^(?!\\/)/, '/').replace(/\\/+$/, '');\n}\n\nexport function resolveEndpoint(value, defaultPath) {\n if (!value) return null;\n if (value === true) return defaultPath;\n return value.startsWith('/') ? value : `/${value}`;\n}\n\n/**\n * Resolve HMR connection URLs from various input formats\n * @param {string|number|Object} options - Connection options\n * @returns {{ wsUrl: string, httpUrl: string }}\n * \n * @example\n * resolveConnectionUrls(1338)\n * // => { wsUrl: 'ws://localhost:1338', httpUrl: 'http://localhost:1338/' }\n * \n * @example\n * resolveConnectionUrls('ws://192.168.1.100:1338')\n * // => { wsUrl: 'ws://192.168.1.100:1338', httpUrl: 'http://192.168.1.100:1338/' }\n * \n * @example\n * resolveConnectionUrls({ host: 'dev.example.com', port: 1338, secure: true })\n * // => { wsUrl: 'wss://dev.example.com:1338', httpUrl: 'https://dev.example.com:1338/' }\n */\nfunction wsUrlToHttpUrl(wsUrl) {\n const u = new URL(wsUrl);\n return `${u.protocol === 'wss:' ? 'https' : 'http'}://${u.host}/`;\n}\n\nfunction httpUrlToWsUrl(httpUrl, wsPath) {\n const u = new URL(httpUrl);\n return `${u.protocol === 'https:' ? 'wss' : 'ws'}://${u.host}${wsPath}`;\n}\n\nexport function resolveConnectionUrls(options, wsPath = '/hmr') {\n if (typeof options === 'string') {\n return { wsUrl: options, httpUrl: wsUrlToHttpUrl(options) };\n }\n\n if (typeof options === 'number') {\n options = { port: options };\n }\n\n if (typeof options !== 'object' || options === null) {\n throw new Error('Options must be a string, number, or object');\n }\n\n if (options.wsUrl && options.httpUrl) {\n return { wsUrl: options.wsUrl, httpUrl: normalizeUrl(options.httpUrl) };\n }\n\n if (options.wsUrl) {\n return { wsUrl: options.wsUrl, httpUrl: wsUrlToHttpUrl(options.wsUrl) };\n }\n\n if (options.httpUrl) {\n const httpUrl = normalizeUrl(options.httpUrl);\n return { wsUrl: httpUrlToWsUrl(httpUrl, wsPath), httpUrl };\n }\n\n if (options.port) {\n const host = options.host || 'localhost';\n const secure = options.secure || false;\n const wsProtocol = secure ? 'wss' : 'ws';\n const httpProtocol = secure ? 'https' : 'http';\n\n const wsUrl = `${wsProtocol}://${host}:${options.port}${wsPath}`;\n const httpUrl = normalizeUrl(`${httpProtocol}://${host}:${options.port}`);\n\n return { wsUrl, httpUrl };\n }\n\n throw new Error('Must provide wsUrl, httpUrl, port, or host+port');\n}", "export const DEFAULT_PORT = 1338;\nexport const WATCHABLE_EXTENSIONS = ['.js', '.cjs', '.mjs', '.css'];\n\nexport const DEFAULT_FILES_ENDPOINT = '/files'\nexport const DEFAULT_CONFIG_ENDPOINT = '/config'\n\nexport const DEFAULT_CORS_PROXY_PATH = '/proxy';\nexport const DEFAULT_WS_PROXY_PATH = '/proxy';\n\nexport const WATCHER_CONFIG = {\n persistent: true,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 50,\n pollInterval: 10\n },\n usePolling: false,\n alwaysStat: true,\n atomic: false\n};\n\nexport const HMR_ACTIONS = {\n RELOAD: 'reload',\n ADD: 'add',\n REMOVE: 'remove',\n INIT: 'init'\n};", "import chalk from 'chalk';\nimport { FileWatcher } from './file-watcher.js';\nimport { Logger } from '../shared/logger.js';\nimport { handleRoutes } from './routes.js';\nimport { handleWSProxy } from './ws-proxy.js';\nimport {\n matchGlob,\n getBrowserFromUA,\n normalizeProxyPath,\n resolveEndpoint\n} from '../shared/utils.js';\nimport {\n DEFAULT_PORT,\n WATCHABLE_EXTENSIONS,\n DEFAULT_CORS_PROXY_PATH,\n DEFAULT_WS_PROXY_PATH,\n HMR_ACTIONS,\n DEFAULT_FILES_ENDPOINT,\n DEFAULT_CONFIG_ENDPOINT,\n} from \"../shared/constants.js\";\n\n/**\n * @typedef {Object} TLSConfig\n * @property {string} key - Path to the private key file (PEM)\n * @property {string} cert - Path to the certificate file (PEM)\n * @property {string} [ca] - Path to a CA certificate file for mutual TLS\n * @property {string} [passphrase] - Passphrase for an encrypted private key\n */\n\n/**\n * @typedef {Object} CORSProxyConfig\n * @property {string|RegExp} [path='/proxy'] - Path prefix or regex that triggers the proxy\n * @property {function(string, Request): Object} [getHeaders] - Return custom headers for the outbound request. Receives `(targetUrl, incomingRequest)`.\n * @property {function(Response): Promise<Response>} [transformResponse] - Transform the upstream response before returning it to the client\n */\n\n/**\n * @typedef {Object} WSProxyConfig\n * @property {string} [path='/proxy'] - Path prefix that triggers the proxy. The remainder of the path must be the full upstream `ws://` or `wss://` URL.\n * @property {Object} [headers] - Static headers sent to every upstream connection.\n * @property {boolean|string[]} [forwardHeaders] - Forward incoming client headers to the upstream connection.\n * `true` forwards all headers; an array of header name strings forwards only the listed ones (case-insensitive).\n * Applied before `headers` and `getHeaders`, so explicit values always win.\n * @property {function(string, Object): Object} [getHeaders] - Return dynamic headers per connection. Receives `(targetUrl, incomingHeaders)`. Merged on top of `headers`.\n * @property {function(string): void} [onConnect] - Called when the upstream connection opens. Receives `targetUrl`.\n * @property {function(*, WebSocket, WebSocket): void} [onClientMessage] - Intercept messages from the browser before forwarding upstream. Receives `(message, clientSocket, upstreamSocket)`.\n * @property {function(*, WebSocket, WebSocket): void} [onUpstreamMessage] - Intercept messages from upstream before forwarding to the browser. Receives `(message, clientSocket, upstreamSocket)`.\n * @property {Object} [options] - Extra options passed to the upstream `WebSocket` constructor (e.g. `options: { perMessageDeflate: true }`)\n */\n\n/**\n * HMR server with optional HTTP features (static files, CORS proxy, WebSocket proxy).\n * All features are opt-in via configuration.\n * \n * @example\n * // Minimal HMR only\n * const hmr = new HMRServer({\n * port: 1338,\n * watch: ['src']\n * });\n * \n * @example\n * // HMR + Development Server\n * const dev = new HMRServer({\n * port: 1338,\n * watch: ['src'],\n * static: '.',\n * injectLoader: 'loader.js'\n * });\n * \n * @example\n * // HMR + Proxies\n * const proxy = new HMRServer({\n * port: 1338,\n * watch: ['src'],\n * corsProxy: { path: '/proxy' },\n * wsProxy: {\n * path: '/proxy',\n * headers: {\n * Origin: 'https://www.example.com',\n * 'User-Agent': 'Mozilla/5.0'\n * }\n * }\n * });\n * \n * @example\n * // Full Stack\n * const server = new HMRServer({\n * port: 1338,\n * watch: ['src'],\n * static: '.',\n * corsProxy: true,\n * wsProxy: {\n * path: '/proxy',\n * headers: {\n * Origin: 'https://www.example.com'\n * },\n * options: { perMessageDeflate: true }\n * },\n * injectLoader: 'loader.js',\n * tls: {\n * key: 'localhost-key.pem',\n * cert: 'localhost.pem'\n * }\n * });\n */\nexport class HMRServer {\n /**\n * @param {Object} [options={}]\n * @param {number} [options.port=1338] - Port to listen on.\n * @param {string} [options.bindHost='localhost'] - Network interface to bind to. Use `'0.0.0.0'` to listen on all interfaces and expose the server on your local network.\n * @param {boolean} [options.watchFiles=true] - Use chokidar to watch files. Set to `false` to scan once at startup for initial file loading only.\n * @param {string} [options.wsPath='/hmr'] - WebSocket upgrade path. Clients must connect to this path.\n * @param {string[]} [options.watch=[]] - Paths or glob patterns to watch (e.g. `['src', 'lib']`)\n * @param {string[]} [options.ignore] - Glob patterns to ignore.\n * @param {string[]} [options.cold] - Glob patterns for files that require a full page reload instead of HMR (e.g. `['**\\/*.config.js']`)\n * @param {string[]} [options.extensions] - File extensions to watch. Defaults to `.js .cjs .mjs .css`\n * @param {function(WebSocket, {files: string[], config: Object}): void} [options.onConnect] - Called when an HMR client connects. Defaults to sending an `init` message with the file list.\n * @param {function(WebSocket): void} [options.onDisconnect] - Called when an HMR client disconnects\n * @param {boolean} [options.logFiles=false] - Log every watched file during watcher initialization\n * @param {boolean|{cors?: boolean, ws?: boolean}} [options.logProxy=false] - Log proxy traffic.\n * `true` enables both. Pass `{ cors: true, ws: false }` to enable only one.\n * @param {string} [options.static] - Directory to serve static files from (e.g. `'.'` or `'public'`), Defaults to `'.'` for serving from project root.\n * @param {string} [options.indexPath='index.html'] - Path to index.html, used as the `/` fallback and for loader injection\n * @param {string} [options.injectLoader] - Path to a script that will be injected into index.html via `<script>` before `</head>`\n * @param {boolean|string|CORSProxyConfig} [options.corsProxy] - Enable the HTTP CORS proxy. `true` mounts at `/proxy`. A string uses that as the path directly e.g. `'/cors'`.\n * @param {WSProxyConfig} [options.wsProxy] - Proxy WebSocket connections to an upstream server\n * @param {function(): string[]} [options.getFiles] - Override the file list sent to connecting clients. Called on every new connection.\n * @param {boolean|string} [options.filesEndpoint] - Expose the watched file list as JSON. `true` mounts at `/files`, a string uses that as the path.\n * @param {boolean|string} [options.configEndpoint] - Expose the server config as JSON. `true` mounts at `/config`, a string uses that as the path.\n * @param {TLSConfig} [options.tls] - Enable HTTPS/WSS\n * @param {boolean|string[]} [options.handleSignals=true] - Register signal handlers that call `stop()` and exit cleanly.\n * Default `yes` adds `SIGINT`/`SIGTERM`; `false` disables; or pass an array (e.g. `['SIGINT','SIGTERM','SIGHUP']`).\n */\n constructor(options = {}) {\n // --- HMR Core\n this.port = options.port || DEFAULT_PORT;\n this.bindHost = options.bindHost ?? 'localhost';\n this.wsPath = options.wsPath || '/hmr'\n this.watchFiles = options.watchFiles ?? true;\n this.watchPaths = options.watch || ['src'];\n this.ignorePaths = options.ignore || [];\n this.coldPatterns = options.cold || [];\n this.extensions = (options.extensions || WATCHABLE_EXTENSIONS).map(e => e.toLowerCase());\n this.onConnectCallback = options.onConnect || this.defaultOnConnect.bind(this);\n this.onDisconnectCallback = options.onDisconnect || (() => { });\n this.logFiles = options.logFiles || false;\n\n // Normalize logProxy to { cors, ws } so callers can enable individually.\n const lp = options.logProxy;\n if (lp === true) {\n this.logProxy = { cors: true, ws: true };\n } else if (lp && typeof lp === 'object') {\n this.logProxy = { cors: !!lp.cors, ws: !!lp.ws };\n } else {\n this.logProxy = { cors: false, ws: false };\n }\n\n this.logger = new Logger();\n this.watcher = null;\n this.server = null;\n /** @type {Set<WebSocket>} */\n this.clients = new Set();\n\n // --- HTTP features\n this.staticDir = options.static === false ? null : (options.static ?? '.');\n this.getFilesCallback = options.getFiles || null;\n this.filesEndpoint = resolveEndpoint(options.filesEndpoint, DEFAULT_FILES_ENDPOINT);\n this.configEndpoint = resolveEndpoint(options.configEndpoint, DEFAULT_CONFIG_ENDPOINT);\n\n // Normalize CORS proxy configuration - supports `true` for defaults or a config object with overrides\n const proxyConfig = options.corsProxy;\n if (proxyConfig === true) {\n this.corsProxy = { path: DEFAULT_CORS_PROXY_PATH };\n } else if (typeof proxyConfig === 'string') {\n this.corsProxy = { path: normalizeProxyPath(proxyConfig, DEFAULT_CORS_PROXY_PATH) };\n } else if (proxyConfig && typeof proxyConfig === 'object') {\n const { path: proxyPath, getHeaders, transformResponse, ...rest } = proxyConfig;\n\n if (Object.keys(rest).length > 0) {\n this.logger.warning(`corsProxy received unknown options: ${Object.keys(rest).join(', ')}, these will be ignored`);\n }\n\n this.corsProxy = {\n path: normalizeProxyPath(proxyPath, DEFAULT_CORS_PROXY_PATH),\n getHeaders: getHeaders || null,\n transformResponse: transformResponse || null\n };\n } else {\n this.corsProxy = null;\n }\n\n // WebSocket Proxy\n if (options.wsProxy) {\n this.wsProxy = {\n ...options.wsProxy,\n path: normalizeProxyPath(options.wsProxy.path, DEFAULT_WS_PROXY_PATH)\n };\n } else {\n this.wsProxy = null;\n }\n\n // Loader injection\n if (options.injectLoader !== undefined && options.injectLoader !== null) {\n if (typeof options.injectLoader !== 'string' || options.injectLoader.trim().length === 0) {\n throw new Error('injectLoader must be a non-empty string path');\n }\n this.loaderPath = options.injectLoader.trim();\n } else {\n this.loaderPath = null;\n }\n this.injectLoader = this.loaderPath !== null;\n this.indexPath = options.indexPath || 'index.html';\n\n // TLS/HTTPS\n this.tls = options.tls || null;\n\n // Process signals to handle for graceful shutdown\n const DEFAULT_SIGNALS = ['SIGINT', 'SIGTERM'];\n this.handleSignals = options.handleSignals === false\n ? false\n : Array.isArray(options.handleSignals)\n ? options.handleSignals\n : DEFAULT_SIGNALS;\n }\n\n isColdFile(file) {\n if (this.coldPatterns.length === 0) return false;\n return matchGlob(file, this.coldPatterns);\n }\n\n /**\n * Send a message to a single HMR client\n * @param {WebSocket} client - The client to send to\n * @param {Object} payload - The payload to send, will be JSON serialized\n * @returns {boolean} Whether the message was sent successfully\n */\n send(client, payload) {\n try {\n client.send(JSON.stringify(payload));\n return true;\n } catch (error) {\n this.logger.error(`Error sending to client: ${error.message}`);\n this.handleHMRDisconnect(client);\n return false;\n }\n }\n\n defaultOnConnect(ws, data) {\n this.send(ws, {\n type: HMR_ACTIONS.INIT,\n files: data.files,\n config: data.config\n });\n }\n\n getConfig() {\n return {\n port: this.port,\n bindHost: this.bindHost,\n wsPath: this.wsPath,\n watch: this.watchPaths,\n ignore: this.ignorePaths,\n cold: this.coldPatterns,\n watchFiles: this.watchFiles,\n extensions: this.extensions,\n static: this.staticDir,\n corsProxy: this.corsProxy,\n wsProxy: this.wsProxy,\n wsProxyHeaders: this.wsProxy?.headers || null,\n wsProxyPrefix: this.wsProxy?.path || null,\n filesEndpoint: this.filesEndpoint,\n injectLoader: this.injectLoader,\n loaderPath: this.loaderPath,\n indexPath: this.indexPath,\n tls: this.tls,\n handleSignals: this.handleSignals,\n logProxy: this.logProxy,\n logFiles: this.logFiles\n };\n }\n\n async setupWatcher() {\n if (!this.watchFiles) {\n console.log(chalk.yellow(`\\n${this.logger.symbols.config} WatchFiles disabled - globbing: ${this.watchPaths.join(', ')}`));\n const files = [];\n const extPatterns = this.extensions.map(ext => `**/*${ext}`);\n for (const pattern of this.watchPaths) {\n const globPattern = pattern.endsWith('*') ? pattern : `${pattern}/**/*`;\n const glob = new Bun.Glob(globPattern);\n for await (const file of glob.scan({ onlyFiles: true })) {\n if (matchGlob(file, extPatterns) && !matchGlob(file, this.ignorePaths)) {\n files.push(file);\n }\n }\n }\n console.log(chalk.cyan(`${this.logger.symbols.watch} Found ${files.length} file${files.length !== 1 ? 's' : ''} (static snapshot, no watcher running)\\n`));\n this.staticFiles = files;\n this.getFilesCallback = () => this.staticFiles;\n return;\n }\n const watcherOptions = {\n logger: this.logger,\n paths: this.watchPaths,\n ignore: this.ignorePaths,\n logFiles: this.logFiles,\n onChange: (path) => {\n if (this.isColdFile(path)) {\n this.logger.file('change', path, 'cyanBright', 'Cold file');\n this.broadcast(HMR_ACTIONS.RELOAD, path, { cold: true });\n return;\n }\n this.logger.file('change', path, 'yellow', 'File changed');\n this.broadcast(HMR_ACTIONS.RELOAD, path);\n },\n onAdd: (path) => {\n this.logger.file('add', path, 'greenBright', 'File added');\n this.broadcast(HMR_ACTIONS.ADD, path);\n },\n onRemove: (path) => {\n this.logger.file('remove', path, 'red', 'File removed');\n this.broadcast(HMR_ACTIONS.REMOVE, path);\n },\n onAddDir: (path) => {\n this.logger.file('dirAdd', path, 'cyan', 'Directory added');\n },\n onRemoveDir: (path) => {\n this.logger.file('dirRemove', path, 'red', 'Directory removed');\n },\n onReady: () => {\n // Ready callback is handled in file-watcher\n }\n };\n\n if (this.extensions) {\n watcherOptions.extensions = this.extensions;\n }\n\n this.watcher = new FileWatcher(watcherOptions);\n await this.watcher.start();\n }\n\n broadcast(action, file, extra = {}) {\n const message = JSON.stringify({ action, file, ...extra });\n const dead = [];\n const sentCount = this.clients.size;\n\n for (const client of this.clients) {\n try {\n client.send(message);\n } catch (error) {\n this.logger.error(`Error sending to client: ${error.message}`);\n dead.push(client);\n }\n }\n\n for (const client of dead) {\n this.handleHMRDisconnect(client);\n }\n\n // Only send logs if there are multiple concurrent connections.\n if (sentCount > 1) {\n console.log(chalk.gray(` \u2514\u2500 Broadcasted to ${sentCount} client${sentCount !== 1 ? 's' : ''}`));\n }\n }\n\n handleHMRConnection(client) {\n this.clients.add(client);\n const browser = getBrowserFromUA(client.data?.headers?.['user-agent']);\n this.logger.custom(\n 'connect',\n `HMR client connected (${this.clients.size} total) - ${browser}`,\n 'green'\n );\n\n const files = this.getFilesCallback\n ? this.getFilesCallback()\n : (this.watcher ? this.watcher.getWatchedFiles() : []);\n const data = {\n files,\n config: this.getConfig()\n };\n this.onConnectCallback(client, data);\n }\n\n handleHMRDisconnect(client) {\n if (!this.clients.has(client)) return;\n this.clients.delete(client);\n this.logger.custom(\n 'disconnect',\n `HMR client disconnected (${this.clients.size} remaining)`,\n 'red'\n );\n this.onDisconnectCallback(client);\n }\n\n getWebSocketConfig() {\n return {\n open: (client) => {\n const path = client.data?.path || '/';\n\n if (this.wsProxy && path.startsWith(this.wsProxy.path + '/')) {\n const proxyHandlers = handleWSProxy(client, path, this.wsProxy, this.logger, this.logProxy.ws);\n // Store handlers so we can use them in message/close\n client.data.proxyHandlers = proxyHandlers;\n return;\n }\n\n this.handleHMRConnection(client);\n },\n\n message: (client, message) => {\n if (client.data?.isProxy) {\n client.data.proxyHandlers?.onMessage(message);\n return;\n }\n\n this.logger.debug(`Received HMR message: ${message}`);\n },\n\n close: (client) => {\n if (client.data?.isProxy) {\n client.data.proxyHandlers?.onClose();\n return;\n }\n\n this.handleHMRDisconnect(client);\n }\n };\n }\n\n /**\n * Start the HMR server\n * @returns {Promise<void>}\n */\n async start() {\n // Validate loader path exists before injection\n if (this.loaderPath) {\n const loaderFile = Bun.file(this.loaderPath);\n if (!(await loaderFile.exists())) {\n this.injectLoader = false;\n }\n }\n\n // Load TLS files if configured\n let tlsConfig = null;\n if (this.tls) {\n try {\n tlsConfig = {\n key: await Bun.file(this.tls.key).text(),\n cert: await Bun.file(this.tls.cert).text(),\n };\n\n if (this.tls.ca) {\n tlsConfig.ca = await Bun.file(this.tls.ca).text();\n }\n if (this.tls.passphrase) {\n tlsConfig.passphrase = this.tls.passphrase;\n }\n } catch (error) {\n this.logger.error(`Failed to load TLS files: ${error.message}`);\n throw error;\n }\n }\n\n const httpProtocol = tlsConfig ? 'https' : 'http';\n const wsProtocol = tlsConfig ? 'wss' : 'ws';\n\n this.logger.banner('HMR Server', {\n ...this.getConfig(),\n httpServer: !!(this.staticDir || this.corsProxy),\n websocket: true,\n protocol: httpProtocol,\n wsProtocol: wsProtocol,\n });\n\n await this.setupWatcher();\n\n const serverConfig = {\n port: this.port,\n hostname: this.bindHost,\n\n fetch: async (req, server) => {\n const url = new URL(req.url);\n const isHMRPath = url.pathname === this.wsPath;\n const isWSProxyPath = this.wsProxy && url.pathname.startsWith(this.wsProxy.path + '/');\n\n if (isHMRPath || isWSProxyPath) {\n const upgraded = server.upgrade(req, {\n data: {\n path: url.pathname,\n headers: Object.fromEntries(req.headers.entries())\n }\n });\n if (upgraded) return;\n }\n\n const response = await handleRoutes(req, this);\n\n // Add CORS headers to all HTTP responses\n const headers = new Headers(response.headers);\n headers.set('Access-Control-Allow-Origin', '*');\n headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');\n headers.set('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');\n return new Response(response.body, { status: response.status, statusText: response.statusText, headers });\n },\n\n websocket: this.getWebSocketConfig()\n };\n\n if (tlsConfig) {\n serverConfig.tls = tlsConfig;\n }\n\n this.server = Bun.serve(serverConfig);\n\n if (this.handleSignals) {\n const shutdown = () => this.stop().then(() => process.exit(0));\n for (const signal of this.handleSignals) {\n process.on(signal, shutdown);\n }\n }\n }\n\n /**\n * Stop the HMR server and clean up resources\n * @returns {Promise<void>}\n */\n async stop() {\n this.logger.shutdown();\n\n if (this.server) {\n // stop(true) closes all active connections immediately\n this.server.stop(true);\n }\n\n if (this.watcher) {\n await this.watcher.stop();\n }\n\n // Clear stale references so the Set doesn't hold onto dead WebSocket\n // objects if the server is restarted in the same process.\n this.clients.clear();\n }\n}", "import chalk from 'chalk';\nimport { formatTime, getFileName, getFilePath } from './utils.js';\n\nexport class Logger {\n constructor() {\n this.symbols = {\n debug: '\u25C6',\n info: '\u2139',\n success: '\u2713',\n warning: '\u26A0',\n error: '\u2716',\n config: '\u26ED',\n connect: '\u25B6',\n disconnect: '\u2726',\n change: '\u232C',\n add: '\u2295',\n remove: '\u2296',\n inject: '\u2398',\n startup: '\u26B5',\n shutdown: '\u26B6',\n corsProxy: '\u29C9',\n wsProxy: '\u224D',\n watch: '\u26AD',\n dirAdd: '\u2B22',\n dirRemove: '\u2B21',\n glob: '\u2042',\n };\n }\n\n debug(message) {\n console.log(chalk.gray(`${this.symbols.debug} [${formatTime()}] ${message}`));\n }\n\n info(message) {\n console.log(chalk.cyan(`${this.symbols.info} [${formatTime()}] ${message}`));\n }\n\n success(message) {\n console.log(chalk.green(`${this.symbols.success} [${formatTime()}] ${message}`));\n }\n\n warning(message) {\n console.log(chalk.yellow(`${this.symbols.warning} [${formatTime()}] ${message}`));\n }\n\n error(message) {\n console.log(chalk.red(`${this.symbols.error} [${formatTime()}] ${message}`));\n }\n\n custom(symbol, message, color = 'white') {\n const sym = this.symbols[symbol] || symbol;\n const msg = `${sym} [${formatTime()}] ${message}`;\n console.log(chalk[color](msg));\n }\n\n file(symbol, filePath, color = 'white', prefix = '') {\n const sym = this.symbols[symbol] || symbol;\n const fileName = getFileName(filePath);\n const dirPath = getFilePath(filePath);\n\n const prefixText = prefix ? `${prefix}: ` : '';\n const msg = `${sym} [${formatTime()}] ${prefixText}${chalk.bold(fileName)} ${chalk.gray.italic(`(${dirPath})`)}`;\n\n console.log(chalk[color](msg));\n }\n\n banner(name, config) {\n console.log(chalk.bgCyan.black.bold(`${this.symbols.startup} ${name} Starting\\n`));\n\n const httpProtocol = config.tls ? 'https' : 'http';\n const wsProtocol = config.tls ? 'wss' : 'ws';\n\n const lines = [\n [config.httpServer, 'blue', `${this.symbols.startup} ${httpProtocol.toUpperCase()} server started on ${httpProtocol}://localhost:${config.port}`],\n [config.websocket, 'blue', `${this.symbols.startup} WebSocket HMR on ${wsProtocol}://localhost:${config.port}${config.wsPath}`],\n [config.corsProxy, 'cyan', `${this.symbols.corsProxy} CORS proxy available at ${config.corsProxy.path}`],\n [config.wsProxy, 'cyan', `${this.symbols.wsProxy} WS proxy available at ${config.wsProxy.path}`],\n [config.injectLoader, 'magenta', `${this.symbols.inject} Injecting loader into index.html (${config.loaderPath})`],\n [!config.injectLoader && config.loaderPath, 'yellow', `${this.symbols.warning} Loader file not found at \"${config.loaderPath}\" -> injection disabled`],\n [config.logFiles, 'yellow', `${this.symbols.config} File logging enabled`],\n [config.logProxy?.cors, 'yellow', `${this.symbols.config} CORS proxy logging enabled`],\n [config.logProxy?.ws, 'yellow', `${this.symbols.config} WS proxy logging enabled`],\n ];\n\n for (const [condition, color, message] of lines) {\n if (condition) console.log(chalk[color](message));\n }\n\n const lists = [\n [config.watch, 'cyan', `\\n${this.symbols.glob} Watching`],\n [config.ignore, 'gray', `${this.symbols.glob} Ignoring`],\n [config.cold, 'blue', `${this.symbols.glob} Cold files`],\n ];\n\n for (const [arr, color, label] of lists) {\n if (arr && arr.length > 0) {\n console.log(chalk[color](`${label}: ${arr.join(', ')}`));\n }\n }\n }\n\n // reqBody / resBody are optional short previews (caller truncates)\n corsProxyRequest(method, url, { reqBody, status, statusText, resBody } = {}) {\n const sym = this.symbols.corsProxy;\n const time = formatTime();\n const statusColor = status >= 500 ? 'red' : status >= 400 ? 'yellow' : 'green';\n\n console.log(chalk.cyan(`${sym} [${time}] ${method} ${url}`));\n\n const rows = [];\n if (reqBody) rows.push({ label: 'Request body', value: reqBody });\n rows.push({ label: 'Response status', value: `${chalk[statusColor](status)} ${statusText}` });\n if (resBody) rows.push({ label: 'Response body', value: resBody });\n\n rows.forEach((row, i) => {\n const branch = i === rows.length - 1 ? '\u2514\u2500' : '\u251C\u2500';\n console.log(chalk.gray(` ${branch} ${row.label}: `) + chalk.white(row.value));\n });\n }\n\n // listing every sent header on new ws proxy connection\n wsProxyConnect(id, url, headers) {\n const sym = this.symbols.wsProxy;\n const time = formatTime();\n const entries = Object.entries(headers);\n\n console.log(chalk.cyan(`${sym} [${time}] [${id}] Connected ${url}`));\n\n if (entries.length === 0) return;\n entries.forEach(([k, v], i) => {\n const branch = i === entries.length - 1 ? '\u2514\u2500' : '\u251C\u2500';\n console.log(chalk.gray(` ${branch} `) + chalk.yellow(k) + chalk.gray(': ') + chalk.white(v));\n });\n }\n\n shutdown() {\n console.log(chalk.bgRed.white.bold(`\\n ${this.symbols.shutdown} Shutting down... `));\n }\n\n watcherStart(paths) {\n const pathsDisplay = paths.join(', ');\n console.log(chalk.cyan(`\\n${this.symbols.watch} Starting file watcher for: ${pathsDisplay}`));\n console.log(chalk.grey(`${this.symbols.watch} Enabling hot directory detection`));\n }\n\n logInitFile(filePath, ignored, reason = '') {\n if (ignored) {\n const reasonText = reason ? ` (${reason})` : '';\n console.log(chalk.red(` ${this.symbols.error} ${filePath}${reasonText}`));\n } else {\n console.log(chalk.green(` ${this.symbols.success} ${filePath}`));\n }\n }\n\n watcherNoFiles(patterns, extensions) {\n console.log(chalk.yellow(`\\n${this.symbols.warning} Warning: No files found matching watch patterns!`));\n console.log(chalk.yellow(` Patterns: ${patterns.join(', ')}`));\n console.log(chalk.yellow(` Check that:`));\n console.log(chalk.yellow(` \u2022 Paths exist`));\n console.log(chalk.yellow(` \u2022 File extensions match: ${extensions.join(', ')}`));\n console.log(chalk.yellow(` \u2022 Ignore patterns aren't too broad\\n`));\n }\n}", "import path from 'path';\n\nexport async function handleRoutes(req, server) {\n const url = new URL(req.url);\n\n if (server.configEndpoint && url.pathname === server.configEndpoint) {\n return Response.json(server.getConfig());\n }\n\n if (server.filesEndpoint && url.pathname === server.filesEndpoint) {\n return handleFilesEndpoint(server);\n }\n\n if (server.corsProxy) {\n const response = await handleCORSProxy(req, url, server);\n if (response) return response;\n }\n\n if (server.injectLoader && url.pathname === '/') {\n return handleIndexInjection(req, server);\n }\n\n if (server.staticDir) {\n return handleStaticFile(url, server);\n }\n\n return new Response('Not Found', { status: 404 });\n}\n\nfunction handleFilesEndpoint(server) {\n try {\n const files = server.getFilesCallback\n ? server.getFilesCallback()\n : server.watcher.getWatchedFiles();\n return Response.json(files);\n } catch (error) {\n server.logger.error(`Error getting files: ${error.message}`);\n return Response.json([], { status: 500 });\n }\n}\n\nasync function handleCORSProxy(req, url, server) {\n const config = server.corsProxy;\n const urlPath = url.pathname;\n\n let matches = false;\n if (typeof config.path === 'string') {\n matches = urlPath.startsWith(config.path + '/');\n } else if (config.path instanceof RegExp) {\n matches = config.path.test(urlPath);\n }\n\n if (!matches) return null;\n\n const targetUrl = typeof config.path === 'string'\n ? urlPath.slice(config.path.length + 1)\n : urlPath.replace(config.path, '');\n\n if (!targetUrl.startsWith('http://') && !targetUrl.startsWith('https://')) {\n return new Response('Invalid target URL', { status: 400 });\n }\n\n try {\n const outboundHeaders = config.getHeaders\n ? config.getHeaders(targetUrl, req)\n : {\n 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',\n 'Content-Type': req.headers.get('content-type') || 'text/plain'\n };\n\n // When logging, buffer the request body so we can both log and forward it.\n // Streaming is preserved for the non-logging path.\n let fetchBody;\n let reqBodyPreview;\n if (server.logProxy.cors && !['GET', 'HEAD'].includes(req.method)) {\n reqBodyPreview = (await req.text()).slice(0, 200);\n fetchBody = reqBodyPreview;\n } else {\n fetchBody = ['GET', 'HEAD'].includes(req.method) ? undefined : req.body;\n }\n\n const response = await fetch(targetUrl, {\n method: req.method,\n headers: outboundHeaders,\n body: fetchBody\n });\n\n const finalResponse = config.transformResponse\n ? await config.transformResponse(response)\n : response;\n\n // Clone upstream headers directly instead of spreading into a plain object\n // to avoid unnecessary allocations on every proxied response.\n const responseHeaders = new Headers(finalResponse.headers);\n responseHeaders.set('Access-Control-Allow-Origin', '*');\n responseHeaders.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');\n responseHeaders.set('Access-Control-Allow-Headers', '*');\n\n if (req.method === 'OPTIONS') {\n return new Response(null, { status: 204, headers: responseHeaders });\n }\n\n if (server.logProxy.cors) {\n // Buffer the response body so we can log a preview and still return it.\n const resText = await finalResponse.text();\n server.logger.corsProxyRequest(req.method, targetUrl, {\n reqBody: reqBodyPreview,\n status: finalResponse.status,\n statusText: finalResponse.statusText,\n resBody: resText.slice(0, 200)\n });\n return new Response(resText, {\n status: finalResponse.status,\n statusText: finalResponse.statusText,\n headers: responseHeaders\n });\n }\n\n return new Response(finalResponse.body, {\n status: finalResponse.status,\n statusText: finalResponse.statusText,\n headers: responseHeaders\n });\n\n } catch (error) {\n server.logger.error(`CORS proxy error: ${error.message}`);\n return new Response('0', { status: 500 });\n }\n}\n\nasync function handleIndexInjection(req, server) {\n try {\n const indexFile = server.indexPath || 'index.html';\n\n // If indexPath is absolute and a staticDir is set, it would escape the\n // static root since path.resolve treats absolute segments as a new root.\n if (server.staticDir && path.isAbsolute(indexFile)) {\n server.logger.error(`indexPath must be relative when staticDir is set, got: \"${indexFile}\"`);\n return new Response('Server configuration error', { status: 500 });\n }\n\n const resolved = server.staticDir\n ? path.resolve(server.staticDir, indexFile)\n : path.resolve(indexFile);\n\n const file = Bun.file(resolved);\n const html = await file.text();\n\n if (!server.loaderPath) {\n return new Response(html, {\n headers: { 'Content-Type': 'text/html' }\n });\n }\n\n const requestHost = req.headers.get('host');\n const protocol = server.tls ? 'https' : 'http';\n const loaderUrl = `${protocol}://${requestHost}/` + server.loaderPath\n .replace(/\\\\/g, '/')\n .replace(/^\\.\\//, '');\n\n const isModule = loaderUrl.endsWith('.mjs');\n const typeAttr = isModule ? ' type=\"module\"' : '';\n\n const injectedHtml = html.replace(\n '</head>',\n `<script${typeAttr} src=\"${loaderUrl}\"></script></head>`\n );\n\n return new Response(injectedHtml, {\n headers: { 'Content-Type': 'text/html' }\n });\n } catch (error) {\n server.logger.error(`Error loading index.html: ${error.message}`);\n return new Response('Error loading index.html', { status: 500 });\n }\n}\n\nconst MIME_TYPES = {\n // HTML, JS, CSS, JSON, source maps\n \".html\": \"text/html\",\n \".js\": \"application/javascript\",\n \".cjs\": \"application/javascript\",\n \".mjs\": \"application/javascript\",\n \".css\": \"text/css\",\n \".json\": \"application/json\",\n \".map\": \"application/json\",\n\n // Images\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".svg\": \"image/svg+xml\",\n \".ico\": \"image/x-icon\",\n \".webp\": \"image/webp\",\n \".avif\": \"image/avif\",\n\n // Fonts\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".ttf\": \"font/ttf\",\n \".otf\": \"font/otf\",\n\n // Video & Audio\n \".mp4\": \"video/mp4\",\n \".webm\": \"video/webm\",\n \".ogg\": \"audio/ogg\",\n \".mp3\": \"audio/mpeg\",\n \".wav\": \"audio/wav\",\n};\n\nasync function handleStaticFile(url, server) {\n let filePath = url.pathname === \"/\" ? \"/index.html\" : url.pathname;\n\n if (url.pathname === \"/\" && server.indexPath) {\n filePath = \"/\" + server.indexPath.replace(/^\\//, \"\");\n }\n\n const baseResolved = path.resolve(server.staticDir);\n\n // Guard against path traversal (e.g. /../../../etc/pwd).\n // Path traversal seems to get collapsed already but I kept the guard in just in case.\n const resolved = path.resolve(baseResolved, \".\" + filePath);\n\n if (!resolved.startsWith(baseResolved + path.sep)) {\n return new Response(\"Forbidden\", { status: 403 });\n }\n\n let file = Bun.file(resolved);\n\n if (!(await file.exists())) {\n // Try treating the path as a directory and look for its index.html\n const indexPath = path.join(resolved, \"index.html\");\n file = Bun.file(indexPath);\n\n if (!(await file.exists())) {\n return new Response(\"Not Found\", { status: 404 });\n }\n }\n\n const ext = path.extname(file.name).toLowerCase();\n const contentType = MIME_TYPES[ext] || \"application/octet-stream\";\n\n return new Response(file, {\n headers: {\n \"Content-Type\": contentType,\n \"Cache-Control\": \"no-cache, no-store, must-revalidate\",\n \"Pragma\": \"no-cache\",\n \"Expires\": \"0\",\n },\n });\n}", "export function handleWSProxy(client, path, config, logger, logProxy) {\n // Extract target URL by removing path prefix\n // '/proxy/wss://example.com:9081/' -> 'wss://example.com:9081/'\n const targetUrl = path.slice(config.path.length + 1);\n\n // Validate the target URL early. Both ws:// and wss:// are supported.\n try {\n const parsed = new URL(targetUrl);\n if (parsed.protocol !== 'ws:' && parsed.protocol !== 'wss:') {\n throw new Error(`Invalid protocol: ${parsed.protocol}`);\n }\n } catch (e) {\n logger.custom('wsProxy', `Invalid WS proxy target: ${e.message}`, 'red');\n client.close(1002, 'Invalid target URL');\n return null;\n }\n\n // Only mark as proxy once we know the connection is legitimate\n client.data.isProxy = true;\n\n // Short random ID used to differentiate between connections to the same host.\n const id = Math.random().toString(36).slice(2, 7);\n const tag = `[${id}]`;\n\n // Build headers - layers applied in order so explicit config always wins:\n // 1. forwardHeaders (client headers, all or selective)\n // 2. config.headers (static overrides)\n // 3. getHeaders (dynamic overrides, highest priority)\n let headers = {};\n\n if (config.forwardHeaders && client.data.headers) {\n if (config.forwardHeaders === true) {\n headers = { ...client.data.headers };\n } else if (Array.isArray(config.forwardHeaders)) {\n for (const name of config.forwardHeaders) {\n const value = client.data.headers?.[name.toLowerCase()];\n if (value !== undefined) {\n headers[name.toLowerCase()] = value;\n }\n }\n }\n }\n\n if (config.headers) {\n headers = { ...headers, ...config.headers };\n }\n\n if (config.getHeaders) {\n headers = { ...headers, ...config.getHeaders(targetUrl, client.data.headers) };\n }\n\n const wsOptions = { headers };\n if (config.options) {\n Object.assign(wsOptions, config.options);\n }\n\n let upstream;\n try {\n upstream = new WebSocket(targetUrl, wsOptions);\n } catch (error) {\n logger.custom('wsProxy', `${tag} Failed to create upstream WebSocket: ${error.message}`, 'red');\n client.close(1011, 'Upstream connection failed');\n return;\n }\n\n client.data.upstream = upstream;\n\n // Guard against double closing from both sides triggering closeBoth simultaneously.\n let closed = false;\n const closeBoth = () => {\n if (closed) return;\n closed = true;\n clientOpen = false;\n upstreamReady = false;\n try { client.close(); } catch { }\n try { upstream.close(); } catch { }\n if (logProxy) logger.custom('wsProxy', `${tag} Closed ${targetUrl}`, 'gray');\n };\n\n // Buffer messages sent by the client before upstream has finished connecting.\n // Without this, any messages sent in the \"CONNECTING\" window are silently dropped,\n // which can cause the game client to time out and retransmit, adding perceived lag.\n const pendingClientMessages = [];\n const MAX_PENDING = 512;\n\n // Plain JS booleans so both message-path hot loops read closure variables\n // rather than crossing the native boundary on every frame.\n // clientOpen starts true - by the time handleWSProxy is called, the Bun\n // server has already completed the WebSocket upgrade.\n let clientOpen = true;\n let upstreamReady = false;\n\n const clientMessageHandler = config.onClientMessage ||\n ((message, _client, upstream) => {\n if (logProxy && typeof message === 'string') {\n logger.custom('wsProxy', `${tag} -> ${message.slice(0, 200)}`, 'gray');\n }\n if (upstreamReady) {\n upstream.send(message);\n } else {\n if (pendingClientMessages.length >= MAX_PENDING) {\n pendingClientMessages.shift(); // drop oldest\n }\n pendingClientMessages.push(message);\n }\n });\n\n const upstreamMessageHandler = config.onUpstreamMessage ||\n ((message, client, _upstream) => {\n if (logProxy && typeof message === 'string') {\n logger.custom('wsProxy', `${tag} <- ${message.slice(0, 200)}`, 'gray');\n }\n if (clientOpen && client.readyState === WebSocket.OPEN) {\n try {\n client.send(message);\n } catch {\n // Client socket died between the clientOpen check and the send,\n // closeBoth will be called so nothing to do here.\n }\n }\n });\n\n upstream.onmessage = (event) => {\n upstreamMessageHandler(event.data, client, upstream);\n };\n\n upstream.onclose = closeBoth;\n\n upstream.onerror = (event) => {\n const message = event instanceof ErrorEvent ? event.message : 'Connection failed';\n if (logProxy) logger.custom('wsProxy', `${tag} Upstream error: ${message}`, 'red');\n closeBoth();\n };\n\n upstream.onopen = () => {\n upstreamReady = true;\n\n if (logProxy) logger.wsProxyConnect(id, targetUrl, headers);\n\n // Flush any messages that arrived while upstream was still connecting\n for (const msg of pendingClientMessages) {\n upstream.send(msg);\n }\n pendingClientMessages.length = 0;\n\n if (config.onConnect) {\n config.onConnect(targetUrl);\n }\n };\n\n return {\n onMessage: (message) => {\n clientMessageHandler(message, client, upstream);\n },\n onClose: closeBoth\n };\n}"],
|
|
5
|
+
"mappings": ";AAAA,OAAO,cAAc;AACrB,OAAO,WAAW;AAClB,OAAO,UAAU;;;ACFjB,OAAO,eAAe;AAGtB,IAAM,eAAe,oBAAI,IAAI;AAEtB,SAAS,UAAU,MAAM,UAAU;AACxC,SAAO,SAAS,KAAK,aAAW;AAC9B,QAAI,CAAC,aAAa,IAAI,OAAO,EAAG,cAAa,IAAI,SAAS,UAAU,OAAO,CAAC;AAC5E,WAAO,aAAa,IAAI,OAAO,EAAE,IAAI;AAAA,EACvC,CAAC;AACH;AAEO,SAAS,aAAa;AAC3B,UAAO,oBAAI,KAAK,GAAE,mBAAmB,SAAS;AAAA,IAC5C,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV,CAAC;AACH;AAEO,SAAS,iBAAiB,WAAW;AAC1C,MAAI,CAAC,UAAW,QAAO;AAEvB,MAAI,UAAU,SAAS,SAAS,EAAG,QAAO;AAC1C,MAAI,UAAU,SAAS,UAAU,EAAG,QAAO;AAC3C,MAAI,UAAU,SAAS,SAAS,KAAK,CAAC,UAAU,SAAS,SAAS,EAAG,QAAO;AAC5E,MAAI,UAAU,SAAS,OAAO,EAAG,QAAO;AACxC,MAAI,UAAU,SAAS,QAAQ,KAAK,UAAU,SAAS,MAAM,EAAG,QAAO;AAEvE,SAAO;AACT;AAEO,SAAS,YAAYA,OAAM;AAChC,SAAOA,MAAK,MAAM,GAAG,EAAE,IAAI;AAC7B;AAEO,SAAS,YAAYA,OAAM;AAChC,QAAM,QAAQA,MAAK,MAAM,GAAG;AAC5B,QAAM,IAAI;AACV,SAAO,MAAM,KAAK,GAAG,KAAK;AAC5B;AAEO,SAAS,aAAa,KAAK;AAChC,SAAO,IAAI,SAAS,GAAG,IAAI,MAAM,MAAM;AACzC;AAEO,SAAS,mBAAmBA,OAAM,aAAa;AACpD,UAAQA,SAAQ,aAAa,QAAQ,WAAW,GAAG,EAAE,QAAQ,QAAQ,EAAE;AACzE;AAEO,SAAS,gBAAgB,OAAO,aAAa;AAClD,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,UAAU,KAAM,QAAO;AAC3B,SAAO,MAAM,WAAW,GAAG,IAAI,QAAQ,IAAI,KAAK;AAClD;AAmBA,SAAS,eAAe,OAAO;AAC7B,QAAM,IAAI,IAAI,IAAI,KAAK;AACvB,SAAO,GAAG,EAAE,aAAa,SAAS,UAAU,MAAM,MAAM,EAAE,IAAI;AAChE;AAEA,SAAS,eAAe,SAAS,QAAQ;AACvC,QAAM,IAAI,IAAI,IAAI,OAAO;AACzB,SAAO,GAAG,EAAE,aAAa,WAAW,QAAQ,IAAI,MAAM,EAAE,IAAI,GAAG,MAAM;AACvE;AAEO,SAAS,sBAAsB,SAAS,SAAS,QAAQ;AAC9D,MAAI,OAAO,YAAY,UAAU;AAC/B,WAAO,EAAE,OAAO,SAAS,SAAS,eAAe,OAAO,EAAE;AAAA,EAC5D;AAEA,MAAI,OAAO,YAAY,UAAU;AAC/B,cAAU,EAAE,MAAM,QAAQ;AAAA,EAC5B;AAEA,MAAI,OAAO,YAAY,YAAY,YAAY,MAAM;AACnD,UAAM,IAAI,MAAM,6CAA6C;AAAA,EAC/D;AAEA,MAAI,QAAQ,SAAS,QAAQ,SAAS;AACpC,WAAO,EAAE,OAAO,QAAQ,OAAO,SAAS,aAAa,QAAQ,OAAO,EAAE;AAAA,EACxE;AAEA,MAAI,QAAQ,OAAO;AACjB,WAAO,EAAE,OAAO,QAAQ,OAAO,SAAS,eAAe,QAAQ,KAAK,EAAE;AAAA,EACxE;AAEA,MAAI,QAAQ,SAAS;AACnB,UAAM,UAAU,aAAa,QAAQ,OAAO;AAC5C,WAAO,EAAE,OAAO,eAAe,SAAS,MAAM,GAAG,QAAQ;AAAA,EAC3D;AAEA,MAAI,QAAQ,MAAM;AAChB,UAAM,OAAO,QAAQ,QAAQ;AAC7B,UAAM,SAAS,QAAQ,UAAU;AACjC,UAAM,aAAa,SAAS,QAAQ;AACpC,UAAM,eAAe,SAAS,UAAU;AAExC,UAAM,QAAQ,GAAG,UAAU,MAAM,IAAI,IAAI,QAAQ,IAAI,GAAG,MAAM;AAC9D,UAAM,UAAU,aAAa,GAAG,YAAY,MAAM,IAAI,IAAI,QAAQ,IAAI,EAAE;AAExE,WAAO,EAAE,OAAO,QAAQ;AAAA,EAC1B;AAEA,QAAM,IAAI,MAAM,iDAAiD;AACnE;;;AC3HO,IAAM,eAAe;AACrB,IAAM,uBAAuB,CAAC,OAAO,QAAQ,QAAQ,MAAM;AAE3D,IAAM,yBAAyB;AAC/B,IAAM,0BAA0B;AAEhC,IAAM,0BAA0B;AAChC,IAAM,wBAAwB;AAE9B,IAAM,iBAAiB;AAAA,EAC5B,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,kBAAkB;AAAA,IAChB,oBAAoB;AAAA,IACpB,cAAc;AAAA,EAChB;AAAA,EACA,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,QAAQ;AACV;AAEO,IAAM,cAAc;AAAA,EACzB,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AACR;;;AFJO,IAAM,cAAN,MAAkB;AAAA,EACvB,YAAY,SAAS;AACnB,SAAK,QAAQ,QAAQ,SAAS,CAAC;AAC/B,SAAK,iBAAiB,QAAQ,UAAU,CAAC;AACzC,SAAK,aAAa,QAAQ,cAAc,CAAC;AACzC,SAAK,WAAW,QAAQ,aAAa,MAAM;AAAA,IAAE;AAC7C,SAAK,QAAQ,QAAQ,UAAU,MAAM;AAAA,IAAE;AACvC,SAAK,WAAW,QAAQ,aAAa,MAAM;AAAA,IAAE;AAC7C,SAAK,WAAW,QAAQ,aAAa,MAAM;AAAA,IAAE;AAC7C,SAAK,cAAc,QAAQ,gBAAgB,MAAM;AAAA,IAAE;AACnD,SAAK,UAAU,QAAQ,YAAY,MAAM;AAAA,IAAE;AAC3C,SAAK,WAAW,QAAQ,YAAY;AAEpC,SAAK,SAAS,QAAQ;AACtB,SAAK,UAAU;AAOf,SAAK,gBAAgB,oBAAI,IAAI;AAG7B,SAAK,iBAAiB;AACtB,SAAK,cAAc,oBAAI,IAAI;AAAA,EAC7B;AAAA,EAEA,aAAa,UAAU,OAAO;AAC5B,UAAM,aAAa,KAAK,cAAc,QAAQ;AAG9C,QAAI,SAAS,MAAM,YAAY,GAAG;AAChC,aAAO,UAAU,YAAY,KAAK,cAAc;AAAA,IAClD;AAEA,QAAI,UAAU,YAAY,KAAK,cAAc,GAAG;AAC9C,WAAK,QAAQ,UAAU,MAAM,iBAAiB;AAC9C,aAAO;AAAA,IACT;AAEA,QAAI,SAAS,MAAM,OAAO,KAAK,CAAC,KAAK,gBAAgB,YAAY,KAAK,UAAU,GAAG;AACjF,WAAK,QAAQ,UAAU,MAAM,yBAAyB;AACtD,aAAO;AAAA,IACT;AAEA,QAAI,SAAS,MAAM,OAAO,GAAG;AAC3B,WAAK,QAAQ,UAAU,KAAK;AAAA,IAC9B;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,cAAc,UAAU;AACtB,WAAO,KAAK,SAAS,KAAK,QAAQ,EAAE,QAAQ,OAAO,GAAG;AAAA,EACxD;AAAA,EAEA,gBAAgB,UAAU,YAAY;AACpC,UAAM,MAAM,KAAK,QAAQ,QAAQ,EAAE,YAAY;AAC/C,WAAO,WAAW,SAAS,GAAG;AAAA,EAChC;AAAA,EAEA,QAAQ,UAAU,SAAS,SAAS,IAAI;AACtC,QAAI,CAAC,KAAK,YAAY,CAAC,KAAK,eAAgB;AAE5C,UAAM,aAAa,KAAK,cAAc,QAAQ;AAC9C,QAAI,KAAK,YAAY,IAAI,UAAU,EAAG;AAEtC,SAAK,YAAY,IAAI,UAAU;AAC/B,SAAK,OAAO,YAAY,YAAY,SAAS,MAAM;AAAA,EACrD;AAAA,EAEA,kBAAkB;AAChB,WAAO,MAAM,KAAK,KAAK,aAAa;AAAA,EACtC;AAAA,EAEA,wBAAwB;AACtB,QAAI,CAAC,KAAK,YAAY,CAAC,KAAK,QAAS;AAErC,UAAM,UAAU,KAAK,QAAQ,WAAW;AACxC,UAAM,aAAa,KAAK,MAAM,IAAI,OAAK,KAAK,cAAc,CAAC,CAAC;AAC5D,UAAM,eAAe,oBAAI,IAAI;AAE7B,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,YAAM,aAAa,KAAK,cAAc,GAAG;AAEzC,YAAM,oBAAoB,WAAW;AAAA,QAAK,UACxC,eAAe,QAAQ,WAAW,WAAW,OAAO,GAAG;AAAA,MACzD;AAEA,UAAI,CAAC,qBAAqB,eAAe,IAAK;AAE9C,YAAM,oBAAoB,MAAM,KAAK,UAAQ;AAC3C,cAAM,WAAW,GAAG,GAAG,IAAI,IAAI,GAAG,QAAQ,OAAO,GAAG;AACpD,cAAM,iBAAiB,KAAK,cAAc,QAAQ;AAClD,eAAO,KAAK,gBAAgB,gBAAgB,KAAK,UAAU,KACzD,CAAC,UAAU,gBAAgB,KAAK,cAAc;AAAA,MAClD,CAAC;AAED,UAAI,mBAAmB;AAGrB,qBAAa,IAAI,UAAU;AAC3B,mBAAW,QAAQ,YAAY;AAC7B,cAAI,WAAW,WAAW,OAAO,GAAG,GAAG;AAErC,kBAAM,QAAQ,WAAW,UAAU,KAAK,SAAS,CAAC,EAAE,MAAM,GAAG;AAC7D,gBAAI,WAAW;AACf,uBAAW,QAAQ,MAAM,MAAM,GAAG,EAAE,GAAG;AACrC,yBAAW,GAAG,QAAQ,IAAI,IAAI;AAC9B,2BAAa,IAAI,QAAQ;AAAA,YAC3B;AACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,aAAa,MAAM,KAAK,YAAY,EAAE,KAAK;AACjD,QAAI,WAAW,WAAW,EAAG;AAE7B,YAAQ,IAAI,MAAM,KAAK;AAAA,EAAK,KAAK,OAAO,QAAQ,KAAK,wBAAwB,CAAC;AAC9E,eAAW,QAAQ,SAAO;AACxB,cAAQ,IAAI,MAAM,MAAM,KAAK,KAAK,OAAO,QAAQ,OAAO,IAAI,GAAG,EAAE,CAAC;AAAA,IACpE,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,QAAQ;AACZ,QAAI,KAAK,SAAS;AAChB,WAAK,OAAO,QAAQ,yBAAyB;AAC7C;AAAA,IACF;AAEA,QAAI,KAAK,MAAM,WAAW,GAAG;AAC3B,WAAK,OAAO,QAAQ,mBAAmB;AACvC;AAAA,IACF;AAEA,SAAK,OAAO,aAAa,KAAK,KAAK;AACnC,SAAK,iBAAiB;AAEtB,SAAK,UAAU,SAAS,MAAM,KAAK,OAAO;AAAA,MACxC,GAAG;AAAA,MACH,SAAS,CAAC,UAAU,UAAU,KAAK,aAAa,UAAU,KAAK;AAAA,IACjE,CAAC;AAED,SAAK,QACF,GAAG,UAAU,CAAC,aAAa;AAC1B,YAAM,aAAa,KAAK,cAAc,QAAQ;AAC9C,WAAK,SAAS,UAAU;AAAA,IAC1B,CAAC,EACA,GAAG,OAAO,CAAC,aAAa;AACvB,YAAM,aAAa,KAAK,cAAc,QAAQ;AAC9C,WAAK,cAAc,IAAI,UAAU;AACjC,WAAK,MAAM,UAAU;AAAA,IACvB,CAAC,EACA,GAAG,UAAU,CAAC,aAAa;AAC1B,YAAM,aAAa,KAAK,cAAc,QAAQ;AAC9C,WAAK,cAAc,OAAO,UAAU;AACpC,WAAK,SAAS,UAAU;AAAA,IAC1B,CAAC,EACA,GAAG,UAAU,CAAC,YAAY;AACzB,YAAM,aAAa,KAAK,cAAc,OAAO;AAC7C,WAAK,SAAS,UAAU;AAAA,IAC1B,CAAC,EACA,GAAG,aAAa,CAAC,YAAY;AAC5B,YAAM,aAAa,KAAK,cAAc,OAAO;AAC7C,WAAK,YAAY,UAAU;AAAA,IAC7B,CAAC,EACA,GAAG,SAAS,CAAC,UAAU;AACtB,WAAK,OAAO,MAAM,kBAAkB,MAAM,OAAO,EAAE;AAAA,IACrD,CAAC,EACA,GAAG,SAAS,MAAM;AACjB,WAAK,iBAAiB;AACtB,WAAK,YAAY,MAAM;AAIvB,YAAM,UAAU,KAAK,QAAQ,WAAW;AACxC,YAAM,aAAa,KAAK,MAAM,IAAI,OAAK,KAAK,cAAc,CAAC,CAAC;AAE5D,UAAI,kBAAkB;AACtB,UAAI,iBAAiB;AAErB,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,cAAM,aAAa,KAAK,cAAc,GAAG;AAEzC,cAAM,oBAAoB,WAAW;AAAA,UAAK,UACxC,eAAe,QAAQ,WAAW,WAAW,OAAO,GAAG;AAAA,QACzD;AAEA,YAAI,CAAC,qBAAqB,eAAe,IAAK;AAE9C,YAAI,oBAAoB;AACxB,mBAAW,QAAQ,OAAO;AACxB,gBAAM,WAAW,GAAG,GAAG,IAAI,IAAI,GAAG,QAAQ,OAAO,GAAG;AACpD,gBAAM,iBAAiB,KAAK,cAAc,QAAQ;AAClD,cAAI,KAAK,gBAAgB,gBAAgB,KAAK,UAAU,KACtD,CAAC,UAAU,gBAAgB,KAAK,cAAc,GAAG;AACjD,iBAAK,cAAc,IAAI,cAAc;AACrC;AACA,gCAAoB;AAAA,UACtB;AAAA,QACF;AAEA,YAAI,kBAAmB;AAAA,MACzB;AAEA,WAAK,sBAAsB;AAE3B,cAAQ,IAAI,MAAM,MAAM;AAAA,EAAK,KAAK,OAAO,QAAQ,KAAK,oBAAoB,CAAC;AAC3E,cAAQ,IAAI,MAAM,KAAK,GAAG,KAAK,OAAO,QAAQ,KAAK,aAAa,eAAe,iBAAiB,cAAc,IAAI,mBAAmB,IAAI,cAAc,aAAa;AAAA,CAAI,CAAC;AAEzK,UAAI,oBAAoB,GAAG;AACzB,aAAK,OAAO,eAAe,KAAK,OAAO,KAAK,UAAU;AAAA,MACxD;AAEA,WAAK,QAAQ;AAAA,IACf,CAAC;AAEH,WAAO,IAAI,QAAQ,aAAW;AAC5B,WAAK,QAAQ,GAAG,SAAS,OAAO;AAAA,IAClC,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,OAAO;AACX,QAAI,KAAK,SAAS;AAChB,YAAM,KAAK,QAAQ,MAAM;AACzB,WAAK,UAAU;AACf,WAAK,cAAc,MAAM;AAAA,IAC3B;AAAA,EACF;AACF;;;AG9PA,OAAOC,YAAW;;;ACAlB,OAAOC,YAAW;AAGX,IAAM,SAAN,MAAa;AAAA,EAClB,cAAc;AACZ,SAAK,UAAU;AAAA,MACb,OAAO;AAAA,MACP,MAAM;AAAA,MACN,SAAS;AAAA,MACT,SAAS;AAAA,MACT,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,QAAQ;AAAA,MACR,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,UAAU;AAAA,MACV,WAAW;AAAA,MACX,SAAS;AAAA,MACT,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,SAAS;AACb,YAAQ,IAAIC,OAAM,KAAK,GAAG,KAAK,QAAQ,KAAK,KAAK,WAAW,CAAC,KAAK,OAAO,EAAE,CAAC;AAAA,EAC9E;AAAA,EAEA,KAAK,SAAS;AACZ,YAAQ,IAAIA,OAAM,KAAK,GAAG,KAAK,QAAQ,IAAI,KAAK,WAAW,CAAC,KAAK,OAAO,EAAE,CAAC;AAAA,EAC7E;AAAA,EAEA,QAAQ,SAAS;AACf,YAAQ,IAAIA,OAAM,MAAM,GAAG,KAAK,QAAQ,OAAO,KAAK,WAAW,CAAC,KAAK,OAAO,EAAE,CAAC;AAAA,EACjF;AAAA,EAEA,QAAQ,SAAS;AACf,YAAQ,IAAIA,OAAM,OAAO,GAAG,KAAK,QAAQ,OAAO,KAAK,WAAW,CAAC,KAAK,OAAO,EAAE,CAAC;AAAA,EAClF;AAAA,EAEA,MAAM,SAAS;AACb,YAAQ,IAAIA,OAAM,IAAI,GAAG,KAAK,QAAQ,KAAK,KAAK,WAAW,CAAC,KAAK,OAAO,EAAE,CAAC;AAAA,EAC7E;AAAA,EAEA,OAAO,QAAQ,SAAS,QAAQ,SAAS;AACvC,UAAM,MAAM,KAAK,QAAQ,MAAM,KAAK;AACpC,UAAM,MAAM,GAAG,GAAG,KAAK,WAAW,CAAC,KAAK,OAAO;AAC/C,YAAQ,IAAIA,OAAM,KAAK,EAAE,GAAG,CAAC;AAAA,EAC/B;AAAA,EAEA,KAAK,QAAQ,UAAU,QAAQ,SAAS,SAAS,IAAI;AACnD,UAAM,MAAM,KAAK,QAAQ,MAAM,KAAK;AACpC,UAAM,WAAW,YAAY,QAAQ;AACrC,UAAM,UAAU,YAAY,QAAQ;AAEpC,UAAM,aAAa,SAAS,GAAG,MAAM,OAAO;AAC5C,UAAM,MAAM,GAAG,GAAG,KAAK,WAAW,CAAC,KAAK,UAAU,GAAGA,OAAM,KAAK,QAAQ,CAAC,IAAIA,OAAM,KAAK,OAAO,IAAI,OAAO,GAAG,CAAC;AAE9G,YAAQ,IAAIA,OAAM,KAAK,EAAE,GAAG,CAAC;AAAA,EAC/B;AAAA,EAEA,OAAO,MAAM,QAAQ;AACnB,YAAQ,IAAIA,OAAM,OAAO,MAAM,KAAK,GAAG,KAAK,QAAQ,OAAO,IAAI,IAAI;AAAA,CAAa,CAAC;AAEjF,UAAM,eAAe,OAAO,MAAM,UAAU;AAC5C,UAAM,aAAa,OAAO,MAAM,QAAQ;AAExC,UAAM,QAAQ;AAAA,MACZ,CAAC,OAAO,YAAY,QAAQ,GAAG,KAAK,QAAQ,OAAO,IAAI,aAAa,YAAY,CAAC,sBAAsB,YAAY,gBAAgB,OAAO,IAAI,EAAE;AAAA,MAChJ,CAAC,OAAO,WAAW,QAAQ,GAAG,KAAK,QAAQ,OAAO,qBAAqB,UAAU,gBAAgB,OAAO,IAAI,GAAG,OAAO,MAAM,EAAE;AAAA,MAC9H,CAAC,OAAO,WAAW,QAAQ,GAAG,KAAK,QAAQ,SAAS,4BAA4B,OAAO,UAAU,IAAI,EAAE;AAAA,MACvG,CAAC,OAAO,SAAS,QAAQ,GAAG,KAAK,QAAQ,OAAO,0BAA0B,OAAO,QAAQ,IAAI,EAAE;AAAA,MAC/F,CAAC,OAAO,cAAc,WAAW,GAAG,KAAK,QAAQ,MAAM,sCAAsC,OAAO,UAAU,GAAG;AAAA,MACjH,CAAC,CAAC,OAAO,gBAAgB,OAAO,YAAY,UAAU,GAAG,KAAK,QAAQ,OAAO,8BAA8B,OAAO,UAAU,yBAAyB;AAAA,MACrJ,CAAC,OAAO,UAAU,UAAU,GAAG,KAAK,QAAQ,MAAM,uBAAuB;AAAA,MACzE,CAAC,OAAO,UAAU,MAAM,UAAU,GAAG,KAAK,QAAQ,MAAM,6BAA6B;AAAA,MACrF,CAAC,OAAO,UAAU,IAAI,UAAU,GAAG,KAAK,QAAQ,MAAM,2BAA2B;AAAA,IACnF;AAEA,eAAW,CAAC,WAAW,OAAO,OAAO,KAAK,OAAO;AAC/C,UAAI,UAAW,SAAQ,IAAIA,OAAM,KAAK,EAAE,OAAO,CAAC;AAAA,IAClD;AAEA,UAAM,QAAQ;AAAA,MACZ,CAAC,OAAO,OAAO,QAAQ;AAAA,EAAK,KAAK,QAAQ,IAAI,WAAW;AAAA,MACxD,CAAC,OAAO,QAAQ,QAAQ,GAAG,KAAK,QAAQ,IAAI,WAAW;AAAA,MACvD,CAAC,OAAO,MAAM,QAAQ,GAAG,KAAK,QAAQ,IAAI,aAAa;AAAA,IACzD;AAEA,eAAW,CAAC,KAAK,OAAO,KAAK,KAAK,OAAO;AACvC,UAAI,OAAO,IAAI,SAAS,GAAG;AACzB,gBAAQ,IAAIA,OAAM,KAAK,EAAE,GAAG,KAAK,KAAK,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;AAAA,MACzD;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,iBAAiB,QAAQ,KAAK,EAAE,SAAS,QAAQ,YAAY,QAAQ,IAAI,CAAC,GAAG;AAC3E,UAAM,MAAM,KAAK,QAAQ;AACzB,UAAM,OAAO,WAAW;AACxB,UAAM,cAAc,UAAU,MAAM,QAAQ,UAAU,MAAM,WAAW;AAEvE,YAAQ,IAAIA,OAAM,KAAK,GAAG,GAAG,KAAK,IAAI,KAAK,MAAM,IAAI,GAAG,EAAE,CAAC;AAE3D,UAAM,OAAO,CAAC;AACd,QAAI,QAAS,MAAK,KAAK,EAAE,OAAO,gBAAgB,OAAO,QAAQ,CAAC;AAChE,SAAK,KAAK,EAAE,OAAO,mBAAmB,OAAO,GAAGA,OAAM,WAAW,EAAE,MAAM,CAAC,IAAI,UAAU,GAAG,CAAC;AAC5F,QAAI,QAAS,MAAK,KAAK,EAAE,OAAO,iBAAiB,OAAO,QAAQ,CAAC;AAEjE,SAAK,QAAQ,CAAC,KAAK,MAAM;AACvB,YAAM,SAAS,MAAM,KAAK,SAAS,IAAI,iBAAO;AAC9C,cAAQ,IAAIA,OAAM,KAAK,KAAK,MAAM,IAAI,IAAI,KAAK,IAAI,IAAIA,OAAM,MAAM,IAAI,KAAK,CAAC;AAAA,IAC/E,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,eAAe,IAAI,KAAK,SAAS;AAC/B,UAAM,MAAM,KAAK,QAAQ;AACzB,UAAM,OAAO,WAAW;AACxB,UAAM,UAAU,OAAO,QAAQ,OAAO;AAEtC,YAAQ,IAAIA,OAAM,KAAK,GAAG,GAAG,KAAK,IAAI,MAAM,EAAE,eAAe,GAAG,EAAE,CAAC;AAEnE,QAAI,QAAQ,WAAW,EAAG;AAC1B,YAAQ,QAAQ,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM;AAC7B,YAAM,SAAS,MAAM,QAAQ,SAAS,IAAI,iBAAO;AACjD,cAAQ,IAAIA,OAAM,KAAK,KAAK,MAAM,GAAG,IAAIA,OAAM,OAAO,CAAC,IAAIA,OAAM,KAAK,IAAI,IAAIA,OAAM,MAAM,CAAC,CAAC;AAAA,IAC9F,CAAC;AAAA,EACH;AAAA,EAEA,WAAW;AACT,YAAQ,IAAIA,OAAM,MAAM,MAAM,KAAK;AAAA,GAAM,KAAK,QAAQ,QAAQ,oBAAoB,CAAC;AAAA,EACrF;AAAA,EAEA,aAAa,OAAO;AAClB,UAAM,eAAe,MAAM,KAAK,IAAI;AACpC,YAAQ,IAAIA,OAAM,KAAK;AAAA,EAAK,KAAK,QAAQ,KAAK,+BAA+B,YAAY,EAAE,CAAC;AAC5F,YAAQ,IAAIA,OAAM,KAAK,GAAG,KAAK,QAAQ,KAAK,mCAAmC,CAAC;AAAA,EAClF;AAAA,EAEA,YAAY,UAAU,SAAS,SAAS,IAAI;AAC1C,QAAI,SAAS;AACX,YAAM,aAAa,SAAS,KAAK,MAAM,MAAM;AAC7C,cAAQ,IAAIA,OAAM,IAAI,KAAK,KAAK,QAAQ,KAAK,IAAI,QAAQ,GAAG,UAAU,EAAE,CAAC;AAAA,IAC3E,OAAO;AACL,cAAQ,IAAIA,OAAM,MAAM,KAAK,KAAK,QAAQ,OAAO,IAAI,QAAQ,EAAE,CAAC;AAAA,IAClE;AAAA,EACF;AAAA,EAEA,eAAe,UAAU,YAAY;AACnC,YAAQ,IAAIA,OAAM,OAAO;AAAA,EAAK,KAAK,QAAQ,OAAO,mDAAmD,CAAC;AACtG,YAAQ,IAAIA,OAAM,OAAO,eAAe,SAAS,KAAK,IAAI,CAAC,EAAE,CAAC;AAC9D,YAAQ,IAAIA,OAAM,OAAO,eAAe,CAAC;AACzC,YAAQ,IAAIA,OAAM,OAAO,wBAAmB,CAAC;AAC7C,YAAQ,IAAIA,OAAM,OAAO,qCAAgC,WAAW,KAAK,IAAI,CAAC,EAAE,CAAC;AACjF,YAAQ,IAAIA,OAAM,OAAO;AAAA,CAA0C,CAAC;AAAA,EACtE;AACF;;;AClKA,OAAOC,WAAU;AAEjB,eAAsB,aAAa,KAAK,QAAQ;AAC9C,QAAM,MAAM,IAAI,IAAI,IAAI,GAAG;AAE3B,MAAI,OAAO,kBAAkB,IAAI,aAAa,OAAO,gBAAgB;AACnE,WAAO,SAAS,KAAK,OAAO,UAAU,CAAC;AAAA,EACzC;AAEA,MAAI,OAAO,iBAAiB,IAAI,aAAa,OAAO,eAAe;AACjE,WAAO,oBAAoB,MAAM;AAAA,EACnC;AAEA,MAAI,OAAO,WAAW;AACpB,UAAM,WAAW,MAAM,gBAAgB,KAAK,KAAK,MAAM;AACvD,QAAI,SAAU,QAAO;AAAA,EACvB;AAEA,MAAI,OAAO,gBAAgB,IAAI,aAAa,KAAK;AAC/C,WAAO,qBAAqB,KAAK,MAAM;AAAA,EACzC;AAEA,MAAI,OAAO,WAAW;AACpB,WAAO,iBAAiB,KAAK,MAAM;AAAA,EACrC;AAEA,SAAO,IAAI,SAAS,aAAa,EAAE,QAAQ,IAAI,CAAC;AAClD;AAEA,SAAS,oBAAoB,QAAQ;AACnC,MAAI;AACF,UAAM,QAAQ,OAAO,mBACjB,OAAO,iBAAiB,IACxB,OAAO,QAAQ,gBAAgB;AACnC,WAAO,SAAS,KAAK,KAAK;AAAA,EAC5B,SAAS,OAAO;AACd,WAAO,OAAO,MAAM,wBAAwB,MAAM,OAAO,EAAE;AAC3D,WAAO,SAAS,KAAK,CAAC,GAAG,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC1C;AACF;AAEA,eAAe,gBAAgB,KAAK,KAAK,QAAQ;AAC/C,QAAM,SAAS,OAAO;AACtB,QAAM,UAAU,IAAI;AAEpB,MAAI,UAAU;AACd,MAAI,OAAO,OAAO,SAAS,UAAU;AACnC,cAAU,QAAQ,WAAW,OAAO,OAAO,GAAG;AAAA,EAChD,WAAW,OAAO,gBAAgB,QAAQ;AACxC,cAAU,OAAO,KAAK,KAAK,OAAO;AAAA,EACpC;AAEA,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,YAAY,OAAO,OAAO,SAAS,WACrC,QAAQ,MAAM,OAAO,KAAK,SAAS,CAAC,IACpC,QAAQ,QAAQ,OAAO,MAAM,EAAE;AAEnC,MAAI,CAAC,UAAU,WAAW,SAAS,KAAK,CAAC,UAAU,WAAW,UAAU,GAAG;AACzE,WAAO,IAAI,SAAS,sBAAsB,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC3D;AAEA,MAAI;AACF,UAAM,kBAAkB,OAAO,aAC3B,OAAO,WAAW,WAAW,GAAG,IAChC;AAAA,MACA,cAAc;AAAA,MACd,gBAAgB,IAAI,QAAQ,IAAI,cAAc,KAAK;AAAA,IACrD;AAIF,QAAI;AACJ,QAAI;AACJ,QAAI,OAAO,SAAS,QAAQ,CAAC,CAAC,OAAO,MAAM,EAAE,SAAS,IAAI,MAAM,GAAG;AACjE,wBAAkB,MAAM,IAAI,KAAK,GAAG,MAAM,GAAG,GAAG;AAChD,kBAAY;AAAA,IACd,OAAO;AACL,kBAAY,CAAC,OAAO,MAAM,EAAE,SAAS,IAAI,MAAM,IAAI,SAAY,IAAI;AAAA,IACrE;AAEA,UAAM,WAAW,MAAM,MAAM,WAAW;AAAA,MACtC,QAAQ,IAAI;AAAA,MACZ,SAAS;AAAA,MACT,MAAM;AAAA,IACR,CAAC;AAED,UAAM,gBAAgB,OAAO,oBACzB,MAAM,OAAO,kBAAkB,QAAQ,IACvC;AAIJ,UAAM,kBAAkB,IAAI,QAAQ,cAAc,OAAO;AACzD,oBAAgB,IAAI,+BAA+B,GAAG;AACtD,oBAAgB,IAAI,gCAAgC,iCAAiC;AACrF,oBAAgB,IAAI,gCAAgC,GAAG;AAEvD,QAAI,IAAI,WAAW,WAAW;AAC5B,aAAO,IAAI,SAAS,MAAM,EAAE,QAAQ,KAAK,SAAS,gBAAgB,CAAC;AAAA,IACrE;AAEA,QAAI,OAAO,SAAS,MAAM;AAExB,YAAM,UAAU,MAAM,cAAc,KAAK;AACzC,aAAO,OAAO,iBAAiB,IAAI,QAAQ,WAAW;AAAA,QACpD,SAAS;AAAA,QACT,QAAQ,cAAc;AAAA,QACtB,YAAY,cAAc;AAAA,QAC1B,SAAS,QAAQ,MAAM,GAAG,GAAG;AAAA,MAC/B,CAAC;AACD,aAAO,IAAI,SAAS,SAAS;AAAA,QAC3B,QAAQ,cAAc;AAAA,QACtB,YAAY,cAAc;AAAA,QAC1B,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAEA,WAAO,IAAI,SAAS,cAAc,MAAM;AAAA,MACtC,QAAQ,cAAc;AAAA,MACtB,YAAY,cAAc;AAAA,MAC1B,SAAS;AAAA,IACX,CAAC;AAAA,EAEH,SAAS,OAAO;AACd,WAAO,OAAO,MAAM,qBAAqB,MAAM,OAAO,EAAE;AACxD,WAAO,IAAI,SAAS,KAAK,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC1C;AACF;AAEA,eAAe,qBAAqB,KAAK,QAAQ;AAC/C,MAAI;AACF,UAAM,YAAY,OAAO,aAAa;AAItC,QAAI,OAAO,aAAaA,MAAK,WAAW,SAAS,GAAG;AAClD,aAAO,OAAO,MAAM,2DAA2D,SAAS,GAAG;AAC3F,aAAO,IAAI,SAAS,8BAA8B,EAAE,QAAQ,IAAI,CAAC;AAAA,IACnE;AAEA,UAAM,WAAW,OAAO,YACpBA,MAAK,QAAQ,OAAO,WAAW,SAAS,IACxCA,MAAK,QAAQ,SAAS;AAE1B,UAAM,OAAO,IAAI,KAAK,QAAQ;AAC9B,UAAM,OAAO,MAAM,KAAK,KAAK;AAE7B,QAAI,CAAC,OAAO,YAAY;AACtB,aAAO,IAAI,SAAS,MAAM;AAAA,QACxB,SAAS,EAAE,gBAAgB,YAAY;AAAA,MACzC,CAAC;AAAA,IACH;AAEA,UAAM,cAAc,IAAI,QAAQ,IAAI,MAAM;AAC1C,UAAM,WAAW,OAAO,MAAM,UAAU;AACxC,UAAM,YAAY,GAAG,QAAQ,MAAM,WAAW,MAAM,OAAO,WACxD,QAAQ,OAAO,GAAG,EAClB,QAAQ,SAAS,EAAE;AAEtB,UAAM,WAAW,UAAU,SAAS,MAAM;AAC1C,UAAM,WAAW,WAAW,mBAAmB;AAE/C,UAAM,eAAe,KAAK;AAAA,MACxB;AAAA,MACA,UAAU,QAAQ,SAAS,SAAS;AAAA,IACtC;AAEA,WAAO,IAAI,SAAS,cAAc;AAAA,MAChC,SAAS,EAAE,gBAAgB,YAAY;AAAA,IACzC,CAAC;AAAA,EACH,SAAS,OAAO;AACd,WAAO,OAAO,MAAM,6BAA6B,MAAM,OAAO,EAAE;AAChE,WAAO,IAAI,SAAS,4BAA4B,EAAE,QAAQ,IAAI,CAAC;AAAA,EACjE;AACF;AAEA,IAAM,aAAa;AAAA;AAAA,EAEjB,SAAS;AAAA,EACT,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA;AAAA,EAGR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA;AAAA,EAGT,SAAS;AAAA,EACT,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,QAAQ;AAAA;AAAA,EAGR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AACV;AAEA,eAAe,iBAAiB,KAAK,QAAQ;AAC3C,MAAI,WAAW,IAAI,aAAa,MAAM,gBAAgB,IAAI;AAE1D,MAAI,IAAI,aAAa,OAAO,OAAO,WAAW;AAC5C,eAAW,MAAM,OAAO,UAAU,QAAQ,OAAO,EAAE;AAAA,EACrD;AAEA,QAAM,eAAeA,MAAK,QAAQ,OAAO,SAAS;AAIlD,QAAM,WAAWA,MAAK,QAAQ,cAAc,MAAM,QAAQ;AAE1D,MAAI,CAAC,SAAS,WAAW,eAAeA,MAAK,GAAG,GAAG;AACjD,WAAO,IAAI,SAAS,aAAa,EAAE,QAAQ,IAAI,CAAC;AAAA,EAClD;AAEA,MAAI,OAAO,IAAI,KAAK,QAAQ;AAE5B,MAAI,CAAE,MAAM,KAAK,OAAO,GAAI;AAE1B,UAAM,YAAYA,MAAK,KAAK,UAAU,YAAY;AAClD,WAAO,IAAI,KAAK,SAAS;AAEzB,QAAI,CAAE,MAAM,KAAK,OAAO,GAAI;AAC1B,aAAO,IAAI,SAAS,aAAa,EAAE,QAAQ,IAAI,CAAC;AAAA,IAClD;AAAA,EACF;AAEA,QAAM,MAAMA,MAAK,QAAQ,KAAK,IAAI,EAAE,YAAY;AAChD,QAAM,cAAc,WAAW,GAAG,KAAK;AAEvC,SAAO,IAAI,SAAS,MAAM;AAAA,IACxB,SAAS;AAAA,MACP,gBAAgB;AAAA,MAChB,iBAAiB;AAAA,MACjB,UAAU;AAAA,MACV,WAAW;AAAA,IACb;AAAA,EACF,CAAC;AACH;;;AC3PO,SAAS,cAAc,QAAQC,OAAM,QAAQ,QAAQ,UAAU;AAGpE,QAAM,YAAYA,MAAK,MAAM,OAAO,KAAK,SAAS,CAAC;AAGnD,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,SAAS;AAChC,QAAI,OAAO,aAAa,SAAS,OAAO,aAAa,QAAQ;AAC3D,YAAM,IAAI,MAAM,qBAAqB,OAAO,QAAQ,EAAE;AAAA,IACxD;AAAA,EACF,SAAS,GAAG;AACV,WAAO,OAAO,WAAW,4BAA4B,EAAE,OAAO,IAAI,KAAK;AACvE,WAAO,MAAM,MAAM,oBAAoB;AACvC,WAAO;AAAA,EACT;AAGA,SAAO,KAAK,UAAU;AAGtB,QAAM,KAAK,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC;AAChD,QAAM,MAAM,IAAI,EAAE;AAMlB,MAAI,UAAU,CAAC;AAEf,MAAI,OAAO,kBAAkB,OAAO,KAAK,SAAS;AAChD,QAAI,OAAO,mBAAmB,MAAM;AAClC,gBAAU,EAAE,GAAG,OAAO,KAAK,QAAQ;AAAA,IACrC,WAAW,MAAM,QAAQ,OAAO,cAAc,GAAG;AAC/C,iBAAW,QAAQ,OAAO,gBAAgB;AACxC,cAAM,QAAQ,OAAO,KAAK,UAAU,KAAK,YAAY,CAAC;AACtD,YAAI,UAAU,QAAW;AACvB,kBAAQ,KAAK,YAAY,CAAC,IAAI;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,OAAO,SAAS;AAClB,cAAU,EAAE,GAAG,SAAS,GAAG,OAAO,QAAQ;AAAA,EAC5C;AAEA,MAAI,OAAO,YAAY;AACrB,cAAU,EAAE,GAAG,SAAS,GAAG,OAAO,WAAW,WAAW,OAAO,KAAK,OAAO,EAAE;AAAA,EAC/E;AAEA,QAAM,YAAY,EAAE,QAAQ;AAC5B,MAAI,OAAO,SAAS;AAClB,WAAO,OAAO,WAAW,OAAO,OAAO;AAAA,EACzC;AAEA,MAAI;AACJ,MAAI;AACF,eAAW,IAAI,UAAU,WAAW,SAAS;AAAA,EAC/C,SAAS,OAAO;AACd,WAAO,OAAO,WAAW,GAAG,GAAG,yCAAyC,MAAM,OAAO,IAAI,KAAK;AAC9F,WAAO,MAAM,MAAM,4BAA4B;AAC/C;AAAA,EACF;AAEA,SAAO,KAAK,WAAW;AAGvB,MAAI,SAAS;AACb,QAAM,YAAY,MAAM;AACtB,QAAI,OAAQ;AACZ,aAAS;AACT,iBAAa;AACb,oBAAgB;AAChB,QAAI;AAAE,aAAO,MAAM;AAAA,IAAG,QAAQ;AAAA,IAAE;AAChC,QAAI;AAAE,eAAS,MAAM;AAAA,IAAG,QAAQ;AAAA,IAAE;AAClC,QAAI,SAAU,QAAO,OAAO,WAAW,GAAG,GAAG,WAAW,SAAS,IAAI,MAAM;AAAA,EAC7E;AAKA,QAAM,wBAAwB,CAAC;AAC/B,QAAM,cAAc;AAMpB,MAAI,aAAa;AACjB,MAAI,gBAAgB;AAEpB,QAAM,uBAAuB,OAAO,oBACjC,CAAC,SAAS,SAASC,cAAa;AAC/B,QAAI,YAAY,OAAO,YAAY,UAAU;AAC3C,aAAO,OAAO,WAAW,GAAG,GAAG,OAAO,QAAQ,MAAM,GAAG,GAAG,CAAC,IAAI,MAAM;AAAA,IACvE;AACA,QAAI,eAAe;AACjB,MAAAA,UAAS,KAAK,OAAO;AAAA,IACvB,OAAO;AACL,UAAI,sBAAsB,UAAU,aAAa;AAC/C,8BAAsB,MAAM;AAAA,MAC9B;AACA,4BAAsB,KAAK,OAAO;AAAA,IACpC;AAAA,EACF;AAEF,QAAM,yBAAyB,OAAO,sBACnC,CAAC,SAASC,SAAQ,cAAc;AAC/B,QAAI,YAAY,OAAO,YAAY,UAAU;AAC3C,aAAO,OAAO,WAAW,GAAG,GAAG,OAAO,QAAQ,MAAM,GAAG,GAAG,CAAC,IAAI,MAAM;AAAA,IACvE;AACA,QAAI,cAAcA,QAAO,eAAe,UAAU,MAAM;AACtD,UAAI;AACF,QAAAA,QAAO,KAAK,OAAO;AAAA,MACrB,QAAQ;AAAA,MAGR;AAAA,IACF;AAAA,EACF;AAEF,WAAS,YAAY,CAAC,UAAU;AAC9B,2BAAuB,MAAM,MAAM,QAAQ,QAAQ;AAAA,EACrD;AAEA,WAAS,UAAU;AAEnB,WAAS,UAAU,CAAC,UAAU;AAC5B,UAAM,UAAU,iBAAiB,aAAa,MAAM,UAAU;AAC9D,QAAI,SAAU,QAAO,OAAO,WAAW,GAAG,GAAG,oBAAoB,OAAO,IAAI,KAAK;AACjF,cAAU;AAAA,EACZ;AAEA,WAAS,SAAS,MAAM;AACtB,oBAAgB;AAEhB,QAAI,SAAU,QAAO,eAAe,IAAI,WAAW,OAAO;AAG1D,eAAW,OAAO,uBAAuB;AACvC,eAAS,KAAK,GAAG;AAAA,IACnB;AACA,0BAAsB,SAAS;AAE/B,QAAI,OAAO,WAAW;AACpB,aAAO,UAAU,SAAS;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO;AAAA,IACL,WAAW,CAAC,YAAY;AACtB,2BAAqB,SAAS,QAAQ,QAAQ;AAAA,IAChD;AAAA,IACA,SAAS;AAAA,EACX;AACF;;;AHlDO,IAAM,YAAN,MAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA4BrB,YAAY,UAAU,CAAC,GAAG;AAExB,SAAK,OAAO,QAAQ,QAAQ;AAC5B,SAAK,WAAW,QAAQ,YAAY;AACpC,SAAK,SAAS,QAAQ,UAAU;AAChC,SAAK,aAAa,QAAQ,cAAc;AACxC,SAAK,aAAa,QAAQ,SAAS,CAAC,KAAK;AACzC,SAAK,cAAc,QAAQ,UAAU,CAAC;AACtC,SAAK,eAAe,QAAQ,QAAQ,CAAC;AACrC,SAAK,cAAc,QAAQ,cAAc,sBAAsB,IAAI,OAAK,EAAE,YAAY,CAAC;AACvF,SAAK,oBAAoB,QAAQ,aAAa,KAAK,iBAAiB,KAAK,IAAI;AAC7E,SAAK,uBAAuB,QAAQ,iBAAiB,MAAM;AAAA,IAAE;AAC7D,SAAK,WAAW,QAAQ,YAAY;AAGpC,UAAM,KAAK,QAAQ;AACnB,QAAI,OAAO,MAAM;AACf,WAAK,WAAW,EAAE,MAAM,MAAM,IAAI,KAAK;AAAA,IACzC,WAAW,MAAM,OAAO,OAAO,UAAU;AACvC,WAAK,WAAW,EAAE,MAAM,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC,CAAC,GAAG,GAAG;AAAA,IACjD,OAAO;AACL,WAAK,WAAW,EAAE,MAAM,OAAO,IAAI,MAAM;AAAA,IAC3C;AAEA,SAAK,SAAS,IAAI,OAAO;AACzB,SAAK,UAAU;AACf,SAAK,SAAS;AAEd,SAAK,UAAU,oBAAI,IAAI;AAGvB,SAAK,YAAY,QAAQ,WAAW,QAAQ,OAAQ,QAAQ,UAAU;AACtE,SAAK,mBAAmB,QAAQ,YAAY;AAC5C,SAAK,gBAAgB,gBAAgB,QAAQ,eAAe,sBAAsB;AAClF,SAAK,iBAAiB,gBAAgB,QAAQ,gBAAgB,uBAAuB;AAGrF,UAAM,cAAc,QAAQ;AAC5B,QAAI,gBAAgB,MAAM;AACxB,WAAK,YAAY,EAAE,MAAM,wBAAwB;AAAA,IACnD,WAAW,OAAO,gBAAgB,UAAU;AAC1C,WAAK,YAAY,EAAE,MAAM,mBAAmB,aAAa,uBAAuB,EAAE;AAAA,IACpF,WAAW,eAAe,OAAO,gBAAgB,UAAU;AACzD,YAAM,EAAE,MAAM,WAAW,YAAY,mBAAmB,GAAG,KAAK,IAAI;AAEpE,UAAI,OAAO,KAAK,IAAI,EAAE,SAAS,GAAG;AAChC,aAAK,OAAO,QAAQ,uCAAuC,OAAO,KAAK,IAAI,EAAE,KAAK,IAAI,CAAC,yBAAyB;AAAA,MAClH;AAEA,WAAK,YAAY;AAAA,QACf,MAAM,mBAAmB,WAAW,uBAAuB;AAAA,QAC3D,YAAY,cAAc;AAAA,QAC1B,mBAAmB,qBAAqB;AAAA,MAC1C;AAAA,IACF,OAAO;AACL,WAAK,YAAY;AAAA,IACnB;AAGA,QAAI,QAAQ,SAAS;AACnB,WAAK,UAAU;AAAA,QACb,GAAG,QAAQ;AAAA,QACX,MAAM,mBAAmB,QAAQ,QAAQ,MAAM,qBAAqB;AAAA,MACtE;AAAA,IACF,OAAO;AACL,WAAK,UAAU;AAAA,IACjB;AAGA,QAAI,QAAQ,iBAAiB,UAAa,QAAQ,iBAAiB,MAAM;AACvE,UAAI,OAAO,QAAQ,iBAAiB,YAAY,QAAQ,aAAa,KAAK,EAAE,WAAW,GAAG;AACxF,cAAM,IAAI,MAAM,8CAA8C;AAAA,MAChE;AACA,WAAK,aAAa,QAAQ,aAAa,KAAK;AAAA,IAC9C,OAAO;AACL,WAAK,aAAa;AAAA,IACpB;AACA,SAAK,eAAe,KAAK,eAAe;AACxC,SAAK,YAAY,QAAQ,aAAa;AAGtC,SAAK,MAAM,QAAQ,OAAO;AAG1B,UAAM,kBAAkB,CAAC,UAAU,SAAS;AAC5C,SAAK,gBAAgB,QAAQ,kBAAkB,QAC3C,QACA,MAAM,QAAQ,QAAQ,aAAa,IACjC,QAAQ,gBACR;AAAA,EACR;AAAA,EAEA,WAAW,MAAM;AACf,QAAI,KAAK,aAAa,WAAW,EAAG,QAAO;AAC3C,WAAO,UAAU,MAAM,KAAK,YAAY;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,KAAK,QAAQ,SAAS;AACpB,QAAI;AACF,aAAO,KAAK,KAAK,UAAU,OAAO,CAAC;AACnC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,OAAO,MAAM,4BAA4B,MAAM,OAAO,EAAE;AAC7D,WAAK,oBAAoB,MAAM;AAC/B,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,iBAAiB,IAAI,MAAM;AACzB,SAAK,KAAK,IAAI;AAAA,MACZ,MAAM,YAAY;AAAA,MAClB,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,IACf,CAAC;AAAA,EACH;AAAA,EAEA,YAAY;AACV,WAAO;AAAA,MACL,MAAM,KAAK;AAAA,MACX,UAAU,KAAK;AAAA,MACf,QAAQ,KAAK;AAAA,MACb,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,MAAM,KAAK;AAAA,MACX,YAAY,KAAK;AAAA,MACjB,YAAY,KAAK;AAAA,MACjB,QAAQ,KAAK;AAAA,MACb,WAAW,KAAK;AAAA,MAChB,SAAS,KAAK;AAAA,MACd,gBAAgB,KAAK,SAAS,WAAW;AAAA,MACzC,eAAe,KAAK,SAAS,QAAQ;AAAA,MACrC,eAAe,KAAK;AAAA,MACpB,cAAc,KAAK;AAAA,MACnB,YAAY,KAAK;AAAA,MACjB,WAAW,KAAK;AAAA,MAChB,KAAK,KAAK;AAAA,MACV,eAAe,KAAK;AAAA,MACpB,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,IACjB;AAAA,EACF;AAAA,EAEA,MAAM,eAAe;AACnB,QAAI,CAAC,KAAK,YAAY;AACpB,cAAQ,IAAIC,OAAM,OAAO;AAAA,EAAK,KAAK,OAAO,QAAQ,MAAM,oCAAoC,KAAK,WAAW,KAAK,IAAI,CAAC,EAAE,CAAC;AACzH,YAAM,QAAQ,CAAC;AACf,YAAM,cAAc,KAAK,WAAW,IAAI,SAAO,OAAO,GAAG,EAAE;AAC3D,iBAAW,WAAW,KAAK,YAAY;AACrC,cAAM,cAAc,QAAQ,SAAS,GAAG,IAAI,UAAU,GAAG,OAAO;AAChE,cAAM,OAAO,IAAI,IAAI,KAAK,WAAW;AACrC,yBAAiB,QAAQ,KAAK,KAAK,EAAE,WAAW,KAAK,CAAC,GAAG;AACvD,cAAI,UAAU,MAAM,WAAW,KAAK,CAAC,UAAU,MAAM,KAAK,WAAW,GAAG;AACtE,kBAAM,KAAK,IAAI;AAAA,UACjB;AAAA,QACF;AAAA,MACF;AACA,cAAQ,IAAIA,OAAM,KAAK,GAAG,KAAK,OAAO,QAAQ,KAAK,UAAU,MAAM,MAAM,QAAQ,MAAM,WAAW,IAAI,MAAM,EAAE;AAAA,CAA0C,CAAC;AACzJ,WAAK,cAAc;AACnB,WAAK,mBAAmB,MAAM,KAAK;AACnC;AAAA,IACF;AACA,UAAM,iBAAiB;AAAA,MACrB,QAAQ,KAAK;AAAA,MACb,OAAO,KAAK;AAAA,MACZ,QAAQ,KAAK;AAAA,MACb,UAAU,KAAK;AAAA,MACf,UAAU,CAACC,UAAS;AAClB,YAAI,KAAK,WAAWA,KAAI,GAAG;AACzB,eAAK,OAAO,KAAK,UAAUA,OAAM,cAAc,WAAW;AAC1D,eAAK,UAAU,YAAY,QAAQA,OAAM,EAAE,MAAM,KAAK,CAAC;AACvD;AAAA,QACF;AACA,aAAK,OAAO,KAAK,UAAUA,OAAM,UAAU,cAAc;AACzD,aAAK,UAAU,YAAY,QAAQA,KAAI;AAAA,MACzC;AAAA,MACA,OAAO,CAACA,UAAS;AACf,aAAK,OAAO,KAAK,OAAOA,OAAM,eAAe,YAAY;AACzD,aAAK,UAAU,YAAY,KAAKA,KAAI;AAAA,MACtC;AAAA,MACA,UAAU,CAACA,UAAS;AAClB,aAAK,OAAO,KAAK,UAAUA,OAAM,OAAO,cAAc;AACtD,aAAK,UAAU,YAAY,QAAQA,KAAI;AAAA,MACzC;AAAA,MACA,UAAU,CAACA,UAAS;AAClB,aAAK,OAAO,KAAK,UAAUA,OAAM,QAAQ,iBAAiB;AAAA,MAC5D;AAAA,MACA,aAAa,CAACA,UAAS;AACrB,aAAK,OAAO,KAAK,aAAaA,OAAM,OAAO,mBAAmB;AAAA,MAChE;AAAA,MACA,SAAS,MAAM;AAAA,MAEf;AAAA,IACF;AAEA,QAAI,KAAK,YAAY;AACnB,qBAAe,aAAa,KAAK;AAAA,IACnC;AAEA,SAAK,UAAU,IAAI,YAAY,cAAc;AAC7C,UAAM,KAAK,QAAQ,MAAM;AAAA,EAC3B;AAAA,EAEA,UAAU,QAAQ,MAAM,QAAQ,CAAC,GAAG;AAClC,UAAM,UAAU,KAAK,UAAU,EAAE,QAAQ,MAAM,GAAG,MAAM,CAAC;AACzD,UAAM,OAAO,CAAC;AACd,UAAM,YAAY,KAAK,QAAQ;AAE/B,eAAW,UAAU,KAAK,SAAS;AACjC,UAAI;AACF,eAAO,KAAK,OAAO;AAAA,MACrB,SAAS,OAAO;AACd,aAAK,OAAO,MAAM,4BAA4B,MAAM,OAAO,EAAE;AAC7D,aAAK,KAAK,MAAM;AAAA,MAClB;AAAA,IACF;AAEA,eAAW,UAAU,MAAM;AACzB,WAAK,oBAAoB,MAAM;AAAA,IACjC;AAGA,QAAI,YAAY,GAAG;AACjB,cAAQ,IAAID,OAAM,KAAK,iCAAuB,SAAS,UAAU,cAAc,IAAI,MAAM,EAAE,EAAE,CAAC;AAAA,IAChG;AAAA,EACF;AAAA,EAEA,oBAAoB,QAAQ;AAC1B,SAAK,QAAQ,IAAI,MAAM;AACvB,UAAM,UAAU,iBAAiB,OAAO,MAAM,UAAU,YAAY,CAAC;AACrE,SAAK,OAAO;AAAA,MACV;AAAA,MACA,yBAAyB,KAAK,QAAQ,IAAI,aAAa,OAAO;AAAA,MAC9D;AAAA,IACF;AAEA,UAAM,QAAQ,KAAK,mBACf,KAAK,iBAAiB,IACrB,KAAK,UAAU,KAAK,QAAQ,gBAAgB,IAAI,CAAC;AACtD,UAAM,OAAO;AAAA,MACX;AAAA,MACA,QAAQ,KAAK,UAAU;AAAA,IACzB;AACA,SAAK,kBAAkB,QAAQ,IAAI;AAAA,EACrC;AAAA,EAEA,oBAAoB,QAAQ;AAC1B,QAAI,CAAC,KAAK,QAAQ,IAAI,MAAM,EAAG;AAC/B,SAAK,QAAQ,OAAO,MAAM;AAC1B,SAAK,OAAO;AAAA,MACV;AAAA,MACA,4BAA4B,KAAK,QAAQ,IAAI;AAAA,MAC7C;AAAA,IACF;AACA,SAAK,qBAAqB,MAAM;AAAA,EAClC;AAAA,EAEA,qBAAqB;AACnB,WAAO;AAAA,MACL,MAAM,CAAC,WAAW;AAChB,cAAMC,QAAO,OAAO,MAAM,QAAQ;AAElC,YAAI,KAAK,WAAWA,MAAK,WAAW,KAAK,QAAQ,OAAO,GAAG,GAAG;AAC5D,gBAAM,gBAAgB,cAAc,QAAQA,OAAM,KAAK,SAAS,KAAK,QAAQ,KAAK,SAAS,EAAE;AAE7F,iBAAO,KAAK,gBAAgB;AAC5B;AAAA,QACF;AAEA,aAAK,oBAAoB,MAAM;AAAA,MACjC;AAAA,MAEA,SAAS,CAAC,QAAQ,YAAY;AAC5B,YAAI,OAAO,MAAM,SAAS;AACxB,iBAAO,KAAK,eAAe,UAAU,OAAO;AAC5C;AAAA,QACF;AAEA,aAAK,OAAO,MAAM,yBAAyB,OAAO,EAAE;AAAA,MACtD;AAAA,MAEA,OAAO,CAAC,WAAW;AACjB,YAAI,OAAO,MAAM,SAAS;AACxB,iBAAO,KAAK,eAAe,QAAQ;AACnC;AAAA,QACF;AAEA,aAAK,oBAAoB,MAAM;AAAA,MACjC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,QAAQ;AAEZ,QAAI,KAAK,YAAY;AACnB,YAAM,aAAa,IAAI,KAAK,KAAK,UAAU;AAC3C,UAAI,CAAE,MAAM,WAAW,OAAO,GAAI;AAChC,aAAK,eAAe;AAAA,MACtB;AAAA,IACF;AAGA,QAAI,YAAY;AAChB,QAAI,KAAK,KAAK;AACZ,UAAI;AACF,oBAAY;AAAA,UACV,KAAK,MAAM,IAAI,KAAK,KAAK,IAAI,GAAG,EAAE,KAAK;AAAA,UACvC,MAAM,MAAM,IAAI,KAAK,KAAK,IAAI,IAAI,EAAE,KAAK;AAAA,QAC3C;AAEA,YAAI,KAAK,IAAI,IAAI;AACf,oBAAU,KAAK,MAAM,IAAI,KAAK,KAAK,IAAI,EAAE,EAAE,KAAK;AAAA,QAClD;AACA,YAAI,KAAK,IAAI,YAAY;AACvB,oBAAU,aAAa,KAAK,IAAI;AAAA,QAClC;AAAA,MACF,SAAS,OAAO;AACd,aAAK,OAAO,MAAM,6BAA6B,MAAM,OAAO,EAAE;AAC9D,cAAM;AAAA,MACR;AAAA,IACF;AAEA,UAAM,eAAe,YAAY,UAAU;AAC3C,UAAM,aAAa,YAAY,QAAQ;AAEvC,SAAK,OAAO,OAAO,cAAc;AAAA,MAC/B,GAAG,KAAK,UAAU;AAAA,MAClB,YAAY,CAAC,EAAE,KAAK,aAAa,KAAK;AAAA,MACtC,WAAW;AAAA,MACX,UAAU;AAAA,MACV;AAAA,IACF,CAAC;AAED,UAAM,KAAK,aAAa;AAExB,UAAM,eAAe;AAAA,MACnB,MAAM,KAAK;AAAA,MACX,UAAU,KAAK;AAAA,MAEf,OAAO,OAAO,KAAK,WAAW;AAC5B,cAAM,MAAM,IAAI,IAAI,IAAI,GAAG;AAC3B,cAAM,YAAY,IAAI,aAAa,KAAK;AACxC,cAAM,gBAAgB,KAAK,WAAW,IAAI,SAAS,WAAW,KAAK,QAAQ,OAAO,GAAG;AAErF,YAAI,aAAa,eAAe;AAC9B,gBAAM,WAAW,OAAO,QAAQ,KAAK;AAAA,YACnC,MAAM;AAAA,cACJ,MAAM,IAAI;AAAA,cACV,SAAS,OAAO,YAAY,IAAI,QAAQ,QAAQ,CAAC;AAAA,YACnD;AAAA,UACF,CAAC;AACD,cAAI,SAAU;AAAA,QAChB;AAEA,cAAM,WAAW,MAAM,aAAa,KAAK,IAAI;AAG7C,cAAM,UAAU,IAAI,QAAQ,SAAS,OAAO;AAC5C,gBAAQ,IAAI,+BAA+B,GAAG;AAC9C,gBAAQ,IAAI,gCAAgC,iCAAiC;AAC7E,gBAAQ,IAAI,gCAAgC,gDAAgD;AAC5F,eAAO,IAAI,SAAS,SAAS,MAAM,EAAE,QAAQ,SAAS,QAAQ,YAAY,SAAS,YAAY,QAAQ,CAAC;AAAA,MAC1G;AAAA,MAEA,WAAW,KAAK,mBAAmB;AAAA,IACrC;AAEA,QAAI,WAAW;AACb,mBAAa,MAAM;AAAA,IACrB;AAEA,SAAK,SAAS,IAAI,MAAM,YAAY;AAEpC,QAAI,KAAK,eAAe;AACtB,YAAM,WAAW,MAAM,KAAK,KAAK,EAAE,KAAK,MAAM,QAAQ,KAAK,CAAC,CAAC;AAC7D,iBAAW,UAAU,KAAK,eAAe;AACvC,gBAAQ,GAAG,QAAQ,QAAQ;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO;AACX,SAAK,OAAO,SAAS;AAErB,QAAI,KAAK,QAAQ;AAEf,WAAK,OAAO,KAAK,IAAI;AAAA,IACvB;AAEA,QAAI,KAAK,SAAS;AAChB,YAAM,KAAK,QAAQ,KAAK;AAAA,IAC1B;AAIA,SAAK,QAAQ,MAAM;AAAA,EACrB;AACF;",
|
|
6
|
+
"names": ["path", "chalk", "chalk", "chalk", "path", "path", "upstream", "client", "chalk", "path"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} FileWatcherOptions
|
|
3
|
+
* @property {string[]} paths - Paths or glob patterns to watch (from project root)
|
|
4
|
+
* @property {string[]} [ignore] - Glob patterns to ignore (from project root)
|
|
5
|
+
* @property {string[]} [extensions] - File extensions to watch
|
|
6
|
+
* @property {import('../shared/logger.js').Logger} logger - Logger instance from HMR server
|
|
7
|
+
* @property {(path: string) => void} [onChange] - Called when file changes
|
|
8
|
+
* @property {(path: string) => void} [onAdd] - Called when file is added
|
|
9
|
+
* @property {(path: string) => void} [onRemove] - Called when file is removed
|
|
10
|
+
* @property {(path: string) => void} [onAddDir] - Called when directory is added
|
|
11
|
+
* @property {(path: string) => void} [onRemoveDir] - Called when directory is removed
|
|
12
|
+
* @property {() => void} [onReady] - Called when watcher is ready
|
|
13
|
+
* @property {boolean} [logFiles=false] - Log watched files during initialization
|
|
14
|
+
*/
|
|
15
|
+
/** File watcher using chokidar with picomatch glob filtering */
|
|
16
|
+
export class FileWatcher {
|
|
17
|
+
constructor(options: any);
|
|
18
|
+
paths: any;
|
|
19
|
+
ignorePatterns: any;
|
|
20
|
+
extensions: any;
|
|
21
|
+
onChange: any;
|
|
22
|
+
onAdd: any;
|
|
23
|
+
onRemove: any;
|
|
24
|
+
onAddDir: any;
|
|
25
|
+
onRemoveDir: any;
|
|
26
|
+
onReady: any;
|
|
27
|
+
logFiles: any;
|
|
28
|
+
logger: any;
|
|
29
|
+
watcher: import("chokidar").FSWatcher;
|
|
30
|
+
/**
|
|
31
|
+
* Incrementally maintained set of watched files.
|
|
32
|
+
* Avoids rescanning chokidar's full watched map on every /files request.
|
|
33
|
+
* @type {Set<string>}
|
|
34
|
+
*/
|
|
35
|
+
_watchedFiles: Set<string>;
|
|
36
|
+
isInitializing: boolean;
|
|
37
|
+
loggedFiles: Set<any>;
|
|
38
|
+
shouldIgnore(filePath: any, stats: any): any;
|
|
39
|
+
normalizePath(filePath: any): string;
|
|
40
|
+
isWatchableFile(filePath: any, extensions: any): any;
|
|
41
|
+
logFile(filePath: any, ignored: any, reason?: string): void;
|
|
42
|
+
getWatchedFiles(): string[];
|
|
43
|
+
logWatchedDirectories(): void;
|
|
44
|
+
start(): Promise<any>;
|
|
45
|
+
stop(): Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
export type FileWatcherOptions = {
|
|
48
|
+
/**
|
|
49
|
+
* - Paths or glob patterns to watch (from project root)
|
|
50
|
+
*/
|
|
51
|
+
paths: string[];
|
|
52
|
+
/**
|
|
53
|
+
* - Glob patterns to ignore (from project root)
|
|
54
|
+
*/
|
|
55
|
+
ignore?: string[];
|
|
56
|
+
/**
|
|
57
|
+
* - File extensions to watch
|
|
58
|
+
*/
|
|
59
|
+
extensions?: string[];
|
|
60
|
+
/**
|
|
61
|
+
* - Logger instance from HMR server
|
|
62
|
+
*/
|
|
63
|
+
logger: import("../shared/logger.js").Logger;
|
|
64
|
+
/**
|
|
65
|
+
* - Called when file changes
|
|
66
|
+
*/
|
|
67
|
+
onChange?: (path: string) => void;
|
|
68
|
+
/**
|
|
69
|
+
* - Called when file is added
|
|
70
|
+
*/
|
|
71
|
+
onAdd?: (path: string) => void;
|
|
72
|
+
/**
|
|
73
|
+
* - Called when file is removed
|
|
74
|
+
*/
|
|
75
|
+
onRemove?: (path: string) => void;
|
|
76
|
+
/**
|
|
77
|
+
* - Called when directory is added
|
|
78
|
+
*/
|
|
79
|
+
onAddDir?: (path: string) => void;
|
|
80
|
+
/**
|
|
81
|
+
* - Called when directory is removed
|
|
82
|
+
*/
|
|
83
|
+
onRemoveDir?: (path: string) => void;
|
|
84
|
+
/**
|
|
85
|
+
* - Called when watcher is ready
|
|
86
|
+
*/
|
|
87
|
+
onReady?: () => void;
|
|
88
|
+
/**
|
|
89
|
+
* - Log watched files during initialization
|
|
90
|
+
*/
|
|
91
|
+
logFiles?: boolean;
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=file-watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-watcher.d.ts","sourceRoot":"","sources":["../../src/server/file-watcher.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;GAaG;AAEH,gEAAgE;AAChE;IACE,0BAyBC;IAxBC,WAAgC;IAChC,oBAA0C;IAC1C,gBAA0C;IAC1C,cAA+C;IAC/C,WAAyC;IACzC,cAA+C;IAC/C,cAA+C;IAC/C,iBAAqD;IACrD,aAA6C;IAC7C,cAAyC;IAEzC,YAA4B;IAC5B,sCAAmB;IAEnB;;;;OAIG;IACH,eAFU,GAAG,CAAC,MAAM,CAAC,CAES;IAG9B,wBAA0B;IAC1B,sBAA4B;IAG9B,6CAuBC;IAED,qCAEC;IAED,qDAGC;IAED,4DAQC;IAED,4BAEC;IAED,8BAiDC;IAED,sBAgGC;IAED,sBAMC;CACF;;;;;WAtPa,MAAM,EAAE;;;;aACR,MAAM,EAAE;;;;iBACR,MAAM,EAAE;;;;YACR,OAAO,qBAAqB,EAAE,MAAM;;;;eACpC,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI;;;;YACtB,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI;;;;eACtB,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI;;;;eACtB,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI;;;;kBACtB,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI;;;;cACtB,MAAM,IAAI;;;;eACV,OAAO"}
|