@imgly/plugin-print-ready-pdfs-web 0.1.0-rc.2 → 1.1.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/CHANGELOG.md CHANGED
@@ -5,6 +5,28 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.1.0] - 2025-12-03
9
+
10
+ ### Added
11
+
12
+ - Export `Logger` class for controlling log verbosity
13
+ - Export `LogLevel` type for TypeScript users
14
+
15
+ ### Changed
16
+
17
+ - Library is now silent by default (log level set to `warn` instead of `info`)
18
+ - Ghostscript WASM module suppresses stdout/stderr output by default
19
+
20
+ ### Fixed
21
+
22
+ - Eliminated Ghostscript warnings about PDF 1.5 features ("Can't use Object streams", "Can't use an XRef stream") by disabling `-dWriteObjStms` and `-dWriteXRefStm` when targeting PDF 1.4 compatibility
23
+
24
+ ## [1.0.0] - 2025-10-21
25
+
26
+ ### Changed
27
+
28
+ - Promoted to stable release
29
+
8
30
  ## [0.1.0-rc.1] - 2025-10-16
9
31
 
10
32
  ### Added
package/README.md CHANGED
@@ -62,42 +62,42 @@ import { convertToPDFX3 } from '@imgly/plugin-print-ready-pdfs-web';
62
62
 
63
63
  const config = {
64
64
  license: 'your-cesdk-license',
65
- ui: {
66
- elements: {
67
- navigation: {
68
- action: {
69
- custom: [
70
- {
71
- label: 'Export Print-Ready PDF',
72
- iconName: '@imgly/icons/Essentials/Download',
73
- callback: async () => {
74
- const sceneId = cesdk.engine.scene.get();
75
- const pdfBlob = await cesdk.engine.block.export(
76
- sceneId,
77
- 'application/pdf'
78
- );
79
- const printReadyBlob = await convertToPDFX3(pdfBlob, {
80
- outputProfile: 'fogra39',
81
- title: 'Print-Ready Export',
82
- });
83
-
84
- // Download
85
- const url = URL.createObjectURL(printReadyBlob);
86
- const link = document.createElement('a');
87
- link.href = url;
88
- link.download = 'design-print-ready.pdf';
89
- link.click();
90
- URL.revokeObjectURL(url);
91
- },
92
- },
93
- ],
94
- },
95
- },
96
- },
97
- },
98
65
  };
99
66
 
100
67
  const cesdk = await CreativeEditorSDK.create('#editor', config);
