+23
-3
@@ -147,6 +147,20 @@ import { PDFFont, PDFImage, PDFPage, SaveOptions, PDFDocument } from 'pdf-lib'; | ||
| }; | ||
| type Fragmentation = { | ||
| kind: "table"; | ||
| /** Table structure retained while a vstack is split across pages. */ | ||
| interface TableFragmentationMeta { | ||
| headerCount: number; | ||
| footerCount: number; | ||
| rowDivider?: Node; | ||
| } | ||
| type Fragmentation = ({ | ||
| kind: "table"; | ||
| } & TableFragmentationMeta) | { | ||
| /** | ||
| * One bounded fragment of a logical vstack supplied incrementally. | ||
| * Consecutive fragments with the same id are merged before pagination. | ||
| */ | ||
| kind: "continuation"; | ||
| id: string; | ||
| final: boolean; | ||
| /** Preserve table row fragmentation while table chunks are merged. */ | ||
| table?: TableFragmentationMeta; | ||
| }; | ||
@@ -382,2 +396,8 @@ interface BoxStyle { | ||
| /** | ||
| * Mark a bounded vstack fragment as part of one logical streamed stack. | ||
| * Consecutive fragments with the same id retain the same gap and box | ||
| * decoration semantics as a single vstack containing all children. | ||
| */ | ||
| declare function flowContinuation(node: Node, id: string, final?: boolean): Node; | ||
| /** | ||
| * Wraps children so that, under `renderFlow`, they paginate as one atomic | ||
@@ -1231,2 +1251,2 @@ * unit — if the combined height won't fit on the current page, the whole | ||
| export { type Align, type AssetSource, type BackgroundImage, type Border, type BorderSides, type BoxStyle, type BoxTransform, type BreakInside, type CellVerticalAlign, Colors, type ColumnSpec, type ColumnWidth, type CrossAxis, type DocumentMetadata, type Edges, type EdgesInput, type FlowOptions, type FlowToPdfOptions, type Fragmentation, type InlineNodeRun, type InlineVerticalAlign, type Justify, type LoadFontOptions, type MainAxis, type MainAxisLayout, type MeasureProfileEvent, type Node, type Overflow, type PageContext, type PageOptions, type PageSize, PageSizes, type ParagraphFloat, type ParagraphFloatLayout, type ParagraphItem, type ParagraphLayout, type ParagraphProps, type ParagraphRun, PdfEncryptionError, type PdfEncryptionErrorCode, type PdfEncryptionOptions, type PdfPermissions, type Position, type RGB, type RelativeLength, type RenderFlowProfileCallback, type RenderFlowProfileEvent, type RenderOptions, type RenderToPdfOptions, type SavePdfOptions, type Size, type StandardFontFamily, type StandardFontSet, type StreamFlowOptions, type StreamPageContext, type TableCell, type TableCellInput, type TableDivider, type TableOptions, type TextOptions, type TextProps, type TextRunStyle, type Theme, type ThemeColors, type ThemeFonts, type ThemeRadii, type ThemeSpacing, type ThemeType, type ThemedTextStyle, type TransformOrigin, aspectRatio, brutalistTheme, cleanTheme, defineStyles, editorialTheme, embedFont, flex, flowToPdf, formatCurrency, group, hex, hline, hstack, image, imageFit, inlineNode, keepTogether, link, linkRun, loadFont, loadImage, measure, measureContent, nodeAdapter, pageContent, pageInner, paragraph, render, renderFlow, renderToPdf, resolveMainAxis, rgb255, run, savePdf, spacer, standardFonts, streamFlow, stripeTheme, svgPath, table, text, vline, vstack }; | ||
| export { type Align, type AssetSource, type BackgroundImage, type Border, type BorderSides, type BoxStyle, type BoxTransform, type BreakInside, type CellVerticalAlign, Colors, type ColumnSpec, type ColumnWidth, type CrossAxis, type DocumentMetadata, type Edges, type EdgesInput, type FlowOptions, type FlowToPdfOptions, type Fragmentation, type InlineNodeRun, type InlineVerticalAlign, type Justify, type LoadFontOptions, type MainAxis, type MainAxisLayout, type MeasureProfileEvent, type Node, type Overflow, type PageContext, type PageOptions, type PageSize, PageSizes, type ParagraphFloat, type ParagraphFloatLayout, type ParagraphItem, type ParagraphLayout, type ParagraphProps, type ParagraphRun, PdfEncryptionError, type PdfEncryptionErrorCode, type PdfEncryptionOptions, type PdfPermissions, type Position, type RGB, type RelativeLength, type RenderFlowProfileCallback, type RenderFlowProfileEvent, type RenderOptions, type RenderToPdfOptions, type SavePdfOptions, type Size, type StandardFontFamily, type StandardFontSet, type StreamFlowOptions, type StreamPageContext, type TableCell, type TableCellInput, type TableDivider, type TableOptions, type TextOptions, type TextProps, type TextRunStyle, type Theme, type ThemeColors, type ThemeFonts, type ThemeRadii, type ThemeSpacing, type ThemeType, type ThemedTextStyle, type TransformOrigin, aspectRatio, brutalistTheme, cleanTheme, defineStyles, editorialTheme, embedFont, flex, flowContinuation, flowToPdf, formatCurrency, group, hex, hline, hstack, image, imageFit, inlineNode, keepTogether, link, linkRun, loadFont, loadImage, measure, measureContent, nodeAdapter, pageContent, pageInner, paragraph, render, renderFlow, renderToPdf, resolveMainAxis, rgb255, run, savePdf, spacer, standardFonts, streamFlow, stripeTheme, svgPath, table, text, vline, vstack }; |
+23
-3
@@ -147,6 +147,20 @@ import { PDFFont, PDFImage, PDFPage, SaveOptions, PDFDocument } from 'pdf-lib'; | ||
| }; | ||
| type Fragmentation = { | ||
| kind: "table"; | ||
| /** Table structure retained while a vstack is split across pages. */ | ||
| interface TableFragmentationMeta { | ||
| headerCount: number; | ||
| footerCount: number; | ||
| rowDivider?: Node; | ||
| } | ||
| type Fragmentation = ({ | ||
| kind: "table"; | ||
| } & TableFragmentationMeta) | { | ||
| /** | ||
| * One bounded fragment of a logical vstack supplied incrementally. | ||
| * Consecutive fragments with the same id are merged before pagination. | ||
| */ | ||
| kind: "continuation"; | ||
| id: string; | ||
| final: boolean; | ||
| /** Preserve table row fragmentation while table chunks are merged. */ | ||
| table?: TableFragmentationMeta; | ||
| }; | ||
@@ -382,2 +396,8 @@ interface BoxStyle { | ||
| /** | ||
| * Mark a bounded vstack fragment as part of one logical streamed stack. | ||
| * Consecutive fragments with the same id retain the same gap and box | ||
| * decoration semantics as a single vstack containing all children. | ||
| */ | ||
| declare function flowContinuation(node: Node, id: string, final?: boolean): Node; | ||
| /** | ||
| * Wraps children so that, under `renderFlow`, they paginate as one atomic | ||
@@ -1231,2 +1251,2 @@ * unit — if the combined height won't fit on the current page, the whole | ||
| export { type Align, type AssetSource, type BackgroundImage, type Border, type BorderSides, type BoxStyle, type BoxTransform, type BreakInside, type CellVerticalAlign, Colors, type ColumnSpec, type ColumnWidth, type CrossAxis, type DocumentMetadata, type Edges, type EdgesInput, type FlowOptions, type FlowToPdfOptions, type Fragmentation, type InlineNodeRun, type InlineVerticalAlign, type Justify, type LoadFontOptions, type MainAxis, type MainAxisLayout, type MeasureProfileEvent, type Node, type Overflow, type PageContext, type PageOptions, type PageSize, PageSizes, type ParagraphFloat, type ParagraphFloatLayout, type ParagraphItem, type ParagraphLayout, type ParagraphProps, type ParagraphRun, PdfEncryptionError, type PdfEncryptionErrorCode, type PdfEncryptionOptions, type PdfPermissions, type Position, type RGB, type RelativeLength, type RenderFlowProfileCallback, type RenderFlowProfileEvent, type RenderOptions, type RenderToPdfOptions, type SavePdfOptions, type Size, type StandardFontFamily, type StandardFontSet, type StreamFlowOptions, type StreamPageContext, type TableCell, type TableCellInput, type TableDivider, type TableOptions, type TextOptions, type TextProps, type TextRunStyle, type Theme, type ThemeColors, type ThemeFonts, type ThemeRadii, type ThemeSpacing, type ThemeType, type ThemedTextStyle, type TransformOrigin, aspectRatio, brutalistTheme, cleanTheme, defineStyles, editorialTheme, embedFont, flex, flowToPdf, formatCurrency, group, hex, hline, hstack, image, imageFit, inlineNode, keepTogether, link, linkRun, loadFont, loadImage, measure, measureContent, nodeAdapter, pageContent, pageInner, paragraph, render, renderFlow, renderToPdf, resolveMainAxis, rgb255, run, savePdf, spacer, standardFonts, streamFlow, stripeTheme, svgPath, table, text, vline, vstack }; | ||
| export { type Align, type AssetSource, type BackgroundImage, type Border, type BorderSides, type BoxStyle, type BoxTransform, type BreakInside, type CellVerticalAlign, Colors, type ColumnSpec, type ColumnWidth, type CrossAxis, type DocumentMetadata, type Edges, type EdgesInput, type FlowOptions, type FlowToPdfOptions, type Fragmentation, type InlineNodeRun, type InlineVerticalAlign, type Justify, type LoadFontOptions, type MainAxis, type MainAxisLayout, type MeasureProfileEvent, type Node, type Overflow, type PageContext, type PageOptions, type PageSize, PageSizes, type ParagraphFloat, type ParagraphFloatLayout, type ParagraphItem, type ParagraphLayout, type ParagraphProps, type ParagraphRun, PdfEncryptionError, type PdfEncryptionErrorCode, type PdfEncryptionOptions, type PdfPermissions, type Position, type RGB, type RelativeLength, type RenderFlowProfileCallback, type RenderFlowProfileEvent, type RenderOptions, type RenderToPdfOptions, type SavePdfOptions, type Size, type StandardFontFamily, type StandardFontSet, type StreamFlowOptions, type StreamPageContext, type TableCell, type TableCellInput, type TableDivider, type TableOptions, type TextOptions, type TextProps, type TextRunStyle, type Theme, type ThemeColors, type ThemeFonts, type ThemeRadii, type ThemeSpacing, type ThemeType, type ThemedTextStyle, type TransformOrigin, aspectRatio, brutalistTheme, cleanTheme, defineStyles, editorialTheme, embedFont, flex, flowContinuation, flowToPdf, formatCurrency, group, hex, hline, hstack, image, imageFit, inlineNode, keepTogether, link, linkRun, loadFont, loadImage, measure, measureContent, nodeAdapter, pageContent, pageInner, paragraph, render, renderFlow, renderToPdf, resolveMainAxis, rgb255, run, savePdf, spacer, standardFonts, streamFlow, stripeTheme, svgPath, table, text, vline, vstack }; |
+3
-1
| { | ||
| "name": "boxpdf", | ||
| "version": "1.11.0", | ||
| "version": "1.12.0", | ||
| "mcpName": "io.github.earonesty/boxpdf", | ||
@@ -62,2 +62,4 @@ "description": "Tiny box-layout DSL over pdf-lib. Flexbox-lite for server-side PDF generation in any JS runtime (Node, Cloudflare Workers, Deno, browsers).", | ||
| "typecheck": "tsc --noEmit", | ||
| "visual:check:stream": "tsx scripts/check-stream-visuals.ts", | ||
| "memory:check:continuation": "tsx scripts/check-continuation-memory.ts", | ||
| "example": "tsx examples/index.ts", | ||
@@ -64,0 +66,0 @@ "gallery": "tsx scripts/build-gallery.ts", |
+35
-0
@@ -333,2 +333,22 @@ # boxpdf | ||
| If one logical stack or table is too large to construct at once, emit bounded | ||
| pieces with `flowContinuation`. Adjacent pieces with the same id are paginated | ||
| as though they were one node, including stack gaps, decoration, table headers, | ||
| and row dividers: | ||
| ```ts | ||
| for (let offset = 0; offset < rows.length; offset += 100) { | ||
| const final = offset + 100 >= rows.length; | ||
| yield flowContinuation( | ||
| table({ columns, header, rows: rows.slice(offset, offset + 100) }), | ||
| "orders", | ||
| final | ||
| ); | ||
| } | ||
| ``` | ||
| Continuation fragments must be consecutive and the last one must set | ||
| `final: true`; `streamFlow` rejects interrupted or unfinished sequences instead | ||
| of silently producing an incomplete layout. | ||
| ### Contract | ||
@@ -355,2 +375,17 @@ | ||
| The continuation path has its own heap-capped subprocess check. Unlike the | ||
| older comparison above, it constructs every fragment lazily and forces a GC | ||
| after output to distinguish V8's allocation high-water mark from the retained | ||
| live set: | ||
| | Continuation fragments | Output pages | Sampled peak heap | Retained heap after GC | Output | | ||
| | ---: | ---: | ---: | ---: | ---: | | ||
| | 100 | 81 | ~58 MB | ~16 MB | 129 KB | | ||
| | 1000 | 810 | ~125 MB | ~26 MB | 1.3 MB | | ||
| Both runs complete with `--max-old-space-size=128`. Across the 10× workload, | ||
| the retained heap grows by about 10 MB, primarily from the final page tree and xref | ||
| index; rendered page content and continuation input are released incrementally. | ||
| Reproduce it with `pnpm memory:check:continuation`. | ||
| ## Cloudflare Workers | ||
@@ -357,0 +392,0 @@ |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
2875582
1.64%17205
2.12%488
7.73%