@meonode/canvas 3.0.0 → 3.0.1

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/CONTRIBUTING.md CHANGED
@@ -35,6 +35,8 @@ At this point, you're ready to make your changes! Feel free to ask for help; eve
35
35
  bun run test
36
36
  ```
37
37
 
38
+ > **Note:** Use `bun run test` (Vitest), not bare `bun test`. The Bun test runner does not load Vitest globals (`describe`, `vi`, etc.).
39
+
38
40
  4. Build the project to generate the distribution files:
39
41
  ```sh
40
42
  bun run build
@@ -1 +1 @@
1
- {"version":3,"file":"grid.canvas.d.ts","sourceRoot":"","sources":["../../../src/canvas/grid.canvas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAiB,aAAa,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACrG,OAAO,EAAE,OAAO,EAA+B,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAIzF;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,OAAO;gBAC3B,KAAK,EAAE,aAAa;CAMjC;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,uBAAuB,aAAa,KAAG,aAI9D,CAAA;AAEF;;;GAGG;AACH,qBAAa,QAAS,SAAQ,OAAO;IACnC;;;OAGG;gBACS,KAAK,EAAE,SAAS;IAQ5B;;OAEG;IACH,OAAO,CAAC,UAAU;IAwBlB;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;OAEG;cACgB,+BAA+B;IAoTlD;;OAEG;IACH,OAAO,CAAC,aAAa;CAkCtB;AAED;;GAEG;AACH,eAAO,MAAM,IAAI,GAAI,uBAAuB,SAAS,KAAG,aAItD,CAAA"}
1
+ {"version":3,"file":"grid.canvas.d.ts","sourceRoot":"","sources":["../../../src/canvas/grid.canvas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAiB,aAAa,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACrG,OAAO,EAAE,OAAO,EAA+B,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAIzF;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,OAAO;gBAC3B,KAAK,EAAE,aAAa;CAMjC;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,uBAAuB,aAAa,KAAG,aAI9D,CAAA;AAEF;;;GAGG;AACH,qBAAa,QAAS,SAAQ,OAAO;IACnC;;;OAGG;gBACS,KAAK,EAAE,SAAS;IAQ5B;;OAEG;IACH,OAAO,CAAC,UAAU;IAwBlB;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;OAEG;cACgB,+BAA+B;IAkTlD;;OAEG;IACH,OAAO,CAAC,aAAa;CAkCtB;AAED;;GAEG;AACH,eAAO,MAAM,IAAI,GAAI,uBAAuB,SAAS,KAAG,aAItD,CAAA"}
@@ -182,7 +182,6 @@ class GridNode extends layout_canvas.RowNode {
182
182
  if (parts[1].startsWith('span')) {
183
183
  const span = parseInt(parts[1].replace('span', '')) || 1;
184
184
  if (colStart !== undefined) {
185
- colEnd = colStart + span;
186
185
  colSpan = span;
187
186
  }
188
187
  else {
@@ -212,7 +211,6 @@ class GridNode extends layout_canvas.RowNode {
212
211
  if (parts[1].startsWith('span')) {
213
212
  const span = parseInt(parts[1].replace('span', '')) || 1;
214
213
  if (rowStart !== undefined) {
215
- rowEnd = rowStart + span;
216
214
  rowSpan = span;
217
215
  }
218
216
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"grid.canvas.js","sources":["../../../../src/canvas/grid.canvas.ts"],"sourcesContent":["import type { GridProps, GridTrackSize, GridItemProps, CanvasElement } from '@/canvas/canvas.type.js'\nimport { BoxNode, normalizeDescriptorChildren, RowNode } from '@/canvas/layout.canvas.js'\nimport { Style } from '@/constant/common.const.js'\nimport { parsePercentage } from '@/canvas/canvas.helper.js'\n\n/**\n * GridItem Node. Theoretically just a BoxNode but typed differently in factory.\n * In runtime, it behaves almost like a BoxNode, but we can detect it if needed,\n * or simply rely on the props being present in the instance.\n */\nexport class GridItemNode extends BoxNode {\n constructor(props: GridItemProps) {\n super({\n ...props,\n name: 'GridItem',\n })\n }\n}\n\n/**\n * Factory for GridItem.\n */\nexport const GridItem = ({ children, ...rest }: GridItemProps): CanvasElement => ({\n __type: 'GridItem',\n props: rest,\n children: normalizeDescriptorChildren(children),\n})\n\n/**\n * Grid layout node that arranges children in a 2D grid.\n * Implements a simplified version of the CSS Grid Layout algorithm.\n */\nexport class GridNode extends RowNode {\n /**\n * Creates a new grid layout node\n * @param props Grid configuration properties\n */\n constructor(props: GridProps) {\n super({\n ...props,\n name: props.name || 'Grid',\n flexWrap: Style.Wrap.Wrap,\n })\n }\n\n /**\n * Helper to parse a track size definition.\n */\n private parseTrack(track: GridTrackSize, availableSpace: number): { type: 'px' | '%' | 'fr' | 'auto'; value: number } {\n if (typeof track === 'number') {\n return { type: 'px', value: track }\n }\n if (track === 'auto') {\n return { type: 'auto', value: 0 }\n }\n if (typeof track === 'string') {\n if (track.endsWith('fr')) {\n return { type: 'fr', value: parseFloat(track) }\n }\n if (track.endsWith('%')) {\n return { type: '%', value: parsePercentage(track, availableSpace) }\n }\n if (track.endsWith('px')) {\n return { type: 'px', value: parseFloat(track) }\n }\n // Try parsing as number (px) if just string \"100\"\n const num = parseFloat(track)\n if (!isNaN(num)) return { type: 'px', value: num }\n }\n return { type: 'auto', value: 0 }\n }\n\n /**\n * Parses the gap property into pixels.\n */\n private getGapPixels(gap: GridProps['gap'], width: number, height: number) {\n let rowGap = 0\n let colGap = 0\n\n if (typeof gap === 'number') {\n rowGap = colGap = gap\n } else if (typeof gap === 'string') {\n const val = parsePercentage(gap, width) // Use width as base for simplicity if %\n rowGap = colGap = val\n } else if (gap && typeof gap === 'object') {\n const colVal = gap.Column ?? gap.All ?? 0\n const rowVal = gap.Row ?? gap.All ?? 0\n colGap = parsePercentage(colVal as string | number, width)\n rowGap = parsePercentage(rowVal as string | number, height)\n }\n\n return { rowGap, colGap }\n }\n\n /**\n * Update layout calculations after the initial layout is computed.\n */\n protected override updateLayoutBasedOnComputedSize() {\n // 1. Get Container Dimensions\n let width = this.node.getComputedWidth()\n const parent = this.node.getParent()\n\n if (parent) {\n const parentWidth = parent.getWidth()\n const parentMinWidth = parent.getMinWidth()\n const parentMaxWidth = parent.getMaxWidth()\n\n // Parent has % minWidth but no hard width/maxWidth constraint\n const hasPercentMinWidth = parentMinWidth.unit === Style.Unit.Percent\n const hasExplicitWidth = parentWidth.unit !== Style.Unit.Undefined && parentWidth.unit !== Style.Unit.Auto\n const hasMaxWidth = parentMaxWidth.unit !== Style.Unit.Undefined && parentMaxWidth.unit !== Style.Unit.Auto\n\n if (hasPercentMinWidth && !hasExplicitWidth && !hasMaxWidth) {\n const grandparent = parent.getParent()\n if (grandparent) {\n const intendedWidth = (parentMinWidth.value / 100) * grandparent.getComputedWidth()\n\n // Check if parent has flexGrow - if so, don't constrain\n const parentFlexGrow = parent.getFlexGrow()\n if (parentFlexGrow > 0) {\n // Allow expansion - use computed width\n } else {\n // No flexGrow - constrain to minWidth\n width = Math.min(width, intendedWidth)\n }\n }\n }\n }\n\n const paddingLeft = this.node.getComputedPadding(Style.Edge.Left)\n const paddingRight = this.node.getComputedPadding(Style.Edge.Right)\n const paddingTop = this.node.getComputedPadding(Style.Edge.Top)\n const paddingBottom = this.node.getComputedPadding(Style.Edge.Bottom)\n\n const contentWidth = Math.max(0, width - paddingLeft - paddingRight)\n const computedHeight = this.node.getComputedHeight()\n const contentHeight = Math.max(0, computedHeight - paddingTop - paddingBottom)\n\n const { templateColumns, templateRows, autoRows = 'auto', gap, columns } = this.props as GridProps\n\n // 2. Resolve Gaps\n const { rowGap, colGap } = this.getGapPixels(gap, contentWidth, contentHeight)\n\n // 3. Resolve Columns (Tracks)\n let explicitColTracks: GridTrackSize[] = templateColumns || []\n if (explicitColTracks.length === 0 && columns) {\n explicitColTracks = Array(columns).fill('1fr')\n }\n if (explicitColTracks.length === 0) explicitColTracks = ['1fr']\n\n const resolvedColTracks = this.resolveTracks(explicitColTracks, contentWidth, colGap)\n\n // Pre-calculate Col Offsets needed for placement/width\n const colOffsetsValues = [0]\n for (let i = 0; i < resolvedColTracks.length; i++) {\n colOffsetsValues.push(colOffsetsValues[i] + resolvedColTracks[i] + colGap)\n }\n\n // 4. Place Items & Resolve Explicit Row Tracks\n const explicitRowTracks = templateRows || []\n const resolvedExplicitRowTracks = this.resolveTracks(explicitRowTracks, contentHeight, rowGap)\n\n const cells: boolean[][] = [] // true if occupied\n const items: { node: BoxNode; rowStart: number; rowEnd: number; colStart: number; colEnd: number }[] = []\n\n const isOccupied = (r: number, c: number) => {\n if (!cells[r]) return false\n return cells[r][c] === true\n }\n const setOccupied = (r: number, c: number) => {\n if (!cells[r]) cells[r] = []\n cells[r][c] = true\n }\n\n let cursorRow = 0\n let cursorCol = 0\n\n for (const child of this.children) {\n const childProps = child.props as GridItemProps\n const { gridColumn, gridRow } = childProps\n\n let colStart: number | undefined\n let colEnd: number | undefined\n let colSpan = 1\n let rowStart: number | undefined\n let rowEnd: number | undefined\n let rowSpan = 1\n\n // ... Grid Placement Logic ...\n if (gridColumn) {\n const parts = gridColumn.split('/').map(s => s.trim())\n if (parts[0]) {\n if (parts[0].startsWith('span')) {\n colSpan = parseInt(parts[0].replace('span', '')) || 1\n } else {\n colStart = parseInt(parts[0]) - 1\n }\n }\n if (parts[1]) {\n if (parts[1].startsWith('span')) {\n const span = parseInt(parts[1].replace('span', '')) || 1\n if (colStart !== undefined) {\n colEnd = colStart + span\n colSpan = span\n } else {\n // If start is undefined but end is span? Unusual. Treat as span.\n colSpan = span\n }\n } else {\n colEnd = parseInt(parts[1]) - 1\n if (colStart !== undefined) {\n colSpan = colEnd - colStart\n }\n }\n }\n }\n\n if (gridRow) {\n const parts = gridRow.split('/').map(s => s.trim())\n if (parts[0]) {\n if (parts[0].startsWith('span')) {\n rowSpan = parseInt(parts[0].replace('span', '')) || 1\n } else {\n rowStart = parseInt(parts[0]) - 1\n }\n }\n if (parts[1]) {\n if (parts[1].startsWith('span')) {\n const span = parseInt(parts[1].replace('span', '')) || 1\n if (rowStart !== undefined) {\n rowEnd = rowStart + span\n rowSpan = span\n } else {\n rowSpan = span\n }\n } else {\n rowEnd = parseInt(parts[1]) - 1\n if (rowStart !== undefined) {\n rowSpan = rowEnd - rowStart\n }\n }\n }\n }\n\n if (colStart !== undefined && rowStart !== undefined) {\n // Fixed position: Check overlap in simpler V1? Or just place?\n // Just place.\n } else {\n // Auto placement\n let placed = false\n while (!placed) {\n if (!cells[cursorRow]) cells[cursorRow] = []\n\n if (colStart !== undefined) cursorCol = colStart\n\n let fits = true\n for (let r = 0; r < rowSpan; r++) {\n for (let c = 0; c < colSpan; c++) {\n if (isOccupied(cursorRow + r, cursorCol + c)) {\n fits = false\n break\n }\n }\n if (!fits) break\n }\n\n if (fits) {\n rowStart = cursorRow\n colStart = cursorCol\n placed = true\n } else {\n cursorCol++\n if (cursorCol + colSpan > resolvedColTracks.length) {\n cursorCol = 0\n cursorRow++\n }\n }\n }\n cursorCol += colSpan\n if (cursorCol >= resolvedColTracks.length) {\n cursorCol = 0\n cursorRow++\n }\n }\n\n rowEnd = (rowStart ?? 0) + rowSpan\n colEnd = (colStart ?? 0) + colSpan\n\n for (let r = rowStart!; r < rowEnd!; r++) {\n for (let c = colStart!; c < colEnd!; c++) {\n setOccupied(r, c)\n }\n }\n\n // CRITICAL FIX: Pre-set width on item to ensure height calculation is accurate later\n const itemColStart = colStart!\n const itemColEnd = colEnd!\n\n // Extend local offsets if needed for spanned columns beyond track count (rare but safe)\n while (colOffsetsValues.length <= itemColEnd) {\n colOffsetsValues.push(colOffsetsValues[colOffsetsValues.length - 1] + 0 + colGap)\n }\n\n const cs = Math.min(itemColStart, colOffsetsValues.length - 1)\n const ce = Math.min(itemColEnd, colOffsetsValues.length - 1)\n const targetWidth = Math.max(0, colOffsetsValues[ce] - colOffsetsValues[cs] - colGap)\n\n child.node.setWidth(targetWidth)\n child.node.calculateLayout(targetWidth, Number.NaN, Style.Direction.LTR)\n\n // Recursively finalize nested children (e.g. inner Grids) so their\n // computed heights are accurate before we measure row sizes.\n child.finalizeLayout()\n if (child.node.isDirty()) {\n child.node.calculateLayout(targetWidth, Number.NaN, Style.Direction.LTR)\n }\n\n items.push({ node: child, rowStart: rowStart!, rowEnd: rowEnd!, colStart: itemColStart, colEnd: itemColEnd })\n }\n\n // 6. Finalize Rows (Implicit)\n const totalRowsNeeded = Math.max(resolvedExplicitRowTracks.length, ...items.map(i => i.rowEnd))\n const resolvedRowTracks = [...resolvedExplicitRowTracks]\n\n // Fill implicit rows\n for (let r = resolvedExplicitRowTracks.length; r < totalRowsNeeded; r++) {\n let rowSize = 0\n\n // Better 'auto' handling:\n if (autoRows === 'auto') {\n const rowItems = items.filter(i => i.rowStart === r && i.rowEnd - i.rowStart === 1)\n for (const item of rowItems) {\n rowSize = Math.max(rowSize, item.node.node.getComputedHeight())\n }\n } else {\n const parsed = this.parseTrack(autoRows, contentHeight)\n rowSize = parsed.value\n }\n resolvedRowTracks.push(rowSize)\n }\n\n // 6. Calculate Offsets (Rows) & Final Layout Application\n const colOffsets = colOffsetsValues // Re-use\n const rowOffsets = [0]\n for (let i = 0; i < resolvedRowTracks.length; i++) {\n let size = resolvedRowTracks[i]\n // Re-check auto-sized explicit rows (value 0)\n if (size === 0) {\n const rowItems = items.filter(it => it.rowStart === i && it.rowEnd - it.rowStart === 1)\n for (const item of rowItems) {\n size = Math.max(size, item.node.node.getComputedHeight())\n }\n resolvedRowTracks[i] = size\n }\n rowOffsets.push(rowOffsets[i] + size + rowGap)\n }\n\n // 7. Apply Positions\n for (const item of items) {\n const x = colOffsets[item.colStart] + paddingLeft\n\n while (colOffsets.length <= item.colEnd) {\n colOffsets.push(colOffsets[colOffsets.length - 1] + 0 + colGap)\n }\n\n const widthStart = colOffsets[item.colStart]\n const widthEnd = colOffsets[item.colEnd]\n const totalWidth = Math.max(0, widthEnd - widthStart - colGap)\n\n const y = rowOffsets[item.rowStart] + paddingTop\n\n const heightStart = rowOffsets[item.rowStart]\n const heightEnd = rowOffsets[item.rowEnd]\n const totalHeight = Math.max(0, heightEnd - heightStart - rowGap)\n\n const childNode = item.node.node\n\n if (childNode.getPositionType() !== Style.PositionType.Absolute) {\n childNode.setPositionType(Style.PositionType.Absolute)\n }\n\n if (childNode.getPosition(Style.Edge.Left).value !== x) {\n childNode.setPosition(Style.Edge.Left, x)\n }\n if (childNode.getPosition(Style.Edge.Top).value !== y) {\n childNode.setPosition(Style.Edge.Top, y)\n }\n\n if (childNode.getWidth().unit !== Style.Unit.Point || Math.abs(childNode.getWidth().value - totalWidth) > 0.1) {\n childNode.setWidth(totalWidth)\n }\n if (childNode.getHeight().unit !== Style.Unit.Point || Math.abs(childNode.getHeight().value - totalHeight) > 0.1) {\n childNode.setHeight(totalHeight)\n }\n }\n\n // 9. Update Grid Height\n const totalGridHeight = Math.max(0, rowOffsets[rowOffsets.length - 1] - rowGap)\n const currentHeightStyle = this.node.getHeight()\n if (currentHeightStyle.unit === Style.Unit.Auto || currentHeightStyle.unit === Style.Unit.Undefined) {\n const targetTotalHeight = totalGridHeight + paddingTop + paddingBottom\n this.node.setHeight(targetTotalHeight)\n }\n }\n\n /**\n * Resolves track sizes to pixels.\n */\n private resolveTracks(tracks: GridTrackSize[], availableSpace: number, gap: number): number[] {\n const resolved: number[] = []\n let usedSpace = 0\n let totalFr = 0\n const frIndices: number[] = []\n\n tracks.forEach((t, i) => {\n const parsed = this.parseTrack(t, availableSpace)\n if (parsed.type === 'px' || parsed.type === '%') {\n resolved[i] = parsed.value\n usedSpace += parsed.value\n } else if (parsed.type === 'fr') {\n totalFr += parsed.value\n resolved[i] = 0\n frIndices.push(i)\n } else {\n resolved[i] = 0\n }\n })\n\n const totalGaps = Math.max(0, tracks.length - 1) * gap\n usedSpace += totalGaps\n\n const remainingSpace = Math.max(0, availableSpace - usedSpace)\n if (totalFr > 0) {\n frIndices.forEach(i => {\n const parsed = this.parseTrack(tracks[i], availableSpace)\n const share = (parsed.value / totalFr) * remainingSpace\n resolved[i] = share\n })\n }\n\n return resolved\n }\n}\n\n/**\n * Factory function to create a new GridNode instance.\n */\nexport const Grid = ({ children, ...rest }: GridProps): CanvasElement => ({\n __type: 'Grid',\n props: rest,\n children: normalizeDescriptorChildren(children),\n})\n"],"names":["BoxNode","normalizeDescriptorChildren","RowNode","Style","parsePercentage"],"mappings":"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"}
1
+ {"version":3,"file":"grid.canvas.js","sources":["../../../../src/canvas/grid.canvas.ts"],"sourcesContent":["import type { GridProps, GridTrackSize, GridItemProps, CanvasElement } from '@/canvas/canvas.type.js'\nimport { BoxNode, normalizeDescriptorChildren, RowNode } from '@/canvas/layout.canvas.js'\nimport { Style } from '@/constant/common.const.js'\nimport { parsePercentage } from '@/canvas/canvas.helper.js'\n\n/**\n * GridItem Node. Theoretically just a BoxNode but typed differently in factory.\n * In runtime, it behaves almost like a BoxNode, but we can detect it if needed,\n * or simply rely on the props being present in the instance.\n */\nexport class GridItemNode extends BoxNode {\n constructor(props: GridItemProps) {\n super({\n ...props,\n name: 'GridItem',\n })\n }\n}\n\n/**\n * Factory for GridItem.\n */\nexport const GridItem = ({ children, ...rest }: GridItemProps): CanvasElement => ({\n __type: 'GridItem',\n props: rest,\n children: normalizeDescriptorChildren(children),\n})\n\n/**\n * Grid layout node that arranges children in a 2D grid.\n * Implements a simplified version of the CSS Grid Layout algorithm.\n */\nexport class GridNode extends RowNode {\n /**\n * Creates a new grid layout node\n * @param props Grid configuration properties\n */\n constructor(props: GridProps) {\n super({\n ...props,\n name: props.name || 'Grid',\n flexWrap: Style.Wrap.Wrap,\n })\n }\n\n /**\n * Helper to parse a track size definition.\n */\n private parseTrack(track: GridTrackSize, availableSpace: number): { type: 'px' | '%' | 'fr' | 'auto'; value: number } {\n if (typeof track === 'number') {\n return { type: 'px', value: track }\n }\n if (track === 'auto') {\n return { type: 'auto', value: 0 }\n }\n if (typeof track === 'string') {\n if (track.endsWith('fr')) {\n return { type: 'fr', value: parseFloat(track) }\n }\n if (track.endsWith('%')) {\n return { type: '%', value: parsePercentage(track, availableSpace) }\n }\n if (track.endsWith('px')) {\n return { type: 'px', value: parseFloat(track) }\n }\n // Try parsing as number (px) if just string \"100\"\n const num = parseFloat(track)\n if (!isNaN(num)) return { type: 'px', value: num }\n }\n return { type: 'auto', value: 0 }\n }\n\n /**\n * Parses the gap property into pixels.\n */\n private getGapPixels(gap: GridProps['gap'], width: number, height: number) {\n let rowGap = 0\n let colGap = 0\n\n if (typeof gap === 'number') {\n rowGap = colGap = gap\n } else if (typeof gap === 'string') {\n const val = parsePercentage(gap, width) // Use width as base for simplicity if %\n rowGap = colGap = val\n } else if (gap && typeof gap === 'object') {\n const colVal = gap.Column ?? gap.All ?? 0\n const rowVal = gap.Row ?? gap.All ?? 0\n colGap = parsePercentage(colVal as string | number, width)\n rowGap = parsePercentage(rowVal as string | number, height)\n }\n\n return { rowGap, colGap }\n }\n\n /**\n * Update layout calculations after the initial layout is computed.\n */\n protected override updateLayoutBasedOnComputedSize() {\n // 1. Get Container Dimensions\n let width = this.node.getComputedWidth()\n const parent = this.node.getParent()\n\n if (parent) {\n const parentWidth = parent.getWidth()\n const parentMinWidth = parent.getMinWidth()\n const parentMaxWidth = parent.getMaxWidth()\n\n // Parent has % minWidth but no hard width/maxWidth constraint\n const hasPercentMinWidth = parentMinWidth.unit === Style.Unit.Percent\n const hasExplicitWidth = parentWidth.unit !== Style.Unit.Undefined && parentWidth.unit !== Style.Unit.Auto\n const hasMaxWidth = parentMaxWidth.unit !== Style.Unit.Undefined && parentMaxWidth.unit !== Style.Unit.Auto\n\n if (hasPercentMinWidth && !hasExplicitWidth && !hasMaxWidth) {\n const grandparent = parent.getParent()\n if (grandparent) {\n const intendedWidth = (parentMinWidth.value / 100) * grandparent.getComputedWidth()\n\n // Check if parent has flexGrow - if so, don't constrain\n const parentFlexGrow = parent.getFlexGrow()\n if (parentFlexGrow > 0) {\n // Allow expansion - use computed width\n } else {\n // No flexGrow - constrain to minWidth\n width = Math.min(width, intendedWidth)\n }\n }\n }\n }\n\n const paddingLeft = this.node.getComputedPadding(Style.Edge.Left)\n const paddingRight = this.node.getComputedPadding(Style.Edge.Right)\n const paddingTop = this.node.getComputedPadding(Style.Edge.Top)\n const paddingBottom = this.node.getComputedPadding(Style.Edge.Bottom)\n\n const contentWidth = Math.max(0, width - paddingLeft - paddingRight)\n const computedHeight = this.node.getComputedHeight()\n const contentHeight = Math.max(0, computedHeight - paddingTop - paddingBottom)\n\n const { templateColumns, templateRows, autoRows = 'auto', gap, columns } = this.props as GridProps\n\n // 2. Resolve Gaps\n const { rowGap, colGap } = this.getGapPixels(gap, contentWidth, contentHeight)\n\n // 3. Resolve Columns (Tracks)\n let explicitColTracks: GridTrackSize[] = templateColumns || []\n if (explicitColTracks.length === 0 && columns) {\n explicitColTracks = Array(columns).fill('1fr')\n }\n if (explicitColTracks.length === 0) explicitColTracks = ['1fr']\n\n const resolvedColTracks = this.resolveTracks(explicitColTracks, contentWidth, colGap)\n\n // Pre-calculate Col Offsets needed for placement/width\n const colOffsetsValues = [0]\n for (let i = 0; i < resolvedColTracks.length; i++) {\n colOffsetsValues.push(colOffsetsValues[i] + resolvedColTracks[i] + colGap)\n }\n\n // 4. Place Items & Resolve Explicit Row Tracks\n const explicitRowTracks = templateRows || []\n const resolvedExplicitRowTracks = this.resolveTracks(explicitRowTracks, contentHeight, rowGap)\n\n const cells: boolean[][] = [] // true if occupied\n const items: { node: BoxNode; rowStart: number; rowEnd: number; colStart: number; colEnd: number }[] = []\n\n const isOccupied = (r: number, c: number) => {\n if (!cells[r]) return false\n return cells[r][c] === true\n }\n const setOccupied = (r: number, c: number) => {\n if (!cells[r]) cells[r] = []\n cells[r][c] = true\n }\n\n let cursorRow = 0\n let cursorCol = 0\n\n for (const child of this.children) {\n const childProps = child.props as GridItemProps\n const { gridColumn, gridRow } = childProps\n\n let colStart: number | undefined\n let colEnd: number | undefined\n let colSpan = 1\n let rowStart: number | undefined\n let rowEnd: number | undefined\n let rowSpan = 1\n\n // ... Grid Placement Logic ...\n if (gridColumn) {\n const parts = gridColumn.split('/').map(s => s.trim())\n if (parts[0]) {\n if (parts[0].startsWith('span')) {\n colSpan = parseInt(parts[0].replace('span', '')) || 1\n } else {\n colStart = parseInt(parts[0]) - 1\n }\n }\n if (parts[1]) {\n if (parts[1].startsWith('span')) {\n const span = parseInt(parts[1].replace('span', '')) || 1\n if (colStart !== undefined) {\n colSpan = span\n } else {\n // If start is undefined but end is span? Unusual. Treat as span.\n colSpan = span\n }\n } else {\n colEnd = parseInt(parts[1]) - 1\n if (colStart !== undefined) {\n colSpan = colEnd - colStart\n }\n }\n }\n }\n\n if (gridRow) {\n const parts = gridRow.split('/').map(s => s.trim())\n if (parts[0]) {\n if (parts[0].startsWith('span')) {\n rowSpan = parseInt(parts[0].replace('span', '')) || 1\n } else {\n rowStart = parseInt(parts[0]) - 1\n }\n }\n if (parts[1]) {\n if (parts[1].startsWith('span')) {\n const span = parseInt(parts[1].replace('span', '')) || 1\n if (rowStart !== undefined) {\n rowSpan = span\n } else {\n rowSpan = span\n }\n } else {\n rowEnd = parseInt(parts[1]) - 1\n if (rowStart !== undefined) {\n rowSpan = rowEnd - rowStart\n }\n }\n }\n }\n\n if (colStart !== undefined && rowStart !== undefined) {\n // Fixed position: Check overlap in simpler V1? Or just place?\n // Just place.\n } else {\n // Auto placement\n let placed = false\n while (!placed) {\n if (!cells[cursorRow]) cells[cursorRow] = []\n\n if (colStart !== undefined) cursorCol = colStart\n\n let fits = true\n for (let r = 0; r < rowSpan; r++) {\n for (let c = 0; c < colSpan; c++) {\n if (isOccupied(cursorRow + r, cursorCol + c)) {\n fits = false\n break\n }\n }\n if (!fits) break\n }\n\n if (fits) {\n rowStart = cursorRow\n colStart = cursorCol\n placed = true\n } else {\n cursorCol++\n if (cursorCol + colSpan > resolvedColTracks.length) {\n cursorCol = 0\n cursorRow++\n }\n }\n }\n cursorCol += colSpan\n if (cursorCol >= resolvedColTracks.length) {\n cursorCol = 0\n cursorRow++\n }\n }\n\n rowEnd = (rowStart ?? 0) + rowSpan\n colEnd = (colStart ?? 0) + colSpan\n\n for (let r = rowStart!; r < rowEnd!; r++) {\n for (let c = colStart!; c < colEnd!; c++) {\n setOccupied(r, c)\n }\n }\n\n // CRITICAL FIX: Pre-set width on item to ensure height calculation is accurate later\n const itemColStart = colStart!\n const itemColEnd = colEnd!\n\n // Extend local offsets if needed for spanned columns beyond track count (rare but safe)\n while (colOffsetsValues.length <= itemColEnd) {\n colOffsetsValues.push(colOffsetsValues[colOffsetsValues.length - 1] + 0 + colGap)\n }\n\n const cs = Math.min(itemColStart, colOffsetsValues.length - 1)\n const ce = Math.min(itemColEnd, colOffsetsValues.length - 1)\n const targetWidth = Math.max(0, colOffsetsValues[ce] - colOffsetsValues[cs] - colGap)\n\n child.node.setWidth(targetWidth)\n child.node.calculateLayout(targetWidth, Number.NaN, Style.Direction.LTR)\n\n // Recursively finalize nested children (e.g. inner Grids) so their\n // computed heights are accurate before we measure row sizes.\n child.finalizeLayout()\n if (child.node.isDirty()) {\n child.node.calculateLayout(targetWidth, Number.NaN, Style.Direction.LTR)\n }\n\n items.push({ node: child, rowStart: rowStart!, rowEnd: rowEnd!, colStart: itemColStart, colEnd: itemColEnd })\n }\n\n // 6. Finalize Rows (Implicit)\n const totalRowsNeeded = Math.max(resolvedExplicitRowTracks.length, ...items.map(i => i.rowEnd))\n const resolvedRowTracks = [...resolvedExplicitRowTracks]\n\n // Fill implicit rows\n for (let r = resolvedExplicitRowTracks.length; r < totalRowsNeeded; r++) {\n let rowSize = 0\n\n // Better 'auto' handling:\n if (autoRows === 'auto') {\n const rowItems = items.filter(i => i.rowStart === r && i.rowEnd - i.rowStart === 1)\n for (const item of rowItems) {\n rowSize = Math.max(rowSize, item.node.node.getComputedHeight())\n }\n } else {\n const parsed = this.parseTrack(autoRows, contentHeight)\n rowSize = parsed.value\n }\n resolvedRowTracks.push(rowSize)\n }\n\n // 6. Calculate Offsets (Rows) & Final Layout Application\n const colOffsets = colOffsetsValues // Re-use\n const rowOffsets = [0]\n for (let i = 0; i < resolvedRowTracks.length; i++) {\n let size = resolvedRowTracks[i]\n // Re-check auto-sized explicit rows (value 0)\n if (size === 0) {\n const rowItems = items.filter(it => it.rowStart === i && it.rowEnd - it.rowStart === 1)\n for (const item of rowItems) {\n size = Math.max(size, item.node.node.getComputedHeight())\n }\n resolvedRowTracks[i] = size\n }\n rowOffsets.push(rowOffsets[i] + size + rowGap)\n }\n\n // 7. Apply Positions\n for (const item of items) {\n const x = colOffsets[item.colStart] + paddingLeft\n\n while (colOffsets.length <= item.colEnd) {\n colOffsets.push(colOffsets[colOffsets.length - 1] + 0 + colGap)\n }\n\n const widthStart = colOffsets[item.colStart]\n const widthEnd = colOffsets[item.colEnd]\n const totalWidth = Math.max(0, widthEnd - widthStart - colGap)\n\n const y = rowOffsets[item.rowStart] + paddingTop\n\n const heightStart = rowOffsets[item.rowStart]\n const heightEnd = rowOffsets[item.rowEnd]\n const totalHeight = Math.max(0, heightEnd - heightStart - rowGap)\n\n const childNode = item.node.node\n\n if (childNode.getPositionType() !== Style.PositionType.Absolute) {\n childNode.setPositionType(Style.PositionType.Absolute)\n }\n\n if (childNode.getPosition(Style.Edge.Left).value !== x) {\n childNode.setPosition(Style.Edge.Left, x)\n }\n if (childNode.getPosition(Style.Edge.Top).value !== y) {\n childNode.setPosition(Style.Edge.Top, y)\n }\n\n if (childNode.getWidth().unit !== Style.Unit.Point || Math.abs(childNode.getWidth().value - totalWidth) > 0.1) {\n childNode.setWidth(totalWidth)\n }\n if (childNode.getHeight().unit !== Style.Unit.Point || Math.abs(childNode.getHeight().value - totalHeight) > 0.1) {\n childNode.setHeight(totalHeight)\n }\n }\n\n // 9. Update Grid Height\n const totalGridHeight = Math.max(0, rowOffsets[rowOffsets.length - 1] - rowGap)\n const currentHeightStyle = this.node.getHeight()\n if (currentHeightStyle.unit === Style.Unit.Auto || currentHeightStyle.unit === Style.Unit.Undefined) {\n const targetTotalHeight = totalGridHeight + paddingTop + paddingBottom\n this.node.setHeight(targetTotalHeight)\n }\n }\n\n /**\n * Resolves track sizes to pixels.\n */\n private resolveTracks(tracks: GridTrackSize[], availableSpace: number, gap: number): number[] {\n const resolved: number[] = []\n let usedSpace = 0\n let totalFr = 0\n const frIndices: number[] = []\n\n tracks.forEach((t, i) => {\n const parsed = this.parseTrack(t, availableSpace)\n if (parsed.type === 'px' || parsed.type === '%') {\n resolved[i] = parsed.value\n usedSpace += parsed.value\n } else if (parsed.type === 'fr') {\n totalFr += parsed.value\n resolved[i] = 0\n frIndices.push(i)\n } else {\n resolved[i] = 0\n }\n })\n\n const totalGaps = Math.max(0, tracks.length - 1) * gap\n usedSpace += totalGaps\n\n const remainingSpace = Math.max(0, availableSpace - usedSpace)\n if (totalFr > 0) {\n frIndices.forEach(i => {\n const parsed = this.parseTrack(tracks[i], availableSpace)\n const share = (parsed.value / totalFr) * remainingSpace\n resolved[i] = share\n })\n }\n\n return resolved\n }\n}\n\n/**\n * Factory function to create a new GridNode instance.\n */\nexport const Grid = ({ children, ...rest }: GridProps): CanvasElement => ({\n __type: 'Grid',\n props: rest,\n children: normalizeDescriptorChildren(children),\n})\n"],"names":["BoxNode","normalizeDescriptorChildren","RowNode","Style","parsePercentage"],"mappings":"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"}
@@ -57,8 +57,8 @@ class ImageNode extends layout_canvas.BoxNode {
57
57
  */
58
58
  async _fetchCanvasImage(diskCacheKey, diskCacheKeys) {
59
59
  const { fileTypeFromBuffer, fileTypeFromFile } = await import('file-type');
60
- let finalSource = this.props.src;
61
- let isSvg = false;
60
+ let finalSource;
61
+ let isSvg;
62
62
  let contentBuffer = null;
63
63
  let detectedMime;
64
64
  if (typeof this.props.src === 'string') {
@@ -1 +1 @@
1
- {"version":3,"file":"image.canvas.js","sources":["../../../../src/canvas/image.canvas.ts"],"sourcesContent":["import type { BaseProps, ImageProps, CanvasElement } from '@/canvas/canvas.type.js'\nimport { type CanvasRenderingContext2D, Image as CanvasImage, loadImage } from 'skia-canvas'\nimport { BoxNode } from '@/canvas/layout.canvas.js'\nimport { drawRoundedRectPath, parseBorderRadius } from '@/canvas/canvas.helper.js'\nimport { promises as fs } from 'fs'\nimport { Style } from '@/constant/common.const.js'\nimport { hashBuffer, readDiskCache, writeDiskCache } from '@/util/disk.cache.js'\n\n/**\n * Calculates pixel offset for image positioning based on percentage or pixel values.\n * This handles centering, edge alignment, and percentage-based positioning.\n */\nfunction calculateOffsetFromValue(positionValue: number | `${number}%` | undefined, availableSpace: number): number {\n const value = positionValue ?? '50%'\n if (typeof value === 'number') {\n return value\n }\n if (typeof value === 'string' && value.endsWith('%')) {\n const percentage = parseFloat(value) / 100\n return availableSpace * percentage\n }\n console.warn(`[ImageNode] Invalid objectPosition value format: ${value}. Defaulting to 50%.`)\n return availableSpace * 0.5\n}\n\n/**\n * Per-render image cache — keyed by `src|color` for string sources.\n * Scoped to a single RootNode.render() call; discarded after rendering.\n * Deduplicates concurrent fetches when multiple ImageNodes share the same src.\n */\nexport type RenderImageCache = Map<string, Promise<CanvasImage>>\n\n/**\n * Renders images with configurable sizing, positioning, and effects.\n * Supports object-fit modes, positioning, border radius, and saturation filters.\n */\nexport class ImageNode extends BoxNode {\n declare props: ImageProps & BaseProps\n private loadedImage: CanvasImage | null = null\n private naturalWidth = 0\n private naturalHeight = 0\n private loadingPromise: Promise<void> | null = null\n\n constructor(props: ImageProps) {\n super({ name: 'Image', ...props, children: undefined })\n\n this.props = {\n objectFit: 'fill',\n overflow: Style.Overflow.Hidden,\n saturate: 1,\n objectPosition: { Left: '50%', Top: '50%' },\n ...props,\n }\n }\n\n public load(cache?: RenderImageCache, diskCacheKeys?: Set<string>): Promise<void> {\n if (!this.loadingPromise) {\n this.loadingPromise = this._loadImage(cache, diskCacheKeys)\n }\n return this.loadingPromise\n }\n\n /**\n * Fetches and processes the image source into a CanvasImage.\n * Does not touch node state — pure fetch logic.\n *\n * If `diskCacheKey` and `diskCacheKeys` are provided, the resolved image buffer\n * is written to disk and the key is recorded so the caller can clean it up later.\n */\n private async _fetchCanvasImage(diskCacheKey?: string, diskCacheKeys?: Set<string>): Promise<CanvasImage> {\n const { fileTypeFromBuffer, fileTypeFromFile } = await import('file-type')\n let finalSource: string | Buffer = this.props.src\n let isSvg = false\n let contentBuffer: Buffer | null = null\n let detectedMime: string | undefined\n\n if (typeof this.props.src === 'string') {\n if (this.props.src.startsWith('http')) {\n const response = await fetch(this.props.src)\n if (!response.ok) {\n throw new Error(`HTTP error ${response.status} fetching image: ${this.props.src}`)\n }\n const imageArrayBuffer = await response.arrayBuffer()\n contentBuffer = Buffer.from(imageArrayBuffer)\n finalSource = contentBuffer\n\n const fileTypeResult = await fileTypeFromBuffer(contentBuffer)\n detectedMime = fileTypeResult?.mime\n isSvg = detectedMime === 'image/svg+xml'\n\n if ((!detectedMime || detectedMime === 'application/xml') && contentBuffer.toString('utf-8').includes('<svg')) {\n isSvg = true\n }\n } else {\n finalSource = this.props.src\n const filePath = this.props.src\n\n try {\n const fileTypeResult = await fileTypeFromFile(filePath)\n detectedMime = fileTypeResult?.mime\n isSvg = detectedMime === 'image/svg+xml'\n\n if ((!detectedMime || detectedMime === 'application/xml') && filePath.toLowerCase().endsWith('.svg')) {\n isSvg = true\n }\n } catch {\n isSvg = filePath.toLowerCase().endsWith('.svg')\n }\n\n if (isSvg && this.props.color) {\n try {\n contentBuffer = await fs.readFile(filePath)\n } catch {\n isSvg = false\n contentBuffer = null\n }\n }\n }\n } else {\n contentBuffer = this.props.src\n finalSource = contentBuffer\n\n const fileTypeResult = await fileTypeFromBuffer(contentBuffer)\n detectedMime = fileTypeResult?.mime\n isSvg = detectedMime === 'image/svg+xml'\n }\n\n if (isSvg && this.props.color && contentBuffer) {\n const svgString = contentBuffer.toString('utf-8')\n const modifiedSvgString = svgString.replace(/fill=\"[^\"]*\"/g, `fill=\"${this.props.color}\"`)\n finalSource = modifiedSvgString !== svgString ? Buffer.from(modifiedSvgString) : contentBuffer\n }\n\n // Write to disk and track the key so the render owner can clean it up\n if (diskCacheKey && diskCacheKeys) {\n const cacheBuffer = Buffer.isBuffer(finalSource) ? finalSource : contentBuffer\n if (cacheBuffer) {\n await writeDiskCache(diskCacheKey, cacheBuffer)\n diskCacheKeys.add(diskCacheKey)\n }\n }\n\n return loadImage(finalSource as Buffer)\n }\n\n /**\n * Loads and processes an image.\n *\n * Resolution order:\n * 1. Disk cache at `.cache/files/<hash>` — survives process restarts.\n * 2. Per-render dedup cache — avoids duplicate in-flight fetches when\n * multiple ImageNodes share the same src within one render pass.\n * 3. Fresh fetch via `_fetchCanvasImage()` — writes buffer to disk cache.\n *\n * Buffer sources use a SHA-256 hash as their cache key (same as string sources).\n * All resolved images are released when the render completes (no cross-render retention).\n */\n private _loadImage(cache?: RenderImageCache, diskCacheKeys?: Set<string>): Promise<void> {\n if (!this.props.src) {\n const aspectRatioFromProps = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : undefined\n this.node.setAspectRatio(aspectRatioFromProps)\n this.naturalWidth = 0\n this.naturalHeight = 0\n return Promise.resolve()\n }\n\n return new Promise(resolve => {\n const load = async () => {\n try {\n const srcHash = typeof this.props.src === 'string' ? hashBuffer(Buffer.from(this.props.src)) : hashBuffer(this.props.src)\n const cacheKey = this.props.color ? `${srcHash}|${this.props.color}` : srcHash\n\n // 1. Disk cache read — only when disk caching is enabled for this render\n if (diskCacheKeys) {\n const diskBuffer = await readDiskCache(cacheKey)\n if (diskBuffer) {\n const img = await loadImage(diskBuffer as Buffer)\n this.loadedImage = img\n this.naturalWidth = img.width\n this.naturalHeight = img.height\n const calculatedAspectRatio = img.width > 0 && img.height > 0 ? img.width / img.height : undefined\n const finalAspectRatio = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : calculatedAspectRatio\n this.node.setAspectRatio(finalAspectRatio)\n this.props.onLoad?.()\n resolve()\n return\n }\n }\n\n // 2. Per-render memory dedup cache or fresh fetch\n let imagePromise: Promise<CanvasImage>\n if (cache) {\n if (!cache.has(cacheKey)) {\n cache.set(cacheKey, this._fetchCanvasImage(diskCacheKeys ? cacheKey : undefined, diskCacheKeys))\n }\n imagePromise = cache.get(cacheKey)!\n } else {\n imagePromise = this._fetchCanvasImage(diskCacheKeys ? cacheKey : undefined, diskCacheKeys)\n }\n\n const img = await imagePromise\n\n this.loadedImage = img\n this.naturalWidth = img.width\n this.naturalHeight = img.height\n\n const calculatedAspectRatio = this.naturalWidth > 0 && this.naturalHeight > 0 ? this.naturalWidth / this.naturalHeight : undefined\n const finalAspectRatio = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : calculatedAspectRatio\n\n this.node.setAspectRatio(finalAspectRatio)\n this.props.onLoad?.()\n resolve()\n } catch (error: any) {\n this.naturalWidth = 0\n this.naturalHeight = 0\n const finalAspectRatioOnError = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : undefined\n this.node.setAspectRatio(finalAspectRatioOnError)\n this.props.onError?.(error)\n resolve()\n }\n }\n load()\n })\n }\n\n public getLoadingPromise(): Promise<void> {\n return this.loadingPromise ?? this.load()\n }\n\n /**\n * Renders the image with correct sizing, clipping, and positioning.\n * Handles object-fit, object-position, and visual effects like saturation.\n */\n protected override async _renderContent(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number) {\n await super._renderContent(ctx, x, y, width, height)\n\n if (!this.loadedImage || width <= 0 || height <= 0) return\n const img = this.loadedImage\n const imgW = this.naturalWidth\n const imgH = this.naturalHeight\n if (imgW <= 0 || imgH <= 0) return\n\n // Calculate content box accounting for padding and borders\n const paddingLeft = this.node.getComputedPadding(Style.Edge.Left)\n const paddingTop = this.node.getComputedPadding(Style.Edge.Top)\n const paddingRight = this.node.getComputedPadding(Style.Edge.Right)\n const paddingBottom = this.node.getComputedPadding(Style.Edge.Bottom)\n const borderLeft = this.node.getComputedBorder(Style.Edge.Left)\n const borderTop = this.node.getComputedBorder(Style.Edge.Top)\n const borderRight = this.node.getComputedBorder(Style.Edge.Right)\n const borderBottom = this.node.getComputedBorder(Style.Edge.Bottom)\n const contentX = x + borderLeft + paddingLeft\n const contentY = y + borderTop + paddingTop\n const contentWidth = Math.max(0, width - borderLeft - paddingLeft - borderRight - paddingRight)\n const contentHeight = Math.max(0, height - borderTop - paddingTop - borderBottom - paddingBottom)\n\n if (contentWidth <= 0 || contentHeight <= 0) return\n\n // Apply clipping for border radius\n ctx.save()\n const outerRadii = parseBorderRadius(this.props.borderRadius)\n const innerBorderRadii = {\n TopLeft: Math.max(0, outerRadii.TopLeft - borderTop),\n TopRight: Math.max(0, outerRadii.TopRight - borderTop),\n BottomRight: Math.max(0, outerRadii.BottomRight - borderBottom),\n BottomLeft: Math.max(0, outerRadii.BottomLeft - borderBottom),\n }\n const contentRadii = {\n TopLeft: Math.max(0, innerBorderRadii.TopLeft - Math.max(paddingLeft, paddingTop)),\n TopRight: Math.max(0, innerBorderRadii.TopRight - Math.max(paddingRight, paddingTop)),\n BottomRight: Math.max(0, innerBorderRadii.BottomRight - Math.max(paddingRight, paddingBottom)),\n BottomLeft: Math.max(0, innerBorderRadii.BottomLeft - Math.max(paddingLeft, paddingBottom)),\n }\n drawRoundedRectPath(ctx, contentX, contentY, contentWidth, contentHeight, contentRadii)\n ctx.clip()\n\n // Calculate image dimensions based on object-fit\n const nodeRatio = contentWidth / contentHeight\n const imgRatio = imgW / imgH\n const objectFit = this.props.objectFit\n let dw = contentWidth\n let dh = contentHeight\n\n if (objectFit === 'contain') {\n if (imgRatio > nodeRatio) {\n dw = contentWidth\n dh = contentWidth / imgRatio\n } else {\n dh = contentHeight\n dw = contentHeight * imgRatio\n }\n } else if (objectFit === 'cover') {\n if (imgRatio > nodeRatio) {\n dh = contentHeight\n dw = contentHeight * imgRatio\n } else {\n dw = contentWidth\n dh = contentWidth / imgRatio\n }\n } else if (objectFit === 'none') {\n dw = imgW\n dh = imgH\n } else if (objectFit === 'scale-down') {\n if (imgW <= contentWidth && imgH <= contentHeight) {\n dw = imgW\n dh = imgH\n } else {\n if (imgRatio > nodeRatio) {\n dw = contentWidth\n dh = contentWidth / imgRatio\n } else {\n dh = contentHeight\n dw = contentHeight * imgRatio\n }\n }\n }\n\n // Calculate image position based on object-position\n const sx = 0\n const sy = 0\n const sw = imgW\n const sh = imgH\n\n const availableWidth = contentWidth - dw\n const availableHeight = contentHeight - dh\n const posProps = this.props.objectPosition || {}\n const horizontalValue = posProps.Left !== undefined ? posProps.Left : posProps.Right !== undefined ? posProps.Right : '50%'\n const verticalValue = posProps.Top !== undefined ? posProps.Top : posProps.Bottom !== undefined ? posProps.Bottom : '50%'\n\n let offsetX = calculateOffsetFromValue(horizontalValue, availableWidth)\n let offsetY = calculateOffsetFromValue(verticalValue, availableHeight)\n\n if (posProps.Left === undefined && posProps.Right !== undefined) {\n offsetX = availableWidth - offsetX\n }\n if (posProps.Top === undefined && posProps.Bottom !== undefined) {\n offsetY = availableHeight - offsetY\n }\n\n const dx = contentX + offsetX\n const dy = contentY + offsetY\n\n // Draw image with filters\n ctx.save()\n try {\n if (this.props.dropShadow) {\n const shadow = this.props.dropShadow\n const shadowBlur = Math.max(shadow.offsetX ?? 0, shadow.offsetY ?? 0)\n ctx.shadowOffsetX = shadow.offsetX ?? 0\n ctx.shadowOffsetY = shadow.offsetY ?? 0\n ctx.shadowBlur = Math.max(0, shadow.blur ?? shadowBlur)\n ctx.shadowColor = shadow.color ?? 'black'\n }\n\n const saturateValue = this.props.saturate ?? 1\n let filterString = ''\n if (saturateValue !== 1) {\n filterString += `saturate(${saturateValue * 100}%) `\n }\n\n if (filterString) {\n const currentFilter = ctx.filter && ctx.filter !== 'none' ? ctx.filter + ' ' : ''\n ctx.filter = currentFilter + filterString.trim()\n }\n\n const finalDX = Math.floor(dx)\n const finalDY = Math.floor(dy)\n const finalDW = Math.ceil(dw + (dx - finalDX))\n const finalDH = Math.ceil(dh + (dy - finalDY))\n\n if (finalDW > 0 && finalDH > 0) {\n ctx.drawImage(img, sx, sy, sw, sh, finalDX, finalDY, finalDW, finalDH)\n }\n } catch (drawError) {\n console.error('[ImageNode] Error drawing image:', drawError)\n } finally {\n ctx.restore()\n }\n\n ctx.restore()\n }\n}\n\n/**\n * Factory function to create ImageNode instances\n */\nexport const Image = (props: ImageProps): CanvasElement => ({\n __type: 'Image',\n props: props as Omit<ImageProps, 'onLoad' | 'onError'>,\n})\n"],"names":["BoxNode","Style","fs","writeDiskCache","loadImage","hashBuffer","readDiskCache","parseBorderRadius","drawRoundedRectPath"],"mappings":"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"}
1
+ {"version":3,"file":"image.canvas.js","sources":["../../../../src/canvas/image.canvas.ts"],"sourcesContent":["import type { BaseProps, ImageProps, CanvasElement } from '@/canvas/canvas.type.js'\nimport { type CanvasRenderingContext2D, Image as CanvasImage, loadImage } from 'skia-canvas'\nimport { BoxNode } from '@/canvas/layout.canvas.js'\nimport { drawRoundedRectPath, parseBorderRadius } from '@/canvas/canvas.helper.js'\nimport { promises as fs } from 'fs'\nimport { Style } from '@/constant/common.const.js'\nimport { hashBuffer, readDiskCache, writeDiskCache } from '@/util/disk.cache.js'\n\n/**\n * Calculates pixel offset for image positioning based on percentage or pixel values.\n * This handles centering, edge alignment, and percentage-based positioning.\n */\nfunction calculateOffsetFromValue(positionValue: number | `${number}%` | undefined, availableSpace: number): number {\n const value = positionValue ?? '50%'\n if (typeof value === 'number') {\n return value\n }\n if (typeof value === 'string' && value.endsWith('%')) {\n const percentage = parseFloat(value) / 100\n return availableSpace * percentage\n }\n console.warn(`[ImageNode] Invalid objectPosition value format: ${value}. Defaulting to 50%.`)\n return availableSpace * 0.5\n}\n\n/**\n * Per-render image cache — keyed by `src|color` for string sources.\n * Scoped to a single RootNode.render() call; discarded after rendering.\n * Deduplicates concurrent fetches when multiple ImageNodes share the same src.\n */\nexport type RenderImageCache = Map<string, Promise<CanvasImage>>\n\n/**\n * Renders images with configurable sizing, positioning, and effects.\n * Supports object-fit modes, positioning, border radius, and saturation filters.\n */\nexport class ImageNode extends BoxNode {\n declare props: ImageProps & BaseProps\n private loadedImage: CanvasImage | null = null\n private naturalWidth = 0\n private naturalHeight = 0\n private loadingPromise: Promise<void> | null = null\n\n constructor(props: ImageProps) {\n super({ name: 'Image', ...props, children: undefined })\n\n this.props = {\n objectFit: 'fill',\n overflow: Style.Overflow.Hidden,\n saturate: 1,\n objectPosition: { Left: '50%', Top: '50%' },\n ...props,\n }\n }\n\n public load(cache?: RenderImageCache, diskCacheKeys?: Set<string>): Promise<void> {\n if (!this.loadingPromise) {\n this.loadingPromise = this._loadImage(cache, diskCacheKeys)\n }\n return this.loadingPromise\n }\n\n /**\n * Fetches and processes the image source into a CanvasImage.\n * Does not touch node state — pure fetch logic.\n *\n * If `diskCacheKey` and `diskCacheKeys` are provided, the resolved image buffer\n * is written to disk and the key is recorded so the caller can clean it up later.\n */\n private async _fetchCanvasImage(diskCacheKey?: string, diskCacheKeys?: Set<string>): Promise<CanvasImage> {\n const { fileTypeFromBuffer, fileTypeFromFile } = await import('file-type')\n let finalSource: string | Buffer\n let isSvg: boolean\n let contentBuffer: Buffer | null = null\n let detectedMime: string | undefined\n\n if (typeof this.props.src === 'string') {\n if (this.props.src.startsWith('http')) {\n const response = await fetch(this.props.src)\n if (!response.ok) {\n throw new Error(`HTTP error ${response.status} fetching image: ${this.props.src}`)\n }\n const imageArrayBuffer = await response.arrayBuffer()\n contentBuffer = Buffer.from(imageArrayBuffer)\n finalSource = contentBuffer\n\n const fileTypeResult = await fileTypeFromBuffer(contentBuffer)\n detectedMime = fileTypeResult?.mime\n isSvg = detectedMime === 'image/svg+xml'\n\n if ((!detectedMime || detectedMime === 'application/xml') && contentBuffer.toString('utf-8').includes('<svg')) {\n isSvg = true\n }\n } else {\n finalSource = this.props.src\n const filePath = this.props.src\n\n try {\n const fileTypeResult = await fileTypeFromFile(filePath)\n detectedMime = fileTypeResult?.mime\n isSvg = detectedMime === 'image/svg+xml'\n\n if ((!detectedMime || detectedMime === 'application/xml') && filePath.toLowerCase().endsWith('.svg')) {\n isSvg = true\n }\n } catch {\n isSvg = filePath.toLowerCase().endsWith('.svg')\n }\n\n if (isSvg && this.props.color) {\n try {\n contentBuffer = await fs.readFile(filePath)\n } catch {\n isSvg = false\n contentBuffer = null\n }\n }\n }\n } else {\n contentBuffer = this.props.src\n finalSource = contentBuffer\n\n const fileTypeResult = await fileTypeFromBuffer(contentBuffer)\n detectedMime = fileTypeResult?.mime\n isSvg = detectedMime === 'image/svg+xml'\n }\n\n if (isSvg && this.props.color && contentBuffer) {\n const svgString = contentBuffer.toString('utf-8')\n const modifiedSvgString = svgString.replace(/fill=\"[^\"]*\"/g, `fill=\"${this.props.color}\"`)\n finalSource = modifiedSvgString !== svgString ? Buffer.from(modifiedSvgString) : contentBuffer\n }\n\n // Write to disk and track the key so the render owner can clean it up\n if (diskCacheKey && diskCacheKeys) {\n const cacheBuffer = Buffer.isBuffer(finalSource) ? finalSource : contentBuffer\n if (cacheBuffer) {\n await writeDiskCache(diskCacheKey, cacheBuffer)\n diskCacheKeys.add(diskCacheKey)\n }\n }\n\n return loadImage(finalSource as Buffer)\n }\n\n /**\n * Loads and processes an image.\n *\n * Resolution order:\n * 1. Disk cache at `.cache/files/<hash>` — survives process restarts.\n * 2. Per-render dedup cache — avoids duplicate in-flight fetches when\n * multiple ImageNodes share the same src within one render pass.\n * 3. Fresh fetch via `_fetchCanvasImage()` — writes buffer to disk cache.\n *\n * Buffer sources use a SHA-256 hash as their cache key (same as string sources).\n * All resolved images are released when the render completes (no cross-render retention).\n */\n private _loadImage(cache?: RenderImageCache, diskCacheKeys?: Set<string>): Promise<void> {\n if (!this.props.src) {\n const aspectRatioFromProps = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : undefined\n this.node.setAspectRatio(aspectRatioFromProps)\n this.naturalWidth = 0\n this.naturalHeight = 0\n return Promise.resolve()\n }\n\n return new Promise(resolve => {\n const load = async () => {\n try {\n const srcHash = typeof this.props.src === 'string' ? hashBuffer(Buffer.from(this.props.src)) : hashBuffer(this.props.src)\n const cacheKey = this.props.color ? `${srcHash}|${this.props.color}` : srcHash\n\n // 1. Disk cache read — only when disk caching is enabled for this render\n if (diskCacheKeys) {\n const diskBuffer = await readDiskCache(cacheKey)\n if (diskBuffer) {\n const img = await loadImage(diskBuffer as Buffer)\n this.loadedImage = img\n this.naturalWidth = img.width\n this.naturalHeight = img.height\n const calculatedAspectRatio = img.width > 0 && img.height > 0 ? img.width / img.height : undefined\n const finalAspectRatio = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : calculatedAspectRatio\n this.node.setAspectRatio(finalAspectRatio)\n this.props.onLoad?.()\n resolve()\n return\n }\n }\n\n // 2. Per-render memory dedup cache or fresh fetch\n let imagePromise: Promise<CanvasImage>\n if (cache) {\n if (!cache.has(cacheKey)) {\n cache.set(cacheKey, this._fetchCanvasImage(diskCacheKeys ? cacheKey : undefined, diskCacheKeys))\n }\n imagePromise = cache.get(cacheKey)!\n } else {\n imagePromise = this._fetchCanvasImage(diskCacheKeys ? cacheKey : undefined, diskCacheKeys)\n }\n\n const img = await imagePromise\n\n this.loadedImage = img\n this.naturalWidth = img.width\n this.naturalHeight = img.height\n\n const calculatedAspectRatio = this.naturalWidth > 0 && this.naturalHeight > 0 ? this.naturalWidth / this.naturalHeight : undefined\n const finalAspectRatio = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : calculatedAspectRatio\n\n this.node.setAspectRatio(finalAspectRatio)\n this.props.onLoad?.()\n resolve()\n } catch (error: any) {\n this.naturalWidth = 0\n this.naturalHeight = 0\n const finalAspectRatioOnError = typeof this.props.aspectRatio === 'number' && this.props.aspectRatio > 0 ? this.props.aspectRatio : undefined\n this.node.setAspectRatio(finalAspectRatioOnError)\n this.props.onError?.(error)\n resolve()\n }\n }\n load()\n })\n }\n\n public getLoadingPromise(): Promise<void> {\n return this.loadingPromise ?? this.load()\n }\n\n /**\n * Renders the image with correct sizing, clipping, and positioning.\n * Handles object-fit, object-position, and visual effects like saturation.\n */\n protected override async _renderContent(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number) {\n await super._renderContent(ctx, x, y, width, height)\n\n if (!this.loadedImage || width <= 0 || height <= 0) return\n const img = this.loadedImage\n const imgW = this.naturalWidth\n const imgH = this.naturalHeight\n if (imgW <= 0 || imgH <= 0) return\n\n // Calculate content box accounting for padding and borders\n const paddingLeft = this.node.getComputedPadding(Style.Edge.Left)\n const paddingTop = this.node.getComputedPadding(Style.Edge.Top)\n const paddingRight = this.node.getComputedPadding(Style.Edge.Right)\n const paddingBottom = this.node.getComputedPadding(Style.Edge.Bottom)\n const borderLeft = this.node.getComputedBorder(Style.Edge.Left)\n const borderTop = this.node.getComputedBorder(Style.Edge.Top)\n const borderRight = this.node.getComputedBorder(Style.Edge.Right)\n const borderBottom = this.node.getComputedBorder(Style.Edge.Bottom)\n const contentX = x + borderLeft + paddingLeft\n const contentY = y + borderTop + paddingTop\n const contentWidth = Math.max(0, width - borderLeft - paddingLeft - borderRight - paddingRight)\n const contentHeight = Math.max(0, height - borderTop - paddingTop - borderBottom - paddingBottom)\n\n if (contentWidth <= 0 || contentHeight <= 0) return\n\n // Apply clipping for border radius\n ctx.save()\n const outerRadii = parseBorderRadius(this.props.borderRadius)\n const innerBorderRadii = {\n TopLeft: Math.max(0, outerRadii.TopLeft - borderTop),\n TopRight: Math.max(0, outerRadii.TopRight - borderTop),\n BottomRight: Math.max(0, outerRadii.BottomRight - borderBottom),\n BottomLeft: Math.max(0, outerRadii.BottomLeft - borderBottom),\n }\n const contentRadii = {\n TopLeft: Math.max(0, innerBorderRadii.TopLeft - Math.max(paddingLeft, paddingTop)),\n TopRight: Math.max(0, innerBorderRadii.TopRight - Math.max(paddingRight, paddingTop)),\n BottomRight: Math.max(0, innerBorderRadii.BottomRight - Math.max(paddingRight, paddingBottom)),\n BottomLeft: Math.max(0, innerBorderRadii.BottomLeft - Math.max(paddingLeft, paddingBottom)),\n }\n drawRoundedRectPath(ctx, contentX, contentY, contentWidth, contentHeight, contentRadii)\n ctx.clip()\n\n // Calculate image dimensions based on object-fit\n const nodeRatio = contentWidth / contentHeight\n const imgRatio = imgW / imgH\n const objectFit = this.props.objectFit\n let dw = contentWidth\n let dh = contentHeight\n\n if (objectFit === 'contain') {\n if (imgRatio > nodeRatio) {\n dw = contentWidth\n dh = contentWidth / imgRatio\n } else {\n dh = contentHeight\n dw = contentHeight * imgRatio\n }\n } else if (objectFit === 'cover') {\n if (imgRatio > nodeRatio) {\n dh = contentHeight\n dw = contentHeight * imgRatio\n } else {\n dw = contentWidth\n dh = contentWidth / imgRatio\n }\n } else if (objectFit === 'none') {\n dw = imgW\n dh = imgH\n } else if (objectFit === 'scale-down') {\n if (imgW <= contentWidth && imgH <= contentHeight) {\n dw = imgW\n dh = imgH\n } else {\n if (imgRatio > nodeRatio) {\n dw = contentWidth\n dh = contentWidth / imgRatio\n } else {\n dh = contentHeight\n dw = contentHeight * imgRatio\n }\n }\n }\n\n // Calculate image position based on object-position\n const sx = 0\n const sy = 0\n const sw = imgW\n const sh = imgH\n\n const availableWidth = contentWidth - dw\n const availableHeight = contentHeight - dh\n const posProps = this.props.objectPosition || {}\n const horizontalValue = posProps.Left !== undefined ? posProps.Left : posProps.Right !== undefined ? posProps.Right : '50%'\n const verticalValue = posProps.Top !== undefined ? posProps.Top : posProps.Bottom !== undefined ? posProps.Bottom : '50%'\n\n let offsetX = calculateOffsetFromValue(horizontalValue, availableWidth)\n let offsetY = calculateOffsetFromValue(verticalValue, availableHeight)\n\n if (posProps.Left === undefined && posProps.Right !== undefined) {\n offsetX = availableWidth - offsetX\n }\n if (posProps.Top === undefined && posProps.Bottom !== undefined) {\n offsetY = availableHeight - offsetY\n }\n\n const dx = contentX + offsetX\n const dy = contentY + offsetY\n\n // Draw image with filters\n ctx.save()\n try {\n if (this.props.dropShadow) {\n const shadow = this.props.dropShadow\n const shadowBlur = Math.max(shadow.offsetX ?? 0, shadow.offsetY ?? 0)\n ctx.shadowOffsetX = shadow.offsetX ?? 0\n ctx.shadowOffsetY = shadow.offsetY ?? 0\n ctx.shadowBlur = Math.max(0, shadow.blur ?? shadowBlur)\n ctx.shadowColor = shadow.color ?? 'black'\n }\n\n const saturateValue = this.props.saturate ?? 1\n let filterString = ''\n if (saturateValue !== 1) {\n filterString += `saturate(${saturateValue * 100}%) `\n }\n\n if (filterString) {\n const currentFilter = ctx.filter && ctx.filter !== 'none' ? ctx.filter + ' ' : ''\n ctx.filter = currentFilter + filterString.trim()\n }\n\n const finalDX = Math.floor(dx)\n const finalDY = Math.floor(dy)\n const finalDW = Math.ceil(dw + (dx - finalDX))\n const finalDH = Math.ceil(dh + (dy - finalDY))\n\n if (finalDW > 0 && finalDH > 0) {\n ctx.drawImage(img, sx, sy, sw, sh, finalDX, finalDY, finalDW, finalDH)\n }\n } catch (drawError) {\n console.error('[ImageNode] Error drawing image:', drawError)\n } finally {\n ctx.restore()\n }\n\n ctx.restore()\n }\n}\n\n/**\n * Factory function to create ImageNode instances\n */\nexport const Image = (props: ImageProps): CanvasElement => ({\n __type: 'Image',\n props: props as Omit<ImageProps, 'onLoad' | 'onError'>,\n})\n"],"names":["BoxNode","Style","fs","writeDiskCache","loadImage","hashBuffer","readDiskCache","parseBorderRadius","drawRoundedRectPath"],"mappings":";;;;;;;;;AAQA;;;AAGG;AACH,SAAS,wBAAwB,CAAC,aAAgD,EAAE,cAAsB,EAAA;AACxG,IAAA,MAAM,KAAK,GAAG,aAAa,IAAI,KAAK;AACpC,IAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAC7B,QAAA,OAAO,KAAK;IACd;AACA,IAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;QACpD,MAAM,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,GAAG;QAC1C,OAAO,cAAc,GAAG,UAAU;IACpC;AACA,IAAA,OAAO,CAAC,IAAI,CAAC,oDAAoD,KAAK,CAAA,oBAAA,CAAsB,CAAC;IAC7F,OAAO,cAAc,GAAG,GAAG;AAC7B;AASA;;;AAGG;AACG,MAAO,SAAU,SAAQA,qBAAO,CAAA;IAE5B,WAAW,GAAuB,IAAI;IACtC,YAAY,GAAG,CAAC;IAChB,aAAa,GAAG,CAAC;IACjB,cAAc,GAAyB,IAAI;AAEnD,IAAA,WAAA,CAAY,KAAiB,EAAA;AAC3B,QAAA,KAAK,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;QAEvD,IAAI,CAAC,KAAK,GAAG;AACX,YAAA,SAAS,EAAE,MAAM;AACjB,YAAA,QAAQ,EAAEC,kBAAK,CAAC,QAAQ,CAAC,MAAM;AAC/B,YAAA,QAAQ,EAAE,CAAC;YACX,cAAc,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE;AAC3C,YAAA,GAAG,KAAK;SACT;IACH;IAEO,IAAI,CAAC,KAAwB,EAAE,aAA2B,EAAA;AAC/D,QAAA,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE;YACxB,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,aAAa,CAAC;QAC7D;QACA,OAAO,IAAI,CAAC,cAAc;IAC5B;AAEA;;;;;;AAMG;AACK,IAAA,MAAM,iBAAiB,CAAC,YAAqB,EAAE,aAA2B,EAAA;QAChF,MAAM,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,GAAG,MAAM,OAAO,WAAW,CAAC;AAC1E,QAAA,IAAI,WAA4B;AAChC,QAAA,IAAI,KAAc;QAClB,IAAI,aAAa,GAAkB,IAAI;AACvC,QAAA,IAAI,YAAgC;QAEpC,IAAI,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,QAAQ,EAAE;YACtC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;gBACrC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;AAC5C,gBAAA,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE;AAChB,oBAAA,MAAM,IAAI,KAAK,CAAC,CAAA,WAAA,EAAc,QAAQ,CAAC,MAAM,CAAA,iBAAA,EAAoB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAA,CAAE,CAAC;gBACpF;AACA,gBAAA,MAAM,gBAAgB,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE;AACrD,gBAAA,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC;gBAC7C,WAAW,GAAG,aAAa;AAE3B,gBAAA,MAAM,cAAc,GAAG,MAAM,kBAAkB,CAAC,aAAa,CAAC;AAC9D,gBAAA,YAAY,GAAG,cAAc,EAAE,IAAI;AACnC,gBAAA,KAAK,GAAG,YAAY,KAAK,eAAe;gBAExC,IAAI,CAAC,CAAC,YAAY,IAAI,YAAY,KAAK,iBAAiB,KAAK,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;oBAC7G,KAAK,GAAG,IAAI;gBACd;YACF;iBAAO;AACL,gBAAA,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG;AAC5B,gBAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG;AAE/B,gBAAA,IAAI;AACF,oBAAA,MAAM,cAAc,GAAG,MAAM,gBAAgB,CAAC,QAAQ,CAAC;AACvD,oBAAA,YAAY,GAAG,cAAc,EAAE,IAAI;AACnC,oBAAA,KAAK,GAAG,YAAY,KAAK,eAAe;AAExC,oBAAA,IAAI,CAAC,CAAC,YAAY,IAAI,YAAY,KAAK,iBAAiB,KAAK,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE;wBACpG,KAAK,GAAG,IAAI;oBACd;gBACF;AAAE,gBAAA,MAAM;oBACN,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC;gBACjD;gBAEA,IAAI,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE;AAC7B,oBAAA,IAAI;wBACF,aAAa,GAAG,MAAMC,WAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC;oBAC7C;AAAE,oBAAA,MAAM;wBACN,KAAK,GAAG,KAAK;wBACb,aAAa,GAAG,IAAI;oBACtB;gBACF;YACF;QACF;aAAO;AACL,YAAA,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG;YAC9B,WAAW,GAAG,aAAa;AAE3B,YAAA,MAAM,cAAc,GAAG,MAAM,kBAAkB,CAAC,aAAa,CAAC;AAC9D,YAAA,YAAY,GAAG,cAAc,EAAE,IAAI;AACnC,YAAA,KAAK,GAAG,YAAY,KAAK,eAAe;QAC1C;QAEA,IAAI,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,aAAa,EAAE;YAC9C,MAAM,SAAS,GAAG,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC;AACjD,YAAA,MAAM,iBAAiB,GAAG,SAAS,CAAC,OAAO,CAAC,eAAe,EAAE,CAAA,MAAA,EAAS,IAAI,CAAC,KAAK,CAAC,KAAK,CAAA,CAAA,CAAG,CAAC;AAC1F,YAAA,WAAW,GAAG,iBAAiB,KAAK,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,aAAa;QAChG;;AAGA,QAAA,IAAI,YAAY,IAAI,aAAa,EAAE;AACjC,YAAA,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,WAAW,GAAG,aAAa;YAC9E,IAAI,WAAW,EAAE;AACf,gBAAA,MAAMC,yBAAc,CAAC,YAAY,EAAE,WAAW,CAAC;AAC/C,gBAAA,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC;YACjC;QACF;AAEA,QAAA,OAAOC,oBAAS,CAAC,WAAqB,CAAC;IACzC;AAEA;;;;;;;;;;;AAWG;IACK,UAAU,CAAC,KAAwB,EAAE,aAA2B,EAAA;AACtE,QAAA,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE;AACnB,YAAA,MAAM,oBAAoB,GAAG,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,SAAS;AAC1I,YAAA,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,oBAAoB,CAAC;AAC9C,YAAA,IAAI,CAAC,YAAY,GAAG,CAAC;AACrB,YAAA,IAAI,CAAC,aAAa,GAAG,CAAC;AACtB,YAAA,OAAO,OAAO,CAAC,OAAO,EAAE;QAC1B;AAEA,QAAA,OAAO,IAAI,OAAO,CAAC,OAAO,IAAG;AAC3B,YAAA,MAAM,IAAI,GAAG,YAAW;AACtB,gBAAA,IAAI;AACF,oBAAA,MAAM,OAAO,GAAG,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,KAAK,QAAQ,GAAGC,qBAAU,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAGA,qBAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;oBACzH,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAA,EAAG,OAAO,CAAA,CAAA,EAAI,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,OAAO;;oBAG9E,IAAI,aAAa,EAAE;AACjB,wBAAA,MAAM,UAAU,GAAG,MAAMC,wBAAa,CAAC,QAAQ,CAAC;wBAChD,IAAI,UAAU,EAAE;AACd,4BAAA,MAAM,GAAG,GAAG,MAAMF,oBAAS,CAAC,UAAoB,CAAC;AACjD,4BAAA,IAAI,CAAC,WAAW,GAAG,GAAG;AACtB,4BAAA,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC,KAAK;AAC7B,4BAAA,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC,MAAM;4BAC/B,MAAM,qBAAqB,GAAG,GAAG,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,MAAM,GAAG,SAAS;AAClG,4BAAA,MAAM,gBAAgB,GAAG,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,qBAAqB;AAClJ,4BAAA,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAC;AAC1C,4BAAA,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI;AACrB,4BAAA,OAAO,EAAE;4BACT;wBACF;oBACF;;AAGA,oBAAA,IAAI,YAAkC;oBACtC,IAAI,KAAK,EAAE;wBACT,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;4BACxB,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,iBAAiB,CAAC,aAAa,GAAG,QAAQ,GAAG,SAAS,EAAE,aAAa,CAAC,CAAC;wBAClG;AACA,wBAAA,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAE;oBACrC;yBAAO;AACL,wBAAA,YAAY,GAAG,IAAI,CAAC,iBAAiB,CAAC,aAAa,GAAG,QAAQ,GAAG,SAAS,EAAE,aAAa,CAAC;oBAC5F;AAEA,oBAAA,MAAM,GAAG,GAAG,MAAM,YAAY;AAE9B,oBAAA,IAAI,CAAC,WAAW,GAAG,GAAG;AACtB,oBAAA,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC,KAAK;AAC7B,oBAAA,IAAI,CAAC,aAAa,GAAG,GAAG,CAAC,MAAM;oBAE/B,MAAM,qBAAqB,GAAG,IAAI,CAAC,YAAY,GAAG,CAAC,IAAI,IAAI,CAAC,aAAa,GAAG,CAAC,GAAG,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,aAAa,GAAG,SAAS;AAClI,oBAAA,MAAM,gBAAgB,GAAG,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,qBAAqB;AAElJ,oBAAA,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAC;AAC1C,oBAAA,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI;AACrB,oBAAA,OAAO,EAAE;gBACX;gBAAE,OAAO,KAAU,EAAE;AACnB,oBAAA,IAAI,CAAC,YAAY,GAAG,CAAC;AACrB,oBAAA,IAAI,CAAC,aAAa,GAAG,CAAC;AACtB,oBAAA,MAAM,uBAAuB,GAAG,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,SAAS;AAC7I,oBAAA,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,uBAAuB,CAAC;oBACjD,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC;AAC3B,oBAAA,OAAO,EAAE;gBACX;AACF,YAAA,CAAC;AACD,YAAA,IAAI,EAAE;AACR,QAAA,CAAC,CAAC;IACJ;IAEO,iBAAiB,GAAA;QACtB,OAAO,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,IAAI,EAAE;IAC3C;AAEA;;;AAGG;IACgB,MAAM,cAAc,CAAC,GAA6B,EAAE,CAAS,EAAE,CAAS,EAAE,KAAa,EAAE,MAAc,EAAA;AACxH,QAAA,MAAM,KAAK,CAAC,cAAc,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC;QAEpD,IAAI,CAAC,IAAI,CAAC,WAAW,IAAI,KAAK,IAAI,CAAC,IAAI,MAAM,IAAI,CAAC;YAAE;AACpD,QAAA,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW;AAC5B,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY;AAC9B,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa;AAC/B,QAAA,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC;YAAE;;AAG5B,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAACH,kBAAK,CAAC,IAAI,CAAC,IAAI,CAAC;AACjE,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAACA,kBAAK,CAAC,IAAI,CAAC,GAAG,CAAC;AAC/D,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAACA,kBAAK,CAAC,IAAI,CAAC,KAAK,CAAC;AACnE,QAAA,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAACA,kBAAK,CAAC,IAAI,CAAC,MAAM,CAAC;AACrE,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAACA,kBAAK,CAAC,IAAI,CAAC,IAAI,CAAC;AAC/D,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAACA,kBAAK,CAAC,IAAI,CAAC,GAAG,CAAC;AAC7D,QAAA,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAACA,kBAAK,CAAC,IAAI,CAAC,KAAK,CAAC;AACjE,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAACA,kBAAK,CAAC,IAAI,CAAC,MAAM,CAAC;AACnE,QAAA,MAAM,QAAQ,GAAG,CAAC,GAAG,UAAU,GAAG,WAAW;AAC7C,QAAA,MAAM,QAAQ,GAAG,CAAC,GAAG,SAAS,GAAG,UAAU;AAC3C,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,UAAU,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,CAAC;AAC/F,QAAA,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,YAAY,GAAG,aAAa,CAAC;AAEjG,QAAA,IAAI,YAAY,IAAI,CAAC,IAAI,aAAa,IAAI,CAAC;YAAE;;QAG7C,GAAG,CAAC,IAAI,EAAE;QACV,MAAM,UAAU,GAAGM,+BAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC;AAC7D,QAAA,MAAM,gBAAgB,GAAG;AACvB,YAAA,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,GAAG,SAAS,CAAC;AACpD,YAAA,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,QAAQ,GAAG,SAAS,CAAC;AACtD,YAAA,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,WAAW,GAAG,YAAY,CAAC;AAC/D,YAAA,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,UAAU,GAAG,YAAY,CAAC;SAC9D;AACD,QAAA,MAAM,YAAY,GAAG;AACnB,YAAA,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,gBAAgB,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;AAClF,YAAA,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,gBAAgB,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;AACrF,YAAA,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,gBAAgB,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;AAC9F,YAAA,UAAU,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,gBAAgB,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;SAC5F;AACD,QAAAC,iCAAmB,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,CAAC;QACvF,GAAG,CAAC,IAAI,EAAE;;AAGV,QAAA,MAAM,SAAS,GAAG,YAAY,GAAG,aAAa;AAC9C,QAAA,MAAM,QAAQ,GAAG,IAAI,GAAG,IAAI;AAC5B,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS;QACtC,IAAI,EAAE,GAAG,YAAY;QACrB,IAAI,EAAE,GAAG,aAAa;AAEtB,QAAA,IAAI,SAAS,KAAK,SAAS,EAAE;AAC3B,YAAA,IAAI,QAAQ,GAAG,SAAS,EAAE;gBACxB,EAAE,GAAG,YAAY;AACjB,gBAAA,EAAE,GAAG,YAAY,GAAG,QAAQ;YAC9B;iBAAO;gBACL,EAAE,GAAG,aAAa;AAClB,gBAAA,EAAE,GAAG,aAAa,GAAG,QAAQ;YAC/B;QACF;AAAO,aAAA,IAAI,SAAS,KAAK,OAAO,EAAE;AAChC,YAAA,IAAI,QAAQ,GAAG,SAAS,EAAE;gBACxB,EAAE,GAAG,aAAa;AAClB,gBAAA,EAAE,GAAG,aAAa,GAAG,QAAQ;YAC/B;iBAAO;gBACL,EAAE,GAAG,YAAY;AACjB,gBAAA,EAAE,GAAG,YAAY,GAAG,QAAQ;YAC9B;QACF;AAAO,aAAA,IAAI,SAAS,KAAK,MAAM,EAAE;YAC/B,EAAE,GAAG,IAAI;YACT,EAAE,GAAG,IAAI;QACX;AAAO,aAAA,IAAI,SAAS,KAAK,YAAY,EAAE;YACrC,IAAI,IAAI,IAAI,YAAY,IAAI,IAAI,IAAI,aAAa,EAAE;gBACjD,EAAE,GAAG,IAAI;gBACT,EAAE,GAAG,IAAI;YACX;iBAAO;AACL,gBAAA,IAAI,QAAQ,GAAG,SAAS,EAAE;oBACxB,EAAE,GAAG,YAAY;AACjB,oBAAA,EAAE,GAAG,YAAY,GAAG,QAAQ;gBAC9B;qBAAO;oBACL,EAAE,GAAG,aAAa;AAClB,oBAAA,EAAE,GAAG,aAAa,GAAG,QAAQ;gBAC/B;YACF;QACF;;QAGA,MAAM,EAAE,GAAG,CAAC;QACZ,MAAM,EAAE,GAAG,CAAC;QACZ,MAAM,EAAE,GAAG,IAAI;QACf,MAAM,EAAE,GAAG,IAAI;AAEf,QAAA,MAAM,cAAc,GAAG,YAAY,GAAG,EAAE;AACxC,QAAA,MAAM,eAAe,GAAG,aAAa,GAAG,EAAE;QAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,IAAI,EAAE;AAChD,QAAA,MAAM,eAAe,GAAG,QAAQ,CAAC,IAAI,KAAK,SAAS,GAAG,QAAQ,CAAC,IAAI,GAAG,QAAQ,CAAC,KAAK,KAAK,SAAS,GAAG,QAAQ,CAAC,KAAK,GAAG,KAAK;AAC3H,QAAA,MAAM,aAAa,GAAG,QAAQ,CAAC,GAAG,KAAK,SAAS,GAAG,QAAQ,CAAC,GAAG,GAAG,QAAQ,CAAC,MAAM,KAAK,SAAS,GAAG,QAAQ,CAAC,MAAM,GAAG,KAAK;QAEzH,IAAI,OAAO,GAAG,wBAAwB,CAAC,eAAe,EAAE,cAAc,CAAC;QACvE,IAAI,OAAO,GAAG,wBAAwB,CAAC,aAAa,EAAE,eAAe,CAAC;AAEtE,QAAA,IAAI,QAAQ,CAAC,IAAI,KAAK,SAAS,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,EAAE;AAC/D,YAAA,OAAO,GAAG,cAAc,GAAG,OAAO;QACpC;AACA,QAAA,IAAI,QAAQ,CAAC,GAAG,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE;AAC/D,YAAA,OAAO,GAAG,eAAe,GAAG,OAAO;QACrC;AAEA,QAAA,MAAM,EAAE,GAAG,QAAQ,GAAG,OAAO;AAC7B,QAAA,MAAM,EAAE,GAAG,QAAQ,GAAG,OAAO;;QAG7B,GAAG,CAAC,IAAI,EAAE;AACV,QAAA,IAAI;AACF,YAAA,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE;AACzB,gBAAA,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU;AACpC,gBAAA,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,EAAE,MAAM,CAAC,OAAO,IAAI,CAAC,CAAC;gBACrE,GAAG,CAAC,aAAa,GAAG,MAAM,CAAC,OAAO,IAAI,CAAC;gBACvC,GAAG,CAAC,aAAa,GAAG,MAAM,CAAC,OAAO,IAAI,CAAC;AACvC,gBAAA,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,IAAI,UAAU,CAAC;gBACvD,GAAG,CAAC,WAAW,GAAG,MAAM,CAAC,KAAK,IAAI,OAAO;YAC3C;YAEA,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC;YAC9C,IAAI,YAAY,GAAG,EAAE;AACrB,YAAA,IAAI,aAAa,KAAK,CAAC,EAAE;AACvB,gBAAA,YAAY,IAAI,CAAA,SAAA,EAAY,aAAa,GAAG,GAAG,KAAK;YACtD;YAEA,IAAI,YAAY,EAAE;gBAChB,MAAM,aAAa,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,GAAG,EAAE;gBACjF,GAAG,CAAC,MAAM,GAAG,aAAa,GAAG,YAAY,CAAC,IAAI,EAAE;YAClD;YAEA,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;AAC9B,YAAA,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,CAAC;AAC9C,YAAA,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,CAAC;YAE9C,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE;gBAC9B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;YACxE;QACF;QAAE,OAAO,SAAS,EAAE;AAClB,YAAA,OAAO,CAAC,KAAK,CAAC,kCAAkC,EAAE,SAAS,CAAC;QAC9D;gBAAU;YACR,GAAG,CAAC,OAAO,EAAE;QACf;QAEA,GAAG,CAAC,OAAO,EAAE;IACf;AACD;AAED;;AAEG;MACU,KAAK,GAAG,CAAC,KAAiB,MAAqB;AAC1D,IAAA,MAAM,EAAE,OAAO;AACf,IAAA,KAAK,EAAE,KAA+C;AACvD,CAAA;;;;;"}
@@ -68,22 +68,34 @@ async function clearDiskCache() {
68
68
  }
69
69
  }
70
70
  }
71
- // Clean up disk cache on process exit to handle crashes mid-render.
72
- // Guard prevents re-entry: clearDiskCache() is async, so without this the
73
- // beforeExit schedule I/O → idle → beforeExit cycle loops forever.
74
- let _exitCleanupStarted = false;
75
- process.on('beforeExit', () => {
76
- if (_exitCleanupStarted)
77
- return;
78
- _exitCleanupStarted = true;
79
- void clearDiskCache();
80
- });
81
- // Also clean up on SIGINT/SIGTERM for graceful shutdowns
82
- const cleanupOnExit = () => {
83
- clearDiskCache().finally(() => process.exit(0));
84
- };
85
- process.on('SIGINT', cleanupOnExit);
86
- process.on('SIGTERM', cleanupOnExit);
71
+ const globalForExit = globalThis;
72
+ function registerExitListeners() {
73
+ const prev = globalForExit.__diskCacheExit;
74
+ const lifecycle = prev?.lifecycle ?? { cleanupStarted: false };
75
+ if (prev) {
76
+ process.removeListener('beforeExit', prev.onBeforeExit);
77
+ process.removeListener('SIGINT', prev.onSignals);
78
+ process.removeListener('SIGTERM', prev.onSignals);
79
+ }
80
+ const onBeforeExit = () => {
81
+ if (lifecycle.cleanupStarted)
82
+ return;
83
+ lifecycle.cleanupStarted = true;
84
+ void clearDiskCache();
85
+ };
86
+ const onSignals = () => {
87
+ clearDiskCache().finally(() => process.exit(0));
88
+ };
89
+ globalForExit.__diskCacheExit = {
90
+ lifecycle,
91
+ onBeforeExit,
92
+ onSignals,
93
+ };
94
+ process.on('beforeExit', onBeforeExit);
95
+ process.on('SIGINT', onSignals);
96
+ process.on('SIGTERM', onSignals);
97
+ }
98
+ registerExitListeners();
87
99
 
88
100
  exports.clearDiskCache = clearDiskCache;
89
101
  exports.deleteDiskCache = deleteDiskCache;
@@ -1 +1 @@
1
- {"version":3,"file":"disk.cache.js","sources":["../../../../src/util/disk.cache.ts"],"sourcesContent":["import { createHash } from 'crypto'\nimport { promises as fs } from 'fs'\nimport { join } from 'path'\n\nlet _cacheDir = join(process.cwd(), '.cache', 'files')\nlet _dirEnsured = false\n\n/**\n * Override the default disk cache directory.\n * Must be called before any cache read/write operations.\n */\nexport function setDiskCacheDir(dir: string): void {\n _cacheDir = dir\n _dirEnsured = false\n}\n\nasync function ensureDir(): Promise<void> {\n if (_dirEnsured) return\n await fs.mkdir(_cacheDir, { recursive: true })\n _dirEnsured = true\n}\n\nexport function hashBuffer(buf: Buffer): string {\n return createHash('sha256').update(buf).digest('hex')\n}\n\nexport async function readDiskCache(key: string): Promise<Buffer | null> {\n try {\n await ensureDir()\n return await fs.readFile(join(_cacheDir, key))\n } catch {\n return null\n }\n}\n\nexport async function writeDiskCache(key: string, data: Buffer): Promise<void> {\n try {\n await ensureDir()\n await fs.writeFile(join(_cacheDir, key), data)\n } catch {\n // best-effort — cache write failures are non-fatal\n }\n}\n\nexport async function deleteDiskCache(key: string): Promise<void> {\n try {\n await fs.unlink(join(_cacheDir, key))\n } catch (err) {\n // non-fatal — file may not exist if write failed earlier\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n console.warn(`[disk.cache] Failed to delete cache entry \"${key}\":`, (err as Error).message)\n }\n }\n}\n\n/**\n * Delete the entire disk cache directory.\n * Called on process exit to clean up any orphaned cache files.\n */\nexport async function clearDiskCache(): Promise<void> {\n _dirEnsured = false\n try {\n await fs.rm(_cacheDir, { recursive: true, force: true })\n } catch (err) {\n // non-fatal — directory may not exist\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n console.warn('[disk.cache] Failed to clear cache directory:', (err as Error).message)\n }\n }\n}\n\n// Clean up disk cache on process exit to handle crashes mid-render.\n// Guard prevents re-entry: clearDiskCache() is async, so without this the\n// beforeExit schedule I/O idle beforeExit cycle loops forever.\nlet _exitCleanupStarted = false\nprocess.on('beforeExit', () => {\n if (_exitCleanupStarted) return\n _exitCleanupStarted = true\n void clearDiskCache()\n})\n\n// Also clean up on SIGINT/SIGTERM for graceful shutdowns\nconst cleanupOnExit = () => {\n clearDiskCache().finally(() => process.exit(0))\n}\nprocess.on('SIGINT', cleanupOnExit)\nprocess.on('SIGTERM', cleanupOnExit)\n"],"names":["join","fs","createHash"],"mappings":";;;;;;AAIA,IAAI,SAAS,GAAGA,SAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC;AACtD,IAAI,WAAW,GAAG,KAAK;AAEvB;;;AAGG;AACG,SAAU,eAAe,CAAC,GAAW,EAAA;IACzC,SAAS,GAAG,GAAG;IACf,WAAW,GAAG,KAAK;AACrB;AAEA,eAAe,SAAS,GAAA;AACtB,IAAA,IAAI,WAAW;QAAE;AACjB,IAAA,MAAMC,WAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAC9C,WAAW,GAAG,IAAI;AACpB;AAEM,SAAU,UAAU,CAAC,GAAW,EAAA;AACpC,IAAA,OAAOC,iBAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;AACvD;AAEO,eAAe,aAAa,CAAC,GAAW,EAAA;AAC7C,IAAA,IAAI;QACF,MAAM,SAAS,EAAE;AACjB,QAAA,OAAO,MAAMD,WAAE,CAAC,QAAQ,CAACD,SAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IAChD;AAAE,IAAA,MAAM;AACN,QAAA,OAAO,IAAI;IACb;AACF;AAEO,eAAe,cAAc,CAAC,GAAW,EAAE,IAAY,EAAA;AAC5D,IAAA,IAAI;QACF,MAAM,SAAS,EAAE;AACjB,QAAA,MAAMC,WAAE,CAAC,SAAS,CAACD,SAAI,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC;IAChD;AAAE,IAAA,MAAM;;IAER;AACF;AAEO,eAAe,eAAe,CAAC,GAAW,EAAA;AAC/C,IAAA,IAAI;QACF,MAAMC,WAAE,CAAC,MAAM,CAACD,SAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IACvC;IAAE,OAAO,GAAG,EAAE;;AAEZ,QAAA,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE;YACpD,OAAO,CAAC,IAAI,CAAC,CAAA,2CAAA,EAA8C,GAAG,CAAA,EAAA,CAAI,EAAG,GAAa,CAAC,OAAO,CAAC;QAC7F;IACF;AACF;AAEA;;;AAGG;AACI,eAAe,cAAc,GAAA;IAClC,WAAW,GAAG,KAAK;AACnB,IAAA,IAAI;AACF,QAAA,MAAMC,WAAE,CAAC,EAAE,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAC1D;IAAE,OAAO,GAAG,EAAE;;AAEZ,QAAA,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE;YACpD,OAAO,CAAC,IAAI,CAAC,+CAA+C,EAAG,GAAa,CAAC,OAAO,CAAC;QACvF;IACF;AACF;AAEA;AACA;AACA;AACA,IAAI,mBAAmB,GAAG,KAAK;AAC/B,OAAO,CAAC,EAAE,CAAC,YAAY,EAAE,MAAK;AAC5B,IAAA,IAAI,mBAAmB;QAAE;IACzB,mBAAmB,GAAG,IAAI;IAC1B,KAAK,cAAc,EAAE;AACvB,CAAC,CAAC;AAEF;AACA,MAAM,aAAa,GAAG,MAAK;AACzB,IAAA,cAAc,EAAE,CAAC,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AACD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,CAAC;AACnC,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC;;;;;;;;;"}
1
+ {"version":3,"file":"disk.cache.js","sources":["../../../../src/util/disk.cache.ts"],"sourcesContent":["import { createHash } from 'crypto'\nimport { promises as fs } from 'fs'\nimport { join } from 'path'\n\nlet _cacheDir = join(process.cwd(), '.cache', 'files')\nlet _dirEnsured = false\n\n/**\n * Override the default disk cache directory.\n * Must be called before any cache read/write operations.\n */\nexport function setDiskCacheDir(dir: string): void {\n _cacheDir = dir\n _dirEnsured = false\n}\n\nasync function ensureDir(): Promise<void> {\n if (_dirEnsured) return\n await fs.mkdir(_cacheDir, { recursive: true })\n _dirEnsured = true\n}\n\nexport function hashBuffer(buf: Buffer): string {\n return createHash('sha256').update(buf).digest('hex')\n}\n\nexport async function readDiskCache(key: string): Promise<Buffer | null> {\n try {\n await ensureDir()\n return await fs.readFile(join(_cacheDir, key))\n } catch {\n return null\n }\n}\n\nexport async function writeDiskCache(key: string, data: Buffer): Promise<void> {\n try {\n await ensureDir()\n await fs.writeFile(join(_cacheDir, key), data)\n } catch {\n // best-effort — cache write failures are non-fatal\n }\n}\n\nexport async function deleteDiskCache(key: string): Promise<void> {\n try {\n await fs.unlink(join(_cacheDir, key))\n } catch (err) {\n // non-fatal — file may not exist if write failed earlier\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n console.warn(`[disk.cache] Failed to delete cache entry \"${key}\":`, (err as Error).message)\n }\n }\n}\n\n/**\n * Delete the entire disk cache directory.\n * Called on process exit to clean up any orphaned cache files.\n */\nexport async function clearDiskCache(): Promise<void> {\n _dirEnsured = false\n try {\n await fs.rm(_cacheDir, { recursive: true, force: true })\n } catch (err) {\n // non-fatal — directory may not exist\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n console.warn('[disk.cache] Failed to clear cache directory:', (err as Error).message)\n }\n }\n}\n\n// Clean up disk cache on process exit to handle crashes mid-render.\n// Handlers live on globalThis so re-evaluations (e.g. vitest.resetModules +\n// dynamic import) can detach the previous closures and attach fresh ones —\n// avoids stale clearDiskCache / duplicate listener buildup.\ninterface DiskCacheExitGlobal {\n /** One-shot guard for async beforeExit re-entry storms */\n lifecycle: { cleanupStarted: boolean }\n onBeforeExit: () => void\n onSignals: () => void\n}\n\nconst globalForExit = globalThis as typeof globalThis & {\n __diskCacheExit?: DiskCacheExitGlobal\n}\n\nfunction registerExitListeners(): void {\n const prev = globalForExit.__diskCacheExit\n\n const lifecycle = prev?.lifecycle ?? { cleanupStarted: false }\n\n if (prev) {\n process.removeListener('beforeExit', prev.onBeforeExit)\n process.removeListener('SIGINT', prev.onSignals)\n process.removeListener('SIGTERM', prev.onSignals)\n }\n\n const onBeforeExit = () => {\n if (lifecycle.cleanupStarted) return\n lifecycle.cleanupStarted = true\n void clearDiskCache()\n }\n\n const onSignals = () => {\n clearDiskCache().finally(() => process.exit(0))\n }\n\n globalForExit.__diskCacheExit = {\n lifecycle,\n onBeforeExit,\n onSignals,\n }\n\n process.on('beforeExit', onBeforeExit)\n process.on('SIGINT', onSignals)\n process.on('SIGTERM', onSignals)\n}\n\nregisterExitListeners()\n"],"names":["join","fs","createHash"],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { RootProps } from '../canvas/canvas.type.js';
2
+ import type { Canvas } from 'skia-canvas';
3
+ import type { RenderResult } from './worker.types.js';
4
+ export interface CanvasHandlerDeps {
5
+ canvases: Map<number, Canvas>;
6
+ getNextCanvasId: () => number;
7
+ renderRoot: (props: RootProps) => Promise<Canvas>;
8
+ }
9
+ export declare function createCanvasHandlers(deps: CanvasHandlerDeps): {
10
+ render(props: RootProps): Promise<RenderResult>;
11
+ callOnCanvas(canvasId: number, method: string, args: unknown[]): Promise<Buffer | string | void>;
12
+ releaseCanvas(canvasId: number): void;
13
+ };
14
+ //# sourceMappingURL=canvas-handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-handlers.d.ts","sourceRoot":"","sources":["../../../src/worker/canvas-handlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAE5D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,eAAe,EAAE,MAAM,MAAM,CAAA;IAC7B,UAAU,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CAClD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB;kBAEpC,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC;2BAYxB,MAAM,UAAU,MAAM,QAAQ,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;4BAoB9E,MAAM,GAAG,IAAI;EAIxC"}
@@ -0,0 +1,42 @@
1
+ 'use strict';
2
+
3
+ function createCanvasHandlers(deps) {
4
+ return {
5
+ async render(props) {
6
+ const canvas = await deps.renderRoot(props);
7
+ const canvasId = deps.getNextCanvasId();
8
+ deps.canvases.set(canvasId, canvas);
9
+ return {
10
+ canvasId,
11
+ buffer: canvas.toBufferSync('png'),
12
+ width: canvas.width,
13
+ height: canvas.height,
14
+ };
15
+ },
16
+ async callOnCanvas(canvasId, method, args) {
17
+ const canvas = deps.canvases.get(canvasId);
18
+ if (!canvas) {
19
+ throw new Error(`[render.worker] Canvas ${canvasId} not found`);
20
+ }
21
+ switch (method) {
22
+ case 'toBuffer':
23
+ return canvas.toBuffer(...args);
24
+ case 'toURL':
25
+ return canvas.toURL(...args);
26
+ case 'toFile':
27
+ await canvas.toFile(...args);
28
+ return;
29
+ case 'toSharp':
30
+ return await canvas.toSharp(...args).toBuffer();
31
+ default:
32
+ throw new Error(`[render.worker] Unknown method: ${method}`);
33
+ }
34
+ },
35
+ releaseCanvas(canvasId) {
36
+ deps.canvases.delete(canvasId);
37
+ },
38
+ };
39
+ }
40
+
41
+ exports.createCanvasHandlers = createCanvasHandlers;
42
+ //# sourceMappingURL=canvas-handlers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-handlers.js","sources":["../../../../src/worker/canvas-handlers.ts"],"sourcesContent":["import type { RootProps } from '@/canvas/canvas.type.js'\nimport type { Canvas } from 'skia-canvas'\nimport type { RenderResult } from '@/worker/worker.types.js'\n\nexport interface CanvasHandlerDeps {\n canvases: Map<number, Canvas>\n getNextCanvasId: () => number\n renderRoot: (props: RootProps) => Promise<Canvas>\n}\n\nexport function createCanvasHandlers(deps: CanvasHandlerDeps) {\n return {\n async render(props: RootProps): Promise<RenderResult> {\n const canvas = await deps.renderRoot(props)\n const canvasId = deps.getNextCanvasId()\n deps.canvases.set(canvasId, canvas)\n return {\n canvasId,\n buffer: canvas.toBufferSync('png'),\n width: canvas.width,\n height: canvas.height,\n }\n },\n\n async callOnCanvas(canvasId: number, method: string, args: unknown[]): Promise<Buffer | string | void> {\n const canvas = deps.canvases.get(canvasId)\n if (!canvas) {\n throw new Error(`[render.worker] Canvas ${canvasId} not found`)\n }\n switch (method) {\n case 'toBuffer':\n return canvas.toBuffer(...(args as [any, any?]))\n case 'toURL':\n return canvas.toURL(...(args as [any, any?]))\n case 'toFile':\n await canvas.toFile(...(args as [string, any?]))\n return\n case 'toSharp':\n return await canvas.toSharp(...(args as [any?])).toBuffer()\n default:\n throw new Error(`[render.worker] Unknown method: ${method}`)\n }\n },\n\n releaseCanvas(canvasId: number): void {\n deps.canvases.delete(canvasId)\n },\n }\n}\n"],"names":[],"mappings":";;AAUM,SAAU,oBAAoB,CAAC,IAAuB,EAAA;IAC1D,OAAO;QACL,MAAM,MAAM,CAAC,KAAgB,EAAA;YAC3B,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;AAC3C,YAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,EAAE;YACvC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC;YACnC,OAAO;gBACL,QAAQ;AACR,gBAAA,MAAM,EAAE,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC;gBAClC,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB;QACH,CAAC;AAED,QAAA,MAAM,YAAY,CAAC,QAAgB,EAAE,MAAc,EAAE,IAAe,EAAA;YAClE,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;YAC1C,IAAI,CAAC,MAAM,EAAE;AACX,gBAAA,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,CAAA,UAAA,CAAY,CAAC;YACjE;YACA,QAAQ,MAAM;AACZ,gBAAA,KAAK,UAAU;AACb,oBAAA,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAI,IAAoB,CAAC;AAClD,gBAAA,KAAK,OAAO;AACV,oBAAA,OAAO,MAAM,CAAC,KAAK,CAAC,GAAI,IAAoB,CAAC;AAC/C,gBAAA,KAAK,QAAQ;AACX,oBAAA,MAAM,MAAM,CAAC,MAAM,CAAC,GAAI,IAAuB,CAAC;oBAChD;AACF,gBAAA,KAAK,SAAS;oBACZ,OAAO,MAAM,MAAM,CAAC,OAAO,CAAC,GAAI,IAAe,CAAC,CAAC,QAAQ,EAAE;AAC7D,gBAAA;AACE,oBAAA,MAAM,IAAI,KAAK,CAAC,mCAAmC,MAAM,CAAA,CAAE,CAAC;;QAElE,CAAC;AAED,QAAA,aAAa,CAAC,QAAgB,EAAA;AAC5B,YAAA,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC;QAChC,CAAC;KACF;AACH;;;;"}
@@ -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;AA4B5D,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;AAIlC,OAAO,YAAY,MAAM,mCAAmC,CAAA;AA4B5D,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAA"}
@@ -23,6 +23,7 @@ function _interopNamespaceDefault(e) {
23
23
 
24
24
  var Comlink__namespace = /*#__PURE__*/_interopNamespaceDefault(Comlink);
25
25
 
26
+ // src/worker/comlink.setup.ts
26
27
  /**
27
28
  * Fix Comlink.proxy() for Node.js worker_threads (issue #313).
28
29
  * The built-in proxy transfer handler uses browser MessageChannel.
@@ -39,7 +40,7 @@ function installNodeProxyHandler() {
39
40
  return [port2, [port2]];
40
41
  },
41
42
  deserialize: (port) => {
42
- port.start?.();
43
+ port.start();
43
44
  return Comlink__namespace.wrap(nodeEndpoint(port));
44
45
  },
45
46
  });
@@ -1 +1 @@
1
- {"version":3,"file":"comlink.setup.js","sources":["../../../../src/worker/comlink.setup.ts"],"sourcesContent":["// src/worker/comlink.setup.ts\nimport * as Comlink from 'comlink'\nimport { MessageChannel } from 'node:worker_threads'\n\n// Use deep import path — Comlink has no `exports` field (issue #508)\n// @ts-expect-error Comlink's node-adapter has no type declarations at this path\nimport nodeEndpoint from 'comlink/dist/esm/node-adapter.mjs'\n\n/**\n * Fix Comlink.proxy() for Node.js worker_threads (issue #313).\n * The built-in proxy transfer handler uses browser MessageChannel.\n * This override uses Node's MessageChannel instead.\n *\n * Must be called on BOTH main thread and worker before any Comlink usage.\n */\nfunction installNodeProxyHandler() {\n Comlink.transferHandlers.set('proxy', {\n canHandle: (obj: unknown): obj is { [Comlink.proxyMarker]: true } =>\n (typeof obj === 'object' || typeof obj === 'function') && obj !== null && Comlink.proxyMarker in obj,\n serialize: (obj: unknown) => {\n const { port1, port2 } = new MessageChannel()\n Comlink.expose(obj, nodeEndpoint(port1))\n return [port2, [port2]]\n },\n deserialize: (port: MessagePort) => {\n ;(port as any).start?.()\n return Comlink.wrap(nodeEndpoint(port))\n },\n })\n}\n\n// Install immediately on import\ninstallNodeProxyHandler()\n\nexport { Comlink, nodeEndpoint }\n"],"names":["Comlink","MessageChannel"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAQA;;;;;;AAMG;AACH,SAAS,uBAAuB,GAAA;AAC9B,IAAAA,kBAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,EAAE;QACpC,SAAS,EAAE,CAAC,GAAY,KACtB,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,UAAU,KAAK,GAAG,KAAK,IAAI,IAAIA,kBAAO,CAAC,WAAW,IAAI,GAAG;AACtG,QAAA,SAAS,EAAE,CAAC,GAAY,KAAI;YAC1B,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAIC,kCAAc,EAAE;YAC7CD,kBAAO,CAAC,MAAM,CAAC,GAAG,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;AACxC,YAAA,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;AACD,QAAA,WAAW,EAAE,CAAC,IAAiB,KAAI;AAC/B,YAAA,IAAY,CAAC,KAAK,IAAI;YACxB,OAAOA,kBAAO,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QACzC,CAAC;AACF,KAAA,CAAC;AACJ;AAEA;AACA,uBAAuB,EAAE;;;;;"}
1
+ {"version":3,"file":"comlink.setup.js","sources":["../../../../src/worker/comlink.setup.ts"],"sourcesContent":["// src/worker/comlink.setup.ts\nimport * as Comlink from 'comlink'\nimport { MessageChannel, type MessagePort } from 'node:worker_threads'\n\n// Deep import — Comlink has no `exports` field (issue #508); types in src/types/comlink-node-adapter.d.ts\nimport nodeEndpoint from 'comlink/dist/esm/node-adapter.mjs'\n\n/**\n * Fix Comlink.proxy() for Node.js worker_threads (issue #313).\n * The built-in proxy transfer handler uses browser MessageChannel.\n * This override uses Node's MessageChannel instead.\n *\n * Must be called on BOTH main thread and worker before any Comlink usage.\n */\nfunction installNodeProxyHandler() {\n Comlink.transferHandlers.set('proxy', {\n canHandle: (obj: unknown): obj is { [Comlink.proxyMarker]: true } =>\n (typeof obj === 'object' || typeof obj === 'function') && obj !== null && Comlink.proxyMarker in obj,\n serialize: (obj: unknown) => {\n const { port1, port2 } = new MessageChannel()\n Comlink.expose(obj, nodeEndpoint(port1))\n return [port2, [port2]]\n },\n deserialize: (port: MessagePort) => {\n port.start()\n return Comlink.wrap(nodeEndpoint(port))\n },\n })\n}\n\n// Install immediately on import\ninstallNodeProxyHandler()\n\nexport { Comlink, nodeEndpoint }\n"],"names":["Comlink","MessageChannel"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAOA;;;;;;AAMG;AACH,SAAS,uBAAuB,GAAA;AAC9B,IAAAA,kBAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,OAAO,EAAE;QACpC,SAAS,EAAE,CAAC,GAAY,KACtB,CAAC,OAAO,GAAG,KAAK,QAAQ,IAAI,OAAO,GAAG,KAAK,UAAU,KAAK,GAAG,KAAK,IAAI,IAAIA,kBAAO,CAAC,WAAW,IAAI,GAAG;AACtG,QAAA,SAAS,EAAE,CAAC,GAAY,KAAI;YAC1B,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAIC,kCAAc,EAAE;YAC7CD,kBAAO,CAAC,MAAM,CAAC,GAAG,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC;AACxC,YAAA,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;QACzB,CAAC;AACD,QAAA,WAAW,EAAE,CAAC,IAAiB,KAAI;YACjC,IAAI,CAAC,KAAK,EAAE;YACZ,OAAOA,kBAAO,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QACzC,CAAC;AACF,KAAA,CAAC;AACJ;AAEA;AACA,uBAAuB,EAAE;;;;;"}
@@ -3,6 +3,7 @@
3
3
  var node_worker_threads = require('node:worker_threads');
4
4
  require('./comlink.setup.js');
5
5
  var comlink_pool = require('./comlink.pool.js');
6
+ var canvasHandlers = require('./canvas-handlers.js');
6
7
  var root_canvas = require('../canvas/root.canvas.js');
7
8
  var Comlink = require('comlink');
8
9
  var nodeEndpoint = require('comlink/dist/esm/node-adapter.mjs');
@@ -31,42 +32,18 @@ if (!node_worker_threads.parentPort) {
31
32
  }
32
33
  const canvases = new Map();
33
34
  let nextCanvasId = 0;
35
+ const handlers = canvasHandlers.createCanvasHandlers({
36
+ canvases,
37
+ getNextCanvasId: () => nextCanvasId++,
38
+ renderRoot: async (props) => new root_canvas.RootNode(props).render(),
39
+ });
34
40
  const api = {
35
41
  async render(props, callFn) {
36
42
  const resolved = callFn ? comlink_pool.restoreFunctions(props, callFn) : props;
37
- const canvas = await new root_canvas.RootNode(resolved).render();
38
- const canvasId = nextCanvasId++;
39
- canvases.set(canvasId, canvas);
40
- const result = {
41
- canvasId,
42
- buffer: canvas.toBufferSync('png'),
43
- width: canvas.width,
44
- height: canvas.height,
45
- };
46
- return result;
47
- },
48
- async callOnCanvas(canvasId, method, args) {
49
- const canvas = canvases.get(canvasId);
50
- if (!canvas) {
51
- throw new Error(`[render.worker] Canvas ${canvasId} not found`);
52
- }
53
- switch (method) {
54
- case 'toBuffer':
55
- return canvas.toBuffer(...args);
56
- case 'toURL':
57
- return canvas.toURL(...args);
58
- case 'toFile':
59
- await canvas.toFile(...args);
60
- return;
61
- case 'toSharp':
62
- return await canvas.toSharp(...args).toBuffer();
63
- default:
64
- throw new Error(`[render.worker] Unknown method: ${method}`);
65
- }
66
- },
67
- releaseCanvas(canvasId) {
68
- canvases.delete(canvasId);
43
+ return handlers.render(resolved);
69
44
  },
45
+ callOnCanvas: handlers.callOnCanvas.bind(handlers),
46
+ releaseCanvas: handlers.releaseCanvas.bind(handlers),
70
47
  };
71
48
  Comlink__namespace.expose(api, nodeEndpoint(node_worker_threads.parentPort));
72
49
  //# sourceMappingURL=render.worker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"render.worker.js","sources":["../../../../src/worker/render.worker.ts"],"sourcesContent":["import { parentPort } from 'node:worker_threads'\nimport { Comlink, nodeEndpoint } from '@/worker/comlink.setup.js'\nimport { restoreFunctions } from '@/worker/comlink.pool.js'\nimport { RootNode } from '@/canvas/root.canvas.js'\nimport type { Canvas } from 'skia-canvas'\nimport type { WorkerAPI, RenderResult, CallFn } from '@/worker/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\nconst api: WorkerAPI = {\n async render(props, callFn?: CallFn) {\n const resolved = callFn ? restoreFunctions(props, callFn) : props\n const canvas = await new RootNode(resolved).render()\n const canvasId = nextCanvasId++\n canvases.set(canvasId, canvas)\n const result: RenderResult = {\n canvasId,\n buffer: canvas.toBufferSync('png'),\n width: canvas.width,\n height: canvas.height,\n }\n return result\n },\n\n async callOnCanvas(canvasId, method, args) {\n const canvas = canvases.get(canvasId)\n if (!canvas) {\n throw new Error(`[render.worker] Canvas ${canvasId} not found`)\n }\n switch (method) {\n case 'toBuffer':\n return canvas.toBuffer(...(args as [any, any?]))\n case 'toURL':\n return canvas.toURL(...(args as [any, any?]))\n case 'toFile':\n await canvas.toFile(...(args as [string, any?]))\n return\n case 'toSharp':\n return await canvas.toSharp(...(args as [any?])).toBuffer()\n default:\n throw new Error(`[render.worker] Unknown method: ${method}`)\n }\n },\n\n releaseCanvas(canvasId) {\n canvases.delete(canvasId)\n },\n}\n\nComlink.expose(api, nodeEndpoint(parentPort))\n"],"names":["parentPort","restoreFunctions","RootNode","Comlink"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,IAAI,CAACA,8BAAU,EAAE;AACf,IAAA,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AACnE;AAEA,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB;AAC1C,IAAI,YAAY,GAAG,CAAC;AAEpB,MAAM,GAAG,GAAc;AACrB,IAAA,MAAM,MAAM,CAAC,KAAK,EAAE,MAAe,EAAA;AACjC,QAAA,MAAM,QAAQ,GAAG,MAAM,GAAGC,6BAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,KAAK;QACjE,MAAM,MAAM,GAAG,MAAM,IAAIC,oBAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE;AACpD,QAAA,MAAM,QAAQ,GAAG,YAAY,EAAE;AAC/B,QAAA,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC;AAC9B,QAAA,MAAM,MAAM,GAAiB;YAC3B,QAAQ;AACR,YAAA,MAAM,EAAE,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC;YAClC,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB;AACD,QAAA,OAAO,MAAM;IACf,CAAC;AAED,IAAA,MAAM,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAA;QACvC,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;QACrC,IAAI,CAAC,MAAM,EAAE;AACX,YAAA,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,CAAA,UAAA,CAAY,CAAC;QACjE;QACA,QAAQ,MAAM;AACZ,YAAA,KAAK,UAAU;AACb,gBAAA,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAI,IAAoB,CAAC;AAClD,YAAA,KAAK,OAAO;AACV,gBAAA,OAAO,MAAM,CAAC,KAAK,CAAC,GAAI,IAAoB,CAAC;AAC/C,YAAA,KAAK,QAAQ;AACX,gBAAA,MAAM,MAAM,CAAC,MAAM,CAAC,GAAI,IAAuB,CAAC;gBAChD;AACF,YAAA,KAAK,SAAS;gBACZ,OAAO,MAAM,MAAM,CAAC,OAAO,CAAC,GAAI,IAAe,CAAC,CAAC,QAAQ,EAAE;AAC7D,YAAA;AACE,gBAAA,MAAM,IAAI,KAAK,CAAC,mCAAmC,MAAM,CAAA,CAAE,CAAC;;IAElE,CAAC;AAED,IAAA,aAAa,CAAC,QAAQ,EAAA;AACpB,QAAA,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC3B,CAAC;CACF;AAEDC,kBAAO,CAAC,MAAM,CAAC,GAAG,EAAE,YAAY,CAACH,8BAAU,CAAC,CAAC;;"}
1
+ {"version":3,"file":"render.worker.js","sources":["../../../../src/worker/render.worker.ts"],"sourcesContent":["import { parentPort } from 'node:worker_threads'\nimport { Comlink, nodeEndpoint } from '@/worker/comlink.setup.js'\nimport { restoreFunctions } from '@/worker/comlink.pool.js'\nimport { createCanvasHandlers } from '@/worker/canvas-handlers.js'\nimport { RootNode } from '@/canvas/root.canvas.js'\nimport type { Canvas } from 'skia-canvas'\nimport type { WorkerAPI, CallFn } from '@/worker/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\nconst handlers = createCanvasHandlers({\n canvases,\n getNextCanvasId: () => nextCanvasId++,\n renderRoot: async props => new RootNode(props).render(),\n})\n\nconst api: WorkerAPI = {\n async render(props, callFn?: CallFn) {\n const resolved = callFn ? restoreFunctions(props, callFn) : props\n return handlers.render(resolved)\n },\n\n callOnCanvas: handlers.callOnCanvas.bind(handlers),\n releaseCanvas: handlers.releaseCanvas.bind(handlers),\n}\n\nComlink.expose(api, nodeEndpoint(parentPort))\n"],"names":["parentPort","createCanvasHandlers","RootNode","restoreFunctions","Comlink"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAQA,IAAI,CAACA,8BAAU,EAAE;AACf,IAAA,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC;AACnE;AAEA,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB;AAC1C,IAAI,YAAY,GAAG,CAAC;AAEpB,MAAM,QAAQ,GAAGC,mCAAoB,CAAC;IACpC,QAAQ;AACR,IAAA,eAAe,EAAE,MAAM,YAAY,EAAE;AACrC,IAAA,UAAU,EAAE,OAAM,KAAK,KAAI,IAAIC,oBAAQ,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE;AACxD,CAAA,CAAC;AAEF,MAAM,GAAG,GAAc;AACrB,IAAA,MAAM,MAAM,CAAC,KAAK,EAAE,MAAe,EAAA;AACjC,QAAA,MAAM,QAAQ,GAAG,MAAM,GAAGC,6BAAgB,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,KAAK;AACjE,QAAA,OAAO,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC;IAClC,CAAC;IAED,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC;IAClD,aAAa,EAAE,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC;CACrD;AAEDC,kBAAO,CAAC,MAAM,CAAC,GAAG,EAAE,YAAY,CAACJ,8BAAU,CAAC,CAAC;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"grid.canvas.d.ts","sourceRoot":"","sources":["../../../src/canvas/grid.canvas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAiB,aAAa,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACrG,OAAO,EAAE,OAAO,EAA+B,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAIzF;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,OAAO;gBAC3B,KAAK,EAAE,aAAa;CAMjC;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,uBAAuB,aAAa,KAAG,aAI9D,CAAA;AAEF;;;GAGG;AACH,qBAAa,QAAS,SAAQ,OAAO;IACnC;;;OAGG;gBACS,KAAK,EAAE,SAAS;IAQ5B;;OAEG;IACH,OAAO,CAAC,UAAU;IAwBlB;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;OAEG;cACgB,+BAA+B;IAoTlD;;OAEG;IACH,OAAO,CAAC,aAAa;CAkCtB;AAED;;GAEG;AACH,eAAO,MAAM,IAAI,GAAI,uBAAuB,SAAS,KAAG,aAItD,CAAA"}
1
+ {"version":3,"file":"grid.canvas.d.ts","sourceRoot":"","sources":["../../../src/canvas/grid.canvas.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAiB,aAAa,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACrG,OAAO,EAAE,OAAO,EAA+B,OAAO,EAAE,MAAM,2BAA2B,CAAA;AAIzF;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,OAAO;gBAC3B,KAAK,EAAE,aAAa;CAMjC;AAED;;GAEG;AACH,eAAO,MAAM,QAAQ,GAAI,uBAAuB,aAAa,KAAG,aAI9D,CAAA;AAEF;;;GAGG;AACH,qBAAa,QAAS,SAAQ,OAAO;IACnC;;;OAGG;gBACS,KAAK,EAAE,SAAS;IAQ5B;;OAEG;IACH,OAAO,CAAC,UAAU;IAwBlB;;OAEG;IACH,OAAO,CAAC,YAAY;IAmBpB;;OAEG;cACgB,+BAA+B;IAkTlD;;OAEG;IACH,OAAO,CAAC,aAAa;CAkCtB;AAED;;GAEG;AACH,eAAO,MAAM,IAAI,GAAI,uBAAuB,SAAS,KAAG,aAItD,CAAA"}
@@ -1,4 +1,4 @@
1
- import { BoxNode, RowNode, normalizeDescriptorChildren } from './layout.canvas.js';
1
+ import { normalizeDescriptorChildren, BoxNode, RowNode } from './layout.canvas.js';
2
2
  import { Style } from '../constant/common.const.js';
3
3
  import { parsePercentage } from './canvas.helper.js';
4
4
 
@@ -180,7 +180,6 @@ class GridNode extends RowNode {
180
180
  if (parts[1].startsWith('span')) {
181
181
  const span = parseInt(parts[1].replace('span', '')) || 1;
182
182
  if (colStart !== undefined) {
183
- colEnd = colStart + span;
184
183
  colSpan = span;
185
184
  }
186
185
  else {
@@ -210,7 +209,6 @@ class GridNode extends RowNode {
210
209
  if (parts[1].startsWith('span')) {
211
210
  const span = parseInt(parts[1].replace('span', '')) || 1;
212
211
  if (rowStart !== undefined) {
213
- rowEnd = rowStart + span;
214
212
  rowSpan = span;
215
213
  }
216
214
  else {
@@ -55,8 +55,8 @@ class ImageNode extends BoxNode {
55
55
  */
56
56
  async _fetchCanvasImage(diskCacheKey, diskCacheKeys) {
57
57
  const { fileTypeFromBuffer, fileTypeFromFile } = await import('file-type');
58
- let finalSource = this.props.src;
59
- let isSvg = false;
58
+ let finalSource;
59
+ let isSvg;
60
60
  let contentBuffer = null;
61
61
  let detectedMime;
62
62
  if (typeof this.props.src === 'string') {
@@ -66,21 +66,33 @@ async function clearDiskCache() {
66
66
  }
67
67
  }
68
68
  }
69
- // Clean up disk cache on process exit to handle crashes mid-render.
70
- // Guard prevents re-entry: clearDiskCache() is async, so without this the
71
- // beforeExit schedule I/O → idle → beforeExit cycle loops forever.
72
- let _exitCleanupStarted = false;
73
- process.on('beforeExit', () => {
74
- if (_exitCleanupStarted)
75
- return;
76
- _exitCleanupStarted = true;
77
- void clearDiskCache();
78
- });
79
- // Also clean up on SIGINT/SIGTERM for graceful shutdowns
80
- const cleanupOnExit = () => {
81
- clearDiskCache().finally(() => process.exit(0));
82
- };
83
- process.on('SIGINT', cleanupOnExit);
84
- process.on('SIGTERM', cleanupOnExit);
69
+ const globalForExit = globalThis;
70
+ function registerExitListeners() {
71
+ const prev = globalForExit.__diskCacheExit;
72
+ const lifecycle = prev?.lifecycle ?? { cleanupStarted: false };
73
+ if (prev) {
74
+ process.removeListener('beforeExit', prev.onBeforeExit);
75
+ process.removeListener('SIGINT', prev.onSignals);
76
+ process.removeListener('SIGTERM', prev.onSignals);
77
+ }
78
+ const onBeforeExit = () => {
79
+ if (lifecycle.cleanupStarted)
80
+ return;
81
+ lifecycle.cleanupStarted = true;
82
+ void clearDiskCache();
83
+ };
84
+ const onSignals = () => {
85
+ clearDiskCache().finally(() => process.exit(0));
86
+ };
87
+ globalForExit.__diskCacheExit = {
88
+ lifecycle,
89
+ onBeforeExit,
90
+ onSignals,
91
+ };
92
+ process.on('beforeExit', onBeforeExit);
93
+ process.on('SIGINT', onSignals);
94
+ process.on('SIGTERM', onSignals);
95
+ }
96
+ registerExitListeners();
85
97
 
86
98
  export { clearDiskCache, deleteDiskCache, hashBuffer, readDiskCache, setDiskCacheDir, writeDiskCache };
@@ -0,0 +1,14 @@
1
+ import type { RootProps } from '../canvas/canvas.type.js';
2
+ import type { Canvas } from 'skia-canvas';
3
+ import type { RenderResult } from './worker.types.js';
4
+ export interface CanvasHandlerDeps {
5
+ canvases: Map<number, Canvas>;
6
+ getNextCanvasId: () => number;
7
+ renderRoot: (props: RootProps) => Promise<Canvas>;
8
+ }
9
+ export declare function createCanvasHandlers(deps: CanvasHandlerDeps): {
10
+ render(props: RootProps): Promise<RenderResult>;
11
+ callOnCanvas(canvasId: number, method: string, args: unknown[]): Promise<Buffer | string | void>;
12
+ releaseCanvas(canvasId: number): void;
13
+ };
14
+ //# sourceMappingURL=canvas-handlers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-handlers.d.ts","sourceRoot":"","sources":["../../../src/worker/canvas-handlers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAE5D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B,eAAe,EAAE,MAAM,MAAM,CAAA;IAC7B,UAAU,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;CAClD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB;kBAEpC,SAAS,GAAG,OAAO,CAAC,YAAY,CAAC;2BAYxB,MAAM,UAAU,MAAM,QAAQ,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;4BAoB9E,MAAM,GAAG,IAAI;EAIxC"}
@@ -0,0 +1,39 @@
1
+ function createCanvasHandlers(deps) {
2
+ return {
3
+ async render(props) {
4
+ const canvas = await deps.renderRoot(props);
5
+ const canvasId = deps.getNextCanvasId();
6
+ deps.canvases.set(canvasId, canvas);
7
+ return {
8
+ canvasId,
9
+ buffer: canvas.toBufferSync('png'),
10
+ width: canvas.width,
11
+ height: canvas.height,
12
+ };
13
+ },
14
+ async callOnCanvas(canvasId, method, args) {
15
+ const canvas = deps.canvases.get(canvasId);
16
+ if (!canvas) {
17
+ throw new Error(`[render.worker] Canvas ${canvasId} not found`);
18
+ }
19
+ switch (method) {
20
+ case 'toBuffer':
21
+ return canvas.toBuffer(...args);
22
+ case 'toURL':
23
+ return canvas.toURL(...args);
24
+ case 'toFile':
25
+ await canvas.toFile(...args);
26
+ return;
27
+ case 'toSharp':
28
+ return await canvas.toSharp(...args).toBuffer();
29
+ default:
30
+ throw new Error(`[render.worker] Unknown method: ${method}`);
31
+ }
32
+ },
33
+ releaseCanvas(canvasId) {
34
+ deps.canvases.delete(canvasId);
35
+ },
36
+ };
37
+ }
38
+
39
+ export { createCanvasHandlers };
@@ -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;AA4B5D,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;AAIlC,OAAO,YAAY,MAAM,mCAAmC,CAAA;AA4B5D,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAA"}
@@ -21,7 +21,7 @@ function installNodeProxyHandler() {
21
21
  return [port2, [port2]];
22
22
  },
23
23
  deserialize: (port) => {
24
- port.start?.();
24
+ port.start();
25
25
  return Comlink.wrap(nodeEndpoint(port));
26
26
  },
27
27
  });
@@ -1,6 +1,7 @@
1
1
  import { parentPort } from 'node:worker_threads';
2
2
  import './comlink.setup.js';
3
3
  import { restoreFunctions } from './comlink.pool.js';
4
+ import { createCanvasHandlers } from './canvas-handlers.js';
4
5
  import { RootNode } from '../canvas/root.canvas.js';
5
6
  import * as Comlink from 'comlink';
6
7
  import nodeEndpoint from 'comlink/dist/esm/node-adapter.mjs';
@@ -10,41 +11,17 @@ if (!parentPort) {
10
11
  }
11
12
  const canvases = new Map();
12
13
  let nextCanvasId = 0;
14
+ const handlers = createCanvasHandlers({
15
+ canvases,
16
+ getNextCanvasId: () => nextCanvasId++,
17
+ renderRoot: async (props) => new RootNode(props).render(),
18
+ });
13
19
  const api = {
14
20
  async render(props, callFn) {
15
21
  const resolved = callFn ? restoreFunctions(props, callFn) : props;
16
- const canvas = await new RootNode(resolved).render();
17
- const canvasId = nextCanvasId++;
18
- canvases.set(canvasId, canvas);
19
- const result = {
20
- canvasId,
21
- buffer: canvas.toBufferSync('png'),
22
- width: canvas.width,
23
- height: canvas.height,
24
- };
25
- return result;
26
- },
27
- async callOnCanvas(canvasId, method, args) {
28
- const canvas = canvases.get(canvasId);
29
- if (!canvas) {
30
- throw new Error(`[render.worker] Canvas ${canvasId} not found`);
31
- }
32
- switch (method) {
33
- case 'toBuffer':
34
- return canvas.toBuffer(...args);
35
- case 'toURL':
36
- return canvas.toURL(...args);
37
- case 'toFile':
38
- await canvas.toFile(...args);
39
- return;
40
- case 'toSharp':
41
- return await canvas.toSharp(...args).toBuffer();
42
- default:
43
- throw new Error(`[render.worker] Unknown method: ${method}`);
44
- }
45
- },
46
- releaseCanvas(canvasId) {
47
- canvases.delete(canvasId);
22
+ return handlers.render(resolved);
48
23
  },
24
+ callOnCanvas: handlers.callOnCanvas.bind(handlers),
25
+ releaseCanvas: handlers.releaseCanvas.bind(handlers),
49
26
  };
50
27
  Comlink.expose(api, nodeEndpoint(parentPort));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meonode/canvas",
3
- "version": "3.0.0",
3
+ "version": "3.0.1",
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",
@@ -39,6 +39,8 @@
39
39
  "scripts": {
40
40
  "build": "bun -e \"fs.rmSync('./dist', {recursive:true, force:true})\" && rollup -c --bundleConfigAsCjs && bun scripts/rewrite-dts-aliases.ts",
41
41
  "test": "vitest run --coverage",
42
+ "test:ci": "node ./node_modules/vitest/vitest.mjs run --coverage",
43
+ "test:integration": "vitest run --config vitest.integration.config.ts",
42
44
  "typecheck": "tsc --noEmit",
43
45
  "lint": "eslint . --ext .ts,.tsx,.js,.jsx,.mjs --fix && bun run typecheck",
44
46
  "format": "prettier --write .",
@@ -47,7 +49,7 @@
47
49
  "prepare": "husky"
48
50
  },
49
51
  "devDependencies": {
50
- "@eslint/js": "^9.39.4",
52
+ "@eslint/js": "^10.0.1",
51
53
  "@rollup/plugin-commonjs": "^29.0.2",
52
54
  "@rollup/plugin-node-resolve": "^16.0.3",
53
55
  "@rollup/plugin-typescript": "^12.3.0",
@@ -57,28 +59,29 @@
57
59
  "@semantic-release/npm": "^13.1.5",
58
60
  "@semantic-release/release-notes-generator": "^14.1.0",
59
61
  "@types/node": "^25.5.0",
60
- "@types/sharp": "^0.32.0",
62
+ "@types/pngjs": "^6.0.5",
61
63
  "@typescript-eslint/eslint-plugin": "^8.57.2",
62
64
  "@typescript-eslint/parser": "^8.57.2",
63
- "@vitest/coverage-v8": "^3.2.4",
64
- "eslint": "^9.39.4",
65
+ "@vitest/coverage-v8": "^4.1.7",
66
+ "eslint": "^10.4.0",
65
67
  "eslint-config-prettier": "^10.1.8",
66
- "eslint-plugin-jsdoc": "^62.8.1",
68
+ "eslint-plugin-jsdoc": "^63.0.0",
67
69
  "eslint-plugin-prettier": "^5.5.5",
68
70
  "eslint-plugin-unused-imports": "^4.4.1",
69
71
  "husky": "^9.1.7",
72
+ "pixelmatch": "^7.2.0",
73
+ "pngjs": "^7.0.0",
70
74
  "prettier": "^3.8.1",
71
75
  "rollup": "^4.60.0",
72
76
  "rollup-plugin-tsconfig-paths": "^1.5.2",
73
- "semantic-release": "24.2.9",
77
+ "semantic-release": "25.0.3",
74
78
  "typescript": "^6.0.2",
75
79
  "typescript-eslint": "^8.57.2",
76
- "vitest": "^3.2.4"
80
+ "vitest": "^4.1.7"
77
81
  },
78
82
  "dependencies": {
79
83
  "comlink": "^4.4.2",
80
84
  "file-type": "^22.0.0",
81
- "sharp": "^0.34.5",
82
85
  "skia-canvas": "^3.0.8",
83
86
  "tslib": "^2.8.1",
84
87
  "yoga-layout": "^3.2.1"