@meonode/canvas 1.7.0 → 1.7.2

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 (43) hide show
  1. package/dist/cjs/canvas/image.canvas.util.d.ts +42 -2
  2. package/dist/cjs/canvas/image.canvas.util.d.ts.map +1 -1
  3. package/dist/cjs/canvas/image.canvas.util.js +145 -7
  4. package/dist/cjs/canvas/image.canvas.util.js.map +1 -1
  5. package/dist/cjs/canvas/root.canvas.util.d.ts +2 -0
  6. package/dist/cjs/canvas/root.canvas.util.d.ts.map +1 -1
  7. package/dist/cjs/canvas/root.canvas.util.js +59 -40
  8. package/dist/cjs/canvas/root.canvas.util.js.map +1 -1
  9. package/dist/cjs/index.d.ts +1 -1
  10. package/dist/cjs/index.d.ts.map +1 -1
  11. package/dist/cjs/index.js +1 -0
  12. package/dist/cjs/index.js.map +1 -1
  13. package/dist/cjs/util/disk.cache.d.ts +4 -0
  14. package/dist/cjs/util/disk.cache.d.ts.map +1 -0
  15. package/dist/cjs/util/disk.cache.js +40 -0
  16. package/dist/cjs/util/disk.cache.js.map +1 -0
  17. package/dist/cjs/worker/render.worker.d.ts.map +1 -0
  18. package/dist/cjs/{render.worker.js → worker/render.worker.js} +1 -1
  19. package/dist/cjs/worker/render.worker.js.map +1 -0
  20. package/dist/{esm/canvas → cjs/worker}/worker.types.d.ts.map +1 -1
  21. package/dist/esm/canvas/image.canvas.util.d.ts +42 -2
  22. package/dist/esm/canvas/image.canvas.util.d.ts.map +1 -1
  23. package/dist/esm/canvas/image.canvas.util.js +143 -8
  24. package/dist/esm/canvas/root.canvas.util.d.ts +2 -0
  25. package/dist/esm/canvas/root.canvas.util.d.ts.map +1 -1
  26. package/dist/esm/canvas/root.canvas.util.js +60 -41
  27. package/dist/esm/index.d.ts +1 -1
  28. package/dist/esm/index.d.ts.map +1 -1
  29. package/dist/esm/index.js +1 -1
  30. package/dist/esm/util/disk.cache.d.ts +4 -0
  31. package/dist/esm/util/disk.cache.d.ts.map +1 -0
  32. package/dist/esm/util/disk.cache.js +35 -0
  33. package/dist/esm/worker/render.worker.d.ts.map +1 -0
  34. package/dist/esm/{render.worker.js → worker/render.worker.js} +1 -1
  35. package/dist/{cjs/canvas → esm/worker}/worker.types.d.ts.map +1 -1
  36. package/package.json +1 -1
  37. package/dist/cjs/render.worker.d.ts.map +0 -1
  38. package/dist/cjs/render.worker.js.map +0 -1
  39. package/dist/esm/render.worker.d.ts.map +0 -1
  40. /package/dist/cjs/{render.worker.d.ts → worker/render.worker.d.ts} +0 -0
  41. /package/dist/cjs/{canvas → worker}/worker.types.d.ts +0 -0
  42. /package/dist/esm/{render.worker.d.ts → worker/render.worker.d.ts} +0 -0
  43. /package/dist/esm/{canvas → worker}/worker.types.d.ts +0 -0
@@ -1,6 +1,6 @@
1
1
  import { FontLibrary, Canvas } from 'skia-canvas';
2
2
  import { ColumnNode, RowNode, BoxNode } from './layout.canvas.util.js';
3
- import { ImageNode } from './image.canvas.util.js';
3
+ import { ImageNode, disposeImageCache, getImageCache } from './image.canvas.util.js';
4
4
  import { TextNode } from './text.canvas.util.js';
5
5
  import { ChartNode } from './chart.canvas.util.js';
6
6
  import { GridItemNode, GridNode } from './grid.canvas.util.js';