68
+ await cesdk.createDesignScene();
69
+
70
+ // Add custom export button to the navigation bar
71
+ cesdk.ui.insertNavigationBarOrderComponent('last', {
72
+ id: 'ly.img.actions.navigationBar',
73
+ children: [
74
+ {
75
+ key: 'export-print-ready-pdf',
76
+ id: 'ly.img.action.navigationBar',
77
+ label: 'Export Print-Ready PDF',
78
+ iconName: '@imgly/Download',
79
+ onClick: async () => {
80
+ const sceneId = cesdk.engine.scene.get();
81
+ const pdfBlob = await cesdk.engine.block.export(
82
+ sceneId,
83
+ 'application/pdf'
84
+ );
85
+ const printReadyBlob = await convertToPDFX3(pdfBlob, {
86
+ outputProfile: 'fogra39',
87
+ title: 'Print-Ready Export',
88
+ });
89
+
90
+ // Download
91
+ const url = URL.createObjectURL(printReadyBlob);
92
+ const link = document.createElement('a');
93
+ link.href = url;
94
+ link.download = 'design-print-ready.pdf';
95
+ link.click();
96
+ URL.revokeObjectURL(url);
97
+ },
98
+ },
99
+ ],
100
+ });
101
101
  ```
102
102
 
103
103
  ## API Reference
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- var c=class o{constructor(t){this.component=t}static globalLogLevel="info";static logs=[];static maxLogs=1e3;static setLogLevel(t){o.globalLogLevel=t}static getLogs(){return[...o.logs]}static clearLogs(){o.logs=[]}debug(t,e){this.log("debug",t,e)}info(t,e){this.log("info",t,e)}warn(t,e){this.log("warn",t,e)}error(t,e){this.log("error",t,e)}log(t,e,i){let r={debug:0,info:1,warn:2,error:3};if(r[t]<r[o.globalLogLevel])return;let s={timestamp:Date.now(),level:t,component:this.component,message:e,data:i};o.logs.push(s),o.logs.length>o.maxLogs&&(o.logs=o.logs.slice(-o.maxLogs));let n=`[${new Date().toISOString()}] [${t.toUpperCase()}] [${this.component}]`,l=i?`${e} ${JSON.stringify(i)}`:e;switch(t){case"debug":console.debug(n,l);break;case"info":console.info(n,l);break;case"warn":console.warn(n,l);break;case"error":console.error(n,l);break;default:break}}};var g=class{supportsWebAssembly(){try{return typeof WebAssembly=="object"&&typeof WebAssembly.instantiate=="function"}catch{return!1}}};async function E(){let o=typeof process<"u"&&process.versions!=null&&process.versions.node!=null,t,e;if(o){let{createRequire:s}=await import("module"),{dirname:n,join:l}=await import("path"),u=s(import.meta.url).resolve("./gs.js"),p=n(u);e=l(p,"gs.wasm"),t=await import(u)}else t=await import(new URL("./gs.js",import.meta.url).href),e=new URL("./gs.wasm",import.meta.url).href;return await(t.default||t)({locateFile:s=>s==="gs.wasm"?e:s})}var h=class{static instance=null;static TIMEOUT_MS=3e4;static async load(t={}){return this.instance?this.instance:(this.instance=this.loadInternal(t),this.instance)}static async loadInternal(t){let e=new c("GhostscriptLoader");if(!new g().supportsWebAssembly())throw new Error("WebAssembly not supported in this browser");let r=t.timeout||this.TIMEOUT_MS;try{return e.info("Loading bundled Ghostscript (AGPL-3.0 licensed)"),e.info("Source available at: https://github.com/imgly/plugins"),await this.loadWithTimeout(()=>this.loadFromBundle(),r)}catch(s){throw e.error("Ghostscript loading failed",{error:s.message}),new Error(`Failed to load Ghostscript: ${s.message}`)}}static async loadFromBundle(){let t=new c("GhostscriptInit");try{t.info("Initializing Ghostscript module");let e=await E();return t.info("Ghostscript module initialized successfully",{version:e.version||"unknown",hasFS:!!e.FS,hasCallMain:!!e.callMain}),e}catch(e){throw t.error("Ghostscript initialization failed",{error:e}),new Error(`Ghostscript initialization failed: ${e.message}`)}}static async loadWithTimeout(t,e){return Promise.race([t(),new Promise((i,r)=>{setTimeout(()=>r(new Error(`Loading timeout after ${e}ms`)),e)})])}static reset(){this.instance=null}};var f=class{static async toUint8Array(t){if(t.arrayBuffer){let e=await t.arrayBuffer();return new Uint8Array(e)}return new Promise((e,i)=>{let r=new FileReader;r.onload=()=>{r.result instanceof ArrayBuffer?e(new Uint8Array(r.result)):i(new Error("Failed to read blob as ArrayBuffer"))},r.onerror=()=>i(r.error),r.readAsArrayBuffer(t)})}static async validatePDF(t){try{let e=await this.toUint8Array(t),i=new Uint8Array([37,80,68,70]);if(e.length<4)return!1;for(let r=0;r<4;r++)if(e[r]!==i[r])return!1;return!0}catch{return!1}}};var w=class{constructor(t,e="/tmp/pdfx"){this.module=t;this.fs=t.FS,this.logger=new c("VirtualFileSystem"),this.workingDir=e,this.initialize()}fs;logger;managedFiles=new Set;workingDir;initialize(){try{this.createDirIfNotExists(this.workingDir),this.createDirIfNotExists(`${this.workingDir}/input`),this.createDirIfNotExists(`${this.workingDir}/output`),this.createDirIfNotExists(`${this.workingDir}/profiles`),this.createDirIfNotExists(`${this.workingDir}/temp`),this.logger.info("Virtual filesystem initialized",{workingDir:this.workingDir})}catch(t){throw this.logger.error("Failed to initialize virtual filesystem",{error:t}),new Error(`VFS initialization failed: ${t}`)}}createDirIfNotExists(t){try{this.fs.mkdir(t)}catch(e){if(e.code!=="EEXIST")throw e}}async writeBlob(t,e,i=!0){try{let r=await f.toUint8Array(e);this.fs.writeFile(t,r),i&&this.managedFiles.add(t),this.logger.debug("File written",{path:t,size:r.length})}catch(r){throw this.logger.error("Failed to write blob",{path:t,error:r}),new Error(`Failed to write file ${t}: ${r}`)}}writeText(t,e,i=!0){try{this.fs.writeFile(t,e),i&&this.managedFiles.add(t),this.logger.debug("Text file written",{path:t,length:e.length})}catch(r){throw this.logger.error("Failed to write text",{path:t,error:r}),new Error(`Failed to write text file ${t}: ${r}`)}}readFile(t){try{let e=this.fs.readFile(t);return this.logger.debug("File read",{path:t,size:e.length}),e}catch(e){throw this.logger.error("Failed to read file",{path:t,error:e}),new Error(`Failed to read file ${t}: ${e}`)}}exists(t){try{return this.fs.stat(t),!0}catch{return!1}}cleanup(){let t=0;for(let e of this.managedFiles)try{this.fs.unlink(e),t++}catch(i){this.logger.warn("Failed to cleanup file",{path:e,error:i})}this.managedFiles.clear(),this.logger.info("Filesystem cleanup completed",{cleanedCount:t})}};async function z(o,t){if(Array.isArray(o)){if(o.length===0)return[];let e=[];for(let i=0;i<o.length;i++)try{let r=await S(o[i],t);e.push(r)}catch(r){throw new Error(`Failed to convert PDF ${i+1} of ${o.length}: ${r instanceof Error?r.message:String(r)}`)}return e}return S(o,t)}async function S(o,t){if(!(o instanceof Blob))throw new Error("Input must be a Blob");if(o.size===0)throw new Error("Input PDF is empty");if(o.size>100*1024*1024)throw new Error(`Input PDF too large (${o.size} bytes). Maximum: 100MB`);if(!t.outputProfile)throw new Error('outputProfile is required. Must be one of: "gracol", "fogra39", "srgb", "custom"');let e=["gracol","fogra39","srgb","custom"];if(!e.includes(t.outputProfile))throw new Error(`Invalid outputProfile "${t.outputProfile}". Must be one of: ${e.join(", ")}`);if(t.outputProfile==="custom"&&!t.customProfile)throw new Error('customProfile Blob is required when outputProfile is "custom"');if(t.customProfile&&!(t.customProfile instanceof Blob))throw new Error("customProfile must be a Blob");if(!await f.validatePDF(o))throw new Error("Invalid PDF format");let r=await h.load(),s=new w(r);try{let n="/tmp/input.pdf",l="/tmp/output.pdf",y="/tmp/pdfx_def.ps",u="/tmp/custom.icc";if(await s.writeBlob(n,o),t.outputProfile==="custom"&&t.customProfile)await s.writeBlob(u,t.customProfile);else if(t.outputProfile!=="custom"){let a=x[t.outputProfile],M=`/tmp/${a.file}`,k=typeof process<"u"&&process.versions?.node!=null,b;if(k){let{readFileSync:v}=await import("fs"),{fileURLToPath:m}=await import("url"),{dirname:G,join:X}=await import("path"),U=G(m(import.meta.url)),R=X(U,a.file),N=v(R);b=new Blob([N],{type:"application/vnd.iccprofile"})}else{let v=new URL(a.file,import.meta.url).href,m=await fetch(v);if(!m.ok)throw new Error(`Failed to load ICC profile ${a.file}: ${m.statusText}`);b=await m.blob()}await s.writeBlob(M,b)}let p,P,F;if(t.outputProfile==="custom")p=u,P=t.outputConditionIdentifier||"Custom Profile",F=t.outputCondition||"Custom ICC Profile";else{let a=x[t.outputProfile];p=`/tmp/${a.file}`,P=t.outputConditionIdentifier||a.identifier,F=t.outputCondition||a.info}let D=s.readFile(p),I=Array.from(D).map(a=>a.toString(16).padStart(2,"0")).join(""),B=D.slice(16,20),L=String.fromCharCode(...B).trim()==="CMYK",T=_(t,I,P,F);s.writeText(y,T);let d=["-dBATCH","-dNOPAUSE","-sDEVICE=pdfwrite","-dCompatibilityLevel=1.4","-dPDFSETTINGS=/prepress","-dSetPageSize=false","-dAutoRotatePages=/None"];t.flattenTransparency!==!1&&d.push("-dHaveTransparency=false"),L?d.push("-sColorConversionStrategy=CMYK","-dProcessColorModel=/DeviceCMYK","-dConvertCMYKImagesToRGB=false"):d.push("-sColorConversionStrategy=RGB"),d.push(`-sOutputFile=${l}`,y,n);let C=await r.callMain(d);if(C!==0)throw new Error(`Ghostscript conversion failed with exit code ${C}`);let O=s.readFile(l),$=new Uint8Array(O),A=new Blob([$],{type:"application/pdf"});return s.cleanup(),A}catch(n){throw s.cleanup(),n}}var x={gracol:{file:"GRACoL2013_CRPC6.icc",identifier:"CGATS 21.2",info:"GRACoL 2013 CRPC6"},fogra39:{file:"ISOcoated_v2_eci.icc",identifier:"FOGRA39",info:"ISO Coated v2 (ECI)"},srgb:{file:"sRGB_IEC61966-2-1.icc",identifier:"sRGB IEC61966-2.1",info:"sRGB IEC61966-2.1"}};function _(o,t,e,i){return`%!
1
+ var f=class o{constructor(t){this.component=t}static globalLogLevel="warn";static logs=[];static maxLogs=1e3;static setLogLevel(t){o.globalLogLevel=t}static getLogs(){return[...o.logs]}static clearLogs(){o.logs=[]}debug(t,e){this.log("debug",t,e)}info(t,e){this.log("info",t,e)}warn(t,e){this.log("warn",t,e)}error(t,e){this.log("error",t,e)}log(t,e,i){let r={debug:0,info:1,warn:2,error:3};if(r[t]<r[o.globalLogLevel])return;let s={timestamp:Date.now(),level:t,component:this.component,message:e,data:i};o.logs.push(s),o.logs.length>o.maxLogs&&(o.logs=o.logs.slice(-o.maxLogs));let n=`[${new Date().toISOString()}] [${t.toUpperCase()}] [${this.component}]`,l=i?`${e} ${JSON.stringify(i)}`:e;switch(t){case"debug":console.debug(n,l);break;case"info":console.info(n,l);break;case"warn":console.warn(n,l);break;case"error":console.error(n,l);break;default:break}}};var P=class{supportsWebAssembly(){try{return typeof WebAssembly=="object"&&typeof WebAssembly.instantiate=="function"}catch{return!1}}};async function D(o={}){let{silent:t=!0}=o,e=typeof process<"u"&&process.versions!=null&&process.versions.node!=null,i,r;if(e){let{createRequire:c}=await import("module"),{dirname:h,join:d}=await import("path"),u=c(import.meta.url).resolve("./gs.js"),y=h(u);r=d(y,"gs.wasm"),i=await import(u)}else i=await import(new URL("./gs.js",import.meta.url).href),r=new URL("./gs.wasm",import.meta.url).href;let s=i.default||i,n={locateFile:c=>c==="gs.wasm"?r:c};return t&&(n.print=()=>{},n.printErr=()=>{}),await s(n)}var F=class{static instance=null;static TIMEOUT_MS=3e4;static async load(t={}){return this.instance?this.instance:(this.instance=this.loadInternal(t),this.instance)}static async loadInternal(t){let e=new f("GhostscriptLoader");if(!new P().supportsWebAssembly())throw new Error("WebAssembly not supported in this browser");let r=t.timeout||this.TIMEOUT_MS;try{return e.info("Loading bundled Ghostscript (AGPL-3.0 licensed)"),e.info("Source available at: https://github.com/imgly/plugins"),await this.loadWithTimeout(()=>this.loadFromBundle(),r)}catch(s){throw e.error("Ghostscript loading failed",{error:s.message}),new Error(`Failed to load Ghostscript: ${s.message}`)}}static async loadFromBundle(){let t=new f("GhostscriptInit");try{t.info("Initializing Ghostscript module");let e=await D();return t.info("Ghostscript module initialized successfully",{version:e.version||"unknown",hasFS:!!e.FS,hasCallMain:!!e.callMain}),e}catch(e){throw t.error("Ghostscript initialization failed",{error:e}),new Error(`Ghostscript initialization failed: ${e.message}`)}}static async loadWithTimeout(t,e){return Promise.race([t(),new Promise((i,r)=>{setTimeout(()=>r(new Error(`Loading timeout after ${e}ms`)),e)})])}static reset(){this.instance=null}};var p=class{static async toUint8Array(t){if(t.arrayBuffer){let e=await t.arrayBuffer();return new Uint8Array(e)}return new Promise((e,i)=>{let r=new FileReader;r.onload=()=>{r.result instanceof ArrayBuffer?e(new Uint8Array(r.result)):i(new Error("Failed to read blob as ArrayBuffer"))},r.onerror=()=>i(r.error),r.readAsArrayBuffer(t)})}static async validatePDF(t){try{let e=await this.toUint8Array(t),i=new Uint8Array([37,80,68,70]);if(e.length<4)return!1;for(let r=0;r<4;r++)if(e[r]!==i[r])return!1;return!0}catch{return!1}}};var b=class{constructor(t,e="/tmp/pdfx"){this.module=t;this.fs=t.FS,this.logger=new f("VirtualFileSystem"),this.workingDir=e,this.initialize()}fs;logger;managedFiles=new Set;workingDir;initialize(){try{this.createDirIfNotExists(this.workingDir),this.createDirIfNotExists(`${this.workingDir}/input`),this.createDirIfNotExists(`${this.workingDir}/output`),this.createDirIfNotExists(`${this.workingDir}/profiles`),this.createDirIfNotExists(`${this.workingDir}/temp`),this.logger.info("Virtual filesystem initialized",{workingDir:this.workingDir})}catch(t){throw this.logger.error("Failed to initialize virtual filesystem",{error:t}),new Error(`VFS initialization failed: ${t}`)}}createDirIfNotExists(t){try{this.fs.mkdir(t)}catch(e){if(e.code!=="EEXIST")throw e}}async writeBlob(t,e,i=!0){try{let r=await p.toUint8Array(e);this.fs.writeFile(t,r),i&&this.managedFiles.add(t),this.logger.debug("File written",{path:t,size:r.length})}catch(r){throw this.logger.error("Failed to write blob",{path:t,error:r}),new Error(`Failed to write file ${t}: ${r}`)}}writeText(t,e,i=!0){try{this.fs.writeFile(t,e),i&&this.managedFiles.add(t),this.logger.debug("Text file written",{path:t,length:e.length})}catch(r){throw this.logger.error("Failed to write text",{path:t,error:r}),new Error(`Failed to write text file ${t}: ${r}`)}}readFile(t){try{let e=this.fs.readFile(t);return this.logger.debug("File read",{path:t,size:e.length}),e}catch(e){throw this.logger.error("Failed to read file",{path:t,error:e}),new Error(`Failed to read file ${t}: ${e}`)}}exists(t){try{return this.fs.stat(t),!0}catch{return!1}}cleanup(){let t=0;for(let e of this.managedFiles)try{this.fs.unlink(e),t++}catch(i){this.logger.warn("Failed to cleanup file",{path:e,error:i})}this.managedFiles.clear(),this.logger.info("Filesystem cleanup completed",{cleanedCount:t})}};async function z(o,t){if(Array.isArray(o)){if(o.length===0)return[];let e=[];for(let i=0;i<o.length;i++)try{let r=await x(o[i],t);e.push(r)}catch(r){throw new Error(`Failed to convert PDF ${i+1} of ${o.length}: ${r instanceof Error?r.message:String(r)}`)}return e}return x(o,t)}async function x(o,t){if(!(o instanceof Blob))throw new Error("Input must be a Blob");if(o.size===0)throw new Error("Input PDF is empty");if(o.size>100*1024*1024)throw new Error(`Input PDF too large (${o.size} bytes). Maximum: 100MB`);if(!t.outputProfile)throw new Error('outputProfile is required. Must be one of: "gracol", "fogra39", "srgb", "custom"');let e=["gracol","fogra39","srgb","custom"];if(!e.includes(t.outputProfile))throw new Error(`Invalid outputProfile "${t.outputProfile}". Must be one of: ${e.join(", ")}`);if(t.outputProfile==="custom"&&!t.customProfile)throw new Error('customProfile Blob is required when outputProfile is "custom"');if(t.customProfile&&!(t.customProfile instanceof Blob))throw new Error("customProfile must be a Blob");if(!await p.validatePDF(o))throw new Error("Invalid PDF format");let r=await F.load(),s=new b(r);try{let n="/tmp/input.pdf",l="/tmp/output.pdf",c="/tmp/pdfx_def.ps",h="/tmp/custom.icc";if(await s.writeBlob(n,o),t.outputProfile==="custom"&&t.customProfile)await s.writeBlob(h,t.customProfile);else if(t.outputProfile!=="custom"){let a=S[t.outputProfile],A=`/tmp/${a.file}`,G=typeof process<"u"&&process.versions?.node!=null,v;if(G){let{readFileSync:E}=await import("fs"),{fileURLToPath:g}=await import("url"),{dirname:k,join:X}=await import("path"),R=k(g(import.meta.url)),U=X(R,a.file),N=E(U);v=new Blob([N],{type:"application/vnd.iccprofile"})}else{let E=new URL(a.file,import.meta.url).href,g=await fetch(E);if(!g.ok)throw new Error(`Failed to load ICC profile ${a.file}: ${g.statusText}`);v=await g.blob()}await s.writeBlob(A,v)}let d,w,u;if(t.outputProfile==="custom")d=h,w=t.outputConditionIdentifier||"Custom Profile",u=t.outputCondition||"Custom ICC Profile";else{let a=S[t.outputProfile];d=`/tmp/${a.file}`,w=t.outputConditionIdentifier||a.identifier,u=t.outputCondition||a.info}let y=s.readFile(d),L=Array.from(y).map(a=>a.toString(16).padStart(2,"0")).join(""),I=y.slice(16,20),B=String.fromCharCode(...I).trim()==="CMYK",T=_(t,L,w,u);s.writeText(c,T);let m=["-dBATCH","-dNOPAUSE","-sDEVICE=pdfwrite","-dCompatibilityLevel=1.4","-dWriteObjStms=false","-dWriteXRefStm=false","-dPDFSETTINGS=/prepress","-dSetPageSize=false","-dAutoRotatePages=/None"];t.flattenTransparency!==!1&&m.push("-dHaveTransparency=false"),B?m.push("-sColorConversionStrategy=CMYK","-dProcessColorModel=/DeviceCMYK","-dConvertCMYKImagesToRGB=false"):m.push("-sColorConversionStrategy=RGB"),m.push(`-sOutputFile=${l}`,c,n);let C=await r.callMain(m);if(C!==0)throw new Error(`Ghostscript conversion failed with exit code ${C}`);let O=s.readFile(l),M=new Uint8Array(O),$=new Blob([M],{type:"application/pdf"});return s.cleanup(),$}catch(n){throw s.cleanup(),n}}var S={gracol:{file:"GRACoL2013_CRPC6.icc",identifier:"CGATS 21.2",info:"GRACoL 2013 CRPC6"},fogra39:{file:"ISOcoated_v2_eci.icc",identifier:"FOGRA39",info:"ISO Coated v2 (ECI)"},srgb:{file:"sRGB_IEC61966-2-1.icc",identifier:"sRGB IEC61966-2.1",info:"sRGB IEC61966-2.1"}};function _(o,t,e,i){return`%!
2
2
  % PDF/X-3 Definition File
3
3
  [ /Title (${o.title||"Untitled"}) /DOCINFO pdfmark
4
4
  [ /Trapped /False /DOCINFO pdfmark
@@ -26,5 +26,5 @@ var c=class o{constructor(t){this.component=t}static globalLogLevel="info";stati
26
26
  >> /PUT pdfmark
27
27
 
28
28
  % Add OutputIntent to Catalog
29
- [{Catalog} <</OutputIntents [{OutputIntent_PDFX}]>> /PUT pdfmark`}export{z as convertToPDFX3};
29
+ [{Catalog} <</OutputIntents [{OutputIntent_PDFX}]>> /PUT pdfmark`}export{f as Logger,z as convertToPDFX3};
30
30
  //# sourceMappingURL=index.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/utils/logger.ts", "../src/utils/browser-detection.ts", "../src/wasm/ghostscript-module.ts", "../src/core/ghostscript-loader.ts", "../src/utils/blob-utils.ts", "../src/core/virtual-filesystem.ts", "../src/pdfx.ts"],
4
- "sourcesContent": ["/* eslint-disable no-console */\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport interface LogEntry {\n timestamp: number;\n level: LogLevel;\n component: string;\n message: string;\n data?: any;\n}\n\nexport class Logger {\n private static globalLogLevel: LogLevel = 'info';\n\n private static logs: LogEntry[] = [];\n\n private static maxLogs = 1000;\n\n constructor(private component: string) {}\n\n static setLogLevel(level: LogLevel): void {\n Logger.globalLogLevel = level;\n }\n\n static getLogs(): LogEntry[] {\n return [...Logger.logs];\n }\n\n static clearLogs(): void {\n Logger.logs = [];\n }\n\n debug(message: string, data?: any): void {\n this.log('debug', message, data);\n }\n\n info(message: string, data?: any): void {\n this.log('info', message, data);\n }\n\n warn(message: string, data?: any): void {\n this.log('warn', message, data);\n }\n\n error(message: string, data?: any): void {\n this.log('error', message, data);\n }\n\n private log(level: LogLevel, message: string, data?: any): void {\n const levelOrder: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n };\n\n if (levelOrder[level] < levelOrder[Logger.globalLogLevel]) {\n return;\n }\n\n const entry: LogEntry = {\n timestamp: Date.now(),\n level,\n component: this.component,\n message,\n data,\n };\n\n Logger.logs.push(entry);\n\n // Keep logs under the limit\n if (Logger.logs.length > Logger.maxLogs) {\n Logger.logs = Logger.logs.slice(-Logger.maxLogs);\n }\n\n // Console output\n const prefix = `[${new Date().toISOString()}] [${level.toUpperCase()}] [${\n this.component\n }]`;\n const logMessage = data ? `${message} ${JSON.stringify(data)}` : message;\n\n switch (level) {\n case 'debug':\n console.debug(prefix, logMessage);\n break;\n case 'info':\n console.info(prefix, logMessage);\n break;\n case 'warn':\n console.warn(prefix, logMessage);\n break;\n case 'error':\n console.error(prefix, logMessage);\n break;\n default:\n // All log levels handled above\n break;\n }\n }\n}\n", "export class BrowserDetection {\n supportsWebAssembly(): boolean {\n try {\n return (\n typeof WebAssembly === 'object' &&\n typeof WebAssembly.instantiate === 'function'\n );\n } catch {\n return false;\n }\n }\n}\n", "// Wrapper for the Ghostscript WASM module to ensure proper loading\nimport type {\n EmscriptenModule,\n GhostscriptModuleFactory,\n} from '../types/ghostscript';\n\nexport default async function createGhostscriptModule(): Promise<EmscriptenModule> {\n // Check if we're in Node.js\n const isNode =\n typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null;\n\n let GhostscriptModule: any;\n let wasmPath: string;\n\n if (isNode) {\n // Node.js: Use require.resolve to find gs.js relative to this module\n const { createRequire } = await import('module');\n const { dirname, join } = await import('path');\n\n const requireForESM = createRequire(import.meta.url);\n\n // Resolve gs.js directly (it's copied to dist/ alongside the bundle)\n const gsPath = requireForESM.resolve('./gs.js');\n const moduleDir = dirname(gsPath);\n wasmPath = join(moduleDir, 'gs.wasm');\n\n GhostscriptModule = await import(gsPath);\n } else {\n // Browser: Use URL-based imports\n const moduleUrl = new URL('./gs.js', import.meta.url).href;\n GhostscriptModule = await import(/* webpackIgnore: true */ moduleUrl);\n wasmPath = new URL('./gs.wasm', import.meta.url).href;\n }\n\n const factory = (GhostscriptModule.default ||\n GhostscriptModule) as GhostscriptModuleFactory;\n\n // Configure the module to load WASM from the bundled location\n const module = await factory({\n locateFile: (filename: string) => {\n if (filename === 'gs.wasm') {\n return wasmPath;\n }\n return filename;\n },\n });\n\n return module;\n}\n", "import type { EmscriptenModule } from '../types/ghostscript';\nimport { Logger } from '../utils/logger';\nimport { BrowserDetection } from '../utils/browser-detection';\nimport createGhostscriptModule from '../wasm/ghostscript-module';\n\nexport interface LoaderOptions {\n timeout?: number;\n}\n\nexport class GhostscriptLoader {\n private static instance: Promise<EmscriptenModule> | null = null;\n\n private static readonly TIMEOUT_MS = 30000;\n\n static async load(options: LoaderOptions = {}): Promise<EmscriptenModule> {\n if (this.instance) {\n return this.instance;\n }\n\n this.instance = this.loadInternal(options);\n return this.instance;\n }\n\n private static async loadInternal(\n options: LoaderOptions\n ): Promise<EmscriptenModule> {\n const logger = new Logger('GhostscriptLoader');\n const browser = new BrowserDetection();\n\n // Check browser compatibility\n if (!browser.supportsWebAssembly()) {\n throw new Error('WebAssembly not supported in this browser');\n }\n\n const timeout = options.timeout || this.TIMEOUT_MS;\n\n try {\n logger.info('Loading bundled Ghostscript (AGPL-3.0 licensed)');\n logger.info('Source available at: https://github.com/imgly/plugins');\n return await this.loadWithTimeout(() => this.loadFromBundle(), timeout);\n } catch (error) {\n logger.error('Ghostscript loading failed', {\n error: (error as Error).message,\n });\n throw new Error(\n `Failed to load Ghostscript: ${(error as Error).message}`\n );\n }\n }\n\n private static async loadFromBundle(): Promise<EmscriptenModule> {\n // Use the bundled WASM module with proper configuration\n const logger = new Logger('GhostscriptInit');\n\n try {\n logger.info('Initializing Ghostscript module');\n\n const module = await createGhostscriptModule();\n\n logger.info('Ghostscript module initialized successfully', {\n version: module.version || 'unknown',\n hasFS: !!module.FS,\n hasCallMain: !!module.callMain,\n });\n\n return module;\n } catch (error) {\n logger.error('Ghostscript initialization failed', { error });\n throw new Error(\n `Ghostscript initialization failed: ${(error as Error).message}`\n );\n }\n }\n\n private static async loadWithTimeout<T>(\n operation: () => Promise<T>,\n timeoutMs: number\n ): Promise<T> {\n return Promise.race([\n operation(),\n new Promise<never>((_, reject) => {\n setTimeout(\n () => reject(new Error(`Loading timeout after ${timeoutMs}ms`)),\n timeoutMs\n );\n }),\n ]);\n }\n\n static reset(): void {\n this.instance = null;\n }\n}\n", "export class BlobUtils {\n static async toUint8Array(blob: Blob): Promise<Uint8Array> {\n if (blob.arrayBuffer) {\n const buffer = await blob.arrayBuffer();\n return new Uint8Array(buffer);\n }\n\n // Fallback for older browsers\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n if (reader.result instanceof ArrayBuffer) {\n resolve(new Uint8Array(reader.result));\n } else {\n reject(new Error('Failed to read blob as ArrayBuffer'));\n }\n };\n reader.onerror = () => reject(reader.error);\n reader.readAsArrayBuffer(blob);\n });\n }\n\n static async validatePDF(blob: Blob): Promise<boolean> {\n try {\n const data = await this.toUint8Array(blob);\n\n // Check PDF magic number\n const pdfHeader = new Uint8Array([0x25, 0x50, 0x44, 0x46]); // %PDF\n\n if (data.length < 4) {\n return false;\n }\n\n for (let i = 0; i < 4; i++) {\n if (data[i] !== pdfHeader[i]) {\n return false;\n }\n }\n\n return true;\n } catch {\n return false;\n }\n }\n}\n", "import type { EmscriptenModule, EmscriptenFS } from '../types/ghostscript';\nimport { Logger } from '../utils/logger';\nimport { BlobUtils } from '../utils/blob-utils';\n\nexport interface FileEntry {\n path: string;\n data: Uint8Array;\n cleanup: boolean;\n}\n\nexport class VirtualFileSystem {\n private readonly fs: EmscriptenFS;\n\n private readonly logger: Logger;\n\n private readonly managedFiles: Set<string> = new Set();\n\n private readonly workingDir: string;\n\n constructor(\n private readonly module: EmscriptenModule,\n workingDir = '/tmp/pdfx'\n ) {\n this.fs = module.FS;\n this.logger = new Logger('VirtualFileSystem');\n this.workingDir = workingDir;\n this.initialize();\n }\n\n private initialize(): void {\n try {\n // Create working directory structure (handle existing directories gracefully)\n this.createDirIfNotExists(this.workingDir);\n this.createDirIfNotExists(`${this.workingDir}/input`);\n this.createDirIfNotExists(`${this.workingDir}/output`);\n this.createDirIfNotExists(`${this.workingDir}/profiles`);\n this.createDirIfNotExists(`${this.workingDir}/temp`);\n\n this.logger.info('Virtual filesystem initialized', {\n workingDir: this.workingDir,\n });\n } catch (error) {\n this.logger.error('Failed to initialize virtual filesystem', { error });\n throw new Error(`VFS initialization failed: ${error}`);\n }\n }\n\n private createDirIfNotExists(path: string): void {\n try {\n this.fs.mkdir(path);\n } catch (error: any) {\n // Ignore \"File exists\" errors, re-throw others\n if (error.code !== 'EEXIST') {\n throw error;\n }\n }\n }\n\n async writeBlob(path: string, blob: Blob, managed = true): Promise<void> {\n try {\n const data = await BlobUtils.toUint8Array(blob);\n this.fs.writeFile(path, data);\n\n if (managed) {\n this.managedFiles.add(path);\n }\n\n this.logger.debug('File written', { path, size: data.length });\n } catch (error) {\n this.logger.error('Failed to write blob', { path, error });\n throw new Error(`Failed to write file ${path}: ${error}`);\n }\n }\n\n writeText(path: string, content: string, managed = true): void {\n try {\n this.fs.writeFile(path, content);\n\n if (managed) {\n this.managedFiles.add(path);\n }\n\n this.logger.debug('Text file written', { path, length: content.length });\n } catch (error) {\n this.logger.error('Failed to write text', { path, error });\n throw new Error(`Failed to write text file ${path}: ${error}`);\n }\n }\n\n readFile(path: string): Uint8Array {\n try {\n const data = this.fs.readFile(path) as Uint8Array;\n this.logger.debug('File read', { path, size: data.length });\n return data;\n } catch (error) {\n this.logger.error('Failed to read file', { path, error });\n throw new Error(`Failed to read file ${path}: ${error}`);\n }\n }\n\n exists(path: string): boolean {\n try {\n this.fs.stat(path);\n return true;\n } catch {\n return false;\n }\n }\n\n cleanup(): void {\n let cleanedCount = 0;\n\n for (const path of this.managedFiles) {\n try {\n this.fs.unlink(path);\n cleanedCount++;\n } catch (error) {\n this.logger.warn('Failed to cleanup file', { path, error });\n }\n }\n\n this.managedFiles.clear();\n this.logger.info('Filesystem cleanup completed', { cleanedCount });\n }\n}\n", "import type { PDFX3Options } from './types/pdfx';\nimport { GhostscriptLoader } from './core/ghostscript-loader';\nimport { VirtualFileSystem } from './core/virtual-filesystem';\nimport { BlobUtils } from './utils/blob-utils';\n\n/**\n * PDF/X-3 conversion function\n * Converts RGB PDF(s) to PDF/X-3 format using specified output profile\n *\n * @overload\n * @param inputPDF Single PDF blob to convert\n * @param options Conversion configuration\n * @returns Promise resolving to converted PDF blob\n *\n * @overload\n * @param inputPDFs Array of PDF blobs to convert\n * @param options Conversion configuration\n * @returns Promise resolving to array of converted PDF blobs\n */\nexport function convertToPDFX3(\n inputPDF: Blob,\n options: PDFX3Options\n): Promise<Blob>;\nexport function convertToPDFX3(\n inputPDFs: Blob[],\n options: PDFX3Options\n): Promise<Blob[]>;\nexport async function convertToPDFX3(\n input: Blob | Blob[],\n options: PDFX3Options\n): Promise<Blob | Blob[]> {\n // Handle array input (batch processing)\n if (Array.isArray(input)) {\n if (input.length === 0) {\n return [];\n }\n\n // Process each blob sequentially to avoid overwhelming the WASM module\n const results: Blob[] = [];\n for (let i = 0; i < input.length; i++) {\n try {\n // eslint-disable-next-line no-await-in-loop\n const converted = await convertToPDFX3Single(input[i], options);\n results.push(converted);\n } catch (error) {\n throw new Error(\n `Failed to convert PDF ${i + 1} of ${input.length}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n return results;\n }\n\n // Handle single blob input\n return convertToPDFX3Single(input, options);\n}\n\n/**\n * Internal function to convert a single PDF\n */\nasync function convertToPDFX3Single(\n inputPDF: Blob,\n options: PDFX3Options\n): Promise<Blob> {\n // Validate inputs\n if (!(inputPDF instanceof Blob)) {\n throw new Error('Input must be a Blob');\n }\n\n if (inputPDF.size === 0) {\n throw new Error('Input PDF is empty');\n }\n\n if (inputPDF.size > 100 * 1024 * 1024) {\n throw new Error(\n `Input PDF too large (${inputPDF.size} bytes). Maximum: 100MB`\n );\n }\n\n // Validate output profile is provided\n if (!options.outputProfile) {\n throw new Error(\n 'outputProfile is required. Must be one of: \"gracol\", \"fogra39\", \"srgb\", \"custom\"'\n );\n }\n\n // Validate output profile value\n const validProfiles = ['gracol', 'fogra39', 'srgb', 'custom'];\n if (!validProfiles.includes(options.outputProfile)) {\n throw new Error(\n `Invalid outputProfile \"${\n options.outputProfile\n }\". Must be one of: ${validProfiles.join(', ')}`\n );\n }\n\n // Validate custom profile requirement\n if (options.outputProfile === 'custom' && !options.customProfile) {\n throw new Error(\n 'customProfile Blob is required when outputProfile is \"custom\"'\n );\n }\n\n // Validate custom profile if provided\n if (options.customProfile && !(options.customProfile instanceof Blob)) {\n throw new Error('customProfile must be a Blob');\n }\n\n // Validate PDF format\n const isValidPDF = await BlobUtils.validatePDF(inputPDF);\n if (!isValidPDF) {\n throw new Error('Invalid PDF format');\n }\n\n // Load Ghostscript\n const module = await GhostscriptLoader.load();\n const vfs = new VirtualFileSystem(module);\n\n try {\n // Setup file paths\n const inputPath = '/tmp/input.pdf';\n const outputPath = '/tmp/output.pdf';\n const pdfxDefPath = '/tmp/pdfx_def.ps';\n const customProfilePath = '/tmp/custom.icc';\n\n // Write input PDF to virtual filesystem\n await vfs.writeBlob(inputPath, inputPDF);\n\n // Write ICC profiles to virtual filesystem\n if (options.outputProfile === 'custom' && options.customProfile) {\n await vfs.writeBlob(customProfilePath, options.customProfile);\n } else if (options.outputProfile !== 'custom') {\n // Load the bundled ICC profile\n const profileInfo =\n PROFILE_PRESETS[options.outputProfile as keyof typeof PROFILE_PRESETS];\n const profilePath = `/tmp/${profileInfo.file}`;\n\n // Load ICC profile - different approach for Node.js vs browser\n const isNode =\n typeof process !== 'undefined' && process.versions?.node != null;\n\n let profileBlob: Blob;\n\n if (isNode) {\n // Node.js: Load from filesystem using readFileSync\n const { readFileSync } = await import('fs');\n const { fileURLToPath } = await import('url');\n const { dirname, join } = await import('path');\n\n // Get the directory of the built module\n const moduleDir = dirname(fileURLToPath(import.meta.url));\n const profileFilePath = join(moduleDir, profileInfo.file);\n\n const profileData = readFileSync(profileFilePath);\n profileBlob = new Blob([profileData], {\n type: 'application/vnd.iccprofile',\n });\n } else {\n // Browser: Use fetch\n const profileUrl = new URL(profileInfo.file, import.meta.url).href;\n const profileResponse = await fetch(profileUrl);\n if (!profileResponse.ok) {\n throw new Error(\n `Failed to load ICC profile ${profileInfo.file}: ${profileResponse.statusText}`\n );\n }\n profileBlob = await profileResponse.blob();\n }\n\n await vfs.writeBlob(profilePath, profileBlob);\n }\n\n // Determine ICC profile path and metadata for Ghostscript\n let iccProfilePath: string;\n let outputConditionIdentifier: string;\n let outputCondition: string;\n\n if (options.outputProfile === 'custom') {\n iccProfilePath = customProfilePath;\n // Use custom values or defaults\n outputConditionIdentifier =\n options.outputConditionIdentifier || 'Custom Profile';\n outputCondition = options.outputCondition || 'Custom ICC Profile';\n } else {\n const preset =\n PROFILE_PRESETS[options.outputProfile as keyof typeof PROFILE_PRESETS];\n iccProfilePath = `/tmp/${preset.file}`;\n // Allow overriding preset values\n outputConditionIdentifier =\n options.outputConditionIdentifier || preset.identifier;\n outputCondition = options.outputCondition || preset.info;\n }\n\n // Read ICC profile data and convert to hex for embedding\n // WASM doesn't support (file) (r) file syntax, so we embed directly\n const iccData = vfs.readFile(iccProfilePath);\n const iccHex = Array.from(iccData)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n\n // Determine color conversion strategy based on profile type\n // ICC profile color space is at bytes 16-19\n // 'RGB ' = 0x52474220, 'CMYK' = 0x434D594B\n const colorSpaceBytes = iccData.slice(16, 20);\n const colorSpaceStr = String.fromCharCode(...colorSpaceBytes);\n const isCMYKProfile = colorSpaceStr.trim() === 'CMYK';\n\n // Generate PDF/X-3 definition with ICC profile hex data\n const pdfxDefinition = generatePDFXDef(\n options,\n iccHex,\n outputConditionIdentifier,\n outputCondition\n );\n vfs.writeText(pdfxDefPath, pdfxDefinition);\n\n // Execute Ghostscript conversion\n // For CMYK profiles, convert all colors to CMYK using the ICC profile\n // Note: Transparency flattening will rasterize transparent content\n const gsArgs = [\n '-dBATCH',\n '-dNOPAUSE',\n '-sDEVICE=pdfwrite',\n '-dCompatibilityLevel=1.4',\n // PDF/X-3 settings\n '-dPDFSETTINGS=/prepress',\n '-dSetPageSize=false',\n '-dAutoRotatePages=/None',\n ];\n\n // Flatten transparency for PDF/X-3 compliance (default: true)\n // HaveTransparency=false tells Ghostscript the target viewer cannot handle\n // PDF 1.4 transparency, so pages with transparency are converted to bitmaps\n const shouldFlattenTransparency = options.flattenTransparency !== false;\n if (shouldFlattenTransparency) {\n gsArgs.push('-dHaveTransparency=false');\n }\n\n // Add color conversion for CMYK profiles\n if (isCMYKProfile) {\n gsArgs.push(\n '-sColorConversionStrategy=CMYK',\n '-dProcessColorModel=/DeviceCMYK',\n '-dConvertCMYKImagesToRGB=false'\n );\n } else {\n // For RGB profiles, we still need a color conversion strategy\n gsArgs.push('-sColorConversionStrategy=RGB');\n }\n\n // Add output file and input files\n gsArgs.push(`-sOutputFile=${outputPath}`, pdfxDefPath, inputPath);\n\n const exitCode = await module.callMain(gsArgs);\n if (exitCode !== 0) {\n throw new Error(\n `Ghostscript conversion failed with exit code ${exitCode}`\n );\n }\n\n // Read output\n const outputData = vfs.readFile(outputPath);\n // Create a copy of the data to ensure it's an ArrayBuffer, not SharedArrayBuffer\n const outputBuffer = new Uint8Array(outputData);\n const outputPDF = new Blob([outputBuffer], { type: 'application/pdf' });\n\n // Cleanup\n vfs.cleanup();\n\n return outputPDF;\n } catch (error) {\n vfs.cleanup();\n throw error;\n }\n}\n\n// Profile presets from the spec\nconst PROFILE_PRESETS = {\n gracol: {\n file: 'GRACoL2013_CRPC6.icc',\n identifier: 'CGATS 21.2',\n info: 'GRACoL 2013 CRPC6',\n },\n fogra39: {\n file: 'ISOcoated_v2_eci.icc',\n identifier: 'FOGRA39',\n info: 'ISO Coated v2 (ECI)',\n },\n srgb: {\n file: 'sRGB_IEC61966-2-1.icc',\n identifier: 'sRGB IEC61966-2.1',\n info: 'sRGB IEC61966-2.1',\n },\n};\n\nfunction generatePDFXDef(\n options: PDFX3Options,\n iccProfileHex: string,\n outputConditionIdentifier: string,\n outputCondition: string\n): string {\n return `%!\n% PDF/X-3 Definition File\n[ /Title (${options.title || 'Untitled'}) /DOCINFO pdfmark\n[ /Trapped /False /DOCINFO pdfmark\n\n% Set PDF/X-3 conformance\n[ /GTS_PDFXVersion (PDF/X-3:2003) /GTS_PDFXConformance (PDF/X-3:2003) /DOCINFO pdfmark\n\n% Set TrimBox to match MediaBox for all pages (required for PDF/X)\n[/TrimBox [0 0 0 0] /PAGE pdfmark\n\n% Embed ICC profile as hex stream\n[/_objdef {icc_PDFX} /type /stream /OBJ pdfmark\n[{icc_PDFX} <</N 4>> /PUT pdfmark\n[{icc_PDFX} <${iccProfileHex}> /PUT pdfmark\n\n% Define OutputIntent with embedded ICC profile\n[/_objdef {OutputIntent_PDFX} /type /dict /OBJ pdfmark\n[{OutputIntent_PDFX} <<\n /Type /OutputIntent\n /S /GTS_PDFX\n /OutputCondition (${outputCondition})\n /OutputConditionIdentifier (${outputConditionIdentifier})\n /RegistryName (http://www.color.org)\n /DestOutputProfile {icc_PDFX}\n>> /PUT pdfmark\n\n% Add OutputIntent to Catalog\n[{Catalog} <</OutputIntents [{OutputIntent_PDFX}]>> /PUT pdfmark`;\n}\n"],
5
- "mappings": "AAWO,IAAMA,EAAN,MAAMC,CAAO,CAOlB,YAAoBC,EAAmB,CAAnB,eAAAA,CAAoB,CANxC,OAAe,eAA2B,OAE1C,OAAe,KAAmB,CAAC,EAEnC,OAAe,QAAU,IAIzB,OAAO,YAAYC,EAAuB,CACxCF,EAAO,eAAiBE,CAC1B,CAEA,OAAO,SAAsB,CAC3B,MAAO,CAAC,GAAGF,EAAO,IAAI,CACxB,CAEA,OAAO,WAAkB,CACvBA,EAAO,KAAO,CAAC,CACjB,CAEA,MAAMG,EAAiBC,EAAkB,CACvC,KAAK,IAAI,QAASD,EAASC,CAAI,CACjC,CAEA,KAAKD,EAAiBC,EAAkB,CACtC,KAAK,IAAI,OAAQD,EAASC,CAAI,CAChC,CAEA,KAAKD,EAAiBC,EAAkB,CACtC,KAAK,IAAI,OAAQD,EAASC,CAAI,CAChC,CAEA,MAAMD,EAAiBC,EAAkB,CACvC,KAAK,IAAI,QAASD,EAASC,CAAI,CACjC,CAEQ,IAAIF,EAAiBC,EAAiBC,EAAkB,CAC9D,IAAMC,EAAuC,CAC3C,MAAO,EACP,KAAM,EACN,KAAM,EACN,MAAO,CACT,EAEA,GAAIA,EAAWH,CAAK,EAAIG,EAAWL,EAAO,cAAc,EACtD,OAGF,IAAMM,EAAkB,CACtB,UAAW,KAAK,IAAI,EACpB,MAAAJ,EACA,UAAW,KAAK,UAChB,QAAAC,EACA,KAAAC,CACF,EAEAJ,EAAO,KAAK,KAAKM,CAAK,EAGlBN,EAAO,KAAK,OAASA,EAAO,UAC9BA,EAAO,KAAOA,EAAO,KAAK,MAAM,CAACA,EAAO,OAAO,GAIjD,IAAMO,EAAS,IAAI,IAAI,KAAK,EAAE,YAAY,CAAC,MAAML,EAAM,YAAY,CAAC,MAClE,KAAK,SACP,IACMM,EAAaJ,EAAO,GAAGD,CAAO,IAAI,KAAK,UAAUC,CAAI,CAAC,GAAKD,EAEjE,OAAQD,EAAO,CACb,IAAK,QACH,QAAQ,MAAMK,EAAQC,CAAU,EAChC,MACF,IAAK,OACH,QAAQ,KAAKD,EAAQC,CAAU,EAC/B,MACF,IAAK,OACH,QAAQ,KAAKD,EAAQC,CAAU,EAC/B,MACF,IAAK,QACH,QAAQ,MAAMD,EAAQC,CAAU,EAChC,MACF,QAEE,KACJ,CACF,CACF,ECnGO,IAAMC,EAAN,KAAuB,CAC5B,qBAA+B,CAC7B,GAAI,CACF,OACE,OAAO,aAAgB,UACvB,OAAO,YAAY,aAAgB,UAEvC,MAAQ,CACN,MAAO,EACT,CACF,CACF,ECLA,eAAOC,GAA4E,CAEjF,IAAMC,EACJ,OAAO,QAAY,KACnB,QAAQ,UAAY,MACpB,QAAQ,SAAS,MAAQ,KAEvBC,EACAC,EAEJ,GAAIF,EAAQ,CAEV,GAAM,CAAE,cAAAG,CAAc,EAAI,KAAM,QAAO,QAAQ,EACzC,CAAE,QAAAC,EAAS,KAAAC,CAAK,EAAI,KAAM,QAAO,MAAM,EAKvCC,EAHgBH,EAAc,YAAY,GAAG,EAGtB,QAAQ,SAAS,EACxCI,EAAYH,EAAQE,CAAM,EAChCJ,EAAWG,EAAKE,EAAW,SAAS,EAEpCN,EAAoB,MAAM,OAAOK,EACnC,MAGEL,EAAoB,MAAM,OADR,IAAI,IAAI,UAAW,YAAY,GAAG,EAAE,MAEtDC,EAAW,IAAI,IAAI,YAAa,YAAY,GAAG,EAAE,KAgBnD,OATe,MAJED,EAAkB,SACjCA,GAG2B,CAC3B,WAAaO,GACPA,IAAa,UACRN,EAEFM,CAEX,CAAC,CAGH,CCzCO,IAAMC,EAAN,KAAwB,CAC7B,OAAe,SAA6C,KAE5D,OAAwB,WAAa,IAErC,aAAa,KAAKC,EAAyB,CAAC,EAA8B,CACxE,OAAI,KAAK,SACA,KAAK,UAGd,KAAK,SAAW,KAAK,aAAaA,CAAO,EAClC,KAAK,SACd,CAEA,aAAqB,aACnBA,EAC2B,CAC3B,IAAMC,EAAS,IAAIC,EAAO,mBAAmB,EAI7C,GAAI,CAHY,IAAIC,EAAiB,EAGxB,oBAAoB,EAC/B,MAAM,IAAI,MAAM,2CAA2C,EAG7D,IAAMC,EAAUJ,EAAQ,SAAW,KAAK,WAExC,GAAI,CACF,OAAAC,EAAO,KAAK,iDAAiD,EAC7DA,EAAO,KAAK,uDAAuD,EAC5D,MAAM,KAAK,gBAAgB,IAAM,KAAK,eAAe,EAAGG,CAAO,CACxE,OAASC,EAAO,CACd,MAAAJ,EAAO,MAAM,6BAA8B,CACzC,MAAQI,EAAgB,OAC1B,CAAC,EACK,IAAI,MACR,+BAAgCA,EAAgB,OAAO,EACzD,CACF,CACF,CAEA,aAAqB,gBAA4C,CAE/D,IAAMJ,EAAS,IAAIC,EAAO,iBAAiB,EAE3C,GAAI,CACFD,EAAO,KAAK,iCAAiC,EAE7C,IAAMK,EAAS,MAAMC,EAAwB,EAE7C,OAAAN,EAAO,KAAK,8CAA+C,CACzD,QAASK,EAAO,SAAW,UAC3B,MAAO,CAAC,CAACA,EAAO,GAChB,YAAa,CAAC,CAACA,EAAO,QACxB,CAAC,EAEMA,CACT,OAASD,EAAO,CACd,MAAAJ,EAAO,MAAM,oCAAqC,CAAE,MAAAI,CAAM,CAAC,EACrD,IAAI,MACR,sCAAuCA,EAAgB,OAAO,EAChE,CACF,CACF,CAEA,aAAqB,gBACnBG,EACAC,EACY,CACZ,OAAO,QAAQ,KAAK,CAClBD,EAAU,EACV,IAAI,QAAe,CAACE,EAAGC,IAAW,CAChC,WACE,IAAMA,EAAO,IAAI,MAAM,yBAAyBF,CAAS,IAAI,CAAC,EAC9DA,CACF,CACF,CAAC,CACH,CAAC,CACH,CAEA,OAAO,OAAc,CACnB,KAAK,SAAW,IAClB,CACF,EC5FO,IAAMG,EAAN,KAAgB,CACrB,aAAa,aAAaC,EAAiC,CACzD,GAAIA,EAAK,YAAa,CACpB,IAAMC,EAAS,MAAMD,EAAK,YAAY,EACtC,OAAO,IAAI,WAAWC,CAAM,CAC9B,CAGA,OAAO,IAAI,QAAQ,CAACC,EAASC,IAAW,CACtC,IAAMC,EAAS,IAAI,WACnBA,EAAO,OAAS,IAAM,CAChBA,EAAO,kBAAkB,YAC3BF,EAAQ,IAAI,WAAWE,EAAO,MAAM,CAAC,EAErCD,EAAO,IAAI,MAAM,oCAAoC,CAAC,CAE1D,EACAC,EAAO,QAAU,IAAMD,EAAOC,EAAO,KAAK,EAC1CA,EAAO,kBAAkBJ,CAAI,CAC/B,CAAC,CACH,CAEA,aAAa,YAAYA,EAA8B,CACrD,GAAI,CACF,IAAMK,EAAO,MAAM,KAAK,aAAaL,CAAI,EAGnCM,EAAY,IAAI,WAAW,CAAC,GAAM,GAAM,GAAM,EAAI,CAAC,EAEzD,GAAID,EAAK,OAAS,EAChB,MAAO,GAGT,QAASE,EAAI,EAAGA,EAAI,EAAGA,IACrB,GAAIF,EAAKE,CAAC,IAAMD,EAAUC,CAAC,EACzB,MAAO,GAIX,MAAO,EACT,MAAQ,CACN,MAAO,EACT,CACF,CACF,EClCO,IAAMC,EAAN,KAAwB,CAS7B,YACmBC,EACjBC,EAAa,YACb,CAFiB,YAAAD,EAGjB,KAAK,GAAKA,EAAO,GACjB,KAAK,OAAS,IAAIE,EAAO,mBAAmB,EAC5C,KAAK,WAAaD,EAClB,KAAK,WAAW,CAClB,CAhBiB,GAEA,OAEA,aAA4B,IAAI,IAEhC,WAYT,YAAmB,CACzB,GAAI,CAEF,KAAK,qBAAqB,KAAK,UAAU,EACzC,KAAK,qBAAqB,GAAG,KAAK,UAAU,QAAQ,EACpD,KAAK,qBAAqB,GAAG,KAAK,UAAU,SAAS,EACrD,KAAK,qBAAqB,GAAG,KAAK,UAAU,WAAW,EACvD,KAAK,qBAAqB,GAAG,KAAK,UAAU,OAAO,EAEnD,KAAK,OAAO,KAAK,iCAAkC,CACjD,WAAY,KAAK,UACnB,CAAC,CACH,OAASE,EAAO,CACd,WAAK,OAAO,MAAM,0CAA2C,CAAE,MAAAA,CAAM,CAAC,EAChE,IAAI,MAAM,8BAA8BA,CAAK,EAAE,CACvD,CACF,CAEQ,qBAAqBC,EAAoB,CAC/C,GAAI,CACF,KAAK,GAAG,MAAMA,CAAI,CACpB,OAASD,EAAY,CAEnB,GAAIA,EAAM,OAAS,SACjB,MAAMA,CAEV,CACF,CAEA,MAAM,UAAUC,EAAcC,EAAYC,EAAU,GAAqB,CACvE,GAAI,CACF,IAAMC,EAAO,MAAMC,EAAU,aAAaH,CAAI,EAC9C,KAAK,GAAG,UAAUD,EAAMG,CAAI,EAExBD,GACF,KAAK,aAAa,IAAIF,CAAI,EAG5B,KAAK,OAAO,MAAM,eAAgB,CAAE,KAAAA,EAAM,KAAMG,EAAK,MAAO,CAAC,CAC/D,OAASJ,EAAO,CACd,WAAK,OAAO,MAAM,uBAAwB,CAAE,KAAAC,EAAM,MAAAD,CAAM,CAAC,EACnD,IAAI,MAAM,wBAAwBC,CAAI,KAAKD,CAAK,EAAE,CAC1D,CACF,CAEA,UAAUC,EAAcK,EAAiBH,EAAU,GAAY,CAC7D,GAAI,CACF,KAAK,GAAG,UAAUF,EAAMK,CAAO,EAE3BH,GACF,KAAK,aAAa,IAAIF,CAAI,EAG5B,KAAK,OAAO,MAAM,oBAAqB,CAAE,KAAAA,EAAM,OAAQK,EAAQ,MAAO,CAAC,CACzE,OAASN,EAAO,CACd,WAAK,OAAO,MAAM,uBAAwB,CAAE,KAAAC,EAAM,MAAAD,CAAM,CAAC,EACnD,IAAI,MAAM,6BAA6BC,CAAI,KAAKD,CAAK,EAAE,CAC/D,CACF,CAEA,SAASC,EAA0B,CACjC,GAAI,CACF,IAAMG,EAAO,KAAK,GAAG,SAASH,CAAI,EAClC,YAAK,OAAO,MAAM,YAAa,CAAE,KAAAA,EAAM,KAAMG,EAAK,MAAO,CAAC,EACnDA,CACT,OAASJ,EAAO,CACd,WAAK,OAAO,MAAM,sBAAuB,CAAE,KAAAC,EAAM,MAAAD,CAAM,CAAC,EAClD,IAAI,MAAM,uBAAuBC,CAAI,KAAKD,CAAK,EAAE,CACzD,CACF,CAEA,OAAOC,EAAuB,CAC5B,GAAI,CACF,YAAK,GAAG,KAAKA,CAAI,EACV,EACT,MAAQ,CACN,MAAO,EACT,CACF,CAEA,SAAgB,CACd,IAAIM,EAAe,EAEnB,QAAWN,KAAQ,KAAK,aACtB,GAAI,CACF,KAAK,GAAG,OAAOA,CAAI,EACnBM,GACF,OAASP,EAAO,CACd,KAAK,OAAO,KAAK,yBAA0B,CAAE,KAAAC,EAAM,MAAAD,CAAM,CAAC,CAC5D,CAGF,KAAK,aAAa,MAAM,EACxB,KAAK,OAAO,KAAK,+BAAgC,CAAE,aAAAO,CAAa,CAAC,CACnE,CACF,ECjGA,eAAsBC,EACpBC,EACAC,EACwB,CAExB,GAAI,MAAM,QAAQD,CAAK,EAAG,CACxB,GAAIA,EAAM,SAAW,EACnB,MAAO,CAAC,EAIV,IAAME,EAAkB,CAAC,EACzB,QAAS,EAAI,EAAG,EAAIF,EAAM,OAAQ,IAChC,GAAI,CAEF,IAAMG,EAAY,MAAMC,EAAqBJ,EAAM,CAAC,EAAGC,CAAO,EAC9DC,EAAQ,KAAKC,CAAS,CACxB,OAASE,EAAO,CACd,MAAM,IAAI,MACR,yBAAyB,EAAI,CAAC,OAAOL,EAAM,MAAM,KAC/CK,aAAiB,MAAQA,EAAM,QAAU,OAAOA,CAAK,CACvD,EACF,CACF,CAEF,OAAOH,CACT,CAGA,OAAOE,EAAqBJ,EAAOC,CAAO,CAC5C,CAKA,eAAeG,EACbE,EACAL,EACe,CAEf,GAAI,EAAEK,aAAoB,MACxB,MAAM,IAAI,MAAM,sBAAsB,EAGxC,GAAIA,EAAS,OAAS,EACpB,MAAM,IAAI,MAAM,oBAAoB,EAGtC,GAAIA,EAAS,KAAO,IAAM,KAAO,KAC/B,MAAM,IAAI,MACR,wBAAwBA,EAAS,IAAI,yBACvC,EAIF,GAAI,CAACL,EAAQ,cACX,MAAM,IAAI,MACR,kFACF,EAIF,IAAMM,EAAgB,CAAC,SAAU,UAAW,OAAQ,QAAQ,EAC5D,GAAI,CAACA,EAAc,SAASN,EAAQ,aAAa,EAC/C,MAAM,IAAI,MACR,0BACEA,EAAQ,aACV,sBAAsBM,EAAc,KAAK,IAAI,CAAC,EAChD,EAIF,GAAIN,EAAQ,gBAAkB,UAAY,CAACA,EAAQ,cACjD,MAAM,IAAI,MACR,+DACF,EAIF,GAAIA,EAAQ,eAAiB,EAAEA,EAAQ,yBAAyB,MAC9D,MAAM,IAAI,MAAM,8BAA8B,EAKhD,GAAI,CADe,MAAMO,EAAU,YAAYF,CAAQ,EAErD,MAAM,IAAI,MAAM,oBAAoB,EAItC,IAAMG,EAAS,MAAMC,EAAkB,KAAK,EACtCC,EAAM,IAAIC,EAAkBH,CAAM,EAExC,GAAI,CAEF,IAAMI,EAAY,iBACZC,EAAa,kBACbC,EAAc,mBACdC,EAAoB,kBAM1B,GAHA,MAAML,EAAI,UAAUE,EAAWP,CAAQ,EAGnCL,EAAQ,gBAAkB,UAAYA,EAAQ,cAChD,MAAMU,EAAI,UAAUK,EAAmBf,EAAQ,aAAa,UACnDA,EAAQ,gBAAkB,SAAU,CAE7C,IAAMgB,EACJC,EAAgBjB,EAAQ,aAA6C,EACjEkB,EAAc,QAAQF,EAAY,IAAI,GAGtCG,EACJ,OAAO,QAAY,KAAe,QAAQ,UAAU,MAAQ,KAE1DC,EAEJ,GAAID,EAAQ,CAEV,GAAM,CAAE,aAAAE,CAAa,EAAI,KAAM,QAAO,IAAI,EACpC,CAAE,cAAAC,CAAc,EAAI,KAAM,QAAO,KAAK,EACtC,CAAE,QAAAC,EAAS,KAAAC,CAAK,EAAI,KAAM,QAAO,MAAM,EAGvCC,EAAYF,EAAQD,EAAc,YAAY,GAAG,CAAC,EAClDI,EAAkBF,EAAKC,EAAWT,EAAY,IAAI,EAElDW,EAAcN,EAAaK,CAAe,EAChDN,EAAc,IAAI,KAAK,CAACO,CAAW,EAAG,CACpC,KAAM,4BACR,CAAC,CACH,KAAO,CAEL,IAAMC,EAAa,IAAI,IAAIZ,EAAY,KAAM,YAAY,GAAG,EAAE,KACxDa,EAAkB,MAAM,MAAMD,CAAU,EAC9C,GAAI,CAACC,EAAgB,GACnB,MAAM,IAAI,MACR,8BAA8Bb,EAAY,IAAI,KAAKa,EAAgB,UAAU,EAC/E,EAEFT,EAAc,MAAMS,EAAgB,KAAK,CAC3C,CAEA,MAAMnB,EAAI,UAAUQ,EAAaE,CAAW,CAC9C,CAGA,IAAIU,EACAC,EACAC,EAEJ,GAAIhC,EAAQ,gBAAkB,SAC5B8B,EAAiBf,EAEjBgB,EACE/B,EAAQ,2BAA6B,iBACvCgC,EAAkBhC,EAAQ,iBAAmB,yBACxC,CACL,IAAMiC,EACJhB,EAAgBjB,EAAQ,aAA6C,EACvE8B,EAAiB,QAAQG,EAAO,IAAI,GAEpCF,EACE/B,EAAQ,2BAA6BiC,EAAO,WAC9CD,EAAkBhC,EAAQ,iBAAmBiC,EAAO,IACtD,CAIA,IAAMC,EAAUxB,EAAI,SAASoB,CAAc,EACrCK,EAAS,MAAM,KAAKD,CAAO,EAC9B,IAAKE,GAAMA,EAAE,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,EAC1C,KAAK,EAAE,EAKJC,EAAkBH,EAAQ,MAAM,GAAI,EAAE,EAEtCI,EADgB,OAAO,aAAa,GAAGD,CAAe,EACxB,KAAK,IAAM,OAGzCE,EAAiBC,EACrBxC,EACAmC,EACAJ,EACAC,CACF,EACAtB,EAAI,UAAUI,EAAayB,CAAc,EAKzC,IAAME,EAAS,CACb,UACA,YACA,oBACA,2BAEA,0BACA,sBACA,yBACF,EAKkCzC,EAAQ,sBAAwB,IAEhEyC,EAAO,KAAK,0BAA0B,EAIpCH,EACFG,EAAO,KACL,iCACA,kCACA,gCACF,EAGAA,EAAO,KAAK,+BAA+B,EAI7CA,EAAO,KAAK,gBAAgB5B,CAAU,GAAIC,EAAaF,CAAS,EAEhE,IAAM8B,EAAW,MAAMlC,EAAO,SAASiC,CAAM,EAC7C,GAAIC,IAAa,EACf,MAAM,IAAI,MACR,gDAAgDA,CAAQ,EAC1D,EAIF,IAAMC,EAAajC,EAAI,SAASG,CAAU,EAEpC+B,EAAe,IAAI,WAAWD,CAAU,EACxCE,EAAY,IAAI,KAAK,CAACD,CAAY,EAAG,CAAE,KAAM,iBAAkB,CAAC,EAGtE,OAAAlC,EAAI,QAAQ,EAELmC,CACT,OAASzC,EAAO,CACd,MAAAM,EAAI,QAAQ,EACNN,CACR,CACF,CAGA,IAAMa,EAAkB,CACtB,OAAQ,CACN,KAAM,uBACN,WAAY,aACZ,KAAM,mBACR,EACA,QAAS,CACP,KAAM,uBACN,WAAY,UACZ,KAAM,qBACR,EACA,KAAM,CACJ,KAAM,wBACN,WAAY,oBACZ,KAAM,mBACR,CACF,EAEA,SAASuB,EACPxC,EACA8C,EACAf,EACAC,EACQ,CACR,MAAO;AAAA;AAAA,YAEGhC,EAAQ,OAAS,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,eAYxB8C,CAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAONd,CAAe;AAAA,gCACLD,CAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iEAOzD",
6
- "names": ["Logger", "_Logger", "component", "level", "message", "data", "levelOrder", "entry", "prefix", "logMessage", "BrowserDetection", "createGhostscriptModule", "isNode", "GhostscriptModule", "wasmPath", "createRequire", "dirname", "join", "gsPath", "moduleDir", "filename", "GhostscriptLoader", "options", "logger", "Logger", "BrowserDetection", "timeout", "error", "module", "createGhostscriptModule", "operation", "timeoutMs", "_", "reject", "BlobUtils", "blob", "buffer", "resolve", "reject", "reader", "data", "pdfHeader", "i", "VirtualFileSystem", "module", "workingDir", "Logger", "error", "path", "blob", "managed", "data", "BlobUtils", "content", "cleanedCount", "convertToPDFX3", "input", "options", "results", "converted", "convertToPDFX3Single", "error", "inputPDF", "validProfiles", "BlobUtils", "module", "GhostscriptLoader", "vfs", "VirtualFileSystem", "inputPath", "outputPath", "pdfxDefPath", "customProfilePath", "profileInfo", "PROFILE_PRESETS", "profilePath", "isNode", "profileBlob", "readFileSync", "fileURLToPath", "dirname", "join", "moduleDir", "profileFilePath", "profileData", "profileUrl", "profileResponse", "iccProfilePath", "outputConditionIdentifier", "outputCondition", "preset", "iccData", "iccHex", "b", "colorSpaceBytes", "isCMYKProfile", "pdfxDefinition", "generatePDFXDef", "gsArgs", "exitCode", "outputData", "outputBuffer", "outputPDF", "iccProfileHex"]
4
+ "sourcesContent": ["/* eslint-disable no-console */\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport interface LogEntry {\n timestamp: number;\n level: LogLevel;\n component: string;\n message: string;\n data?: any;\n}\n\nexport class Logger {\n private static globalLogLevel: LogLevel = 'warn';\n\n private static logs: LogEntry[] = [];\n\n private static maxLogs = 1000;\n\n constructor(private component: string) {}\n\n static setLogLevel(level: LogLevel): void {\n Logger.globalLogLevel = level;\n }\n\n static getLogs(): LogEntry[] {\n return [...Logger.logs];\n }\n\n static clearLogs(): void {\n Logger.logs = [];\n }\n\n debug(message: string, data?: any): void {\n this.log('debug', message, data);\n }\n\n info(message: string, data?: any): void {\n this.log('info', message, data);\n }\n\n warn(message: string, data?: any): void {\n this.log('warn', message, data);\n }\n\n error(message: string, data?: any): void {\n this.log('error', message, data);\n }\n\n private log(level: LogLevel, message: string, data?: any): void {\n const levelOrder: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n };\n\n if (levelOrder[level] < levelOrder[Logger.globalLogLevel]) {\n return;\n }\n\n const entry: LogEntry = {\n timestamp: Date.now(),\n level,\n component: this.component,\n message,\n data,\n };\n\n Logger.logs.push(entry);\n\n // Keep logs under the limit\n if (Logger.logs.length > Logger.maxLogs) {\n Logger.logs = Logger.logs.slice(-Logger.maxLogs);\n }\n\n // Console output\n const prefix = `[${new Date().toISOString()}] [${level.toUpperCase()}] [${\n this.component\n }]`;\n const logMessage = data ? `${message} ${JSON.stringify(data)}` : message;\n\n switch (level) {\n case 'debug':\n console.debug(prefix, logMessage);\n break;\n case 'info':\n console.info(prefix, logMessage);\n break;\n case 'warn':\n console.warn(prefix, logMessage);\n break;\n case 'error':\n console.error(prefix, logMessage);\n break;\n default:\n // All log levels handled above\n break;\n }\n }\n}\n", "export class BrowserDetection {\n supportsWebAssembly(): boolean {\n try {\n return (\n typeof WebAssembly === 'object' &&\n typeof WebAssembly.instantiate === 'function'\n );\n } catch {\n return false;\n }\n }\n}\n", "// Wrapper for the Ghostscript WASM module to ensure proper loading\nimport type {\n EmscriptenModule,\n GhostscriptModuleFactory,\n} from '../types/ghostscript';\n\nexport interface GhostscriptModuleOptions {\n /**\n * Whether to suppress Ghostscript's stdout/stderr output.\n * Default: true (silent mode)\n */\n silent?: boolean;\n}\n\nexport default async function createGhostscriptModule(\n options: GhostscriptModuleOptions = {}\n): Promise<EmscriptenModule> {\n const { silent = true } = options;\n // Check if we're in Node.js\n const isNode =\n typeof process !== 'undefined' &&\n process.versions != null &&\n process.versions.node != null;\n\n let GhostscriptModule: any;\n let wasmPath: string;\n\n if (isNode) {\n // Node.js: Use require.resolve to find gs.js relative to this module\n const { createRequire } = await import('module');\n const { dirname, join } = await import('path');\n\n const requireForESM = createRequire(import.meta.url);\n\n // Resolve gs.js directly (it's copied to dist/ alongside the bundle)\n const gsPath = requireForESM.resolve('./gs.js');\n const moduleDir = dirname(gsPath);\n wasmPath = join(moduleDir, 'gs.wasm');\n\n GhostscriptModule = await import(gsPath);\n } else {\n // Browser: Use URL-based imports\n const moduleUrl = new URL('./gs.js', import.meta.url).href;\n GhostscriptModule = await import(/* webpackIgnore: true */ moduleUrl);\n wasmPath = new URL('./gs.wasm', import.meta.url).href;\n }\n\n const factory = (GhostscriptModule.default ||\n GhostscriptModule) as GhostscriptModuleFactory;\n\n // Configure the module to load WASM from the bundled location\n const moduleConfig: Record<string, unknown> = {\n locateFile: (filename: string) => {\n if (filename === 'gs.wasm') {\n return wasmPath;\n }\n return filename;\n },\n };\n\n // Suppress Ghostscript stdout/stderr output in silent mode\n if (silent) {\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n moduleConfig.print = () => {};\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n moduleConfig.printErr = () => {};\n }\n\n const module = await factory(moduleConfig);\n\n return module;\n}\n", "import type { EmscriptenModule } from '../types/ghostscript';\nimport { Logger } from '../utils/logger';\nimport { BrowserDetection } from '../utils/browser-detection';\nimport createGhostscriptModule from '../wasm/ghostscript-module';\n\nexport interface LoaderOptions {\n timeout?: number;\n}\n\nexport class GhostscriptLoader {\n private static instance: Promise<EmscriptenModule> | null = null;\n\n private static readonly TIMEOUT_MS = 30000;\n\n static async load(options: LoaderOptions = {}): Promise<EmscriptenModule> {\n if (this.instance) {\n return this.instance;\n }\n\n this.instance = this.loadInternal(options);\n return this.instance;\n }\n\n private static async loadInternal(\n options: LoaderOptions\n ): Promise<EmscriptenModule> {\n const logger = new Logger('GhostscriptLoader');\n const browser = new BrowserDetection();\n\n // Check browser compatibility\n if (!browser.supportsWebAssembly()) {\n throw new Error('WebAssembly not supported in this browser');\n }\n\n const timeout = options.timeout || this.TIMEOUT_MS;\n\n try {\n logger.info('Loading bundled Ghostscript (AGPL-3.0 licensed)');\n logger.info('Source available at: https://github.com/imgly/plugins');\n return await this.loadWithTimeout(() => this.loadFromBundle(), timeout);\n } catch (error) {\n logger.error('Ghostscript loading failed', {\n error: (error as Error).message,\n });\n throw new Error(\n `Failed to load Ghostscript: ${(error as Error).message}`\n );\n }\n }\n\n private static async loadFromBundle(): Promise<EmscriptenModule> {\n // Use the bundled WASM module with proper configuration\n const logger = new Logger('GhostscriptInit');\n\n try {\n logger.info('Initializing Ghostscript module');\n\n const module = await createGhostscriptModule();\n\n logger.info('Ghostscript module initialized successfully', {\n version: module.version || 'unknown',\n hasFS: !!module.FS,\n hasCallMain: !!module.callMain,\n });\n\n return module;\n } catch (error) {\n logger.error('Ghostscript initialization failed', { error });\n throw new Error(\n `Ghostscript initialization failed: ${(error as Error).message}`\n );\n }\n }\n\n private static async loadWithTimeout<T>(\n operation: () => Promise<T>,\n timeoutMs: number\n ): Promise<T> {\n return Promise.race([\n operation(),\n new Promise<never>((_, reject) => {\n setTimeout(\n () => reject(new Error(`Loading timeout after ${timeoutMs}ms`)),\n timeoutMs\n );\n }),\n ]);\n }\n\n static reset(): void {\n this.instance = null;\n }\n}\n", "export class BlobUtils {\n static async toUint8Array(blob: Blob): Promise<Uint8Array> {\n if (blob.arrayBuffer) {\n const buffer = await blob.arrayBuffer();\n return new Uint8Array(buffer);\n }\n\n // Fallback for older browsers\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n if (reader.result instanceof ArrayBuffer) {\n resolve(new Uint8Array(reader.result));\n } else {\n reject(new Error('Failed to read blob as ArrayBuffer'));\n }\n };\n reader.onerror = () => reject(reader.error);\n reader.readAsArrayBuffer(blob);\n });\n }\n\n static async validatePDF(blob: Blob): Promise<boolean> {\n try {\n const data = await this.toUint8Array(blob);\n\n // Check PDF magic number\n const pdfHeader = new Uint8Array([0x25, 0x50, 0x44, 0x46]); // %PDF\n\n if (data.length < 4) {\n return false;\n }\n\n for (let i = 0; i < 4; i++) {\n if (data[i] !== pdfHeader[i]) {\n return false;\n }\n }\n\n return true;\n } catch {\n return false;\n }\n }\n}\n", "import type { EmscriptenModule, EmscriptenFS } from '../types/ghostscript';\nimport { Logger } from '../utils/logger';\nimport { BlobUtils } from '../utils/blob-utils';\n\nexport interface FileEntry {\n path: string;\n data: Uint8Array;\n cleanup: boolean;\n}\n\nexport class VirtualFileSystem {\n private readonly fs: EmscriptenFS;\n\n private readonly logger: Logger;\n\n private readonly managedFiles: Set<string> = new Set();\n\n private readonly workingDir: string;\n\n constructor(\n private readonly module: EmscriptenModule,\n workingDir = '/tmp/pdfx'\n ) {\n this.fs = module.FS;\n this.logger = new Logger('VirtualFileSystem');\n this.workingDir = workingDir;\n this.initialize();\n }\n\n private initialize(): void {\n try {\n // Create working directory structure (handle existing directories gracefully)\n this.createDirIfNotExists(this.workingDir);\n this.createDirIfNotExists(`${this.workingDir}/input`);\n this.createDirIfNotExists(`${this.workingDir}/output`);\n this.createDirIfNotExists(`${this.workingDir}/profiles`);\n this.createDirIfNotExists(`${this.workingDir}/temp`);\n\n this.logger.info('Virtual filesystem initialized', {\n workingDir: this.workingDir,\n });\n } catch (error) {\n this.logger.error('Failed to initialize virtual filesystem', { error });\n throw new Error(`VFS initialization failed: ${error}`);\n }\n }\n\n private createDirIfNotExists(path: string): void {\n try {\n this.fs.mkdir(path);\n } catch (error: any) {\n // Ignore \"File exists\" errors, re-throw others\n if (error.code !== 'EEXIST') {\n throw error;\n }\n }\n }\n\n async writeBlob(path: string, blob: Blob, managed = true): Promise<void> {\n try {\n const data = await BlobUtils.toUint8Array(blob);\n this.fs.writeFile(path, data);\n\n if (managed) {\n this.managedFiles.add(path);\n }\n\n this.logger.debug('File written', { path, size: data.length });\n } catch (error) {\n this.logger.error('Failed to write blob', { path, error });\n throw new Error(`Failed to write file ${path}: ${error}`);\n }\n }\n\n writeText(path: string, content: string, managed = true): void {\n try {\n this.fs.writeFile(path, content);\n\n if (managed) {\n this.managedFiles.add(path);\n }\n\n this.logger.debug('Text file written', { path, length: content.length });\n } catch (error) {\n this.logger.error('Failed to write text', { path, error });\n throw new Error(`Failed to write text file ${path}: ${error}`);\n }\n }\n\n readFile(path: string): Uint8Array {\n try {\n const data = this.fs.readFile(path) as Uint8Array;\n this.logger.debug('File read', { path, size: data.length });\n return data;\n } catch (error) {\n this.logger.error('Failed to read file', { path, error });\n throw new Error(`Failed to read file ${path}: ${error}`);\n }\n }\n\n exists(path: string): boolean {\n try {\n this.fs.stat(path);\n return true;\n } catch {\n return false;\n }\n }\n\n cleanup(): void {\n let cleanedCount = 0;\n\n for (const path of this.managedFiles) {\n try {\n this.fs.unlink(path);\n cleanedCount++;\n } catch (error) {\n this.logger.warn('Failed to cleanup file', { path, error });\n }\n }\n\n this.managedFiles.clear();\n this.logger.info('Filesystem cleanup completed', { cleanedCount });\n }\n}\n", "import type { PDFX3Options } from './types/pdfx';\nimport { GhostscriptLoader } from './core/ghostscript-loader';\nimport { VirtualFileSystem } from './core/virtual-filesystem';\nimport { BlobUtils } from './utils/blob-utils';\n\n/**\n * PDF/X-3 conversion function\n * Converts RGB PDF(s) to PDF/X-3 format using specified output profile\n *\n * @overload\n * @param inputPDF Single PDF blob to convert\n * @param options Conversion configuration\n * @returns Promise resolving to converted PDF blob\n *\n * @overload\n * @param inputPDFs Array of PDF blobs to convert\n * @param options Conversion configuration\n * @returns Promise resolving to array of converted PDF blobs\n */\nexport function convertToPDFX3(\n inputPDF: Blob,\n options: PDFX3Options\n): Promise<Blob>;\nexport function convertToPDFX3(\n inputPDFs: Blob[],\n options: PDFX3Options\n): Promise<Blob[]>;\nexport async function convertToPDFX3(\n input: Blob | Blob[],\n options: PDFX3Options\n): Promise<Blob | Blob[]> {\n // Handle array input (batch processing)\n if (Array.isArray(input)) {\n if (input.length === 0) {\n return [];\n }\n\n // Process each blob sequentially to avoid overwhelming the WASM module\n const results: Blob[] = [];\n for (let i = 0; i < input.length; i++) {\n try {\n // eslint-disable-next-line no-await-in-loop\n const converted = await convertToPDFX3Single(input[i], options);\n results.push(converted);\n } catch (error) {\n throw new Error(\n `Failed to convert PDF ${i + 1} of ${input.length}: ${\n error instanceof Error ? error.message : String(error)\n }`\n );\n }\n }\n return results;\n }\n\n // Handle single blob input\n return convertToPDFX3Single(input, options);\n}\n\n/**\n * Internal function to convert a single PDF\n */\nasync function convertToPDFX3Single(\n inputPDF: Blob,\n options: PDFX3Options\n): Promise<Blob> {\n // Validate inputs\n if (!(inputPDF instanceof Blob)) {\n throw new Error('Input must be a Blob');\n }\n\n if (inputPDF.size === 0) {\n throw new Error('Input PDF is empty');\n }\n\n if (inputPDF.size > 100 * 1024 * 1024) {\n throw new Error(\n `Input PDF too large (${inputPDF.size} bytes). Maximum: 100MB`\n );\n }\n\n // Validate output profile is provided\n if (!options.outputProfile) {\n throw new Error(\n 'outputProfile is required. Must be one of: \"gracol\", \"fogra39\", \"srgb\", \"custom\"'\n );\n }\n\n // Validate output profile value\n const validProfiles = ['gracol', 'fogra39', 'srgb', 'custom'];\n if (!validProfiles.includes(options.outputProfile)) {\n throw new Error(\n `Invalid outputProfile \"${\n options.outputProfile\n }\". Must be one of: ${validProfiles.join(', ')}`\n );\n }\n\n // Validate custom profile requirement\n if (options.outputProfile === 'custom' && !options.customProfile) {\n throw new Error(\n 'customProfile Blob is required when outputProfile is \"custom\"'\n );\n }\n\n // Validate custom profile if provided\n if (options.customProfile && !(options.customProfile instanceof Blob)) {\n throw new Error('customProfile must be a Blob');\n }\n\n // Validate PDF format\n const isValidPDF = await BlobUtils.validatePDF(inputPDF);\n if (!isValidPDF) {\n throw new Error('Invalid PDF format');\n }\n\n // Load Ghostscript\n const module = await GhostscriptLoader.load();\n const vfs = new VirtualFileSystem(module);\n\n try {\n // Setup file paths\n const inputPath = '/tmp/input.pdf';\n const outputPath = '/tmp/output.pdf';\n const pdfxDefPath = '/tmp/pdfx_def.ps';\n const customProfilePath = '/tmp/custom.icc';\n\n // Write input PDF to virtual filesystem\n await vfs.writeBlob(inputPath, inputPDF);\n\n // Write ICC profiles to virtual filesystem\n if (options.outputProfile === 'custom' && options.customProfile) {\n await vfs.writeBlob(customProfilePath, options.customProfile);\n } else if (options.outputProfile !== 'custom') {\n // Load the bundled ICC profile\n const profileInfo =\n PROFILE_PRESETS[options.outputProfile as keyof typeof PROFILE_PRESETS];\n const profilePath = `/tmp/${profileInfo.file}`;\n\n // Load ICC profile - different approach for Node.js vs browser\n const isNode =\n typeof process !== 'undefined' && process.versions?.node != null;\n\n let profileBlob: Blob;\n\n if (isNode) {\n // Node.js: Load from filesystem using readFileSync\n const { readFileSync } = await import('fs');\n const { fileURLToPath } = await import('url');\n const { dirname, join } = await import('path');\n\n // Get the directory of the built module\n const moduleDir = dirname(fileURLToPath(import.meta.url));\n const profileFilePath = join(moduleDir, profileInfo.file);\n\n const profileData = readFileSync(profileFilePath);\n profileBlob = new Blob([profileData], {\n type: 'application/vnd.iccprofile',\n });\n } else {\n // Browser: Use fetch\n const profileUrl = new URL(profileInfo.file, import.meta.url).href;\n const profileResponse = await fetch(profileUrl);\n if (!profileResponse.ok) {\n throw new Error(\n `Failed to load ICC profile ${profileInfo.file}: ${profileResponse.statusText}`\n );\n }\n profileBlob = await profileResponse.blob();\n }\n\n await vfs.writeBlob(profilePath, profileBlob);\n }\n\n // Determine ICC profile path and metadata for Ghostscript\n let iccProfilePath: string;\n let outputConditionIdentifier: string;\n let outputCondition: string;\n\n if (options.outputProfile === 'custom') {\n iccProfilePath = customProfilePath;\n // Use custom values or defaults\n outputConditionIdentifier =\n options.outputConditionIdentifier || 'Custom Profile';\n outputCondition = options.outputCondition || 'Custom ICC Profile';\n } else {\n const preset =\n PROFILE_PRESETS[options.outputProfile as keyof typeof PROFILE_PRESETS];\n iccProfilePath = `/tmp/${preset.file}`;\n // Allow overriding preset values\n outputConditionIdentifier =\n options.outputConditionIdentifier || preset.identifier;\n outputCondition = options.outputCondition || preset.info;\n }\n\n // Read ICC profile data and convert to hex for embedding\n // WASM doesn't support (file) (r) file syntax, so we embed directly\n const iccData = vfs.readFile(iccProfilePath);\n const iccHex = Array.from(iccData)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n\n // Determine color conversion strategy based on profile type\n // ICC profile color space is at bytes 16-19\n // 'RGB ' = 0x52474220, 'CMYK' = 0x434D594B\n const colorSpaceBytes = iccData.slice(16, 20);\n const colorSpaceStr = String.fromCharCode(...colorSpaceBytes);\n const isCMYKProfile = colorSpaceStr.trim() === 'CMYK';\n\n // Generate PDF/X-3 definition with ICC profile hex data\n const pdfxDefinition = generatePDFXDef(\n options,\n iccHex,\n outputConditionIdentifier,\n outputCondition\n );\n vfs.writeText(pdfxDefPath, pdfxDefinition);\n\n // Execute Ghostscript conversion\n // For CMYK profiles, convert all colors to CMYK using the ICC profile\n // Note: Transparency flattening will rasterize transparent content\n const gsArgs = [\n '-dBATCH',\n '-dNOPAUSE',\n '-sDEVICE=pdfwrite',\n '-dCompatibilityLevel=1.4',\n // Disable PDF 1.5+ features to avoid warnings with PDF 1.4 compatibility\n '-dWriteObjStms=false',\n '-dWriteXRefStm=false',\n // PDF/X-3 settings\n '-dPDFSETTINGS=/prepress',\n '-dSetPageSize=false',\n '-dAutoRotatePages=/None',\n ];\n\n // Flatten transparency for PDF/X-3 compliance (default: true)\n // HaveTransparency=false tells Ghostscript the target viewer cannot handle\n // PDF 1.4 transparency, so pages with transparency are converted to bitmaps\n const shouldFlattenTransparency = options.flattenTransparency !== false;\n if (shouldFlattenTransparency) {\n gsArgs.push('-dHaveTransparency=false');\n }\n\n // Add color conversion for CMYK profiles\n if (isCMYKProfile) {\n gsArgs.push(\n '-sColorConversionStrategy=CMYK',\n '-dProcessColorModel=/DeviceCMYK',\n '-dConvertCMYKImagesToRGB=false'\n );\n } else {\n // For RGB profiles, we still need a color conversion strategy\n gsArgs.push('-sColorConversionStrategy=RGB');\n }\n\n // Add output file and input files\n gsArgs.push(`-sOutputFile=${outputPath}`, pdfxDefPath, inputPath);\n\n const exitCode = await module.callMain(gsArgs);\n if (exitCode !== 0) {\n throw new Error(\n `Ghostscript conversion failed with exit code ${exitCode}`\n );\n }\n\n // Read output\n const outputData = vfs.readFile(outputPath);\n // Create a copy of the data to ensure it's an ArrayBuffer, not SharedArrayBuffer\n const outputBuffer = new Uint8Array(outputData);\n const outputPDF = new Blob([outputBuffer], { type: 'application/pdf' });\n\n // Cleanup\n vfs.cleanup();\n\n return outputPDF;\n } catch (error) {\n vfs.cleanup();\n throw error;\n }\n}\n\n// Profile presets from the spec\nconst PROFILE_PRESETS = {\n gracol: {\n file: 'GRACoL2013_CRPC6.icc',\n identifier: 'CGATS 21.2',\n info: 'GRACoL 2013 CRPC6',\n },\n fogra39: {\n file: 'ISOcoated_v2_eci.icc',\n identifier: 'FOGRA39',\n info: 'ISO Coated v2 (ECI)',\n },\n srgb: {\n file: 'sRGB_IEC61966-2-1.icc',\n identifier: 'sRGB IEC61966-2.1',\n info: 'sRGB IEC61966-2.1',\n },\n};\n\nfunction generatePDFXDef(\n options: PDFX3Options,\n iccProfileHex: string,\n outputConditionIdentifier: string,\n outputCondition: string\n): string {\n return `%!\n% PDF/X-3 Definition File\n[ /Title (${options.title || 'Untitled'}) /DOCINFO pdfmark\n[ /Trapped /False /DOCINFO pdfmark\n\n% Set PDF/X-3 conformance\n[ /GTS_PDFXVersion (PDF/X-3:2003) /GTS_PDFXConformance (PDF/X-3:2003) /DOCINFO pdfmark\n\n% Set TrimBox to match MediaBox for all pages (required for PDF/X)\n[/TrimBox [0 0 0 0] /PAGE pdfmark\n\n% Embed ICC profile as hex stream\n[/_objdef {icc_PDFX} /type /stream /OBJ pdfmark\n[{icc_PDFX} <</N 4>> /PUT pdfmark\n[{icc_PDFX} <${iccProfileHex}> /PUT pdfmark\n\n% Define OutputIntent with embedded ICC profile\n[/_objdef {OutputIntent_PDFX} /type /dict /OBJ pdfmark\n[{OutputIntent_PDFX} <<\n /Type /OutputIntent\n /S /GTS_PDFX\n /OutputCondition (${outputCondition})\n /OutputConditionIdentifier (${outputConditionIdentifier})\n /RegistryName (http://www.color.org)\n /DestOutputProfile {icc_PDFX}\n>> /PUT pdfmark\n\n% Add OutputIntent to Catalog\n[{Catalog} <</OutputIntents [{OutputIntent_PDFX}]>> /PUT pdfmark`;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["Logger", "_Logger", "component", "level", "message", "data", "levelOrder", "entry", "prefix", "logMessage", "BrowserDetection", "createGhostscriptModule", "options", "silent", "isNode", "GhostscriptModule", "wasmPath", "createRequire", "dirname", "join", "gsPath", "moduleDir", "factory", "moduleConfig", "filename", "GhostscriptLoader", "options", "logger", "Logger", "BrowserDetection", "timeout", "error", "module", "createGhostscriptModule", "operation", "timeoutMs", "_", "reject", "BlobUtils", "blob", "buffer", "resolve", "reject", "reader", "data", "pdfHeader", "i", "VirtualFileSystem", "module", "workingDir", "Logger", "error", "path", "blob", "managed", "data", "BlobUtils", "content", "cleanedCount", "convertToPDFX3", "input", "options", "results", "converted", "convertToPDFX3Single", "error", "inputPDF", "validProfiles", "BlobUtils", "module", "GhostscriptLoader", "vfs", "VirtualFileSystem", "inputPath", "outputPath", "pdfxDefPath", "customProfilePath", "profileInfo", "PROFILE_PRESETS", "profilePath", "isNode", "profileBlob", "readFileSync", "fileURLToPath", "dirname", "join", "moduleDir", "profileFilePath", "profileData", "profileUrl", "profileResponse", "iccProfilePath", "outputConditionIdentifier", "outputCondition", "preset", "iccData", "iccHex", "b", "colorSpaceBytes", "isCMYKProfile", "pdfxDefinition", "generatePDFXDef", "gsArgs", "exitCode", "outputData", "outputBuffer", "outputPDF", "iccProfileHex"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imgly/plugin-print-ready-pdfs-web",
3
- "version": "0.1.0-rc.2",
3
+ "version": "1.1.0",
4
4
  "description": "Print-Ready PDFs plugin for CE.SDK editor - PDF/X conversion and export functionality. Contains AGPL-3.0 licensed Ghostscript WASM.",
5
5
  "keywords": [
6
6
  "CE.SDK",
@@ -54,6 +54,7 @@
54
54
  "playwright": "^1.54.1",
55
55
  "pnpm-sync-dependencies-meta-injected": "^0.0.14",
56
56
  "prettier": "^2.8.8",
57
+ "rimraf": "^6.0.1",
57
58
  "typescript": "^5.7.3",
58
59
  "vitest": "^2.1.8",
59
60
  "wait-on": "8.0.2",
@@ -86,10 +87,11 @@
86
87
  "test:browser": "pnpm run build && playwright test test/browser-test.spec.ts",
87
88
  "test:node": "pnpm run build && node test/node-test.mjs",
88
89
  "test": "pnpm run test:integration",
89
- "test:integration": "pnpm run build && vitest run",
90
+ "test:integration": "bash scripts/setup-test-tools.sh && pnpm run build && vitest run",
90
91
  "test:profiles": "pnpm run build && vitest run profile-conversion",
91
92
  "test:metadata": "pnpm run build && vitest run metadata-validation",
92
93
  "test:content": "pnpm run build && vitest run content-preservation",
94
+ "test:silent": "pnpm run build && vitest run silent-conversion",
93
95
  "test:all": "pnpm run test:browser && pnpm run test:integration",
94
96
  "test:visual": "pnpm run build && node test/visual-test.mjs"
95
97
  }
@@ -4,7 +4,18 @@ import type {
4
4
  GhostscriptModuleFactory,
5
5
  } from '../types/ghostscript';
6
6
 
7
- export default async function createGhostscriptModule(): Promise<EmscriptenModule> {
7
+ export interface GhostscriptModuleOptions {
8
+ /**
9
+ * Whether to suppress Ghostscript's stdout/stderr output.
10
+ * Default: true (silent mode)
11
+ */
12
+ silent?: boolean;
13
+ }
14
+
15
+ export default async function createGhostscriptModule(
16
+ options: GhostscriptModuleOptions = {}
17
+ ): Promise<EmscriptenModule> {
18
+ const { silent = true } = options;
8
19
  // Check if we're in Node.js
9
20
  const isNode =
10
21
  typeof process !== 'undefined' &&
@@ -38,14 +49,24 @@ export default async function createGhostscriptModule(): Promise<EmscriptenModul
38
49
  GhostscriptModule) as GhostscriptModuleFactory;
39
50
 
40
51
  // Configure the module to load WASM from the bundled location
41
- const module = await factory({
52
+ const moduleConfig: Record<string, unknown> = {
42
53
  locateFile: (filename: string) => {
43
54
  if (filename === 'gs.wasm') {
44
55
  return wasmPath;
45
56
  }
46
57
  return filename;
47
58
  },
48
- });
59
+ };
60
+
61
+ // Suppress Ghostscript stdout/stderr output in silent mode
62
+ if (silent) {
63
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
64
+ moduleConfig.print = () => {};
65
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
66
+ moduleConfig.printErr = () => {};
67
+ }
68
+
69
+ const module = await factory(moduleConfig);
49
70
 
50
71
  return module;
51
72
  }