@meonode/canvas 2.0.4 → 3.0.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 (79) hide show
  1. package/CONTRIBUTING.md +9 -9
  2. package/README.md +9 -21
  3. package/dist/cjs/canvas/canvas.helper.d.ts +1 -1
  4. package/dist/cjs/canvas/canvas.type.d.ts +9 -4
  5. package/dist/cjs/canvas/canvas.type.d.ts.map +1 -1
  6. package/dist/cjs/canvas/chart.canvas.d.ts +7 -3
  7. package/dist/cjs/canvas/chart.canvas.d.ts.map +1 -1
  8. package/dist/cjs/canvas/chart.canvas.js +3 -4
  9. package/dist/cjs/canvas/chart.canvas.js.map +1 -1
  10. package/dist/cjs/canvas/grid.canvas.d.ts +2 -2
  11. package/dist/cjs/canvas/grid.canvas.d.ts.map +1 -1
  12. package/dist/cjs/canvas/grid.canvas.js +2 -8
  13. package/dist/cjs/canvas/grid.canvas.js.map +1 -1
  14. package/dist/cjs/canvas/image.canvas.d.ts +2 -2
  15. package/dist/cjs/canvas/image.canvas.js.map +1 -1
  16. package/dist/cjs/canvas/layout.canvas.d.ts +5 -1
  17. package/dist/cjs/canvas/layout.canvas.d.ts.map +1 -1
  18. package/dist/cjs/canvas/layout.canvas.js +59 -68
  19. package/dist/cjs/canvas/layout.canvas.js.map +1 -1
  20. package/dist/cjs/canvas/root.canvas.d.ts +9 -16
  21. package/dist/cjs/canvas/root.canvas.d.ts.map +1 -1
  22. package/dist/cjs/canvas/root.canvas.js +56 -43
  23. package/dist/cjs/canvas/root.canvas.js.map +1 -1
  24. package/dist/cjs/canvas/text.canvas.d.ts +7 -3
  25. package/dist/cjs/canvas/text.canvas.d.ts.map +1 -1
  26. package/dist/cjs/canvas/text.canvas.js +25 -85
  27. package/dist/cjs/canvas/text.canvas.js.map +1 -1
  28. package/dist/cjs/index.d.ts +2 -2
  29. package/dist/cjs/index.d.ts.map +1 -1
  30. package/dist/cjs/index.js +1 -1
  31. package/dist/cjs/util/disk.cache.d.ts +5 -0
  32. package/dist/cjs/util/disk.cache.d.ts.map +1 -1
  33. package/dist/cjs/util/disk.cache.js +23 -8
  34. package/dist/cjs/util/disk.cache.js.map +1 -1
  35. package/dist/cjs/worker/comlink.pool.d.ts +15 -4
  36. package/dist/cjs/worker/comlink.pool.d.ts.map +1 -1
  37. package/dist/cjs/worker/comlink.pool.js +69 -18
  38. package/dist/cjs/worker/comlink.pool.js.map +1 -1
  39. package/dist/cjs/worker/comlink.setup.d.ts.map +1 -1
  40. package/dist/cjs/worker/comlink.setup.js +1 -2
  41. package/dist/cjs/worker/comlink.setup.js.map +1 -1
  42. package/dist/cjs/worker/render.worker.js +4 -2
  43. package/dist/cjs/worker/render.worker.js.map +1 -1
  44. package/dist/cjs/worker/worker.types.d.ts +2 -1
  45. package/dist/cjs/worker/worker.types.d.ts.map +1 -1
  46. package/dist/esm/canvas/canvas.helper.d.ts +1 -1
  47. package/dist/esm/canvas/canvas.type.d.ts +9 -4
  48. package/dist/esm/canvas/canvas.type.d.ts.map +1 -1
  49. package/dist/esm/canvas/chart.canvas.d.ts +7 -3
  50. package/dist/esm/canvas/chart.canvas.d.ts.map +1 -1
  51. package/dist/esm/canvas/chart.canvas.js +3 -4
  52. package/dist/esm/canvas/grid.canvas.d.ts +2 -2
  53. package/dist/esm/canvas/grid.canvas.d.ts.map +1 -1
  54. package/dist/esm/canvas/grid.canvas.js +1 -7
  55. package/dist/esm/canvas/image.canvas.d.ts +2 -2
  56. package/dist/esm/canvas/layout.canvas.d.ts +5 -1
  57. package/dist/esm/canvas/layout.canvas.d.ts.map +1 -1
  58. package/dist/esm/canvas/layout.canvas.js +59 -69
  59. package/dist/esm/canvas/root.canvas.d.ts +9 -16
  60. package/dist/esm/canvas/root.canvas.d.ts.map +1 -1
  61. package/dist/esm/canvas/root.canvas.js +57 -43
  62. package/dist/esm/canvas/text.canvas.d.ts +7 -3
  63. package/dist/esm/canvas/text.canvas.d.ts.map +1 -1
  64. package/dist/esm/canvas/text.canvas.js +25 -85
  65. package/dist/esm/index.d.ts +2 -2
  66. package/dist/esm/index.d.ts.map +1 -1
  67. package/dist/esm/index.js +2 -2
  68. package/dist/esm/util/disk.cache.d.ts +5 -0
  69. package/dist/esm/util/disk.cache.d.ts.map +1 -1
  70. package/dist/esm/util/disk.cache.js +23 -9
  71. package/dist/esm/worker/comlink.pool.d.ts +15 -4
  72. package/dist/esm/worker/comlink.pool.d.ts.map +1 -1
  73. package/dist/esm/worker/comlink.pool.js +67 -18
  74. package/dist/esm/worker/comlink.setup.d.ts.map +1 -1
  75. package/dist/esm/worker/comlink.setup.js +1 -1
  76. package/dist/esm/worker/render.worker.js +4 -2
  77. package/dist/esm/worker/worker.types.d.ts +2 -1
  78. package/dist/esm/worker/worker.types.d.ts.map +1 -1
  79. package/package.json +9 -16
