@embedpdf/plugin-document-manager 2.1.2 → 2.2.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/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/models"),o=class extends e.BasePlugin{constructor(t,o,n){super(t,o),this.id=t,this.documentOpened$=e.createBehaviorEmitter(),this.documentClosed$=e.createBehaviorEmitter(),this.activeDocumentChanged$=e.createBehaviorEmitter(),this.documentError$=e.createBehaviorEmitter(),this.documentOrderChanged$=e.createBehaviorEmitter(),this.openFileRequest$=e.createEmitter(),this.loadOptions=new Map,this.maxDocuments=null==n?void 0:n.maxDocuments}buildCapability(){return{openFileDialog:e=>this.openFileDialog(e),openDocumentUrl:e=>this.openDocumentUrl(e),openDocumentBuffer:e=>this.openDocumentBuffer(e),retryDocument:(e,t)=>this.retryDocument(e,t),closeDocument:e=>this.closeDocument(e),closeAllDocuments:()=>this.closeAllDocuments(),setActiveDocument:t=>{if(!this.isDocumentOpen(t))throw new Error(`Cannot set active document: ${t} is not open`);this.dispatchCoreAction(e.setActiveDocument(t))},getActiveDocumentId:()=>this.coreState.core.activeDocumentId,getActiveDocument:()=>{var e;const t=this.coreState.core.activeDocumentId;return t?(null==(e=this.coreState.core.documents[t])?void 0:e.document)??null:null},getDocumentOrder:()=>this.coreState.core.documentOrder,moveDocument:(t,o)=>{this.dispatchCoreAction(e.moveDocument(t,o))},swapDocuments:(t,o)=>{const n=this.coreState.core.documentOrder,r=n.indexOf(t),s=n.indexOf(o);if(-1===r||-1===s)throw new Error("One or both documents not found in order");const c=[...n];[c[r],c[s]]=[c[s],c[r]],this.dispatchCoreAction(e.reorderDocuments(c))},getDocument:e=>{var t;return(null==(t=this.coreState.core.documents[e])?void 0:t.document)??null},getDocumentState:e=>this.coreState.core.documents[e]??null,getOpenDocuments:()=>this.coreState.core.documentOrder.map(e=>this.coreState.core.documents[e]).filter(e=>null!==e),isDocumentOpen:e=>this.isDocumentOpen(e),getDocumentCount:()=>Object.keys(this.coreState.core.documents).length,getDocumentIndex:e=>this.coreState.core.documentOrder.indexOf(e),onDocumentOpened:this.documentOpened$.on,onDocumentClosed:this.documentClosed$.on,onDocumentError:this.documentError$.on,onActiveDocumentChanged:this.activeDocumentChanged$.on,onDocumentOrderChanged:this.documentOrderChanged$.on}}isDocumentOpen(e){return!!this.coreState.core.documents[e]}onDocumentLoaded(e){const t=this.coreState.core.documents[e];t&&"loaded"===t.status&&(this.loadOptions.delete(e),this.documentOpened$.emit(t),this.logger.info("DocumentManagerPlugin","DocumentOpened",`Document ${e} opened successfully`,{name:t.name}))}onDocumentClosed(e){this.loadOptions.delete(e),this.documentClosed$.emit(e),this.logger.info("DocumentManagerPlugin","DocumentClosed",`Document ${e} closed`)}onActiveDocumentChanged(e,t){this.activeDocumentChanged$.emit({previousDocumentId:e,currentDocumentId:t}),this.logger.info("DocumentManagerPlugin","ActiveDocumentChanged",`Active document changed from ${e} to ${t}`)}onCoreStoreUpdated(e,t){e.core.documentOrder!==t.core.documentOrder&&this.documentOrderChanged$.emit({order:t.core.documentOrder})}onOpenFileRequest(e){return this.openFileRequest$.on(e)}openDocumentUrl(o){const n=new t.Task,r=o.documentId||this.generateDocumentId(),s=this.checkDocumentLimit();if(s)return n.reject(s),n;const c=o.name??this.extractNameFromUrl(o.url);this.loadOptions.set(r,o),this.dispatchCoreAction(e.startLoadingDocument(r,c,o.scale,o.rotation,!!o.password,o.autoActivate)),this.logger.info("DocumentManagerPlugin","OpenDocumentUrl",`Starting to load document from URL: ${o.url}`,{documentId:r,passwordProvided:!!o.password});const i={id:r,url:o.url},a=this.engine.openDocumentUrl(i,{password:o.password,mode:o.mode,requestOptions:o.requestOptions});return n.resolve({documentId:r,task:a}),this.handleLoadTask(r,a,"OpenDocumentUrl"),n}openDocumentBuffer(o){const n=new t.Task,r=this.checkDocumentLimit();if(r)return n.reject(r),n;const s=o.documentId||this.generateDocumentId();this.loadOptions.set(s,o),this.dispatchCoreAction(e.startLoadingDocument(s,o.name,o.scale,o.rotation,!!o.password,o.autoActivate)),this.logger.info("DocumentManagerPlugin","OpenDocumentBuffer",`Starting to load document from buffer: ${o.name}`,{documentId:s,passwordProvided:!!o.password});const c={id:s,content:o.buffer},i=this.engine.openDocumentBuffer(c,{password:o.password});return n.resolve({documentId:s,task:i}),this.handleLoadTask(s,i,"OpenDocumentBuffer"),n}retryDocument(o,n){const r=new t.Task,s=this.validateRetry(o);if(!s.valid)return r.reject(s.error),r;const c={...this.loadOptions.get(o),...(null==n?void 0:n.password)&&{password:n.password}};this.loadOptions.set(o,c),this.dispatchCoreAction(e.retryLoadingDocument(o,!!(null==n?void 0:n.password))),this.logger.info("DocumentManagerPlugin","RetryDocument",`Retrying to load document ${o}`,{passwordProvided:!!(null==n?void 0:n.password)});const i="url"in c?this.retryUrlDocument(o,c):this.retryBufferDocument(o,c);return r.resolve({documentId:o,task:i}),this.handleLoadTask(o,i,"RetryDocument"),r}openFileDialog(e){const o=new t.Task;return this.openFileRequest$.emit({task:o,options:e}),o}closeDocument(o){const n=new t.Task,r=this.coreState.core.documents[o];return r?("loaded"===r.status&&r.document?this.engine.closeDocument(r.document).wait(()=>{this.dispatchCoreAction(e.closeDocument(o)),n.resolve()},e=>{this.logger.error("DocumentManagerPlugin","CloseDocument",`Failed to close document ${o}`,e),n.fail(e)}):(this.logger.info("DocumentManagerPlugin","CloseDocument",`Closing document ${o} in ${r.status} state (skipping engine close)`),this.dispatchCoreAction(e.closeDocument(o)),n.resolve()),n):(this.logger.warn("DocumentManagerPlugin","CloseDocument",`Cannot close document ${o}: not found in state`),n.resolve(),n)}closeAllDocuments(){const e=Object.keys(this.coreState.core.documents),o=e.map(e=>this.closeDocument(e));return this.logger.info("DocumentManagerPlugin","CloseAllDocuments",`Closing ${e.length} documents`),t.Task.all(o)}checkDocumentLimit(){return this.maxDocuments&&Object.keys(this.coreState.core.documents).length>=this.maxDocuments?{code:t.PdfErrorCode.Unknown,message:`Maximum number of documents (${this.maxDocuments}) reached`}:null}validateRetry(e){const o=this.coreState.core.documents[e];return o?"loaded"===o.status?{valid:!1,error:{code:t.PdfErrorCode.Unknown,message:`Document ${e} is already loaded successfully`}}:"error"!==o.status?{valid:!1,error:{code:t.PdfErrorCode.Unknown,message:`Document ${e} is not in error state (current state: ${o.status})`}}:this.loadOptions.has(e)?{valid:!0}:{valid:!1,error:{code:t.PdfErrorCode.Unknown,message:`No retry information available for document ${e}`}}:{valid:!1,error:{code:t.PdfErrorCode.NotFound,message:`Document ${e} not found`}}}retryUrlDocument(e,t){const o={id:e,url:t.url};return this.engine.openDocumentUrl(o,{password:t.password,mode:t.mode,requestOptions:t.requestOptions})}retryBufferDocument(e,t){const o={id:e,content:t.buffer};return this.engine.openDocumentBuffer(o,{password:t.password})}handleLoadTask(t,o,n){o.wait(o=>{this.dispatchCoreAction(e.setDocumentLoaded(t,o))},e=>{this.handleLoadError(t,e,n)})}handleLoadError(t,o,n){var r,s,c;const i=(null==(r=o.reason)?void 0:r.message)||"Failed to load document";this.logger.error("DocumentManagerPlugin",n,"Failed to load document",o),this.dispatchCoreAction(e.setDocumentError(t,i,null==(s=o.reason)?void 0:s.code,o.reason)),this.documentError$.emit({documentId:t,message:i,code:null==(c=o.reason)?void 0:c.code,reason:o.reason})}generateDocumentId(){return`doc-${Date.now()}-${Math.random().toString(36).substr(2,9)}`}extractNameFromUrl(e){try{const t=new URL(e),o=t.pathname.split("/").pop();if(!o)return;let n=decodeURIComponent(o);return n.toLowerCase().endsWith(".pdf")||(n+=".pdf"),n}catch{return}}async initialize(e){var t;if(this.logger.info("DocumentManagerPlugin","Initialize","Document Manager Plugin initialized",{maxDocuments:this.maxDocuments,initialDocumentsCount:(null==(t=e.initialDocuments)?void 0:t.length)??0}),e.initialDocuments&&e.initialDocuments.length>0)for(const n of e.initialDocuments)try{"buffer"in n?this.openDocumentBuffer(n):"url"in n&&this.openDocumentUrl(n)}catch(o){this.logger.error("DocumentManagerPlugin","Initialize","Failed to initiate initial document load",o)}}async destroy(){await this.closeAllDocuments().toPromise(),this.loadOptions.clear(),this.documentOpened$.clear(),this.documentClosed$.clear(),this.activeDocumentChanged$.clear(),this.documentOrderChanged$.clear(),this.documentError$.clear(),super.destroy()}};o.id="document-manager";let n=o;const r="document-manager",s={id:r,name:"Document Manager Plugin",version:"1.0.0",provides:["document-manager"],requires:[],optional:[],defaultConfig:{maxDocuments:10}},c={manifest:s,create:(e,t)=>new n(r,e,t),reducer:e=>e,initialState:{}};exports.DOCUMENT_MANAGER_PLUGIN_ID=r,exports.DocumentManagerPlugin=n,exports.DocumentManagerPluginPackage=c,exports.manifest=s;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("@embedpdf/core"),t=require("@embedpdf/models"),o=class extends e.BasePlugin{constructor(t,o,n){super(t,o),this.id=t,this.documentOpened$=e.createBehaviorEmitter(),this.documentClosed$=e.createBehaviorEmitter(),this.activeDocumentChanged$=e.createBehaviorEmitter(),this.documentError$=e.createBehaviorEmitter(),this.documentOrderChanged$=e.createBehaviorEmitter(),this.openFileRequest$=e.createEmitter(),this.loadOptions=new Map,this.maxDocuments=null==n?void 0:n.maxDocuments}buildCapability(){return{openFileDialog:e=>this.openFileDialog(e),openDocumentUrl:e=>this.openDocumentUrl(e),openDocumentBuffer:e=>this.openDocumentBuffer(e),retryDocument:(e,t)=>this.retryDocument(e,t),closeDocument:e=>this.closeDocument(e),closeAllDocuments:()=>this.closeAllDocuments(),setActiveDocument:t=>{if(!this.isDocumentOpen(t))throw new Error(`Cannot set active document: ${t} is not open`);this.dispatchCoreAction(e.setActiveDocument(t))},getActiveDocumentId:()=>this.coreState.core.activeDocumentId,getActiveDocument:()=>{var e;const t=this.coreState.core.activeDocumentId;return t?(null==(e=this.coreState.core.documents[t])?void 0:e.document)??null:null},getDocumentOrder:()=>this.coreState.core.documentOrder,moveDocument:(t,o)=>{this.dispatchCoreAction(e.moveDocument(t,o))},swapDocuments:(t,o)=>{const n=this.coreState.core.documentOrder,r=n.indexOf(t),s=n.indexOf(o);if(-1===r||-1===s)throw new Error("One or both documents not found in order");const i=[...n];[i[r],i[s]]=[i[s],i[r]],this.dispatchCoreAction(e.reorderDocuments(i))},getDocument:e=>{var t;return(null==(t=this.coreState.core.documents[e])?void 0:t.document)??null},getDocumentState:e=>this.coreState.core.documents[e]??null,getOpenDocuments:()=>this.coreState.core.documentOrder.map(e=>this.coreState.core.documents[e]).filter(e=>null!==e),isDocumentOpen:e=>this.isDocumentOpen(e),getDocumentCount:()=>Object.keys(this.coreState.core.documents).length,getDocumentIndex:e=>this.coreState.core.documentOrder.indexOf(e),setDocumentEncryption:(e,t)=>this.setDocumentEncryption(e,t),unlockOwnerPermissions:(e,t)=>this.unlockOwnerPermissions(e,t),removeEncryption:e=>this.removeEncryption(e),onDocumentOpened:this.documentOpened$.on,onDocumentClosed:this.documentClosed$.on,onDocumentError:this.documentError$.on,onActiveDocumentChanged:this.activeDocumentChanged$.on,onDocumentOrderChanged:this.documentOrderChanged$.on}}isDocumentOpen(e){return!!this.coreState.core.documents[e]}onDocumentLoaded(e){const t=this.coreState.core.documents[e];t&&"loaded"===t.status&&(this.loadOptions.delete(e),this.documentOpened$.emit(t),this.logger.info("DocumentManagerPlugin","DocumentOpened",`Document ${e} opened successfully`,{name:t.name}))}onDocumentClosed(e){this.loadOptions.delete(e),this.documentClosed$.emit(e),this.logger.info("DocumentManagerPlugin","DocumentClosed",`Document ${e} closed`)}onActiveDocumentChanged(e,t){this.activeDocumentChanged$.emit({previousDocumentId:e,currentDocumentId:t}),this.logger.info("DocumentManagerPlugin","ActiveDocumentChanged",`Active document changed from ${e} to ${t}`)}onCoreStoreUpdated(e,t){e.core.documentOrder!==t.core.documentOrder&&this.documentOrderChanged$.emit({order:t.core.documentOrder})}onOpenFileRequest(e){return this.openFileRequest$.on(e)}openDocumentUrl(o){const n=new t.Task,r=o.documentId||this.generateDocumentId(),s=this.checkDocumentLimit();if(s)return n.reject(s),n;const i=o.name??this.extractNameFromUrl(o.url);this.loadOptions.set(r,o),this.dispatchCoreAction(e.startLoadingDocument(r,i,o.scale,o.rotation,!!o.password,o.autoActivate,o.permissions)),this.logger.info("DocumentManagerPlugin","OpenDocumentUrl",`Starting to load document from URL: ${o.url}`,{documentId:r,passwordProvided:!!o.password});const c={id:r,url:o.url},u=this.engine.openDocumentUrl(c,{password:o.password,mode:o.mode,requestOptions:o.requestOptions});return n.resolve({documentId:r,task:u}),this.handleLoadTask(r,u,"OpenDocumentUrl"),n}openDocumentBuffer(o){const n=new t.Task,r=this.checkDocumentLimit();if(r)return n.reject(r),n;const s=o.documentId||this.generateDocumentId();this.loadOptions.set(s,o),this.dispatchCoreAction(e.startLoadingDocument(s,o.name,o.scale,o.rotation,!!o.password,o.autoActivate,o.permissions)),this.logger.info("DocumentManagerPlugin","OpenDocumentBuffer",`Starting to load document from buffer: ${o.name}`,{documentId:s,passwordProvided:!!o.password});const i={id:s,content:o.buffer},c=this.engine.openDocumentBuffer(i,{password:o.password});return n.resolve({documentId:s,task:c}),this.handleLoadTask(s,c,"OpenDocumentBuffer"),n}retryDocument(o,n){const r=new t.Task,s=this.validateRetry(o);if(!s.valid)return r.reject(s.error),r;const i={...this.loadOptions.get(o),...(null==n?void 0:n.password)&&{password:n.password}};this.loadOptions.set(o,i),this.dispatchCoreAction(e.retryLoadingDocument(o,!!(null==n?void 0:n.password))),this.logger.info("DocumentManagerPlugin","RetryDocument",`Retrying to load document ${o}`,{passwordProvided:!!(null==n?void 0:n.password)});const c="url"in i?this.retryUrlDocument(o,i):this.retryBufferDocument(o,i);return r.resolve({documentId:o,task:c}),this.handleLoadTask(o,c,"RetryDocument"),r}openFileDialog(e){const o=new t.Task;return this.openFileRequest$.emit({task:o,options:e}),o}closeDocument(o){const n=new t.Task,r=this.coreState.core.documents[o];return r?("loaded"===r.status&&r.document?this.engine.closeDocument(r.document).wait(()=>{this.dispatchCoreAction(e.closeDocument(o)),n.resolve()},e=>{this.logger.error("DocumentManagerPlugin","CloseDocument",`Failed to close document ${o}`,e),n.fail(e)}):(this.logger.info("DocumentManagerPlugin","CloseDocument",`Closing document ${o} in ${r.status} state (skipping engine close)`),this.dispatchCoreAction(e.closeDocument(o)),n.resolve()),n):(this.logger.warn("DocumentManagerPlugin","CloseDocument",`Cannot close document ${o}: not found in state`),n.resolve(),n)}closeAllDocuments(){const e=Object.keys(this.coreState.core.documents),o=e.map(e=>this.closeDocument(e));return this.logger.info("DocumentManagerPlugin","CloseAllDocuments",`Closing ${e.length} documents`),t.Task.all(o)}setDocumentEncryption(e,o){const n=new t.Task,r=this.coreState.core.documents[e];if(!(null==r?void 0:r.document))return n.reject({code:t.PdfErrorCode.DocNotOpen,message:`Document ${e} is not open`}),n;this.logger.info("DocumentManagerPlugin","SetDocumentEncryption",`Setting encryption on document ${e}`,{hasUserPassword:!!o.userPassword,allowedFlags:o.allowedFlags});return this.engine.setDocumentEncryption(r.document,o.userPassword??"",o.ownerPassword,o.allowedFlags).wait(t=>{t&&this.logger.info("DocumentManagerPlugin","SetDocumentEncryption",`Encryption set successfully on document ${e}`),n.resolve(t)},t=>{this.logger.error("DocumentManagerPlugin","SetDocumentEncryption",`Failed to set encryption on document ${e}`,t),n.fail(t)}),n}unlockOwnerPermissions(o,n){const r=new t.Task,s=this.coreState.core.documents[o];if(!(null==s?void 0:s.document))return r.reject({code:t.PdfErrorCode.DocNotOpen,message:`Document ${o} is not open`}),r;const i=s.document;this.logger.info("DocumentManagerPlugin","UnlockOwnerPermissions",`Attempting to unlock owner permissions on document ${o}`);return this.engine.unlockOwnerPermissions(i,n).wait(t=>{if(t){this.logger.info("DocumentManagerPlugin","UnlockOwnerPermissions",`Owner permissions unlocked on document ${o}`);const t=4294967295;this.dispatchCoreAction(e.updateDocumentSecurity(o,t,!0))}r.resolve(t)},e=>{this.logger.error("DocumentManagerPlugin","UnlockOwnerPermissions",`Failed to unlock owner permissions on document ${o}`,e),r.fail(e)}),r}removeEncryption(e){const o=new t.Task,n=this.coreState.core.documents[e];if(!(null==n?void 0:n.document))return o.reject({code:t.PdfErrorCode.DocNotOpen,message:`Document ${e} is not open`}),o;this.logger.info("DocumentManagerPlugin","RemoveEncryption",`Marking document ${e} for encryption removal on save`);return this.engine.removeEncryption(n.document).wait(t=>{t&&this.logger.info("DocumentManagerPlugin","RemoveEncryption",`Document ${e} marked for encryption removal`),o.resolve(t)},t=>{this.logger.error("DocumentManagerPlugin","RemoveEncryption",`Failed to mark document ${e} for encryption removal`,t),o.fail(t)}),o}checkDocumentLimit(){return this.maxDocuments&&Object.keys(this.coreState.core.documents).length>=this.maxDocuments?{code:t.PdfErrorCode.Unknown,message:`Maximum number of documents (${this.maxDocuments}) reached`}:null}validateRetry(e){const o=this.coreState.core.documents[e];return o?"loaded"===o.status?{valid:!1,error:{code:t.PdfErrorCode.Unknown,message:`Document ${e} is already loaded successfully`}}:"error"!==o.status?{valid:!1,error:{code:t.PdfErrorCode.Unknown,message:`Document ${e} is not in error state (current state: ${o.status})`}}:this.loadOptions.has(e)?{valid:!0}:{valid:!1,error:{code:t.PdfErrorCode.Unknown,message:`No retry information available for document ${e}`}}:{valid:!1,error:{code:t.PdfErrorCode.NotFound,message:`Document ${e} not found`}}}retryUrlDocument(e,t){const o={id:e,url:t.url};return this.engine.openDocumentUrl(o,{password:t.password,mode:t.mode,requestOptions:t.requestOptions})}retryBufferDocument(e,t){const o={id:e,content:t.buffer};return this.engine.openDocumentBuffer(o,{password:t.password})}handleLoadTask(t,o,n){o.wait(o=>{this.dispatchCoreAction(e.setDocumentLoaded(t,o))},e=>{this.handleLoadError(t,e,n)})}handleLoadError(t,o,n){var r,s,i;const c=(null==(r=o.reason)?void 0:r.message)||"Failed to load document";this.logger.error("DocumentManagerPlugin",n,"Failed to load document",o),this.dispatchCoreAction(e.setDocumentError(t,c,null==(s=o.reason)?void 0:s.code,o.reason)),this.documentError$.emit({documentId:t,message:c,code:null==(i=o.reason)?void 0:i.code,reason:o.reason})}generateDocumentId(){return`doc-${Date.now()}-${Math.random().toString(36).substr(2,9)}`}extractNameFromUrl(e){try{const t=new URL(e),o=t.pathname.split("/").pop();if(!o)return;let n=decodeURIComponent(o);return n.toLowerCase().endsWith(".pdf")||(n+=".pdf"),n}catch{return}}async initialize(e){var t;if(this.logger.info("DocumentManagerPlugin","Initialize","Document Manager Plugin initialized",{maxDocuments:this.maxDocuments,initialDocumentsCount:(null==(t=e.initialDocuments)?void 0:t.length)??0}),e.initialDocuments&&e.initialDocuments.length>0)for(const n of e.initialDocuments)try{"buffer"in n?this.openDocumentBuffer(n):"url"in n&&this.openDocumentUrl(n)}catch(o){this.logger.error("DocumentManagerPlugin","Initialize","Failed to initiate initial document load",o)}}async destroy(){await this.closeAllDocuments().toPromise(),this.loadOptions.clear(),this.documentOpened$.clear(),this.documentClosed$.clear(),this.activeDocumentChanged$.clear(),this.documentOrderChanged$.clear(),this.documentError$.clear(),super.destroy()}};o.id="document-manager";let n=o;const r="document-manager",s={id:r,name:"Document Manager Plugin",version:"1.0.0",provides:["document-manager"],requires:[],optional:[],defaultConfig:{maxDocuments:10}},i={manifest:s,create:(e,t)=>new n(r,e,t),reducer:e=>e,initialState:{}};exports.DOCUMENT_MANAGER_PLUGIN_ID=r,exports.DocumentManagerPlugin=n,exports.DocumentManagerPluginPackage=i,exports.manifest=s;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/lib/document-manager-plugin.ts","../src/lib/manifest.ts","../src/lib/index.ts"],"sourcesContent":["import {\n BasePlugin,\n PluginRegistry,\n createBehaviorEmitter,\n startLoadingDocument,\n setDocumentLoaded,\n setDocumentError,\n retryLoadingDocument,\n closeDocument as closeDocumentAction,\n setActiveDocument as setActiveDocumentAction,\n moveDocument as moveDocumentAction,\n reorderDocuments as reorderDocumentsAction,\n DocumentState,\n Unsubscribe,\n Listener,\n createEmitter,\n} from '@embedpdf/core';\nimport {\n PdfDocumentObject,\n Task,\n PdfFile,\n PdfFileUrl,\n PdfErrorReason,\n PdfErrorCode,\n} from '@embedpdf/models';\n\nimport {\n DocumentManagerPluginConfig,\n DocumentManagerCapability,\n DocumentChangeEvent,\n DocumentOrderChangeEvent,\n LoadDocumentUrlOptions,\n LoadDocumentBufferOptions,\n RetryOptions,\n DocumentErrorEvent,\n OpenDocumentResponse,\n OpenFileDialogOptions,\n} from './types';\n\nexport class DocumentManagerPlugin extends BasePlugin<\n DocumentManagerPluginConfig,\n DocumentManagerCapability\n> {\n static readonly id = 'document-manager' as const;\n\n private readonly documentOpened$ = createBehaviorEmitter<DocumentState>();\n private readonly documentClosed$ = createBehaviorEmitter<string>();\n private readonly activeDocumentChanged$ = createBehaviorEmitter<DocumentChangeEvent>();\n private readonly documentError$ = createBehaviorEmitter<DocumentErrorEvent>();\n\n private readonly documentOrderChanged$ = createBehaviorEmitter<DocumentOrderChangeEvent>();\n\n private readonly openFileRequest$ = createEmitter<{\n task: Task<OpenDocumentResponse, PdfErrorReason>;\n options?: OpenFileDialogOptions;\n }>();\n\n private maxDocuments?: number;\n\n private loadOptions = new Map<string, LoadDocumentUrlOptions | LoadDocumentBufferOptions>();\n\n constructor(\n public readonly id: string,\n registry: PluginRegistry,\n config?: DocumentManagerPluginConfig,\n ) {\n super(id, registry);\n this.maxDocuments = config?.maxDocuments;\n }\n\n protected buildCapability(): DocumentManagerCapability {\n return {\n // Document lifecycle - orchestration only\n openFileDialog: (options) => this.openFileDialog(options),\n openDocumentUrl: (options) => this.openDocumentUrl(options),\n openDocumentBuffer: (options) => this.openDocumentBuffer(options),\n retryDocument: (documentId, options) => this.retryDocument(documentId, options),\n closeDocument: (documentId) => this.closeDocument(documentId),\n closeAllDocuments: () => this.closeAllDocuments(),\n\n setActiveDocument: (documentId) => {\n if (!this.isDocumentOpen(documentId)) {\n throw new Error(`Cannot set active document: ${documentId} is not open`);\n }\n this.dispatchCoreAction(setActiveDocumentAction(documentId));\n },\n\n getActiveDocumentId: () => this.coreState.core.activeDocumentId,\n getActiveDocument: () => {\n const activeId = this.coreState.core.activeDocumentId;\n if (!activeId) return null;\n return this.coreState.core.documents[activeId]?.document ?? null;\n },\n\n getDocumentOrder: () => this.coreState.core.documentOrder,\n\n moveDocument: (documentId, toIndex) => {\n this.dispatchCoreAction(moveDocumentAction(documentId, toIndex));\n },\n\n swapDocuments: (id1, id2) => {\n const order = this.coreState.core.documentOrder;\n const index1 = order.indexOf(id1);\n const index2 = order.indexOf(id2);\n\n if (index1 === -1 || index2 === -1) {\n throw new Error('One or both documents not found in order');\n }\n\n const newOrder = [...order];\n [newOrder[index1], newOrder[index2]] = [newOrder[index2], newOrder[index1]];\n\n this.dispatchCoreAction(reorderDocumentsAction(newOrder));\n },\n\n getDocument: (documentId) => {\n return this.coreState.core.documents[documentId]?.document ?? null;\n },\n\n getDocumentState: (documentId) => {\n return this.coreState.core.documents[documentId] ?? null;\n },\n\n getOpenDocuments: () => {\n return this.coreState.core.documentOrder\n .map((documentId) => this.coreState.core.documents[documentId])\n .filter((state): state is DocumentState => state !== null);\n },\n\n isDocumentOpen: (documentId) => this.isDocumentOpen(documentId),\n\n getDocumentCount: () => {\n return Object.keys(this.coreState.core.documents).length;\n },\n\n getDocumentIndex: (documentId) => {\n return this.coreState.core.documentOrder.indexOf(documentId);\n },\n\n // Events\n onDocumentOpened: this.documentOpened$.on,\n onDocumentClosed: this.documentClosed$.on,\n onDocumentError: this.documentError$.on,\n onActiveDocumentChanged: this.activeDocumentChanged$.on,\n onDocumentOrderChanged: this.documentOrderChanged$.on,\n };\n }\n\n /**\n * Check if a document is currently open\n */\n private isDocumentOpen(documentId: string): boolean {\n return !!this.coreState.core.documents[documentId];\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Lifecycle Hooks (from BasePlugin)\n // ─────────────────────────────────────────────────────────\n\n protected override onDocumentLoaded(documentId: string): void {\n const docState = this.coreState.core.documents[documentId];\n if (!docState || docState.status !== 'loaded') return;\n\n // Clean up load options to free memory\n this.loadOptions.delete(documentId);\n\n // Emit opened event\n this.documentOpened$.emit(docState);\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'DocumentOpened',\n `Document ${documentId} opened successfully`,\n { name: docState.name },\n );\n }\n\n protected override onDocumentClosed(documentId: string): void {\n // Clean up load options\n this.loadOptions.delete(documentId);\n\n // Emit closed event\n this.documentClosed$.emit(documentId);\n\n this.logger.info('DocumentManagerPlugin', 'DocumentClosed', `Document ${documentId} closed`);\n }\n\n protected override onActiveDocumentChanged(\n previousId: string | null,\n currentId: string | null,\n ): void {\n this.activeDocumentChanged$.emit({\n previousDocumentId: previousId,\n currentDocumentId: currentId,\n });\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'ActiveDocumentChanged',\n `Active document changed from ${previousId} to ${currentId}`,\n );\n }\n\n protected override onCoreStoreUpdated(oldState: any, newState: any): void {\n // Emit order change event if order changed\n if (oldState.core.documentOrder !== newState.core.documentOrder) {\n this.documentOrderChanged$.emit({\n order: newState.core.documentOrder,\n });\n }\n }\n\n public onOpenFileRequest(\n handler: Listener<{\n task: Task<OpenDocumentResponse, PdfErrorReason>;\n options?: OpenFileDialogOptions;\n }>,\n ): Unsubscribe {\n return this.openFileRequest$.on(handler);\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Loading (orchestration only - no state management)\n // ─────────────────────────────────────────────────────────\n\n private openDocumentUrl(\n options: LoadDocumentUrlOptions,\n ): Task<OpenDocumentResponse, PdfErrorReason> {\n const task = new Task<OpenDocumentResponse, PdfErrorReason>();\n\n const documentId = options.documentId || this.generateDocumentId();\n\n // Check limit\n const limitError = this.checkDocumentLimit();\n if (limitError) {\n task.reject(limitError);\n return task;\n }\n\n const documentName = options.name ?? this.extractNameFromUrl(options.url);\n\n // Store options for potential retry\n this.loadOptions.set(documentId, options);\n\n this.dispatchCoreAction(\n startLoadingDocument(\n documentId,\n documentName,\n options.scale,\n options.rotation,\n !!options.password,\n options.autoActivate,\n ),\n );\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'OpenDocumentUrl',\n `Starting to load document from URL: ${options.url}`,\n { documentId, passwordProvided: !!options.password },\n );\n\n // Create file object and call engine\n const file: PdfFileUrl = {\n id: documentId,\n url: options.url,\n };\n const engineTask = this.engine.openDocumentUrl(file, {\n password: options.password,\n mode: options.mode,\n requestOptions: options.requestOptions,\n });\n\n task.resolve({\n documentId,\n task: engineTask,\n });\n\n // Handle result\n this.handleLoadTask(documentId, engineTask, 'OpenDocumentUrl');\n\n return task;\n }\n\n private openDocumentBuffer(\n options: LoadDocumentBufferOptions,\n ): Task<OpenDocumentResponse, PdfErrorReason> {\n const task = new Task<OpenDocumentResponse, PdfErrorReason>();\n\n const limitError = this.checkDocumentLimit();\n if (limitError) {\n task.reject(limitError);\n return task;\n }\n\n const documentId = options.documentId || this.generateDocumentId();\n\n // Store options for potential retry\n this.loadOptions.set(documentId, options);\n\n this.dispatchCoreAction(\n startLoadingDocument(\n documentId,\n options.name,\n options.scale,\n options.rotation,\n !!options.password,\n options.autoActivate,\n ),\n );\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'OpenDocumentBuffer',\n `Starting to load document from buffer: ${options.name}`,\n { documentId, passwordProvided: !!options.password },\n );\n\n // Create file object and call engine\n const file: PdfFile = {\n id: documentId,\n content: options.buffer,\n };\n const engineTask = this.engine.openDocumentBuffer(file, {\n password: options.password,\n });\n\n task.resolve({\n documentId,\n task: engineTask,\n });\n\n // Handle result\n this.handleLoadTask(documentId, engineTask, 'OpenDocumentBuffer');\n\n return task;\n }\n\n private retryDocument(\n documentId: string,\n retryOptions?: RetryOptions,\n ): Task<OpenDocumentResponse, PdfErrorReason> {\n const task = new Task<OpenDocumentResponse, PdfErrorReason>();\n\n // Validate retry\n const validation = this.validateRetry(documentId);\n if (!validation.valid) {\n task.reject(validation.error!);\n return task;\n }\n\n const originalOptions = this.loadOptions.get(documentId)!;\n\n // Merge retry options (e.g., new password)\n const mergedOptions = {\n ...originalOptions,\n ...(retryOptions?.password && { password: retryOptions.password }),\n };\n\n // Update stored options\n this.loadOptions.set(documentId, mergedOptions);\n\n // Set back to loading state\n this.dispatchCoreAction(retryLoadingDocument(documentId, !!retryOptions?.password));\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'RetryDocument',\n `Retrying to load document ${documentId}`,\n { passwordProvided: !!retryOptions?.password },\n );\n\n // Execute retry based on type\n const engineTask =\n 'url' in mergedOptions\n ? this.retryUrlDocument(documentId, mergedOptions)\n : this.retryBufferDocument(documentId, mergedOptions);\n\n task.resolve({\n documentId,\n task: engineTask,\n });\n\n // Handle result\n this.handleLoadTask(documentId, engineTask, 'RetryDocument');\n\n return task;\n }\n\n private openFileDialog(\n options?: OpenFileDialogOptions,\n ): Task<OpenDocumentResponse, PdfErrorReason> {\n const task = new Task<OpenDocumentResponse, PdfErrorReason>();\n this.openFileRequest$.emit({ task, options });\n return task;\n }\n\n private closeDocument(documentId: string): Task<void, PdfErrorReason> {\n const task = new Task<void, PdfErrorReason>();\n\n const docState = this.coreState.core.documents[documentId];\n if (!docState) {\n this.logger.warn(\n 'DocumentManagerPlugin',\n 'CloseDocument',\n `Cannot close document ${documentId}: not found in state`,\n );\n task.resolve();\n return task;\n }\n\n // ✅ SIMPLIFIED: Just dispatch - reducer calculates next active!\n if (docState.status === 'loaded' && docState.document) {\n this.engine.closeDocument(docState.document).wait(\n () => {\n this.dispatchCoreAction(closeDocumentAction(documentId));\n task.resolve();\n },\n (error) => {\n this.logger.error(\n 'DocumentManagerPlugin',\n 'CloseDocument',\n `Failed to close document ${documentId}`,\n error,\n );\n task.fail(error);\n },\n );\n } else {\n // Document is not loaded (error, loading, etc.), just clean up state\n this.logger.info(\n 'DocumentManagerPlugin',\n 'CloseDocument',\n `Closing document ${documentId} in ${docState.status} state (skipping engine close)`,\n );\n this.dispatchCoreAction(closeDocumentAction(documentId));\n task.resolve();\n }\n\n return task;\n }\n\n private closeAllDocuments(): Task<void[], PdfErrorReason> {\n const documentIds = Object.keys(this.coreState.core.documents);\n const tasks = documentIds.map((documentId) => this.closeDocument(documentId));\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'CloseAllDocuments',\n `Closing ${documentIds.length} documents`,\n );\n\n return Task.all(tasks);\n }\n\n // ─────────────────────────────────────────────────────────\n // Helper Methods\n // ─────────────────────────────────────────────────────────\n\n private checkDocumentLimit(): PdfErrorReason | null {\n if (\n this.maxDocuments &&\n Object.keys(this.coreState.core.documents).length >= this.maxDocuments\n ) {\n return {\n code: PdfErrorCode.Unknown,\n message: `Maximum number of documents (${this.maxDocuments}) reached`,\n };\n }\n return null;\n }\n\n private validateRetry(documentId: string): {\n valid: boolean;\n error?: PdfErrorReason;\n } {\n const docState = this.coreState.core.documents[documentId];\n\n if (!docState) {\n return {\n valid: false,\n error: {\n code: PdfErrorCode.NotFound,\n message: `Document ${documentId} not found`,\n },\n };\n }\n\n if (docState.status === 'loaded') {\n return {\n valid: false,\n error: {\n code: PdfErrorCode.Unknown,\n message: `Document ${documentId} is already loaded successfully`,\n },\n };\n }\n\n if (docState.status !== 'error') {\n return {\n valid: false,\n error: {\n code: PdfErrorCode.Unknown,\n message: `Document ${documentId} is not in error state (current state: ${docState.status})`,\n },\n };\n }\n\n if (!this.loadOptions.has(documentId)) {\n return {\n valid: false,\n error: {\n code: PdfErrorCode.Unknown,\n message: `No retry information available for document ${documentId}`,\n },\n };\n }\n\n return { valid: true };\n }\n\n private retryUrlDocument(\n documentId: string,\n options: LoadDocumentUrlOptions,\n ): Task<PdfDocumentObject, PdfErrorReason> {\n const file: PdfFileUrl = {\n id: documentId,\n url: options.url,\n };\n\n return this.engine.openDocumentUrl(file, {\n password: options.password,\n mode: options.mode,\n requestOptions: options.requestOptions,\n });\n }\n\n private retryBufferDocument(\n documentId: string,\n options: LoadDocumentBufferOptions,\n ): Task<PdfDocumentObject, PdfErrorReason> {\n const file: PdfFile = {\n id: documentId,\n content: options.buffer,\n };\n\n return this.engine.openDocumentBuffer(file, {\n password: options.password,\n });\n }\n\n private handleLoadTask(\n documentId: string,\n engineTask: Task<PdfDocumentObject, PdfErrorReason>,\n context: string,\n ): void {\n engineTask.wait(\n (pdfDocument) => {\n this.dispatchCoreAction(setDocumentLoaded(documentId, pdfDocument));\n },\n (error) => {\n this.handleLoadError(documentId, error, context);\n },\n );\n }\n\n private handleLoadError(documentId: string, error: any, context: string): void {\n const errorMessage = error.reason?.message || 'Failed to load document';\n\n this.logger.error('DocumentManagerPlugin', context, 'Failed to load document', error);\n\n this.dispatchCoreAction(\n setDocumentError(documentId, errorMessage, error.reason?.code, error.reason),\n );\n\n this.documentError$.emit({\n documentId,\n message: errorMessage,\n code: error.reason?.code,\n reason: error.reason,\n });\n }\n\n private generateDocumentId(): string {\n return `doc-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n }\n\n private extractNameFromUrl(url: string): string | undefined {\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n const lastSegment = pathname.split('/').pop();\n if (!lastSegment) {\n return undefined;\n }\n let filename = decodeURIComponent(lastSegment);\n if (!filename.toLowerCase().endsWith('.pdf')) {\n filename += '.pdf';\n }\n return filename;\n } catch {\n return undefined;\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Plugin Lifecycle\n // ─────────────────────────────────────────────────────────\n\n async initialize(config: DocumentManagerPluginConfig): Promise<void> {\n this.logger.info('DocumentManagerPlugin', 'Initialize', 'Document Manager Plugin initialized', {\n maxDocuments: this.maxDocuments,\n initialDocumentsCount: config.initialDocuments?.length ?? 0,\n });\n\n // Handle initial documents from config\n if (config.initialDocuments && config.initialDocuments.length > 0) {\n // Process strictly in order\n for (const docConfig of config.initialDocuments) {\n try {\n // Type guard to distinguish between URL and Buffer options\n if ('buffer' in docConfig) {\n this.openDocumentBuffer(docConfig);\n } else if ('url' in docConfig) {\n this.openDocumentUrl(docConfig);\n }\n } catch (error) {\n this.logger.error(\n 'DocumentManagerPlugin',\n 'Initialize',\n 'Failed to initiate initial document load',\n error,\n );\n }\n }\n }\n }\n\n async destroy(): Promise<void> {\n // Close all documents\n await this.closeAllDocuments().toPromise();\n\n // Clear load options\n this.loadOptions.clear();\n\n // Clear emitters\n this.documentOpened$.clear();\n this.documentClosed$.clear();\n this.activeDocumentChanged$.clear();\n this.documentOrderChanged$.clear();\n this.documentError$.clear();\n\n super.destroy();\n }\n}\n","import { PluginManifest } from '@embedpdf/core';\nimport { DocumentManagerPluginConfig } from './types';\n\nexport const DOCUMENT_MANAGER_PLUGIN_ID = 'document-manager';\n\nexport const manifest: PluginManifest<DocumentManagerPluginConfig> = {\n id: DOCUMENT_MANAGER_PLUGIN_ID,\n name: 'Document Manager Plugin',\n version: '1.0.0',\n provides: ['document-manager'],\n requires: [],\n optional: [],\n defaultConfig: {\n maxDocuments: 10,\n },\n};\n","import { PluginPackage } from '@embedpdf/core';\nimport { DocumentManagerPlugin } from './document-manager-plugin';\nimport { manifest, DOCUMENT_MANAGER_PLUGIN_ID } from './manifest';\nimport { DocumentManagerPluginConfig } from './types';\n\nexport const DocumentManagerPluginPackage: PluginPackage<\n DocumentManagerPlugin,\n DocumentManagerPluginConfig\n> = {\n manifest,\n create: (registry, config) =>\n new DocumentManagerPlugin(DOCUMENT_MANAGER_PLUGIN_ID, registry, config),\n reducer: (state) => state,\n initialState: {},\n};\n\nexport * from './document-manager-plugin';\nexport * from './types';\nexport * from './manifest';\n"],"names":["_DocumentManagerPlugin","BasePlugin","constructor","id","registry","config","super","this","documentOpened$","createBehaviorEmitter","documentClosed$","activeDocumentChanged$","documentError$","documentOrderChanged$","openFileRequest$","createEmitter","loadOptions","Map","maxDocuments","buildCapability","openFileDialog","options","openDocumentUrl","openDocumentBuffer","retryDocument","documentId","closeDocument","closeAllDocuments","setActiveDocument","isDocumentOpen","Error","dispatchCoreAction","setActiveDocumentAction","getActiveDocumentId","coreState","core","activeDocumentId","getActiveDocument","activeId","_a","documents","document","getDocumentOrder","documentOrder","moveDocument","toIndex","moveDocumentAction","swapDocuments","id1","id2","order","index1","indexOf","index2","newOrder","reorderDocumentsAction","getDocument","getDocumentState","getOpenDocuments","map","filter","state","getDocumentCount","Object","keys","length","getDocumentIndex","onDocumentOpened","on","onDocumentClosed","onDocumentError","onActiveDocumentChanged","onDocumentOrderChanged","onDocumentLoaded","docState","status","delete","emit","logger","info","name","previousId","currentId","previousDocumentId","currentDocumentId","onCoreStoreUpdated","oldState","newState","onOpenFileRequest","handler","task","Task","generateDocumentId","limitError","checkDocumentLimit","reject","documentName","extractNameFromUrl","url","set","startLoadingDocument","scale","rotation","password","autoActivate","passwordProvided","file","engineTask","engine","mode","requestOptions","resolve","handleLoadTask","content","buffer","retryOptions","validation","validateRetry","valid","error","mergedOptions","get","retryLoadingDocument","retryUrlDocument","retryBufferDocument","wait","closeDocumentAction","fail","warn","documentIds","tasks","all","code","PdfErrorCode","Unknown","message","has","NotFound","context","pdfDocument","setDocumentLoaded","handleLoadError","errorMessage","reason","setDocumentError","_b","_c","Date","now","Math","random","toString","substr","urlObj","URL","lastSegment","pathname","split","pop","filename","decodeURIComponent","toLowerCase","endsWith","initialize","initialDocumentsCount","initialDocuments","docConfig","destroy","toPromise","clear","DocumentManagerPlugin","DOCUMENT_MANAGER_PLUGIN_ID","manifest","version","provides","requires","optional","defaultConfig","DocumentManagerPluginPackage","create","reducer","initialState"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/lib/document-manager-plugin.ts","../src/lib/manifest.ts","../src/lib/index.ts"],"sourcesContent":["import {\n BasePlugin,\n PluginRegistry,\n createBehaviorEmitter,\n startLoadingDocument,\n setDocumentLoaded,\n setDocumentError,\n retryLoadingDocument,\n closeDocument as closeDocumentAction,\n setActiveDocument as setActiveDocumentAction,\n moveDocument as moveDocumentAction,\n reorderDocuments as reorderDocumentsAction,\n updateDocumentSecurity,\n DocumentState,\n Unsubscribe,\n Listener,\n createEmitter,\n} from '@embedpdf/core';\nimport {\n PdfDocumentObject,\n Task,\n PdfFile,\n PdfFileUrl,\n PdfErrorReason,\n PdfErrorCode,\n} from '@embedpdf/models';\n\nimport {\n DocumentManagerPluginConfig,\n DocumentManagerCapability,\n DocumentChangeEvent,\n DocumentOrderChangeEvent,\n LoadDocumentUrlOptions,\n LoadDocumentBufferOptions,\n RetryOptions,\n DocumentErrorEvent,\n OpenDocumentResponse,\n OpenFileDialogOptions,\n SetEncryptionOptions,\n} from './types';\n\nexport class DocumentManagerPlugin extends BasePlugin<\n DocumentManagerPluginConfig,\n DocumentManagerCapability\n> {\n static readonly id = 'document-manager' as const;\n\n private readonly documentOpened$ = createBehaviorEmitter<DocumentState>();\n private readonly documentClosed$ = createBehaviorEmitter<string>();\n private readonly activeDocumentChanged$ = createBehaviorEmitter<DocumentChangeEvent>();\n private readonly documentError$ = createBehaviorEmitter<DocumentErrorEvent>();\n\n private readonly documentOrderChanged$ = createBehaviorEmitter<DocumentOrderChangeEvent>();\n\n private readonly openFileRequest$ = createEmitter<{\n task: Task<OpenDocumentResponse, PdfErrorReason>;\n options?: OpenFileDialogOptions;\n }>();\n\n private maxDocuments?: number;\n\n private loadOptions = new Map<string, LoadDocumentUrlOptions | LoadDocumentBufferOptions>();\n\n constructor(\n public readonly id: string,\n registry: PluginRegistry,\n config?: DocumentManagerPluginConfig,\n ) {\n super(id, registry);\n this.maxDocuments = config?.maxDocuments;\n }\n\n protected buildCapability(): DocumentManagerCapability {\n return {\n // Document lifecycle - orchestration only\n openFileDialog: (options) => this.openFileDialog(options),\n openDocumentUrl: (options) => this.openDocumentUrl(options),\n openDocumentBuffer: (options) => this.openDocumentBuffer(options),\n retryDocument: (documentId, options) => this.retryDocument(documentId, options),\n closeDocument: (documentId) => this.closeDocument(documentId),\n closeAllDocuments: () => this.closeAllDocuments(),\n\n setActiveDocument: (documentId) => {\n if (!this.isDocumentOpen(documentId)) {\n throw new Error(`Cannot set active document: ${documentId} is not open`);\n }\n this.dispatchCoreAction(setActiveDocumentAction(documentId));\n },\n\n getActiveDocumentId: () => this.coreState.core.activeDocumentId,\n getActiveDocument: () => {\n const activeId = this.coreState.core.activeDocumentId;\n if (!activeId) return null;\n return this.coreState.core.documents[activeId]?.document ?? null;\n },\n\n getDocumentOrder: () => this.coreState.core.documentOrder,\n\n moveDocument: (documentId, toIndex) => {\n this.dispatchCoreAction(moveDocumentAction(documentId, toIndex));\n },\n\n swapDocuments: (id1, id2) => {\n const order = this.coreState.core.documentOrder;\n const index1 = order.indexOf(id1);\n const index2 = order.indexOf(id2);\n\n if (index1 === -1 || index2 === -1) {\n throw new Error('One or both documents not found in order');\n }\n\n const newOrder = [...order];\n [newOrder[index1], newOrder[index2]] = [newOrder[index2], newOrder[index1]];\n\n this.dispatchCoreAction(reorderDocumentsAction(newOrder));\n },\n\n getDocument: (documentId) => {\n return this.coreState.core.documents[documentId]?.document ?? null;\n },\n\n getDocumentState: (documentId) => {\n return this.coreState.core.documents[documentId] ?? null;\n },\n\n getOpenDocuments: () => {\n return this.coreState.core.documentOrder\n .map((documentId) => this.coreState.core.documents[documentId])\n .filter((state): state is DocumentState => state !== null);\n },\n\n isDocumentOpen: (documentId) => this.isDocumentOpen(documentId),\n\n getDocumentCount: () => {\n return Object.keys(this.coreState.core.documents).length;\n },\n\n getDocumentIndex: (documentId) => {\n return this.coreState.core.documentOrder.indexOf(documentId);\n },\n\n // Security\n setDocumentEncryption: (documentId, options) =>\n this.setDocumentEncryption(documentId, options),\n unlockOwnerPermissions: (documentId, ownerPassword) =>\n this.unlockOwnerPermissions(documentId, ownerPassword),\n removeEncryption: (documentId) => this.removeEncryption(documentId),\n\n // Events\n onDocumentOpened: this.documentOpened$.on,\n onDocumentClosed: this.documentClosed$.on,\n onDocumentError: this.documentError$.on,\n onActiveDocumentChanged: this.activeDocumentChanged$.on,\n onDocumentOrderChanged: this.documentOrderChanged$.on,\n };\n }\n\n /**\n * Check if a document is currently open\n */\n private isDocumentOpen(documentId: string): boolean {\n return !!this.coreState.core.documents[documentId];\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Lifecycle Hooks (from BasePlugin)\n // ─────────────────────────────────────────────────────────\n\n protected override onDocumentLoaded(documentId: string): void {\n const docState = this.coreState.core.documents[documentId];\n if (!docState || docState.status !== 'loaded') return;\n\n // Clean up load options to free memory\n this.loadOptions.delete(documentId);\n\n // Emit opened event\n this.documentOpened$.emit(docState);\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'DocumentOpened',\n `Document ${documentId} opened successfully`,\n { name: docState.name },\n );\n }\n\n protected override onDocumentClosed(documentId: string): void {\n // Clean up load options\n this.loadOptions.delete(documentId);\n\n // Emit closed event\n this.documentClosed$.emit(documentId);\n\n this.logger.info('DocumentManagerPlugin', 'DocumentClosed', `Document ${documentId} closed`);\n }\n\n protected override onActiveDocumentChanged(\n previousId: string | null,\n currentId: string | null,\n ): void {\n this.activeDocumentChanged$.emit({\n previousDocumentId: previousId,\n currentDocumentId: currentId,\n });\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'ActiveDocumentChanged',\n `Active document changed from ${previousId} to ${currentId}`,\n );\n }\n\n protected override onCoreStoreUpdated(oldState: any, newState: any): void {\n // Emit order change event if order changed\n if (oldState.core.documentOrder !== newState.core.documentOrder) {\n this.documentOrderChanged$.emit({\n order: newState.core.documentOrder,\n });\n }\n }\n\n public onOpenFileRequest(\n handler: Listener<{\n task: Task<OpenDocumentResponse, PdfErrorReason>;\n options?: OpenFileDialogOptions;\n }>,\n ): Unsubscribe {\n return this.openFileRequest$.on(handler);\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Loading (orchestration only - no state management)\n // ─────────────────────────────────────────────────────────\n\n private openDocumentUrl(\n options: LoadDocumentUrlOptions,\n ): Task<OpenDocumentResponse, PdfErrorReason> {\n const task = new Task<OpenDocumentResponse, PdfErrorReason>();\n\n const documentId = options.documentId || this.generateDocumentId();\n\n // Check limit\n const limitError = this.checkDocumentLimit();\n if (limitError) {\n task.reject(limitError);\n return task;\n }\n\n const documentName = options.name ?? this.extractNameFromUrl(options.url);\n\n // Store options for potential retry\n this.loadOptions.set(documentId, options);\n\n this.dispatchCoreAction(\n startLoadingDocument(\n documentId,\n documentName,\n options.scale,\n options.rotation,\n !!options.password,\n options.autoActivate,\n options.permissions,\n ),\n );\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'OpenDocumentUrl',\n `Starting to load document from URL: ${options.url}`,\n { documentId, passwordProvided: !!options.password },\n );\n\n // Create file object and call engine\n const file: PdfFileUrl = {\n id: documentId,\n url: options.url,\n };\n const engineTask = this.engine.openDocumentUrl(file, {\n password: options.password,\n mode: options.mode,\n requestOptions: options.requestOptions,\n });\n\n task.resolve({\n documentId,\n task: engineTask,\n });\n\n // Handle result\n this.handleLoadTask(documentId, engineTask, 'OpenDocumentUrl');\n\n return task;\n }\n\n private openDocumentBuffer(\n options: LoadDocumentBufferOptions,\n ): Task<OpenDocumentResponse, PdfErrorReason> {\n const task = new Task<OpenDocumentResponse, PdfErrorReason>();\n\n const limitError = this.checkDocumentLimit();\n if (limitError) {\n task.reject(limitError);\n return task;\n }\n\n const documentId = options.documentId || this.generateDocumentId();\n\n // Store options for potential retry\n this.loadOptions.set(documentId, options);\n\n this.dispatchCoreAction(\n startLoadingDocument(\n documentId,\n options.name,\n options.scale,\n options.rotation,\n !!options.password,\n options.autoActivate,\n options.permissions,\n ),\n );\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'OpenDocumentBuffer',\n `Starting to load document from buffer: ${options.name}`,\n { documentId, passwordProvided: !!options.password },\n );\n\n // Create file object and call engine\n const file: PdfFile = {\n id: documentId,\n content: options.buffer,\n };\n const engineTask = this.engine.openDocumentBuffer(file, {\n password: options.password,\n });\n\n task.resolve({\n documentId,\n task: engineTask,\n });\n\n // Handle result\n this.handleLoadTask(documentId, engineTask, 'OpenDocumentBuffer');\n\n return task;\n }\n\n private retryDocument(\n documentId: string,\n retryOptions?: RetryOptions,\n ): Task<OpenDocumentResponse, PdfErrorReason> {\n const task = new Task<OpenDocumentResponse, PdfErrorReason>();\n\n // Validate retry\n const validation = this.validateRetry(documentId);\n if (!validation.valid) {\n task.reject(validation.error!);\n return task;\n }\n\n const originalOptions = this.loadOptions.get(documentId)!;\n\n // Merge retry options (e.g., new password)\n const mergedOptions = {\n ...originalOptions,\n ...(retryOptions?.password && { password: retryOptions.password }),\n };\n\n // Update stored options\n this.loadOptions.set(documentId, mergedOptions);\n\n // Set back to loading state\n this.dispatchCoreAction(retryLoadingDocument(documentId, !!retryOptions?.password));\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'RetryDocument',\n `Retrying to load document ${documentId}`,\n { passwordProvided: !!retryOptions?.password },\n );\n\n // Execute retry based on type\n const engineTask =\n 'url' in mergedOptions\n ? this.retryUrlDocument(documentId, mergedOptions)\n : this.retryBufferDocument(documentId, mergedOptions);\n\n task.resolve({\n documentId,\n task: engineTask,\n });\n\n // Handle result\n this.handleLoadTask(documentId, engineTask, 'RetryDocument');\n\n return task;\n }\n\n private openFileDialog(\n options?: OpenFileDialogOptions,\n ): Task<OpenDocumentResponse, PdfErrorReason> {\n const task = new Task<OpenDocumentResponse, PdfErrorReason>();\n this.openFileRequest$.emit({ task, options });\n return task;\n }\n\n private closeDocument(documentId: string): Task<void, PdfErrorReason> {\n const task = new Task<void, PdfErrorReason>();\n\n const docState = this.coreState.core.documents[documentId];\n if (!docState) {\n this.logger.warn(\n 'DocumentManagerPlugin',\n 'CloseDocument',\n `Cannot close document ${documentId}: not found in state`,\n );\n task.resolve();\n return task;\n }\n\n // ✅ SIMPLIFIED: Just dispatch - reducer calculates next active!\n if (docState.status === 'loaded' && docState.document) {\n this.engine.closeDocument(docState.document).wait(\n () => {\n this.dispatchCoreAction(closeDocumentAction(documentId));\n task.resolve();\n },\n (error) => {\n this.logger.error(\n 'DocumentManagerPlugin',\n 'CloseDocument',\n `Failed to close document ${documentId}`,\n error,\n );\n task.fail(error);\n },\n );\n } else {\n // Document is not loaded (error, loading, etc.), just clean up state\n this.logger.info(\n 'DocumentManagerPlugin',\n 'CloseDocument',\n `Closing document ${documentId} in ${docState.status} state (skipping engine close)`,\n );\n this.dispatchCoreAction(closeDocumentAction(documentId));\n task.resolve();\n }\n\n return task;\n }\n\n private closeAllDocuments(): Task<void[], PdfErrorReason> {\n const documentIds = Object.keys(this.coreState.core.documents);\n const tasks = documentIds.map((documentId) => this.closeDocument(documentId));\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'CloseAllDocuments',\n `Closing ${documentIds.length} documents`,\n );\n\n return Task.all(tasks);\n }\n\n // ─────────────────────────────────────────────────────────\n // Security Methods\n // ─────────────────────────────────────────────────────────\n\n private setDocumentEncryption(\n documentId: string,\n options: SetEncryptionOptions,\n ): Task<boolean, PdfErrorReason> {\n const task = new Task<boolean, PdfErrorReason>();\n\n const docState = this.coreState.core.documents[documentId];\n if (!docState?.document) {\n task.reject({\n code: PdfErrorCode.DocNotOpen,\n message: `Document ${documentId} is not open`,\n });\n return task;\n }\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'SetDocumentEncryption',\n `Setting encryption on document ${documentId}`,\n { hasUserPassword: !!options.userPassword, allowedFlags: options.allowedFlags },\n );\n\n const engineTask = this.engine.setDocumentEncryption(\n docState.document,\n options.userPassword ?? '',\n options.ownerPassword,\n options.allowedFlags,\n );\n\n engineTask.wait(\n (success) => {\n if (success) {\n this.logger.info(\n 'DocumentManagerPlugin',\n 'SetDocumentEncryption',\n `Encryption set successfully on document ${documentId}`,\n );\n }\n task.resolve(success);\n },\n (error) => {\n this.logger.error(\n 'DocumentManagerPlugin',\n 'SetDocumentEncryption',\n `Failed to set encryption on document ${documentId}`,\n error,\n );\n task.fail(error);\n },\n );\n\n return task;\n }\n\n private unlockOwnerPermissions(\n documentId: string,\n ownerPassword: string,\n ): Task<boolean, PdfErrorReason> {\n const task = new Task<boolean, PdfErrorReason>();\n\n const docState = this.coreState.core.documents[documentId];\n if (!docState?.document) {\n task.reject({\n code: PdfErrorCode.DocNotOpen,\n message: `Document ${documentId} is not open`,\n });\n return task;\n }\n\n // Capture document reference before async operations\n const document = docState.document;\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'UnlockOwnerPermissions',\n `Attempting to unlock owner permissions on document ${documentId}`,\n );\n\n const engineTask = this.engine.unlockOwnerPermissions(document, ownerPassword);\n\n engineTask.wait(\n (success) => {\n if (success) {\n this.logger.info(\n 'DocumentManagerPlugin',\n 'UnlockOwnerPermissions',\n `Owner permissions unlocked on document ${documentId}`,\n );\n\n // Update the document security state in the store\n // After owner unlock, permissions are effectively \"all\"\n const fullPermissions = 0xffffffff; // All bits set = all permissions\n this.dispatchCoreAction(updateDocumentSecurity(documentId, fullPermissions, true));\n }\n task.resolve(success);\n },\n (error) => {\n this.logger.error(\n 'DocumentManagerPlugin',\n 'UnlockOwnerPermissions',\n `Failed to unlock owner permissions on document ${documentId}`,\n error,\n );\n task.fail(error);\n },\n );\n\n return task;\n }\n\n private removeEncryption(documentId: string): Task<boolean, PdfErrorReason> {\n const task = new Task<boolean, PdfErrorReason>();\n\n const docState = this.coreState.core.documents[documentId];\n if (!docState?.document) {\n task.reject({\n code: PdfErrorCode.DocNotOpen,\n message: `Document ${documentId} is not open`,\n });\n return task;\n }\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'RemoveEncryption',\n `Marking document ${documentId} for encryption removal on save`,\n );\n\n const engineTask = this.engine.removeEncryption(docState.document);\n\n engineTask.wait(\n (success) => {\n if (success) {\n this.logger.info(\n 'DocumentManagerPlugin',\n 'RemoveEncryption',\n `Document ${documentId} marked for encryption removal`,\n );\n }\n task.resolve(success);\n },\n (error) => {\n this.logger.error(\n 'DocumentManagerPlugin',\n 'RemoveEncryption',\n `Failed to mark document ${documentId} for encryption removal`,\n error,\n );\n task.fail(error);\n },\n );\n\n return task;\n }\n\n // ─────────────────────────────────────────────────────────\n // Helper Methods\n // ─────────────────────────────────────────────────────────\n\n private checkDocumentLimit(): PdfErrorReason | null {\n if (\n this.maxDocuments &&\n Object.keys(this.coreState.core.documents).length >= this.maxDocuments\n ) {\n return {\n code: PdfErrorCode.Unknown,\n message: `Maximum number of documents (${this.maxDocuments}) reached`,\n };\n }\n return null;\n }\n\n private validateRetry(documentId: string): {\n valid: boolean;\n error?: PdfErrorReason;\n } {\n const docState = this.coreState.core.documents[documentId];\n\n if (!docState) {\n return {\n valid: false,\n error: {\n code: PdfErrorCode.NotFound,\n message: `Document ${documentId} not found`,\n },\n };\n }\n\n if (docState.status === 'loaded') {\n return {\n valid: false,\n error: {\n code: PdfErrorCode.Unknown,\n message: `Document ${documentId} is already loaded successfully`,\n },\n };\n }\n\n if (docState.status !== 'error') {\n return {\n valid: false,\n error: {\n code: PdfErrorCode.Unknown,\n message: `Document ${documentId} is not in error state (current state: ${docState.status})`,\n },\n };\n }\n\n if (!this.loadOptions.has(documentId)) {\n return {\n valid: false,\n error: {\n code: PdfErrorCode.Unknown,\n message: `No retry information available for document ${documentId}`,\n },\n };\n }\n\n return { valid: true };\n }\n\n private retryUrlDocument(\n documentId: string,\n options: LoadDocumentUrlOptions,\n ): Task<PdfDocumentObject, PdfErrorReason> {\n const file: PdfFileUrl = {\n id: documentId,\n url: options.url,\n };\n\n return this.engine.openDocumentUrl(file, {\n password: options.password,\n mode: options.mode,\n requestOptions: options.requestOptions,\n });\n }\n\n private retryBufferDocument(\n documentId: string,\n options: LoadDocumentBufferOptions,\n ): Task<PdfDocumentObject, PdfErrorReason> {\n const file: PdfFile = {\n id: documentId,\n content: options.buffer,\n };\n\n return this.engine.openDocumentBuffer(file, {\n password: options.password,\n });\n }\n\n private handleLoadTask(\n documentId: string,\n engineTask: Task<PdfDocumentObject, PdfErrorReason>,\n context: string,\n ): void {\n engineTask.wait(\n (pdfDocument) => {\n this.dispatchCoreAction(setDocumentLoaded(documentId, pdfDocument));\n },\n (error) => {\n this.handleLoadError(documentId, error, context);\n },\n );\n }\n\n private handleLoadError(documentId: string, error: any, context: string): void {\n const errorMessage = error.reason?.message || 'Failed to load document';\n\n this.logger.error('DocumentManagerPlugin', context, 'Failed to load document', error);\n\n this.dispatchCoreAction(\n setDocumentError(documentId, errorMessage, error.reason?.code, error.reason),\n );\n\n this.documentError$.emit({\n documentId,\n message: errorMessage,\n code: error.reason?.code,\n reason: error.reason,\n });\n }\n\n private generateDocumentId(): string {\n return `doc-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n }\n\n private extractNameFromUrl(url: string): string | undefined {\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n const lastSegment = pathname.split('/').pop();\n if (!lastSegment) {\n return undefined;\n }\n let filename = decodeURIComponent(lastSegment);\n if (!filename.toLowerCase().endsWith('.pdf')) {\n filename += '.pdf';\n }\n return filename;\n } catch {\n return undefined;\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Plugin Lifecycle\n // ─────────────────────────────────────────────────────────\n\n async initialize(config: DocumentManagerPluginConfig): Promise<void> {\n this.logger.info('DocumentManagerPlugin', 'Initialize', 'Document Manager Plugin initialized', {\n maxDocuments: this.maxDocuments,\n initialDocumentsCount: config.initialDocuments?.length ?? 0,\n });\n\n // Handle initial documents from config\n if (config.initialDocuments && config.initialDocuments.length > 0) {\n // Process strictly in order\n for (const docConfig of config.initialDocuments) {\n try {\n // Type guard to distinguish between URL and Buffer options\n if ('buffer' in docConfig) {\n this.openDocumentBuffer(docConfig);\n } else if ('url' in docConfig) {\n this.openDocumentUrl(docConfig);\n }\n } catch (error) {\n this.logger.error(\n 'DocumentManagerPlugin',\n 'Initialize',\n 'Failed to initiate initial document load',\n error,\n );\n }\n }\n }\n }\n\n async destroy(): Promise<void> {\n // Close all documents\n await this.closeAllDocuments().toPromise();\n\n // Clear load options\n this.loadOptions.clear();\n\n // Clear emitters\n this.documentOpened$.clear();\n this.documentClosed$.clear();\n this.activeDocumentChanged$.clear();\n this.documentOrderChanged$.clear();\n this.documentError$.clear();\n\n super.destroy();\n }\n}\n","import { PluginManifest } from '@embedpdf/core';\nimport { DocumentManagerPluginConfig } from './types';\n\nexport const DOCUMENT_MANAGER_PLUGIN_ID = 'document-manager';\n\nexport const manifest: PluginManifest<DocumentManagerPluginConfig> = {\n id: DOCUMENT_MANAGER_PLUGIN_ID,\n name: 'Document Manager Plugin',\n version: '1.0.0',\n provides: ['document-manager'],\n requires: [],\n optional: [],\n defaultConfig: {\n maxDocuments: 10,\n },\n};\n","import { PluginPackage } from '@embedpdf/core';\nimport { DocumentManagerPlugin } from './document-manager-plugin';\nimport { manifest, DOCUMENT_MANAGER_PLUGIN_ID } from './manifest';\nimport { DocumentManagerPluginConfig } from './types';\n\nexport const DocumentManagerPluginPackage: PluginPackage<\n DocumentManagerPlugin,\n DocumentManagerPluginConfig\n> = {\n manifest,\n create: (registry, config) =>\n new DocumentManagerPlugin(DOCUMENT_MANAGER_PLUGIN_ID, registry, config),\n reducer: (state) => state,\n initialState: {},\n};\n\nexport * from './document-manager-plugin';\nexport * from './types';\nexport * from './manifest';\n"],"names":["_DocumentManagerPlugin","BasePlugin","constructor","id","registry","config","super","this","documentOpened$","createBehaviorEmitter","documentClosed$","activeDocumentChanged$","documentError$","documentOrderChanged$","openFileRequest$","createEmitter","loadOptions","Map","maxDocuments","buildCapability","openFileDialog","options","openDocumentUrl","openDocumentBuffer","retryDocument","documentId","closeDocument","closeAllDocuments","setActiveDocument","isDocumentOpen","Error","dispatchCoreAction","setActiveDocumentAction","getActiveDocumentId","coreState","core","activeDocumentId","getActiveDocument","activeId","_a","documents","document","getDocumentOrder","documentOrder","moveDocument","toIndex","moveDocumentAction","swapDocuments","id1","id2","order","index1","indexOf","index2","newOrder","reorderDocumentsAction","getDocument","getDocumentState","getOpenDocuments","map","filter","state","getDocumentCount","Object","keys","length","getDocumentIndex","setDocumentEncryption","unlockOwnerPermissions","ownerPassword","removeEncryption","onDocumentOpened","on","onDocumentClosed","onDocumentError","onActiveDocumentChanged","onDocumentOrderChanged","onDocumentLoaded","docState","status","delete","emit","logger","info","name","previousId","currentId","previousDocumentId","currentDocumentId","onCoreStoreUpdated","oldState","newState","onOpenFileRequest","handler","task","Task","generateDocumentId","limitError","checkDocumentLimit","reject","documentName","extractNameFromUrl","url","set","startLoadingDocument","scale","rotation","password","autoActivate","permissions","passwordProvided","file","engineTask","engine","mode","requestOptions","resolve","handleLoadTask","content","buffer","retryOptions","validation","validateRetry","valid","error","mergedOptions","get","retryLoadingDocument","retryUrlDocument","retryBufferDocument","wait","closeDocumentAction","fail","warn","documentIds","tasks","all","code","PdfErrorCode","DocNotOpen","message","hasUserPassword","userPassword","allowedFlags","success","fullPermissions","updateDocumentSecurity","Unknown","has","NotFound","context","pdfDocument","setDocumentLoaded","handleLoadError","errorMessage","reason","setDocumentError","_b","_c","Date","now","Math","random","toString","substr","urlObj","URL","lastSegment","pathname","split","pop","filename","decodeURIComponent","toLowerCase","endsWith","initialize","initialDocumentsCount","initialDocuments","docConfig","destroy","toPromise","clear","DocumentManagerPlugin","DOCUMENT_MANAGER_PLUGIN_ID","manifest","version","provides","requires","optional","defaultConfig","DocumentManagerPluginPackage","create","reducer","initialState"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { BasePlugin, createBehaviorEmitter, createEmitter, reorderDocuments, moveDocument, setActiveDocument, startLoadingDocument, retryLoadingDocument, closeDocument, setDocumentLoaded, setDocumentError } from "@embedpdf/core";
1
+ import { BasePlugin, createBehaviorEmitter, createEmitter, reorderDocuments, moveDocument, setActiveDocument, startLoadingDocument, retryLoadingDocument, closeDocument, updateDocumentSecurity, setDocumentLoaded, setDocumentError } from "@embedpdf/core";
2
2
  import { Task, PdfErrorCode } from "@embedpdf/models";
3
3
  const _DocumentManagerPlugin = class _DocumentManagerPlugin extends BasePlugin {
4
4
  constructor(id, registry, config) {
@@ -67,6 +67,10 @@ const _DocumentManagerPlugin = class _DocumentManagerPlugin extends BasePlugin {
67
67
  getDocumentIndex: (documentId) => {
68
68
  return this.coreState.core.documentOrder.indexOf(documentId);
69
69
  },
70
+ // Security
71
+ setDocumentEncryption: (documentId, options) => this.setDocumentEncryption(documentId, options),
72
+ unlockOwnerPermissions: (documentId, ownerPassword) => this.unlockOwnerPermissions(documentId, ownerPassword),
73
+ removeEncryption: (documentId) => this.removeEncryption(documentId),
70
74
  // Events
71
75
  onDocumentOpened: this.documentOpened$.on,
72
76
  onDocumentClosed: this.documentClosed$.on,
@@ -142,7 +146,8 @@ const _DocumentManagerPlugin = class _DocumentManagerPlugin extends BasePlugin {
142
146
  options.scale,
143
147
  options.rotation,
144
148
  !!options.password,
145
- options.autoActivate
149
+ options.autoActivate,
150
+ options.permissions
146
151
  )
147
152
  );
148
153
  this.logger.info(
@@ -183,7 +188,8 @@ const _DocumentManagerPlugin = class _DocumentManagerPlugin extends BasePlugin {
183
188
  options.scale,
184
189
  options.rotation,
185
190
  !!options.password,
186
- options.autoActivate
191
+ options.autoActivate,
192
+ options.permissions
187
193
  )
188
194
  );
189
195
  this.logger.info(
@@ -289,6 +295,135 @@ const _DocumentManagerPlugin = class _DocumentManagerPlugin extends BasePlugin {
289
295
  return Task.all(tasks);
290
296
  }
291
297
  // ─────────────────────────────────────────────────────────
298
+ // Security Methods
299
+ // ─────────────────────────────────────────────────────────
300
+ setDocumentEncryption(documentId, options) {
301
+ const task = new Task();
302
+ const docState = this.coreState.core.documents[documentId];
303
+ if (!(docState == null ? void 0 : docState.document)) {
304
+ task.reject({
305
+ code: PdfErrorCode.DocNotOpen,
306
+ message: `Document ${documentId} is not open`
307
+ });
308
+ return task;
309
+ }
310
+ this.logger.info(
311
+ "DocumentManagerPlugin",
312
+ "SetDocumentEncryption",
313
+ `Setting encryption on document ${documentId}`,
314
+ { hasUserPassword: !!options.userPassword, allowedFlags: options.allowedFlags }
315
+ );
316
+ const engineTask = this.engine.setDocumentEncryption(
317
+ docState.document,
318
+ options.userPassword ?? "",
319
+ options.ownerPassword,
320
+ options.allowedFlags
321
+ );
322
+ engineTask.wait(
323
+ (success) => {
324
+ if (success) {
325
+ this.logger.info(
326
+ "DocumentManagerPlugin",
327
+ "SetDocumentEncryption",
328
+ `Encryption set successfully on document ${documentId}`
329
+ );
330
+ }
331
+ task.resolve(success);
332
+ },
333
+ (error) => {
334
+ this.logger.error(
335
+ "DocumentManagerPlugin",
336
+ "SetDocumentEncryption",
337
+ `Failed to set encryption on document ${documentId}`,
338
+ error
339
+ );
340
+ task.fail(error);
341
+ }
342
+ );
343
+ return task;
344
+ }
345
+ unlockOwnerPermissions(documentId, ownerPassword) {
346
+ const task = new Task();
347
+ const docState = this.coreState.core.documents[documentId];
348
+ if (!(docState == null ? void 0 : docState.document)) {
349
+ task.reject({
350
+ code: PdfErrorCode.DocNotOpen,
351
+ message: `Document ${documentId} is not open`
352
+ });
353
+ return task;
354
+ }
355
+ const document = docState.document;
356
+ this.logger.info(
357
+ "DocumentManagerPlugin",
358
+ "UnlockOwnerPermissions",
359
+ `Attempting to unlock owner permissions on document ${documentId}`
360
+ );
361
+ const engineTask = this.engine.unlockOwnerPermissions(document, ownerPassword);
362
+ engineTask.wait(
363
+ (success) => {
364
+ if (success) {
365
+ this.logger.info(
366
+ "DocumentManagerPlugin",
367
+ "UnlockOwnerPermissions",
368
+ `Owner permissions unlocked on document ${documentId}`
369
+ );
370
+ const fullPermissions = 4294967295;
371
+ this.dispatchCoreAction(updateDocumentSecurity(documentId, fullPermissions, true));
372
+ }
373
+ task.resolve(success);
374
+ },
375
+ (error) => {
376
+ this.logger.error(
377
+ "DocumentManagerPlugin",
378
+ "UnlockOwnerPermissions",
379
+ `Failed to unlock owner permissions on document ${documentId}`,
380
+ error
381
+ );
382
+ task.fail(error);
383
+ }
384
+ );
385
+ return task;
386
+ }
387
+ removeEncryption(documentId) {
388
+ const task = new Task();
389
+ const docState = this.coreState.core.documents[documentId];
390
+ if (!(docState == null ? void 0 : docState.document)) {
391
+ task.reject({
392
+ code: PdfErrorCode.DocNotOpen,
393
+ message: `Document ${documentId} is not open`
394
+ });
395
+ return task;
396
+ }
397
+ this.logger.info(
398
+ "DocumentManagerPlugin",
399
+ "RemoveEncryption",
400
+ `Marking document ${documentId} for encryption removal on save`
401
+ );
402
+ const engineTask = this.engine.removeEncryption(docState.document);
403
+ engineTask.wait(
404
+ (success) => {
405
+ if (success) {
406
+ this.logger.info(
407
+ "DocumentManagerPlugin",
408
+ "RemoveEncryption",
409
+ `Document ${documentId} marked for encryption removal`
410
+ );
411
+ }
412
+ task.resolve(success);
413
+ },
414
+ (error) => {
415
+ this.logger.error(
416
+ "DocumentManagerPlugin",
417
+ "RemoveEncryption",
418
+ `Failed to mark document ${documentId} for encryption removal`,
419
+ error
420
+ );
421
+ task.fail(error);
422
+ }
423
+ );
424
+ return task;
425
+ }
426
+ // ─────────────────────────────────────────────────────────
292
427
  // Helper Methods
293
428
  // ─────────────────────────────────────────────────────────
294
429
  checkDocumentLimit() {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/lib/document-manager-plugin.ts","../src/lib/manifest.ts","../src/lib/index.ts"],"sourcesContent":["import {\n BasePlugin,\n PluginRegistry,\n createBehaviorEmitter,\n startLoadingDocument,\n setDocumentLoaded,\n setDocumentError,\n retryLoadingDocument,\n closeDocument as closeDocumentAction,\n setActiveDocument as setActiveDocumentAction,\n moveDocument as moveDocumentAction,\n reorderDocuments as reorderDocumentsAction,\n DocumentState,\n Unsubscribe,\n Listener,\n createEmitter,\n} from '@embedpdf/core';\nimport {\n PdfDocumentObject,\n Task,\n PdfFile,\n PdfFileUrl,\n PdfErrorReason,\n PdfErrorCode,\n} from '@embedpdf/models';\n\nimport {\n DocumentManagerPluginConfig,\n DocumentManagerCapability,\n DocumentChangeEvent,\n DocumentOrderChangeEvent,\n LoadDocumentUrlOptions,\n LoadDocumentBufferOptions,\n RetryOptions,\n DocumentErrorEvent,\n OpenDocumentResponse,\n OpenFileDialogOptions,\n} from './types';\n\nexport class DocumentManagerPlugin extends BasePlugin<\n DocumentManagerPluginConfig,\n DocumentManagerCapability\n> {\n static readonly id = 'document-manager' as const;\n\n private readonly documentOpened$ = createBehaviorEmitter<DocumentState>();\n private readonly documentClosed$ = createBehaviorEmitter<string>();\n private readonly activeDocumentChanged$ = createBehaviorEmitter<DocumentChangeEvent>();\n private readonly documentError$ = createBehaviorEmitter<DocumentErrorEvent>();\n\n private readonly documentOrderChanged$ = createBehaviorEmitter<DocumentOrderChangeEvent>();\n\n private readonly openFileRequest$ = createEmitter<{\n task: Task<OpenDocumentResponse, PdfErrorReason>;\n options?: OpenFileDialogOptions;\n }>();\n\n private maxDocuments?: number;\n\n private loadOptions = new Map<string, LoadDocumentUrlOptions | LoadDocumentBufferOptions>();\n\n constructor(\n public readonly id: string,\n registry: PluginRegistry,\n config?: DocumentManagerPluginConfig,\n ) {\n super(id, registry);\n this.maxDocuments = config?.maxDocuments;\n }\n\n protected buildCapability(): DocumentManagerCapability {\n return {\n // Document lifecycle - orchestration only\n openFileDialog: (options) => this.openFileDialog(options),\n openDocumentUrl: (options) => this.openDocumentUrl(options),\n openDocumentBuffer: (options) => this.openDocumentBuffer(options),\n retryDocument: (documentId, options) => this.retryDocument(documentId, options),\n closeDocument: (documentId) => this.closeDocument(documentId),\n closeAllDocuments: () => this.closeAllDocuments(),\n\n setActiveDocument: (documentId) => {\n if (!this.isDocumentOpen(documentId)) {\n throw new Error(`Cannot set active document: ${documentId} is not open`);\n }\n this.dispatchCoreAction(setActiveDocumentAction(documentId));\n },\n\n getActiveDocumentId: () => this.coreState.core.activeDocumentId,\n getActiveDocument: () => {\n const activeId = this.coreState.core.activeDocumentId;\n if (!activeId) return null;\n return this.coreState.core.documents[activeId]?.document ?? null;\n },\n\n getDocumentOrder: () => this.coreState.core.documentOrder,\n\n moveDocument: (documentId, toIndex) => {\n this.dispatchCoreAction(moveDocumentAction(documentId, toIndex));\n },\n\n swapDocuments: (id1, id2) => {\n const order = this.coreState.core.documentOrder;\n const index1 = order.indexOf(id1);\n const index2 = order.indexOf(id2);\n\n if (index1 === -1 || index2 === -1) {\n throw new Error('One or both documents not found in order');\n }\n\n const newOrder = [...order];\n [newOrder[index1], newOrder[index2]] = [newOrder[index2], newOrder[index1]];\n\n this.dispatchCoreAction(reorderDocumentsAction(newOrder));\n },\n\n getDocument: (documentId) => {\n return this.coreState.core.documents[documentId]?.document ?? null;\n },\n\n getDocumentState: (documentId) => {\n return this.coreState.core.documents[documentId] ?? null;\n },\n\n getOpenDocuments: () => {\n return this.coreState.core.documentOrder\n .map((documentId) => this.coreState.core.documents[documentId])\n .filter((state): state is DocumentState => state !== null);\n },\n\n isDocumentOpen: (documentId) => this.isDocumentOpen(documentId),\n\n getDocumentCount: () => {\n return Object.keys(this.coreState.core.documents).length;\n },\n\n getDocumentIndex: (documentId) => {\n return this.coreState.core.documentOrder.indexOf(documentId);\n },\n\n // Events\n onDocumentOpened: this.documentOpened$.on,\n onDocumentClosed: this.documentClosed$.on,\n onDocumentError: this.documentError$.on,\n onActiveDocumentChanged: this.activeDocumentChanged$.on,\n onDocumentOrderChanged: this.documentOrderChanged$.on,\n };\n }\n\n /**\n * Check if a document is currently open\n */\n private isDocumentOpen(documentId: string): boolean {\n return !!this.coreState.core.documents[documentId];\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Lifecycle Hooks (from BasePlugin)\n // ─────────────────────────────────────────────────────────\n\n protected override onDocumentLoaded(documentId: string): void {\n const docState = this.coreState.core.documents[documentId];\n if (!docState || docState.status !== 'loaded') return;\n\n // Clean up load options to free memory\n this.loadOptions.delete(documentId);\n\n // Emit opened event\n this.documentOpened$.emit(docState);\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'DocumentOpened',\n `Document ${documentId} opened successfully`,\n { name: docState.name },\n );\n }\n\n protected override onDocumentClosed(documentId: string): void {\n // Clean up load options\n this.loadOptions.delete(documentId);\n\n // Emit closed event\n this.documentClosed$.emit(documentId);\n\n this.logger.info('DocumentManagerPlugin', 'DocumentClosed', `Document ${documentId} closed`);\n }\n\n protected override onActiveDocumentChanged(\n previousId: string | null,\n currentId: string | null,\n ): void {\n this.activeDocumentChanged$.emit({\n previousDocumentId: previousId,\n currentDocumentId: currentId,\n });\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'ActiveDocumentChanged',\n `Active document changed from ${previousId} to ${currentId}`,\n );\n }\n\n protected override onCoreStoreUpdated(oldState: any, newState: any): void {\n // Emit order change event if order changed\n if (oldState.core.documentOrder !== newState.core.documentOrder) {\n this.documentOrderChanged$.emit({\n order: newState.core.documentOrder,\n });\n }\n }\n\n public onOpenFileRequest(\n handler: Listener<{\n task: Task<OpenDocumentResponse, PdfErrorReason>;\n options?: OpenFileDialogOptions;\n }>,\n ): Unsubscribe {\n return this.openFileRequest$.on(handler);\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Loading (orchestration only - no state management)\n // ─────────────────────────────────────────────────────────\n\n private openDocumentUrl(\n options: LoadDocumentUrlOptions,\n ): Task<OpenDocumentResponse, PdfErrorReason> {\n const task = new Task<OpenDocumentResponse, PdfErrorReason>();\n\n const documentId = options.documentId || this.generateDocumentId();\n\n // Check limit\n const limitError = this.checkDocumentLimit();\n if (limitError) {\n task.reject(limitError);\n return task;\n }\n\n const documentName = options.name ?? this.extractNameFromUrl(options.url);\n\n // Store options for potential retry\n this.loadOptions.set(documentId, options);\n\n this.dispatchCoreAction(\n startLoadingDocument(\n documentId,\n documentName,\n options.scale,\n options.rotation,\n !!options.password,\n options.autoActivate,\n ),\n );\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'OpenDocumentUrl',\n `Starting to load document from URL: ${options.url}`,\n { documentId, passwordProvided: !!options.password },\n );\n\n // Create file object and call engine\n const file: PdfFileUrl = {\n id: documentId,\n url: options.url,\n };\n const engineTask = this.engine.openDocumentUrl(file, {\n password: options.password,\n mode: options.mode,\n requestOptions: options.requestOptions,\n });\n\n task.resolve({\n documentId,\n task: engineTask,\n });\n\n // Handle result\n this.handleLoadTask(documentId, engineTask, 'OpenDocumentUrl');\n\n return task;\n }\n\n private openDocumentBuffer(\n options: LoadDocumentBufferOptions,\n ): Task<OpenDocumentResponse, PdfErrorReason> {\n const task = new Task<OpenDocumentResponse, PdfErrorReason>();\n\n const limitError = this.checkDocumentLimit();\n if (limitError) {\n task.reject(limitError);\n return task;\n }\n\n const documentId = options.documentId || this.generateDocumentId();\n\n // Store options for potential retry\n this.loadOptions.set(documentId, options);\n\n this.dispatchCoreAction(\n startLoadingDocument(\n documentId,\n options.name,\n options.scale,\n options.rotation,\n !!options.password,\n options.autoActivate,\n ),\n );\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'OpenDocumentBuffer',\n `Starting to load document from buffer: ${options.name}`,\n { documentId, passwordProvided: !!options.password },\n );\n\n // Create file object and call engine\n const file: PdfFile = {\n id: documentId,\n content: options.buffer,\n };\n const engineTask = this.engine.openDocumentBuffer(file, {\n password: options.password,\n });\n\n task.resolve({\n documentId,\n task: engineTask,\n });\n\n // Handle result\n this.handleLoadTask(documentId, engineTask, 'OpenDocumentBuffer');\n\n return task;\n }\n\n private retryDocument(\n documentId: string,\n retryOptions?: RetryOptions,\n ): Task<OpenDocumentResponse, PdfErrorReason> {\n const task = new Task<OpenDocumentResponse, PdfErrorReason>();\n\n // Validate retry\n const validation = this.validateRetry(documentId);\n if (!validation.valid) {\n task.reject(validation.error!);\n return task;\n }\n\n const originalOptions = this.loadOptions.get(documentId)!;\n\n // Merge retry options (e.g., new password)\n const mergedOptions = {\n ...originalOptions,\n ...(retryOptions?.password && { password: retryOptions.password }),\n };\n\n // Update stored options\n this.loadOptions.set(documentId, mergedOptions);\n\n // Set back to loading state\n this.dispatchCoreAction(retryLoadingDocument(documentId, !!retryOptions?.password));\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'RetryDocument',\n `Retrying to load document ${documentId}`,\n { passwordProvided: !!retryOptions?.password },\n );\n\n // Execute retry based on type\n const engineTask =\n 'url' in mergedOptions\n ? this.retryUrlDocument(documentId, mergedOptions)\n : this.retryBufferDocument(documentId, mergedOptions);\n\n task.resolve({\n documentId,\n task: engineTask,\n });\n\n // Handle result\n this.handleLoadTask(documentId, engineTask, 'RetryDocument');\n\n return task;\n }\n\n private openFileDialog(\n options?: OpenFileDialogOptions,\n ): Task<OpenDocumentResponse, PdfErrorReason> {\n const task = new Task<OpenDocumentResponse, PdfErrorReason>();\n this.openFileRequest$.emit({ task, options });\n return task;\n }\n\n private closeDocument(documentId: string): Task<void, PdfErrorReason> {\n const task = new Task<void, PdfErrorReason>();\n\n const docState = this.coreState.core.documents[documentId];\n if (!docState) {\n this.logger.warn(\n 'DocumentManagerPlugin',\n 'CloseDocument',\n `Cannot close document ${documentId}: not found in state`,\n );\n task.resolve();\n return task;\n }\n\n // ✅ SIMPLIFIED: Just dispatch - reducer calculates next active!\n if (docState.status === 'loaded' && docState.document) {\n this.engine.closeDocument(docState.document).wait(\n () => {\n this.dispatchCoreAction(closeDocumentAction(documentId));\n task.resolve();\n },\n (error) => {\n this.logger.error(\n 'DocumentManagerPlugin',\n 'CloseDocument',\n `Failed to close document ${documentId}`,\n error,\n );\n task.fail(error);\n },\n );\n } else {\n // Document is not loaded (error, loading, etc.), just clean up state\n this.logger.info(\n 'DocumentManagerPlugin',\n 'CloseDocument',\n `Closing document ${documentId} in ${docState.status} state (skipping engine close)`,\n );\n this.dispatchCoreAction(closeDocumentAction(documentId));\n task.resolve();\n }\n\n return task;\n }\n\n private closeAllDocuments(): Task<void[], PdfErrorReason> {\n const documentIds = Object.keys(this.coreState.core.documents);\n const tasks = documentIds.map((documentId) => this.closeDocument(documentId));\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'CloseAllDocuments',\n `Closing ${documentIds.length} documents`,\n );\n\n return Task.all(tasks);\n }\n\n // ─────────────────────────────────────────────────────────\n // Helper Methods\n // ─────────────────────────────────────────────────────────\n\n private checkDocumentLimit(): PdfErrorReason | null {\n if (\n this.maxDocuments &&\n Object.keys(this.coreState.core.documents).length >= this.maxDocuments\n ) {\n return {\n code: PdfErrorCode.Unknown,\n message: `Maximum number of documents (${this.maxDocuments}) reached`,\n };\n }\n return null;\n }\n\n private validateRetry(documentId: string): {\n valid: boolean;\n error?: PdfErrorReason;\n } {\n const docState = this.coreState.core.documents[documentId];\n\n if (!docState) {\n return {\n valid: false,\n error: {\n code: PdfErrorCode.NotFound,\n message: `Document ${documentId} not found`,\n },\n };\n }\n\n if (docState.status === 'loaded') {\n return {\n valid: false,\n error: {\n code: PdfErrorCode.Unknown,\n message: `Document ${documentId} is already loaded successfully`,\n },\n };\n }\n\n if (docState.status !== 'error') {\n return {\n valid: false,\n error: {\n code: PdfErrorCode.Unknown,\n message: `Document ${documentId} is not in error state (current state: ${docState.status})`,\n },\n };\n }\n\n if (!this.loadOptions.has(documentId)) {\n return {\n valid: false,\n error: {\n code: PdfErrorCode.Unknown,\n message: `No retry information available for document ${documentId}`,\n },\n };\n }\n\n return { valid: true };\n }\n\n private retryUrlDocument(\n documentId: string,\n options: LoadDocumentUrlOptions,\n ): Task<PdfDocumentObject, PdfErrorReason> {\n const file: PdfFileUrl = {\n id: documentId,\n url: options.url,\n };\n\n return this.engine.openDocumentUrl(file, {\n password: options.password,\n mode: options.mode,\n requestOptions: options.requestOptions,\n });\n }\n\n private retryBufferDocument(\n documentId: string,\n options: LoadDocumentBufferOptions,\n ): Task<PdfDocumentObject, PdfErrorReason> {\n const file: PdfFile = {\n id: documentId,\n content: options.buffer,\n };\n\n return this.engine.openDocumentBuffer(file, {\n password: options.password,\n });\n }\n\n private handleLoadTask(\n documentId: string,\n engineTask: Task<PdfDocumentObject, PdfErrorReason>,\n context: string,\n ): void {\n engineTask.wait(\n (pdfDocument) => {\n this.dispatchCoreAction(setDocumentLoaded(documentId, pdfDocument));\n },\n (error) => {\n this.handleLoadError(documentId, error, context);\n },\n );\n }\n\n private handleLoadError(documentId: string, error: any, context: string): void {\n const errorMessage = error.reason?.message || 'Failed to load document';\n\n this.logger.error('DocumentManagerPlugin', context, 'Failed to load document', error);\n\n this.dispatchCoreAction(\n setDocumentError(documentId, errorMessage, error.reason?.code, error.reason),\n );\n\n this.documentError$.emit({\n documentId,\n message: errorMessage,\n code: error.reason?.code,\n reason: error.reason,\n });\n }\n\n private generateDocumentId(): string {\n return `doc-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n }\n\n private extractNameFromUrl(url: string): string | undefined {\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n const lastSegment = pathname.split('/').pop();\n if (!lastSegment) {\n return undefined;\n }\n let filename = decodeURIComponent(lastSegment);\n if (!filename.toLowerCase().endsWith('.pdf')) {\n filename += '.pdf';\n }\n return filename;\n } catch {\n return undefined;\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Plugin Lifecycle\n // ─────────────────────────────────────────────────────────\n\n async initialize(config: DocumentManagerPluginConfig): Promise<void> {\n this.logger.info('DocumentManagerPlugin', 'Initialize', 'Document Manager Plugin initialized', {\n maxDocuments: this.maxDocuments,\n initialDocumentsCount: config.initialDocuments?.length ?? 0,\n });\n\n // Handle initial documents from config\n if (config.initialDocuments && config.initialDocuments.length > 0) {\n // Process strictly in order\n for (const docConfig of config.initialDocuments) {\n try {\n // Type guard to distinguish between URL and Buffer options\n if ('buffer' in docConfig) {\n this.openDocumentBuffer(docConfig);\n } else if ('url' in docConfig) {\n this.openDocumentUrl(docConfig);\n }\n } catch (error) {\n this.logger.error(\n 'DocumentManagerPlugin',\n 'Initialize',\n 'Failed to initiate initial document load',\n error,\n );\n }\n }\n }\n }\n\n async destroy(): Promise<void> {\n // Close all documents\n await this.closeAllDocuments().toPromise();\n\n // Clear load options\n this.loadOptions.clear();\n\n // Clear emitters\n this.documentOpened$.clear();\n this.documentClosed$.clear();\n this.activeDocumentChanged$.clear();\n this.documentOrderChanged$.clear();\n this.documentError$.clear();\n\n super.destroy();\n }\n}\n","import { PluginManifest } from '@embedpdf/core';\nimport { DocumentManagerPluginConfig } from './types';\n\nexport const DOCUMENT_MANAGER_PLUGIN_ID = 'document-manager';\n\nexport const manifest: PluginManifest<DocumentManagerPluginConfig> = {\n id: DOCUMENT_MANAGER_PLUGIN_ID,\n name: 'Document Manager Plugin',\n version: '1.0.0',\n provides: ['document-manager'],\n requires: [],\n optional: [],\n defaultConfig: {\n maxDocuments: 10,\n },\n};\n","import { PluginPackage } from '@embedpdf/core';\nimport { DocumentManagerPlugin } from './document-manager-plugin';\nimport { manifest, DOCUMENT_MANAGER_PLUGIN_ID } from './manifest';\nimport { DocumentManagerPluginConfig } from './types';\n\nexport const DocumentManagerPluginPackage: PluginPackage<\n DocumentManagerPlugin,\n DocumentManagerPluginConfig\n> = {\n manifest,\n create: (registry, config) =>\n new DocumentManagerPlugin(DOCUMENT_MANAGER_PLUGIN_ID, registry, config),\n reducer: (state) => state,\n initialState: {},\n};\n\nexport * from './document-manager-plugin';\nexport * from './types';\nexport * from './manifest';\n"],"names":["setActiveDocumentAction","moveDocumentAction","reorderDocumentsAction","closeDocumentAction"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/lib/document-manager-plugin.ts","../src/lib/manifest.ts","../src/lib/index.ts"],"sourcesContent":["import {\n BasePlugin,\n PluginRegistry,\n createBehaviorEmitter,\n startLoadingDocument,\n setDocumentLoaded,\n setDocumentError,\n retryLoadingDocument,\n closeDocument as closeDocumentAction,\n setActiveDocument as setActiveDocumentAction,\n moveDocument as moveDocumentAction,\n reorderDocuments as reorderDocumentsAction,\n updateDocumentSecurity,\n DocumentState,\n Unsubscribe,\n Listener,\n createEmitter,\n} from '@embedpdf/core';\nimport {\n PdfDocumentObject,\n Task,\n PdfFile,\n PdfFileUrl,\n PdfErrorReason,\n PdfErrorCode,\n} from '@embedpdf/models';\n\nimport {\n DocumentManagerPluginConfig,\n DocumentManagerCapability,\n DocumentChangeEvent,\n DocumentOrderChangeEvent,\n LoadDocumentUrlOptions,\n LoadDocumentBufferOptions,\n RetryOptions,\n DocumentErrorEvent,\n OpenDocumentResponse,\n OpenFileDialogOptions,\n SetEncryptionOptions,\n} from './types';\n\nexport class DocumentManagerPlugin extends BasePlugin<\n DocumentManagerPluginConfig,\n DocumentManagerCapability\n> {\n static readonly id = 'document-manager' as const;\n\n private readonly documentOpened$ = createBehaviorEmitter<DocumentState>();\n private readonly documentClosed$ = createBehaviorEmitter<string>();\n private readonly activeDocumentChanged$ = createBehaviorEmitter<DocumentChangeEvent>();\n private readonly documentError$ = createBehaviorEmitter<DocumentErrorEvent>();\n\n private readonly documentOrderChanged$ = createBehaviorEmitter<DocumentOrderChangeEvent>();\n\n private readonly openFileRequest$ = createEmitter<{\n task: Task<OpenDocumentResponse, PdfErrorReason>;\n options?: OpenFileDialogOptions;\n }>();\n\n private maxDocuments?: number;\n\n private loadOptions = new Map<string, LoadDocumentUrlOptions | LoadDocumentBufferOptions>();\n\n constructor(\n public readonly id: string,\n registry: PluginRegistry,\n config?: DocumentManagerPluginConfig,\n ) {\n super(id, registry);\n this.maxDocuments = config?.maxDocuments;\n }\n\n protected buildCapability(): DocumentManagerCapability {\n return {\n // Document lifecycle - orchestration only\n openFileDialog: (options) => this.openFileDialog(options),\n openDocumentUrl: (options) => this.openDocumentUrl(options),\n openDocumentBuffer: (options) => this.openDocumentBuffer(options),\n retryDocument: (documentId, options) => this.retryDocument(documentId, options),\n closeDocument: (documentId) => this.closeDocument(documentId),\n closeAllDocuments: () => this.closeAllDocuments(),\n\n setActiveDocument: (documentId) => {\n if (!this.isDocumentOpen(documentId)) {\n throw new Error(`Cannot set active document: ${documentId} is not open`);\n }\n this.dispatchCoreAction(setActiveDocumentAction(documentId));\n },\n\n getActiveDocumentId: () => this.coreState.core.activeDocumentId,\n getActiveDocument: () => {\n const activeId = this.coreState.core.activeDocumentId;\n if (!activeId) return null;\n return this.coreState.core.documents[activeId]?.document ?? null;\n },\n\n getDocumentOrder: () => this.coreState.core.documentOrder,\n\n moveDocument: (documentId, toIndex) => {\n this.dispatchCoreAction(moveDocumentAction(documentId, toIndex));\n },\n\n swapDocuments: (id1, id2) => {\n const order = this.coreState.core.documentOrder;\n const index1 = order.indexOf(id1);\n const index2 = order.indexOf(id2);\n\n if (index1 === -1 || index2 === -1) {\n throw new Error('One or both documents not found in order');\n }\n\n const newOrder = [...order];\n [newOrder[index1], newOrder[index2]] = [newOrder[index2], newOrder[index1]];\n\n this.dispatchCoreAction(reorderDocumentsAction(newOrder));\n },\n\n getDocument: (documentId) => {\n return this.coreState.core.documents[documentId]?.document ?? null;\n },\n\n getDocumentState: (documentId) => {\n return this.coreState.core.documents[documentId] ?? null;\n },\n\n getOpenDocuments: () => {\n return this.coreState.core.documentOrder\n .map((documentId) => this.coreState.core.documents[documentId])\n .filter((state): state is DocumentState => state !== null);\n },\n\n isDocumentOpen: (documentId) => this.isDocumentOpen(documentId),\n\n getDocumentCount: () => {\n return Object.keys(this.coreState.core.documents).length;\n },\n\n getDocumentIndex: (documentId) => {\n return this.coreState.core.documentOrder.indexOf(documentId);\n },\n\n // Security\n setDocumentEncryption: (documentId, options) =>\n this.setDocumentEncryption(documentId, options),\n unlockOwnerPermissions: (documentId, ownerPassword) =>\n this.unlockOwnerPermissions(documentId, ownerPassword),\n removeEncryption: (documentId) => this.removeEncryption(documentId),\n\n // Events\n onDocumentOpened: this.documentOpened$.on,\n onDocumentClosed: this.documentClosed$.on,\n onDocumentError: this.documentError$.on,\n onActiveDocumentChanged: this.activeDocumentChanged$.on,\n onDocumentOrderChanged: this.documentOrderChanged$.on,\n };\n }\n\n /**\n * Check if a document is currently open\n */\n private isDocumentOpen(documentId: string): boolean {\n return !!this.coreState.core.documents[documentId];\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Lifecycle Hooks (from BasePlugin)\n // ─────────────────────────────────────────────────────────\n\n protected override onDocumentLoaded(documentId: string): void {\n const docState = this.coreState.core.documents[documentId];\n if (!docState || docState.status !== 'loaded') return;\n\n // Clean up load options to free memory\n this.loadOptions.delete(documentId);\n\n // Emit opened event\n this.documentOpened$.emit(docState);\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'DocumentOpened',\n `Document ${documentId} opened successfully`,\n { name: docState.name },\n );\n }\n\n protected override onDocumentClosed(documentId: string): void {\n // Clean up load options\n this.loadOptions.delete(documentId);\n\n // Emit closed event\n this.documentClosed$.emit(documentId);\n\n this.logger.info('DocumentManagerPlugin', 'DocumentClosed', `Document ${documentId} closed`);\n }\n\n protected override onActiveDocumentChanged(\n previousId: string | null,\n currentId: string | null,\n ): void {\n this.activeDocumentChanged$.emit({\n previousDocumentId: previousId,\n currentDocumentId: currentId,\n });\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'ActiveDocumentChanged',\n `Active document changed from ${previousId} to ${currentId}`,\n );\n }\n\n protected override onCoreStoreUpdated(oldState: any, newState: any): void {\n // Emit order change event if order changed\n if (oldState.core.documentOrder !== newState.core.documentOrder) {\n this.documentOrderChanged$.emit({\n order: newState.core.documentOrder,\n });\n }\n }\n\n public onOpenFileRequest(\n handler: Listener<{\n task: Task<OpenDocumentResponse, PdfErrorReason>;\n options?: OpenFileDialogOptions;\n }>,\n ): Unsubscribe {\n return this.openFileRequest$.on(handler);\n }\n\n // ─────────────────────────────────────────────────────────\n // Document Loading (orchestration only - no state management)\n // ─────────────────────────────────────────────────────────\n\n private openDocumentUrl(\n options: LoadDocumentUrlOptions,\n ): Task<OpenDocumentResponse, PdfErrorReason> {\n const task = new Task<OpenDocumentResponse, PdfErrorReason>();\n\n const documentId = options.documentId || this.generateDocumentId();\n\n // Check limit\n const limitError = this.checkDocumentLimit();\n if (limitError) {\n task.reject(limitError);\n return task;\n }\n\n const documentName = options.name ?? this.extractNameFromUrl(options.url);\n\n // Store options for potential retry\n this.loadOptions.set(documentId, options);\n\n this.dispatchCoreAction(\n startLoadingDocument(\n documentId,\n documentName,\n options.scale,\n options.rotation,\n !!options.password,\n options.autoActivate,\n options.permissions,\n ),\n );\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'OpenDocumentUrl',\n `Starting to load document from URL: ${options.url}`,\n { documentId, passwordProvided: !!options.password },\n );\n\n // Create file object and call engine\n const file: PdfFileUrl = {\n id: documentId,\n url: options.url,\n };\n const engineTask = this.engine.openDocumentUrl(file, {\n password: options.password,\n mode: options.mode,\n requestOptions: options.requestOptions,\n });\n\n task.resolve({\n documentId,\n task: engineTask,\n });\n\n // Handle result\n this.handleLoadTask(documentId, engineTask, 'OpenDocumentUrl');\n\n return task;\n }\n\n private openDocumentBuffer(\n options: LoadDocumentBufferOptions,\n ): Task<OpenDocumentResponse, PdfErrorReason> {\n const task = new Task<OpenDocumentResponse, PdfErrorReason>();\n\n const limitError = this.checkDocumentLimit();\n if (limitError) {\n task.reject(limitError);\n return task;\n }\n\n const documentId = options.documentId || this.generateDocumentId();\n\n // Store options for potential retry\n this.loadOptions.set(documentId, options);\n\n this.dispatchCoreAction(\n startLoadingDocument(\n documentId,\n options.name,\n options.scale,\n options.rotation,\n !!options.password,\n options.autoActivate,\n options.permissions,\n ),\n );\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'OpenDocumentBuffer',\n `Starting to load document from buffer: ${options.name}`,\n { documentId, passwordProvided: !!options.password },\n );\n\n // Create file object and call engine\n const file: PdfFile = {\n id: documentId,\n content: options.buffer,\n };\n const engineTask = this.engine.openDocumentBuffer(file, {\n password: options.password,\n });\n\n task.resolve({\n documentId,\n task: engineTask,\n });\n\n // Handle result\n this.handleLoadTask(documentId, engineTask, 'OpenDocumentBuffer');\n\n return task;\n }\n\n private retryDocument(\n documentId: string,\n retryOptions?: RetryOptions,\n ): Task<OpenDocumentResponse, PdfErrorReason> {\n const task = new Task<OpenDocumentResponse, PdfErrorReason>();\n\n // Validate retry\n const validation = this.validateRetry(documentId);\n if (!validation.valid) {\n task.reject(validation.error!);\n return task;\n }\n\n const originalOptions = this.loadOptions.get(documentId)!;\n\n // Merge retry options (e.g., new password)\n const mergedOptions = {\n ...originalOptions,\n ...(retryOptions?.password && { password: retryOptions.password }),\n };\n\n // Update stored options\n this.loadOptions.set(documentId, mergedOptions);\n\n // Set back to loading state\n this.dispatchCoreAction(retryLoadingDocument(documentId, !!retryOptions?.password));\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'RetryDocument',\n `Retrying to load document ${documentId}`,\n { passwordProvided: !!retryOptions?.password },\n );\n\n // Execute retry based on type\n const engineTask =\n 'url' in mergedOptions\n ? this.retryUrlDocument(documentId, mergedOptions)\n : this.retryBufferDocument(documentId, mergedOptions);\n\n task.resolve({\n documentId,\n task: engineTask,\n });\n\n // Handle result\n this.handleLoadTask(documentId, engineTask, 'RetryDocument');\n\n return task;\n }\n\n private openFileDialog(\n options?: OpenFileDialogOptions,\n ): Task<OpenDocumentResponse, PdfErrorReason> {\n const task = new Task<OpenDocumentResponse, PdfErrorReason>();\n this.openFileRequest$.emit({ task, options });\n return task;\n }\n\n private closeDocument(documentId: string): Task<void, PdfErrorReason> {\n const task = new Task<void, PdfErrorReason>();\n\n const docState = this.coreState.core.documents[documentId];\n if (!docState) {\n this.logger.warn(\n 'DocumentManagerPlugin',\n 'CloseDocument',\n `Cannot close document ${documentId}: not found in state`,\n );\n task.resolve();\n return task;\n }\n\n // ✅ SIMPLIFIED: Just dispatch - reducer calculates next active!\n if (docState.status === 'loaded' && docState.document) {\n this.engine.closeDocument(docState.document).wait(\n () => {\n this.dispatchCoreAction(closeDocumentAction(documentId));\n task.resolve();\n },\n (error) => {\n this.logger.error(\n 'DocumentManagerPlugin',\n 'CloseDocument',\n `Failed to close document ${documentId}`,\n error,\n );\n task.fail(error);\n },\n );\n } else {\n // Document is not loaded (error, loading, etc.), just clean up state\n this.logger.info(\n 'DocumentManagerPlugin',\n 'CloseDocument',\n `Closing document ${documentId} in ${docState.status} state (skipping engine close)`,\n );\n this.dispatchCoreAction(closeDocumentAction(documentId));\n task.resolve();\n }\n\n return task;\n }\n\n private closeAllDocuments(): Task<void[], PdfErrorReason> {\n const documentIds = Object.keys(this.coreState.core.documents);\n const tasks = documentIds.map((documentId) => this.closeDocument(documentId));\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'CloseAllDocuments',\n `Closing ${documentIds.length} documents`,\n );\n\n return Task.all(tasks);\n }\n\n // ─────────────────────────────────────────────────────────\n // Security Methods\n // ─────────────────────────────────────────────────────────\n\n private setDocumentEncryption(\n documentId: string,\n options: SetEncryptionOptions,\n ): Task<boolean, PdfErrorReason> {\n const task = new Task<boolean, PdfErrorReason>();\n\n const docState = this.coreState.core.documents[documentId];\n if (!docState?.document) {\n task.reject({\n code: PdfErrorCode.DocNotOpen,\n message: `Document ${documentId} is not open`,\n });\n return task;\n }\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'SetDocumentEncryption',\n `Setting encryption on document ${documentId}`,\n { hasUserPassword: !!options.userPassword, allowedFlags: options.allowedFlags },\n );\n\n const engineTask = this.engine.setDocumentEncryption(\n docState.document,\n options.userPassword ?? '',\n options.ownerPassword,\n options.allowedFlags,\n );\n\n engineTask.wait(\n (success) => {\n if (success) {\n this.logger.info(\n 'DocumentManagerPlugin',\n 'SetDocumentEncryption',\n `Encryption set successfully on document ${documentId}`,\n );\n }\n task.resolve(success);\n },\n (error) => {\n this.logger.error(\n 'DocumentManagerPlugin',\n 'SetDocumentEncryption',\n `Failed to set encryption on document ${documentId}`,\n error,\n );\n task.fail(error);\n },\n );\n\n return task;\n }\n\n private unlockOwnerPermissions(\n documentId: string,\n ownerPassword: string,\n ): Task<boolean, PdfErrorReason> {\n const task = new Task<boolean, PdfErrorReason>();\n\n const docState = this.coreState.core.documents[documentId];\n if (!docState?.document) {\n task.reject({\n code: PdfErrorCode.DocNotOpen,\n message: `Document ${documentId} is not open`,\n });\n return task;\n }\n\n // Capture document reference before async operations\n const document = docState.document;\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'UnlockOwnerPermissions',\n `Attempting to unlock owner permissions on document ${documentId}`,\n );\n\n const engineTask = this.engine.unlockOwnerPermissions(document, ownerPassword);\n\n engineTask.wait(\n (success) => {\n if (success) {\n this.logger.info(\n 'DocumentManagerPlugin',\n 'UnlockOwnerPermissions',\n `Owner permissions unlocked on document ${documentId}`,\n );\n\n // Update the document security state in the store\n // After owner unlock, permissions are effectively \"all\"\n const fullPermissions = 0xffffffff; // All bits set = all permissions\n this.dispatchCoreAction(updateDocumentSecurity(documentId, fullPermissions, true));\n }\n task.resolve(success);\n },\n (error) => {\n this.logger.error(\n 'DocumentManagerPlugin',\n 'UnlockOwnerPermissions',\n `Failed to unlock owner permissions on document ${documentId}`,\n error,\n );\n task.fail(error);\n },\n );\n\n return task;\n }\n\n private removeEncryption(documentId: string): Task<boolean, PdfErrorReason> {\n const task = new Task<boolean, PdfErrorReason>();\n\n const docState = this.coreState.core.documents[documentId];\n if (!docState?.document) {\n task.reject({\n code: PdfErrorCode.DocNotOpen,\n message: `Document ${documentId} is not open`,\n });\n return task;\n }\n\n this.logger.info(\n 'DocumentManagerPlugin',\n 'RemoveEncryption',\n `Marking document ${documentId} for encryption removal on save`,\n );\n\n const engineTask = this.engine.removeEncryption(docState.document);\n\n engineTask.wait(\n (success) => {\n if (success) {\n this.logger.info(\n 'DocumentManagerPlugin',\n 'RemoveEncryption',\n `Document ${documentId} marked for encryption removal`,\n );\n }\n task.resolve(success);\n },\n (error) => {\n this.logger.error(\n 'DocumentManagerPlugin',\n 'RemoveEncryption',\n `Failed to mark document ${documentId} for encryption removal`,\n error,\n );\n task.fail(error);\n },\n );\n\n return task;\n }\n\n // ─────────────────────────────────────────────────────────\n // Helper Methods\n // ─────────────────────────────────────────────────────────\n\n private checkDocumentLimit(): PdfErrorReason | null {\n if (\n this.maxDocuments &&\n Object.keys(this.coreState.core.documents).length >= this.maxDocuments\n ) {\n return {\n code: PdfErrorCode.Unknown,\n message: `Maximum number of documents (${this.maxDocuments}) reached`,\n };\n }\n return null;\n }\n\n private validateRetry(documentId: string): {\n valid: boolean;\n error?: PdfErrorReason;\n } {\n const docState = this.coreState.core.documents[documentId];\n\n if (!docState) {\n return {\n valid: false,\n error: {\n code: PdfErrorCode.NotFound,\n message: `Document ${documentId} not found`,\n },\n };\n }\n\n if (docState.status === 'loaded') {\n return {\n valid: false,\n error: {\n code: PdfErrorCode.Unknown,\n message: `Document ${documentId} is already loaded successfully`,\n },\n };\n }\n\n if (docState.status !== 'error') {\n return {\n valid: false,\n error: {\n code: PdfErrorCode.Unknown,\n message: `Document ${documentId} is not in error state (current state: ${docState.status})`,\n },\n };\n }\n\n if (!this.loadOptions.has(documentId)) {\n return {\n valid: false,\n error: {\n code: PdfErrorCode.Unknown,\n message: `No retry information available for document ${documentId}`,\n },\n };\n }\n\n return { valid: true };\n }\n\n private retryUrlDocument(\n documentId: string,\n options: LoadDocumentUrlOptions,\n ): Task<PdfDocumentObject, PdfErrorReason> {\n const file: PdfFileUrl = {\n id: documentId,\n url: options.url,\n };\n\n return this.engine.openDocumentUrl(file, {\n password: options.password,\n mode: options.mode,\n requestOptions: options.requestOptions,\n });\n }\n\n private retryBufferDocument(\n documentId: string,\n options: LoadDocumentBufferOptions,\n ): Task<PdfDocumentObject, PdfErrorReason> {\n const file: PdfFile = {\n id: documentId,\n content: options.buffer,\n };\n\n return this.engine.openDocumentBuffer(file, {\n password: options.password,\n });\n }\n\n private handleLoadTask(\n documentId: string,\n engineTask: Task<PdfDocumentObject, PdfErrorReason>,\n context: string,\n ): void {\n engineTask.wait(\n (pdfDocument) => {\n this.dispatchCoreAction(setDocumentLoaded(documentId, pdfDocument));\n },\n (error) => {\n this.handleLoadError(documentId, error, context);\n },\n );\n }\n\n private handleLoadError(documentId: string, error: any, context: string): void {\n const errorMessage = error.reason?.message || 'Failed to load document';\n\n this.logger.error('DocumentManagerPlugin', context, 'Failed to load document', error);\n\n this.dispatchCoreAction(\n setDocumentError(documentId, errorMessage, error.reason?.code, error.reason),\n );\n\n this.documentError$.emit({\n documentId,\n message: errorMessage,\n code: error.reason?.code,\n reason: error.reason,\n });\n }\n\n private generateDocumentId(): string {\n return `doc-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;\n }\n\n private extractNameFromUrl(url: string): string | undefined {\n try {\n const urlObj = new URL(url);\n const pathname = urlObj.pathname;\n const lastSegment = pathname.split('/').pop();\n if (!lastSegment) {\n return undefined;\n }\n let filename = decodeURIComponent(lastSegment);\n if (!filename.toLowerCase().endsWith('.pdf')) {\n filename += '.pdf';\n }\n return filename;\n } catch {\n return undefined;\n }\n }\n\n // ─────────────────────────────────────────────────────────\n // Plugin Lifecycle\n // ─────────────────────────────────────────────────────────\n\n async initialize(config: DocumentManagerPluginConfig): Promise<void> {\n this.logger.info('DocumentManagerPlugin', 'Initialize', 'Document Manager Plugin initialized', {\n maxDocuments: this.maxDocuments,\n initialDocumentsCount: config.initialDocuments?.length ?? 0,\n });\n\n // Handle initial documents from config\n if (config.initialDocuments && config.initialDocuments.length > 0) {\n // Process strictly in order\n for (const docConfig of config.initialDocuments) {\n try {\n // Type guard to distinguish between URL and Buffer options\n if ('buffer' in docConfig) {\n this.openDocumentBuffer(docConfig);\n } else if ('url' in docConfig) {\n this.openDocumentUrl(docConfig);\n }\n } catch (error) {\n this.logger.error(\n 'DocumentManagerPlugin',\n 'Initialize',\n 'Failed to initiate initial document load',\n error,\n );\n }\n }\n }\n }\n\n async destroy(): Promise<void> {\n // Close all documents\n await this.closeAllDocuments().toPromise();\n\n // Clear load options\n this.loadOptions.clear();\n\n // Clear emitters\n this.documentOpened$.clear();\n this.documentClosed$.clear();\n this.activeDocumentChanged$.clear();\n this.documentOrderChanged$.clear();\n this.documentError$.clear();\n\n super.destroy();\n }\n}\n","import { PluginManifest } from '@embedpdf/core';\nimport { DocumentManagerPluginConfig } from './types';\n\nexport const DOCUMENT_MANAGER_PLUGIN_ID = 'document-manager';\n\nexport const manifest: PluginManifest<DocumentManagerPluginConfig> = {\n id: DOCUMENT_MANAGER_PLUGIN_ID,\n name: 'Document Manager Plugin',\n version: '1.0.0',\n provides: ['document-manager'],\n requires: [],\n optional: [],\n defaultConfig: {\n maxDocuments: 10,\n },\n};\n","import { PluginPackage } from '@embedpdf/core';\nimport { DocumentManagerPlugin } from './document-manager-plugin';\nimport { manifest, DOCUMENT_MANAGER_PLUGIN_ID } from './manifest';\nimport { DocumentManagerPluginConfig } from './types';\n\nexport const DocumentManagerPluginPackage: PluginPackage<\n DocumentManagerPlugin,\n DocumentManagerPluginConfig\n> = {\n manifest,\n create: (registry, config) =>\n new DocumentManagerPlugin(DOCUMENT_MANAGER_PLUGIN_ID, registry, config),\n reducer: (state) => state,\n initialState: {},\n};\n\nexport * from './document-manager-plugin';\nexport * from './types';\nexport * from './manifest';\n"],"names":["setActiveDocumentAction","moveDocumentAction","reorderDocumentsAction","closeDocumentAction"],"mappings":"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"}
@@ -32,6 +32,9 @@ export declare class DocumentManagerPlugin extends BasePlugin<DocumentManagerPlu
32
32
  private openFileDialog;
33
33
  private closeDocument;
34
34
  private closeAllDocuments;
35
+ private setDocumentEncryption;
36
+ private unlockOwnerPermissions;
37
+ private removeEncryption;
35
38
  private checkDocumentLimit;
36
39
  private validateRetry;
37
40
  private retryUrlDocument;
@@ -1,4 +1,4 @@
1
- import { BasePluginConfig, EventHook, DocumentState } from '@embedpdf/core';
1
+ import { BasePluginConfig, EventHook, DocumentState, PermissionConfig } from '@embedpdf/core';
2
2
  import { PdfDocumentObject, Rotation, Task, PdfErrorReason, PdfRequestOptions } from '@embedpdf/models';
3
3
  export type InitialDocumentOptions = LoadDocumentUrlOptions | LoadDocumentBufferOptions;
4
4
  export interface DocumentManagerPluginConfig extends BasePluginConfig {
@@ -31,6 +31,8 @@ export interface LoadDocumentUrlOptions {
31
31
  scale?: number;
32
32
  rotation?: Rotation;
33
33
  autoActivate?: boolean;
34
+ /** Per-document permission overrides */
35
+ permissions?: PermissionConfig;
34
36
  }
35
37
  export interface LoadDocumentBufferOptions {
36
38
  buffer: ArrayBuffer;
@@ -40,6 +42,8 @@ export interface LoadDocumentBufferOptions {
40
42
  scale?: number;
41
43
  rotation?: Rotation;
42
44
  autoActivate?: boolean;
45
+ /** Per-document permission overrides */
46
+ permissions?: PermissionConfig;
43
47
  }
44
48
  export interface RetryOptions {
45
49
  password?: string;
@@ -49,11 +53,21 @@ export interface OpenFileDialogOptions {
49
53
  scale?: number;
50
54
  rotation?: Rotation;
51
55
  autoActivate?: boolean;
56
+ /** Per-document permission overrides */
57
+ permissions?: PermissionConfig;
52
58
  }
53
59
  export interface OpenDocumentResponse {
54
60
  documentId: string;
55
61
  task: Task<PdfDocumentObject, PdfErrorReason>;
56
62
  }
63
+ export interface SetEncryptionOptions {
64
+ /** User password (open password) - can be empty for no open password */
65
+ userPassword?: string;
66
+ /** Owner password (permissions password) - required */
67
+ ownerPassword: string;
68
+ /** Permission flags to allow. Use PdfPermissionFlag enum values combined with | operator */
69
+ allowedFlags: number;
70
+ }
57
71
  export interface DocumentManagerCapability {
58
72
  openFileDialog: (options?: OpenFileDialogOptions) => Task<OpenDocumentResponse, PdfErrorReason>;
59
73
  openDocumentUrl(options: LoadDocumentUrlOptions): Task<OpenDocumentResponse, PdfErrorReason>;
@@ -73,6 +87,32 @@ export interface DocumentManagerCapability {
73
87
  isDocumentOpen(documentId: string): boolean;
74
88
  getDocumentCount(): number;
75
89
  getDocumentIndex(documentId: string): number;
90
+ /**
91
+ * Set encryption (password protection) on a document.
92
+ * The encryption is pending until the document is saved.
93
+ *
94
+ * @param documentId - The document to protect
95
+ * @param options - Encryption options including passwords and permissions
96
+ * @returns Task that resolves to true on success
97
+ */
98
+ setDocumentEncryption(documentId: string, options: SetEncryptionOptions): Task<boolean, PdfErrorReason>;
99
+ /**
100
+ * Unlock owner permissions on an already-opened encrypted document.
101
+ * After successful unlock, FPDF_GetDocPermissions will return full permissions.
102
+ *
103
+ * @param documentId - The document to unlock
104
+ * @param ownerPassword - The owner password
105
+ * @returns Task that resolves to true if password was correct and permissions unlocked
106
+ */
107
+ unlockOwnerPermissions(documentId: string, ownerPassword: string): Task<boolean, PdfErrorReason>;
108
+ /**
109
+ * Mark document for encryption removal on save.
110
+ * When the document is saved, it will be saved without any password protection.
111
+ *
112
+ * @param documentId - The document to remove encryption from
113
+ * @returns Task that resolves to true on success
114
+ */
115
+ removeEncryption(documentId: string): Task<boolean, PdfErrorReason>;
76
116
  onDocumentOpened: EventHook<DocumentState>;
77
117
  onDocumentClosed: EventHook<string>;
78
118
  onDocumentError: EventHook<DocumentErrorEvent>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@embedpdf/plugin-document-manager",
3
- "version": "2.1.2",
3
+ "version": "2.2.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "main": "./dist/index.cjs",
@@ -34,13 +34,13 @@
34
34
  }
35
35
  },
36
36
  "dependencies": {
37
- "@embedpdf/models": "2.1.2"
37
+ "@embedpdf/models": "2.2.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/react": "^18.2.0",
41
41
  "typescript": "^5.0.0",
42
- "@embedpdf/build": "1.1.0",
43
- "@embedpdf/core": "2.1.2"
42
+ "@embedpdf/core": "2.2.0",
43
+ "@embedpdf/build": "1.1.0"
44
44
  },
45
45
  "peerDependencies": {
46
46
  "react": ">=16.8.0",
@@ -48,7 +48,7 @@
48
48
  "preact": "^10.26.4",
49
49
  "vue": ">=3.2.0",
50
50
  "svelte": ">=5 <6",
51
- "@embedpdf/core": "2.1.2"
51
+ "@embedpdf/core": "2.2.0"
52
52
  },
53
53
  "files": [
54
54
  "dist",