@embedpdf/engines 1.0.26 → 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.
Files changed (66) hide show
  1. package/dist/{engine-BH98VpS7.js → engine-Cm-940a0.js} +135 -12
  2. package/dist/engine-Cm-940a0.js.map +1 -0
  3. package/dist/engine-DVTbcCVE.cjs +2 -0
  4. package/dist/engine-DVTbcCVE.cjs.map +1 -0
  5. package/dist/index-BZKyCIIQ.cjs +2 -0
  6. package/dist/{index-CpWF5iWs.cjs.map → index-BZKyCIIQ.cjs.map} +1 -1
  7. package/dist/{index-DF0oRaJr.js → index-D9GgzViI.js} +6 -3
  8. package/dist/{index-DF0oRaJr.js.map → index-D9GgzViI.js.map} +1 -1
  9. package/dist/index.cjs +1 -1
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.js +8 -4
  12. package/dist/index.js.map +1 -1
  13. package/dist/lib/pdfium/cache.d.ts +43 -5
  14. package/dist/lib/pdfium/engine.d.ts +11 -1
  15. package/dist/lib/pdfium/index.cjs +1 -1
  16. package/dist/lib/pdfium/index.js +2 -2
  17. package/dist/lib/pdfium/web/direct-engine.cjs +1 -1
  18. package/dist/lib/pdfium/web/direct-engine.js +1 -1
  19. package/dist/lib/pdfium/web/worker-engine.cjs +1 -1
  20. package/dist/lib/pdfium/web/worker-engine.js +1 -1
  21. package/dist/lib/webworker/engine.cjs +1 -1
  22. package/dist/lib/webworker/engine.cjs.map +1 -1
  23. package/dist/lib/webworker/engine.d.ts +6 -0
  24. package/dist/lib/webworker/engine.js +14 -1
  25. package/dist/lib/webworker/engine.js.map +1 -1
  26. package/dist/preact/adapter.d.ts +3 -1
  27. package/dist/preact/index.cjs +1 -1
  28. package/dist/preact/index.cjs.map +1 -1
  29. package/dist/preact/index.js +47 -7
  30. package/dist/preact/index.js.map +1 -1
  31. package/dist/react/adapter.d.ts +2 -1
  32. package/dist/react/index.cjs +1 -1
  33. package/dist/react/index.cjs.map +1 -1
  34. package/dist/react/index.js +46 -7
  35. package/dist/react/index.js.map +1 -1
  36. package/dist/shared-preact/components/index.d.ts +1 -0
  37. package/dist/shared-preact/components/pdf-engine-provider.d.ts +16 -0
  38. package/dist/shared-preact/context/index.d.ts +1 -0
  39. package/dist/shared-preact/context/pdf-engine-context.d.ts +7 -0
  40. package/dist/shared-preact/hooks/index.d.ts +1 -0
  41. package/dist/shared-preact/hooks/use-engine-context.d.ts +12 -0
  42. package/dist/shared-preact/index.d.ts +1 -0
  43. package/dist/shared-react/components/index.d.ts +1 -0
  44. package/dist/shared-react/components/pdf-engine-provider.d.ts +16 -0
  45. package/dist/shared-react/context/index.d.ts +1 -0
  46. package/dist/shared-react/context/pdf-engine-context.d.ts +7 -0
  47. package/dist/shared-react/hooks/index.d.ts +1 -0
  48. package/dist/shared-react/hooks/use-engine-context.d.ts +12 -0
  49. package/dist/shared-react/index.d.ts +1 -0
  50. package/dist/vue/components/index.d.ts +1 -0
  51. package/dist/vue/components/pdf-engine-provider.vue.d.ts +18 -0
  52. package/dist/vue/composables/index.d.ts +2 -0
  53. package/dist/vue/composables/use-engine-context.d.ts +12 -0
  54. package/dist/vue/context/pdf-engine-context.d.ts +8 -0
  55. package/dist/vue/index.cjs +1 -1
  56. package/dist/vue/index.cjs.map +1 -1
  57. package/dist/vue/index.d.ts +2 -1
  58. package/dist/vue/index.js +57 -7
  59. package/dist/vue/index.js.map +1 -1
  60. package/package.json +3 -3
  61. package/dist/engine-BH98VpS7.js.map +0 -1
  62. package/dist/engine-CudZwyui.cjs +0 -2
  63. package/dist/engine-CudZwyui.cjs.map +0 -1
  64. package/dist/index-CpWF5iWs.cjs +0 -2
  65. package/dist/vue/hooks/index.d.ts +0 -1
  66. /package/dist/vue/{hooks → composables}/use-pdfium-engine.d.ts +0 -0
