@embedpdf/core 2.14.4 → 3.0.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +192 -21
- package/dist/index.cjs +864 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +313 -0
- package/dist/index.d.ts +313 -1
- package/dist/index.js +816 -2124
- package/dist/index.js.map +1 -1
- package/package.json +22 -52
- package/README.md +0 -40
- package/dist/lib/base/base-plugin.d.ts +0 -190
- package/dist/lib/index.d.ts +0 -17
- package/dist/lib/plugin/builder.d.ts +0 -11
- package/dist/lib/registry/plugin-registry.d.ts +0 -104
- package/dist/lib/store/actions.d.ts +0 -154
- package/dist/lib/store/index.d.ts +0 -6
- package/dist/lib/store/initial-state.d.ts +0 -31
- package/dist/lib/store/plugin-store.d.ts +0 -48
- package/dist/lib/store/reducer-helpers.d.ts +0 -11
- package/dist/lib/store/reducer.d.ts +0 -4
- package/dist/lib/store/selectors.d.ts +0 -41
- package/dist/lib/store/store.d.ts +0 -106
- package/dist/lib/store/types.d.ts +0 -28
- package/dist/lib/types/errors.d.ts +0 -21
- package/dist/lib/types/permissions.d.ts +0 -55
- package/dist/lib/types/plugin.d.ts +0 -75
- package/dist/lib/utils/dependency-resolver.d.ts +0 -6
- package/dist/lib/utils/event-control.d.ts +0 -58
- package/dist/lib/utils/eventing.d.ts +0 -19
- package/dist/lib/utils/math.d.ts +0 -22
- package/dist/lib/utils/plugin-helpers.d.ts +0 -6
- package/dist/lib/utils/scoped-eventing.d.ts +0 -71
- package/dist/lib/utils/typed-object.d.ts +0 -12
- package/dist/preact/adapter.d.ts +0 -11
- package/dist/preact/index.cjs +0 -2
- package/dist/preact/index.cjs.map +0 -1
- package/dist/preact/index.d.ts +0 -1
- package/dist/preact/index.js +0 -323
- package/dist/preact/index.js.map +0 -1
- package/dist/react/adapter.d.ts +0 -2
- package/dist/react/index.cjs +0 -2
- package/dist/react/index.cjs.map +0 -1
- package/dist/react/index.d.ts +0 -1
- package/dist/react/index.js +0 -322
- package/dist/react/index.js.map +0 -1
- package/dist/shared/components/auto-mount.d.ts +0 -8
- package/dist/shared/components/embed-pdf.d.ts +0 -37
- package/dist/shared/components/index.d.ts +0 -1
- package/dist/shared/context.d.ts +0 -12
- package/dist/shared/hooks/index.d.ts +0 -7
- package/dist/shared/hooks/use-capability.d.ts +0 -16
- package/dist/shared/hooks/use-core-state.d.ts +0 -8
- package/dist/shared/hooks/use-document-permissions.d.ts +0 -35
- package/dist/shared/hooks/use-document-state.d.ts +0 -8
- package/dist/shared/hooks/use-plugin.d.ts +0 -16
- package/dist/shared/hooks/use-registry.d.ts +0 -6
- package/dist/shared/hooks/use-store-state.d.ts +0 -6
- package/dist/shared/index.d.ts +0 -3
- package/dist/shared-preact/components/auto-mount.d.ts +0 -8
- package/dist/shared-preact/components/embed-pdf.d.ts +0 -37
- package/dist/shared-preact/components/index.d.ts +0 -1
- package/dist/shared-preact/context.d.ts +0 -12
- package/dist/shared-preact/hooks/index.d.ts +0 -7
- package/dist/shared-preact/hooks/use-capability.d.ts +0 -16
- package/dist/shared-preact/hooks/use-core-state.d.ts +0 -8
- package/dist/shared-preact/hooks/use-document-permissions.d.ts +0 -35
- package/dist/shared-preact/hooks/use-document-state.d.ts +0 -8
- package/dist/shared-preact/hooks/use-plugin.d.ts +0 -16
- package/dist/shared-preact/hooks/use-registry.d.ts +0 -6
- package/dist/shared-preact/hooks/use-store-state.d.ts +0 -6
- package/dist/shared-preact/index.d.ts +0 -3
- package/dist/shared-react/components/auto-mount.d.ts +0 -8
- package/dist/shared-react/components/embed-pdf.d.ts +0 -37
- package/dist/shared-react/components/index.d.ts +0 -1
- package/dist/shared-react/context.d.ts +0 -12
- package/dist/shared-react/hooks/index.d.ts +0 -7
- package/dist/shared-react/hooks/use-capability.d.ts +0 -16
- package/dist/shared-react/hooks/use-core-state.d.ts +0 -8
- package/dist/shared-react/hooks/use-document-permissions.d.ts +0 -35
- package/dist/shared-react/hooks/use-document-state.d.ts +0 -8
- package/dist/shared-react/hooks/use-plugin.d.ts +0 -16
- package/dist/shared-react/hooks/use-registry.d.ts +0 -6
- package/dist/shared-react/hooks/use-store-state.d.ts +0 -6
- package/dist/shared-react/index.d.ts +0 -3
- package/dist/svelte/components/AutoMount.svelte.d.ts +0 -9
- package/dist/svelte/components/EmbedPDF.svelte.d.ts +0 -40
- package/dist/svelte/components/NestedWrapper.svelte.d.ts +0 -10
- package/dist/svelte/components/index.d.ts +0 -1
- package/dist/svelte/hooks/index.d.ts +0 -6
- package/dist/svelte/hooks/use-capability.svelte.d.ts +0 -14
- package/dist/svelte/hooks/use-core-state.svelte.d.ts +0 -9
- package/dist/svelte/hooks/use-document-permissions.svelte.d.ts +0 -35
- package/dist/svelte/hooks/use-document-state.svelte.d.ts +0 -9
- package/dist/svelte/hooks/use-plugin.svelte.d.ts +0 -14
- package/dist/svelte/hooks/use-registry.svelte.d.ts +0 -17
- package/dist/svelte/index.cjs +0 -2
- package/dist/svelte/index.cjs.map +0 -1
- package/dist/svelte/index.d.ts +0 -2
- package/dist/svelte/index.js +0 -430
- package/dist/svelte/index.js.map +0 -1
- package/dist/vue/components/auto-mount.vue.d.ts +0 -19
- package/dist/vue/components/embed-pdf.vue.d.ts +0 -104
- package/dist/vue/components/index.d.ts +0 -1
- package/dist/vue/components/nested-wrapper.vue.d.ts +0 -19
- package/dist/vue/composables/index.d.ts +0 -7
- package/dist/vue/composables/use-capability.d.ts +0 -15
- package/dist/vue/composables/use-core-state.d.ts +0 -9
- package/dist/vue/composables/use-document-permissions.d.ts +0 -36
- package/dist/vue/composables/use-document-state.d.ts +0 -8
- package/dist/vue/composables/use-plugin.d.ts +0 -8
- package/dist/vue/composables/use-registry.d.ts +0 -1
- package/dist/vue/composables/use-store-state.d.ts +0 -10
- package/dist/vue/context.d.ts +0 -13
- package/dist/vue/index.cjs +0 -2
- package/dist/vue/index.cjs.map +0 -1
- package/dist/vue/index.d.ts +0 -2
- package/dist/vue/index.js +0 -384
- package/dist/vue/index.js.map +0 -1
package/dist/index.cjs.map
CHANGED
|
@@ -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/types/permissions.ts","../src/lib/store/selectors.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/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';\nimport { PermissionConfig } from '../types/permissions';\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// Security actions\nexport const UPDATE_DOCUMENT_SECURITY = 'UPDATE_DOCUMENT_SECURITY';\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 UPDATE_DOCUMENT_SECURITY,\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 permissions?: PermissionConfig; // Per-document permission overrides\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// Security Actions\n// ─────────────────────────────────────────────────────────\n\nexport interface UpdateDocumentSecurityAction {\n type: typeof UPDATE_DOCUMENT_SECURITY;\n payload: {\n documentId: string;\n permissions: number;\n isOwnerUnlocked: boolean;\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 | UpdateDocumentSecurityAction;\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 permissions?: PermissionConfig,\n): CoreAction => ({\n type: START_LOADING_DOCUMENT,\n payload: { documentId, name, scale, rotation, passwordProvided, autoActivate, permissions },\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\nexport const updateDocumentSecurity = (\n documentId: string,\n permissions: number,\n isOwnerUnlocked: boolean,\n): CoreAction => ({\n type: UPDATE_DOCUMENT_SECURITY,\n payload: { documentId, permissions, isOwnerUnlocked },\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';\nimport { PermissionConfig } from '../types/permissions';\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 // Per-document permission overrides (optional)\n permissions?: PermissionConfig;\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 /** Global permission configuration applied to all documents unless overridden per-document */\n globalPermissions?: PermissionConfig;\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 globalPermissions: config?.permissions,\n});\n","import { PdfPermissionFlag } from '@embedpdf/models';\n\n/**\n * Human-readable permission names for use in configuration.\n */\nexport type PermissionName =\n | 'print'\n | 'modifyContents'\n | 'copyContents'\n | 'modifyAnnotations'\n | 'fillForms'\n | 'extractForAccessibility'\n | 'assembleDocument'\n | 'printHighQuality';\n\n/**\n * Map from human-readable names to PdfPermissionFlag values.\n */\nexport const PERMISSION_NAME_TO_FLAG: Record<PermissionName, PdfPermissionFlag> = {\n print: PdfPermissionFlag.Print,\n modifyContents: PdfPermissionFlag.ModifyContents,\n copyContents: PdfPermissionFlag.CopyContents,\n modifyAnnotations: PdfPermissionFlag.ModifyAnnotations,\n fillForms: PdfPermissionFlag.FillForms,\n extractForAccessibility: PdfPermissionFlag.ExtractForAccessibility,\n assembleDocument: PdfPermissionFlag.AssembleDocument,\n printHighQuality: PdfPermissionFlag.PrintHighQuality,\n};\n\n/**\n * Permission overrides can use either numeric flags or human-readable string names.\n */\nexport type PermissionOverrides = Partial<\n Record<PdfPermissionFlag, boolean> & Record<PermissionName, boolean>\n>;\n\n/**\n * Configuration for overriding document permissions.\n * Can be applied globally (at PluginRegistry level) or per-document (when opening).\n */\nexport interface PermissionConfig {\n /**\n * When true (default): use PDF's permissions as the base, then apply overrides.\n * When false: treat document as having all permissions allowed, then apply overrides.\n */\n enforceDocumentPermissions?: boolean;\n\n /**\n * Explicit per-flag overrides. Supports both numeric flags and string names.\n * - true = force allow (even if PDF denies)\n * - false = force deny (even if PDF allows)\n * - undefined = use base permissions\n *\n * @example\n * // Using string names (recommended)\n * overrides: { print: false, modifyAnnotations: true }\n *\n * @example\n * // Using numeric flags\n * overrides: { [PdfPermissionFlag.Print]: false }\n */\n overrides?: PermissionOverrides;\n}\n\n/**\n * All permission flags for iteration when computing effective permissions.\n */\nexport const ALL_PERMISSION_FLAGS: PdfPermissionFlag[] = [\n PdfPermissionFlag.Print,\n PdfPermissionFlag.ModifyContents,\n PdfPermissionFlag.CopyContents,\n PdfPermissionFlag.ModifyAnnotations,\n PdfPermissionFlag.FillForms,\n PdfPermissionFlag.ExtractForAccessibility,\n PdfPermissionFlag.AssembleDocument,\n PdfPermissionFlag.PrintHighQuality,\n];\n\n/**\n * All permission names for iteration.\n */\nexport const ALL_PERMISSION_NAMES: PermissionName[] = [\n 'print',\n 'modifyContents',\n 'copyContents',\n 'modifyAnnotations',\n 'fillForms',\n 'extractForAccessibility',\n 'assembleDocument',\n 'printHighQuality',\n];\n\n/**\n * Map from PdfPermissionFlag to human-readable name.\n */\nexport const PERMISSION_FLAG_TO_NAME: Record<PdfPermissionFlag, PermissionName> = {\n [PdfPermissionFlag.Print]: 'print',\n [PdfPermissionFlag.ModifyContents]: 'modifyContents',\n [PdfPermissionFlag.CopyContents]: 'copyContents',\n [PdfPermissionFlag.ModifyAnnotations]: 'modifyAnnotations',\n [PdfPermissionFlag.FillForms]: 'fillForms',\n [PdfPermissionFlag.ExtractForAccessibility]: 'extractForAccessibility',\n [PdfPermissionFlag.AssembleDocument]: 'assembleDocument',\n [PdfPermissionFlag.PrintHighQuality]: 'printHighQuality',\n};\n\n/**\n * Helper to get the override value for a permission flag, checking both numeric and string keys.\n */\nexport function getPermissionOverride(\n overrides: PermissionOverrides | undefined,\n flag: PdfPermissionFlag,\n): boolean | undefined {\n if (!overrides) return undefined;\n\n // Check numeric key first\n if (flag in overrides) {\n return (overrides as Record<PdfPermissionFlag, boolean>)[flag];\n }\n\n // Check string key\n const name = PERMISSION_FLAG_TO_NAME[flag];\n if (name && name in overrides) {\n return (overrides as Record<PermissionName, boolean>)[name];\n }\n\n return undefined;\n}\n","import { PdfPermissionFlag } from '@embedpdf/models';\nimport { CoreState, DocumentState } from './initial-state';\nimport { ALL_PERMISSION_FLAGS, getPermissionOverride } from '../types/permissions';\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\n// ─────────────────────────────────────────────────────────\n// Permission Selectors\n// ─────────────────────────────────────────────────────────\n\n/**\n * Check if a specific permission flag is effectively allowed for a document.\n * Applies layered resolution: per-document override → global override → enforceDocumentPermissions → PDF permission.\n *\n * @param state - The core state\n * @param documentId - The document ID to check permissions for\n * @param flag - The permission flag to check\n * @returns true if the permission is allowed, false otherwise\n */\nexport function getEffectivePermission(\n state: CoreState,\n documentId: string,\n flag: PdfPermissionFlag,\n): boolean {\n const docState = state.documents[documentId];\n const docConfig = docState?.permissions;\n const globalConfig = state.globalPermissions;\n const pdfPermissions = docState?.document?.permissions ?? PdfPermissionFlag.AllowAll;\n\n // 1. Per-document override wins (supports both numeric and string keys)\n const docOverride = getPermissionOverride(docConfig?.overrides, flag);\n if (docOverride !== undefined) {\n return docOverride;\n }\n\n // 2. Global override (supports both numeric and string keys)\n const globalOverride = getPermissionOverride(globalConfig?.overrides, flag);\n if (globalOverride !== undefined) {\n return globalOverride;\n }\n\n // 3. Check enforce setting (per-doc takes precedence over global)\n const enforce =\n docConfig?.enforceDocumentPermissions ?? globalConfig?.enforceDocumentPermissions ?? true;\n\n if (!enforce) return true; // Not enforcing = allow all\n\n // 4. Use PDF permission\n return (pdfPermissions & flag) !== 0;\n}\n\n/**\n * Get all effective permissions as a bitmask for a document.\n * Combines all individual permission checks into a single bitmask.\n *\n * @param state - The core state\n * @param documentId - The document ID to get permissions for\n * @returns A bitmask of all effective permissions\n */\nexport function getEffectivePermissions(state: CoreState, documentId: string): number {\n return ALL_PERMISSION_FLAGS.reduce((acc, flag) => {\n return getEffectivePermission(state, documentId, flag) ? acc | flag : acc;\n }, 0);\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 UPDATE_DOCUMENT_SECURITY,\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 permissions,\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 permissions,\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 case UPDATE_DOCUMENT_SECURITY: {\n const { documentId, permissions, isOwnerUnlocked } = action.payload;\n const docState = state.documents[documentId];\n\n if (!docState?.document) return state;\n\n return {\n ...state,\n documents: {\n ...state.documents,\n [documentId]: {\n ...docState,\n document: {\n ...docState.document,\n permissions,\n isOwnerUnlocked,\n },\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, PdfPermissionFlag, PermissionDeniedError } from '@embedpdf/models';\nimport { DocumentState } from '../store/initial-state';\nimport { getEffectivePermission, getEffectivePermissions } from '../store/selectors';\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 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 // ─────────────────────────────────────────────────────────\n // Permission Helpers\n // ─────────────────────────────────────────────────────────\n\n /**\n * Get the effective permission flags for a document.\n * Applies layered resolution: per-document override → global override → PDF permission.\n * Returns AllowAll if document not found.\n * @param documentId Document ID (optional, defaults to active document)\n */\n protected getDocumentPermissions(documentId?: string): number {\n const docId = documentId ?? this.coreState.core.activeDocumentId;\n if (!docId) return PdfPermissionFlag.AllowAll;\n\n return getEffectivePermissions(this.coreState.core, docId);\n }\n\n /**\n * Check if a document has the required permissions (returns boolean).\n * Applies layered resolution: per-document override → global override → PDF permission.\n * Useful for conditional UI logic.\n * @param documentId Document ID (optional, defaults to active document)\n * @param flags Permission flags to check\n */\n protected checkPermission(\n documentId: string | undefined,\n ...flags: PdfPermissionFlag[]\n ): boolean {\n const docId = documentId ?? this.coreState.core.activeDocumentId;\n if (!docId) return true;\n\n return flags.every((flag) => getEffectivePermission(this.coreState.core, docId, flag));\n }\n\n /**\n * Assert that a document has the required permissions.\n * Applies layered resolution: per-document override → global override → PDF permission.\n * Throws PermissionDeniedError if any flag is missing.\n * @param documentId Document ID (optional, defaults to active document)\n * @param flags Permission flags to require\n */\n protected requirePermission(documentId: string | undefined, ...flags: PdfPermissionFlag[]): void {\n const docId = documentId ?? this.coreState.core.activeDocumentId;\n if (!docId) return;\n\n const missingFlags: PdfPermissionFlag[] = [];\n\n for (const flag of flags) {\n if (!getEffectivePermission(this.coreState.core, docId, flag)) {\n missingFlags.push(flag);\n }\n }\n\n if (missingFlags.length > 0) {\n const effectivePermissions = getEffectivePermissions(this.coreState.core, docId);\n throw new PermissionDeniedError(missingFlags, effectivePermissions);\n }\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 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 * 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 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 { PluginRegistry } from '../registry/plugin-registry';\nimport { Logger, PdfEngine, Rotation } from '@embedpdf/models';\nimport { Action, Reducer } from '../store/types';\nimport { CoreState } from '../store';\nimport { PermissionConfig } from './permissions';\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 * Global permission configuration.\n * Applied to all documents unless overridden per-document.\n */\n permissions?: PermissionConfig;\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","UPDATE_DOCUMENT_SECURITY","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","globalPermissions","permissions","PERMISSION_NAME_TO_FLAG","print","PdfPermissionFlag","Print","modifyContents","ModifyContents","copyContents","CopyContents","modifyAnnotations","ModifyAnnotations","fillForms","FillForms","extractForAccessibility","ExtractForAccessibility","assembleDocument","AssembleDocument","printHighQuality","PrintHighQuality","ALL_PERMISSION_FLAGS","PERMISSION_FLAG_TO_NAME","getPermissionOverride","overrides","flag","getEffectivePermission","documentId","docState","docConfig","globalConfig","pdfPermissions","document","AllowAll","docOverride","globalOverride","enforceDocumentPermissions","getEffectivePermissions","reduce","acc","calculateNextActiveDocument","closingDocumentId","explicitNext","currentActiveId","closingIndex","indexOf","scale","rotation","passwordProvided","autoActivate","payload","newDocState","status","loadingProgress","error","pageRefreshVersions","loadStartedAt","Date","now","progress","errorCode","errorDetails","loadedAt","nextActiveDocumentId","removed","remainingDocs","toIndex","newOrder","currentOrder","fromIndex","moveDocumentInOrder","targetId","pageIndexes","newVersions","pageIndex","isOwnerUnlocked","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","getDocumentPermissions","docId","checkPermission","flags","every","requirePermission","missingFlags","effectivePermissions","PermissionDeniedError","manifests","capabilities","configurations","initPromise","pendingRegistrations","processingRegistrations","initialized","isInitializing","pluginsReadyPromise","destroyed","resolver","NoopLogger","registerPlugin","pluginPackage","validateManifest","manifest","defaultConfig","pluginsReady","initialize","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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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["CONTINUOUS_RENDER_POLICY"],"sources":["../src/types.ts","../src/store.ts","../src/context.ts","../src/order.ts","../src/scope.ts","../src/kernel.ts","../src/index.ts"],"sourcesContent":["/**\n * @embedpdf/core — core contracts.\n *\n * Framework-free and serializable. The engine boundary is the REAL one:\n * `@embedpdf/engine-core`'s `Engine`/`DocumentHandle` — implemented identically by\n * local-wasm (`@embedpdf/engine`), cloud (`@cloudpdf/engine`), and the test fake.\n * The kernel adds *document scope*: plugins declare a scope and the kernel\n * multiplexes document-scoped plugins per document.\n */\nimport type {\n DocumentHandle,\n Engine,\n EngineFactory,\n OpenInput,\n OpenOptions,\n PageLayout,\n PageObjectNumber,\n PageRotation,\n PageRotateResult,\n PageMoveResult,\n PageDeleteResult,\n DocCapability,\n PdfSaveMode,\n DocumentMetadata,\n MetadataPatch,\n MetadataUpdateResult,\n DocumentEvent,\n EngineRenderPolicy,\n PdfDestination,\n} from '@embedpdf/engine-core/runtime';\n\n// re-export the engine contracts so consumers import them from @embedpdf/core\nexport type {\n DocumentHandle,\n Engine,\n EngineFactory,\n OpenInput,\n OpenOptions,\n PageLayout,\n PdfDestination,\n PageObjectNumber,\n PageRotation,\n PageRotateResult,\n PageMoveResult,\n PageDeleteResult,\n DocCapability,\n PdfSaveMode,\n DocumentMetadata,\n MetadataPatch,\n MetadataUpdateResult,\n DocumentEvent,\n};\n\nexport type Unsubscribe = () => void;\n\n/** Every state transition is a plain, serializable action. */\nexport interface Action {\n readonly type: string;\n}\n\n/** Kernel-emitted document-lifecycle actions; plugins may react via `onAction`. */\nexport const CORE_DOCUMENT_ADDED = '@@core/document-added';\nexport const CORE_DOCUMENT_REMOVED = '@@core/document-removed';\nexport const CORE_ACTIVE_CHANGED = '@@core/active-changed';\nexport const CORE_ORDER_CHANGED = '@@core/order-changed';\n/** A document's page registry was replaced by a mutation event (rotate/move/delete). */\nexport const CORE_DOCUMENT_PAGES_UPDATED = '@@core/document-pages-updated';\n/** A tab slot was reserved: `open()` was called; the document is loading. */\nexport const CORE_DOCUMENT_OPENING = '@@core/document-opening';\n/** The engine reports the document needs a password (`documents.unlock`). */\nexport const CORE_DOCUMENT_LOCKED = '@@core/document-locked';\n/** The open failed; the tab stays with `status: 'error'` until closed. */\nexport const CORE_DOCUMENT_OPEN_FAILED = '@@core/document-open-failed';\n\n/** A typed handle to a capability — typed resolution, no string casts. */\nexport interface CapabilityToken<T> {\n readonly name: string;\n /** phantom — never present at runtime */\n readonly __type?: T;\n}\n\n/**\n * What the kernel knows about an open document — the page registry captured at open.\n * `pages` is the engine's own snapshot (`PageLayout`: index, pageObjectNumber, size,\n * rotation, label, boxes). The `pageObjectNumber` (pon) is the durable per-page\n * identity; the array index is only display order.\n */\nexport interface DocumentMeta {\n readonly id: string;\n readonly name?: string;\n readonly pageCount: number;\n readonly pages: readonly PageLayout[];\n /**\n * Bumps every time the page registry is replaced by a document mutation\n * event (rotate/move/delete). The registry's monotonic version: anything\n * caching a derivation of `pages` (e.g. the Stage's laid-out scene) keys\n * on it so a same-`pageCount` change — like a rotation — still invalidates.\n */\n readonly revision: number;\n /**\n * The deployment render policy the document's engine advertises — a\n * document FACT like `pages`, materialized by the kernel at open (before\n * publish), NOT plugin state. One lifecycle (here), one interpretation\n * (engine-core's pure `snap*` helpers); any plugin reads it. Engines\n * without a render service — and failed policy reads — resolve to\n * `continuous`, so consumers never branch on absence. Naming rule: the\n * domain appears exactly once — bare `policy()` on the render SERVICE,\n * `renderPolicy` on flat envelopes like this one and `/v1/access`.\n */\n readonly renderPolicy: EngineRenderPolicy;\n}\n\n/**\n * A tab slot whose document is not (yet) real: still opening, waiting for a\n * password, or failed. Lives beside `documents`, never inside it — plugins\n * only ever see READY documents; pending slots are pure registry/UI state.\n * Request-time lifecycle: `open()` reserves the slot (id, order position,\n * activation) synchronously; only the content arrives at completion time.\n */\nexport interface PendingMeta {\n readonly id: string;\n readonly name?: string;\n readonly status: 'loading' | 'locked' | 'error';\n /** `locked` only: a password was supplied at open and rejected — the\n * prompt should show its \"incorrect password\" copy, not \"required\". */\n readonly passwordProvided?: boolean;\n /** `error` only: what the open rejected with. Never carries a password. */\n readonly error?: unknown;\n}\n\n/** The document registry — what document scope is built on. */\nexport interface CoreState {\n readonly documents: Readonly<Record<string, DocumentMeta>>;\n readonly pending: Readonly<Record<string, PendingMeta>>;\n /** THE tab strip: spans ready docs and pending slots, in request order. */\n readonly order: readonly string[];\n /** May point at a pending slot (a loading or locked tab can be selected). */\n readonly activeId: string | null;\n}\n\nexport interface GlobalState {\n readonly core: CoreState;\n readonly plugins: Readonly<Record<string, unknown>>;\n}\n\nexport type PluginScope = 'workspace' | 'document';\n\n/**\n * The context a plugin receives. Document-scoped plugins get a context bound to a\n * single document — `documentId`, `document()` (metadata), `doc` (the engine handle),\n * and `get()` resolving document-scoped capabilities for it.\n */\nexport interface PluginContext<S, A extends Action = Action> {\n readonly id: string;\n readonly engine: Engine;\n /** The bound document (document-scoped plugins only; undefined for workspace). */\n readonly documentId?: string;\n /** The bound document's engine handle; for workspace plugins, the active doc's handle, or null. */\n readonly doc: DocumentHandle | null;\n /** Resolve a live engine handle by document id; omitted follows this context's normal active/bound rule. */\n documentHandle(documentId?: string): DocumentHandle | null;\n getState(): S;\n dispatch(action: A): void;\n subscribe(listener: () => void): Unsubscribe;\n core(): CoreState;\n /** The bound document's metadata; for workspace plugins, the active doc's, or null. */\n document(): DocumentMeta | null;\n get<T>(token: CapabilityToken<T>): T;\n forDocument<T>(token: CapabilityToken<T>, documentId: string): T;\n tryGet<T>(token: CapabilityToken<T>): T | null;\n /**\n * Register a resource teardown owned by this plugin instance. Document-\n * scoped callbacks run when that document closes; workspace callbacks run\n * when the kernel is destroyed. Asynchronous teardowns are awaited.\n * Registering after the owner is already disposed runs the teardown\n * immediately instead of dropping it — a late registration cannot leak.\n * Safe for capability-held timers, runtimes, subscriptions, object URLs,\n * and binary caches.\n */\n cleanup(fn: () => void | Promise<void>): void;\n}\n\n/** Side-effect context: the only place async/IO/cross-plugin reactions live. */\nexport interface EffectContext<S, A extends Action = Action> extends PluginContext<S, A> {\n watch<R>(\n select: () => R,\n handler: (value: R, previous: R) => void,\n isEqual?: (a: R, b: R) => boolean,\n ): Unsubscribe;\n onAction(type: string, handler: (action: Action) => void): Unsubscribe;\n}\n\n/**\n * A plugin definition. `scope` decides multiplexing:\n * 'workspace' (default) — one instance; can see every document.\n * 'document' — one instance PER open document; authored single-document.\n */\nexport interface PluginDef<S = unknown, A extends Action = Action, C = unknown> {\n readonly id: string;\n readonly token?: CapabilityToken<C>;\n readonly scope?: PluginScope;\n readonly requires?: ReadonlyArray<CapabilityToken<unknown>>;\n readonly optional?: ReadonlyArray<CapabilityToken<unknown>>;\n readonly initialState?: S | (() => S);\n readonly reduce?: (state: S, action: A) => S;\n readonly capability?: (ctx: PluginContext<S, A>) => C;\n readonly init?: (ctx: PluginContext<S, A>) => void | Promise<void>;\n readonly effects?: (ctx: EffectContext<S, A>) => void;\n}\n\nexport type AnyPlugin = PluginDef<any, any, any>;\n\n// ── Built-in: the document registry, exposed as a capability ─────────────────\n\nexport type DocStatus = 'loading' | 'locked' | 'ready' | 'error';\n\nexport interface DocInfo {\n id: string;\n name?: string;\n /** Lifecycle state — the tab bar renders directly off this. */\n status: DocStatus;\n /** 0 until the document is `ready`. */\n pageCount: number;\n /** `locked` only: a supplied password was rejected (show \"incorrect\"). */\n passwordProvided?: boolean;\n}\n\n/** Field-wise DocInfo equality — the ONE definition every adapter's reactive\n * `docs` read keys on, so a new lifecycle field can never silently stop\n * re-rendering one framework's tab bar. */\nexport const docInfoEquals = (a: DocInfo, b: DocInfo): boolean =>\n a.id === b.id &&\n a.name === b.name &&\n a.status === b.status &&\n a.pageCount === b.pageCount &&\n a.passwordProvided === b.passwordProvided;\n\nexport const docInfoListEquals = (a: readonly DocInfo[], b: readonly DocInfo[]): boolean =>\n a === b || (a.length === b.length && a.every((d, i) => docInfoEquals(d, b[i])));\n\n/** Options for opening a document: kernel concerns (activate/name) + engine OpenOptions. */\nexport type OpenDocumentOptions = OpenOptions & { activate?: boolean; name?: string };\n\n/**\n * What `open()` accepts: an engine `OpenInput`, or a thunk producing one.\n * The thunk form makes the FETCH happen under the loading tab — the slot is\n * reserved synchronously, then the thunk runs (network), then the engine\n * opens. Prefer it for anything that isn't already in memory.\n *\n * The thunk receives an AbortSignal that fires if the tab is closed while\n * the fetch is still running — pass it to `fetch()` so a closed tab stops\n * the network work. Zero-argument thunks keep working unchanged.\n */\nexport type OpenSource = OpenInput | ((signal: AbortSignal) => OpenInput | Promise<OpenInput>);\n\n/**\n * One boot document for `documents.openAll()` — THE shared shape every\n * framework adapter's `initialDocuments` input uses (adapters re-export it,\n * never redefine it). `active` picks the selected tab (default: the first);\n * all other open options (name, password, scope, identity, …) pass straight\n * through to `open()`, so the declarative and imperative paths cannot drift.\n */\nexport type InitialDocument = { source: OpenSource; active?: boolean } & Omit<\n OpenDocumentOptions,\n 'activate'\n>;\n\nexport interface DocumentsCapability {\n open(input: OpenSource, options?: OpenDocumentOptions): Promise<string>;\n /**\n * Boot-open a batch: fires every `open()` WITHOUT awaiting, so each tab\n * slot is reserved synchronously — all tabs exist immediately, in array\n * order — and exactly ONE is selected (the `active` entry, else the\n * first), decided at request time so a slow document can never steal\n * focus. Failures surface as the tab's `error`/`locked` status, never as\n * unhandled rejections. This is kernel-owned POLICY: adapters call this\n * one line instead of each re-implementing activation and error handling.\n */\n openAll(docs: readonly InitialDocument[]): void;\n /**\n * Unlock a `locked` document with a password and promote it to `ready`.\n * Rejects with the engine's DocPasswordIncorrect on a wrong password —\n * the document stays locked and unlock can be called again. Identical\n * behavior on the local (worker loads the parked bytes) and cloud\n * (/access grant) engines.\n */\n unlock(id: string, input: { password: string }): Promise<void>;\n close(id: string): Promise<void>;\n closeAll(): Promise<void>;\n setActive(id: string): void;\n activeId(): string | null;\n list(): DocInfo[];\n get(id: string): DocInfo | null;\n has(id: string): boolean;\n count(): number;\n order(): string[];\n /** Move a document (tab) to a new position in the order. */\n move(id: string, toIndex: number): void;\n /** Swap two documents (tabs) in the order. */\n swap(a: string, b: string): void;\n /**\n * Save the COMPLETE document (base + layer) to PDF bytes. `mode` is\n * `'incremental'` (append changes, original bytes preserved) or `'rewrite'`\n * (flatten to a fresh PDF). Defaults to the active document.\n */\n download(id?: string, opts?: { mode?: PdfSaveMode }): Promise<Uint8Array>;\n /**\n * Export JUST the document's LAYER artifact (re-openable via `OpenInputLayerBytes`).\n * Rejects when the document was opened without a layer, or the engine can't\n * export one (cloud manages layers server-side — `DocumentHandle.downloadLayer`\n * is absent there). Defaults to the active document.\n */\n downloadLayer(id?: string): Promise<Uint8Array>;\n}\n\n/** Built-in token for the document registry capability (provided by the kernel). */\nexport const DocumentsToken: CapabilityToken<DocumentsCapability> = { name: 'documents' };\n","import type { Action, CoreState, GlobalState, Unsubscribe } from './types';\n\n/**\n * The store: one state tree ({ core, plugins }), keyed plugin slices, and two\n * channels — `subscribe` (state changed, for reactivity/`watch`) and\n * `subscribeAction` (an action was dispatched, for `onAction`). Slice keys are\n * opaque strings; the kernel uses `pluginId` for workspace plugins and\n * `pluginId::docId` for document-scoped ones.\n *\n * Change notification is non-re-entrant: if a listener dispatches, we finish the\n * current pass and run another — keeping listener order deterministic.\n */\nexport interface Store {\n registerSlice(key: string, reducer: (s: unknown, a: Action) => unknown, initial: unknown): void;\n removeSlice(key: string): void;\n getSlice(key: string): unknown;\n getCore(): CoreState;\n getState(): GlobalState;\n dispatchTo(key: string, action: Action): void;\n setCore(patch: Partial<CoreState>, action: Action): void;\n subscribe(listener: () => void): Unsubscribe;\n subscribeAction(listener: (action: Action) => void): Unsubscribe;\n /** Kernel-destroy teardown: reset core, drop every slice/reducer/listener.\n * Reads stay legal afterwards (empty state); writes become no-ops. */\n destroy(): void;\n}\n\nexport function createStore(report: (error: unknown) => void = console.error): Store {\n let core: CoreState = { documents: {}, pending: {}, order: [], activeId: null };\n const slices: Record<string, unknown> = {};\n const reducers: Record<string, (s: unknown, a: Action) => unknown> = {};\n const changeListeners = new Set<() => void>();\n const actionListeners = new Set<(a: Action) => void>();\n\n // Per-listener isolation: one throwing subscriber (a plugin effect, a React\n // read) must never halt the pass for its siblings, and must never unwind a\n // kernel lifecycle transition out of setCore/dispatchTo mid-update.\n const guarded = (fn: () => void) => {\n try {\n fn();\n } catch (error) {\n report(error);\n }\n };\n\n let emitting = false;\n let pending = false;\n const emitChange = () => {\n if (emitting) {\n pending = true;\n return;\n }\n emitting = true;\n try {\n do {\n pending = false;\n changeListeners.forEach((listener) => guarded(listener));\n } while (pending);\n } finally {\n emitting = false;\n }\n };\n const emitAction = (action: Action) =>\n actionListeners.forEach((listener) => guarded(() => listener(action)));\n\n return {\n registerSlice(key, reducer, initial) {\n reducers[key] = reducer;\n slices[key] = initial;\n },\n removeSlice(key) {\n delete reducers[key];\n delete slices[key];\n emitChange();\n },\n getSlice: (key) => slices[key],\n getCore: () => core,\n getState: () => ({ core, plugins: slices }),\n dispatchTo(key, action) {\n const r = reducers[key];\n if (!r) return;\n const next = r(slices[key], action);\n if (next !== slices[key]) {\n slices[key] = next;\n emitChange();\n }\n emitAction(action);\n },\n setCore(patch, action) {\n core = { ...core, ...patch };\n emitChange();\n emitAction(action);\n },\n subscribe(listener) {\n changeListeners.add(listener);\n return () => void changeListeners.delete(listener);\n },\n subscribeAction(listener) {\n actionListeners.add(listener);\n return () => void actionListeners.delete(listener);\n },\n destroy() {\n core = { documents: {}, pending: {}, order: [], activeId: null };\n for (const key of Object.keys(slices)) delete slices[key];\n for (const key of Object.keys(reducers)) delete reducers[key];\n changeListeners.clear();\n actionListeners.clear();\n },\n };\n}\n","import type {\n Action,\n AnyPlugin,\n CapabilityToken,\n DocumentHandle,\n DocumentMeta,\n EffectContext,\n Engine,\n PluginContext,\n} from './types';\nimport type { Store } from './store';\nimport type { Scope } from './scope';\n\n/** A plugin's slice key. Workspace plugins use their id; document-scoped plugins are per-document. */\nexport const sliceKey = (pluginId: string, documentId?: string): string =>\n documentId ? `${pluginId}::${documentId}` : pluginId;\n\n/**\n * The slice of a DocumentSession a context needs — structural, so this module\n * has no cycle with the kernel. Holding the session OBJECT (not its id) is\n * what makes late teardown registration safe: a context created for a session\n * can always reach that session's scope, even after the session has been\n * closed and removed from the kernel's map.\n */\nexport interface SessionRef {\n id: string;\n handle: DocumentHandle | null;\n /** Meta staged during bring-up, before the document is published. */\n stagedMeta: DocumentMeta | null;\n readonly scope: Scope;\n}\n\n/**\n * Everything a context needs from the kernel, injected so this module has no cycles\n * with the capability resolver or the document lifecycle.\n */\nexport interface ContextServices {\n readonly engine: Engine;\n readonly store: Store;\n readonly workspaceScope: Scope;\n resolveCapability<T>(token: CapabilityToken<T>, documentId?: string): T;\n /** Total resolution (the kernel's internal rule: bring-up or ready) — what\n * `ctx.tryGet` delegates to. Never exception-driven: a throwing capability\n * constructor is a BUG and propagates. */\n tryResolveCapability<T>(token: CapabilityToken<T>, documentId?: string): T | null;\n documentHandle(documentId?: string): DocumentHandle | null;\n}\n\n/**\n * Build the context a plugin sees. When `session` is given the context is bound\n * to that document — `getState`/`dispatch` target its slice, `document()` returns\n * it, and `get()` resolves document-scoped capabilities for it.\n */\nexport function createPluginContext(\n services: ContextServices,\n plugin: AnyPlugin,\n session?: SessionRef,\n): PluginContext<unknown> {\n const { engine, store } = services;\n const documentId = session?.id;\n const key = sliceKey(plugin.id, documentId);\n const ownScope = session?.scope ?? services.workspaceScope;\n return {\n id: plugin.id,\n engine,\n documentId,\n doc: session ? session.handle : services.documentHandle(undefined),\n documentHandle: (requestedDocumentId) =>\n requestedDocumentId\n ? services.documentHandle(requestedDocumentId)\n : session\n ? session.handle\n : services.documentHandle(undefined),\n getState: () => store.getSlice(key),\n dispatch: (action: Action) => store.dispatchTo(key, action),\n subscribe: store.subscribe,\n core: store.getCore,\n document: () => {\n if (session) return store.getCore().documents[session.id] ?? session.stagedMeta;\n const id = store.getCore().activeId;\n return id ? (store.getCore().documents[id] ?? null) : null;\n },\n get: <T>(token: CapabilityToken<T>): T => services.resolveCapability(token, documentId),\n forDocument: <T>(token: CapabilityToken<T>, otherDocumentId: string): T =>\n services.resolveCapability(token, otherDocumentId),\n tryGet: <T>(token: CapabilityToken<T>): T | null =>\n services.tryResolveCapability(token, documentId),\n cleanup: (teardown) => ownScope.defer(teardown),\n };\n}\n\n/** A plugin context plus the side-effect primitives (watch / onAction / cleanup). */\nexport function createEffectContext(\n services: ContextServices,\n plugin: AnyPlugin,\n session?: SessionRef,\n): EffectContext<unknown> {\n const { store } = services;\n const ownScope = session?.scope ?? services.workspaceScope;\n return {\n ...createPluginContext(services, plugin, session),\n watch: (select, handler, isEqual = Object.is) => {\n let previous = select();\n const unsubscribe = store.subscribe(() => {\n const next = select();\n if (!isEqual(previous, next)) {\n const prior = previous;\n previous = next;\n handler(next, prior);\n }\n });\n ownScope.defer(unsubscribe);\n return unsubscribe;\n },\n onAction: (type, handler) => {\n const unsubscribe = store.subscribeAction((action) => {\n if (action.type === type) handler(action);\n });\n ownScope.defer(unsubscribe);\n return unsubscribe;\n },\n };\n}\n","import { DocumentsToken, type AnyPlugin, type CapabilityToken, type PluginScope } from './types';\n\n/**\n * The result of analysing a plugin list: a dependency-ordered list, plus lookups\n * for which plugin provides a token and what scope a token has. Pure and testable.\n */\nexport interface PluginPlan {\n readonly ordered: AnyPlugin[];\n providerOf(token: CapabilityToken<unknown>): AnyPlugin | undefined;\n scopeOf(token: CapabilityToken<unknown>): PluginScope;\n}\n\n/**\n * Validate `requires` (fail fast) and topologically sort plugins so dependencies\n * are initialised before dependents.\n */\nexport function planPlugins(plugins: readonly AnyPlugin[]): PluginPlan {\n const providerByToken = new Map<CapabilityToken<unknown>, AnyPlugin>();\n const scopeByToken = new Map<CapabilityToken<unknown>, PluginScope>([\n [DocumentsToken, 'workspace'],\n ]);\n\n for (const plugin of plugins) {\n if (plugin.token && plugin.capability) {\n providerByToken.set(plugin.token, plugin);\n scopeByToken.set(plugin.token, plugin.scope ?? 'workspace');\n }\n }\n\n // every required token must be provided (the documents token is always available)\n for (const plugin of plugins) {\n for (const required of plugin.requires ?? []) {\n if (required !== DocumentsToken && !providerByToken.has(required)) {\n throw new Error(\n `Plugin \"${plugin.id}\" requires capability \"${required.name}\", which no plugin provides.`,\n );\n }\n }\n }\n\n // depth-first topological sort (dependencies pushed before dependents)\n const ordered: AnyPlugin[] = [];\n const status = new Map<string, 'visiting' | 'done'>();\n const visit = (plugin: AnyPlugin) => {\n const state = status.get(plugin.id);\n if (state === 'done') return;\n if (state === 'visiting') throw new Error(`Dependency cycle involving plugin \"${plugin.id}\".`);\n status.set(plugin.id, 'visiting');\n for (const token of [...(plugin.requires ?? []), ...(plugin.optional ?? [])]) {\n const dependency = providerByToken.get(token);\n if (dependency && dependency !== plugin) visit(dependency);\n }\n status.set(plugin.id, 'done');\n ordered.push(plugin);\n };\n for (const plugin of plugins) visit(plugin);\n\n return {\n ordered,\n providerOf: (token) => providerByToken.get(token),\n scopeOf: (token) => scopeByToken.get(token) ?? 'workspace',\n };\n}\n","/**\n * Resource scope — the ownership half of the lifecycle model.\n *\n * Every resource acquisition registers its release into the owning scope AT\n * the acquisition site (`scope.defer(release)` on the line after acquiring),\n * so no exit path can forget it. `dispose()` unwinds the stack LIFO, awaits\n * asynchronous teardowns, and is idempotent — every call returns the same\n * promise.\n *\n * THE rule that deletes the silent-leak bug class: a disposed scope never\n * swallows a teardown. Registering against a scope that is already disposing\n * runs the teardown as soon as the in-flight disposal finishes, instead of\n * dropping it. (Producers are still expected to stop at their next\n * cancellation checkpoint; this rule is the safety net, not the primary\n * synchronization — that's the session's operation join.)\n */\n\nexport type Teardown = () => void | Promise<void>;\n\n/**\n * A lifecycle operation was cancelled — the tab was closed mid-open, or the\n * kernel was destroyed mid-start. NOT a failure: callers that race `open()`\n * against `close()` should treat this rejection as \"the close won\".\n */\nexport class CancelledError extends Error {\n constructor(what: string) {\n super(`[kernel] cancelled: ${what}`);\n this.name = 'CancelledError';\n }\n}\n\nexport const isCancelled = (error: unknown): error is CancelledError =>\n error instanceof CancelledError;\n\nexport interface Scope {\n readonly disposed: boolean;\n defer(teardown: Teardown): void;\n dispose(): Promise<void>;\n}\n\nexport function createScope(report: (error: unknown) => void): Scope {\n const teardowns: Teardown[] = [];\n let disposal: Promise<void> | null = null;\n\n return {\n get disposed() {\n return disposal !== null;\n },\n defer(teardown) {\n if (disposal) void disposal.then(() => Promise.resolve().then(teardown).catch(report));\n else teardowns.push(teardown);\n },\n dispose() {\n return (disposal ??= (async () => {\n while (teardowns.length) {\n try {\n await teardowns.pop()!();\n } catch (error) {\n report(error); // one failing teardown never strands the rest\n }\n }\n })());\n },\n };\n}\n","import { createStore } from './store';\nimport {\n createEffectContext,\n createPluginContext,\n sliceKey,\n type ContextServices,\n type SessionRef,\n} from './context';\nimport { planPlugins } from './order';\nimport { createScope, CancelledError, isCancelled, type Scope } from './scope';\nimport {\n CORE_ACTIVE_CHANGED,\n CORE_DOCUMENT_ADDED,\n CORE_DOCUMENT_LOCKED,\n CORE_DOCUMENT_OPENING,\n CORE_DOCUMENT_OPEN_FAILED,\n CORE_DOCUMENT_PAGES_UPDATED,\n CORE_DOCUMENT_REMOVED,\n CORE_ORDER_CHANGED,\n DocumentsToken,\n type Action,\n type AnyPlugin,\n type CapabilityToken,\n type CoreState,\n type DocInfo,\n type DocumentHandle,\n type DocumentMeta,\n type DocumentsCapability,\n type Engine,\n type GlobalState,\n type OpenDocumentOptions,\n type OpenInput,\n type OpenSource,\n type PendingMeta,\n type PluginScope,\n type Unsubscribe,\n} from './types';\nimport {\n CONTINUOUS_RENDER_POLICY,\n type DocumentEvent,\n type EngineRenderPolicy,\n} from '@embedpdf/engine-core/runtime';\n\n/** The new page registry a document mutation carries, or null for events that\n * don't change page structure (annotations, metadata). The snapshot is the\n * same shape `pages.list()` returns, so callers swap it in directly. */\nfunction layoutFromEvent(event: DocumentEvent) {\n switch (event.type) {\n case 'pages.moved':\n case 'pages.rotated':\n case 'pages.deleted':\n case 'pages.inserted':\n return event.layout;\n default:\n return null;\n }\n}\n\n/** Kernel lifecycle. Monotonic: created → starting → started, then destroying →\n * destroyed; `failed` is a terminal branch off starting. */\nexport type KernelStatus =\n | 'created'\n | 'starting'\n | 'started'\n | 'failed'\n | 'destroying'\n | 'destroyed';\n\nexport interface Kernel {\n readonly engine: Engine;\n readonly documents: DocumentsCapability;\n /** Resolve a capability. For document-scoped tokens, `documentId` defaults to the active doc. */\n capability<T>(token: CapabilityToken<T>, documentId?: string): T;\n /**\n * Total sibling of `capability()`: `null` instead of throwing — no\n * provider, no document, or a document that isn't `ready` yet. This is the\n * method adapters subscribe to (`useKernelValue`-style): resolution is a\n * VALUE derived from kernel state, not a pure function of its arguments —\n * a pending document's promotion changes the result while the id stays the\n * same, so caching a `capability()` call by id goes stale. The returned\n * instance is reference-stable per (plugin, document), so equality-cached\n * reads don't churn.\n */\n tryCapability<T>(token: CapabilityToken<T>, documentId?: string): T | null;\n /** A token's scope — adapters use this to decide whether to bind a document. */\n scopeOf(token: CapabilityToken<unknown>): PluginScope;\n subscribe(listener: () => void): Unsubscribe;\n getState(): GlobalState;\n status(): KernelStatus;\n /** Idempotent: a second call joins the first. Throws after destroy(). */\n start(): Promise<void>;\n /**\n * Idempotent: every call returns the same promise. Joins an in-flight\n * start(), closes every document (their engine handles included), then\n * unwinds workspace resources. Never throws.\n */\n destroy(): Promise<void>;\n}\n\nconst isDocumentScoped = (plugin: AnyPlugin) => plugin.scope === 'document';\nconst initialStateOf = (plugin: AnyPlugin): unknown =>\n typeof plugin.initialState === 'function'\n ? (plugin.initialState as () => unknown)()\n : (plugin.initialState ?? {});\nconst reducerOf = (plugin: AnyPlugin) =>\n (plugin.reduce ?? ((state: unknown) => state)) as (state: unknown, action: Action) => unknown;\nconst toDocInfo = (meta: DocumentMeta): DocInfo => ({\n id: meta.id,\n name: meta.name,\n status: 'ready',\n pageCount: meta.pageCount,\n});\nconst pendingToDocInfo = (meta: PendingMeta): DocInfo => ({\n id: meta.id,\n name: meta.name,\n status: meta.status,\n pageCount: 0,\n passwordProvided: meta.passwordProvided,\n});\n\n/** The stable id an input implies, if it carries one ('bytes'/'layerBytes'/'id'). */\nconst idOfInput = (input: OpenInput): string | null =>\n 'id' in input && typeof input.id === 'string' ? input.id : null;\nconst passwordOfInput = (input: OpenInput): string | null | undefined =>\n 'password' in input ? input.password : undefined;\n\n/**\n * Everything one open document owns, in one place: the engine handle, the\n * resource scope (event subs, slices, plugin cleanups, the handle's own\n * close), the capability instances, and the in-flight lifecycle operation.\n * The session IS the document's lifecycle; the store's `documents`/`pending`\n * entries are its UI projection.\n *\n * opening — slot reserved; source resolving / engine opening\n * locked — parked on a password; the scope already owns handle.close\n * bringup — post-security: slices, inits, effect setup; NOT yet published\n * ready — committed; the only phase adapters resolve capabilities in\n * error — open failed after the slot was reserved; resources disposed\n * closing — close() won; unpublished, joining the operation, disposing\n */\ninterface DocumentSession extends SessionRef {\n name?: string;\n phase: 'opening' | 'locked' | 'bringup' | 'ready' | 'error' | 'closing';\n /** In-flight open/unlock — close() cancels, then JOINS this before disposing,\n * so \"close resolved\" means \"no producer is still acquiring resources\". */\n operation: Promise<unknown> | null;\n /** The current engine call, retained so close() can abort real worker-side\n * work instead of waiting for it to land at a checkpoint. */\n engineOp: { abort(reason?: unknown): void } | null;\n cancel: AbortController;\n capabilities: Map<AnyPlugin, unknown>;\n close(): Promise<void>;\n}\n\n/** Engine rejections carry AbortError when close() aborts the live call;\n * match structurally so test fakes with plain promises still work. */\nconst isAbortLike = (error: unknown): boolean =>\n error instanceof Error && error.name === 'AbortError';\n\n/**\n * Assemble a kernel from an engine + plugins.\n *\n * planPlugins — validate dependencies, order them\n * resolveCapability — workspace singletons, or per-document instances built lazily\n * document lifecycle — one DocumentSession per document: transactional open\n * (publish-last), one idempotent close for every phase\n * start / destroy — explicit status machine; destroy closes everything\n *\n * The kernel closes every handle it opened; it never destroys the engine —\n * ownership follows acquisition, and the engine was handed in by the caller.\n */\nexport function createKernel(opts: {\n engine: Engine;\n plugins: AnyPlugin[];\n /** Observability seam: teardown/effect/join failures land here. Default: console.error. */\n report?: (error: unknown) => void;\n}): Kernel {\n const { engine, plugins } = opts;\n const report = opts.report ?? ((error: unknown) => console.error('[kernel]', error));\n const store = createStore(report);\n const plan = planPlugins(plugins);\n const documentScopedPlugins = plan.ordered.filter(isDocumentScoped);\n\n const workspaceCapabilities = new Map<CapabilityToken<unknown>, unknown>();\n const workspaceScope = createScope(report);\n const sessions = new Map<string, DocumentSession>();\n\n let status: KernelStatus = 'created';\n let startPromise: Promise<void> | null = null;\n let destroyPromise: Promise<void> | null = null;\n\n const guardUsable = (what: string) => {\n if (status === 'failed' || status === 'destroying' || status === 'destroyed') {\n throw new Error(`[kernel] ${what} on a ${status} kernel`);\n }\n };\n\n // ── sessions ─────────────────────────────────────────────────────────────────\n\n const checkpoint = (session: DocumentSession) => {\n if (session.cancel.signal.aborted) {\n throw new CancelledError(`closed while opening: ${session.id}`);\n }\n };\n\n /**\n * Await an engine/network call under the session's cancellation:\n * - the call is retained so close() can abort real worker-side work\n * (`AbortablePromise`), and\n * - the await RACES the cancellation, so close()'s join never blocks on a\n * call that cannot be aborted (a plain-promise engine, a stuck fetch).\n * When cancellation wins but the call later lands anyway, `onLateResult`\n * routes the result into the session scope — whose late-defer rule runs it\n * immediately after disposal — so a late-arriving resource cannot leak.\n * (Plugin inits are deliberately NOT raced: they are first-party code that\n * close() joins to completion; only unbounded external waits are raced.)\n */\n async function engineCall<T>(\n session: DocumentSession,\n call: Promise<T>,\n onLateResult?: (value: T) => void | Promise<void>,\n ): Promise<T> {\n const abortable = call as Promise<T> & { abort?: (reason?: unknown) => void };\n session.engineOp = typeof abortable.abort === 'function' ? (abortable as never) : null;\n const signal = session.cancel.signal;\n let onAbort: (() => void) | undefined;\n const cancellation = new Promise<never>((_, reject) => {\n onAbort = () => reject(new CancelledError(`closed while opening: ${session.id}`));\n if (signal.aborted) onAbort();\n else signal.addEventListener('abort', onAbort, { once: true });\n });\n try {\n return await Promise.race([call, cancellation]);\n } catch (error) {\n if (isCancelled(error)) {\n void call.then(\n (value) => {\n if (onLateResult) session.scope.defer(() => onLateResult(value));\n },\n () => {}, // the abandoned call's own rejection is not separately actionable\n );\n }\n throw error;\n } finally {\n if (onAbort) signal.removeEventListener('abort', onAbort);\n session.engineOp = null;\n }\n }\n\n function createSession(id: string, name: string | undefined): DocumentSession {\n const session: DocumentSession = {\n id,\n name,\n phase: 'opening',\n handle: null,\n stagedMeta: null,\n scope: createScope(report),\n operation: null,\n engineOp: null,\n cancel: new AbortController(),\n capabilities: new Map(),\n close: () => closeSession(session),\n };\n return session;\n }\n\n /** One transition at a time per session (open, then possibly unlock). */\n function beginOperation<T>(session: DocumentSession, run: () => Promise<T>): Promise<T> {\n if (session.operation) {\n throw new Error(`[documents] \"${session.id}\" already has an active transition`);\n }\n const operation = run().finally(() => {\n if (session.operation === operation) session.operation = null;\n });\n session.operation = operation;\n return operation;\n }\n\n /** Atomic ticket → real-id reconciliation: the sessions map, the store slot,\n * order position, and activation all move together, or not at all. */\n function rekeySession(session: DocumentSession, nextId: string): void {\n const previousId = session.id;\n if (previousId === nextId) return;\n const core = store.getCore();\n if (sessions.has(nextId) || core.documents[nextId] || core.pending[nextId]) {\n throw new Error(`[documents] duplicate document id: ${nextId}`);\n }\n sessions.delete(previousId);\n session.id = nextId;\n sessions.set(nextId, session);\n const slot = core.pending[previousId];\n if (slot) {\n const { [previousId]: _moved, ...pending } = core.pending;\n store.setCore(\n {\n pending: { ...pending, [nextId]: { ...slot, id: nextId } },\n order: core.order.map((id) => (id === previousId ? nextId : id)),\n activeId: core.activeId === previousId ? nextId : core.activeId,\n },\n { type: CORE_ORDER_CHANGED },\n );\n }\n }\n\n const closingSessions = new WeakMap<DocumentSession, Promise<void>>();\n function closeSession(session: DocumentSession): Promise<void> {\n const inFlight = closingSessions.get(session);\n if (inFlight) return inFlight;\n const closing = (async () => {\n session.phase = 'closing';\n unpublishSlot(session.id); // synchronous: the tab disappears NOW\n // Cancel, JOIN the producer, then drain its resources — in that order.\n // After the join, no known producer can register more resources; the\n // scope's late-defer rule covers anything unknowable.\n const reason = new CancelledError(`closed while opening: ${session.id}`);\n session.cancel.abort(reason);\n session.engineOp?.abort(reason);\n await session.operation?.catch((error) => {\n if (!isCancelled(error) && !isAbortLike(error)) report(error);\n });\n await session.scope.dispose();\n if (sessions.get(session.id) === session) sessions.delete(session.id);\n })();\n closingSessions.set(session, closing);\n return closing;\n }\n\n // ── store projection (publish/unpublish) ─────────────────────────────────────\n\n function nextActiveDocument(core: CoreState, removedId: string): string | null {\n if (core.activeId !== removedId) return core.activeId;\n const index = core.order.indexOf(removedId);\n const remaining = core.order.filter((id) => id !== removedId);\n return remaining.length === 0 ? null : (remaining[Math.max(0, index - 1)] ?? remaining[0]);\n }\n\n function publishPendingSlot(session: DocumentSession, activate: boolean): void {\n const core = store.getCore();\n store.setCore(\n {\n pending: {\n ...core.pending,\n [session.id]: { id: session.id, name: session.name, status: 'loading' },\n },\n order: [...core.order, session.id],\n activeId: activate || core.activeId === null ? session.id : core.activeId,\n },\n { type: CORE_DOCUMENT_OPENING },\n );\n }\n\n function publishLocked(session: DocumentSession, passwordProvided: boolean): void {\n const core = store.getCore();\n store.setCore(\n {\n pending: {\n ...core.pending,\n [session.id]: { id: session.id, name: session.name, status: 'locked', passwordProvided },\n },\n },\n { type: CORE_DOCUMENT_LOCKED },\n );\n }\n\n function publishError(session: DocumentSession, error: unknown): void {\n const core = store.getCore();\n store.setCore(\n {\n pending: {\n ...core.pending,\n [session.id]: { id: session.id, name: session.name, status: 'error', error },\n },\n },\n { type: CORE_DOCUMENT_OPEN_FAILED },\n );\n }\n\n function unpublishSlot(id: string): void {\n const core = store.getCore();\n if (!core.pending[id] && !core.documents[id]) return;\n const { [id]: _pending, ...pending } = core.pending;\n const { [id]: _document, ...documents } = core.documents;\n store.setCore(\n {\n pending,\n documents,\n order: core.order.filter((other) => other !== id),\n activeId: nextActiveDocument(core, id),\n },\n { type: CORE_DOCUMENT_REMOVED },\n );\n }\n\n /** The ONE ready transition: swap the pending slot for the staged meta and\n * fire CORE_DOCUMENT_ADDED. Everything before this is unpublished and rolls\n * back by disposing the session scope; nothing after this can fail. */\n function commitReady(session: DocumentSession): void {\n session.phase = 'ready';\n const meta = session.stagedMeta!;\n const core = store.getCore();\n const { [session.id]: _resolved, ...pending } = core.pending;\n store.setCore(\n { documents: { ...core.documents, [session.id]: meta }, pending },\n { type: CORE_DOCUMENT_ADDED },\n );\n }\n\n // ── capability resolution ────────────────────────────────────────────────────\n\n const sessionOf = (documentId?: string): DocumentSession | null => {\n const id = documentId ?? store.getCore().activeId;\n return id ? (sessions.get(id) ?? null) : null;\n };\n\n /** The handle plugins may touch: bring-up or ready — never locked, never\n * a handle whose close already won. */\n const documentHandle = (documentId?: string): DocumentHandle | null => {\n const session = sessionOf(documentId);\n if (!session) return null;\n return session.phase === 'bringup' || session.phase === 'ready' ? session.handle : null;\n };\n\n function buildDocumentCapability(plugin: AnyPlugin, session: DocumentSession): unknown {\n let capability = session.capabilities.get(plugin);\n if (!capability) {\n capability = plugin.capability!(createPluginContext(services, plugin, session));\n session.capabilities.set(plugin, capability);\n }\n return capability;\n }\n\n function resolveCapability<T>(token: CapabilityToken<T>, documentId?: string): T {\n guardUsable(`capability(\"${token.name}\")`);\n const workspaceCapability = workspaceCapabilities.get(token);\n if (workspaceCapability) return workspaceCapability as T;\n const provider = plan.providerOf(token);\n if (!provider) throw new Error(`No capability \"${token.name}\".`);\n const id = documentId ?? store.getCore().activeId;\n if (!id) throw new Error(`Capability \"${token.name}\" requires an active document.`);\n const session = sessions.get(id);\n if (!session) throw new Error(`Capability \"${token.name}\" unavailable: no document \"${id}\".`);\n if (session.phase === 'bringup' || session.phase === 'ready') {\n return buildDocumentCapability(provider, session) as T;\n }\n // Fail fast and truthfully: a loading/locked/error document has no\n // plugin instances yet. `useOptional*` adapters turn this into their\n // fallback; strict resolution surfaces the real state.\n const shown = session.phase === 'opening' ? 'loading' : session.phase;\n throw new Error(`Capability \"${token.name}\" unavailable: document \"${id}\" is ${shown}.`);\n }\n\n /** Internal total resolver: bring-up counts, so a plugin's `ctx.tryGet`\n * works during its own document's init. */\n function tryResolveInternal<T>(token: CapabilityToken<T>, documentId?: string): T | null {\n if (status === 'destroying' || status === 'destroyed') return null;\n const workspaceCapability = workspaceCapabilities.get(token);\n if (workspaceCapability) return workspaceCapability as T;\n const provider = plan.providerOf(token);\n if (!provider) return null;\n const session = sessionOf(documentId);\n if (!session || (session.phase !== 'bringup' && session.phase !== 'ready')) return null;\n return buildDocumentCapability(provider, session) as T;\n }\n\n /** Public total resolver — see `Kernel.tryCapability`. `ready` only: the\n * null→instance flip at commit time IS the adapters' re-render signal. */\n function tryResolveCapability<T>(token: CapabilityToken<T>, documentId?: string): T | null {\n if (status === 'destroying' || status === 'destroyed') return null;\n const workspaceCapability = workspaceCapabilities.get(token);\n if (workspaceCapability) return workspaceCapability as T;\n const provider = plan.providerOf(token);\n if (!provider) return null;\n const session = sessionOf(documentId);\n if (!session || session.phase !== 'ready') return null;\n return buildDocumentCapability(provider, session) as T;\n }\n\n const services: ContextServices = {\n engine,\n store,\n workspaceScope,\n resolveCapability,\n tryResolveCapability: tryResolveInternal,\n documentHandle,\n };\n\n // ── document lifecycle ───────────────────────────────────────────────────────\n\n // Tickets for slots whose real id isn't known yet (thunk sources).\n let ticketCounter = 0;\n const nextTicket = () => `pending:${++ticketCounter}`;\n\n /** Slices + event subscription + plugin inits + effect SETUP — every step's\n * release deferred into the session scope, every await followed by a\n * checkpoint. Runs entirely pre-commit: a failure anywhere rolls the whole\n * session back and the document was never `ready`. */\n async function bringUp(\n session: DocumentSession,\n snapshot: { pageCount: number; pages: DocumentMeta['pages'] },\n ): Promise<void> {\n session.phase = 'bringup';\n // The render policy is a document FACT (Pattern A, like the page\n // registry): async on the engine contract, materialized ONCE here —\n // pre-publish — so every consumer reads it synchronously off the meta\n // and no \"policy still resolving\" state exists anywhere downstream.\n // Best-effort by design: no render service, or a failed read, means\n // `continuous` — a policy hiccup must never block a document open.\n let renderPolicy: EngineRenderPolicy = CONTINUOUS_RENDER_POLICY;\n try {\n renderPolicy = (await session.handle!.render?.policy()) ?? CONTINUOUS_RENDER_POLICY;\n } catch {\n /* unreachable policy = continuous */\n }\n checkpoint(session);\n session.stagedMeta = {\n id: session.id,\n name: session.name,\n pageCount: snapshot.pageCount,\n pages: snapshot.pages,\n revision: 0,\n renderPolicy,\n };\n\n // Document mutation events (rotate/move/delete) replace the page\n // registry in place — the snapshot they carry is byte-identical to\n // pages.list(), so this is a direct swap, no merge. Own mutations and\n // remote (collaborator) mutations arrive identically; the handler is\n // origin-agnostic, as the event model intends.\n const unsubscribeEvents = session.handle!.events.subscribe((event) => {\n const layout = layoutFromEvent(event);\n if (!layout) return;\n const now = store.getCore();\n const existing = now.documents[session.id];\n if (!existing) return; // pre-commit or closed — registry not published\n const updated: DocumentMeta = {\n ...existing,\n pageCount: layout.pageCount,\n pages: layout.pages,\n revision: existing.revision + 1,\n };\n store.setCore(\n { documents: { ...now.documents, [session.id]: updated } },\n { type: CORE_DOCUMENT_PAGES_UPDATED },\n );\n });\n session.scope.defer(unsubscribeEvents);\n\n for (const plugin of documentScopedPlugins) {\n const key = sliceKey(plugin.id, session.id);\n store.registerSlice(key, reducerOf(plugin), initialStateOf(plugin));\n session.scope.defer(() => store.removeSlice(key)); // LIFO ⇒ reverse dependency order\n }\n for (const plugin of documentScopedPlugins) {\n await plugin.init?.(createPluginContext(services, plugin, session));\n checkpoint(session);\n }\n // Effect SETUP is part of the transaction (it can throw); the callbacks\n // it registers fire post-commit and are isolated by the store instead.\n for (const plugin of documentScopedPlugins) {\n plugin.effects?.(createEffectContext(services, plugin, session));\n }\n checkpoint(session);\n }\n\n async function openDocument(input: OpenSource, options?: OpenDocumentOptions): Promise<string> {\n guardUsable('documents.open()');\n const { activate, name, ...engineOptions } = options ?? {};\n\n // 1. Reserve the tab slot SYNCHRONOUSLY (before the first await): id,\n // order position, and activation are decided at request time; only the\n // content arrives at completion time. Fire-and-forget concurrent opens\n // therefore keep call order as tab order.\n const requestedId =\n typeof input === 'function' ? nextTicket() : (idOfInput(input) ?? nextTicket());\n if (sessions.has(requestedId)) {\n throw new Error(`[documents] document already open: ${requestedId}`);\n }\n const session = createSession(requestedId, name);\n sessions.set(session.id, session);\n publishPendingSlot(session, activate ?? true);\n\n return beginOperation(session, async () => {\n try {\n const source =\n typeof input === 'function'\n ? await engineCall(session, Promise.resolve(input(session.cancel.signal)))\n : input;\n checkpoint(session);\n const sourceId = idOfInput(source);\n if (sourceId) rekeySession(session, sourceId);\n\n // A handle that lands after close() won still gets closed — see engineCall.\n const handle = await engineCall(session, engine.open(source, engineOptions), (late) =>\n late.close(),\n );\n session.handle = handle;\n session.scope.defer(() => handle.close()); // paired at acquisition — no exit path leaks it\n checkpoint(session);\n if (handle.id !== session.id) rekeySession(session, handle.id);\n\n // 2. A password-locked handle parks here — BEFORE pages.list(), which\n // would reject on a locked document. `documents.unlock()` finishes\n // the job later. `passwordProvided` records that a supplied password\n // was already tried and rejected (drives the \"incorrect\" copy).\n if (handle.security?.passwordPrompt?.state === 'required') {\n const passwordProvided =\n ('password' in engineOptions && engineOptions.password != null) ||\n passwordOfInput(source) != null;\n session.phase = 'locked';\n publishLocked(session, passwordProvided);\n return session.id;\n }\n\n const snapshot = await engineCall(session, handle.pages.list());\n checkpoint(session);\n await bringUp(session, snapshot);\n commitReady(session);\n return session.id;\n } catch (error) {\n // Close won the race: close() owns unpublish + disposal; just get out\n // of its way, rejecting with the typed cancellation either way.\n if (isCancelled(error)) throw error;\n if (session.phase === 'closing' || isAbortLike(error)) {\n throw new CancelledError(`closed while opening: ${session.id}`);\n }\n // 3. Real failure: ROLLBACK (scope releases exactly what was acquired,\n // however far we got), then park the tab as `error` — closable, and\n // reopenable after close. The document was never `ready`.\n await session.scope.dispose();\n session.phase = 'error';\n publishError(session, error);\n throw error;\n }\n });\n }\n\n async function unlockDocument(id: string, input: { password: string }): Promise<void> {\n guardUsable('documents.unlock()');\n const session = sessions.get(id);\n if (!session || session.phase !== 'locked' || !session.handle) {\n throw new Error(`[documents] document is not locked: ${id}`);\n }\n const handle = session.handle;\n return beginOperation(session, async () => {\n // Engine-agnostic by design: local loads the parked worker bytes, cloud\n // POSTs /access — same call, same result. A WRONG PASSWORD rejects here\n // and nothing changes: the document stays locked, unlock is retryable.\n try {\n await engineCall(session, handle.security.unlock({ password: input.password }));\n } catch (error) {\n if (session.phase === 'closing' || isAbortLike(error)) {\n throw new CancelledError(`closed while opening: ${session.id}`);\n }\n throw error; // still locked — deliberately no state change\n }\n checkpoint(session);\n // Past the password: failures from here are REAL open failures — the\n // same rollback + `error` policy as the open path.\n try {\n const snapshot = await engineCall(session, handle.pages.list());\n checkpoint(session);\n await bringUp(session, snapshot);\n commitReady(session);\n } catch (error) {\n if (isCancelled(error)) throw error;\n if (session.phase === 'closing' || isAbortLike(error)) {\n throw new CancelledError(`closed while opening: ${session.id}`);\n }\n await session.scope.dispose();\n session.phase = 'error';\n publishError(session, error);\n throw error;\n }\n });\n }\n\n async function closeDocument(documentId: string): Promise<void> {\n const session = sessions.get(documentId);\n if (!session) return; // idempotent — unknown or already closed\n await session.close();\n }\n\n function reorder(next: string[]) {\n store.setCore({ order: next }, { type: CORE_ORDER_CHANGED });\n }\n\n const documents: DocumentsCapability = {\n open: openDocument,\n openAll: (docs) => {\n guardUsable('documents.openAll()');\n // Fire-and-forget on purpose: each open() reserves its tab slot\n // synchronously, so tabs exist immediately in array order; exactly one\n // activation, decided here at request time. Failures are tab state\n // (`error`/`locked`), never unhandled rejections.\n const activeIndex = Math.max(\n 0,\n docs.findIndex((d) => d.active),\n );\n docs.forEach(({ source, active: _active, ...options }, index) => {\n void openDocument(source, { ...options, activate: index === activeIndex }).catch(() => {});\n });\n },\n unlock: unlockDocument,\n close: closeDocument,\n closeAll: async () => {\n for (const id of [...store.getCore().order]) await closeDocument(id);\n },\n setActive: (id) => {\n const core = store.getCore();\n // Pending tabs are selectable — a loading or locked tab is a real tab.\n if (core.documents[id] || core.pending[id])\n store.setCore({ activeId: id }, { type: CORE_ACTIVE_CHANGED });\n },\n activeId: () => store.getCore().activeId,\n list: (): DocInfo[] =>\n store.getCore().order.map((id) => {\n const core = store.getCore();\n const meta = core.documents[id];\n return meta ? toDocInfo(meta) : pendingToDocInfo(core.pending[id]);\n }),\n get: (id) => {\n const core = store.getCore();\n const meta = core.documents[id];\n if (meta) return toDocInfo(meta);\n const pending = core.pending[id];\n return pending ? pendingToDocInfo(pending) : null;\n },\n has: (id) => {\n const core = store.getCore();\n return core.documents[id] !== undefined || core.pending[id] !== undefined;\n },\n count: () => store.getCore().order.length,\n order: () => [...store.getCore().order],\n move: (id, toIndex) => {\n const core = store.getCore();\n if (!core.documents[id] && !core.pending[id]) return;\n const without = core.order.filter((x) => x !== id);\n const clamped = Math.max(0, Math.min(toIndex, without.length));\n without.splice(clamped, 0, id);\n reorder(without);\n },\n swap: (a, b) => {\n const core = store.getCore();\n const indexA = core.order.indexOf(a);\n const indexB = core.order.indexOf(b);\n if (indexA < 0 || indexB < 0) return;\n const next = [...core.order];\n next[indexA] = b;\n next[indexB] = a;\n reorder(next);\n },\n // Document IO — siblings of open/close, straight to the live engine handle.\n download: (id, opts) => {\n const handle = documentHandle(id);\n if (!handle) return Promise.reject(new Error('[documents] no document to download'));\n return handle.download(opts);\n },\n downloadLayer: (id) => {\n const handle = documentHandle(id);\n if (!handle) return Promise.reject(new Error('[documents] no document to download'));\n if (!handle.downloadLayer) {\n return Promise.reject(\n new Error(\n '[documents] this engine cannot export a layer (open with a layer on the local engine)',\n ),\n );\n }\n return handle.downloadLayer();\n },\n };\n workspaceCapabilities.set(DocumentsToken, documents);\n\n // ── workspace plugins: seed slices, then build their capabilities ────────────\n for (const plugin of plan.ordered) {\n if (!isDocumentScoped(plugin))\n store.registerSlice(plugin.id, reducerOf(plugin), initialStateOf(plugin));\n }\n for (const plugin of plan.ordered) {\n if (!isDocumentScoped(plugin) && plugin.token && plugin.capability) {\n workspaceCapabilities.set(\n plugin.token,\n plugin.capability(createPluginContext(services, plugin)),\n );\n }\n }\n\n return {\n engine,\n documents,\n capability: resolveCapability,\n tryCapability: tryResolveCapability,\n scopeOf: plan.scopeOf,\n subscribe: store.subscribe,\n getState: store.getState,\n status: () => status,\n start: () => {\n if (status === 'destroying' || status === 'destroyed' || status === 'failed') {\n return Promise.reject(new Error(`[kernel] start() on a ${status} kernel`));\n }\n return (startPromise ??= (async () => {\n status = 'starting';\n try {\n for (const plugin of plan.ordered) {\n if (status !== 'starting') return; // destroy() raced us — stop within one init\n if (!isDocumentScoped(plugin))\n await plugin.init?.(createPluginContext(services, plugin));\n }\n if (status !== 'starting') return;\n for (const plugin of plan.ordered) {\n if (!isDocumentScoped(plugin)) plugin.effects?.(createEffectContext(services, plugin));\n }\n status = 'started';\n } catch (error) {\n // Startup failure unwinds everything construction + start registered;\n // the kernel is terminally failed (destroy() remains legal, and idle).\n status = 'failed';\n await workspaceScope.dispose();\n workspaceCapabilities.clear();\n throw error;\n }\n })());\n },\n destroy: () => {\n return (destroyPromise ??= (async () => {\n const wasFailed = status === 'failed';\n status = 'destroying'; // an in-flight start exits at its next check\n await startPromise?.catch((error) => {\n if (!isCancelled(error) && !wasFailed) report(error);\n });\n // Close every session — the RESOURCE-owning map, not store.order: a\n // session mid-close is already unpublished but still needs joining.\n await Promise.allSettled([...sessions.values()].map((session) => session.close()));\n sessions.clear();\n await workspaceScope.dispose();\n workspaceCapabilities.clear();\n store.destroy();\n status = 'destroyed';\n })());\n },\n };\n}\n","export * from './types';\nexport * from './kernel';\nexport { CancelledError, isCancelled } from './scope';\n\n// Re-export the engine contracts so plugins/adapters import them from @embedpdf/core.\nexport {\n AbortablePromise,\n CONTINUOUS_RENDER_POLICY,\n snapAppearanceScale,\n snapFullPageViewport,\n snapTileScale,\n} from '@embedpdf/engine-core/runtime';\nexport type {\n EngineRenderPolicy,\n PageHandle,\n PageRaster,\n PageRenderOptions,\n PageRenderTarget,\n PageRenderViewport,\n PageImageHandle,\n PageImageOptions,\n PageImageObjectUrl,\n PdfRect,\n} from '@embedpdf/engine-core/runtime';\n\nimport type { Action, CapabilityToken, PluginDef } from './types';\n\n/** Create a typed capability token. `name` is for debugging only. */\nexport function createCapabilityToken<T>(name: string): CapabilityToken<T> {\n return { name };\n}\n\n/** Identity helper that pins a plugin's generics. The real win is inference. */\nexport function definePlugin<S = unknown, A extends Action = Action, C = unknown>(\n def: PluginDef<S, A, C>,\n): PluginDef<S, A, C> {\n return def;\n}\n"],"mappings":"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"}
|