@@ -27,6 +27,11 @@ function configure(options) {
27
27
  _workerMode = options.workerMode;
28
28
  if (options.workers !== undefined)
29
29
  _workerPoolSize = options.workers;
30
+ if (options.imageCacheSize !== undefined) {
31
+ // Dispose existing cache and create a new one with the specified size
32
+ disposeImageCache();
33
+ getImageCache(options.imageCacheSize);
34
+ }
30
35
  if (_workerMode) {
31
36
  _workerPool = new WorkerPool(_workerPoolSize);
32
37
  }
@@ -113,7 +118,7 @@ class WorkerPool {
113
118
  this.init(size);
114
119
  }
115
120
  init(size) {
116
- const workerFile = path.join(path.dirname(fileURLToPath(import.meta.url)), '../render.worker.js');
121
+ const workerFile = path.join(path.dirname(fileURLToPath(import.meta.url)), '../worker/render.worker.js');
117
122
  for (let i = 0; i < size; i++) {
118
123
  const workerIdx = i;
119
124
  const worker = new Worker(workerFile);
@@ -290,42 +295,49 @@ class RootNode extends ColumnNode {
290
295
  * @returns Promise resolving to the rendered Canvas instance
291
296
  */
292
297
  async render() {
293
- // Step 1: Load all images with a concurrency limit to avoid overwhelming remote sources.
294
- // A per-render cache deduplicates identical src+color combinations within this render pass.
295
- const imageNodes = this.findAllImageNodes();
296
- if (imageNodes.length > 0) {
297
- const imageCache = new Map();
298
- const CONCURRENCY = 5;
299
- const queue = [...imageNodes];
300
- const workers = Array.from({ length: Math.min(CONCURRENCY, queue.length) }, async () => {
301
- while (queue.length > 0) {
302
- const node = queue.shift();
303
- await node.load(imageCache);
304
- }
305
- });
306
- await Promise.allSettled(workers);
307
- }
308
- // Step 2: Calculate initial layout
309
- this.node.calculateLayout(this.targetWidth, undefined, Style.Direction.LTR);
310
- // Step 3: Allow nodes to finalize their layout
311
- const needRecalculate = this.finalizeLayout();
312
- if (needRecalculate) {
298
+ try {
299
+ // Step 1: Load all images with a concurrency limit to avoid overwhelming remote sources.
300
+ // A per-render cache deduplicates identical src+color combinations within this render pass.
301
+ const imageNodes = this.findAllImageNodes();
302
+ if (imageNodes.length > 0) {
303
+ const imageCache = new Map();
304
+ const CONCURRENCY = 5;
305
+ const queue = [...imageNodes];
306
+ const workers = Array.from({ length: Math.min(CONCURRENCY, queue.length) }, async () => {
307
+ while (queue.length > 0) {
308
+ const node = queue.shift();
309
+ await node.load(imageCache);
310
+ }
311
+ });
312
+ await Promise.allSettled(workers);
313
+ }
314
+ // Step 2: Calculate initial layout
313
315
  this.node.calculateLayout(this.targetWidth, undefined, Style.Direction.LTR);
316
+ // Step 3: Allow nodes to finalize their layout
317
+ const needRecalculate = this.finalizeLayout();
318
+ if (needRecalculate) {
319
+ this.node.calculateLayout(this.targetWidth, undefined, Style.Direction.LTR);
320
+ }
321
+ // Step 4: Create a canvas with calculated dimensions
322
+ const calculatedContentHeight = this.node.getComputedHeight();
323
+ const finalCanvasWidth = Math.ceil(this.targetWidth * this.scale);
324
+ const finalCanvasHeight = this.targetHeight ? Math.ceil(this.targetHeight * this.scale) : Math.max(1, Math.ceil(calculatedContentHeight * this.scale));
325
+ // Step 5: Set up canvas context
326
+ this.canvas = new Canvas(finalCanvasWidth, finalCanvasHeight);
327
+ this.ctx = this.canvas.getContext('2d');
328
+ this.ctx.scale(this.scale, this.scale);
329
+ // Step 6: Render content
330
+ super.render(this.ctx, 0, 0);
331
+ if (!this.canvas) {
332
+ throw new Error('Canvas not initialized');
333
+ }
334
+ return this.canvas;
314
335
  }
315
- // Step 4: Create a canvas with calculated dimensions
316
- const calculatedContentHeight = this.node.getComputedHeight();
317
- const finalCanvasWidth = Math.ceil(this.targetWidth * this.scale);
318
- const finalCanvasHeight = this.targetHeight ? Math.ceil(this.targetHeight * this.scale) : Math.max(1, Math.ceil(calculatedContentHeight * this.scale));
319
- // Step 5: Set up canvas context
320
- this.canvas = new Canvas(finalCanvasWidth, finalCanvasHeight);
321
- this.ctx = this.canvas.getContext('2d');
322
- this.ctx.scale(this.scale, this.scale);
323
- // Step 6: Render content
324
- super.render(this.ctx, 0, 0);
325
- if (!this.canvas) {
326
- throw new Error('Canvas not initialized');
336
+ finally {
337
+ // Always clear the persistent image cache after render (success or error)
338
+ // so resolved CanvasImage references don't outlive the render pass.
339
+ disposeImageCache();
327
340
  }
328
- return this.canvas;
329
341
  }
330
342
  }
331
343
  /**
@@ -336,14 +348,21 @@ class RootNode extends ColumnNode {
336
348
  * @returns Promise resolving to the rendered Canvas (or WorkerCanvas in worker mode)
337
349
  */
338
350
  const Root = async (props) => {
339
- if (_workerMode) {
340
- if (!_workerPool) {
341
- _workerPool = new WorkerPool(_workerPoolSize);
351
+ try {
352
+ if (_workerMode) {
353
+ if (!_workerPool) {
354
+ _workerPool = new WorkerPool(_workerPoolSize);
355
+ }
356
+ const result = await _workerPool.render(props);
357
+ return new WorkerCanvas({ ...result, pool: _workerPool });
342
358
  }
343
- const result = await _workerPool.render(props);
344
- return new WorkerCanvas({ ...result, pool: _workerPool });
359
+ return await new RootNode(props).render();
360
+ }
361
+ catch (err) {
362
+ // Ensure cache is cleared even if Root-level orchestration fails
363
+ disposeImageCache();
364
+ throw err;
345
365
  }
346
- return new RootNode(props).render();
347
366
  };
348
367
 
349
368
  export { Root, RootNode, buildTree, configure };
@@ -1,7 +1,7 @@
1
1
  export * from './constant/common.const.js';
2
2
  export * from './canvas/canvas.type.js';
3
3
  export { Box, Column, Row, type BoxNode } from './canvas/layout.canvas.util.js';
4
- export { Image } from './canvas/image.canvas.util.js';
4
+ export { Image, disposeImageCache } from './canvas/image.canvas.util.js';
5
5
  export { Text } from './canvas/text.canvas.util.js';
6
6
  export { Root, configure } from './canvas/root.canvas.util.js';
7
7
  export { GridItem } from './canvas/grid.canvas.util.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAA;AAC1C,cAAc,yBAAyB,CAAA;AACvC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAC/E,OAAO,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAA;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAA;AACnD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAA;AAC1C,cAAc,yBAAyB,CAAA;AACvC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAC/E,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAA;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAA;AACnD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAA;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,8BAA8B,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAA"}
package/dist/esm/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  export { Border, Style } from './constant/common.const.js';
2
2
  export { Box, Column, Row } from './canvas/layout.canvas.util.js';
3
- export { Image } from './canvas/image.canvas.util.js';
3
+ export { Image, disposeImageCache } from './canvas/image.canvas.util.js';
4
4
  export { Text } from './canvas/text.canvas.util.js';
5
5
  export { Root, configure } from './canvas/root.canvas.util.js';
6
6
  export { Grid, GridItem } from './canvas/grid.canvas.util.js';
@@ -0,0 +1,4 @@
1
+ export declare function hashBuffer(buf: Buffer): string;
2
+ export declare function readDiskCache(key: string): Promise<Buffer | null>;
3
+ export declare function writeDiskCache(key: string, data: Buffer): Promise<void>;
4
+ //# sourceMappingURL=disk.cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disk.cache.d.ts","sourceRoot":"","sources":["../../../src/util/disk.cache.ts"],"names":[],"mappings":"AAaA,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOvE;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAO7E"}
@@ -0,0 +1,35 @@
1
+ import { createHash } from 'crypto';
2
+ import { promises } from 'fs';
3
+ import { join } from 'path';
4
+
5
+ const CACHE_DIR = join(process.cwd(), '.cache', 'files');
6
+ let _dirEnsured = false;
7
+ async function ensureDir() {
8
+ if (_dirEnsured)
9
+ return;
10
+ await promises.mkdir(CACHE_DIR, { recursive: true });
11
+ _dirEnsured = true;
12
+ }
13
+ function hashBuffer(buf) {
14
+ return createHash('sha256').update(buf).digest('hex');
15
+ }
16
+ async function readDiskCache(key) {
17
+ try {
18
+ await ensureDir();
19
+ return await promises.readFile(join(CACHE_DIR, key));
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ }
25
+ async function writeDiskCache(key, data) {
26
+ try {
27
+ await ensureDir();
28
+ await promises.writeFile(join(CACHE_DIR, key), data);
29
+ }
30
+ catch {
31
+ // best-effort — cache write failures are non-fatal
32
+ }
33
+ }
34
+
35
+ export { hashBuffer, readDiskCache, writeDiskCache };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.worker.d.ts","sourceRoot":"","sources":["../../../src/worker/render.worker.ts"],"names":[],"mappings":""}
@@ -1,5 +1,5 @@
1
1
  import { parentPort } from 'worker_threads';
2
- import { RootNode } from './canvas/root.canvas.util.js';
2
+ import { RootNode } from '../canvas/root.canvas.util.js';
3
3
 
4
4
  /**
5
5
  * Worker thread entry point for off-main-thread canvas rendering.
@@ -1 +1 @@
1
- {"version":3,"file":"worker.types.d.ts","sourceRoot":"","sources":["../../../src/canvas/worker.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC1F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAMxD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE;QAAE,IAAI,EAAE,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAClE,KAAK,EAAE;QAAE,IAAI,EAAE,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAC/D,MAAM,EAAE;QAAE,IAAI,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;QAAC,MAAM,EAAE,IAAI,CAAA;KAAE,CAAA;IACtD,OAAO,EAAE;QAAE,IAAI,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CACpD;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,aAAa,CAAA;AAClD,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,gBAAgB,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;AAC3E,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,gBAAgB,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAA;AAM/E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,QAAQ,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,SAAS,CAAA;CACjB;AAED,+EAA+E;AAC/E,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC,UAAU,CAAC,CAAA;CAAE,GAClG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAA;CAAE,GAC5F;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAA;CAAE,GAC9F;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAA;CAAE,CAAA;AAEpG,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,SAAS,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,MAAM,aAAa,GAAG,mBAAmB,GAAG,iBAAiB,GAAG,oBAAoB,CAAA;AAM1F,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CAC/B;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,MAAM,cAAc,GAAG,oBAAoB,GAAG,kBAAkB,GAAG,mBAAmB,CAAA"}
1
+ {"version":3,"file":"worker.types.d.ts","sourceRoot":"","sources":["../../../src/worker/worker.types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meonode/canvas",
3
- "version": "1.7.0",
3
+ "version": "1.7.2",
4
4
  "description": "A declarative, component-based library for server-side canvas image generation. Write complex visuals with simple functions, similar to the composition style of @meonode/ui.",
5
5
  "keywords": [
6
6
  "canvas",
@@ -1 +0,0 @@
1
- {"version":3,"file":"render.worker.d.ts","sourceRoot":"","sources":["../../src/render.worker.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"render.worker.js","sources":["../../../src/render.worker.ts"],"sourcesContent":["/**\n * Worker thread entry point for off-main-thread canvas rendering.\n *\n * Message protocol (main → worker):\n * { type: 'render', taskId, props } — render and keep Canvas alive\n * { type: 'call', taskId, canvasId, method, args } — call a method on a live Canvas\n * { type: 'release', canvasId } — free Canvas from memory\n *\n * Responses (worker → main):\n * WorkerRenderResponse — render complete (includes pre-encoded PNG buffer)\n * WorkerCallResponse — method call result\n * WorkerErrorResponse — any failure\n */\nimport { parentPort } from 'worker_threads'\nimport { RootNode } from '@/canvas/root.canvas.util.js'\nimport type { Canvas } from 'skia-canvas'\nimport type { WorkerRequest, WorkerRenderResponse, WorkerCallResponse, WorkerErrorResponse } from '@/canvas/worker.types.js'\n\nif (!parentPort) {\n throw new Error('[render.worker] Must be run as a worker thread')\n}\n\nconst canvases = new Map<number, Canvas>()\nlet nextCanvasId = 0\n\nfunction reply(msg: WorkerRenderResponse | WorkerCallResponse | WorkerErrorResponse) {\n parentPort!.postMessage(msg)\n}\n\nparentPort.on('message', async (msg: WorkerRequest) => {\n if (msg.type === 'render') {\n try {\n const canvas = await new RootNode(msg.props).render()\n const canvasId = nextCanvasId++\n canvases.set(canvasId, canvas)\n reply({ taskId: msg.taskId, canvasId, buffer: canvas.toBufferSync('png'), width: canvas.width, height: canvas.height })\n } catch (err) {\n reply({ taskId: msg.taskId, error: String(err) })\n }\n } else if (msg.type === 'call') {\n const canvas = canvases.get(msg.canvasId)\n if (!canvas) {\n reply({ taskId: msg.taskId, error: `[render.worker] Canvas ${msg.canvasId} not found` })\n return\n }\n try {\n let result: Buffer | string | void\n switch (msg.method) {\n case 'toBuffer':\n result = await canvas.toBuffer(...msg.args)\n break\n case 'toURL':\n result = await canvas.toURL(...msg.args)\n break\n case 'toFile':\n result = await canvas.toFile(...msg.args)\n break\n case 'toSharp':\n // Sharp instances can't be transferred across threads — serialize to buffer\n result = await canvas.toSharp(...msg.args).toBuffer()\n break\n }\n reply({ taskId: msg.taskId, result })\n } catch (err) {\n reply({ taskId: msg.taskId, error: String(err) })\n }\n } else {\n // type === 'release'\n canvases.delete(msg.canvasId)\n }\n})\n"],"names":["parentPort","RootNode"],"mappings":";;;;;AAAA;;;;;;;;;;;;AAYG;AAMH,IAAI,CAACA,yBAAU,EAAE;AACf,IAAA,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AACnE;AAEA,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB;AAC1C,IAAI,YAAY,GAAG,CAAC;AAEpB,SAAS,KAAK,CAAC,GAAoE,EAAA;AACjF,IAAAA,yBAAW,CAAC,WAAW,CAAC,GAAG,CAAC;AAC9B;AAEAA,yBAAU,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,GAAkB,KAAI;AACpD,IAAA,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE;AACzB,QAAA,IAAI;AACF,YAAA,MAAM,MAAM,GAAG,MAAM,IAAIC,yBAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE;AACrD,YAAA,MAAM,QAAQ,GAAG,YAAY,EAAE;AAC/B,YAAA,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC;AAC9B,YAAA,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;QACzH;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACnD;IACF;AAAO,SAAA,IAAI,GAAG,CAAC,IAAI,KAAK,MAAM,EAAE;QAC9B,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC;QACzC,IAAI,CAAC,MAAM,EAAE;AACX,YAAA,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,0BAA0B,GAAG,CAAC,QAAQ,CAAA,UAAA,CAAY,EAAE,CAAC;YACxF;QACF;AACA,QAAA,IAAI;AACF,YAAA,IAAI,MAA8B;AAClC,YAAA,QAAQ,GAAG,CAAC,MAAM;AAChB,gBAAA,KAAK,UAAU;oBACb,MAAM,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC;oBAC3C;AACF,gBAAA,KAAK,OAAO;oBACV,MAAM,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC;oBACxC;AACF,gBAAA,KAAK,QAAQ;oBACX,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC;oBACzC;AACF,gBAAA,KAAK,SAAS;;AAEZ,oBAAA,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE;oBACrD;;YAEJ,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QACvC;QAAE,OAAO,GAAG,EAAE;AACZ,YAAA,KAAK,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACnD;IACF;SAAO;;AAEL,QAAA,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC/B;AACF,CAAC,CAAC;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"render.worker.d.ts","sourceRoot":"","sources":["../../src/render.worker.ts"],"names":[],"mappings":""}
File without changes
File without changes