@@ -53,16 +53,22 @@ function isValidCustomKey(key) {
53
53
  }
54
54
  return true;
55
55
  }
56
+ const DEFAULT_CONFIG = {
57
+ pageTtl: 5e3,
58
+ // 5 seconds
59
+ maxPagesPerDocument: 10
60
+ };
56
61
  class PdfCache {
57
- constructor(pdfium) {
62
+ constructor(pdfium, config = {}) {
58
63
  this.pdfium = pdfium;
59
64
  this.docs = /* @__PURE__ */ new Map();
65
+ this.config = { ...DEFAULT_CONFIG, ...config };
60
66
  }
61
67
  /** Open (or re-use) a document */
62
68
  setDocument(id, filePtr, docPtr) {
63
69
  let ctx = this.docs.get(id);
64
70
  if (!ctx) {
65
- ctx = new DocumentContext(filePtr, docPtr, this.pdfium);
71
+ ctx = new DocumentContext(filePtr, docPtr, this.pdfium, this.config);
66
72
  this.docs.set(id, ctx);
67
73
  }
68
74
  }
@@ -78,12 +84,41 @@ class PdfCache {
78
84
  this.docs.delete(docId);
79
85
  return true;
80
86
  }
87
+ /** Close all documents */
88
+ closeAllDocuments() {
89
+ for (const ctx of this.docs.values()) {
90
+ ctx.dispose();
91
+ }
92
+ this.docs.clear();
93
+ }
94
+ /** Update cache configuration for all existing documents */
95
+ updateConfig(newConfig) {
96
+ Object.assign(this.config, newConfig);
97
+ for (const ctx of this.docs.values()) {
98
+ ctx.updateConfig(this.config);
99
+ }
100
+ }
101
+ /** Get current cache statistics */
102
+ getCacheStats() {
103
+ const pagesByDocument = {};
104
+ let totalPages = 0;
105
+ for (const [docId, ctx] of this.docs.entries()) {
106
+ const pageCount = ctx.getCacheSize();
107
+ pagesByDocument[docId] = pageCount;
108
+ totalPages += pageCount;
109
+ }
110
+ return {
111
+ documents: this.docs.size,
112
+ totalPages,
113
+ pagesByDocument
114
+ };
115
+ }
81
116
  }
82
117
  class DocumentContext {
83
- constructor(filePtr, docPtr, pdfium) {
118
+ constructor(filePtr, docPtr, pdfium, config) {
84
119
  this.filePtr = filePtr;
85
120
  this.docPtr = docPtr;
86
- this.pageCache = new PageCache(pdfium, docPtr);
121
+ this.pageCache = new PageCache(pdfium, docPtr, config);
87
122
  }
88
123
  /** Main accessor for pages */
89
124
  acquirePage(pageIdx) {
@@ -93,6 +128,14 @@ class DocumentContext {
93
128
  borrowPage(pageIdx, fn) {
94
129
  return this.pageCache.borrowPage(pageIdx, fn);
95
130
  }
131
+ /** Update cache configuration */
132
+ updateConfig(config) {
133
+ this.pageCache.updateConfig(config);
134
+ }
135
+ /** Get number of pages currently in cache */
136
+ getCacheSize() {
137
+ return this.pageCache.size();
138
+ }
96
139
  /** Tear down all pages + this document */
97
140
  dispose() {
98
141
  this.pageCache.forceReleaseAll();
@@ -101,25 +144,30 @@ class DocumentContext {
101
144
  }
102
145
  }
103
146
  class PageCache {
104
- constructor(pdf, docPtr) {
147
+ constructor(pdf, docPtr, config) {
105
148
  this.pdf = pdf;
106
149
  this.docPtr = docPtr;
107
150
  this.cache = /* @__PURE__ */ new Map();
151
+ this.accessOrder = [];
152
+ this.config = config;
108
153
  }
109
154
  acquire(pageIdx) {
110
155
  let ctx = this.cache.get(pageIdx);
111
156
  if (!ctx) {
157
+ this.evictIfNeeded();
112
158
  const pagePtr = this.pdf.FPDF_LoadPage(this.docPtr, pageIdx);
113
- ctx = new PageContext(this.pdf, this.docPtr, pageIdx, pagePtr, () => {
159
+ ctx = new PageContext(this.pdf, this.docPtr, pageIdx, pagePtr, this.config.pageTtl, () => {
114
160
  this.cache.delete(pageIdx);
161
+ this.removeFromAccessOrder(pageIdx);
115
162
  });
116
163
  this.cache.set(pageIdx, ctx);
117
164
  }
165
+ this.updateAccessOrder(pageIdx);
118
166
  ctx.clearExpiryTimer();
119
167
  ctx.bumpRefCount();
120
168
  return ctx;
121
169
  }
122
- /** Helper: run a function scoped to a page.
170
+ /** Helper: run a function "scoped" to a page.
123
171
  * – if the page was already cached → .release() (keeps TTL logic)
124
172
  * – if the page was loaded just now → .disposeImmediate() (free right away)
125
173
  */
@@ -137,11 +185,55 @@ class PageCache {
137
185
  ctx.disposeImmediate();
138
186
  }
139
187
  this.cache.clear();
188
+ this.accessOrder.length = 0;
189
+ }
190
+ /** Update cache configuration */
191
+ updateConfig(config) {
192
+ this.config = config;
193
+ for (const ctx of this.cache.values()) {
194
+ ctx.updateTtl(config.pageTtl);
195
+ }
196
+ this.evictIfNeeded();
197
+ }
198
+ /** Get current cache size */
199
+ size() {
200
+ return this.cache.size;
201
+ }
202
+ /** Evict least recently used pages if cache exceeds max size */
203
+ evictIfNeeded() {
204
+ while (this.cache.size >= this.config.maxPagesPerDocument) {
205
+ const lruPageIdx = this.accessOrder[0];
206
+ if (lruPageIdx !== void 0) {
207
+ const ctx = this.cache.get(lruPageIdx);
208
+ if (ctx) {
209
+ if (ctx.getRefCount() === 0) {
210
+ ctx.disposeImmediate();
211
+ } else {
212
+ break;
213
+ }
214
+ } else {
215
+ this.removeFromAccessOrder(lruPageIdx);
216
+ }
217
+ } else {
218
+ break;
219
+ }
220
+ }
221
+ }
222
+ /** Update the access order for LRU tracking */
223
+ updateAccessOrder(pageIdx) {
224
+ this.removeFromAccessOrder(pageIdx);
225
+ this.accessOrder.push(pageIdx);
226
+ }
227
+ /** Remove a page from the access order array */
228
+ removeFromAccessOrder(pageIdx) {
229
+ const index = this.accessOrder.indexOf(pageIdx);
230
+ if (index > -1) {
231
+ this.accessOrder.splice(index, 1);
232
+ }
140
233
  }
141
234
  }
142
- const PAGE_TTL = 5e3;
143
235
  class PageContext {
144
- constructor(pdf, docPtr, pageIdx, pagePtr, onFinalDispose) {
236
+ constructor(pdf, docPtr, pageIdx, pagePtr, ttl, onFinalDispose) {
145
237
  this.pdf = pdf;
146
238
  this.docPtr = docPtr;
147
239
  this.pageIdx = pageIdx;
@@ -149,12 +241,17 @@ class PageContext {
149
241
  this.onFinalDispose = onFinalDispose;
150
242
  this.refCount = 0;
151
243
  this.disposed = false;
244
+ this.ttl = ttl;
152
245
  }
153
246
  /** Called by PageCache.acquire() */
154
247
  bumpRefCount() {
155
248
  if (this.disposed) throw new Error("Context already disposed");
156
249
  this.refCount++;
157
250
  }
251
+ /** Get current reference count */
252
+ getRefCount() {
253
+ return this.refCount;
254
+ }
158
255
  /** Called by PageCache.acquire() */
159
256
  clearExpiryTimer() {
160
257
  if (this.expiryTimer) {
@@ -162,18 +259,27 @@ class PageContext {
162
259
  this.expiryTimer = void 0;
163
260
  }
164
261
  }
262
+ /** Update TTL configuration */
263
+ updateTtl(newTtl) {
264
+ this.ttl = newTtl;
265
+ if (this.expiryTimer && this.refCount === 0) {
266
+ this.clearExpiryTimer();
267
+ this.expiryTimer = setTimeout(() => this.disposeImmediate(), this.ttl);
268
+ }
269
+ }
165
270
  /** Called by PageCache.release() internally */
166
271
  release() {
167
272
  if (this.disposed) return;
168
273
  this.refCount--;
169
274
  if (this.refCount === 0) {
170
- this.expiryTimer = setTimeout(() => this.disposeImmediate(), PAGE_TTL);
275
+ this.expiryTimer = setTimeout(() => this.disposeImmediate(), this.ttl);
171
276
  }
172
277
  }
173
278
  /** Tear down _all_ sub-pointers & the page. */
174
279
  disposeImmediate() {
175
280
  if (this.disposed) return;
176
281
  this.disposed = true;
282
+ this.clearExpiryTimer();
177
283
  if (this.textPagePtr !== void 0) {
178
284
  this.pdf.FPDFText_ClosePage(this.textPagePtr);
179
285
  }
@@ -365,6 +471,7 @@ class PdfiumEngine {
365
471
  */
366
472
  constructor(pdfiumModule, options = {}) {
367
473
  this.pdfiumModule = pdfiumModule;
474
+ this.memoryLeakCheckInterval = null;
368
475
  const {
369
476
  logger = new NoopLogger(),
370
477
  imageDataConverter = browserImageDataToBlobConverter
@@ -374,7 +481,7 @@ class PdfiumEngine {
374
481
  this.imageDataConverter = imageDataConverter;
375
482
  this.memoryManager = new MemoryManager(this.pdfiumModule, this.logger);
376
483
  if (this.logger.isEnabled("debug")) {
377
- setInterval(() => {
484
+ this.memoryLeakCheckInterval = setInterval(() => {
378
485
  this.memoryManager.checkLeaks();
379
486
  }, 1e4);
380
487
  }
@@ -400,6 +507,10 @@ class PdfiumEngine {
400
507
  this.logger.debug(LOG_SOURCE, LOG_CATEGORY, "destroy");
401
508
  this.logger.perf(LOG_SOURCE, LOG_CATEGORY, `Destroy`, "Begin", "General");
402
509
  this.pdfiumModule.FPDF_DestroyLibrary();
510
+ if (this.memoryLeakCheckInterval) {
511
+ clearInterval(this.memoryLeakCheckInterval);
512
+ this.memoryLeakCheckInterval = null;
513
+ }
403
514
  this.logger.perf(LOG_SOURCE, LOG_CATEGORY, `Destroy`, "End", "General");
404
515
  return PdfTaskHelper.resolve(true);
405
516
  }
@@ -2026,6 +2137,18 @@ class PdfiumEngine {
2026
2137
  this.logger.perf(LOG_SOURCE, LOG_CATEGORY, `CloseDocument`, "End", doc.id);
2027
2138
  return PdfTaskHelper.resolve(true);
2028
2139
  }
2140
+ /**
2141
+ * {@inheritDoc @embedpdf/models!PdfEngine.closeAllDocuments}
2142
+ *
2143
+ * @public
2144
+ */
2145
+ closeAllDocuments() {
2146
+ this.logger.debug(LOG_SOURCE, LOG_CATEGORY, "closeAllDocuments");
2147
+ this.logger.perf(LOG_SOURCE, LOG_CATEGORY, `CloseAllDocuments`, "Begin");
2148
+ this.cache.closeAllDocuments();
2149
+ this.logger.perf(LOG_SOURCE, LOG_CATEGORY, `CloseAllDocuments`, "End");
2150
+ return PdfTaskHelper.resolve(true);
2151
+ }
2029
2152
  /**
2030
2153
  * Add text content to annotation
2031
2154
  * @param page - page info
@@ -6502,4 +6625,4 @@ export {
6502
6625
  isValidCustomKey as i,
6503
6626
  readString as r
6504
6627
  };
6505
- //# sourceMappingURL=engine-BH98VpS7.js.map
6628
+ //# sourceMappingURL=engine-Cm-940a0.js.map