@json-to-office/jto 6.4.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/cli.js +17 -9
  2. package/dist/cli.js.map +1 -1
  3. package/dist/client/assets/{HomePage-DgyrBIGY.js → HomePage-CAQsE0sn.js} +4 -4
  4. package/dist/client/assets/HomePage-CAQsE0sn.js.map +1 -0
  5. package/dist/client/assets/{JsonEditorPage-BGctWRXE.js → JsonEditorPage-Cqz2zDan.js} +3 -3
  6. package/dist/client/assets/{JsonEditorPage-BGctWRXE.js.map → JsonEditorPage-Cqz2zDan.js.map} +1 -1
  7. package/dist/client/assets/{MonacoPluginProvider-DbBCCotq.js → MonacoPluginProvider-FJHgHgFQ.js} +5 -5
  8. package/dist/client/assets/{MonacoPluginProvider-DbBCCotq.js.map → MonacoPluginProvider-FJHgHgFQ.js.map} +1 -1
  9. package/dist/client/assets/{_virtual_jto-plugin-type-libs-BpQu9aDr.js → _virtual_jto-plugin-type-libs-DroopP3q.js} +67 -19
  10. package/dist/client/assets/{_virtual_jto-plugin-type-libs-BpQu9aDr.js.map → _virtual_jto-plugin-type-libs-DroopP3q.js.map} +1 -1
  11. package/dist/client/assets/_virtual_jto-sandbox-runtime-v4kQF3ee.js +2 -0
  12. package/dist/client/assets/_virtual_jto-sandbox-runtime-v4kQF3ee.js.map +1 -0
  13. package/dist/client/assets/{editor-DnPnx_0M.js → editor-1mTGQjga.js} +2 -2
  14. package/dist/client/assets/{editor-DnPnx_0M.js.map → editor-1mTGQjga.js.map} +1 -1
  15. package/dist/client/assets/{editor-monaco-json-B_U6hHbA.js → editor-monaco-json-B19wOO_b.js} +2 -2
  16. package/dist/client/assets/{editor-monaco-json-B_U6hHbA.js.map → editor-monaco-json-B19wOO_b.js.map} +1 -1
  17. package/dist/client/assets/{index-CWzQeme_.js → index-Da5mi8tP.js} +2 -2
  18. package/dist/client/assets/{index-CWzQeme_.js.map → index-Da5mi8tP.js.map} +1 -1
  19. package/dist/client/assets/{index-2S58SOrb.js → index-DsuZTLjf.js} +5 -5
  20. package/dist/client/assets/index-DsuZTLjf.js.map +1 -0
  21. package/dist/client/assets/{preview-Bdmil0FT.js → preview-T1T-uQbx.js} +2 -2
  22. package/dist/client/assets/preview-T1T-uQbx.js.map +1 -0
  23. package/dist/client/assets/{useQualityAnalysis-B0tasjoU.js → useQualityAnalysis-CnLgG345.js} +2 -2
  24. package/dist/client/assets/{useQualityAnalysis-B0tasjoU.js.map → useQualityAnalysis-CnLgG345.js.map} +1 -1
  25. package/dist/client/index.html +1 -1
  26. package/dist/client/templates/client-report-blocks.docx.json +1 -1
  27. package/dist/client/templates/consulting-deck-blocks.pptx.json +39 -18
  28. package/dist/client/templates/data-report-presentation.pptx.json +1 -1
  29. package/dist/client/templates/management-plan.pptx.json +4 -4
  30. package/dist/client/templates/minimalist-pitch-deck.pptx.json +1 -1
  31. package/dist/client/templates/modern-annual-report-3.docx.json +1 -0
  32. package/dist/client/templates/technical-report-blocks.docx.json +1 -1
  33. package/package.json +10 -10
  34. package/dist/client/assets/HomePage-DgyrBIGY.js.map +0 -1
  35. package/dist/client/assets/_virtual_jto-sandbox-runtime-CySzPJ5n.js +0 -2
  36. package/dist/client/assets/_virtual_jto-sandbox-runtime-CySzPJ5n.js.map +0 -1
  37. package/dist/client/assets/index-2S58SOrb.js.map +0 -1
  38. package/dist/client/assets/preview-Bdmil0FT.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"mappings":"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","names":["validateThemeJson","jsonString","parsed","getThemeName","themeJson","_ThemeChangeEmitter","event","callback","handler","e","__publicField","ThemeChangeEmitter","themeChangeEmitter","promisifyRequest","request","resolve","reject","createStore","dbName","storeName","dbp","getDB","db","txMode","defaultGetStoreFunc","defaultGetStore","get","key","customStore","store","set","value","del","idbStorage","name","validThemesByName","customThemes","out","theme","initThemesStore","defaultInitThemesState","createThemesStore","initState","devtools","persist","documentName","content","state","validation","themeName","parsedContent","extractedName","existingTheme","isUpdate","hasContentChanged","customTheme","removedTheme","newCustomThemes","names","createJSONStorage","ThemesStoreContext","createContext","ThemesStoreProvider","children","storeRef","useRef","useThemesStore","selector","themesStoreContext","useContext","useStore","hashSource","text","hash","i","createBrowserPluginRecord","docName","patch","now","useBrowserPluginsStore","create","existing","enabled","allowNetwork","networkOrigins","previous","origin","oldName","newName","records","persisted","record","whenBrowserPluginsHydrated","api","stop","selectActivePlugins","active","a","b","activePluginsSignature","components","browserComponentsForSchema","componentNameOwner","componentName","owner","_a","plugin","v","recordErrors","d","NOTHING","HOST","isLoopback","host","normalizeNetworkOrigin","input","trimmed","withScheme","wildcard","parseable","url","protocol","parseNetworkOrigins","origins","errors","line","result","connectSrcValue","safe","nonce","bytes","sandboxDocument","scriptNonce","SandboxFrame","options","iframe","resolveReady","rejectReady","readyTimer","data","message","framePolicy","spec","samePolicy","LOAD_TIMEOUT_MS","RENDER_TIMEOUT_MS","IDLE_TIMEOUT_MS","PluginTimeoutError","what","ms","PluginAbortedError","runtimePromise","loadRuntime","module","error","sameSpec","PluginHost","policy","runtime","raced","entry","response","pending","payload","timeoutMs","signal","id","onAbort","detach","timer","reason","pluginHost","MAX_OPEN_TABS","PLUGIN_FILE_SUFFIX","isPluginDocumentName","pluginDocumentName","resolveSourceName","documents","doc","initDocumentsStore","defaultInitDocumentsState","createDocumentsStore","opts","docType","newDoc","newDocumentTypes","k","docIndex","openTabs","index","tab","activeTab","buildError","buildErrors","original","modified","applyId","accepted","diff","next","ids","acceptedApplyIds","DocumentsStoreContext","DocumentsStoreProvider","useDocumentsStore","documentsStoreContext","useResolveSourceName","useCallback","initOutputStore","defaultInitOutputState","createOutputStore","partialState","s","OutputStoreContext","OutputStoreProvider","useOutputStore","outputStoreContext","usePluginsStore","newSelectedPlugins","newMetadata","pluginName","onSuccess","onError","selectedPluginNames","loader","__vitePreload","updateMonacoWithPlugins","n","monaco","errorMessage","str","serialized","pluginApiDeclaration","sharedPackage","componentType","themeType","DOCX_API","PPTX_API","manifest","withPluginSubpath","PLUGIN_TYPE_SHIMS","configured","ensurePluginTypeScript","configure","markReady","ts","files","__vite_default__","path","pluginTypeScriptReady","ready","readyListeners","onPluginTypeScriptReady","listener","MODEL_SCHEME_PATH","pluginModelPath","isAttachedToEditor","model","flattenMessage","parts","queue","toDiagnostic","diagnostic","start","end","compilePlugin","source","skipIfHash","uri","client","fileName","syntactic","semantic","emit","diagnostics","hasErrors","js","file","disposePluginModel","noopRunner","CompileQueue","runner","delayMs","running","task","done","waiters","waiter","compileQueue","extractPluginExamples","examples","normalize","fenced","match","title","block","json","propsMatch","cleaned","inline","standardComponentNames","format","registry","STANDARD_COMPONENTS_REGISTRY","PPTX_STANDARD_COMPONENTS_REGISTRY","component","PLUGIN_NAME_PATTERN","NETWORK_OFF_MARKER","COMPILE_DEBOUNCE_MS","PLUGIN_TYPE","BROWSER_PLUGINS_CHANGED_EVENT","announceChange","conflictDiagnostic","sandboxDiagnostic","useBrowserPluginsSync","diskPluginNames","documentsStore","diskNamesRef","useEffect","disposed","nameConflict","FORMAT","reconcileConflicts","others","hadConflict","conflict","otherErrors","compileNow","settled","compiled","finalHash","metadata","reconcile","documentTypes","pluginDocs","present","pluginsStore","removed","unsubscribe","initSettingsStore","defaultInitSettingsState","createSettingsStore","settings","SettingsStoreContext","SettingsStoreProvider","useSettingsStore","settingsStoreContext","BrowserPluginsProvider","emptyNames","subscribe","useCustomThemeNames","cachedRef","getSnapshot","useSyncExternalStore","useMonacoPlugins","monacoRef","selectedPlugins","customThemeNames","browserSignature","themesStore","themesStoreRef","previousPluginsRef","previousThemesRef","previousBrowserRef","currentPlugins","currentThemes","browserState","success","pluginsChanged","themesChanged","browserChanged","MonacoPluginProvider"],"ignoreList":[2],"sources":["../../../src/client/lib/theme-validation.ts","../../../src/client/utils/theme-change-emitter.ts","../../../../../node_modules/.pnpm/idb-keyval@6.2.2/node_modules/idb-keyval/dist/index.js","../../../src/client/lib/idb-storage.ts","../../../src/client/store/themes-store.ts","../../../src/client/store/themes-store-provider.tsx","../../../src/client/lib/plugins/hash.ts","../../../src/client/store/browser-plugins-store.ts","../../../src/client/lib/plugins/network-policy.ts","../../../src/client/lib/plugins/sandbox-frame.ts","../../../src/client/lib/plugins/host.ts","../../../src/client/store/documents-store.ts","../../../src/client/store/documents-store-provider.tsx","../../../src/client/store/output-store.ts","../../../src/client/store/output-store-provider.tsx","../../../src/client/store/plugins-store.ts","../../../src/client/lib/plugins/type-shims.ts","../../../src/client/lib/plugins/type-libs.ts","../../../src/client/lib/plugins/compiler.ts","../../../src/client/lib/plugins/compile-queue.ts","../../../src/client/lib/plugins/examples.ts","../../../src/client/lib/plugins/names.ts","../../../src/client/lib/plugins/types.ts","../../../src/client/hooks/useBrowserPluginsSync.ts","../../../src/client/store/settings-store.ts","../../../src/client/store/settings-store-provider.tsx","../../../src/client/components/BrowserPluginsProvider.tsx","../../../src/client/hooks/useMonacoPlugins.ts","../../../src/client/components/MonacoPluginProvider.tsx"],"sourcesContent":["export interface ThemeValidationError {\n message: string;\n line?: number;\n column?: number;\n path?: string;\n}\n\nexport interface ThemeValidationResult {\n valid: boolean;\n errors?: ThemeValidationError[];\n}\n\n/**\n * Basic structural validation for theme JSON (used by themes store).\n * Full schema validation is handled by Monaco's JSON language service.\n */\nexport function validateThemeJson(jsonString: string): ThemeValidationResult {\n try {\n const parsed = JSON.parse(jsonString);\n\n if (!parsed || typeof parsed !== 'object') {\n return {\n valid: false,\n errors: [{ message: 'Theme must be a JSON object' }],\n };\n }\n\n if (typeof parsed.name !== 'string' || !parsed.name.trim()) {\n return {\n valid: false,\n errors: [{ message: 'Theme must have a non-empty \"name\" property' }],\n };\n }\n\n return { valid: true };\n } catch (e) {\n return {\n valid: false,\n errors: [\n {\n message:\n e instanceof SyntaxError\n ? `Invalid JSON: ${e.message}`\n : 'Failed to parse theme JSON',\n },\n ],\n };\n }\n}\n\n/**\n * Gets theme name from a theme JSON object\n */\nexport function getThemeName(themeJson: unknown): string | null {\n try {\n if (\n themeJson &&\n typeof themeJson === 'object' &&\n 'name' in (themeJson as any) &&\n typeof (themeJson as any).name === 'string'\n ) {\n return (themeJson as any).name as string;\n }\n return null;\n } catch {\n return null;\n }\n}\n","// Theme change event emitter for coordinating theme updates across components\nexport interface ThemeChangeEvent {\n themeName: string;\n timestamp: number;\n changeType: 'create' | 'update' | 'delete';\n}\n\nexport class ThemeChangeEmitter extends EventTarget {\n private static instance: ThemeChangeEmitter;\n\n private constructor() {\n super();\n }\n\n static getInstance(): ThemeChangeEmitter {\n if (!ThemeChangeEmitter.instance) {\n ThemeChangeEmitter.instance = new ThemeChangeEmitter();\n }\n return ThemeChangeEmitter.instance;\n }\n\n emitThemeChange(event: ThemeChangeEvent): void {\n this.dispatchEvent(new CustomEvent('themechange', { detail: event }));\n }\n\n onThemeChange(callback: (event: ThemeChangeEvent) => void): () => void {\n const handler = (e: Event) => {\n const customEvent = e as CustomEvent<ThemeChangeEvent>;\n callback(customEvent.detail);\n };\n\n this.addEventListener('themechange', handler);\n\n // Track listener count\n (this as any)._listenerCount = ((this as any)._listenerCount || 0) + 1;\n\n // Return unsubscribe function\n return () => {\n this.removeEventListener('themechange', handler);\n (this as any)._listenerCount = Math.max(\n 0,\n ((this as any)._listenerCount || 1) - 1\n );\n };\n }\n}\n\nexport const themeChangeEmitter = ThemeChangeEmitter.getInstance();\n","function promisifyRequest(request) {\n return new Promise((resolve, reject) => {\n // @ts-ignore - file size hacks\n request.oncomplete = request.onsuccess = () => resolve(request.result);\n // @ts-ignore - file size hacks\n request.onabort = request.onerror = () => reject(request.error);\n });\n}\nfunction createStore(dbName, storeName) {\n let dbp;\n const getDB = () => {\n if (dbp)\n return dbp;\n const request = indexedDB.open(dbName);\n request.onupgradeneeded = () => request.result.createObjectStore(storeName);\n dbp = promisifyRequest(request);\n dbp.then((db) => {\n // It seems like Safari sometimes likes to just close the connection.\n // It's supposed to fire this event when that happens. Let's hope it does!\n db.onclose = () => (dbp = undefined);\n }, () => { });\n return dbp;\n };\n return (txMode, callback) => getDB().then((db) => callback(db.transaction(storeName, txMode).objectStore(storeName)));\n}\nlet defaultGetStoreFunc;\nfunction defaultGetStore() {\n if (!defaultGetStoreFunc) {\n defaultGetStoreFunc = createStore('keyval-store', 'keyval');\n }\n return defaultGetStoreFunc;\n}\n/**\n * Get a value by its key.\n *\n * @param key\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction get(key, customStore = defaultGetStore()) {\n return customStore('readonly', (store) => promisifyRequest(store.get(key)));\n}\n/**\n * Set a value with a key.\n *\n * @param key\n * @param value\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction set(key, value, customStore = defaultGetStore()) {\n return customStore('readwrite', (store) => {\n store.put(value, key);\n return promisifyRequest(store.transaction);\n });\n}\n/**\n * Set multiple values at once. This is faster than calling set() multiple times.\n * It's also atomic – if one of the pairs can't be added, none will be added.\n *\n * @param entries Array of entries, where each entry is an array of `[key, value]`.\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction setMany(entries, customStore = defaultGetStore()) {\n return customStore('readwrite', (store) => {\n entries.forEach((entry) => store.put(entry[1], entry[0]));\n return promisifyRequest(store.transaction);\n });\n}\n/**\n * Get multiple values by their keys\n *\n * @param keys\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction getMany(keys, customStore = defaultGetStore()) {\n return customStore('readonly', (store) => Promise.all(keys.map((key) => promisifyRequest(store.get(key)))));\n}\n/**\n * Update a value. This lets you see the old value and update it as an atomic operation.\n *\n * @param key\n * @param updater A callback that takes the old value and returns a new value.\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction update(key, updater, customStore = defaultGetStore()) {\n return customStore('readwrite', (store) => \n // Need to create the promise manually.\n // If I try to chain promises, the transaction closes in browsers\n // that use a promise polyfill (IE10/11).\n new Promise((resolve, reject) => {\n store.get(key).onsuccess = function () {\n try {\n store.put(updater(this.result), key);\n resolve(promisifyRequest(store.transaction));\n }\n catch (err) {\n reject(err);\n }\n };\n }));\n}\n/**\n * Delete a particular key from the store.\n *\n * @param key\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction del(key, customStore = defaultGetStore()) {\n return customStore('readwrite', (store) => {\n store.delete(key);\n return promisifyRequest(store.transaction);\n });\n}\n/**\n * Delete multiple keys at once.\n *\n * @param keys List of keys to delete.\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction delMany(keys, customStore = defaultGetStore()) {\n return customStore('readwrite', (store) => {\n keys.forEach((key) => store.delete(key));\n return promisifyRequest(store.transaction);\n });\n}\n/**\n * Clear all values in the store.\n *\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction clear(customStore = defaultGetStore()) {\n return customStore('readwrite', (store) => {\n store.clear();\n return promisifyRequest(store.transaction);\n });\n}\nfunction eachCursor(store, callback) {\n store.openCursor().onsuccess = function () {\n if (!this.result)\n return;\n callback(this.result);\n this.result.continue();\n };\n return promisifyRequest(store.transaction);\n}\n/**\n * Get all keys in the store.\n *\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction keys(customStore = defaultGetStore()) {\n return customStore('readonly', (store) => {\n // Fast path for modern browsers\n if (store.getAllKeys) {\n return promisifyRequest(store.getAllKeys());\n }\n const items = [];\n return eachCursor(store, (cursor) => items.push(cursor.key)).then(() => items);\n });\n}\n/**\n * Get all values in the store.\n *\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction values(customStore = defaultGetStore()) {\n return customStore('readonly', (store) => {\n // Fast path for modern browsers\n if (store.getAll) {\n return promisifyRequest(store.getAll());\n }\n const items = [];\n return eachCursor(store, (cursor) => items.push(cursor.value)).then(() => items);\n });\n}\n/**\n * Get all entries in the store. Each entry is an array of `[key, value]`.\n *\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction entries(customStore = defaultGetStore()) {\n return customStore('readonly', (store) => {\n // Fast path for modern browsers\n // (although, hopefully we'll get a simpler path some day)\n if (store.getAll && store.getAllKeys) {\n return Promise.all([\n promisifyRequest(store.getAllKeys()),\n promisifyRequest(store.getAll()),\n ]).then(([keys, values]) => keys.map((key, i) => [key, values[i]]));\n }\n const items = [];\n return customStore('readonly', (store) => eachCursor(store, (cursor) => items.push([cursor.key, cursor.value])).then(() => items));\n });\n}\n\nexport { clear, createStore, del, delMany, entries, get, getMany, keys, promisifyRequest, set, setMany, update, values };\n","/**\n * IndexedDB storage adapter for Zustand persist middleware using idb-keyval.\n */\nimport { get, set, del } from 'idb-keyval';\nimport type { StateStorage } from 'zustand/middleware';\n\nexport const idbStorage: StateStorage = {\n getItem: async (name: string): Promise<string | null> => {\n return (await get(name)) ?? null;\n },\n setItem: async (name: string, value: string): Promise<void> => {\n await set(name, value);\n },\n removeItem: async (name: string): Promise<void> => {\n await del(name);\n },\n};\n","import { persist, devtools, createJSONStorage } from 'zustand/middleware';\nimport { createStore } from 'zustand/vanilla';\nimport type { ThemeConfigJson } from '@json-to-office/shared-pptx';\nimport { validateThemeJson, getThemeName } from '../lib/theme-validation';\nimport { themeChangeEmitter } from '../utils/theme-change-emitter';\nimport { idbStorage } from '../lib/idb-storage';\n\nexport type CustomTheme = {\n name: string;\n content: string;\n parsed?: ThemeConfigJson;\n valid: boolean;\n lastModified: Date;\n};\n\nexport type ThemesState = {\n customThemes: { [name: string]: CustomTheme };\n};\n\n/**\n * Valid custom themes keyed by theme name — the `customThemes` shape every\n * server request carries. File names are the store's keys; the server and\n * the plugin sandbox look themes up by the name inside the JSON.\n */\nexport function validThemesByName(customThemes: {\n [name: string]: CustomTheme;\n}): Record<string, ThemeConfigJson> {\n const out: Record<string, ThemeConfigJson> = {};\n for (const theme of Object.values(customThemes)) {\n if (theme.valid && theme.parsed) out[theme.name] = theme.parsed;\n }\n return out;\n}\n\nexport type ThemesActions = {\n updateTheme: (documentName: string, content: string) => void;\n removeTheme: (documentName: string) => void;\n getTheme: (themeName: string) => ThemeConfigJson | null;\n getAllThemeNames: () => string[];\n isThemeValid: (themeName: string) => boolean;\n};\n\nexport type ThemesStore = ThemesState & ThemesActions;\n\nexport const initThemesStore = (): ThemesState => {\n return {\n customThemes: {},\n };\n};\n\nexport const defaultInitThemesState: ThemesState = {\n ...initThemesStore(),\n};\n\nexport const createThemesStore = (\n initState: ThemesState = defaultInitThemesState\n) => {\n return createStore<ThemesStore>()(\n devtools(\n persist(\n (set, get) => ({\n ...initState,\n\n updateTheme: (documentName, content) =>\n set((state) => {\n const validation = validateThemeJson(content);\n\n let parsed: ThemeConfigJson | undefined;\n let themeName = documentName;\n\n if (validation.valid) {\n try {\n const parsedContent = JSON.parse(content);\n parsed = parsedContent;\n const extractedName = getThemeName(parsedContent);\n if (extractedName) {\n themeName = extractedName;\n }\n } catch {\n // Keep the document name if parsing fails\n }\n }\n\n const existingTheme = state.customThemes[documentName];\n const isUpdate = !!existingTheme;\n const hasContentChanged = existingTheme?.content !== content;\n\n const customTheme: CustomTheme = {\n name: themeName,\n content,\n parsed,\n valid: validation.valid,\n lastModified: new Date(),\n };\n\n // Emit theme change if content changed OR if this is a newly valid theme\n const shouldEmitEvent =\n (hasContentChanged ||\n (!existingTheme?.valid && validation.valid)) &&\n validation.valid;\n\n if (shouldEmitEvent) {\n // Use setTimeout to ensure state is updated before event is processed\n setTimeout(() => {\n themeChangeEmitter.emitThemeChange({\n themeName,\n timestamp: Date.now(),\n changeType: isUpdate ? 'update' : 'create',\n });\n }, 0);\n }\n\n return {\n customThemes: {\n ...state.customThemes,\n [documentName]: customTheme,\n },\n };\n }),\n\n removeTheme: (documentName) =>\n set((state) => {\n const removedTheme = state.customThemes[documentName];\n const newCustomThemes = { ...state.customThemes };\n delete newCustomThemes[documentName];\n\n // Emit theme deletion event\n if (removedTheme) {\n setTimeout(() => {\n themeChangeEmitter.emitThemeChange({\n themeName: removedTheme.name,\n timestamp: Date.now(),\n changeType: 'delete',\n });\n }, 0);\n }\n\n return {\n customThemes: newCustomThemes,\n };\n }),\n\n getTheme: (themeName) => {\n const state = get();\n\n // First check custom themes by theme name\n for (const customTheme of Object.values(state.customThemes)) {\n if (\n customTheme.valid &&\n customTheme.name === themeName &&\n customTheme.parsed\n ) {\n return customTheme.parsed;\n }\n }\n\n // Theme not found in custom themes\n return null;\n },\n\n getAllThemeNames: () => {\n const state = get();\n const names: string[] = [];\n\n // Add custom theme names\n for (const customTheme of Object.values(state.customThemes)) {\n if (customTheme.valid && customTheme.name) {\n names.push(customTheme.name);\n }\n }\n\n return names;\n },\n\n isThemeValid: (themeName) => {\n const state = get();\n\n // Check custom themes\n for (const customTheme of Object.values(state.customThemes)) {\n if (customTheme.name === themeName) {\n return customTheme.valid;\n }\n }\n\n return false;\n },\n }),\n {\n name: 'themes-storage',\n version: 4, // v4: migrate from localStorage to IndexedDB\n storage: createJSONStorage(() => idbStorage),\n // Only persist the themes data, not the functions\n partialize: (state) => ({ customThemes: state.customThemes }),\n // Handle date deserialization when loading from storage\n onRehydrateStorage: () => (state) => {\n if (state && state.customThemes) {\n // Convert lastModified strings back to Date objects\n Object.keys(state.customThemes).forEach((key) => {\n const theme = state.customThemes[key];\n if (\n theme.lastModified &&\n typeof theme.lastModified === 'string'\n ) {\n theme.lastModified = new Date(theme.lastModified);\n }\n });\n }\n },\n }\n )\n )\n );\n};\n","import { type ReactNode, createContext, useRef, useContext } from 'react';\nimport { useStore } from 'zustand';\n\nimport {\n type ThemesStore,\n createThemesStore,\n initThemesStore,\n} from './themes-store';\n\nexport type ThemesStoreApi = ReturnType<typeof createThemesStore>;\n\nexport const ThemesStoreContext = createContext<ThemesStoreApi | undefined>(\n undefined\n);\n\nexport interface ThemesStoreProviderProps {\n children: ReactNode;\n}\n\nexport const ThemesStoreProvider = ({ children }: ThemesStoreProviderProps) => {\n const storeRef = useRef<ThemesStoreApi>(undefined);\n if (!storeRef.current) {\n storeRef.current = createThemesStore(initThemesStore());\n }\n\n return (\n <ThemesStoreContext.Provider value={storeRef.current}>\n {children}\n </ThemesStoreContext.Provider>\n );\n};\n\nexport const useThemesStore = <T,>(selector: (store: ThemesStore) => T): T => {\n const themesStoreContext = useContext(ThemesStoreContext);\n\n if (!themesStoreContext) {\n throw new Error('useThemesStore must be used within ThemesStoreProvider');\n }\n\n return useStore(themesStoreContext, selector);\n};\n","/**\n * Cheap content hash for change detection (djb2, base-36). Not\n * cryptographic — it only decides whether a plugin source needs recompiling.\n */\nexport function hashSource(text: string): string {\n let hash = 5381;\n for (let i = 0; i < text.length; i++) {\n hash = ((hash << 5) + hash + text.charCodeAt(i)) | 0;\n }\n return `${(hash >>> 0).toString(36)}-${text.length.toString(36)}`;\n}\n","import { create } from 'zustand';\nimport { createJSONStorage, persist } from 'zustand/middleware';\nimport { idbStorage } from '../lib/idb-storage';\nimport { hashSource } from '../lib/plugins/hash';\nimport type {\n BrowserPluginMetadata,\n BrowserPluginRecord,\n PluginDiagnostic,\n} from '../lib/plugins/types';\n\n/**\n * Plugins compiled in the browser, one record per `*.component.ts` file.\n *\n * The compiled JavaScript and the metadata are persisted alongside the\n * enable switches, so a reload can expand documents and offer completions\n * without recompiling first — compiling needs Monaco's TypeScript worker,\n * which is not up until the editor is. The source itself lives with the\n * document; `sourceHash` is what tells the sync hook a record is stale.\n *\n * IndexedDB, like the documents and themes: compiled code for a plugin that\n * inlines an asset runs past what localStorage tolerates, and a store that\n * stops persisting on a quota error would do so silently.\n */\n\nexport interface BrowserPluginsState {\n records: Record<string, BrowserPluginRecord>;\n}\n\nexport interface BrowserPluginsActions {\n /** Create or update a record; missing fields keep their previous value. */\n upsert: (\n docName: string,\n patch: Partial<Omit<BrowserPluginRecord, 'docName' | 'createdAt'>>\n ) => void;\n setEnabled: (docName: string, enabled: boolean) => void;\n setAllowNetwork: (docName: string, allowNetwork: boolean) => void;\n /** The hosts the Network switch grants; anything else stays refused. */\n setNetworkOrigins: (docName: string, networkOrigins: string[]) => void;\n rename: (oldName: string, newName: string) => void;\n remove: (docName: string) => void;\n}\n\nexport type BrowserPluginsStore = BrowserPluginsState & BrowserPluginsActions;\n\nexport function createBrowserPluginRecord(\n docName: string,\n patch: Partial<Omit<BrowserPluginRecord, 'docName'>> = {}\n): BrowserPluginRecord {\n const now = Date.now();\n return {\n docName,\n enabled: true,\n allowNetwork: false,\n networkOrigins: [],\n status: 'idle',\n sourceHash: '',\n diagnostics: [],\n createdAt: now,\n updatedAt: now,\n ...patch,\n };\n}\n\nexport const useBrowserPluginsStore = create<BrowserPluginsStore>()(\n persist(\n (set) => ({\n records: {},\n\n upsert: (docName, patch) =>\n set((state) => {\n const existing =\n state.records[docName] ?? createBrowserPluginRecord(docName);\n return {\n records: {\n ...state.records,\n [docName]: { ...existing, ...patch, updatedAt: Date.now() },\n },\n };\n }),\n\n // A plugin file is on screen before the sync hook has compiled it, so\n // these two create the record they are missing rather than dropping the\n // switch: the setting the author just made has to survive the compile.\n setEnabled: (docName, enabled) =>\n set((state) => {\n const existing =\n state.records[docName] ?? createBrowserPluginRecord(docName);\n if (state.records[docName] && existing.enabled === enabled)\n return state;\n return {\n records: {\n ...state.records,\n [docName]: { ...existing, enabled, updatedAt: Date.now() },\n },\n };\n }),\n\n setAllowNetwork: (docName, allowNetwork) =>\n set((state) => {\n const existing =\n state.records[docName] ?? createBrowserPluginRecord(docName);\n if (state.records[docName] && existing.allowNetwork === allowNetwork)\n return state;\n return {\n records: {\n ...state.records,\n [docName]: { ...existing, allowNetwork, updatedAt: Date.now() },\n },\n };\n }),\n\n setNetworkOrigins: (docName, networkOrigins) =>\n set((state) => {\n const existing =\n state.records[docName] ?? createBrowserPluginRecord(docName);\n const previous = existing.networkOrigins ?? [];\n if (\n state.records[docName] &&\n previous.length === networkOrigins.length &&\n previous.every((origin, i) => origin === networkOrigins[i])\n ) {\n return state;\n }\n return {\n records: {\n ...state.records,\n [docName]: {\n ...existing,\n networkOrigins: [...networkOrigins],\n updatedAt: Date.now(),\n },\n },\n };\n }),\n\n rename: (oldName, newName) =>\n set((state) => {\n const existing = state.records[oldName];\n if (!existing || oldName === newName) return state;\n const records = { ...state.records };\n delete records[oldName];\n records[newName] = { ...existing, docName: newName };\n return { records };\n }),\n\n remove: (docName) =>\n set((state) => {\n if (!state.records[docName]) return state;\n const records = { ...state.records };\n delete records[docName];\n return { records };\n }),\n }),\n {\n name: 'jto-browser-plugins',\n version: 3,\n storage: createJSONStorage(() => idbStorage),\n partialize: (state) => ({ records: state.records }),\n // v1 lived in localStorage and had no createdAt. v2 had no origin list,\n // and `allowNetwork` alone meant the whole internet — a record from then\n // comes back with the switch on but nothing listed, which reaches\n // nothing until its author says which hosts it needs.\n migrate: (persisted) => {\n const state = persisted as {\n records?: Record<string, BrowserPluginRecord>;\n };\n const records: Record<string, BrowserPluginRecord> = {};\n for (const [name, record] of Object.entries(state?.records ?? {})) {\n records[name] = {\n ...record,\n createdAt: record.createdAt ?? record.updatedAt ?? Date.now(),\n networkOrigins: record.networkOrigins ?? [],\n };\n }\n return { records };\n },\n }\n )\n);\n\n/**\n * Resolves once the persisted records are in memory. The IndexedDB read is\n * asynchronous, and a sync that ran before it would compile every plugin\n * from scratch and then be overwritten by what the store had all along.\n */\nexport function whenBrowserPluginsHydrated(): Promise<void> {\n const api = useBrowserPluginsStore.persist;\n if (api.hasHydrated()) return Promise.resolve();\n return new Promise((resolve) => {\n const stop = api.onFinishHydration(() => {\n stop();\n resolve();\n });\n });\n}\n\n/** A plugin that takes part in schema generation and expansion. */\nexport interface ActiveBrowserPlugin {\n docName: string;\n metadata: BrowserPluginMetadata;\n}\n\nexport function selectActivePlugins(\n state: BrowserPluginsState\n): ActiveBrowserPlugin[] {\n const active: ActiveBrowserPlugin[] = [];\n for (const record of Object.values(state.records)) {\n if (record.enabled && record.status === 'ready' && record.metadata) {\n active.push({ docName: record.docName, metadata: record.metadata });\n }\n }\n return active.sort((a, b) => a.docName.localeCompare(b.docName));\n}\n\n/**\n * A string that changes exactly when the set of active plugins, or any of\n * their schemas, changes — what schema refreshes key on.\n */\nexport function activePluginsSignature(state: BrowserPluginsState): string {\n const components = browserComponentsForSchema(state);\n // Empty stays empty, so a page with no active plugin keys on '' rather than\n // on the hash of an empty array.\n if (components.length === 0) return '';\n // The whole payload the schema route receives, not the props alone:\n // `hasChildren` and `description` reach the composed schema too.\n return hashSource(JSON.stringify(components));\n}\n\n/**\n * Which file owns a component name when several claim it: the one created\n * first. Deterministic across reloads, and a rename of the newcomer resolves\n * it on its next compile.\n */\nexport function componentNameOwner(\n records: Record<string, BrowserPluginRecord>,\n componentName: string\n): string | undefined {\n let owner: BrowserPluginRecord | undefined;\n for (const record of Object.values(records)) {\n if (record.metadata?.name !== componentName) continue;\n if (!owner || record.createdAt < owner.createdAt) owner = record;\n }\n return owner?.docName;\n}\n\n/** The shape `POST /api/discovery/schemas/document` accepts for a browser plugin. */\nexport interface BrowserComponentSchemaInfo {\n name: string;\n versions: Array<{\n version: string;\n propsSchema: Record<string, unknown>;\n hasChildren?: boolean;\n description?: string;\n }>;\n}\n\nexport function browserComponentsForSchema(\n state: BrowserPluginsState\n): BrowserComponentSchemaInfo[] {\n return selectActivePlugins(state).map((plugin) => ({\n name: plugin.metadata.name,\n versions: plugin.metadata.versions.map((v) => ({\n version: v.version,\n propsSchema: v.propsSchema,\n ...(v.hasChildren ? { hasChildren: true } : {}),\n ...(v.description ? { description: v.description } : {}),\n })),\n }));\n}\n\n/** Diagnostics a record carries, for the sidebar and the editor strip. */\nexport function recordErrors(\n record: BrowserPluginRecord | undefined\n): PluginDiagnostic[] {\n return (record?.diagnostics ?? []).filter((d) => d.severity === 'error');\n}\n","/**\n * Which origins a browser plugin may reach when its Network switch is on.\n *\n * `connect-src *` would make that switch mean \"the whole internet\", and the\n * same policy carries `'unsafe-eval'`: a plugin could then fetch code and run\n * it, so a source someone read and found harmless could pull its real payload\n * at render time, and anything it renders could be posted anywhere. Neither is\n * an escape from the sandbox — fetched code runs under the same opaque origin\n * and the same policy — but both defeat reading the plugin before trusting it.\n *\n * So the switch grants the origins listed against the plugin and nothing else.\n * Every value here ends up inside a CSP header, which is why parsing is strict\n * rather than forgiving: a stray `;` or space would end the directive and open\n * the rest of the policy.\n */\n\n/** What a plugin with Network on but nothing listed is allowed to reach. */\nconst NOTHING = \"'none'\";\n\nexport type OriginResult =\n | { ok: true; origin: string }\n | { ok: false; reason: string };\n\n/** Hostname, or `*.` plus one: letters, digits, hyphens and dots only. */\nconst HOST =\n /^(\\*\\.)?[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/;\n\n/** Loopback may be reached over plain http; everything else must be https. */\nfunction isLoopback(host: string): boolean {\n return host === 'localhost' || host === '127.0.0.1' || host === '[::1]';\n}\n\n/**\n * Turn one line of author input into a CSP source expression.\n *\n * `api.example.com` and `https://api.example.com` both mean the same origin;\n * a bare host is read as https because that is the only scheme worth\n * defaulting to. `*.example.com` matches subdomains, as CSP defines it.\n */\nexport function normalizeNetworkOrigin(input: string): OriginResult {\n const trimmed = input.trim().replace(/\\/+$/, '');\n if (!trimmed) return { ok: false, reason: 'is empty' };\n // A blanket source would put the switch back to meaning \"anywhere\".\n if (trimmed === '*' || /^https?:$/i.test(trimmed) || trimmed === '*:*') {\n return { ok: false, reason: 'is a wildcard — name the hosts you need' };\n }\n\n const withScheme = /^[a-z][a-z0-9+.-]*:\\/\\//i.test(trimmed)\n ? trimmed\n : `https://${trimmed}`;\n\n // `*.` is a CSP source expression, not a legal URL label: take it off before\n // parsing and put it back on the hostname afterwards.\n const wildcard = /^(https?:\\/\\/)\\*\\./i.test(withScheme);\n const parseable = wildcard\n ? withScheme.replace(/^(https?:\\/\\/)\\*\\./i, '$1')\n : withScheme;\n\n let url: URL;\n try {\n url = new URL(parseable);\n } catch {\n return { ok: false, reason: 'is not a URL' };\n }\n\n if (url.username || url.password) {\n return { ok: false, reason: 'must not carry credentials' };\n }\n if (url.pathname !== '/' || url.search || url.hash) {\n return { ok: false, reason: 'must be an origin, with no path' };\n }\n\n const host = wildcard ? `*.${url.hostname}` : url.hostname;\n if (!HOST.test(host)) return { ok: false, reason: 'is not a hostname' };\n\n const protocol = url.protocol.toLowerCase();\n if (protocol !== 'https:' && protocol !== 'http:') {\n return { ok: false, reason: 'must be http or https' };\n }\n if (protocol === 'http:' && !isLoopback(url.hostname)) {\n return { ok: false, reason: 'must use https (http is only for localhost)' };\n }\n\n return {\n ok: true,\n origin: `${protocol}//${host}${url.port ? `:${url.port}` : ''}`,\n };\n}\n\nexport interface ParsedOrigins {\n origins: string[];\n /** One per rejected line, ready to show against the field. */\n errors: string[];\n}\n\n/** Parse the field's text: one origin per line, or comma separated. */\nexport function parseNetworkOrigins(text: string): ParsedOrigins {\n const origins: string[] = [];\n const errors: string[] = [];\n for (const line of text.split(/[\\n,]/)) {\n if (!line.trim()) continue;\n const result = normalizeNetworkOrigin(line);\n if (!result.ok) errors.push(`\"${line.trim()}\" ${result.reason}`);\n else if (!origins.includes(result.origin)) origins.push(result.origin);\n }\n return { origins, errors };\n}\n\n/**\n * The `connect-src` value for a plugin. Anything that did not survive\n * `normalizeNetworkOrigin` is dropped rather than trusted: this string is\n * interpolated into a policy, and a record could have been persisted by an\n * older build with looser rules.\n */\nexport function connectSrcValue(\n allowNetwork: boolean,\n origins: readonly string[] | undefined\n): string {\n if (!allowNetwork || !origins?.length) return NOTHING;\n const safe = origins\n .map((origin) => normalizeNetworkOrigin(origin))\n .filter((result): result is { ok: true; origin: string } => result.ok)\n .map((result) => result.origin);\n return safe.length > 0 ? safe.join(' ') : NOTHING;\n}\n\n/** True when the plugin can reach anything at all — what the worker hardens on. */\nexport function hasNetworkAccess(\n allowNetwork: boolean,\n origins: readonly string[] | undefined\n): boolean {\n return connectSrcValue(allowNetwork, origins) !== NOTHING;\n}\n","/**\n * The boundary a plugin runs behind.\n *\n * An `<iframe sandbox=\"allow-scripts\">` with no `allow-same-origin` has an\n * opaque origin: nothing inside it can read the playground's storage, send\n * its cookies or call its API as the user. The frame's own document carries a\n * Content-Security-Policy, and the worker it spawns from a blob: URL inherits\n * that policy — so `import()` of a remote script, `fetch`, WebSockets and\n * WebTransport are refused by the browser itself, not by a list of globals\n * the runtime tried to delete. `connect-src` is the one knob, and it names\n * the plugin's own origins: `'none'` until its Network switch is on and its\n * allowlist has something in it (network-policy.ts).\n *\n * The page talks to the frame with `postMessage`; the frame relays to the\n * worker. Only messages from this frame's window are accepted back.\n */\nimport { connectSrcValue } from './network-policy';\n\nexport interface SandboxFrameOptions {\n /** The bundled runtime script (virtual:jto-sandbox-runtime). */\n runtime: string;\n allowNetwork: boolean;\n /** Origins the switch grants; empty reaches nothing. */\n networkOrigins?: readonly string[];\n onMessage: (data: unknown) => void;\n onError: (message: string) => void;\n}\n\nfunction nonce(): string {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * The frame's document. Everything is inline and nonce-bound: the frame has\n * no origin to load anything else from, and the policy says so.\n */\nexport function sandboxDocument(\n scriptNonce: string,\n allowNetwork: boolean,\n networkOrigins?: readonly string[]\n): string {\n const csp = [\n \"default-src 'none'\",\n // blob: for the worker script; 'unsafe-eval' because the runtime turns\n // the plugin's compiled CommonJS into a function. No host, so the\n // worker cannot import() code from anywhere.\n `script-src 'nonce-${scriptNonce}' blob: 'unsafe-eval'`,\n 'worker-src blob:',\n // Built by network-policy.ts, which re-validates every origin: the value\n // lands inside the policy, so nothing reaches it unparsed.\n `connect-src ${connectSrcValue(allowNetwork, networkOrigins)}`,\n \"base-uri 'none'\",\n \"form-action 'none'\",\n ].join('; ');\n return `<!doctype html><html><head><meta charset=\"utf-8\"><meta http-equiv=\"Content-Security-Policy\" content=\"${csp}\"></head><body><script nonce=\"${scriptNonce}\">\n(function () {\n var worker = null;\n window.addEventListener('message', function (event) {\n if (event.source !== window.parent) return;\n var message = event.data;\n if (!message || typeof message !== 'object') return;\n if (message.type === 'init') {\n if (worker) return;\n var url = URL.createObjectURL(new Blob([message.runtime], { type: 'text/javascript' }));\n worker = new Worker(url);\n worker.onmessage = function (reply) { window.parent.postMessage(reply.data, '*'); };\n worker.onerror = function (error) {\n window.parent.postMessage({ type: 'workerError', message: (error && error.message) || 'Worker error' }, '*');\n };\n window.parent.postMessage({ type: 'ready' }, '*');\n return;\n }\n if (worker) worker.postMessage(message);\n });\n})();\n</script></body></html>`;\n}\n\nexport class SandboxFrame {\n private readonly iframe: HTMLIFrameElement;\n private readonly ready: Promise<void>;\n private readonly listener: (event: MessageEvent) => void;\n private disposed = false;\n\n constructor(options: SandboxFrameOptions) {\n const scriptNonce = nonce();\n const iframe = document.createElement('iframe');\n iframe.setAttribute('sandbox', 'allow-scripts');\n iframe.setAttribute('aria-hidden', 'true');\n iframe.setAttribute('title', 'Plugin sandbox');\n iframe.tabIndex = -1;\n iframe.style.cssText =\n 'position:absolute;width:0;height:0;border:0;visibility:hidden;pointer-events:none;';\n this.iframe = iframe;\n\n let resolveReady: () => void = () => {};\n let rejectReady: (error: Error) => void = () => {};\n this.ready = new Promise<void>((resolve, reject) => {\n resolveReady = resolve;\n rejectReady = reject;\n });\n // A frame that never answers would leave every request waiting on it.\n const readyTimer = setTimeout(() => {\n rejectReady(new Error('Plugin sandbox did not start'));\n }, 10_000);\n\n this.listener = (event: MessageEvent) => {\n if (event.source !== iframe.contentWindow) return;\n const data = event.data as { type?: unknown; message?: unknown } | null;\n if (!data || typeof data !== 'object') return;\n if (data.type === 'ready') {\n clearTimeout(readyTimer);\n resolveReady();\n return;\n }\n if (data.type === 'workerError') {\n options.onError(\n typeof data.message === 'string' ? data.message : 'Worker error'\n );\n return;\n }\n options.onMessage(data);\n };\n window.addEventListener('message', this.listener);\n\n iframe.addEventListener('load', () => {\n iframe.contentWindow?.postMessage(\n { type: 'init', runtime: options.runtime },\n '*'\n );\n });\n iframe.srcdoc = sandboxDocument(\n scriptNonce,\n options.allowNetwork,\n options.networkOrigins\n );\n document.body.appendChild(iframe);\n // Nobody awaits `ready` before the first post; surface a start failure\n // there rather than as an unhandled rejection here.\n this.ready.catch(() => {});\n }\n\n async post(message: unknown): Promise<void> {\n await this.ready;\n if (this.disposed) throw new Error('Plugin sandbox was closed');\n this.iframe.contentWindow?.postMessage(message, '*');\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n window.removeEventListener('message', this.listener);\n this.iframe.remove();\n }\n}\n","import { useBrowserPluginsStore } from '../../store/browser-plugins-store';\nimport type { PluginRenderRequest, PluginRenderResult } from './expand';\nimport { SandboxFrame } from './sandbox-frame';\nimport type {\n BrowserPluginMetadata,\n PluginExample,\n PluginFormat,\n SandboxRequest,\n SandboxResponse,\n} from './types';\n\n/**\n * The page side of the sandbox: one frame (and one worker) per plugin file,\n * request/response over `postMessage`, hard time limits.\n *\n * A plugin that misses its deadline is torn down, not asked nicely — an\n * infinite loop in a render cannot be interrupted any other way — and the\n * next request starts a fresh one from the persisted compiled code. Idle\n * plugins are torn down too: a worker nobody is rendering with has no\n * business running.\n */\n\nexport interface LoadSpec {\n js: string;\n format: PluginFormat;\n allowNetwork: boolean;\n /** Origins the frame's CSP will name; order-insensitive for `sameSpec`. */\n networkOrigins?: string[];\n examples: PluginExample[];\n}\n\n/** The part of a spec baked into the frame's policy and unchangeable after. */\ninterface FramePolicy {\n allowNetwork: boolean;\n networkOrigins: string[];\n}\n\nfunction framePolicy(spec: {\n allowNetwork: boolean;\n networkOrigins?: readonly string[];\n}): FramePolicy {\n return {\n allowNetwork: spec.allowNetwork,\n networkOrigins: [...(spec.networkOrigins ?? [])].sort(),\n };\n}\n\nfunction samePolicy(a: FramePolicy, b: FramePolicy): boolean {\n return (\n a.allowNetwork === b.allowNetwork &&\n a.networkOrigins.length === b.networkOrigins.length &&\n a.networkOrigins.every((origin, i) => origin === b.networkOrigins[i])\n );\n}\n\nconst LOAD_TIMEOUT_MS = 8_000;\nconst RENDER_TIMEOUT_MS = 20_000;\nconst IDLE_TIMEOUT_MS = 30_000;\n\n/** `Omit` that distributes over the request union instead of intersecting it. */\ntype RequestPayload<T> = T extends { id: number } ? Omit<T, 'id'> : never;\ntype SandboxRequestPayload = RequestPayload<SandboxRequest>;\n\ninterface Pending {\n resolve: (response: SandboxResponse) => void;\n reject: (error: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\ninterface Entry {\n frame: SandboxFrame;\n /**\n * The policy this frame's CSP was built from. A frame cannot be re-policed\n * after `srcdoc`, so a request under a different one needs a new frame.\n */\n policy: FramePolicy;\n /** The spec the worker was loaded with; null until `loaded` arrives. */\n loaded: LoadSpec | null;\n pending: Map<number, Pending>;\n idleTimer: ReturnType<typeof setTimeout> | null;\n}\n\nexport class PluginTimeoutError extends Error {\n constructor(docName: string, what: string, ms: number) {\n super(\n `Plugin \"${docName}\" did not finish ${what} within ${Math.round(ms / 1000)}s and was stopped.`\n );\n this.name = 'PluginTimeoutError';\n }\n}\n\nexport class PluginAbortedError extends Error {\n constructor(docName: string) {\n super(`Plugin \"${docName}\" render was cancelled`);\n this.name = 'PluginAbortedError';\n }\n}\n\nlet runtimePromise: Promise<string> | null = null;\n\n/** The bundled runtime, fetched once; a failed load is retried next time. */\nfunction loadRuntime(): Promise<string> {\n if (!runtimePromise) {\n runtimePromise = import('virtual:jto-sandbox-runtime')\n .then((module) => module.default)\n .catch((error) => {\n runtimePromise = null;\n throw error;\n });\n }\n return runtimePromise;\n}\n\nfunction sameSpec(a: LoadSpec, b: LoadSpec): boolean {\n return (\n a.js === b.js &&\n a.format === b.format &&\n samePolicy(framePolicy(a), framePolicy(b)) &&\n JSON.stringify(a.examples) === JSON.stringify(b.examples)\n );\n}\n\nclass PluginHost {\n private entries = new Map<string, Entry>();\n private nextId = 1;\n\n private async entry(docName: string, policy: FramePolicy): Promise<Entry> {\n const existing = this.entries.get(docName);\n if (existing) {\n // The CSP is fixed when the frame is written. Reusing one built under a\n // wider policy would keep granting what the switch has since taken\n // away, so the mismatch is what forces a new frame — not the caller\n // remembering to dispose.\n if (samePolicy(existing.policy, policy)) return existing;\n this.dispose(\n docName,\n new Error(`Plugin \"${docName}\" network policy changed`)\n );\n }\n const runtime = await loadRuntime();\n // Two callers racing to create the same frame: the second wins nothing.\n const raced = this.entries.get(docName);\n if (raced) return raced;\n const entry: Entry = {\n frame: null as unknown as SandboxFrame,\n policy,\n loaded: null,\n pending: new Map(),\n idleTimer: null,\n };\n entry.frame = new SandboxFrame({\n runtime,\n allowNetwork: policy.allowNetwork,\n networkOrigins: policy.networkOrigins,\n onMessage: (data) => {\n const response = data as SandboxResponse;\n if (!response || typeof response.id !== 'number') return;\n const pending = entry.pending.get(response.id);\n if (!pending) return;\n entry.pending.delete(response.id);\n clearTimeout(pending.timer);\n pending.resolve(response);\n this.touch(docName, entry);\n },\n onError: (message) => {\n this.dispose(\n docName,\n new Error(`Plugin \"${docName}\" crashed: ${message}`)\n );\n },\n });\n this.entries.set(docName, entry);\n return entry;\n }\n\n /** Restart the idle clock; a frame with nothing pending is closed after it. */\n private touch(docName: string, entry: Entry): void {\n if (entry.idleTimer) clearTimeout(entry.idleTimer);\n entry.idleTimer = setTimeout(() => {\n if (entry.pending.size === 0 && this.entries.get(docName) === entry) {\n this.dispose(docName);\n }\n }, IDLE_TIMEOUT_MS);\n }\n\n private async request(\n docName: string,\n policy: FramePolicy,\n payload: SandboxRequestPayload,\n timeoutMs: number,\n what: string,\n signal?: AbortSignal\n ): Promise<SandboxResponse> {\n if (signal?.aborted) throw new PluginAbortedError(docName);\n const entry = await this.entry(docName, policy);\n if (entry.idleTimer) clearTimeout(entry.idleTimer);\n const id = this.nextId++;\n const result = new Promise<SandboxResponse>((resolve, reject) => {\n // The caller's signal outlives this request — a build aborts its signal\n // during cleanup, long after the renders it guarded have settled. Left\n // attached, that abort would dispose the frame and reject whatever is\n // in flight at the time, so the listener goes when the request does.\n let onAbort: (() => void) | null = null;\n const detach = () => {\n if (onAbort) signal?.removeEventListener('abort', onAbort);\n onAbort = null;\n };\n const timer = setTimeout(() => {\n entry.pending.delete(id);\n detach();\n this.dispose(docName, new PluginTimeoutError(docName, what, timeoutMs));\n reject(new PluginTimeoutError(docName, what, timeoutMs));\n }, timeoutMs);\n entry.pending.set(id, {\n resolve: (response) => {\n detach();\n resolve(response);\n },\n reject: (error) => {\n detach();\n reject(error);\n },\n timer,\n });\n onAbort = () => {\n // A cancelled build must not leave a render burning in the worker.\n this.dispose(docName, new PluginAbortedError(docName));\n };\n signal?.addEventListener('abort', onAbort, { once: true });\n entry.frame.post({ id, ...payload } as SandboxRequest).catch((error) => {\n entry.pending.delete(id);\n clearTimeout(timer);\n detach();\n reject(error instanceof Error ? error : new Error(String(error)));\n });\n });\n return result;\n }\n\n /** Evaluate compiled code in a fresh sandbox and describe the component. */\n async load(docName: string, spec: LoadSpec): Promise<BrowserPluginMetadata> {\n const existing = this.entries.get(docName);\n if (existing && (!existing.loaded || !sameSpec(existing.loaded, spec))) {\n // The policy and the module state are per frame: a new spec gets a\n // new one.\n this.dispose(docName, new Error(`Plugin \"${docName}\" was reloaded`));\n }\n const response = await this.request(\n docName,\n framePolicy(spec),\n {\n type: 'load',\n js: spec.js,\n format: spec.format,\n allowNetwork: spec.allowNetwork,\n networkOrigins: spec.networkOrigins ?? [],\n examples: spec.examples,\n },\n LOAD_TIMEOUT_MS,\n 'loading'\n );\n if (response.type === 'error') {\n this.dispose(docName, new Error(response.message));\n throw new Error(response.message);\n }\n if (response.type !== 'loaded') {\n throw new Error(`Unexpected sandbox reply \"${response.type}\"`);\n }\n const entry = this.entries.get(docName);\n if (entry) entry.loaded = spec;\n return response.metadata;\n }\n\n /**\n * Render one component instance. Loads the sandbox from the persisted\n * record first when nothing is running (a reload, a timeout, idleness).\n */\n async render(\n docName: string,\n request: PluginRenderRequest,\n signal?: AbortSignal\n ): Promise<PluginRenderResult> {\n const record = useBrowserPluginsStore.getState().records[docName];\n const policy = framePolicy({\n allowNetwork: record?.allowNetwork ?? false,\n networkOrigins: record?.networkOrigins,\n });\n const entry = this.entries.get(docName);\n if (!entry || !entry.loaded || !samePolicy(entry.policy, policy)) {\n if (!record?.js || !record.metadata) {\n throw new Error(`Plugin \"${docName}\" is not compiled`);\n }\n await this.load(docName, {\n js: record.js,\n format: record.metadata.format,\n allowNetwork: record.allowNetwork,\n networkOrigins: record.networkOrigins,\n examples: record.metadata.examples,\n });\n }\n const response = await this.request(\n docName,\n policy,\n {\n type: 'render',\n version: request.version,\n props: request.props,\n theme: request.theme,\n children: request.children,\n },\n RENDER_TIMEOUT_MS,\n 'rendering',\n signal\n );\n if (response.type === 'error') throw new Error(response.message);\n if (response.type !== 'rendered') {\n throw new Error(`Unexpected sandbox reply \"${response.type}\"`);\n }\n return { components: response.components, warnings: response.warnings };\n }\n\n /** Tear the sandbox down; every request still in flight rejects with `reason`. */\n dispose(docName: string, reason?: Error): void {\n const entry = this.entries.get(docName);\n if (!entry) return;\n this.entries.delete(docName);\n if (entry.idleTimer) clearTimeout(entry.idleTimer);\n for (const pending of entry.pending.values()) {\n clearTimeout(pending.timer);\n pending.reject(reason ?? new Error(`Plugin \"${docName}\" was unloaded`));\n }\n entry.pending.clear();\n entry.frame.dispose();\n }\n\n isLoaded(docName: string): boolean {\n return this.entries.get(docName)?.loaded != null;\n }\n}\n\nexport const pluginHost = new PluginHost();\n","import { persist, devtools, createJSONStorage } from 'zustand/middleware';\nimport { createStore } from 'zustand/vanilla';\nimport type { TextFile } from '../lib/types';\nimport { idbStorage } from '../lib/idb-storage';\n\nconst MAX_OPEN_TABS = 3;\n\n/**\n * What a file in the workspace is: a document, a theme, or a plugin — the\n * TypeScript source of a custom component compiled and run in the browser.\n */\nexport type DocumentType =\n | 'application/json+report'\n | 'application/json+theme'\n | 'application/typescript+plugin';\n\n/** File-name suffix that marks a plugin source, the same one disk discovery uses. */\nexport const PLUGIN_FILE_SUFFIX = '.component.ts';\n\nexport function isPluginDocumentName(name: string): boolean {\n return name.toLowerCase().endsWith(PLUGIN_FILE_SUFFIX);\n}\n\n/**\n * The file name a plugin will actually be stored under. The type is decided\n * by the name, so a plugin keeps its suffix however it is typed — which is\n * why duplicate checks have to run on this, not on what the author entered:\n * `foo` and `foo.component.ts` are the same file.\n */\nexport function pluginDocumentName(name: string): string {\n const trimmed = name.trim();\n if (isPluginDocumentName(trimmed)) return trimmed;\n return trimmed.replace(/\\.(component)?\\.?ts$/i, '') + PLUGIN_FILE_SUFFIX;\n}\n\nexport type DocumentsState = {\n documents: TextFile[];\n openTabs: string[];\n activeTab: string;\n buildErrors: { [key: string]: string };\n documentTypes: { [key: string]: DocumentType };\n pendingDiffs: {\n [key: string]: { original: string; modified: string; applyId?: string };\n };\n acceptedApplyIds: string[];\n};\n\nexport type DocumentsActions = {\n createDocument: (\n name: string,\n text: string,\n opts?: { templateSource?: string }\n ) => void;\n deleteDocument: (name: string) => void;\n saveDocument: (name: string, text: string) => void;\n renameDocument: (oldName: string, newName: string) => void;\n openDocument: (name: string) => void;\n closeDocument: (name: string) => void;\n setActiveTab: (name: string) => void;\n setBuildError: (name: string, buildError?: string) => void;\n setPendingDiff: (\n name: string,\n original: string,\n modified: string,\n applyId?: string\n ) => void;\n clearPendingDiff: (name: string, accepted?: boolean) => void;\n};\n\nexport type DocumentsStore = DocumentsState & DocumentsActions;\n\n/**\n * The `options.sourceName` to send with generate/preview requests: the\n * document's template provenance when it has one, else its display name.\n * The server only matches sourceName against its own discovered documents,\n * so provenance keeps a renamed copy of a bundled template resolving its\n * relative media/fonts, while the display-name fallback preserves behaviour\n * for documents created before templateSource existed.\n */\nexport function resolveSourceName(\n documents: TextFile[],\n docName: string\n): string {\n return (\n documents.find((doc) => doc.name === docName)?.templateSource ?? docName\n );\n}\n\nexport const initDocumentsStore = (): DocumentsState => {\n return {\n documents: [],\n openTabs: [],\n activeTab: '',\n buildErrors: {},\n documentTypes: {},\n pendingDiffs: {},\n acceptedApplyIds: [],\n };\n};\n\nexport const defaultInitDocumentsState: DocumentsState = {\n ...initDocumentsStore(),\n};\n\nexport const createDocumentsStore = (\n initState: DocumentsState = defaultInitDocumentsState\n) => {\n return createStore<DocumentsStore>()(\n devtools(\n persist(\n (set) => ({\n ...initState,\n createDocument: (name, text, opts) =>\n set((state) => {\n const docIndex = state.documents.findIndex(\n (doc) => doc.name === name\n );\n if (docIndex === -1) {\n // if the document does not exist\n // Determine document type based on file name and content\n let docType: DocumentType = 'application/json+report';\n if (isPluginDocumentName(name)) {\n docType = 'application/typescript+plugin';\n } else if (\n name.toLowerCase().includes('theme') ||\n name.toLowerCase().includes('.theme.')\n ) {\n docType = 'application/json+theme';\n } else {\n // Try to parse JSON to check if it's a theme\n try {\n const parsed = JSON.parse(text);\n if (parsed.colors && parsed.fonts && parsed.styles) {\n docType = 'application/json+theme';\n }\n } catch {\n // If not valid JSON, default to report\n }\n }\n\n const newDoc = {\n name,\n type:\n docType === 'application/typescript+plugin'\n ? 'text/typescript'\n : 'application/json',\n text,\n mtime: new Date(),\n ctime: new Date(),\n atime: new Date(),\n // Survives renames: renameDocument spreads the record.\n ...(opts?.templateSource\n ? { templateSource: opts.templateSource }\n : {}),\n };\n return {\n documents: [...state.documents, newDoc],\n documentTypes: { ...state.documentTypes, [name]: docType },\n };\n }\n return state;\n }),\n deleteDocument: (name) =>\n set((state) => {\n const newDocumentTypes = { ...state.documentTypes };\n delete newDocumentTypes[name];\n return {\n documents: state.documents.filter((doc) => doc.name !== name),\n documentTypes: newDocumentTypes,\n pendingDiffs: Object.fromEntries(\n Object.entries(state.pendingDiffs).filter(([k]) => k !== name)\n ),\n };\n }),\n saveDocument: (name, text) =>\n set((state) => {\n const docIndex = state.documents.findIndex(\n (doc) => doc.name === name\n );\n if (docIndex === -1) return state;\n // Skip update if text is unchanged to avoid spurious re-renders\n if (state.documents[docIndex].text === text) return state;\n const documents = state.documents.map((doc, i) =>\n i === docIndex ? { ...doc, text, mtime: new Date() } : doc\n );\n return { documents };\n }),\n renameDocument: (oldName, newName) =>\n set((state) => {\n const docIndex = state.documents.findIndex(\n (doc) => doc.name === oldName\n );\n if (docIndex === -1) return state;\n const documents = state.documents.map((doc, i) =>\n i === docIndex\n ? { ...doc, name: newName, ctime: new Date() }\n : doc\n );\n const docType = state.documentTypes[oldName];\n if (docType) {\n const newDocumentTypes = { ...state.documentTypes };\n delete newDocumentTypes[oldName];\n newDocumentTypes[newName] = docType;\n return { documents, documentTypes: newDocumentTypes };\n }\n return { documents };\n }),\n openDocument: (name) =>\n set((state) => {\n const docIndex = state.documents.findIndex(\n (doc) => doc.name === name\n );\n if (docIndex === -1) return state;\n const documents = state.documents.map((doc, i) =>\n i === docIndex ? { ...doc, atime: new Date() } : doc\n );\n let openTabs = state.openTabs;\n if (!openTabs.includes(name)) {\n openTabs =\n openTabs.length >= MAX_OPEN_TABS\n ? [...openTabs.slice(1), name]\n : [...openTabs, name];\n }\n return { documents, openTabs, activeTab: name };\n }),\n closeDocument: (name) =>\n set((state) => {\n const index = state.openTabs.indexOf(name);\n if (index === -1) return state;\n const openTabs = state.openTabs.filter((tab) => tab !== name);\n let activeTab = state.activeTab;\n if (activeTab === name) {\n if (openTabs.length) {\n activeTab = index === 0 ? openTabs[0] : openTabs[index - 1];\n } else {\n activeTab = '';\n }\n }\n return { openTabs, activeTab };\n }),\n setActiveTab: (name) => set({ activeTab: name }),\n setBuildError: (name, buildError) =>\n set((state) => {\n if (state.buildErrors[name] === buildError) return state;\n const buildErrors = { ...state.buildErrors };\n if (buildError) buildErrors[name] = buildError;\n else delete buildErrors[name];\n return { buildErrors };\n }),\n setPendingDiff: (name, original, modified, applyId) =>\n set((state) => {\n return {\n pendingDiffs: {\n ...state.pendingDiffs,\n [name]: { original, modified, applyId },\n },\n };\n }),\n clearPendingDiff: (name, accepted) =>\n set((state) => {\n const diff = state.pendingDiffs[name];\n if (!diff) return state;\n const next = { ...state.pendingDiffs };\n delete next[name];\n const ids = state.acceptedApplyIds || [];\n const acceptedApplyIds =\n accepted && diff.applyId\n ? [...ids.slice(-(200 - 1)), diff.applyId]\n : ids;\n return { pendingDiffs: next, acceptedApplyIds };\n }),\n }),\n {\n name: 'documents-storage',\n version: 1,\n storage: createJSONStorage(() => idbStorage),\n partialize: (state) => ({\n documents: state.documents,\n openTabs: state.openTabs,\n activeTab: state.activeTab,\n documentTypes: state.documentTypes,\n // buildErrors + pendingDiffs + acceptedApplyIds excluded — transient UI state\n }),\n onRehydrateStorage: () => (state) => {\n if (state?.documents) {\n for (const doc of state.documents) {\n for (const key of ['mtime', 'ctime', 'atime'] as const) {\n if (doc[key] && typeof doc[key] === 'string') {\n (doc as Record<string, unknown>)[key] = new Date(\n doc[key] as unknown as string\n );\n }\n }\n }\n }\n },\n }\n )\n )\n );\n};\n","import {\n type ReactNode,\n createContext,\n useCallback,\n useRef,\n useContext,\n} from 'react';\nimport { useStore } from 'zustand';\nimport {\n type DocumentsStore,\n createDocumentsStore,\n initDocumentsStore,\n resolveSourceName,\n} from './documents-store';\n\nexport type DocumentsStoreApi = ReturnType<typeof createDocumentsStore>;\n\nexport const DocumentsStoreContext = createContext<\n DocumentsStoreApi | undefined\n>(undefined);\n\nexport interface DocumentsStoreProviderProps {\n children: ReactNode;\n}\n\nexport const DocumentsStoreProvider = ({\n children,\n}: DocumentsStoreProviderProps) => {\n const storeRef = useRef<DocumentsStoreApi | null>(null);\n if (!storeRef.current) {\n storeRef.current = createDocumentsStore(initDocumentsStore());\n }\n\n return (\n <DocumentsStoreContext.Provider value={storeRef.current}>\n {children}\n </DocumentsStoreContext.Provider>\n );\n};\n\nexport const useDocumentsStore = <T,>(\n selector: (store: DocumentsStore) => T\n): T => {\n const documentsStoreContext = useContext(DocumentsStoreContext);\n\n if (!documentsStoreContext) {\n throw new Error(\n 'useDocumentsStore must be used within DocumentsStoreProvider'\n );\n }\n\n return useStore(documentsStoreContext, selector);\n};\n\n/**\n * Stable `docName -> options.sourceName` resolver for generate/preview\n * requests. Reads the store imperatively at call time — no subscription, so\n * callbacks holding it don't re-create on every document edit.\n */\nexport const useResolveSourceName = (): ((docName: string) => string) => {\n const documentsStoreContext = useContext(DocumentsStoreContext);\n\n if (!documentsStoreContext) {\n throw new Error(\n 'useResolveSourceName must be used within DocumentsStoreProvider'\n );\n }\n\n return useCallback(\n (docName: string) =>\n resolveSourceName(documentsStoreContext.getState().documents, docName),\n [documentsStoreContext]\n );\n};\n","import { devtools } from 'zustand/middleware';\nimport { createStore } from 'zustand/vanilla';\nimport type { QualityFinding } from '../lib/quality-findings';\n\nexport interface GenerationWarning {\n component: string;\n message: string;\n severity?: 'warning' | 'info';\n context?: Record<string, unknown>;\n}\n\n/**\n * The last quality analysis, whichever round trip produced it.\n *\n * `/generate` and `/validate` report the same findings in different shapes, so\n * both are normalised into this one slice — the panel should not have to know\n * which endpoint the author's last action happened to hit.\n */\nexport interface QualityState {\n findings: QualityFinding[];\n counts: { error: number; warning: number; info: number };\n /**\n * The document these findings were computed against.\n *\n * Every finding is a JSON Pointer plus, sometimes, an RFC 6902 patch. Both\n * are meaningless against a different file, and a tab switch leaves the panel\n * showing the previous document's findings until a new analysis lands — so\n * \"Apply fix\" and \"Reveal\" must both refuse to act when this no longer names\n * the active tab.\n */\n documentName: string;\n /** Ordering ticket; see lib/quality-sequence.ts. */\n seq: number;\n profileId?: string;\n blocked?: boolean;\n truncated?: boolean;\n /** Which round trip produced this: a full build, or a validate-only pass. */\n source: 'generate' | 'validate';\n analyzedAt: number;\n /**\n * Set only when the run policy's gate actually rejected the build. The panel\n * paints a destructive \"blocked\" state from this, so a transport failure must\n * never land here — it would assert a rejection that never happened, and with\n * the default gate of `none` no gate was even evaluated.\n */\n gateError?: string;\n /** The analysis could not be run (offline, rate limited, server error). */\n analysisError?: string;\n}\n\nexport type OutputState = {\n name?: string; // last success => document name\n text?: string; // last success => code used to generate the document\n blob?: Blob; // last success => generated document\n renderer?: string; // last success => backend captured with the generated bytes\n globalError?: string; // last failed => global error message\n isGenerating?: boolean; // document generation in progress\n generationProgress?: {\n stage: 'parsing' | 'building' | 'rendering' | 'finalizing';\n message?: string;\n };\n generationStartedAt?: number; // Date.now() when the current build started\n cancelGeneration?: () => void; // registered by the editor; aborts the in-flight build\n cacheStatus?: 'HIT' | 'MISS' | 'UNKNOWN'; // cache hit/miss status\n cacheHitRate?: string; // cache hit rate percentage\n warnings?: GenerationWarning[] | null; // warnings from custom component processing\n quality?: QualityState | null; // last quality analysis; null until one runs\n isRendering?: boolean; // preview rendering in progress (iframe/LibreOffice)\n isPreviewStale?: boolean; // preview outdated (new blob generated but not yet rendered)\n editSequence?: number; // incremented on every Monaco keystroke (init 0)\n lastBuiltSequence?: number; // stamped when generation completes (init 0)\n editTimestamp?: number; // Date.now() of the last edit (for debounce countdown)\n hasValidationErrors?: boolean; // true when Monaco reports schema validation errors\n // ⚠️ name doesn't necessarily correspond to the global error message\n};\n\nexport type OutputActions = {\n setOutput: (partialState: OutputState) => void;\n bumpEditSequence: () => void;\n};\n\nexport type OutputStore = OutputState & OutputActions;\n\nexport const initOutputStore = (): OutputState => {\n return {\n name: undefined,\n text: undefined,\n blob: undefined,\n globalError: undefined,\n isGenerating: false,\n generationProgress: undefined,\n isRendering: false,\n isPreviewStale: false,\n editSequence: 0,\n lastBuiltSequence: 0,\n hasValidationErrors: false,\n quality: null,\n };\n};\n\nexport const defaultInitOutputState: OutputState = {\n ...initOutputStore(),\n};\n\nexport const createOutputStore = (\n initState: OutputState = defaultInitOutputState\n) => {\n return createStore<OutputStore>()(\n devtools((set) => ({\n ...initState,\n setOutput: (partialState) => set({ ...partialState }),\n bumpEditSequence: () =>\n set((s) => ({\n editSequence: (s.editSequence ?? 0) + 1,\n editTimestamp: Date.now(),\n })),\n }))\n );\n};\n","import { type ReactNode, createContext, useRef, useContext } from 'react';\nimport { useStore } from 'zustand';\nimport {\n type OutputStore,\n createOutputStore,\n initOutputStore,\n} from './output-store';\n\nexport type OutputStoreApi = ReturnType<typeof createOutputStore>;\n\nexport const OutputStoreContext = createContext<OutputStoreApi | undefined>(\n undefined\n);\n\nexport interface OutputStoreProviderProps {\n children: ReactNode;\n}\n\nexport const OutputStoreProvider = ({ children }: OutputStoreProviderProps) => {\n const storeRef = useRef<OutputStoreApi | null>(null);\n if (!storeRef.current) {\n storeRef.current = createOutputStore(initOutputStore());\n }\n\n return (\n <OutputStoreContext.Provider value={storeRef.current}>\n {children}\n </OutputStoreContext.Provider>\n );\n};\n\nexport const useOutputStore = <T,>(selector: (store: OutputStore) => T): T => {\n const outputStoreContext = useContext(OutputStoreContext);\n\n if (!outputStoreContext) {\n throw new Error('useOutputStore must be used within OutputStoreProvider');\n }\n\n return useStore(outputStoreContext, selector);\n};\n","import { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\nimport type { PluginMetadata } from '../hooks/useDiscovery';\n\ninterface PluginsState {\n // Selected plugin names (used for schema generation)\n selectedPlugins: Set<string>;\n\n // Full plugin metadata for selected plugins\n selectedPluginMetadata: Map<string, PluginMetadata>;\n\n // Schema application state\n isApplyingPlugins: boolean;\n lastApplyError: string | null;\n\n // Actions\n selectPlugin: (plugin: PluginMetadata) => void;\n deselectPlugin: (pluginName: string) => void;\n togglePlugin: (plugin: PluginMetadata) => void;\n clearSelections: () => void;\n isPluginSelected: (pluginName: string) => boolean;\n getSelectedPluginsList: () => PluginMetadata[];\n getSelectedPluginNames: () => string[];\n applyPluginsWithValidation: (\n onSuccess?: () => void,\n onError?: (error: string) => void\n ) => Promise<boolean>;\n}\n\nexport const usePluginsStore = create<PluginsState>()(\n persist(\n (set, get) => ({\n selectedPlugins: new Set<string>(),\n selectedPluginMetadata: new Map<string, PluginMetadata>(),\n isApplyingPlugins: false,\n lastApplyError: null,\n\n selectPlugin: (plugin: PluginMetadata) => {\n set((state) => {\n const newSelectedPlugins = new Set(state.selectedPlugins);\n const newMetadata = new Map(state.selectedPluginMetadata);\n\n newSelectedPlugins.add(plugin.name);\n newMetadata.set(plugin.name, plugin);\n\n return {\n selectedPlugins: newSelectedPlugins,\n selectedPluginMetadata: newMetadata,\n };\n });\n },\n\n deselectPlugin: (pluginName: string) => {\n set((state) => {\n const newSelectedPlugins = new Set(state.selectedPlugins);\n const newMetadata = new Map(state.selectedPluginMetadata);\n\n newSelectedPlugins.delete(pluginName);\n newMetadata.delete(pluginName);\n\n return {\n selectedPlugins: newSelectedPlugins,\n selectedPluginMetadata: newMetadata,\n };\n });\n },\n\n togglePlugin: (plugin: PluginMetadata) => {\n const isSelected = get().isPluginSelected(plugin.name);\n if (isSelected) {\n get().deselectPlugin(plugin.name);\n } else {\n get().selectPlugin(plugin);\n }\n // Auto-apply schema changes\n get().applyPluginsWithValidation().catch(console.error);\n },\n\n clearSelections: () => {\n set({\n selectedPlugins: new Set<string>(),\n selectedPluginMetadata: new Map<string, PluginMetadata>(),\n });\n // Auto-apply schema changes\n get().applyPluginsWithValidation().catch(console.error);\n },\n\n isPluginSelected: (pluginName: string) => {\n return get().selectedPlugins.has(pluginName);\n },\n\n getSelectedPluginsList: () => {\n return Array.from(get().selectedPluginMetadata.values());\n },\n\n getSelectedPluginNames: () => {\n return Array.from(get().selectedPlugins);\n },\n\n applyPluginsWithValidation: async (onSuccess, onError) => {\n set({ isApplyingPlugins: true, lastApplyError: null });\n\n try {\n // Get the current selected plugins\n const selectedPluginNames = Array.from(get().selectedPlugins);\n\n // Import Monaco and schema update function dynamically\n const { loader } = await import('@monaco-editor/react');\n const { updateMonacoWithPlugins } = await import(\n '../lib/monaco-config'\n );\n\n // Get Monaco instance\n const monaco = await loader.init();\n\n // Apply the plugins and wait for validation. Browser plugins ride\n // along from their own store, so toggling a disk plugin never\n // drops them from the schema.\n const { browserComponentsForSchema, useBrowserPluginsStore } =\n await import('./browser-plugins-store');\n const success = await updateMonacoWithPlugins(\n monaco,\n selectedPluginNames,\n undefined,\n browserComponentsForSchema(useBrowserPluginsStore.getState())\n );\n\n if (!success) {\n throw new Error('Schema validation failed');\n }\n\n // Success - schema has been applied and validated\n set({ isApplyingPlugins: false, lastApplyError: null });\n\n if (onSuccess) {\n onSuccess();\n }\n\n return true;\n } catch (error) {\n const errorMessage =\n error instanceof Error\n ? error.message\n : 'Failed to apply plugin schemas';\n\n set({\n isApplyingPlugins: false,\n lastApplyError: errorMessage,\n });\n\n if (onError) {\n onError(errorMessage);\n }\n\n console.error('Failed to apply plugins with validation:', error);\n return false;\n }\n },\n }),\n {\n name: 'jtp-selected-plugins',\n // Custom storage to handle Set and Map serialization\n storage: {\n getItem: (name) => {\n const str = localStorage.getItem(name);\n if (!str) return null;\n\n const { state } = JSON.parse(str);\n return {\n state: {\n ...state,\n selectedPlugins: new Set(state.selectedPlugins || []),\n selectedPluginMetadata: new Map(\n state.selectedPluginMetadata || []\n ),\n },\n };\n },\n setItem: (name, value) => {\n const { state } = value as { state: PluginsState };\n const serialized = JSON.stringify({\n state: {\n ...state,\n selectedPlugins: Array.from(state.selectedPlugins),\n selectedPluginMetadata: Array.from(\n state.selectedPluginMetadata.entries()\n ),\n },\n });\n localStorage.setItem(name, serialized);\n },\n removeItem: (name) => localStorage.removeItem(name),\n },\n }\n )\n);\n","/**\n * Type declarations for the import paths a plugin file uses for the plugin\n * API, mirroring what the published packages export.\n *\n * The runtime behind every one of these is the shared `createComponent` /\n * `createVersion` (see sandbox.worker.ts); what differs per format is the\n * component and theme types `render` sees. Declaring only the plugin API here\n * also makes the shim the allowlist: a plugin that reaches for\n * `generateBufferFromJson` gets a type error in the editor, which is the same\n * answer the sandbox would give at run time.\n */\n\nfunction pluginApiDeclaration(\n sharedPackage: string,\n componentType: string,\n themeType: string\n): string {\n return `import type { TSchema } from '@sinclair/typebox';\nimport type { ${componentType}, ${themeType} } from '${sharedPackage}';\nimport type {\n RenderContext as SharedRenderContext,\n RenderFunction as SharedRenderFunction,\n ComponentVersion as SharedComponentVersion,\n ComponentVersionMap as SharedComponentVersionMap,\n CustomComponent as SharedCustomComponent,\n} from '@json-to-office/shared/plugin';\n\n/** The resolved theme handed to \\`render\\`. */\nexport type ThemeConfig = ${themeType};\n\nexport type RenderContext<T> = SharedRenderContext<T, ${themeType}>;\n\nexport type RenderFunction<\n TProps,\n TComponentDefinition = ${componentType},\n> = SharedRenderFunction<TProps, TComponentDefinition, ${themeType}>;\n\nexport type ComponentVersion<\n TComponentDefinition = ${componentType},\n TPropsSchema extends TSchema = TSchema,\n> = SharedComponentVersion<TComponentDefinition, TPropsSchema, ${themeType}>;\n\nexport type ComponentVersionMap<TComponentDefinition = ${componentType}> =\n SharedComponentVersionMap<TComponentDefinition, ${themeType}>;\n\nexport type CustomComponent<\n TComponentDefinition = ${componentType},\n TVersions extends\n ComponentVersionMap<TComponentDefinition> = ComponentVersionMap<TComponentDefinition>,\n TName extends string = string,\n> = SharedCustomComponent<TComponentDefinition, TVersions, TName>;\n\n/** Create one semver version entry with full type inference for its props. */\nexport declare function createVersion<\n TPropsSchema extends TSchema,\n TComponentDefinition = ${componentType},\n>(\n version: ComponentVersion<TComponentDefinition, TPropsSchema>\n): ComponentVersion<TComponentDefinition, TPropsSchema>;\n\n/** Create a custom component with semver-keyed versions. */\nexport declare function createComponent<\n TComponentDefinition = ${componentType},\n TVersions extends\n ComponentVersionMap<TComponentDefinition> = ComponentVersionMap<TComponentDefinition>,\n TName extends string = string,\n>(\n component: CustomComponent<TComponentDefinition, TVersions, TName>\n): CustomComponent<TComponentDefinition, TVersions, TName>;\n\nexport {\n resolveComponentVersion,\n ComponentValidationError,\n DuplicateComponentError,\n} from '@json-to-office/shared/plugin';\nexport type { ${componentType}, ${themeType} } from '${sharedPackage}';\n`;\n}\n\nconst DOCX_API = pluginApiDeclaration(\n '@json-to-office/shared-docx',\n 'ComponentDefinition',\n 'ThemeConfigJson'\n);\nconst PPTX_API = pluginApiDeclaration(\n '@json-to-office/shared-pptx',\n 'PptxComponentDefinition',\n 'ThemeConfigJson'\n);\n\nfunction manifest(name: string, withPluginSubpath: boolean): string {\n return JSON.stringify(\n {\n name,\n version: '0.0.0-playground',\n types: 'index.d.ts',\n exports: {\n '.': { types: './index.d.ts' },\n ...(withPluginSubpath\n ? { './plugin': { types: './plugin/index.d.ts' } }\n : {}),\n },\n },\n null,\n 2\n );\n}\n\n/**\n * Virtual files keyed like the generated type libs\n * (`node_modules/<pkg>/<file>`).\n */\nexport const PLUGIN_TYPE_SHIMS: Readonly<Record<string, string>> = {\n 'node_modules/@json-to-office/core-docx/package.json': manifest(\n '@json-to-office/core-docx',\n true\n ),\n 'node_modules/@json-to-office/core-docx/index.d.ts': DOCX_API,\n 'node_modules/@json-to-office/core-docx/plugin/index.d.ts': DOCX_API,\n 'node_modules/@json-to-office/json-to-docx/package.json': manifest(\n '@json-to-office/json-to-docx',\n false\n ),\n 'node_modules/@json-to-office/json-to-docx/index.d.ts': DOCX_API,\n 'node_modules/@json-to-office/core-pptx/package.json': manifest(\n '@json-to-office/core-pptx',\n true\n ),\n 'node_modules/@json-to-office/core-pptx/index.d.ts': PPTX_API,\n 'node_modules/@json-to-office/core-pptx/plugin/index.d.ts': PPTX_API,\n 'node_modules/@json-to-office/json-to-pptx/package.json': manifest(\n '@json-to-office/json-to-pptx',\n false\n ),\n 'node_modules/@json-to-office/json-to-pptx/index.d.ts': PPTX_API,\n};\n\n/**\n * Module ids the sandbox resolves to the shared plugin API. Kept next to the\n * declarations above so the editor and the runtime agree on what exists.\n */\nexport const PLUGIN_API_MODULE_IDS: readonly string[] = [\n '@json-to-office/core-docx',\n '@json-to-office/core-docx/plugin',\n '@json-to-office/json-to-docx',\n '@json-to-office/core-pptx',\n '@json-to-office/core-pptx/plugin',\n '@json-to-office/json-to-pptx',\n];\n","import type { Monaco } from '@monaco-editor/react';\nimport { PLUGIN_TYPE_SHIMS } from './type-shims';\n\n/**\n * Configure Monaco's TypeScript service for plugin sources, once.\n *\n * Plugins are emitted as CommonJS so the sandbox can hand them a `require`\n * that resolves only the allowlisted modules. Module resolution is TypeScript's\n * `Bundler` mode (value 100 — Monaco's enum predates it) so the `exports` maps\n * in the virtual package.json files route `@json-to-office/shared/plugin` and\n * friends to their `.d.ts`. The declaration files themselves come from the\n * `virtual:jto-plugin-type-libs` module built by vite.config.ts and are\n * imported lazily: they are large and only a plugin editor needs them.\n */\nlet configured: Promise<void> | null = null;\n\nexport function ensurePluginTypeScript(monaco: Monaco): Promise<void> {\n if (!configured) {\n configured = configure(monaco)\n .then(markReady)\n .catch((error) => {\n configured = null;\n throw error;\n });\n }\n return configured;\n}\n\nasync function configure(monaco: Monaco): Promise<void> {\n const ts = monaco.languages.typescript;\n ts.typescriptDefaults.setCompilerOptions({\n target: ts.ScriptTarget.ES2020,\n module: ts.ModuleKind.CommonJS,\n // ModuleResolutionKind.Bundler; see the module comment.\n moduleResolution: 100 as unknown as typeof ts.ModuleResolutionKind.NodeJs,\n lib: ['es2020', 'dom'],\n strict: true,\n esModuleInterop: true,\n allowSyntheticDefaultImports: true,\n allowNonTsExtensions: true,\n skipLibCheck: true,\n noEmitOnError: false,\n resolveJsonModule: false,\n typeRoots: [],\n types: [],\n });\n // Until the declarations are in, every import is \"Cannot find module\":\n // semantic checking stays off so an editor that opened first does not\n // flash red for the second the download takes.\n ts.typescriptDefaults.setDiagnosticsOptions({\n noSemanticValidation: true,\n noSyntaxValidation: false,\n noSuggestionDiagnostics: true,\n });\n ts.typescriptDefaults.setEagerModelSync(true);\n\n const libs = (await import('virtual:jto-plugin-type-libs')).default;\n const files: Record<string, string> = { ...libs, ...PLUGIN_TYPE_SHIMS };\n for (const [path, content] of Object.entries(files)) {\n ts.typescriptDefaults.addExtraLib(content, `file:///${path}`);\n }\n ts.typescriptDefaults.setDiagnosticsOptions({\n noSemanticValidation: false,\n noSyntaxValidation: false,\n noSuggestionDiagnostics: true,\n });\n}\n\n/** True once the declarations are registered; the editor strip reads it. */\nexport function pluginTypeScriptReady(): boolean {\n return ready;\n}\n\nlet ready = false;\nconst readyListeners = new Set<() => void>();\n\n/** Notified once when the declarations finish loading. */\nexport function onPluginTypeScriptReady(listener: () => void): () => void {\n if (ready) {\n listener();\n return () => {};\n }\n readyListeners.add(listener);\n return () => {\n readyListeners.delete(listener);\n };\n}\n\nfunction markReady(): void {\n ready = true;\n for (const listener of readyListeners) listener();\n readyListeners.clear();\n}\n","import { loader } from '@monaco-editor/react';\nimport type { Monaco } from '@monaco-editor/react';\nimport type { editor as MonacoEditorType } from 'monaco-editor';\nimport { ensurePluginTypeScript } from './type-libs';\nimport { hashSource } from './hash';\nimport type { PluginDiagnostic } from './types';\n\n/**\n * Compile a plugin source with Monaco's TypeScript worker.\n *\n * Headless: the compiler owns one text model per plugin file, at the same\n * URI the editor tab opens, so the two share it — a compile started by the\n * sync hook and the diagnostics the editor shows come from one program.\n * When the model is on screen its live text wins over the store snapshot,\n * which trails the editor by the save debounce.\n */\n\nexport interface CompileResult {\n /** The text that was compiled (the live model text, which may be newer than the store). */\n source: string;\n /** Emitted CommonJS, or null when the source has errors. */\n js: string | null;\n diagnostics: PluginDiagnostic[];\n /** True when the live text matched `skipIfHash` and nothing was compiled. */\n skipped: boolean;\n}\n\nconst MODEL_SCHEME_PATH = 'file:///plugins/';\n\n/** The model URI for a plugin file; the editor tab must use the same path. */\nexport function pluginModelPath(docName: string): string {\n return `${MODEL_SCHEME_PATH}${encodeURIComponent(docName)}`;\n}\n\nfunction isAttachedToEditor(\n monaco: Monaco,\n model: MonacoEditorType.ITextModel\n): boolean {\n return monaco.editor.getEditors().some((e) => e.getModel() === model);\n}\n\ninterface WorkerDiagnostic {\n start?: number;\n length?: number;\n messageText: string | { messageText: string; next?: unknown[] };\n category: number;\n code: number;\n}\n\nfunction flattenMessage(text: WorkerDiagnostic['messageText']): string {\n if (typeof text === 'string') return text;\n const parts: string[] = [text.messageText];\n const queue = Array.isArray(text.next) ? [...text.next] : [];\n while (queue.length > 0) {\n const next = queue.shift() as WorkerDiagnostic['messageText'] | undefined;\n if (!next) continue;\n if (typeof next === 'string') parts.push(next);\n else {\n parts.push(next.messageText);\n if (Array.isArray(next.next)) queue.push(...next.next);\n }\n }\n return parts.join(' ');\n}\n\nfunction toDiagnostic(\n diagnostic: WorkerDiagnostic,\n model: MonacoEditorType.ITextModel\n): PluginDiagnostic {\n // TypeScript's DiagnosticCategory: Warning = 0, Error = 1, Suggestion = 2, Message = 3.\n const severity: PluginDiagnostic['severity'] =\n diagnostic.category === 1\n ? 'error'\n : diagnostic.category === 0\n ? 'warning'\n : 'info';\n const result: PluginDiagnostic = {\n severity,\n message: `${flattenMessage(diagnostic.messageText)} (TS${diagnostic.code})`,\n source: 'typescript',\n };\n if (typeof diagnostic.start === 'number') {\n const start = model.getPositionAt(diagnostic.start);\n const end = model.getPositionAt(\n diagnostic.start + (diagnostic.length ?? 0)\n );\n result.line = start.lineNumber;\n result.column = start.column;\n result.endLine = end.lineNumber;\n result.endColumn = end.column;\n }\n return result;\n}\n\nexport async function compilePlugin(\n docName: string,\n source: string,\n skipIfHash?: string\n): Promise<CompileResult> {\n const monaco = await loader.init();\n await ensurePluginTypeScript(monaco);\n\n const uri = monaco.Uri.parse(pluginModelPath(docName));\n let model = monaco.editor.getModel(uri);\n if (!model) {\n model = monaco.editor.createModel(source, 'typescript', uri);\n } else if (\n model.getValue() !== source &&\n !isAttachedToEditor(monaco, model)\n ) {\n model.setValue(source);\n }\n const text = model.getValue();\n\n // The store trails an open editor by its save debounce, so a sync started\n // from the store can find that the live text is the one it already\n // compiled. Say so instead of compiling it a second time.\n if (skipIfHash !== undefined && hashSource(text) === skipIfHash) {\n return { source: text, js: null, diagnostics: [], skipped: true };\n }\n\n const getWorker = await monaco.languages.typescript.getTypeScriptWorker();\n const client = await getWorker(uri);\n const fileName = uri.toString();\n const [syntactic, semantic, emit] = await Promise.all([\n client.getSyntacticDiagnostics(fileName),\n client.getSemanticDiagnostics(fileName),\n client.getEmitOutput(fileName),\n ]);\n\n const diagnostics = [\n ...(syntactic as unknown as WorkerDiagnostic[]),\n ...(semantic as unknown as WorkerDiagnostic[]),\n ]\n .map((d) => toDiagnostic(d, model!))\n .filter((d) => d.severity !== 'info');\n const hasErrors = diagnostics.some((d) => d.severity === 'error');\n const js =\n emit.outputFiles.find((file) => file.name.endsWith('.js'))?.text ?? null;\n\n return {\n source: text,\n js: hasErrors ? null : js,\n diagnostics,\n skipped: false,\n };\n}\n\n/** Drop the headless model once its file is gone, unless an editor still shows it. */\nexport function disposePluginModel(docName: string): void {\n const monaco = loader.__getMonacoInstance();\n if (!monaco) return;\n const model = monaco.editor.getModel(\n monaco.Uri.parse(pluginModelPath(docName))\n );\n if (model && !isAttachedToEditor(monaco, model)) model.dispose();\n}\n","/**\n * The compile schedule for plugin files.\n *\n * The sync hook debounces compiles behind the editor; Run cannot wait for a\n * debounce it does not know about, so the schedule lives here where both\n * can reach it: the hook registers the runner and schedules, Run flushes\n * everything pending and awaits the queue going idle.\n */\n\ntype Runner = (docName: string) => Promise<void>;\n\nconst noopRunner: Runner = async () => {};\n\nexport class CompileQueue {\n private runner: Runner = noopRunner;\n private timers = new Map<string, ReturnType<typeof setTimeout>>();\n private inFlight = new Map<string, Promise<void>>();\n private queued = new Set<string>();\n private idleWaiters: Array<() => void> = [];\n\n setRunner(runner: Runner): void {\n this.runner = runner;\n }\n\n /** Compile after `delayMs`; a newer schedule for the same file replaces an older one. */\n schedule(docName: string, delayMs: number): void {\n this.cancel(docName);\n this.timers.set(\n docName,\n setTimeout(() => {\n this.timers.delete(docName);\n this.run(docName);\n }, delayMs)\n );\n }\n\n /** Drop a pending schedule (not a compile already running). */\n cancel(docName: string): void {\n const timer = this.timers.get(docName);\n if (timer) clearTimeout(timer);\n this.timers.delete(docName);\n }\n\n /** Compile now, or right after the compile already running for this file. */\n run(docName: string): Promise<void> {\n this.cancel(docName);\n const running = this.inFlight.get(docName);\n if (running) {\n this.queued.add(docName);\n return running.then(\n () => this.inFlight.get(docName) ?? Promise.resolve()\n );\n }\n const task = this.runner(docName)\n .catch(() => {})\n .finally(() => {\n this.inFlight.delete(docName);\n if (this.queued.delete(docName)) {\n this.run(docName);\n } else {\n this.settleIfIdle();\n }\n });\n this.inFlight.set(docName, task);\n return task;\n }\n\n /** Every scheduled compile, started now. */\n flush(): void {\n for (const docName of Array.from(this.timers.keys())) this.run(docName);\n }\n\n get isIdle(): boolean {\n return this.timers.size === 0 && this.inFlight.size === 0;\n }\n\n /** Resolves once nothing is scheduled or running, or after `timeoutMs`. */\n whenIdle(timeoutMs = 15_000): Promise<void> {\n if (this.isIdle) return Promise.resolve();\n return new Promise((resolve) => {\n const timer = setTimeout(done, timeoutMs);\n function done() {\n clearTimeout(timer);\n resolve();\n }\n this.idleWaiters.push(done);\n });\n }\n\n /** Forget everything; used when the owning hook unmounts. */\n reset(): void {\n for (const timer of this.timers.values()) clearTimeout(timer);\n this.timers.clear();\n this.queued.clear();\n this.runner = noopRunner;\n this.settleIfIdle();\n }\n\n private settleIfIdle(): void {\n if (!this.isIdle) return;\n const waiters = this.idleWaiters;\n this.idleWaiters = [];\n for (const waiter of waiters) waiter();\n }\n}\n\nexport const compileQueue = new CompileQueue();\n","import type { PluginExample } from './types';\n\n/**\n * Usage examples embedded in a plugin's source.\n *\n * The same two conventions disk discovery reads (`PluginMetadataExtractor`\n * in jto-cli): a JSDoc `@example` carrying a fenced JSON/TypeScript block,\n * optionally captioned, and a `// Example: {...}` line. A block that holds a\n * whole `{ name, props }` component is reduced to its `props`, so the\n * example is always the props object documents put under the component.\n */\nexport function extractPluginExamples(source: string): PluginExample[] {\n const examples: PluginExample[] = [];\n const normalize = (input: unknown): unknown =>\n input && typeof input === 'object' && 'props' in input\n ? (input as { props: unknown }).props\n : input;\n\n const fenced =\n /@example\\s*(?:<caption>(.*?)<\\/caption>)?\\s*\\*?\\s*```(?:json|typescript|ts)?\\s*([\\s\\S]*?)```/gi;\n let match: RegExpExecArray | null;\n while ((match = fenced.exec(source)) !== null) {\n const title = match[1]?.trim() || undefined;\n const block = match[2]\n .split('\\n')\n .map((line) => line.replace(/^\\s*\\*\\s?/, ''))\n .join('\\n')\n .trim();\n const json = block.match(/\\{[\\s\\S]*\\}/);\n if (!json) continue;\n try {\n examples.push({ title, props: normalize(JSON.parse(json[0])) });\n } catch {\n // A TypeScript object literal rather than JSON: quote the keys and\n // swap single quotes, which covers the examples plugins actually carry.\n const propsMatch = block.match(/props:\\s*\\{[\\s\\S]*?\\}/);\n if (!propsMatch) continue;\n try {\n const cleaned = propsMatch[0]\n .replace(/props:\\s*/, '')\n .replace(/(['\"])?([a-zA-Z0-9_]+)(['\"])?:/g, '\"$2\":')\n .replace(/'/g, '\"')\n .replace(/,(\\s*[}\\]])/g, '$1')\n .replace(/,\\s*$/, '');\n examples.push({ title, props: JSON.parse(cleaned) });\n } catch {}\n }\n }\n\n const inline = /\\/\\/\\s*Example:\\s*(\\{.*?\\})/g;\n while ((match = inline.exec(source)) !== null) {\n try {\n examples.push({ props: normalize(JSON.parse(match[1])) });\n } catch {}\n }\n\n return examples;\n}\n","import { STANDARD_COMPONENTS_REGISTRY } from '@json-to-office/shared-docx';\nimport { PPTX_STANDARD_COMPONENTS_REGISTRY } from '@json-to-office/shared-pptx';\nimport type { PluginFormat } from './types';\n\n/**\n * Component names the format already owns. A browser plugin cannot take one\n * of these: the schema would carry two branches for the same `name` and the\n * expander would swallow a standard component.\n */\nexport function standardComponentNames(format: PluginFormat): Set<string> {\n const registry =\n format === 'docx'\n ? STANDARD_COMPONENTS_REGISTRY\n : PPTX_STANDARD_COMPONENTS_REGISTRY;\n return new Set(registry.map((component) => component.name));\n}\n\n/** Names a plugin may use: what disk discovery accepts, roughly a kebab identifier. */\nexport const PLUGIN_NAME_PATTERN = /^[a-zA-Z][a-zA-Z0-9_-]*$/;\n","/**\n * Types shared by the in-browser plugin system: the compiled record the\n * store keeps, the metadata the sandbox reports, and the wire protocol\n * between the page and a plugin's worker.\n */\n\nexport type PluginFormat = 'docx' | 'pptx';\n\n/** One semver-keyed version of a component, as the sandbox describes it. */\nexport interface PluginVersionMetadata {\n version: string;\n /** The TypeBox props schema, JSON-roundtripped (no Kind symbols). */\n propsSchema: Record<string, unknown>;\n hasChildren: boolean;\n description?: string;\n}\n\nexport interface PluginExample {\n title?: string;\n description?: string;\n props: unknown;\n}\n\nexport interface BrowserPluginMetadata {\n /** The component name documents use in `name`. */\n name: string;\n format: PluginFormat;\n versions: PluginVersionMetadata[];\n latest: string;\n examples: PluginExample[];\n}\n\nexport interface PluginDiagnostic {\n severity: 'error' | 'warning' | 'info';\n message: string;\n /** Who produced it: the TypeScript compiler, the sandbox, or the playground itself. */\n source: 'typescript' | 'sandbox' | 'playground';\n /** Machine-readable kind for playground diagnostics the sync re-evaluates. */\n code?: 'name-conflict' | 'timeout' | 'network-off';\n line?: number;\n column?: number;\n endLine?: number;\n endColumn?: number;\n}\n\nexport type BrowserPluginStatus = 'idle' | 'compiling' | 'ready' | 'error';\n\nexport interface BrowserPluginRecord {\n /** The workspace file this plugin was compiled from (`*.component.ts`). */\n docName: string;\n /** Take part in schema generation and expansion. */\n enabled: boolean;\n /** Leave `fetch` and friends available inside the sandbox. */\n allowNetwork: boolean;\n /**\n * The origins the switch grants, as CSP source expressions. On with an\n * empty list reaches nothing: the switch alone is not a grant.\n */\n networkOrigins?: string[];\n status: BrowserPluginStatus;\n /** Hash of the source `js`/`metadata` were produced from. */\n sourceHash: string;\n /** Compiled CommonJS; present once a compile succeeded. */\n js?: string;\n metadata?: BrowserPluginMetadata;\n diagnostics: PluginDiagnostic[];\n /** When the record was first created; the older of two same-named plugins keeps the name. */\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface PluginRenderWarning {\n message: string;\n context?: Record<string, unknown>;\n}\n\n/**\n * Prefix of the error a sandbox throws when a plugin reaches for the network\n * with its switch off; the page turns it into a diagnostic that names the\n * switch instead of a bare ReferenceError.\n */\nexport const NETWORK_OFF_MARKER = '[plugin-network-off]';\n\n// ---- Sandbox protocol ----\n\nexport interface SandboxLoadRequest {\n id: number;\n type: 'load';\n js: string;\n format: PluginFormat;\n /** Whether anything is reachable at all; the frame's CSP names what. */\n allowNetwork: boolean;\n /** Shown in the error when a call is refused, so it names the allowlist. */\n networkOrigins: string[];\n examples: PluginExample[];\n}\n\nexport interface SandboxRenderRequest {\n id: number;\n type: 'render';\n version?: string;\n props: unknown;\n theme: unknown;\n children?: unknown[];\n}\n\nexport type SandboxRequest = SandboxLoadRequest | SandboxRenderRequest;\n\nexport interface SandboxLoadedResponse {\n id: number;\n type: 'loaded';\n metadata: BrowserPluginMetadata;\n}\n\nexport interface SandboxRenderedResponse {\n id: number;\n type: 'rendered';\n components: unknown[];\n warnings: PluginRenderWarning[];\n}\n\nexport interface SandboxErrorResponse {\n id: number;\n type: 'error';\n message: string;\n stack?: string;\n}\n\nexport type SandboxResponse =\n | SandboxLoadedResponse\n | SandboxRenderedResponse\n | SandboxErrorResponse;\n","import { useContext, useEffect, useRef } from 'react';\nimport { DocumentsStoreContext } from '../store/documents-store-provider';\nimport {\n componentNameOwner,\n useBrowserPluginsStore,\n whenBrowserPluginsHydrated,\n} from '../store/browser-plugins-store';\nimport { compilePlugin, disposePluginModel } from '../lib/plugins/compiler';\nimport { compileQueue } from '../lib/plugins/compile-queue';\nimport { extractPluginExamples } from '../lib/plugins/examples';\nimport { hashSource } from '../lib/plugins/hash';\nimport { pluginHost, PluginTimeoutError } from '../lib/plugins/host';\nimport {\n PLUGIN_NAME_PATTERN,\n standardComponentNames,\n} from '../lib/plugins/names';\nimport {\n NETWORK_OFF_MARKER,\n type BrowserPluginRecord,\n type PluginDiagnostic,\n} from '../lib/plugins/types';\nimport { FORMAT } from '../lib/env';\n\n/**\n * Keep every `*.component.ts` file compiled.\n *\n * Watches the documents store: a plugin file whose text no longer matches\n * the hash its record was built from is recompiled after a short debounce,\n * loaded into its sandbox to be described, and checked for a name the format\n * already uses. A file that disappears takes its record, its sandbox and its\n * Monaco model with it. Compilation reads the live editor model when the\n * file is open, so what runs is what is on screen, not the last save.\n *\n * Name conflicts are re-judged without recompiling whenever the set of\n * records changes: the metadata is kept on a conflicting record, so the\n * newcomer becomes ready the moment the owner is renamed or deleted.\n */\n\nconst COMPILE_DEBOUNCE_MS = 400;\n\nconst PLUGIN_TYPE = 'application/typescript+plugin';\n\n/** Fired on `window` after a plugin finished compiling, ready or not. */\nexport const BROWSER_PLUGINS_CHANGED_EVENT = 'browser-plugins:changed';\n\nfunction announceChange(docName: string): void {\n window.dispatchEvent(\n new CustomEvent(BROWSER_PLUGINS_CHANGED_EVENT, { detail: { docName } })\n );\n}\n\nfunction conflictDiagnostic(message: string): PluginDiagnostic {\n return {\n severity: 'error',\n source: 'playground',\n code: 'name-conflict',\n message,\n };\n}\n\n/** A sandbox failure, worded for the author. */\nfunction sandboxDiagnostic(error: unknown): PluginDiagnostic {\n const message = error instanceof Error ? error.message : String(error);\n if (message.includes(NETWORK_OFF_MARKER)) {\n return {\n severity: 'error',\n source: 'playground',\n code: 'network-off',\n message: message.replace(NETWORK_OFF_MARKER, '').trim(),\n };\n }\n if (error instanceof PluginTimeoutError) {\n return {\n severity: 'error',\n source: 'sandbox',\n code: 'timeout',\n message: `${message} Edit the file to compile it again.`,\n };\n }\n return { severity: 'error', source: 'sandbox', message };\n}\n\nexport function useBrowserPluginsSync(\n diskPluginNames: readonly string[]\n): void {\n const documentsStore = useContext(DocumentsStoreContext);\n if (!documentsStore) {\n throw new Error(\n 'useBrowserPluginsSync must be used within DocumentsStoreProvider'\n );\n }\n // Read at compile time rather than captured: discovery finishes after the\n // first compile more often than not.\n const diskNamesRef = useRef<readonly string[]>(diskPluginNames);\n diskNamesRef.current = diskPluginNames;\n\n useEffect(() => {\n let disposed = false;\n\n /** Why `componentName` cannot be `docName`'s, or null when it can. */\n const nameConflict = (\n docName: string,\n componentName: string\n ): string | null => {\n if (!PLUGIN_NAME_PATTERN.test(componentName)) {\n return `Component name \"${componentName}\" must start with a letter and contain only letters, digits, \"-\" and \"_\".`;\n }\n if (standardComponentNames(FORMAT).has(componentName)) {\n return `\"${componentName}\" is a built-in ${FORMAT} component; choose another name.`;\n }\n if (diskNamesRef.current.includes(componentName)) {\n return `\"${componentName}\" is already provided by a plugin on disk; choose another name or disable that plugin.`;\n }\n const owner = componentNameOwner(\n useBrowserPluginsStore.getState().records,\n componentName\n );\n if (owner && owner !== docName) {\n return `\"${componentName}\" is already defined by ${owner}; rename one of them.`;\n }\n return null;\n };\n\n /**\n * Re-judge every settled record's name without compiling. Only the\n * conflict diagnostic moves; TypeScript and sandbox diagnostics stay.\n */\n const reconcileConflicts = (): void => {\n const store = useBrowserPluginsStore.getState();\n for (const record of Object.values(store.records)) {\n if (\n !record.metadata ||\n record.status === 'compiling' ||\n record.status === 'idle'\n ) {\n continue;\n }\n const others = record.diagnostics.filter(\n (d) => d.code !== 'name-conflict'\n );\n const hadConflict = others.length !== record.diagnostics.length;\n const conflict = nameConflict(record.docName, record.metadata.name);\n const otherErrors = others.some((d) => d.severity === 'error');\n if (conflict && !hadConflict) {\n store.upsert(record.docName, {\n status: 'error',\n diagnostics: [...others, conflictDiagnostic(conflict)],\n });\n } else if (!conflict && hadConflict) {\n store.upsert(record.docName, {\n status: otherErrors || !record.js ? 'error' : 'ready',\n diagnostics: others,\n });\n announceChange(record.docName);\n }\n }\n };\n\n const compileNow = async (docName: string): Promise<void> => {\n const doc = documentsStore\n .getState()\n .documents.find((d) => d.name === docName);\n if (!doc || disposed) return;\n const store = useBrowserPluginsStore.getState();\n const record = store.records[docName];\n const hash = hashSource(doc.text);\n const current =\n record &&\n record.sourceHash === hash &&\n (record.status === 'ready' || record.status === 'error');\n if (current) return;\n\n // A settled record may already describe the live editor text, which the\n // store has not caught up with yet; the compiler checks before working.\n const settled: BrowserPluginRecord | undefined =\n record && (record.status === 'ready' || record.status === 'error')\n ? record\n : undefined;\n store.upsert(docName, {\n status: 'compiling',\n sourceHash: hash,\n diagnostics: [],\n });\n try {\n const compiled = await compilePlugin(\n docName,\n doc.text,\n settled?.sourceHash\n );\n if (disposed) return;\n if (compiled.skipped && settled) {\n useBrowserPluginsStore.getState().upsert(docName, {\n status: settled.status,\n sourceHash: settled.sourceHash,\n diagnostics: settled.diagnostics,\n });\n return;\n }\n const finalHash = hashSource(compiled.source);\n if (!compiled.js) {\n pluginHost.dispose(docName);\n useBrowserPluginsStore.getState().upsert(docName, {\n status: 'error',\n sourceHash: finalHash,\n js: undefined,\n metadata: undefined,\n diagnostics: compiled.diagnostics,\n });\n announceChange(docName);\n return;\n }\n const record = useBrowserPluginsStore.getState().records[docName];\n const metadata = await pluginHost.load(docName, {\n js: compiled.js,\n format: FORMAT,\n allowNetwork: record?.allowNetwork ?? false,\n networkOrigins: record?.networkOrigins,\n examples: extractPluginExamples(compiled.source),\n });\n if (disposed) return;\n // The record must carry its metadata before the ownership check, or\n // it cannot own its own name.\n useBrowserPluginsStore.getState().upsert(docName, {\n status: 'ready',\n sourceHash: finalHash,\n js: compiled.js,\n metadata,\n diagnostics: compiled.diagnostics,\n });\n const conflict = nameConflict(docName, metadata.name);\n if (conflict) {\n useBrowserPluginsStore.getState().upsert(docName, {\n status: 'error',\n diagnostics: [\n ...compiled.diagnostics,\n conflictDiagnostic(conflict),\n ],\n });\n }\n reconcileConflicts();\n announceChange(docName);\n } catch (error) {\n if (disposed) return;\n pluginHost.dispose(docName);\n useBrowserPluginsStore.getState().upsert(docName, {\n status: 'error',\n sourceHash: hash,\n js: undefined,\n metadata: undefined,\n diagnostics: [sandboxDiagnostic(error)],\n });\n reconcileConflicts();\n announceChange(docName);\n }\n };\n\n const reconcile = (): void => {\n const { documents, documentTypes } = documentsStore.getState();\n const pluginDocs = documents.filter(\n (d) => documentTypes[d.name] === PLUGIN_TYPE\n );\n const present = new Set(pluginDocs.map((d) => d.name));\n const pluginsStore = useBrowserPluginsStore.getState();\n let removed = false;\n for (const name of Object.keys(pluginsStore.records)) {\n if (!present.has(name)) {\n pluginsStore.remove(name);\n pluginHost.dispose(name);\n disposePluginModel(name);\n compileQueue.cancel(name);\n removed = true;\n }\n }\n if (removed) reconcileConflicts();\n for (const doc of pluginDocs) {\n const record = pluginsStore.records[doc.name];\n const stale =\n !record ||\n record.sourceHash !== hashSource(doc.text) ||\n record.status === 'idle' ||\n record.status === 'compiling';\n if (stale) compileQueue.schedule(doc.name, COMPILE_DEBOUNCE_MS);\n }\n };\n\n compileQueue.setRunner(compileNow);\n let unsubscribe: (() => void) | undefined;\n // The persisted records arrive from IndexedDB; a reconcile before that\n // would compile everything and then be overwritten by the read.\n whenBrowserPluginsHydrated().then(() => {\n if (disposed) return;\n reconcile();\n unsubscribe = documentsStore.subscribe((state, previous) => {\n if (\n state.documents !== previous.documents ||\n state.documentTypes !== previous.documentTypes\n ) {\n reconcile();\n }\n });\n });\n\n return () => {\n disposed = true;\n unsubscribe?.();\n compileQueue.reset();\n };\n }, [documentsStore]);\n}\n","import { devtools, persist } from 'zustand/middleware';\nimport { createStore } from 'zustand/vanilla';\nimport type { Settings } from '../lib/types';\n\nexport type SettingsState = Settings;\n\nexport type SettingsActions = {\n setSettings: (settings: Partial<Settings>) => void;\n};\n\nexport type SettingsStore = SettingsState & SettingsActions;\n\nexport const initSettingsStore = (): SettingsState => {\n return {\n saveDocumentDebounceWait: 300,\n // UI preference to use a single preview header spanning editor + preview\n useGlobalPreviewHeader: true,\n // Report, never block: a gate is something an author opts into once they\n // know what the profile flags, not a default that refuses their first\n // build.\n qualityGate: 'none',\n // Warning-and-above, deliberately. The shipped PPTX templates produce\n // roughly two hundred info-severity findings, so an info default would\n // bury the panel in noise the first time it is opened and teach authors\n // to ignore it.\n qualityMinSeverity: 'warning',\n };\n};\n\nexport const defaultInitSettingsState: SettingsState = {\n ...initSettingsStore(),\n};\n\nexport const createSettingsStore = (\n initState: SettingsState = defaultInitSettingsState\n) => {\n return createStore<SettingsStore>()(\n devtools(\n persist(\n (set) => ({\n ...initState,\n setSettings: (settings) => set({ ...settings }),\n }),\n {\n name: 'settings-storage', // name of the item in the storage (must be unique)\n // (optional) by default, 'localStorage' is used as storage\n }\n )\n )\n );\n};\n","import { type ReactNode, createContext, useRef, useContext } from 'react';\nimport { useStore } from 'zustand';\nimport {\n type SettingsStore,\n createSettingsStore,\n initSettingsStore,\n} from './settings-store';\n\nexport type SettingsStoreApi = ReturnType<typeof createSettingsStore>;\n\nexport const SettingsStoreContext = createContext<SettingsStoreApi | undefined>(\n undefined\n);\n\nexport interface SettingsStoreProviderProps {\n children: ReactNode;\n}\n\nexport const SettingsStoreProvider = ({\n children,\n}: SettingsStoreProviderProps) => {\n const storeRef = useRef<SettingsStoreApi | null>(null);\n if (!storeRef.current) {\n storeRef.current = createSettingsStore(initSettingsStore());\n }\n\n return (\n <SettingsStoreContext.Provider value={storeRef.current}>\n {children}\n </SettingsStoreContext.Provider>\n );\n};\n\nexport const useSettingsStore = <T,>(\n selector: (store: SettingsStore) => T\n): T => {\n const settingsStoreContext = useContext(SettingsStoreContext);\n\n if (!settingsStoreContext) {\n throw new Error(\n 'useSettingsStore must be used within SettingsStoreProvider'\n );\n }\n\n return useStore(settingsStoreContext, selector);\n};\n","import { useBrowserPluginsSync } from '../hooks/useBrowserPluginsSync';\n\n/**\n * Mounts the browser-plugin sync once, under the documents store it watches.\n */\nexport function BrowserPluginsProvider({\n diskPluginNames,\n children,\n}: {\n diskPluginNames: readonly string[];\n children: React.ReactNode;\n}) {\n useBrowserPluginsSync(diskPluginNames);\n return <>{children}</>;\n}\n","import { useEffect, useRef, useContext, useSyncExternalStore } from 'react';\nimport { loader } from '@monaco-editor/react';\nimport type { Monaco } from '@monaco-editor/react';\nimport { usePluginsStore } from '../store/plugins-store';\nimport {\n activePluginsSignature,\n browserComponentsForSchema,\n useBrowserPluginsStore,\n} from '../store/browser-plugins-store';\nimport { ThemesStoreContext } from '../store/themes-store-provider';\nimport { updateMonacoWithPlugins } from '../lib/monaco-config';\n\nconst emptyNames: string[] = [];\nconst subscribe = () => () => {};\n\n/**\n * Read custom theme names from the ThemesStore if available,\n * returning [] when outside a ThemesStoreProvider.\n *\n * getSnapshot must return a referentially stable value to avoid\n * infinite re-renders with useSyncExternalStore.\n */\nfunction useCustomThemeNames(): string[] {\n const store = useContext(ThemesStoreContext);\n const cachedRef = useRef<string[]>(emptyNames);\n\n const getSnapshot = store\n ? () => {\n const next = store.getState().getAllThemeNames();\n // Only update the cached reference when the list actually changes\n if (\n next.length !== cachedRef.current.length ||\n next.some((n, i) => n !== cachedRef.current[i])\n ) {\n cachedRef.current = next;\n }\n return cachedRef.current;\n }\n : () => emptyNames;\n\n return useSyncExternalStore(store ? store.subscribe : subscribe, getSnapshot);\n}\n\n/**\n * Hook to synchronize selected plugins and custom themes with Monaco editor schemas.\n * Ensures real-time validation and autocomplete include plugin-specific schemas\n * and custom theme names.\n */\nexport function useMonacoPlugins() {\n const monacoRef = useRef<Monaco | null>(null);\n const selectedPlugins = usePluginsStore((state) => state.selectedPlugins);\n const selectedPluginNames = Array.from(selectedPlugins);\n const customThemeNames = useCustomThemeNames();\n // A string that changes exactly when the active browser plugins or their\n // schemas change — cheaper to compare than the records themselves.\n const browserSignature = useBrowserPluginsStore(activePluginsSignature);\n const themesStore = useContext(ThemesStoreContext);\n const themesStoreRef = useRef(themesStore);\n themesStoreRef.current = themesStore;\n const previousPluginsRef = useRef<string[]>([]);\n const previousThemesRef = useRef<string[]>([]);\n const previousBrowserRef = useRef<string>('');\n\n useEffect(() => {\n loader\n .init()\n .then((monaco) => {\n monacoRef.current = monaco;\n // Read current state from stores (not stale closure) since\n // zustand persist may have hydrated while loader.init() was pending\n const currentPlugins = Array.from(\n usePluginsStore.getState().selectedPlugins\n );\n const currentThemes =\n themesStoreRef.current?.getState().getAllThemeNames() ?? [];\n const browserState = useBrowserPluginsStore.getState();\n updateMonacoWithPlugins(\n monaco,\n currentPlugins,\n currentThemes,\n browserComponentsForSchema(browserState)\n )\n .then((success) => {\n if (success) {\n console.log(\n '[useMonacoPlugins] Monaco initialized with plugins:',\n currentPlugins\n );\n } else {\n console.warn(\n '[useMonacoPlugins] Monaco initialization completed with warnings'\n );\n }\n })\n .catch((error) => {\n console.error(\n '[useMonacoPlugins] Failed to update Monaco with plugins:',\n error\n );\n });\n previousPluginsRef.current = [...currentPlugins];\n previousThemesRef.current = [...currentThemes];\n previousBrowserRef.current = activePluginsSignature(browserState);\n })\n .catch((error) => {\n console.error('Failed to initialize Monaco:', error);\n });\n }, []); // Keep empty dependency to run only once\n\n useEffect(() => {\n const pluginsChanged =\n selectedPluginNames.length !== previousPluginsRef.current.length ||\n selectedPluginNames.some(\n (name, index) => name !== previousPluginsRef.current[index]\n );\n\n const themesChanged =\n customThemeNames.length !== previousThemesRef.current.length ||\n customThemeNames.some(\n (name, index) => name !== previousThemesRef.current[index]\n );\n\n const browserChanged = browserSignature !== previousBrowserRef.current;\n\n if (!pluginsChanged && !themesChanged && !browserChanged) {\n return;\n }\n\n if (monacoRef.current) {\n updateMonacoWithPlugins(\n monacoRef.current,\n selectedPluginNames,\n customThemeNames,\n browserComponentsForSchema(useBrowserPluginsStore.getState())\n ).catch((error) => {\n console.error(\n '[useMonacoPlugins] Failed to update Monaco schemas:',\n error\n );\n });\n previousPluginsRef.current = [...selectedPluginNames];\n previousThemesRef.current = [...customThemeNames];\n previousBrowserRef.current = browserSignature;\n }\n }, [selectedPluginNames, customThemeNames, browserSignature]);\n\n return {\n monaco: monacoRef.current,\n selectedPlugins: selectedPluginNames,\n };\n}\n","import { useMonacoPlugins } from '../hooks/useMonacoPlugins';\n\n/**\n * Provider component that manages Monaco plugin synchronization\n * This must be rendered within the app after stores are initialized\n */\nexport function MonacoPluginProvider({\n children,\n}: {\n children: React.ReactNode;\n}) {\n // Initialize Monaco plugin synchronization\n useMonacoPlugins();\n\n return <>{children}</>;\n}\n"],"file":"assets/MonacoPluginProvider-DbBCCotq.js"}
1
+ {"version":3,"mappings":";6aAgBO,SAASA,GAAkBC,EAA2C,CAC3E,GAAI,CACF,MAAMC,EAAS,KAAK,MAAMD,CAAU,EAEpC,MAAI,CAACC,GAAU,OAAOA,GAAW,SACxB,CACL,MAAO,GACP,OAAQ,CAAC,CAAE,QAAS,8BAA+B,GAInD,OAAOA,EAAO,MAAS,UAAY,CAACA,EAAO,KAAK,OAC3C,CACL,MAAO,GACP,OAAQ,CAAC,CAAE,QAAS,8CAA+C,GAIhE,CAAE,MAAO,GAClB,OAAS,EAAG,CACV,MAAO,CACL,MAAO,GACP,OAAQ,CACN,CACE,QACE,aAAa,YACT,iBAAiB,EAAE,OAAO,GAC1B,6BACR,CACF,CAEJ,CACF,CAKO,SAASC,GAAaC,EAAmC,CAC9D,GAAI,CACF,OACEA,GACA,OAAOA,GAAc,UACrB,SAAWA,GACX,OAAQA,EAAkB,MAAS,SAE3BA,EAAkB,KAErB,IACT,MAAQ,CACN,OAAO,IACT,CACF,CC5DO,MAAMC,EAAN,MAAMA,UAA2B,WAAY,CAG1C,aAAc,CACpB,OACF,CAEA,OAAO,aAAkC,CACvC,OAAKA,EAAmB,WACtBA,EAAmB,SAAW,IAAIA,GAE7BA,EAAmB,QAC5B,CAEA,gBAAgBC,EAA+B,CAC7C,KAAK,cAAc,IAAI,YAAY,cAAe,CAAE,OAAQA,CAAA,CAAO,CAAC,CACtE,CAEA,cAAcC,EAAyD,CACrE,MAAMC,EAAWC,GAAa,CAE5BF,EADoBE,EACC,MAAM,CAC7B,EAEA,YAAK,iBAAiB,cAAeD,CAAO,EAG3C,KAAa,gBAAmB,KAAa,gBAAkB,GAAK,EAG9D,IAAM,CACX,KAAK,oBAAoB,cAAeA,CAAO,EAC9C,KAAa,eAAiB,KAAK,IAClC,GACE,KAAa,gBAAkB,GAAK,EAE1C,CACF,CACF,EArCEE,EADWL,EACI,YADV,IAAMM,EAANN,EAwCA,MAAMO,GAAqBD,EAAmB,cC/CrD,SAASE,EAAiBC,EAAS,CAC/B,OAAO,IAAI,QAAQ,CAACC,EAASC,IAAW,CAEpCF,EAAQ,WAAaA,EAAQ,UAAY,IAAMC,EAAQD,EAAQ,MAAM,EAErEA,EAAQ,QAAUA,EAAQ,QAAU,IAAME,EAAOF,EAAQ,KAAK,CAClE,CAAC,CACL,CACA,SAASG,GAAYC,EAAQC,EAAW,CACpC,IAAIC,EACJ,MAAMC,EAAQ,IAAM,CAChB,GAAID,EACA,OAAOA,EACX,MAAMN,EAAU,UAAU,KAAKI,CAAM,EACrC,OAAAJ,EAAQ,gBAAkB,IAAMA,EAAQ,OAAO,kBAAkBK,CAAS,EAC1EC,EAAMP,EAAiBC,CAAO,EAC9BM,EAAI,KAAME,GAAO,CAGbA,EAAG,QAAU,IAAOF,EAAM,MAC9B,EAAG,IAAM,CAAE,CAAC,EACLA,CACX,EACA,MAAO,CAACG,EAAQhB,IAAac,EAAK,EAAG,KAAMC,GAAOf,EAASe,EAAG,YAAYH,EAAWI,CAAM,EAAE,YAAYJ,CAAS,CAAC,CAAC,CACxH,CACA,IAAIK,EACJ,SAASC,GAAkB,CACvB,OAAKD,IACDA,EAAsBP,GAAY,eAAgB,QAAQ,GAEvDO,CACX,CAOA,SAASE,GAAIC,EAAKC,EAAcH,IAAmB,CAC/C,OAAOG,EAAY,WAAaC,GAAUhB,EAAiBgB,EAAM,IAAIF,CAAG,CAAC,CAAC,CAC9E,CAQA,SAASG,GAAIH,EAAKI,EAAOH,EAAcH,EAAe,EAAI,CACtD,OAAOG,EAAY,YAAcC,IAC7BA,EAAM,IAAIE,EAAOJ,CAAG,EACbd,EAAiBgB,EAAM,WAAW,EAC5C,CACL,CAqDA,SAASG,GAAIL,EAAKC,EAAcH,IAAmB,CAC/C,OAAOG,EAAY,YAAcC,IAC7BA,EAAM,OAAOF,CAAG,EACTd,EAAiBgB,EAAM,WAAW,EAC5C,CACL,CCzGO,MAAMI,GAA2B,CACtC,QAAS,MAAOC,GACN,MAAMR,GAAIQ,CAAI,GAAM,KAE9B,QAAS,MAAOA,EAAcH,IAAiC,CAC7D,MAAMD,GAAII,EAAMH,CAAK,CACvB,EACA,WAAY,MAAOG,GAAgC,CACjD,MAAMF,GAAIE,CAAI,CAChB,CACF,ECQO,SAASC,GAAkBC,EAEE,CAClC,MAAMC,EAAuC,GAC7C,UAAWC,KAAS,OAAO,OAAOF,CAAY,EACxCE,EAAM,OAASA,EAAM,WAAYA,EAAM,IAAI,EAAIA,EAAM,QAE3D,OAAOD,CACT,CAYO,MAAME,GAAkB,KACtB,CACL,aAAc,EAAC,GAINC,GAAsC,CACjD,GAAGD,GAAA,CACL,EAEaE,GAAoB,CAC/BC,EAAyBF,KAElBvB,EAAA,EACL0B,EACEC,EACE,CAACd,EAAKJ,KAAS,CACb,GAAGgB,EAEH,YAAa,CAACG,EAAcC,IAC1BhB,EAAKiB,GAAU,CACb,MAAMC,EAAahD,GAAkB8C,CAAO,EAE5C,IAAI5C,EACA+C,EAAYJ,EAEhB,GAAIG,EAAW,MACb,GAAI,CACF,MAAME,EAAgB,KAAK,MAAMJ,CAAO,EACxC5C,EAASgD,EACT,MAAMC,EAAgBhD,GAAa+C,CAAa,EAC5CC,IACFF,EAAYE,EAEhB,MAAQ,CAER,CAGF,MAAMC,EAAgBL,EAAM,aAAaF,CAAY,EAC/CQ,EAAW,CAAC,CAACD,EACbE,GAAoBF,GAAA,YAAAA,EAAe,WAAYN,EAE/CS,EAA2B,CAC/B,KAAMN,EACN,QAAAH,EACA,OAAA5C,EACA,MAAO8C,EAAW,MAClB,iBAAkB,IAAK,EASzB,OAJGM,GACE,EAACF,GAAA,MAAAA,EAAe,QAASJ,EAAW,QACvCA,EAAW,OAIX,WAAW,IAAM,CACfpC,GAAmB,gBAAgB,CACjC,UAAAqC,EACA,UAAW,KAAK,MAChB,WAAYI,EAAW,SAAW,SACnC,CACH,EAAG,CAAC,EAGC,CACL,aAAc,CACZ,GAAGN,EAAM,aACT,CAACF,CAAY,EAAGU,CAAA,CAClB,CAEJ,CAAC,EAEH,YAAcV,GACZf,EAAKiB,GAAU,CACb,MAAMS,EAAeT,EAAM,aAAaF,CAAY,EAC9CY,EAAkB,CAAE,GAAGV,EAAM,cACnC,cAAOU,EAAgBZ,CAAY,EAG/BW,GACF,WAAW,IAAM,CACf5C,GAAmB,gBAAgB,CACjC,UAAW4C,EAAa,KACxB,UAAW,KAAK,MAChB,WAAY,SACb,CACH,EAAG,CAAC,EAGC,CACL,aAAcC,CAAA,CAElB,CAAC,EAEH,SAAWR,GAAc,CACvB,MAAMF,EAAQrB,EAAA,EAGd,UAAW6B,KAAe,OAAO,OAAOR,EAAM,YAAY,EACxD,GACEQ,EAAY,OACZA,EAAY,OAASN,GACrBM,EAAY,OAEZ,OAAOA,EAAY,OAKvB,OAAO,IACT,EAEA,iBAAkB,IAAM,CACtB,MAAMR,EAAQrB,EAAA,EACRgC,EAAkB,GAGxB,UAAWH,KAAe,OAAO,OAAOR,EAAM,YAAY,EACpDQ,EAAY,OAASA,EAAY,MACnCG,EAAM,KAAKH,EAAY,IAAI,EAI/B,OAAOG,CACT,EAEA,aAAeT,GAAc,CAC3B,MAAMF,EAAQrB,EAAA,EAGd,UAAW6B,KAAe,OAAO,OAAOR,EAAM,YAAY,EACxD,GAAIQ,EAAY,OAASN,EACvB,OAAOM,EAAY,MAIvB,MAAO,EACT,IAEF,CACE,KAAM,iBACN,QAAS,EACT,QAASI,EAAkB,IAAM1B,EAAU,EAE3C,WAAac,IAAW,CAAE,aAAcA,EAAM,eAE9C,mBAAoB,IAAOA,GAAU,CAC/BA,GAASA,EAAM,cAEjB,OAAO,KAAKA,EAAM,YAAY,EAAE,QAASpB,GAAQ,CAC/C,MAAMW,EAAQS,EAAM,aAAapB,CAAG,EAElCW,EAAM,cACN,OAAOA,EAAM,cAAiB,WAE9BA,EAAM,aAAe,IAAI,KAAKA,EAAM,YAAY,EAEpD,CAAC,CAEL,EACF,CACF,CACF,ECvMSsB,EAAqBC,gBAChC,MACF,EAMaC,GAAsB,CAAC,CAAE,SAAAC,KAAyC,CAC7E,MAAMC,EAAWC,SAAuB,MAAS,EACjD,OAAKD,EAAS,UACZA,EAAS,QAAUvB,GAAkBF,IAAiB,SAIrDqB,EAAmB,SAAnB,CAA4B,MAAOI,EAAS,QAC1C,SAAAD,EACH,CAEJ,EAEaG,GAAsBC,GAA2C,CAC5E,MAAMC,EAAqBC,aAAWT,CAAkB,EAExD,GAAI,CAACQ,EACH,MAAM,IAAI,MAAM,wDAAwD,EAG1E,OAAOE,EAASF,EAAoBD,CAAQ,CAC9C,ECpCO,SAASI,EAAWC,EAAsB,CAC/C,IAAIC,EAAO,KACX,QAASC,EAAI,EAAGA,EAAIF,EAAK,OAAQE,IAC/BD,GAASA,GAAQ,GAAKA,EAAOD,EAAK,WAAWE,CAAC,EAAK,EAErD,MAAO,IAAID,IAAS,GAAG,SAAS,EAAE,CAAC,IAAID,EAAK,OAAO,SAAS,EAAE,CAAC,EACjE,CCkCO,SAASG,EACdC,EACAC,EAAuD,GAClC,CACrB,MAAMC,EAAM,KAAK,MACjB,MAAO,CACL,QAAAF,EACA,QAAS,GACT,aAAc,GACd,eAAgB,GAChB,OAAQ,OACR,WAAY,GACZ,YAAa,GACb,UAAWE,EACX,UAAWA,EACX,GAAGD,CAAA,CAEP,CAEO,MAAME,EAAyBC,GAAA,EACpCpC,EACGd,IAAS,CACR,QAAS,GAET,OAAQ,CAAC8C,EAASC,IAChB/C,EAAKiB,GAAU,CACb,MAAMkC,EACJlC,EAAM,QAAQ6B,CAAO,GAAKD,EAA0BC,CAAO,EAC7D,MAAO,CACL,QAAS,CACP,GAAG7B,EAAM,QACT,CAAC6B,CAAO,EAAG,CAAE,GAAGK,EAAU,GAAGJ,EAAO,UAAW,KAAK,KAAI,CAAE,CAC5D,CAEJ,CAAC,EAKH,WAAY,CAACD,EAASM,IACpBpD,EAAKiB,GAAU,CACb,MAAMkC,EACJlC,EAAM,QAAQ6B,CAAO,GAAKD,EAA0BC,CAAO,EAC7D,OAAI7B,EAAM,QAAQ6B,CAAO,GAAKK,EAAS,UAAYC,EAC1CnC,EACF,CACL,QAAS,CACP,GAAGA,EAAM,QACT,CAAC6B,CAAO,EAAG,CAAE,GAAGK,EAAU,QAAAC,EAAS,UAAW,KAAK,KAAI,CAAE,CAC3D,CAEJ,CAAC,EAEH,gBAAiB,CAACN,EAASO,IACzBrD,EAAKiB,GAAU,CACb,MAAMkC,EACJlC,EAAM,QAAQ6B,CAAO,GAAKD,EAA0BC,CAAO,EAC7D,OAAI7B,EAAM,QAAQ6B,CAAO,GAAKK,EAAS,eAAiBE,EAC/CpC,EACF,CACL,QAAS,CACP,GAAGA,EAAM,QACT,CAAC6B,CAAO,EAAG,CAAE,GAAGK,EAAU,aAAAE,EAAc,UAAW,KAAK,KAAI,CAAE,CAChE,CAEJ,CAAC,EAEH,kBAAmB,CAACP,EAASQ,IAC3BtD,EAAKiB,GAAU,CACb,MAAMkC,EACJlC,EAAM,QAAQ6B,CAAO,GAAKD,EAA0BC,CAAO,EACvDS,EAAWJ,EAAS,gBAAkB,GAC5C,OACElC,EAAM,QAAQ6B,CAAO,GACrBS,EAAS,SAAWD,EAAe,QACnCC,EAAS,MAAM,CAACC,EAAQ,IAAMA,IAAWF,EAAe,CAAC,CAAC,EAEnDrC,EAEF,CACL,QAAS,CACP,GAAGA,EAAM,QACT,CAAC6B,CAAO,EAAG,CACT,GAAGK,EACH,eAAgB,CAAC,GAAGG,CAAc,EAClC,UAAW,KAAK,KAAI,CACtB,CACF,CAEJ,CAAC,EAEH,OAAQ,CAACG,EAASC,IAChB1D,EAAKiB,GAAU,CACb,MAAMkC,EAAWlC,EAAM,QAAQwC,CAAO,EACtC,GAAI,CAACN,GAAYM,IAAYC,EAAS,OAAOzC,EAC7C,MAAM0C,EAAU,CAAE,GAAG1C,EAAM,SAC3B,cAAO0C,EAAQF,CAAO,EACtBE,EAAQD,CAAO,EAAI,CAAE,GAAGP,EAAU,QAASO,CAAA,EACpC,CAAE,QAAAC,CAAA,CACX,CAAC,EAEH,OAASb,GACP9C,EAAKiB,GAAU,CACb,GAAI,CAACA,EAAM,QAAQ6B,CAAO,EAAG,OAAO7B,EACpC,MAAM0C,EAAU,CAAE,GAAG1C,EAAM,SAC3B,cAAO0C,EAAQb,CAAO,EACf,CAAE,QAAAa,CAAA,CACX,CAAC,IAEL,CACE,KAAM,sBACN,QAAS,EACT,QAAS9B,EAAkB,IAAM1B,EAAU,EAC3C,WAAac,IAAW,CAAE,QAASA,EAAM,UAKzC,QAAU2C,GAAc,CACtB,MAAM3C,EAAQ2C,EAGRD,EAA+C,GACrD,SAAW,CAACvD,EAAMyD,CAAM,IAAK,OAAO,SAAQ5C,GAAA,YAAAA,EAAO,UAAW,EAAE,EAC9D0C,EAAQvD,CAAI,EAAI,CACd,GAAGyD,EACH,UAAWA,EAAO,WAAaA,EAAO,WAAa,KAAK,MACxD,eAAgBA,EAAO,gBAAkB,EAAC,EAG9C,MAAO,CAAE,QAAAF,CAAA,CACX,EACF,CAEJ,EAOO,SAASG,IAA4C,CAC1D,MAAMC,EAAMd,EAAuB,QACnC,OAAIc,EAAI,cAAsB,QAAQ,UAC/B,IAAI,QAAS9E,GAAY,CAC9B,MAAM+E,EAAOD,EAAI,kBAAkB,IAAM,CACvCC,EAAA,EACA/E,EAAA,CACF,CAAC,CACH,CAAC,CACH,CAQO,SAASgF,GACdhD,EACuB,CACvB,MAAMiD,EAAgC,GACtC,UAAWL,KAAU,OAAO,OAAO5C,EAAM,OAAO,EAC1C4C,EAAO,SAAWA,EAAO,SAAW,SAAWA,EAAO,UACxDK,EAAO,KAAK,CAAE,QAASL,EAAO,QAAS,SAAUA,EAAO,SAAU,EAGtE,OAAOK,EAAO,KAAK,CAACC,EAAGC,IAAMD,EAAE,QAAQ,cAAcC,EAAE,OAAO,CAAC,CACjE,CAMO,SAASC,EAAuBpD,EAAoC,CACzE,MAAMqD,EAAaC,EAA2BtD,CAAK,EAGnD,OAAIqD,EAAW,SAAW,EAAU,GAG7B7B,EAAW,KAAK,UAAU6B,CAAU,CAAC,CAC9C,CAOO,SAASE,GACdb,EACAc,EACoB,OACpB,IAAIC,EACJ,UAAWb,KAAU,OAAO,OAAOF,CAAO,IACpCgB,EAAAd,EAAO,WAAP,YAAAc,EAAiB,QAASF,IAC1B,CAACC,GAASb,EAAO,UAAYa,EAAM,aAAWA,EAAQb,GAE5D,OAAOa,GAAA,YAAAA,EAAO,OAChB,CAaO,SAASH,EACdtD,EAC8B,CAC9B,OAAOgD,GAAoBhD,CAAK,EAAE,IAAK2D,IAAY,CACjD,KAAMA,EAAO,SAAS,KACtB,SAAUA,EAAO,SAAS,SAAS,IAAKC,IAAO,CAC7C,QAASA,EAAE,QACX,YAAaA,EAAE,YACf,GAAIA,EAAE,YAAc,CAAE,YAAa,IAAS,GAC5C,GAAIA,EAAE,YAAc,CAAE,YAAaA,EAAE,aAAgB,EAAC,EACtD,GACF,CACJ,CAGO,SAASC,GACdjB,EACoB,CACpB,QAAQA,GAAA,YAAAA,EAAQ,cAAe,IAAI,OAAQkB,GAAMA,EAAE,WAAa,OAAO,CACzE,2SClQMC,GAAU,SAOVC,GACJ,2EAGF,SAASC,GAAWC,EAAuB,CACzC,OAAOA,IAAS,aAAeA,IAAS,aAAeA,IAAS,OAClE,CASO,SAASC,GAAuBC,EAA6B,CAClE,MAAMC,EAAUD,EAAM,OAAO,QAAQ,OAAQ,EAAE,EAC/C,GAAI,CAACC,EAAS,MAAO,CAAE,GAAI,GAAO,OAAQ,YAE1C,GAAIA,IAAY,KAAO,aAAa,KAAKA,CAAO,GAAKA,IAAY,MAC/D,MAAO,CAAE,GAAI,GAAO,OAAQ,2CAG9B,MAAMC,EAAa,2BAA2B,KAAKD,CAAO,EACtDA,EACA,WAAWA,CAAO,GAIhBE,EAAW,sBAAsB,KAAKD,CAAU,EAChDE,EAAYD,EACdD,EAAW,QAAQ,sBAAuB,IAAI,EAC9CA,EAEJ,IAAIG,EACJ,GAAI,CACFA,EAAM,IAAI,IAAID,CAAS,CACzB,MAAQ,CACN,MAAO,CAAE,GAAI,GAAO,OAAQ,eAC9B,CAEA,GAAIC,EAAI,UAAYA,EAAI,SACtB,MAAO,CAAE,GAAI,GAAO,OAAQ,8BAE9B,GAAIA,EAAI,WAAa,KAAOA,EAAI,QAAUA,EAAI,KAC5C,MAAO,CAAE,GAAI,GAAO,OAAQ,mCAG9B,MAAMP,EAAOK,EAAW,KAAKE,EAAI,QAAQ,GAAKA,EAAI,SAClD,GAAI,CAACT,GAAK,KAAKE,CAAI,QAAU,CAAE,GAAI,GAAO,OAAQ,qBAElD,MAAMQ,EAAWD,EAAI,SAAS,cAC9B,OAAIC,IAAa,UAAYA,IAAa,QACjC,CAAE,GAAI,GAAO,OAAQ,yBAE1BA,IAAa,SAAW,CAACT,GAAWQ,EAAI,QAAQ,EAC3C,CAAE,GAAI,GAAO,OAAQ,+CAGvB,CACL,GAAI,GACJ,OAAQ,GAAGC,CAAQ,KAAKR,CAAI,GAAGO,EAAI,KAAO,IAAIA,EAAI,IAAI,GAAK,EAAE,GAEjE,CASO,SAASE,GAAoBlD,EAA6B,CAC/D,MAAMmD,EAAoB,GACpBC,EAAmB,GACzB,UAAWC,KAAQrD,EAAK,MAAM,OAAO,EAAG,CACtC,GAAI,CAACqD,EAAK,OAAQ,SAClB,MAAMC,EAASZ,GAAuBW,CAAI,EACrCC,EAAO,GACFH,EAAQ,SAASG,EAAO,MAAM,GAAGH,EAAQ,KAAKG,EAAO,MAAM,EADrDF,EAAO,KAAK,IAAIC,EAAK,MAAM,KAAKC,EAAO,MAAM,EAAE,CAEjE,CACA,MAAO,CAAE,QAAAH,EAAS,OAAAC,CAAA,CACpB,CAQO,SAASG,GACd5C,EACAwC,EACQ,CACR,GAAI,CAACxC,GAAgB,EAACwC,GAAA,MAAAA,EAAS,QAAQ,OAAOb,GAC9C,MAAMkB,EAAOL,EACV,IAAKrC,GAAW4B,GAAuB5B,CAAM,CAAC,EAC9C,OAAQwC,GAAmDA,EAAO,EAAE,EACpE,IAAKA,GAAWA,EAAO,MAAM,EAChC,OAAOE,EAAK,OAAS,EAAIA,EAAK,KAAK,GAAG,EAAIlB,EAC5C,CChGA,SAASmB,IAAgB,CACvB,MAAMC,EAAQ,IAAI,WAAW,EAAE,EAC/B,cAAO,gBAAgBA,CAAK,EACrB,MAAM,KAAKA,EAAQhC,GAAMA,EAAE,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,EAAE,KAAK,EAAE,CAC1E,CAMO,SAASiC,GACdC,EACAjD,EACAC,EACQ,CAcR,MAAO,wGAbK,CACV,qBAIA,qBAAqBgD,CAAW,wBAChC,mBAGA,eAAeL,GAAgB5C,EAAcC,CAAc,CAAC,GAC5D,kBACA,sBACA,KAAK,IAAI,CACuG,iCAAiCgD,CAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAsBhK,CAEO,MAAMC,EAAa,CAMxB,YAAYC,EAA8B,CALzB5H,EAAA,eACAA,EAAA,cACAA,EAAA,iBACTA,EAAA,gBAAW,IAGjB,MAAM0H,EAAcH,GAAA,EACdM,EAAS,SAAS,cAAc,QAAQ,EAC9CA,EAAO,aAAa,UAAW,eAAe,EAC9CA,EAAO,aAAa,cAAe,MAAM,EACzCA,EAAO,aAAa,QAAS,gBAAgB,EAC7CA,EAAO,SAAW,GAClBA,EAAO,MAAM,QACX,qFACF,KAAK,OAASA,EAEd,IAAIC,EAA2B,IAAM,CAAC,EAClCC,EAAsC,IAAM,CAAC,EACjD,KAAK,MAAQ,IAAI,QAAc,CAAC1H,EAASC,IAAW,CAClDwH,EAAezH,EACf0H,EAAczH,CAChB,CAAC,EAED,MAAM0H,EAAa,WAAW,IAAM,CAClCD,EAAY,IAAI,MAAM,8BAA8B,CAAC,CACvD,EAAG,GAAM,EAET,KAAK,SAAYnI,GAAwB,CACvC,GAAIA,EAAM,SAAWiI,EAAO,cAAe,OAC3C,MAAMI,EAAOrI,EAAM,KACnB,GAAI,GAACqI,GAAQ,OAAOA,GAAS,UAC7B,IAAIA,EAAK,OAAS,QAAS,CACzB,aAAaD,CAAU,EACvBF,EAAA,EACA,MACF,CACA,GAAIG,EAAK,OAAS,cAAe,CAC/BL,EAAQ,QACN,OAAOK,EAAK,SAAY,SAAWA,EAAK,QAAU,gBAEpD,MACF,CACAL,EAAQ,UAAUK,CAAI,EACxB,EACA,OAAO,iBAAiB,UAAW,KAAK,QAAQ,EAEhDJ,EAAO,iBAAiB,OAAQ,IAAM,QACpC9B,EAAA8B,EAAO,gBAAP,MAAA9B,EAAsB,YACpB,CAAE,KAAM,OAAQ,QAAS6B,EAAQ,SACjC,IAEJ,CAAC,EACDC,EAAO,OAASJ,GACdC,EACAE,EAAQ,aACRA,EAAQ,gBAEV,SAAS,KAAK,YAAYC,CAAM,EAGhC,KAAK,MAAM,MAAM,IAAM,CAAC,CAAC,CAC3B,CAEA,MAAM,KAAKK,EAAiC,OAE1C,GADA,MAAM,KAAK,MACP,KAAK,SAAU,MAAM,IAAI,MAAM,2BAA2B,GAC9DnC,EAAA,KAAK,OAAO,gBAAZ,MAAAA,EAA2B,YAAYmC,EAAS,IAClD,CAEA,SAAgB,CACV,KAAK,WACT,KAAK,SAAW,GAChB,OAAO,oBAAoB,UAAW,KAAK,QAAQ,EACnD,KAAK,OAAO,SACd,CACF,CCvHA,SAASC,EAAYC,EAGL,CACd,MAAO,CACL,aAAcA,EAAK,aACnB,eAAgB,CAAC,GAAIA,EAAK,gBAAkB,EAAG,EAAE,MAAK,CAE1D,CAEA,SAASC,EAAW9C,EAAgBC,EAAyB,CAC3D,OACED,EAAE,eAAiBC,EAAE,cACrBD,EAAE,eAAe,SAAWC,EAAE,eAAe,QAC7CD,EAAE,eAAe,MAAM,CAACX,EAAQZ,IAAMY,IAAWY,EAAE,eAAexB,CAAC,CAAC,CAExE,CAEA,MAAMsE,GAAkB,IAClBC,GAAoB,IACpBC,GAAkB,IAyBjB,MAAMC,UAA2B,KAAM,CAC5C,YAAYvE,EAAiBwE,EAAcC,EAAY,CACrD,MACE,WAAWzE,CAAO,oBAAoBwE,CAAI,WAAW,KAAK,MAAMC,EAAK,GAAI,CAAC,sBAE5E,KAAK,KAAO,oBACd,CACF,CAEO,MAAMC,WAA2B,KAAM,CAC5C,YAAY1E,EAAiB,CAC3B,MAAM,WAAWA,CAAO,wBAAwB,EAChD,KAAK,KAAO,oBACd,CACF,CAEA,IAAI2E,EAAyC,KAG7C,SAASC,IAA+B,CACtC,OAAKD,IACHA,QAAiB,OAAO,4CAA6B,MAClD,KAAME,GAAWA,EAAO,OAAO,EAC/B,MAAOC,GAAU,CAChB,MAAAH,EAAiB,KACXG,CACR,CAAC,GAEEH,CACT,CAEA,SAASI,GAAS1D,EAAaC,EAAsB,CACnD,OACED,EAAE,KAAOC,EAAE,IACXD,EAAE,SAAWC,EAAE,QACf6C,EAAWF,EAAY5C,CAAC,EAAG4C,EAAY3C,CAAC,CAAC,GACzC,KAAK,UAAUD,EAAE,QAAQ,IAAM,KAAK,UAAUC,EAAE,QAAQ,CAE5D,CAEA,MAAM0D,EAAW,CAAjB,cACUlJ,EAAA,mBAAc,KACdA,EAAA,cAAS,GAEjB,MAAc,MAAMkE,EAAiBiF,EAAqC,CACxE,MAAM5E,EAAW,KAAK,QAAQ,IAAIL,CAAO,EACzC,GAAIK,EAAU,CAKZ,GAAI8D,EAAW9D,EAAS,OAAQ4E,CAAM,EAAG,OAAO5E,EAChD,KAAK,QACHL,EACA,IAAI,MAAM,WAAWA,CAAO,0BAA0B,EAE1D,CACA,MAAMkF,EAAU,MAAMN,GAAA,EAEhBO,EAAQ,KAAK,QAAQ,IAAInF,CAAO,EACtC,GAAImF,EAAO,OAAOA,EAClB,MAAMC,EAAe,CACnB,MAAO,KACP,OAAAH,EACA,OAAQ,KACR,YAAa,IACb,UAAW,MAEb,OAAAG,EAAM,MAAQ,IAAI3B,GAAa,CAC7B,QAAAyB,EACA,aAAcD,EAAO,aACrB,eAAgBA,EAAO,eACvB,UAAYlB,GAAS,CACnB,MAAMsB,EAAWtB,EACjB,GAAI,CAACsB,GAAY,OAAOA,EAAS,IAAO,SAAU,OAClD,MAAMC,EAAUF,EAAM,QAAQ,IAAIC,EAAS,EAAE,EACxCC,IACLF,EAAM,QAAQ,OAAOC,EAAS,EAAE,EAChC,aAAaC,EAAQ,KAAK,EAC1BA,EAAQ,QAAQD,CAAQ,EACxB,KAAK,MAAMrF,EAASoF,CAAK,EAC3B,EACA,QAAUpB,GAAY,CACpB,KAAK,QACHhE,EACA,IAAI,MAAM,WAAWA,CAAO,cAAcgE,CAAO,EAAE,EAEvD,EACD,EACD,KAAK,QAAQ,IAAIhE,EAASoF,CAAK,EACxBA,CACT,CAGQ,MAAMpF,EAAiBoF,EAAoB,CAC7CA,EAAM,WAAW,aAAaA,EAAM,SAAS,EACjDA,EAAM,UAAY,WAAW,IAAM,CAC7BA,EAAM,QAAQ,OAAS,GAAK,KAAK,QAAQ,IAAIpF,CAAO,IAAMoF,GAC5D,KAAK,QAAQpF,CAAO,CAExB,EAAGsE,EAAe,CACpB,CAEA,MAAc,QACZtE,EACAiF,EACAM,EACAC,EACAhB,EACAiB,EAC0B,CAC1B,GAAIA,GAAA,MAAAA,EAAQ,QAAS,MAAM,IAAIf,GAAmB1E,CAAO,EACzD,MAAMoF,EAAQ,MAAM,KAAK,MAAMpF,EAASiF,CAAM,EAC1CG,EAAM,WAAW,aAAaA,EAAM,SAAS,EACjD,MAAMM,EAAK,KAAK,SAwChB,OAvCe,IAAI,QAAyB,CAACvJ,EAASC,IAAW,CAK/D,IAAIuJ,EAA+B,KACnC,MAAMC,EAAS,IAAM,CACfD,IAASF,GAAA,MAAAA,EAAQ,oBAAoB,QAASE,IAClDA,EAAU,IACZ,EACME,EAAQ,WAAW,IAAM,CAC7BT,EAAM,QAAQ,OAAOM,CAAE,EACvBE,EAAA,EACA,KAAK,QAAQ5F,EAAS,IAAIuE,EAAmBvE,EAASwE,EAAMgB,CAAS,CAAC,EACtEpJ,EAAO,IAAImI,EAAmBvE,EAASwE,EAAMgB,CAAS,CAAC,CACzD,EAAGA,CAAS,EACZJ,EAAM,QAAQ,IAAIM,EAAI,CACpB,QAAUL,GAAa,CACrBO,EAAA,EACAzJ,EAAQkJ,CAAQ,CAClB,EACA,OAASP,GAAU,CACjBc,EAAA,EACAxJ,EAAO0I,CAAK,CACd,EACA,MAAAe,CAAA,CACD,EACDF,EAAU,IAAM,CAEd,KAAK,QAAQ3F,EAAS,IAAI0E,GAAmB1E,CAAO,CAAC,CACvD,EACAyF,GAAA,MAAAA,EAAQ,iBAAiB,QAASE,EAAS,CAAE,KAAM,KACnDP,EAAM,MAAM,KAAK,CAAE,GAAAM,EAAI,GAAGH,EAA2B,EAAE,MAAOT,GAAU,CACtEM,EAAM,QAAQ,OAAOM,CAAE,EACvB,aAAaG,CAAK,EAClBD,EAAA,EACAxJ,EAAO0I,aAAiB,MAAQA,EAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,CAAC,CAClE,CAAC,CACH,CAAC,CAEH,CAGA,MAAM,KAAK9E,EAAiBkE,EAAgD,CAC1E,MAAM7D,EAAW,KAAK,QAAQ,IAAIL,CAAO,EACrCK,IAAa,CAACA,EAAS,QAAU,CAAC0E,GAAS1E,EAAS,OAAQ6D,CAAI,IAGlE,KAAK,QAAQlE,EAAS,IAAI,MAAM,WAAWA,CAAO,gBAAgB,CAAC,EAErE,MAAMqF,EAAW,MAAM,KAAK,QAC1BrF,EACAiE,EAAYC,CAAI,EAChB,CACE,KAAM,OACN,GAAIA,EAAK,GACT,OAAQA,EAAK,OACb,aAAcA,EAAK,aACnB,eAAgBA,EAAK,gBAAkB,GACvC,SAAUA,EAAK,UAEjBE,GACA,WAEF,GAAIiB,EAAS,OAAS,QACpB,WAAK,QAAQrF,EAAS,IAAI,MAAMqF,EAAS,OAAO,CAAC,EAC3C,IAAI,MAAMA,EAAS,OAAO,EAElC,GAAIA,EAAS,OAAS,SACpB,MAAM,IAAI,MAAM,6BAA6BA,EAAS,IAAI,GAAG,EAE/D,MAAMD,EAAQ,KAAK,QAAQ,IAAIpF,CAAO,EACtC,OAAIoF,MAAa,OAASlB,GACnBmB,EAAS,QAClB,CAMA,MAAM,OACJrF,EACA9D,EACAuJ,EAC6B,CAC7B,MAAM1E,EAASZ,EAAuB,WAAW,QAAQH,CAAO,EAC1DiF,EAAShB,EAAY,CACzB,cAAclD,GAAA,YAAAA,EAAQ,eAAgB,GACtC,eAAgBA,GAAA,YAAAA,EAAQ,eACzB,EACKqE,EAAQ,KAAK,QAAQ,IAAIpF,CAAO,EACtC,GAAI,CAACoF,GAAS,CAACA,EAAM,QAAU,CAACjB,EAAWiB,EAAM,OAAQH,CAAM,EAAG,CAChE,GAAI,EAAClE,GAAA,MAAAA,EAAQ,KAAM,CAACA,EAAO,SACzB,MAAM,IAAI,MAAM,WAAWf,CAAO,mBAAmB,EAEvD,MAAM,KAAK,KAAKA,EAAS,CACvB,GAAIe,EAAO,GACX,OAAQA,EAAO,SAAS,OACxB,aAAcA,EAAO,aACrB,eAAgBA,EAAO,eACvB,SAAUA,EAAO,SAAS,SAC3B,CACH,CACA,MAAMsE,EAAW,MAAM,KAAK,QAC1BrF,EACAiF,EACA,CACE,KAAM,SACN,QAAS/I,EAAQ,QACjB,MAAOA,EAAQ,MACf,MAAOA,EAAQ,MACf,SAAUA,EAAQ,UAEpBmI,GACA,YACAoB,CAAA,EAEF,GAAIJ,EAAS,OAAS,cAAe,IAAI,MAAMA,EAAS,OAAO,EAC/D,GAAIA,EAAS,OAAS,WACpB,MAAM,IAAI,MAAM,6BAA6BA,EAAS,IAAI,GAAG,EAE/D,MAAO,CAAE,WAAYA,EAAS,WAAY,SAAUA,EAAS,SAC/D,CAGA,QAAQrF,EAAiB8F,EAAsB,CAC7C,MAAMV,EAAQ,KAAK,QAAQ,IAAIpF,CAAO,EACtC,GAAKoF,EACL,MAAK,QAAQ,OAAOpF,CAAO,EACvBoF,EAAM,WAAW,aAAaA,EAAM,SAAS,EACjD,UAAWE,KAAWF,EAAM,QAAQ,SAClC,aAAaE,EAAQ,KAAK,EAC1BA,EAAQ,OAAOQ,GAAU,IAAI,MAAM,WAAW9F,CAAO,gBAAgB,CAAC,EAExEoF,EAAM,QAAQ,QACdA,EAAM,MAAM,UACd,CAEA,SAASpF,EAA0B,OACjC,QAAO6B,EAAA,KAAK,QAAQ,IAAI7B,CAAO,IAAxB,YAAA6B,EAA2B,SAAU,IAC9C,CACF,CAEO,MAAMkE,EAAa,IAAIf,GC/UxBgB,GAAgB,EAYTC,GAAqB,gBAE3B,SAASC,GAAqB5I,EAAuB,CAC1D,OAAOA,EAAK,cAAc,SAAS2I,EAAkB,CACvD,CAQO,SAASE,GAAmB7I,EAAsB,CACvD,MAAMkF,EAAUlF,EAAK,OACrB,OAAI4I,GAAqB1D,CAAO,EAAUA,EACnCA,EAAQ,QAAQ,wBAAyB,EAAE,EAAIyD,EACxD,CA8CO,SAASG,GACdC,EACArG,EACQ,OACR,QACE6B,EAAAwE,EAAU,KAAMC,GAAQA,EAAI,OAAStG,CAAO,IAA5C,YAAA6B,EAA+C,iBAAkB7B,CAErE,CAEO,MAAMuG,GAAqB,KACzB,CACL,UAAW,GACX,SAAU,GACV,UAAW,GACX,YAAa,GACb,cAAe,GACf,aAAc,GACd,iBAAkB,EAAC,GAIVC,GAA4C,CACvD,GAAGD,GAAA,CACL,EAEaE,GAAuB,CAClC3I,EAA4B0I,KAErBnK,EAAA,EACL0B,EACEC,EACGd,IAAS,CACR,GAAGY,EACH,eAAgB,CAACR,EAAMsC,EAAM8G,IAC3BxJ,EAAKiB,GAAU,CAIb,GAHiBA,EAAM,UAAU,UAC9BmI,GAAQA,EAAI,OAAShJ,CAAA,IAEP,GAAI,CAGnB,IAAIqJ,EAAwB,0BAC5B,GAAIT,GAAqB5I,CAAI,EAC3BqJ,EAAU,wCAEVrJ,EAAK,cAAc,SAAS,OAAO,GACnCA,EAAK,cAAc,SAAS,SAAS,EAErCqJ,EAAU,6BAGV,IAAI,CACF,MAAMrL,EAAS,KAAK,MAAMsE,CAAI,EAC1BtE,EAAO,QAAUA,EAAO,OAASA,EAAO,SAC1CqL,EAAU,yBAEd,MAAQ,CAER,CAGF,MAAMC,EAAS,CACb,KAAAtJ,EACA,KACEqJ,IAAY,gCACR,kBACA,mBACN,KAAA/G,EACA,UAAW,KACX,UAAW,KACX,UAAW,KAEX,GAAI8G,GAAA,MAAAA,EAAM,eACN,CAAE,eAAgBA,EAAK,gBACvB,EAAC,EAEP,MAAO,CACL,UAAW,CAAC,GAAGvI,EAAM,UAAWyI,CAAM,EACtC,cAAe,CAAE,GAAGzI,EAAM,cAAe,CAACb,CAAI,EAAGqJ,CAAA,CAAQ,CAE7D,CACA,OAAOxI,CACT,CAAC,EACH,eAAiBb,GACfJ,EAAKiB,GAAU,CACb,MAAM0I,EAAmB,CAAE,GAAG1I,EAAM,eACpC,cAAO0I,EAAiBvJ,CAAI,EACrB,CACL,UAAWa,EAAM,UAAU,OAAQmI,GAAQA,EAAI,OAAShJ,CAAI,EAC5D,cAAeuJ,EACf,aAAc,OAAO,YACnB,OAAO,QAAQ1I,EAAM,YAAY,EAAE,OAAO,CAAC,CAAC2I,CAAC,IAAMA,IAAMxJ,CAAI,EAC/D,CAEJ,CAAC,EACH,aAAc,CAACA,EAAMsC,IACnB1C,EAAKiB,GAAU,CACb,MAAM4I,EAAW5I,EAAM,UAAU,UAC9BmI,GAAQA,EAAI,OAAShJ,CAAA,EAIxB,OAFIyJ,IAAa,IAEb5I,EAAM,UAAU4I,CAAQ,EAAE,OAASnH,EAAazB,EAI7C,CAAE,UAHSA,EAAM,UAAU,IAAI,CAACmI,EAAKxG,IAC1CA,IAAMiH,EAAW,CAAE,GAAGT,EAAK,KAAA1G,EAAM,MAAO,IAAI,MAAW0G,CAAA,CAEhD,CACX,CAAC,EACH,eAAgB,CAAC3F,EAASC,IACxB1D,EAAKiB,GAAU,CACb,MAAM4I,EAAW5I,EAAM,UAAU,UAC9BmI,GAAQA,EAAI,OAAS3F,CAAA,EAExB,GAAIoG,IAAa,GAAI,OAAO5I,EAC5B,MAAMkI,EAAYlI,EAAM,UAAU,IAAI,CAACmI,EAAKxG,IAC1CA,IAAMiH,EACF,CAAE,GAAGT,EAAK,KAAM1F,EAAS,MAAO,IAAI,MACpC0F,CAAA,EAEAK,EAAUxI,EAAM,cAAcwC,CAAO,EAC3C,GAAIgG,EAAS,CACX,MAAME,EAAmB,CAAE,GAAG1I,EAAM,eACpC,cAAO0I,EAAiBlG,CAAO,EAC/BkG,EAAiBjG,CAAO,EAAI+F,EACrB,CAAE,UAAAN,EAAW,cAAeQ,CAAA,CACrC,CACA,MAAO,CAAE,UAAAR,CAAA,CACX,CAAC,EACH,aAAe/I,GACbJ,EAAKiB,GAAU,CACb,MAAM4I,EAAW5I,EAAM,UAAU,UAC9BmI,GAAQA,EAAI,OAAShJ,CAAA,EAExB,GAAIyJ,IAAa,GAAI,OAAO5I,EAC5B,MAAMkI,EAAYlI,EAAM,UAAU,IAAI,CAACmI,EAAKxG,IAC1CA,IAAMiH,EAAW,CAAE,GAAGT,EAAK,MAAO,IAAI,MAAWA,CAAA,EAEnD,IAAIU,EAAW7I,EAAM,SACrB,OAAK6I,EAAS,SAAS1J,CAAI,IACzB0J,EACEA,EAAS,QAAUhB,GACf,CAAC,GAAGgB,EAAS,MAAM,CAAC,EAAG1J,CAAI,EAC3B,CAAC,GAAG0J,EAAU1J,CAAI,GAEnB,CAAE,UAAA+I,EAAW,SAAAW,EAAU,UAAW1J,CAAA,CAC3C,CAAC,EACH,cAAgBA,GACdJ,EAAKiB,GAAU,CACb,MAAM8I,EAAQ9I,EAAM,SAAS,QAAQb,CAAI,EACzC,GAAI2J,IAAU,GAAI,OAAO9I,EACzB,MAAM6I,EAAW7I,EAAM,SAAS,OAAQ+I,GAAQA,IAAQ5J,CAAI,EAC5D,IAAI6J,EAAYhJ,EAAM,UACtB,OAAIgJ,IAAc7J,IACZ0J,EAAS,OACXG,EAAYF,IAAU,EAAID,EAAS,CAAC,EAAIA,EAASC,EAAQ,CAAC,EAE1DE,EAAY,IAGT,CAAE,SAAAH,EAAU,UAAAG,CAAA,CACrB,CAAC,EACH,aAAe7J,GAASJ,EAAI,CAAE,UAAWI,EAAM,EAC/C,cAAe,CAACA,EAAM8J,IACpBlK,EAAKiB,GAAU,CACb,GAAIA,EAAM,YAAYb,CAAI,IAAM8J,EAAY,OAAOjJ,EACnD,MAAMkJ,EAAc,CAAE,GAAGlJ,EAAM,aAC/B,OAAIiJ,EAAYC,EAAY/J,CAAI,EAAI8J,EAC/B,OAAOC,EAAY/J,CAAI,EACrB,CAAE,YAAA+J,CAAA,CACX,CAAC,EACH,eAAgB,CAAC/J,EAAMgK,EAAUC,EAAUC,IACzCtK,EAAKiB,IACI,CACL,aAAc,CACZ,GAAGA,EAAM,aACT,CAACb,CAAI,EAAG,CAAE,SAAAgK,EAAU,SAAAC,EAAU,QAAAC,CAAA,CAAQ,CACxC,EAEH,EACH,iBAAkB,CAAClK,EAAMmK,IACvBvK,EAAKiB,GAAU,CACb,MAAMuJ,EAAOvJ,EAAM,aAAab,CAAI,EACpC,GAAI,CAACoK,EAAM,OAAOvJ,EAClB,MAAMwJ,EAAO,CAAE,GAAGxJ,EAAM,cACxB,OAAOwJ,EAAKrK,CAAI,EAChB,MAAMsK,EAAMzJ,EAAM,kBAAoB,GAChC0J,EACJJ,GAAYC,EAAK,QACb,CAAC,GAAGE,EAAI,MAAM,IAAU,EAAGF,EAAK,OAAO,EACvCE,EACN,MAAO,CAAE,aAAcD,EAAM,iBAAAE,CAAA,CAC/B,CAAC,IAEL,CACE,KAAM,oBACN,QAAS,EACT,QAAS9I,EAAkB,IAAM1B,EAAU,EAC3C,WAAac,IAAW,CACtB,UAAWA,EAAM,UACjB,SAAUA,EAAM,SAChB,UAAWA,EAAM,UACjB,cAAeA,EAAM,gBAGvB,mBAAoB,IAAOA,GAAU,CACnC,GAAIA,GAAA,MAAAA,EAAO,UACT,UAAWmI,KAAOnI,EAAM,UACtB,UAAWpB,IAAO,CAAC,QAAS,QAAS,OAAO,EACtCuJ,EAAIvJ,CAAG,GAAK,OAAOuJ,EAAIvJ,CAAG,GAAM,WACjCuJ,EAAgCvJ,CAAG,EAAI,IAAI,KAC1CuJ,EAAIvJ,CAAG,GAMnB,EACF,CACF,CACF,ECzRS+K,EAAwB7I,gBAEnC,MAAS,EAME8I,GAAyB,CAAC,CACrC,SAAA5I,CACF,IAAmC,CACjC,MAAMC,EAAWC,SAAiC,IAAI,EACtD,OAAKD,EAAS,UACZA,EAAS,QAAUqH,GAAqBF,IAAoB,SAI3DuB,EAAsB,SAAtB,CAA+B,MAAO1I,EAAS,QAC7C,SAAAD,EACH,CAEJ,EAEa6I,GACXzI,GACM,CACN,MAAM0I,EAAwBxI,aAAWqI,CAAqB,EAE9D,GAAI,CAACG,EACH,MAAM,IAAI,MACR,gEAIJ,OAAOvI,EAASuI,EAAuB1I,CAAQ,CACjD,EAOa2I,GAAuB,IAAqC,CACvE,MAAMD,EAAwBxI,aAAWqI,CAAqB,EAE9D,GAAI,CAACG,EACH,MAAM,IAAI,MACR,mEAIJ,OAAOE,cACJnI,GACCoG,GAAkB6B,EAAsB,WAAW,UAAWjI,CAAO,EACvE,CAACiI,CAAqB,EAE1B,ECUaG,GAAkB,KACtB,CACL,KAAM,OACN,KAAM,OACN,KAAM,OACN,YAAa,OACb,aAAc,GACd,mBAAoB,OACpB,YAAa,GACb,eAAgB,GAChB,aAAc,EACd,kBAAmB,EACnB,oBAAqB,GACrB,QAAS,OAIAC,GAAsC,CACjD,GAAGD,GAAA,CACL,EAEaE,GAAoB,CAC/BxK,EAAyBuK,KAElBhM,EAAA,EACL0B,EAAUb,IAAS,CACjB,GAAGY,EACH,UAAYyK,GAAiBrL,EAAI,CAAE,GAAGqL,EAAc,EACpD,iBAAkB,IAChBrL,EAAKsL,IAAO,CACV,cAAeA,EAAE,cAAgB,GAAK,EACtC,cAAe,KAAK,KAAI,EACxB,GACJ,GC1GOC,GAAqBxJ,gBAChC,MACF,EAMayJ,GAAsB,CAAC,CAAE,SAAAvJ,KAAyC,CAC7E,MAAMC,EAAWC,SAA8B,IAAI,EACnD,OAAKD,EAAS,UACZA,EAAS,QAAUkJ,GAAkBF,IAAiB,SAIrDK,GAAmB,SAAnB,CAA4B,MAAOrJ,EAAS,QAC1C,SAAAD,EACH,CAEJ,EAEawJ,GAAsBpJ,GAA2C,CAC5E,MAAMqJ,EAAqBnJ,aAAWgJ,EAAkB,EAExD,GAAI,CAACG,EACH,MAAM,IAAI,MAAM,wDAAwD,EAG1E,OAAOlJ,EAASkJ,EAAoBrJ,CAAQ,CAC9C,ECVasJ,GAAkBzI,GAAA,EAC7BpC,EACE,CAACd,EAAKJ,KAAS,CACb,oBAAqB,IACrB,2BAA4B,IAC5B,kBAAmB,GACnB,eAAgB,KAEhB,aAAegF,GAA2B,CACxC5E,EAAKiB,GAAU,CACb,MAAM2K,EAAqB,IAAI,IAAI3K,EAAM,eAAe,EAClD4K,EAAc,IAAI,IAAI5K,EAAM,sBAAsB,EAExD,OAAA2K,EAAmB,IAAIhH,EAAO,IAAI,EAClCiH,EAAY,IAAIjH,EAAO,KAAMA,CAAM,EAE5B,CACL,gBAAiBgH,EACjB,uBAAwBC,CAAA,CAE5B,CAAC,CACH,EAEA,eAAiBC,GAAuB,CACtC9L,EAAKiB,GAAU,CACb,MAAM2K,EAAqB,IAAI,IAAI3K,EAAM,eAAe,EAClD4K,EAAc,IAAI,IAAI5K,EAAM,sBAAsB,EAExD,OAAA2K,EAAmB,OAAOE,CAAU,EACpCD,EAAY,OAAOC,CAAU,EAEtB,CACL,gBAAiBF,EACjB,uBAAwBC,CAAA,CAE5B,CAAC,CACH,EAEA,aAAejH,GAA2B,CACrBhF,EAAA,EAAM,iBAAiBgF,EAAO,IAAI,EAEnDhF,IAAM,eAAegF,EAAO,IAAI,EAEhChF,EAAA,EAAM,aAAagF,CAAM,EAG3BhF,EAAA,EAAM,6BAA6B,MAAM,QAAQ,KAAK,CACxD,EAEA,gBAAiB,IAAM,CACrBI,EAAI,CACF,oBAAqB,IACrB,2BAA4B,GAA4B,CACzD,EAEDJ,EAAA,EAAM,6BAA6B,MAAM,QAAQ,KAAK,CACxD,EAEA,iBAAmBkM,GACVlM,EAAA,EAAM,gBAAgB,IAAIkM,CAAU,EAG7C,uBAAwB,IACf,MAAM,KAAKlM,EAAA,EAAM,uBAAuB,QAAQ,EAGzD,uBAAwB,IACf,MAAM,KAAKA,EAAA,EAAM,eAAe,EAGzC,2BAA4B,MAAOmM,EAAWC,IAAY,CACxDhM,EAAI,CAAE,kBAAmB,GAAM,eAAgB,KAAM,EAErD,GAAI,CAEF,MAAMiM,EAAsB,MAAM,KAAKrM,EAAA,EAAM,eAAe,EAGtD,CAAE,OAAAsM,CAAA,EAAW,MAAAC,EAAA,uBAAAD,GAAA,KAAM,QAAO,6BAAsB,gBAAAA,CAAA,2BAChD,CAAE,wBAAAE,CAAA,EAA4B,MAAAD,EAAA,wCAAAC,GAAA,KAAM,QACxC,qBACF,OAAAC,KAAA,kCAAAD,CAAA,uCAGME,EAAS,MAAMJ,EAAO,OAKtB,CAAE,2BAAA3H,EAA4B,uBAAAtB,GAClC,MAAAkJ,EAAA,2CAAA5H,EAAA,uBAAAtB,CAAA,QAAM,+BAAgC,kCAAAsB,EAAA,uBAAAtB,CAAA,WAQxC,GAAI,CAPY,MAAMmJ,EACpBE,EACAL,EACA,OACA1H,EAA2BtB,EAAuB,UAAU,GAI5D,MAAM,IAAI,MAAM,0BAA0B,EAI5C,OAAAjD,EAAI,CAAE,kBAAmB,GAAO,eAAgB,KAAM,EAElD+L,GACFA,EAAA,EAGK,EACT,OAASnE,EAAO,CACd,MAAM2E,EACJ3E,aAAiB,MACbA,EAAM,QACN,iCAEN,OAAA5H,EAAI,CACF,kBAAmB,GACnB,eAAgBuM,CAAA,CACjB,EAEGP,GACFA,EAAQO,CAAY,EAGtB,QAAQ,MAAM,2CAA4C3E,CAAK,EACxD,EACT,CACF,IAEF,CACE,KAAM,uBAEN,QAAS,CACP,QAAUxH,GAAS,CACjB,MAAMoM,EAAM,aAAa,QAAQpM,CAAI,EACrC,GAAI,CAACoM,EAAK,OAAO,KAEjB,KAAM,CAAE,MAAAvL,CAAA,EAAU,KAAK,MAAMuL,CAAG,EAChC,MAAO,CACL,MAAO,CACL,GAAGvL,EACH,gBAAiB,IAAI,IAAIA,EAAM,iBAAmB,EAAE,EACpD,uBAAwB,IAAI,IAC1BA,EAAM,wBAA0B,EAAC,CACnC,CACF,CAEJ,EACA,QAAS,CAACb,EAAMH,IAAU,CACxB,KAAM,CAAE,MAAAgB,GAAUhB,EACZwM,EAAa,KAAK,UAAU,CAChC,MAAO,CACL,GAAGxL,EACH,gBAAiB,MAAM,KAAKA,EAAM,eAAe,EACjD,uBAAwB,MAAM,KAC5BA,EAAM,uBAAuB,SAAQ,CACvC,CACF,CACD,EACD,aAAa,QAAQb,EAAMqM,CAAU,CACvC,EACA,WAAarM,GAAS,aAAa,WAAWA,CAAI,EACpD,CACF,CAEJ,ECvLA,SAASsM,GACPC,EACAC,EACAC,EACQ,CACR,MAAO;AAAA,gBACOD,CAAa,KAAKC,CAAS,YAAYF,CAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA,4BAUxCE,CAAS;;AAAA,wDAEmBA,CAAS;;AAAA;AAAA;AAAA,2BAItCD,CAAa;AAAA,yDACiBC,CAAS;;AAAA;AAAA,2BAGvCD,CAAa;AAAA;AAAA,iEAEyBC,CAAS;;AAAA,yDAEjBD,CAAa;AAAA,oDAClBC,CAAS;;AAAA;AAAA,2BAGlCD,CAAa;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA,2BASbA,CAAa;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,2BAObA,CAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAaxBA,CAAa,KAAKC,CAAS,YAAYF,CAAa;AAAA,CAEpE,CAEA,MAAMG,EAAWJ,GACf,8BACA,sBACA,iBACF,EACMK,EAAWL,GACf,8BACA,0BACA,iBACF,EAEA,SAASM,EAAS5M,EAAc6M,EAAoC,CAClE,OAAO,KAAK,UACV,CACE,KAAA7M,EACA,QAAS,mBACT,MAAO,aACP,QAAS,CACP,IAAK,CAAE,MAAO,gBACd,GAAI6M,EACA,CAAE,WAAY,CAAE,MAAO,sBAAsB,EAC7C,EAAC,CACP,EAEF,KACA,EAEJ,CAMO,MAAMC,GAAsD,CACjE,sDAAuDF,EACrD,4BACA,IAEF,oDAAqDF,EACrD,2DAA4DA,EAC5D,yDAA0DE,EACxD,+BACA,IAEF,uDAAwDF,EACxD,sDAAuDE,EACrD,4BACA,IAEF,oDAAqDD,EACrD,2DAA4DA,EAC5D,yDAA0DC,EACxD,+BACA,IAEF,uDAAwDD,CAC1D,ECzHA,IAAII,EAAmC,KAEhC,SAASC,GAAuBd,EAA+B,CACpE,OAAKa,IACHA,EAAaE,GAAUf,CAAM,EAC1B,KAAKgB,EAAS,EACd,MAAO1F,GAAU,CAChB,MAAAuF,EAAa,KACPvF,CACR,CAAC,GAEEuF,CACT,CAEA,eAAeE,GAAUf,EAA+B,CACtD,MAAMiB,EAAKjB,EAAO,UAAU,WAC5BiB,EAAG,mBAAmB,mBAAmB,CACvC,OAAQA,EAAG,aAAa,OACxB,OAAQA,EAAG,WAAW,SAEtB,iBAAkB,IAClB,IAAK,CAAC,SAAU,KAAK,EACrB,OAAQ,GACR,gBAAiB,GACjB,6BAA8B,GAC9B,qBAAsB,GACtB,aAAc,GACd,cAAe,GACf,kBAAmB,GACnB,UAAW,GACX,MAAO,EAAC,CACT,EAIDA,EAAG,mBAAmB,sBAAsB,CAC1C,qBAAsB,GACtB,mBAAoB,GACpB,wBAAyB,GAC1B,EACDA,EAAG,mBAAmB,kBAAkB,EAAI,EAG5C,MAAMC,EAAgC,CAAE,IAD1B,MAAArB,EAAA,wBAAAsB,CAAA,OAAM,QAAO,6CAA8B,iBAAAA,CAAA,QAAG,QACX,GAAGP,EAAA,EACpD,SAAW,CAACQ,EAAM1M,CAAO,IAAK,OAAO,QAAQwM,CAAK,EAChDD,EAAG,mBAAmB,YAAYvM,EAAS,WAAW0M,CAAI,EAAE,EAE9DH,EAAG,mBAAmB,sBAAsB,CAC1C,qBAAsB,GACtB,mBAAoB,GACpB,wBAAyB,GAC1B,CACH,CAGO,SAASI,IAAiC,CAC/C,OAAOC,EACT,CAEA,IAAIA,GAAQ,GACZ,MAAMC,MAAqB,IAGpB,SAASC,GAAwBC,EAAkC,CACxE,OAAIH,IACFG,EAAA,EACO,IAAM,CAAC,IAEhBF,EAAe,IAAIE,CAAQ,EACpB,IAAM,CACXF,EAAe,OAAOE,CAAQ,CAChC,EACF,CAEA,SAAST,IAAkB,CACzBM,GAAQ,GACR,UAAWG,KAAYF,EAAgBE,EAAA,EACvCF,EAAe,OACjB,CCjEA,MAAMG,GAAoB,mBAGnB,SAASC,GAAgBnL,EAAyB,CACvD,MAAO,GAAGkL,EAAiB,GAAG,mBAAmBlL,CAAO,CAAC,EAC3D,CAEA,SAASoL,GACP5B,EACA6B,EACS,CACT,OAAO7B,EAAO,OAAO,aAAa,KAAM3N,GAAMA,EAAE,aAAewP,CAAK,CACtE,CAUA,SAASC,GAAe1L,EAA+C,CACrE,GAAI,OAAOA,GAAS,SAAU,OAAOA,EACrC,MAAM2L,EAAkB,CAAC3L,EAAK,WAAW,EACnC4L,EAAQ,MAAM,QAAQ5L,EAAK,IAAI,EAAI,CAAC,GAAGA,EAAK,IAAI,EAAI,GAC1D,KAAO4L,EAAM,OAAS,GAAG,CACvB,MAAM7D,EAAO6D,EAAM,QACd7D,IACD,OAAOA,GAAS,SAAU4D,EAAM,KAAK5D,CAAI,GAE3C4D,EAAM,KAAK5D,EAAK,WAAW,EACvB,MAAM,QAAQA,EAAK,IAAI,GAAG6D,EAAM,KAAK,GAAG7D,EAAK,IAAI,GAEzD,CACA,OAAO4D,EAAM,KAAK,GAAG,CACvB,CAEA,SAASE,GACPC,EACAL,EACkB,CAQlB,MAAMnI,EAA2B,CAC/B,SANAwI,EAAW,WAAa,EACpB,QACAA,EAAW,WAAa,EACtB,UACA,OAGN,QAAS,GAAGJ,GAAeI,EAAW,WAAW,CAAC,OAAOA,EAAW,IAAI,IACxE,OAAQ,cAEV,GAAI,OAAOA,EAAW,OAAU,SAAU,CACxC,MAAMC,EAAQN,EAAM,cAAcK,EAAW,KAAK,EAC5CE,EAAMP,EAAM,cAChBK,EAAW,OAASA,EAAW,QAAU,IAE3CxI,EAAO,KAAOyI,EAAM,WACpBzI,EAAO,OAASyI,EAAM,OACtBzI,EAAO,QAAU0I,EAAI,WACrB1I,EAAO,UAAY0I,EAAI,MACzB,CACA,OAAO1I,CACT,CAEA,eAAsB2I,GACpB7L,EACA8L,EACAC,EACwB,OACxB,MAAMvC,EAAS,MAAMJ,EAAO,OAC5B,MAAMkB,GAAuBd,CAAM,EAEnC,MAAMwC,EAAMxC,EAAO,IAAI,MAAM2B,GAAgBnL,CAAO,CAAC,EACrD,IAAIqL,EAAQ7B,EAAO,OAAO,SAASwC,CAAG,EACjCX,EAGHA,EAAM,aAAeS,GACrB,CAACV,GAAmB5B,EAAQ6B,CAAK,GAEjCA,EAAM,SAASS,CAAM,EALrBT,EAAQ7B,EAAO,OAAO,YAAYsC,EAAQ,aAAcE,CAAG,EAO7D,MAAMpM,EAAOyL,EAAM,WAKnB,GAAIU,IAAe,QAAapM,EAAWC,CAAI,IAAMmM,EACnD,MAAO,CAAE,OAAQnM,EAAM,GAAI,KAAM,YAAa,GAAI,QAAS,IAI7D,MAAMqM,EAAS,MADG,MAAMzC,EAAO,UAAU,WAAW,uBACrBwC,CAAG,EAC5BE,EAAWF,EAAI,WACf,CAACG,EAAWC,EAAUC,CAAI,EAAI,MAAM,QAAQ,IAAI,CACpDJ,EAAO,wBAAwBC,CAAQ,EACvCD,EAAO,uBAAuBC,CAAQ,EACtCD,EAAO,cAAcC,CAAQ,EAC9B,EAEKI,EAAc,CAClB,GAAIH,EACJ,GAAIC,CAAA,EAEH,IAAKnK,GAAMwJ,GAAaxJ,EAAGoJ,CAAM,CAAC,EAClC,OAAQpJ,GAAMA,EAAE,WAAa,MAAM,EAChCsK,EAAYD,EAAY,KAAMrK,GAAMA,EAAE,WAAa,OAAO,EAC1DuK,IACJ3K,EAAAwK,EAAK,YAAY,KAAMI,GAASA,EAAK,KAAK,SAAS,KAAK,CAAC,IAAzD,YAAA5K,EAA4D,OAAQ,KAEtE,MAAO,CACL,OAAQjC,EACR,GAAI2M,EAAY,KAAOC,EACvB,YAAAF,EACA,QAAS,GAEb,CAGO,SAASI,GAAmB1M,EAAuB,CACxD,MAAMwJ,EAASJ,EAAO,sBACtB,GAAI,CAACI,EAAQ,OACb,MAAM6B,EAAQ7B,EAAO,OAAO,SAC1BA,EAAO,IAAI,MAAM2B,GAAgBnL,CAAO,CAAC,GAEvCqL,GAAS,CAACD,GAAmB5B,EAAQ6B,CAAK,KAAS,SACzD,CCjJA,MAAMsB,GAAqB,SAAY,CAAC,EAEjC,MAAMC,EAAa,CAAnB,cACG9Q,EAAA,cAAiB6Q,IACjB7Q,EAAA,kBAAa,KACbA,EAAA,oBAAe,KACfA,EAAA,kBAAa,KACbA,EAAA,mBAAiC,IAEzC,UAAU+Q,EAAsB,CAC9B,KAAK,OAASA,CAChB,CAGA,SAAS7M,EAAiB8M,EAAuB,CAC/C,KAAK,OAAO9M,CAAO,EACnB,KAAK,OAAO,IACVA,EACA,WAAW,IAAM,CACf,KAAK,OAAO,OAAOA,CAAO,EAC1B,KAAK,IAAIA,CAAO,CAClB,EAAG8M,CAAO,EAEd,CAGA,OAAO9M,EAAuB,CAC5B,MAAM6F,EAAQ,KAAK,OAAO,IAAI7F,CAAO,EACjC6F,gBAAoBA,CAAK,EAC7B,KAAK,OAAO,OAAO7F,CAAO,CAC5B,CAGA,IAAIA,EAAgC,CAClC,KAAK,OAAOA,CAAO,EACnB,MAAM+M,EAAU,KAAK,SAAS,IAAI/M,CAAO,EACzC,GAAI+M,EACF,YAAK,OAAO,IAAI/M,CAAO,EAChB+M,EAAQ,KACb,IAAM,KAAK,SAAS,IAAI/M,CAAO,GAAK,QAAQ,SAAQ,EAGxD,MAAMgN,EAAO,KAAK,OAAOhN,CAAO,EAC7B,MAAM,IAAM,CAAC,CAAC,EACd,QAAQ,IAAM,CACb,KAAK,SAAS,OAAOA,CAAO,EACxB,KAAK,OAAO,OAAOA,CAAO,EAC5B,KAAK,IAAIA,CAAO,EAEhB,KAAK,cAET,CAAC,EACH,YAAK,SAAS,IAAIA,EAASgN,CAAI,EACxBA,CACT,CAGA,OAAc,CACZ,UAAWhN,KAAW,MAAM,KAAK,KAAK,OAAO,MAAM,EAAG,KAAK,IAAIA,CAAO,CACxE,CAEA,IAAI,QAAkB,CACpB,OAAO,KAAK,OAAO,OAAS,GAAK,KAAK,SAAS,OAAS,CAC1D,CAGA,SAASwF,EAAY,KAAuB,CAC1C,OAAI,KAAK,OAAe,QAAQ,UACzB,IAAI,QAASrJ,GAAY,CAC9B,MAAM0J,EAAQ,WAAWoH,EAAMzH,CAAS,EACxC,SAASyH,GAAO,CACd,aAAapH,CAAK,EAClB1J,EAAA,CACF,CACA,KAAK,YAAY,KAAK8Q,CAAI,CAC5B,CAAC,CACH,CAGA,OAAc,CACZ,UAAWpH,KAAS,KAAK,OAAO,sBAAuBA,CAAK,EAC5D,KAAK,OAAO,QACZ,KAAK,OAAO,QACZ,KAAK,OAAS8G,GACd,KAAK,cACP,CAEQ,cAAqB,CAC3B,GAAI,CAAC,KAAK,OAAQ,OAClB,MAAMO,EAAU,KAAK,YACrB,KAAK,YAAc,GACnB,UAAWC,KAAUD,EAASC,EAAA,CAChC,CACF,CAEO,MAAMC,EAAe,IAAIR,GC/FzB,SAASS,GAAsBvB,EAAiC,OACrE,MAAMwB,EAA4B,GAC5BC,EAAahL,GACjBA,GAAS,OAAOA,GAAU,UAAY,UAAWA,EAC5CA,EAA6B,MAC9BA,EAEAiL,EACJ,iGACF,IAAIC,EACJ,MAAQA,EAAQD,EAAO,KAAK1B,CAAM,KAAO,MAAM,CAC7C,MAAM4B,IAAQ7L,EAAA4L,EAAM,CAAC,IAAP,YAAA5L,EAAU,SAAU,OAC5B8L,EAAQF,EAAM,CAAC,EAClB,MAAM;AAAA,CAAI,EACV,IAAKxK,GAASA,EAAK,QAAQ,YAAa,EAAE,CAAC,EAC3C,KAAK;AAAA,CAAI,EACT,OACG2K,EAAOD,EAAM,MAAM,aAAa,EACtC,GAAKC,EACL,GAAI,CACFN,EAAS,KAAK,CAAE,MAAAI,EAAO,MAAOH,EAAU,KAAK,MAAMK,EAAK,CAAC,CAAC,CAAC,EAAG,CAChE,MAAQ,CAGN,MAAMC,EAAaF,EAAM,MAAM,uBAAuB,EACtD,GAAI,CAACE,EAAY,SACjB,GAAI,CACF,MAAMC,EAAUD,EAAW,CAAC,EACzB,QAAQ,YAAa,EAAE,EACvB,QAAQ,kCAAmC,OAAO,EAClD,QAAQ,KAAM,GAAG,EACjB,QAAQ,eAAgB,IAAI,EAC5B,QAAQ,QAAS,EAAE,EACtBP,EAAS,KAAK,CAAE,MAAAI,EAAO,MAAO,KAAK,MAAMI,CAAO,EAAG,CACrD,MAAQ,CAAC,CACX,CACF,CAEA,MAAMC,EAAS,+BACf,MAAQN,EAAQM,EAAO,KAAKjC,CAAM,KAAO,MACvC,GAAI,CACFwB,EAAS,KAAK,CAAE,MAAOC,EAAU,KAAK,MAAME,EAAM,CAAC,CAAC,CAAC,EAAG,CAC1D,MAAQ,CAAC,CAGX,OAAOH,CACT,CChDO,SAASU,GAAuBC,EAAmC,CACxE,MAAMC,EACJD,IAAW,OACPE,GACAC,GACN,OAAO,IAAI,IAAIF,EAAS,IAAKG,GAAcA,EAAU,IAAI,CAAC,CAC5D,CAGO,MAAMC,GAAsB,2BC+DtBC,GAAqB,uBC3C5BC,GAAsB,IAEtBC,GAAc,gCAGPC,GAAgC,0BAE7C,SAASC,EAAe3O,EAAuB,CAC7C,OAAO,cACL,IAAI,YAAY0O,GAA+B,CAAE,OAAQ,CAAE,QAAA1O,CAAA,EAAW,EAE1E,CAEA,SAAS4O,GAAmB5K,EAAmC,CAC7D,MAAO,CACL,SAAU,QACV,OAAQ,aACR,KAAM,gBACN,QAAAA,CAAA,CAEJ,CAGA,SAAS6K,GAAkB/J,EAAkC,CAC3D,MAAMd,EAAUc,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,EACrE,OAAId,EAAQ,SAASuK,EAAkB,EAC9B,CACL,SAAU,QACV,OAAQ,aACR,KAAM,cACN,QAASvK,EAAQ,QAAQuK,GAAoB,EAAE,EAAE,MAAK,EAGtDzJ,aAAiBP,EACZ,CACL,SAAU,QACV,OAAQ,UACR,KAAM,UACN,QAAS,GAAGP,CAAO,uCAGhB,CAAE,SAAU,QAAS,OAAQ,UAAW,QAAAA,CAAA,CACjD,CAEO,SAAS8K,GACdC,EACM,CACN,MAAMC,EAAiBvP,aAAWqI,CAAqB,EACvD,GAAI,CAACkH,EACH,MAAM,IAAI,MACR,oEAKJ,MAAMC,EAAe5P,SAA0B0P,CAAe,EAC9DE,EAAa,QAAUF,EAEvBG,YAAU,IAAM,CACd,IAAIC,EAAW,GAGf,MAAMC,EAAe,CACnBpP,EACA2B,IACkB,CAClB,GAAI,CAAC2M,GAAoB,KAAK3M,CAAa,EACzC,MAAO,mBAAmBA,CAAa,4EAEzC,GAAIqM,GAAuBqB,CAAM,EAAE,IAAI1N,CAAa,EAClD,MAAO,IAAIA,CAAa,mBAAmB0N,CAAM,mCAEnD,GAAIJ,EAAa,QAAQ,SAAStN,CAAa,EAC7C,MAAO,IAAIA,CAAa,yFAE1B,MAAMC,EAAQF,GACZvB,EAAuB,WAAW,QAClCwB,CAAA,EAEF,OAAIC,GAASA,IAAU5B,EACd,IAAI2B,CAAa,2BAA2BC,CAAK,wBAEnD,IACT,EAMM0N,EAAqB,IAAY,CACrC,MAAMrS,EAAQkD,EAAuB,WACrC,UAAWY,KAAU,OAAO,OAAO9D,EAAM,OAAO,EAAG,CACjD,GACE,CAAC8D,EAAO,UACRA,EAAO,SAAW,aAClBA,EAAO,SAAW,OAElB,SAEF,MAAMwO,EAASxO,EAAO,YAAY,OAC/B,GAAM,EAAE,OAAS,iBAEdyO,EAAcD,EAAO,SAAWxO,EAAO,YAAY,OACnD0O,EAAWL,EAAarO,EAAO,QAASA,EAAO,SAAS,IAAI,EAC5D2O,EAAcH,EAAO,KAAM,GAAM,EAAE,WAAa,OAAO,EACzDE,GAAY,CAACD,EACfvS,EAAM,OAAO8D,EAAO,QAAS,CAC3B,OAAQ,QACR,YAAa,CAAC,GAAGwO,EAAQX,GAAmBa,CAAQ,CAAC,EACtD,EACQ,CAACA,GAAYD,IACtBvS,EAAM,OAAO8D,EAAO,QAAS,CAC3B,OAAQ2O,GAAe,CAAC3O,EAAO,GAAK,QAAU,QAC9C,YAAawO,CAAA,CACd,EACDZ,EAAe5N,EAAO,OAAO,EAEjC,CACF,EAEM4O,EAAa,MAAO3P,GAAmC,CAC3D,MAAMsG,EAAM0I,EACT,WACA,UAAU,KAAM/M,GAAMA,EAAE,OAASjC,CAAO,EAC3C,GAAI,CAACsG,GAAO6I,EAAU,OACtB,MAAMlS,EAAQkD,EAAuB,WAC/BY,EAAS9D,EAAM,QAAQ+C,CAAO,EAC9BH,EAAOF,EAAW2G,EAAI,IAAI,EAKhC,GAHEvF,GACAA,EAAO,aAAelB,IACrBkB,EAAO,SAAW,SAAWA,EAAO,SAAW,SACrC,OAIb,MAAM6O,EACJ7O,IAAWA,EAAO,SAAW,SAAWA,EAAO,SAAW,SACtDA,EACA,OACN9D,EAAM,OAAO+C,EAAS,CACpB,OAAQ,YACR,WAAYH,EACZ,YAAa,EAAC,CACf,EACD,GAAI,CACF,MAAMgQ,EAAW,MAAMhE,GACrB7L,EACAsG,EAAI,KACJsJ,GAAA,YAAAA,EAAS,YAEX,GAAIT,EAAU,OACd,GAAIU,EAAS,SAAWD,EAAS,CAC/BzP,EAAuB,WAAW,OAAOH,EAAS,CAChD,OAAQ4P,EAAQ,OAChB,WAAYA,EAAQ,WACpB,YAAaA,EAAQ,YACtB,EACD,MACF,CACA,MAAME,EAAYnQ,EAAWkQ,EAAS,MAAM,EAC5C,GAAI,CAACA,EAAS,GAAI,CAChB9J,EAAW,QAAQ/F,CAAO,EAC1BG,EAAuB,WAAW,OAAOH,EAAS,CAChD,OAAQ,QACR,WAAY8P,EACZ,GAAI,OACJ,SAAU,OACV,YAAaD,EAAS,YACvB,EACDlB,EAAe3O,CAAO,EACtB,MACF,CACA,MAAMe,EAASZ,EAAuB,WAAW,QAAQH,CAAO,EAC1D+P,GAAW,MAAMhK,EAAW,KAAK/F,EAAS,CAC9C,GAAI6P,EAAS,GACb,OAAQR,EACR,cAActO,iBAAQ,eAAgB,GACtC,eAAgBA,iBAAQ,eACxB,SAAUsM,GAAsBwC,EAAS,MAAM,EAChD,EACD,GAAIV,EAAU,OAGdhP,EAAuB,WAAW,OAAOH,EAAS,CAChD,OAAQ,QACR,WAAY8P,EACZ,GAAID,EAAS,GACb,SAAAE,GACA,YAAaF,EAAS,YACvB,EACD,MAAMJ,GAAWL,EAAapP,EAAS+P,GAAS,IAAI,EAChDN,IACFtP,EAAuB,WAAW,OAAOH,EAAS,CAChD,OAAQ,QACR,YAAa,CACX,GAAG6P,EAAS,YACZjB,GAAmBa,EAAQ,EAC7B,CACD,EAEHH,EAAA,EACAX,EAAe3O,CAAO,CACxB,OAAS8E,EAAO,CACd,GAAIqK,EAAU,OACdpJ,EAAW,QAAQ/F,CAAO,EAC1BG,EAAuB,WAAW,OAAOH,EAAS,CAChD,OAAQ,QACR,WAAYH,EACZ,GAAI,OACJ,SAAU,OACV,YAAa,CAACgP,GAAkB/J,CAAK,CAAC,EACvC,EACDwK,EAAA,EACAX,EAAe3O,CAAO,CACxB,CACF,EAEMgQ,EAAY,IAAY,CAC5B,KAAM,CAAE,UAAA3J,EAAW,cAAA4J,GAAkBjB,EAAe,WAC9CkB,EAAa7J,EAAU,OAC1B,GAAM4J,EAAc,EAAE,IAAI,IAAMxB,EAAA,EAE7B0B,EAAU,IAAI,IAAID,EAAW,IAAK,GAAM,EAAE,IAAI,CAAC,EAC/CE,EAAejQ,EAAuB,WAC5C,IAAIkQ,EAAU,GACd,UAAW/S,KAAQ,OAAO,KAAK8S,EAAa,OAAO,EAC5CD,EAAQ,IAAI7S,CAAI,IACnB8S,EAAa,OAAO9S,CAAI,EACxByI,EAAW,QAAQzI,CAAI,EACvBoP,GAAmBpP,CAAI,EACvB8P,EAAa,OAAO9P,CAAI,EACxB+S,EAAU,IAGVA,GAASf,EAAA,EACb,UAAWhJ,KAAO4J,EAAY,CAC5B,MAAMnP,EAASqP,EAAa,QAAQ9J,EAAI,IAAI,GAE1C,CAACvF,GACDA,EAAO,aAAepB,EAAW2G,EAAI,IAAI,GACzCvF,EAAO,SAAW,QAClBA,EAAO,SAAW,cACTqM,EAAa,SAAS9G,EAAI,KAAMkI,EAAmB,CAChE,CACF,EAEApB,EAAa,UAAUuC,CAAU,EACjC,IAAIW,EAGJ,OAAAtP,GAAA,EAA6B,KAAK,IAAM,CAClCmO,IACJa,EAAA,EACAM,EAActB,EAAe,UAAU,CAAC7Q,EAAOsC,IAAa,EAExDtC,EAAM,YAAcsC,EAAS,WAC7BtC,EAAM,gBAAkBsC,EAAS,gBAEjCuP,EAAA,CAEJ,CAAC,EACH,CAAC,EAEM,IAAM,CACXb,EAAW,GACXmB,GAAA,MAAAA,IACAlD,EAAa,OACf,CACF,EAAG,CAAC4B,CAAc,CAAC,CACrB,CCxSO,MAAMuB,GAAoB,KACxB,CACL,yBAA0B,IAE1B,uBAAwB,GAIxB,YAAa,OAKb,mBAAoB,YAIXC,GAA0C,CACrD,GAAGD,GAAA,CACL,EAEaE,GAAsB,CACjC3S,EAA2B0S,KAEpBnU,EAAA,EACL0B,EACEC,EACGd,IAAS,CACR,GAAGY,EACH,YAAc4S,GAAaxT,EAAI,CAAE,GAAGwT,EAAU,IAEhD,CACE,KAAM,mBAER,CACF,CACF,ECtCSC,GAAuB1R,gBAClC,MACF,EAMa2R,GAAwB,CAAC,CACpC,SAAAzR,CACF,IAAkC,CAChC,MAAMC,EAAWC,SAAgC,IAAI,EACrD,OAAKD,EAAS,UACZA,EAAS,QAAUqR,GAAoBF,IAAmB,SAIzDI,GAAqB,SAArB,CAA8B,MAAOvR,EAAS,QAC5C,SAAAD,EACH,CAEJ,EAEa0R,GACXtR,GACM,CACN,MAAMuR,EAAuBrR,aAAWkR,EAAoB,EAE5D,GAAI,CAACG,EACH,MAAM,IAAI,MACR,8DAIJ,OAAOpR,EAASoR,EAAsBvR,CAAQ,CAChD,ECxCO,SAASwR,GAAuB,CACrC,gBAAAhC,EACA,SAAA5P,CACF,EAGG,CACD,OAAA2P,GAAsBC,CAAe,oBAC3B,SAAA5P,EAAS,CACrB,CCFA,MAAM6R,GAAuB,GACvBC,GAAY,IAAM,IAAM,CAAC,EAS/B,SAASC,IAAgC,CACvC,MAAMjU,EAAQwC,aAAWT,CAAkB,EACrCmS,EAAY9R,SAAiB2R,EAAU,EAEvCI,EAAcnU,EAChB,IAAM,CACJ,MAAM0K,EAAO1K,EAAM,WAAW,mBAE9B,OACE0K,EAAK,SAAWwJ,EAAU,QAAQ,QAClCxJ,EAAK,KAAK,CAAC4B,EAAGzJ,IAAMyJ,IAAM4H,EAAU,QAAQrR,CAAC,CAAC,KAE9CqR,EAAU,QAAUxJ,GAEfwJ,EAAU,OACnB,EACA,IAAMH,GAEV,OAAOK,uBAAqBpU,EAAQA,EAAM,UAAYgU,GAAWG,CAAW,CAC9E,CAOO,SAASE,IAAmB,CACjC,MAAMC,EAAYlS,SAAsB,IAAI,EACtCmS,EAAkB3I,GAAiB1K,GAAUA,EAAM,eAAe,EAClEgL,EAAsB,MAAM,KAAKqI,CAAe,EAChDC,EAAmBP,GAAA,EAGnBQ,EAAmBvR,EAAuBoB,CAAsB,EAChEoQ,EAAclS,aAAWT,CAAkB,EAC3C4S,EAAiBvS,SAAOsS,CAAW,EACzCC,EAAe,QAAUD,EACzB,MAAME,EAAqBxS,SAAiB,EAAE,EACxCyS,EAAoBzS,SAAiB,EAAE,EACvC0S,EAAqB1S,SAAe,EAAE,EAE5C6P,mBAAU,IAAM,CACd9F,EACG,OACA,KAAMI,GAAW,OAChB+H,EAAU,QAAU/H,EAGpB,MAAMwI,EAAiB,MAAM,KAC3BnJ,GAAgB,WAAW,iBAEvBoJ,IACJpQ,EAAA+P,EAAe,UAAf,YAAA/P,EAAwB,WAAW,qBAAsB,GACrDqQ,EAAe/R,EAAuB,WAC5CmJ,GACEE,EACAwI,EACAC,EACAxQ,EAA2ByQ,CAAY,GAEtC,KAAMC,GAAY,CACbA,EACF,QAAQ,IACN,sDACAH,CAAA,EAGF,QAAQ,KACN,mEAGN,CAAC,EACA,MAAOlN,GAAU,CAChB,QAAQ,MACN,2DACAA,CAAA,CAEJ,CAAC,EACH+M,EAAmB,QAAU,CAAC,GAAGG,CAAc,EAC/CF,EAAkB,QAAU,CAAC,GAAGG,CAAa,EAC7CF,EAAmB,QAAUxQ,EAAuB2Q,CAAY,CAClE,CAAC,EACA,MAAOpN,GAAU,CAChB,QAAQ,MAAM,+BAAgCA,CAAK,CACrD,CAAC,CACL,EAAG,EAAE,EAELoK,YAAU,IAAM,CACd,MAAMkD,EACJjJ,EAAoB,SAAW0I,EAAmB,QAAQ,QAC1D1I,EAAoB,KAClB,CAAC7L,EAAM2J,IAAU3J,IAASuU,EAAmB,QAAQ5K,CAAK,GAGxDoL,EACJZ,EAAiB,SAAWK,EAAkB,QAAQ,QACtDL,EAAiB,KACf,CAACnU,EAAM2J,IAAU3J,IAASwU,EAAkB,QAAQ7K,CAAK,GAGvDqL,EAAiBZ,IAAqBK,EAAmB,QAE3D,CAACK,GAAkB,CAACC,GAAiB,CAACC,GAItCf,EAAU,UACZjI,GACEiI,EAAU,QACVpI,EACAsI,EACAhQ,EAA2BtB,EAAuB,UAAU,GAC5D,MAAO2E,GAAU,CACjB,QAAQ,MACN,sDACAA,CAAA,CAEJ,CAAC,EACD+M,EAAmB,QAAU,CAAC,GAAG1I,CAAmB,EACpD2I,EAAkB,QAAU,CAAC,GAAGL,CAAgB,EAChDM,EAAmB,QAAUL,EAEjC,EAAG,CAACvI,EAAqBsI,EAAkBC,CAAgB,CAAC,EAErD,CACL,OAAQH,EAAU,QAClB,gBAAiBpI,CAAA,CAErB,CChJO,SAASoJ,GAAqB,CACnC,SAAApT,CACF,EAEG,CAED,OAAAmS,GAAA,oBAEU,SAAAnS,EAAS,CACrB","names":["validateThemeJson","jsonString","parsed","getThemeName","themeJson","_ThemeChangeEmitter","event","callback","handler","e","__publicField","ThemeChangeEmitter","themeChangeEmitter","promisifyRequest","request","resolve","reject","createStore","dbName","storeName","dbp","getDB","db","txMode","defaultGetStoreFunc","defaultGetStore","get","key","customStore","store","set","value","del","idbStorage","name","validThemesByName","customThemes","out","theme","initThemesStore","defaultInitThemesState","createThemesStore","initState","devtools","persist","documentName","content","state","validation","themeName","parsedContent","extractedName","existingTheme","isUpdate","hasContentChanged","customTheme","removedTheme","newCustomThemes","names","createJSONStorage","ThemesStoreContext","createContext","ThemesStoreProvider","children","storeRef","useRef","useThemesStore","selector","themesStoreContext","useContext","useStore","hashSource","text","hash","i","createBrowserPluginRecord","docName","patch","now","useBrowserPluginsStore","create","existing","enabled","allowNetwork","networkOrigins","previous","origin","oldName","newName","records","persisted","record","whenBrowserPluginsHydrated","api","stop","selectActivePlugins","active","a","b","activePluginsSignature","components","browserComponentsForSchema","componentNameOwner","componentName","owner","_a","plugin","v","recordErrors","d","NOTHING","HOST","isLoopback","host","normalizeNetworkOrigin","input","trimmed","withScheme","wildcard","parseable","url","protocol","parseNetworkOrigins","origins","errors","line","result","connectSrcValue","safe","nonce","bytes","sandboxDocument","scriptNonce","SandboxFrame","options","iframe","resolveReady","rejectReady","readyTimer","data","message","framePolicy","spec","samePolicy","LOAD_TIMEOUT_MS","RENDER_TIMEOUT_MS","IDLE_TIMEOUT_MS","PluginTimeoutError","what","ms","PluginAbortedError","runtimePromise","loadRuntime","module","error","sameSpec","PluginHost","policy","runtime","raced","entry","response","pending","payload","timeoutMs","signal","id","onAbort","detach","timer","reason","pluginHost","MAX_OPEN_TABS","PLUGIN_FILE_SUFFIX","isPluginDocumentName","pluginDocumentName","resolveSourceName","documents","doc","initDocumentsStore","defaultInitDocumentsState","createDocumentsStore","opts","docType","newDoc","newDocumentTypes","k","docIndex","openTabs","index","tab","activeTab","buildError","buildErrors","original","modified","applyId","accepted","diff","next","ids","acceptedApplyIds","DocumentsStoreContext","DocumentsStoreProvider","useDocumentsStore","documentsStoreContext","useResolveSourceName","useCallback","initOutputStore","defaultInitOutputState","createOutputStore","partialState","s","OutputStoreContext","OutputStoreProvider","useOutputStore","outputStoreContext","usePluginsStore","newSelectedPlugins","newMetadata","pluginName","onSuccess","onError","selectedPluginNames","loader","__vitePreload","updateMonacoWithPlugins","n","monaco","errorMessage","str","serialized","pluginApiDeclaration","sharedPackage","componentType","themeType","DOCX_API","PPTX_API","manifest","withPluginSubpath","PLUGIN_TYPE_SHIMS","configured","ensurePluginTypeScript","configure","markReady","ts","files","__vite_default__","path","pluginTypeScriptReady","ready","readyListeners","onPluginTypeScriptReady","listener","MODEL_SCHEME_PATH","pluginModelPath","isAttachedToEditor","model","flattenMessage","parts","queue","toDiagnostic","diagnostic","start","end","compilePlugin","source","skipIfHash","uri","client","fileName","syntactic","semantic","emit","diagnostics","hasErrors","js","file","disposePluginModel","noopRunner","CompileQueue","runner","delayMs","running","task","done","waiters","waiter","compileQueue","extractPluginExamples","examples","normalize","fenced","match","title","block","json","propsMatch","cleaned","inline","standardComponentNames","format","registry","STANDARD_COMPONENTS_REGISTRY","PPTX_STANDARD_COMPONENTS_REGISTRY","component","PLUGIN_NAME_PATTERN","NETWORK_OFF_MARKER","COMPILE_DEBOUNCE_MS","PLUGIN_TYPE","BROWSER_PLUGINS_CHANGED_EVENT","announceChange","conflictDiagnostic","sandboxDiagnostic","useBrowserPluginsSync","diskPluginNames","documentsStore","diskNamesRef","useEffect","disposed","nameConflict","FORMAT","reconcileConflicts","others","hadConflict","conflict","otherErrors","compileNow","settled","compiled","finalHash","metadata","reconcile","documentTypes","pluginDocs","present","pluginsStore","removed","unsubscribe","initSettingsStore","defaultInitSettingsState","createSettingsStore","settings","SettingsStoreContext","SettingsStoreProvider","useSettingsStore","settingsStoreContext","BrowserPluginsProvider","emptyNames","subscribe","useCustomThemeNames","cachedRef","getSnapshot","useSyncExternalStore","useMonacoPlugins","monacoRef","selectedPlugins","customThemeNames","browserSignature","themesStore","themesStoreRef","previousPluginsRef","previousThemesRef","previousBrowserRef","currentPlugins","currentThemes","browserState","success","pluginsChanged","themesChanged","browserChanged","MonacoPluginProvider"],"ignoreList":[2],"sources":["../../../src/client/lib/theme-validation.ts","../../../src/client/utils/theme-change-emitter.ts","../../../../../node_modules/.pnpm/idb-keyval@6.2.2/node_modules/idb-keyval/dist/index.js","../../../src/client/lib/idb-storage.ts","../../../src/client/store/themes-store.ts","../../../src/client/store/themes-store-provider.tsx","../../../src/client/lib/plugins/hash.ts","../../../src/client/store/browser-plugins-store.ts","../../../src/client/lib/plugins/network-policy.ts","../../../src/client/lib/plugins/sandbox-frame.ts","../../../src/client/lib/plugins/host.ts","../../../src/client/store/documents-store.ts","../../../src/client/store/documents-store-provider.tsx","../../../src/client/store/output-store.ts","../../../src/client/store/output-store-provider.tsx","../../../src/client/store/plugins-store.ts","../../../src/client/lib/plugins/type-shims.ts","../../../src/client/lib/plugins/type-libs.ts","../../../src/client/lib/plugins/compiler.ts","../../../src/client/lib/plugins/compile-queue.ts","../../../src/client/lib/plugins/examples.ts","../../../src/client/lib/plugins/names.ts","../../../src/client/lib/plugins/types.ts","../../../src/client/hooks/useBrowserPluginsSync.ts","../../../src/client/store/settings-store.ts","../../../src/client/store/settings-store-provider.tsx","../../../src/client/components/BrowserPluginsProvider.tsx","../../../src/client/hooks/useMonacoPlugins.ts","../../../src/client/components/MonacoPluginProvider.tsx"],"sourcesContent":["export interface ThemeValidationError {\n message: string;\n line?: number;\n column?: number;\n path?: string;\n}\n\nexport interface ThemeValidationResult {\n valid: boolean;\n errors?: ThemeValidationError[];\n}\n\n/**\n * Basic structural validation for theme JSON (used by themes store).\n * Full schema validation is handled by Monaco's JSON language service.\n */\nexport function validateThemeJson(jsonString: string): ThemeValidationResult {\n try {\n const parsed = JSON.parse(jsonString);\n\n if (!parsed || typeof parsed !== 'object') {\n return {\n valid: false,\n errors: [{ message: 'Theme must be a JSON object' }],\n };\n }\n\n if (typeof parsed.name !== 'string' || !parsed.name.trim()) {\n return {\n valid: false,\n errors: [{ message: 'Theme must have a non-empty \"name\" property' }],\n };\n }\n\n return { valid: true };\n } catch (e) {\n return {\n valid: false,\n errors: [\n {\n message:\n e instanceof SyntaxError\n ? `Invalid JSON: ${e.message}`\n : 'Failed to parse theme JSON',\n },\n ],\n };\n }\n}\n\n/**\n * Gets theme name from a theme JSON object\n */\nexport function getThemeName(themeJson: unknown): string | null {\n try {\n if (\n themeJson &&\n typeof themeJson === 'object' &&\n 'name' in (themeJson as any) &&\n typeof (themeJson as any).name === 'string'\n ) {\n return (themeJson as any).name as string;\n }\n return null;\n } catch {\n return null;\n }\n}\n","// Theme change event emitter for coordinating theme updates across components\nexport interface ThemeChangeEvent {\n themeName: string;\n timestamp: number;\n changeType: 'create' | 'update' | 'delete';\n}\n\nexport class ThemeChangeEmitter extends EventTarget {\n private static instance: ThemeChangeEmitter;\n\n private constructor() {\n super();\n }\n\n static getInstance(): ThemeChangeEmitter {\n if (!ThemeChangeEmitter.instance) {\n ThemeChangeEmitter.instance = new ThemeChangeEmitter();\n }\n return ThemeChangeEmitter.instance;\n }\n\n emitThemeChange(event: ThemeChangeEvent): void {\n this.dispatchEvent(new CustomEvent('themechange', { detail: event }));\n }\n\n onThemeChange(callback: (event: ThemeChangeEvent) => void): () => void {\n const handler = (e: Event) => {\n const customEvent = e as CustomEvent<ThemeChangeEvent>;\n callback(customEvent.detail);\n };\n\n this.addEventListener('themechange', handler);\n\n // Track listener count\n (this as any)._listenerCount = ((this as any)._listenerCount || 0) + 1;\n\n // Return unsubscribe function\n return () => {\n this.removeEventListener('themechange', handler);\n (this as any)._listenerCount = Math.max(\n 0,\n ((this as any)._listenerCount || 1) - 1\n );\n };\n }\n}\n\nexport const themeChangeEmitter = ThemeChangeEmitter.getInstance();\n","function promisifyRequest(request) {\n return new Promise((resolve, reject) => {\n // @ts-ignore - file size hacks\n request.oncomplete = request.onsuccess = () => resolve(request.result);\n // @ts-ignore - file size hacks\n request.onabort = request.onerror = () => reject(request.error);\n });\n}\nfunction createStore(dbName, storeName) {\n let dbp;\n const getDB = () => {\n if (dbp)\n return dbp;\n const request = indexedDB.open(dbName);\n request.onupgradeneeded = () => request.result.createObjectStore(storeName);\n dbp = promisifyRequest(request);\n dbp.then((db) => {\n // It seems like Safari sometimes likes to just close the connection.\n // It's supposed to fire this event when that happens. Let's hope it does!\n db.onclose = () => (dbp = undefined);\n }, () => { });\n return dbp;\n };\n return (txMode, callback) => getDB().then((db) => callback(db.transaction(storeName, txMode).objectStore(storeName)));\n}\nlet defaultGetStoreFunc;\nfunction defaultGetStore() {\n if (!defaultGetStoreFunc) {\n defaultGetStoreFunc = createStore('keyval-store', 'keyval');\n }\n return defaultGetStoreFunc;\n}\n/**\n * Get a value by its key.\n *\n * @param key\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction get(key, customStore = defaultGetStore()) {\n return customStore('readonly', (store) => promisifyRequest(store.get(key)));\n}\n/**\n * Set a value with a key.\n *\n * @param key\n * @param value\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction set(key, value, customStore = defaultGetStore()) {\n return customStore('readwrite', (store) => {\n store.put(value, key);\n return promisifyRequest(store.transaction);\n });\n}\n/**\n * Set multiple values at once. This is faster than calling set() multiple times.\n * It's also atomic – if one of the pairs can't be added, none will be added.\n *\n * @param entries Array of entries, where each entry is an array of `[key, value]`.\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction setMany(entries, customStore = defaultGetStore()) {\n return customStore('readwrite', (store) => {\n entries.forEach((entry) => store.put(entry[1], entry[0]));\n return promisifyRequest(store.transaction);\n });\n}\n/**\n * Get multiple values by their keys\n *\n * @param keys\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction getMany(keys, customStore = defaultGetStore()) {\n return customStore('readonly', (store) => Promise.all(keys.map((key) => promisifyRequest(store.get(key)))));\n}\n/**\n * Update a value. This lets you see the old value and update it as an atomic operation.\n *\n * @param key\n * @param updater A callback that takes the old value and returns a new value.\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction update(key, updater, customStore = defaultGetStore()) {\n return customStore('readwrite', (store) => \n // Need to create the promise manually.\n // If I try to chain promises, the transaction closes in browsers\n // that use a promise polyfill (IE10/11).\n new Promise((resolve, reject) => {\n store.get(key).onsuccess = function () {\n try {\n store.put(updater(this.result), key);\n resolve(promisifyRequest(store.transaction));\n }\n catch (err) {\n reject(err);\n }\n };\n }));\n}\n/**\n * Delete a particular key from the store.\n *\n * @param key\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction del(key, customStore = defaultGetStore()) {\n return customStore('readwrite', (store) => {\n store.delete(key);\n return promisifyRequest(store.transaction);\n });\n}\n/**\n * Delete multiple keys at once.\n *\n * @param keys List of keys to delete.\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction delMany(keys, customStore = defaultGetStore()) {\n return customStore('readwrite', (store) => {\n keys.forEach((key) => store.delete(key));\n return promisifyRequest(store.transaction);\n });\n}\n/**\n * Clear all values in the store.\n *\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction clear(customStore = defaultGetStore()) {\n return customStore('readwrite', (store) => {\n store.clear();\n return promisifyRequest(store.transaction);\n });\n}\nfunction eachCursor(store, callback) {\n store.openCursor().onsuccess = function () {\n if (!this.result)\n return;\n callback(this.result);\n this.result.continue();\n };\n return promisifyRequest(store.transaction);\n}\n/**\n * Get all keys in the store.\n *\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction keys(customStore = defaultGetStore()) {\n return customStore('readonly', (store) => {\n // Fast path for modern browsers\n if (store.getAllKeys) {\n return promisifyRequest(store.getAllKeys());\n }\n const items = [];\n return eachCursor(store, (cursor) => items.push(cursor.key)).then(() => items);\n });\n}\n/**\n * Get all values in the store.\n *\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction values(customStore = defaultGetStore()) {\n return customStore('readonly', (store) => {\n // Fast path for modern browsers\n if (store.getAll) {\n return promisifyRequest(store.getAll());\n }\n const items = [];\n return eachCursor(store, (cursor) => items.push(cursor.value)).then(() => items);\n });\n}\n/**\n * Get all entries in the store. Each entry is an array of `[key, value]`.\n *\n * @param customStore Method to get a custom store. Use with caution (see the docs).\n */\nfunction entries(customStore = defaultGetStore()) {\n return customStore('readonly', (store) => {\n // Fast path for modern browsers\n // (although, hopefully we'll get a simpler path some day)\n if (store.getAll && store.getAllKeys) {\n return Promise.all([\n promisifyRequest(store.getAllKeys()),\n promisifyRequest(store.getAll()),\n ]).then(([keys, values]) => keys.map((key, i) => [key, values[i]]));\n }\n const items = [];\n return customStore('readonly', (store) => eachCursor(store, (cursor) => items.push([cursor.key, cursor.value])).then(() => items));\n });\n}\n\nexport { clear, createStore, del, delMany, entries, get, getMany, keys, promisifyRequest, set, setMany, update, values };\n","/**\n * IndexedDB storage adapter for Zustand persist middleware using idb-keyval.\n */\nimport { get, set, del } from 'idb-keyval';\nimport type { StateStorage } from 'zustand/middleware';\n\nexport const idbStorage: StateStorage = {\n getItem: async (name: string): Promise<string | null> => {\n return (await get(name)) ?? null;\n },\n setItem: async (name: string, value: string): Promise<void> => {\n await set(name, value);\n },\n removeItem: async (name: string): Promise<void> => {\n await del(name);\n },\n};\n","import { persist, devtools, createJSONStorage } from 'zustand/middleware';\nimport { createStore } from 'zustand/vanilla';\nimport type { ThemeConfigJson } from '@json-to-office/shared-pptx';\nimport { validateThemeJson, getThemeName } from '../lib/theme-validation';\nimport { themeChangeEmitter } from '../utils/theme-change-emitter';\nimport { idbStorage } from '../lib/idb-storage';\n\nexport type CustomTheme = {\n name: string;\n content: string;\n parsed?: ThemeConfigJson;\n valid: boolean;\n lastModified: Date;\n};\n\nexport type ThemesState = {\n customThemes: { [name: string]: CustomTheme };\n};\n\n/**\n * Valid custom themes keyed by theme name — the `customThemes` shape every\n * server request carries. File names are the store's keys; the server and\n * the plugin sandbox look themes up by the name inside the JSON.\n */\nexport function validThemesByName(customThemes: {\n [name: string]: CustomTheme;\n}): Record<string, ThemeConfigJson> {\n const out: Record<string, ThemeConfigJson> = {};\n for (const theme of Object.values(customThemes)) {\n if (theme.valid && theme.parsed) out[theme.name] = theme.parsed;\n }\n return out;\n}\n\nexport type ThemesActions = {\n updateTheme: (documentName: string, content: string) => void;\n removeTheme: (documentName: string) => void;\n getTheme: (themeName: string) => ThemeConfigJson | null;\n getAllThemeNames: () => string[];\n isThemeValid: (themeName: string) => boolean;\n};\n\nexport type ThemesStore = ThemesState & ThemesActions;\n\nexport const initThemesStore = (): ThemesState => {\n return {\n customThemes: {},\n };\n};\n\nexport const defaultInitThemesState: ThemesState = {\n ...initThemesStore(),\n};\n\nexport const createThemesStore = (\n initState: ThemesState = defaultInitThemesState\n) => {\n return createStore<ThemesStore>()(\n devtools(\n persist(\n (set, get) => ({\n ...initState,\n\n updateTheme: (documentName, content) =>\n set((state) => {\n const validation = validateThemeJson(content);\n\n let parsed: ThemeConfigJson | undefined;\n let themeName = documentName;\n\n if (validation.valid) {\n try {\n const parsedContent = JSON.parse(content);\n parsed = parsedContent;\n const extractedName = getThemeName(parsedContent);\n if (extractedName) {\n themeName = extractedName;\n }\n } catch {\n // Keep the document name if parsing fails\n }\n }\n\n const existingTheme = state.customThemes[documentName];\n const isUpdate = !!existingTheme;\n const hasContentChanged = existingTheme?.content !== content;\n\n const customTheme: CustomTheme = {\n name: themeName,\n content,\n parsed,\n valid: validation.valid,\n lastModified: new Date(),\n };\n\n // Emit theme change if content changed OR if this is a newly valid theme\n const shouldEmitEvent =\n (hasContentChanged ||\n (!existingTheme?.valid && validation.valid)) &&\n validation.valid;\n\n if (shouldEmitEvent) {\n // Use setTimeout to ensure state is updated before event is processed\n setTimeout(() => {\n themeChangeEmitter.emitThemeChange({\n themeName,\n timestamp: Date.now(),\n changeType: isUpdate ? 'update' : 'create',\n });\n }, 0);\n }\n\n return {\n customThemes: {\n ...state.customThemes,\n [documentName]: customTheme,\n },\n };\n }),\n\n removeTheme: (documentName) =>\n set((state) => {\n const removedTheme = state.customThemes[documentName];\n const newCustomThemes = { ...state.customThemes };\n delete newCustomThemes[documentName];\n\n // Emit theme deletion event\n if (removedTheme) {\n setTimeout(() => {\n themeChangeEmitter.emitThemeChange({\n themeName: removedTheme.name,\n timestamp: Date.now(),\n changeType: 'delete',\n });\n }, 0);\n }\n\n return {\n customThemes: newCustomThemes,\n };\n }),\n\n getTheme: (themeName) => {\n const state = get();\n\n // First check custom themes by theme name\n for (const customTheme of Object.values(state.customThemes)) {\n if (\n customTheme.valid &&\n customTheme.name === themeName &&\n customTheme.parsed\n ) {\n return customTheme.parsed;\n }\n }\n\n // Theme not found in custom themes\n return null;\n },\n\n getAllThemeNames: () => {\n const state = get();\n const names: string[] = [];\n\n // Add custom theme names\n for (const customTheme of Object.values(state.customThemes)) {\n if (customTheme.valid && customTheme.name) {\n names.push(customTheme.name);\n }\n }\n\n return names;\n },\n\n isThemeValid: (themeName) => {\n const state = get();\n\n // Check custom themes\n for (const customTheme of Object.values(state.customThemes)) {\n if (customTheme.name === themeName) {\n return customTheme.valid;\n }\n }\n\n return false;\n },\n }),\n {\n name: 'themes-storage',\n version: 4, // v4: migrate from localStorage to IndexedDB\n storage: createJSONStorage(() => idbStorage),\n // Only persist the themes data, not the functions\n partialize: (state) => ({ customThemes: state.customThemes }),\n // Handle date deserialization when loading from storage\n onRehydrateStorage: () => (state) => {\n if (state && state.customThemes) {\n // Convert lastModified strings back to Date objects\n Object.keys(state.customThemes).forEach((key) => {\n const theme = state.customThemes[key];\n if (\n theme.lastModified &&\n typeof theme.lastModified === 'string'\n ) {\n theme.lastModified = new Date(theme.lastModified);\n }\n });\n }\n },\n }\n )\n )\n );\n};\n","import { type ReactNode, createContext, useRef, useContext } from 'react';\nimport { useStore } from 'zustand';\n\nimport {\n type ThemesStore,\n createThemesStore,\n initThemesStore,\n} from './themes-store';\n\nexport type ThemesStoreApi = ReturnType<typeof createThemesStore>;\n\nexport const ThemesStoreContext = createContext<ThemesStoreApi | undefined>(\n undefined\n);\n\nexport interface ThemesStoreProviderProps {\n children: ReactNode;\n}\n\nexport const ThemesStoreProvider = ({ children }: ThemesStoreProviderProps) => {\n const storeRef = useRef<ThemesStoreApi>(undefined);\n if (!storeRef.current) {\n storeRef.current = createThemesStore(initThemesStore());\n }\n\n return (\n <ThemesStoreContext.Provider value={storeRef.current}>\n {children}\n </ThemesStoreContext.Provider>\n );\n};\n\nexport const useThemesStore = <T,>(selector: (store: ThemesStore) => T): T => {\n const themesStoreContext = useContext(ThemesStoreContext);\n\n if (!themesStoreContext) {\n throw new Error('useThemesStore must be used within ThemesStoreProvider');\n }\n\n return useStore(themesStoreContext, selector);\n};\n","/**\n * Cheap content hash for change detection (djb2, base-36). Not\n * cryptographic — it only decides whether a plugin source needs recompiling.\n */\nexport function hashSource(text: string): string {\n let hash = 5381;\n for (let i = 0; i < text.length; i++) {\n hash = ((hash << 5) + hash + text.charCodeAt(i)) | 0;\n }\n return `${(hash >>> 0).toString(36)}-${text.length.toString(36)}`;\n}\n","import { create } from 'zustand';\nimport { createJSONStorage, persist } from 'zustand/middleware';\nimport { idbStorage } from '../lib/idb-storage';\nimport { hashSource } from '../lib/plugins/hash';\nimport type {\n BrowserPluginMetadata,\n BrowserPluginRecord,\n PluginDiagnostic,\n} from '../lib/plugins/types';\n\n/**\n * Plugins compiled in the browser, one record per `*.component.ts` file.\n *\n * The compiled JavaScript and the metadata are persisted alongside the\n * enable switches, so a reload can expand documents and offer completions\n * without recompiling first — compiling needs Monaco's TypeScript worker,\n * which is not up until the editor is. The source itself lives with the\n * document; `sourceHash` is what tells the sync hook a record is stale.\n *\n * IndexedDB, like the documents and themes: compiled code for a plugin that\n * inlines an asset runs past what localStorage tolerates, and a store that\n * stops persisting on a quota error would do so silently.\n */\n\nexport interface BrowserPluginsState {\n records: Record<string, BrowserPluginRecord>;\n}\n\nexport interface BrowserPluginsActions {\n /** Create or update a record; missing fields keep their previous value. */\n upsert: (\n docName: string,\n patch: Partial<Omit<BrowserPluginRecord, 'docName' | 'createdAt'>>\n ) => void;\n setEnabled: (docName: string, enabled: boolean) => void;\n setAllowNetwork: (docName: string, allowNetwork: boolean) => void;\n /** The hosts the Network switch grants; anything else stays refused. */\n setNetworkOrigins: (docName: string, networkOrigins: string[]) => void;\n rename: (oldName: string, newName: string) => void;\n remove: (docName: string) => void;\n}\n\nexport type BrowserPluginsStore = BrowserPluginsState & BrowserPluginsActions;\n\nexport function createBrowserPluginRecord(\n docName: string,\n patch: Partial<Omit<BrowserPluginRecord, 'docName'>> = {}\n): BrowserPluginRecord {\n const now = Date.now();\n return {\n docName,\n enabled: true,\n allowNetwork: false,\n networkOrigins: [],\n status: 'idle',\n sourceHash: '',\n diagnostics: [],\n createdAt: now,\n updatedAt: now,\n ...patch,\n };\n}\n\nexport const useBrowserPluginsStore = create<BrowserPluginsStore>()(\n persist(\n (set) => ({\n records: {},\n\n upsert: (docName, patch) =>\n set((state) => {\n const existing =\n state.records[docName] ?? createBrowserPluginRecord(docName);\n return {\n records: {\n ...state.records,\n [docName]: { ...existing, ...patch, updatedAt: Date.now() },\n },\n };\n }),\n\n // A plugin file is on screen before the sync hook has compiled it, so\n // these two create the record they are missing rather than dropping the\n // switch: the setting the author just made has to survive the compile.\n setEnabled: (docName, enabled) =>\n set((state) => {\n const existing =\n state.records[docName] ?? createBrowserPluginRecord(docName);\n if (state.records[docName] && existing.enabled === enabled)\n return state;\n return {\n records: {\n ...state.records,\n [docName]: { ...existing, enabled, updatedAt: Date.now() },\n },\n };\n }),\n\n setAllowNetwork: (docName, allowNetwork) =>\n set((state) => {\n const existing =\n state.records[docName] ?? createBrowserPluginRecord(docName);\n if (state.records[docName] && existing.allowNetwork === allowNetwork)\n return state;\n return {\n records: {\n ...state.records,\n [docName]: { ...existing, allowNetwork, updatedAt: Date.now() },\n },\n };\n }),\n\n setNetworkOrigins: (docName, networkOrigins) =>\n set((state) => {\n const existing =\n state.records[docName] ?? createBrowserPluginRecord(docName);\n const previous = existing.networkOrigins ?? [];\n if (\n state.records[docName] &&\n previous.length === networkOrigins.length &&\n previous.every((origin, i) => origin === networkOrigins[i])\n ) {\n return state;\n }\n return {\n records: {\n ...state.records,\n [docName]: {\n ...existing,\n networkOrigins: [...networkOrigins],\n updatedAt: Date.now(),\n },\n },\n };\n }),\n\n rename: (oldName, newName) =>\n set((state) => {\n const existing = state.records[oldName];\n if (!existing || oldName === newName) return state;\n const records = { ...state.records };\n delete records[oldName];\n records[newName] = { ...existing, docName: newName };\n return { records };\n }),\n\n remove: (docName) =>\n set((state) => {\n if (!state.records[docName]) return state;\n const records = { ...state.records };\n delete records[docName];\n return { records };\n }),\n }),\n {\n name: 'jto-browser-plugins',\n version: 3,\n storage: createJSONStorage(() => idbStorage),\n partialize: (state) => ({ records: state.records }),\n // v1 lived in localStorage and had no createdAt. v2 had no origin list,\n // and `allowNetwork` alone meant the whole internet — a record from then\n // comes back with the switch on but nothing listed, which reaches\n // nothing until its author says which hosts it needs.\n migrate: (persisted) => {\n const state = persisted as {\n records?: Record<string, BrowserPluginRecord>;\n };\n const records: Record<string, BrowserPluginRecord> = {};\n for (const [name, record] of Object.entries(state?.records ?? {})) {\n records[name] = {\n ...record,\n createdAt: record.createdAt ?? record.updatedAt ?? Date.now(),\n networkOrigins: record.networkOrigins ?? [],\n };\n }\n return { records };\n },\n }\n )\n);\n\n/**\n * Resolves once the persisted records are in memory. The IndexedDB read is\n * asynchronous, and a sync that ran before it would compile every plugin\n * from scratch and then be overwritten by what the store had all along.\n */\nexport function whenBrowserPluginsHydrated(): Promise<void> {\n const api = useBrowserPluginsStore.persist;\n if (api.hasHydrated()) return Promise.resolve();\n return new Promise((resolve) => {\n const stop = api.onFinishHydration(() => {\n stop();\n resolve();\n });\n });\n}\n\n/** A plugin that takes part in schema generation and expansion. */\nexport interface ActiveBrowserPlugin {\n docName: string;\n metadata: BrowserPluginMetadata;\n}\n\nexport function selectActivePlugins(\n state: BrowserPluginsState\n): ActiveBrowserPlugin[] {\n const active: ActiveBrowserPlugin[] = [];\n for (const record of Object.values(state.records)) {\n if (record.enabled && record.status === 'ready' && record.metadata) {\n active.push({ docName: record.docName, metadata: record.metadata });\n }\n }\n return active.sort((a, b) => a.docName.localeCompare(b.docName));\n}\n\n/**\n * A string that changes exactly when the set of active plugins, or any of\n * their schemas, changes — what schema refreshes key on.\n */\nexport function activePluginsSignature(state: BrowserPluginsState): string {\n const components = browserComponentsForSchema(state);\n // Empty stays empty, so a page with no active plugin keys on '' rather than\n // on the hash of an empty array.\n if (components.length === 0) return '';\n // The whole payload the schema route receives, not the props alone:\n // `hasChildren` and `description` reach the composed schema too.\n return hashSource(JSON.stringify(components));\n}\n\n/**\n * Which file owns a component name when several claim it: the one created\n * first. Deterministic across reloads, and a rename of the newcomer resolves\n * it on its next compile.\n */\nexport function componentNameOwner(\n records: Record<string, BrowserPluginRecord>,\n componentName: string\n): string | undefined {\n let owner: BrowserPluginRecord | undefined;\n for (const record of Object.values(records)) {\n if (record.metadata?.name !== componentName) continue;\n if (!owner || record.createdAt < owner.createdAt) owner = record;\n }\n return owner?.docName;\n}\n\n/** The shape `POST /api/discovery/schemas/document` accepts for a browser plugin. */\nexport interface BrowserComponentSchemaInfo {\n name: string;\n versions: Array<{\n version: string;\n propsSchema: Record<string, unknown>;\n hasChildren?: boolean;\n description?: string;\n }>;\n}\n\nexport function browserComponentsForSchema(\n state: BrowserPluginsState\n): BrowserComponentSchemaInfo[] {\n return selectActivePlugins(state).map((plugin) => ({\n name: plugin.metadata.name,\n versions: plugin.metadata.versions.map((v) => ({\n version: v.version,\n propsSchema: v.propsSchema,\n ...(v.hasChildren ? { hasChildren: true } : {}),\n ...(v.description ? { description: v.description } : {}),\n })),\n }));\n}\n\n/** Diagnostics a record carries, for the sidebar and the editor strip. */\nexport function recordErrors(\n record: BrowserPluginRecord | undefined\n): PluginDiagnostic[] {\n return (record?.diagnostics ?? []).filter((d) => d.severity === 'error');\n}\n","/**\n * Which origins a browser plugin may reach when its Network switch is on.\n *\n * `connect-src *` would make that switch mean \"the whole internet\", and the\n * same policy carries `'unsafe-eval'`: a plugin could then fetch code and run\n * it, so a source someone read and found harmless could pull its real payload\n * at render time, and anything it renders could be posted anywhere. Neither is\n * an escape from the sandbox — fetched code runs under the same opaque origin\n * and the same policy — but both defeat reading the plugin before trusting it.\n *\n * So the switch grants the origins listed against the plugin and nothing else.\n * Every value here ends up inside a CSP header, which is why parsing is strict\n * rather than forgiving: a stray `;` or space would end the directive and open\n * the rest of the policy.\n */\n\n/** What a plugin with Network on but nothing listed is allowed to reach. */\nconst NOTHING = \"'none'\";\n\nexport type OriginResult =\n | { ok: true; origin: string }\n | { ok: false; reason: string };\n\n/** Hostname, or `*.` plus one: letters, digits, hyphens and dots only. */\nconst HOST =\n /^(\\*\\.)?[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/;\n\n/** Loopback may be reached over plain http; everything else must be https. */\nfunction isLoopback(host: string): boolean {\n return host === 'localhost' || host === '127.0.0.1' || host === '[::1]';\n}\n\n/**\n * Turn one line of author input into a CSP source expression.\n *\n * `api.example.com` and `https://api.example.com` both mean the same origin;\n * a bare host is read as https because that is the only scheme worth\n * defaulting to. `*.example.com` matches subdomains, as CSP defines it.\n */\nexport function normalizeNetworkOrigin(input: string): OriginResult {\n const trimmed = input.trim().replace(/\\/+$/, '');\n if (!trimmed) return { ok: false, reason: 'is empty' };\n // A blanket source would put the switch back to meaning \"anywhere\".\n if (trimmed === '*' || /^https?:$/i.test(trimmed) || trimmed === '*:*') {\n return { ok: false, reason: 'is a wildcard — name the hosts you need' };\n }\n\n const withScheme = /^[a-z][a-z0-9+.-]*:\\/\\//i.test(trimmed)\n ? trimmed\n : `https://${trimmed}`;\n\n // `*.` is a CSP source expression, not a legal URL label: take it off before\n // parsing and put it back on the hostname afterwards.\n const wildcard = /^(https?:\\/\\/)\\*\\./i.test(withScheme);\n const parseable = wildcard\n ? withScheme.replace(/^(https?:\\/\\/)\\*\\./i, '$1')\n : withScheme;\n\n let url: URL;\n try {\n url = new URL(parseable);\n } catch {\n return { ok: false, reason: 'is not a URL' };\n }\n\n if (url.username || url.password) {\n return { ok: false, reason: 'must not carry credentials' };\n }\n if (url.pathname !== '/' || url.search || url.hash) {\n return { ok: false, reason: 'must be an origin, with no path' };\n }\n\n const host = wildcard ? `*.${url.hostname}` : url.hostname;\n if (!HOST.test(host)) return { ok: false, reason: 'is not a hostname' };\n\n const protocol = url.protocol.toLowerCase();\n if (protocol !== 'https:' && protocol !== 'http:') {\n return { ok: false, reason: 'must be http or https' };\n }\n if (protocol === 'http:' && !isLoopback(url.hostname)) {\n return { ok: false, reason: 'must use https (http is only for localhost)' };\n }\n\n return {\n ok: true,\n origin: `${protocol}//${host}${url.port ? `:${url.port}` : ''}`,\n };\n}\n\nexport interface ParsedOrigins {\n origins: string[];\n /** One per rejected line, ready to show against the field. */\n errors: string[];\n}\n\n/** Parse the field's text: one origin per line, or comma separated. */\nexport function parseNetworkOrigins(text: string): ParsedOrigins {\n const origins: string[] = [];\n const errors: string[] = [];\n for (const line of text.split(/[\\n,]/)) {\n if (!line.trim()) continue;\n const result = normalizeNetworkOrigin(line);\n if (!result.ok) errors.push(`\"${line.trim()}\" ${result.reason}`);\n else if (!origins.includes(result.origin)) origins.push(result.origin);\n }\n return { origins, errors };\n}\n\n/**\n * The `connect-src` value for a plugin. Anything that did not survive\n * `normalizeNetworkOrigin` is dropped rather than trusted: this string is\n * interpolated into a policy, and a record could have been persisted by an\n * older build with looser rules.\n */\nexport function connectSrcValue(\n allowNetwork: boolean,\n origins: readonly string[] | undefined\n): string {\n if (!allowNetwork || !origins?.length) return NOTHING;\n const safe = origins\n .map((origin) => normalizeNetworkOrigin(origin))\n .filter((result): result is { ok: true; origin: string } => result.ok)\n .map((result) => result.origin);\n return safe.length > 0 ? safe.join(' ') : NOTHING;\n}\n\n/** True when the plugin can reach anything at all — what the worker hardens on. */\nexport function hasNetworkAccess(\n allowNetwork: boolean,\n origins: readonly string[] | undefined\n): boolean {\n return connectSrcValue(allowNetwork, origins) !== NOTHING;\n}\n","/**\n * The boundary a plugin runs behind.\n *\n * An `<iframe sandbox=\"allow-scripts\">` with no `allow-same-origin` has an\n * opaque origin: nothing inside it can read the playground's storage, send\n * its cookies or call its API as the user. The frame's own document carries a\n * Content-Security-Policy, and the worker it spawns from a blob: URL inherits\n * that policy — so `import()` of a remote script, `fetch`, WebSockets and\n * WebTransport are refused by the browser itself, not by a list of globals\n * the runtime tried to delete. `connect-src` is the one knob, and it names\n * the plugin's own origins: `'none'` until its Network switch is on and its\n * allowlist has something in it (network-policy.ts).\n *\n * The page talks to the frame with `postMessage`; the frame relays to the\n * worker. Only messages from this frame's window are accepted back.\n */\nimport { connectSrcValue } from './network-policy';\n\nexport interface SandboxFrameOptions {\n /** The bundled runtime script (virtual:jto-sandbox-runtime). */\n runtime: string;\n allowNetwork: boolean;\n /** Origins the switch grants; empty reaches nothing. */\n networkOrigins?: readonly string[];\n onMessage: (data: unknown) => void;\n onError: (message: string) => void;\n}\n\nfunction nonce(): string {\n const bytes = new Uint8Array(16);\n crypto.getRandomValues(bytes);\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * The frame's document. Everything is inline and nonce-bound: the frame has\n * no origin to load anything else from, and the policy says so.\n */\nexport function sandboxDocument(\n scriptNonce: string,\n allowNetwork: boolean,\n networkOrigins?: readonly string[]\n): string {\n const csp = [\n \"default-src 'none'\",\n // blob: for the worker script; 'unsafe-eval' because the runtime turns\n // the plugin's compiled CommonJS into a function. No host, so the\n // worker cannot import() code from anywhere.\n `script-src 'nonce-${scriptNonce}' blob: 'unsafe-eval'`,\n 'worker-src blob:',\n // Built by network-policy.ts, which re-validates every origin: the value\n // lands inside the policy, so nothing reaches it unparsed.\n `connect-src ${connectSrcValue(allowNetwork, networkOrigins)}`,\n \"base-uri 'none'\",\n \"form-action 'none'\",\n ].join('; ');\n return `<!doctype html><html><head><meta charset=\"utf-8\"><meta http-equiv=\"Content-Security-Policy\" content=\"${csp}\"></head><body><script nonce=\"${scriptNonce}\">\n(function () {\n var worker = null;\n window.addEventListener('message', function (event) {\n if (event.source !== window.parent) return;\n var message = event.data;\n if (!message || typeof message !== 'object') return;\n if (message.type === 'init') {\n if (worker) return;\n var url = URL.createObjectURL(new Blob([message.runtime], { type: 'text/javascript' }));\n worker = new Worker(url);\n worker.onmessage = function (reply) { window.parent.postMessage(reply.data, '*'); };\n worker.onerror = function (error) {\n window.parent.postMessage({ type: 'workerError', message: (error && error.message) || 'Worker error' }, '*');\n };\n window.parent.postMessage({ type: 'ready' }, '*');\n return;\n }\n if (worker) worker.postMessage(message);\n });\n})();\n</script></body></html>`;\n}\n\nexport class SandboxFrame {\n private readonly iframe: HTMLIFrameElement;\n private readonly ready: Promise<void>;\n private readonly listener: (event: MessageEvent) => void;\n private disposed = false;\n\n constructor(options: SandboxFrameOptions) {\n const scriptNonce = nonce();\n const iframe = document.createElement('iframe');\n iframe.setAttribute('sandbox', 'allow-scripts');\n iframe.setAttribute('aria-hidden', 'true');\n iframe.setAttribute('title', 'Plugin sandbox');\n iframe.tabIndex = -1;\n iframe.style.cssText =\n 'position:absolute;width:0;height:0;border:0;visibility:hidden;pointer-events:none;';\n this.iframe = iframe;\n\n let resolveReady: () => void = () => {};\n let rejectReady: (error: Error) => void = () => {};\n this.ready = new Promise<void>((resolve, reject) => {\n resolveReady = resolve;\n rejectReady = reject;\n });\n // A frame that never answers would leave every request waiting on it.\n const readyTimer = setTimeout(() => {\n rejectReady(new Error('Plugin sandbox did not start'));\n }, 10_000);\n\n this.listener = (event: MessageEvent) => {\n if (event.source !== iframe.contentWindow) return;\n const data = event.data as { type?: unknown; message?: unknown } | null;\n if (!data || typeof data !== 'object') return;\n if (data.type === 'ready') {\n clearTimeout(readyTimer);\n resolveReady();\n return;\n }\n if (data.type === 'workerError') {\n options.onError(\n typeof data.message === 'string' ? data.message : 'Worker error'\n );\n return;\n }\n options.onMessage(data);\n };\n window.addEventListener('message', this.listener);\n\n iframe.addEventListener('load', () => {\n iframe.contentWindow?.postMessage(\n { type: 'init', runtime: options.runtime },\n '*'\n );\n });\n iframe.srcdoc = sandboxDocument(\n scriptNonce,\n options.allowNetwork,\n options.networkOrigins\n );\n document.body.appendChild(iframe);\n // Nobody awaits `ready` before the first post; surface a start failure\n // there rather than as an unhandled rejection here.\n this.ready.catch(() => {});\n }\n\n async post(message: unknown): Promise<void> {\n await this.ready;\n if (this.disposed) throw new Error('Plugin sandbox was closed');\n this.iframe.contentWindow?.postMessage(message, '*');\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n window.removeEventListener('message', this.listener);\n this.iframe.remove();\n }\n}\n","import { useBrowserPluginsStore } from '../../store/browser-plugins-store';\nimport type { PluginRenderRequest, PluginRenderResult } from './expand';\nimport { SandboxFrame } from './sandbox-frame';\nimport type {\n BrowserPluginMetadata,\n PluginExample,\n PluginFormat,\n SandboxRequest,\n SandboxResponse,\n} from './types';\n\n/**\n * The page side of the sandbox: one frame (and one worker) per plugin file,\n * request/response over `postMessage`, hard time limits.\n *\n * A plugin that misses its deadline is torn down, not asked nicely — an\n * infinite loop in a render cannot be interrupted any other way — and the\n * next request starts a fresh one from the persisted compiled code. Idle\n * plugins are torn down too: a worker nobody is rendering with has no\n * business running.\n */\n\nexport interface LoadSpec {\n js: string;\n format: PluginFormat;\n allowNetwork: boolean;\n /** Origins the frame's CSP will name; order-insensitive for `sameSpec`. */\n networkOrigins?: string[];\n examples: PluginExample[];\n}\n\n/** The part of a spec baked into the frame's policy and unchangeable after. */\ninterface FramePolicy {\n allowNetwork: boolean;\n networkOrigins: string[];\n}\n\nfunction framePolicy(spec: {\n allowNetwork: boolean;\n networkOrigins?: readonly string[];\n}): FramePolicy {\n return {\n allowNetwork: spec.allowNetwork,\n networkOrigins: [...(spec.networkOrigins ?? [])].sort(),\n };\n}\n\nfunction samePolicy(a: FramePolicy, b: FramePolicy): boolean {\n return (\n a.allowNetwork === b.allowNetwork &&\n a.networkOrigins.length === b.networkOrigins.length &&\n a.networkOrigins.every((origin, i) => origin === b.networkOrigins[i])\n );\n}\n\nconst LOAD_TIMEOUT_MS = 8_000;\nconst RENDER_TIMEOUT_MS = 20_000;\nconst IDLE_TIMEOUT_MS = 30_000;\n\n/** `Omit` that distributes over the request union instead of intersecting it. */\ntype RequestPayload<T> = T extends { id: number } ? Omit<T, 'id'> : never;\ntype SandboxRequestPayload = RequestPayload<SandboxRequest>;\n\ninterface Pending {\n resolve: (response: SandboxResponse) => void;\n reject: (error: Error) => void;\n timer: ReturnType<typeof setTimeout>;\n}\n\ninterface Entry {\n frame: SandboxFrame;\n /**\n * The policy this frame's CSP was built from. A frame cannot be re-policed\n * after `srcdoc`, so a request under a different one needs a new frame.\n */\n policy: FramePolicy;\n /** The spec the worker was loaded with; null until `loaded` arrives. */\n loaded: LoadSpec | null;\n pending: Map<number, Pending>;\n idleTimer: ReturnType<typeof setTimeout> | null;\n}\n\nexport class PluginTimeoutError extends Error {\n constructor(docName: string, what: string, ms: number) {\n super(\n `Plugin \"${docName}\" did not finish ${what} within ${Math.round(ms / 1000)}s and was stopped.`\n );\n this.name = 'PluginTimeoutError';\n }\n}\n\nexport class PluginAbortedError extends Error {\n constructor(docName: string) {\n super(`Plugin \"${docName}\" render was cancelled`);\n this.name = 'PluginAbortedError';\n }\n}\n\nlet runtimePromise: Promise<string> | null = null;\n\n/** The bundled runtime, fetched once; a failed load is retried next time. */\nfunction loadRuntime(): Promise<string> {\n if (!runtimePromise) {\n runtimePromise = import('virtual:jto-sandbox-runtime')\n .then((module) => module.default)\n .catch((error) => {\n runtimePromise = null;\n throw error;\n });\n }\n return runtimePromise;\n}\n\nfunction sameSpec(a: LoadSpec, b: LoadSpec): boolean {\n return (\n a.js === b.js &&\n a.format === b.format &&\n samePolicy(framePolicy(a), framePolicy(b)) &&\n JSON.stringify(a.examples) === JSON.stringify(b.examples)\n );\n}\n\nclass PluginHost {\n private entries = new Map<string, Entry>();\n private nextId = 1;\n\n private async entry(docName: string, policy: FramePolicy): Promise<Entry> {\n const existing = this.entries.get(docName);\n if (existing) {\n // The CSP is fixed when the frame is written. Reusing one built under a\n // wider policy would keep granting what the switch has since taken\n // away, so the mismatch is what forces a new frame — not the caller\n // remembering to dispose.\n if (samePolicy(existing.policy, policy)) return existing;\n this.dispose(\n docName,\n new Error(`Plugin \"${docName}\" network policy changed`)\n );\n }\n const runtime = await loadRuntime();\n // Two callers racing to create the same frame: the second wins nothing.\n const raced = this.entries.get(docName);\n if (raced) return raced;\n const entry: Entry = {\n frame: null as unknown as SandboxFrame,\n policy,\n loaded: null,\n pending: new Map(),\n idleTimer: null,\n };\n entry.frame = new SandboxFrame({\n runtime,\n allowNetwork: policy.allowNetwork,\n networkOrigins: policy.networkOrigins,\n onMessage: (data) => {\n const response = data as SandboxResponse;\n if (!response || typeof response.id !== 'number') return;\n const pending = entry.pending.get(response.id);\n if (!pending) return;\n entry.pending.delete(response.id);\n clearTimeout(pending.timer);\n pending.resolve(response);\n this.touch(docName, entry);\n },\n onError: (message) => {\n this.dispose(\n docName,\n new Error(`Plugin \"${docName}\" crashed: ${message}`)\n );\n },\n });\n this.entries.set(docName, entry);\n return entry;\n }\n\n /** Restart the idle clock; a frame with nothing pending is closed after it. */\n private touch(docName: string, entry: Entry): void {\n if (entry.idleTimer) clearTimeout(entry.idleTimer);\n entry.idleTimer = setTimeout(() => {\n if (entry.pending.size === 0 && this.entries.get(docName) === entry) {\n this.dispose(docName);\n }\n }, IDLE_TIMEOUT_MS);\n }\n\n private async request(\n docName: string,\n policy: FramePolicy,\n payload: SandboxRequestPayload,\n timeoutMs: number,\n what: string,\n signal?: AbortSignal\n ): Promise<SandboxResponse> {\n if (signal?.aborted) throw new PluginAbortedError(docName);\n const entry = await this.entry(docName, policy);\n if (entry.idleTimer) clearTimeout(entry.idleTimer);\n const id = this.nextId++;\n const result = new Promise<SandboxResponse>((resolve, reject) => {\n // The caller's signal outlives this request — a build aborts its signal\n // during cleanup, long after the renders it guarded have settled. Left\n // attached, that abort would dispose the frame and reject whatever is\n // in flight at the time, so the listener goes when the request does.\n let onAbort: (() => void) | null = null;\n const detach = () => {\n if (onAbort) signal?.removeEventListener('abort', onAbort);\n onAbort = null;\n };\n const timer = setTimeout(() => {\n entry.pending.delete(id);\n detach();\n this.dispose(docName, new PluginTimeoutError(docName, what, timeoutMs));\n reject(new PluginTimeoutError(docName, what, timeoutMs));\n }, timeoutMs);\n entry.pending.set(id, {\n resolve: (response) => {\n detach();\n resolve(response);\n },\n reject: (error) => {\n detach();\n reject(error);\n },\n timer,\n });\n onAbort = () => {\n // A cancelled build must not leave a render burning in the worker.\n this.dispose(docName, new PluginAbortedError(docName));\n };\n signal?.addEventListener('abort', onAbort, { once: true });\n entry.frame.post({ id, ...payload } as SandboxRequest).catch((error) => {\n entry.pending.delete(id);\n clearTimeout(timer);\n detach();\n reject(error instanceof Error ? error : new Error(String(error)));\n });\n });\n return result;\n }\n\n /** Evaluate compiled code in a fresh sandbox and describe the component. */\n async load(docName: string, spec: LoadSpec): Promise<BrowserPluginMetadata> {\n const existing = this.entries.get(docName);\n if (existing && (!existing.loaded || !sameSpec(existing.loaded, spec))) {\n // The policy and the module state are per frame: a new spec gets a\n // new one.\n this.dispose(docName, new Error(`Plugin \"${docName}\" was reloaded`));\n }\n const response = await this.request(\n docName,\n framePolicy(spec),\n {\n type: 'load',\n js: spec.js,\n format: spec.format,\n allowNetwork: spec.allowNetwork,\n networkOrigins: spec.networkOrigins ?? [],\n examples: spec.examples,\n },\n LOAD_TIMEOUT_MS,\n 'loading'\n );\n if (response.type === 'error') {\n this.dispose(docName, new Error(response.message));\n throw new Error(response.message);\n }\n if (response.type !== 'loaded') {\n throw new Error(`Unexpected sandbox reply \"${response.type}\"`);\n }\n const entry = this.entries.get(docName);\n if (entry) entry.loaded = spec;\n return response.metadata;\n }\n\n /**\n * Render one component instance. Loads the sandbox from the persisted\n * record first when nothing is running (a reload, a timeout, idleness).\n */\n async render(\n docName: string,\n request: PluginRenderRequest,\n signal?: AbortSignal\n ): Promise<PluginRenderResult> {\n const record = useBrowserPluginsStore.getState().records[docName];\n const policy = framePolicy({\n allowNetwork: record?.allowNetwork ?? false,\n networkOrigins: record?.networkOrigins,\n });\n const entry = this.entries.get(docName);\n if (!entry || !entry.loaded || !samePolicy(entry.policy, policy)) {\n if (!record?.js || !record.metadata) {\n throw new Error(`Plugin \"${docName}\" is not compiled`);\n }\n await this.load(docName, {\n js: record.js,\n format: record.metadata.format,\n allowNetwork: record.allowNetwork,\n networkOrigins: record.networkOrigins,\n examples: record.metadata.examples,\n });\n }\n const response = await this.request(\n docName,\n policy,\n {\n type: 'render',\n version: request.version,\n props: request.props,\n theme: request.theme,\n children: request.children,\n },\n RENDER_TIMEOUT_MS,\n 'rendering',\n signal\n );\n if (response.type === 'error') throw new Error(response.message);\n if (response.type !== 'rendered') {\n throw new Error(`Unexpected sandbox reply \"${response.type}\"`);\n }\n return { components: response.components, warnings: response.warnings };\n }\n\n /** Tear the sandbox down; every request still in flight rejects with `reason`. */\n dispose(docName: string, reason?: Error): void {\n const entry = this.entries.get(docName);\n if (!entry) return;\n this.entries.delete(docName);\n if (entry.idleTimer) clearTimeout(entry.idleTimer);\n for (const pending of entry.pending.values()) {\n clearTimeout(pending.timer);\n pending.reject(reason ?? new Error(`Plugin \"${docName}\" was unloaded`));\n }\n entry.pending.clear();\n entry.frame.dispose();\n }\n\n isLoaded(docName: string): boolean {\n return this.entries.get(docName)?.loaded != null;\n }\n}\n\nexport const pluginHost = new PluginHost();\n","import { persist, devtools, createJSONStorage } from 'zustand/middleware';\nimport { createStore } from 'zustand/vanilla';\nimport type { TextFile } from '../lib/types';\nimport { idbStorage } from '../lib/idb-storage';\n\nconst MAX_OPEN_TABS = 3;\n\n/**\n * What a file in the workspace is: a document, a theme, or a plugin — the\n * TypeScript source of a custom component compiled and run in the browser.\n */\nexport type DocumentType =\n | 'application/json+report'\n | 'application/json+theme'\n | 'application/typescript+plugin';\n\n/** File-name suffix that marks a plugin source, the same one disk discovery uses. */\nexport const PLUGIN_FILE_SUFFIX = '.component.ts';\n\nexport function isPluginDocumentName(name: string): boolean {\n return name.toLowerCase().endsWith(PLUGIN_FILE_SUFFIX);\n}\n\n/**\n * The file name a plugin will actually be stored under. The type is decided\n * by the name, so a plugin keeps its suffix however it is typed — which is\n * why duplicate checks have to run on this, not on what the author entered:\n * `foo` and `foo.component.ts` are the same file.\n */\nexport function pluginDocumentName(name: string): string {\n const trimmed = name.trim();\n if (isPluginDocumentName(trimmed)) return trimmed;\n return trimmed.replace(/\\.(component)?\\.?ts$/i, '') + PLUGIN_FILE_SUFFIX;\n}\n\nexport type DocumentsState = {\n documents: TextFile[];\n openTabs: string[];\n activeTab: string;\n buildErrors: { [key: string]: string };\n documentTypes: { [key: string]: DocumentType };\n pendingDiffs: {\n [key: string]: { original: string; modified: string; applyId?: string };\n };\n acceptedApplyIds: string[];\n};\n\nexport type DocumentsActions = {\n createDocument: (\n name: string,\n text: string,\n opts?: { templateSource?: string }\n ) => void;\n deleteDocument: (name: string) => void;\n saveDocument: (name: string, text: string) => void;\n renameDocument: (oldName: string, newName: string) => void;\n openDocument: (name: string) => void;\n closeDocument: (name: string) => void;\n setActiveTab: (name: string) => void;\n setBuildError: (name: string, buildError?: string) => void;\n setPendingDiff: (\n name: string,\n original: string,\n modified: string,\n applyId?: string\n ) => void;\n clearPendingDiff: (name: string, accepted?: boolean) => void;\n};\n\nexport type DocumentsStore = DocumentsState & DocumentsActions;\n\n/**\n * The `options.sourceName` to send with generate/preview requests: the\n * document's template provenance when it has one, else its display name.\n * The server only matches sourceName against its own discovered documents,\n * so provenance keeps a renamed copy of a bundled template resolving its\n * relative media/fonts, while the display-name fallback preserves behaviour\n * for documents created before templateSource existed.\n */\nexport function resolveSourceName(\n documents: TextFile[],\n docName: string\n): string {\n return (\n documents.find((doc) => doc.name === docName)?.templateSource ?? docName\n );\n}\n\nexport const initDocumentsStore = (): DocumentsState => {\n return {\n documents: [],\n openTabs: [],\n activeTab: '',\n buildErrors: {},\n documentTypes: {},\n pendingDiffs: {},\n acceptedApplyIds: [],\n };\n};\n\nexport const defaultInitDocumentsState: DocumentsState = {\n ...initDocumentsStore(),\n};\n\nexport const createDocumentsStore = (\n initState: DocumentsState = defaultInitDocumentsState\n) => {\n return createStore<DocumentsStore>()(\n devtools(\n persist(\n (set) => ({\n ...initState,\n createDocument: (name, text, opts) =>\n set((state) => {\n const docIndex = state.documents.findIndex(\n (doc) => doc.name === name\n );\n if (docIndex === -1) {\n // if the document does not exist\n // Determine document type based on file name and content\n let docType: DocumentType = 'application/json+report';\n if (isPluginDocumentName(name)) {\n docType = 'application/typescript+plugin';\n } else if (\n name.toLowerCase().includes('theme') ||\n name.toLowerCase().includes('.theme.')\n ) {\n docType = 'application/json+theme';\n } else {\n // Try to parse JSON to check if it's a theme\n try {\n const parsed = JSON.parse(text);\n if (parsed.colors && parsed.fonts && parsed.styles) {\n docType = 'application/json+theme';\n }\n } catch {\n // If not valid JSON, default to report\n }\n }\n\n const newDoc = {\n name,\n type:\n docType === 'application/typescript+plugin'\n ? 'text/typescript'\n : 'application/json',\n text,\n mtime: new Date(),\n ctime: new Date(),\n atime: new Date(),\n // Survives renames: renameDocument spreads the record.\n ...(opts?.templateSource\n ? { templateSource: opts.templateSource }\n : {}),\n };\n return {\n documents: [...state.documents, newDoc],\n documentTypes: { ...state.documentTypes, [name]: docType },\n };\n }\n return state;\n }),\n deleteDocument: (name) =>\n set((state) => {\n const newDocumentTypes = { ...state.documentTypes };\n delete newDocumentTypes[name];\n return {\n documents: state.documents.filter((doc) => doc.name !== name),\n documentTypes: newDocumentTypes,\n pendingDiffs: Object.fromEntries(\n Object.entries(state.pendingDiffs).filter(([k]) => k !== name)\n ),\n };\n }),\n saveDocument: (name, text) =>\n set((state) => {\n const docIndex = state.documents.findIndex(\n (doc) => doc.name === name\n );\n if (docIndex === -1) return state;\n // Skip update if text is unchanged to avoid spurious re-renders\n if (state.documents[docIndex].text === text) return state;\n const documents = state.documents.map((doc, i) =>\n i === docIndex ? { ...doc, text, mtime: new Date() } : doc\n );\n return { documents };\n }),\n renameDocument: (oldName, newName) =>\n set((state) => {\n const docIndex = state.documents.findIndex(\n (doc) => doc.name === oldName\n );\n if (docIndex === -1) return state;\n const documents = state.documents.map((doc, i) =>\n i === docIndex\n ? { ...doc, name: newName, ctime: new Date() }\n : doc\n );\n const docType = state.documentTypes[oldName];\n if (docType) {\n const newDocumentTypes = { ...state.documentTypes };\n delete newDocumentTypes[oldName];\n newDocumentTypes[newName] = docType;\n return { documents, documentTypes: newDocumentTypes };\n }\n return { documents };\n }),\n openDocument: (name) =>\n set((state) => {\n const docIndex = state.documents.findIndex(\n (doc) => doc.name === name\n );\n if (docIndex === -1) return state;\n const documents = state.documents.map((doc, i) =>\n i === docIndex ? { ...doc, atime: new Date() } : doc\n );\n let openTabs = state.openTabs;\n if (!openTabs.includes(name)) {\n openTabs =\n openTabs.length >= MAX_OPEN_TABS\n ? [...openTabs.slice(1), name]\n : [...openTabs, name];\n }\n return { documents, openTabs, activeTab: name };\n }),\n closeDocument: (name) =>\n set((state) => {\n const index = state.openTabs.indexOf(name);\n if (index === -1) return state;\n const openTabs = state.openTabs.filter((tab) => tab !== name);\n let activeTab = state.activeTab;\n if (activeTab === name) {\n if (openTabs.length) {\n activeTab = index === 0 ? openTabs[0] : openTabs[index - 1];\n } else {\n activeTab = '';\n }\n }\n return { openTabs, activeTab };\n }),\n setActiveTab: (name) => set({ activeTab: name }),\n setBuildError: (name, buildError) =>\n set((state) => {\n if (state.buildErrors[name] === buildError) return state;\n const buildErrors = { ...state.buildErrors };\n if (buildError) buildErrors[name] = buildError;\n else delete buildErrors[name];\n return { buildErrors };\n }),\n setPendingDiff: (name, original, modified, applyId) =>\n set((state) => {\n return {\n pendingDiffs: {\n ...state.pendingDiffs,\n [name]: { original, modified, applyId },\n },\n };\n }),\n clearPendingDiff: (name, accepted) =>\n set((state) => {\n const diff = state.pendingDiffs[name];\n if (!diff) return state;\n const next = { ...state.pendingDiffs };\n delete next[name];\n const ids = state.acceptedApplyIds || [];\n const acceptedApplyIds =\n accepted && diff.applyId\n ? [...ids.slice(-(200 - 1)), diff.applyId]\n : ids;\n return { pendingDiffs: next, acceptedApplyIds };\n }),\n }),\n {\n name: 'documents-storage',\n version: 1,\n storage: createJSONStorage(() => idbStorage),\n partialize: (state) => ({\n documents: state.documents,\n openTabs: state.openTabs,\n activeTab: state.activeTab,\n documentTypes: state.documentTypes,\n // buildErrors + pendingDiffs + acceptedApplyIds excluded — transient UI state\n }),\n onRehydrateStorage: () => (state) => {\n if (state?.documents) {\n for (const doc of state.documents) {\n for (const key of ['mtime', 'ctime', 'atime'] as const) {\n if (doc[key] && typeof doc[key] === 'string') {\n (doc as Record<string, unknown>)[key] = new Date(\n doc[key] as unknown as string\n );\n }\n }\n }\n }\n },\n }\n )\n )\n );\n};\n","import {\n type ReactNode,\n createContext,\n useCallback,\n useRef,\n useContext,\n} from 'react';\nimport { useStore } from 'zustand';\nimport {\n type DocumentsStore,\n createDocumentsStore,\n initDocumentsStore,\n resolveSourceName,\n} from './documents-store';\n\nexport type DocumentsStoreApi = ReturnType<typeof createDocumentsStore>;\n\nexport const DocumentsStoreContext = createContext<\n DocumentsStoreApi | undefined\n>(undefined);\n\nexport interface DocumentsStoreProviderProps {\n children: ReactNode;\n}\n\nexport const DocumentsStoreProvider = ({\n children,\n}: DocumentsStoreProviderProps) => {\n const storeRef = useRef<DocumentsStoreApi | null>(null);\n if (!storeRef.current) {\n storeRef.current = createDocumentsStore(initDocumentsStore());\n }\n\n return (\n <DocumentsStoreContext.Provider value={storeRef.current}>\n {children}\n </DocumentsStoreContext.Provider>\n );\n};\n\nexport const useDocumentsStore = <T,>(\n selector: (store: DocumentsStore) => T\n): T => {\n const documentsStoreContext = useContext(DocumentsStoreContext);\n\n if (!documentsStoreContext) {\n throw new Error(\n 'useDocumentsStore must be used within DocumentsStoreProvider'\n );\n }\n\n return useStore(documentsStoreContext, selector);\n};\n\n/**\n * Stable `docName -> options.sourceName` resolver for generate/preview\n * requests. Reads the store imperatively at call time — no subscription, so\n * callbacks holding it don't re-create on every document edit.\n */\nexport const useResolveSourceName = (): ((docName: string) => string) => {\n const documentsStoreContext = useContext(DocumentsStoreContext);\n\n if (!documentsStoreContext) {\n throw new Error(\n 'useResolveSourceName must be used within DocumentsStoreProvider'\n );\n }\n\n return useCallback(\n (docName: string) =>\n resolveSourceName(documentsStoreContext.getState().documents, docName),\n [documentsStoreContext]\n );\n};\n","import { devtools } from 'zustand/middleware';\nimport { createStore } from 'zustand/vanilla';\nimport type { QualityFinding } from '../lib/quality-findings';\n\nexport interface GenerationWarning {\n component: string;\n message: string;\n severity?: 'warning' | 'info';\n context?: Record<string, unknown>;\n}\n\n/**\n * The last quality analysis, whichever round trip produced it.\n *\n * `/generate` and `/validate` report the same findings in different shapes, so\n * both are normalised into this one slice — the panel should not have to know\n * which endpoint the author's last action happened to hit.\n */\nexport interface QualityState {\n findings: QualityFinding[];\n counts: { error: number; warning: number; info: number };\n /**\n * The document these findings were computed against.\n *\n * Every finding is a JSON Pointer plus, sometimes, an RFC 6902 patch. Both\n * are meaningless against a different file, and a tab switch leaves the panel\n * showing the previous document's findings until a new analysis lands — so\n * \"Apply fix\" and \"Reveal\" must both refuse to act when this no longer names\n * the active tab.\n */\n documentName: string;\n /** Ordering ticket; see lib/quality-sequence.ts. */\n seq: number;\n profileId?: string;\n blocked?: boolean;\n truncated?: boolean;\n /** Which round trip produced this: a full build, or a validate-only pass. */\n source: 'generate' | 'validate';\n analyzedAt: number;\n /**\n * Set only when the run policy's gate actually rejected the build. The panel\n * paints a destructive \"blocked\" state from this, so a transport failure must\n * never land here — it would assert a rejection that never happened, and with\n * the default gate of `none` no gate was even evaluated.\n */\n gateError?: string;\n /** The analysis could not be run (offline, rate limited, server error). */\n analysisError?: string;\n}\n\nexport type OutputState = {\n name?: string; // last success => document name\n text?: string; // last success => code used to generate the document\n blob?: Blob; // last success => generated document\n renderer?: string; // last success => backend captured with the generated bytes\n globalError?: string; // last failed => global error message\n isGenerating?: boolean; // document generation in progress\n generationProgress?: {\n stage: 'parsing' | 'building' | 'rendering' | 'finalizing';\n message?: string;\n };\n generationStartedAt?: number; // Date.now() when the current build started\n cancelGeneration?: () => void; // registered by the editor; aborts the in-flight build\n cacheStatus?: 'HIT' | 'MISS' | 'UNKNOWN'; // cache hit/miss status\n cacheHitRate?: string; // cache hit rate percentage\n warnings?: GenerationWarning[] | null; // warnings from custom component processing\n quality?: QualityState | null; // last quality analysis; null until one runs\n isRendering?: boolean; // preview rendering in progress (iframe/LibreOffice)\n isPreviewStale?: boolean; // preview outdated (new blob generated but not yet rendered)\n editSequence?: number; // incremented on every Monaco keystroke (init 0)\n lastBuiltSequence?: number; // stamped when generation completes (init 0)\n editTimestamp?: number; // Date.now() of the last edit (for debounce countdown)\n hasValidationErrors?: boolean; // true when Monaco reports schema validation errors\n // ⚠️ name doesn't necessarily correspond to the global error message\n};\n\nexport type OutputActions = {\n setOutput: (partialState: OutputState) => void;\n bumpEditSequence: () => void;\n};\n\nexport type OutputStore = OutputState & OutputActions;\n\nexport const initOutputStore = (): OutputState => {\n return {\n name: undefined,\n text: undefined,\n blob: undefined,\n globalError: undefined,\n isGenerating: false,\n generationProgress: undefined,\n isRendering: false,\n isPreviewStale: false,\n editSequence: 0,\n lastBuiltSequence: 0,\n hasValidationErrors: false,\n quality: null,\n };\n};\n\nexport const defaultInitOutputState: OutputState = {\n ...initOutputStore(),\n};\n\nexport const createOutputStore = (\n initState: OutputState = defaultInitOutputState\n) => {\n return createStore<OutputStore>()(\n devtools((set) => ({\n ...initState,\n setOutput: (partialState) => set({ ...partialState }),\n bumpEditSequence: () =>\n set((s) => ({\n editSequence: (s.editSequence ?? 0) + 1,\n editTimestamp: Date.now(),\n })),\n }))\n );\n};\n","import { type ReactNode, createContext, useRef, useContext } from 'react';\nimport { useStore } from 'zustand';\nimport {\n type OutputStore,\n createOutputStore,\n initOutputStore,\n} from './output-store';\n\nexport type OutputStoreApi = ReturnType<typeof createOutputStore>;\n\nexport const OutputStoreContext = createContext<OutputStoreApi | undefined>(\n undefined\n);\n\nexport interface OutputStoreProviderProps {\n children: ReactNode;\n}\n\nexport const OutputStoreProvider = ({ children }: OutputStoreProviderProps) => {\n const storeRef = useRef<OutputStoreApi | null>(null);\n if (!storeRef.current) {\n storeRef.current = createOutputStore(initOutputStore());\n }\n\n return (\n <OutputStoreContext.Provider value={storeRef.current}>\n {children}\n </OutputStoreContext.Provider>\n );\n};\n\nexport const useOutputStore = <T,>(selector: (store: OutputStore) => T): T => {\n const outputStoreContext = useContext(OutputStoreContext);\n\n if (!outputStoreContext) {\n throw new Error('useOutputStore must be used within OutputStoreProvider');\n }\n\n return useStore(outputStoreContext, selector);\n};\n","import { create } from 'zustand';\nimport { persist } from 'zustand/middleware';\nimport type { PluginMetadata } from '../hooks/useDiscovery';\n\ninterface PluginsState {\n // Selected plugin names (used for schema generation)\n selectedPlugins: Set<string>;\n\n // Full plugin metadata for selected plugins\n selectedPluginMetadata: Map<string, PluginMetadata>;\n\n // Schema application state\n isApplyingPlugins: boolean;\n lastApplyError: string | null;\n\n // Actions\n selectPlugin: (plugin: PluginMetadata) => void;\n deselectPlugin: (pluginName: string) => void;\n togglePlugin: (plugin: PluginMetadata) => void;\n clearSelections: () => void;\n isPluginSelected: (pluginName: string) => boolean;\n getSelectedPluginsList: () => PluginMetadata[];\n getSelectedPluginNames: () => string[];\n applyPluginsWithValidation: (\n onSuccess?: () => void,\n onError?: (error: string) => void\n ) => Promise<boolean>;\n}\n\nexport const usePluginsStore = create<PluginsState>()(\n persist(\n (set, get) => ({\n selectedPlugins: new Set<string>(),\n selectedPluginMetadata: new Map<string, PluginMetadata>(),\n isApplyingPlugins: false,\n lastApplyError: null,\n\n selectPlugin: (plugin: PluginMetadata) => {\n set((state) => {\n const newSelectedPlugins = new Set(state.selectedPlugins);\n const newMetadata = new Map(state.selectedPluginMetadata);\n\n newSelectedPlugins.add(plugin.name);\n newMetadata.set(plugin.name, plugin);\n\n return {\n selectedPlugins: newSelectedPlugins,\n selectedPluginMetadata: newMetadata,\n };\n });\n },\n\n deselectPlugin: (pluginName: string) => {\n set((state) => {\n const newSelectedPlugins = new Set(state.selectedPlugins);\n const newMetadata = new Map(state.selectedPluginMetadata);\n\n newSelectedPlugins.delete(pluginName);\n newMetadata.delete(pluginName);\n\n return {\n selectedPlugins: newSelectedPlugins,\n selectedPluginMetadata: newMetadata,\n };\n });\n },\n\n togglePlugin: (plugin: PluginMetadata) => {\n const isSelected = get().isPluginSelected(plugin.name);\n if (isSelected) {\n get().deselectPlugin(plugin.name);\n } else {\n get().selectPlugin(plugin);\n }\n // Auto-apply schema changes\n get().applyPluginsWithValidation().catch(console.error);\n },\n\n clearSelections: () => {\n set({\n selectedPlugins: new Set<string>(),\n selectedPluginMetadata: new Map<string, PluginMetadata>(),\n });\n // Auto-apply schema changes\n get().applyPluginsWithValidation().catch(console.error);\n },\n\n isPluginSelected: (pluginName: string) => {\n return get().selectedPlugins.has(pluginName);\n },\n\n getSelectedPluginsList: () => {\n return Array.from(get().selectedPluginMetadata.values());\n },\n\n getSelectedPluginNames: () => {\n return Array.from(get().selectedPlugins);\n },\n\n applyPluginsWithValidation: async (onSuccess, onError) => {\n set({ isApplyingPlugins: true, lastApplyError: null });\n\n try {\n // Get the current selected plugins\n const selectedPluginNames = Array.from(get().selectedPlugins);\n\n // Import Monaco and schema update function dynamically\n const { loader } = await import('@monaco-editor/react');\n const { updateMonacoWithPlugins } = await import(\n '../lib/monaco-config'\n );\n\n // Get Monaco instance\n const monaco = await loader.init();\n\n // Apply the plugins and wait for validation. Browser plugins ride\n // along from their own store, so toggling a disk plugin never\n // drops them from the schema.\n const { browserComponentsForSchema, useBrowserPluginsStore } =\n await import('./browser-plugins-store');\n const success = await updateMonacoWithPlugins(\n monaco,\n selectedPluginNames,\n undefined,\n browserComponentsForSchema(useBrowserPluginsStore.getState())\n );\n\n if (!success) {\n throw new Error('Schema validation failed');\n }\n\n // Success - schema has been applied and validated\n set({ isApplyingPlugins: false, lastApplyError: null });\n\n if (onSuccess) {\n onSuccess();\n }\n\n return true;\n } catch (error) {\n const errorMessage =\n error instanceof Error\n ? error.message\n : 'Failed to apply plugin schemas';\n\n set({\n isApplyingPlugins: false,\n lastApplyError: errorMessage,\n });\n\n if (onError) {\n onError(errorMessage);\n }\n\n console.error('Failed to apply plugins with validation:', error);\n return false;\n }\n },\n }),\n {\n name: 'jtp-selected-plugins',\n // Custom storage to handle Set and Map serialization\n storage: {\n getItem: (name) => {\n const str = localStorage.getItem(name);\n if (!str) return null;\n\n const { state } = JSON.parse(str);\n return {\n state: {\n ...state,\n selectedPlugins: new Set(state.selectedPlugins || []),\n selectedPluginMetadata: new Map(\n state.selectedPluginMetadata || []\n ),\n },\n };\n },\n setItem: (name, value) => {\n const { state } = value as { state: PluginsState };\n const serialized = JSON.stringify({\n state: {\n ...state,\n selectedPlugins: Array.from(state.selectedPlugins),\n selectedPluginMetadata: Array.from(\n state.selectedPluginMetadata.entries()\n ),\n },\n });\n localStorage.setItem(name, serialized);\n },\n removeItem: (name) => localStorage.removeItem(name),\n },\n }\n )\n);\n","/**\n * Type declarations for the import paths a plugin file uses for the plugin\n * API, mirroring what the published packages export.\n *\n * The runtime behind every one of these is the shared `createComponent` /\n * `createVersion` (see sandbox.worker.ts); what differs per format is the\n * component and theme types `render` sees. Declaring only the plugin API here\n * also makes the shim the allowlist: a plugin that reaches for\n * `generateBufferFromJson` gets a type error in the editor, which is the same\n * answer the sandbox would give at run time.\n */\n\nfunction pluginApiDeclaration(\n sharedPackage: string,\n componentType: string,\n themeType: string\n): string {\n return `import type { TSchema } from '@sinclair/typebox';\nimport type { ${componentType}, ${themeType} } from '${sharedPackage}';\nimport type {\n RenderContext as SharedRenderContext,\n RenderFunction as SharedRenderFunction,\n ComponentVersion as SharedComponentVersion,\n ComponentVersionMap as SharedComponentVersionMap,\n CustomComponent as SharedCustomComponent,\n} from '@json-to-office/shared/plugin';\n\n/** The resolved theme handed to \\`render\\`. */\nexport type ThemeConfig = ${themeType};\n\nexport type RenderContext<T> = SharedRenderContext<T, ${themeType}>;\n\nexport type RenderFunction<\n TProps,\n TComponentDefinition = ${componentType},\n> = SharedRenderFunction<TProps, TComponentDefinition, ${themeType}>;\n\nexport type ComponentVersion<\n TComponentDefinition = ${componentType},\n TPropsSchema extends TSchema = TSchema,\n> = SharedComponentVersion<TComponentDefinition, TPropsSchema, ${themeType}>;\n\nexport type ComponentVersionMap<TComponentDefinition = ${componentType}> =\n SharedComponentVersionMap<TComponentDefinition, ${themeType}>;\n\nexport type CustomComponent<\n TComponentDefinition = ${componentType},\n TVersions extends\n ComponentVersionMap<TComponentDefinition> = ComponentVersionMap<TComponentDefinition>,\n TName extends string = string,\n> = SharedCustomComponent<TComponentDefinition, TVersions, TName>;\n\n/** Create one semver version entry with full type inference for its props. */\nexport declare function createVersion<\n TPropsSchema extends TSchema,\n TComponentDefinition = ${componentType},\n>(\n version: ComponentVersion<TComponentDefinition, TPropsSchema>\n): ComponentVersion<TComponentDefinition, TPropsSchema>;\n\n/** Create a custom component with semver-keyed versions. */\nexport declare function createComponent<\n TComponentDefinition = ${componentType},\n TVersions extends\n ComponentVersionMap<TComponentDefinition> = ComponentVersionMap<TComponentDefinition>,\n TName extends string = string,\n>(\n component: CustomComponent<TComponentDefinition, TVersions, TName>\n): CustomComponent<TComponentDefinition, TVersions, TName>;\n\nexport {\n resolveComponentVersion,\n ComponentValidationError,\n DuplicateComponentError,\n} from '@json-to-office/shared/plugin';\nexport type { ${componentType}, ${themeType} } from '${sharedPackage}';\n`;\n}\n\nconst DOCX_API = pluginApiDeclaration(\n '@json-to-office/shared-docx',\n 'ComponentDefinition',\n 'ThemeConfigJson'\n);\nconst PPTX_API = pluginApiDeclaration(\n '@json-to-office/shared-pptx',\n 'PptxComponentDefinition',\n 'ThemeConfigJson'\n);\n\nfunction manifest(name: string, withPluginSubpath: boolean): string {\n return JSON.stringify(\n {\n name,\n version: '0.0.0-playground',\n types: 'index.d.ts',\n exports: {\n '.': { types: './index.d.ts' },\n ...(withPluginSubpath\n ? { './plugin': { types: './plugin/index.d.ts' } }\n : {}),\n },\n },\n null,\n 2\n );\n}\n\n/**\n * Virtual files keyed like the generated type libs\n * (`node_modules/<pkg>/<file>`).\n */\nexport const PLUGIN_TYPE_SHIMS: Readonly<Record<string, string>> = {\n 'node_modules/@json-to-office/core-docx/package.json': manifest(\n '@json-to-office/core-docx',\n true\n ),\n 'node_modules/@json-to-office/core-docx/index.d.ts': DOCX_API,\n 'node_modules/@json-to-office/core-docx/plugin/index.d.ts': DOCX_API,\n 'node_modules/@json-to-office/json-to-docx/package.json': manifest(\n '@json-to-office/json-to-docx',\n false\n ),\n 'node_modules/@json-to-office/json-to-docx/index.d.ts': DOCX_API,\n 'node_modules/@json-to-office/core-pptx/package.json': manifest(\n '@json-to-office/core-pptx',\n true\n ),\n 'node_modules/@json-to-office/core-pptx/index.d.ts': PPTX_API,\n 'node_modules/@json-to-office/core-pptx/plugin/index.d.ts': PPTX_API,\n 'node_modules/@json-to-office/json-to-pptx/package.json': manifest(\n '@json-to-office/json-to-pptx',\n false\n ),\n 'node_modules/@json-to-office/json-to-pptx/index.d.ts': PPTX_API,\n};\n\n/**\n * Module ids the sandbox resolves to the shared plugin API. Kept next to the\n * declarations above so the editor and the runtime agree on what exists.\n */\nexport const PLUGIN_API_MODULE_IDS: readonly string[] = [\n '@json-to-office/core-docx',\n '@json-to-office/core-docx/plugin',\n '@json-to-office/json-to-docx',\n '@json-to-office/core-pptx',\n '@json-to-office/core-pptx/plugin',\n '@json-to-office/json-to-pptx',\n];\n","import type { Monaco } from '@monaco-editor/react';\nimport { PLUGIN_TYPE_SHIMS } from './type-shims';\n\n/**\n * Configure Monaco's TypeScript service for plugin sources, once.\n *\n * Plugins are emitted as CommonJS so the sandbox can hand them a `require`\n * that resolves only the allowlisted modules. Module resolution is TypeScript's\n * `Bundler` mode (value 100 — Monaco's enum predates it) so the `exports` maps\n * in the virtual package.json files route `@json-to-office/shared/plugin` and\n * friends to their `.d.ts`. The declaration files themselves come from the\n * `virtual:jto-plugin-type-libs` module built by vite.config.ts and are\n * imported lazily: they are large and only a plugin editor needs them.\n */\nlet configured: Promise<void> | null = null;\n\nexport function ensurePluginTypeScript(monaco: Monaco): Promise<void> {\n if (!configured) {\n configured = configure(monaco)\n .then(markReady)\n .catch((error) => {\n configured = null;\n throw error;\n });\n }\n return configured;\n}\n\nasync function configure(monaco: Monaco): Promise<void> {\n const ts = monaco.languages.typescript;\n ts.typescriptDefaults.setCompilerOptions({\n target: ts.ScriptTarget.ES2020,\n module: ts.ModuleKind.CommonJS,\n // ModuleResolutionKind.Bundler; see the module comment.\n moduleResolution: 100 as unknown as typeof ts.ModuleResolutionKind.NodeJs,\n lib: ['es2020', 'dom'],\n strict: true,\n esModuleInterop: true,\n allowSyntheticDefaultImports: true,\n allowNonTsExtensions: true,\n skipLibCheck: true,\n noEmitOnError: false,\n resolveJsonModule: false,\n typeRoots: [],\n types: [],\n });\n // Until the declarations are in, every import is \"Cannot find module\":\n // semantic checking stays off so an editor that opened first does not\n // flash red for the second the download takes.\n ts.typescriptDefaults.setDiagnosticsOptions({\n noSemanticValidation: true,\n noSyntaxValidation: false,\n noSuggestionDiagnostics: true,\n });\n ts.typescriptDefaults.setEagerModelSync(true);\n\n const libs = (await import('virtual:jto-plugin-type-libs')).default;\n const files: Record<string, string> = { ...libs, ...PLUGIN_TYPE_SHIMS };\n for (const [path, content] of Object.entries(files)) {\n ts.typescriptDefaults.addExtraLib(content, `file:///${path}`);\n }\n ts.typescriptDefaults.setDiagnosticsOptions({\n noSemanticValidation: false,\n noSyntaxValidation: false,\n noSuggestionDiagnostics: true,\n });\n}\n\n/** True once the declarations are registered; the editor strip reads it. */\nexport function pluginTypeScriptReady(): boolean {\n return ready;\n}\n\nlet ready = false;\nconst readyListeners = new Set<() => void>();\n\n/** Notified once when the declarations finish loading. */\nexport function onPluginTypeScriptReady(listener: () => void): () => void {\n if (ready) {\n listener();\n return () => {};\n }\n readyListeners.add(listener);\n return () => {\n readyListeners.delete(listener);\n };\n}\n\nfunction markReady(): void {\n ready = true;\n for (const listener of readyListeners) listener();\n readyListeners.clear();\n}\n","import { loader } from '@monaco-editor/react';\nimport type { Monaco } from '@monaco-editor/react';\nimport type { editor as MonacoEditorType } from 'monaco-editor';\nimport { ensurePluginTypeScript } from './type-libs';\nimport { hashSource } from './hash';\nimport type { PluginDiagnostic } from './types';\n\n/**\n * Compile a plugin source with Monaco's TypeScript worker.\n *\n * Headless: the compiler owns one text model per plugin file, at the same\n * URI the editor tab opens, so the two share it — a compile started by the\n * sync hook and the diagnostics the editor shows come from one program.\n * When the model is on screen its live text wins over the store snapshot,\n * which trails the editor by the save debounce.\n */\n\nexport interface CompileResult {\n /** The text that was compiled (the live model text, which may be newer than the store). */\n source: string;\n /** Emitted CommonJS, or null when the source has errors. */\n js: string | null;\n diagnostics: PluginDiagnostic[];\n /** True when the live text matched `skipIfHash` and nothing was compiled. */\n skipped: boolean;\n}\n\nconst MODEL_SCHEME_PATH = 'file:///plugins/';\n\n/** The model URI for a plugin file; the editor tab must use the same path. */\nexport function pluginModelPath(docName: string): string {\n return `${MODEL_SCHEME_PATH}${encodeURIComponent(docName)}`;\n}\n\nfunction isAttachedToEditor(\n monaco: Monaco,\n model: MonacoEditorType.ITextModel\n): boolean {\n return monaco.editor.getEditors().some((e) => e.getModel() === model);\n}\n\ninterface WorkerDiagnostic {\n start?: number;\n length?: number;\n messageText: string | { messageText: string; next?: unknown[] };\n category: number;\n code: number;\n}\n\nfunction flattenMessage(text: WorkerDiagnostic['messageText']): string {\n if (typeof text === 'string') return text;\n const parts: string[] = [text.messageText];\n const queue = Array.isArray(text.next) ? [...text.next] : [];\n while (queue.length > 0) {\n const next = queue.shift() as WorkerDiagnostic['messageText'] | undefined;\n if (!next) continue;\n if (typeof next === 'string') parts.push(next);\n else {\n parts.push(next.messageText);\n if (Array.isArray(next.next)) queue.push(...next.next);\n }\n }\n return parts.join(' ');\n}\n\nfunction toDiagnostic(\n diagnostic: WorkerDiagnostic,\n model: MonacoEditorType.ITextModel\n): PluginDiagnostic {\n // TypeScript's DiagnosticCategory: Warning = 0, Error = 1, Suggestion = 2, Message = 3.\n const severity: PluginDiagnostic['severity'] =\n diagnostic.category === 1\n ? 'error'\n : diagnostic.category === 0\n ? 'warning'\n : 'info';\n const result: PluginDiagnostic = {\n severity,\n message: `${flattenMessage(diagnostic.messageText)} (TS${diagnostic.code})`,\n source: 'typescript',\n };\n if (typeof diagnostic.start === 'number') {\n const start = model.getPositionAt(diagnostic.start);\n const end = model.getPositionAt(\n diagnostic.start + (diagnostic.length ?? 0)\n );\n result.line = start.lineNumber;\n result.column = start.column;\n result.endLine = end.lineNumber;\n result.endColumn = end.column;\n }\n return result;\n}\n\nexport async function compilePlugin(\n docName: string,\n source: string,\n skipIfHash?: string\n): Promise<CompileResult> {\n const monaco = await loader.init();\n await ensurePluginTypeScript(monaco);\n\n const uri = monaco.Uri.parse(pluginModelPath(docName));\n let model = monaco.editor.getModel(uri);\n if (!model) {\n model = monaco.editor.createModel(source, 'typescript', uri);\n } else if (\n model.getValue() !== source &&\n !isAttachedToEditor(monaco, model)\n ) {\n model.setValue(source);\n }\n const text = model.getValue();\n\n // The store trails an open editor by its save debounce, so a sync started\n // from the store can find that the live text is the one it already\n // compiled. Say so instead of compiling it a second time.\n if (skipIfHash !== undefined && hashSource(text) === skipIfHash) {\n return { source: text, js: null, diagnostics: [], skipped: true };\n }\n\n const getWorker = await monaco.languages.typescript.getTypeScriptWorker();\n const client = await getWorker(uri);\n const fileName = uri.toString();\n const [syntactic, semantic, emit] = await Promise.all([\n client.getSyntacticDiagnostics(fileName),\n client.getSemanticDiagnostics(fileName),\n client.getEmitOutput(fileName),\n ]);\n\n const diagnostics = [\n ...(syntactic as unknown as WorkerDiagnostic[]),\n ...(semantic as unknown as WorkerDiagnostic[]),\n ]\n .map((d) => toDiagnostic(d, model!))\n .filter((d) => d.severity !== 'info');\n const hasErrors = diagnostics.some((d) => d.severity === 'error');\n const js =\n emit.outputFiles.find((file) => file.name.endsWith('.js'))?.text ?? null;\n\n return {\n source: text,\n js: hasErrors ? null : js,\n diagnostics,\n skipped: false,\n };\n}\n\n/** Drop the headless model once its file is gone, unless an editor still shows it. */\nexport function disposePluginModel(docName: string): void {\n const monaco = loader.__getMonacoInstance();\n if (!monaco) return;\n const model = monaco.editor.getModel(\n monaco.Uri.parse(pluginModelPath(docName))\n );\n if (model && !isAttachedToEditor(monaco, model)) model.dispose();\n}\n","/**\n * The compile schedule for plugin files.\n *\n * The sync hook debounces compiles behind the editor; Run cannot wait for a\n * debounce it does not know about, so the schedule lives here where both\n * can reach it: the hook registers the runner and schedules, Run flushes\n * everything pending and awaits the queue going idle.\n */\n\ntype Runner = (docName: string) => Promise<void>;\n\nconst noopRunner: Runner = async () => {};\n\nexport class CompileQueue {\n private runner: Runner = noopRunner;\n private timers = new Map<string, ReturnType<typeof setTimeout>>();\n private inFlight = new Map<string, Promise<void>>();\n private queued = new Set<string>();\n private idleWaiters: Array<() => void> = [];\n\n setRunner(runner: Runner): void {\n this.runner = runner;\n }\n\n /** Compile after `delayMs`; a newer schedule for the same file replaces an older one. */\n schedule(docName: string, delayMs: number): void {\n this.cancel(docName);\n this.timers.set(\n docName,\n setTimeout(() => {\n this.timers.delete(docName);\n this.run(docName);\n }, delayMs)\n );\n }\n\n /** Drop a pending schedule (not a compile already running). */\n cancel(docName: string): void {\n const timer = this.timers.get(docName);\n if (timer) clearTimeout(timer);\n this.timers.delete(docName);\n }\n\n /** Compile now, or right after the compile already running for this file. */\n run(docName: string): Promise<void> {\n this.cancel(docName);\n const running = this.inFlight.get(docName);\n if (running) {\n this.queued.add(docName);\n return running.then(\n () => this.inFlight.get(docName) ?? Promise.resolve()\n );\n }\n const task = this.runner(docName)\n .catch(() => {})\n .finally(() => {\n this.inFlight.delete(docName);\n if (this.queued.delete(docName)) {\n this.run(docName);\n } else {\n this.settleIfIdle();\n }\n });\n this.inFlight.set(docName, task);\n return task;\n }\n\n /** Every scheduled compile, started now. */\n flush(): void {\n for (const docName of Array.from(this.timers.keys())) this.run(docName);\n }\n\n get isIdle(): boolean {\n return this.timers.size === 0 && this.inFlight.size === 0;\n }\n\n /** Resolves once nothing is scheduled or running, or after `timeoutMs`. */\n whenIdle(timeoutMs = 15_000): Promise<void> {\n if (this.isIdle) return Promise.resolve();\n return new Promise((resolve) => {\n const timer = setTimeout(done, timeoutMs);\n function done() {\n clearTimeout(timer);\n resolve();\n }\n this.idleWaiters.push(done);\n });\n }\n\n /** Forget everything; used when the owning hook unmounts. */\n reset(): void {\n for (const timer of this.timers.values()) clearTimeout(timer);\n this.timers.clear();\n this.queued.clear();\n this.runner = noopRunner;\n this.settleIfIdle();\n }\n\n private settleIfIdle(): void {\n if (!this.isIdle) return;\n const waiters = this.idleWaiters;\n this.idleWaiters = [];\n for (const waiter of waiters) waiter();\n }\n}\n\nexport const compileQueue = new CompileQueue();\n","import type { PluginExample } from './types';\n\n/**\n * Usage examples embedded in a plugin's source.\n *\n * The same two conventions disk discovery reads (`PluginMetadataExtractor`\n * in jto-cli): a JSDoc `@example` carrying a fenced JSON/TypeScript block,\n * optionally captioned, and a `// Example: {...}` line. A block that holds a\n * whole `{ name, props }` component is reduced to its `props`, so the\n * example is always the props object documents put under the component.\n */\nexport function extractPluginExamples(source: string): PluginExample[] {\n const examples: PluginExample[] = [];\n const normalize = (input: unknown): unknown =>\n input && typeof input === 'object' && 'props' in input\n ? (input as { props: unknown }).props\n : input;\n\n const fenced =\n /@example\\s*(?:<caption>(.*?)<\\/caption>)?\\s*\\*?\\s*```(?:json|typescript|ts)?\\s*([\\s\\S]*?)```/gi;\n let match: RegExpExecArray | null;\n while ((match = fenced.exec(source)) !== null) {\n const title = match[1]?.trim() || undefined;\n const block = match[2]\n .split('\\n')\n .map((line) => line.replace(/^\\s*\\*\\s?/, ''))\n .join('\\n')\n .trim();\n const json = block.match(/\\{[\\s\\S]*\\}/);\n if (!json) continue;\n try {\n examples.push({ title, props: normalize(JSON.parse(json[0])) });\n } catch {\n // A TypeScript object literal rather than JSON: quote the keys and\n // swap single quotes, which covers the examples plugins actually carry.\n const propsMatch = block.match(/props:\\s*\\{[\\s\\S]*?\\}/);\n if (!propsMatch) continue;\n try {\n const cleaned = propsMatch[0]\n .replace(/props:\\s*/, '')\n .replace(/(['\"])?([a-zA-Z0-9_]+)(['\"])?:/g, '\"$2\":')\n .replace(/'/g, '\"')\n .replace(/,(\\s*[}\\]])/g, '$1')\n .replace(/,\\s*$/, '');\n examples.push({ title, props: JSON.parse(cleaned) });\n } catch {}\n }\n }\n\n const inline = /\\/\\/\\s*Example:\\s*(\\{.*?\\})/g;\n while ((match = inline.exec(source)) !== null) {\n try {\n examples.push({ props: normalize(JSON.parse(match[1])) });\n } catch {}\n }\n\n return examples;\n}\n","import { STANDARD_COMPONENTS_REGISTRY } from '@json-to-office/shared-docx';\nimport { PPTX_STANDARD_COMPONENTS_REGISTRY } from '@json-to-office/shared-pptx';\nimport type { PluginFormat } from './types';\n\n/**\n * Component names the format already owns. A browser plugin cannot take one\n * of these: the schema would carry two branches for the same `name` and the\n * expander would swallow a standard component.\n */\nexport function standardComponentNames(format: PluginFormat): Set<string> {\n const registry =\n format === 'docx'\n ? STANDARD_COMPONENTS_REGISTRY\n : PPTX_STANDARD_COMPONENTS_REGISTRY;\n return new Set(registry.map((component) => component.name));\n}\n\n/** Names a plugin may use: what disk discovery accepts, roughly a kebab identifier. */\nexport const PLUGIN_NAME_PATTERN = /^[a-zA-Z][a-zA-Z0-9_-]*$/;\n","/**\n * Types shared by the in-browser plugin system: the compiled record the\n * store keeps, the metadata the sandbox reports, and the wire protocol\n * between the page and a plugin's worker.\n */\n\nexport type PluginFormat = 'docx' | 'pptx';\n\n/** One semver-keyed version of a component, as the sandbox describes it. */\nexport interface PluginVersionMetadata {\n version: string;\n /** The TypeBox props schema, JSON-roundtripped (no Kind symbols). */\n propsSchema: Record<string, unknown>;\n hasChildren: boolean;\n description?: string;\n}\n\nexport interface PluginExample {\n title?: string;\n description?: string;\n props: unknown;\n}\n\nexport interface BrowserPluginMetadata {\n /** The component name documents use in `name`. */\n name: string;\n format: PluginFormat;\n versions: PluginVersionMetadata[];\n latest: string;\n examples: PluginExample[];\n}\n\nexport interface PluginDiagnostic {\n severity: 'error' | 'warning' | 'info';\n message: string;\n /** Who produced it: the TypeScript compiler, the sandbox, or the playground itself. */\n source: 'typescript' | 'sandbox' | 'playground';\n /** Machine-readable kind for playground diagnostics the sync re-evaluates. */\n code?: 'name-conflict' | 'timeout' | 'network-off';\n line?: number;\n column?: number;\n endLine?: number;\n endColumn?: number;\n}\n\nexport type BrowserPluginStatus = 'idle' | 'compiling' | 'ready' | 'error';\n\nexport interface BrowserPluginRecord {\n /** The workspace file this plugin was compiled from (`*.component.ts`). */\n docName: string;\n /** Take part in schema generation and expansion. */\n enabled: boolean;\n /** Leave `fetch` and friends available inside the sandbox. */\n allowNetwork: boolean;\n /**\n * The origins the switch grants, as CSP source expressions. On with an\n * empty list reaches nothing: the switch alone is not a grant.\n */\n networkOrigins?: string[];\n status: BrowserPluginStatus;\n /** Hash of the source `js`/`metadata` were produced from. */\n sourceHash: string;\n /** Compiled CommonJS; present once a compile succeeded. */\n js?: string;\n metadata?: BrowserPluginMetadata;\n diagnostics: PluginDiagnostic[];\n /** When the record was first created; the older of two same-named plugins keeps the name. */\n createdAt: number;\n updatedAt: number;\n}\n\nexport interface PluginRenderWarning {\n message: string;\n context?: Record<string, unknown>;\n}\n\n/**\n * Prefix of the error a sandbox throws when a plugin reaches for the network\n * with its switch off; the page turns it into a diagnostic that names the\n * switch instead of a bare ReferenceError.\n */\nexport const NETWORK_OFF_MARKER = '[plugin-network-off]';\n\n// ---- Sandbox protocol ----\n\nexport interface SandboxLoadRequest {\n id: number;\n type: 'load';\n js: string;\n format: PluginFormat;\n /** Whether anything is reachable at all; the frame's CSP names what. */\n allowNetwork: boolean;\n /** Shown in the error when a call is refused, so it names the allowlist. */\n networkOrigins: string[];\n examples: PluginExample[];\n}\n\nexport interface SandboxRenderRequest {\n id: number;\n type: 'render';\n version?: string;\n props: unknown;\n theme: unknown;\n children?: unknown[];\n}\n\nexport type SandboxRequest = SandboxLoadRequest | SandboxRenderRequest;\n\nexport interface SandboxLoadedResponse {\n id: number;\n type: 'loaded';\n metadata: BrowserPluginMetadata;\n}\n\nexport interface SandboxRenderedResponse {\n id: number;\n type: 'rendered';\n components: unknown[];\n warnings: PluginRenderWarning[];\n}\n\nexport interface SandboxErrorResponse {\n id: number;\n type: 'error';\n message: string;\n stack?: string;\n}\n\nexport type SandboxResponse =\n | SandboxLoadedResponse\n | SandboxRenderedResponse\n | SandboxErrorResponse;\n","import { useContext, useEffect, useRef } from 'react';\nimport { DocumentsStoreContext } from '../store/documents-store-provider';\nimport {\n componentNameOwner,\n useBrowserPluginsStore,\n whenBrowserPluginsHydrated,\n} from '../store/browser-plugins-store';\nimport { compilePlugin, disposePluginModel } from '../lib/plugins/compiler';\nimport { compileQueue } from '../lib/plugins/compile-queue';\nimport { extractPluginExamples } from '../lib/plugins/examples';\nimport { hashSource } from '../lib/plugins/hash';\nimport { pluginHost, PluginTimeoutError } from '../lib/plugins/host';\nimport {\n PLUGIN_NAME_PATTERN,\n standardComponentNames,\n} from '../lib/plugins/names';\nimport {\n NETWORK_OFF_MARKER,\n type BrowserPluginRecord,\n type PluginDiagnostic,\n} from '../lib/plugins/types';\nimport { FORMAT } from '../lib/env';\n\n/**\n * Keep every `*.component.ts` file compiled.\n *\n * Watches the documents store: a plugin file whose text no longer matches\n * the hash its record was built from is recompiled after a short debounce,\n * loaded into its sandbox to be described, and checked for a name the format\n * already uses. A file that disappears takes its record, its sandbox and its\n * Monaco model with it. Compilation reads the live editor model when the\n * file is open, so what runs is what is on screen, not the last save.\n *\n * Name conflicts are re-judged without recompiling whenever the set of\n * records changes: the metadata is kept on a conflicting record, so the\n * newcomer becomes ready the moment the owner is renamed or deleted.\n */\n\nconst COMPILE_DEBOUNCE_MS = 400;\n\nconst PLUGIN_TYPE = 'application/typescript+plugin';\n\n/** Fired on `window` after a plugin finished compiling, ready or not. */\nexport const BROWSER_PLUGINS_CHANGED_EVENT = 'browser-plugins:changed';\n\nfunction announceChange(docName: string): void {\n window.dispatchEvent(\n new CustomEvent(BROWSER_PLUGINS_CHANGED_EVENT, { detail: { docName } })\n );\n}\n\nfunction conflictDiagnostic(message: string): PluginDiagnostic {\n return {\n severity: 'error',\n source: 'playground',\n code: 'name-conflict',\n message,\n };\n}\n\n/** A sandbox failure, worded for the author. */\nfunction sandboxDiagnostic(error: unknown): PluginDiagnostic {\n const message = error instanceof Error ? error.message : String(error);\n if (message.includes(NETWORK_OFF_MARKER)) {\n return {\n severity: 'error',\n source: 'playground',\n code: 'network-off',\n message: message.replace(NETWORK_OFF_MARKER, '').trim(),\n };\n }\n if (error instanceof PluginTimeoutError) {\n return {\n severity: 'error',\n source: 'sandbox',\n code: 'timeout',\n message: `${message} Edit the file to compile it again.`,\n };\n }\n return { severity: 'error', source: 'sandbox', message };\n}\n\nexport function useBrowserPluginsSync(\n diskPluginNames: readonly string[]\n): void {\n const documentsStore = useContext(DocumentsStoreContext);\n if (!documentsStore) {\n throw new Error(\n 'useBrowserPluginsSync must be used within DocumentsStoreProvider'\n );\n }\n // Read at compile time rather than captured: discovery finishes after the\n // first compile more often than not.\n const diskNamesRef = useRef<readonly string[]>(diskPluginNames);\n diskNamesRef.current = diskPluginNames;\n\n useEffect(() => {\n let disposed = false;\n\n /** Why `componentName` cannot be `docName`'s, or null when it can. */\n const nameConflict = (\n docName: string,\n componentName: string\n ): string | null => {\n if (!PLUGIN_NAME_PATTERN.test(componentName)) {\n return `Component name \"${componentName}\" must start with a letter and contain only letters, digits, \"-\" and \"_\".`;\n }\n if (standardComponentNames(FORMAT).has(componentName)) {\n return `\"${componentName}\" is a built-in ${FORMAT} component; choose another name.`;\n }\n if (diskNamesRef.current.includes(componentName)) {\n return `\"${componentName}\" is already provided by a plugin on disk; choose another name or disable that plugin.`;\n }\n const owner = componentNameOwner(\n useBrowserPluginsStore.getState().records,\n componentName\n );\n if (owner && owner !== docName) {\n return `\"${componentName}\" is already defined by ${owner}; rename one of them.`;\n }\n return null;\n };\n\n /**\n * Re-judge every settled record's name without compiling. Only the\n * conflict diagnostic moves; TypeScript and sandbox diagnostics stay.\n */\n const reconcileConflicts = (): void => {\n const store = useBrowserPluginsStore.getState();\n for (const record of Object.values(store.records)) {\n if (\n !record.metadata ||\n record.status === 'compiling' ||\n record.status === 'idle'\n ) {\n continue;\n }\n const others = record.diagnostics.filter(\n (d) => d.code !== 'name-conflict'\n );\n const hadConflict = others.length !== record.diagnostics.length;\n const conflict = nameConflict(record.docName, record.metadata.name);\n const otherErrors = others.some((d) => d.severity === 'error');\n if (conflict && !hadConflict) {\n store.upsert(record.docName, {\n status: 'error',\n diagnostics: [...others, conflictDiagnostic(conflict)],\n });\n } else if (!conflict && hadConflict) {\n store.upsert(record.docName, {\n status: otherErrors || !record.js ? 'error' : 'ready',\n diagnostics: others,\n });\n announceChange(record.docName);\n }\n }\n };\n\n const compileNow = async (docName: string): Promise<void> => {\n const doc = documentsStore\n .getState()\n .documents.find((d) => d.name === docName);\n if (!doc || disposed) return;\n const store = useBrowserPluginsStore.getState();\n const record = store.records[docName];\n const hash = hashSource(doc.text);\n const current =\n record &&\n record.sourceHash === hash &&\n (record.status === 'ready' || record.status === 'error');\n if (current) return;\n\n // A settled record may already describe the live editor text, which the\n // store has not caught up with yet; the compiler checks before working.\n const settled: BrowserPluginRecord | undefined =\n record && (record.status === 'ready' || record.status === 'error')\n ? record\n : undefined;\n store.upsert(docName, {\n status: 'compiling',\n sourceHash: hash,\n diagnostics: [],\n });\n try {\n const compiled = await compilePlugin(\n docName,\n doc.text,\n settled?.sourceHash\n );\n if (disposed) return;\n if (compiled.skipped && settled) {\n useBrowserPluginsStore.getState().upsert(docName, {\n status: settled.status,\n sourceHash: settled.sourceHash,\n diagnostics: settled.diagnostics,\n });\n return;\n }\n const finalHash = hashSource(compiled.source);\n if (!compiled.js) {\n pluginHost.dispose(docName);\n useBrowserPluginsStore.getState().upsert(docName, {\n status: 'error',\n sourceHash: finalHash,\n js: undefined,\n metadata: undefined,\n diagnostics: compiled.diagnostics,\n });\n announceChange(docName);\n return;\n }\n const record = useBrowserPluginsStore.getState().records[docName];\n const metadata = await pluginHost.load(docName, {\n js: compiled.js,\n format: FORMAT,\n allowNetwork: record?.allowNetwork ?? false,\n networkOrigins: record?.networkOrigins,\n examples: extractPluginExamples(compiled.source),\n });\n if (disposed) return;\n // The record must carry its metadata before the ownership check, or\n // it cannot own its own name.\n useBrowserPluginsStore.getState().upsert(docName, {\n status: 'ready',\n sourceHash: finalHash,\n js: compiled.js,\n metadata,\n diagnostics: compiled.diagnostics,\n });\n const conflict = nameConflict(docName, metadata.name);\n if (conflict) {\n useBrowserPluginsStore.getState().upsert(docName, {\n status: 'error',\n diagnostics: [\n ...compiled.diagnostics,\n conflictDiagnostic(conflict),\n ],\n });\n }\n reconcileConflicts();\n announceChange(docName);\n } catch (error) {\n if (disposed) return;\n pluginHost.dispose(docName);\n useBrowserPluginsStore.getState().upsert(docName, {\n status: 'error',\n sourceHash: hash,\n js: undefined,\n metadata: undefined,\n diagnostics: [sandboxDiagnostic(error)],\n });\n reconcileConflicts();\n announceChange(docName);\n }\n };\n\n const reconcile = (): void => {\n const { documents, documentTypes } = documentsStore.getState();\n const pluginDocs = documents.filter(\n (d) => documentTypes[d.name] === PLUGIN_TYPE\n );\n const present = new Set(pluginDocs.map((d) => d.name));\n const pluginsStore = useBrowserPluginsStore.getState();\n let removed = false;\n for (const name of Object.keys(pluginsStore.records)) {\n if (!present.has(name)) {\n pluginsStore.remove(name);\n pluginHost.dispose(name);\n disposePluginModel(name);\n compileQueue.cancel(name);\n removed = true;\n }\n }\n if (removed) reconcileConflicts();\n for (const doc of pluginDocs) {\n const record = pluginsStore.records[doc.name];\n const stale =\n !record ||\n record.sourceHash !== hashSource(doc.text) ||\n record.status === 'idle' ||\n record.status === 'compiling';\n if (stale) compileQueue.schedule(doc.name, COMPILE_DEBOUNCE_MS);\n }\n };\n\n compileQueue.setRunner(compileNow);\n let unsubscribe: (() => void) | undefined;\n // The persisted records arrive from IndexedDB; a reconcile before that\n // would compile everything and then be overwritten by the read.\n whenBrowserPluginsHydrated().then(() => {\n if (disposed) return;\n reconcile();\n unsubscribe = documentsStore.subscribe((state, previous) => {\n if (\n state.documents !== previous.documents ||\n state.documentTypes !== previous.documentTypes\n ) {\n reconcile();\n }\n });\n });\n\n return () => {\n disposed = true;\n unsubscribe?.();\n compileQueue.reset();\n };\n }, [documentsStore]);\n}\n","import { devtools, persist } from 'zustand/middleware';\nimport { createStore } from 'zustand/vanilla';\nimport type { Settings } from '../lib/types';\n\nexport type SettingsState = Settings;\n\nexport type SettingsActions = {\n setSettings: (settings: Partial<Settings>) => void;\n};\n\nexport type SettingsStore = SettingsState & SettingsActions;\n\nexport const initSettingsStore = (): SettingsState => {\n return {\n saveDocumentDebounceWait: 300,\n // UI preference to use a single preview header spanning editor + preview\n useGlobalPreviewHeader: true,\n // Report, never block: a gate is something an author opts into once they\n // know what the profile flags, not a default that refuses their first\n // build.\n qualityGate: 'none',\n // Warning-and-above, deliberately. The shipped PPTX templates produce\n // roughly two hundred info-severity findings, so an info default would\n // bury the panel in noise the first time it is opened and teach authors\n // to ignore it.\n qualityMinSeverity: 'warning',\n };\n};\n\nexport const defaultInitSettingsState: SettingsState = {\n ...initSettingsStore(),\n};\n\nexport const createSettingsStore = (\n initState: SettingsState = defaultInitSettingsState\n) => {\n return createStore<SettingsStore>()(\n devtools(\n persist(\n (set) => ({\n ...initState,\n setSettings: (settings) => set({ ...settings }),\n }),\n {\n name: 'settings-storage', // name of the item in the storage (must be unique)\n // (optional) by default, 'localStorage' is used as storage\n }\n )\n )\n );\n};\n","import { type ReactNode, createContext, useRef, useContext } from 'react';\nimport { useStore } from 'zustand';\nimport {\n type SettingsStore,\n createSettingsStore,\n initSettingsStore,\n} from './settings-store';\n\nexport type SettingsStoreApi = ReturnType<typeof createSettingsStore>;\n\nexport const SettingsStoreContext = createContext<SettingsStoreApi | undefined>(\n undefined\n);\n\nexport interface SettingsStoreProviderProps {\n children: ReactNode;\n}\n\nexport const SettingsStoreProvider = ({\n children,\n}: SettingsStoreProviderProps) => {\n const storeRef = useRef<SettingsStoreApi | null>(null);\n if (!storeRef.current) {\n storeRef.current = createSettingsStore(initSettingsStore());\n }\n\n return (\n <SettingsStoreContext.Provider value={storeRef.current}>\n {children}\n </SettingsStoreContext.Provider>\n );\n};\n\nexport const useSettingsStore = <T,>(\n selector: (store: SettingsStore) => T\n): T => {\n const settingsStoreContext = useContext(SettingsStoreContext);\n\n if (!settingsStoreContext) {\n throw new Error(\n 'useSettingsStore must be used within SettingsStoreProvider'\n );\n }\n\n return useStore(settingsStoreContext, selector);\n};\n","import { useBrowserPluginsSync } from '../hooks/useBrowserPluginsSync';\n\n/**\n * Mounts the browser-plugin sync once, under the documents store it watches.\n */\nexport function BrowserPluginsProvider({\n diskPluginNames,\n children,\n}: {\n diskPluginNames: readonly string[];\n children: React.ReactNode;\n}) {\n useBrowserPluginsSync(diskPluginNames);\n return <>{children}</>;\n}\n","import { useEffect, useRef, useContext, useSyncExternalStore } from 'react';\nimport { loader } from '@monaco-editor/react';\nimport type { Monaco } from '@monaco-editor/react';\nimport { usePluginsStore } from '../store/plugins-store';\nimport {\n activePluginsSignature,\n browserComponentsForSchema,\n useBrowserPluginsStore,\n} from '../store/browser-plugins-store';\nimport { ThemesStoreContext } from '../store/themes-store-provider';\nimport { updateMonacoWithPlugins } from '../lib/monaco-config';\n\nconst emptyNames: string[] = [];\nconst subscribe = () => () => {};\n\n/**\n * Read custom theme names from the ThemesStore if available,\n * returning [] when outside a ThemesStoreProvider.\n *\n * getSnapshot must return a referentially stable value to avoid\n * infinite re-renders with useSyncExternalStore.\n */\nfunction useCustomThemeNames(): string[] {\n const store = useContext(ThemesStoreContext);\n const cachedRef = useRef<string[]>(emptyNames);\n\n const getSnapshot = store\n ? () => {\n const next = store.getState().getAllThemeNames();\n // Only update the cached reference when the list actually changes\n if (\n next.length !== cachedRef.current.length ||\n next.some((n, i) => n !== cachedRef.current[i])\n ) {\n cachedRef.current = next;\n }\n return cachedRef.current;\n }\n : () => emptyNames;\n\n return useSyncExternalStore(store ? store.subscribe : subscribe, getSnapshot);\n}\n\n/**\n * Hook to synchronize selected plugins and custom themes with Monaco editor schemas.\n * Ensures real-time validation and autocomplete include plugin-specific schemas\n * and custom theme names.\n */\nexport function useMonacoPlugins() {\n const monacoRef = useRef<Monaco | null>(null);\n const selectedPlugins = usePluginsStore((state) => state.selectedPlugins);\n const selectedPluginNames = Array.from(selectedPlugins);\n const customThemeNames = useCustomThemeNames();\n // A string that changes exactly when the active browser plugins or their\n // schemas change — cheaper to compare than the records themselves.\n const browserSignature = useBrowserPluginsStore(activePluginsSignature);\n const themesStore = useContext(ThemesStoreContext);\n const themesStoreRef = useRef(themesStore);\n themesStoreRef.current = themesStore;\n const previousPluginsRef = useRef<string[]>([]);\n const previousThemesRef = useRef<string[]>([]);\n const previousBrowserRef = useRef<string>('');\n\n useEffect(() => {\n loader\n .init()\n .then((monaco) => {\n monacoRef.current = monaco;\n // Read current state from stores (not stale closure) since\n // zustand persist may have hydrated while loader.init() was pending\n const currentPlugins = Array.from(\n usePluginsStore.getState().selectedPlugins\n );\n const currentThemes =\n themesStoreRef.current?.getState().getAllThemeNames() ?? [];\n const browserState = useBrowserPluginsStore.getState();\n updateMonacoWithPlugins(\n monaco,\n currentPlugins,\n currentThemes,\n browserComponentsForSchema(browserState)\n )\n .then((success) => {\n if (success) {\n console.log(\n '[useMonacoPlugins] Monaco initialized with plugins:',\n currentPlugins\n );\n } else {\n console.warn(\n '[useMonacoPlugins] Monaco initialization completed with warnings'\n );\n }\n })\n .catch((error) => {\n console.error(\n '[useMonacoPlugins] Failed to update Monaco with plugins:',\n error\n );\n });\n previousPluginsRef.current = [...currentPlugins];\n previousThemesRef.current = [...currentThemes];\n previousBrowserRef.current = activePluginsSignature(browserState);\n })\n .catch((error) => {\n console.error('Failed to initialize Monaco:', error);\n });\n }, []); // Keep empty dependency to run only once\n\n useEffect(() => {\n const pluginsChanged =\n selectedPluginNames.length !== previousPluginsRef.current.length ||\n selectedPluginNames.some(\n (name, index) => name !== previousPluginsRef.current[index]\n );\n\n const themesChanged =\n customThemeNames.length !== previousThemesRef.current.length ||\n customThemeNames.some(\n (name, index) => name !== previousThemesRef.current[index]\n );\n\n const browserChanged = browserSignature !== previousBrowserRef.current;\n\n if (!pluginsChanged && !themesChanged && !browserChanged) {\n return;\n }\n\n if (monacoRef.current) {\n updateMonacoWithPlugins(\n monacoRef.current,\n selectedPluginNames,\n customThemeNames,\n browserComponentsForSchema(useBrowserPluginsStore.getState())\n ).catch((error) => {\n console.error(\n '[useMonacoPlugins] Failed to update Monaco schemas:',\n error\n );\n });\n previousPluginsRef.current = [...selectedPluginNames];\n previousThemesRef.current = [...customThemeNames];\n previousBrowserRef.current = browserSignature;\n }\n }, [selectedPluginNames, customThemeNames, browserSignature]);\n\n return {\n monaco: monacoRef.current,\n selectedPlugins: selectedPluginNames,\n };\n}\n","import { useMonacoPlugins } from '../hooks/useMonacoPlugins';\n\n/**\n * Provider component that manages Monaco plugin synchronization\n * This must be rendered within the app after stores are initialized\n */\nexport function MonacoPluginProvider({\n children,\n}: {\n children: React.ReactNode;\n}) {\n // Initialize Monaco plugin synchronization\n useMonacoPlugins();\n\n return <>{children}</>;\n}\n"],"file":"assets/MonacoPluginProvider-FJHgHgFQ.js"}