{"version":3,"file":"index-DUBTcZ7X.cjs","sources":["../src/lib/webworker/runner.ts","../src/lib/pdfium/index.ts","../src/lib/pdfium/runner.ts"],"sourcesContent":["import {\r\n  Logger,\r\n  NoopLogger,\r\n  PdfEngine,\r\n  PdfEngineError,\r\n  PdfEngineMethodArgs,\r\n  PdfEngineMethodName,\r\n  PdfEngineMethodReturnType,\r\n  PdfErrorCode,\r\n  Task,\r\n  TaskReturn,\r\n} from '@elhalawany/models';\r\n\r\n/**\r\n * Request body that represent method calls of PdfEngine, it contains the\r\n * method name and arguments\r\n */\r\nexport type PdfEngineMethodRequestBody = {\r\n  [P in PdfEngineMethodName]: {\r\n    name: P;\r\n    args: PdfEngineMethodArgs<P>;\r\n  };\r\n}[PdfEngineMethodName];\r\n\r\n/**\r\n * Request body that represent method calls of PdfEngine, it contains the\r\n * method name and arguments\r\n */\r\nexport type SpecificExecuteRequest<M extends PdfEngineMethodName> = {\r\n  id: string;\r\n  type: 'ExecuteRequest';\r\n  data: {\r\n    name: M;\r\n    args: PdfEngineMethodArgs<M>;\r\n  };\r\n};\r\n\r\n/**\r\n * Response body that represent return value of PdfEngine\r\n */\r\nexport type PdfEngineMethodResponseBody = {\r\n  [P in PdfEngineMethodName]: TaskReturn<PdfEngineMethodReturnType<P>>;\r\n}[PdfEngineMethodName];\r\n\r\n/**\r\n * Request that abort the specified task\r\n */\r\nexport interface AbortRequest {\r\n  /**\r\n   * message id\r\n   */\r\n  id: string;\r\n  /**\r\n   * request type\r\n   */\r\n  type: 'AbortRequest';\r\n}\r\n/**\r\n * Request that execute pdf engine method\r\n */\r\nexport interface ExecuteRequest {\r\n  /**\r\n   * message id\r\n   */\r\n  id: string;\r\n  /**\r\n   * request type\r\n   */\r\n  type: 'ExecuteRequest';\r\n  /**\r\n   * request body\r\n   */\r\n  data: PdfEngineMethodRequestBody;\r\n}\r\n/**\r\n * Response that execute pdf engine method\r\n */\r\nexport interface ExecuteResponse {\r\n  /**\r\n   * message id\r\n   */\r\n  id: string;\r\n  /**\r\n   * response type\r\n   */\r\n  type: 'ExecuteResponse';\r\n  /**\r\n   * response body\r\n   */\r\n  data: PdfEngineMethodResponseBody;\r\n}\r\n\r\n/**\r\n * Response that indicate progress of the task\r\n */\r\nexport interface ExecuteProgress<T = unknown> {\r\n  /**\r\n   * message id\r\n   */\r\n  id: string;\r\n  /**\r\n   * response type\r\n   */\r\n  type: 'ExecuteProgress';\r\n  /**\r\n   * response body\r\n   */\r\n  data: T;\r\n}\r\n\r\n/**\r\n * Response that indicate engine is ready\r\n */\r\nexport interface ReadyResponse {\r\n  /**\r\n   * message id\r\n   */\r\n  id: string;\r\n  /**\r\n   * response type\r\n   */\r\n  type: 'ReadyResponse';\r\n}\r\n\r\n/**\r\n * Request type\r\n */\r\nexport type Request = ExecuteRequest | AbortRequest;\r\n/**\r\n * Response type\r\n */\r\nexport type Response = ExecuteResponse | ReadyResponse | ExecuteProgress;\r\n\r\nconst LOG_SOURCE = 'WebWorkerEngineRunner';\r\nconst LOG_CATEGORY = 'Engine';\r\n\r\n/**\r\n * Pdf engine runner, it will execute pdf engine based on the request it received and\r\n * send back the response with post message\r\n */\r\nexport class EngineRunner {\r\n  engine: PdfEngine | undefined;\r\n\r\n  /** All running tasks, keyed by the message-id coming from the UI */\r\n  private tasks = new Map<string, Task<any, any>>();\r\n\r\n  /**\r\n   * Last time we yielded to the event loop\r\n   */\r\n  private lastYield = 0;\r\n  /**\r\n   * Ids of tasks that have been cancelled\r\n   */\r\n  private cancelledIds = new Set<string>();\r\n\r\n  /**\r\n   * Create instance of EngineRunnder\r\n   * @param logger - logger instance\r\n   */\r\n  constructor(public logger: Logger = new NoopLogger()) {}\r\n\r\n  /**\r\n   * Listening on post message\r\n   */\r\n  listen() {\r\n    self.onmessage = (evt: MessageEvent<Request>) => {\r\n      return this.handle(evt);\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Handle post message\r\n   */\r\n  handle(evt: MessageEvent<Request>) {\r\n    this.logger.debug(LOG_SOURCE, LOG_CATEGORY, 'webworker receive message event: ', evt.data);\r\n    try {\r\n      const request = evt.data as Request;\r\n      switch (request.type) {\r\n        case 'ExecuteRequest':\r\n          this.execute(request);\r\n          break;\r\n        case 'AbortRequest':\r\n          this.abort(request);\r\n          break;\r\n      }\r\n    } catch (e) {\r\n      this.logger.info(\r\n        LOG_SOURCE,\r\n        LOG_CATEGORY,\r\n        'webworker met error when processing message event:',\r\n        e,\r\n      );\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Send the ready response when pdf engine is ready\r\n   * @returns\r\n   *\r\n   * @protected\r\n   */\r\n  ready() {\r\n    this.listen();\r\n\r\n    this.respond({\r\n      id: '0',\r\n      type: 'ReadyResponse',\r\n    });\r\n    this.logger.debug(LOG_SOURCE, LOG_CATEGORY, 'runner is ready');\r\n  }\r\n\r\n  private abort(request: AbortRequest) {\r\n    const t = this.tasks.get(request.id);\r\n\r\n    // Always record the abort id\r\n    this.cancelledIds.add(request.id);\r\n\r\n    if (!t) {\r\n      // nothing to cancel (already finished or wrong id) – just ignore\r\n      return;\r\n    }\r\n\r\n    t.abort({\r\n      code: PdfErrorCode.Cancelled,\r\n      message: 'aborted by client',\r\n    });\r\n\r\n    // we won’t hear from that task again\r\n    this.tasks.delete(request.id);\r\n  }\r\n\r\n  private async maybeYield() {\r\n    const now = performance.now();\r\n    // give the event loop a breath roughly every ~8ms (tune as you like)\r\n    if (now - this.lastYield > 8) {\r\n      await new Promise((r) => setTimeout(r, 0));\r\n      this.lastYield = performance.now();\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Execute the request\r\n   * @param request - request that represent the pdf engine call\r\n   * @returns\r\n   *\r\n   * @protected\r\n   */\r\n  execute = async (request: ExecuteRequest) => {\r\n    this.logger.debug(LOG_SOURCE, LOG_CATEGORY, 'runner start exeucte request');\r\n    if (!this.engine) {\r\n      const error: PdfEngineError = {\r\n        type: 'reject',\r\n        reason: {\r\n          code: PdfErrorCode.NotReady,\r\n          message: 'engine has not started yet',\r\n        },\r\n      };\r\n      const response: ExecuteResponse = {\r\n        id: request.id,\r\n        type: 'ExecuteResponse',\r\n        data: {\r\n          type: 'error',\r\n          value: error,\r\n        },\r\n      };\r\n      this.respond(response);\r\n      return;\r\n    }\r\n\r\n    // let AbortRequest messages land and pre-cancel flags get set\r\n    await this.maybeYield();\r\n\r\n    if (this.cancelledIds.has(request.id)) {\r\n      this.respond({\r\n        id: request.id,\r\n        type: 'ExecuteResponse',\r\n        data: {\r\n          type: 'error',\r\n          value: {\r\n            type: 'reject',\r\n            reason: { code: PdfErrorCode.Cancelled, message: 'aborted by client (pre-cancelled)' },\r\n          },\r\n        },\r\n      });\r\n      return;\r\n    }\r\n\r\n    const engine = this.engine;\r\n    const { name, args } = request.data;\r\n    if (!engine[name]) {\r\n      const error: PdfEngineError = {\r\n        type: 'reject',\r\n        reason: {\r\n          code: PdfErrorCode.NotSupport,\r\n          message: `engine method ${name} is not supported yet`,\r\n        },\r\n      };\r\n      const response: ExecuteResponse = {\r\n        id: request.id,\r\n        type: 'ExecuteResponse',\r\n        data: {\r\n          type: 'error',\r\n          value: error,\r\n        },\r\n      };\r\n      this.respond(response);\r\n      return;\r\n    }\r\n\r\n    let task: PdfEngineMethodReturnType<typeof name>;\r\n    switch (name) {\r\n      case 'isSupport':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'initialize':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'destroy':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'openDocumentUrl':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'openDocumentBuffer':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'getDocPermissions':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'getDocUserPermissions':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'getMetadata':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'setMetadata':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'getBookmarks':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'setBookmarks':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'deleteBookmarks':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'getSignatures':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'renderPage':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'renderPageRect':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'renderPageAnnotation':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'renderThumbnail':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'getAllAnnotations':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'getPageAnnotations':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'createPageAnnotation':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'updatePageAnnotation':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'removePageAnnotation':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'getPageTextRects':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'searchAllPages':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'closeDocument':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'closeAllDocuments':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'saveAsCopy':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'getAttachments':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'addAttachment':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'removeAttachment':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'readAttachmentContent':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'setFormFieldValue':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'flattenPage':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'extractPages':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'extractText':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'redactTextInRects':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'getTextSlices':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'getPageGlyphs':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'getPageGeometry':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'merge':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'mergePages':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n      case 'preparePrintDocument':\r\n        task = this.engine[name]!(...args);\r\n        break;\r\n    }\r\n\r\n    this.tasks.set(request.id, task);\r\n\r\n    task.onProgress((progress) => {\r\n      const response: ExecuteProgress = {\r\n        id: request.id,\r\n        type: 'ExecuteProgress',\r\n        data: progress,\r\n      };\r\n      this.respond(response);\r\n    });\r\n\r\n    task.wait(\r\n      (result) => {\r\n        const response: ExecuteResponse = {\r\n          id: request.id,\r\n          type: 'ExecuteResponse',\r\n          data: {\r\n            type: 'result',\r\n            value: result,\r\n          },\r\n        };\r\n        this.respond(response);\r\n        this.tasks.delete(request.id);\r\n        this.cancelledIds.delete(request.id);\r\n      },\r\n      (error) => {\r\n        const response: ExecuteResponse = {\r\n          id: request.id,\r\n          type: 'ExecuteResponse',\r\n          data: {\r\n            type: 'error',\r\n            value: error,\r\n          },\r\n        };\r\n        this.respond(response);\r\n        this.tasks.delete(request.id);\r\n        this.cancelledIds.delete(request.id);\r\n      },\r\n    );\r\n  };\r\n\r\n  /**\r\n   * Send back the response\r\n   * @param response - response that needs sent back\r\n   *\r\n   * @protected\r\n   */\r\n  respond(response: Response) {\r\n    this.logger.debug(LOG_SOURCE, LOG_CATEGORY, 'runner respond: ', response);\r\n    self.postMessage(response);\r\n  }\r\n}\r\n","export * from './engine';\r\nexport * from './helper';\r\nexport * from './runner';\r\n\r\nexport const DEFAULT_PDFIUM_WASM_URL: string =\r\n  'https://cdn.jsdelivr.net/npm/@elhalawany/pdfium@__PDFIUM_VERSION__/dist/pdfium.wasm';\r\n","import { init } from '@elhalawany/pdfium';\r\nimport { EngineRunner } from '../webworker/runner';\r\nimport { PdfiumEngine } from './engine';\r\nimport { Logger } from '@elhalawany/models';\r\n\r\n/**\r\n * EngineRunner for pdfium-based wasm engine\r\n */\r\nexport class PdfiumEngineRunner extends EngineRunner {\r\n  /**\r\n   * Create an instance of PdfiumEngineRunner\r\n   * @param wasmBinary - wasm binary that contains the pdfium wasm file\r\n   */\r\n  constructor(\r\n    private wasmBinary: ArrayBuffer,\r\n    logger?: Logger,\r\n  ) {\r\n    super(logger);\r\n  }\r\n\r\n  /**\r\n   * Initialize runner\r\n   */\r\n  async prepare() {\r\n    const wasmBinary = this.wasmBinary;\r\n    const wasmModule = await init({ wasmBinary });\r\n    this.engine = new PdfiumEngine(wasmModule, { logger: this.logger });\r\n    this.ready();\r\n  }\r\n}\r\n"],"names":["LOG_SOURCE","LOG_CATEGORY","EngineRunner","constructor","logger","NoopLogger","this","tasks","Map","lastYield","cancelledIds","Set","execute","async","request","debug","engine","error","type","reason","code","PdfErrorCode","NotReady","message","response","id","data","value","respond","maybeYield","has","Cancelled","name","args","NotSupport","task","set","onProgress","progress","wait","result","delete","listen","self","onmessage","evt","handle","abort","e","info","ready","t","get","add","performance","now","Promise","r","setTimeout","postMessage","wasmBinary","super","prepare","wasmModule","init","PdfiumEngine"],"mappings":"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"}