@embedpdf/core 2.0.0-next.1 → 2.0.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/lib/utils/dependency-resolver.ts","../src/lib/types/errors.ts","../src/lib/store/plugin-store.ts","../src/lib/store/actions.ts","../src/lib/store/store.ts","../src/lib/store/initial-state.ts","../src/lib/store/reducer-helpers.ts","../src/lib/store/reducer.ts","../src/lib/utils/event-control.ts","../src/lib/utils/math.ts","../src/lib/plugin/builder.ts","../src/lib/base/base-plugin.ts","../src/lib/registry/plugin-registry.ts","../src/lib/utils/eventing.ts","../src/lib/utils/plugin-helpers.ts","../src/lib/utils/scoped-eventing.ts","../src/lib/utils/typed-object.ts","../src/lib/store/selectors.ts","../src/lib/types/plugin.ts"],"sourcesContent":["export class DependencyResolver {\n private dependencyGraph = new Map<string, Set<string>>();\n\n addNode(id: string, dependencies: string[] = []) {\n this.dependencyGraph.set(id, new Set(dependencies));\n }\n\n private hasCircularDependencies(): boolean {\n const visited = new Set<string>();\n const recursionStack = new Set<string>();\n\n const dfs = (id: string): boolean => {\n visited.add(id);\n recursionStack.add(id);\n\n const dependencies = this.dependencyGraph.get(id) || new Set();\n for (const dep of dependencies) {\n if (!visited.has(dep)) {\n if (dfs(dep)) return true;\n } else if (recursionStack.has(dep)) {\n return true; // Circular dependency found\n }\n }\n\n recursionStack.delete(id);\n return false;\n };\n\n for (const id of this.dependencyGraph.keys()) {\n if (!visited.has(id)) {\n if (dfs(id)) return true;\n }\n }\n\n return false;\n }\n\n resolveLoadOrder(): string[] {\n if (this.hasCircularDependencies()) {\n throw new Error('Circular dependencies detected');\n }\n\n const result: string[] = [];\n const visited = new Set<string>();\n const temp = new Set<string>();\n\n const visit = (id: string) => {\n if (temp.has(id)) throw new Error('Circular dependency');\n if (visited.has(id)) return;\n\n temp.add(id);\n\n const dependencies = this.dependencyGraph.get(id) || new Set();\n for (const dep of dependencies) {\n visit(dep);\n }\n\n temp.delete(id);\n visited.add(id);\n result.push(id);\n };\n\n for (const id of this.dependencyGraph.keys()) {\n if (!visited.has(id)) {\n visit(id);\n }\n }\n\n return result;\n }\n}\n","export class PluginRegistrationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PluginRegistrationError';\n }\n}\n\nexport class PluginNotFoundError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PluginNotFoundError';\n }\n}\n\nexport class CircularDependencyError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'CircularDependencyError';\n }\n}\n\nexport class CapabilityNotFoundError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'CapabilityNotFoundError';\n }\n}\n\n// You might also want to add:\nexport class CapabilityConflictError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'CapabilityConflictError';\n }\n}\n\nexport class PluginInitializationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PluginInitializationError';\n }\n}\n\nexport class PluginConfigurationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PluginConfigurationError';\n }\n}\n","import { Store } from './store';\nimport { Action } from './types';\n\n/**\n * A type-safe store handle for plugins, providing access to plugin-specific state and actions.\n */\nexport class PluginStore<PluginState, PluginAction extends Action> {\n private store: Store<any, any>;\n private pluginId: string;\n\n /**\n * Initializes the PluginStore with the main store and plugin ID.\n * @param store The main store instance.\n * @param pluginId The unique identifier for the plugin.\n */\n constructor(store: Store<any, any>, pluginId: string) {\n this.store = store;\n this.pluginId = pluginId;\n }\n\n /**\n * Gets the current state of the plugin.\n * @returns The plugin's state.\n */\n getState(): PluginState {\n return this.store.getState().plugins[this.pluginId] as PluginState;\n }\n\n /**\n * Dispatches an action for the plugin and returns the *new* global state.\n * If you only need the plugin’s updated state, call `getState()` afterward.\n * @param action The action to dispatch.\n * @returns The updated global store state (after plugin reducer).\n */\n dispatch(action: PluginAction): PluginState {\n return this.store.dispatchToPlugin(this.pluginId, action);\n }\n\n /**\n * Subscribes to state changes only for this specific plugin.\n * You now receive (action, newPluginState, oldPluginState) in the callback.\n *\n * @param listener The callback to invoke when plugin state changes.\n * @returns A function to unsubscribe the listener.\n */\n subscribeToState(\n listener: (action: PluginAction, newState: PluginState, oldState: PluginState) => void,\n ) {\n return this.store.subscribeToPlugin(this.pluginId, (action, newPluginState, oldPluginState) => {\n listener(\n action as PluginAction,\n newPluginState as PluginState,\n oldPluginState as PluginState,\n );\n });\n }\n\n /**\n * Subscribes to a specific action type for the plugin.\n * This still uses the main store's `onAction`, so you get the *global*\n * old/new store states there. If you specifically want old/new plugin state,\n * use `subscribeToState` instead.\n *\n * @param type The action type to listen for.\n * @param handler The callback to invoke when the action occurs.\n * @returns A function to unsubscribe the handler.\n */\n onAction<T extends PluginAction['type']>(\n type: T,\n handler: (\n action: Extract<PluginAction, { type: T }>,\n state: PluginState,\n oldState: PluginState,\n ) => void,\n ) {\n return this.store.onAction(type, (action, state, oldState) => {\n handler(\n action as Extract<PluginAction, { type: T }>,\n state.plugins[this.pluginId] as PluginState,\n oldState.plugins[this.pluginId] as PluginState,\n );\n });\n }\n}\n","import { PdfDocumentObject, PdfErrorCode, PdfPageObject, Rotation } from '@embedpdf/models';\n\n// Document lifecycle actions\nexport const START_LOADING_DOCUMENT = 'START_LOADING_DOCUMENT';\nexport const UPDATE_DOCUMENT_LOADING_PROGRESS = 'UPDATE_DOCUMENT_LOADING_PROGRESS';\nexport const SET_DOCUMENT_LOADED = 'SET_DOCUMENT_LOADED';\nexport const SET_DOCUMENT_ERROR = 'SET_DOCUMENT_ERROR';\nexport const RETRY_LOADING_DOCUMENT = 'RETRY_LOADING_DOCUMENT';\nexport const CLOSE_DOCUMENT = 'CLOSE_DOCUMENT';\nexport const SET_ACTIVE_DOCUMENT = 'SET_ACTIVE_DOCUMENT';\n\n// Reorder document actions\nexport const REORDER_DOCUMENTS = 'REORDER_DOCUMENTS';\nexport const MOVE_DOCUMENT = 'MOVE_DOCUMENT';\n\n// Document-specific actions\nexport const REFRESH_DOCUMENT = 'REFRESH_DOCUMENT';\nexport const REFRESH_PAGES = 'REFRESH_PAGES';\nexport const SET_PAGES = 'SET_PAGES';\nexport const SET_SCALE = 'SET_SCALE';\nexport const SET_ROTATION = 'SET_ROTATION';\n\n// Global default actions\nexport const SET_DEFAULT_SCALE = 'SET_DEFAULT_SCALE';\nexport const SET_DEFAULT_ROTATION = 'SET_DEFAULT_ROTATION';\n\nexport const CORE_ACTION_TYPES = [\n START_LOADING_DOCUMENT,\n UPDATE_DOCUMENT_LOADING_PROGRESS,\n SET_DOCUMENT_LOADED,\n CLOSE_DOCUMENT,\n SET_ACTIVE_DOCUMENT,\n SET_DOCUMENT_ERROR,\n RETRY_LOADING_DOCUMENT,\n REFRESH_DOCUMENT,\n REFRESH_PAGES,\n SET_PAGES,\n SET_SCALE,\n SET_ROTATION,\n SET_DEFAULT_SCALE,\n SET_DEFAULT_ROTATION,\n REORDER_DOCUMENTS,\n MOVE_DOCUMENT,\n] as const;\n\n// ─────────────────────────────────────────────────────────\n// Document Lifecycle Actions\n// ─────────────────────────────────────────────────────────\n\nexport interface StartLoadingDocumentAction {\n type: typeof START_LOADING_DOCUMENT;\n payload: {\n documentId: string;\n name?: string;\n scale?: number;\n rotation?: Rotation;\n passwordProvided?: boolean;\n autoActivate?: boolean; // If true, this document becomes active when opened. Default: true\n };\n}\n\nexport interface UpdateDocumentLoadingProgressAction {\n type: typeof UPDATE_DOCUMENT_LOADING_PROGRESS;\n payload: {\n documentId: string;\n progress: number;\n };\n}\n\nexport interface SetDocumentLoadedAction {\n type: typeof SET_DOCUMENT_LOADED;\n payload: {\n documentId: string;\n document: PdfDocumentObject;\n };\n}\n\nexport interface SetDocumentErrorAction {\n type: typeof SET_DOCUMENT_ERROR;\n payload: {\n documentId: string;\n error: string;\n errorCode?: PdfErrorCode;\n errorDetails?: any;\n };\n}\n\nexport interface RetryLoadingDocumentAction {\n type: typeof RETRY_LOADING_DOCUMENT;\n payload: {\n documentId: string;\n passwordProvided?: boolean;\n };\n}\n\nexport interface CloseDocumentAction {\n type: typeof CLOSE_DOCUMENT;\n payload: {\n documentId: string;\n nextActiveDocumentId?: string | null; // Optional: what to activate next\n };\n}\n\nexport interface SetActiveDocumentAction {\n type: typeof SET_ACTIVE_DOCUMENT;\n payload: string | null; // documentId or null\n}\n\nexport interface ReorderDocumentsAction {\n type: typeof REORDER_DOCUMENTS;\n payload: string[]; // New order\n}\n\nexport interface MoveDocumentAction {\n type: typeof MOVE_DOCUMENT;\n payload: {\n documentId: string;\n toIndex: number;\n };\n}\n\n// ─────────────────────────────────────────────────────────\n// Document-Specific Actions\n// ─────────────────────────────────────────────────────────\n\nexport interface RefreshDocumentAction {\n type: typeof REFRESH_DOCUMENT;\n payload: {\n documentId: string;\n document: PdfDocumentObject;\n };\n}\n\nexport interface RefreshPagesAction {\n type: typeof REFRESH_PAGES;\n payload: {\n documentId: string;\n pageIndexes: number[];\n };\n}\n\nexport interface SetPagesAction {\n type: typeof SET_PAGES;\n payload: {\n documentId: string;\n pages: PdfPageObject[][];\n };\n}\n\nexport interface SetScaleAction {\n type: typeof SET_SCALE;\n payload: {\n documentId?: string; // If not provided, applies to active document\n scale: number;\n };\n}\n\nexport interface SetRotationAction {\n type: typeof SET_ROTATION;\n payload: {\n documentId?: string; // If not provided, applies to active document\n rotation: Rotation;\n };\n}\n\n// ─────────────────────────────────────────────────────────\n// Global Default Actions\n// ─────────────────────────────────────────────────────────\n\nexport interface SetDefaultScaleAction {\n type: typeof SET_DEFAULT_SCALE;\n payload: number;\n}\n\nexport interface SetDefaultRotationAction {\n type: typeof SET_DEFAULT_ROTATION;\n payload: Rotation;\n}\n\nexport type DocumentAction =\n | StartLoadingDocumentAction\n | UpdateDocumentLoadingProgressAction\n | SetDocumentLoadedAction\n | SetDocumentErrorAction\n | RetryLoadingDocumentAction\n | CloseDocumentAction\n | SetActiveDocumentAction\n | RefreshDocumentAction\n | RefreshPagesAction\n | SetPagesAction\n | SetScaleAction\n | SetRotationAction\n | SetDefaultScaleAction\n | SetDefaultRotationAction\n | ReorderDocumentsAction\n | MoveDocumentAction;\n\n// Core actions\nexport type CoreAction = DocumentAction;\n\n// ─────────────────────────────────────────────────────────\n// Action Creators\n// ─────────────────────────────────────────────────────────\nexport const startLoadingDocument = (\n documentId: string,\n name?: string,\n scale?: number,\n rotation?: Rotation,\n passwordProvided?: boolean,\n autoActivate?: boolean,\n): CoreAction => ({\n type: START_LOADING_DOCUMENT,\n payload: { documentId, name, scale, rotation, passwordProvided, autoActivate },\n});\n\nexport const updateDocumentLoadingProgress = (\n documentId: string,\n progress: number,\n): CoreAction => ({\n type: UPDATE_DOCUMENT_LOADING_PROGRESS,\n payload: { documentId, progress },\n});\n\nexport const setDocumentLoaded = (documentId: string, document: PdfDocumentObject): CoreAction => ({\n type: SET_DOCUMENT_LOADED,\n payload: { documentId, document },\n});\n\nexport const setDocumentError = (\n documentId: string,\n error: string,\n errorCode?: PdfErrorCode,\n errorDetails?: any,\n): CoreAction => ({\n type: SET_DOCUMENT_ERROR,\n payload: { documentId, error, errorCode, errorDetails },\n});\n\nexport const retryLoadingDocument = (\n documentId: string,\n passwordProvided?: boolean,\n): CoreAction => ({\n type: RETRY_LOADING_DOCUMENT,\n payload: { documentId, passwordProvided },\n});\n\nexport const closeDocument = (\n documentId: string,\n nextActiveDocumentId?: string | null,\n): CoreAction => ({\n type: CLOSE_DOCUMENT,\n payload: { documentId, nextActiveDocumentId },\n});\n\nexport const setActiveDocument = (documentId: string | null): CoreAction => ({\n type: SET_ACTIVE_DOCUMENT,\n payload: documentId,\n});\n\nexport const refreshDocument = (documentId: string, document: PdfDocumentObject): CoreAction => ({\n type: REFRESH_DOCUMENT,\n payload: { documentId, document },\n});\n\nexport const refreshPages = (documentId: string, pageIndexes: number[]): CoreAction => ({\n type: REFRESH_PAGES,\n payload: { documentId, pageIndexes },\n});\n\nexport const setPages = (documentId: string, pages: PdfPageObject[][]): CoreAction => ({\n type: SET_PAGES,\n payload: { documentId, pages },\n});\n\nexport const setScale = (scale: number, documentId?: string): CoreAction => ({\n type: SET_SCALE,\n payload: { scale, documentId },\n});\n\nexport const setRotation = (rotation: Rotation, documentId?: string): CoreAction => ({\n type: SET_ROTATION,\n payload: { rotation, documentId },\n});\n\nexport const setDefaultScale = (scale: number): CoreAction => ({\n type: SET_DEFAULT_SCALE,\n payload: scale,\n});\n\nexport const setDefaultRotation = (rotation: Rotation): CoreAction => ({\n type: SET_DEFAULT_ROTATION,\n payload: rotation,\n});\n\nexport const reorderDocuments = (order: string[]): CoreAction => ({\n type: REORDER_DOCUMENTS,\n payload: order,\n});\n\nexport const moveDocument = (documentId: string, toIndex: number): CoreAction => ({\n type: MOVE_DOCUMENT,\n payload: { documentId, toIndex },\n});\n","import { Reducer, Action, StoreState, StoreListener, PluginListener } from './types';\nimport { PluginStore } from './plugin-store';\nimport { CORE_ACTION_TYPES } from './actions';\n\n/**\n * A generic, type-safe store class managing core and plugin states, reducers, and subscriptions.\n * @template CoreState The type of the core state.\n * @template CoreAction The type of actions handled by core reducers (extends Action).\n */\nexport class Store<CoreState, CoreAction extends Action = Action> {\n private state: StoreState<CoreState>;\n private coreReducer: Reducer<CoreState, CoreAction>;\n private pluginReducers: Record<string, Reducer<any, Action>> = {};\n\n private listeners: StoreListener<CoreState>[] = [];\n private pluginListeners: Record<string, PluginListener[]> = {};\n\n // Prevents re-entrant dispatch during reducer execution (like Redux)\n private isDispatching = false;\n\n /**\n * Initializes the store with the provided core state.\n * @param reducer The core reducer function\n * @param initialCoreState The initial core state\n */\n constructor(\n reducer: Reducer<CoreState, CoreAction>,\n public initialCoreState: CoreState,\n ) {\n this.state = { core: initialCoreState, plugins: {} };\n this.coreReducer = reducer;\n }\n\n /**\n * Adds a reducer for a plugin-specific state.\n * @param pluginId The unique identifier for the plugin.\n * @param reducer The reducer function for the plugin state.\n * @param initialState The initial state for the plugin.\n */\n addPluginReducer<PluginState>(\n pluginId: string,\n reducer: Reducer<PluginState, Action>,\n initialState: PluginState,\n ) {\n this.state.plugins[pluginId] = initialState;\n this.pluginReducers[pluginId] = reducer;\n }\n\n /**\n * Dispatches an action *only* to the core reducer.\n * Notifies the global store listeners with (action, newState, oldState).\n *\n * @param action The action to dispatch, typed as CoreAction\n * @returns The updated *global* store state\n */\n dispatchToCore(action: CoreAction): StoreState<CoreState> {\n if (!this.coreReducer) {\n return this.getState();\n }\n\n if (this.isDispatching) {\n throw new Error(\n 'Reducers may not dispatch actions. ' +\n 'To trigger cascading actions, dispatch from a listener callback instead.',\n );\n }\n\n const oldState = this.getState();\n\n try {\n this.isDispatching = true;\n // Update core state via its reducer\n this.state.core = this.coreReducer(this.state.core, action);\n } finally {\n // Always reset flag, even if reducer throws\n this.isDispatching = false;\n }\n\n // Notify all main-store subscribers (can now safely dispatch)\n // Get fresh state for each listener to handle nested dispatches correctly\n this.listeners.forEach((listener) => {\n const currentState = this.getState(); // Fresh snapshot for each listener\n listener(action, currentState, oldState);\n });\n\n return this.getState();\n }\n\n /**\n * Dispatches an action *only* to a specific plugin.\n * Optionally notifies global store listeners if `notifyGlobal` is true.\n * Always notifies plugin-specific listeners with (action, newPluginState, oldPluginState).\n *\n * @param pluginId The plugin identifier\n * @param action The plugin action to dispatch\n * @param notifyGlobal Whether to also notify global store listeners\n * @returns The updated plugin state\n */\n dispatchToPlugin<PluginAction extends Action>(\n pluginId: string,\n action: PluginAction,\n notifyGlobal: boolean = true,\n ): any {\n if (this.isDispatching) {\n throw new Error(\n 'Reducers may not dispatch actions. ' +\n 'To trigger cascading actions, dispatch from a listener callback instead.',\n );\n }\n\n const oldGlobalState = this.getState();\n\n const reducer = this.pluginReducers[pluginId];\n if (!reducer) {\n // No plugin found, just return the old state\n return oldGlobalState.plugins[pluginId];\n }\n\n // Grab the old plugin state\n const oldPluginState = oldGlobalState.plugins[pluginId];\n\n try {\n this.isDispatching = true;\n // Reduce to new plugin state\n const newPluginState = reducer(oldPluginState, action);\n // Update the store's plugin slice\n this.state.plugins[pluginId] = newPluginState;\n } finally {\n this.isDispatching = false;\n }\n\n // Notify listeners (can now safely dispatch)\n // Get fresh state for each listener to handle nested dispatches correctly\n if (notifyGlobal) {\n this.listeners.forEach((listener) => {\n const currentGlobalState = this.getState(); // Fresh snapshot for each listener\n listener(action, currentGlobalState, oldGlobalState);\n });\n }\n\n // Notify plugin-specific listeners\n // Get fresh plugin state for each listener\n if (this.pluginListeners[pluginId]) {\n this.pluginListeners[pluginId].forEach((listener) => {\n const currentPluginState = this.getState().plugins[pluginId]; // Fresh snapshot for each listener\n listener(action, currentPluginState, oldPluginState);\n });\n }\n\n return this.getState().plugins[pluginId];\n }\n\n /**\n * Dispatches an action to update the state using:\n * - the core reducer (if it's a CoreAction)\n * - *all* plugin reducers (regardless of action type), with no global notify for each plugin\n *\n * Returns the new *global* store state after all reducers have processed the action.\n *\n * @param action The action to dispatch (can be CoreAction or any Action).\n */\n dispatch(action: CoreAction | Action): StoreState<CoreState> {\n if (this.isDispatching) {\n throw new Error(\n 'Reducers may not dispatch actions. ' +\n 'To trigger cascading actions, dispatch from a listener callback instead.',\n );\n }\n\n const oldState = this.getState();\n\n try {\n this.isDispatching = true;\n\n // 1) Apply core reducer (only if action is a CoreAction)\n if (this.isCoreAction(action)) {\n this.state.core = this.coreReducer(this.state.core, action);\n }\n\n // 2) Apply plugin reducers (without globally notifying after each plugin)\n for (const pluginId in this.pluginReducers) {\n const reducer = this.pluginReducers[pluginId];\n const oldPluginState = oldState.plugins[pluginId];\n if (reducer) {\n this.state.plugins[pluginId] = reducer(oldPluginState, action);\n }\n }\n } finally {\n this.isDispatching = false;\n }\n\n // 3) Notify global listeners *once* with the final new state (can now safely dispatch)\n // Get fresh state for each listener to handle nested dispatches correctly\n this.listeners.forEach((listener) => {\n const currentState = this.getState(); // Fresh snapshot for each listener\n listener(action, currentState, oldState);\n });\n\n // 4) Return the new global store state\n return this.getState();\n }\n\n /**\n * Returns a shallow copy of the current state.\n * @returns The current store state.\n */\n getState(): StoreState<CoreState> {\n if (this.isDispatching) {\n throw new Error(\n 'You may not call store.getState() while the reducer is executing. ' +\n 'The reducer has already received the state as an argument. ' +\n 'Pass it down from the top reducer instead of reading it from the store.',\n );\n }\n\n return {\n core: { ...this.state.core },\n plugins: { ...this.state.plugins },\n };\n }\n\n /**\n * Subscribes a listener to *global* state changes.\n * The callback signature is now (action, newState, oldState).\n *\n * @param listener The callback to invoke on state changes\n * @returns A function to unsubscribe the listener\n */\n subscribe(listener: StoreListener<CoreState>) {\n if (this.isDispatching) {\n throw new Error(\n 'You may not call store.subscribe() while the reducer is executing. ' +\n 'If you would like to be notified after the store has been updated, subscribe from a ' +\n 'component and invoke store.getState() in the callback to access the latest state.',\n );\n }\n\n this.listeners.push(listener);\n return () => {\n if (this.isDispatching) {\n throw new Error(\n 'You may not unsubscribe from a store listener while the reducer is executing.',\n );\n }\n this.listeners = this.listeners.filter((l) => l !== listener);\n };\n }\n\n /**\n * Subscribes a listener to *plugin-specific* state changes.\n * The callback signature is now (action, newPluginState, oldPluginState).\n *\n * @param pluginId The unique identifier for the plugin.\n * @param listener The callback to invoke on plugin state changes.\n * @returns A function to unsubscribe the listener.\n */\n subscribeToPlugin(pluginId: string, listener: PluginListener) {\n if (!(pluginId in this.state.plugins)) {\n throw new Error(\n `Plugin state not found for plugin \"${pluginId}\". Did you forget to call addPluginReducer?`,\n );\n }\n\n if (this.isDispatching) {\n throw new Error('You may not call store.subscribeToPlugin() while the reducer is executing.');\n }\n\n if (!this.pluginListeners[pluginId]) {\n this.pluginListeners[pluginId] = [];\n }\n this.pluginListeners[pluginId].push(listener);\n\n return () => {\n if (this.isDispatching) {\n throw new Error(\n 'You may not unsubscribe from a store listener while the reducer is executing.',\n );\n }\n this.pluginListeners[pluginId] = this.pluginListeners[pluginId].filter((l) => l !== listener);\n if (this.pluginListeners[pluginId].length === 0) {\n delete this.pluginListeners[pluginId];\n }\n };\n }\n\n /**\n * Subscribes to a specific action type (only from the core's action union).\n * The callback signature is (action, newState, oldState).\n *\n * @param type The action type to listen for.\n * @param handler The callback to invoke when the action occurs.\n * @returns A function to unsubscribe the handler.\n */\n onAction<T extends CoreAction['type']>(\n type: T,\n handler: (\n action: Extract<CoreAction, { type: T }>,\n state: StoreState<CoreState>,\n oldState: StoreState<CoreState>,\n ) => void,\n ) {\n return this.subscribe((action, newState, oldState) => {\n if (action.type === type) {\n handler(action as Extract<CoreAction, { type: T }>, newState, oldState);\n }\n });\n }\n\n /**\n * Gets a PluginStore handle for a specific plugin.\n * @param pluginId The unique identifier for the plugin.\n * @returns A PluginStore instance for the plugin.\n */\n getPluginStore<PluginState, PluginAction extends Action>(\n pluginId: string,\n ): PluginStore<PluginState, PluginAction> {\n if (!(pluginId in this.state.plugins)) {\n throw new Error(\n `Plugin state not found for plugin \"${pluginId}\". Did you forget to call addPluginReducer?`,\n );\n }\n return new PluginStore<PluginState, PluginAction>(this, pluginId);\n }\n\n /**\n * Helper method to check if an action is a CoreAction.\n * Adjust if you have a more refined way to differentiate CoreAction vs. any other Action.\n */\n public isCoreAction(action: Action): action is CoreAction {\n return CORE_ACTION_TYPES.includes(action.type as (typeof CORE_ACTION_TYPES)[number]);\n }\n\n /**\n * Destroy the store: drop every listener and plugin reducer\n */\n public destroy(): void {\n // 1. empty listener collections\n this.listeners.length = 0;\n for (const id in this.pluginListeners) {\n this.pluginListeners[id]?.splice?.(0);\n }\n this.pluginListeners = {};\n\n // 2. wipe plugin reducers and states\n this.pluginReducers = {};\n this.state.plugins = {};\n\n // 3. reset core state to initial\n this.state.core = { ...this.initialCoreState };\n }\n}\n","import { PdfDocumentObject, PdfErrorCode, Rotation } from '@embedpdf/models';\nimport { PluginRegistryConfig } from '../types/plugin';\n\nexport type DocumentStatus = 'loading' | 'loaded' | 'error';\n\nexport interface DocumentState {\n id: string;\n name?: string;\n // Lifecycle status\n status: DocumentStatus;\n\n // Loading progress (0-100)\n loadingProgress?: number;\n\n // Error information (when status is 'error')\n error: string | null;\n errorCode?: PdfErrorCode;\n errorDetails?: any;\n\n // Track if this load attempt included a password\n passwordProvided?: boolean;\n\n // Document data (null when loading or error)\n document: PdfDocumentObject | null;\n\n // View settings (set even during loading for when it succeeds)\n scale: number;\n rotation: Rotation;\n\n // Maps page index (0-based) to refresh version number\n // When a page is refreshed, its version is incremented\n pageRefreshVersions: Record<number, number>;\n\n // Metadata\n loadStartedAt: number;\n loadedAt?: number;\n}\n\nexport interface CoreState {\n documents: Record<string, DocumentState>;\n documentOrder: string[];\n activeDocumentId: string | null;\n defaultScale: number;\n defaultRotation: Rotation;\n}\n\nexport const initialCoreState: (config?: PluginRegistryConfig) => CoreState = (config) => ({\n documents: {},\n documentOrder: [],\n activeDocumentId: null,\n defaultScale: config?.defaultScale ?? 1,\n defaultRotation: config?.defaultRotation ?? Rotation.Degree0,\n});\n","import { CoreState } from './initial-state';\n\n/**\n * Calculate the next active document when closing a document.\n * Returns the document to activate, or null if no documents remain.\n */\nexport function calculateNextActiveDocument(\n state: CoreState,\n closingDocumentId: string,\n explicitNext?: string | null,\n): string | null {\n const currentActiveId = state.activeDocumentId;\n\n // Only calculate if we're closing the active document\n if (currentActiveId !== closingDocumentId) {\n return currentActiveId;\n }\n\n // If explicit next was provided, validate and use it\n if (explicitNext !== undefined) {\n // Validate that the document exists\n return explicitNext && state.documents[explicitNext] ? explicitNext : null;\n }\n\n // Auto-calculate: Try left, then right, then null\n const closingIndex = state.documentOrder.indexOf(closingDocumentId);\n\n if (closingIndex === -1) {\n // Document not in order (shouldn't happen)\n return null;\n }\n\n // Try left first\n if (closingIndex > 0) {\n return state.documentOrder[closingIndex - 1];\n }\n\n // Try right\n if (closingIndex < state.documentOrder.length - 1) {\n return state.documentOrder[closingIndex + 1];\n }\n\n // No other documents\n return null;\n}\n\n/**\n * Reorder a document within the documentOrder array.\n * Returns the new order, or null if the operation is invalid.\n */\nexport function moveDocumentInOrder(\n currentOrder: string[],\n documentId: string,\n toIndex: number,\n): string[] | null {\n const fromIndex = currentOrder.indexOf(documentId);\n\n // Validation\n if (fromIndex === -1) return null;\n if (toIndex < 0 || toIndex >= currentOrder.length) return null;\n if (fromIndex === toIndex) return null;\n\n // Calculate new order\n const newOrder = [...currentOrder];\n newOrder.splice(fromIndex, 1);\n newOrder.splice(toIndex, 0, documentId);\n\n return newOrder;\n}\n","import { Reducer } from './types';\nimport { CoreState, DocumentState } from './initial-state';\nimport {\n CoreAction,\n START_LOADING_DOCUMENT,\n UPDATE_DOCUMENT_LOADING_PROGRESS,\n SET_DOCUMENT_LOADED,\n SET_DOCUMENT_ERROR,\n RETRY_LOADING_DOCUMENT,\n CLOSE_DOCUMENT,\n SET_ACTIVE_DOCUMENT,\n SET_ROTATION,\n SET_SCALE,\n REFRESH_PAGES,\n REORDER_DOCUMENTS,\n MOVE_DOCUMENT,\n} from './actions';\nimport { calculateNextActiveDocument, moveDocumentInOrder } from './reducer-helpers';\n\nexport const coreReducer: Reducer<CoreState, CoreAction> = (state, action): CoreState => {\n switch (action.type) {\n case START_LOADING_DOCUMENT: {\n const {\n documentId,\n name,\n scale,\n rotation,\n passwordProvided,\n autoActivate = true,\n } = action.payload;\n\n const newDocState: DocumentState = {\n id: documentId,\n name,\n status: 'loading',\n loadingProgress: 0,\n error: null,\n document: null,\n scale: scale ?? state.defaultScale,\n rotation: rotation ?? state.defaultRotation,\n passwordProvided: passwordProvided ?? false,\n pageRefreshVersions: {},\n loadStartedAt: Date.now(),\n };\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: newDocState,\n },\n documentOrder: [...state.documentOrder, documentId],\n // Only activate if autoActivate is true (default), or if no document is currently active\n activeDocumentId:\n autoActivate || !state.activeDocumentId ? documentId : state.activeDocumentId,\n };\n }\n\n case UPDATE_DOCUMENT_LOADING_PROGRESS: {\n const { documentId, progress } = action.payload;\n const docState = state.documents[documentId];\n\n if (!docState || docState.status !== 'loading') return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...docState,\n loadingProgress: progress,\n },\n },\n };\n }\n\n case SET_DOCUMENT_LOADED: {\n const { documentId, document } = action.payload;\n const docState = state.documents[documentId];\n\n if (!docState) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...docState,\n status: 'loaded',\n document,\n error: null,\n errorCode: undefined,\n errorDetails: undefined,\n passwordProvided: undefined,\n loadedAt: Date.now(),\n },\n },\n };\n }\n\n case SET_DOCUMENT_ERROR: {\n const { documentId, error, errorCode, errorDetails } = action.payload;\n const docState = state.documents[documentId];\n\n if (!docState) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...docState,\n status: 'error',\n error,\n errorCode,\n errorDetails,\n },\n },\n };\n }\n\n case RETRY_LOADING_DOCUMENT: {\n const { documentId, passwordProvided } = action.payload;\n const docState = state.documents[documentId];\n\n if (!docState || docState.status !== 'error') return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...docState,\n status: 'loading',\n loadingProgress: 0,\n error: null,\n errorCode: undefined,\n errorDetails: undefined,\n passwordProvided: passwordProvided ?? false,\n loadStartedAt: Date.now(),\n },\n },\n };\n }\n\n case CLOSE_DOCUMENT: {\n const { documentId, nextActiveDocumentId } = action.payload;\n const { [documentId]: removed, ...remainingDocs } = state.documents;\n\n return {\n ...state,\n documents: remainingDocs,\n documentOrder: state.documentOrder.filter((id) => id !== documentId),\n activeDocumentId: calculateNextActiveDocument(state, documentId, nextActiveDocumentId),\n };\n }\n\n case MOVE_DOCUMENT: {\n const { documentId, toIndex } = action.payload;\n const newOrder = moveDocumentInOrder(state.documentOrder, documentId, toIndex);\n\n // If invalid, return unchanged state\n if (!newOrder) return state;\n\n return {\n ...state,\n documentOrder: newOrder,\n };\n }\n\n case REORDER_DOCUMENTS: {\n return {\n ...state,\n documentOrder: action.payload,\n };\n }\n\n case SET_ACTIVE_DOCUMENT: {\n return {\n ...state,\n activeDocumentId: action.payload,\n };\n }\n\n case SET_SCALE: {\n const { scale, documentId } = action.payload;\n const targetId = documentId ?? state.activeDocumentId;\n\n if (!targetId) return state;\n\n const docState = state.documents[targetId];\n if (!docState) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [targetId]: {\n ...docState,\n scale,\n },\n },\n };\n }\n\n case SET_ROTATION: {\n const { rotation, documentId } = action.payload;\n const targetId = documentId ?? state.activeDocumentId;\n\n if (!targetId) return state;\n\n const docState = state.documents[targetId];\n if (!docState) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [targetId]: {\n ...docState,\n rotation,\n },\n },\n };\n }\n\n case REFRESH_PAGES: {\n const { documentId, pageIndexes } = action.payload;\n const docState = state.documents[documentId];\n\n if (!docState) return state;\n\n // Convert 1-based page numbers to 0-based indices and increment versions\n const newVersions = { ...docState.pageRefreshVersions };\n for (const pageIndex of pageIndexes) {\n newVersions[pageIndex] = (newVersions[pageIndex] || 0) + 1;\n }\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...docState,\n pageRefreshVersions: newVersions,\n },\n },\n };\n }\n\n default:\n return state;\n }\n};\n","export type EventHandler<T> = (data: T) => void;\n\nexport interface BaseEventControlOptions {\n wait: number;\n}\n\nexport interface DebounceOptions extends BaseEventControlOptions {\n mode: 'debounce';\n}\n\nexport interface ThrottleOptions extends BaseEventControlOptions {\n mode: 'throttle';\n throttleMode?: 'leading-trailing' | 'trailing';\n}\n\nexport interface KeyedDebounceOptions<T> extends BaseEventControlOptions {\n mode: 'debounce';\n keyExtractor: (data: T) => string | number;\n}\n\nexport interface KeyedThrottleOptions<T> extends BaseEventControlOptions {\n mode: 'throttle';\n throttleMode?: 'leading-trailing' | 'trailing';\n keyExtractor: (data: T) => string | number;\n}\n\nexport type EventControlOptions<T = any> =\n | DebounceOptions\n | ThrottleOptions\n | KeyedDebounceOptions<T>\n | KeyedThrottleOptions<T>;\n\nexport class EventControl<T> {\n private timeoutId?: number;\n private lastRun: number = 0;\n\n constructor(\n private handler: EventHandler<T>,\n private options: DebounceOptions | ThrottleOptions,\n ) {}\n\n handle = (data: T): void => {\n if (this.options.mode === 'debounce') {\n this.debounce(data);\n } else {\n this.throttle(data);\n }\n };\n\n private debounce(data: T): void {\n if (this.timeoutId) {\n window.clearTimeout(this.timeoutId);\n }\n\n this.timeoutId = window.setTimeout(() => {\n this.handler(data);\n this.timeoutId = undefined;\n }, this.options.wait);\n }\n\n private throttle(data: T): void {\n if (this.options.mode === 'debounce') return;\n\n const now = Date.now();\n const throttleMode = this.options.throttleMode || 'leading-trailing';\n\n if (now - this.lastRun >= this.options.wait) {\n if (throttleMode === 'leading-trailing') {\n this.handler(data);\n }\n this.lastRun = now;\n }\n\n // Always schedule the trailing execution\n if (this.timeoutId) {\n window.clearTimeout(this.timeoutId);\n }\n\n this.timeoutId = window.setTimeout(\n () => {\n this.handler(data);\n this.lastRun = Date.now();\n this.timeoutId = undefined;\n },\n this.options.wait - (now - this.lastRun),\n );\n }\n\n destroy(): void {\n if (this.timeoutId) {\n window.clearTimeout(this.timeoutId);\n }\n }\n}\n\n/**\n * Event control with independent debouncing/throttling per key.\n * Useful when events carry a discriminator (like documentId) and\n * you want to debounce/throttle each key's events independently.\n *\n * @example\n * // Debounce viewport resize events independently per document\n * const control = new KeyedEventControl(\n * (event) => recalcZoom(event.documentId),\n * { mode: 'debounce', wait: 150, keyExtractor: (e) => e.documentId }\n * );\n * control.handle(event); // Each documentId gets its own 150ms debounce\n */\nexport class KeyedEventControl<T> {\n private controls = new Map<string, EventControl<T>>();\n private readonly baseOptions: DebounceOptions | ThrottleOptions;\n\n constructor(\n private handler: EventHandler<T>,\n private options: KeyedDebounceOptions<T> | KeyedThrottleOptions<T>,\n ) {\n // Extract base options without keyExtractor for individual EventControls\n this.baseOptions = {\n mode: options.mode,\n wait: options.wait,\n ...(options.mode === 'throttle' && 'throttleMode' in options\n ? { throttleMode: options.throttleMode }\n : {}),\n } as DebounceOptions | ThrottleOptions;\n }\n\n handle = (data: T): void => {\n const key = String(this.options.keyExtractor(data));\n\n let control = this.controls.get(key);\n if (!control) {\n control = new EventControl(this.handler, this.baseOptions);\n this.controls.set(key, control);\n }\n\n control.handle(data);\n };\n\n destroy(): void {\n for (const control of this.controls.values()) {\n control.destroy();\n }\n this.controls.clear();\n }\n}\n\n/**\n * Type guard to check if options are keyed\n */\nexport function isKeyedOptions<T>(\n options: EventControlOptions<T>,\n): options is KeyedDebounceOptions<T> | KeyedThrottleOptions<T> {\n return 'keyExtractor' in options;\n}\n","/**\n * Restrict a numeric value to the inclusive range [min, max].\n *\n * @example\n * clamp( 5, 0, 10) // 5\n * clamp(-3, 0, 10) // 0\n * clamp(17, 0, 10) // 10\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value < min ? min : value > max ? max : value;\n}\n\n/**\n * Deeply compares two values (objects, arrays, primitives)\n * with the following rules:\n * - Objects are compared ignoring property order.\n * - Arrays are compared ignoring element order (multiset comparison).\n * - Primitives are compared by strict equality.\n * - null/undefined are treated as normal primitives.\n *\n * @param a First value\n * @param b Second value\n * @param visited Used internally to detect cycles\n */\nexport function arePropsEqual(a: any, b: any, visited?: Set<any>): boolean {\n // Quick path for reference equality or same primitive\n if (a === b) {\n return true;\n }\n\n // Handle null/undefined mismatch\n if (a == null || b == null) {\n // If one is null/undefined and the other isn't, no match\n return a === b;\n }\n\n // Check types\n const aType = typeof a;\n const bType = typeof b;\n if (aType !== bType) return false;\n\n // If they are both objects or arrays, handle recursively\n if (aType === 'object') {\n // Optionally handle cyclical references\n if (!visited) visited = new Set();\n const pairId = getPairId(a, b);\n if (visited.has(pairId)) {\n // Already compared these two objects => assume true to avoid infinite recursion\n // or return false if you want to treat cycles as inequality\n return true;\n }\n visited.add(pairId);\n\n const aIsArray = Array.isArray(a);\n const bIsArray = Array.isArray(b);\n if (aIsArray && bIsArray) {\n // Compare as arrays ignoring order\n return arraysEqualUnordered(a, b, visited);\n } else if (!aIsArray && !bIsArray) {\n // Compare as plain objects (order of properties doesn't matter)\n return objectsEqual(a, b, visited);\n } else {\n // One is array, the other is object => not equal\n return false;\n }\n }\n\n // If both are function, symbol, etc. - typically we might say false\n // But you can decide your own logic for function or symbol equality\n return false;\n}\n\nfunction getPairId(a: any, b: any) {\n // Could do something more advanced. This is a cheap approach:\n // e.g. use the memory reference or an object identity approach\n return `${objectId(a)}__${objectId(b)}`;\n}\n\n/**\n * If you want stable object IDs, you'd need a WeakMap to store them.\n * This simplistic approach just calls toString on the object.\n */\nlet objectIdCounter = 0;\nconst objectIds = new WeakMap<object, number>();\n\nfunction objectId(obj: object): number {\n if (!objectIds.has(obj)) {\n objectIds.set(obj, ++objectIdCounter);\n }\n return objectIds.get(obj)!;\n}\n\nfunction arraysEqualUnordered(a: any[], b: any[], visited?: Set<any>): boolean {\n if (a.length !== b.length) return false;\n\n const used = new Array<boolean>(b.length).fill(false);\n\n // For each element in a, find an unused matching element in b\n outer: for (let i = 0; i < a.length; i++) {\n const elemA = a[i];\n for (let j = 0; j < b.length; j++) {\n if (used[j]) continue; // already used that slot\n if (arePropsEqual(elemA, b[j], visited)) {\n used[j] = true;\n continue outer; // found match for a[i], proceed\n }\n }\n // If we never found a match\n return false;\n }\n\n return true;\n}\n\nfunction objectsEqual(a: object, b: object, visited?: Set<any>): boolean {\n // Get all prop keys\n const aKeys = Object.keys(a).sort();\n const bKeys = Object.keys(b).sort();\n if (aKeys.length !== bKeys.length) return false;\n\n // Compare each property name\n for (let i = 0; i < aKeys.length; i++) {\n if (aKeys[i] !== bKeys[i]) return false;\n }\n\n // Compare each property value\n for (const key of aKeys) {\n // @ts-ignore\n const valA = a[key];\n // @ts-ignore\n const valB = b[key];\n if (!arePropsEqual(valA, valB, visited)) {\n return false;\n }\n }\n return true;\n}\n","import {\n PluginPackage,\n WithAutoMount,\n AutoMountElement,\n StandaloneComponent,\n ContainerComponent,\n IPlugin,\n} from '../types/plugin';\nimport { Action } from '../store/types';\n\nexport class PluginPackageBuilder<\n T extends IPlugin<TConfig>,\n TConfig = unknown,\n TState = unknown,\n TAction extends Action = Action,\n> {\n private package: PluginPackage<T, TConfig, TState, TAction>;\n private autoMountElements: AutoMountElement[] = [];\n\n constructor(basePackage: PluginPackage<T, TConfig, TState, TAction>) {\n this.package = basePackage;\n }\n\n addUtility(component: StandaloneComponent): this {\n this.autoMountElements.push({ component, type: 'utility' });\n return this;\n }\n\n addWrapper(component: ContainerComponent): this {\n this.autoMountElements.push({ component, type: 'wrapper' });\n return this;\n }\n\n build(): WithAutoMount<PluginPackage<T, TConfig, TState, TAction>> {\n return {\n ...this.package,\n autoMountElements: () => this.autoMountElements,\n };\n }\n}\n\n// Helper function for cleaner API\nexport function createPluginPackage<\n T extends IPlugin<TConfig>,\n TConfig = unknown,\n TState = unknown,\n TAction extends Action = Action,\n>(basePackage: PluginPackage<T, TConfig, TState, TAction>) {\n return new PluginPackageBuilder(basePackage);\n}\n","import { IPlugin } from '../types/plugin';\nimport { PluginRegistry } from '../registry/plugin-registry';\nimport {\n Action,\n CLOSE_DOCUMENT,\n CoreAction,\n CoreState,\n PluginStore,\n SET_ACTIVE_DOCUMENT,\n SET_DOCUMENT_LOADED,\n SET_ROTATION,\n SET_SCALE,\n START_LOADING_DOCUMENT,\n Store,\n StoreState,\n} from '../store';\nimport { Logger, PdfEngine } from '@embedpdf/models';\nimport { DocumentState } from '../store/initial-state';\n\nexport interface StateChangeHandler<TState> {\n (state: TState): void;\n}\n\nexport abstract class BasePlugin<\n TConfig = unknown,\n TCapability = unknown,\n TState = unknown,\n TAction extends Action = Action,\n> implements IPlugin<TConfig>\n{\n static readonly id: string;\n\n protected pluginStore: PluginStore<TState, TAction>;\n protected coreStore: Store<CoreState, CoreAction>;\n protected readonly logger: Logger;\n protected readonly engine: PdfEngine;\n\n // Track cooldown actions (renamed from debouncedActions)\n private cooldownActions: Record<string, number> = {};\n private debouncedTimeouts: Record<string, number> = {};\n private unsubscribeFromState: (() => void) | null = null;\n private unsubscribeFromCoreStore: (() => void) | null = null;\n private unsubscribeFromStartLoadingDocument: (() => void) | null = null;\n private unsubscribeFromSetDocumentLoaded: (() => void) | null = null;\n private unsubscribeFromCloseDocument: (() => void) | null = null;\n private unsubscribeFromSetScale: (() => void) | null = null;\n private unsubscribeFromSetRotation: (() => void) | null = null;\n\n private _capability?: Readonly<TCapability>;\n\n private readyPromise: Promise<void>;\n private readyResolve!: () => void;\n\n constructor(\n public readonly id: string,\n protected registry: PluginRegistry,\n ) {\n if (id !== (this.constructor as typeof BasePlugin).id) {\n throw new Error(\n `Plugin ID mismatch: ${id} !== ${(this.constructor as typeof BasePlugin).id}`,\n );\n }\n this.engine = this.registry.getEngine();\n this.logger = this.registry.getLogger();\n this.coreStore = this.registry.getStore();\n this.pluginStore = this.coreStore.getPluginStore<TState, TAction>(this.id);\n this.unsubscribeFromState = this.pluginStore.subscribeToState((action, newState, oldState) => {\n this.onStoreUpdated(oldState, newState);\n });\n this.unsubscribeFromCoreStore = this.coreStore.subscribe((action, newState, oldState) => {\n this.onCoreStoreUpdated(oldState, newState);\n if (newState.core.activeDocumentId !== oldState.core.activeDocumentId) {\n this.onActiveDocumentChanged(\n oldState.core.activeDocumentId,\n newState.core.activeDocumentId,\n );\n }\n });\n this.unsubscribeFromStartLoadingDocument = this.coreStore.onAction(\n START_LOADING_DOCUMENT,\n (action) => {\n this.onDocumentLoadingStarted(action.payload.documentId);\n },\n );\n this.unsubscribeFromSetDocumentLoaded = this.coreStore.onAction(\n SET_DOCUMENT_LOADED,\n (action) => {\n this.onDocumentLoaded(action.payload.documentId);\n },\n );\n this.unsubscribeFromCloseDocument = this.coreStore.onAction(CLOSE_DOCUMENT, (action) => {\n this.onDocumentClosed(action.payload.documentId);\n });\n this.unsubscribeFromSetScale = this.coreStore.onAction(SET_SCALE, (action, state) => {\n const targetId = action.payload.documentId ?? state.core.activeDocumentId;\n if (targetId) {\n this.onScaleChanged(targetId, action.payload.scale);\n }\n });\n this.unsubscribeFromSetRotation = this.coreStore.onAction(SET_ROTATION, (action, state) => {\n const targetId = action.payload.documentId ?? state.core.activeDocumentId;\n if (targetId) {\n this.onRotationChanged(targetId, action.payload.rotation);\n }\n });\n\n // Initialize ready state\n this.readyPromise = new Promise((resolve) => {\n this.readyResolve = resolve;\n });\n // By default, plugins are ready immediately\n this.readyResolve();\n }\n\n /** Construct the public capability (called once & cached). */\n protected abstract buildCapability(): TCapability;\n\n public provides(): Readonly<TCapability> {\n if (!this._capability) {\n const cap = this.buildCapability();\n\n this._capability = Object.freeze(cap);\n }\n return this._capability;\n }\n\n /**\n * Initialize plugin with config\n */\n abstract initialize(config: TConfig): Promise<void>;\n\n /**\n * Get a copy of the current state\n */\n protected get state(): Readonly<TState> {\n return this.pluginStore.getState();\n }\n\n /**\n * Get a copy of the current core state\n */\n protected get coreState(): Readonly<StoreState<CoreState>> {\n return this.coreStore.getState();\n }\n\n /**\n * @deprecated use `this.state` Get a copy of the current state\n */\n protected getState(): TState {\n return this.pluginStore.getState();\n }\n\n /**\n * @deprecated use `this.coreState` Get a copy of the current core state\n */\n protected getCoreState(): StoreState<CoreState> {\n return this.coreStore.getState();\n }\n\n /**\n * Core Dispatch\n */\n protected dispatchCoreAction(action: CoreAction): StoreState<CoreState> {\n return this.coreStore.dispatchToCore(action);\n }\n\n /**\n * Dispatch an action to all plugins\n */\n protected dispatchToAllPlugins(action: TAction): StoreState<CoreState> {\n return this.coreStore.dispatch(action);\n }\n\n /**\n * Dispatch an action\n */\n protected dispatch(action: TAction): TState {\n return this.pluginStore.dispatch(action);\n }\n\n /**\n * Dispatch an action with a cooldown to prevent rapid repeated calls\n * This executes immediately if cooldown has expired, then blocks subsequent calls\n * @param action The action to dispatch\n * @param cooldownTime Time in ms for cooldown (default: 100ms)\n * @returns boolean indicating whether the action was dispatched or blocked\n */\n protected cooldownDispatch(action: TAction, cooldownTime: number = 100): boolean {\n const now = Date.now();\n const lastActionTime = this.cooldownActions[action.type] || 0;\n\n if (now - lastActionTime >= cooldownTime) {\n this.cooldownActions[action.type] = now;\n this.dispatch(action);\n return true;\n }\n\n return false;\n }\n\n /**\n * Dispatch an action with true debouncing - waits for the delay after the last call\n * Each new call resets the timer. Action only executes after no calls for the specified time.\n * @param action The action to dispatch\n * @param debounceTime Time in ms to wait after the last call\n */\n protected debouncedDispatch(action: TAction, debounceTime: number = 100): void {\n const actionKey = action.type;\n\n // Clear existing timeout\n if (this.debouncedTimeouts[actionKey]) {\n clearTimeout(this.debouncedTimeouts[actionKey]);\n }\n\n // Set new timeout\n this.debouncedTimeouts[actionKey] = setTimeout(() => {\n this.dispatch(action);\n delete this.debouncedTimeouts[actionKey];\n }, debounceTime) as unknown as number;\n }\n\n /**\n * Cancel a pending debounced action\n * @param actionType The action type to cancel\n */\n protected cancelDebouncedDispatch(actionType: string): void {\n if (this.debouncedTimeouts[actionType]) {\n clearTimeout(this.debouncedTimeouts[actionType]);\n delete this.debouncedTimeouts[actionType];\n }\n }\n\n /**\n * Subscribe to state changes\n */\n protected subscribe(listener: (action: TAction, state: TState) => void): () => void {\n return this.pluginStore.subscribeToState(listener);\n }\n\n /**\n * Subscribe to core store changes\n */\n protected subscribeToCoreStore(\n listener: (action: Action, state: StoreState<CoreState>) => void,\n ): () => void {\n return this.coreStore.subscribe(listener);\n }\n\n /**\n * Called when the plugin store state is updated\n * @param oldState Previous state\n * @param newState New state\n */\n protected onStoreUpdated(oldState: TState, newState: TState): void {\n // Default implementation does nothing - can be overridden by plugins\n }\n\n /**\n * Called when the core store state is updated\n * @param oldState Previous state\n * @param newState New state\n */\n protected onCoreStoreUpdated(\n oldState: StoreState<CoreState>,\n newState: StoreState<CoreState>,\n ): void {\n // Default implementation does nothing - can be overridden by plugins\n }\n\n /**\n * Called when a document is opened\n * Override to initialize per-document state\n * @param documentId The ID of the document that was opened\n */\n protected onDocumentLoadingStarted(documentId: string): void {\n // Default: no-op\n }\n\n /**\n * Called when a document is loaded\n * @param documentId The ID of the document that is loaded\n */\n protected onDocumentLoaded(documentId: string): void {\n // Default: no-op\n }\n\n /**\n * Called when a document is closed\n * Override to cleanup per-document state\n * @param documentId The ID of the document that was closed\n */\n protected onDocumentClosed(documentId: string): void {\n // Default: no-op\n }\n\n /**\n * Called when the active document changes\n * @param previousId The ID of the previous active document\n * @param currentId The ID of the new active document\n */\n protected onActiveDocumentChanged(previousId: string | null, currentId: string | null): void {\n // Default: no-op\n }\n\n protected onScaleChanged(documentId: string, scale: number): void {\n // Default: no-op\n }\n\n protected onRotationChanged(documentId: string, rotation: number): void {\n // Default: no-op\n }\n\n /**\n * Cleanup method to be called when plugin is being destroyed\n */\n public destroy(): void {\n // Clear all pending timeouts\n Object.values(this.debouncedTimeouts).forEach((timeout) => {\n clearTimeout(timeout);\n });\n this.debouncedTimeouts = {};\n\n if (this.unsubscribeFromState) {\n this.unsubscribeFromState();\n this.unsubscribeFromState = null;\n }\n if (this.unsubscribeFromCoreStore) {\n this.unsubscribeFromCoreStore();\n this.unsubscribeFromCoreStore = null;\n }\n if (this.unsubscribeFromStartLoadingDocument) {\n this.unsubscribeFromStartLoadingDocument();\n this.unsubscribeFromStartLoadingDocument = null;\n }\n if (this.unsubscribeFromSetDocumentLoaded) {\n this.unsubscribeFromSetDocumentLoaded();\n this.unsubscribeFromSetDocumentLoaded = null;\n }\n if (this.unsubscribeFromCloseDocument) {\n this.unsubscribeFromCloseDocument();\n this.unsubscribeFromCloseDocument = null;\n }\n if (this.unsubscribeFromSetScale) {\n this.unsubscribeFromSetScale();\n this.unsubscribeFromSetScale = null;\n }\n if (this.unsubscribeFromSetRotation) {\n this.unsubscribeFromSetRotation();\n this.unsubscribeFromSetRotation = null;\n }\n }\n\n /**\n * Returns a promise that resolves when the plugin is ready\n */\n public ready(): Promise<void> {\n return this.readyPromise;\n }\n\n /**\n * Mark the plugin as ready\n */\n protected markReady(): void {\n this.readyResolve();\n }\n\n /**\n * Reset the ready state (useful for plugins that need to reinitialize)\n */\n protected resetReady(): void {\n this.readyPromise = new Promise((resolve) => {\n this.readyResolve = resolve;\n });\n }\n\n /**\n * Get the active document ID\n * @throws Error if no active document exists\n */\n protected getActiveDocumentId(): string {\n const id = this.coreState.core.activeDocumentId;\n if (!id) {\n throw new Error('No active document');\n }\n return id;\n }\n\n /**\n * Get the active document ID or null if none exists\n */\n protected getActiveDocumentIdOrNull(): string | null {\n return this.coreState.core.activeDocumentId;\n }\n\n /**\n * Get core document state for a specific document\n * @param documentId Document ID (optional, defaults to active document)\n * @returns Document state or null if not found\n */\n protected getCoreDocument(documentId?: string): DocumentState | null {\n const id = documentId ?? this.getActiveDocumentIdOrNull();\n if (!id) return null;\n return this.coreState.core.documents[id] ?? null;\n }\n\n /**\n * Get core document state for a specific document\n * @param documentId Document ID (optional, defaults to active document)\n * @throws Error if document not found\n */\n protected getCoreDocumentOrThrow(documentId?: string): DocumentState {\n const doc = this.getCoreDocument(documentId);\n if (!doc) {\n throw new Error(`Document not found: ${documentId ?? 'active'}`);\n }\n return doc;\n }\n}\n","import { DependencyResolver } from '../utils/dependency-resolver';\nimport {\n IPlugin,\n PluginBatchRegistration,\n PluginManifest,\n PluginStatus,\n PluginPackage,\n PluginRegistryConfig,\n PluginBatchRegistrations,\n} from '../types/plugin';\nimport {\n PluginRegistrationError,\n PluginNotFoundError,\n CircularDependencyError,\n PluginConfigurationError,\n} from '../types/errors';\nimport { Logger, NoopLogger, PdfEngine } from '@embedpdf/models';\nimport { Action, CoreState, Store, initialCoreState, Reducer } from '../store';\nimport { CoreAction } from '../store/actions';\nimport { coreReducer } from '../store/reducer';\n\n// Define a more flexible generic type for plugin registrations\ninterface PluginRegistration {\n // Use existential types for the plugin package to allow accepting any plugin type\n package: PluginPackage<any, any, any, any>;\n config?: any;\n}\n\nexport class PluginRegistry {\n private plugins: Map<string, IPlugin> = new Map();\n private manifests: Map<string, PluginManifest> = new Map();\n private capabilities: Map<string, string> = new Map(); // capability -> pluginId\n private status: Map<string, PluginStatus> = new Map();\n private resolver: DependencyResolver;\n private configurations: Map<string, unknown> = new Map();\n private engine: PdfEngine;\n private engineInitialized = false;\n private store: Store<CoreState, CoreAction>;\n private initPromise: Promise<void> | null = null;\n private logger: Logger;\n\n private pendingRegistrations: PluginRegistration[] = [];\n private processingRegistrations: PluginRegistration[] = [];\n private initialized = false;\n private isInitializing = false;\n private initialCoreState: CoreState;\n private pluginsReadyPromise: Promise<void> | null = null;\n private destroyed = false;\n\n constructor(engine: PdfEngine, config?: PluginRegistryConfig) {\n this.resolver = new DependencyResolver();\n this.engine = engine;\n this.initialCoreState = initialCoreState(config);\n this.store = new Store<CoreState, CoreAction>(coreReducer, this.initialCoreState);\n this.logger = config?.logger ?? new NoopLogger();\n }\n\n /**\n * Get the logger instance\n */\n getLogger(): Logger {\n return this.logger;\n }\n\n /**\n * Ensure engine is initialized before proceeding\n */\n private async ensureEngineInitialized(): Promise<void> {\n if (this.engineInitialized) {\n return;\n }\n\n if (this.engine.initialize) {\n const task = this.engine.initialize();\n await task.toPromise();\n this.engineInitialized = true;\n } else {\n this.engineInitialized = true;\n }\n }\n\n /**\n * Register a plugin without initializing it\n */\n registerPlugin<\n TPlugin extends IPlugin<TConfig>,\n TConfig = unknown,\n TState = unknown,\n TAction extends Action = Action,\n >(\n pluginPackage: PluginPackage<TPlugin, TConfig, TState, TAction>,\n config?: Partial<TConfig>,\n ): void {\n if (this.initialized && !this.isInitializing) {\n throw new PluginRegistrationError('Cannot register plugins after initialization');\n }\n\n this.validateManifest(pluginPackage.manifest);\n\n // Use appropriate typing for store methods\n this.store.addPluginReducer(\n pluginPackage.manifest.id,\n // We need one type assertion here since we can't fully reconcile TAction with Action\n // due to TypeScript's type system limitations with generic variance\n pluginPackage.reducer as Reducer<TState, Action>,\n 'function' === typeof pluginPackage.initialState\n ? (pluginPackage.initialState as (coreState: CoreState, config: TConfig) => TState)(\n this.initialCoreState,\n {\n ...pluginPackage.manifest.defaultConfig,\n ...config,\n },\n )\n : pluginPackage.initialState,\n );\n\n this.pendingRegistrations.push({\n package: pluginPackage,\n config,\n });\n }\n\n /**\n * Get the central store instance\n */\n getStore(): Store<CoreState, CoreAction> {\n return this.store;\n }\n\n /**\n * Get the engine instance\n */\n getEngine(): PdfEngine {\n return this.engine;\n }\n\n /**\n * Get a promise that resolves when all plugins are ready\n */\n public pluginsReady(): Promise<void> {\n // Re-use the same promise every time it’s asked for\n if (this.pluginsReadyPromise) {\n return this.pluginsReadyPromise;\n }\n\n // Build the promise the *first* time it’s requested\n this.pluginsReadyPromise = (async () => {\n // 1. Wait until the registry itself has finished initialising\n if (!this.initialized) {\n await this.initialize();\n }\n\n // 2. Wait for every plugin’s ready() promise (if it has one)\n const readyPromises = Array.from(this.plugins.values()).map((p) =>\n typeof p.ready === 'function' ? p.ready() : Promise.resolve(),\n );\n\n await Promise.all(readyPromises); // resolves when the slowest is done\n })();\n\n return this.pluginsReadyPromise;\n }\n\n /**\n * INITIALISE THE REGISTRY – runs once no-matter-how-many calls *\n */\n async initialize(): Promise<void> {\n if (this.destroyed) {\n throw new PluginRegistrationError('Registry has been destroyed');\n }\n\n if (this.initPromise) {\n return this.initPromise;\n }\n\n this.initPromise = (async () => {\n if (this.initialized) {\n throw new PluginRegistrationError('Registry is already initialized');\n }\n\n this.isInitializing = true;\n\n try {\n await this.ensureEngineInitialized();\n if (this.destroyed) return;\n\n while (this.pendingRegistrations.length > 0) {\n if (this.destroyed) return;\n\n this.processingRegistrations = [...this.pendingRegistrations];\n this.pendingRegistrations = [];\n\n // ------------------------------------------------------------\n // STEP 1: RESOLVE ORDER (Using Manifests)\n // ------------------------------------------------------------\n // We use the static manifests to figure out the graph before creating instances.\n for (const reg of this.processingRegistrations) {\n const dependsOn = new Set<string>();\n const allDeps = [...reg.package.manifest.requires, ...reg.package.manifest.optional];\n\n for (const cap of allDeps) {\n // Check if provider is in the current batch\n const provider = this.processingRegistrations.find((r) =>\n r.package.manifest.provides.includes(cap),\n );\n\n // If the provider is in this batch, we must load after it.\n // If the provider was in a previous batch, it's already loaded, so no edge needed.\n if (provider) {\n dependsOn.add(provider.package.manifest.id);\n }\n }\n this.resolver.addNode(reg.package.manifest.id, [...dependsOn]);\n }\n\n const loadOrder = this.resolver.resolveLoadOrder();\n\n // ------------------------------------------------------------\n // STEP 2: INSTANTIATION (Constructors)\n // ------------------------------------------------------------\n // Create all instances and register capabilities.\n // Now \"this.plugins.get('id')\" will return an object for everyone in this batch.\n for (const id of loadOrder) {\n const reg = this.processingRegistrations.find((r) => r.package.manifest.id === id)!;\n this.instantiatePlugin(reg.package.manifest, reg.package.create, reg.config);\n }\n\n // ------------------------------------------------------------\n // STEP 3: INITIALIZATION (Logic)\n // ------------------------------------------------------------\n // Now run the async logic. Since step 2 is done,\n // Plugin A can safely access Plugin B's instance during initialize.\n for (const id of loadOrder) {\n await this.runPluginInitialization(id);\n }\n\n this.processingRegistrations = [];\n this.resolver = new DependencyResolver();\n }\n\n // postInitialize is removed as requested/agreed!\n\n this.initialized = true;\n } catch (err) {\n if (err instanceof Error) {\n throw new CircularDependencyError(\n `Failed to resolve plugin dependencies: ${err.message}`,\n );\n }\n throw err;\n } finally {\n this.isInitializing = false;\n }\n })();\n\n return this.initPromise;\n }\n\n /**\n * Phase 2: Create instance and register capabilities\n */\n private instantiatePlugin<TConfig>(\n manifest: PluginManifest<TConfig>,\n packageCreator: (registry: PluginRegistry, config?: TConfig) => IPlugin<TConfig>,\n config?: Partial<TConfig>,\n ): void {\n const finalConfig = {\n ...manifest.defaultConfig,\n ...config,\n };\n\n this.validateConfig(manifest.id, finalConfig, manifest.defaultConfig);\n\n // Create plugin instance (Constructor runs here)\n const plugin = packageCreator(this, finalConfig);\n this.validatePlugin(plugin);\n\n // Check existing capabilities (sanity check)\n for (const capability of manifest.provides) {\n if (this.capabilities.has(capability)) {\n throw new PluginRegistrationError(\n `Capability ${capability} is already provided by plugin ${this.capabilities.get(capability)}`,\n );\n }\n this.capabilities.set(capability, manifest.id);\n }\n\n // Store plugin and manifest\n this.plugins.set(manifest.id, plugin);\n this.manifests.set(manifest.id, manifest);\n this.status.set(manifest.id, 'registered'); // Ready for init\n this.configurations.set(manifest.id, finalConfig);\n }\n\n /**\n * Phase 3: Run the initialize method\n */\n private async runPluginInitialization(pluginId: string): Promise<void> {\n const plugin = this.plugins.get(pluginId);\n if (!plugin) return; // Should not happen given loadOrder logic\n\n const manifest = this.manifests.get(pluginId)!;\n const config = this.configurations.get(pluginId);\n\n // Validate requirements are met (now that everyone is instantiated)\n for (const capability of manifest.requires) {\n if (!this.capabilities.has(capability)) {\n throw new PluginRegistrationError(\n `Missing required capability: ${capability} for plugin ${pluginId}`,\n );\n }\n }\n\n this.logger.debug('PluginRegistry', 'InitializePlugin', `Initializing plugin ${pluginId}`);\n\n try {\n if (plugin.initialize) {\n await plugin.initialize(config);\n }\n this.status.set(pluginId, 'active');\n\n this.logger.info(\n 'PluginRegistry',\n 'PluginInitialized',\n `Plugin ${pluginId} initialized successfully`,\n );\n } catch (error) {\n // Rollback logic\n this.status.set(pluginId, 'error');\n this.logger.error(\n 'PluginRegistry',\n 'InitializationFailed',\n `Plugin ${pluginId} initialization failed`,\n { error },\n );\n throw error;\n }\n }\n\n getPluginConfig<TConfig>(pluginId: string): TConfig {\n const config = this.configurations.get(pluginId);\n if (!config) {\n throw new PluginNotFoundError(`Configuration for plugin ${pluginId} not found`);\n }\n return config as TConfig;\n }\n\n private validateConfig(pluginId: string, config: unknown, defaultConfig: unknown): void {\n // Check all required fields exist\n const requiredKeys = Object.keys(defaultConfig as object);\n const missingKeys = requiredKeys.filter((key) => !(config as object).hasOwnProperty(key));\n\n if (missingKeys.length > 0) {\n throw new PluginConfigurationError(\n `Missing required configuration keys for plugin ${pluginId}: ${missingKeys.join(', ')}`,\n );\n }\n\n // You could add more validation here:\n // - Type checking\n // - Value range validation\n // - Format validation\n // etc.\n }\n\n async updatePluginConfig<TConfig>(pluginId: string, config: Partial<TConfig>): Promise<void> {\n const plugin = this.getPlugin(pluginId);\n\n if (!plugin) {\n throw new PluginNotFoundError(`Plugin ${pluginId} not found`);\n }\n\n const manifest = this.manifests.get(pluginId);\n const currentConfig = this.configurations.get(pluginId);\n\n if (!manifest || !currentConfig) {\n throw new PluginNotFoundError(`Plugin ${pluginId} not found`);\n }\n\n // Merge new config with current\n const newConfig = {\n ...currentConfig,\n ...config,\n };\n\n // Validate new configuration\n this.validateConfig(pluginId, newConfig, manifest.defaultConfig);\n\n // Store new configuration\n this.configurations.set(pluginId, newConfig);\n\n // Reinitialize plugin if needed\n if (plugin.initialize) {\n await plugin.initialize(newConfig);\n }\n }\n\n /**\n * Register multiple plugins at once\n */\n registerPluginBatch(registrations: PluginBatchRegistrations): void {\n for (const reg of registrations) {\n this.registerPlugin(reg.package, reg.config);\n }\n }\n\n /**\n * Unregister a plugin\n */\n async unregisterPlugin(pluginId: string): Promise<void> {\n const plugin = this.plugins.get(pluginId);\n if (!plugin) {\n throw new PluginNotFoundError(`Plugin ${pluginId} is not registered`);\n }\n\n const manifest = this.manifests.get(pluginId);\n if (!manifest) {\n throw new PluginNotFoundError(`Manifest for plugin ${pluginId} not found`);\n }\n\n // Check if any other plugins depend on this one\n for (const [otherId, otherManifest] of this.manifests.entries()) {\n if (otherId === pluginId) continue;\n\n const dependsOnThis = [...otherManifest.requires, ...otherManifest.optional].some((cap) =>\n manifest.provides.includes(cap),\n );\n\n if (dependsOnThis) {\n throw new PluginRegistrationError(\n `Cannot unregister plugin ${pluginId}: plugin ${otherId} depends on it`,\n );\n }\n }\n\n // Cleanup plugin\n try {\n if (plugin.destroy) {\n await plugin.destroy();\n }\n\n // Remove capabilities\n for (const capability of manifest.provides) {\n this.capabilities.delete(capability);\n }\n\n // Remove plugin and manifest\n this.plugins.delete(pluginId);\n this.manifests.delete(pluginId);\n this.status.delete(pluginId);\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to unregister plugin ${pluginId}: ${error.message}`);\n }\n throw error;\n }\n }\n\n /**\n * Get a plugin instance\n * @param pluginId The ID of the plugin to get\n * @returns The plugin instance or null if not found\n */\n getPlugin<T extends IPlugin>(pluginId: string): T | null {\n const plugin = this.plugins.get(pluginId);\n if (!plugin) {\n return null;\n }\n return plugin as T;\n }\n\n /**\n * Get a plugin that provides a specific capability\n * @param capability The capability to get a provider for\n * @returns The plugin providing the capability or null if not found\n */\n getCapabilityProvider(capability: string): IPlugin | null {\n const pluginId = this.capabilities.get(capability);\n if (!pluginId) {\n return null;\n }\n return this.getPlugin(pluginId);\n }\n\n /**\n * Check if a capability is available\n */\n hasCapability(capability: string): boolean {\n return this.capabilities.has(capability);\n }\n\n /**\n * Get all registered plugins\n */\n getAllPlugins(): IPlugin[] {\n return Array.from(this.plugins.values());\n }\n\n /**\n * Get plugin status\n */\n getPluginStatus(pluginId: string): PluginStatus {\n const status = this.status.get(pluginId);\n if (!status) {\n throw new PluginNotFoundError(`Plugin ${pluginId} not found`);\n }\n return status;\n }\n\n /**\n * Validate plugin object\n */\n private validatePlugin(plugin: IPlugin): void {\n if (!plugin.id) {\n throw new PluginRegistrationError('Plugin must have an id');\n }\n }\n\n /**\n * Validate plugin manifest\n */\n private validateManifest(manifest: PluginManifest): void {\n if (!manifest.id) {\n throw new PluginRegistrationError('Manifest must have an id');\n }\n if (!manifest.name) {\n throw new PluginRegistrationError('Manifest must have a name');\n }\n if (!manifest.version) {\n throw new PluginRegistrationError('Manifest must have a version');\n }\n if (!Array.isArray(manifest.provides)) {\n throw new PluginRegistrationError('Manifest must have a provides array');\n }\n if (!Array.isArray(manifest.requires)) {\n throw new PluginRegistrationError('Manifest must have a requires array');\n }\n if (!Array.isArray(manifest.optional)) {\n throw new PluginRegistrationError('Manifest must have an optional array');\n }\n }\n\n isDestroyed(): boolean {\n return this.destroyed;\n }\n\n /**\n * DESTROY EVERYTHING – waits for any ongoing initialise(), once *\n */\n async destroy(): Promise<void> {\n if (this.destroyed) throw new PluginRegistrationError('Registry has already been destroyed');\n this.destroyed = true;\n\n // If initialisation is still underway, wait (success OR failure)\n try {\n await this.initPromise;\n } catch {\n /* ignore – still need to clean up */\n }\n\n /* ------- original teardown, unchanged except the guard ------ */\n for (const plugin of Array.from(this.plugins.values()).reverse()) {\n await plugin.destroy?.();\n }\n\n this.store.destroy();\n\n this.plugins.clear();\n this.manifests.clear();\n this.capabilities.clear();\n this.status.clear();\n this.pendingRegistrations.length = 0;\n this.processingRegistrations.length = 0;\n }\n}\n","import {\n EventControl,\n EventControlOptions,\n KeyedEventControl,\n isKeyedOptions,\n} from './event-control';\nimport { arePropsEqual } from './math';\n\n/* ------------------------------------------------------------------ */\n/* basic types */\n/* ------------------------------------------------------------------ */\nexport type Listener<T = any> = (value: T) => void;\nexport type Unsubscribe = () => void;\n\n/* ------------------------------------------------------------------ */\n/* EventListener */\n/* ------------------------------------------------------------------ */\nexport type EventListener<T> =\n | ((listener: Listener<T>) => Unsubscribe)\n | ((listener: Listener<T>, options?: EventControlOptions<T>) => Unsubscribe);\n\n/* ------------------------------------------------------------ */\n/* helpers for typing `.on()` with an optional second argument */\n/* ------------------------------------------------------------ */\nexport type EventHook<T = any> = EventListener<T>;\n\n/* ------------------------------------------------------------------ */\n/* minimal \"dumb\" emitter (no value cache, no equality) */\n/* ------------------------------------------------------------------ */\nexport interface Emitter<T = any> {\n emit(value?: T): void;\n on(listener: Listener<T>): Unsubscribe;\n off(listener: Listener<T>): void;\n clear(): void;\n}\n\nexport function createEmitter<T = any>(): Emitter<T> {\n const listeners = new Set<Listener<T>>();\n\n const on: EventHook<T> = (l: Listener<T>) => {\n listeners.add(l);\n return () => listeners.delete(l);\n };\n\n return {\n emit: (v = undefined as T) => listeners.forEach((l) => l(v)),\n on,\n off: (l) => listeners.delete(l),\n clear: () => listeners.clear(),\n };\n}\n\n/* ------------------------------------------------------------ */\n/* public interface */\n/* ------------------------------------------------------------ */\nexport interface BehaviorEmitter<T = any> extends Omit<Emitter<T>, 'on' | 'off'> {\n readonly value?: T;\n on: EventHook<T>;\n off(listener: Listener<T>): void;\n select<U>(selector: (v: T) => U, equality?: (a: U, b: U) => boolean): EventHook<U>;\n}\n\n/* ------------------------------------------------------------ */\n/* implementation */\n/* ------------------------------------------------------------ */\nexport function createBehaviorEmitter<T = any>(\n initial?: T,\n equality: (a: T, b: T) => boolean = arePropsEqual,\n): BehaviorEmitter<T> {\n const listeners = new Set<Listener<T>>();\n const proxyMap = new Map<Listener<T>, { wrapped: Listener<T>; destroy: () => void }>();\n let _value = initial; // cached value\n\n /* -------------- helpers ----------------------------------- */\n const notify = (v: T) => listeners.forEach((l) => l(v));\n\n const baseOn: EventHook<T> = (listener: Listener<T>, options?: EventControlOptions<T>) => {\n /* wrap & remember if we have control options ------------------ */\n let realListener = listener;\n let destroy = () => {};\n\n if (options) {\n // Check if it's keyed options\n if (isKeyedOptions(options)) {\n const ctl = new KeyedEventControl(listener, options);\n realListener = ctl.handle as Listener<T>;\n destroy = () => ctl.destroy();\n } else {\n const ctl = new EventControl(listener, options);\n realListener = ctl.handle as Listener<T>;\n destroy = () => ctl.destroy();\n }\n proxyMap.set(listener, { wrapped: realListener, destroy });\n }\n\n /* immediate replay of last value ------------------------------ */\n if (_value !== undefined) realListener(_value);\n\n listeners.add(realListener);\n\n return () => {\n listeners.delete(realListener);\n destroy();\n proxyMap.delete(listener);\n };\n };\n\n /* -------------- public object ------------------------------ */\n return {\n /* emitter behaviour ---------------------------------------- */\n get value() {\n return _value;\n },\n\n emit(v = undefined as T) {\n if (_value === undefined || !equality(_value, v)) {\n _value = v;\n notify(v);\n }\n },\n\n on: baseOn,\n off(listener: Listener<T>) {\n /* did we wrap this listener? */\n const proxy = proxyMap.get(listener);\n if (proxy) {\n listeners.delete(proxy.wrapped);\n proxy.destroy();\n proxyMap.delete(listener);\n } else {\n listeners.delete(listener);\n }\n },\n\n clear() {\n listeners.clear();\n proxyMap.forEach((p) => p.destroy());\n proxyMap.clear();\n },\n\n /* derived hook --------------------------------------------- */\n select<U>(selector: (v: T) => U, eq: (a: U, b: U) => boolean = arePropsEqual): EventHook<U> {\n return (listener: Listener<U>, options?: EventControlOptions<U>) => {\n let prev: U | undefined;\n\n /* replay */\n if (_value !== undefined) {\n const mapped = selector(_value);\n prev = mapped;\n listener(mapped);\n }\n\n /* subscribe to parent */\n return baseOn(\n (next) => {\n const mapped = selector(next);\n if (prev === undefined || !eq(prev, mapped)) {\n prev = mapped;\n listener(mapped);\n }\n },\n options as EventControlOptions<T> | undefined,\n ); // pass control opts straight through\n };\n },\n };\n}\n","import { Action } from '../store';\nimport { IPlugin, PluginBatchRegistration, PluginPackage } from '../types/plugin';\n\n/**\n * Helper function to create a properly typed plugin registration\n */\nexport function createPluginRegistration<\n T extends IPlugin<TConfig>,\n TConfig,\n TState,\n TAction extends Action,\n>(\n pluginPackage: PluginPackage<T, TConfig, TState, TAction>,\n config?: Partial<TConfig>,\n): PluginBatchRegistration<T, TConfig, any, any> {\n return {\n package: pluginPackage,\n config,\n };\n}\n","import {\n EventControl,\n EventControlOptions,\n KeyedEventControl,\n isKeyedOptions,\n} from './event-control';\nimport { EventHook, Listener, Unsubscribe } from './eventing';\nimport { arePropsEqual } from './math';\n\n/* ------------------------------------------------------------------ */\n/* Scoped Emitter - Generic Key-Based Event Scoping */\n/* ------------------------------------------------------------------ */\n\n/**\n * A scoped behavior emitter that maintains separate cached values\n * and listener sets per scope key.\n *\n * @typeParam TData - The scoped data type (without key context)\n * @typeParam TGlobalEvent - The global event type (includes key context)\n * @typeParam TKey - The key type (string, number, or both)\n */\nexport interface ScopedEmitter<\n TData = any,\n TGlobalEvent = { key: string; data: TData },\n TKey extends string | number = string | number,\n> {\n /**\n * Emit an event for a specific scope key.\n */\n emit(key: TKey, data: TData): void;\n\n /**\n * Get a scoped event hook that only receives events for this key.\n */\n forScope(key: TKey): EventHook<TData>;\n\n /**\n * Global event hook that receives events from all scopes.\n */\n readonly onGlobal: EventHook<TGlobalEvent>;\n\n /**\n * Clear all scopes' caches and listeners\n */\n clear(): void;\n\n /**\n * Clear a specific scope's cache and listeners\n */\n clearScope(key: TKey): void;\n\n /**\n * Get the current cached value for a specific scope\n */\n getValue(key: TKey): TData | undefined;\n\n /**\n * Get all active scope keys\n */\n getScopes(): TKey[];\n}\n\n/**\n * Creates a scoped emitter with optional caching behavior.\n *\n * @param toGlobalEvent - Transform function to convert (key, data) into a global event\n * @param options - Configuration options\n * @param options.cache - Whether to cache values per scope (default: true)\n * @param options.equality - Equality function for cached values (default: arePropsEqual)\n *\n * @example\n * ```typescript\n * // With caching (stateful) - default behavior\n * const window$ = createScopedEmitter<WindowState, WindowChangeEvent, string>(\n * (documentId, window) => ({ documentId, window })\n * );\n *\n * // Without caching (transient events)\n * const refreshPages$ = createScopedEmitter<number[], RefreshPagesEvent, string>(\n * (documentId, pages) => ({ documentId, pages }),\n * { cache: false }\n * );\n * ```\n */\nexport function createScopedEmitter<\n TData = any,\n TGlobalEvent = { key: string; data: TData },\n TKey extends string | number = string | number,\n>(\n toGlobalEvent: (key: TKey, data: TData) => TGlobalEvent,\n options?: {\n cache?: boolean;\n equality?: (a: TData, b: TData) => boolean;\n },\n): ScopedEmitter<TData, TGlobalEvent, TKey> {\n const shouldCache = options?.cache ?? true;\n const equality = options?.equality ?? arePropsEqual;\n\n // Per-scope state\n const scopeCaches = new Map<string, TData>();\n const scopeListeners = new Map<string, Set<Listener<TData>>>();\n const scopeProxyMaps = new Map<\n string,\n Map<Listener<TData>, { wrapped: Listener<TData>; destroy: () => void }>\n >();\n\n // Global listeners\n const globalListeners = new Set<Listener<TGlobalEvent>>();\n const globalProxyMap = new Map<\n Listener<TGlobalEvent>,\n { wrapped: Listener<TGlobalEvent>; destroy: () => void }\n >();\n\n const normalizeKey = (key: TKey): string => String(key);\n\n const getOrCreateListeners = (key: string): Set<Listener<TData>> => {\n let listeners = scopeListeners.get(key);\n if (!listeners) {\n listeners = new Set();\n scopeListeners.set(key, listeners);\n }\n return listeners;\n };\n\n const getOrCreateProxyMap = (\n key: string,\n ): Map<Listener<TData>, { wrapped: Listener<TData>; destroy: () => void }> => {\n let proxyMap = scopeProxyMaps.get(key);\n if (!proxyMap) {\n proxyMap = new Map();\n scopeProxyMaps.set(key, proxyMap);\n }\n return proxyMap;\n };\n\n const onGlobal: EventHook<TGlobalEvent> = (\n listener: Listener<TGlobalEvent>,\n options?: EventControlOptions<TGlobalEvent>,\n ): Unsubscribe => {\n let realListener = listener;\n let destroy = () => {};\n\n if (options) {\n if (isKeyedOptions(options)) {\n const ctl = new KeyedEventControl(listener, options);\n realListener = ctl.handle as Listener<TGlobalEvent>;\n destroy = () => ctl.destroy();\n } else {\n const ctl = new EventControl(listener, options);\n realListener = ctl.handle as Listener<TGlobalEvent>;\n destroy = () => ctl.destroy();\n }\n globalProxyMap.set(listener, { wrapped: realListener, destroy });\n }\n\n globalListeners.add(realListener);\n\n return () => {\n globalListeners.delete(realListener);\n destroy();\n globalProxyMap.delete(listener);\n };\n };\n\n return {\n emit(key: TKey, data: TData) {\n const normalizedKey = normalizeKey(key);\n\n if (shouldCache) {\n // Behavior mode: check equality before emitting\n const cached = scopeCaches.get(normalizedKey);\n if (cached !== undefined && equality(cached, data)) {\n return; // Skip emission if value hasn't changed\n }\n scopeCaches.set(normalizedKey, data);\n }\n\n // Notify per-scope listeners\n const listeners = scopeListeners.get(normalizedKey);\n if (listeners) {\n listeners.forEach((l) => l(data));\n }\n\n // Notify global listeners\n const globalEvent = toGlobalEvent(key, data);\n globalListeners.forEach((l) => l(globalEvent));\n },\n\n forScope(key: TKey): EventHook<TData> {\n const normalizedKey = normalizeKey(key);\n\n return (listener: Listener<TData>, options?: EventControlOptions<TData>): Unsubscribe => {\n const listeners = getOrCreateListeners(normalizedKey);\n const proxyMap = getOrCreateProxyMap(normalizedKey);\n\n let realListener = listener;\n let destroy = () => {};\n\n if (options) {\n if (isKeyedOptions(options)) {\n const ctl = new KeyedEventControl(listener, options);\n realListener = ctl.handle as Listener<TData>;\n destroy = () => ctl.destroy();\n } else {\n const ctl = new EventControl(listener, options);\n realListener = ctl.handle as Listener<TData>;\n destroy = () => ctl.destroy();\n }\n proxyMap.set(listener, { wrapped: realListener, destroy });\n }\n\n // Replay cached value ONLY if caching is enabled\n if (shouldCache) {\n const cached = scopeCaches.get(normalizedKey);\n if (cached !== undefined) {\n realListener(cached);\n }\n }\n\n listeners.add(realListener);\n\n return () => {\n listeners.delete(realListener);\n destroy();\n proxyMap.delete(listener);\n\n if (listeners.size === 0) {\n scopeListeners.delete(normalizedKey);\n }\n if (proxyMap.size === 0) {\n scopeProxyMaps.delete(normalizedKey);\n }\n };\n };\n },\n\n onGlobal,\n\n getValue(key: TKey): TData | undefined {\n return shouldCache ? scopeCaches.get(normalizeKey(key)) : undefined;\n },\n\n getScopes(): TKey[] {\n if (shouldCache) {\n return Array.from(scopeCaches.keys()) as TKey[];\n }\n // Without cache, return all scopes that have active listeners\n return Array.from(scopeListeners.keys()) as TKey[];\n },\n\n clearScope(key: TKey): void {\n const normalizedKey = normalizeKey(key);\n\n if (shouldCache) {\n scopeCaches.delete(normalizedKey);\n }\n\n const listeners = scopeListeners.get(normalizedKey);\n if (listeners) {\n listeners.clear();\n scopeListeners.delete(normalizedKey);\n }\n\n const proxyMap = scopeProxyMaps.get(normalizedKey);\n if (proxyMap) {\n proxyMap.forEach((p) => p.destroy());\n proxyMap.clear();\n scopeProxyMaps.delete(normalizedKey);\n }\n },\n\n clear(): void {\n if (shouldCache) {\n scopeCaches.clear();\n }\n scopeListeners.forEach((set) => set.clear());\n scopeListeners.clear();\n scopeProxyMaps.forEach((map) => {\n map.forEach((p) => p.destroy());\n map.clear();\n });\n scopeProxyMaps.clear();\n\n globalListeners.clear();\n globalProxyMap.forEach((p) => p.destroy());\n globalProxyMap.clear();\n },\n };\n}\n","/* ------------------------------------------------------------------ */\n/* enumEntries – iterate over enum-keyed Records with strong typing */\n/* ------------------------------------------------------------------ */\n\ntype EnumKey = string | number;\n\n/**\n * Iterate over a Record whose keys are enum members (numeric or string),\n * getting back a fully-typed `[key, value]` tuple array.\n *\n * Usage:\n * for (const [subtype, defaults] of enumEntries(this.state.toolDefaults)) {\n * // subtype is inferred as keyof ToolDefaultsBySubtype\n * }\n */\nexport function enumEntries<E extends EnumKey, V>(record: Record<E, V>): Array<[E, V]> {\n // Tell TS the values are V (not unknown) *before* we map.\n return (Object.entries(record) as [string, V][]).map(([k, v]) => {\n // Numeric enums come out of Object.entries as \"0\", \"1\", … → convert.\n const maybeNum = Number(k);\n const typedKey: E =\n Number.isFinite(maybeNum) && k.trim() !== '' // looks like a number?\n ? (maybeNum as unknown as E) // numeric enum key\n : (k as unknown as E); // string enum key\n\n return [typedKey, v]; // v is already typed as V\n });\n}\n","import { CoreState, DocumentState } from './initial-state';\n\n/**\n * Get the active document state\n */\nexport const getActiveDocumentState = (state: CoreState): DocumentState | null => {\n if (!state.activeDocumentId) return null;\n return state.documents[state.activeDocumentId] ?? null;\n};\n\n/**\n * Get document state by ID\n */\nexport const getDocumentState = (state: CoreState, documentId: string): DocumentState | null => {\n return state.documents[documentId] ?? null;\n};\n\n/**\n * Get all document IDs\n */\nexport const getDocumentIds = (state: CoreState): string[] => {\n return Object.keys(state.documents);\n};\n\n/**\n * Check if a document is loaded\n */\nexport const isDocumentLoaded = (state: CoreState, documentId: string): boolean => {\n return !!state.documents[documentId];\n};\n\n/**\n * Get the number of open documents\n */\nexport const getDocumentCount = (state: CoreState): number => {\n return Object.keys(state.documents).length;\n};\n","import { PluginRegistry } from '../registry/plugin-registry';\nimport { Logger, PdfEngine, Rotation } from '@embedpdf/models';\nimport { Action, Reducer } from '../store/types';\nimport { CoreState } from '../store';\n\nexport interface IPlugin<TConfig = unknown> {\n id: string;\n\n initialize?(config: TConfig): Promise<void>;\n destroy?(): Promise<void> | void;\n provides?(): any;\n postInitialize?(): Promise<void>;\n ready?(): Promise<void>;\n}\n\nexport interface BasePluginConfig {\n enabled?: boolean;\n}\n\nexport interface PluginRegistryConfig {\n defaultRotation?: Rotation;\n defaultScale?: number;\n logger?: Logger;\n}\n\nexport interface PluginManifest<TConfig = unknown> {\n id: string;\n name: string;\n version: string;\n provides: string[]; // Capabilities this plugin provides\n requires: string[]; // Mandatory capabilities\n optional: string[]; // Optional capabilities\n defaultConfig: TConfig; // Default configuration\n metadata?: {\n description?: string;\n author?: string;\n homepage?: string;\n [key: string]: unknown;\n };\n}\n\nexport interface PluginPackage<\n T extends IPlugin<TConfig>,\n TConfig = unknown,\n TState = unknown,\n TAction extends Action = Action,\n> {\n manifest: PluginManifest<TConfig>;\n create(registry: PluginRegistry, config: TConfig): T;\n reducer: Reducer<TState, TAction>;\n initialState: TState | ((coreState: CoreState, config: TConfig) => TState);\n}\n\nexport type Component = any;\n\n// Use semantic names that describe PURPOSE, not implementation\nexport type StandaloneComponent = Component; // Doesn't wrap content\nexport type ContainerComponent = Component; // Wraps/contains content\n\nexport type AutoMountElement =\n | {\n component: StandaloneComponent;\n type: 'utility';\n }\n | {\n component: ContainerComponent;\n type: 'wrapper';\n };\n\nexport type WithAutoMount<T extends PluginPackage<any, any, any, any>> = T & {\n /**\n * Returns an array of components/elements with their mount type.\n * - 'utility': Mounted as hidden DOM elements (file pickers, download anchors)\n * - 'wrapper': Wraps the viewer content (fullscreen providers, theme providers)\n */\n autoMountElements: () => AutoMountElement[];\n};\n\nexport function hasAutoMountElements<T extends PluginPackage<any, any, any, any>>(\n pkg: T,\n): pkg is WithAutoMount<T> {\n return 'autoMountElements' in pkg && typeof pkg.autoMountElements === 'function';\n}\n\nexport type PluginStatus =\n | 'registered' // Plugin is registered but not initialized\n | 'active' // Plugin is initialized and running\n | 'error' // Plugin encountered an error\n | 'disabled' // Plugin is temporarily disabled\n | 'unregistered'; // Plugin is being unregistered\n\nexport interface PluginBatchRegistration<\n T extends IPlugin<TConfig>,\n TConfig = unknown,\n TState = unknown,\n TAction extends Action = Action,\n> {\n package: PluginPackage<T, TConfig, TState, TAction>;\n config?: Partial<TConfig>;\n}\n\nexport type PluginBatchRegistrations = PluginBatchRegistration<IPlugin<any>, any>[];\n\nexport interface GlobalStoreState<TPlugins extends Record<string, any> = {}> {\n core: CoreState;\n plugins: TPlugins;\n}\n"],"names":["DependencyResolver","constructor","this","dependencyGraph","Map","addNode","id","dependencies","set","Set","hasCircularDependencies","visited","recursionStack","dfs","add","get","dep","has","delete","keys","resolveLoadOrder","Error","result","temp","visit","push","PluginRegistrationError","message","super","name","PluginNotFoundError","CircularDependencyError","CapabilityNotFoundError","CapabilityConflictError","PluginInitializationError","PluginConfigurationError","PluginStore","store","pluginId","getState","plugins","dispatch","action","dispatchToPlugin","subscribeToState","listener","subscribeToPlugin","newPluginState","oldPluginState","onAction","type","handler","state","oldState","START_LOADING_DOCUMENT","UPDATE_DOCUMENT_LOADING_PROGRESS","SET_DOCUMENT_LOADED","SET_DOCUMENT_ERROR","RETRY_LOADING_DOCUMENT","CLOSE_DOCUMENT","SET_ACTIVE_DOCUMENT","REORDER_DOCUMENTS","MOVE_DOCUMENT","REFRESH_DOCUMENT","REFRESH_PAGES","SET_PAGES","SET_SCALE","SET_ROTATION","SET_DEFAULT_SCALE","SET_DEFAULT_ROTATION","CORE_ACTION_TYPES","Store","reducer","initialCoreState","pluginReducers","listeners","pluginListeners","isDispatching","core","coreReducer","addPluginReducer","initialState","dispatchToCore","forEach","currentState","notifyGlobal","oldGlobalState","currentGlobalState","currentPluginState","isCoreAction","subscribe","filter","l","length","newState","getPluginStore","includes","destroy","_b","_a","splice","call","config","documents","documentOrder","activeDocumentId","defaultScale","defaultRotation","Rotation","Degree0","calculateNextActiveDocument","closingDocumentId","explicitNext","currentActiveId","closingIndex","indexOf","documentId","scale","rotation","passwordProvided","autoActivate","payload","newDocState","status","loadingProgress","error","document","pageRefreshVersions","loadStartedAt","Date","now","progress","docState","errorCode","errorDetails","loadedAt","nextActiveDocumentId","removed","remainingDocs","toIndex","newOrder","currentOrder","fromIndex","moveDocumentInOrder","targetId","pageIndexes","newVersions","pageIndex","EventControl","options","lastRun","handle","data","mode","debounce","throttle","timeoutId","window","clearTimeout","setTimeout","wait","throttleMode","KeyedEventControl","controls","key","String","keyExtractor","control","baseOptions","values","clear","isKeyedOptions","arePropsEqual","a","b","aType","pairId","objectId","getPairId","aIsArray","Array","isArray","bIsArray","used","fill","outer","i","elemA","j","arraysEqualUnordered","aKeys","Object","sort","bKeys","objectsEqual","objectIdCounter","objectIds","WeakMap","obj","PluginPackageBuilder","basePackage","autoMountElements","package","addUtility","component","addWrapper","build","registry","cooldownActions","debouncedTimeouts","unsubscribeFromState","unsubscribeFromCoreStore","unsubscribeFromStartLoadingDocument","unsubscribeFromSetDocumentLoaded","unsubscribeFromCloseDocument","unsubscribeFromSetScale","unsubscribeFromSetRotation","engine","getEngine","logger","getLogger","coreStore","getStore","pluginStore","onStoreUpdated","onCoreStoreUpdated","onActiveDocumentChanged","onDocumentLoadingStarted","onDocumentLoaded","onDocumentClosed","onScaleChanged","onRotationChanged","readyPromise","Promise","resolve","readyResolve","provides","_capability","cap","buildCapability","freeze","coreState","getCoreState","dispatchCoreAction","dispatchToAllPlugins","cooldownDispatch","cooldownTime","debouncedDispatch","debounceTime","actionKey","cancelDebouncedDispatch","actionType","subscribeToCoreStore","previousId","currentId","timeout","ready","markReady","resetReady","getActiveDocumentId","getActiveDocumentIdOrNull","getCoreDocument","getCoreDocumentOrThrow","doc","manifests","capabilities","configurations","engineInitialized","initPromise","pendingRegistrations","processingRegistrations","initialized","isInitializing","pluginsReadyPromise","destroyed","resolver","NoopLogger","ensureEngineInitialized","initialize","task","toPromise","registerPlugin","pluginPackage","validateManifest","manifest","defaultConfig","pluginsReady","readyPromises","from","map","p","all","reg","dependsOn","allDeps","requires","optional","provider","find","r","loadOrder","instantiatePlugin","create","runPluginInitialization","err","packageCreator","finalConfig","validateConfig","plugin","validatePlugin","capability","debug","info","getPluginConfig","missingKeys","hasOwnProperty","join","updatePluginConfig","getPlugin","currentConfig","newConfig","registerPluginBatch","registrations","unregisterPlugin","otherId","otherManifest","entries","some","getCapabilityProvider","hasCapability","getAllPlugins","getPluginStatus","version","isDestroyed","reverse","value","min","max","initial","equality","proxyMap","_value","baseOn","realListener","ctl","wrapped","emit","v","notify","on","off","proxy","select","selector","eq","prev","mapped","next","toGlobalEvent","shouldCache","cache","scopeCaches","scopeListeners","scopeProxyMaps","globalListeners","globalProxyMap","normalizeKey","normalizedKey","cached","globalEvent","forScope","getOrCreateListeners","getOrCreateProxyMap","size","onGlobal","getValue","getScopes","clearScope","record","k","maybeNum","Number","isFinite","trim","pkg","order","pages"],"mappings":"oHAAO,MAAMA,EAAN,WAAAC,GACLC,KAAQC,oBAAsBC,GAAyB,CAEvD,OAAAC,CAAQC,EAAYC,EAAyB,IAC3CL,KAAKC,gBAAgBK,IAAIF,EAAI,IAAIG,IAAIF,GACvC,CAEQ,uBAAAG,GACN,MAAMC,MAAcF,IACdG,MAAqBH,IAErBI,EAAOP,IACXK,EAAQG,IAAIR,GACZM,EAAeE,IAAIR,GAEnB,MAAMC,EAAeL,KAAKC,gBAAgBY,IAAIT,QAAWG,IACzD,IAAA,MAAWO,KAAOT,EAChB,GAAKI,EAAQM,IAAID,IAEjB,GAAWJ,EAAeK,IAAID,GAC5B,OAAO,OAFP,GAAIH,EAAIG,GAAM,OAAO,EAOzB,OADAJ,EAAeM,OAAOZ,IACf,GAGT,IAAA,MAAWA,KAAMJ,KAAKC,gBAAgBgB,OACpC,IAAKR,EAAQM,IAAIX,IACXO,EAAIP,GAAK,OAAO,EAIxB,OAAO,CACT,CAEA,gBAAAc,GACE,GAAIlB,KAAKQ,0BACP,MAAM,IAAIW,MAAM,kCAGlB,MAAMC,EAAmB,GACnBX,MAAcF,IACdc,MAAWd,IAEXe,EAASlB,IACb,GAAIiB,EAAKN,IAAIX,GAAK,MAAM,IAAIe,MAAM,uBAClC,GAAIV,EAAQM,IAAIX,GAAK,OAErBiB,EAAKT,IAAIR,GAET,MAAMC,EAAeL,KAAKC,gBAAgBY,IAAIT,QAAWG,IACzD,IAAA,MAAWO,KAAOT,EAChBiB,EAAMR,GAGRO,EAAKL,OAAOZ,GACZK,EAAQG,IAAIR,GACZgB,EAAOG,KAAKnB,IAGd,IAAA,MAAWA,KAAMJ,KAAKC,gBAAgBgB,OAC/BR,EAAQM,IAAIX,IACfkB,EAAMlB,GAIV,OAAOgB,CACT,ECrEK,MAAMI,UAAgCL,MAC3C,WAAApB,CAAY0B,GACVC,MAAMD,GACNzB,KAAK2B,KAAO,yBACd,EAGK,MAAMC,UAA4BT,MACvC,WAAApB,CAAY0B,GACVC,MAAMD,GACNzB,KAAK2B,KAAO,qBACd,EAGK,MAAME,UAAgCV,MAC3C,WAAApB,CAAY0B,GACVC,MAAMD,GACNzB,KAAK2B,KAAO,yBACd,EAGK,MAAMG,UAAgCX,MAC3C,WAAApB,CAAY0B,GACVC,MAAMD,GACNzB,KAAK2B,KAAO,yBACd,EAIK,MAAMI,UAAgCZ,MAC3C,WAAApB,CAAY0B,GACVC,MAAMD,GACNzB,KAAK2B,KAAO,yBACd,EAGK,MAAMK,UAAkCb,MAC7C,WAAApB,CAAY0B,GACVC,MAAMD,GACNzB,KAAK2B,KAAO,2BACd,EAGK,MAAMM,UAAiCd,MAC5C,WAAApB,CAAY0B,GACVC,MAAMD,GACNzB,KAAK2B,KAAO,0BACd,ECzCK,MAAMO,EASX,WAAAnC,CAAYoC,EAAwBC,GAClCpC,KAAKmC,MAAQA,EACbnC,KAAKoC,SAAWA,CAClB,CAMA,QAAAC,GACE,OAAOrC,KAAKmC,MAAME,WAAWC,QAAQtC,KAAKoC,SAC5C,CAQA,QAAAG,CAASC,GACP,OAAOxC,KAAKmC,MAAMM,iBAAiBzC,KAAKoC,SAAUI,EACpD,CASA,gBAAAE,CACEC,GAEA,OAAO3C,KAAKmC,MAAMS,kBAAkB5C,KAAKoC,SAAU,CAACI,EAAQK,EAAgBC,KAC1EH,EACEH,EACAK,EACAC,IAGN,CAYA,QAAAC,CACEC,EACAC,GAMA,OAAOjD,KAAKmC,MAAMY,SAASC,EAAM,CAACR,EAAQU,EAAOC,KAC/CF,EACET,EACAU,EAAMZ,QAAQtC,KAAKoC,UACnBe,EAASb,QAAQtC,KAAKoC,YAG5B,EC/EK,MAAMgB,EAAyB,yBACzBC,EAAmC,mCACnCC,EAAsB,sBACtBC,EAAqB,qBACrBC,EAAyB,yBACzBC,EAAiB,iBACjBC,EAAsB,sBAGtBC,EAAoB,oBACpBC,EAAgB,gBAGhBC,EAAmB,mBACnBC,EAAgB,gBAChBC,EAAY,YACZC,EAAY,YACZC,EAAe,eAGfC,EAAoB,oBACpBC,EAAuB,uBAEvBC,EAAoB,CAC/BhB,EACAC,EACAC,EACAG,EACAC,EACAH,EACAC,EACAK,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAR,EACAC,GCjCK,MAAMS,EAgBX,WAAAtE,CACEuE,EACOC,GAAAvE,KAAAuE,iBAAAA,EAfTvE,KAAQwE,eAAuD,CAAA,EAE/DxE,KAAQyE,UAAwC,GAChDzE,KAAQ0E,gBAAoD,CAAA,EAG5D1E,KAAQ2E,eAAgB,EAWtB3E,KAAKkD,MAAQ,CAAE0B,KAAML,EAAkBjC,QAAS,CAAA,GAChDtC,KAAK6E,YAAcP,CACrB,CAQA,gBAAAQ,CACE1C,EACAkC,EACAS,GAEA/E,KAAKkD,MAAMZ,QAAQF,GAAY2C,EAC/B/E,KAAKwE,eAAepC,GAAYkC,CAClC,CASA,cAAAU,CAAexC,GACb,IAAKxC,KAAK6E,YACR,OAAO7E,KAAKqC,WAGd,GAAIrC,KAAK2E,cACP,MAAM,IAAIxD,MACR,+GAKJ,MAAMgC,EAAWnD,KAAKqC,WAEtB,IACErC,KAAK2E,eAAgB,EAErB3E,KAAKkD,MAAM0B,KAAO5E,KAAK6E,YAAY7E,KAAKkD,MAAM0B,KAAMpC,EACtD,CAAA,QAEExC,KAAK2E,eAAgB,CACvB,CASA,OALA3E,KAAKyE,UAAUQ,QAAStC,IACtB,MAAMuC,EAAelF,KAAKqC,WAC1BM,EAASH,EAAQ0C,EAAc/B,KAG1BnD,KAAKqC,UACd,CAYA,gBAAAI,CACEL,EACAI,EACA2C,GAAwB,GAExB,GAAInF,KAAK2E,cACP,MAAM,IAAIxD,MACR,+GAKJ,MAAMiE,EAAiBpF,KAAKqC,WAEtBiC,EAAUtE,KAAKwE,eAAepC,GACpC,IAAKkC,EAEH,OAAOc,EAAe9C,QAAQF,GAIhC,MAAMU,EAAiBsC,EAAe9C,QAAQF,GAE9C,IACEpC,KAAK2E,eAAgB,EAErB,MAAM9B,EAAiByB,EAAQxB,EAAgBN,GAE/CxC,KAAKkD,MAAMZ,QAAQF,GAAYS,CACjC,CAAA,QACE7C,KAAK2E,eAAgB,CACvB,CAoBA,OAhBIQ,GACFnF,KAAKyE,UAAUQ,QAAStC,IACtB,MAAM0C,EAAqBrF,KAAKqC,WAChCM,EAASH,EAAQ6C,EAAoBD,KAMrCpF,KAAK0E,gBAAgBtC,IACvBpC,KAAK0E,gBAAgBtC,GAAU6C,QAAStC,IACtC,MAAM2C,EAAqBtF,KAAKqC,WAAWC,QAAQF,GACnDO,EAASH,EAAQ8C,EAAoBxC,KAIlC9C,KAAKqC,WAAWC,QAAQF,EACjC,CAWA,QAAAG,CAASC,GACP,GAAIxC,KAAK2E,cACP,MAAM,IAAIxD,MACR,+GAKJ,MAAMgC,EAAWnD,KAAKqC,WAEtB,IACErC,KAAK2E,eAAgB,EAGjB3E,KAAKuF,aAAa/C,KACpBxC,KAAKkD,MAAM0B,KAAO5E,KAAK6E,YAAY7E,KAAKkD,MAAM0B,KAAMpC,IAItD,IAAA,MAAWJ,KAAYpC,KAAKwE,eAAgB,CAC1C,MAAMF,EAAUtE,KAAKwE,eAAepC,GAC9BU,EAAiBK,EAASb,QAAQF,GACpCkC,IACFtE,KAAKkD,MAAMZ,QAAQF,GAAYkC,EAAQxB,EAAgBN,GAE3D,CACF,CAAA,QACExC,KAAK2E,eAAgB,CACvB,CAUA,OANA3E,KAAKyE,UAAUQ,QAAStC,IACtB,MAAMuC,EAAelF,KAAKqC,WAC1BM,EAASH,EAAQ0C,EAAc/B,KAI1BnD,KAAKqC,UACd,CAMA,QAAAA,GACE,GAAIrC,KAAK2E,cACP,MAAM,IAAIxD,MACR,wMAMJ,MAAO,CACLyD,KAAM,IAAK5E,KAAKkD,MAAM0B,MACtBtC,QAAS,IAAKtC,KAAKkD,MAAMZ,SAE7B,CASA,SAAAkD,CAAU7C,GACR,GAAI3C,KAAK2E,cACP,MAAM,IAAIxD,MACR,4OAOJ,OADAnB,KAAKyE,UAAUlD,KAAKoB,GACb,KACL,GAAI3C,KAAK2E,cACP,MAAM,IAAIxD,MACR,iFAGJnB,KAAKyE,UAAYzE,KAAKyE,UAAUgB,OAAQC,GAAMA,IAAM/C,GAExD,CAUA,iBAAAC,CAAkBR,EAAkBO,GAClC,KAAMP,KAAYpC,KAAKkD,MAAMZ,SAC3B,MAAM,IAAInB,MACR,sCAAsCiB,gDAI1C,GAAIpC,KAAK2E,cACP,MAAM,IAAIxD,MAAM,8EAQlB,OALKnB,KAAK0E,gBAAgBtC,KACxBpC,KAAK0E,gBAAgBtC,GAAY,IAEnCpC,KAAK0E,gBAAgBtC,GAAUb,KAAKoB,GAE7B,KACL,GAAI3C,KAAK2E,cACP,MAAM,IAAIxD,MACR,iFAGJnB,KAAK0E,gBAAgBtC,GAAYpC,KAAK0E,gBAAgBtC,GAAUqD,OAAQC,GAAMA,IAAM/C,GACtC,IAA1C3C,KAAK0E,gBAAgBtC,GAAUuD,eAC1B3F,KAAK0E,gBAAgBtC,GAGlC,CAUA,QAAAW,CACEC,EACAC,GAMA,OAAOjD,KAAKwF,UAAU,CAAChD,EAAQoD,EAAUzC,KACnCX,EAAOQ,OAASA,GAClBC,EAAQT,EAA4CoD,EAAUzC,IAGpE,CAOA,cAAA0C,CACEzD,GAEA,KAAMA,KAAYpC,KAAKkD,MAAMZ,SAC3B,MAAM,IAAInB,MACR,sCAAsCiB,gDAG1C,OAAO,IAAIF,EAAuClC,KAAMoC,EAC1D,CAMO,YAAAmD,CAAa/C,GAClB,OAAO4B,EAAkB0B,SAAStD,EAAOQ,KAC3C,CAKO,OAAA+C,WAEL/F,KAAKyE,UAAUkB,OAAS,EACxB,IAAA,MAAWvF,KAAMJ,KAAK0E,gBACpB,OAAAsB,EAAA,OAAAC,EAAAjG,KAAK0E,gBAAgBtE,SAArB,EAAA6F,EAA0BC,SAA1BF,EAAAG,KAAAF,EAAmC,GAErCjG,KAAK0E,gBAAkB,CAAA,EAGvB1E,KAAKwE,eAAiB,CAAA,EACtBxE,KAAKkD,MAAMZ,QAAU,CAAA,EAGrBtC,KAAKkD,MAAM0B,KAAO,IAAK5E,KAAKuE,iBAC9B,EC/SK,MAAMA,EAAkE6B,IAAA,CAC7EC,UAAW,CAAA,EACXC,cAAe,GACfC,iBAAkB,KAClBC,oBAAcJ,WAAQI,eAAgB,EACtCC,iBAAiB,MAAAL,OAAA,EAAAA,EAAQK,kBAAmBC,WAASC,UC7ChD,SAASC,EACd1D,EACA2D,EACAC,GAEA,MAAMC,EAAkB7D,EAAMqD,iBAG9B,GAAIQ,IAAoBF,EACtB,OAAOE,EAIT,QAAqB,IAAjBD,EAEF,OAAOA,GAAgB5D,EAAMmD,UAAUS,GAAgBA,EAAe,KAIxE,MAAME,EAAe9D,EAAMoD,cAAcW,QAAQJ,GAEjD,OAAqB,IAAjBG,EAEK,KAILA,EAAe,EACV9D,EAAMoD,cAAcU,EAAe,GAIxCA,EAAe9D,EAAMoD,cAAcX,OAAS,EACvCzC,EAAMoD,cAAcU,EAAe,GAIrC,IACT,CCzBO,MAAMnC,EAA8C,CAAC3B,EAAOV,KACjE,OAAQA,EAAOQ,MACb,KAAKI,EAAwB,CAC3B,MAAM8D,WACJA,EAAAvF,KACAA,EAAAwF,MACAA,EAAAC,SACAA,EAAAC,iBACAA,EAAAC,aACAA,GAAe,GACb9E,EAAO+E,QAELC,EAA6B,CACjCpH,GAAI8G,EACJvF,OACA8F,OAAQ,UACRC,gBAAiB,EACjBC,MAAO,KACPC,SAAU,KACVT,MAAOA,GAASjE,EAAMsD,aACtBY,SAAUA,GAAYlE,EAAMuD,gBAC5BY,iBAAkBA,IAAoB,EACtCQ,oBAAqB,CAAA,EACrBC,cAAeC,KAAKC,OAGtB,MAAO,IACF9E,EACHmD,UAAW,IACNnD,EAAMmD,UACTa,CAACA,GAAaM,GAEhBlB,cAAe,IAAIpD,EAAMoD,cAAeY,GAExCX,iBACEe,IAAiBpE,EAAMqD,iBAAmBW,EAAahE,EAAMqD,iBAEnE,CAEA,KAAKlD,EAAkC,CACrC,MAAM6D,WAAEA,EAAAe,SAAYA,GAAazF,EAAO+E,QAClCW,EAAWhF,EAAMmD,UAAUa,GAEjC,OAAKgB,GAAgC,YAApBA,EAAST,OAEnB,IACFvE,EACHmD,UAAW,IACNnD,EAAMmD,UACTa,CAACA,GAAa,IACTgB,EACHR,gBAAiBO,KARgC/E,CAYzD,CAEA,KAAKI,EAAqB,CACxB,MAAM4D,WAAEA,EAAAU,SAAYA,GAAapF,EAAO+E,QAClCW,EAAWhF,EAAMmD,UAAUa,GAEjC,OAAKgB,EAEE,IACFhF,EACHmD,UAAW,IACNnD,EAAMmD,UACTa,CAACA,GAAa,IACTgB,EACHT,OAAQ,SACRG,WACAD,MAAO,KACPQ,eAAW,EACXC,kBAAc,EACdf,sBAAkB,EAClBgB,SAAUN,KAAKC,SAdC9E,CAkBxB,CAEA,KAAKK,EAAoB,CACvB,MAAM2D,WAAEA,EAAAS,MAAYA,EAAAQ,UAAOA,EAAAC,aAAWA,GAAiB5F,EAAO+E,QACxDW,EAAWhF,EAAMmD,UAAUa,GAEjC,OAAKgB,EAEE,IACFhF,EACHmD,UAAW,IACNnD,EAAMmD,UACTa,CAACA,GAAa,IACTgB,EACHT,OAAQ,QACRE,QACAQ,YACAC,kBAXgBlF,CAexB,CAEA,KAAKM,EAAwB,CAC3B,MAAM0D,WAAEA,EAAAG,iBAAYA,GAAqB7E,EAAO+E,QAC1CW,EAAWhF,EAAMmD,UAAUa,GAEjC,OAAKgB,GAAgC,UAApBA,EAAST,OAEnB,IACFvE,EACHmD,UAAW,IACNnD,EAAMmD,UACTa,CAACA,GAAa,IACTgB,EACHT,OAAQ,UACRC,gBAAiB,EACjBC,MAAO,KACPQ,eAAW,EACXC,kBAAc,EACdf,iBAAkBA,IAAoB,EACtCS,cAAeC,KAAKC,SAd2B9E,CAkBvD,CAEA,KAAKO,EAAgB,CACnB,MAAMyD,WAAEA,EAAAoB,qBAAYA,GAAyB9F,EAAO+E,SAC5CL,CAACA,GAAaqB,KAAYC,GAAkBtF,EAAMmD,UAE1D,MAAO,IACFnD,EACHmD,UAAWmC,EACXlC,cAAepD,EAAMoD,cAAcb,OAAQrF,GAAOA,IAAO8G,GACzDX,iBAAkBK,EAA4B1D,EAAOgE,EAAYoB,GAErE,CAEA,KAAK1E,EAAe,CAClB,MAAMsD,WAAEA,EAAAuB,QAAYA,GAAYjG,EAAO+E,QACjCmB,ED7GL,SACLC,EACAzB,EACAuB,GAEA,MAAMG,EAAYD,EAAa1B,QAAQC,GAGvC,QAAI0B,EAAkB,OAAO,KAC7B,GAAIH,EAAU,GAAKA,GAAWE,EAAahD,OAAQ,OAAO,KAC1D,GAAIiD,IAAcH,EAAS,OAAO,KAGlC,MAAMC,EAAW,IAAIC,GAIrB,OAHAD,EAASxC,OAAO0C,EAAW,GAC3BF,EAASxC,OAAOuC,EAAS,EAAGvB,GAErBwB,CACT,CC2FuBG,CAAoB3F,EAAMoD,cAAeY,EAAYuB,GAGtE,OAAKC,EAEE,IACFxF,EACHoD,cAAeoC,GAJKxF,CAMxB,CAEA,KAAKS,EACH,MAAO,IACFT,EACHoD,cAAe9D,EAAO+E,SAI1B,KAAK7D,EACH,MAAO,IACFR,EACHqD,iBAAkB/D,EAAO+E,SAI7B,KAAKvD,EAAW,CACd,MAAMmD,MAAEA,EAAAD,WAAOA,GAAe1E,EAAO+E,QAC/BuB,EAAW5B,GAAchE,EAAMqD,iBAErC,IAAKuC,EAAU,OAAO5F,EAEtB,MAAMgF,EAAWhF,EAAMmD,UAAUyC,GACjC,OAAKZ,EAEE,IACFhF,EACHmD,UAAW,IACNnD,EAAMmD,UACTyC,CAACA,GAAW,IACPZ,EACHf,WARgBjE,CAYxB,CAEA,KAAKe,EAAc,CACjB,MAAMmD,SAAEA,EAAAF,WAAUA,GAAe1E,EAAO+E,QAClCuB,EAAW5B,GAAchE,EAAMqD,iBAErC,IAAKuC,EAAU,OAAO5F,EAEtB,MAAMgF,EAAWhF,EAAMmD,UAAUyC,GACjC,OAAKZ,EAEE,IACFhF,EACHmD,UAAW,IACNnD,EAAMmD,UACTyC,CAACA,GAAW,IACPZ,EACHd,cARgBlE,CAYxB,CAEA,KAAKY,EAAe,CAClB,MAAMoD,WAAEA,EAAA6B,YAAYA,GAAgBvG,EAAO+E,QACrCW,EAAWhF,EAAMmD,UAAUa,GAEjC,IAAKgB,EAAU,OAAOhF,EAGtB,MAAM8F,EAAc,IAAKd,EAASL,qBAClC,IAAA,MAAWoB,KAAaF,EACtBC,EAAYC,IAAcD,EAAYC,IAAc,GAAK,EAG3D,MAAO,IACF/F,EACHmD,UAAW,IACNnD,EAAMmD,UACTa,CAACA,GAAa,IACTgB,EACHL,oBAAqBmB,IAI7B,CAEA,QACE,OAAO9F,IC3NN,MAAMgG,EAIX,WAAAnJ,CACUkD,EACAkG,GADAnJ,KAAAiD,QAAAA,EACAjD,KAAAmJ,QAAAA,EAJVnJ,KAAQoJ,QAAkB,EAO1BpJ,KAAAqJ,OAAUC,IACkB,aAAtBtJ,KAAKmJ,QAAQI,KACfvJ,KAAKwJ,SAASF,GAEdtJ,KAAKyJ,SAASH,GANf,CAUK,QAAAE,CAASF,GACXtJ,KAAK0J,WACPC,OAAOC,aAAa5J,KAAK0J,WAG3B1J,KAAK0J,UAAYC,OAAOE,WAAW,KACjC7J,KAAKiD,QAAQqG,GACbtJ,KAAK0J,eAAY,GAChB1J,KAAKmJ,QAAQW,KAClB,CAEQ,QAAAL,CAASH,GACf,GAA0B,aAAtBtJ,KAAKmJ,QAAQI,KAAqB,OAEtC,MAAMvB,EAAMD,KAAKC,MACX+B,EAAe/J,KAAKmJ,QAAQY,cAAgB,mBAE9C/B,EAAMhI,KAAKoJ,SAAWpJ,KAAKmJ,QAAQW,OAChB,qBAAjBC,GACF/J,KAAKiD,QAAQqG,GAEftJ,KAAKoJ,QAAUpB,GAIbhI,KAAK0J,WACPC,OAAOC,aAAa5J,KAAK0J,WAG3B1J,KAAK0J,UAAYC,OAAOE,WACtB,KACE7J,KAAKiD,QAAQqG,GACbtJ,KAAKoJ,QAAUrB,KAAKC,MACpBhI,KAAK0J,eAAY,GAEnB1J,KAAKmJ,QAAQW,MAAQ9B,EAAMhI,KAAKoJ,SAEpC,CAEA,OAAArD,GACM/F,KAAK0J,WACPC,OAAOC,aAAa5J,KAAK0J,UAE7B,EAgBK,MAAMM,EAIX,WAAAjK,CACUkD,EACAkG,GADAnJ,KAAAiD,QAAAA,EACAjD,KAAAmJ,QAAAA,EALVnJ,KAAQiK,aAAe/J,IAiBvBF,KAAAqJ,OAAUC,IACR,MAAMY,EAAMC,OAAOnK,KAAKmJ,QAAQiB,aAAad,IAE7C,IAAIe,EAAUrK,KAAKiK,SAASpJ,IAAIqJ,GAC3BG,IACHA,EAAU,IAAInB,EAAalJ,KAAKiD,QAASjD,KAAKsK,aAC9CtK,KAAKiK,SAAS3J,IAAI4J,EAAKG,IAGzBA,EAAQhB,OAAOC,IAlBftJ,KAAKsK,YAAc,CACjBf,KAAMJ,EAAQI,KACdO,KAAMX,EAAQW,QACO,aAAjBX,EAAQI,MAAuB,iBAAkBJ,EACjD,CAAEY,aAAcZ,EAAQY,cACxB,CAAA,EAER,CAcA,OAAAhE,GACE,IAAA,MAAWsE,KAAWrK,KAAKiK,SAASM,SAClCF,EAAQtE,UAEV/F,KAAKiK,SAASO,OAChB,EAMK,SAASC,EACdtB,GAEA,MAAO,iBAAkBA,CAC3B,CCjIO,SAASuB,EAAcC,EAAQC,EAAQnK,GAE5C,GAAIkK,IAAMC,EACR,OAAO,EAIT,GAAS,MAALD,GAAkB,MAALC,EAEf,OAAOD,IAAMC,EAIf,MAAMC,SAAeF,EAErB,GAAIE,WADiBD,EACA,OAAO,EAG5B,GAAc,WAAVC,EAAoB,CAEjBpK,IAASA,EAAU,IAAIF,KAC5B,MAAMuK,EA2BV,SAAmBH,EAAQC,GAGzB,MAAO,GAAGG,EAASJ,OAAOI,EAASH,IACrC,CA/BmBI,CAAUL,EAAGC,GAC5B,GAAInK,EAAQM,IAAI+J,GAGd,OAAO,EAETrK,EAAQG,IAAIkK,GAEZ,MAAMG,EAAWC,MAAMC,QAAQR,GACzBS,EAAWF,MAAMC,QAAQP,GAC/B,OAAIK,GAAYG,EAqCpB,SAA8BT,EAAUC,EAAUnK,GAChD,GAAIkK,EAAEhF,SAAWiF,EAAEjF,OAAQ,OAAO,EAElC,MAAM0F,EAAO,IAAIH,MAAeN,EAAEjF,QAAQ2F,MAAK,GAG/CC,UAAgBC,EAAI,EAAGA,EAAIb,EAAEhF,OAAQ6F,IAAK,CACxC,MAAMC,EAAQd,EAAEa,GAChB,IAAA,IAASE,EAAI,EAAGA,EAAId,EAAEjF,OAAQ+F,IAC5B,IAAIL,EAAKK,IACLhB,EAAce,EAAOb,EAAEc,GAAIjL,GAAU,CACvC4K,EAAKK,IAAK,EACV,SAASH,CACX,CAGF,OAAO,CACT,CAEA,OAAO,CACT,CAvDaI,CAAqBhB,EAAGC,EAAGnK,IACxBwK,IAAaG,GAwD7B,SAAsBT,EAAWC,EAAWnK,GAE1C,MAAMmL,EAAQC,OAAO5K,KAAK0J,GAAGmB,OACvBC,EAAQF,OAAO5K,KAAK2J,GAAGkB,OAC7B,GAAIF,EAAMjG,SAAWoG,EAAMpG,OAAQ,OAAO,EAG1C,IAAA,IAAS6F,EAAI,EAAGA,EAAII,EAAMjG,OAAQ6F,IAChC,GAAII,EAAMJ,KAAOO,EAAMP,GAAI,OAAO,EAIpC,IAAA,MAAWtB,KAAO0B,EAAO,CAKvB,IAAKlB,EAHQC,EAAET,GAEFU,EAAEV,GACgBzJ,GAC7B,OAAO,CAEX,CACA,OAAO,CACT,CA5EauL,CAAarB,EAAGC,EAAGnK,EAK9B,CAIA,OAAO,CACT,CAYA,IAAIwL,EAAkB,EACtB,MAAMC,MAAgBC,QAEtB,SAASpB,EAASqB,GAIhB,OAHKF,EAAUnL,IAAIqL,IACjBF,EAAU5L,IAAI8L,IAAOH,GAEhBC,EAAUrL,IAAIuL,EACvB,CChFO,MAAMC,EASX,WAAAtM,CAAYuM,GAFZtM,KAAQuM,kBAAwC,GAG9CvM,KAAKwM,QAAUF,CACjB,CAEA,UAAAG,CAAWC,GAET,OADA1M,KAAKuM,kBAAkBhL,KAAK,CAAEmL,YAAW1J,KAAM,YACxChD,IACT,CAEA,UAAA2M,CAAWD,GAET,OADA1M,KAAKuM,kBAAkBhL,KAAK,CAAEmL,YAAW1J,KAAM,YACxChD,IACT,CAEA,KAAA4M,GACE,MAAO,IACF5M,KAAKwM,QACRD,kBAAmB,IAAMvM,KAAKuM,kBAElC,qBCfK,MA8BL,WAAAxM,CACkBK,EACNyM,GAEV,GAHgB7M,KAAAI,GAAAA,EACNJ,KAAA6M,SAAAA,EAjBZ7M,KAAQ8M,gBAA0C,CAAA,EAClD9M,KAAQ+M,kBAA4C,CAAA,EACpD/M,KAAQgN,qBAA4C,KACpDhN,KAAQiN,yBAAgD,KACxDjN,KAAQkN,oCAA2D,KACnElN,KAAQmN,iCAAwD,KAChEnN,KAAQoN,6BAAoD,KAC5DpN,KAAQqN,wBAA+C,KACvDrN,KAAQsN,2BAAkD,KAWpDlN,IAAQJ,KAAKD,YAAkCK,GACjD,MAAM,IAAIe,MACR,uBAAuBf,SAAWJ,KAAKD,YAAkCK,MAG7EJ,KAAKuN,OAASvN,KAAK6M,SAASW,YAC5BxN,KAAKyN,OAASzN,KAAK6M,SAASa,YAC5B1N,KAAK2N,UAAY3N,KAAK6M,SAASe,WAC/B5N,KAAK6N,YAAc7N,KAAK2N,UAAU9H,eAAgC7F,KAAKI,IACvEJ,KAAKgN,qBAAuBhN,KAAK6N,YAAYnL,iBAAiB,CAACF,EAAQoD,EAAUzC,KAC/EnD,KAAK8N,eAAe3K,EAAUyC,KAEhC5F,KAAKiN,yBAA2BjN,KAAK2N,UAAUnI,UAAU,CAAChD,EAAQoD,EAAUzC,KAC1EnD,KAAK+N,mBAAmB5K,EAAUyC,GAC9BA,EAAShB,KAAK2B,mBAAqBpD,EAASyB,KAAK2B,kBACnDvG,KAAKgO,wBACH7K,EAASyB,KAAK2B,iBACdX,EAAShB,KAAK2B,oBAIpBvG,KAAKkN,oCAAsClN,KAAK2N,UAAU5K,SACxDK,EACCZ,IACCxC,KAAKiO,yBAAyBzL,EAAO+E,QAAQL,cAGjDlH,KAAKmN,iCAAmCnN,KAAK2N,UAAU5K,SACrDO,EACCd,IACCxC,KAAKkO,iBAAiB1L,EAAO+E,QAAQL,cAGzClH,KAAKoN,6BAA+BpN,KAAK2N,UAAU5K,SAASU,EAAiBjB,IAC3ExC,KAAKmO,iBAAiB3L,EAAO+E,QAAQL,cAEvClH,KAAKqN,wBAA0BrN,KAAK2N,UAAU5K,SAASiB,EAAW,CAACxB,EAAQU,KACzE,MAAM4F,EAAWtG,EAAO+E,QAAQL,YAAchE,EAAM0B,KAAK2B,iBACrDuC,GACF9I,KAAKoO,eAAetF,EAAUtG,EAAO+E,QAAQJ,SAGjDnH,KAAKsN,2BAA6BtN,KAAK2N,UAAU5K,SAASkB,EAAc,CAACzB,EAAQU,KAC/E,MAAM4F,EAAWtG,EAAO+E,QAAQL,YAAchE,EAAM0B,KAAK2B,iBACrDuC,GACF9I,KAAKqO,kBAAkBvF,EAAUtG,EAAO+E,QAAQH,YAKpDpH,KAAKsO,aAAe,IAAIC,QAASC,IAC/BxO,KAAKyO,aAAeD,IAGtBxO,KAAKyO,cACP,CAKO,QAAAC,GACL,IAAK1O,KAAK2O,YAAa,CACrB,MAAMC,EAAM5O,KAAK6O,kBAEjB7O,KAAK2O,YAAc9C,OAAOiD,OAAOF,EACnC,CACA,OAAO5O,KAAK2O,WACd,CAUA,SAAczL,GACZ,OAAOlD,KAAK6N,YAAYxL,UAC1B,CAKA,aAAc0M,GACZ,OAAO/O,KAAK2N,UAAUtL,UACxB,CAKU,QAAAA,GACR,OAAOrC,KAAK6N,YAAYxL,UAC1B,CAKU,YAAA2M,GACR,OAAOhP,KAAK2N,UAAUtL,UACxB,CAKU,kBAAA4M,CAAmBzM,GAC3B,OAAOxC,KAAK2N,UAAU3I,eAAexC,EACvC,CAKU,oBAAA0M,CAAqB1M,GAC7B,OAAOxC,KAAK2N,UAAUpL,SAASC,EACjC,CAKU,QAAAD,CAASC,GACjB,OAAOxC,KAAK6N,YAAYtL,SAASC,EACnC,CASU,gBAAA2M,CAAiB3M,EAAiB4M,EAAuB,KACjE,MAAMpH,EAAMD,KAAKC,MAGjB,OAAIA,GAFmBhI,KAAK8M,gBAAgBtK,EAAOQ,OAAS,IAEhCoM,IAC1BpP,KAAK8M,gBAAgBtK,EAAOQ,MAAQgF,EACpChI,KAAKuC,SAASC,IACP,EAIX,CAQU,iBAAA6M,CAAkB7M,EAAiB8M,EAAuB,KAClE,MAAMC,EAAY/M,EAAOQ,KAGrBhD,KAAK+M,kBAAkBwC,IACzB3F,aAAa5J,KAAK+M,kBAAkBwC,IAItCvP,KAAK+M,kBAAkBwC,GAAa1F,WAAW,KAC7C7J,KAAKuC,SAASC,UACPxC,KAAK+M,kBAAkBwC,IAC7BD,EACL,CAMU,uBAAAE,CAAwBC,GAC5BzP,KAAK+M,kBAAkB0C,KACzB7F,aAAa5J,KAAK+M,kBAAkB0C,WAC7BzP,KAAK+M,kBAAkB0C,GAElC,CAKU,SAAAjK,CAAU7C,GAClB,OAAO3C,KAAK6N,YAAYnL,iBAAiBC,EAC3C,CAKU,oBAAA+M,CACR/M,GAEA,OAAO3C,KAAK2N,UAAUnI,UAAU7C,EAClC,CAOU,cAAAmL,CAAe3K,EAAkByC,GAE3C,CAOU,kBAAAmI,CACR5K,EACAyC,GAGF,CAOU,wBAAAqI,CAAyB/G,GAEnC,CAMU,gBAAAgH,CAAiBhH,GAE3B,CAOU,gBAAAiH,CAAiBjH,GAE3B,CAOU,uBAAA8G,CAAwB2B,EAA2BC,GAE7D,CAEU,cAAAxB,CAAelH,EAAoBC,GAE7C,CAEU,iBAAAkH,CAAkBnH,EAAoBE,GAEhD,CAKO,OAAArB,GAEL8F,OAAOtB,OAAOvK,KAAK+M,mBAAmB9H,QAAS4K,IAC7CjG,aAAaiG,KAEf7P,KAAK+M,kBAAoB,CAAA,EAErB/M,KAAKgN,uBACPhN,KAAKgN,uBACLhN,KAAKgN,qBAAuB,MAE1BhN,KAAKiN,2BACPjN,KAAKiN,2BACLjN,KAAKiN,yBAA2B,MAE9BjN,KAAKkN,sCACPlN,KAAKkN,sCACLlN,KAAKkN,oCAAsC,MAEzClN,KAAKmN,mCACPnN,KAAKmN,mCACLnN,KAAKmN,iCAAmC,MAEtCnN,KAAKoN,+BACPpN,KAAKoN,+BACLpN,KAAKoN,6BAA+B,MAElCpN,KAAKqN,0BACPrN,KAAKqN,0BACLrN,KAAKqN,wBAA0B,MAE7BrN,KAAKsN,6BACPtN,KAAKsN,6BACLtN,KAAKsN,2BAA6B,KAEtC,CAKO,KAAAwC,GACL,OAAO9P,KAAKsO,YACd,CAKU,SAAAyB,GACR/P,KAAKyO,cACP,CAKU,UAAAuB,GACRhQ,KAAKsO,aAAe,IAAIC,QAASC,IAC/BxO,KAAKyO,aAAeD,GAExB,CAMU,mBAAAyB,GACR,MAAM7P,EAAKJ,KAAK+O,UAAUnK,KAAK2B,iBAC/B,IAAKnG,EACH,MAAM,IAAIe,MAAM,sBAElB,OAAOf,CACT,CAKU,yBAAA8P,GACR,OAAOlQ,KAAK+O,UAAUnK,KAAK2B,gBAC7B,CAOU,eAAA4J,CAAgBjJ,GACxB,MAAM9G,EAAK8G,GAAclH,KAAKkQ,4BAC9B,OAAK9P,EACEJ,KAAK+O,UAAUnK,KAAKyB,UAAUjG,IAAO,KAD5B,IAElB,CAOU,sBAAAgQ,CAAuBlJ,GAC/B,MAAMmJ,EAAMrQ,KAAKmQ,gBAAgBjJ,GACjC,IAAKmJ,EACH,MAAM,IAAIlP,MAAM,uBAAuB+F,GAAc,YAEvD,OAAOmJ,CACT,mcCpYK,MAqBL,WAAAtQ,CAAYwN,EAAmBnH,GApB/BpG,KAAQsC,YAAoCpC,IAC5CF,KAAQsQ,cAA6CpQ,IACrDF,KAAQuQ,iBAAwCrQ,IAChDF,KAAQyH,WAAwCvH,IAEhDF,KAAQwQ,mBAA2CtQ,IAEnDF,KAAQyQ,mBAAoB,EAE5BzQ,KAAQ0Q,YAAoC,KAG5C1Q,KAAQ2Q,qBAA6C,GACrD3Q,KAAQ4Q,wBAAgD,GACxD5Q,KAAQ6Q,aAAc,EACtB7Q,KAAQ8Q,gBAAiB,EAEzB9Q,KAAQ+Q,oBAA4C,KACpD/Q,KAAQgR,WAAY,EAGlBhR,KAAKiR,SAAW,IAAInR,EACpBE,KAAKuN,OAASA,EACdvN,KAAKuE,iBAAmBA,EAAiB6B,GACzCpG,KAAKmC,MAAQ,IAAIkC,EAA6BQ,EAAa7E,KAAKuE,kBAChEvE,KAAKyN,QAAS,MAAArH,OAAA,EAAAA,EAAQqH,SAAU,IAAIyD,EAAAA,UACtC,CAKA,SAAAxD,GACE,OAAO1N,KAAKyN,MACd,CAKA,6BAAc0D,GACZ,IAAInR,KAAKyQ,kBAIT,GAAIzQ,KAAKuN,OAAO6D,WAAY,CAC1B,MAAMC,EAAOrR,KAAKuN,OAAO6D,mBACnBC,EAAKC,YACXtR,KAAKyQ,mBAAoB,CAC3B,MACEzQ,KAAKyQ,mBAAoB,CAE7B,CAKA,cAAAc,CAMEC,EACApL,GAEA,GAAIpG,KAAK6Q,cAAgB7Q,KAAK8Q,eAC5B,MAAM,IAAItP,EAAwB,gDAGpCxB,KAAKyR,iBAAiBD,EAAcE,UAGpC1R,KAAKmC,MAAM2C,iBACT0M,EAAcE,SAAStR,GAGvBoR,EAAclN,QACd,mBAAsBkN,EAAczM,aAC/ByM,EAAczM,aACb/E,KAAKuE,iBACL,IACKiN,EAAcE,SAASC,iBACvBvL,IAGPoL,EAAczM,cAGpB/E,KAAK2Q,qBAAqBpP,KAAK,CAC7BiL,QAASgF,EACTpL,UAEJ,CAKA,QAAAwH,GACE,OAAO5N,KAAKmC,KACd,CAKA,SAAAqL,GACE,OAAOxN,KAAKuN,MACd,CAKO,YAAAqE,GAEL,OAAI5R,KAAK+Q,sBAKT/Q,KAAK+Q,+BAEE/Q,KAAK6Q,mBACF7Q,KAAKoR,aAIb,MAAMS,EAAgB3G,MAAM4G,KAAK9R,KAAKsC,QAAQiI,UAAUwH,IAAKC,GACxC,mBAAZA,EAAElC,MAAuBkC,EAAElC,QAAUvB,QAAQC,iBAGhDD,QAAQ0D,IAAIJ,EACpB,MAhBS7R,KAAK+Q,mBAmBhB,CAKA,gBAAMK,GACJ,GAAIpR,KAAKgR,UACP,MAAM,IAAIxP,EAAwB,+BAGpC,OAAIxB,KAAK0Q,cAIT1Q,KAAK0Q,uBACH,GAAI1Q,KAAK6Q,YACP,MAAM,IAAIrP,EAAwB,mCAGpCxB,KAAK8Q,gBAAiB,EAEtB,IAEE,SADM9Q,KAAKmR,0BACPnR,KAAKgR,UAAW,OAEpB,KAAOhR,KAAK2Q,qBAAqBhL,OAAS,GAAG,CAC3C,GAAI3F,KAAKgR,UAAW,OAEpBhR,KAAK4Q,wBAA0B,IAAI5Q,KAAK2Q,sBACxC3Q,KAAK2Q,qBAAuB,GAM5B,IAAA,MAAWuB,KAAOlS,KAAK4Q,wBAAyB,CAC9C,MAAMuB,MAAgB5R,IAChB6R,EAAU,IAAIF,EAAI1F,QAAQkF,SAASW,YAAaH,EAAI1F,QAAQkF,SAASY,UAE3E,IAAA,MAAW1D,KAAOwD,EAAS,CAEzB,MAAMG,EAAWvS,KAAK4Q,wBAAwB4B,KAAMC,GAClDA,EAAEjG,QAAQkF,SAAShD,SAAS5I,SAAS8I,IAKnC2D,GACFJ,EAAUvR,IAAI2R,EAAS/F,QAAQkF,SAAStR,GAE5C,CACAJ,KAAKiR,SAAS9Q,QAAQ+R,EAAI1F,QAAQkF,SAAStR,GAAI,IAAI+R,GACrD,CAEA,MAAMO,EAAY1S,KAAKiR,SAAS/P,mBAOhC,IAAA,MAAWd,KAAMsS,EAAW,CAC1B,MAAMR,EAAMlS,KAAK4Q,wBAAwB4B,KAAMC,GAAMA,EAAEjG,QAAQkF,SAAStR,KAAOA,GAC/EJ,KAAK2S,kBAAkBT,EAAI1F,QAAQkF,SAAUQ,EAAI1F,QAAQoG,OAAQV,EAAI9L,OACvE,CAOA,IAAA,MAAWhG,KAAMsS,QACT1S,KAAK6S,wBAAwBzS,GAGrCJ,KAAK4Q,wBAA0B,GAC/B5Q,KAAKiR,SAAW,IAAInR,CACtB,CAIAE,KAAK6Q,aAAc,CACrB,OAASiC,GACP,GAAIA,aAAe3R,MACjB,MAAM,IAAIU,EACR,0CAA0CiR,EAAIrR,WAGlD,MAAMqR,CACR,CAAA,QACE9S,KAAK8Q,gBAAiB,CACxB,CACF,MAjFS9Q,KAAK0Q,WAoFhB,CAKQ,iBAAAiC,CACNjB,EACAqB,EACA3M,GAEA,MAAM4M,EAAc,IACftB,EAASC,iBACTvL,GAGLpG,KAAKiT,eAAevB,EAAStR,GAAI4S,EAAatB,EAASC,eAGvD,MAAMuB,EAASH,EAAe/S,KAAMgT,GACpChT,KAAKmT,eAAeD,GAGpB,IAAA,MAAWE,KAAc1B,EAAShD,SAAU,CAC1C,GAAI1O,KAAKuQ,aAAaxP,IAAIqS,GACxB,MAAM,IAAI5R,EACR,cAAc4R,mCAA4CpT,KAAKuQ,aAAa1P,IAAIuS,MAGpFpT,KAAKuQ,aAAajQ,IAAI8S,EAAY1B,EAAStR,GAC7C,CAGAJ,KAAKsC,QAAQhC,IAAIoR,EAAStR,GAAI8S,GAC9BlT,KAAKsQ,UAAUhQ,IAAIoR,EAAStR,GAAIsR,GAChC1R,KAAKyH,OAAOnH,IAAIoR,EAAStR,GAAI,cAC7BJ,KAAKwQ,eAAelQ,IAAIoR,EAAStR,GAAI4S,EACvC,CAKA,6BAAcH,CAAwBzQ,GACpC,MAAM8Q,EAASlT,KAAKsC,QAAQzB,IAAIuB,GAChC,IAAK8Q,EAAQ,OAEb,MAAMxB,EAAW1R,KAAKsQ,UAAUzP,IAAIuB,GAC9BgE,EAASpG,KAAKwQ,eAAe3P,IAAIuB,GAGvC,IAAA,MAAWgR,KAAc1B,EAASW,SAChC,IAAKrS,KAAKuQ,aAAaxP,IAAIqS,GACzB,MAAM,IAAI5R,EACR,gCAAgC4R,gBAAyBhR,KAK/DpC,KAAKyN,OAAO4F,MAAM,iBAAkB,mBAAoB,uBAAuBjR,KAE/E,IACM8Q,EAAO9B,kBACH8B,EAAO9B,WAAWhL,GAE1BpG,KAAKyH,OAAOnH,IAAI8B,EAAU,UAE1BpC,KAAKyN,OAAO6F,KACV,iBACA,oBACA,UAAUlR,6BAEd,OAASuF,GASP,MAPA3H,KAAKyH,OAAOnH,IAAI8B,EAAU,SAC1BpC,KAAKyN,OAAO9F,MACV,iBACA,uBACA,UAAUvF,0BACV,CAAEuF,UAEEA,CACR,CACF,CAEA,eAAA4L,CAAyBnR,GACvB,MAAMgE,EAASpG,KAAKwQ,eAAe3P,IAAIuB,GACvC,IAAKgE,EACH,MAAM,IAAIxE,EAAoB,4BAA4BQ,eAE5D,OAAOgE,CACT,CAEQ,cAAA6M,CAAe7Q,EAAkBgE,EAAiBuL,GAExD,MACM6B,EADe3H,OAAO5K,KAAK0Q,GACAlM,OAAQyE,IAAU9D,EAAkBqN,eAAevJ,IAEpF,GAAIsJ,EAAY7N,OAAS,EACvB,MAAM,IAAI1D,EACR,kDAAkDG,MAAaoR,EAAYE,KAAK,QAStF,CAEA,wBAAMC,CAA4BvR,EAAkBgE,GAClD,MAAM8M,EAASlT,KAAK4T,UAAUxR,GAE9B,IAAK8Q,EACH,MAAM,IAAItR,EAAoB,UAAUQ,eAG1C,MAAMsP,EAAW1R,KAAKsQ,UAAUzP,IAAIuB,GAC9ByR,EAAgB7T,KAAKwQ,eAAe3P,IAAIuB,GAE9C,IAAKsP,IAAamC,EAChB,MAAM,IAAIjS,EAAoB,UAAUQ,eAI1C,MAAM0R,EAAY,IACbD,KACAzN,GAILpG,KAAKiT,eAAe7Q,EAAU0R,EAAWpC,EAASC,eAGlD3R,KAAKwQ,eAAelQ,IAAI8B,EAAU0R,GAG9BZ,EAAO9B,kBACH8B,EAAO9B,WAAW0C,EAE5B,CAKA,mBAAAC,CAAoBC,GAClB,IAAA,MAAW9B,KAAO8B,EAChBhU,KAAKuR,eAAeW,EAAI1F,QAAS0F,EAAI9L,OAEzC,CAKA,sBAAM6N,CAAiB7R,GACrB,MAAM8Q,EAASlT,KAAKsC,QAAQzB,IAAIuB,GAChC,IAAK8Q,EACH,MAAM,IAAItR,EAAoB,UAAUQ,uBAG1C,MAAMsP,EAAW1R,KAAKsQ,UAAUzP,IAAIuB,GACpC,IAAKsP,EACH,MAAM,IAAI9P,EAAoB,uBAAuBQ,eAIvD,IAAA,MAAY8R,EAASC,KAAkBnU,KAAKsQ,UAAU8D,UAAW,CAC/D,GAAIF,IAAY9R,EAAU,SAM1B,GAJsB,IAAI+R,EAAc9B,YAAa8B,EAAc7B,UAAU+B,KAAMzF,GACjF8C,EAAShD,SAAS5I,SAAS8I,IAI3B,MAAM,IAAIpN,EACR,4BAA4BY,aAAoB8R,kBAGtD,CAGA,IACMhB,EAAOnN,eACHmN,EAAOnN,UAIf,IAAA,MAAWqN,KAAc1B,EAAShD,SAChC1O,KAAKuQ,aAAavP,OAAOoS,GAI3BpT,KAAKsC,QAAQtB,OAAOoB,GACpBpC,KAAKsQ,UAAUtP,OAAOoB,GACtBpC,KAAKyH,OAAOzG,OAAOoB,EACrB,OAASuF,GACP,GAAIA,aAAiBxG,MACnB,MAAM,IAAIA,MAAM,+BAA+BiB,MAAauF,EAAMlG,WAEpE,MAAMkG,CACR,CACF,CAOA,SAAAiM,CAA6BxR,GAC3B,MAAM8Q,EAASlT,KAAKsC,QAAQzB,IAAIuB,GAChC,OAAK8Q,GACI,IAGX,CAOA,qBAAAoB,CAAsBlB,GACpB,MAAMhR,EAAWpC,KAAKuQ,aAAa1P,IAAIuS,GACvC,OAAKhR,EAGEpC,KAAK4T,UAAUxR,GAFb,IAGX,CAKA,aAAAmS,CAAcnB,GACZ,OAAOpT,KAAKuQ,aAAaxP,IAAIqS,EAC/B,CAKA,aAAAoB,GACE,OAAOtJ,MAAM4G,KAAK9R,KAAKsC,QAAQiI,SACjC,CAKA,eAAAkK,CAAgBrS,GACd,MAAMqF,EAASzH,KAAKyH,OAAO5G,IAAIuB,GAC/B,IAAKqF,EACH,MAAM,IAAI7F,EAAoB,UAAUQ,eAE1C,OAAOqF,CACT,CAKQ,cAAA0L,CAAeD,GACrB,IAAKA,EAAO9S,GACV,MAAM,IAAIoB,EAAwB,yBAEtC,CAKQ,gBAAAiQ,CAAiBC,GACvB,IAAKA,EAAStR,GACZ,MAAM,IAAIoB,EAAwB,4BAEpC,IAAKkQ,EAAS/P,KACZ,MAAM,IAAIH,EAAwB,6BAEpC,IAAKkQ,EAASgD,QACZ,MAAM,IAAIlT,EAAwB,gCAEpC,IAAK0J,MAAMC,QAAQuG,EAAShD,UAC1B,MAAM,IAAIlN,EAAwB,uCAEpC,IAAK0J,MAAMC,QAAQuG,EAASW,UAC1B,MAAM,IAAI7Q,EAAwB,uCAEpC,IAAK0J,MAAMC,QAAQuG,EAASY,UAC1B,MAAM,IAAI9Q,EAAwB,uCAEtC,CAEA,WAAAmT,GACE,OAAO3U,KAAKgR,SACd,CAKA,aAAMjL,SACJ,GAAI/F,KAAKgR,UAAW,MAAM,IAAIxP,EAAwB,uCACtDxB,KAAKgR,WAAY,EAGjB,UACQhR,KAAK0Q,WACb,CAAA,MAEA,CAGA,IAAA,MAAWwC,KAAUhI,MAAM4G,KAAK9R,KAAKsC,QAAQiI,UAAUqK,gBAC/C,OAAA3O,IAAOF,cAAP,EAAAE,EAAAE,KAAA+M,IAGRlT,KAAKmC,MAAM4D,UAEX/F,KAAKsC,QAAQkI,QACbxK,KAAKsQ,UAAU9F,QACfxK,KAAKuQ,aAAa/F,QAClBxK,KAAKyH,OAAO+C,QACZxK,KAAK2Q,qBAAqBhL,OAAS,EACnC3F,KAAK4Q,wBAAwBjL,OAAS,CACxC,wbHrjBK,SAAekP,EAAeC,EAAaC,GAChD,OAAOF,EAAQC,EAAMA,EAAMD,EAAQE,EAAMA,EAAMF,CACjD,wBN4O6B,CAC3B3N,EACAoB,KAAA,CAEAtF,KAAMS,EACN8D,QAAS,CAAEL,aAAYoB,wDU1LlB,SACL0M,EACAC,EAAoCvK,GAEpC,MAAMjG,MAAgBlE,IAChB2U,MAAehV,IACrB,IAAIiV,EAASH,EAGb,MAEMI,EAAuB,CAACzS,EAAuBwG,KAEnD,IAAIkM,EAAe1S,EACfoD,EAAU,OAEd,GAAIoD,EAAS,CAEX,GAAIsB,EAAetB,GAAU,CAC3B,MAAMmM,EAAM,IAAItL,EAAkBrH,EAAUwG,GAC5CkM,EAAeC,EAAIjM,OACnBtD,EAAU,IAAMuP,EAAIvP,SACtB,KAAO,CACL,MAAMuP,EAAM,IAAIpM,EAAavG,EAAUwG,GACvCkM,EAAeC,EAAIjM,OACnBtD,EAAU,IAAMuP,EAAIvP,SACtB,CACAmP,EAAS5U,IAAIqC,EAAU,CAAE4S,QAASF,EAActP,WAClD,CAOA,YAJe,IAAXoP,GAAsBE,EAAaF,GAEvC1Q,EAAU7D,IAAIyU,GAEP,KACL5Q,EAAUzD,OAAOqU,GACjBtP,IACAmP,EAASlU,OAAO2B,KAKpB,MAAO,CAEL,SAAIkS,GACF,OAAOM,CACT,EAEA,IAAAK,CAAKC,OAAI,QACQ,IAAXN,GAAyBF,EAASE,EAAQM,KAC5CN,EAASM,EA1CA,CAACA,IAAShR,EAAUQ,QAASS,GAAMA,EAAE+P,KA2C9CC,CAAOD,GAEX,EAEAE,GAAIP,EACJ,GAAAQ,CAAIjT,GAEF,MAAMkT,EAAQX,EAASrU,IAAI8B,GACvBkT,GACFpR,EAAUzD,OAAO6U,EAAMN,SACvBM,EAAM9P,UACNmP,EAASlU,OAAO2B,IAEhB8B,EAAUzD,OAAO2B,EAErB,EAEA,KAAA6H,GACE/F,EAAU+F,QACV0K,EAASjQ,QAAS+M,GAAMA,EAAEjM,WAC1BmP,EAAS1K,OACX,EAGAsL,OAAA,CAAUC,EAAuBC,EAA8BtL,IACtD,CAAC/H,EAAuBwG,KAC7B,IAAI8M,EAGJ,QAAe,IAAXd,EAAsB,CACxB,MAAMe,EAASH,EAASZ,GACxBc,EAAOC,EACPvT,EAASuT,EACX,CAGA,OAAOd,EACJe,IACC,MAAMD,EAASH,EAASI,QACX,IAATF,GAAuBD,EAAGC,EAAMC,KAClCD,EAAOC,EACPvT,EAASuT,KAGb/M,IAKV,wBAlIO,WACL,MAAM1E,MAAgBlE,IAOtB,MAAO,CACLiV,KAAM,CAACC,OAAI,IAAmBhR,EAAUQ,QAASS,GAAMA,EAAE+P,IACzDE,GAPwBjQ,IACxBjB,EAAU7D,IAAI8E,GACP,IAAMjB,EAAUzD,OAAO0E,IAM9BkQ,IAAMlQ,GAAMjB,EAAUzD,OAAO0E,GAC7B8E,MAAO,IAAM/F,EAAU+F,QAE3B,8BHRO,SAKL8B,GACA,OAAO,IAAID,EAAqBC,EAClC,mCI3CO,SAMLkF,EACApL,GAEA,MAAO,CACLoG,QAASgF,EACTpL,SAEJ,8BCiEO,SAKLgQ,EACAjN,GAKA,MAAMkN,SAAclN,WAASmN,SAAS,EAChCrB,SAAW9L,WAAS8L,WAAYvK,EAGhC6L,MAAkBrW,IAClBsW,MAAqBtW,IACrBuW,MAAqBvW,IAMrBwW,MAAsBnW,IACtBoW,MAAqBzW,IAKrB0W,EAAgB1M,GAAsBC,OAAOD,GAmDnD,MAAO,CACL,IAAAsL,CAAKtL,EAAWZ,GACd,MAAMuN,EAAgBD,EAAa1M,GAEnC,GAAImM,EAAa,CAEf,MAAMS,EAASP,EAAY1V,IAAIgW,GAC/B,QAAe,IAAXC,GAAwB7B,EAAS6B,EAAQxN,GAC3C,OAEFiN,EAAYjW,IAAIuW,EAAevN,EACjC,CAGA,MAAM7E,EAAY+R,EAAe3V,IAAIgW,GACjCpS,GACFA,EAAUQ,QAASS,GAAMA,EAAE4D,IAI7B,MAAMyN,EAAcX,EAAclM,EAAKZ,GACvCoN,EAAgBzR,QAASS,GAAMA,EAAEqR,GACnC,EAEA,QAAAC,CAAS9M,GACP,MAAM2M,EAAgBD,EAAa1M,GAEnC,MAAO,CAACvH,EAA2BwG,KACjC,MAAM1E,EA7EiB,CAACyF,IAC5B,IAAIzF,EAAY+R,EAAe3V,IAAIqJ,GAKnC,OAJKzF,IACHA,MAAgBlE,IAChBiW,EAAelW,IAAI4J,EAAKzF,IAEnBA,GAuEewS,CAAqBJ,GACjC3B,EArEgB,CAC1BhL,IAEA,IAAIgL,EAAWuB,EAAe5V,IAAIqJ,GAKlC,OAJKgL,IACHA,MAAehV,IACfuW,EAAenW,IAAI4J,EAAKgL,IAEnBA,GA6DcgC,CAAoBL,GAErC,IAAIxB,EAAe1S,EACfoD,EAAU,OAEd,GAAIoD,EAAS,CACX,GAAIsB,EAAetB,GAAU,CAC3B,MAAMmM,EAAM,IAAItL,EAAkBrH,EAAUwG,GAC5CkM,EAAeC,EAAIjM,OACnBtD,EAAU,IAAMuP,EAAIvP,SACtB,KAAO,CACL,MAAMuP,EAAM,IAAIpM,EAAavG,EAAUwG,GACvCkM,EAAeC,EAAIjM,OACnBtD,EAAU,IAAMuP,EAAIvP,SACtB,CACAmP,EAAS5U,IAAIqC,EAAU,CAAE4S,QAASF,EAActP,WAClD,CAGA,GAAIsQ,EAAa,CACf,MAAMS,EAASP,EAAY1V,IAAIgW,QAChB,IAAXC,GACFzB,EAAayB,EAEjB,CAIA,OAFArS,EAAU7D,IAAIyU,GAEP,KACL5Q,EAAUzD,OAAOqU,GACjBtP,IACAmP,EAASlU,OAAO2B,GAEO,IAAnB8B,EAAU0S,MACZX,EAAexV,OAAO6V,GAEF,IAAlB3B,EAASiC,MACXV,EAAezV,OAAO6V,IAI9B,EAEAO,SArGwC,CACxCzU,EACAwG,KAEA,IAAIkM,EAAe1S,EACfoD,EAAU,OAEd,GAAIoD,EAAS,CACX,GAAIsB,EAAetB,GAAU,CAC3B,MAAMmM,EAAM,IAAItL,EAAkBrH,EAAUwG,GAC5CkM,EAAeC,EAAIjM,OACnBtD,EAAU,IAAMuP,EAAIvP,SACtB,KAAO,CACL,MAAMuP,EAAM,IAAIpM,EAAavG,EAAUwG,GACvCkM,EAAeC,EAAIjM,OACnBtD,EAAU,IAAMuP,EAAIvP,SACtB,CACA4Q,EAAerW,IAAIqC,EAAU,CAAE4S,QAASF,EAActP,WACxD,CAIA,OAFA2Q,EAAgB9V,IAAIyU,GAEb,KACLqB,EAAgB1V,OAAOqU,GACvBtP,IACA4Q,EAAe3V,OAAO2B,KA8ExB0U,SAASnN,GACAmM,EAAcE,EAAY1V,IAAI+V,EAAa1M,SAAQ,EAG5DoN,UAAA,IACMjB,EACKnL,MAAM4G,KAAKyE,EAAYtV,QAGzBiK,MAAM4G,KAAK0E,EAAevV,QAGnC,UAAAsW,CAAWrN,GACT,MAAM2M,EAAgBD,EAAa1M,GAE/BmM,GACFE,EAAYvV,OAAO6V,GAGrB,MAAMpS,EAAY+R,EAAe3V,IAAIgW,GACjCpS,IACFA,EAAU+F,QACVgM,EAAexV,OAAO6V,IAGxB,MAAM3B,EAAWuB,EAAe5V,IAAIgW,GAChC3B,IACFA,EAASjQ,QAAS+M,GAAMA,EAAEjM,WAC1BmP,EAAS1K,QACTiM,EAAezV,OAAO6V,GAE1B,EAEA,KAAArM,GACM6L,GACFE,EAAY/L,QAEdgM,EAAevR,QAAS3E,GAAQA,EAAIkK,SACpCgM,EAAehM,QACfiM,EAAexR,QAAS8M,IACtBA,EAAI9M,QAAS+M,GAAMA,EAAEjM,WACrBgM,EAAIvH,UAENiM,EAAejM,QAEfkM,EAAgBlM,QAChBmM,EAAe1R,QAAS+M,GAAMA,EAAEjM,WAChC4Q,EAAenM,OACjB,EAEJ,sBCjRO,SAA2CgN,GAEhD,OAAQ3L,OAAOuI,QAAQoD,GAA0BzF,IAAI,EAAE0F,EAAGhC,MAExD,MAAMiC,EAAWC,OAAOF,GAMxB,MAAO,CAJLE,OAAOC,SAASF,IAA0B,KAAbD,EAAEI,OAC1BH,EACAD,EAEWhC,IAEtB,iCCtBuCvS,GAChCA,EAAMqD,iBACJrD,EAAMmD,UAAUnD,EAAMqD,mBAAqB,KADd,8BA4BLrD,GACxB2I,OAAO5K,KAAKiC,EAAMmD,WAAWV,8BAfPzC,GACtB2I,OAAO5K,KAAKiC,EAAMmD,oCARK,CAACnD,EAAkBgE,IAC1ChE,EAAMmD,UAAUa,IAAe,kCCgEjC,SACL4Q,GAEA,MAAO,sBAAuBA,GAAwC,mBAA1BA,EAAIvL,iBAClD,sDDvDgC,CAACrJ,EAAkBgE,MACxChE,EAAMmD,UAAUa,iDd+QC,CAACA,EAAoBuB,KAAA,CAC/CzF,KAAMY,EACN2D,QAAS,CAAEL,aAAYuB,qCA1CM,CAACvB,EAAoBU,KAAA,CAClD5E,KAAMa,EACN0D,QAAS,CAAEL,aAAYU,mCAGG,CAACV,EAAoB6B,KAAA,CAC/C/F,KAAMc,EACNyD,QAAS,CAAEL,aAAY6B,0CA4BQgP,IAAA,CAC/B/U,KAAMW,EACN4D,QAASwQ,iCA1DyB,CAClC7Q,EACAG,KAAA,CAEArE,KAAMQ,EACN+D,QAAS,CAAEL,aAAYG,gDAWSH,IAAA,CAChClE,KAAMU,EACN6D,QAASL,+BAiCwBE,IAAA,CACjCpE,KAAMmB,EACNoD,QAASH,4BAPqBD,IAAA,CAC9BnE,KAAMkB,EACNqD,QAASJ,6BA1DqB,CAC9BD,EACAS,EACAQ,EACAC,KAAA,CAEApF,KAAMO,EACNgE,QAAS,CAAEL,aAAYS,QAAOQ,YAAWC,4CAZV,CAAClB,EAAoBU,KAAA,CACpD5E,KAAMM,EACNiE,QAAS,CAAEL,aAAYU,+BA4CD,CAACV,EAAoB8Q,KAAA,CAC3ChV,KAAMe,EACNwD,QAAS,CAAEL,aAAY8Q,+BAQE,CAAC5Q,EAAoBF,KAAA,CAC9ClE,KAAMiB,EACNsD,QAAS,CAAEH,WAAUF,iCAPC,CAACC,EAAeD,KAAA,CACtClE,KAAMgB,EACNuD,QAAS,CAAEJ,QAAOD,6CAzEgB,CAClCA,EACAvF,EACAwF,EACAC,EACAC,EACAC,KAAA,CAEAtE,KAAMI,EACNmE,QAAS,CAAEL,aAAYvF,OAAMwF,QAAOC,WAAUC,mBAAkBC,wDAGrB,CAC3CJ,EACAe,KAAA,CAEAjF,KAAMK,EACNkE,QAAS,CAAEL,aAAYe"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/lib/utils/dependency-resolver.ts","../src/lib/types/errors.ts","../src/lib/store/plugin-store.ts","../src/lib/store/actions.ts","../src/lib/store/store.ts","../src/lib/store/initial-state.ts","../src/lib/store/reducer-helpers.ts","../src/lib/store/reducer.ts","../src/lib/utils/event-control.ts","../src/lib/utils/math.ts","../src/lib/plugin/builder.ts","../src/lib/base/base-plugin.ts","../src/lib/registry/plugin-registry.ts","../src/lib/utils/eventing.ts","../src/lib/utils/plugin-helpers.ts","../src/lib/utils/scoped-eventing.ts","../src/lib/utils/typed-object.ts","../src/lib/store/selectors.ts","../src/lib/types/plugin.ts"],"sourcesContent":["export class DependencyResolver {\n private dependencyGraph = new Map<string, Set<string>>();\n\n addNode(id: string, dependencies: string[] = []) {\n this.dependencyGraph.set(id, new Set(dependencies));\n }\n\n private hasCircularDependencies(): boolean {\n const visited = new Set<string>();\n const recursionStack = new Set<string>();\n\n const dfs = (id: string): boolean => {\n visited.add(id);\n recursionStack.add(id);\n\n const dependencies = this.dependencyGraph.get(id) || new Set();\n for (const dep of dependencies) {\n if (!visited.has(dep)) {\n if (dfs(dep)) return true;\n } else if (recursionStack.has(dep)) {\n return true; // Circular dependency found\n }\n }\n\n recursionStack.delete(id);\n return false;\n };\n\n for (const id of this.dependencyGraph.keys()) {\n if (!visited.has(id)) {\n if (dfs(id)) return true;\n }\n }\n\n return false;\n }\n\n resolveLoadOrder(): string[] {\n if (this.hasCircularDependencies()) {\n throw new Error('Circular dependencies detected');\n }\n\n const result: string[] = [];\n const visited = new Set<string>();\n const temp = new Set<string>();\n\n const visit = (id: string) => {\n if (temp.has(id)) throw new Error('Circular dependency');\n if (visited.has(id)) return;\n\n temp.add(id);\n\n const dependencies = this.dependencyGraph.get(id) || new Set();\n for (const dep of dependencies) {\n visit(dep);\n }\n\n temp.delete(id);\n visited.add(id);\n result.push(id);\n };\n\n for (const id of this.dependencyGraph.keys()) {\n if (!visited.has(id)) {\n visit(id);\n }\n }\n\n return result;\n }\n}\n","export class PluginRegistrationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PluginRegistrationError';\n }\n}\n\nexport class PluginNotFoundError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PluginNotFoundError';\n }\n}\n\nexport class CircularDependencyError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'CircularDependencyError';\n }\n}\n\nexport class CapabilityNotFoundError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'CapabilityNotFoundError';\n }\n}\n\n// You might also want to add:\nexport class CapabilityConflictError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'CapabilityConflictError';\n }\n}\n\nexport class PluginInitializationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PluginInitializationError';\n }\n}\n\nexport class PluginConfigurationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'PluginConfigurationError';\n }\n}\n","import { Store } from './store';\nimport { Action } from './types';\n\n/**\n * A type-safe store handle for plugins, providing access to plugin-specific state and actions.\n */\nexport class PluginStore<PluginState, PluginAction extends Action> {\n private store: Store<any, any>;\n private pluginId: string;\n\n /**\n * Initializes the PluginStore with the main store and plugin ID.\n * @param store The main store instance.\n * @param pluginId The unique identifier for the plugin.\n */\n constructor(store: Store<any, any>, pluginId: string) {\n this.store = store;\n this.pluginId = pluginId;\n }\n\n /**\n * Gets the current state of the plugin.\n * @returns The plugin's state.\n */\n getState(): PluginState {\n return this.store.getState().plugins[this.pluginId] as PluginState;\n }\n\n /**\n * Dispatches an action for the plugin and returns the *new* global state.\n * If you only need the plugin’s updated state, call `getState()` afterward.\n * @param action The action to dispatch.\n * @returns The updated global store state (after plugin reducer).\n */\n dispatch(action: PluginAction): PluginState {\n return this.store.dispatchToPlugin(this.pluginId, action);\n }\n\n /**\n * Subscribes to state changes only for this specific plugin.\n * You now receive (action, newPluginState, oldPluginState) in the callback.\n *\n * @param listener The callback to invoke when plugin state changes.\n * @returns A function to unsubscribe the listener.\n */\n subscribeToState(\n listener: (action: PluginAction, newState: PluginState, oldState: PluginState) => void,\n ) {\n return this.store.subscribeToPlugin(this.pluginId, (action, newPluginState, oldPluginState) => {\n listener(\n action as PluginAction,\n newPluginState as PluginState,\n oldPluginState as PluginState,\n );\n });\n }\n\n /**\n * Subscribes to a specific action type for the plugin.\n * This still uses the main store's `onAction`, so you get the *global*\n * old/new store states there. If you specifically want old/new plugin state,\n * use `subscribeToState` instead.\n *\n * @param type The action type to listen for.\n * @param handler The callback to invoke when the action occurs.\n * @returns A function to unsubscribe the handler.\n */\n onAction<T extends PluginAction['type']>(\n type: T,\n handler: (\n action: Extract<PluginAction, { type: T }>,\n state: PluginState,\n oldState: PluginState,\n ) => void,\n ) {\n return this.store.onAction(type, (action, state, oldState) => {\n handler(\n action as Extract<PluginAction, { type: T }>,\n state.plugins[this.pluginId] as PluginState,\n oldState.plugins[this.pluginId] as PluginState,\n );\n });\n }\n}\n","import { PdfDocumentObject, PdfErrorCode, PdfPageObject, Rotation } from '@embedpdf/models';\n\n// Document lifecycle actions\nexport const START_LOADING_DOCUMENT = 'START_LOADING_DOCUMENT';\nexport const UPDATE_DOCUMENT_LOADING_PROGRESS = 'UPDATE_DOCUMENT_LOADING_PROGRESS';\nexport const SET_DOCUMENT_LOADED = 'SET_DOCUMENT_LOADED';\nexport const SET_DOCUMENT_ERROR = 'SET_DOCUMENT_ERROR';\nexport const RETRY_LOADING_DOCUMENT = 'RETRY_LOADING_DOCUMENT';\nexport const CLOSE_DOCUMENT = 'CLOSE_DOCUMENT';\nexport const SET_ACTIVE_DOCUMENT = 'SET_ACTIVE_DOCUMENT';\n\n// Reorder document actions\nexport const REORDER_DOCUMENTS = 'REORDER_DOCUMENTS';\nexport const MOVE_DOCUMENT = 'MOVE_DOCUMENT';\n\n// Document-specific actions\nexport const REFRESH_DOCUMENT = 'REFRESH_DOCUMENT';\nexport const REFRESH_PAGES = 'REFRESH_PAGES';\nexport const SET_PAGES = 'SET_PAGES';\nexport const SET_SCALE = 'SET_SCALE';\nexport const SET_ROTATION = 'SET_ROTATION';\n\n// Global default actions\nexport const SET_DEFAULT_SCALE = 'SET_DEFAULT_SCALE';\nexport const SET_DEFAULT_ROTATION = 'SET_DEFAULT_ROTATION';\n\nexport const CORE_ACTION_TYPES = [\n START_LOADING_DOCUMENT,\n UPDATE_DOCUMENT_LOADING_PROGRESS,\n SET_DOCUMENT_LOADED,\n CLOSE_DOCUMENT,\n SET_ACTIVE_DOCUMENT,\n SET_DOCUMENT_ERROR,\n RETRY_LOADING_DOCUMENT,\n REFRESH_DOCUMENT,\n REFRESH_PAGES,\n SET_PAGES,\n SET_SCALE,\n SET_ROTATION,\n SET_DEFAULT_SCALE,\n SET_DEFAULT_ROTATION,\n REORDER_DOCUMENTS,\n MOVE_DOCUMENT,\n] as const;\n\n// ─────────────────────────────────────────────────────────\n// Document Lifecycle Actions\n// ─────────────────────────────────────────────────────────\n\nexport interface StartLoadingDocumentAction {\n type: typeof START_LOADING_DOCUMENT;\n payload: {\n documentId: string;\n name?: string;\n scale?: number;\n rotation?: Rotation;\n passwordProvided?: boolean;\n autoActivate?: boolean; // If true, this document becomes active when opened. Default: true\n };\n}\n\nexport interface UpdateDocumentLoadingProgressAction {\n type: typeof UPDATE_DOCUMENT_LOADING_PROGRESS;\n payload: {\n documentId: string;\n progress: number;\n };\n}\n\nexport interface SetDocumentLoadedAction {\n type: typeof SET_DOCUMENT_LOADED;\n payload: {\n documentId: string;\n document: PdfDocumentObject;\n };\n}\n\nexport interface SetDocumentErrorAction {\n type: typeof SET_DOCUMENT_ERROR;\n payload: {\n documentId: string;\n error: string;\n errorCode?: PdfErrorCode;\n errorDetails?: any;\n };\n}\n\nexport interface RetryLoadingDocumentAction {\n type: typeof RETRY_LOADING_DOCUMENT;\n payload: {\n documentId: string;\n passwordProvided?: boolean;\n };\n}\n\nexport interface CloseDocumentAction {\n type: typeof CLOSE_DOCUMENT;\n payload: {\n documentId: string;\n nextActiveDocumentId?: string | null; // Optional: what to activate next\n };\n}\n\nexport interface SetActiveDocumentAction {\n type: typeof SET_ACTIVE_DOCUMENT;\n payload: string | null; // documentId or null\n}\n\nexport interface ReorderDocumentsAction {\n type: typeof REORDER_DOCUMENTS;\n payload: string[]; // New order\n}\n\nexport interface MoveDocumentAction {\n type: typeof MOVE_DOCUMENT;\n payload: {\n documentId: string;\n toIndex: number;\n };\n}\n\n// ─────────────────────────────────────────────────────────\n// Document-Specific Actions\n// ─────────────────────────────────────────────────────────\n\nexport interface RefreshDocumentAction {\n type: typeof REFRESH_DOCUMENT;\n payload: {\n documentId: string;\n document: PdfDocumentObject;\n };\n}\n\nexport interface RefreshPagesAction {\n type: typeof REFRESH_PAGES;\n payload: {\n documentId: string;\n pageIndexes: number[];\n };\n}\n\nexport interface SetPagesAction {\n type: typeof SET_PAGES;\n payload: {\n documentId: string;\n pages: PdfPageObject[][];\n };\n}\n\nexport interface SetScaleAction {\n type: typeof SET_SCALE;\n payload: {\n documentId?: string; // If not provided, applies to active document\n scale: number;\n };\n}\n\nexport interface SetRotationAction {\n type: typeof SET_ROTATION;\n payload: {\n documentId?: string; // If not provided, applies to active document\n rotation: Rotation;\n };\n}\n\n// ─────────────────────────────────────────────────────────\n// Global Default Actions\n// ─────────────────────────────────────────────────────────\n\nexport interface SetDefaultScaleAction {\n type: typeof SET_DEFAULT_SCALE;\n payload: number;\n}\n\nexport interface SetDefaultRotationAction {\n type: typeof SET_DEFAULT_ROTATION;\n payload: Rotation;\n}\n\nexport type DocumentAction =\n | StartLoadingDocumentAction\n | UpdateDocumentLoadingProgressAction\n | SetDocumentLoadedAction\n | SetDocumentErrorAction\n | RetryLoadingDocumentAction\n | CloseDocumentAction\n | SetActiveDocumentAction\n | RefreshDocumentAction\n | RefreshPagesAction\n | SetPagesAction\n | SetScaleAction\n | SetRotationAction\n | SetDefaultScaleAction\n | SetDefaultRotationAction\n | ReorderDocumentsAction\n | MoveDocumentAction;\n\n// Core actions\nexport type CoreAction = DocumentAction;\n\n// ─────────────────────────────────────────────────────────\n// Action Creators\n// ─────────────────────────────────────────────────────────\nexport const startLoadingDocument = (\n documentId: string,\n name?: string,\n scale?: number,\n rotation?: Rotation,\n passwordProvided?: boolean,\n autoActivate?: boolean,\n): CoreAction => ({\n type: START_LOADING_DOCUMENT,\n payload: { documentId, name, scale, rotation, passwordProvided, autoActivate },\n});\n\nexport const updateDocumentLoadingProgress = (\n documentId: string,\n progress: number,\n): CoreAction => ({\n type: UPDATE_DOCUMENT_LOADING_PROGRESS,\n payload: { documentId, progress },\n});\n\nexport const setDocumentLoaded = (documentId: string, document: PdfDocumentObject): CoreAction => ({\n type: SET_DOCUMENT_LOADED,\n payload: { documentId, document },\n});\n\nexport const setDocumentError = (\n documentId: string,\n error: string,\n errorCode?: PdfErrorCode,\n errorDetails?: any,\n): CoreAction => ({\n type: SET_DOCUMENT_ERROR,\n payload: { documentId, error, errorCode, errorDetails },\n});\n\nexport const retryLoadingDocument = (\n documentId: string,\n passwordProvided?: boolean,\n): CoreAction => ({\n type: RETRY_LOADING_DOCUMENT,\n payload: { documentId, passwordProvided },\n});\n\nexport const closeDocument = (\n documentId: string,\n nextActiveDocumentId?: string | null,\n): CoreAction => ({\n type: CLOSE_DOCUMENT,\n payload: { documentId, nextActiveDocumentId },\n});\n\nexport const setActiveDocument = (documentId: string | null): CoreAction => ({\n type: SET_ACTIVE_DOCUMENT,\n payload: documentId,\n});\n\nexport const refreshDocument = (documentId: string, document: PdfDocumentObject): CoreAction => ({\n type: REFRESH_DOCUMENT,\n payload: { documentId, document },\n});\n\nexport const refreshPages = (documentId: string, pageIndexes: number[]): CoreAction => ({\n type: REFRESH_PAGES,\n payload: { documentId, pageIndexes },\n});\n\nexport const setPages = (documentId: string, pages: PdfPageObject[][]): CoreAction => ({\n type: SET_PAGES,\n payload: { documentId, pages },\n});\n\nexport const setScale = (scale: number, documentId?: string): CoreAction => ({\n type: SET_SCALE,\n payload: { scale, documentId },\n});\n\nexport const setRotation = (rotation: Rotation, documentId?: string): CoreAction => ({\n type: SET_ROTATION,\n payload: { rotation, documentId },\n});\n\nexport const setDefaultScale = (scale: number): CoreAction => ({\n type: SET_DEFAULT_SCALE,\n payload: scale,\n});\n\nexport const setDefaultRotation = (rotation: Rotation): CoreAction => ({\n type: SET_DEFAULT_ROTATION,\n payload: rotation,\n});\n\nexport const reorderDocuments = (order: string[]): CoreAction => ({\n type: REORDER_DOCUMENTS,\n payload: order,\n});\n\nexport const moveDocument = (documentId: string, toIndex: number): CoreAction => ({\n type: MOVE_DOCUMENT,\n payload: { documentId, toIndex },\n});\n","import { Reducer, Action, StoreState, StoreListener, PluginListener } from './types';\nimport { PluginStore } from './plugin-store';\nimport { CORE_ACTION_TYPES } from './actions';\n\n/**\n * A generic, type-safe store class managing core and plugin states, reducers, and subscriptions.\n * @template CoreState The type of the core state.\n * @template CoreAction The type of actions handled by core reducers (extends Action).\n */\nexport class Store<CoreState, CoreAction extends Action = Action> {\n private state: StoreState<CoreState>;\n private coreReducer: Reducer<CoreState, CoreAction>;\n private pluginReducers: Record<string, Reducer<any, Action>> = {};\n\n private listeners: StoreListener<CoreState>[] = [];\n private pluginListeners: Record<string, PluginListener[]> = {};\n\n // Prevents re-entrant dispatch during reducer execution (like Redux)\n private isDispatching = false;\n\n /**\n * Initializes the store with the provided core state.\n * @param reducer The core reducer function\n * @param initialCoreState The initial core state\n */\n constructor(\n reducer: Reducer<CoreState, CoreAction>,\n public initialCoreState: CoreState,\n ) {\n this.state = { core: initialCoreState, plugins: {} };\n this.coreReducer = reducer;\n }\n\n /**\n * Adds a reducer for a plugin-specific state.\n * @param pluginId The unique identifier for the plugin.\n * @param reducer The reducer function for the plugin state.\n * @param initialState The initial state for the plugin.\n */\n addPluginReducer<PluginState>(\n pluginId: string,\n reducer: Reducer<PluginState, Action>,\n initialState: PluginState,\n ) {\n this.state.plugins[pluginId] = initialState;\n this.pluginReducers[pluginId] = reducer;\n }\n\n /**\n * Dispatches an action *only* to the core reducer.\n * Notifies the global store listeners with (action, newState, oldState).\n *\n * @param action The action to dispatch, typed as CoreAction\n * @returns The updated *global* store state\n */\n dispatchToCore(action: CoreAction): StoreState<CoreState> {\n if (!this.coreReducer) {\n return this.getState();\n }\n\n if (this.isDispatching) {\n throw new Error(\n 'Reducers may not dispatch actions. ' +\n 'To trigger cascading actions, dispatch from a listener callback instead.',\n );\n }\n\n const oldState = this.getState();\n\n try {\n this.isDispatching = true;\n // Update core state via its reducer\n this.state.core = this.coreReducer(this.state.core, action);\n } finally {\n // Always reset flag, even if reducer throws\n this.isDispatching = false;\n }\n\n // Notify all main-store subscribers (can now safely dispatch)\n // Get fresh state for each listener to handle nested dispatches correctly\n this.listeners.forEach((listener) => {\n const currentState = this.getState(); // Fresh snapshot for each listener\n listener(action, currentState, oldState);\n });\n\n return this.getState();\n }\n\n /**\n * Dispatches an action *only* to a specific plugin.\n * Optionally notifies global store listeners if `notifyGlobal` is true.\n * Always notifies plugin-specific listeners with (action, newPluginState, oldPluginState).\n *\n * @param pluginId The plugin identifier\n * @param action The plugin action to dispatch\n * @param notifyGlobal Whether to also notify global store listeners\n * @returns The updated plugin state\n */\n dispatchToPlugin<PluginAction extends Action>(\n pluginId: string,\n action: PluginAction,\n notifyGlobal: boolean = true,\n ): any {\n if (this.isDispatching) {\n throw new Error(\n 'Reducers may not dispatch actions. ' +\n 'To trigger cascading actions, dispatch from a listener callback instead.',\n );\n }\n\n const oldGlobalState = this.getState();\n\n const reducer = this.pluginReducers[pluginId];\n if (!reducer) {\n // No plugin found, just return the old state\n return oldGlobalState.plugins[pluginId];\n }\n\n // Grab the old plugin state\n const oldPluginState = oldGlobalState.plugins[pluginId];\n\n try {\n this.isDispatching = true;\n // Reduce to new plugin state\n const newPluginState = reducer(oldPluginState, action);\n // Update the store's plugin slice\n this.state.plugins[pluginId] = newPluginState;\n } finally {\n this.isDispatching = false;\n }\n\n // Notify listeners (can now safely dispatch)\n // Get fresh state for each listener to handle nested dispatches correctly\n if (notifyGlobal) {\n this.listeners.forEach((listener) => {\n const currentGlobalState = this.getState(); // Fresh snapshot for each listener\n listener(action, currentGlobalState, oldGlobalState);\n });\n }\n\n // Notify plugin-specific listeners\n // Get fresh plugin state for each listener\n if (this.pluginListeners[pluginId]) {\n this.pluginListeners[pluginId].forEach((listener) => {\n const currentPluginState = this.getState().plugins[pluginId]; // Fresh snapshot for each listener\n listener(action, currentPluginState, oldPluginState);\n });\n }\n\n return this.getState().plugins[pluginId];\n }\n\n /**\n * Dispatches an action to update the state using:\n * - the core reducer (if it's a CoreAction)\n * - *all* plugin reducers (regardless of action type), with no global notify for each plugin\n *\n * Returns the new *global* store state after all reducers have processed the action.\n *\n * @param action The action to dispatch (can be CoreAction or any Action).\n */\n dispatch(action: CoreAction | Action): StoreState<CoreState> {\n if (this.isDispatching) {\n throw new Error(\n 'Reducers may not dispatch actions. ' +\n 'To trigger cascading actions, dispatch from a listener callback instead.',\n );\n }\n\n const oldState = this.getState();\n\n try {\n this.isDispatching = true;\n\n // 1) Apply core reducer (only if action is a CoreAction)\n if (this.isCoreAction(action)) {\n this.state.core = this.coreReducer(this.state.core, action);\n }\n\n // 2) Apply plugin reducers (without globally notifying after each plugin)\n for (const pluginId in this.pluginReducers) {\n const reducer = this.pluginReducers[pluginId];\n const oldPluginState = oldState.plugins[pluginId];\n if (reducer) {\n this.state.plugins[pluginId] = reducer(oldPluginState, action);\n }\n }\n } finally {\n this.isDispatching = false;\n }\n\n // 3) Notify global listeners *once* with the final new state (can now safely dispatch)\n // Get fresh state for each listener to handle nested dispatches correctly\n this.listeners.forEach((listener) => {\n const currentState = this.getState(); // Fresh snapshot for each listener\n listener(action, currentState, oldState);\n });\n\n // 4) Return the new global store state\n return this.getState();\n }\n\n /**\n * Returns a shallow copy of the current state.\n * @returns The current store state.\n */\n getState(): StoreState<CoreState> {\n if (this.isDispatching) {\n throw new Error(\n 'You may not call store.getState() while the reducer is executing. ' +\n 'The reducer has already received the state as an argument. ' +\n 'Pass it down from the top reducer instead of reading it from the store.',\n );\n }\n\n return {\n core: { ...this.state.core },\n plugins: { ...this.state.plugins },\n };\n }\n\n /**\n * Subscribes a listener to *global* state changes.\n * The callback signature is now (action, newState, oldState).\n *\n * @param listener The callback to invoke on state changes\n * @returns A function to unsubscribe the listener\n */\n subscribe(listener: StoreListener<CoreState>) {\n if (this.isDispatching) {\n throw new Error(\n 'You may not call store.subscribe() while the reducer is executing. ' +\n 'If you would like to be notified after the store has been updated, subscribe from a ' +\n 'component and invoke store.getState() in the callback to access the latest state.',\n );\n }\n\n this.listeners.push(listener);\n return () => {\n if (this.isDispatching) {\n throw new Error(\n 'You may not unsubscribe from a store listener while the reducer is executing.',\n );\n }\n this.listeners = this.listeners.filter((l) => l !== listener);\n };\n }\n\n /**\n * Subscribes a listener to *plugin-specific* state changes.\n * The callback signature is now (action, newPluginState, oldPluginState).\n *\n * @param pluginId The unique identifier for the plugin.\n * @param listener The callback to invoke on plugin state changes.\n * @returns A function to unsubscribe the listener.\n */\n subscribeToPlugin(pluginId: string, listener: PluginListener) {\n if (!(pluginId in this.state.plugins)) {\n throw new Error(\n `Plugin state not found for plugin \"${pluginId}\". Did you forget to call addPluginReducer?`,\n );\n }\n\n if (this.isDispatching) {\n throw new Error('You may not call store.subscribeToPlugin() while the reducer is executing.');\n }\n\n if (!this.pluginListeners[pluginId]) {\n this.pluginListeners[pluginId] = [];\n }\n this.pluginListeners[pluginId].push(listener);\n\n return () => {\n if (this.isDispatching) {\n throw new Error(\n 'You may not unsubscribe from a store listener while the reducer is executing.',\n );\n }\n this.pluginListeners[pluginId] = this.pluginListeners[pluginId].filter((l) => l !== listener);\n if (this.pluginListeners[pluginId].length === 0) {\n delete this.pluginListeners[pluginId];\n }\n };\n }\n\n /**\n * Subscribes to a specific action type (only from the core's action union).\n * The callback signature is (action, newState, oldState).\n *\n * @param type The action type to listen for.\n * @param handler The callback to invoke when the action occurs.\n * @returns A function to unsubscribe the handler.\n */\n onAction<T extends CoreAction['type']>(\n type: T,\n handler: (\n action: Extract<CoreAction, { type: T }>,\n state: StoreState<CoreState>,\n oldState: StoreState<CoreState>,\n ) => void,\n ) {\n return this.subscribe((action, newState, oldState) => {\n if (action.type === type) {\n handler(action as Extract<CoreAction, { type: T }>, newState, oldState);\n }\n });\n }\n\n /**\n * Gets a PluginStore handle for a specific plugin.\n * @param pluginId The unique identifier for the plugin.\n * @returns A PluginStore instance for the plugin.\n */\n getPluginStore<PluginState, PluginAction extends Action>(\n pluginId: string,\n ): PluginStore<PluginState, PluginAction> {\n if (!(pluginId in this.state.plugins)) {\n throw new Error(\n `Plugin state not found for plugin \"${pluginId}\". Did you forget to call addPluginReducer?`,\n );\n }\n return new PluginStore<PluginState, PluginAction>(this, pluginId);\n }\n\n /**\n * Helper method to check if an action is a CoreAction.\n * Adjust if you have a more refined way to differentiate CoreAction vs. any other Action.\n */\n public isCoreAction(action: Action): action is CoreAction {\n return CORE_ACTION_TYPES.includes(action.type as (typeof CORE_ACTION_TYPES)[number]);\n }\n\n /**\n * Destroy the store: drop every listener and plugin reducer\n */\n public destroy(): void {\n // 1. empty listener collections\n this.listeners.length = 0;\n for (const id in this.pluginListeners) {\n this.pluginListeners[id]?.splice?.(0);\n }\n this.pluginListeners = {};\n\n // 2. wipe plugin reducers and states\n this.pluginReducers = {};\n this.state.plugins = {};\n\n // 3. reset core state to initial\n this.state.core = { ...this.initialCoreState };\n }\n}\n","import { PdfDocumentObject, PdfErrorCode, Rotation } from '@embedpdf/models';\nimport { PluginRegistryConfig } from '../types/plugin';\n\nexport type DocumentStatus = 'loading' | 'loaded' | 'error';\n\nexport interface DocumentState {\n id: string;\n name?: string;\n // Lifecycle status\n status: DocumentStatus;\n\n // Loading progress (0-100)\n loadingProgress?: number;\n\n // Error information (when status is 'error')\n error: string | null;\n errorCode?: PdfErrorCode;\n errorDetails?: any;\n\n // Track if this load attempt included a password\n passwordProvided?: boolean;\n\n // Document data (null when loading or error)\n document: PdfDocumentObject | null;\n\n // View settings (set even during loading for when it succeeds)\n scale: number;\n rotation: Rotation;\n\n // Maps page index (0-based) to refresh version number\n // When a page is refreshed, its version is incremented\n pageRefreshVersions: Record<number, number>;\n\n // Metadata\n loadStartedAt: number;\n loadedAt?: number;\n}\n\nexport interface CoreState {\n documents: Record<string, DocumentState>;\n documentOrder: string[];\n activeDocumentId: string | null;\n defaultScale: number;\n defaultRotation: Rotation;\n}\n\nexport const initialCoreState: (config?: PluginRegistryConfig) => CoreState = (config) => ({\n documents: {},\n documentOrder: [],\n activeDocumentId: null,\n defaultScale: config?.defaultScale ?? 1,\n defaultRotation: config?.defaultRotation ?? Rotation.Degree0,\n});\n","import { CoreState } from './initial-state';\n\n/**\n * Calculate the next active document when closing a document.\n * Returns the document to activate, or null if no documents remain.\n */\nexport function calculateNextActiveDocument(\n state: CoreState,\n closingDocumentId: string,\n explicitNext?: string | null,\n): string | null {\n const currentActiveId = state.activeDocumentId;\n\n // Only calculate if we're closing the active document\n if (currentActiveId !== closingDocumentId) {\n return currentActiveId;\n }\n\n // If explicit next was provided, validate and use it\n if (explicitNext !== undefined) {\n // Validate that the document exists\n return explicitNext && state.documents[explicitNext] ? explicitNext : null;\n }\n\n // Auto-calculate: Try left, then right, then null\n const closingIndex = state.documentOrder.indexOf(closingDocumentId);\n\n if (closingIndex === -1) {\n // Document not in order (shouldn't happen)\n return null;\n }\n\n // Try left first\n if (closingIndex > 0) {\n return state.documentOrder[closingIndex - 1];\n }\n\n // Try right\n if (closingIndex < state.documentOrder.length - 1) {\n return state.documentOrder[closingIndex + 1];\n }\n\n // No other documents\n return null;\n}\n\n/**\n * Reorder a document within the documentOrder array.\n * Returns the new order, or null if the operation is invalid.\n */\nexport function moveDocumentInOrder(\n currentOrder: string[],\n documentId: string,\n toIndex: number,\n): string[] | null {\n const fromIndex = currentOrder.indexOf(documentId);\n\n // Validation\n if (fromIndex === -1) return null;\n if (toIndex < 0 || toIndex >= currentOrder.length) return null;\n if (fromIndex === toIndex) return null;\n\n // Calculate new order\n const newOrder = [...currentOrder];\n newOrder.splice(fromIndex, 1);\n newOrder.splice(toIndex, 0, documentId);\n\n return newOrder;\n}\n","import { Reducer } from './types';\nimport { CoreState, DocumentState } from './initial-state';\nimport {\n CoreAction,\n START_LOADING_DOCUMENT,\n UPDATE_DOCUMENT_LOADING_PROGRESS,\n SET_DOCUMENT_LOADED,\n SET_DOCUMENT_ERROR,\n RETRY_LOADING_DOCUMENT,\n CLOSE_DOCUMENT,\n SET_ACTIVE_DOCUMENT,\n SET_ROTATION,\n SET_SCALE,\n REFRESH_PAGES,\n REORDER_DOCUMENTS,\n MOVE_DOCUMENT,\n} from './actions';\nimport { calculateNextActiveDocument, moveDocumentInOrder } from './reducer-helpers';\n\nexport const coreReducer: Reducer<CoreState, CoreAction> = (state, action): CoreState => {\n switch (action.type) {\n case START_LOADING_DOCUMENT: {\n const {\n documentId,\n name,\n scale,\n rotation,\n passwordProvided,\n autoActivate = true,\n } = action.payload;\n\n const newDocState: DocumentState = {\n id: documentId,\n name,\n status: 'loading',\n loadingProgress: 0,\n error: null,\n document: null,\n scale: scale ?? state.defaultScale,\n rotation: rotation ?? state.defaultRotation,\n passwordProvided: passwordProvided ?? false,\n pageRefreshVersions: {},\n loadStartedAt: Date.now(),\n };\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: newDocState,\n },\n documentOrder: [...state.documentOrder, documentId],\n // Only activate if autoActivate is true (default), or if no document is currently active\n activeDocumentId:\n autoActivate || !state.activeDocumentId ? documentId : state.activeDocumentId,\n };\n }\n\n case UPDATE_DOCUMENT_LOADING_PROGRESS: {\n const { documentId, progress } = action.payload;\n const docState = state.documents[documentId];\n\n if (!docState || docState.status !== 'loading') return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...docState,\n loadingProgress: progress,\n },\n },\n };\n }\n\n case SET_DOCUMENT_LOADED: {\n const { documentId, document } = action.payload;\n const docState = state.documents[documentId];\n\n if (!docState) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...docState,\n status: 'loaded',\n document,\n error: null,\n errorCode: undefined,\n errorDetails: undefined,\n passwordProvided: undefined,\n loadedAt: Date.now(),\n },\n },\n };\n }\n\n case SET_DOCUMENT_ERROR: {\n const { documentId, error, errorCode, errorDetails } = action.payload;\n const docState = state.documents[documentId];\n\n if (!docState) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...docState,\n status: 'error',\n error,\n errorCode,\n errorDetails,\n },\n },\n };\n }\n\n case RETRY_LOADING_DOCUMENT: {\n const { documentId, passwordProvided } = action.payload;\n const docState = state.documents[documentId];\n\n if (!docState || docState.status !== 'error') return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...docState,\n status: 'loading',\n loadingProgress: 0,\n error: null,\n errorCode: undefined,\n errorDetails: undefined,\n passwordProvided: passwordProvided ?? false,\n loadStartedAt: Date.now(),\n },\n },\n };\n }\n\n case CLOSE_DOCUMENT: {\n const { documentId, nextActiveDocumentId } = action.payload;\n const { [documentId]: removed, ...remainingDocs } = state.documents;\n\n return {\n ...state,\n documents: remainingDocs,\n documentOrder: state.documentOrder.filter((id) => id !== documentId),\n activeDocumentId: calculateNextActiveDocument(state, documentId, nextActiveDocumentId),\n };\n }\n\n case MOVE_DOCUMENT: {\n const { documentId, toIndex } = action.payload;\n const newOrder = moveDocumentInOrder(state.documentOrder, documentId, toIndex);\n\n // If invalid, return unchanged state\n if (!newOrder) return state;\n\n return {\n ...state,\n documentOrder: newOrder,\n };\n }\n\n case REORDER_DOCUMENTS: {\n return {\n ...state,\n documentOrder: action.payload,\n };\n }\n\n case SET_ACTIVE_DOCUMENT: {\n return {\n ...state,\n activeDocumentId: action.payload,\n };\n }\n\n case SET_SCALE: {\n const { scale, documentId } = action.payload;\n const targetId = documentId ?? state.activeDocumentId;\n\n if (!targetId) return state;\n\n const docState = state.documents[targetId];\n if (!docState) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [targetId]: {\n ...docState,\n scale,\n },\n },\n };\n }\n\n case SET_ROTATION: {\n const { rotation, documentId } = action.payload;\n const targetId = documentId ?? state.activeDocumentId;\n\n if (!targetId) return state;\n\n const docState = state.documents[targetId];\n if (!docState) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [targetId]: {\n ...docState,\n rotation,\n },\n },\n };\n }\n\n case REFRESH_PAGES: {\n const { documentId, pageIndexes } = action.payload;\n const docState = state.documents[documentId];\n\n if (!docState) return state;\n\n // Convert 1-based page numbers to 0-based indices and increment versions\n const newVersions = { ...docState.pageRefreshVersions };\n for (const pageIndex of pageIndexes) {\n newVersions[pageIndex] = (newVersions[pageIndex] || 0) + 1;\n }\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...docState,\n pageRefreshVersions: newVersions,\n },\n },\n };\n }\n\n default:\n return state;\n }\n};\n","export type EventHandler<T> = (data: T) => void;\n\nexport interface BaseEventControlOptions {\n wait: number;\n}\n\nexport interface DebounceOptions extends BaseEventControlOptions {\n mode: 'debounce';\n}\n\nexport interface ThrottleOptions extends BaseEventControlOptions {\n mode: 'throttle';\n throttleMode?: 'leading-trailing' | 'trailing';\n}\n\nexport interface KeyedDebounceOptions<T> extends BaseEventControlOptions {\n mode: 'debounce';\n keyExtractor: (data: T) => string | number;\n}\n\nexport interface KeyedThrottleOptions<T> extends BaseEventControlOptions {\n mode: 'throttle';\n throttleMode?: 'leading-trailing' | 'trailing';\n keyExtractor: (data: T) => string | number;\n}\n\nexport type EventControlOptions<T = any> =\n | DebounceOptions\n | ThrottleOptions\n | KeyedDebounceOptions<T>\n | KeyedThrottleOptions<T>;\n\nexport class EventControl<T> {\n private timeoutId?: number;\n private lastRun: number = 0;\n\n constructor(\n private handler: EventHandler<T>,\n private options: DebounceOptions | ThrottleOptions,\n ) {}\n\n handle = (data: T): void => {\n if (this.options.mode === 'debounce') {\n this.debounce(data);\n } else {\n this.throttle(data);\n }\n };\n\n private debounce(data: T): void {\n if (this.timeoutId) {\n window.clearTimeout(this.timeoutId);\n }\n\n this.timeoutId = window.setTimeout(() => {\n this.handler(data);\n this.timeoutId = undefined;\n }, this.options.wait);\n }\n\n private throttle(data: T): void {\n if (this.options.mode === 'debounce') return;\n\n const now = Date.now();\n const throttleMode = this.options.throttleMode || 'leading-trailing';\n\n if (now - this.lastRun >= this.options.wait) {\n if (throttleMode === 'leading-trailing') {\n this.handler(data);\n }\n this.lastRun = now;\n }\n\n // Always schedule the trailing execution\n if (this.timeoutId) {\n window.clearTimeout(this.timeoutId);\n }\n\n this.timeoutId = window.setTimeout(\n () => {\n this.handler(data);\n this.lastRun = Date.now();\n this.timeoutId = undefined;\n },\n this.options.wait - (now - this.lastRun),\n );\n }\n\n destroy(): void {\n if (this.timeoutId) {\n window.clearTimeout(this.timeoutId);\n }\n }\n}\n\n/**\n * Event control with independent debouncing/throttling per key.\n * Useful when events carry a discriminator (like documentId) and\n * you want to debounce/throttle each key's events independently.\n *\n * @example\n * // Debounce viewport resize events independently per document\n * const control = new KeyedEventControl(\n * (event) => recalcZoom(event.documentId),\n * { mode: 'debounce', wait: 150, keyExtractor: (e) => e.documentId }\n * );\n * control.handle(event); // Each documentId gets its own 150ms debounce\n */\nexport class KeyedEventControl<T> {\n private controls = new Map<string, EventControl<T>>();\n private readonly baseOptions: DebounceOptions | ThrottleOptions;\n\n constructor(\n private handler: EventHandler<T>,\n private options: KeyedDebounceOptions<T> | KeyedThrottleOptions<T>,\n ) {\n // Extract base options without keyExtractor for individual EventControls\n this.baseOptions = {\n mode: options.mode,\n wait: options.wait,\n ...(options.mode === 'throttle' && 'throttleMode' in options\n ? { throttleMode: options.throttleMode }\n : {}),\n } as DebounceOptions | ThrottleOptions;\n }\n\n handle = (data: T): void => {\n const key = String(this.options.keyExtractor(data));\n\n let control = this.controls.get(key);\n if (!control) {\n control = new EventControl(this.handler, this.baseOptions);\n this.controls.set(key, control);\n }\n\n control.handle(data);\n };\n\n destroy(): void {\n for (const control of this.controls.values()) {\n control.destroy();\n }\n this.controls.clear();\n }\n}\n\n/**\n * Type guard to check if options are keyed\n */\nexport function isKeyedOptions<T>(\n options: EventControlOptions<T>,\n): options is KeyedDebounceOptions<T> | KeyedThrottleOptions<T> {\n return 'keyExtractor' in options;\n}\n","/**\n * Restrict a numeric value to the inclusive range [min, max].\n *\n * @example\n * clamp( 5, 0, 10) // 5\n * clamp(-3, 0, 10) // 0\n * clamp(17, 0, 10) // 10\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value < min ? min : value > max ? max : value;\n}\n\n/**\n * Deeply compares two values (objects, arrays, primitives)\n * with the following rules:\n * - Objects are compared ignoring property order.\n * - Arrays are compared ignoring element order (multiset comparison).\n * - Primitives are compared by strict equality.\n * - null/undefined are treated as normal primitives.\n *\n * @param a First value\n * @param b Second value\n * @param visited Used internally to detect cycles\n */\nexport function arePropsEqual(a: any, b: any, visited?: Set<any>): boolean {\n // Quick path for reference equality or same primitive\n if (a === b) {\n return true;\n }\n\n // Handle null/undefined mismatch\n if (a == null || b == null) {\n // If one is null/undefined and the other isn't, no match\n return a === b;\n }\n\n // Check types\n const aType = typeof a;\n const bType = typeof b;\n if (aType !== bType) return false;\n\n // If they are both objects or arrays, handle recursively\n if (aType === 'object') {\n // Optionally handle cyclical references\n if (!visited) visited = new Set();\n const pairId = getPairId(a, b);\n if (visited.has(pairId)) {\n // Already compared these two objects => assume true to avoid infinite recursion\n // or return false if you want to treat cycles as inequality\n return true;\n }\n visited.add(pairId);\n\n const aIsArray = Array.isArray(a);\n const bIsArray = Array.isArray(b);\n if (aIsArray && bIsArray) {\n // Compare as arrays ignoring order\n return arraysEqualUnordered(a, b, visited);\n } else if (!aIsArray && !bIsArray) {\n // Compare as plain objects (order of properties doesn't matter)\n return objectsEqual(a, b, visited);\n } else {\n // One is array, the other is object => not equal\n return false;\n }\n }\n\n // If both are function, symbol, etc. - typically we might say false\n // But you can decide your own logic for function or symbol equality\n return false;\n}\n\nfunction getPairId(a: any, b: any) {\n // Could do something more advanced. This is a cheap approach:\n // e.g. use the memory reference or an object identity approach\n return `${objectId(a)}__${objectId(b)}`;\n}\n\n/**\n * If you want stable object IDs, you'd need a WeakMap to store them.\n * This simplistic approach just calls toString on the object.\n */\nlet objectIdCounter = 0;\nconst objectIds = new WeakMap<object, number>();\n\nfunction objectId(obj: object): number {\n if (!objectIds.has(obj)) {\n objectIds.set(obj, ++objectIdCounter);\n }\n return objectIds.get(obj)!;\n}\n\nfunction arraysEqualUnordered(a: any[], b: any[], visited?: Set<any>): boolean {\n if (a.length !== b.length) return false;\n\n const used = new Array<boolean>(b.length).fill(false);\n\n // For each element in a, find an unused matching element in b\n outer: for (let i = 0; i < a.length; i++) {\n const elemA = a[i];\n for (let j = 0; j < b.length; j++) {\n if (used[j]) continue; // already used that slot\n if (arePropsEqual(elemA, b[j], visited)) {\n used[j] = true;\n continue outer; // found match for a[i], proceed\n }\n }\n // If we never found a match\n return false;\n }\n\n return true;\n}\n\nfunction objectsEqual(a: object, b: object, visited?: Set<any>): boolean {\n // Get all prop keys\n const aKeys = Object.keys(a).sort();\n const bKeys = Object.keys(b).sort();\n if (aKeys.length !== bKeys.length) return false;\n\n // Compare each property name\n for (let i = 0; i < aKeys.length; i++) {\n if (aKeys[i] !== bKeys[i]) return false;\n }\n\n // Compare each property value\n for (const key of aKeys) {\n // @ts-ignore\n const valA = a[key];\n // @ts-ignore\n const valB = b[key];\n if (!arePropsEqual(valA, valB, visited)) {\n return false;\n }\n }\n return true;\n}\n","import {\n PluginPackage,\n WithAutoMount,\n AutoMountElement,\n StandaloneComponent,\n ContainerComponent,\n IPlugin,\n} from '../types/plugin';\nimport { Action } from '../store/types';\n\nexport class PluginPackageBuilder<\n T extends IPlugin<TConfig>,\n TConfig = unknown,\n TState = unknown,\n TAction extends Action = Action,\n> {\n private package: PluginPackage<T, TConfig, TState, TAction>;\n private autoMountElements: AutoMountElement[] = [];\n\n constructor(basePackage: PluginPackage<T, TConfig, TState, TAction>) {\n this.package = basePackage;\n }\n\n addUtility(component: StandaloneComponent): this {\n this.autoMountElements.push({ component, type: 'utility' });\n return this;\n }\n\n addWrapper(component: ContainerComponent): this {\n this.autoMountElements.push({ component, type: 'wrapper' });\n return this;\n }\n\n build(): WithAutoMount<PluginPackage<T, TConfig, TState, TAction>> {\n return {\n ...this.package,\n autoMountElements: () => this.autoMountElements,\n };\n }\n}\n\n// Helper function for cleaner API\nexport function createPluginPackage<\n T extends IPlugin<TConfig>,\n TConfig = unknown,\n TState = unknown,\n TAction extends Action = Action,\n>(basePackage: PluginPackage<T, TConfig, TState, TAction>) {\n return new PluginPackageBuilder(basePackage);\n}\n","import { IPlugin } from '../types/plugin';\nimport { PluginRegistry } from '../registry/plugin-registry';\nimport {\n Action,\n CLOSE_DOCUMENT,\n CoreAction,\n CoreState,\n PluginStore,\n SET_ACTIVE_DOCUMENT,\n SET_DOCUMENT_LOADED,\n SET_ROTATION,\n SET_SCALE,\n START_LOADING_DOCUMENT,\n Store,\n StoreState,\n} from '../store';\nimport { Logger, PdfEngine } from '@embedpdf/models';\nimport { DocumentState } from '../store/initial-state';\n\nexport interface StateChangeHandler<TState> {\n (state: TState): void;\n}\n\nexport abstract class BasePlugin<\n TConfig = unknown,\n TCapability = unknown,\n TState = unknown,\n TAction extends Action = Action,\n> implements IPlugin<TConfig>\n{\n static readonly id: string;\n\n protected pluginStore: PluginStore<TState, TAction>;\n protected coreStore: Store<CoreState, CoreAction>;\n protected readonly logger: Logger;\n protected readonly engine: PdfEngine;\n\n // Track cooldown actions (renamed from debouncedActions)\n private cooldownActions: Record<string, number> = {};\n private debouncedTimeouts: Record<string, number> = {};\n private unsubscribeFromState: (() => void) | null = null;\n private unsubscribeFromCoreStore: (() => void) | null = null;\n private unsubscribeFromStartLoadingDocument: (() => void) | null = null;\n private unsubscribeFromSetDocumentLoaded: (() => void) | null = null;\n private unsubscribeFromCloseDocument: (() => void) | null = null;\n private unsubscribeFromSetScale: (() => void) | null = null;\n private unsubscribeFromSetRotation: (() => void) | null = null;\n\n private _capability?: Readonly<TCapability>;\n\n private readyPromise: Promise<void>;\n private readyResolve!: () => void;\n\n constructor(\n public readonly id: string,\n protected registry: PluginRegistry,\n ) {\n if (id !== (this.constructor as typeof BasePlugin).id) {\n throw new Error(\n `Plugin ID mismatch: ${id} !== ${(this.constructor as typeof BasePlugin).id}`,\n );\n }\n this.engine = this.registry.getEngine();\n this.logger = this.registry.getLogger();\n this.coreStore = this.registry.getStore();\n this.pluginStore = this.coreStore.getPluginStore<TState, TAction>(this.id);\n this.unsubscribeFromState = this.pluginStore.subscribeToState((action, newState, oldState) => {\n this.onStoreUpdated(oldState, newState);\n });\n this.unsubscribeFromCoreStore = this.coreStore.subscribe((action, newState, oldState) => {\n this.onCoreStoreUpdated(oldState, newState);\n if (newState.core.activeDocumentId !== oldState.core.activeDocumentId) {\n this.onActiveDocumentChanged(\n oldState.core.activeDocumentId,\n newState.core.activeDocumentId,\n );\n }\n });\n this.unsubscribeFromStartLoadingDocument = this.coreStore.onAction(\n START_LOADING_DOCUMENT,\n (action) => {\n this.onDocumentLoadingStarted(action.payload.documentId);\n },\n );\n this.unsubscribeFromSetDocumentLoaded = this.coreStore.onAction(\n SET_DOCUMENT_LOADED,\n (action) => {\n this.onDocumentLoaded(action.payload.documentId);\n },\n );\n this.unsubscribeFromCloseDocument = this.coreStore.onAction(CLOSE_DOCUMENT, (action) => {\n this.onDocumentClosed(action.payload.documentId);\n });\n this.unsubscribeFromSetScale = this.coreStore.onAction(SET_SCALE, (action, state) => {\n const targetId = action.payload.documentId ?? state.core.activeDocumentId;\n if (targetId) {\n this.onScaleChanged(targetId, action.payload.scale);\n }\n });\n this.unsubscribeFromSetRotation = this.coreStore.onAction(SET_ROTATION, (action, state) => {\n const targetId = action.payload.documentId ?? state.core.activeDocumentId;\n if (targetId) {\n this.onRotationChanged(targetId, action.payload.rotation);\n }\n });\n\n // Initialize ready state\n this.readyPromise = new Promise((resolve) => {\n this.readyResolve = resolve;\n });\n // By default, plugins are ready immediately\n this.readyResolve();\n }\n\n /** Construct the public capability (called once & cached). */\n protected abstract buildCapability(): TCapability;\n\n public provides(): Readonly<TCapability> {\n if (!this._capability) {\n const cap = this.buildCapability();\n\n this._capability = Object.freeze(cap);\n }\n return this._capability;\n }\n\n /**\n * Initialize plugin with config\n */\n abstract initialize(config: TConfig): Promise<void>;\n\n /**\n * Get a copy of the current state\n */\n protected get state(): Readonly<TState> {\n return this.pluginStore.getState();\n }\n\n /**\n * Get a copy of the current core state\n */\n protected get coreState(): Readonly<StoreState<CoreState>> {\n return this.coreStore.getState();\n }\n\n /**\n * @deprecated use `this.state` Get a copy of the current state\n */\n protected getState(): TState {\n return this.pluginStore.getState();\n }\n\n /**\n * @deprecated use `this.coreState` Get a copy of the current core state\n */\n protected getCoreState(): StoreState<CoreState> {\n return this.coreStore.getState();\n }\n\n /**\n * Core Dispatch\n */\n protected dispatchCoreAction(action: CoreAction): StoreState<CoreState> {\n return this.coreStore.dispatchToCore(action);\n }\n\n /**\n * Dispatch an action to all plugins\n */\n protected dispatchToAllPlugins(action: TAction): StoreState<CoreState> {\n return this.coreStore.dispatch(action);\n }\n\n /**\n * Dispatch an action\n */\n protected dispatch(action: TAction): TState {\n return this.pluginStore.dispatch(action);\n }\n\n /**\n * Dispatch an action with a cooldown to prevent rapid repeated calls\n * This executes immediately if cooldown has expired, then blocks subsequent calls\n * @param action The action to dispatch\n * @param cooldownTime Time in ms for cooldown (default: 100ms)\n * @returns boolean indicating whether the action was dispatched or blocked\n */\n protected cooldownDispatch(action: TAction, cooldownTime: number = 100): boolean {\n const now = Date.now();\n const lastActionTime = this.cooldownActions[action.type] || 0;\n\n if (now - lastActionTime >= cooldownTime) {\n this.cooldownActions[action.type] = now;\n this.dispatch(action);\n return true;\n }\n\n return false;\n }\n\n /**\n * Dispatch an action with true debouncing - waits for the delay after the last call\n * Each new call resets the timer. Action only executes after no calls for the specified time.\n * @param action The action to dispatch\n * @param debounceTime Time in ms to wait after the last call\n */\n protected debouncedDispatch(action: TAction, debounceTime: number = 100): void {\n const actionKey = action.type;\n\n // Clear existing timeout\n if (this.debouncedTimeouts[actionKey]) {\n clearTimeout(this.debouncedTimeouts[actionKey]);\n }\n\n // Set new timeout\n this.debouncedTimeouts[actionKey] = setTimeout(() => {\n this.dispatch(action);\n delete this.debouncedTimeouts[actionKey];\n }, debounceTime) as unknown as number;\n }\n\n /**\n * Cancel a pending debounced action\n * @param actionType The action type to cancel\n */\n protected cancelDebouncedDispatch(actionType: string): void {\n if (this.debouncedTimeouts[actionType]) {\n clearTimeout(this.debouncedTimeouts[actionType]);\n delete this.debouncedTimeouts[actionType];\n }\n }\n\n /**\n * Subscribe to state changes\n */\n protected subscribe(listener: (action: TAction, state: TState) => void): () => void {\n return this.pluginStore.subscribeToState(listener);\n }\n\n /**\n * Subscribe to core store changes\n */\n protected subscribeToCoreStore(\n listener: (action: Action, state: StoreState<CoreState>) => void,\n ): () => void {\n return this.coreStore.subscribe(listener);\n }\n\n /**\n * Called when the plugin store state is updated\n * @param oldState Previous state\n * @param newState New state\n */\n protected onStoreUpdated(oldState: TState, newState: TState): void {\n // Default implementation does nothing - can be overridden by plugins\n }\n\n /**\n * Called when the core store state is updated\n * @param oldState Previous state\n * @param newState New state\n */\n protected onCoreStoreUpdated(\n oldState: StoreState<CoreState>,\n newState: StoreState<CoreState>,\n ): void {\n // Default implementation does nothing - can be overridden by plugins\n }\n\n /**\n * Called when a document is opened\n * Override to initialize per-document state\n * @param documentId The ID of the document that was opened\n */\n protected onDocumentLoadingStarted(documentId: string): void {\n // Default: no-op\n }\n\n /**\n * Called when a document is loaded\n * @param documentId The ID of the document that is loaded\n */\n protected onDocumentLoaded(documentId: string): void {\n // Default: no-op\n }\n\n /**\n * Called when a document is closed\n * Override to cleanup per-document state\n * @param documentId The ID of the document that was closed\n */\n protected onDocumentClosed(documentId: string): void {\n // Default: no-op\n }\n\n /**\n * Called when the active document changes\n * @param previousId The ID of the previous active document\n * @param currentId The ID of the new active document\n */\n protected onActiveDocumentChanged(previousId: string | null, currentId: string | null): void {\n // Default: no-op\n }\n\n protected onScaleChanged(documentId: string, scale: number): void {\n // Default: no-op\n }\n\n protected onRotationChanged(documentId: string, rotation: number): void {\n // Default: no-op\n }\n\n /**\n * Cleanup method to be called when plugin is being destroyed\n */\n public destroy(): void {\n // Clear all pending timeouts\n Object.values(this.debouncedTimeouts).forEach((timeout) => {\n clearTimeout(timeout);\n });\n this.debouncedTimeouts = {};\n\n if (this.unsubscribeFromState) {\n this.unsubscribeFromState();\n this.unsubscribeFromState = null;\n }\n if (this.unsubscribeFromCoreStore) {\n this.unsubscribeFromCoreStore();\n this.unsubscribeFromCoreStore = null;\n }\n if (this.unsubscribeFromStartLoadingDocument) {\n this.unsubscribeFromStartLoadingDocument();\n this.unsubscribeFromStartLoadingDocument = null;\n }\n if (this.unsubscribeFromSetDocumentLoaded) {\n this.unsubscribeFromSetDocumentLoaded();\n this.unsubscribeFromSetDocumentLoaded = null;\n }\n if (this.unsubscribeFromCloseDocument) {\n this.unsubscribeFromCloseDocument();\n this.unsubscribeFromCloseDocument = null;\n }\n if (this.unsubscribeFromSetScale) {\n this.unsubscribeFromSetScale();\n this.unsubscribeFromSetScale = null;\n }\n if (this.unsubscribeFromSetRotation) {\n this.unsubscribeFromSetRotation();\n this.unsubscribeFromSetRotation = null;\n }\n }\n\n /**\n * Returns a promise that resolves when the plugin is ready\n */\n public ready(): Promise<void> {\n return this.readyPromise;\n }\n\n /**\n * Mark the plugin as ready\n */\n protected markReady(): void {\n this.readyResolve();\n }\n\n /**\n * Reset the ready state (useful for plugins that need to reinitialize)\n */\n protected resetReady(): void {\n this.readyPromise = new Promise((resolve) => {\n this.readyResolve = resolve;\n });\n }\n\n /**\n * Get the active document ID\n * @throws Error if no active document exists\n */\n protected getActiveDocumentId(): string {\n const id = this.coreState.core.activeDocumentId;\n if (!id) {\n throw new Error('No active document');\n }\n return id;\n }\n\n /**\n * Get the active document ID or null if none exists\n */\n protected getActiveDocumentIdOrNull(): string | null {\n return this.coreState.core.activeDocumentId;\n }\n\n /**\n * Get core document state for a specific document\n * @param documentId Document ID (optional, defaults to active document)\n * @returns Document state or null if not found\n */\n protected getCoreDocument(documentId?: string): DocumentState | null {\n const id = documentId ?? this.getActiveDocumentIdOrNull();\n if (!id) return null;\n return this.coreState.core.documents[id] ?? null;\n }\n\n /**\n * Get core document state for a specific document\n * @param documentId Document ID (optional, defaults to active document)\n * @throws Error if document not found\n */\n protected getCoreDocumentOrThrow(documentId?: string): DocumentState {\n const doc = this.getCoreDocument(documentId);\n if (!doc) {\n throw new Error(`Document not found: ${documentId ?? 'active'}`);\n }\n return doc;\n }\n}\n","import { DependencyResolver } from '../utils/dependency-resolver';\nimport {\n IPlugin,\n PluginBatchRegistration,\n PluginManifest,\n PluginStatus,\n PluginPackage,\n PluginRegistryConfig,\n PluginBatchRegistrations,\n} from '../types/plugin';\nimport {\n PluginRegistrationError,\n PluginNotFoundError,\n CircularDependencyError,\n PluginConfigurationError,\n} from '../types/errors';\nimport { Logger, NoopLogger, PdfEngine } from '@embedpdf/models';\nimport { Action, CoreState, Store, initialCoreState, Reducer } from '../store';\nimport { CoreAction } from '../store/actions';\nimport { coreReducer } from '../store/reducer';\n\n// Define a more flexible generic type for plugin registrations\ninterface PluginRegistration {\n // Use existential types for the plugin package to allow accepting any plugin type\n package: PluginPackage<any, any, any, any>;\n config?: any;\n}\n\nexport class PluginRegistry {\n private plugins: Map<string, IPlugin> = new Map();\n private manifests: Map<string, PluginManifest> = new Map();\n private capabilities: Map<string, string> = new Map(); // capability -> pluginId\n private status: Map<string, PluginStatus> = new Map();\n private resolver: DependencyResolver;\n private configurations: Map<string, unknown> = new Map();\n private engine: PdfEngine;\n private engineInitialized = false;\n private store: Store<CoreState, CoreAction>;\n private initPromise: Promise<void> | null = null;\n private logger: Logger;\n\n private pendingRegistrations: PluginRegistration[] = [];\n private processingRegistrations: PluginRegistration[] = [];\n private initialized = false;\n private isInitializing = false;\n private initialCoreState: CoreState;\n private pluginsReadyPromise: Promise<void> | null = null;\n private destroyed = false;\n\n constructor(engine: PdfEngine, config?: PluginRegistryConfig) {\n this.resolver = new DependencyResolver();\n this.engine = engine;\n this.initialCoreState = initialCoreState(config);\n this.store = new Store<CoreState, CoreAction>(coreReducer, this.initialCoreState);\n this.logger = config?.logger ?? new NoopLogger();\n }\n\n /**\n * Get the logger instance\n */\n getLogger(): Logger {\n return this.logger;\n }\n\n /**\n * Ensure engine is initialized before proceeding\n */\n private async ensureEngineInitialized(): Promise<void> {\n if (this.engineInitialized) {\n return;\n }\n\n if (this.engine.initialize) {\n const task = this.engine.initialize();\n await task.toPromise();\n this.engineInitialized = true;\n } else {\n this.engineInitialized = true;\n }\n }\n\n /**\n * Register a plugin without initializing it\n */\n registerPlugin<\n TPlugin extends IPlugin<TConfig>,\n TConfig = unknown,\n TState = unknown,\n TAction extends Action = Action,\n >(\n pluginPackage: PluginPackage<TPlugin, TConfig, TState, TAction>,\n config?: Partial<TConfig>,\n ): void {\n if (this.initialized && !this.isInitializing) {\n throw new PluginRegistrationError('Cannot register plugins after initialization');\n }\n\n this.validateManifest(pluginPackage.manifest);\n\n // Use appropriate typing for store methods\n this.store.addPluginReducer(\n pluginPackage.manifest.id,\n // We need one type assertion here since we can't fully reconcile TAction with Action\n // due to TypeScript's type system limitations with generic variance\n pluginPackage.reducer as Reducer<TState, Action>,\n 'function' === typeof pluginPackage.initialState\n ? (pluginPackage.initialState as (coreState: CoreState, config: TConfig) => TState)(\n this.initialCoreState,\n {\n ...pluginPackage.manifest.defaultConfig,\n ...config,\n },\n )\n : pluginPackage.initialState,\n );\n\n this.pendingRegistrations.push({\n package: pluginPackage,\n config,\n });\n }\n\n /**\n * Get the central store instance\n */\n getStore(): Store<CoreState, CoreAction> {\n return this.store;\n }\n\n /**\n * Get the engine instance\n */\n getEngine(): PdfEngine {\n return this.engine;\n }\n\n /**\n * Get a promise that resolves when all plugins are ready\n */\n public pluginsReady(): Promise<void> {\n // Re-use the same promise every time it’s asked for\n if (this.pluginsReadyPromise) {\n return this.pluginsReadyPromise;\n }\n\n // Build the promise the *first* time it’s requested\n this.pluginsReadyPromise = (async () => {\n // 1. Wait until the registry itself has finished initialising\n if (!this.initialized) {\n await this.initialize();\n }\n\n // 2. Wait for every plugin’s ready() promise (if it has one)\n const readyPromises = Array.from(this.plugins.values()).map((p) =>\n typeof p.ready === 'function' ? p.ready() : Promise.resolve(),\n );\n\n await Promise.all(readyPromises); // resolves when the slowest is done\n })();\n\n return this.pluginsReadyPromise;\n }\n\n /**\n * INITIALISE THE REGISTRY – runs once no-matter-how-many calls *\n */\n async initialize(): Promise<void> {\n if (this.destroyed) {\n throw new PluginRegistrationError('Registry has been destroyed');\n }\n\n if (this.initPromise) {\n return this.initPromise;\n }\n\n this.initPromise = (async () => {\n if (this.initialized) {\n throw new PluginRegistrationError('Registry is already initialized');\n }\n\n this.isInitializing = true;\n\n try {\n await this.ensureEngineInitialized();\n if (this.destroyed) return;\n\n while (this.pendingRegistrations.length > 0) {\n if (this.destroyed) return;\n\n this.processingRegistrations = [...this.pendingRegistrations];\n this.pendingRegistrations = [];\n\n // ------------------------------------------------------------\n // STEP 1: RESOLVE ORDER (Using Manifests)\n // ------------------------------------------------------------\n // We use the static manifests to figure out the graph before creating instances.\n for (const reg of this.processingRegistrations) {\n const dependsOn = new Set<string>();\n const allDeps = [...reg.package.manifest.requires, ...reg.package.manifest.optional];\n\n for (const cap of allDeps) {\n // Check if provider is in the current batch\n const provider = this.processingRegistrations.find((r) =>\n r.package.manifest.provides.includes(cap),\n );\n\n // If the provider is in this batch, we must load after it.\n // If the provider was in a previous batch, it's already loaded, so no edge needed.\n if (provider) {\n dependsOn.add(provider.package.manifest.id);\n }\n }\n this.resolver.addNode(reg.package.manifest.id, [...dependsOn]);\n }\n\n const loadOrder = this.resolver.resolveLoadOrder();\n\n // ------------------------------------------------------------\n // STEP 2: INSTANTIATION (Constructors)\n // ------------------------------------------------------------\n // Create all instances and register capabilities.\n // Now \"this.plugins.get('id')\" will return an object for everyone in this batch.\n for (const id of loadOrder) {\n const reg = this.processingRegistrations.find((r) => r.package.manifest.id === id)!;\n this.instantiatePlugin(reg.package.manifest, reg.package.create, reg.config);\n }\n\n // ------------------------------------------------------------\n // STEP 3: INITIALIZATION (Logic)\n // ------------------------------------------------------------\n // Now run the async logic. Since step 2 is done,\n // Plugin A can safely access Plugin B's instance during initialize.\n for (const id of loadOrder) {\n await this.runPluginInitialization(id);\n }\n\n this.processingRegistrations = [];\n this.resolver = new DependencyResolver();\n }\n\n // postInitialize is removed as requested/agreed!\n\n this.initialized = true;\n } catch (err) {\n if (err instanceof Error) {\n throw new CircularDependencyError(\n `Failed to resolve plugin dependencies: ${err.message}`,\n );\n }\n throw err;\n } finally {\n this.isInitializing = false;\n }\n })();\n\n return this.initPromise;\n }\n\n /**\n * Phase 2: Create instance and register capabilities\n */\n private instantiatePlugin<TConfig>(\n manifest: PluginManifest<TConfig>,\n packageCreator: (registry: PluginRegistry, config?: TConfig) => IPlugin<TConfig>,\n config?: Partial<TConfig>,\n ): void {\n const finalConfig = {\n ...manifest.defaultConfig,\n ...config,\n };\n\n this.validateConfig(manifest.id, finalConfig, manifest.defaultConfig);\n\n // Create plugin instance (Constructor runs here)\n const plugin = packageCreator(this, finalConfig);\n this.validatePlugin(plugin);\n\n // Check existing capabilities (sanity check)\n for (const capability of manifest.provides) {\n if (this.capabilities.has(capability)) {\n throw new PluginRegistrationError(\n `Capability ${capability} is already provided by plugin ${this.capabilities.get(capability)}`,\n );\n }\n this.capabilities.set(capability, manifest.id);\n }\n\n // Store plugin and manifest\n this.plugins.set(manifest.id, plugin);\n this.manifests.set(manifest.id, manifest);\n this.status.set(manifest.id, 'registered'); // Ready for init\n this.configurations.set(manifest.id, finalConfig);\n }\n\n /**\n * Phase 3: Run the initialize method\n */\n private async runPluginInitialization(pluginId: string): Promise<void> {\n const plugin = this.plugins.get(pluginId);\n if (!plugin) return; // Should not happen given loadOrder logic\n\n const manifest = this.manifests.get(pluginId)!;\n const config = this.configurations.get(pluginId);\n\n // Validate requirements are met (now that everyone is instantiated)\n for (const capability of manifest.requires) {\n if (!this.capabilities.has(capability)) {\n throw new PluginRegistrationError(\n `Missing required capability: ${capability} for plugin ${pluginId}`,\n );\n }\n }\n\n this.logger.debug('PluginRegistry', 'InitializePlugin', `Initializing plugin ${pluginId}`);\n\n try {\n if (plugin.initialize) {\n await plugin.initialize(config);\n }\n this.status.set(pluginId, 'active');\n\n this.logger.info(\n 'PluginRegistry',\n 'PluginInitialized',\n `Plugin ${pluginId} initialized successfully`,\n );\n } catch (error) {\n // Rollback logic\n this.status.set(pluginId, 'error');\n this.logger.error(\n 'PluginRegistry',\n 'InitializationFailed',\n `Plugin ${pluginId} initialization failed`,\n { error },\n );\n throw error;\n }\n }\n\n getPluginConfig<TConfig>(pluginId: string): TConfig {\n const config = this.configurations.get(pluginId);\n if (!config) {\n throw new PluginNotFoundError(`Configuration for plugin ${pluginId} not found`);\n }\n return config as TConfig;\n }\n\n private validateConfig(pluginId: string, config: unknown, defaultConfig: unknown): void {\n // Check all required fields exist\n const requiredKeys = Object.keys(defaultConfig as object);\n const missingKeys = requiredKeys.filter((key) => !(config as object).hasOwnProperty(key));\n\n if (missingKeys.length > 0) {\n throw new PluginConfigurationError(\n `Missing required configuration keys for plugin ${pluginId}: ${missingKeys.join(', ')}`,\n );\n }\n\n // You could add more validation here:\n // - Type checking\n // - Value range validation\n // - Format validation\n // etc.\n }\n\n async updatePluginConfig<TConfig>(pluginId: string, config: Partial<TConfig>): Promise<void> {\n const plugin = this.getPlugin(pluginId);\n\n if (!plugin) {\n throw new PluginNotFoundError(`Plugin ${pluginId} not found`);\n }\n\n const manifest = this.manifests.get(pluginId);\n const currentConfig = this.configurations.get(pluginId);\n\n if (!manifest || !currentConfig) {\n throw new PluginNotFoundError(`Plugin ${pluginId} not found`);\n }\n\n // Merge new config with current\n const newConfig = {\n ...currentConfig,\n ...config,\n };\n\n // Validate new configuration\n this.validateConfig(pluginId, newConfig, manifest.defaultConfig);\n\n // Store new configuration\n this.configurations.set(pluginId, newConfig);\n\n // Reinitialize plugin if needed\n if (plugin.initialize) {\n await plugin.initialize(newConfig);\n }\n }\n\n /**\n * Register multiple plugins at once\n */\n registerPluginBatch(registrations: PluginBatchRegistrations): void {\n for (const reg of registrations) {\n this.registerPlugin(reg.package, reg.config);\n }\n }\n\n /**\n * Unregister a plugin\n */\n async unregisterPlugin(pluginId: string): Promise<void> {\n const plugin = this.plugins.get(pluginId);\n if (!plugin) {\n throw new PluginNotFoundError(`Plugin ${pluginId} is not registered`);\n }\n\n const manifest = this.manifests.get(pluginId);\n if (!manifest) {\n throw new PluginNotFoundError(`Manifest for plugin ${pluginId} not found`);\n }\n\n // Check if any other plugins depend on this one\n for (const [otherId, otherManifest] of this.manifests.entries()) {\n if (otherId === pluginId) continue;\n\n const dependsOnThis = [...otherManifest.requires, ...otherManifest.optional].some((cap) =>\n manifest.provides.includes(cap),\n );\n\n if (dependsOnThis) {\n throw new PluginRegistrationError(\n `Cannot unregister plugin ${pluginId}: plugin ${otherId} depends on it`,\n );\n }\n }\n\n // Cleanup plugin\n try {\n if (plugin.destroy) {\n await plugin.destroy();\n }\n\n // Remove capabilities\n for (const capability of manifest.provides) {\n this.capabilities.delete(capability);\n }\n\n // Remove plugin and manifest\n this.plugins.delete(pluginId);\n this.manifests.delete(pluginId);\n this.status.delete(pluginId);\n } catch (error) {\n if (error instanceof Error) {\n throw new Error(`Failed to unregister plugin ${pluginId}: ${error.message}`);\n }\n throw error;\n }\n }\n\n /**\n * Get a plugin instance\n * @param pluginId The ID of the plugin to get\n * @returns The plugin instance or null if not found\n */\n getPlugin<T extends IPlugin>(pluginId: string): T | null {\n const plugin = this.plugins.get(pluginId);\n if (!plugin) {\n return null;\n }\n return plugin as T;\n }\n\n /**\n * Get a plugin that provides a specific capability\n * @param capability The capability to get a provider for\n * @returns The plugin providing the capability or null if not found\n */\n getCapabilityProvider(capability: string): IPlugin | null {\n const pluginId = this.capabilities.get(capability);\n if (!pluginId) {\n return null;\n }\n return this.getPlugin(pluginId);\n }\n\n /**\n * Check if a capability is available\n */\n hasCapability(capability: string): boolean {\n return this.capabilities.has(capability);\n }\n\n /**\n * Get all registered plugins\n */\n getAllPlugins(): IPlugin[] {\n return Array.from(this.plugins.values());\n }\n\n /**\n * Get plugin status\n */\n getPluginStatus(pluginId: string): PluginStatus {\n const status = this.status.get(pluginId);\n if (!status) {\n throw new PluginNotFoundError(`Plugin ${pluginId} not found`);\n }\n return status;\n }\n\n /**\n * Validate plugin object\n */\n private validatePlugin(plugin: IPlugin): void {\n if (!plugin.id) {\n throw new PluginRegistrationError('Plugin must have an id');\n }\n }\n\n /**\n * Validate plugin manifest\n */\n private validateManifest(manifest: PluginManifest): void {\n if (!manifest.id) {\n throw new PluginRegistrationError('Manifest must have an id');\n }\n if (!manifest.name) {\n throw new PluginRegistrationError('Manifest must have a name');\n }\n if (!manifest.version) {\n throw new PluginRegistrationError('Manifest must have a version');\n }\n if (!Array.isArray(manifest.provides)) {\n throw new PluginRegistrationError('Manifest must have a provides array');\n }\n if (!Array.isArray(manifest.requires)) {\n throw new PluginRegistrationError('Manifest must have a requires array');\n }\n if (!Array.isArray(manifest.optional)) {\n throw new PluginRegistrationError('Manifest must have an optional array');\n }\n }\n\n isDestroyed(): boolean {\n return this.destroyed;\n }\n\n /**\n * DESTROY EVERYTHING – waits for any ongoing initialise(), once *\n */\n async destroy(): Promise<void> {\n if (this.destroyed) throw new PluginRegistrationError('Registry has already been destroyed');\n this.destroyed = true;\n\n // If initialisation is still underway, wait (success OR failure)\n try {\n await this.initPromise;\n } catch {\n /* ignore – still need to clean up */\n }\n\n /* ------- original teardown, unchanged except the guard ------ */\n for (const plugin of Array.from(this.plugins.values()).reverse()) {\n await plugin.destroy?.();\n }\n\n this.store.destroy();\n\n this.plugins.clear();\n this.manifests.clear();\n this.capabilities.clear();\n this.status.clear();\n this.pendingRegistrations.length = 0;\n this.processingRegistrations.length = 0;\n }\n}\n","import {\n EventControl,\n EventControlOptions,\n KeyedEventControl,\n isKeyedOptions,\n} from './event-control';\nimport { arePropsEqual } from './math';\n\n/* ------------------------------------------------------------------ */\n/* basic types */\n/* ------------------------------------------------------------------ */\nexport type Listener<T = any> = (value: T) => void;\nexport type Unsubscribe = () => void;\n\n/* ------------------------------------------------------------------ */\n/* EventListener */\n/* ------------------------------------------------------------------ */\nexport type EventListener<T> =\n | ((listener: Listener<T>) => Unsubscribe)\n | ((listener: Listener<T>, options?: EventControlOptions<T>) => Unsubscribe);\n\n/* ------------------------------------------------------------ */\n/* helpers for typing `.on()` with an optional second argument */\n/* ------------------------------------------------------------ */\nexport type EventHook<T = any> = EventListener<T>;\n\n/* ------------------------------------------------------------------ */\n/* minimal \"dumb\" emitter (no value cache, no equality) */\n/* ------------------------------------------------------------------ */\nexport interface Emitter<T = any> {\n emit(value?: T): void;\n on(listener: Listener<T>): Unsubscribe;\n off(listener: Listener<T>): void;\n clear(): void;\n}\n\nexport function createEmitter<T = any>(): Emitter<T> {\n const listeners = new Set<Listener<T>>();\n\n const on: EventHook<T> = (l: Listener<T>) => {\n listeners.add(l);\n return () => listeners.delete(l);\n };\n\n return {\n emit: (v = undefined as T) => listeners.forEach((l) => l(v)),\n on,\n off: (l) => listeners.delete(l),\n clear: () => listeners.clear(),\n };\n}\n\n/* ------------------------------------------------------------ */\n/* public interface */\n/* ------------------------------------------------------------ */\nexport interface BehaviorEmitter<T = any> extends Omit<Emitter<T>, 'on' | 'off'> {\n readonly value?: T;\n on: EventHook<T>;\n off(listener: Listener<T>): void;\n select<U>(selector: (v: T) => U, equality?: (a: U, b: U) => boolean): EventHook<U>;\n}\n\n/* ------------------------------------------------------------ */\n/* implementation */\n/* ------------------------------------------------------------ */\nexport function createBehaviorEmitter<T = any>(\n initial?: T,\n equality: (a: T, b: T) => boolean = arePropsEqual,\n): BehaviorEmitter<T> {\n const listeners = new Set<Listener<T>>();\n const proxyMap = new Map<Listener<T>, { wrapped: Listener<T>; destroy: () => void }>();\n let _value = initial; // cached value\n\n /* -------------- helpers ----------------------------------- */\n const notify = (v: T) => listeners.forEach((l) => l(v));\n\n const baseOn: EventHook<T> = (listener: Listener<T>, options?: EventControlOptions<T>) => {\n /* wrap & remember if we have control options ------------------ */\n let realListener = listener;\n let destroy = () => {};\n\n if (options) {\n // Check if it's keyed options\n if (isKeyedOptions(options)) {\n const ctl = new KeyedEventControl(listener, options);\n realListener = ctl.handle as Listener<T>;\n destroy = () => ctl.destroy();\n } else {\n const ctl = new EventControl(listener, options);\n realListener = ctl.handle as Listener<T>;\n destroy = () => ctl.destroy();\n }\n proxyMap.set(listener, { wrapped: realListener, destroy });\n }\n\n /* immediate replay of last value ------------------------------ */\n if (_value !== undefined) realListener(_value);\n\n listeners.add(realListener);\n\n return () => {\n listeners.delete(realListener);\n destroy();\n proxyMap.delete(listener);\n };\n };\n\n /* -------------- public object ------------------------------ */\n return {\n /* emitter behaviour ---------------------------------------- */\n get value() {\n return _value;\n },\n\n emit(v = undefined as T) {\n if (_value === undefined || !equality(_value, v)) {\n _value = v;\n notify(v);\n }\n },\n\n on: baseOn,\n off(listener: Listener<T>) {\n /* did we wrap this listener? */\n const proxy = proxyMap.get(listener);\n if (proxy) {\n listeners.delete(proxy.wrapped);\n proxy.destroy();\n proxyMap.delete(listener);\n } else {\n listeners.delete(listener);\n }\n },\n\n clear() {\n listeners.clear();\n proxyMap.forEach((p) => p.destroy());\n proxyMap.clear();\n },\n\n /* derived hook --------------------------------------------- */\n select<U>(selector: (v: T) => U, eq: (a: U, b: U) => boolean = arePropsEqual): EventHook<U> {\n return (listener: Listener<U>, options?: EventControlOptions<U>) => {\n let prev: U | undefined;\n\n /* replay */\n if (_value !== undefined) {\n const mapped = selector(_value);\n prev = mapped;\n listener(mapped);\n }\n\n /* subscribe to parent */\n return baseOn(\n (next) => {\n const mapped = selector(next);\n if (prev === undefined || !eq(prev, mapped)) {\n prev = mapped;\n listener(mapped);\n }\n },\n options as EventControlOptions<T> | undefined,\n ); // pass control opts straight through\n };\n },\n };\n}\n","import { Action } from '../store';\nimport { IPlugin, PluginBatchRegistration, PluginPackage } from '../types/plugin';\n\n/**\n * Helper function to create a properly typed plugin registration\n */\nexport function createPluginRegistration<\n T extends IPlugin<TConfig>,\n TConfig,\n TState,\n TAction extends Action,\n>(\n pluginPackage: PluginPackage<T, TConfig, TState, TAction>,\n config?: Partial<TConfig>,\n): PluginBatchRegistration<T, TConfig, any, any> {\n return {\n package: pluginPackage,\n config,\n };\n}\n","import {\n EventControl,\n EventControlOptions,\n KeyedEventControl,\n isKeyedOptions,\n} from './event-control';\nimport { EventHook, Listener, Unsubscribe } from './eventing';\nimport { arePropsEqual } from './math';\n\n/* ------------------------------------------------------------------ */\n/* Scoped Emitter - Generic Key-Based Event Scoping */\n/* ------------------------------------------------------------------ */\n\n/**\n * A scoped behavior emitter that maintains separate cached values\n * and listener sets per scope key.\n *\n * @typeParam TData - The scoped data type (without key context)\n * @typeParam TGlobalEvent - The global event type (includes key context)\n * @typeParam TKey - The key type (string, number, or both)\n */\nexport interface ScopedEmitter<\n TData = any,\n TGlobalEvent = { key: string; data: TData },\n TKey extends string | number = string | number,\n> {\n /**\n * Emit an event for a specific scope key.\n */\n emit(key: TKey, data: TData): void;\n\n /**\n * Get a scoped event hook that only receives events for this key.\n */\n forScope(key: TKey): EventHook<TData>;\n\n /**\n * Global event hook that receives events from all scopes.\n */\n readonly onGlobal: EventHook<TGlobalEvent>;\n\n /**\n * Clear all scopes' caches and listeners\n */\n clear(): void;\n\n /**\n * Clear a specific scope's cache and listeners\n */\n clearScope(key: TKey): void;\n\n /**\n * Get the current cached value for a specific scope\n */\n getValue(key: TKey): TData | undefined;\n\n /**\n * Get all active scope keys\n */\n getScopes(): TKey[];\n}\n\n/**\n * Creates a scoped emitter with optional caching behavior.\n *\n * @param toGlobalEvent - Transform function to convert (key, data) into a global event\n * @param options - Configuration options\n * @param options.cache - Whether to cache values per scope (default: true)\n * @param options.equality - Equality function for cached values (default: arePropsEqual)\n *\n * @example\n * ```typescript\n * // With caching (stateful) - default behavior\n * const window$ = createScopedEmitter<WindowState, WindowChangeEvent, string>(\n * (documentId, window) => ({ documentId, window })\n * );\n *\n * // Without caching (transient events)\n * const refreshPages$ = createScopedEmitter<number[], RefreshPagesEvent, string>(\n * (documentId, pages) => ({ documentId, pages }),\n * { cache: false }\n * );\n * ```\n */\nexport function createScopedEmitter<\n TData = any,\n TGlobalEvent = { key: string; data: TData },\n TKey extends string | number = string | number,\n>(\n toGlobalEvent: (key: TKey, data: TData) => TGlobalEvent,\n options?: {\n cache?: boolean;\n equality?: (a: TData, b: TData) => boolean;\n },\n): ScopedEmitter<TData, TGlobalEvent, TKey> {\n const shouldCache = options?.cache ?? true;\n const equality = options?.equality ?? arePropsEqual;\n\n // Per-scope state\n const scopeCaches = new Map<string, TData>();\n const scopeListeners = new Map<string, Set<Listener<TData>>>();\n const scopeProxyMaps = new Map<\n string,\n Map<Listener<TData>, { wrapped: Listener<TData>; destroy: () => void }>\n >();\n\n // Global listeners\n const globalListeners = new Set<Listener<TGlobalEvent>>();\n const globalProxyMap = new Map<\n Listener<TGlobalEvent>,\n { wrapped: Listener<TGlobalEvent>; destroy: () => void }\n >();\n\n const normalizeKey = (key: TKey): string => String(key);\n\n const getOrCreateListeners = (key: string): Set<Listener<TData>> => {\n let listeners = scopeListeners.get(key);\n if (!listeners) {\n listeners = new Set();\n scopeListeners.set(key, listeners);\n }\n return listeners;\n };\n\n const getOrCreateProxyMap = (\n key: string,\n ): Map<Listener<TData>, { wrapped: Listener<TData>; destroy: () => void }> => {\n let proxyMap = scopeProxyMaps.get(key);\n if (!proxyMap) {\n proxyMap = new Map();\n scopeProxyMaps.set(key, proxyMap);\n }\n return proxyMap;\n };\n\n const onGlobal: EventHook<TGlobalEvent> = (\n listener: Listener<TGlobalEvent>,\n options?: EventControlOptions<TGlobalEvent>,\n ): Unsubscribe => {\n let realListener = listener;\n let destroy = () => {};\n\n if (options) {\n if (isKeyedOptions(options)) {\n const ctl = new KeyedEventControl(listener, options);\n realListener = ctl.handle as Listener<TGlobalEvent>;\n destroy = () => ctl.destroy();\n } else {\n const ctl = new EventControl(listener, options);\n realListener = ctl.handle as Listener<TGlobalEvent>;\n destroy = () => ctl.destroy();\n }\n globalProxyMap.set(listener, { wrapped: realListener, destroy });\n }\n\n globalListeners.add(realListener);\n\n return () => {\n globalListeners.delete(realListener);\n destroy();\n globalProxyMap.delete(listener);\n };\n };\n\n return {\n emit(key: TKey, data: TData) {\n const normalizedKey = normalizeKey(key);\n\n if (shouldCache) {\n // Behavior mode: check equality before emitting\n const cached = scopeCaches.get(normalizedKey);\n if (cached !== undefined && equality(cached, data)) {\n return; // Skip emission if value hasn't changed\n }\n scopeCaches.set(normalizedKey, data);\n }\n\n // Notify per-scope listeners\n const listeners = scopeListeners.get(normalizedKey);\n if (listeners) {\n listeners.forEach((l) => l(data));\n }\n\n // Notify global listeners\n const globalEvent = toGlobalEvent(key, data);\n globalListeners.forEach((l) => l(globalEvent));\n },\n\n forScope(key: TKey): EventHook<TData> {\n const normalizedKey = normalizeKey(key);\n\n return (listener: Listener<TData>, options?: EventControlOptions<TData>): Unsubscribe => {\n const listeners = getOrCreateListeners(normalizedKey);\n const proxyMap = getOrCreateProxyMap(normalizedKey);\n\n let realListener = listener;\n let destroy = () => {};\n\n if (options) {\n if (isKeyedOptions(options)) {\n const ctl = new KeyedEventControl(listener, options);\n realListener = ctl.handle as Listener<TData>;\n destroy = () => ctl.destroy();\n } else {\n const ctl = new EventControl(listener, options);\n realListener = ctl.handle as Listener<TData>;\n destroy = () => ctl.destroy();\n }\n proxyMap.set(listener, { wrapped: realListener, destroy });\n }\n\n // Replay cached value ONLY if caching is enabled\n if (shouldCache) {\n const cached = scopeCaches.get(normalizedKey);\n if (cached !== undefined) {\n realListener(cached);\n }\n }\n\n listeners.add(realListener);\n\n return () => {\n listeners.delete(realListener);\n destroy();\n proxyMap.delete(listener);\n\n if (listeners.size === 0) {\n scopeListeners.delete(normalizedKey);\n }\n if (proxyMap.size === 0) {\n scopeProxyMaps.delete(normalizedKey);\n }\n };\n };\n },\n\n onGlobal,\n\n getValue(key: TKey): TData | undefined {\n return shouldCache ? scopeCaches.get(normalizeKey(key)) : undefined;\n },\n\n getScopes(): TKey[] {\n if (shouldCache) {\n return Array.from(scopeCaches.keys()) as TKey[];\n }\n // Without cache, return all scopes that have active listeners\n return Array.from(scopeListeners.keys()) as TKey[];\n },\n\n clearScope(key: TKey): void {\n const normalizedKey = normalizeKey(key);\n\n if (shouldCache) {\n scopeCaches.delete(normalizedKey);\n }\n\n const listeners = scopeListeners.get(normalizedKey);\n if (listeners) {\n listeners.clear();\n scopeListeners.delete(normalizedKey);\n }\n\n const proxyMap = scopeProxyMaps.get(normalizedKey);\n if (proxyMap) {\n proxyMap.forEach((p) => p.destroy());\n proxyMap.clear();\n scopeProxyMaps.delete(normalizedKey);\n }\n },\n\n clear(): void {\n if (shouldCache) {\n scopeCaches.clear();\n }\n scopeListeners.forEach((set) => set.clear());\n scopeListeners.clear();\n scopeProxyMaps.forEach((map) => {\n map.forEach((p) => p.destroy());\n map.clear();\n });\n scopeProxyMaps.clear();\n\n globalListeners.clear();\n globalProxyMap.forEach((p) => p.destroy());\n globalProxyMap.clear();\n },\n };\n}\n","/* ------------------------------------------------------------------ */\n/* enumEntries – iterate over enum-keyed Records with strong typing */\n/* ------------------------------------------------------------------ */\n\ntype EnumKey = string | number;\n\n/**\n * Iterate over a Record whose keys are enum members (numeric or string),\n * getting back a fully-typed `[key, value]` tuple array.\n *\n * Usage:\n * for (const [subtype, defaults] of enumEntries(this.state.toolDefaults)) {\n * // subtype is inferred as keyof ToolDefaultsBySubtype\n * }\n */\nexport function enumEntries<E extends EnumKey, V>(record: Record<E, V>): Array<[E, V]> {\n // Tell TS the values are V (not unknown) *before* we map.\n return (Object.entries(record) as [string, V][]).map(([k, v]) => {\n // Numeric enums come out of Object.entries as \"0\", \"1\", … → convert.\n const maybeNum = Number(k);\n const typedKey: E =\n Number.isFinite(maybeNum) && k.trim() !== '' // looks like a number?\n ? (maybeNum as unknown as E) // numeric enum key\n : (k as unknown as E); // string enum key\n\n return [typedKey, v]; // v is already typed as V\n });\n}\n","import { CoreState, DocumentState } from './initial-state';\n\n/**\n * Get the active document state\n */\nexport const getActiveDocumentState = (state: CoreState): DocumentState | null => {\n if (!state.activeDocumentId) return null;\n return state.documents[state.activeDocumentId] ?? null;\n};\n\n/**\n * Get document state by ID\n */\nexport const getDocumentState = (state: CoreState, documentId: string): DocumentState | null => {\n return state.documents[documentId] ?? null;\n};\n\n/**\n * Get all document IDs\n */\nexport const getDocumentIds = (state: CoreState): string[] => {\n return Object.keys(state.documents);\n};\n\n/**\n * Check if a document is loaded\n */\nexport const isDocumentLoaded = (state: CoreState, documentId: string): boolean => {\n return !!state.documents[documentId];\n};\n\n/**\n * Get the number of open documents\n */\nexport const getDocumentCount = (state: CoreState): number => {\n return Object.keys(state.documents).length;\n};\n","import { PluginRegistry } from '../registry/plugin-registry';\nimport { Logger, PdfEngine, Rotation } from '@embedpdf/models';\nimport { Action, Reducer } from '../store/types';\nimport { CoreState } from '../store';\n\nexport interface IPlugin<TConfig = unknown> {\n id: string;\n\n initialize?(config: TConfig): Promise<void>;\n destroy?(): Promise<void> | void;\n provides?(): any;\n postInitialize?(): Promise<void>;\n ready?(): Promise<void>;\n}\n\nexport interface BasePluginConfig {\n // Base interface for plugin configs - extend with plugin-specific options\n}\n\nexport interface PluginRegistryConfig {\n defaultRotation?: Rotation;\n defaultScale?: number;\n logger?: Logger;\n}\n\nexport interface PluginManifest<TConfig = unknown> {\n id: string;\n name: string;\n version: string;\n provides: string[]; // Capabilities this plugin provides\n requires: string[]; // Mandatory capabilities\n optional: string[]; // Optional capabilities\n defaultConfig: TConfig; // Default configuration\n metadata?: {\n description?: string;\n author?: string;\n homepage?: string;\n [key: string]: unknown;\n };\n}\n\nexport interface PluginPackage<\n T extends IPlugin<TConfig>,\n TConfig = unknown,\n TState = unknown,\n TAction extends Action = Action,\n> {\n manifest: PluginManifest<TConfig>;\n create(registry: PluginRegistry, config: TConfig): T;\n reducer: Reducer<TState, TAction>;\n initialState: TState | ((coreState: CoreState, config: TConfig) => TState);\n}\n\nexport type Component = any;\n\n// Use semantic names that describe PURPOSE, not implementation\nexport type StandaloneComponent = Component; // Doesn't wrap content\nexport type ContainerComponent = Component; // Wraps/contains content\n\nexport type AutoMountElement =\n | {\n component: StandaloneComponent;\n type: 'utility';\n }\n | {\n component: ContainerComponent;\n type: 'wrapper';\n };\n\nexport type WithAutoMount<T extends PluginPackage<any, any, any, any>> = T & {\n /**\n * Returns an array of components/elements with their mount type.\n * - 'utility': Mounted as hidden DOM elements (file pickers, download anchors)\n * - 'wrapper': Wraps the viewer content (fullscreen providers, theme providers)\n */\n autoMountElements: () => AutoMountElement[];\n};\n\nexport function hasAutoMountElements<T extends PluginPackage<any, any, any, any>>(\n pkg: T,\n): pkg is WithAutoMount<T> {\n return 'autoMountElements' in pkg && typeof pkg.autoMountElements === 'function';\n}\n\nexport type PluginStatus =\n | 'registered' // Plugin is registered but not initialized\n | 'active' // Plugin is initialized and running\n | 'error' // Plugin encountered an error\n | 'disabled' // Plugin is temporarily disabled\n | 'unregistered'; // Plugin is being unregistered\n\nexport interface PluginBatchRegistration<\n T extends IPlugin<TConfig>,\n TConfig = unknown,\n TState = unknown,\n TAction extends Action = Action,\n> {\n package: PluginPackage<T, TConfig, TState, TAction>;\n config?: Partial<TConfig>;\n}\n\nexport type PluginBatchRegistrations = PluginBatchRegistration<IPlugin<any>, any>[];\n\nexport interface GlobalStoreState<TPlugins extends Record<string, any> = {}> {\n core: CoreState;\n plugins: TPlugins;\n}\n"],"names":["DependencyResolver","constructor","this","dependencyGraph","Map","addNode","id","dependencies","set","Set","hasCircularDependencies","visited","recursionStack","dfs","add","get","dep","has","delete","keys","resolveLoadOrder","Error","result","temp","visit","push","PluginRegistrationError","message","super","name","PluginNotFoundError","CircularDependencyError","CapabilityNotFoundError","CapabilityConflictError","PluginInitializationError","PluginConfigurationError","PluginStore","store","pluginId","getState","plugins","dispatch","action","dispatchToPlugin","subscribeToState","listener","subscribeToPlugin","newPluginState","oldPluginState","onAction","type","handler","state","oldState","START_LOADING_DOCUMENT","UPDATE_DOCUMENT_LOADING_PROGRESS","SET_DOCUMENT_LOADED","SET_DOCUMENT_ERROR","RETRY_LOADING_DOCUMENT","CLOSE_DOCUMENT","SET_ACTIVE_DOCUMENT","REORDER_DOCUMENTS","MOVE_DOCUMENT","REFRESH_DOCUMENT","REFRESH_PAGES","SET_PAGES","SET_SCALE","SET_ROTATION","SET_DEFAULT_SCALE","SET_DEFAULT_ROTATION","CORE_ACTION_TYPES","Store","reducer","initialCoreState","pluginReducers","listeners","pluginListeners","isDispatching","core","coreReducer","addPluginReducer","initialState","dispatchToCore","forEach","currentState","notifyGlobal","oldGlobalState","currentGlobalState","currentPluginState","isCoreAction","subscribe","filter","l","length","newState","getPluginStore","includes","destroy","_b","_a","splice","call","config","documents","documentOrder","activeDocumentId","defaultScale","defaultRotation","Rotation","Degree0","calculateNextActiveDocument","closingDocumentId","explicitNext","currentActiveId","closingIndex","indexOf","documentId","scale","rotation","passwordProvided","autoActivate","payload","newDocState","status","loadingProgress","error","document","pageRefreshVersions","loadStartedAt","Date","now","progress","docState","errorCode","errorDetails","loadedAt","nextActiveDocumentId","removed","remainingDocs","toIndex","newOrder","currentOrder","fromIndex","moveDocumentInOrder","targetId","pageIndexes","newVersions","pageIndex","EventControl","options","lastRun","handle","data","mode","debounce","throttle","timeoutId","window","clearTimeout","setTimeout","wait","throttleMode","KeyedEventControl","controls","key","String","keyExtractor","control","baseOptions","values","clear","isKeyedOptions","arePropsEqual","a","b","aType","pairId","objectId","getPairId","aIsArray","Array","isArray","bIsArray","used","fill","outer","i","elemA","j","arraysEqualUnordered","aKeys","Object","sort","bKeys","objectsEqual","objectIdCounter","objectIds","WeakMap","obj","PluginPackageBuilder","basePackage","autoMountElements","package","addUtility","component","addWrapper","build","registry","cooldownActions","debouncedTimeouts","unsubscribeFromState","unsubscribeFromCoreStore","unsubscribeFromStartLoadingDocument","unsubscribeFromSetDocumentLoaded","unsubscribeFromCloseDocument","unsubscribeFromSetScale","unsubscribeFromSetRotation","engine","getEngine","logger","getLogger","coreStore","getStore","pluginStore","onStoreUpdated","onCoreStoreUpdated","onActiveDocumentChanged","onDocumentLoadingStarted","onDocumentLoaded","onDocumentClosed","onScaleChanged","onRotationChanged","readyPromise","Promise","resolve","readyResolve","provides","_capability","cap","buildCapability","freeze","coreState","getCoreState","dispatchCoreAction","dispatchToAllPlugins","cooldownDispatch","cooldownTime","debouncedDispatch","debounceTime","actionKey","cancelDebouncedDispatch","actionType","subscribeToCoreStore","previousId","currentId","timeout","ready","markReady","resetReady","getActiveDocumentId","getActiveDocumentIdOrNull","getCoreDocument","getCoreDocumentOrThrow","doc","manifests","capabilities","configurations","engineInitialized","initPromise","pendingRegistrations","processingRegistrations","initialized","isInitializing","pluginsReadyPromise","destroyed","resolver","NoopLogger","ensureEngineInitialized","initialize","task","toPromise","registerPlugin","pluginPackage","validateManifest","manifest","defaultConfig","pluginsReady","readyPromises","from","map","p","all","reg","dependsOn","allDeps","requires","optional","provider","find","r","loadOrder","instantiatePlugin","create","runPluginInitialization","err","packageCreator","finalConfig","validateConfig","plugin","validatePlugin","capability","debug","info","getPluginConfig","missingKeys","hasOwnProperty","join","updatePluginConfig","getPlugin","currentConfig","newConfig","registerPluginBatch","registrations","unregisterPlugin","otherId","otherManifest","entries","some","getCapabilityProvider","hasCapability","getAllPlugins","getPluginStatus","version","isDestroyed","reverse","value","min","max","initial","equality","proxyMap","_value","baseOn","realListener","ctl","wrapped","emit","v","notify","on","off","proxy","select","selector","eq","prev","mapped","next","toGlobalEvent","shouldCache","cache","scopeCaches","scopeListeners","scopeProxyMaps","globalListeners","globalProxyMap","normalizeKey","normalizedKey","cached","globalEvent","forScope","getOrCreateListeners","getOrCreateProxyMap","size","onGlobal","getValue","getScopes","clearScope","record","k","maybeNum","Number","isFinite","trim","pkg","order","pages"],"mappings":"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"}