vite-plugin-asset-manager 0.0.1 → 0.0.2
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 +21 -0
- package/README.md +2 -1
- package/dist/client/assets/index-BSP-y0L4.css +1 -0
- package/dist/client/assets/index-DMq3biEu.js +148 -0
- package/dist/client/index.html +2 -2
- package/dist/index.cjs +53 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +53 -2
- package/dist/index.js.map +1 -1
- package/package.json +20 -18
- package/dist/client/assets/index-BGQcqNrG.js +0 -144
- package/dist/client/assets/index-u18B5UIt.css +0 -1
package/dist/index.js
CHANGED
|
@@ -207,12 +207,57 @@ async function handleGetGroupedAssets(res, scanner, query) {
|
|
|
207
207
|
count: group.assets.filter((a) => (a.duplicatesCount ?? 0) > 0).length
|
|
208
208
|
})).filter((group) => group.count > 0);
|
|
209
209
|
}
|
|
210
|
+
const minSize = query.minSize ? parseInt(query.minSize, 10) : void 0;
|
|
211
|
+
const maxSize = query.maxSize ? parseInt(query.maxSize, 10) : void 0;
|
|
212
|
+
if (minSize !== void 0 || maxSize !== void 0) {
|
|
213
|
+
groups = groups.map((group) => ({
|
|
214
|
+
...group,
|
|
215
|
+
assets: group.assets.filter((a) => {
|
|
216
|
+
if (minSize !== void 0 && a.size < minSize) return false;
|
|
217
|
+
if (maxSize !== void 0 && a.size > maxSize) return false;
|
|
218
|
+
return true;
|
|
219
|
+
})
|
|
220
|
+
})).map((g) => ({ ...g, count: g.assets.length })).filter((g) => g.count > 0);
|
|
221
|
+
}
|
|
222
|
+
const minDate = query.minDate ? parseInt(query.minDate, 10) : void 0;
|
|
223
|
+
const maxDate = query.maxDate ? parseInt(query.maxDate, 10) : void 0;
|
|
224
|
+
if (minDate !== void 0 || maxDate !== void 0) {
|
|
225
|
+
groups = groups.map((group) => ({
|
|
226
|
+
...group,
|
|
227
|
+
assets: group.assets.filter((a) => {
|
|
228
|
+
if (minDate !== void 0 && a.mtime < minDate) return false;
|
|
229
|
+
if (maxDate !== void 0 && a.mtime > maxDate) return false;
|
|
230
|
+
return true;
|
|
231
|
+
})
|
|
232
|
+
})).map((g) => ({ ...g, count: g.assets.length })).filter((g) => g.count > 0);
|
|
233
|
+
}
|
|
234
|
+
const extensions = query.extensions;
|
|
235
|
+
if (extensions) {
|
|
236
|
+
const extList = extensions.split(",").map((e) => e.trim().toLowerCase());
|
|
237
|
+
groups = groups.map((group) => ({
|
|
238
|
+
...group,
|
|
239
|
+
assets: group.assets.filter((a) => extList.includes(a.extension.toLowerCase()))
|
|
240
|
+
})).map((g) => ({ ...g, count: g.assets.length })).filter((g) => g.count > 0);
|
|
241
|
+
}
|
|
210
242
|
const total = groups.reduce((sum, g) => sum + g.count, 0);
|
|
211
243
|
sendJson(res, { groups, total });
|
|
212
244
|
}
|
|
213
245
|
async function handleSearch(res, scanner, query) {
|
|
214
246
|
const q = query.q || "";
|
|
215
|
-
|
|
247
|
+
let results = scanner.search(q);
|
|
248
|
+
const minSize = query.minSize ? parseInt(query.minSize, 10) : void 0;
|
|
249
|
+
const maxSize = query.maxSize ? parseInt(query.maxSize, 10) : void 0;
|
|
250
|
+
const minDate = query.minDate ? parseInt(query.minDate, 10) : void 0;
|
|
251
|
+
const maxDate = query.maxDate ? parseInt(query.maxDate, 10) : void 0;
|
|
252
|
+
const extensions = query.extensions;
|
|
253
|
+
if (minSize !== void 0) results = results.filter((a) => a.size >= minSize);
|
|
254
|
+
if (maxSize !== void 0) results = results.filter((a) => a.size <= maxSize);
|
|
255
|
+
if (minDate !== void 0) results = results.filter((a) => a.mtime >= minDate);
|
|
256
|
+
if (maxDate !== void 0) results = results.filter((a) => a.mtime <= maxDate);
|
|
257
|
+
if (extensions) {
|
|
258
|
+
const extList = extensions.split(",").map((e) => e.trim().toLowerCase());
|
|
259
|
+
results = results.filter((a) => extList.includes(a.extension.toLowerCase()));
|
|
260
|
+
}
|
|
216
261
|
sendJson(res, { assets: results, total: results.length, query: q });
|
|
217
262
|
}
|
|
218
263
|
async function handleThumbnail(res, thumbnailService, root, query) {
|
|
@@ -273,6 +318,11 @@ async function handleServeFile(res, root, query) {
|
|
|
273
318
|
async function handleGetStats(res, scanner, duplicateScanner) {
|
|
274
319
|
const assets = scanner.getAssets();
|
|
275
320
|
const dupStats = duplicateScanner.getStats();
|
|
321
|
+
const extensionCounts = /* @__PURE__ */ new Map();
|
|
322
|
+
for (const asset of assets) {
|
|
323
|
+
const ext = asset.extension.toLowerCase();
|
|
324
|
+
extensionCounts.set(ext, (extensionCounts.get(ext) || 0) + 1);
|
|
325
|
+
}
|
|
276
326
|
const stats = {
|
|
277
327
|
total: assets.length,
|
|
278
328
|
byType: {
|
|
@@ -289,7 +339,8 @@ async function handleGetStats(res, scanner, duplicateScanner) {
|
|
|
289
339
|
directories: [...new Set(assets.map((a) => a.directory))].length,
|
|
290
340
|
unused: assets.filter((a) => a.importersCount === 0).length,
|
|
291
341
|
duplicateGroups: dupStats.duplicateGroups,
|
|
292
|
-
duplicateFiles: dupStats.duplicateFiles
|
|
342
|
+
duplicateFiles: dupStats.duplicateFiles,
|
|
343
|
+
extensionBreakdown: Object.fromEntries(extensionCounts)
|
|
293
344
|
};
|
|
294
345
|
sendJson(res, stats);
|
|
295
346
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugin.ts","../src/server/index.ts","../src/server/api.ts","../src/server/editor-launcher.ts","../src/server/file-revealer.ts","../src/server/scanner.ts","../src/server/importer-scanner.ts","../src/server/duplicate-scanner.ts","../src/server/thumbnail.ts","../src/shared/types.ts","../src/index.ts"],"sourcesContent":["import type { Plugin, ViteDevServer, ResolvedConfig, IndexHtmlTransformResult } from 'vite'\nimport colors from 'picocolors'\nimport { setupMiddleware } from './server/index.js'\nimport { AssetScanner } from './server/scanner.js'\nimport { ImporterScanner } from './server/importer-scanner.js'\nimport { DuplicateScanner } from './server/duplicate-scanner.js'\nimport { ThumbnailService } from './server/thumbnail.js'\nimport { broadcastSSE } from './server/api.js'\nimport { resolveOptions, type AssetManagerOptions } from './shared/types.js'\n\nconst FLOATING_ICON_SCRIPT = (base: string) => `\n<script type=\"module\">\n(function() {\n const BASE_URL = '${base}';\n const STORAGE_KEY = 'vite-asset-manager-open';\n\n // Styles for the floating button and overlay\n const styles = document.createElement('style');\n styles.textContent = \\`\n #vam-trigger {\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 48px;\n height: 48px;\n border-radius: 14px;\n background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 24px -4px rgba(139, 92, 246, 0.5), 0 0 0 1px rgba(255,255,255,0.1) inset;\n transition: all 0.2s ease;\n z-index: 99998;\n }\n #vam-trigger:hover {\n transform: translateY(-2px) scale(1.05);\n box-shadow: 0 8px 32px -4px rgba(139, 92, 246, 0.6), 0 0 0 1px rgba(255,255,255,0.15) inset;\n }\n #vam-trigger:active {\n transform: translateY(0) scale(0.98);\n }\n #vam-trigger svg {\n width: 24px;\n height: 24px;\n color: white;\n }\n #vam-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.6);\n backdrop-filter: blur(4px);\n z-index: 99999;\n opacity: 0;\n visibility: hidden;\n transition: opacity 0.3s ease, visibility 0.3s ease;\n }\n #vam-overlay.open {\n opacity: 1;\n visibility: visible;\n }\n #vam-panel {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: min(90vw, 1200px);\n background: #09090b;\n border-left: 1px solid rgba(255,255,255,0.08);\n transform: translateX(100%);\n transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1);\n z-index: 100000;\n display: flex;\n flex-direction: column;\n }\n #vam-overlay.open #vam-panel {\n transform: translateX(0);\n }\n #vam-panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid rgba(255,255,255,0.08);\n background: #0f0f11;\n }\n #vam-panel-title {\n font-family: 'JetBrains Mono', ui-monospace, monospace;\n font-size: 12px;\n font-weight: 600;\n color: #fafafa;\n letter-spacing: 0.05em;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n #vam-panel-title svg {\n width: 18px;\n height: 18px;\n color: #8b5cf6;\n }\n #vam-close-btn {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #71717a;\n transition: all 0.15s ease;\n }\n #vam-close-btn:hover {\n background: rgba(255,255,255,0.1);\n color: #fafafa;\n }\n #vam-iframe {\n flex: 1;\n border: none;\n width: 100%;\n height: 100%;\n }\n \\`;\n document.head.appendChild(styles);\n\n // Create trigger button\n const trigger = document.createElement('button');\n trigger.id = 'vam-trigger';\n trigger.title = 'Open Asset Manager (⌥⇧A)';\n trigger.innerHTML = \\`\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\">\n <path d=\"M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40Zm0,16V88H40V56Zm0,144H40V104H216v96ZM64,128a8,8,0,0,1,8-8h80a8,8,0,0,1,0,16H72A8,8,0,0,1,64,128Zm0,32a8,8,0,0,1,8-8h80a8,8,0,0,1,0,16H72A8,8,0,0,1,64,160Z\"/>\n </svg>\n \\`;\n\n // Create overlay and panel\n const overlay = document.createElement('div');\n overlay.id = 'vam-overlay';\n overlay.innerHTML = \\`\n <div id=\"vam-panel\">\n <div id=\"vam-panel-header\">\n <div id=\"vam-panel-title\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\">\n <path d=\"M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40Zm0,160H40V56H216V200ZM176,88a48,48,0,1,0-96,0,48,48,0,0,0,96,0Zm-48,32a32,32,0,1,1,32-32A32,32,0,0,1,128,120Zm80,56a8,8,0,0,1-8,8H56a8,8,0,0,1-6.65-12.44l24-36a8,8,0,0,1,13.3,0l15.18,22.77,24.89-41.48a8,8,0,0,1,13.72.18l40,64A8,8,0,0,1,208,176Z\"/>\n </svg>\n ASSET MANAGER\n </div>\n <button id=\"vam-close-btn\" title=\"Close (Esc)\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 256 256\" fill=\"currentColor\">\n <path d=\"M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z\"/>\n </svg>\n </button>\n </div>\n <iframe id=\"vam-iframe\" src=\"\\${BASE_URL}?embedded=true\"></iframe>\n </div>\n \\`;\n\n document.body.appendChild(trigger);\n document.body.appendChild(overlay);\n\n // State management\n let isOpen = sessionStorage.getItem(STORAGE_KEY) === 'true';\n\n function open() {\n isOpen = true;\n overlay.classList.add('open');\n sessionStorage.setItem(STORAGE_KEY, 'true');\n }\n\n function close() {\n isOpen = false;\n overlay.classList.remove('open');\n sessionStorage.setItem(STORAGE_KEY, 'false');\n }\n\n // Restore state\n if (isOpen) {\n requestAnimationFrame(() => open());\n }\n\n // Event listeners\n trigger.addEventListener('click', () => {\n if (isOpen) close();\n else open();\n });\n\n overlay.addEventListener('click', (e) => {\n if (e.target === overlay) close();\n });\n\n document.getElementById('vam-close-btn').addEventListener('click', close);\n\n document.addEventListener('keydown', (e) => {\n // Close on Escape\n if (e.key === 'Escape' && isOpen) {\n close();\n }\n // Toggle on Option/Alt + Shift + A\n if (e.altKey && e.shiftKey && e.code === 'KeyA') {\n e.preventDefault();\n if (isOpen) close();\n else open();\n }\n });\n})();\n</script>\n`\n\nexport function createAssetManagerPlugin(options: AssetManagerOptions = {}): Plugin {\n let config: ResolvedConfig\n let scanner: AssetScanner\n let importerScanner: ImporterScanner\n let duplicateScanner: DuplicateScanner\n let thumbnailService: ThumbnailService\n\n const resolvedOptions = resolveOptions(options)\n\n return {\n name: 'vite-plugin-asset-manager',\n apply: 'serve',\n\n configResolved(resolvedConfig) {\n config = resolvedConfig\n },\n\n configureServer(server: ViteDevServer) {\n scanner = new AssetScanner(config.root, resolvedOptions)\n importerScanner = new ImporterScanner(config.root, resolvedOptions)\n duplicateScanner = new DuplicateScanner(config.root, resolvedOptions)\n thumbnailService = new ThumbnailService(resolvedOptions.thumbnailSize)\n\n setupMiddleware(server, {\n base: resolvedOptions.base,\n scanner,\n importerScanner,\n duplicateScanner,\n thumbnailService,\n root: config.root,\n launchEditor: resolvedOptions.launchEditor\n })\n\n scanner.init().then(async () => {\n await importerScanner.init()\n scanner.enrichWithImporterCounts(importerScanner)\n\n await duplicateScanner.init()\n await duplicateScanner.scanAssets(scanner.getAssets())\n scanner.enrichWithDuplicateInfo(duplicateScanner)\n\n if (resolvedOptions.watch) {\n duplicateScanner.initWatcher()\n }\n })\n\n const _printUrls = server.printUrls\n server.printUrls = () => {\n _printUrls()\n\n const colorUrl = (url: string) =>\n colors.cyan(url.replace(/:(\\d+)\\//, (_, port) => `:${colors.bold(port)}/`))\n\n let host = `${server.config.server.https ? 'https' : 'http'}://localhost:${server.config.server.port || '80'}`\n const url = server.resolvedUrls?.local[0]\n if (url) {\n try {\n const u = new URL(url)\n host = `${u.protocol}//${u.host}`\n } catch {}\n }\n\n const base = server.config.base || '/'\n const fullUrl = `${host}${base}${resolvedOptions.base.replace(/^\\//, '')}/`\n\n server.config.logger.info(\n ` ${colors.magenta('➜')} ${colors.bold('Asset Manager')}: Open ${colorUrl(fullUrl)} as a separate window`\n )\n server.config.logger.info(\n ` ${colors.magenta('➜')} ${colors.bold('Asset Manager')}: Press ${colors.yellow('Option(⌥)+Shift(⇧)+A')} in App to toggle the Asset Manager`\n )\n }\n\n if (resolvedOptions.watch) {\n scanner.on('change', async event => {\n await duplicateScanner.scanAssets(scanner.getAssets())\n scanner.enrichWithDuplicateInfo(duplicateScanner)\n broadcastSSE('asset-manager:update', event)\n })\n importerScanner.on('change', event => {\n scanner.enrichWithImporterCounts(importerScanner)\n broadcastSSE('asset-manager:importers-update', event)\n })\n duplicateScanner.on('change', event => {\n scanner.enrichWithDuplicateInfo(duplicateScanner)\n broadcastSSE('asset-manager:duplicates-update', event)\n })\n }\n },\n\n transformIndexHtml(): IndexHtmlTransformResult {\n if (!resolvedOptions.floatingIcon) {\n return []\n }\n\n return [\n {\n tag: 'script',\n attrs: { type: 'module' },\n children: FLOATING_ICON_SCRIPT(resolvedOptions.base)\n .replace(/<\\/?script[^>]*>/g, '')\n .trim(),\n injectTo: 'body'\n }\n ]\n },\n\n resolveId(id) {\n if (id === 'virtual:asset-manager-config') {\n return '\\0virtual:asset-manager-config'\n }\n },\n\n load(id) {\n if (id === '\\0virtual:asset-manager-config') {\n return `export default ${JSON.stringify({\n base: resolvedOptions.base,\n extensions: resolvedOptions.extensions\n })}`\n }\n },\n\n buildEnd() {\n scanner?.destroy()\n importerScanner?.destroy()\n duplicateScanner?.destroy()\n }\n }\n}\n","import type { ViteDevServer } from 'vite'\nimport sirv from 'sirv'\nimport path from 'path'\nimport fs from 'fs'\nimport { fileURLToPath } from 'url'\nimport { createApiRouter } from './api.js'\nimport type { AssetScanner } from './scanner.js'\nimport type { ImporterScanner } from './importer-scanner.js'\nimport type { DuplicateScanner } from './duplicate-scanner.js'\nimport type { ThumbnailService } from './thumbnail.js'\nimport type { EditorType } from '../shared/types.js'\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\n\nfunction findClientDir(): string {\n // When running from built dist: __dirname is dist/, client is at dist/client\n const fromDist = path.join(__dirname, 'client')\n if (fs.existsSync(fromDist)) {\n return fromDist\n }\n\n // When running from source (e.g., playground): __dirname is src/server, client is at dist/client\n const fromSource = path.resolve(__dirname, '../../dist/client')\n if (fs.existsSync(fromSource)) {\n return fromSource\n }\n\n // Fallback - will show error if client not built\n return fromDist\n}\n\nexport interface MiddlewareContext {\n base: string\n scanner: AssetScanner\n importerScanner: ImporterScanner\n duplicateScanner: DuplicateScanner\n thumbnailService: ThumbnailService\n root: string\n launchEditor: EditorType\n}\n\nexport function setupMiddleware(server: ViteDevServer, context: MiddlewareContext): void {\n const { base, scanner, importerScanner, duplicateScanner, thumbnailService, root, launchEditor } =\n context\n\n const apiRouter = createApiRouter(\n scanner,\n importerScanner,\n duplicateScanner,\n thumbnailService,\n root,\n base,\n launchEditor\n )\n\n const clientDir = findClientDir()\n\n server.middlewares.use((req, res, next) => {\n const url = req.url || ''\n\n if (url.startsWith(`${base}/api/`)) {\n return apiRouter(req, res, next)\n }\n\n if (url === base || url.startsWith(`${base}/`)) {\n const serve = sirv(clientDir, {\n single: true,\n dev: true\n })\n\n req.url = url.slice(base.length) || '/'\n return serve(req, res, next)\n }\n\n next()\n })\n}\n","import type { IncomingMessage, ServerResponse } from 'http'\nimport { parse as parseUrl } from 'url'\nimport path from 'path'\nimport fs from 'fs'\nimport archiver from 'archiver'\nimport type { AssetScanner } from './scanner.js'\nimport type { ImporterScanner } from './importer-scanner.js'\nimport type { DuplicateScanner } from './duplicate-scanner.js'\nimport type { ThumbnailService } from './thumbnail.js'\nimport { launchEditor } from './editor-launcher.js'\nimport { revealInFileExplorer } from './file-revealer.js'\nimport type { AssetStats, AssetType, EditorType } from '../shared/types.js'\n\ntype NextFunction = () => void\n\nconst sseClients = new Set<ServerResponse>()\n\nconst MIME_TYPES: Record<string, string> = {\n /**\n * Images:\n */\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.ico': 'image/x-icon',\n '.bmp': 'image/bmp',\n '.tiff': 'image/tiff',\n '.tif': 'image/tiff',\n '.heic': 'image/heic',\n '.heif': 'image/heif',\n /**\n * Videos:\n */\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.ogg': 'video/ogg',\n '.mov': 'video/quicktime',\n /**\n * Audio:\n */\n '.mp3': 'audio/mpeg',\n '.wav': 'audio/wav',\n /**\n * Documents:\n */\n '.pdf': 'application/pdf',\n '.json': 'application/json',\n '.md': 'text/markdown',\n '.txt': 'text/plain',\n '.csv': 'text/csv',\n /**\n * Config files:\n */\n '.yml': 'text/yaml',\n '.yaml': 'text/yaml',\n '.toml': 'application/toml',\n '.xml': 'application/xml',\n /**\n * Fonts:\n */\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.otf': 'font/otf',\n '.eot': 'application/vnd.ms-fontobject'\n}\n\nexport function createApiRouter(\n scanner: AssetScanner,\n importerScanner: ImporterScanner,\n duplicateScanner: DuplicateScanner,\n thumbnailService: ThumbnailService,\n root: string,\n basePath: string,\n editor: EditorType\n) {\n return async (req: IncomingMessage, res: ServerResponse, next: NextFunction) => {\n const { pathname, query } = parseUrl(req.url || '', true)\n const apiPath = pathname?.replace(`${basePath}/api`, '') || ''\n\n try {\n switch (apiPath) {\n case '/assets':\n return handleGetAssets(res, scanner, query)\n case '/assets/grouped':\n return handleGetGroupedAssets(res, scanner, query)\n case '/search':\n return handleSearch(res, scanner, query)\n case '/thumbnail':\n return handleThumbnail(res, thumbnailService, root, query)\n case '/file':\n return handleServeFile(res, root, query)\n case '/stats':\n return handleGetStats(res, scanner, duplicateScanner)\n case '/duplicates':\n return handleGetDuplicates(res, scanner, duplicateScanner, query)\n case '/importers':\n return handleGetImporters(res, importerScanner, query)\n case '/open-in-editor':\n return handleOpenInEditor(req, res, root, editor, query)\n case '/reveal-in-finder':\n return handleRevealInFinder(req, res, root, query)\n case '/bulk-download':\n return handleBulkDownload(req, res, root)\n case '/bulk-delete':\n return handleBulkDelete(req, res, root)\n case '/events':\n return handleSSE(res)\n default:\n next()\n }\n } catch (error) {\n console.error('[asset-manager] API error:', error)\n res.statusCode = 500\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify({ error: 'Internal server error' }))\n }\n }\n}\n\nasync function handleGetAssets(\n res: ServerResponse,\n scanner: AssetScanner,\n query: Record<string, any>\n) {\n const assets = scanner.getAssets()\n\n let filtered = assets\n\n const directory = query.directory as string | undefined\n if (directory) {\n filtered = filtered.filter(\n a => a.directory === directory || a.directory.startsWith(directory + '/')\n )\n }\n\n const type = query.type as AssetType | undefined\n if (type) {\n filtered = filtered.filter(a => a.type === type)\n }\n\n sendJson(res, { assets: filtered, total: filtered.length })\n}\n\nasync function handleGetGroupedAssets(\n res: ServerResponse,\n scanner: AssetScanner,\n query: Record<string, any>\n) {\n let groups = scanner.getGroupedAssets()\n\n const type = query.type as AssetType | undefined\n if (type) {\n groups = groups\n .map(group => ({\n ...group,\n assets: group.assets.filter(a => a.type === type),\n count: group.assets.filter(a => a.type === type).length\n }))\n .filter(group => group.count > 0)\n }\n\n const unused = query.unused === 'true'\n if (unused) {\n groups = groups\n .map(group => ({\n ...group,\n assets: group.assets.filter(a => a.importersCount === 0),\n count: group.assets.filter(a => a.importersCount === 0).length\n }))\n .filter(group => group.count > 0)\n }\n\n const duplicates = query.duplicates === 'true'\n if (duplicates) {\n groups = groups\n .map(group => ({\n ...group,\n assets: group.assets.filter(a => (a.duplicatesCount ?? 0) > 0),\n count: group.assets.filter(a => (a.duplicatesCount ?? 0) > 0).length\n }))\n .filter(group => group.count > 0)\n }\n\n const total = groups.reduce((sum, g) => sum + g.count, 0)\n sendJson(res, { groups, total })\n}\n\nasync function handleSearch(\n res: ServerResponse,\n scanner: AssetScanner,\n query: Record<string, any>\n) {\n const q = (query.q as string) || ''\n const results = scanner.search(q)\n sendJson(res, { assets: results, total: results.length, query: q })\n}\n\nasync function handleThumbnail(\n res: ServerResponse,\n thumbnailService: ThumbnailService,\n root: string,\n query: Record<string, any>\n) {\n const relativePath = query.path as string\n if (!relativePath) {\n res.statusCode = 400\n res.end('Missing path parameter')\n return\n }\n\n const absolutePath = path.resolve(root, relativePath)\n\n if (!absolutePath.startsWith(root)) {\n res.statusCode = 403\n res.end('Forbidden')\n return\n }\n\n if (relativePath.endsWith('.svg')) {\n res.setHeader('Content-Type', 'image/svg+xml')\n res.setHeader('Cache-Control', 'public, max-age=31536000')\n fs.createReadStream(absolutePath).pipe(res)\n return\n }\n\n const thumbnail = await thumbnailService.getThumbnail(absolutePath)\n\n if (thumbnail) {\n res.setHeader('Content-Type', 'image/jpeg')\n res.setHeader('Cache-Control', 'public, max-age=31536000')\n res.end(thumbnail)\n } else {\n const ext = path.extname(relativePath).toLowerCase()\n res.setHeader('Content-Type', MIME_TYPES[ext] || 'application/octet-stream')\n fs.createReadStream(absolutePath).pipe(res)\n }\n}\n\nasync function handleServeFile(res: ServerResponse, root: string, query: Record<string, any>) {\n const relativePath = query.path as string\n if (!relativePath) {\n res.statusCode = 400\n res.end('Missing path parameter')\n return\n }\n\n const absolutePath = path.resolve(root, relativePath)\n\n if (!absolutePath.startsWith(root)) {\n res.statusCode = 403\n res.end('Forbidden')\n return\n }\n\n try {\n await fs.promises.access(absolutePath, fs.constants.R_OK)\n } catch {\n res.statusCode = 404\n res.end('File not found')\n return\n }\n\n const ext = path.extname(relativePath).toLowerCase()\n res.setHeader('Content-Type', MIME_TYPES[ext] || 'application/octet-stream')\n res.setHeader('Cache-Control', 'public, max-age=3600')\n fs.createReadStream(absolutePath).pipe(res)\n}\n\nasync function handleGetStats(\n res: ServerResponse,\n scanner: AssetScanner,\n duplicateScanner: DuplicateScanner\n) {\n const assets = scanner.getAssets()\n const dupStats = duplicateScanner.getStats()\n\n const stats: AssetStats = {\n total: assets.length,\n byType: {\n image: assets.filter(a => a.type === 'image').length,\n video: assets.filter(a => a.type === 'video').length,\n audio: assets.filter(a => a.type === 'audio').length,\n document: assets.filter(a => a.type === 'document').length,\n font: assets.filter(a => a.type === 'font').length,\n data: assets.filter(a => a.type === 'data').length,\n text: assets.filter(a => a.type === 'text').length,\n other: assets.filter(a => a.type === 'other').length\n },\n totalSize: assets.reduce((sum, a) => sum + a.size, 0),\n directories: [...new Set(assets.map(a => a.directory))].length,\n unused: assets.filter(a => a.importersCount === 0).length,\n duplicateGroups: dupStats.duplicateGroups,\n duplicateFiles: dupStats.duplicateFiles\n }\n\n sendJson(res, stats)\n}\n\nasync function handleGetDuplicates(\n res: ServerResponse,\n scanner: AssetScanner,\n duplicateScanner: DuplicateScanner,\n query: Record<string, any>\n) {\n const hash = query.hash as string\n\n if (hash) {\n // Get specific duplicate group by hash\n const paths = duplicateScanner.getDuplicatesByHash(hash)\n const assets = scanner.getAssets().filter(a => paths.includes(a.path))\n sendJson(res, { duplicates: assets, total: assets.length, hash })\n } else {\n // Get all assets that have duplicates\n const assets = scanner.getAssets().filter(a => (a.duplicatesCount ?? 0) > 0)\n sendJson(res, { duplicates: assets, total: assets.length })\n }\n}\n\nfunction sendJson(res: ServerResponse, data: unknown) {\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(data))\n}\n\nfunction handleSSE(res: ServerResponse) {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n 'Access-Control-Allow-Origin': '*'\n })\n\n res.write(`data: ${JSON.stringify({ type: 'connected' })}\\n\\n`)\n\n sseClients.add(res)\n\n res.on('close', () => {\n sseClients.delete(res)\n })\n}\n\nexport function broadcastSSE(event: string, data: unknown) {\n const message = JSON.stringify({ event, data })\n for (const client of sseClients) {\n client.write(`data: ${message}\\n\\n`)\n }\n}\n\nasync function handleGetImporters(\n res: ServerResponse,\n importerScanner: ImporterScanner,\n query: Record<string, any>\n) {\n const assetPath = query.path as string\n if (!assetPath) {\n res.statusCode = 400\n sendJson(res, { error: 'Missing path parameter' })\n return\n }\n\n const importers = importerScanner.getImporters(assetPath)\n sendJson(res, { importers, total: importers.length })\n}\n\nasync function handleOpenInEditor(\n req: IncomingMessage,\n res: ServerResponse,\n root: string,\n editor: EditorType,\n query: Record<string, any>\n) {\n if (req.method !== 'POST') {\n res.statusCode = 405\n sendJson(res, { error: 'Method not allowed' })\n return\n }\n\n const filePath = query.file as string\n const line = parseInt(query.line as string) || 1\n const column = parseInt(query.column as string) || 1\n\n if (!filePath) {\n res.statusCode = 400\n sendJson(res, { error: 'Missing file parameter' })\n return\n }\n\n const absolutePath = path.resolve(root, filePath)\n\n if (!absolutePath.startsWith(root)) {\n res.statusCode = 403\n sendJson(res, { error: 'Forbidden' })\n return\n }\n\n try {\n await fs.promises.access(absolutePath, fs.constants.R_OK)\n } catch {\n res.statusCode = 404\n sendJson(res, { error: 'File not found' })\n return\n }\n\n try {\n await launchEditor(absolutePath, line, column, editor)\n sendJson(res, { success: true })\n } catch (error) {\n res.statusCode = 500\n sendJson(res, { error: error instanceof Error ? error.message : 'Failed to open editor' })\n }\n}\n\nasync function handleRevealInFinder(\n req: IncomingMessage,\n res: ServerResponse,\n root: string,\n query: Record<string, any>\n) {\n if (req.method !== 'POST') {\n res.statusCode = 405\n sendJson(res, { error: 'Method not allowed' })\n return\n }\n\n const filePath = query.path as string\n\n if (!filePath) {\n res.statusCode = 400\n sendJson(res, { error: 'Missing path parameter' })\n return\n }\n\n const absolutePath = path.resolve(root, filePath)\n\n // Security: validate path is within project root\n if (!absolutePath.startsWith(root)) {\n res.statusCode = 403\n sendJson(res, { error: 'Invalid path' })\n return\n }\n\n // Check if file exists\n try {\n await fs.promises.access(absolutePath, fs.constants.R_OK)\n } catch {\n res.statusCode = 404\n sendJson(res, { error: 'File not found' })\n return\n }\n\n try {\n await revealInFileExplorer(absolutePath)\n sendJson(res, { success: true })\n } catch (error) {\n res.statusCode = 500\n sendJson(res, {\n error: error instanceof Error ? error.message : 'Failed to reveal file'\n })\n }\n}\n\nasync function parseJsonBody(req: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let body = ''\n req.on('data', (chunk: Buffer) => {\n body += chunk.toString()\n })\n req.on('end', () => {\n try {\n resolve(JSON.parse(body))\n } catch {\n reject(new Error('Invalid JSON'))\n }\n })\n req.on('error', reject)\n })\n}\n\nasync function handleBulkDownload(req: IncomingMessage, res: ServerResponse, root: string) {\n if (req.method !== 'POST') {\n res.statusCode = 405\n sendJson(res, { error: 'Method not allowed' })\n return\n }\n\n let body: { paths?: string[] }\n try {\n body = (await parseJsonBody(req)) as { paths?: string[] }\n } catch {\n res.statusCode = 400\n sendJson(res, { error: 'Invalid JSON body' })\n return\n }\n\n const paths = body.paths\n if (!Array.isArray(paths) || paths.length === 0) {\n res.statusCode = 400\n sendJson(res, { error: 'Missing or invalid paths array' })\n return\n }\n\n const validatedPaths: { relativePath: string; absolutePath: string }[] = []\n\n for (const relativePath of paths) {\n const absolutePath = path.resolve(root, relativePath)\n\n if (!absolutePath.startsWith(root)) {\n res.statusCode = 403\n sendJson(res, { error: `Forbidden path: ${relativePath}` })\n return\n }\n\n try {\n await fs.promises.access(absolutePath, fs.constants.R_OK)\n validatedPaths.push({ relativePath, absolutePath })\n } catch {\n console.warn(`[asset-manager] Bulk download skipping missing file: ${relativePath}`)\n }\n }\n\n if (validatedPaths.length === 0) {\n res.statusCode = 404\n sendJson(res, { error: 'No valid files found' })\n return\n }\n\n res.setHeader('Content-Type', 'application/zip')\n res.setHeader('Content-Disposition', `attachment; filename=\"assets-${Date.now()}.zip\"`)\n\n const archive = archiver('zip', { zlib: { level: 6 } })\n\n archive.on('error', err => {\n console.error('[asset-manager] ZIP creation error:', err)\n if (!res.headersSent) {\n res.statusCode = 500\n res.end('ZIP creation failed')\n }\n })\n\n archive.pipe(res)\n\n for (const { relativePath, absolutePath } of validatedPaths) {\n archive.file(absolutePath, { name: relativePath })\n }\n\n await archive.finalize()\n}\n\nasync function handleBulkDelete(req: IncomingMessage, res: ServerResponse, root: string) {\n if (req.method !== 'POST') {\n res.statusCode = 405\n sendJson(res, { error: 'Method not allowed' })\n return\n }\n\n let body: { paths?: string[] }\n try {\n body = (await parseJsonBody(req)) as { paths?: string[] }\n } catch {\n res.statusCode = 400\n sendJson(res, { error: 'Invalid JSON body' })\n return\n }\n\n const paths = body.paths\n if (!Array.isArray(paths) || paths.length === 0) {\n res.statusCode = 400\n sendJson(res, { error: 'Missing or invalid paths array' })\n return\n }\n\n const results = {\n deleted: 0,\n failed: [] as string[],\n errors: [] as string[]\n }\n\n for (const relativePath of paths) {\n const absolutePath = path.resolve(root, relativePath)\n\n if (!absolutePath.startsWith(root)) {\n results.failed.push(relativePath)\n results.errors.push(`Forbidden path: ${relativePath}`)\n continue\n }\n\n try {\n await fs.promises.unlink(absolutePath)\n results.deleted++\n } catch (error) {\n results.failed.push(relativePath)\n results.errors.push(error instanceof Error ? error.message : 'Unknown error')\n }\n }\n\n sendJson(res, {\n deleted: results.deleted,\n failed: results.failed.length,\n errors: results.errors\n })\n}\n","import launch from 'launch-editor'\nimport type { EditorType } from '../shared/types.js'\n\n/**\n * Opens a file in the configured editor at the specified line and column.\n *\n * @param absolutePath - Absolute path to the file\n * @param line - Line number (1-indexed)\n * @param column - Column number (1-indexed)\n * @param editor - Editor to open the file in\n */\nexport function launchEditor(\n absolutePath: string,\n line: number,\n column: number,\n editor: EditorType\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const fileSpec = `${absolutePath}:${line}:${column}`\n\n launch(fileSpec, editor, (_fileName: string, errorMsg: string | null) => {\n if (errorMsg) {\n reject(new Error(errorMsg))\n } else {\n resolve()\n }\n })\n })\n}\n","import { spawn } from 'child_process'\nimport path from 'path'\n\n/**\n * Opens the file in the system's file explorer and highlights it\n * @param absolutePath Absolute path to the file to reveal\n */\nexport async function revealInFileExplorer(absolutePath: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const platform = process.platform\n\n let command: string\n let args: string[]\n\n switch (platform) {\n case 'darwin': // macOS\n command = 'open'\n args = ['-R', absolutePath]\n break\n\n case 'win32': // Windows\n command = 'explorer'\n args = ['/select,', absolutePath]\n break\n\n case 'linux': {\n // Linux - xdg-open doesn't support file selection, so open the containing directory\n const directory = path.dirname(absolutePath)\n command = 'xdg-open'\n args = [directory]\n break\n }\n\n default:\n return reject(new Error(`Unsupported platform: ${platform}`))\n }\n\n const child = spawn(command, args)\n\n child.on('error', error => {\n reject(new Error(`Failed to reveal file: ${error.message}`))\n })\n\n child.on('close', code => {\n if (code === 0) {\n resolve()\n } else {\n reject(new Error(`Reveal command exited with code ${code}`))\n }\n })\n })\n}\n","import { EventEmitter } from 'events'\nimport fg from 'fast-glob'\nimport path from 'path'\nimport fs from 'fs/promises'\nimport chokidar from 'chokidar'\nimport type { Asset, AssetGroup, AssetType, ResolvedOptions } from '../shared/types.js'\n\nexport interface ScannerEvents {\n change: [{ event: string; path: string }]\n}\n\nexport class AssetScanner extends EventEmitter {\n private root: string\n private options: ResolvedOptions\n private cache: Map<string, Asset> = new Map()\n private watcher?: chokidar.FSWatcher\n private scanPromise?: Promise<void>\n\n constructor(root: string, options: ResolvedOptions) {\n super()\n this.root = root\n this.options = options\n }\n\n async init(): Promise<void> {\n await this.scan()\n if (this.options.watch) {\n this.initWatcher()\n }\n }\n\n async scan(): Promise<Asset[]> {\n if (this.scanPromise) {\n await this.scanPromise\n return this.getAssets()\n }\n\n this.scanPromise = this.performScan()\n await this.scanPromise\n this.scanPromise = undefined\n\n return this.getAssets()\n }\n\n private async performScan(): Promise<void> {\n const extensionPattern = this.options.extensions.map(ext => ext.replace('.', '')).join(',')\n\n const patterns = this.options.include.map(dir => `${dir}/**/*.{${extensionPattern}}`)\n\n const entries = await fg(patterns, {\n cwd: this.root,\n ignore: this.options.exclude.map(p => `**/${p}/**`),\n absolute: false,\n stats: true,\n onlyFiles: true,\n dot: false\n })\n\n this.cache.clear()\n\n for (const entry of entries) {\n const asset = this.createAsset(entry)\n this.cache.set(asset.path, asset)\n }\n }\n\n private createAsset(entry: fg.Entry): Asset {\n const relativePath = entry.path\n const absolutePath = path.join(this.root, relativePath)\n const extension = path.extname(relativePath).toLowerCase()\n const name = path.basename(relativePath)\n const directory = path.dirname(relativePath)\n\n return {\n id: Buffer.from(relativePath).toString('base64url'),\n name,\n path: relativePath,\n absolutePath,\n extension,\n type: this.getAssetType(extension),\n size: entry.stats?.size || 0,\n mtime: entry.stats?.mtimeMs || Date.now(),\n directory: directory === '.' ? '/' : directory\n }\n }\n\n private getAssetType(extension: string): AssetType {\n const imageExts = [\n '.png',\n '.jpg',\n '.jpeg',\n '.gif',\n '.svg',\n '.webp',\n '.avif',\n '.ico',\n '.bmp',\n '.tiff',\n '.tif',\n '.heic',\n '.heif'\n ]\n const videoExts = ['.mp4', '.webm', '.ogg', '.mov', '.avi']\n const audioExts = ['.mp3', '.wav', '.flac', '.aac']\n const docExts = ['.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx']\n const fontExts = ['.woff', '.woff2', '.ttf', '.otf', '.eot']\n const dataExts = ['.json', '.csv', '.xml', '.yml', '.yaml', '.toml']\n const textExts = ['.md', '.txt']\n\n if (imageExts.includes(extension)) return 'image'\n if (videoExts.includes(extension)) return 'video'\n if (audioExts.includes(extension)) return 'audio'\n if (docExts.includes(extension)) return 'document'\n if (fontExts.includes(extension)) return 'font'\n if (dataExts.includes(extension)) return 'data'\n if (textExts.includes(extension)) return 'text'\n return 'other'\n }\n\n getAssets(): Asset[] {\n return Array.from(this.cache.values())\n }\n\n getGroupedAssets(): AssetGroup[] {\n const groups = new Map<string, Asset[]>()\n\n for (const asset of this.cache.values()) {\n const dir = asset.directory\n if (!groups.has(dir)) {\n groups.set(dir, [])\n }\n groups.get(dir)!.push(asset)\n }\n\n return Array.from(groups.entries())\n .map(([directory, assets]) => ({\n directory,\n assets: assets.sort((a, b) => a.name.localeCompare(b.name)),\n count: assets.length\n }))\n .sort((a, b) => a.directory.localeCompare(b.directory))\n }\n\n search(query: string): Asset[] {\n const normalizedQuery = query.toLowerCase().trim()\n if (!normalizedQuery) return this.getAssets()\n\n return this.getAssets().filter(\n asset =>\n asset.name.toLowerCase().includes(normalizedQuery) ||\n asset.path.toLowerCase().includes(normalizedQuery)\n )\n }\n\n getAsset(relativePath: string): Asset | undefined {\n return this.cache.get(relativePath)\n }\n\n /**\n * Enrich assets with importer count metadata.\n * Should be called after scanning completes and when importers change.\n */\n enrichWithImporterCounts(importerScanner: { getImporters: (assetPath: string) => any[] }): void {\n for (const asset of this.cache.values()) {\n const importers = importerScanner.getImporters(asset.path)\n asset.importersCount = importers.length\n }\n }\n\n /**\n * Enrich assets with duplicate detection metadata.\n * Should be called after scanning completes and when file content changes.\n */\n enrichWithDuplicateInfo(duplicateScanner: {\n getDuplicateInfo: (assetPath: string) => { hash: string; duplicatesCount: number }\n }): void {\n for (const asset of this.cache.values()) {\n const info = duplicateScanner.getDuplicateInfo(asset.path)\n asset.contentHash = info.hash\n asset.duplicatesCount = info.duplicatesCount\n }\n }\n\n private initWatcher(): void {\n const watchPaths = this.options.include.map(dir => path.join(this.root, dir))\n\n this.watcher = chokidar.watch(watchPaths, {\n ignored: this.options.exclude.map(p => `**/${p}/**`),\n persistent: true,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 100,\n pollInterval: 50\n }\n })\n\n this.watcher.on('add', filePath => this.handleFileChange('add', filePath))\n this.watcher.on('unlink', filePath => this.handleFileChange('unlink', filePath))\n this.watcher.on('change', filePath => this.handleFileChange('change', filePath))\n }\n\n private async handleFileChange(event: string, absolutePath: string): Promise<void> {\n const relativePath = path.relative(this.root, absolutePath)\n const extension = path.extname(relativePath).toLowerCase()\n\n if (!this.options.extensions.includes(extension)) {\n return\n }\n\n if (event === 'unlink') {\n this.cache.delete(relativePath)\n } else {\n try {\n const stats = await fs.stat(absolutePath)\n const asset: Asset = {\n id: Buffer.from(relativePath).toString('base64url'),\n name: path.basename(relativePath),\n path: relativePath,\n absolutePath,\n extension,\n type: this.getAssetType(extension),\n size: stats.size,\n mtime: stats.mtimeMs,\n directory: path.dirname(relativePath)\n }\n this.cache.set(relativePath, asset)\n } catch {\n return\n }\n }\n\n this.emit('change', { event, path: relativePath })\n }\n\n destroy(): void {\n this.watcher?.close()\n }\n}\n","import { EventEmitter } from 'events'\nimport fg from 'fast-glob'\nimport path from 'path'\nimport fs from 'fs/promises'\nimport chokidar from 'chokidar'\nimport type { Importer, ImportType, ResolvedOptions } from '../shared/types.js'\n\nexport interface ImporterScannerEvents {\n change: [{ event: string; path: string; affectedAssets: string[] }]\n}\n\n/** Source file extensions to scan for imports */\nconst SOURCE_EXTENSIONS = ['js', 'jsx', 'ts', 'tsx', 'vue', 'svelte', 'css', 'scss', 'less', 'html']\n\n/** Asset extensions to look for in imports */\nconst ASSET_EXTENSIONS = [\n 'png',\n 'jpg',\n 'jpeg',\n 'gif',\n 'svg',\n 'webp',\n 'avif',\n 'ico',\n 'bmp',\n 'tiff',\n 'tif',\n 'heic',\n 'heif',\n 'mp4',\n 'webm',\n 'ogg',\n 'mov',\n 'avi',\n 'mp3',\n 'wav',\n 'flac',\n 'aac',\n 'woff',\n 'woff2',\n 'ttf',\n 'otf',\n 'eot',\n 'pdf',\n 'json',\n 'md',\n 'txt',\n 'csv',\n 'xml',\n 'yml',\n 'yaml',\n 'toml'\n]\n\nconst ASSET_EXT_PATTERN = ASSET_EXTENSIONS.join('|')\n\n/**\n * Regex patterns to find asset imports in source files.\n * Each pattern captures the asset path in group 1.\n */\nconst IMPORT_PATTERNS: { type: ImportType; pattern: RegExp }[] = [\n {\n type: 'es-import',\n pattern: new RegExp(\n `import\\\\s+(?:[\\\\w\\\\s{},*]+\\\\s+from\\\\s+)?['\"]([^'\"]*\\\\.(?:${ASSET_EXT_PATTERN}))['\"]`,\n 'gi'\n )\n },\n {\n type: 'dynamic-import',\n pattern: new RegExp(`import\\\\s*\\\\(\\\\s*['\"]([^'\"]*\\\\.(?:${ASSET_EXT_PATTERN}))['\"]\\\\s*\\\\)`, 'gi')\n },\n {\n type: 'require',\n pattern: new RegExp(\n `require\\\\s*\\\\(\\\\s*['\"]([^'\"]*\\\\.(?:${ASSET_EXT_PATTERN}))['\"]\\\\s*\\\\)`,\n 'gi'\n )\n },\n {\n type: 'css-url',\n pattern: new RegExp(\n `url\\\\s*\\\\(\\\\s*['\"]?([^'\")\\\\s]+\\\\.(?:${ASSET_EXT_PATTERN}))['\"]?\\\\s*\\\\)`,\n 'gi'\n )\n },\n {\n type: 'html-src',\n pattern: new RegExp(`\\\\bsrc\\\\s*=\\\\s*['\"]([^'\"]*\\\\.(?:${ASSET_EXT_PATTERN}))['\"]`, 'gi')\n },\n {\n type: 'html-href',\n pattern: new RegExp(`\\\\bhref\\\\s*=\\\\s*['\"]([^'\"]*\\\\.(?:${ASSET_EXT_PATTERN}))['\"]`, 'gi')\n }\n]\n\nexport class ImporterScanner extends EventEmitter {\n private root: string\n private options: ResolvedOptions\n /** Maps asset path -> array of importers */\n private cache: Map<string, Importer[]> = new Map()\n /** Reverse index: source file -> set of asset paths it imports */\n private reverseIndex: Map<string, Set<string>> = new Map()\n private watcher?: chokidar.FSWatcher\n private scanPromise?: Promise<void>\n private initialized = false\n\n constructor(root: string, options: ResolvedOptions) {\n super()\n this.root = root\n this.options = options\n }\n\n async init(): Promise<void> {\n if (this.initialized) return\n await this.scan()\n if (this.options.watch) {\n this.initWatcher()\n }\n this.initialized = true\n }\n\n async scan(): Promise<void> {\n if (this.scanPromise) {\n await this.scanPromise\n return\n }\n\n this.scanPromise = this.performScan()\n await this.scanPromise\n this.scanPromise = undefined\n }\n\n private async performScan(): Promise<void> {\n const patterns = this.options.include.map(dir => `${dir}/**/*.{${SOURCE_EXTENSIONS.join(',')}}`)\n\n const entries = await fg(patterns, {\n cwd: this.root,\n ignore: this.options.exclude.map(p => `**/${p}/**`),\n absolute: false,\n onlyFiles: true,\n dot: false\n })\n\n this.cache.clear()\n this.reverseIndex.clear()\n\n const BATCH_SIZE = 50\n for (let i = 0; i < entries.length; i += BATCH_SIZE) {\n const batch = entries.slice(i, i + BATCH_SIZE)\n await Promise.all(batch.map(filePath => this.scanFile(filePath)))\n }\n }\n\n private async scanFile(relativePath: string): Promise<void> {\n const absolutePath = path.join(this.root, relativePath)\n\n try {\n const content = await fs.readFile(absolutePath, 'utf-8')\n const importers = this.findImportsInFile(content, relativePath, absolutePath)\n\n const previousAssets = this.reverseIndex.get(relativePath)\n if (previousAssets) {\n for (const assetPath of previousAssets) {\n const assetImporters = this.cache.get(assetPath)\n if (assetImporters) {\n const filtered = assetImporters.filter(i => i.filePath !== relativePath)\n if (filtered.length > 0) {\n this.cache.set(assetPath, filtered)\n } else {\n this.cache.delete(assetPath)\n }\n }\n }\n }\n\n const newAssets = new Set<string>()\n\n for (const importer of importers) {\n const assetPath = this.resolveAssetPath(importer.filePath, importer.snippet)\n if (assetPath) {\n newAssets.add(assetPath)\n\n const existing = this.cache.get(assetPath) || []\n existing.push({ ...importer, filePath: relativePath, absolutePath })\n this.cache.set(assetPath, existing)\n }\n }\n\n this.reverseIndex.set(relativePath, newAssets)\n } catch {\n // File might have been deleted or is unreadable\n }\n }\n\n private findImportsInFile(\n content: string,\n relativePath: string,\n absolutePath: string\n ): Importer[] {\n const importers: Importer[] = []\n const lines = content.split('\\n')\n const fileDir = path.dirname(relativePath)\n\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\n const line = lines[lineIndex]\n\n for (const { type, pattern } of IMPORT_PATTERNS) {\n pattern.lastIndex = 0\n\n let match\n while ((match = pattern.exec(line)) !== null) {\n const importPath = match[1]\n const resolvedAssetPath = this.resolveImportPath(importPath, fileDir)\n\n if (resolvedAssetPath) {\n importers.push({\n filePath: relativePath,\n absolutePath,\n line: lineIndex + 1,\n column: match.index + 1,\n importType: type,\n snippet: line.trim().slice(0, 100)\n })\n }\n }\n }\n }\n\n return importers\n }\n\n /**\n * Resolves an import path relative to the file directory.\n * Returns the normalized asset path relative to project root, or null if invalid.\n */\n private resolveImportPath(importPath: string, fileDir: string): string | null {\n if (\n importPath.startsWith('http://') ||\n importPath.startsWith('https://') ||\n importPath.startsWith('//')\n ) {\n return null\n }\n\n if (\n !importPath.startsWith('.') &&\n !importPath.startsWith('/') &&\n !importPath.startsWith('@/')\n ) {\n return null\n }\n\n let resolvedPath: string\n\n if (importPath.startsWith('/')) {\n resolvedPath = importPath.slice(1)\n if (!resolvedPath.startsWith('public/')) {\n resolvedPath = 'public' + importPath\n }\n } else if (importPath.startsWith('@/')) {\n resolvedPath = 'src/' + importPath.slice(2)\n } else {\n resolvedPath = path.normalize(path.join(fileDir, importPath))\n }\n\n resolvedPath = resolvedPath.split(path.sep).join('/')\n\n return resolvedPath\n }\n\n /**\n * Extract asset path from importer snippet (for reverse lookup)\n */\n private resolveAssetPath(sourceFile: string, snippet: string): string | null {\n const fileDir = path.dirname(sourceFile)\n\n for (const { pattern } of IMPORT_PATTERNS) {\n pattern.lastIndex = 0\n const match = pattern.exec(snippet)\n if (match) {\n return this.resolveImportPath(match[1], fileDir)\n }\n }\n\n return null\n }\n\n /**\n * Get all importers for a specific asset.\n * @param assetPath - Relative path to the asset from project root\n */\n getImporters(assetPath: string): Importer[] {\n const normalizedPath = assetPath.split(path.sep).join('/')\n\n let importers = this.cache.get(normalizedPath)\n\n if (!importers) {\n if (normalizedPath.startsWith('public/')) {\n importers = this.cache.get(normalizedPath.slice(7))\n } else {\n importers = this.cache.get('public/' + normalizedPath)\n }\n }\n\n return importers || []\n }\n\n /**\n * Get assets affected when a source file changes.\n */\n private getAffectedAssets(sourceFile: string): string[] {\n return Array.from(this.reverseIndex.get(sourceFile) || [])\n }\n\n private initWatcher(): void {\n const watchPaths = this.options.include.map(dir => path.join(this.root, dir))\n\n this.watcher = chokidar.watch(watchPaths, {\n ignored: [\n ...this.options.exclude.map(p => `**/${p}/**`),\n (filePath: string) => {\n const ext = path.extname(filePath).slice(1)\n return ext !== '' && !SOURCE_EXTENSIONS.includes(ext)\n }\n ],\n persistent: true,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 200,\n pollInterval: 50\n }\n })\n\n this.watcher.on('add', filePath => this.handleFileChange('add', filePath))\n this.watcher.on('unlink', filePath => this.handleFileChange('unlink', filePath))\n this.watcher.on('change', filePath => this.handleFileChange('change', filePath))\n }\n\n private async handleFileChange(event: string, absolutePath: string): Promise<void> {\n const relativePath = path.relative(this.root, absolutePath)\n const extension = path.extname(relativePath).slice(1)\n\n if (!SOURCE_EXTENSIONS.includes(extension)) {\n return\n }\n\n const previousAssets = this.getAffectedAssets(relativePath)\n\n if (event === 'unlink') {\n for (const assetPath of previousAssets) {\n const assetImporters = this.cache.get(assetPath)\n if (assetImporters) {\n const filtered = assetImporters.filter(i => i.filePath !== relativePath)\n if (filtered.length > 0) {\n this.cache.set(assetPath, filtered)\n } else {\n this.cache.delete(assetPath)\n }\n }\n }\n this.reverseIndex.delete(relativePath)\n } else {\n await this.scanFile(relativePath)\n }\n\n const currentAssets = this.getAffectedAssets(relativePath)\n const allAffectedAssets = [...new Set([...previousAssets, ...currentAssets])]\n\n if (allAffectedAssets.length > 0) {\n this.emit('change', {\n event,\n path: relativePath,\n affectedAssets: allAffectedAssets\n })\n }\n }\n\n destroy(): void {\n this.watcher?.close()\n }\n}\n","import { EventEmitter } from 'events'\nimport crypto from 'crypto'\nimport fs from 'fs'\nimport path from 'path'\nimport chokidar from 'chokidar'\nimport type { ResolvedOptions, Asset } from '../shared/types.js'\n\nexport interface DuplicateScannerEvents {\n change: [{ event: string; affectedHashes: string[] }]\n}\n\nexport interface DuplicateInfo {\n hash: string\n duplicatesCount: number\n}\n\n/** Threshold for streaming hash computation (1MB) */\nconst STREAMING_THRESHOLD = 1024 * 1024\n\nexport class DuplicateScanner extends EventEmitter {\n private root: string\n private options: ResolvedOptions\n /** Maps relative path -> { hash, mtime, size } for cache validation */\n private hashCache: Map<string, { hash: string; mtime: number; size: number }> = new Map()\n /** Maps hash -> set of relative paths (for grouping duplicates) */\n private duplicateGroups: Map<string, Set<string>> = new Map()\n /** Reverse index: path -> hash (for quick lookups) */\n private pathToHash: Map<string, string> = new Map()\n private watcher?: chokidar.FSWatcher\n private scanPromise?: Promise<void>\n private initialized = false\n\n constructor(root: string, options: ResolvedOptions) {\n super()\n this.root = root\n this.options = options\n }\n\n async init(): Promise<void> {\n if (this.initialized) return\n this.initialized = true\n }\n\n /**\n * Scan all assets and compute hashes.\n * Called after AssetScanner has discovered assets.\n */\n async scanAssets(assets: Asset[]): Promise<void> {\n if (this.scanPromise) {\n await this.scanPromise\n return\n }\n\n this.scanPromise = this.performScan(assets)\n await this.scanPromise\n this.scanPromise = undefined\n }\n\n private async performScan(assets: Asset[]): Promise<void> {\n this.duplicateGroups.clear()\n this.pathToHash.clear()\n\n const BATCH_SIZE = 20\n for (let i = 0; i < assets.length; i += BATCH_SIZE) {\n const batch = assets.slice(i, i + BATCH_SIZE)\n await Promise.all(batch.map(asset => this.processAsset(asset)))\n }\n }\n\n private async processAsset(asset: Asset): Promise<void> {\n try {\n const hash = await this.getOrComputeHash(asset.path, asset.absolutePath)\n if (hash) {\n this.pathToHash.set(asset.path, hash)\n\n if (!this.duplicateGroups.has(hash)) {\n this.duplicateGroups.set(hash, new Set())\n }\n this.duplicateGroups.get(hash)!.add(asset.path)\n }\n } catch {\n // File might have been deleted or is unreadable\n }\n }\n\n /**\n * Get cached hash or compute new one if cache is invalid.\n */\n private async getOrComputeHash(\n relativePath: string,\n absolutePath: string\n ): Promise<string | null> {\n try {\n const stats = await fs.promises.stat(absolutePath)\n\n const cached = this.hashCache.get(relativePath)\n if (cached && cached.mtime === stats.mtimeMs && cached.size === stats.size) {\n return cached.hash\n }\n\n const hash = await this.computeFileHash(absolutePath, stats.size)\n\n this.hashCache.set(relativePath, {\n hash,\n mtime: stats.mtimeMs,\n size: stats.size\n })\n\n return hash\n } catch {\n return null\n }\n }\n\n /**\n * Compute MD5 hash of file contents.\n * Uses streaming for large files to avoid memory issues.\n */\n private async computeFileHash(absolutePath: string, size: number): Promise<string> {\n if (size > STREAMING_THRESHOLD) {\n return new Promise((resolve, reject) => {\n const hash = crypto.createHash('md5')\n const stream = fs.createReadStream(absolutePath)\n stream.on('data', (chunk: Buffer) => hash.update(chunk))\n stream.on('end', () => resolve(hash.digest('hex')))\n stream.on('error', reject)\n })\n }\n\n const content = await fs.promises.readFile(absolutePath)\n return crypto.createHash('md5').update(content).digest('hex')\n }\n\n /**\n * Get duplicate info for a specific asset.\n */\n getDuplicateInfo(assetPath: string): DuplicateInfo {\n const normalizedPath = assetPath.split(path.sep).join('/')\n const hash = this.pathToHash.get(normalizedPath)\n\n if (!hash) {\n return { hash: '', duplicatesCount: 0 }\n }\n\n const group = this.duplicateGroups.get(hash)\n const duplicatesCount = group ? group.size - 1 : 0 // Exclude self\n\n return { hash, duplicatesCount }\n }\n\n /**\n * Get all assets in a duplicate group by hash.\n */\n getDuplicatesByHash(hash: string): string[] {\n const group = this.duplicateGroups.get(hash)\n return group ? Array.from(group).sort() : []\n }\n\n /**\n * Get duplicate statistics.\n */\n getStats(): { duplicateGroups: number; duplicateFiles: number } {\n let duplicateGroups = 0\n let duplicateFiles = 0\n\n for (const [, paths] of this.duplicateGroups) {\n if (paths.size > 1) {\n duplicateGroups++\n duplicateFiles += paths.size\n }\n }\n\n return { duplicateGroups, duplicateFiles }\n }\n\n /**\n * Enrich assets with duplicate detection metadata.\n */\n enrichAssetsWithDuplicateInfo(assets: Asset[]): void {\n for (const asset of assets) {\n const info = this.getDuplicateInfo(asset.path)\n asset.contentHash = info.hash\n asset.duplicatesCount = info.duplicatesCount\n }\n }\n\n /**\n * Handle file change event from watcher.\n * Recalculates hash and updates duplicate groups.\n */\n async handleAssetChange(\n event: 'add' | 'change' | 'unlink',\n relativePath: string,\n absolutePath: string\n ): Promise<void> {\n const normalizedPath = relativePath.split(path.sep).join('/')\n const previousHash = this.pathToHash.get(normalizedPath)\n const affectedHashes: string[] = []\n\n if (previousHash) {\n affectedHashes.push(previousHash)\n const oldGroup = this.duplicateGroups.get(previousHash)\n if (oldGroup) {\n oldGroup.delete(normalizedPath)\n if (oldGroup.size === 0) {\n this.duplicateGroups.delete(previousHash)\n }\n }\n this.pathToHash.delete(normalizedPath)\n }\n\n if (event === 'unlink') {\n this.hashCache.delete(normalizedPath)\n } else {\n try {\n const stats = await fs.promises.stat(absolutePath)\n const hash = await this.computeFileHash(absolutePath, stats.size)\n\n this.hashCache.set(normalizedPath, {\n hash,\n mtime: stats.mtimeMs,\n size: stats.size\n })\n this.pathToHash.set(normalizedPath, hash)\n\n if (!this.duplicateGroups.has(hash)) {\n this.duplicateGroups.set(hash, new Set())\n }\n this.duplicateGroups.get(hash)!.add(normalizedPath)\n\n if (!affectedHashes.includes(hash)) {\n affectedHashes.push(hash)\n }\n } catch {}\n }\n\n if (affectedHashes.length > 0) {\n this.emit('change', { event, affectedHashes })\n }\n }\n\n /**\n * Initialize file watcher for real-time updates.\n * Note: This watches asset files, not source files.\n */\n initWatcher(): void {\n if (this.watcher) return\n\n const watchPaths = this.options.include.map(dir => path.join(this.root, dir))\n // const extensionPattern = this.options.extensions.map(ext => ext.replace('.', '')).join(',')\n\n this.watcher = chokidar.watch(watchPaths, {\n ignored: [\n ...this.options.exclude.map(p => `**/${p}/**`),\n (filePath: string) => {\n const ext = path.extname(filePath).toLowerCase()\n return ext !== '' && !this.options.extensions.includes(ext)\n }\n ],\n persistent: true,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 200,\n pollInterval: 50\n }\n })\n\n this.watcher.on('add', async filePath => {\n const relativePath = path.relative(this.root, filePath)\n await this.handleAssetChange('add', relativePath, filePath)\n })\n\n this.watcher.on('change', async filePath => {\n const relativePath = path.relative(this.root, filePath)\n await this.handleAssetChange('change', relativePath, filePath)\n })\n\n this.watcher.on('unlink', async filePath => {\n const relativePath = path.relative(this.root, filePath)\n await this.handleAssetChange('unlink', relativePath, filePath)\n })\n }\n\n destroy(): void {\n this.watcher?.close()\n this.hashCache.clear()\n this.duplicateGroups.clear()\n this.pathToHash.clear()\n }\n}\n","import sharp from 'sharp'\nimport path from 'path'\nimport fs from 'fs/promises'\nimport { createHash } from 'crypto'\nimport os from 'os'\n\nexport class ThumbnailService {\n private size: number\n private cache: Map<string, Buffer> = new Map()\n private cacheDir: string\n private supportedFormats = ['.jpg', '.jpeg', '.png', '.webp', '.avif', '.gif', '.tiff']\n\n constructor(size: number = 200) {\n this.size = size\n this.cacheDir = path.join(os.tmpdir(), 'vite-asset-manager-thumbnails')\n }\n\n async getThumbnail(absolutePath: string): Promise<Buffer | null> {\n const extension = path.extname(absolutePath).toLowerCase()\n\n if (!this.supportedFormats.includes(extension)) {\n return null\n }\n\n const cacheKey = await this.getCacheKey(absolutePath)\n\n const cached = this.cache.get(cacheKey)\n if (cached) {\n return cached\n }\n\n const diskCached = await this.loadFromDiskCache(cacheKey)\n if (diskCached) {\n this.cache.set(cacheKey, diskCached)\n return diskCached\n }\n\n try {\n const thumbnail = await this.generateThumbnail(absolutePath)\n this.cache.set(cacheKey, thumbnail)\n await this.saveToDiskCache(cacheKey, thumbnail)\n return thumbnail\n } catch (error) {\n console.warn(`[asset-manager] Failed to generate thumbnail for ${absolutePath}:`, error)\n return null\n }\n }\n\n private async generateThumbnail(absolutePath: string): Promise<Buffer> {\n return sharp(absolutePath)\n .resize(this.size, this.size, {\n fit: 'cover',\n position: 'center'\n })\n .jpeg({ quality: 80 })\n .toBuffer()\n }\n\n private async getCacheKey(absolutePath: string): Promise<string> {\n const hash = createHash('md5')\n hash.update(absolutePath)\n hash.update(this.size.toString())\n\n try {\n const stats = await fs.stat(absolutePath)\n hash.update(stats.mtimeMs.toString())\n } catch {\n // File might not exist\n }\n\n return hash.digest('hex')\n }\n\n private async loadFromDiskCache(key: string): Promise<Buffer | null> {\n try {\n const cachePath = path.join(this.cacheDir, `${key}.jpg`)\n return await fs.readFile(cachePath)\n } catch {\n return null\n }\n }\n\n private async saveToDiskCache(key: string, data: Buffer): Promise<void> {\n try {\n await fs.mkdir(this.cacheDir, { recursive: true })\n const cachePath = path.join(this.cacheDir, `${key}.jpg`)\n await fs.writeFile(cachePath, data)\n } catch {\n // Ignore cache write failures\n }\n }\n\n invalidate(absolutePath: string): void {\n this.getCacheKey(absolutePath).then(key => {\n this.cache.delete(key)\n })\n }\n\n isSupportedFormat(extension: string): boolean {\n return this.supportedFormats.includes(extension.toLowerCase())\n }\n}\n","export type AssetType =\n | 'image'\n | 'video'\n | 'audio'\n | 'document'\n | 'font'\n | 'data'\n | 'text'\n | 'other'\n\nexport type EditorType =\n | 'appcode'\n | 'atom'\n | 'atom-beta'\n | 'brackets'\n | 'clion'\n | 'code'\n | 'code-insiders'\n | 'codium'\n | 'cursor'\n | 'emacs'\n | 'idea'\n | 'notepad++'\n | 'pycharm'\n | 'phpstorm'\n | 'rubymine'\n | 'sublime'\n | 'vim'\n | 'visualstudio'\n | 'webstorm'\n | 'rider'\n | (string & {})\n\nexport type ImportType =\n | 'es-import'\n | 'dynamic-import'\n | 'require'\n | 'css-url'\n | 'html-src'\n | 'html-href'\n\nexport interface Importer {\n filePath: string\n absolutePath: string\n line: number\n column: number\n importType: ImportType\n snippet: string\n}\n\nexport interface Asset {\n id: string\n name: string\n path: string\n absolutePath: string\n extension: string\n type: AssetType\n size: number\n mtime: number\n directory: string\n importersCount?: number\n contentHash?: string\n duplicatesCount?: number\n}\n\nexport interface AssetGroup {\n directory: string\n assets: Asset[]\n count: number\n}\n\nexport interface AssetStats {\n total: number\n byType: Record<AssetType, number>\n totalSize: number\n directories: number\n unused: number\n duplicateGroups: number\n duplicateFiles: number\n}\n\nexport interface AssetManagerOptions {\n base?: string\n include?: string[]\n exclude?: string[]\n extensions?: string[]\n thumbnails?: boolean\n thumbnailSize?: number\n watch?: boolean\n floatingIcon?: boolean\n /**\n * Target editor when opening files via \"Open in Editor\"\n * @default 'code' (Visual Studio Code)\n */\n launchEditor?: EditorType\n}\n\nexport interface ResolvedOptions {\n base: string\n include: string[]\n exclude: string[]\n extensions: string[]\n thumbnails: boolean\n thumbnailSize: number\n watch: boolean\n floatingIcon: boolean\n launchEditor: EditorType\n}\n\nexport const DEFAULT_OPTIONS: ResolvedOptions = {\n base: '/__asset_manager__',\n include: ['src', 'public'],\n exclude: ['node_modules', '.git', 'dist', '.cache', 'coverage'],\n extensions: [\n /**\n * Images:\n */\n '.png',\n '.jpg',\n '.jpeg',\n '.gif',\n '.svg',\n '.webp',\n '.avif',\n '.ico',\n '.bmp',\n '.tiff',\n '.tif',\n '.heic',\n '.heif',\n /**\n * Videos:\n */\n '.mp4',\n '.webm',\n '.ogg',\n '.mov',\n '.avi',\n /**\n * Audio:\n */\n '.mp3',\n '.wav',\n '.flac',\n '.aac',\n /**\n * Documents:\n */\n '.pdf',\n '.doc',\n '.docx',\n '.xls',\n '.xlsx',\n '.ppt',\n '.pptx',\n /**\n * Text/Config:\n */\n '.json',\n '.md',\n '.txt',\n '.csv',\n '.yml',\n '.yaml',\n '.toml',\n '.xml',\n /**\n * Fonts:\n */\n '.woff',\n '.woff2',\n '.ttf',\n '.otf',\n '.eot'\n ],\n thumbnails: true,\n thumbnailSize: 200,\n watch: true,\n floatingIcon: true,\n launchEditor: 'code'\n}\n\nexport function resolveOptions(options: AssetManagerOptions): ResolvedOptions {\n return {\n ...DEFAULT_OPTIONS,\n ...options\n }\n}\n","import type { Plugin } from 'vite'\nimport { createAssetManagerPlugin } from './plugin'\nimport type { AssetManagerOptions } from './shared/types'\n\nexport type { AssetManagerOptions } from './shared/types'\nexport type { Asset, AssetGroup, AssetType, AssetStats } from './shared/types'\n\nexport default function assetManager(options: AssetManagerOptions = {}): Plugin {\n return createAssetManagerPlugin(options)\n}\n\nexport { assetManager }\n"],"mappings":";AACA,OAAO,YAAY;;;ACAnB,OAAO,UAAU;AACjB,OAAOA,WAAU;AACjB,OAAOC,SAAQ;AACf,SAAS,qBAAqB;;;ACH9B,SAAS,SAAS,gBAAgB;AAClC,OAAOC,WAAU;AACjB,OAAO,QAAQ;AACf,OAAO,cAAc;;;ACJrB,OAAO,YAAY;AAWZ,SAAS,aACd,cACA,MACA,QACA,QACe;AACf,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,WAAW,GAAG,YAAY,IAAI,IAAI,IAAI,MAAM;AAElD,WAAO,UAAU,QAAQ,CAAC,WAAmB,aAA4B;AACvE,UAAI,UAAU;AACZ,eAAO,IAAI,MAAM,QAAQ,CAAC;AAAA,MAC5B,OAAO;AACL,gBAAQ;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;;;AC5BA,SAAS,aAAa;AACtB,OAAO,UAAU;AAMjB,eAAsB,qBAAqB,cAAqC;AAC9E,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,WAAW,QAAQ;AAEzB,QAAI;AACJ,QAAI;AAEJ,YAAQ,UAAU;AAAA,MAChB,KAAK;AACH,kBAAU;AACV,eAAO,CAAC,MAAM,YAAY;AAC1B;AAAA,MAEF,KAAK;AACH,kBAAU;AACV,eAAO,CAAC,YAAY,YAAY;AAChC;AAAA,MAEF,KAAK,SAAS;AAEZ,cAAM,YAAY,KAAK,QAAQ,YAAY;AAC3C,kBAAU;AACV,eAAO,CAAC,SAAS;AACjB;AAAA,MACF;AAAA,MAEA;AACE,eAAO,OAAO,IAAI,MAAM,yBAAyB,QAAQ,EAAE,CAAC;AAAA,IAChE;AAEA,UAAM,QAAQ,MAAM,SAAS,IAAI;AAEjC,UAAM,GAAG,SAAS,WAAS;AACzB,aAAO,IAAI,MAAM,0BAA0B,MAAM,OAAO,EAAE,CAAC;AAAA,IAC7D,CAAC;AAED,UAAM,GAAG,SAAS,UAAQ;AACxB,UAAI,SAAS,GAAG;AACd,gBAAQ;AAAA,MACV,OAAO;AACL,eAAO,IAAI,MAAM,mCAAmC,IAAI,EAAE,CAAC;AAAA,MAC7D;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AACH;;;AFpCA,IAAM,aAAa,oBAAI,IAAoB;AAE3C,IAAM,aAAqC;AAAA;AAAA;AAAA;AAAA,EAIzC,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA;AAAA;AAAA;AAAA,EAIT,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA;AAAA;AAAA;AAAA,EAIR,QAAQ;AAAA,EACR,QAAQ;AAAA;AAAA;AAAA;AAAA,EAIR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,QAAQ;AAAA;AAAA;AAAA;AAAA,EAIR,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA;AAAA;AAAA;AAAA,EAIR,SAAS;AAAA,EACT,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ;AACV;AAEO,SAAS,gBACd,SACA,iBACA,kBACA,kBACA,MACA,UACA,QACA;AACA,SAAO,OAAO,KAAsB,KAAqB,SAAuB;AAC9E,UAAM,EAAE,UAAU,MAAM,IAAI,SAAS,IAAI,OAAO,IAAI,IAAI;AACxD,UAAM,UAAU,UAAU,QAAQ,GAAG,QAAQ,QAAQ,EAAE,KAAK;AAE5D,QAAI;AACF,cAAQ,SAAS;AAAA,QACf,KAAK;AACH,iBAAO,gBAAgB,KAAK,SAAS,KAAK;AAAA,QAC5C,KAAK;AACH,iBAAO,uBAAuB,KAAK,SAAS,KAAK;AAAA,QACnD,KAAK;AACH,iBAAO,aAAa,KAAK,SAAS,KAAK;AAAA,QACzC,KAAK;AACH,iBAAO,gBAAgB,KAAK,kBAAkB,MAAM,KAAK;AAAA,QAC3D,KAAK;AACH,iBAAO,gBAAgB,KAAK,MAAM,KAAK;AAAA,QACzC,KAAK;AACH,iBAAO,eAAe,KAAK,SAAS,gBAAgB;AAAA,QACtD,KAAK;AACH,iBAAO,oBAAoB,KAAK,SAAS,kBAAkB,KAAK;AAAA,QAClE,KAAK;AACH,iBAAO,mBAAmB,KAAK,iBAAiB,KAAK;AAAA,QACvD,KAAK;AACH,iBAAO,mBAAmB,KAAK,KAAK,MAAM,QAAQ,KAAK;AAAA,QACzD,KAAK;AACH,iBAAO,qBAAqB,KAAK,KAAK,MAAM,KAAK;AAAA,QACnD,KAAK;AACH,iBAAO,mBAAmB,KAAK,KAAK,IAAI;AAAA,QAC1C,KAAK;AACH,iBAAO,iBAAiB,KAAK,KAAK,IAAI;AAAA,QACxC,KAAK;AACH,iBAAO,UAAU,GAAG;AAAA,QACtB;AACE,eAAK;AAAA,MACT;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,8BAA8B,KAAK;AACjD,UAAI,aAAa;AACjB,UAAI,UAAU,gBAAgB,kBAAkB;AAChD,UAAI,IAAI,KAAK,UAAU,EAAE,OAAO,wBAAwB,CAAC,CAAC;AAAA,IAC5D;AAAA,EACF;AACF;AAEA,eAAe,gBACb,KACA,SACA,OACA;AACA,QAAM,SAAS,QAAQ,UAAU;AAEjC,MAAI,WAAW;AAEf,QAAM,YAAY,MAAM;AACxB,MAAI,WAAW;AACb,eAAW,SAAS;AAAA,MAClB,OAAK,EAAE,cAAc,aAAa,EAAE,UAAU,WAAW,YAAY,GAAG;AAAA,IAC1E;AAAA,EACF;AAEA,QAAM,OAAO,MAAM;AACnB,MAAI,MAAM;AACR,eAAW,SAAS,OAAO,OAAK,EAAE,SAAS,IAAI;AAAA,EACjD;AAEA,WAAS,KAAK,EAAE,QAAQ,UAAU,OAAO,SAAS,OAAO,CAAC;AAC5D;AAEA,eAAe,uBACb,KACA,SACA,OACA;AACA,MAAI,SAAS,QAAQ,iBAAiB;AAEtC,QAAM,OAAO,MAAM;AACnB,MAAI,MAAM;AACR,aAAS,OACN,IAAI,YAAU;AAAA,MACb,GAAG;AAAA,MACH,QAAQ,MAAM,OAAO,OAAO,OAAK,EAAE,SAAS,IAAI;AAAA,MAChD,OAAO,MAAM,OAAO,OAAO,OAAK,EAAE,SAAS,IAAI,EAAE;AAAA,IACnD,EAAE,EACD,OAAO,WAAS,MAAM,QAAQ,CAAC;AAAA,EACpC;AAEA,QAAM,SAAS,MAAM,WAAW;AAChC,MAAI,QAAQ;AACV,aAAS,OACN,IAAI,YAAU;AAAA,MACb,GAAG;AAAA,MACH,QAAQ,MAAM,OAAO,OAAO,OAAK,EAAE,mBAAmB,CAAC;AAAA,MACvD,OAAO,MAAM,OAAO,OAAO,OAAK,EAAE,mBAAmB,CAAC,EAAE;AAAA,IAC1D,EAAE,EACD,OAAO,WAAS,MAAM,QAAQ,CAAC;AAAA,EACpC;AAEA,QAAM,aAAa,MAAM,eAAe;AACxC,MAAI,YAAY;AACd,aAAS,OACN,IAAI,YAAU;AAAA,MACb,GAAG;AAAA,MACH,QAAQ,MAAM,OAAO,OAAO,QAAM,EAAE,mBAAmB,KAAK,CAAC;AAAA,MAC7D,OAAO,MAAM,OAAO,OAAO,QAAM,EAAE,mBAAmB,KAAK,CAAC,EAAE;AAAA,IAChE,EAAE,EACD,OAAO,WAAS,MAAM,QAAQ,CAAC;AAAA,EACpC;AAEA,QAAM,QAAQ,OAAO,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC;AACxD,WAAS,KAAK,EAAE,QAAQ,MAAM,CAAC;AACjC;AAEA,eAAe,aACb,KACA,SACA,OACA;AACA,QAAM,IAAK,MAAM,KAAgB;AACjC,QAAM,UAAU,QAAQ,OAAO,CAAC;AAChC,WAAS,KAAK,EAAE,QAAQ,SAAS,OAAO,QAAQ,QAAQ,OAAO,EAAE,CAAC;AACpE;AAEA,eAAe,gBACb,KACA,kBACA,MACA,OACA;AACA,QAAM,eAAe,MAAM;AAC3B,MAAI,CAAC,cAAc;AACjB,QAAI,aAAa;AACjB,QAAI,IAAI,wBAAwB;AAChC;AAAA,EACF;AAEA,QAAM,eAAeC,MAAK,QAAQ,MAAM,YAAY;AAEpD,MAAI,CAAC,aAAa,WAAW,IAAI,GAAG;AAClC,QAAI,aAAa;AACjB,QAAI,IAAI,WAAW;AACnB;AAAA,EACF;AAEA,MAAI,aAAa,SAAS,MAAM,GAAG;AACjC,QAAI,UAAU,gBAAgB,eAAe;AAC7C,QAAI,UAAU,iBAAiB,0BAA0B;AACzD,OAAG,iBAAiB,YAAY,EAAE,KAAK,GAAG;AAC1C;AAAA,EACF;AAEA,QAAM,YAAY,MAAM,iBAAiB,aAAa,YAAY;AAElE,MAAI,WAAW;AACb,QAAI,UAAU,gBAAgB,YAAY;AAC1C,QAAI,UAAU,iBAAiB,0BAA0B;AACzD,QAAI,IAAI,SAAS;AAAA,EACnB,OAAO;AACL,UAAM,MAAMA,MAAK,QAAQ,YAAY,EAAE,YAAY;AACnD,QAAI,UAAU,gBAAgB,WAAW,GAAG,KAAK,0BAA0B;AAC3E,OAAG,iBAAiB,YAAY,EAAE,KAAK,GAAG;AAAA,EAC5C;AACF;AAEA,eAAe,gBAAgB,KAAqB,MAAc,OAA4B;AAC5F,QAAM,eAAe,MAAM;AAC3B,MAAI,CAAC,cAAc;AACjB,QAAI,aAAa;AACjB,QAAI,IAAI,wBAAwB;AAChC;AAAA,EACF;AAEA,QAAM,eAAeA,MAAK,QAAQ,MAAM,YAAY;AAEpD,MAAI,CAAC,aAAa,WAAW,IAAI,GAAG;AAClC,QAAI,aAAa;AACjB,QAAI,IAAI,WAAW;AACnB;AAAA,EACF;AAEA,MAAI;AACF,UAAM,GAAG,SAAS,OAAO,cAAc,GAAG,UAAU,IAAI;AAAA,EAC1D,QAAQ;AACN,QAAI,aAAa;AACjB,QAAI,IAAI,gBAAgB;AACxB;AAAA,EACF;AAEA,QAAM,MAAMA,MAAK,QAAQ,YAAY,EAAE,YAAY;AACnD,MAAI,UAAU,gBAAgB,WAAW,GAAG,KAAK,0BAA0B;AAC3E,MAAI,UAAU,iBAAiB,sBAAsB;AACrD,KAAG,iBAAiB,YAAY,EAAE,KAAK,GAAG;AAC5C;AAEA,eAAe,eACb,KACA,SACA,kBACA;AACA,QAAM,SAAS,QAAQ,UAAU;AACjC,QAAM,WAAW,iBAAiB,SAAS;AAE3C,QAAM,QAAoB;AAAA,IACxB,OAAO,OAAO;AAAA,IACd,QAAQ;AAAA,MACN,OAAO,OAAO,OAAO,OAAK,EAAE,SAAS,OAAO,EAAE;AAAA,MAC9C,OAAO,OAAO,OAAO,OAAK,EAAE,SAAS,OAAO,EAAE;AAAA,MAC9C,OAAO,OAAO,OAAO,OAAK,EAAE,SAAS,OAAO,EAAE;AAAA,MAC9C,UAAU,OAAO,OAAO,OAAK,EAAE,SAAS,UAAU,EAAE;AAAA,MACpD,MAAM,OAAO,OAAO,OAAK,EAAE,SAAS,MAAM,EAAE;AAAA,MAC5C,MAAM,OAAO,OAAO,OAAK,EAAE,SAAS,MAAM,EAAE;AAAA,MAC5C,MAAM,OAAO,OAAO,OAAK,EAAE,SAAS,MAAM,EAAE;AAAA,MAC5C,OAAO,OAAO,OAAO,OAAK,EAAE,SAAS,OAAO,EAAE;AAAA,IAChD;AAAA,IACA,WAAW,OAAO,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,MAAM,CAAC;AAAA,IACpD,aAAa,CAAC,GAAG,IAAI,IAAI,OAAO,IAAI,OAAK,EAAE,SAAS,CAAC,CAAC,EAAE;AAAA,IACxD,QAAQ,OAAO,OAAO,OAAK,EAAE,mBAAmB,CAAC,EAAE;AAAA,IACnD,iBAAiB,SAAS;AAAA,IAC1B,gBAAgB,SAAS;AAAA,EAC3B;AAEA,WAAS,KAAK,KAAK;AACrB;AAEA,eAAe,oBACb,KACA,SACA,kBACA,OACA;AACA,QAAM,OAAO,MAAM;AAEnB,MAAI,MAAM;AAER,UAAM,QAAQ,iBAAiB,oBAAoB,IAAI;AACvD,UAAM,SAAS,QAAQ,UAAU,EAAE,OAAO,OAAK,MAAM,SAAS,EAAE,IAAI,CAAC;AACrE,aAAS,KAAK,EAAE,YAAY,QAAQ,OAAO,OAAO,QAAQ,KAAK,CAAC;AAAA,EAClE,OAAO;AAEL,UAAM,SAAS,QAAQ,UAAU,EAAE,OAAO,QAAM,EAAE,mBAAmB,KAAK,CAAC;AAC3E,aAAS,KAAK,EAAE,YAAY,QAAQ,OAAO,OAAO,OAAO,CAAC;AAAA,EAC5D;AACF;AAEA,SAAS,SAAS,KAAqB,MAAe;AACpD,MAAI,UAAU,gBAAgB,kBAAkB;AAChD,MAAI,IAAI,KAAK,UAAU,IAAI,CAAC;AAC9B;AAEA,SAAS,UAAU,KAAqB;AACtC,MAAI,UAAU,KAAK;AAAA,IACjB,gBAAgB;AAAA,IAChB,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ,+BAA+B;AAAA,EACjC,CAAC;AAED,MAAI,MAAM,SAAS,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC,CAAC;AAAA;AAAA,CAAM;AAE9D,aAAW,IAAI,GAAG;AAElB,MAAI,GAAG,SAAS,MAAM;AACpB,eAAW,OAAO,GAAG;AAAA,EACvB,CAAC;AACH;AAEO,SAAS,aAAa,OAAe,MAAe;AACzD,QAAM,UAAU,KAAK,UAAU,EAAE,OAAO,KAAK,CAAC;AAC9C,aAAW,UAAU,YAAY;AAC/B,WAAO,MAAM,SAAS,OAAO;AAAA;AAAA,CAAM;AAAA,EACrC;AACF;AAEA,eAAe,mBACb,KACA,iBACA,OACA;AACA,QAAM,YAAY,MAAM;AACxB,MAAI,CAAC,WAAW;AACd,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,yBAAyB,CAAC;AACjD;AAAA,EACF;AAEA,QAAM,YAAY,gBAAgB,aAAa,SAAS;AACxD,WAAS,KAAK,EAAE,WAAW,OAAO,UAAU,OAAO,CAAC;AACtD;AAEA,eAAe,mBACb,KACA,KACA,MACA,QACA,OACA;AACA,MAAI,IAAI,WAAW,QAAQ;AACzB,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,qBAAqB,CAAC;AAC7C;AAAA,EACF;AAEA,QAAM,WAAW,MAAM;AACvB,QAAM,OAAO,SAAS,MAAM,IAAc,KAAK;AAC/C,QAAM,SAAS,SAAS,MAAM,MAAgB,KAAK;AAEnD,MAAI,CAAC,UAAU;AACb,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,yBAAyB,CAAC;AACjD;AAAA,EACF;AAEA,QAAM,eAAeA,MAAK,QAAQ,MAAM,QAAQ;AAEhD,MAAI,CAAC,aAAa,WAAW,IAAI,GAAG;AAClC,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,YAAY,CAAC;AACpC;AAAA,EACF;AAEA,MAAI;AACF,UAAM,GAAG,SAAS,OAAO,cAAc,GAAG,UAAU,IAAI;AAAA,EAC1D,QAAQ;AACN,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,iBAAiB,CAAC;AACzC;AAAA,EACF;AAEA,MAAI;AACF,UAAM,aAAa,cAAc,MAAM,QAAQ,MAAM;AACrD,aAAS,KAAK,EAAE,SAAS,KAAK,CAAC;AAAA,EACjC,SAAS,OAAO;AACd,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,wBAAwB,CAAC;AAAA,EAC3F;AACF;AAEA,eAAe,qBACb,KACA,KACA,MACA,OACA;AACA,MAAI,IAAI,WAAW,QAAQ;AACzB,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,qBAAqB,CAAC;AAC7C;AAAA,EACF;AAEA,QAAM,WAAW,MAAM;AAEvB,MAAI,CAAC,UAAU;AACb,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,yBAAyB,CAAC;AACjD;AAAA,EACF;AAEA,QAAM,eAAeA,MAAK,QAAQ,MAAM,QAAQ;AAGhD,MAAI,CAAC,aAAa,WAAW,IAAI,GAAG;AAClC,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,eAAe,CAAC;AACvC;AAAA,EACF;AAGA,MAAI;AACF,UAAM,GAAG,SAAS,OAAO,cAAc,GAAG,UAAU,IAAI;AAAA,EAC1D,QAAQ;AACN,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,iBAAiB,CAAC;AACzC;AAAA,EACF;AAEA,MAAI;AACF,UAAM,qBAAqB,YAAY;AACvC,aAAS,KAAK,EAAE,SAAS,KAAK,CAAC;AAAA,EACjC,SAAS,OAAO;AACd,QAAI,aAAa;AACjB,aAAS,KAAK;AAAA,MACZ,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAClD,CAAC;AAAA,EACH;AACF;AAEA,eAAe,cAAc,KAAwC;AACnE,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,QAAI,OAAO;AACX,QAAI,GAAG,QAAQ,CAAC,UAAkB;AAChC,cAAQ,MAAM,SAAS;AAAA,IACzB,CAAC;AACD,QAAI,GAAG,OAAO,MAAM;AAClB,UAAI;AACF,gBAAQ,KAAK,MAAM,IAAI,CAAC;AAAA,MAC1B,QAAQ;AACN,eAAO,IAAI,MAAM,cAAc,CAAC;AAAA,MAClC;AAAA,IACF,CAAC;AACD,QAAI,GAAG,SAAS,MAAM;AAAA,EACxB,CAAC;AACH;AAEA,eAAe,mBAAmB,KAAsB,KAAqB,MAAc;AACzF,MAAI,IAAI,WAAW,QAAQ;AACzB,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,qBAAqB,CAAC;AAC7C;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,WAAQ,MAAM,cAAc,GAAG;AAAA,EACjC,QAAQ;AACN,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,oBAAoB,CAAC;AAC5C;AAAA,EACF;AAEA,QAAM,QAAQ,KAAK;AACnB,MAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,GAAG;AAC/C,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,iCAAiC,CAAC;AACzD;AAAA,EACF;AAEA,QAAM,iBAAmE,CAAC;AAE1E,aAAW,gBAAgB,OAAO;AAChC,UAAM,eAAeA,MAAK,QAAQ,MAAM,YAAY;AAEpD,QAAI,CAAC,aAAa,WAAW,IAAI,GAAG;AAClC,UAAI,aAAa;AACjB,eAAS,KAAK,EAAE,OAAO,mBAAmB,YAAY,GAAG,CAAC;AAC1D;AAAA,IACF;AAEA,QAAI;AACF,YAAM,GAAG,SAAS,OAAO,cAAc,GAAG,UAAU,IAAI;AACxD,qBAAe,KAAK,EAAE,cAAc,aAAa,CAAC;AAAA,IACpD,QAAQ;AACN,cAAQ,KAAK,wDAAwD,YAAY,EAAE;AAAA,IACrF;AAAA,EACF;AAEA,MAAI,eAAe,WAAW,GAAG;AAC/B,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,uBAAuB,CAAC;AAC/C;AAAA,EACF;AAEA,MAAI,UAAU,gBAAgB,iBAAiB;AAC/C,MAAI,UAAU,uBAAuB,gCAAgC,KAAK,IAAI,CAAC,OAAO;AAEtF,QAAM,UAAU,SAAS,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC;AAEtD,UAAQ,GAAG,SAAS,SAAO;AACzB,YAAQ,MAAM,uCAAuC,GAAG;AACxD,QAAI,CAAC,IAAI,aAAa;AACpB,UAAI,aAAa;AACjB,UAAI,IAAI,qBAAqB;AAAA,IAC/B;AAAA,EACF,CAAC;AAED,UAAQ,KAAK,GAAG;AAEhB,aAAW,EAAE,cAAc,aAAa,KAAK,gBAAgB;AAC3D,YAAQ,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAAA,EACnD;AAEA,QAAM,QAAQ,SAAS;AACzB;AAEA,eAAe,iBAAiB,KAAsB,KAAqB,MAAc;AACvF,MAAI,IAAI,WAAW,QAAQ;AACzB,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,qBAAqB,CAAC;AAC7C;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,WAAQ,MAAM,cAAc,GAAG;AAAA,EACjC,QAAQ;AACN,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,oBAAoB,CAAC;AAC5C;AAAA,EACF;AAEA,QAAM,QAAQ,KAAK;AACnB,MAAI,CAAC,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,GAAG;AAC/C,QAAI,aAAa;AACjB,aAAS,KAAK,EAAE,OAAO,iCAAiC,CAAC;AACzD;AAAA,EACF;AAEA,QAAM,UAAU;AAAA,IACd,SAAS;AAAA,IACT,QAAQ,CAAC;AAAA,IACT,QAAQ,CAAC;AAAA,EACX;AAEA,aAAW,gBAAgB,OAAO;AAChC,UAAM,eAAeA,MAAK,QAAQ,MAAM,YAAY;AAEpD,QAAI,CAAC,aAAa,WAAW,IAAI,GAAG;AAClC,cAAQ,OAAO,KAAK,YAAY;AAChC,cAAQ,OAAO,KAAK,mBAAmB,YAAY,EAAE;AACrD;AAAA,IACF;AAEA,QAAI;AACF,YAAM,GAAG,SAAS,OAAO,YAAY;AACrC,cAAQ;AAAA,IACV,SAAS,OAAO;AACd,cAAQ,OAAO,KAAK,YAAY;AAChC,cAAQ,OAAO,KAAK,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,IAC9E;AAAA,EACF;AAEA,WAAS,KAAK;AAAA,IACZ,SAAS,QAAQ;AAAA,IACjB,QAAQ,QAAQ,OAAO;AAAA,IACvB,QAAQ,QAAQ;AAAA,EAClB,CAAC;AACH;;;ADhlBA,IAAMC,aAAYC,MAAK,QAAQ,cAAc,YAAY,GAAG,CAAC;AAE7D,SAAS,gBAAwB;AAE/B,QAAM,WAAWA,MAAK,KAAKD,YAAW,QAAQ;AAC9C,MAAIE,IAAG,WAAW,QAAQ,GAAG;AAC3B,WAAO;AAAA,EACT;AAGA,QAAM,aAAaD,MAAK,QAAQD,YAAW,mBAAmB;AAC9D,MAAIE,IAAG,WAAW,UAAU,GAAG;AAC7B,WAAO;AAAA,EACT;AAGA,SAAO;AACT;AAYO,SAAS,gBAAgB,QAAuB,SAAkC;AACvF,QAAM,EAAE,MAAM,SAAS,iBAAiB,kBAAkB,kBAAkB,MAAM,cAAAC,cAAa,IAC7F;AAEF,QAAM,YAAY;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACAA;AAAA,EACF;AAEA,QAAM,YAAY,cAAc;AAEhC,SAAO,YAAY,IAAI,CAAC,KAAK,KAAK,SAAS;AACzC,UAAM,MAAM,IAAI,OAAO;AAEvB,QAAI,IAAI,WAAW,GAAG,IAAI,OAAO,GAAG;AAClC,aAAO,UAAU,KAAK,KAAK,IAAI;AAAA,IACjC;AAEA,QAAI,QAAQ,QAAQ,IAAI,WAAW,GAAG,IAAI,GAAG,GAAG;AAC9C,YAAM,QAAQ,KAAK,WAAW;AAAA,QAC5B,QAAQ;AAAA,QACR,KAAK;AAAA,MACP,CAAC;AAED,UAAI,MAAM,IAAI,MAAM,KAAK,MAAM,KAAK;AACpC,aAAO,MAAM,KAAK,KAAK,IAAI;AAAA,IAC7B;AAEA,SAAK;AAAA,EACP,CAAC;AACH;;;AI5EA,SAAS,oBAAoB;AAC7B,OAAO,QAAQ;AACf,OAAOC,WAAU;AACjB,OAAOC,SAAQ;AACf,OAAO,cAAc;AAOd,IAAM,eAAN,cAA2B,aAAa;AAAA,EACrC;AAAA,EACA;AAAA,EACA,QAA4B,oBAAI,IAAI;AAAA,EACpC;AAAA,EACA;AAAA,EAER,YAAY,MAAc,SAA0B;AAClD,UAAM;AACN,SAAK,OAAO;AACZ,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,OAAsB;AAC1B,UAAM,KAAK,KAAK;AAChB,QAAI,KAAK,QAAQ,OAAO;AACtB,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,MAAM,OAAyB;AAC7B,QAAI,KAAK,aAAa;AACpB,YAAM,KAAK;AACX,aAAO,KAAK,UAAU;AAAA,IACxB;AAEA,SAAK,cAAc,KAAK,YAAY;AACpC,UAAM,KAAK;AACX,SAAK,cAAc;AAEnB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA,EAEA,MAAc,cAA6B;AACzC,UAAM,mBAAmB,KAAK,QAAQ,WAAW,IAAI,SAAO,IAAI,QAAQ,KAAK,EAAE,CAAC,EAAE,KAAK,GAAG;AAE1F,UAAM,WAAW,KAAK,QAAQ,QAAQ,IAAI,SAAO,GAAG,GAAG,UAAU,gBAAgB,GAAG;AAEpF,UAAM,UAAU,MAAM,GAAG,UAAU;AAAA,MACjC,KAAK,KAAK;AAAA,MACV,QAAQ,KAAK,QAAQ,QAAQ,IAAI,OAAK,MAAM,CAAC,KAAK;AAAA,MAClD,UAAU;AAAA,MACV,OAAO;AAAA,MACP,WAAW;AAAA,MACX,KAAK;AAAA,IACP,CAAC;AAED,SAAK,MAAM,MAAM;AAEjB,eAAW,SAAS,SAAS;AAC3B,YAAM,QAAQ,KAAK,YAAY,KAAK;AACpC,WAAK,MAAM,IAAI,MAAM,MAAM,KAAK;AAAA,IAClC;AAAA,EACF;AAAA,EAEQ,YAAY,OAAwB;AAC1C,UAAM,eAAe,MAAM;AAC3B,UAAM,eAAeD,MAAK,KAAK,KAAK,MAAM,YAAY;AACtD,UAAM,YAAYA,MAAK,QAAQ,YAAY,EAAE,YAAY;AACzD,UAAM,OAAOA,MAAK,SAAS,YAAY;AACvC,UAAM,YAAYA,MAAK,QAAQ,YAAY;AAE3C,WAAO;AAAA,MACL,IAAI,OAAO,KAAK,YAAY,EAAE,SAAS,WAAW;AAAA,MAClD;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,MAAM,KAAK,aAAa,SAAS;AAAA,MACjC,MAAM,MAAM,OAAO,QAAQ;AAAA,MAC3B,OAAO,MAAM,OAAO,WAAW,KAAK,IAAI;AAAA,MACxC,WAAW,cAAc,MAAM,MAAM;AAAA,IACvC;AAAA,EACF;AAAA,EAEQ,aAAa,WAA8B;AACjD,UAAM,YAAY;AAAA,MAChB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,YAAY,CAAC,QAAQ,SAAS,QAAQ,QAAQ,MAAM;AAC1D,UAAM,YAAY,CAAC,QAAQ,QAAQ,SAAS,MAAM;AAClD,UAAM,UAAU,CAAC,QAAQ,QAAQ,SAAS,QAAQ,SAAS,QAAQ,OAAO;AAC1E,UAAM,WAAW,CAAC,SAAS,UAAU,QAAQ,QAAQ,MAAM;AAC3D,UAAM,WAAW,CAAC,SAAS,QAAQ,QAAQ,QAAQ,SAAS,OAAO;AACnE,UAAM,WAAW,CAAC,OAAO,MAAM;AAE/B,QAAI,UAAU,SAAS,SAAS,EAAG,QAAO;AAC1C,QAAI,UAAU,SAAS,SAAS,EAAG,QAAO;AAC1C,QAAI,UAAU,SAAS,SAAS,EAAG,QAAO;AAC1C,QAAI,QAAQ,SAAS,SAAS,EAAG,QAAO;AACxC,QAAI,SAAS,SAAS,SAAS,EAAG,QAAO;AACzC,QAAI,SAAS,SAAS,SAAS,EAAG,QAAO;AACzC,QAAI,SAAS,SAAS,SAAS,EAAG,QAAO;AACzC,WAAO;AAAA,EACT;AAAA,EAEA,YAAqB;AACnB,WAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC;AAAA,EACvC;AAAA,EAEA,mBAAiC;AAC/B,UAAM,SAAS,oBAAI,IAAqB;AAExC,eAAW,SAAS,KAAK,MAAM,OAAO,GAAG;AACvC,YAAM,MAAM,MAAM;AAClB,UAAI,CAAC,OAAO,IAAI,GAAG,GAAG;AACpB,eAAO,IAAI,KAAK,CAAC,CAAC;AAAA,MACpB;AACA,aAAO,IAAI,GAAG,EAAG,KAAK,KAAK;AAAA,IAC7B;AAEA,WAAO,MAAM,KAAK,OAAO,QAAQ,CAAC,EAC/B,IAAI,CAAC,CAAC,WAAW,MAAM,OAAO;AAAA,MAC7B;AAAA,MACA,QAAQ,OAAO,KAAK,CAAC,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,IAAI,CAAC;AAAA,MAC1D,OAAO,OAAO;AAAA,IAChB,EAAE,EACD,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC;AAAA,EAC1D;AAAA,EAEA,OAAO,OAAwB;AAC7B,UAAM,kBAAkB,MAAM,YAAY,EAAE,KAAK;AACjD,QAAI,CAAC,gBAAiB,QAAO,KAAK,UAAU;AAE5C,WAAO,KAAK,UAAU,EAAE;AAAA,MACtB,WACE,MAAM,KAAK,YAAY,EAAE,SAAS,eAAe,KACjD,MAAM,KAAK,YAAY,EAAE,SAAS,eAAe;AAAA,IACrD;AAAA,EACF;AAAA,EAEA,SAAS,cAAyC;AAChD,WAAO,KAAK,MAAM,IAAI,YAAY;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,yBAAyB,iBAAuE;AAC9F,eAAW,SAAS,KAAK,MAAM,OAAO,GAAG;AACvC,YAAM,YAAY,gBAAgB,aAAa,MAAM,IAAI;AACzD,YAAM,iBAAiB,UAAU;AAAA,IACnC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,wBAAwB,kBAEf;AACP,eAAW,SAAS,KAAK,MAAM,OAAO,GAAG;AACvC,YAAM,OAAO,iBAAiB,iBAAiB,MAAM,IAAI;AACzD,YAAM,cAAc,KAAK;AACzB,YAAM,kBAAkB,KAAK;AAAA,IAC/B;AAAA,EACF;AAAA,EAEQ,cAAoB;AAC1B,UAAM,aAAa,KAAK,QAAQ,QAAQ,IAAI,SAAOA,MAAK,KAAK,KAAK,MAAM,GAAG,CAAC;AAE5E,SAAK,UAAU,SAAS,MAAM,YAAY;AAAA,MACxC,SAAS,KAAK,QAAQ,QAAQ,IAAI,OAAK,MAAM,CAAC,KAAK;AAAA,MACnD,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,kBAAkB;AAAA,QAChB,oBAAoB;AAAA,QACpB,cAAc;AAAA,MAChB;AAAA,IACF,CAAC;AAED,SAAK,QAAQ,GAAG,OAAO,cAAY,KAAK,iBAAiB,OAAO,QAAQ,CAAC;AACzE,SAAK,QAAQ,GAAG,UAAU,cAAY,KAAK,iBAAiB,UAAU,QAAQ,CAAC;AAC/E,SAAK,QAAQ,GAAG,UAAU,cAAY,KAAK,iBAAiB,UAAU,QAAQ,CAAC;AAAA,EACjF;AAAA,EAEA,MAAc,iBAAiB,OAAe,cAAqC;AACjF,UAAM,eAAeA,MAAK,SAAS,KAAK,MAAM,YAAY;AAC1D,UAAM,YAAYA,MAAK,QAAQ,YAAY,EAAE,YAAY;AAEzD,QAAI,CAAC,KAAK,QAAQ,WAAW,SAAS,SAAS,GAAG;AAChD;AAAA,IACF;AAEA,QAAI,UAAU,UAAU;AACtB,WAAK,MAAM,OAAO,YAAY;AAAA,IAChC,OAAO;AACL,UAAI;AACF,cAAM,QAAQ,MAAMC,IAAG,KAAK,YAAY;AACxC,cAAM,QAAe;AAAA,UACnB,IAAI,OAAO,KAAK,YAAY,EAAE,SAAS,WAAW;AAAA,UAClD,MAAMD,MAAK,SAAS,YAAY;AAAA,UAChC,MAAM;AAAA,UACN;AAAA,UACA;AAAA,UACA,MAAM,KAAK,aAAa,SAAS;AAAA,UACjC,MAAM,MAAM;AAAA,UACZ,OAAO,MAAM;AAAA,UACb,WAAWA,MAAK,QAAQ,YAAY;AAAA,QACtC;AACA,aAAK,MAAM,IAAI,cAAc,KAAK;AAAA,MACpC,QAAQ;AACN;AAAA,MACF;AAAA,IACF;AAEA,SAAK,KAAK,UAAU,EAAE,OAAO,MAAM,aAAa,CAAC;AAAA,EACnD;AAAA,EAEA,UAAgB;AACd,SAAK,SAAS,MAAM;AAAA,EACtB;AACF;;;AC7OA,SAAS,gBAAAE,qBAAoB;AAC7B,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,OAAOC,SAAQ;AACf,OAAOC,eAAc;AAQrB,IAAM,oBAAoB,CAAC,MAAM,OAAO,MAAM,OAAO,OAAO,UAAU,OAAO,QAAQ,QAAQ,MAAM;AAGnG,IAAM,mBAAmB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,oBAAoB,iBAAiB,KAAK,GAAG;AAMnD,IAAM,kBAA2D;AAAA,EAC/D;AAAA,IACE,MAAM;AAAA,IACN,SAAS,IAAI;AAAA,MACX,4DAA4D,iBAAiB;AAAA,MAC7E;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS,IAAI,OAAO,qCAAqC,iBAAiB,iBAAiB,IAAI;AAAA,EACjG;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS,IAAI;AAAA,MACX,sCAAsC,iBAAiB;AAAA,MACvD;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS,IAAI;AAAA,MACX,uCAAuC,iBAAiB;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS,IAAI,OAAO,mCAAmC,iBAAiB,UAAU,IAAI;AAAA,EACxF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,SAAS,IAAI,OAAO,oCAAoC,iBAAiB,UAAU,IAAI;AAAA,EACzF;AACF;AAEO,IAAM,kBAAN,cAA8BJ,cAAa;AAAA,EACxC;AAAA,EACA;AAAA;AAAA,EAEA,QAAiC,oBAAI,IAAI;AAAA;AAAA,EAEzC,eAAyC,oBAAI,IAAI;AAAA,EACjD;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EAEtB,YAAY,MAAc,SAA0B;AAClD,UAAM;AACN,SAAK,OAAO;AACZ,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,OAAsB;AAC1B,QAAI,KAAK,YAAa;AACtB,UAAM,KAAK,KAAK;AAChB,QAAI,KAAK,QAAQ,OAAO;AACtB,WAAK,YAAY;AAAA,IACnB;AACA,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,MAAM,OAAsB;AAC1B,QAAI,KAAK,aAAa;AACpB,YAAM,KAAK;AACX;AAAA,IACF;AAEA,SAAK,cAAc,KAAK,YAAY;AACpC,UAAM,KAAK;AACX,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,MAAc,cAA6B;AACzC,UAAM,WAAW,KAAK,QAAQ,QAAQ,IAAI,SAAO,GAAG,GAAG,UAAU,kBAAkB,KAAK,GAAG,CAAC,GAAG;AAE/F,UAAM,UAAU,MAAMC,IAAG,UAAU;AAAA,MACjC,KAAK,KAAK;AAAA,MACV,QAAQ,KAAK,QAAQ,QAAQ,IAAI,OAAK,MAAM,CAAC,KAAK;AAAA,MAClD,UAAU;AAAA,MACV,WAAW;AAAA,MACX,KAAK;AAAA,IACP,CAAC;AAED,SAAK,MAAM,MAAM;AACjB,SAAK,aAAa,MAAM;AAExB,UAAM,aAAa;AACnB,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK,YAAY;AACnD,YAAM,QAAQ,QAAQ,MAAM,GAAG,IAAI,UAAU;AAC7C,YAAM,QAAQ,IAAI,MAAM,IAAI,cAAY,KAAK,SAAS,QAAQ,CAAC,CAAC;AAAA,IAClE;AAAA,EACF;AAAA,EAEA,MAAc,SAAS,cAAqC;AAC1D,UAAM,eAAeC,MAAK,KAAK,KAAK,MAAM,YAAY;AAEtD,QAAI;AACF,YAAM,UAAU,MAAMC,IAAG,SAAS,cAAc,OAAO;AACvD,YAAM,YAAY,KAAK,kBAAkB,SAAS,cAAc,YAAY;AAE5E,YAAM,iBAAiB,KAAK,aAAa,IAAI,YAAY;AACzD,UAAI,gBAAgB;AAClB,mBAAW,aAAa,gBAAgB;AACtC,gBAAM,iBAAiB,KAAK,MAAM,IAAI,SAAS;AAC/C,cAAI,gBAAgB;AAClB,kBAAM,WAAW,eAAe,OAAO,OAAK,EAAE,aAAa,YAAY;AACvE,gBAAI,SAAS,SAAS,GAAG;AACvB,mBAAK,MAAM,IAAI,WAAW,QAAQ;AAAA,YACpC,OAAO;AACL,mBAAK,MAAM,OAAO,SAAS;AAAA,YAC7B;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,YAAM,YAAY,oBAAI,IAAY;AAElC,iBAAW,YAAY,WAAW;AAChC,cAAM,YAAY,KAAK,iBAAiB,SAAS,UAAU,SAAS,OAAO;AAC3E,YAAI,WAAW;AACb,oBAAU,IAAI,SAAS;AAEvB,gBAAM,WAAW,KAAK,MAAM,IAAI,SAAS,KAAK,CAAC;AAC/C,mBAAS,KAAK,EAAE,GAAG,UAAU,UAAU,cAAc,aAAa,CAAC;AACnE,eAAK,MAAM,IAAI,WAAW,QAAQ;AAAA,QACpC;AAAA,MACF;AAEA,WAAK,aAAa,IAAI,cAAc,SAAS;AAAA,IAC/C,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEQ,kBACN,SACA,cACA,cACY;AACZ,UAAM,YAAwB,CAAC;AAC/B,UAAM,QAAQ,QAAQ,MAAM,IAAI;AAChC,UAAM,UAAUD,MAAK,QAAQ,YAAY;AAEzC,aAAS,YAAY,GAAG,YAAY,MAAM,QAAQ,aAAa;AAC7D,YAAM,OAAO,MAAM,SAAS;AAE5B,iBAAW,EAAE,MAAM,QAAQ,KAAK,iBAAiB;AAC/C,gBAAQ,YAAY;AAEpB,YAAI;AACJ,gBAAQ,QAAQ,QAAQ,KAAK,IAAI,OAAO,MAAM;AAC5C,gBAAM,aAAa,MAAM,CAAC;AAC1B,gBAAM,oBAAoB,KAAK,kBAAkB,YAAY,OAAO;AAEpE,cAAI,mBAAmB;AACrB,sBAAU,KAAK;AAAA,cACb,UAAU;AAAA,cACV;AAAA,cACA,MAAM,YAAY;AAAA,cAClB,QAAQ,MAAM,QAAQ;AAAA,cACtB,YAAY;AAAA,cACZ,SAAS,KAAK,KAAK,EAAE,MAAM,GAAG,GAAG;AAAA,YACnC,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,kBAAkB,YAAoB,SAAgC;AAC5E,QACE,WAAW,WAAW,SAAS,KAC/B,WAAW,WAAW,UAAU,KAChC,WAAW,WAAW,IAAI,GAC1B;AACA,aAAO;AAAA,IACT;AAEA,QACE,CAAC,WAAW,WAAW,GAAG,KAC1B,CAAC,WAAW,WAAW,GAAG,KAC1B,CAAC,WAAW,WAAW,IAAI,GAC3B;AACA,aAAO;AAAA,IACT;AAEA,QAAI;AAEJ,QAAI,WAAW,WAAW,GAAG,GAAG;AAC9B,qBAAe,WAAW,MAAM,CAAC;AACjC,UAAI,CAAC,aAAa,WAAW,SAAS,GAAG;AACvC,uBAAe,WAAW;AAAA,MAC5B;AAAA,IACF,WAAW,WAAW,WAAW,IAAI,GAAG;AACtC,qBAAe,SAAS,WAAW,MAAM,CAAC;AAAA,IAC5C,OAAO;AACL,qBAAeA,MAAK,UAAUA,MAAK,KAAK,SAAS,UAAU,CAAC;AAAA,IAC9D;AAEA,mBAAe,aAAa,MAAMA,MAAK,GAAG,EAAE,KAAK,GAAG;AAEpD,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,YAAoB,SAAgC;AAC3E,UAAM,UAAUA,MAAK,QAAQ,UAAU;AAEvC,eAAW,EAAE,QAAQ,KAAK,iBAAiB;AACzC,cAAQ,YAAY;AACpB,YAAM,QAAQ,QAAQ,KAAK,OAAO;AAClC,UAAI,OAAO;AACT,eAAO,KAAK,kBAAkB,MAAM,CAAC,GAAG,OAAO;AAAA,MACjD;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,aAAa,WAA+B;AAC1C,UAAM,iBAAiB,UAAU,MAAMA,MAAK,GAAG,EAAE,KAAK,GAAG;AAEzD,QAAI,YAAY,KAAK,MAAM,IAAI,cAAc;AAE7C,QAAI,CAAC,WAAW;AACd,UAAI,eAAe,WAAW,SAAS,GAAG;AACxC,oBAAY,KAAK,MAAM,IAAI,eAAe,MAAM,CAAC,CAAC;AAAA,MACpD,OAAO;AACL,oBAAY,KAAK,MAAM,IAAI,YAAY,cAAc;AAAA,MACvD;AAAA,IACF;AAEA,WAAO,aAAa,CAAC;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,YAA8B;AACtD,WAAO,MAAM,KAAK,KAAK,aAAa,IAAI,UAAU,KAAK,CAAC,CAAC;AAAA,EAC3D;AAAA,EAEQ,cAAoB;AAC1B,UAAM,aAAa,KAAK,QAAQ,QAAQ,IAAI,SAAOA,MAAK,KAAK,KAAK,MAAM,GAAG,CAAC;AAE5E,SAAK,UAAUE,UAAS,MAAM,YAAY;AAAA,MACxC,SAAS;AAAA,QACP,GAAG,KAAK,QAAQ,QAAQ,IAAI,OAAK,MAAM,CAAC,KAAK;AAAA,QAC7C,CAAC,aAAqB;AACpB,gBAAM,MAAMF,MAAK,QAAQ,QAAQ,EAAE,MAAM,CAAC;AAC1C,iBAAO,QAAQ,MAAM,CAAC,kBAAkB,SAAS,GAAG;AAAA,QACtD;AAAA,MACF;AAAA,MACA,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,kBAAkB;AAAA,QAChB,oBAAoB;AAAA,QACpB,cAAc;AAAA,MAChB;AAAA,IACF,CAAC;AAED,SAAK,QAAQ,GAAG,OAAO,cAAY,KAAK,iBAAiB,OAAO,QAAQ,CAAC;AACzE,SAAK,QAAQ,GAAG,UAAU,cAAY,KAAK,iBAAiB,UAAU,QAAQ,CAAC;AAC/E,SAAK,QAAQ,GAAG,UAAU,cAAY,KAAK,iBAAiB,UAAU,QAAQ,CAAC;AAAA,EACjF;AAAA,EAEA,MAAc,iBAAiB,OAAe,cAAqC;AACjF,UAAM,eAAeA,MAAK,SAAS,KAAK,MAAM,YAAY;AAC1D,UAAM,YAAYA,MAAK,QAAQ,YAAY,EAAE,MAAM,CAAC;AAEpD,QAAI,CAAC,kBAAkB,SAAS,SAAS,GAAG;AAC1C;AAAA,IACF;AAEA,UAAM,iBAAiB,KAAK,kBAAkB,YAAY;AAE1D,QAAI,UAAU,UAAU;AACtB,iBAAW,aAAa,gBAAgB;AACtC,cAAM,iBAAiB,KAAK,MAAM,IAAI,SAAS;AAC/C,YAAI,gBAAgB;AAClB,gBAAM,WAAW,eAAe,OAAO,OAAK,EAAE,aAAa,YAAY;AACvE,cAAI,SAAS,SAAS,GAAG;AACvB,iBAAK,MAAM,IAAI,WAAW,QAAQ;AAAA,UACpC,OAAO;AACL,iBAAK,MAAM,OAAO,SAAS;AAAA,UAC7B;AAAA,QACF;AAAA,MACF;AACA,WAAK,aAAa,OAAO,YAAY;AAAA,IACvC,OAAO;AACL,YAAM,KAAK,SAAS,YAAY;AAAA,IAClC;AAEA,UAAM,gBAAgB,KAAK,kBAAkB,YAAY;AACzD,UAAM,oBAAoB,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,gBAAgB,GAAG,aAAa,CAAC,CAAC;AAE5E,QAAI,kBAAkB,SAAS,GAAG;AAChC,WAAK,KAAK,UAAU;AAAA,QAClB;AAAA,QACA,MAAM;AAAA,QACN,gBAAgB;AAAA,MAClB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,SAAK,SAAS,MAAM;AAAA,EACtB;AACF;;;AC7XA,SAAS,gBAAAG,qBAAoB;AAC7B,OAAO,YAAY;AACnB,OAAOC,SAAQ;AACf,OAAOC,WAAU;AACjB,OAAOC,eAAc;AAarB,IAAM,sBAAsB,OAAO;AAE5B,IAAM,mBAAN,cAA+BH,cAAa;AAAA,EACzC;AAAA,EACA;AAAA;AAAA,EAEA,YAAwE,oBAAI,IAAI;AAAA;AAAA,EAEhF,kBAA4C,oBAAI,IAAI;AAAA;AAAA,EAEpD,aAAkC,oBAAI,IAAI;AAAA,EAC1C;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EAEtB,YAAY,MAAc,SAA0B;AAClD,UAAM;AACN,SAAK,OAAO;AACZ,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,OAAsB;AAC1B,QAAI,KAAK,YAAa;AACtB,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAW,QAAgC;AAC/C,QAAI,KAAK,aAAa;AACpB,YAAM,KAAK;AACX;AAAA,IACF;AAEA,SAAK,cAAc,KAAK,YAAY,MAAM;AAC1C,UAAM,KAAK;AACX,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,MAAc,YAAY,QAAgC;AACxD,SAAK,gBAAgB,MAAM;AAC3B,SAAK,WAAW,MAAM;AAEtB,UAAM,aAAa;AACnB,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,YAAY;AAClD,YAAM,QAAQ,OAAO,MAAM,GAAG,IAAI,UAAU;AAC5C,YAAM,QAAQ,IAAI,MAAM,IAAI,WAAS,KAAK,aAAa,KAAK,CAAC,CAAC;AAAA,IAChE;AAAA,EACF;AAAA,EAEA,MAAc,aAAa,OAA6B;AACtD,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,iBAAiB,MAAM,MAAM,MAAM,YAAY;AACvE,UAAI,MAAM;AACR,aAAK,WAAW,IAAI,MAAM,MAAM,IAAI;AAEpC,YAAI,CAAC,KAAK,gBAAgB,IAAI,IAAI,GAAG;AACnC,eAAK,gBAAgB,IAAI,MAAM,oBAAI,IAAI,CAAC;AAAA,QAC1C;AACA,aAAK,gBAAgB,IAAI,IAAI,EAAG,IAAI,MAAM,IAAI;AAAA,MAChD;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,iBACZ,cACA,cACwB;AACxB,QAAI;AACF,YAAM,QAAQ,MAAMC,IAAG,SAAS,KAAK,YAAY;AAEjD,YAAM,SAAS,KAAK,UAAU,IAAI,YAAY;AAC9C,UAAI,UAAU,OAAO,UAAU,MAAM,WAAW,OAAO,SAAS,MAAM,MAAM;AAC1E,eAAO,OAAO;AAAA,MAChB;AAEA,YAAM,OAAO,MAAM,KAAK,gBAAgB,cAAc,MAAM,IAAI;AAEhE,WAAK,UAAU,IAAI,cAAc;AAAA,QAC/B;AAAA,QACA,OAAO,MAAM;AAAA,QACb,MAAM,MAAM;AAAA,MACd,CAAC;AAED,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,gBAAgB,cAAsB,MAA+B;AACjF,QAAI,OAAO,qBAAqB;AAC9B,aAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,cAAM,OAAO,OAAO,WAAW,KAAK;AACpC,cAAM,SAASA,IAAG,iBAAiB,YAAY;AAC/C,eAAO,GAAG,QAAQ,CAAC,UAAkB,KAAK,OAAO,KAAK,CAAC;AACvD,eAAO,GAAG,OAAO,MAAM,QAAQ,KAAK,OAAO,KAAK,CAAC,CAAC;AAClD,eAAO,GAAG,SAAS,MAAM;AAAA,MAC3B,CAAC;AAAA,IACH;AAEA,UAAM,UAAU,MAAMA,IAAG,SAAS,SAAS,YAAY;AACvD,WAAO,OAAO,WAAW,KAAK,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAAA,EAC9D;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,WAAkC;AACjD,UAAM,iBAAiB,UAAU,MAAMC,MAAK,GAAG,EAAE,KAAK,GAAG;AACzD,UAAM,OAAO,KAAK,WAAW,IAAI,cAAc;AAE/C,QAAI,CAAC,MAAM;AACT,aAAO,EAAE,MAAM,IAAI,iBAAiB,EAAE;AAAA,IACxC;AAEA,UAAM,QAAQ,KAAK,gBAAgB,IAAI,IAAI;AAC3C,UAAM,kBAAkB,QAAQ,MAAM,OAAO,IAAI;AAEjD,WAAO,EAAE,MAAM,gBAAgB;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoB,MAAwB;AAC1C,UAAM,QAAQ,KAAK,gBAAgB,IAAI,IAAI;AAC3C,WAAO,QAAQ,MAAM,KAAK,KAAK,EAAE,KAAK,IAAI,CAAC;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,WAAgE;AAC9D,QAAI,kBAAkB;AACtB,QAAI,iBAAiB;AAErB,eAAW,CAAC,EAAE,KAAK,KAAK,KAAK,iBAAiB;AAC5C,UAAI,MAAM,OAAO,GAAG;AAClB;AACA,0BAAkB,MAAM;AAAA,MAC1B;AAAA,IACF;AAEA,WAAO,EAAE,iBAAiB,eAAe;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,8BAA8B,QAAuB;AACnD,eAAW,SAAS,QAAQ;AAC1B,YAAM,OAAO,KAAK,iBAAiB,MAAM,IAAI;AAC7C,YAAM,cAAc,KAAK;AACzB,YAAM,kBAAkB,KAAK;AAAA,IAC/B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,kBACJ,OACA,cACA,cACe;AACf,UAAM,iBAAiB,aAAa,MAAMA,MAAK,GAAG,EAAE,KAAK,GAAG;AAC5D,UAAM,eAAe,KAAK,WAAW,IAAI,cAAc;AACvD,UAAM,iBAA2B,CAAC;AAElC,QAAI,cAAc;AAChB,qBAAe,KAAK,YAAY;AAChC,YAAM,WAAW,KAAK,gBAAgB,IAAI,YAAY;AACtD,UAAI,UAAU;AACZ,iBAAS,OAAO,cAAc;AAC9B,YAAI,SAAS,SAAS,GAAG;AACvB,eAAK,gBAAgB,OAAO,YAAY;AAAA,QAC1C;AAAA,MACF;AACA,WAAK,WAAW,OAAO,cAAc;AAAA,IACvC;AAEA,QAAI,UAAU,UAAU;AACtB,WAAK,UAAU,OAAO,cAAc;AAAA,IACtC,OAAO;AACL,UAAI;AACF,cAAM,QAAQ,MAAMD,IAAG,SAAS,KAAK,YAAY;AACjD,cAAM,OAAO,MAAM,KAAK,gBAAgB,cAAc,MAAM,IAAI;AAEhE,aAAK,UAAU,IAAI,gBAAgB;AAAA,UACjC;AAAA,UACA,OAAO,MAAM;AAAA,UACb,MAAM,MAAM;AAAA,QACd,CAAC;AACD,aAAK,WAAW,IAAI,gBAAgB,IAAI;AAExC,YAAI,CAAC,KAAK,gBAAgB,IAAI,IAAI,GAAG;AACnC,eAAK,gBAAgB,IAAI,MAAM,oBAAI,IAAI,CAAC;AAAA,QAC1C;AACA,aAAK,gBAAgB,IAAI,IAAI,EAAG,IAAI,cAAc;AAElD,YAAI,CAAC,eAAe,SAAS,IAAI,GAAG;AAClC,yBAAe,KAAK,IAAI;AAAA,QAC1B;AAAA,MACF,QAAQ;AAAA,MAAC;AAAA,IACX;AAEA,QAAI,eAAe,SAAS,GAAG;AAC7B,WAAK,KAAK,UAAU,EAAE,OAAO,eAAe,CAAC;AAAA,IAC/C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,cAAoB;AAClB,QAAI,KAAK,QAAS;AAElB,UAAM,aAAa,KAAK,QAAQ,QAAQ,IAAI,SAAOC,MAAK,KAAK,KAAK,MAAM,GAAG,CAAC;AAG5E,SAAK,UAAUC,UAAS,MAAM,YAAY;AAAA,MACxC,SAAS;AAAA,QACP,GAAG,KAAK,QAAQ,QAAQ,IAAI,OAAK,MAAM,CAAC,KAAK;AAAA,QAC7C,CAAC,aAAqB;AACpB,gBAAM,MAAMD,MAAK,QAAQ,QAAQ,EAAE,YAAY;AAC/C,iBAAO,QAAQ,MAAM,CAAC,KAAK,QAAQ,WAAW,SAAS,GAAG;AAAA,QAC5D;AAAA,MACF;AAAA,MACA,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,kBAAkB;AAAA,QAChB,oBAAoB;AAAA,QACpB,cAAc;AAAA,MAChB;AAAA,IACF,CAAC;AAED,SAAK,QAAQ,GAAG,OAAO,OAAM,aAAY;AACvC,YAAM,eAAeA,MAAK,SAAS,KAAK,MAAM,QAAQ;AACtD,YAAM,KAAK,kBAAkB,OAAO,cAAc,QAAQ;AAAA,IAC5D,CAAC;AAED,SAAK,QAAQ,GAAG,UAAU,OAAM,aAAY;AAC1C,YAAM,eAAeA,MAAK,SAAS,KAAK,MAAM,QAAQ;AACtD,YAAM,KAAK,kBAAkB,UAAU,cAAc,QAAQ;AAAA,IAC/D,CAAC;AAED,SAAK,QAAQ,GAAG,UAAU,OAAM,aAAY;AAC1C,YAAM,eAAeA,MAAK,SAAS,KAAK,MAAM,QAAQ;AACtD,YAAM,KAAK,kBAAkB,UAAU,cAAc,QAAQ;AAAA,IAC/D,CAAC;AAAA,EACH;AAAA,EAEA,UAAgB;AACd,SAAK,SAAS,MAAM;AACpB,SAAK,UAAU,MAAM;AACrB,SAAK,gBAAgB,MAAM;AAC3B,SAAK,WAAW,MAAM;AAAA,EACxB;AACF;;;ACjSA,OAAO,WAAW;AAClB,OAAOE,WAAU;AACjB,OAAOC,SAAQ;AACf,SAAS,kBAAkB;AAC3B,OAAO,QAAQ;AAER,IAAM,mBAAN,MAAuB;AAAA,EACpB;AAAA,EACA,QAA6B,oBAAI,IAAI;AAAA,EACrC;AAAA,EACA,mBAAmB,CAAC,QAAQ,SAAS,QAAQ,SAAS,SAAS,QAAQ,OAAO;AAAA,EAEtF,YAAY,OAAe,KAAK;AAC9B,SAAK,OAAO;AACZ,SAAK,WAAWD,MAAK,KAAK,GAAG,OAAO,GAAG,+BAA+B;AAAA,EACxE;AAAA,EAEA,MAAM,aAAa,cAA8C;AAC/D,UAAM,YAAYA,MAAK,QAAQ,YAAY,EAAE,YAAY;AAEzD,QAAI,CAAC,KAAK,iBAAiB,SAAS,SAAS,GAAG;AAC9C,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,MAAM,KAAK,YAAY,YAAY;AAEpD,UAAM,SAAS,KAAK,MAAM,IAAI,QAAQ;AACtC,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAEA,UAAM,aAAa,MAAM,KAAK,kBAAkB,QAAQ;AACxD,QAAI,YAAY;AACd,WAAK,MAAM,IAAI,UAAU,UAAU;AACnC,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,YAAY,MAAM,KAAK,kBAAkB,YAAY;AAC3D,WAAK,MAAM,IAAI,UAAU,SAAS;AAClC,YAAM,KAAK,gBAAgB,UAAU,SAAS;AAC9C,aAAO;AAAA,IACT,SAAS,OAAO;AACd,cAAQ,KAAK,oDAAoD,YAAY,KAAK,KAAK;AACvF,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,kBAAkB,cAAuC;AACrE,WAAO,MAAM,YAAY,EACtB,OAAO,KAAK,MAAM,KAAK,MAAM;AAAA,MAC5B,KAAK;AAAA,MACL,UAAU;AAAA,IACZ,CAAC,EACA,KAAK,EAAE,SAAS,GAAG,CAAC,EACpB,SAAS;AAAA,EACd;AAAA,EAEA,MAAc,YAAY,cAAuC;AAC/D,UAAM,OAAO,WAAW,KAAK;AAC7B,SAAK,OAAO,YAAY;AACxB,SAAK,OAAO,KAAK,KAAK,SAAS,CAAC;AAEhC,QAAI;AACF,YAAM,QAAQ,MAAMC,IAAG,KAAK,YAAY;AACxC,WAAK,OAAO,MAAM,QAAQ,SAAS,CAAC;AAAA,IACtC,QAAQ;AAAA,IAER;AAEA,WAAO,KAAK,OAAO,KAAK;AAAA,EAC1B;AAAA,EAEA,MAAc,kBAAkB,KAAqC;AACnE,QAAI;AACF,YAAM,YAAYD,MAAK,KAAK,KAAK,UAAU,GAAG,GAAG,MAAM;AACvD,aAAO,MAAMC,IAAG,SAAS,SAAS;AAAA,IACpC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAc,gBAAgB,KAAa,MAA6B;AACtE,QAAI;AACF,YAAMA,IAAG,MAAM,KAAK,UAAU,EAAE,WAAW,KAAK,CAAC;AACjD,YAAM,YAAYD,MAAK,KAAK,KAAK,UAAU,GAAG,GAAG,MAAM;AACvD,YAAMC,IAAG,UAAU,WAAW,IAAI;AAAA,IACpC,QAAQ;AAAA,IAER;AAAA,EACF;AAAA,EAEA,WAAW,cAA4B;AACrC,SAAK,YAAY,YAAY,EAAE,KAAK,SAAO;AACzC,WAAK,MAAM,OAAO,GAAG;AAAA,IACvB,CAAC;AAAA,EACH;AAAA,EAEA,kBAAkB,WAA4B;AAC5C,WAAO,KAAK,iBAAiB,SAAS,UAAU,YAAY,CAAC;AAAA,EAC/D;AACF;;;ACQO,IAAM,kBAAmC;AAAA,EAC9C,MAAM;AAAA,EACN,SAAS,CAAC,OAAO,QAAQ;AAAA,EACzB,SAAS,CAAC,gBAAgB,QAAQ,QAAQ,UAAU,UAAU;AAAA,EAC9D,YAAY;AAAA;AAAA;AAAA;AAAA,IAIV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA,IAIA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA,IAIA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA,IAIA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA,IAIA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA;AAAA;AAAA,IAIA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,OAAO;AAAA,EACP,cAAc;AAAA,EACd,cAAc;AAChB;AAEO,SAAS,eAAe,SAA+C;AAC5E,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAG;AAAA,EACL;AACF;;;ATjLA,IAAM,uBAAuB,CAAC,SAAiB;AAAA;AAAA;AAAA,sBAGzB,IAAI;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;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;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;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;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;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;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;AAsMnB,SAAS,yBAAyB,UAA+B,CAAC,GAAW;AAClF,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,MAAI;AAEJ,QAAM,kBAAkB,eAAe,OAAO;AAE9C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IAEP,eAAe,gBAAgB;AAC7B,eAAS;AAAA,IACX;AAAA,IAEA,gBAAgB,QAAuB;AACrC,gBAAU,IAAI,aAAa,OAAO,MAAM,eAAe;AACvD,wBAAkB,IAAI,gBAAgB,OAAO,MAAM,eAAe;AAClE,yBAAmB,IAAI,iBAAiB,OAAO,MAAM,eAAe;AACpE,yBAAmB,IAAI,iBAAiB,gBAAgB,aAAa;AAErE,sBAAgB,QAAQ;AAAA,QACtB,MAAM,gBAAgB;AAAA,QACtB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,MAAM,OAAO;AAAA,QACb,cAAc,gBAAgB;AAAA,MAChC,CAAC;AAED,cAAQ,KAAK,EAAE,KAAK,YAAY;AAC9B,cAAM,gBAAgB,KAAK;AAC3B,gBAAQ,yBAAyB,eAAe;AAEhD,cAAM,iBAAiB,KAAK;AAC5B,cAAM,iBAAiB,WAAW,QAAQ,UAAU,CAAC;AACrD,gBAAQ,wBAAwB,gBAAgB;AAEhD,YAAI,gBAAgB,OAAO;AACzB,2BAAiB,YAAY;AAAA,QAC/B;AAAA,MACF,CAAC;AAED,YAAM,aAAa,OAAO;AAC1B,aAAO,YAAY,MAAM;AACvB,mBAAW;AAEX,cAAM,WAAW,CAACC,SAChB,OAAO,KAAKA,KAAI,QAAQ,YAAY,CAAC,GAAG,SAAS,IAAI,OAAO,KAAK,IAAI,CAAC,GAAG,CAAC;AAE5E,YAAI,OAAO,GAAG,OAAO,OAAO,OAAO,QAAQ,UAAU,MAAM,gBAAgB,OAAO,OAAO,OAAO,QAAQ,IAAI;AAC5G,cAAM,MAAM,OAAO,cAAc,MAAM,CAAC;AACxC,YAAI,KAAK;AACP,cAAI;AACF,kBAAM,IAAI,IAAI,IAAI,GAAG;AACrB,mBAAO,GAAG,EAAE,QAAQ,KAAK,EAAE,IAAI;AAAA,UACjC,QAAQ;AAAA,UAAC;AAAA,QACX;AAEA,cAAM,OAAO,OAAO,OAAO,QAAQ;AACnC,cAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,gBAAgB,KAAK,QAAQ,OAAO,EAAE,CAAC;AAExE,eAAO,OAAO,OAAO;AAAA,UACnB,KAAK,OAAO,QAAQ,QAAG,CAAC,KAAK,OAAO,KAAK,eAAe,CAAC,UAAU,SAAS,OAAO,CAAC;AAAA,QACtF;AACA,eAAO,OAAO,OAAO;AAAA,UACnB,KAAK,OAAO,QAAQ,QAAG,CAAC,KAAK,OAAO,KAAK,eAAe,CAAC,WAAW,OAAO,OAAO,gCAAsB,CAAC;AAAA,QAC3G;AAAA,MACF;AAEA,UAAI,gBAAgB,OAAO;AACzB,gBAAQ,GAAG,UAAU,OAAM,UAAS;AAClC,gBAAM,iBAAiB,WAAW,QAAQ,UAAU,CAAC;AACrD,kBAAQ,wBAAwB,gBAAgB;AAChD,uBAAa,wBAAwB,KAAK;AAAA,QAC5C,CAAC;AACD,wBAAgB,GAAG,UAAU,WAAS;AACpC,kBAAQ,yBAAyB,eAAe;AAChD,uBAAa,kCAAkC,KAAK;AAAA,QACtD,CAAC;AACD,yBAAiB,GAAG,UAAU,WAAS;AACrC,kBAAQ,wBAAwB,gBAAgB;AAChD,uBAAa,mCAAmC,KAAK;AAAA,QACvD,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IAEA,qBAA+C;AAC7C,UAAI,CAAC,gBAAgB,cAAc;AACjC,eAAO,CAAC;AAAA,MACV;AAEA,aAAO;AAAA,QACL;AAAA,UACE,KAAK;AAAA,UACL,OAAO,EAAE,MAAM,SAAS;AAAA,UACxB,UAAU,qBAAqB,gBAAgB,IAAI,EAChD,QAAQ,qBAAqB,EAAE,EAC/B,KAAK;AAAA,UACR,UAAU;AAAA,QACZ;AAAA,MACF;AAAA,IACF;AAAA,IAEA,UAAU,IAAI;AACZ,UAAI,OAAO,gCAAgC;AACzC,eAAO;AAAA,MACT;AAAA,IACF;AAAA,IAEA,KAAK,IAAI;AACP,UAAI,OAAO,kCAAkC;AAC3C,eAAO,kBAAkB,KAAK,UAAU;AAAA,UACtC,MAAM,gBAAgB;AAAA,UACtB,YAAY,gBAAgB;AAAA,QAC9B,CAAC,CAAC;AAAA,MACJ;AAAA,IACF;AAAA,IAEA,WAAW;AACT,eAAS,QAAQ;AACjB,uBAAiB,QAAQ;AACzB,wBAAkB,QAAQ;AAAA,IAC5B;AAAA,EACF;AACF;;;AU5Ue,SAAR,aAA8B,UAA+B,CAAC,GAAW;AAC9E,SAAO,yBAAyB,OAAO;AACzC;","names":["path","fs","path","path","__dirname","path","fs","launchEditor","path","fs","EventEmitter","fg","path","fs","chokidar","EventEmitter","fs","path","chokidar","path","fs","url"]}
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts","../src/server/index.ts","../src/server/api.ts","../src/server/editor-launcher.ts","../src/server/file-revealer.ts","../src/server/scanner.ts","../src/server/importer-scanner.ts","../src/server/duplicate-scanner.ts","../src/server/thumbnail.ts","../src/shared/types.ts","../src/index.ts"],"sourcesContent":["import type { Plugin, ViteDevServer, ResolvedConfig, IndexHtmlTransformResult } from 'vite'\nimport colors from 'picocolors'\nimport { setupMiddleware } from './server/index.js'\nimport { AssetScanner } from './server/scanner.js'\nimport { ImporterScanner } from './server/importer-scanner.js'\nimport { DuplicateScanner } from './server/duplicate-scanner.js'\nimport { ThumbnailService } from './server/thumbnail.js'\nimport { broadcastSSE } from './server/api.js'\nimport { resolveOptions, type AssetManagerOptions } from './shared/types.js'\n\nconst FLOATING_ICON_SCRIPT = (base: string) => `\n<script type=\"module\">\n(function() {\n const BASE_URL = '${base}';\n const STORAGE_KEY = 'vite-asset-manager-open';\n\n // Styles for the floating button and overlay\n const styles = document.createElement('style');\n styles.textContent = \\`\n #vam-trigger {\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 48px;\n height: 48px;\n border-radius: 14px;\n background: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);\n border: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n box-shadow: 0 4px 24px -4px rgba(139, 92, 246, 0.5), 0 0 0 1px rgba(255,255,255,0.1) inset;\n transition: all 0.2s ease;\n z-index: 99998;\n }\n #vam-trigger:hover {\n transform: translateY(-2px) scale(1.05);\n box-shadow: 0 8px 32px -4px rgba(139, 92, 246, 0.6), 0 0 0 1px rgba(255,255,255,0.15) inset;\n }\n #vam-trigger:active {\n transform: translateY(0) scale(0.98);\n }\n #vam-trigger svg {\n width: 24px;\n height: 24px;\n color: white;\n }\n #vam-overlay {\n position: fixed;\n inset: 0;\n background: rgba(0, 0, 0, 0.6);\n backdrop-filter: blur(4px);\n z-index: 99999;\n opacity: 0;\n visibility: hidden;\n transition: opacity 0.3s ease, visibility 0.3s ease;\n }\n #vam-overlay.open {\n opacity: 1;\n visibility: visible;\n }\n #vam-panel {\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n width: min(90vw, 1200px);\n background: #09090b;\n border-left: 1px solid rgba(255,255,255,0.08);\n transform: translateX(100%);\n transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1);\n z-index: 100000;\n display: flex;\n flex-direction: column;\n }\n #vam-overlay.open #vam-panel {\n transform: translateX(0);\n }\n #vam-panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 16px;\n border-bottom: 1px solid rgba(255,255,255,0.08);\n background: #0f0f11;\n }\n #vam-panel-title {\n font-family: 'JetBrains Mono', ui-monospace, monospace;\n font-size: 12px;\n font-weight: 600;\n color: #fafafa;\n letter-spacing: 0.05em;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n #vam-panel-title svg {\n width: 18px;\n height: 18px;\n color: #8b5cf6;\n }\n #vam-close-btn {\n width: 32px;\n height: 32px;\n border-radius: 8px;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #71717a;\n transition: all 0.15s ease;\n }\n #vam-close-btn:hover {\n background: rgba(255,255,255,0.1);\n color: #fafafa;\n }\n #vam-iframe {\n flex: 1;\n border: none;\n width: 100%;\n height: 100%;\n }\n \\`;\n document.head.appendChild(styles);\n\n // Create trigger button\n const trigger = document.createElement('button');\n trigger.id = 'vam-trigger';\n trigger.title = 'Open Asset Manager (⌥⇧A)';\n trigger.innerHTML = \\`\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\">\n <path d=\"M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40Zm0,16V88H40V56Zm0,144H40V104H216v96ZM64,128a8,8,0,0,1,8-8h80a8,8,0,0,1,0,16H72A8,8,0,0,1,64,128Zm0,32a8,8,0,0,1,8-8h80a8,8,0,0,1,0,16H72A8,8,0,0,1,64,160Z\"/>\n </svg>\n \\`;\n\n // Create overlay and panel\n const overlay = document.createElement('div');\n overlay.id = 'vam-overlay';\n overlay.innerHTML = \\`\n <div id=\"vam-panel\">\n <div id=\"vam-panel-header\">\n <div id=\"vam-panel-title\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 256 256\" fill=\"currentColor\">\n <path d=\"M216,40H40A16,16,0,0,0,24,56V200a16,16,0,0,0,16,16H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40Zm0,160H40V56H216V200ZM176,88a48,48,0,1,0-96,0,48,48,0,0,0,96,0Zm-48,32a32,32,0,1,1,32-32A32,32,0,0,1,128,120Zm80,56a8,8,0,0,1-8,8H56a8,8,0,0,1-6.65-12.44l24-36a8,8,0,0,1,13.3,0l15.18,22.77,24.89-41.48a8,8,0,0,1,13.72.18l40,64A8,8,0,0,1,208,176Z\"/>\n </svg>\n ASSET MANAGER\n </div>\n <button id=\"vam-close-btn\" title=\"Close (Esc)\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 256 256\" fill=\"currentColor\">\n <path d=\"M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z\"/>\n </svg>\n </button>\n </div>\n <iframe id=\"vam-iframe\" src=\"\\${BASE_URL}?embedded=true\"></iframe>\n </div>\n \\`;\n\n document.body.appendChild(trigger);\n document.body.appendChild(overlay);\n\n // State management\n let isOpen = sessionStorage.getItem(STORAGE_KEY) === 'true';\n\n function open() {\n isOpen = true;\n overlay.classList.add('open');\n sessionStorage.setItem(STORAGE_KEY, 'true');\n }\n\n function close() {\n isOpen = false;\n overlay.classList.remove('open');\n sessionStorage.setItem(STORAGE_KEY, 'false');\n }\n\n // Restore state\n if (isOpen) {\n requestAnimationFrame(() => open());\n }\n\n // Event listeners\n trigger.addEventListener('click', () => {\n if (isOpen) close();\n else open();\n });\n\n overlay.addEventListener('click', (e) => {\n if (e.target === overlay) close();\n });\n\n document.getElementById('vam-close-btn').addEventListener('click', close);\n\n document.addEventListener('keydown', (e) => {\n // Close on Escape\n if (e.key === 'Escape' && isOpen) {\n close();\n }\n // Toggle on Option/Alt + Shift + A\n if (e.altKey && e.shiftKey && e.code === 'KeyA') {\n e.preventDefault();\n if (isOpen) close();\n else open();\n }\n });\n})();\n</script>\n`\n\nexport function createAssetManagerPlugin(options: AssetManagerOptions = {}): Plugin {\n let config: ResolvedConfig\n let scanner: AssetScanner\n let importerScanner: ImporterScanner\n let duplicateScanner: DuplicateScanner\n let thumbnailService: ThumbnailService\n\n const resolvedOptions = resolveOptions(options)\n\n return {\n name: 'vite-plugin-asset-manager',\n apply: 'serve',\n\n configResolved(resolvedConfig) {\n config = resolvedConfig\n },\n\n configureServer(server: ViteDevServer) {\n scanner = new AssetScanner(config.root, resolvedOptions)\n importerScanner = new ImporterScanner(config.root, resolvedOptions)\n duplicateScanner = new DuplicateScanner(config.root, resolvedOptions)\n thumbnailService = new ThumbnailService(resolvedOptions.thumbnailSize)\n\n setupMiddleware(server, {\n base: resolvedOptions.base,\n scanner,\n importerScanner,\n duplicateScanner,\n thumbnailService,\n root: config.root,\n launchEditor: resolvedOptions.launchEditor\n })\n\n scanner.init().then(async () => {\n await importerScanner.init()\n scanner.enrichWithImporterCounts(importerScanner)\n\n await duplicateScanner.init()\n await duplicateScanner.scanAssets(scanner.getAssets())\n scanner.enrichWithDuplicateInfo(duplicateScanner)\n\n if (resolvedOptions.watch) {\n duplicateScanner.initWatcher()\n }\n })\n\n const _printUrls = server.printUrls\n server.printUrls = () => {\n _printUrls()\n\n const colorUrl = (url: string) =>\n colors.cyan(url.replace(/:(\\d+)\\//, (_, port) => `:${colors.bold(port)}/`))\n\n let host = `${server.config.server.https ? 'https' : 'http'}://localhost:${server.config.server.port || '80'}`\n const url = server.resolvedUrls?.local[0]\n if (url) {\n try {\n const u = new URL(url)\n host = `${u.protocol}//${u.host}`\n } catch {}\n }\n\n const base = server.config.base || '/'\n const fullUrl = `${host}${base}${resolvedOptions.base.replace(/^\\//, '')}/`\n\n server.config.logger.info(\n ` ${colors.magenta('➜')} ${colors.bold('Asset Manager')}: Open ${colorUrl(fullUrl)} as a separate window`\n )\n server.config.logger.info(\n ` ${colors.magenta('➜')} ${colors.bold('Asset Manager')}: Press ${colors.yellow('Option(⌥)+Shift(⇧)+A')} in App to toggle the Asset Manager`\n )\n }\n\n if (resolvedOptions.watch) {\n scanner.on('change', async event => {\n await duplicateScanner.scanAssets(scanner.getAssets())\n scanner.enrichWithDuplicateInfo(duplicateScanner)\n broadcastSSE('asset-manager:update', event)\n })\n importerScanner.on('change', event => {\n scanner.enrichWithImporterCounts(importerScanner)\n broadcastSSE('asset-manager:importers-update', event)\n })\n duplicateScanner.on('change', event => {\n scanner.enrichWithDuplicateInfo(duplicateScanner)\n broadcastSSE('asset-manager:duplicates-update', event)\n })\n }\n },\n\n transformIndexHtml(): IndexHtmlTransformResult {\n if (!resolvedOptions.floatingIcon) {\n return []\n }\n\n return [\n {\n tag: 'script',\n attrs: { type: 'module' },\n children: FLOATING_ICON_SCRIPT(resolvedOptions.base)\n .replace(/<\\/?script[^>]*>/g, '')\n .trim(),\n injectTo: 'body'\n }\n ]\n },\n\n resolveId(id) {\n if (id === 'virtual:asset-manager-config') {\n return '\\0virtual:asset-manager-config'\n }\n },\n\n load(id) {\n if (id === '\\0virtual:asset-manager-config') {\n return `export default ${JSON.stringify({\n base: resolvedOptions.base,\n extensions: resolvedOptions.extensions\n })}`\n }\n },\n\n buildEnd() {\n scanner?.destroy()\n importerScanner?.destroy()\n duplicateScanner?.destroy()\n }\n }\n}\n","import type { ViteDevServer } from 'vite'\nimport sirv from 'sirv'\nimport path from 'path'\nimport fs from 'fs'\nimport { fileURLToPath } from 'url'\nimport { createApiRouter } from './api.js'\nimport type { AssetScanner } from './scanner.js'\nimport type { ImporterScanner } from './importer-scanner.js'\nimport type { DuplicateScanner } from './duplicate-scanner.js'\nimport type { ThumbnailService } from './thumbnail.js'\nimport type { EditorType } from '../shared/types.js'\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url))\n\nfunction findClientDir(): string {\n // When running from built dist: __dirname is dist/, client is at dist/client\n const fromDist = path.join(__dirname, 'client')\n if (fs.existsSync(fromDist)) {\n return fromDist\n }\n\n // When running from source (e.g., playground): __dirname is src/server, client is at dist/client\n const fromSource = path.resolve(__dirname, '../../dist/client')\n if (fs.existsSync(fromSource)) {\n return fromSource\n }\n\n // Fallback - will show error if client not built\n return fromDist\n}\n\nexport interface MiddlewareContext {\n base: string\n scanner: AssetScanner\n importerScanner: ImporterScanner\n duplicateScanner: DuplicateScanner\n thumbnailService: ThumbnailService\n root: string\n launchEditor: EditorType\n}\n\nexport function setupMiddleware(server: ViteDevServer, context: MiddlewareContext): void {\n const { base, scanner, importerScanner, duplicateScanner, thumbnailService, root, launchEditor } =\n context\n\n const apiRouter = createApiRouter(\n scanner,\n importerScanner,\n duplicateScanner,\n thumbnailService,\n root,\n base,\n launchEditor\n )\n\n const clientDir = findClientDir()\n\n server.middlewares.use((req, res, next) => {\n const url = req.url || ''\n\n if (url.startsWith(`${base}/api/`)) {\n return apiRouter(req, res, next)\n }\n\n if (url === base || url.startsWith(`${base}/`)) {\n const serve = sirv(clientDir, {\n single: true,\n dev: true\n })\n\n req.url = url.slice(base.length) || '/'\n return serve(req, res, next)\n }\n\n next()\n })\n}\n","import type { IncomingMessage, ServerResponse } from 'http'\nimport { parse as parseUrl } from 'url'\nimport path from 'path'\nimport fs from 'fs'\nimport archiver from 'archiver'\nimport type { AssetScanner } from './scanner.js'\nimport type { ImporterScanner } from './importer-scanner.js'\nimport type { DuplicateScanner } from './duplicate-scanner.js'\nimport type { ThumbnailService } from './thumbnail.js'\nimport { launchEditor } from './editor-launcher.js'\nimport { revealInFileExplorer } from './file-revealer.js'\nimport type { AssetStats, AssetType, EditorType } from '../shared/types.js'\n\ntype NextFunction = () => void\n\nconst sseClients = new Set<ServerResponse>()\n\nconst MIME_TYPES: Record<string, string> = {\n /**\n * Images:\n */\n '.png': 'image/png',\n '.jpg': 'image/jpeg',\n '.jpeg': 'image/jpeg',\n '.gif': 'image/gif',\n '.svg': 'image/svg+xml',\n '.webp': 'image/webp',\n '.avif': 'image/avif',\n '.ico': 'image/x-icon',\n '.bmp': 'image/bmp',\n '.tiff': 'image/tiff',\n '.tif': 'image/tiff',\n '.heic': 'image/heic',\n '.heif': 'image/heif',\n /**\n * Videos:\n */\n '.mp4': 'video/mp4',\n '.webm': 'video/webm',\n '.ogg': 'video/ogg',\n '.mov': 'video/quicktime',\n /**\n * Audio:\n */\n '.mp3': 'audio/mpeg',\n '.wav': 'audio/wav',\n /**\n * Documents:\n */\n '.pdf': 'application/pdf',\n '.json': 'application/json',\n '.md': 'text/markdown',\n '.txt': 'text/plain',\n '.csv': 'text/csv',\n /**\n * Config files:\n */\n '.yml': 'text/yaml',\n '.yaml': 'text/yaml',\n '.toml': 'application/toml',\n '.xml': 'application/xml',\n /**\n * Fonts:\n */\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.ttf': 'font/ttf',\n '.otf': 'font/otf',\n '.eot': 'application/vnd.ms-fontobject'\n}\n\nexport function createApiRouter(\n scanner: AssetScanner,\n importerScanner: ImporterScanner,\n duplicateScanner: DuplicateScanner,\n thumbnailService: ThumbnailService,\n root: string,\n basePath: string,\n editor: EditorType\n) {\n return async (req: IncomingMessage, res: ServerResponse, next: NextFunction) => {\n const { pathname, query } = parseUrl(req.url || '', true)\n const apiPath = pathname?.replace(`${basePath}/api`, '') || ''\n\n try {\n switch (apiPath) {\n case '/assets':\n return handleGetAssets(res, scanner, query)\n case '/assets/grouped':\n return handleGetGroupedAssets(res, scanner, query)\n case '/search':\n return handleSearch(res, scanner, query)\n case '/thumbnail':\n return handleThumbnail(res, thumbnailService, root, query)\n case '/file':\n return handleServeFile(res, root, query)\n case '/stats':\n return handleGetStats(res, scanner, duplicateScanner)\n case '/duplicates':\n return handleGetDuplicates(res, scanner, duplicateScanner, query)\n case '/importers':\n return handleGetImporters(res, importerScanner, query)\n case '/open-in-editor':\n return handleOpenInEditor(req, res, root, editor, query)\n case '/reveal-in-finder':\n return handleRevealInFinder(req, res, root, query)\n case '/bulk-download':\n return handleBulkDownload(req, res, root)\n case '/bulk-delete':\n return handleBulkDelete(req, res, root)\n case '/events':\n return handleSSE(res)\n default:\n next()\n }\n } catch (error) {\n console.error('[asset-manager] API error:', error)\n res.statusCode = 500\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify({ error: 'Internal server error' }))\n }\n }\n}\n\nasync function handleGetAssets(\n res: ServerResponse,\n scanner: AssetScanner,\n query: Record<string, any>\n) {\n const assets = scanner.getAssets()\n\n let filtered = assets\n\n const directory = query.directory as string | undefined\n if (directory) {\n filtered = filtered.filter(\n a => a.directory === directory || a.directory.startsWith(directory + '/')\n )\n }\n\n const type = query.type as AssetType | undefined\n if (type) {\n filtered = filtered.filter(a => a.type === type)\n }\n\n sendJson(res, { assets: filtered, total: filtered.length })\n}\n\nasync function handleGetGroupedAssets(\n res: ServerResponse,\n scanner: AssetScanner,\n query: Record<string, any>\n) {\n let groups = scanner.getGroupedAssets()\n\n const type = query.type as AssetType | undefined\n if (type) {\n groups = groups\n .map(group => ({\n ...group,\n assets: group.assets.filter(a => a.type === type),\n count: group.assets.filter(a => a.type === type).length\n }))\n .filter(group => group.count > 0)\n }\n\n const unused = query.unused === 'true'\n if (unused) {\n groups = groups\n .map(group => ({\n ...group,\n assets: group.assets.filter(a => a.importersCount === 0),\n count: group.assets.filter(a => a.importersCount === 0).length\n }))\n .filter(group => group.count > 0)\n }\n\n const duplicates = query.duplicates === 'true'\n if (duplicates) {\n groups = groups\n .map(group => ({\n ...group,\n assets: group.assets.filter(a => (a.duplicatesCount ?? 0) > 0),\n count: group.assets.filter(a => (a.duplicatesCount ?? 0) > 0).length\n }))\n .filter(group => group.count > 0)\n }\n\n const minSize = query.minSize ? parseInt(query.minSize as string, 10) : undefined\n const maxSize = query.maxSize ? parseInt(query.maxSize as string, 10) : undefined\n if (minSize !== undefined || maxSize !== undefined) {\n groups = groups\n .map(group => ({\n ...group,\n assets: group.assets.filter(a => {\n if (minSize !== undefined && a.size < minSize) return false\n if (maxSize !== undefined && a.size > maxSize) return false\n return true\n })\n }))\n .map(g => ({ ...g, count: g.assets.length }))\n .filter(g => g.count > 0)\n }\n\n const minDate = query.minDate ? parseInt(query.minDate as string, 10) : undefined\n const maxDate = query.maxDate ? parseInt(query.maxDate as string, 10) : undefined\n if (minDate !== undefined || maxDate !== undefined) {\n groups = groups\n .map(group => ({\n ...group,\n assets: group.assets.filter(a => {\n if (minDate !== undefined && a.mtime < minDate) return false\n if (maxDate !== undefined && a.mtime > maxDate) return false\n return true\n })\n }))\n .map(g => ({ ...g, count: g.assets.length }))\n .filter(g => g.count > 0)\n }\n\n const extensions = query.extensions as string | undefined\n if (extensions) {\n const extList = extensions.split(',').map(e => e.trim().toLowerCase())\n groups = groups\n .map(group => ({\n ...group,\n assets: group.assets.filter(a => extList.includes(a.extension.toLowerCase()))\n }))\n .map(g => ({ ...g, count: g.assets.length }))\n .filter(g => g.count > 0)\n }\n\n const total = groups.reduce((sum, g) => sum + g.count, 0)\n sendJson(res, { groups, total })\n}\n\nasync function handleSearch(\n res: ServerResponse,\n scanner: AssetScanner,\n query: Record<string, any>\n) {\n const q = (query.q as string) || ''\n let results = scanner.search(q)\n\n const minSize = query.minSize ? parseInt(query.minSize as string, 10) : undefined\n const maxSize = query.maxSize ? parseInt(query.maxSize as string, 10) : undefined\n const minDate = query.minDate ? parseInt(query.minDate as string, 10) : undefined\n const maxDate = query.maxDate ? parseInt(query.maxDate as string, 10) : undefined\n const extensions = query.extensions as string | undefined\n\n if (minSize !== undefined) results = results.filter(a => a.size >= minSize)\n if (maxSize !== undefined) results = results.filter(a => a.size <= maxSize)\n if (minDate !== undefined) results = results.filter(a => a.mtime >= minDate)\n if (maxDate !== undefined) results = results.filter(a => a.mtime <= maxDate)\n if (extensions) {\n const extList = extensions.split(',').map(e => e.trim().toLowerCase())\n results = results.filter(a => extList.includes(a.extension.toLowerCase()))\n }\n\n sendJson(res, { assets: results, total: results.length, query: q })\n}\n\nasync function handleThumbnail(\n res: ServerResponse,\n thumbnailService: ThumbnailService,\n root: string,\n query: Record<string, any>\n) {\n const relativePath = query.path as string\n if (!relativePath) {\n res.statusCode = 400\n res.end('Missing path parameter')\n return\n }\n\n const absolutePath = path.resolve(root, relativePath)\n\n if (!absolutePath.startsWith(root)) {\n res.statusCode = 403\n res.end('Forbidden')\n return\n }\n\n if (relativePath.endsWith('.svg')) {\n res.setHeader('Content-Type', 'image/svg+xml')\n res.setHeader('Cache-Control', 'public, max-age=31536000')\n fs.createReadStream(absolutePath).pipe(res)\n return\n }\n\n const thumbnail = await thumbnailService.getThumbnail(absolutePath)\n\n if (thumbnail) {\n res.setHeader('Content-Type', 'image/jpeg')\n res.setHeader('Cache-Control', 'public, max-age=31536000')\n res.end(thumbnail)\n } else {\n const ext = path.extname(relativePath).toLowerCase()\n res.setHeader('Content-Type', MIME_TYPES[ext] || 'application/octet-stream')\n fs.createReadStream(absolutePath).pipe(res)\n }\n}\n\nasync function handleServeFile(res: ServerResponse, root: string, query: Record<string, any>) {\n const relativePath = query.path as string\n if (!relativePath) {\n res.statusCode = 400\n res.end('Missing path parameter')\n return\n }\n\n const absolutePath = path.resolve(root, relativePath)\n\n if (!absolutePath.startsWith(root)) {\n res.statusCode = 403\n res.end('Forbidden')\n return\n }\n\n try {\n await fs.promises.access(absolutePath, fs.constants.R_OK)\n } catch {\n res.statusCode = 404\n res.end('File not found')\n return\n }\n\n const ext = path.extname(relativePath).toLowerCase()\n res.setHeader('Content-Type', MIME_TYPES[ext] || 'application/octet-stream')\n res.setHeader('Cache-Control', 'public, max-age=3600')\n fs.createReadStream(absolutePath).pipe(res)\n}\n\nasync function handleGetStats(\n res: ServerResponse,\n scanner: AssetScanner,\n duplicateScanner: DuplicateScanner\n) {\n const assets = scanner.getAssets()\n const dupStats = duplicateScanner.getStats()\n\n const extensionCounts = new Map<string, number>()\n for (const asset of assets) {\n const ext = asset.extension.toLowerCase()\n extensionCounts.set(ext, (extensionCounts.get(ext) || 0) + 1)\n }\n\n const stats: AssetStats = {\n total: assets.length,\n byType: {\n image: assets.filter(a => a.type === 'image').length,\n video: assets.filter(a => a.type === 'video').length,\n audio: assets.filter(a => a.type === 'audio').length,\n document: assets.filter(a => a.type === 'document').length,\n font: assets.filter(a => a.type === 'font').length,\n data: assets.filter(a => a.type === 'data').length,\n text: assets.filter(a => a.type === 'text').length,\n other: assets.filter(a => a.type === 'other').length\n },\n totalSize: assets.reduce((sum, a) => sum + a.size, 0),\n directories: [...new Set(assets.map(a => a.directory))].length,\n unused: assets.filter(a => a.importersCount === 0).length,\n duplicateGroups: dupStats.duplicateGroups,\n duplicateFiles: dupStats.duplicateFiles,\n extensionBreakdown: Object.fromEntries(extensionCounts)\n }\n\n sendJson(res, stats)\n}\n\nasync function handleGetDuplicates(\n res: ServerResponse,\n scanner: AssetScanner,\n duplicateScanner: DuplicateScanner,\n query: Record<string, any>\n) {\n const hash = query.hash as string\n\n if (hash) {\n // Get specific duplicate group by hash\n const paths = duplicateScanner.getDuplicatesByHash(hash)\n const assets = scanner.getAssets().filter(a => paths.includes(a.path))\n sendJson(res, { duplicates: assets, total: assets.length, hash })\n } else {\n // Get all assets that have duplicates\n const assets = scanner.getAssets().filter(a => (a.duplicatesCount ?? 0) > 0)\n sendJson(res, { duplicates: assets, total: assets.length })\n }\n}\n\nfunction sendJson(res: ServerResponse, data: unknown) {\n res.setHeader('Content-Type', 'application/json')\n res.end(JSON.stringify(data))\n}\n\nfunction handleSSE(res: ServerResponse) {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n Connection: 'keep-alive',\n 'Access-Control-Allow-Origin': '*'\n })\n\n res.write(`data: ${JSON.stringify({ type: 'connected' })}\\n\\n`)\n\n sseClients.add(res)\n\n res.on('close', () => {\n sseClients.delete(res)\n })\n}\n\nexport function broadcastSSE(event: string, data: unknown) {\n const message = JSON.stringify({ event, data })\n for (const client of sseClients) {\n client.write(`data: ${message}\\n\\n`)\n }\n}\n\nasync function handleGetImporters(\n res: ServerResponse,\n importerScanner: ImporterScanner,\n query: Record<string, any>\n) {\n const assetPath = query.path as string\n if (!assetPath) {\n res.statusCode = 400\n sendJson(res, { error: 'Missing path parameter' })\n return\n }\n\n const importers = importerScanner.getImporters(assetPath)\n sendJson(res, { importers, total: importers.length })\n}\n\nasync function handleOpenInEditor(\n req: IncomingMessage,\n res: ServerResponse,\n root: string,\n editor: EditorType,\n query: Record<string, any>\n) {\n if (req.method !== 'POST') {\n res.statusCode = 405\n sendJson(res, { error: 'Method not allowed' })\n return\n }\n\n const filePath = query.file as string\n const line = parseInt(query.line as string) || 1\n const column = parseInt(query.column as string) || 1\n\n if (!filePath) {\n res.statusCode = 400\n sendJson(res, { error: 'Missing file parameter' })\n return\n }\n\n const absolutePath = path.resolve(root, filePath)\n\n if (!absolutePath.startsWith(root)) {\n res.statusCode = 403\n sendJson(res, { error: 'Forbidden' })\n return\n }\n\n try {\n await fs.promises.access(absolutePath, fs.constants.R_OK)\n } catch {\n res.statusCode = 404\n sendJson(res, { error: 'File not found' })\n return\n }\n\n try {\n await launchEditor(absolutePath, line, column, editor)\n sendJson(res, { success: true })\n } catch (error) {\n res.statusCode = 500\n sendJson(res, { error: error instanceof Error ? error.message : 'Failed to open editor' })\n }\n}\n\nasync function handleRevealInFinder(\n req: IncomingMessage,\n res: ServerResponse,\n root: string,\n query: Record<string, any>\n) {\n if (req.method !== 'POST') {\n res.statusCode = 405\n sendJson(res, { error: 'Method not allowed' })\n return\n }\n\n const filePath = query.path as string\n\n if (!filePath) {\n res.statusCode = 400\n sendJson(res, { error: 'Missing path parameter' })\n return\n }\n\n const absolutePath = path.resolve(root, filePath)\n\n // Security: validate path is within project root\n if (!absolutePath.startsWith(root)) {\n res.statusCode = 403\n sendJson(res, { error: 'Invalid path' })\n return\n }\n\n // Check if file exists\n try {\n await fs.promises.access(absolutePath, fs.constants.R_OK)\n } catch {\n res.statusCode = 404\n sendJson(res, { error: 'File not found' })\n return\n }\n\n try {\n await revealInFileExplorer(absolutePath)\n sendJson(res, { success: true })\n } catch (error) {\n res.statusCode = 500\n sendJson(res, {\n error: error instanceof Error ? error.message : 'Failed to reveal file'\n })\n }\n}\n\nasync function parseJsonBody(req: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let body = ''\n req.on('data', (chunk: Buffer) => {\n body += chunk.toString()\n })\n req.on('end', () => {\n try {\n resolve(JSON.parse(body))\n } catch {\n reject(new Error('Invalid JSON'))\n }\n })\n req.on('error', reject)\n })\n}\n\nasync function handleBulkDownload(req: IncomingMessage, res: ServerResponse, root: string) {\n if (req.method !== 'POST') {\n res.statusCode = 405\n sendJson(res, { error: 'Method not allowed' })\n return\n }\n\n let body: { paths?: string[] }\n try {\n body = (await parseJsonBody(req)) as { paths?: string[] }\n } catch {\n res.statusCode = 400\n sendJson(res, { error: 'Invalid JSON body' })\n return\n }\n\n const paths = body.paths\n if (!Array.isArray(paths) || paths.length === 0) {\n res.statusCode = 400\n sendJson(res, { error: 'Missing or invalid paths array' })\n return\n }\n\n const validatedPaths: { relativePath: string; absolutePath: string }[] = []\n\n for (const relativePath of paths) {\n const absolutePath = path.resolve(root, relativePath)\n\n if (!absolutePath.startsWith(root)) {\n res.statusCode = 403\n sendJson(res, { error: `Forbidden path: ${relativePath}` })\n return\n }\n\n try {\n await fs.promises.access(absolutePath, fs.constants.R_OK)\n validatedPaths.push({ relativePath, absolutePath })\n } catch {\n console.warn(`[asset-manager] Bulk download skipping missing file: ${relativePath}`)\n }\n }\n\n if (validatedPaths.length === 0) {\n res.statusCode = 404\n sendJson(res, { error: 'No valid files found' })\n return\n }\n\n res.setHeader('Content-Type', 'application/zip')\n res.setHeader('Content-Disposition', `attachment; filename=\"assets-${Date.now()}.zip\"`)\n\n const archive = archiver('zip', { zlib: { level: 6 } })\n\n archive.on('error', err => {\n console.error('[asset-manager] ZIP creation error:', err)\n if (!res.headersSent) {\n res.statusCode = 500\n res.end('ZIP creation failed')\n }\n })\n\n archive.pipe(res)\n\n for (const { relativePath, absolutePath } of validatedPaths) {\n archive.file(absolutePath, { name: relativePath })\n }\n\n await archive.finalize()\n}\n\nasync function handleBulkDelete(req: IncomingMessage, res: ServerResponse, root: string) {\n if (req.method !== 'POST') {\n res.statusCode = 405\n sendJson(res, { error: 'Method not allowed' })\n return\n }\n\n let body: { paths?: string[] }\n try {\n body = (await parseJsonBody(req)) as { paths?: string[] }\n } catch {\n res.statusCode = 400\n sendJson(res, { error: 'Invalid JSON body' })\n return\n }\n\n const paths = body.paths\n if (!Array.isArray(paths) || paths.length === 0) {\n res.statusCode = 400\n sendJson(res, { error: 'Missing or invalid paths array' })\n return\n }\n\n const results = {\n deleted: 0,\n failed: [] as string[],\n errors: [] as string[]\n }\n\n for (const relativePath of paths) {\n const absolutePath = path.resolve(root, relativePath)\n\n if (!absolutePath.startsWith(root)) {\n results.failed.push(relativePath)\n results.errors.push(`Forbidden path: ${relativePath}`)\n continue\n }\n\n try {\n await fs.promises.unlink(absolutePath)\n results.deleted++\n } catch (error) {\n results.failed.push(relativePath)\n results.errors.push(error instanceof Error ? error.message : 'Unknown error')\n }\n }\n\n sendJson(res, {\n deleted: results.deleted,\n failed: results.failed.length,\n errors: results.errors\n })\n}\n","import launch from 'launch-editor'\nimport type { EditorType } from '../shared/types.js'\n\n/**\n * Opens a file in the configured editor at the specified line and column.\n *\n * @param absolutePath - Absolute path to the file\n * @param line - Line number (1-indexed)\n * @param column - Column number (1-indexed)\n * @param editor - Editor to open the file in\n */\nexport function launchEditor(\n absolutePath: string,\n line: number,\n column: number,\n editor: EditorType\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const fileSpec = `${absolutePath}:${line}:${column}`\n\n launch(fileSpec, editor, (_fileName: string, errorMsg: string | null) => {\n if (errorMsg) {\n reject(new Error(errorMsg))\n } else {\n resolve()\n }\n })\n })\n}\n","import { spawn } from 'child_process'\nimport path from 'path'\n\n/**\n * Opens the file in the system's file explorer and highlights it\n * @param absolutePath Absolute path to the file to reveal\n */\nexport async function revealInFileExplorer(absolutePath: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const platform = process.platform\n\n let command: string\n let args: string[]\n\n switch (platform) {\n case 'darwin': // macOS\n command = 'open'\n args = ['-R', absolutePath]\n break\n\n case 'win32': // Windows\n command = 'explorer'\n args = ['/select,', absolutePath]\n break\n\n case 'linux': {\n // Linux - xdg-open doesn't support file selection, so open the containing directory\n const directory = path.dirname(absolutePath)\n command = 'xdg-open'\n args = [directory]\n break\n }\n\n default:\n return reject(new Error(`Unsupported platform: ${platform}`))\n }\n\n const child = spawn(command, args)\n\n child.on('error', error => {\n reject(new Error(`Failed to reveal file: ${error.message}`))\n })\n\n child.on('close', code => {\n if (code === 0) {\n resolve()\n } else {\n reject(new Error(`Reveal command exited with code ${code}`))\n }\n })\n })\n}\n","import { EventEmitter } from 'events'\nimport fg from 'fast-glob'\nimport path from 'path'\nimport fs from 'fs/promises'\nimport chokidar from 'chokidar'\nimport type { Asset, AssetGroup, AssetType, ResolvedOptions } from '../shared/types.js'\n\nexport interface ScannerEvents {\n change: [{ event: string; path: string }]\n}\n\nexport class AssetScanner extends EventEmitter {\n private root: string\n private options: ResolvedOptions\n private cache: Map<string, Asset> = new Map()\n private watcher?: chokidar.FSWatcher\n private scanPromise?: Promise<void>\n\n constructor(root: string, options: ResolvedOptions) {\n super()\n this.root = root\n this.options = options\n }\n\n async init(): Promise<void> {\n await this.scan()\n if (this.options.watch) {\n this.initWatcher()\n }\n }\n\n async scan(): Promise<Asset[]> {\n if (this.scanPromise) {\n await this.scanPromise\n return this.getAssets()\n }\n\n this.scanPromise = this.performScan()\n await this.scanPromise\n this.scanPromise = undefined\n\n return this.getAssets()\n }\n\n private async performScan(): Promise<void> {\n const extensionPattern = this.options.extensions.map(ext => ext.replace('.', '')).join(',')\n\n const patterns = this.options.include.map(dir => `${dir}/**/*.{${extensionPattern}}`)\n\n const entries = await fg(patterns, {\n cwd: this.root,\n ignore: this.options.exclude.map(p => `**/${p}/**`),\n absolute: false,\n stats: true,\n onlyFiles: true,\n dot: false\n })\n\n this.cache.clear()\n\n for (const entry of entries) {\n const asset = this.createAsset(entry)\n this.cache.set(asset.path, asset)\n }\n }\n\n private createAsset(entry: fg.Entry): Asset {\n const relativePath = entry.path\n const absolutePath = path.join(this.root, relativePath)\n const extension = path.extname(relativePath).toLowerCase()\n const name = path.basename(relativePath)\n const directory = path.dirname(relativePath)\n\n return {\n id: Buffer.from(relativePath).toString('base64url'),\n name,\n path: relativePath,\n absolutePath,\n extension,\n type: this.getAssetType(extension),\n size: entry.stats?.size || 0,\n mtime: entry.stats?.mtimeMs || Date.now(),\n directory: directory === '.' ? '/' : directory\n }\n }\n\n private getAssetType(extension: string): AssetType {\n const imageExts = [\n '.png',\n '.jpg',\n '.jpeg',\n '.gif',\n '.svg',\n '.webp',\n '.avif',\n '.ico',\n '.bmp',\n '.tiff',\n '.tif',\n '.heic',\n '.heif'\n ]\n const videoExts = ['.mp4', '.webm', '.ogg', '.mov', '.avi']\n const audioExts = ['.mp3', '.wav', '.flac', '.aac']\n const docExts = ['.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx']\n const fontExts = ['.woff', '.woff2', '.ttf', '.otf', '.eot']\n const dataExts = ['.json', '.csv', '.xml', '.yml', '.yaml', '.toml']\n const textExts = ['.md', '.txt']\n\n if (imageExts.includes(extension)) return 'image'\n if (videoExts.includes(extension)) return 'video'\n if (audioExts.includes(extension)) return 'audio'\n if (docExts.includes(extension)) return 'document'\n if (fontExts.includes(extension)) return 'font'\n if (dataExts.includes(extension)) return 'data'\n if (textExts.includes(extension)) return 'text'\n return 'other'\n }\n\n getAssets(): Asset[] {\n return Array.from(this.cache.values())\n }\n\n getGroupedAssets(): AssetGroup[] {\n const groups = new Map<string, Asset[]>()\n\n for (const asset of this.cache.values()) {\n const dir = asset.directory\n if (!groups.has(dir)) {\n groups.set(dir, [])\n }\n groups.get(dir)!.push(asset)\n }\n\n return Array.from(groups.entries())\n .map(([directory, assets]) => ({\n directory,\n assets: assets.sort((a, b) => a.name.localeCompare(b.name)),\n count: assets.length\n }))\n .sort((a, b) => a.directory.localeCompare(b.directory))\n }\n\n search(query: string): Asset[] {\n const normalizedQuery = query.toLowerCase().trim()\n if (!normalizedQuery) return this.getAssets()\n\n return this.getAssets().filter(\n asset =>\n asset.name.toLowerCase().includes(normalizedQuery) ||\n asset.path.toLowerCase().includes(normalizedQuery)\n )\n }\n\n getAsset(relativePath: string): Asset | undefined {\n return this.cache.get(relativePath)\n }\n\n /**\n * Enrich assets with importer count metadata.\n * Should be called after scanning completes and when importers change.\n */\n enrichWithImporterCounts(importerScanner: { getImporters: (assetPath: string) => any[] }): void {\n for (const asset of this.cache.values()) {\n const importers = importerScanner.getImporters(asset.path)\n asset.importersCount = importers.length\n }\n }\n\n /**\n * Enrich assets with duplicate detection metadata.\n * Should be called after scanning completes and when file content changes.\n */\n enrichWithDuplicateInfo(duplicateScanner: {\n getDuplicateInfo: (assetPath: string) => { hash: string; duplicatesCount: number }\n }): void {\n for (const asset of this.cache.values()) {\n const info = duplicateScanner.getDuplicateInfo(asset.path)\n asset.contentHash = info.hash\n asset.duplicatesCount = info.duplicatesCount\n }\n }\n\n private initWatcher(): void {\n const watchPaths = this.options.include.map(dir => path.join(this.root, dir))\n\n this.watcher = chokidar.watch(watchPaths, {\n ignored: this.options.exclude.map(p => `**/${p}/**`),\n persistent: true,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 100,\n pollInterval: 50\n }\n })\n\n this.watcher.on('add', filePath => this.handleFileChange('add', filePath))\n this.watcher.on('unlink', filePath => this.handleFileChange('unlink', filePath))\n this.watcher.on('change', filePath => this.handleFileChange('change', filePath))\n }\n\n private async handleFileChange(event: string, absolutePath: string): Promise<void> {\n const relativePath = path.relative(this.root, absolutePath)\n const extension = path.extname(relativePath).toLowerCase()\n\n if (!this.options.extensions.includes(extension)) {\n return\n }\n\n if (event === 'unlink') {\n this.cache.delete(relativePath)\n } else {\n try {\n const stats = await fs.stat(absolutePath)\n const asset: Asset = {\n id: Buffer.from(relativePath).toString('base64url'),\n name: path.basename(relativePath),\n path: relativePath,\n absolutePath,\n extension,\n type: this.getAssetType(extension),\n size: stats.size,\n mtime: stats.mtimeMs,\n directory: path.dirname(relativePath)\n }\n this.cache.set(relativePath, asset)\n } catch {\n return\n }\n }\n\n this.emit('change', { event, path: relativePath })\n }\n\n destroy(): void {\n this.watcher?.close()\n }\n}\n","import { EventEmitter } from 'events'\nimport fg from 'fast-glob'\nimport path from 'path'\nimport fs from 'fs/promises'\nimport chokidar from 'chokidar'\nimport type { Importer, ImportType, ResolvedOptions } from '../shared/types.js'\n\nexport interface ImporterScannerEvents {\n change: [{ event: string; path: string; affectedAssets: string[] }]\n}\n\n/** Source file extensions to scan for imports */\nconst SOURCE_EXTENSIONS = ['js', 'jsx', 'ts', 'tsx', 'vue', 'svelte', 'css', 'scss', 'less', 'html']\n\n/** Asset extensions to look for in imports */\nconst ASSET_EXTENSIONS = [\n 'png',\n 'jpg',\n 'jpeg',\n 'gif',\n 'svg',\n 'webp',\n 'avif',\n 'ico',\n 'bmp',\n 'tiff',\n 'tif',\n 'heic',\n 'heif',\n 'mp4',\n 'webm',\n 'ogg',\n 'mov',\n 'avi',\n 'mp3',\n 'wav',\n 'flac',\n 'aac',\n 'woff',\n 'woff2',\n 'ttf',\n 'otf',\n 'eot',\n 'pdf',\n 'json',\n 'md',\n 'txt',\n 'csv',\n 'xml',\n 'yml',\n 'yaml',\n 'toml'\n]\n\nconst ASSET_EXT_PATTERN = ASSET_EXTENSIONS.join('|')\n\n/**\n * Regex patterns to find asset imports in source files.\n * Each pattern captures the asset path in group 1.\n */\nconst IMPORT_PATTERNS: { type: ImportType; pattern: RegExp }[] = [\n {\n type: 'es-import',\n pattern: new RegExp(\n `import\\\\s+(?:[\\\\w\\\\s{},*]+\\\\s+from\\\\s+)?['\"]([^'\"]*\\\\.(?:${ASSET_EXT_PATTERN}))['\"]`,\n 'gi'\n )\n },\n {\n type: 'dynamic-import',\n pattern: new RegExp(`import\\\\s*\\\\(\\\\s*['\"]([^'\"]*\\\\.(?:${ASSET_EXT_PATTERN}))['\"]\\\\s*\\\\)`, 'gi')\n },\n {\n type: 'require',\n pattern: new RegExp(\n `require\\\\s*\\\\(\\\\s*['\"]([^'\"]*\\\\.(?:${ASSET_EXT_PATTERN}))['\"]\\\\s*\\\\)`,\n 'gi'\n )\n },\n {\n type: 'css-url',\n pattern: new RegExp(\n `url\\\\s*\\\\(\\\\s*['\"]?([^'\")\\\\s]+\\\\.(?:${ASSET_EXT_PATTERN}))['\"]?\\\\s*\\\\)`,\n 'gi'\n )\n },\n {\n type: 'html-src',\n pattern: new RegExp(`\\\\bsrc\\\\s*=\\\\s*['\"]([^'\"]*\\\\.(?:${ASSET_EXT_PATTERN}))['\"]`, 'gi')\n },\n {\n type: 'html-href',\n pattern: new RegExp(`\\\\bhref\\\\s*=\\\\s*['\"]([^'\"]*\\\\.(?:${ASSET_EXT_PATTERN}))['\"]`, 'gi')\n }\n]\n\nexport class ImporterScanner extends EventEmitter {\n private root: string\n private options: ResolvedOptions\n /** Maps asset path -> array of importers */\n private cache: Map<string, Importer[]> = new Map()\n /** Reverse index: source file -> set of asset paths it imports */\n private reverseIndex: Map<string, Set<string>> = new Map()\n private watcher?: chokidar.FSWatcher\n private scanPromise?: Promise<void>\n private initialized = false\n\n constructor(root: string, options: ResolvedOptions) {\n super()\n this.root = root\n this.options = options\n }\n\n async init(): Promise<void> {\n if (this.initialized) return\n await this.scan()\n if (this.options.watch) {\n this.initWatcher()\n }\n this.initialized = true\n }\n\n async scan(): Promise<void> {\n if (this.scanPromise) {\n await this.scanPromise\n return\n }\n\n this.scanPromise = this.performScan()\n await this.scanPromise\n this.scanPromise = undefined\n }\n\n private async performScan(): Promise<void> {\n const patterns = this.options.include.map(dir => `${dir}/**/*.{${SOURCE_EXTENSIONS.join(',')}}`)\n\n const entries = await fg(patterns, {\n cwd: this.root,\n ignore: this.options.exclude.map(p => `**/${p}/**`),\n absolute: false,\n onlyFiles: true,\n dot: false\n })\n\n this.cache.clear()\n this.reverseIndex.clear()\n\n const BATCH_SIZE = 50\n for (let i = 0; i < entries.length; i += BATCH_SIZE) {\n const batch = entries.slice(i, i + BATCH_SIZE)\n await Promise.all(batch.map(filePath => this.scanFile(filePath)))\n }\n }\n\n private async scanFile(relativePath: string): Promise<void> {\n const absolutePath = path.join(this.root, relativePath)\n\n try {\n const content = await fs.readFile(absolutePath, 'utf-8')\n const importers = this.findImportsInFile(content, relativePath, absolutePath)\n\n const previousAssets = this.reverseIndex.get(relativePath)\n if (previousAssets) {\n for (const assetPath of previousAssets) {\n const assetImporters = this.cache.get(assetPath)\n if (assetImporters) {\n const filtered = assetImporters.filter(i => i.filePath !== relativePath)\n if (filtered.length > 0) {\n this.cache.set(assetPath, filtered)\n } else {\n this.cache.delete(assetPath)\n }\n }\n }\n }\n\n const newAssets = new Set<string>()\n\n for (const importer of importers) {\n const assetPath = this.resolveAssetPath(importer.filePath, importer.snippet)\n if (assetPath) {\n newAssets.add(assetPath)\n\n const existing = this.cache.get(assetPath) || []\n existing.push({ ...importer, filePath: relativePath, absolutePath })\n this.cache.set(assetPath, existing)\n }\n }\n\n this.reverseIndex.set(relativePath, newAssets)\n } catch {\n // File might have been deleted or is unreadable\n }\n }\n\n private findImportsInFile(\n content: string,\n relativePath: string,\n absolutePath: string\n ): Importer[] {\n const importers: Importer[] = []\n const lines = content.split('\\n')\n const fileDir = path.dirname(relativePath)\n\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\n const line = lines[lineIndex]\n\n for (const { type, pattern } of IMPORT_PATTERNS) {\n pattern.lastIndex = 0\n\n let match\n while ((match = pattern.exec(line)) !== null) {\n const importPath = match[1]\n const resolvedAssetPath = this.resolveImportPath(importPath, fileDir)\n\n if (resolvedAssetPath) {\n importers.push({\n filePath: relativePath,\n absolutePath,\n line: lineIndex + 1,\n column: match.index + 1,\n importType: type,\n snippet: line.trim().slice(0, 100)\n })\n }\n }\n }\n }\n\n return importers\n }\n\n /**\n * Resolves an import path relative to the file directory.\n * Returns the normalized asset path relative to project root, or null if invalid.\n */\n private resolveImportPath(importPath: string, fileDir: string): string | null {\n if (\n importPath.startsWith('http://') ||\n importPath.startsWith('https://') ||\n importPath.startsWith('//')\n ) {\n return null\n }\n\n if (\n !importPath.startsWith('.') &&\n !importPath.startsWith('/') &&\n !importPath.startsWith('@/')\n ) {\n return null\n }\n\n let resolvedPath: string\n\n if (importPath.startsWith('/')) {\n resolvedPath = importPath.slice(1)\n if (!resolvedPath.startsWith('public/')) {\n resolvedPath = 'public' + importPath\n }\n } else if (importPath.startsWith('@/')) {\n resolvedPath = 'src/' + importPath.slice(2)\n } else {\n resolvedPath = path.normalize(path.join(fileDir, importPath))\n }\n\n resolvedPath = resolvedPath.split(path.sep).join('/')\n\n return resolvedPath\n }\n\n /**\n * Extract asset path from importer snippet (for reverse lookup)\n */\n private resolveAssetPath(sourceFile: string, snippet: string): string | null {\n const fileDir = path.dirname(sourceFile)\n\n for (const { pattern } of IMPORT_PATTERNS) {\n pattern.lastIndex = 0\n const match = pattern.exec(snippet)\n if (match) {\n return this.resolveImportPath(match[1], fileDir)\n }\n }\n\n return null\n }\n\n /**\n * Get all importers for a specific asset.\n * @param assetPath - Relative path to the asset from project root\n */\n getImporters(assetPath: string): Importer[] {\n const normalizedPath = assetPath.split(path.sep).join('/')\n\n let importers = this.cache.get(normalizedPath)\n\n if (!importers) {\n if (normalizedPath.startsWith('public/')) {\n importers = this.cache.get(normalizedPath.slice(7))\n } else {\n importers = this.cache.get('public/' + normalizedPath)\n }\n }\n\n return importers || []\n }\n\n /**\n * Get assets affected when a source file changes.\n */\n private getAffectedAssets(sourceFile: string): string[] {\n return Array.from(this.reverseIndex.get(sourceFile) || [])\n }\n\n private initWatcher(): void {\n const watchPaths = this.options.include.map(dir => path.join(this.root, dir))\n\n this.watcher = chokidar.watch(watchPaths, {\n ignored: [\n ...this.options.exclude.map(p => `**/${p}/**`),\n (filePath: string) => {\n const ext = path.extname(filePath).slice(1)\n return ext !== '' && !SOURCE_EXTENSIONS.includes(ext)\n }\n ],\n persistent: true,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 200,\n pollInterval: 50\n }\n })\n\n this.watcher.on('add', filePath => this.handleFileChange('add', filePath))\n this.watcher.on('unlink', filePath => this.handleFileChange('unlink', filePath))\n this.watcher.on('change', filePath => this.handleFileChange('change', filePath))\n }\n\n private async handleFileChange(event: string, absolutePath: string): Promise<void> {\n const relativePath = path.relative(this.root, absolutePath)\n const extension = path.extname(relativePath).slice(1)\n\n if (!SOURCE_EXTENSIONS.includes(extension)) {\n return\n }\n\n const previousAssets = this.getAffectedAssets(relativePath)\n\n if (event === 'unlink') {\n for (const assetPath of previousAssets) {\n const assetImporters = this.cache.get(assetPath)\n if (assetImporters) {\n const filtered = assetImporters.filter(i => i.filePath !== relativePath)\n if (filtered.length > 0) {\n this.cache.set(assetPath, filtered)\n } else {\n this.cache.delete(assetPath)\n }\n }\n }\n this.reverseIndex.delete(relativePath)\n } else {\n await this.scanFile(relativePath)\n }\n\n const currentAssets = this.getAffectedAssets(relativePath)\n const allAffectedAssets = [...new Set([...previousAssets, ...currentAssets])]\n\n if (allAffectedAssets.length > 0) {\n this.emit('change', {\n event,\n path: relativePath,\n affectedAssets: allAffectedAssets\n })\n }\n }\n\n destroy(): void {\n this.watcher?.close()\n }\n}\n","import { EventEmitter } from 'events'\nimport crypto from 'crypto'\nimport fs from 'fs'\nimport path from 'path'\nimport chokidar from 'chokidar'\nimport type { ResolvedOptions, Asset } from '../shared/types.js'\n\nexport interface DuplicateScannerEvents {\n change: [{ event: string; affectedHashes: string[] }]\n}\n\nexport interface DuplicateInfo {\n hash: string\n duplicatesCount: number\n}\n\n/** Threshold for streaming hash computation (1MB) */\nconst STREAMING_THRESHOLD = 1024 * 1024\n\nexport class DuplicateScanner extends EventEmitter {\n private root: string\n private options: ResolvedOptions\n /** Maps relative path -> { hash, mtime, size } for cache validation */\n private hashCache: Map<string, { hash: string; mtime: number; size: number }> = new Map()\n /** Maps hash -> set of relative paths (for grouping duplicates) */\n private duplicateGroups: Map<string, Set<string>> = new Map()\n /** Reverse index: path -> hash (for quick lookups) */\n private pathToHash: Map<string, string> = new Map()\n private watcher?: chokidar.FSWatcher\n private scanPromise?: Promise<void>\n private initialized = false\n\n constructor(root: string, options: ResolvedOptions) {\n super()\n this.root = root\n this.options = options\n }\n\n async init(): Promise<void> {\n if (this.initialized) return\n this.initialized = true\n }\n\n /**\n * Scan all assets and compute hashes.\n * Called after AssetScanner has discovered assets.\n */\n async scanAssets(assets: Asset[]): Promise<void> {\n if (this.scanPromise) {\n await this.scanPromise\n return\n }\n\n this.scanPromise = this.performScan(assets)\n await this.scanPromise\n this.scanPromise = undefined\n }\n\n private async performScan(assets: Asset[]): Promise<void> {\n this.duplicateGroups.clear()\n this.pathToHash.clear()\n\n const BATCH_SIZE = 20\n for (let i = 0; i < assets.length; i += BATCH_SIZE) {\n const batch = assets.slice(i, i + BATCH_SIZE)\n await Promise.all(batch.map(asset => this.processAsset(asset)))\n }\n }\n\n private async processAsset(asset: Asset): Promise<void> {\n try {\n const hash = await this.getOrComputeHash(asset.path, asset.absolutePath)\n if (hash) {\n this.pathToHash.set(asset.path, hash)\n\n if (!this.duplicateGroups.has(hash)) {\n this.duplicateGroups.set(hash, new Set())\n }\n this.duplicateGroups.get(hash)!.add(asset.path)\n }\n } catch {\n // File might have been deleted or is unreadable\n }\n }\n\n /**\n * Get cached hash or compute new one if cache is invalid.\n */\n private async getOrComputeHash(\n relativePath: string,\n absolutePath: string\n ): Promise<string | null> {\n try {\n const stats = await fs.promises.stat(absolutePath)\n\n const cached = this.hashCache.get(relativePath)\n if (cached && cached.mtime === stats.mtimeMs && cached.size === stats.size) {\n return cached.hash\n }\n\n const hash = await this.computeFileHash(absolutePath, stats.size)\n\n this.hashCache.set(relativePath, {\n hash,\n mtime: stats.mtimeMs,\n size: stats.size\n })\n\n return hash\n } catch {\n return null\n }\n }\n\n /**\n * Compute MD5 hash of file contents.\n * Uses streaming for large files to avoid memory issues.\n */\n private async computeFileHash(absolutePath: string, size: number): Promise<string> {\n if (size > STREAMING_THRESHOLD) {\n return new Promise((resolve, reject) => {\n const hash = crypto.createHash('md5')\n const stream = fs.createReadStream(absolutePath)\n stream.on('data', (chunk: Buffer) => hash.update(chunk))\n stream.on('end', () => resolve(hash.digest('hex')))\n stream.on('error', reject)\n })\n }\n\n const content = await fs.promises.readFile(absolutePath)\n return crypto.createHash('md5').update(content).digest('hex')\n }\n\n /**\n * Get duplicate info for a specific asset.\n */\n getDuplicateInfo(assetPath: string): DuplicateInfo {\n const normalizedPath = assetPath.split(path.sep).join('/')\n const hash = this.pathToHash.get(normalizedPath)\n\n if (!hash) {\n return { hash: '', duplicatesCount: 0 }\n }\n\n const group = this.duplicateGroups.get(hash)\n const duplicatesCount = group ? group.size - 1 : 0 // Exclude self\n\n return { hash, duplicatesCount }\n }\n\n /**\n * Get all assets in a duplicate group by hash.\n */\n getDuplicatesByHash(hash: string): string[] {\n const group = this.duplicateGroups.get(hash)\n return group ? Array.from(group).sort() : []\n }\n\n /**\n * Get duplicate statistics.\n */\n getStats(): { duplicateGroups: number; duplicateFiles: number } {\n let duplicateGroups = 0\n let duplicateFiles = 0\n\n for (const [, paths] of this.duplicateGroups) {\n if (paths.size > 1) {\n duplicateGroups++\n duplicateFiles += paths.size\n }\n }\n\n return { duplicateGroups, duplicateFiles }\n }\n\n /**\n * Enrich assets with duplicate detection metadata.\n */\n enrichAssetsWithDuplicateInfo(assets: Asset[]): void {\n for (const asset of assets) {\n const info = this.getDuplicateInfo(asset.path)\n asset.contentHash = info.hash\n asset.duplicatesCount = info.duplicatesCount\n }\n }\n\n /**\n * Handle file change event from watcher.\n * Recalculates hash and updates duplicate groups.\n */\n async handleAssetChange(\n event: 'add' | 'change' | 'unlink',\n relativePath: string,\n absolutePath: string\n ): Promise<void> {\n const normalizedPath = relativePath.split(path.sep).join('/')\n const previousHash = this.pathToHash.get(normalizedPath)\n const affectedHashes: string[] = []\n\n if (previousHash) {\n affectedHashes.push(previousHash)\n const oldGroup = this.duplicateGroups.get(previousHash)\n if (oldGroup) {\n oldGroup.delete(normalizedPath)\n if (oldGroup.size === 0) {\n this.duplicateGroups.delete(previousHash)\n }\n }\n this.pathToHash.delete(normalizedPath)\n }\n\n if (event === 'unlink') {\n this.hashCache.delete(normalizedPath)\n } else {\n try {\n const stats = await fs.promises.stat(absolutePath)\n const hash = await this.computeFileHash(absolutePath, stats.size)\n\n this.hashCache.set(normalizedPath, {\n hash,\n mtime: stats.mtimeMs,\n size: stats.size\n })\n this.pathToHash.set(normalizedPath, hash)\n\n if (!this.duplicateGroups.has(hash)) {\n this.duplicateGroups.set(hash, new Set())\n }\n this.duplicateGroups.get(hash)!.add(normalizedPath)\n\n if (!affectedHashes.includes(hash)) {\n affectedHashes.push(hash)\n }\n } catch {}\n }\n\n if (affectedHashes.length > 0) {\n this.emit('change', { event, affectedHashes })\n }\n }\n\n /**\n * Initialize file watcher for real-time updates.\n * Note: This watches asset files, not source files.\n */\n initWatcher(): void {\n if (this.watcher) return\n\n const watchPaths = this.options.include.map(dir => path.join(this.root, dir))\n // const extensionPattern = this.options.extensions.map(ext => ext.replace('.', '')).join(',')\n\n this.watcher = chokidar.watch(watchPaths, {\n ignored: [\n ...this.options.exclude.map(p => `**/${p}/**`),\n (filePath: string) => {\n const ext = path.extname(filePath).toLowerCase()\n return ext !== '' && !this.options.extensions.includes(ext)\n }\n ],\n persistent: true,\n ignoreInitial: true,\n awaitWriteFinish: {\n stabilityThreshold: 200,\n pollInterval: 50\n }\n })\n\n this.watcher.on('add', async filePath => {\n const relativePath = path.relative(this.root, filePath)\n await this.handleAssetChange('add', relativePath, filePath)\n })\n\n this.watcher.on('change', async filePath => {\n const relativePath = path.relative(this.root, filePath)\n await this.handleAssetChange('change', relativePath, filePath)\n })\n\n this.watcher.on('unlink', async filePath => {\n const relativePath = path.relative(this.root, filePath)\n await this.handleAssetChange('unlink', relativePath, filePath)\n })\n }\n\n destroy(): void {\n this.watcher?.close()\n this.hashCache.clear()\n this.duplicateGroups.clear()\n this.pathToHash.clear()\n }\n}\n","import sharp from 'sharp'\nimport path from 'path'\nimport fs from 'fs/promises'\nimport { createHash } from 'crypto'\nimport os from 'os'\n\nexport class ThumbnailService {\n private size: number\n private cache: Map<string, Buffer> = new Map()\n private cacheDir: string\n private supportedFormats = ['.jpg', '.jpeg', '.png', '.webp', '.avif', '.gif', '.tiff']\n\n constructor(size: number = 200) {\n this.size = size\n this.cacheDir = path.join(os.tmpdir(), 'vite-asset-manager-thumbnails')\n }\n\n async getThumbnail(absolutePath: string): Promise<Buffer | null> {\n const extension = path.extname(absolutePath).toLowerCase()\n\n if (!this.supportedFormats.includes(extension)) {\n return null\n }\n\n const cacheKey = await this.getCacheKey(absolutePath)\n\n const cached = this.cache.get(cacheKey)\n if (cached) {\n return cached\n }\n\n const diskCached = await this.loadFromDiskCache(cacheKey)\n if (diskCached) {\n this.cache.set(cacheKey, diskCached)\n return diskCached\n }\n\n try {\n const thumbnail = await this.generateThumbnail(absolutePath)\n this.cache.set(cacheKey, thumbnail)\n await this.saveToDiskCache(cacheKey, thumbnail)\n return thumbnail\n } catch (error) {\n console.warn(`[asset-manager] Failed to generate thumbnail for ${absolutePath}:`, error)\n return null\n }\n }\n\n private async generateThumbnail(absolutePath: string): Promise<Buffer> {\n return sharp(absolutePath)\n .resize(this.size, this.size, {\n fit: 'cover',\n position: 'center'\n })\n .jpeg({ quality: 80 })\n .toBuffer()\n }\n\n private async getCacheKey(absolutePath: string): Promise<string> {\n const hash = createHash('md5')\n hash.update(absolutePath)\n hash.update(this.size.toString())\n\n try {\n const stats = await fs.stat(absolutePath)\n hash.update(stats.mtimeMs.toString())\n } catch {\n // File might not exist\n }\n\n return hash.digest('hex')\n }\n\n private async loadFromDiskCache(key: string): Promise<Buffer | null> {\n try {\n const cachePath = path.join(this.cacheDir, `${key}.jpg`)\n return await fs.readFile(cachePath)\n } catch {\n return null\n }\n }\n\n private async saveToDiskCache(key: string, data: Buffer): Promise<void> {\n try {\n await fs.mkdir(this.cacheDir, { recursive: true })\n const cachePath = path.join(this.cacheDir, `${key}.jpg`)\n await fs.writeFile(cachePath, data)\n } catch {\n // Ignore cache write failures\n }\n }\n\n invalidate(absolutePath: string): void {\n this.getCacheKey(absolutePath).then(key => {\n this.cache.delete(key)\n })\n }\n\n isSupportedFormat(extension: string): boolean {\n return this.supportedFormats.includes(extension.toLowerCase())\n }\n}\n","export type AssetType =\n | 'image'\n | 'video'\n | 'audio'\n | 'document'\n | 'font'\n | 'data'\n | 'text'\n | 'other'\n\nexport type EditorType =\n | 'appcode'\n | 'atom'\n | 'atom-beta'\n | 'brackets'\n | 'clion'\n | 'code'\n | 'code-insiders'\n | 'codium'\n | 'cursor'\n | 'emacs'\n | 'idea'\n | 'notepad++'\n | 'pycharm'\n | 'phpstorm'\n | 'rubymine'\n | 'sublime'\n | 'vim'\n | 'visualstudio'\n | 'webstorm'\n | 'rider'\n | (string & {})\n\nexport type ImportType =\n | 'es-import'\n | 'dynamic-import'\n | 'require'\n | 'css-url'\n | 'html-src'\n | 'html-href'\n\nexport interface Importer {\n filePath: string\n absolutePath: string\n line: number\n column: number\n importType: ImportType\n snippet: string\n}\n\nexport interface Asset {\n id: string\n name: string\n path: string\n absolutePath: string\n extension: string\n type: AssetType\n size: number\n mtime: number\n directory: string\n importersCount?: number\n contentHash?: string\n duplicatesCount?: number\n}\n\nexport interface AssetGroup {\n directory: string\n assets: Asset[]\n count: number\n}\n\nexport interface AssetStats {\n total: number\n byType: Record<AssetType, number>\n totalSize: number\n directories: number\n unused: number\n duplicateGroups: number\n duplicateFiles: number\n extensionBreakdown?: Record<string, number>\n}\n\nexport type SizeFilterPreset = 'any' | 'small' | 'medium' | 'large' | 'xlarge'\nexport type DateFilterPreset =\n | 'any'\n | 'today'\n | 'last7days'\n | 'last30days'\n | 'last90days'\n | 'thisYear'\n\nexport interface SizeFilter {\n preset: SizeFilterPreset\n minBytes?: number\n maxBytes?: number\n}\n\nexport interface DateFilter {\n preset: DateFilterPreset\n startDate?: number\n endDate?: number\n}\n\nexport interface ExtensionFilter {\n extensions: string[]\n}\n\nexport interface AdvancedFilters {\n size?: SizeFilter\n date?: DateFilter\n extensions?: ExtensionFilter\n}\n\nexport interface AssetManagerOptions {\n base?: string\n include?: string[]\n exclude?: string[]\n extensions?: string[]\n thumbnails?: boolean\n thumbnailSize?: number\n watch?: boolean\n floatingIcon?: boolean\n /**\n * Target editor when opening files via \"Open in Editor\"\n * @default 'code' (Visual Studio Code)\n */\n launchEditor?: EditorType\n}\n\nexport interface ResolvedOptions {\n base: string\n include: string[]\n exclude: string[]\n extensions: string[]\n thumbnails: boolean\n thumbnailSize: number\n watch: boolean\n floatingIcon: boolean\n launchEditor: EditorType\n}\n\nexport const DEFAULT_OPTIONS: ResolvedOptions = {\n base: '/__asset_manager__',\n include: ['src', 'public'],\n exclude: ['node_modules', '.git', 'dist', '.cache', 'coverage'],\n extensions: [\n /**\n * Images:\n */\n '.png',\n '.jpg',\n '.jpeg',\n '.gif',\n '.svg',\n '.webp',\n '.avif',\n '.ico',\n '.bmp',\n '.tiff',\n '.tif',\n '.heic',\n '.heif',\n /**\n * Videos:\n */\n '.mp4',\n '.webm',\n '.ogg',\n '.mov',\n '.avi',\n /**\n * Audio:\n */\n '.mp3',\n '.wav',\n '.flac',\n '.aac',\n /**\n * Documents:\n */\n '.pdf',\n '.doc',\n '.docx',\n '.xls',\n '.xlsx',\n '.ppt',\n '.pptx',\n /**\n * Text/Config:\n */\n '.json',\n '.md',\n '.txt',\n '.csv',\n '.yml',\n '.yaml',\n '.toml',\n '.xml',\n /**\n * Fonts:\n */\n '.woff',\n '.woff2',\n '.ttf',\n '.otf',\n '.eot'\n ],\n thumbnails: true,\n thumbnailSize: 200,\n watch: true,\n floatingIcon: true,\n launchEditor: 'code'\n}\n\nexport function resolveOptions(options: AssetManagerOptions): ResolvedOptions {\n return {\n ...DEFAULT_OPTIONS,\n ...options\n }\n}\n","import type { Plugin } from 'vite'\nimport { createAssetManagerPlugin } from './plugin'\nimport type { AssetManagerOptions } from './shared/types'\n\nexport type { AssetManagerOptions } from './shared/types'\nexport type { Asset, AssetGroup, AssetType, AssetStats } from './shared/types'\n\nexport default function assetManager(options: AssetManagerOptions = {}): Plugin {\n return createAssetManagerPlugin(options)\n}\n\nexport { assetManager }\n"],"mappings":"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","names":["path","fs","path","path","__dirname","path","fs","launchEditor","path","fs","EventEmitter","fg","path","fs","chokidar","EventEmitter","fs","path","chokidar","path","fs","url"]}
|