@@ -2,12 +2,20 @@ import { createHash } from 'crypto';
2
2
  import { promises } from 'fs';
3
3
  import { join } from 'path';
4
4
 
5
- const CACHE_DIR = join(process.cwd(), '.cache', 'files');
5
+ let _cacheDir = join(process.cwd(), '.cache', 'files');
6
6
  let _dirEnsured = false;
7
+ /**
8
+ * Override the default disk cache directory.
9
+ * Must be called before any cache read/write operations.
10
+ */
11
+ function setDiskCacheDir(dir) {
12
+ _cacheDir = dir;
13
+ _dirEnsured = false;
14
+ }
7
15
  async function ensureDir() {
8
16
  if (_dirEnsured)
9
17
  return;
10
- await promises.mkdir(CACHE_DIR, { recursive: true });
18
+ await promises.mkdir(_cacheDir, { recursive: true });
11
19
  _dirEnsured = true;
12
20
  }
13
21
  function hashBuffer(buf) {
@@ -16,7 +24,7 @@ function hashBuffer(buf) {
16
24
  async function readDiskCache(key) {
17
25
  try {
18
26
  await ensureDir();
19
- return await promises.readFile(join(CACHE_DIR, key));
27
+ return await promises.readFile(join(_cacheDir, key));
20
28
  }
21
29
  catch {
22
30
  return null;
@@ -25,7 +33,7 @@ async function readDiskCache(key) {
25
33
  async function writeDiskCache(key, data) {
26
34
  try {
27
35
  await ensureDir();
28
- await promises.writeFile(join(CACHE_DIR, key), data);
36
+ await promises.writeFile(join(_cacheDir, key), data);
29
37
  }
30
38
  catch {
31
39
  // best-effort — cache write failures are non-fatal
@@ -33,10 +41,13 @@ async function writeDiskCache(key, data) {
33
41
  }
34
42
  async function deleteDiskCache(key) {
35
43
  try {
36
- await promises.unlink(join(CACHE_DIR, key));
44
+ await promises.unlink(join(_cacheDir, key));
37
45
  }
38
- catch {
46
+ catch (err) {
39
47
  // non-fatal — file may not exist if write failed earlier
48
+ if (err.code !== 'ENOENT') {
49
+ console.warn(`[disk.cache] Failed to delete cache entry "${key}":`, err.message);
50
+ }
40
51
  }
41
52
  }
42
53
  /**
@@ -46,10 +57,13 @@ async function deleteDiskCache(key) {
46
57
  async function clearDiskCache() {
47
58
  _dirEnsured = false;
48
59
  try {
49
- await promises.rm(CACHE_DIR, { recursive: true, force: true });
60
+ await promises.rm(_cacheDir, { recursive: true, force: true });
50
61
  }
51
- catch {
62
+ catch (err) {
52
63
  // non-fatal — directory may not exist
64
+ if (err.code !== 'ENOENT') {
65
+ console.warn('[disk.cache] Failed to clear cache directory:', err.message);
66
+ }
53
67
  }
54
68
  }
55
69
  // Clean up disk cache on process exit to handle crashes mid-render.
@@ -69,4 +83,4 @@ const cleanupOnExit = () => {
69
83
  process.on('SIGINT', cleanupOnExit);
70
84
  process.on('SIGTERM', cleanupOnExit);
71
85
 
72
- export { clearDiskCache, deleteDiskCache, hashBuffer, readDiskCache, writeDiskCache };
86
+ export { clearDiskCache, deleteDiskCache, hashBuffer, readDiskCache, setDiskCacheDir, writeDiskCache };
@@ -1,13 +1,24 @@
1
- import type { RenderResult } from '../worker/worker.types.js';
1
+ import type { RenderResult } from './worker.types.js';
2
2
  import type { RootProps } from '../canvas/canvas.type.js';
3
3
  export interface PoolRenderResult extends RenderResult {
4
4
  workerIdx: number;
5
5
  }
6
+ /** Sentinel embedded in serialized props to mark where a function was extracted. */
7
+ export declare const FN_MARKER = "__comlinkFnId";
6
8
  /**
7
- * Deeply walks an object tree, wraps any function values with Comlink.proxy(),
8
- * and tracks wrapped proxies for deterministic cleanup.
9
+ * Deeply walks an object tree, replaces function values with `{ [FN_MARKER]: id }` sentinels,
10
+ * and collects the original functions in a Map keyed by their assigned id.
11
+ * Returns the cleaned (function-free) tree that is safe for structured clone.
9
12
  */
10
- export declare function wrapFunctions<T>(obj: T, proxies: Set<unknown>): T;
13
+ export declare function extractFunctions<T>(obj: T, fnMap: Map<number, (...args: unknown[]) => unknown>, nextId: {
14
+ value: number;
15
+ }): T;
16
+ /**
17
+ * Deeply walks an object tree received on the worker side, replaces
18
+ * `{ [FN_MARKER]: id }` sentinels with async functions that delegate
19
+ * to the main-thread callback proxy.
20
+ */
21
+ export declare function restoreFunctions<T>(obj: T, callFn: (id: number, ...args: unknown[]) => Promise<unknown>): T;
11
22
  /**
12
23
  * Pool of Comlink-wrapped worker threads.
13
24
  * Manages idle/queue scheduling and proxy lifecycle.
@@ -1 +1 @@
1
- {"version":3,"file":"comlink.pool.d.ts","sourceRoot":"","sources":["../../../src/worker/comlink.pool.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAa,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACvE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAExD,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACpD,SAAS,EAAE,MAAM,CAAA;CAClB;AAQD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAuBjE;AAED;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,IAAI,CAAe;IAC3B,OAAO,CAAC,KAAK,CAAmB;gBAEpB,IAAI,EAAE,MAAM;IAYxB,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,KAAK;YAQC,aAAa;IAWrB,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA0CzD,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAInH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIxD,SAAS;CAOV"}
1
+ {"version":3,"file":"comlink.pool.d.ts","sourceRoot":"","sources":["../../../src/worker/comlink.pool.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAa,YAAY,EAAU,MAAM,0BAA0B,CAAA;AAC/E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAExD,MAAM,WAAW,gBAAiB,SAAQ,YAAY;IACpD,SAAS,EAAE,MAAM,CAAA;CAClB;AASD,oFAAoF;AACpF,eAAO,MAAM,SAAS,kBAAkB,CAAA;AAExC;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,EAAE,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,CAAC,CAuB7H;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAuB3G;AAED;;;GAGG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,SAAS,CAA0B;IAC3C,OAAO,CAAC,IAAI,CAAe;IAC3B,OAAO,CAAC,KAAK,CAAmB;gBAEpB,IAAI,EAAE,MAAM;IAYxB,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,OAAO;IAKf,OAAO,CAAC,KAAK;YAQC,aAAa;IAiBrB,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA2DzD,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAInH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAIxD,SAAS;CAOV"}
@@ -5,17 +5,20 @@ import './comlink.setup.js';
5
5
  import * as Comlink from 'comlink';
6
6
  import nodeEndpoint from 'comlink/dist/esm/node-adapter.mjs';
7
7
 
8
+ /** Sentinel embedded in serialized props to mark where a function was extracted. */
9
+ const FN_MARKER = '__comlinkFnId';
8
10
  /**
9
- * Deeply walks an object tree, wraps any function values with Comlink.proxy(),
10
- * and tracks wrapped proxies for deterministic cleanup.
11
+ * Deeply walks an object tree, replaces function values with `{ [FN_MARKER]: id }` sentinels,
12
+ * and collects the original functions in a Map keyed by their assigned id.
13
+ * Returns the cleaned (function-free) tree that is safe for structured clone.
11
14
  */
12
- function wrapFunctions(obj, proxies) {
15
+ function extractFunctions(obj, fnMap, nextId) {
13
16
  if (obj === null || obj === undefined)
14
17
  return obj;
15
18
  if (typeof obj === 'function') {
16
- const wrapped = Comlink.proxy(obj);
17
- proxies.add(wrapped);
18
- return wrapped;
19
+ const id = nextId.value++;
20
+ fnMap.set(id, obj);
21
+ return { [FN_MARKER]: id };
19
22
  }
20
23
  if (typeof obj !== 'object')
21
24
  return obj;
@@ -27,11 +30,41 @@ function wrapFunctions(obj, proxies) {
27
30
  if (ArrayBuffer.isView(obj))
28
31
  return obj;
29
32
  if (Array.isArray(obj)) {
30
- return obj.map(item => wrapFunctions(item, proxies));
33
+ return obj.map(item => extractFunctions(item, fnMap, nextId));
31
34
  }
32
35
  const result = {};
33
36
  for (const key of Object.keys(obj)) {
34
- result[key] = wrapFunctions(obj[key], proxies);
37
+ result[key] = extractFunctions(obj[key], fnMap, nextId);
38
+ }
39
+ return result;
40
+ }
41
+ /**
42
+ * Deeply walks an object tree received on the worker side, replaces
43
+ * `{ [FN_MARKER]: id }` sentinels with async functions that delegate
44
+ * to the main-thread callback proxy.
45
+ */
46
+ function restoreFunctions(obj, callFn) {
47
+ if (obj === null || obj === undefined)
48
+ return obj;
49
+ if (typeof obj !== 'object')
50
+ return obj;
51
+ if (Buffer.isBuffer(obj))
52
+ return obj;
53
+ if (obj instanceof ArrayBuffer)
54
+ return obj;
55
+ if (ArrayBuffer.isView(obj))
56
+ return obj;
57
+ // Check for sentinel
58
+ if (FN_MARKER in obj) {
59
+ const id = obj[FN_MARKER];
60
+ return ((...args) => callFn(id, ...args));
61
+ }
62
+ if (Array.isArray(obj)) {
63
+ return obj.map(item => restoreFunctions(item, callFn));
64
+ }
65
+ const result = {};
66
+ for (const key of Object.keys(obj)) {
67
+ result[key] = restoreFunctions(obj[key], callFn);
35
68
  }
36
69
  return result;
37
70
  }
@@ -65,12 +98,12 @@ class ComlinkPool {
65
98
  while (this.queue.length > 0 && this.idle.length > 0) {
66
99
  const task = this.queue.shift();
67
100
  const idx = this.idle.pop();
68
- void this.executeRender(idx, task.props, task.resolve, task.reject);
101
+ void this.executeRender(idx, task.props, task.callFn, task.resolve, task.reject);
69
102
  }
70
103
  }
71
- async executeRender(idx, props, resolve, reject) {
104
+ async executeRender(idx, props, callFn, resolve, reject) {
72
105
  try {
73
- const result = await this.endpoints[idx].render(props);
106
+ const result = await this.endpoints[idx].render(props, callFn);
74
107
  resolve({ ...result, workerIdx: idx });
75
108
  }
76
109
  catch (err) {
@@ -81,13 +114,28 @@ class ComlinkPool {
81
114
  }
82
115
  }
83
116
  async render(props) {
84
- const proxies = new Set();
85
- const wrapped = wrapFunctions(props, proxies);
117
+ if (this.endpoints.length === 0) {
118
+ throw new Error('[ComlinkPool] Pool has been terminated');
119
+ }
120
+ // Extract functions from props, replacing them with serializable sentinels.
121
+ // A single Comlink.proxy() callback is created at the top level so Comlink
122
+ // can correctly transfer it via its proxy transfer handler.
123
+ const fnMap = new Map();
124
+ const cleaned = extractFunctions(props, fnMap, { value: 0 });
125
+ let callFnProxy;
126
+ if (fnMap.size > 0) {
127
+ callFnProxy = Comlink.proxy(async (id, ...args) => {
128
+ const fn = fnMap.get(id);
129
+ if (!fn)
130
+ throw new Error(`[ComlinkPool] Function #${id} not found`);
131
+ return fn(...args);
132
+ });
133
+ }
86
134
  const cleanup = () => {
87
- for (const p of proxies) {
135
+ if (callFnProxy) {
88
136
  try {
89
137
  ;
90
- p[Comlink.releaseProxy]?.();
138
+ callFnProxy[Comlink.releaseProxy]?.();
91
139
  }
92
140
  catch {
93
141
  // Proxy may already be released
@@ -98,7 +146,7 @@ class ComlinkPool {
98
146
  const idx = this.acquire();
99
147
  if (idx !== null) {
100
148
  try {
101
- const result = await this.endpoints[idx].render(wrapped);
149
+ const result = await this.endpoints[idx].render(cleaned, callFnProxy);
102
150
  return { ...result, workerIdx: idx };
103
151
  }
104
152
  finally {
@@ -109,7 +157,8 @@ class ComlinkPool {
109
157
  // Queued path — cleanup AFTER the queued task completes, not before
110
158
  return new Promise((resolve, reject) => {
111
159
  this.queue.push({
112
- props: wrapped,
160
+ props: cleaned,
161
+ callFn: callFnProxy,
113
162
  resolve: result => {
114
163
  cleanup();
115
164
  resolve(result);
@@ -136,4 +185,4 @@ class ComlinkPool {
136
185
  }
137
186
  }
138
187
 
139
- export { ComlinkPool, wrapFunctions };
188
+ export { ComlinkPool, FN_MARKER, extractFunctions, restoreFunctions };
@@ -1 +1 @@
1
- {"version":3,"file":"comlink.setup.d.ts","sourceRoot":"","sources":["../../../src/worker/comlink.setup.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAA;AAKlC,OAAO,YAAY,MAAM,mCAAmC,CAAA;AA2B5D,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAA"}
1
+ {"version":3,"file":"comlink.setup.d.ts","sourceRoot":"","sources":["../../../src/worker/comlink.setup.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAA;AAKlC,OAAO,YAAY,MAAM,mCAAmC,CAAA;AA4B5D,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAA"}
@@ -14,7 +14,7 @@ export { default as nodeEndpoint } from 'comlink/dist/esm/node-adapter.mjs';
14
14
  */
15
15
  function installNodeProxyHandler() {
16
16
  Comlink.transferHandlers.set('proxy', {
17
- canHandle: (obj) => typeof obj === 'object' && obj !== null && Comlink.proxyMarker in obj,
17
+ canHandle: (obj) => (typeof obj === 'object' || typeof obj === 'function') && obj !== null && Comlink.proxyMarker in obj,
18
18
  serialize: (obj) => {
19
19
  const { port1, port2 } = new MessageChannel();
20
20
  Comlink.expose(obj, nodeEndpoint(port1));
@@ -1,5 +1,6 @@
1
1
  import { parentPort } from 'node:worker_threads';
2
2
  import './comlink.setup.js';
3
+ import { restoreFunctions } from './comlink.pool.js';
3
4
  import { RootNode } from '../canvas/root.canvas.js';
4
5
  import * as Comlink from 'comlink';
5
6
  import nodeEndpoint from 'comlink/dist/esm/node-adapter.mjs';
@@ -10,8 +11,9 @@ if (!parentPort) {
10
11
  const canvases = new Map();
11
12
  let nextCanvasId = 0;
12
13
  const api = {
13
- async render(props) {
14
- const canvas = await new RootNode(props).render();
14
+ async render(props, callFn) {
15
+ const resolved = callFn ? restoreFunctions(props, callFn) : props;
16
+ const canvas = await new RootNode(resolved).render();
15
17
  const canvasId = nextCanvasId++;
16
18
  canvases.set(canvasId, canvas);
17
19
  const result = {
@@ -1,4 +1,5 @@
1
1
  import type { RootProps } from '../canvas/canvas.type.js';
2
+ export type CallFn = (id: number, ...args: unknown[]) => Promise<unknown>;
2
3
  export interface RenderResult {
3
4
  canvasId: number;
4
5
  buffer: Buffer;
@@ -6,7 +7,7 @@ export interface RenderResult {
6
7
  height: number;
7
8
  }
8
9
  export interface WorkerAPI {
9
- render(props: RootProps): Promise<RenderResult>;
10
+ render(props: RootProps, callFn?: CallFn): Promise<RenderResult>;
10
11
  callOnCanvas(canvasId: number, method: string, args: unknown[]): Promise<Buffer | string | void>;
11
12
  releaseCanvas(canvasId: number): void;
12
13
  }
@@ -1 +1 @@
1
- {"version":3,"file":"worker.types.d.ts","sourceRoot":"","sources":["../../../src/worker/worker.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAExD,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IAC/C,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,CAAA;IAChG,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACtC"}
1
+ {"version":3,"file":"worker.types.d.ts","sourceRoot":"","sources":["../../../src/worker/worker.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAExD,MAAM,MAAM,MAAM,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAEzE,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IAChE,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC,CAAA;IAChG,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACtC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meonode/canvas",
3
- "version": "2.0.4",
3
+ "version": "3.0.0",
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",
@@ -37,9 +37,10 @@
37
37
  }
38
38
  },
39
39
  "scripts": {
40
- "build": "rm -rf ./dist && rollup -c --bundleConfigAsCjs && tsc-alias -p tsconfig.esm.json && tsc-alias -p tsconfig.cjs.json",
41
- "test": "node --no-experimental-webstorage --experimental-vm-modules $(yarn bin jest)",
42
- "lint": "eslint . --ext .ts,.tsx,.js,.jsx,.mjs --fix",
40
+ "build": "bun -e \"fs.rmSync('./dist', {recursive:true, force:true})\" && rollup -c --bundleConfigAsCjs && bun scripts/rewrite-dts-aliases.ts",
41
+ "test": "vitest run --coverage",
42
+ "typecheck": "tsc --noEmit",
43
+ "lint": "eslint . --ext .ts,.tsx,.js,.jsx,.mjs --fix && bun run typecheck",
43
44
  "format": "prettier --write .",
44
45
  "generate:samples": "npx tsx scripts/generate_sample_charts.ts && npx tsx scripts/generate_sample_grids.ts && npx tsx scripts/generate_sample_nested_grids.ts",
45
46
  "check:memory": "npx tsx --expose-gc scripts/check_memory.ts",
@@ -47,7 +48,6 @@
47
48
  },
48
49
  "devDependencies": {
49
50
  "@eslint/js": "^9.39.4",
50
- "@jest/globals": "^30.3.0",
51
51
  "@rollup/plugin-commonjs": "^29.0.2",
52
52
  "@rollup/plugin-node-resolve": "^16.0.3",
53
53
  "@rollup/plugin-typescript": "^12.3.0",
@@ -56,37 +56,30 @@
56
56
  "@semantic-release/gitlab": "^13.3.2",
57
57
  "@semantic-release/npm": "^13.1.5",
58
58
  "@semantic-release/release-notes-generator": "^14.1.0",
59
- "@types/jest": "^30.0.0",
60
- "@types/lodash-es": "^4.17.12",
61
59
  "@types/node": "^25.5.0",
62
60
  "@types/sharp": "^0.32.0",
63
- "@types/tinycolor2": "^1.4.6",
64
61
  "@typescript-eslint/eslint-plugin": "^8.57.2",
65
62
  "@typescript-eslint/parser": "^8.57.2",
63
+ "@vitest/coverage-v8": "^3.2.4",
66
64
  "eslint": "^9.39.4",
67
65
  "eslint-config-prettier": "^10.1.8",
68
66
  "eslint-plugin-jsdoc": "^62.8.1",
69
67
  "eslint-plugin-prettier": "^5.5.5",
70
68
  "eslint-plugin-unused-imports": "^4.4.1",
71
69
  "husky": "^9.1.7",
72
- "jest": "^30.3.0",
73
70
  "prettier": "^3.8.1",
74
71
  "rollup": "^4.60.0",
75
72
  "rollup-plugin-tsconfig-paths": "^1.5.2",
76
- "semantic-release": "^25.0.3",
77
- "ts-jest": "^29.4.6",
78
- "tsc-alias": "^1.8.16",
73
+ "semantic-release": "24.2.9",
79
74
  "typescript": "^6.0.2",
80
- "typescript-eslint": "^8.57.2"
75
+ "typescript-eslint": "^8.57.2",
76
+ "vitest": "^3.2.4"
81
77
  },
82
- "packageManager": "yarn@4.11.0",
83
78
  "dependencies": {
84
79
  "comlink": "^4.4.2",
85
80
  "file-type": "^22.0.0",
86
- "lodash-es": "^4.17.23",
87
81
  "sharp": "^0.34.5",
88
82
  "skia-canvas": "^3.0.8",
89
- "tinycolor2": "^1.6.0",
90
83
  "tslib": "^2.8.1",
91
84
  "yoga-layout": "^3.2.1"
92
85
  },