tabulark 0.0.4 → 0.2.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/CHANGELOG.md +81 -0
- package/README.md +316 -128
- package/THIRD_PARTY_NOTICES.md +37 -0
- package/dist/adapters.d.ts +62 -0
- package/dist/arrow.d.ts +3 -0
- package/dist/arrow.js +2 -0
- package/dist/arrow.js.map +7 -0
- package/dist/client.d.ts +145 -0
- package/dist/errors.d.ts +25 -0
- package/dist/excel.d.ts +3 -0
- package/dist/excel.js +2 -0
- package/dist/excel.js.map +7 -0
- package/dist/experimental.d.ts +13 -0
- package/dist/experimental.js +2 -0
- package/dist/experimental.js.map +7 -0
- package/dist/http.d.ts +65 -0
- package/dist/http.js +2 -0
- package/dist/http.js.map +7 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +7 -0
- package/dist/model.d.ts +392 -0
- package/dist/official-adapter-manifest.d.ts +31 -0
- package/dist/parquet.d.ts +3 -0
- package/dist/parquet.js +2 -0
- package/dist/parquet.js.map +7 -0
- package/dist/protocol.d.ts +54 -0
- package/dist/range-cache.d.ts +47 -0
- package/dist/range-source.d.ts +64 -0
- package/dist/rpc-client.d.ts +31 -0
- package/dist/source.d.ts +13 -0
- package/dist/view/accessible-grid.d.ts +36 -0
- package/dist/view/canvas-painter.d.ts +91 -0
- package/dist/view/canvas-table-view-public.d.ts +64 -0
- package/dist/view/canvas-table-view.d.ts +40 -0
- package/dist/view/controller.d.ts +34 -0
- package/dist/view/layout.d.ts +34 -0
- package/dist/view/selection.d.ts +7 -0
- package/dist/view/types.d.ts +184 -0
- package/dist/wasm/arrow/tabulark_arrow.d.ts +153 -0
- package/dist/wasm/arrow/tabulark_arrow.js +883 -0
- package/dist/wasm/arrow/tabulark_arrow_bg.wasm +0 -0
- package/dist/wasm/arrow/tabulark_arrow_bg.wasm.d.ts +30 -0
- package/dist/wasm/delimited/tabulark_delimited.d.ts +157 -0
- package/dist/wasm/delimited/tabulark_delimited.js +952 -0
- package/dist/wasm/delimited/tabulark_delimited_bg.wasm +0 -0
- package/dist/wasm/delimited/tabulark_delimited_bg.wasm.d.ts +31 -0
- package/dist/wasm/excel/tabulark_excel.d.ts +146 -0
- package/dist/wasm/excel/tabulark_excel.js +876 -0
- package/dist/wasm/excel/tabulark_excel_bg.wasm +0 -0
- package/dist/wasm/excel/tabulark_excel_bg.wasm.d.ts +30 -0
- package/dist/wasm/parquet/tabulark_parquet.d.ts +146 -0
- package/dist/wasm/parquet/tabulark_parquet.js +872 -0
- package/dist/wasm/parquet/tabulark_parquet_bg.wasm +0 -0
- package/dist/wasm/parquet/tabulark_parquet_bg.wasm.d.ts +30 -0
- package/dist/worker/blob-source-accessor.d.ts +10 -0
- package/dist/worker/source-accessor.d.ts +76 -0
- package/dist/worker/wasm-adapter.d.ts +58 -0
- package/dist/worker/worker-errors.d.ts +9 -0
- package/dist/worker-range-source.d.ts +1 -0
- package/dist/worker-range-source.js +2 -0
- package/dist/worker-range-source.js.map +7 -0
- package/dist/worker.d.ts +1 -0
- package/dist/worker.js +2 -0
- package/dist/worker.js.map +7 -0
- package/package.json +62 -12
- package/js/index.d.ts +0 -18
- package/js/index.js +0 -26
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../js/view/canvas-painter.ts", "../js/errors.ts", "../js/model.ts", "../js/view/types.ts", "../js/view/layout.ts", "../js/view/selection.ts", "../js/view/controller.ts"],
|
|
4
|
+
"sourcesContent": ["import type {\n MergedCellRegion,\n PresentationBorderSide,\n PresentationStyle,\n} from \"../model.js\";\n\nexport interface CanvasPaintColumn {\n readonly index: number;\n readonly name: string;\n /** Viewport-relative x coordinate, including the pinned row gutter offset. */\n readonly x: number;\n readonly width: number;\n readonly frozen?: boolean;\n}\n\nexport interface CanvasPaintCell {\n readonly columnIndex: number;\n readonly value: string | null | undefined;\n readonly style?: PresentationStyle;\n /** The cell is painted by its merge anchor rather than its own grid slot. */\n readonly coveredByMerge?: boolean;\n}\n\nexport interface CanvasPaintRow {\n readonly index: number;\n /** Viewport-relative y coordinate, including the pinned header offset. */\n readonly y: number;\n readonly height: number;\n readonly frozen?: boolean;\n readonly cells: readonly CanvasPaintCell[];\n}\n\nexport interface CanvasPaintMergedCell {\n readonly region: Readonly<MergedCellRegion>;\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n readonly value: string | null | undefined;\n readonly style?: PresentationStyle;\n /** A pane-clipped continuation; only the anchor fragment paints the value. */\n readonly continuation?: boolean;\n}\n\nexport interface CanvasPaintSelection {\n readonly rowStart: number;\n /** Exclusive table row bound. */\n readonly rowEnd: number;\n readonly columnStart: number;\n /** Exclusive table column bound. */\n readonly columnEnd: number;\n}\n\nexport interface CanvasPaintActiveCell {\n readonly rowIndex: number;\n readonly columnIndex: number;\n}\n\nexport interface CanvasPaintSnapshot {\n readonly width: number;\n readonly height: number;\n readonly headerHeight: number;\n readonly rowGutterWidth: number;\n readonly columns: readonly CanvasPaintColumn[];\n readonly rows: readonly CanvasPaintRow[];\n readonly mergedCells?: readonly CanvasPaintMergedCell[];\n readonly selection?: CanvasPaintSelection;\n readonly activeCell?: CanvasPaintActiveCell;\n readonly busy: boolean;\n}\n\nexport interface CanvasTableTheme {\n readonly background: string;\n readonly foreground: string;\n readonly mutedForeground: string;\n readonly headerBackground: string;\n readonly headerForeground: string;\n readonly alternateRowBackground: string;\n readonly gridLine: string;\n readonly selectionBackground: string;\n readonly selectionBorder: string;\n readonly activeCellBorder: string;\n readonly loadingBackground: string;\n readonly font: string;\n readonly headerFont: string;\n}\n\nexport const DEFAULT_CANVAS_TABLE_THEME: Readonly<CanvasTableTheme> = Object.freeze({\n background: \"#ffffff\",\n foreground: \"#172033\",\n mutedForeground: \"#667085\",\n headerBackground: \"#f2f4f7\",\n headerForeground: \"#344054\",\n alternateRowBackground: \"#f9fafb\",\n gridLine: \"#d0d5dd\",\n selectionBackground: \"rgba(21, 112, 239, 0.14)\",\n selectionBorder: \"#1570ef\",\n activeCellBorder: \"#175cd3\",\n loadingBackground: \"#e4e7ec\",\n font: '13px ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif',\n headerFont: '600 13px ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif',\n});\n\n/** Resolves author-independent system colors for Windows High Contrast and other forced palettes. */\nexport function forcedColorsCanvasTableTheme(\n base: Readonly<CanvasTableTheme> = DEFAULT_CANVAS_TABLE_THEME,\n): Readonly<CanvasTableTheme> {\n return Object.freeze({\n ...base,\n background: \"Canvas\",\n foreground: \"CanvasText\",\n mutedForeground: \"GrayText\",\n headerBackground: \"Canvas\",\n headerForeground: \"CanvasText\",\n alternateRowBackground: \"Canvas\",\n gridLine: \"CanvasText\",\n selectionBackground: \"Highlight\",\n selectionBorder: \"Highlight\",\n activeCellBorder: \"CanvasText\",\n loadingBackground: \"GrayText\",\n });\n}\n\n/** Paints one viewport frame and keeps the backing store device-pixel aware. */\nexport class CanvasTablePainter {\n readonly canvas: HTMLCanvasElement;\n readonly #context: CanvasRenderingContext2D;\n #theme: Readonly<CanvasTableTheme>;\n readonly #maxDevicePixelRatio: number;\n #forcedColors: boolean;\n\n #cssWidth = 0;\n #cssHeight = 0;\n #devicePixelRatio = 1;\n\n constructor(\n canvas: HTMLCanvasElement,\n options: {\n readonly theme?: Partial<CanvasTableTheme>;\n readonly maxDevicePixelRatio?: number;\n readonly forcedColors?: boolean;\n } = {},\n ) {\n const context = canvas.getContext(\"2d\", { alpha: false });\n if (context === null) {\n throw new Error(\"Tabulark Canvas rendering requires a 2D rendering context\");\n }\n this.canvas = canvas;\n this.#context = context;\n this.#theme = Object.freeze({ ...DEFAULT_CANVAS_TABLE_THEME, ...options.theme });\n this.#maxDevicePixelRatio = positive(options.maxDevicePixelRatio, Number.POSITIVE_INFINITY);\n this.#forcedColors = options.forcedColors ?? false;\n }\n\n setTheme(theme: Readonly<CanvasTableTheme>, options: { readonly forcedColors?: boolean } = {}): void {\n this.#theme = Object.freeze({ ...theme });\n this.#forcedColors = options.forcedColors ?? false;\n }\n\n paint(snapshot: CanvasPaintSnapshot): void {\n this.#resize(snapshot.width, snapshot.height);\n const context = this.#context;\n const theme = this.#theme;\n\n context.save();\n context.setTransform(\n this.#devicePixelRatio,\n 0,\n 0,\n this.#devicePixelRatio,\n 0,\n 0,\n );\n context.clearRect(0, 0, snapshot.width, snapshot.height);\n context.fillStyle = theme.background;\n context.fillRect(0, 0, snapshot.width, snapshot.height);\n\n this.#paintRows(snapshot);\n this.#paintHeader(snapshot);\n this.#paintGrid(snapshot);\n this.#paintMergedCells(snapshot);\n this.#paintSelection(snapshot);\n context.restore();\n }\n\n #resize(width: number, height: number): void {\n const view = this.canvas.ownerDocument.defaultView;\n const browserRatio = view?.devicePixelRatio ?? 1;\n const ratio = Math.max(1, Math.min(browserRatio, this.#maxDevicePixelRatio));\n const cssWidth = Math.max(0, Math.floor(width));\n const cssHeight = Math.max(0, Math.floor(height));\n const pixelWidth = Math.max(1, Math.round(cssWidth * ratio));\n const pixelHeight = Math.max(1, Math.round(cssHeight * ratio));\n\n if (\n cssWidth === this.#cssWidth &&\n cssHeight === this.#cssHeight &&\n ratio === this.#devicePixelRatio &&\n this.canvas.width === pixelWidth &&\n this.canvas.height === pixelHeight\n ) {\n return;\n }\n\n this.#cssWidth = cssWidth;\n this.#cssHeight = cssHeight;\n this.#devicePixelRatio = ratio;\n this.canvas.width = pixelWidth;\n this.canvas.height = pixelHeight;\n this.canvas.style.width = `${cssWidth}px`;\n this.canvas.style.height = `${cssHeight}px`;\n }\n\n #paintRows(snapshot: CanvasPaintSnapshot): void {\n const context = this.#context;\n const theme = this.#theme;\n const columnsByIndex = new Map(snapshot.columns.map((column) => [column.index, column]));\n context.font = theme.font;\n context.textBaseline = \"middle\";\n\n const rows = [\n ...snapshot.rows.filter((row) => row.frozen !== true),\n ...snapshot.rows.filter((row) => row.frozen === true),\n ];\n for (const row of rows) {\n if (row.y + row.height <= snapshot.headerHeight || row.y >= snapshot.height) {\n continue;\n }\n context.fillStyle = row.index % 2 === 0 ? theme.background : theme.alternateRowBackground;\n context.fillRect(0, row.y, snapshot.width, row.height);\n\n context.fillStyle = theme.mutedForeground;\n context.textAlign = \"right\";\n context.fillText(\n String(row.index + 1),\n snapshot.rowGutterWidth - 10,\n row.y + row.height / 2,\n );\n\n const cells = [\n ...row.cells.filter((cell) => columnsByIndex.get(cell.columnIndex)?.frozen !== true),\n ...row.cells.filter((cell) => columnsByIndex.get(cell.columnIndex)?.frozen === true),\n ];\n for (const cell of cells) {\n const column = columnsByIndex.get(cell.columnIndex);\n if (\n column === undefined\n || column.x + column.width <= snapshot.rowGutterWidth\n || cell.coveredByMerge === true\n ) {\n continue;\n }\n this.#paintCellValue(\n cell.value,\n column.x,\n row.y,\n column.width,\n row.height,\n cell.style,\n );\n }\n }\n }\n\n #paintCellValue(\n value: string | null | undefined,\n x: number,\n y: number,\n width: number,\n height: number,\n style?: PresentationStyle,\n ): void {\n const context = this.#context;\n const theme = this.#theme;\n const horizontalPadding = 10;\n if (width <= horizontalPadding * 2) {\n return;\n }\n\n context.save();\n context.beginPath();\n context.rect(x + 1, y + 1, Math.max(0, width - 2), Math.max(0, height - 2));\n context.clip();\n this.#paintCellFill(x, y, width, height, style);\n this.#applyCellFont(style);\n context.textAlign = horizontalAlignment(style);\n context.textBaseline = verticalBaseline(style);\n if (value === undefined) {\n context.fillStyle = theme.loadingBackground;\n const skeletonWidth = Math.max(12, Math.min(width - horizontalPadding * 2, width * 0.42));\n context.fillRect(x + horizontalPadding, y + height / 2 - 3, skeletonWidth, 6);\n } else {\n context.fillStyle = value === null\n ? theme.mutedForeground\n : this.#cellForeground(style, theme.foreground);\n const label = value === null ? \"\u2205\" : value;\n const textX = horizontalTextX(context.textAlign, x, width, horizontalPadding);\n const textY = verticalTextY(context.textBaseline, y, height, 4);\n context.fillText(label, textX, textY, Math.max(0, width - horizontalPadding * 2));\n if (style?.font?.underline === true) {\n const measured = Math.min(context.measureText(label).width, width - horizontalPadding * 2);\n const start = underlineStart(context.textAlign, textX, measured);\n context.strokeStyle = String(context.fillStyle);\n context.lineWidth = 1;\n context.beginPath();\n context.moveTo(start, Math.min(y + height - 4, textY + 3));\n context.lineTo(start + measured, Math.min(y + height - 4, textY + 3));\n context.stroke();\n }\n }\n this.#paintCellBorders(x, y, width, height, style);\n context.restore();\n }\n\n #paintMergedCells(snapshot: CanvasPaintSnapshot): void {\n for (const merged of snapshot.mergedCells ?? []) {\n if (\n merged.width <= 0\n || merged.height <= 0\n || merged.x + merged.width <= snapshot.rowGutterWidth\n || merged.y + merged.height <= snapshot.headerHeight\n || merged.x >= snapshot.width\n || merged.y >= snapshot.height\n ) {\n continue;\n }\n this.#context.fillStyle = merged.region.rowStart % 2 === 0\n ? this.#theme.background\n : this.#theme.alternateRowBackground;\n this.#context.fillRect(merged.x, merged.y, merged.width, merged.height);\n if (merged.continuation === true) {\n this.#paintCellFill(merged.x, merged.y, merged.width, merged.height, merged.style);\n this.#paintCellBorders(merged.x, merged.y, merged.width, merged.height, merged.style);\n } else {\n this.#paintCellValue(\n merged.value,\n merged.x,\n merged.y,\n merged.width,\n merged.height,\n merged.style,\n );\n }\n this.#context.strokeStyle = this.#theme.gridLine;\n this.#context.lineWidth = 1 / this.#devicePixelRatio;\n this.#context.strokeRect(\n merged.x + 0.5 / this.#devicePixelRatio,\n merged.y + 0.5 / this.#devicePixelRatio,\n Math.max(0, merged.width - 1 / this.#devicePixelRatio),\n Math.max(0, merged.height - 1 / this.#devicePixelRatio),\n );\n }\n }\n\n #paintCellFill(\n x: number,\n y: number,\n width: number,\n height: number,\n style: PresentationStyle | undefined,\n ): void {\n if (this.#forcedColors || style === undefined) return;\n const color = cssColor(style.fillColor ?? style.backgroundColor);\n if (color === undefined) return;\n this.#context.fillStyle = color;\n this.#context.fillRect(x + 1, y + 1, Math.max(0, width - 2), Math.max(0, height - 2));\n }\n\n #applyCellFont(style: PresentationStyle | undefined): void {\n if (style?.font === undefined) {\n this.#context.font = this.#theme.font;\n return;\n }\n const font = style.font;\n const size = finitePositive(font.size) ?? 13;\n const family = font.family && font.family.trim().length > 0\n ? font.family\n : 'ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", sans-serif';\n this.#context.font = `${font.italic === true ? \"italic \" : \"\"}${font.bold === true ? \"700 \" : \"400 \"}${size}px ${family}`;\n }\n\n #cellForeground(style: PresentationStyle | undefined, fallback: string): string {\n if (this.#forcedColors) return fallback;\n return cssColor(style?.font?.color)\n ?? cssColor(style?.foregroundColor)\n ?? fallback;\n }\n\n #paintCellBorders(\n x: number,\n y: number,\n width: number,\n height: number,\n style: PresentationStyle | undefined,\n ): void {\n if (style?.borders === undefined) return;\n const context = this.#context;\n const sides = style.borders;\n const paint = (\n side: \"top\" | \"right\" | \"bottom\" | \"left\",\n startX: number,\n startY: number,\n endX: number,\n endY: number,\n ) => {\n const border = sides[side];\n if (border === undefined || border.style === \"none\") return;\n context.save();\n const widthForStyle = borderWidth(border.style);\n context.lineWidth = widthForStyle;\n context.strokeStyle = this.#forcedColors\n ? this.#theme.gridLine\n : cssColor(border.color) ?? this.#theme.gridLine;\n context.setLineDash(borderDash(border.style));\n context.beginPath();\n context.moveTo(startX, startY);\n context.lineTo(endX, endY);\n context.stroke();\n if (border.style === \"double\") {\n const offset = Math.max(2, widthForStyle + 1);\n const horizontal = startY === endY;\n context.beginPath();\n context.moveTo(horizontal ? startX : startX + offset, horizontal ? startY + offset : startY);\n context.lineTo(horizontal ? endX : endX + offset, horizontal ? endY + offset : endY);\n context.stroke();\n }\n context.restore();\n };\n paint(\"top\", x + 0.5, y + 0.5, x + width - 0.5, y + 0.5);\n paint(\"right\", x + width - 0.5, y + 0.5, x + width - 0.5, y + height - 0.5);\n paint(\"bottom\", x + 0.5, y + height - 0.5, x + width - 0.5, y + height - 0.5);\n paint(\"left\", x + 0.5, y + 0.5, x + 0.5, y + height - 0.5);\n }\n\n #paintHeader(snapshot: CanvasPaintSnapshot): void {\n const context = this.#context;\n const theme = this.#theme;\n context.fillStyle = theme.headerBackground;\n context.fillRect(0, 0, snapshot.width, snapshot.headerHeight);\n context.font = theme.headerFont;\n context.fillStyle = theme.headerForeground;\n context.textBaseline = \"middle\";\n context.textAlign = \"left\";\n\n const columns = [\n ...snapshot.columns.filter((column) => column.frozen !== true),\n ...snapshot.columns.filter((column) => column.frozen === true),\n ];\n for (const column of columns) {\n if (column.x + column.width <= snapshot.rowGutterWidth || column.x >= snapshot.width) {\n continue;\n }\n context.save();\n context.beginPath();\n context.rect(column.x + 1, 0, Math.max(0, column.width - 2), snapshot.headerHeight);\n context.clip();\n context.fillText(column.name, column.x + 10, snapshot.headerHeight / 2);\n context.restore();\n }\n\n context.textAlign = \"center\";\n context.fillText(\n \"#\",\n snapshot.rowGutterWidth / 2,\n snapshot.headerHeight / 2,\n snapshot.rowGutterWidth,\n );\n }\n\n #paintGrid(snapshot: CanvasPaintSnapshot): void {\n const context = this.#context;\n const theme = this.#theme;\n context.strokeStyle = theme.gridLine;\n context.lineWidth = 1 / this.#devicePixelRatio;\n context.beginPath();\n\n const snap = 0.5 / this.#devicePixelRatio;\n context.moveTo(snapshot.rowGutterWidth + snap, 0);\n context.lineTo(snapshot.rowGutterWidth + snap, snapshot.height);\n context.moveTo(0, snapshot.headerHeight + snap);\n context.lineTo(snapshot.width, snapshot.headerHeight + snap);\n\n for (const column of snapshot.columns) {\n const x = column.x + column.width + snap;\n if (x > snapshot.rowGutterWidth && x < snapshot.width) {\n context.moveTo(x, 0);\n context.lineTo(x, snapshot.height);\n }\n }\n for (const row of snapshot.rows) {\n const y = row.y + row.height + snap;\n if (y > snapshot.headerHeight && y < snapshot.height) {\n context.moveTo(0, y);\n context.lineTo(snapshot.width, y);\n }\n }\n context.stroke();\n }\n\n #paintSelection(snapshot: CanvasPaintSnapshot): void {\n const selection = snapshot.selection;\n const context = this.#context;\n const theme = this.#theme;\n if (selection !== undefined) {\n const selectedColumns = snapshot.columns.filter(\n (column) => column.index >= selection.columnStart && column.index < selection.columnEnd,\n );\n const selectedRows = snapshot.rows.filter(\n (row) => row.index >= selection.rowStart && row.index < selection.rowEnd,\n );\n if (selectedColumns.length > 0 && selectedRows.length > 0) {\n const firstColumn = selectedColumns[0]!;\n const lastColumn = selectedColumns.at(-1)!;\n const firstRow = selectedRows[0]!;\n const lastRow = selectedRows.at(-1)!;\n const x = Math.max(snapshot.rowGutterWidth, firstColumn.x);\n const y = Math.max(snapshot.headerHeight, firstRow.y);\n const right = Math.min(snapshot.width, lastColumn.x + lastColumn.width);\n const bottom = Math.min(snapshot.height, lastRow.y + lastRow.height);\n if (right > x && bottom > y) {\n context.save();\n context.fillStyle = theme.selectionBackground;\n if (this.#forcedColors) {\n context.globalAlpha = 0.28;\n }\n context.fillRect(x, y, right - x, bottom - y);\n context.restore();\n context.strokeStyle = theme.selectionBorder;\n context.lineWidth = this.#forcedColors ? 2 : 1;\n context.setLineDash(this.#forcedColors ? [4, 2] : []);\n context.strokeRect(\n x + context.lineWidth / 2,\n y + context.lineWidth / 2,\n Math.max(0, right - x - context.lineWidth),\n Math.max(0, bottom - y - context.lineWidth),\n );\n context.setLineDash([]);\n }\n }\n }\n\n const activeMerges = snapshot.activeCell === undefined\n ? []\n : snapshot.mergedCells?.filter((merged) => (\n snapshot.activeCell!.rowIndex >= merged.region.rowStart\n && snapshot.activeCell!.rowIndex < merged.region.rowEnd\n && snapshot.activeCell!.columnIndex >= merged.region.columnStart\n && snapshot.activeCell!.columnIndex < merged.region.columnEnd\n )) ?? [];\n const activeColumn = snapshot.activeCell === undefined\n ? undefined\n : snapshot.columns.find((column) => column.index === snapshot.activeCell!.columnIndex);\n const activeRow = snapshot.activeCell === undefined\n ? undefined\n : snapshot.rows.find((row) => row.index === snapshot.activeCell!.rowIndex);\n const activeRects = activeMerges.length > 0\n ? activeMerges\n : activeColumn !== undefined && activeRow !== undefined\n ? [{\n x: activeColumn.x,\n y: activeRow.y,\n width: activeColumn.width,\n height: activeRow.height,\n }]\n : [];\n for (const activeRect of activeRects) {\n const activeX = Math.max(snapshot.rowGutterWidth, activeRect.x);\n const activeY = Math.max(snapshot.headerHeight, activeRect.y);\n const activeRight = Math.min(snapshot.width, activeRect.x + activeRect.width);\n const activeBottom = Math.min(snapshot.height, activeRect.y + activeRect.height);\n context.strokeStyle = theme.activeCellBorder;\n context.lineWidth = this.#forcedColors ? 3 : 2;\n context.setLineDash([]);\n context.strokeRect(\n activeX + context.lineWidth / 2,\n activeY + context.lineWidth / 2,\n Math.max(0, activeRight - activeX - context.lineWidth),\n Math.max(0, activeBottom - activeY - context.lineWidth),\n );\n }\n }\n}\n\nfunction cssColor(color: { readonly css?: string } | undefined): string | undefined {\n const value = color?.css?.trim();\n if (!value) return undefined;\n const supports = globalThis.CSS?.supports;\n return typeof supports !== \"function\" || supports(\"color\", value) ? value : undefined;\n}\n\nfunction finitePositive(value: number | undefined): number | undefined {\n return value !== undefined && Number.isFinite(value) && value > 0 ? value : undefined;\n}\n\nfunction horizontalAlignment(style: PresentationStyle | undefined): CanvasTextAlign {\n switch (style?.horizontalAlignment) {\n case \"center\":\n return \"center\";\n case \"right\":\n return \"right\";\n case \"left\":\n case \"justify\":\n case \"general\":\n default:\n return \"left\";\n }\n}\n\nfunction verticalBaseline(style: PresentationStyle | undefined): CanvasTextBaseline {\n switch (style?.verticalAlignment) {\n case \"top\":\n return \"top\";\n case \"bottom\":\n return \"bottom\";\n case \"center\":\n case \"justify\":\n default:\n return \"middle\";\n }\n}\n\nfunction horizontalTextX(\n alignment: CanvasTextAlign,\n x: number,\n width: number,\n padding: number,\n): number {\n if (alignment === \"center\") return x + width / 2;\n if (alignment === \"right\" || alignment === \"end\") return x + width - padding;\n return x + padding;\n}\n\nfunction verticalTextY(\n baseline: CanvasTextBaseline,\n y: number,\n height: number,\n padding: number,\n): number {\n if (baseline === \"top\" || baseline === \"hanging\") return y + padding;\n if (baseline === \"bottom\" || baseline === \"ideographic\") return y + height - padding;\n return y + height / 2;\n}\n\nfunction underlineStart(alignment: CanvasTextAlign, textX: number, width: number): number {\n if (alignment === \"center\") return textX - width / 2;\n if (alignment === \"right\" || alignment === \"end\") return textX - width;\n return textX;\n}\n\nfunction borderWidth(style: PresentationBorderSide[\"style\"]): number {\n switch (style) {\n case \"medium\":\n return 2;\n case \"thick\":\n return 3;\n case \"double\":\n return 1;\n default:\n return 1;\n }\n}\n\nfunction borderDash(style: string | undefined): readonly number[] {\n if (style === \"dashed\") return [4, 2];\n if (style === \"dotted\") return [1, 2];\n return [];\n}\n\nfunction positive(value: number | undefined, fallback: number): number {\n return value !== undefined && Number.isFinite(value) && value > 0 ? value : fallback;\n}\n", "import type { SerializedError } from \"./protocol.js\";\n\nexport type TabularkErrorCode =\n | \"INVALID_ARGUMENT\"\n | \"INVALID_RANGE\"\n | \"RANGE_NOT_INDEXED\"\n | \"RESOURCE_LIMIT\"\n | \"CANCELLED\"\n | \"HANDLE_CLOSED\"\n | \"PROTOCOL_INCOMPATIBLE\"\n | \"PARSE_FAILED\"\n | \"UNSUPPORTED_FEATURE\"\n | \"UNSUPPORTED_RUNTIME\"\n | \"RUNTIME_FAILURE\"\n /** A remote/source provider could not be reached or did not return bytes. */\n | \"SOURCE_UNAVAILABLE\"\n /** The provider validator or total length changed while a reader was open. */\n | \"SOURCE_CHANGED\"\n /** The provider did not honor the required single-range protocol. */\n | \"RANGE_UNSUPPORTED\"\n | (string & {});\n\n/** A stable, serializable error returned by Tabulark. */\nexport class TabularkError extends Error {\n readonly code: TabularkErrorCode;\n readonly retryable: boolean;\n readonly details?: unknown;\n\n constructor(\n code: TabularkErrorCode,\n message: string,\n options: { retryable?: boolean; details?: unknown; cause?: unknown } = {},\n ) {\n super(message, { cause: options.cause });\n this.name = \"TabularkError\";\n this.code = code;\n this.retryable = options.retryable ?? false;\n this.details = code === \"RESOURCE_LIMIT\"\n ? normalizeResourceLimitDetails(options.details)\n : options.details;\n }\n\n static fromSerialized(error: SerializedError): TabularkError {\n return new TabularkError(error.code, error.message, {\n retryable: error.retryable,\n details: error.details,\n });\n }\n}\n\n/** @internal Ensures every resource-limit error has a stable capacity shape. */\nexport function normalizeResourceLimitDetails(details: unknown): Readonly<Record<string, unknown>> {\n const raw = isRecord(details) ? details : {};\n const resource = typeof raw.resource === \"string\" && raw.resource.length > 0\n ? raw.resource\n : typeof raw.resourceCategory === \"string\" && raw.resourceCategory.length > 0\n ? raw.resourceCategory\n : inferResource(raw);\n if (isQuantity(raw.requiredBytes) && isQuantity(raw.availableBytes)) {\n return Object.freeze({ ...raw, resource });\n }\n if (isQuantity(raw.required) && isQuantity(raw.available)) {\n return Object.freeze({ ...raw, resource });\n }\n\n const byteLimit = firstQuantity(raw, [\n \"maxDecodedBytes\",\n \"maxOutputBytes\",\n \"maxMetadataBytes\",\n \"maxBlockBytes\",\n \"maxDisplayCellBytes\",\n \"maxDisplayBytes\",\n \"maxSourceBytes\",\n \"maxFieldBytes\",\n \"maxBatchBytes\",\n \"maxOperationBytes\",\n \"maxZipEntryBytes\",\n \"maxZipUncompressedBytes\",\n \"maxCfbStreamBytes\",\n ]);\n if (byteLimit !== undefined) {\n const requiredBytes = firstQuantity(raw, [\n \"decodedBytes\",\n \"outputBytes\",\n \"metadataBytes\",\n \"blockBytes\",\n \"displayCellBytes\",\n \"displayBytes\",\n \"sourceBytes\",\n \"fieldBytes\",\n \"batchBytes\",\n \"operationBytes\",\n ]) ?? byteLimit + 1;\n return Object.freeze({\n ...raw,\n resource,\n requiredBytes,\n availableBytes: byteLimit,\n });\n }\n\n const available = firstQuantity(raw, [\n \"limit\",\n \"maxCells\",\n \"maxRangeCells\",\n \"maxSources\",\n \"maxActiveRanges\",\n \"maxRangeWaiters\",\n \"maxColumns\",\n \"maxFields\",\n \"maxNestingDepth\",\n \"maxWorksheetRows\",\n \"maxWorksheetColumns\",\n \"maxStyles\",\n \"maxMergedRegions\",\n ]) ?? 0;\n const required = firstQuantity(raw, [\n \"cells\",\n \"cellCount\",\n \"visibleCellCount\",\n \"sources\",\n \"activeRanges\",\n \"rangeWaiters\",\n \"columns\",\n \"fields\",\n \"nestingDepth\",\n \"worksheetRows\",\n \"worksheetColumns\",\n \"styles\",\n \"mergedRegions\",\n ]) ?? available + 1;\n return Object.freeze({ ...raw, resource, required, available });\n}\n\nfunction inferResource(details: Record<string, unknown>): string {\n const keys = Object.keys(details).join(\" \").toLowerCase();\n if (keys.includes(\"source\")) return keys.includes(\"byte\") ? \"source-staging\" : \"source-slots\";\n if (keys.includes(\"metadata\")) return \"metadata\";\n if (keys.includes(\"decoded\") || keys.includes(\"decompress\")) return \"decompression\";\n if (keys.includes(\"display\")) return \"display-values\";\n if (keys.includes(\"field\")) return \"field\";\n if (keys.includes(\"batch\")) return \"batch\";\n if (keys.includes(\"range\") || keys.includes(\"cell\")) return \"range-cells\";\n if (keys.includes(\"column\")) return \"columns\";\n if (keys.includes(\"nest\")) return \"descriptor-nesting\";\n if (keys.includes(\"worksheet\")) return \"worksheet-dimensions\";\n return \"adapter-resource\";\n}\n\nfunction firstQuantity(\n details: Record<string, unknown>,\n names: readonly string[],\n): number | undefined {\n for (const name of names) {\n if (isQuantity(details[name])) return details[name] as number;\n }\n return undefined;\n}\n\nfunction isQuantity(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value) && value >= 0;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function cancelledError(): TabularkError {\n return new TabularkError(\"CANCELLED\", \"The operation was cancelled\");\n}\n\nexport function closedError(resource: string): TabularkError {\n return new TabularkError(\"HANDLE_CLOSED\", `${resource} is closed`);\n}\n\nexport function invalidArgument(message: string, details?: unknown): TabularkError {\n return new TabularkError(\"INVALID_ARGUMENT\", message, { details });\n}\n", "import { TabularkError, invalidArgument } from \"./errors.js\";\nimport { BATCH_LAYOUT_VERSION } from \"./protocol.js\";\n\nexport const DEFAULT_MEMORY_BUDGET_BYTES = 256 * 1024 * 1024;\nexport const MAX_ARRAY_BUFFER_BYTES = 128 * 1024 * 1024;\nexport const MAX_RANGE_CELLS = 250_000;\nexport const DEFAULT_TO_ROWS_CELL_LIMIT = 10_000;\nexport const MAX_NESTING_DEPTH = 64;\n\nconst INDEX_BUDGET_MAX_BYTES = 64 * 1024 * 1024;\nconst ADAPTER_TILE_CACHE_MAX_BYTES = 96 * 1024 * 1024;\nconst MAIN_THREAD_RANGE_CACHE_MAX_BYTES = 32 * 1024 * 1024;\nconst FIELD_AND_BATCH_MAX_BYTES = 8 * 1024 * 1024;\n\n// Batch values are decoded one cell at a time by the logical facade. Reusing\n// these immutable helpers avoids constructing a TextDecoder/DataView for every\n// UTF-8 value and primitive read while keeping the cache weakly tied to the\n// transferred backing buffer's lifetime.\nconst UTF8_DECODER = new TextDecoder();\nconst DATA_VIEW_CACHE = new WeakMap<object, Map<number, Map<number, DataView>>>();\n\nexport const MAX_SOURCES = 2;\nexport const MAX_ACTIVE_RANGES = 2;\nexport const MAX_RANGE_WAITERS = 8;\n\nexport interface MemoryBudgetLimits {\n readonly memoryBudgetBytes: number;\n /** Cross-thread accounting slices used by RangeSource brokers. */\n readonly workerBudgetBytes: number;\n readonly mainThreadSourceBytes: number;\n readonly mainThreadRetainedBytes: number;\n readonly sourceRangeCacheBytes: number;\n /** Shared retained capacity allocated among the adapters actually registered. */\n readonly adapterRuntimePoolBytes: number;\n /** Maximum transient/decoded budget retained by one active adapter operation. */\n readonly operationBudgetBytes: number;\n readonly indexBudgetBytes: number;\n readonly adapterTileCacheBudgetBytes: number;\n readonly mainThreadRangeCacheBytes: number;\n readonly maxFieldBytes: number;\n readonly maxBatchBytes: number;\n readonly maxArrayBufferBytes: number;\n readonly maxSources: number;\n readonly maxActiveRanges: number;\n readonly maxRangeWaiters: number;\n}\n\n/** Derives every bounded runtime allocation from one engine-wide budget. */\nexport function deriveMemoryBudgetLimits(memoryBudgetBytes: number): MemoryBudgetLimits {\n assertPositiveSafeInteger(memoryBudgetBytes, \"memoryBudgetBytes\");\n const oneEighth = Math.floor(memoryBudgetBytes / 8);\n const oneThirtySecond = Math.floor(memoryBudgetBytes / 32);\n // The Worker allocates this pool through one reservation ledger using the\n // adapters actually registered for an engine. This deliberately avoids a\n // hard-coded split based on a historic number of built-in adapters.\n const adapterRuntimePoolBytes = Math.max(1, Math.floor(memoryBudgetBytes / 2));\n const operationBudgetBytes = Math.max(1, Math.floor(memoryBudgetBytes / 8));\n const workerBudgetBytes = Math.max(1, Math.floor(memoryBudgetBytes * 3 / 4));\n const mainThreadSourceBytes = Math.max(1, oneEighth);\n const mainThreadRetainedBytes = Math.max(\n 1,\n memoryBudgetBytes - workerBudgetBytes - mainThreadSourceBytes,\n );\n return Object.freeze({\n memoryBudgetBytes,\n workerBudgetBytes,\n mainThreadSourceBytes,\n mainThreadRetainedBytes,\n sourceRangeCacheBytes: Math.max(1, Math.floor(workerBudgetBytes / 8)),\n adapterRuntimePoolBytes,\n operationBudgetBytes,\n indexBudgetBytes: Math.min(INDEX_BUDGET_MAX_BYTES, oneEighth),\n adapterTileCacheBudgetBytes: Math.min(ADAPTER_TILE_CACHE_MAX_BYTES, operationBudgetBytes),\n mainThreadRangeCacheBytes: Math.min(MAIN_THREAD_RANGE_CACHE_MAX_BYTES, oneEighth),\n maxFieldBytes: Math.min(FIELD_AND_BATCH_MAX_BYTES, oneThirtySecond),\n maxBatchBytes: Math.min(FIELD_AND_BATCH_MAX_BYTES, oneThirtySecond),\n maxArrayBufferBytes: Math.min(MAX_ARRAY_BUFFER_BYTES, Math.floor(memoryBudgetBytes / 2)),\n maxSources: MAX_SOURCES,\n maxActiveRanges: MAX_ACTIVE_RANGES,\n maxRangeWaiters: MAX_RANGE_WAITERS,\n });\n}\n\nexport type MemoryResourceKind =\n | \"adapter-runtime\"\n | \"source-staging\"\n | \"compressed-page\"\n | \"decompression\"\n | \"batch\";\n\nexport interface MemoryReservation {\n readonly resource: MemoryResourceKind;\n readonly bytes: number;\n release(): void;\n}\n\n/**\n * Single-accounting ledger for Worker-owned bounded allocations.\n *\n * A reservation is deliberately idempotent so cancellation, close and failure\n * races can all execute their normal cleanup paths without double accounting.\n */\nexport class MemoryReservationLedger {\n readonly #capacityBytes: number;\n #usedBytes = 0;\n\n constructor(capacityBytes: number) {\n assertPositiveSafeInteger(capacityBytes, \"capacityBytes\");\n this.#capacityBytes = capacityBytes;\n }\n\n get capacityBytes(): number {\n return this.#capacityBytes;\n }\n\n get usedBytes(): number {\n return this.#usedBytes;\n }\n\n get availableBytes(): number {\n return this.#capacityBytes - this.#usedBytes;\n }\n\n reserve(resource: MemoryResourceKind, bytes: number): MemoryReservation {\n if (!Number.isSafeInteger(bytes) || bytes < 0) {\n throw invalidArgument(\"Reservation bytes must be a non-negative safe integer\");\n }\n const availableBytes = this.availableBytes;\n if (bytes > availableBytes) {\n throw new TabularkError(\n \"RESOURCE_LIMIT\",\n `Insufficient memory reservation capacity for ${resource}`,\n { details: { resource, requiredBytes: bytes, availableBytes } },\n );\n }\n this.#usedBytes += bytes;\n let released = false;\n return Object.freeze({\n resource,\n bytes,\n release: () => {\n if (released) return;\n released = true;\n this.#usedBytes -= bytes;\n },\n });\n }\n}\n\nexport type AxisExtent =\n | Readonly<{ kind: \"exact\"; value: number }>\n | Readonly<{ kind: \"at-least\"; value: number }>\n | Readonly<{ kind: \"unknown\" }>;\n\nexport interface TableExtent {\n readonly rows: AxisExtent;\n readonly columns: AxisExtent;\n}\n\nexport type TimeUnit = \"second\" | \"millisecond\" | \"microsecond\" | \"nanosecond\";\nexport type IntervalUnit = \"year-month\" | \"day-time\" | \"month-day-nano\";\n\nexport interface ArrowField {\n readonly name: string;\n readonly nullable: boolean;\n readonly dataType: ArrowDataType;\n readonly metadata?: Readonly<Record<string, string>>;\n}\n\ninterface SimpleDataType<Type extends string> {\n readonly type: Type;\n}\n\n/** A recursive representation of every arrow-schema 59.1.0 built-in DataType. */\nexport type ArrowDataType =\n | SimpleDataType<\n | \"null\"\n | \"unknown\"\n | \"boolean\"\n | \"int8\"\n | \"int16\"\n | \"int32\"\n | \"int64\"\n | \"uint8\"\n | \"uint16\"\n | \"uint32\"\n | \"uint64\"\n | \"float16\"\n | \"float32\"\n | \"float64\"\n | \"date32\"\n | \"date64\"\n | \"binary\"\n | \"large-binary\"\n | \"binary-view\"\n | \"utf8\"\n | \"large-utf8\"\n | \"utf8-view\"\n >\n | Readonly<{ type: \"timestamp\"; unit: TimeUnit; timezone?: string }>\n | Readonly<{ type: \"time32\" | \"time64\" | \"duration\"; unit: TimeUnit }>\n | Readonly<{ type: \"interval\"; unit: IntervalUnit }>\n | Readonly<{ type: \"fixed-size-binary\"; byteWidth: number }>\n | Readonly<{ type: \"decimal32\" | \"decimal64\" | \"decimal128\" | \"decimal256\"; precision: number; scale: number }>\n | Readonly<{ type: \"list\" | \"large-list\" | \"list-view\" | \"large-list-view\"; field: ArrowField }>\n | Readonly<{ type: \"fixed-size-list\"; field: ArrowField; listSize: number }>\n | Readonly<{ type: \"struct\"; fields: readonly ArrowField[] }>\n | Readonly<{\n type: \"union\";\n mode: \"sparse\" | \"dense\";\n fields: readonly Readonly<{ typeId: number; field: ArrowField }>[];\n }>\n | Readonly<{\n type: \"dictionary\";\n indexType: ArrowDataType;\n valueType: ArrowDataType;\n ordered?: boolean;\n }>\n | Readonly<{ type: \"map\"; entries: ArrowField; keysSorted: boolean }>\n | Readonly<{ type: \"run-end-encoded\"; runEnds: ArrowField; values: ArrowField }>\n | Readonly<{\n type: \"extension\";\n name: string;\n metadata?: string;\n storageType: ArrowDataType;\n }>;\n\nexport interface ColumnSchema {\n readonly id: string;\n readonly name: string;\n readonly index: number;\n readonly dataType: ArrowDataType;\n readonly nullable: boolean;\n readonly metadata?: Readonly<Record<string, string>>;\n}\n\nexport interface TableCapabilities {\n readonly randomAccess: \"indexed-prefix\" | \"full\";\n readonly typedValues: boolean;\n readonly search: boolean;\n readonly sort: boolean;\n readonly filter: boolean;\n readonly multiTable: boolean;\n readonly [name: string]: unknown;\n}\n\nexport interface TableMetadata {\n readonly tableId: string;\n readonly name: string;\n readonly revision: number;\n readonly extent: Readonly<TableExtent>;\n readonly schema: Readonly<{\n readonly version: number;\n readonly columns: readonly Readonly<ColumnSchema>[];\n }>;\n readonly capabilities: Readonly<TableCapabilities>;\n}\n\nexport type WorksheetVisibility = \"visible\" | \"hidden\" | \"very-hidden\";\n\n/** One sparse row or column override supplied by a spreadsheet presentation. */\nexport interface PresentationAxisEntry {\n readonly index: number;\n /** CSS pixel extent when the source supplies an explicit dimension. */\n readonly size?: number;\n readonly hidden?: boolean;\n}\n\nexport interface PresentationColor {\n /** CSS-compatible resolved color, when the workbook supplied one. */\n readonly css?: string;\n}\n\nexport interface PresentationFont {\n readonly family?: string;\n readonly size?: number;\n readonly bold?: boolean;\n readonly italic?: boolean;\n readonly underline?: boolean;\n readonly color?: PresentationColor;\n}\n\nexport interface PresentationBorderSide {\n readonly style?: \"none\" | \"thin\" | \"medium\" | \"thick\" | \"dashed\" | \"dotted\" | \"double\";\n readonly color?: PresentationColor;\n}\n\n/** Static cell styling that 0.1 preserves from spreadsheet input. */\nexport interface PresentationStyle {\n readonly numberFormat?: string;\n readonly font?: PresentationFont;\n readonly foregroundColor?: PresentationColor;\n readonly backgroundColor?: PresentationColor;\n readonly fillColor?: PresentationColor;\n readonly borders?: Readonly<{\n readonly top?: PresentationBorderSide;\n readonly right?: PresentationBorderSide;\n readonly bottom?: PresentationBorderSide;\n readonly left?: PresentationBorderSide;\n }>;\n readonly horizontalAlignment?: \"general\" | \"left\" | \"center\" | \"right\" | \"justify\";\n readonly verticalAlignment?: \"top\" | \"center\" | \"bottom\" | \"justify\";\n readonly wrapText?: boolean;\n}\n\nexport interface MergedCellRegion {\n readonly rowStart: number;\n readonly rowEnd: number;\n readonly columnStart: number;\n readonly columnEnd: number;\n}\n\n/**\n * Presentation metadata for a worksheet. It is intentionally static: formula\n * calculation and document round-tripping are outside the 0.1 contract.\n */\nexport interface SpreadsheetPresentation {\n readonly kind: \"spreadsheet-v1\";\n readonly tableId: string;\n readonly revision: number;\n readonly visibility: WorksheetVisibility;\n readonly frozenRows: number;\n readonly frozenColumns: number;\n readonly rows: readonly PresentationAxisEntry[];\n readonly columns: readonly PresentationAxisEntry[];\n /** Deduplicated styles addressed by `SpreadsheetPresentationRange.styleIds`. */\n readonly styles: readonly PresentationStyle[];\n}\n\nexport type TablePresentation = SpreadsheetPresentation;\n\nexport interface SpreadsheetPresentationRange {\n readonly kind: \"spreadsheet-v1\";\n readonly tableId: string;\n readonly revision: number;\n readonly range: Readonly<ReturnedRange>;\n /** Rows and columns are exactly aligned with `range`; null means no style. */\n readonly styleIds: readonly (readonly (number | null)[])[];\n readonly mergedCells: readonly MergedCellRegion[];\n /** Sparse layout entries that intersect this requested range. */\n readonly rows: readonly PresentationAxisEntry[];\n readonly columns: readonly PresentationAxisEntry[];\n}\n\nexport type PresentationRange = SpreadsheetPresentationRange;\n\nexport interface TableDescriptor {\n readonly id: string;\n readonly name: string;\n}\n\nexport interface RangeRequest {\n readonly rowStart: number;\n readonly rowCount: number;\n readonly columnStart: number;\n readonly columnCount: number;\n}\n\nexport interface ReturnedRange extends RangeRequest {}\n\n/** A byte region in the batch's deduplicated buffer pool. */\nexport interface BatchBufferRegion {\n readonly buffer: number;\n readonly byteOffset?: number;\n readonly byteLength?: number;\n /** First bit for bitmap regions; ignored for byte-oriented regions. */\n readonly bitOffset?: number;\n}\n\n/** UTF-8 text generated by Rust for rendering, ARIA, width measurement and copy. */\nexport interface DisplayColumnDescriptor {\n readonly encoding: \"utf8\";\n readonly data: BatchBufferRegion;\n readonly offsets: BatchBufferRegion;\n readonly validity?: BatchBufferRegion;\n /** Logical offset into the display arrays, for sliced batches. */\n readonly offset?: number;\n}\n\n/**\n * Recursive Arrow ArrayData layout. Buffer regions always point into the\n * enclosing TableBatch buffer pool; encoded dictionaries and run ends remain\n * visible in this descriptor even though `toRows()` returns logical values.\n */\nexport interface NativeColumnDescriptor {\n /** Rust ArrayData layout encoding (for example `dictionary` or `run-end-encoded`). */\n readonly encoding?: string;\n readonly dataType: ArrowDataType;\n readonly length: number;\n readonly offset?: number;\n readonly validity?: BatchBufferRegion;\n readonly values?: BatchBufferRegion;\n readonly offsets?: BatchBufferRegion;\n readonly sizes?: BatchBufferRegion;\n readonly data?: BatchBufferRegion;\n readonly typeIds?: BatchBufferRegion;\n readonly unionOffsets?: BatchBufferRegion;\n readonly variadicBuffers?: readonly BatchBufferRegion[];\n readonly children?: readonly NativeColumnDescriptor[];\n readonly dictionary?: NativeColumnDescriptor;\n readonly runEnds?: NativeColumnDescriptor;\n readonly typeId?: number;\n}\n\n/** @internal Layout-v1 column descriptor received from an official WASM runtime. */\nexport interface WireTableBatchColumn {\n readonly columnId: string;\n readonly native: NativeColumnDescriptor;\n readonly display: DisplayColumnDescriptor;\n}\n\nexport interface DecimalValue {\n readonly kind: \"decimal\";\n readonly unscaled: bigint;\n readonly precision: number;\n readonly scale: number;\n}\n\nexport interface TemporalValue {\n readonly kind: \"date32\" | \"date64\" | \"time32\" | \"time64\" | \"timestamp\" | \"duration\";\n readonly value: number | bigint;\n readonly unit?: TimeUnit;\n readonly timezone?: string;\n}\n\nexport interface IntervalValue {\n readonly kind: \"interval\";\n readonly unit: IntervalUnit;\n readonly months?: number;\n readonly days?: number;\n readonly milliseconds?: number;\n readonly nanoseconds?: bigint;\n}\n\nexport interface UnionValue {\n readonly kind: \"union\";\n readonly typeId: number;\n readonly value: NativeValue | null;\n}\n\nexport interface MapEntryValue {\n readonly key: NativeValue | null;\n readonly value: NativeValue | null;\n}\n\nexport interface NativeListValue extends ReadonlyArray<NativeValue | null> {}\nexport interface NativeStructValue {\n readonly [name: string]: NativeValue | null;\n}\nexport interface NativeMapValue extends ReadonlyArray<Readonly<MapEntryValue>> {}\n\nexport type NativeValue =\n | boolean\n | number\n | bigint\n | string\n | Uint8Array\n | DecimalValue\n | TemporalValue\n | IntervalValue\n | UnionValue\n | NativeListValue\n | NativeStructValue\n | NativeMapValue;\n\nexport interface ToRowsOptions {\n /** Maximum decoded cells. Defaults to 10,000. */\n readonly maxCells?: number;\n}\n\n/**\n * Logical, column-oriented access to one returned batch column.\n *\n * Values are indexed relative to `TableBatch.range.rowStart`; physical buffer\n * regions and adapter transport details intentionally remain private.\n */\nexport interface TableBatchColumn {\n readonly columnId: string;\n readonly columnIndex: number;\n readonly rowCount: number;\n getValue(rowOffset: number): NativeValue | null;\n getDisplayValue(rowOffset: number): string | null;\n toValues(options?: ToRowsOptions): (NativeValue | null)[];\n toDisplayValues(options?: ToRowsOptions): (string | null)[];\n}\n\n/** Stable logical batch contract. Wire buffers and ABI layout stay private. */\nexport interface TableBatch {\n readonly tableId: string;\n readonly revision: number;\n readonly schemaVersion: number;\n readonly range: Readonly<ReturnedRange>;\n readonly columns: readonly TableBatchColumn[];\n readonly complete: boolean;\n toRows(options?: ToRowsOptions): (NativeValue | null)[][];\n toDisplayRows(options?: ToRowsOptions): (string | null)[][];\n}\n\nexport type WireBatchBuffer = ArrayBuffer | ArrayBufferView;\n\nexport interface WireTableBatch {\n readonly layoutVersion: typeof BATCH_LAYOUT_VERSION;\n readonly tableId: string;\n readonly revision: number;\n readonly schemaVersion: number;\n readonly range: ReturnedRange;\n readonly buffers: readonly WireBatchBuffer[];\n readonly columns: readonly WireTableBatchColumn[];\n readonly complete: boolean;\n}\n\n/** Owns and validates one generic layout-v1 batch received from the Worker. */\nexport class ColumnarTableBatch implements TableBatch {\n readonly tableId: string;\n readonly revision: number;\n readonly schemaVersion: number;\n readonly range: Readonly<ReturnedRange>;\n readonly columns: readonly TableBatchColumn[];\n readonly complete: boolean;\n readonly #buffers: readonly Uint8Array[];\n readonly #wireColumns: readonly WireTableBatchColumn[];\n\n constructor(value: WireTableBatch) {\n if (value.layoutVersion !== BATCH_LAYOUT_VERSION) {\n throw invalidArgument(\n `Batch layout ${String(value.layoutVersion)} is incompatible with layout ${BATCH_LAYOUT_VERSION}`,\n );\n }\n this.tableId = value.tableId;\n this.revision = value.revision;\n this.schemaVersion = value.schemaVersion;\n this.range = Object.freeze({ ...value.range });\n this.#buffers = Object.freeze(value.buffers.map(asUint8Array));\n this.#wireColumns = Object.freeze(value.columns.map((column) => freezeWireColumn(column)));\n this.complete = value.complete;\n validateWireBatch(this.range, this.#buffers, this.#wireColumns);\n this.columns = Object.freeze(this.#wireColumns.map((column, index) => new LogicalBatchColumn(\n column,\n this.#buffers,\n this.range.rowCount,\n this.range.columnStart + index,\n )));\n }\n\n toRows(options: ToRowsOptions = {}): (NativeValue | null)[][] {\n const maxCells = normalizeCellLimit(options.maxCells);\n assertCellLimit(this.range.rowCount, this.columns.length, maxCells);\n const rows: (NativeValue | null)[][] = Array.from(\n { length: this.range.rowCount },\n () => Array<NativeValue | null>(this.columns.length),\n );\n for (let columnIndex = 0; columnIndex < this.columns.length; columnIndex += 1) {\n for (let rowIndex = 0; rowIndex < this.range.rowCount; rowIndex += 1) {\n rows[rowIndex]![columnIndex] = this.columns[columnIndex]!.getValue(rowIndex);\n }\n }\n return rows;\n }\n\n toDisplayRows(options: ToRowsOptions = {}): (string | null)[][] {\n const maxCells = normalizeCellLimit(options.maxCells);\n assertCellLimit(this.range.rowCount, this.columns.length, maxCells);\n const rows: (string | null)[][] = Array.from(\n { length: this.range.rowCount },\n () => Array<string | null>(this.columns.length),\n );\n\n for (let columnIndex = 0; columnIndex < this.columns.length; columnIndex += 1) {\n for (let rowIndex = 0; rowIndex < this.range.rowCount; rowIndex += 1) {\n rows[rowIndex]![columnIndex] = this.columns[columnIndex]!.getDisplayValue(rowIndex);\n }\n }\n return rows;\n }\n}\n\nclass LogicalBatchColumn implements TableBatchColumn {\n readonly columnId: string;\n readonly columnIndex: number;\n readonly rowCount: number;\n readonly #wire: WireTableBatchColumn;\n readonly #buffers: readonly Uint8Array[];\n\n constructor(\n wire: WireTableBatchColumn,\n buffers: readonly Uint8Array[],\n rowCount: number,\n columnIndex: number,\n ) {\n this.columnId = wire.columnId;\n this.columnIndex = columnIndex;\n this.rowCount = rowCount;\n this.#wire = wire;\n this.#buffers = buffers;\n Object.freeze(this);\n }\n\n getValue(rowOffset: number): NativeValue | null {\n assertBatchRowOffset(rowOffset, this.rowCount);\n return decodeNativeValue(this.#wire.native, rowOffset, this.#buffers, 0);\n }\n\n getDisplayValue(rowOffset: number): string | null {\n assertBatchRowOffset(rowOffset, this.rowCount);\n return decodeDisplayValue(this.#wire.display, rowOffset, this.#buffers, this.columnId);\n }\n\n toValues(options: ToRowsOptions = {}): (NativeValue | null)[] {\n const maxCells = normalizeCellLimit(options.maxCells);\n assertCellLimit(this.rowCount, 1, maxCells);\n return Array.from({ length: this.rowCount }, (_, index) => this.getValue(index));\n }\n\n toDisplayValues(options: ToRowsOptions = {}): (string | null)[] {\n const maxCells = normalizeCellLimit(options.maxCells);\n assertCellLimit(this.rowCount, 1, maxCells);\n return Array.from({ length: this.rowCount }, (_, index) => this.getDisplayValue(index));\n }\n}\n\nfunction assertBatchRowOffset(rowOffset: number, rowCount: number): void {\n if (!Number.isSafeInteger(rowOffset) || rowOffset < 0 || rowOffset >= rowCount) {\n throw invalidArgument(`Batch row offset must be an integer from 0 through ${Math.max(0, rowCount - 1)}`);\n }\n}\n\nfunction decodeDisplayValue(\n display: DisplayColumnDescriptor,\n rowOffset: number,\n buffers: readonly Uint8Array[],\n columnId: string,\n): string | null {\n const physicalIndex = (display.offset ?? 0) + rowOffset;\n if (!validAt(display.validity, physicalIndex, buffers)) {\n return null;\n }\n const offsets = regionView(display.offsets, buffers, \"display offsets\");\n const data = regionView(display.data, buffers, \"display data\");\n const start = readUnsignedOffset(offsets, physicalIndex, 4);\n const end = readUnsignedOffset(offsets, physicalIndex + 1, 4);\n if (end < start || end > data.byteLength) {\n throw invalidArgument(`Column ${columnId} has invalid display offsets`);\n }\n return UTF8_DECODER.decode(data.subarray(start, end));\n}\n\nexport function validateRange(request: RangeRequest): RangeRequest {\n for (const [name, value] of Object.entries(request)) {\n assertNonNegativeSafeInteger(value, name);\n }\n if (\n request.rowCount > Number.MAX_SAFE_INTEGER - request.rowStart\n || request.columnCount > Number.MAX_SAFE_INTEGER - request.columnStart\n ) {\n throw new TabularkError(\"INVALID_RANGE\", \"Range end must be a safe integer\");\n }\n const cells = request.rowCount * request.columnCount;\n // Bound each dimension as well as the product. A zero-height/zero-width\n // range still reaches adapter loops and must not smuggle an unbounded axis\n // through the `0 * Number.MAX_SAFE_INTEGER` product.\n if (\n request.rowCount > MAX_RANGE_CELLS\n || request.columnCount > MAX_RANGE_CELLS\n || !Number.isSafeInteger(cells)\n || cells > MAX_RANGE_CELLS\n ) {\n const required = Number.isSafeInteger(cells)\n ? Math.max(cells, request.rowCount, request.columnCount)\n : Number.MAX_SAFE_INTEGER;\n throw new TabularkError(\n \"RESOURCE_LIMIT\",\n `A range may contain at most ${MAX_RANGE_CELLS} cells`,\n {\n details: {\n resource: \"range-cells\",\n required,\n available: MAX_RANGE_CELLS,\n cells: Number.isSafeInteger(cells) ? cells : Number.MAX_SAFE_INTEGER,\n limit: MAX_RANGE_CELLS,\n },\n },\n );\n }\n return Object.freeze({ ...request });\n}\n\nexport function normalizeMetadata(value: TableMetadata): Readonly<TableMetadata> {\n return Object.freeze({\n ...value,\n extent: Object.freeze({\n rows: Object.freeze({ ...value.extent.rows }),\n columns: Object.freeze({ ...value.extent.columns }),\n }),\n schema: Object.freeze({\n version: value.schema.version,\n columns: Object.freeze(value.schema.columns.map((column) => Object.freeze({\n ...column,\n dataType: freezeDataType(column.dataType),\n ...(column.metadata ? { metadata: Object.freeze({ ...column.metadata }) } : {}),\n }))),\n }),\n capabilities: Object.freeze({ ...value.capabilities }),\n });\n}\n\n/** Normalizes a protocol DataType and rejects cycles or excessive nesting. */\nexport function normalizeDataType(value: unknown, depth = 0): ArrowDataType {\n if (depth >= MAX_NESTING_DEPTH) {\n throw invalidArgument(`Arrow data type nesting may not exceed ${MAX_NESTING_DEPTH}`);\n }\n if (!isRecord(value) || typeof value.type !== \"string\") {\n throw invalidArgument(\"Column dataType must be a recursive Arrow data type descriptor\");\n }\n const type: string = ({\n \"u-int8\": \"uint8\",\n \"u-int16\": \"uint16\",\n \"u-int32\": \"uint32\",\n \"u-int64\": \"uint64\",\n } as const)[value.type as \"u-int8\" | \"u-int16\" | \"u-int32\" | \"u-int64\"] ?? value.type;\n const simple = new Set([\n \"unknown\", \"null\", \"boolean\", \"int8\", \"int16\", \"int32\", \"int64\", \"uint8\", \"uint16\", \"uint32\", \"uint64\",\n \"float16\", \"float32\", \"float64\", \"date32\", \"date64\", \"binary\", \"large-binary\", \"binary-view\",\n \"utf8\", \"large-utf8\", \"utf8-view\",\n ]);\n if (simple.has(type)) {\n return Object.freeze({ type }) as ArrowDataType;\n }\n if (type === \"timestamp\") {\n return Object.freeze({\n type,\n unit: timeUnit(value.unit),\n ...(typeof value.timezone === \"string\" ? { timezone: value.timezone } : {}),\n });\n }\n if (type === \"time32\" || type === \"time64\" || type === \"duration\") {\n return Object.freeze({ type, unit: timeUnit(value.unit) });\n }\n if (type === \"interval\") {\n return Object.freeze({ type, unit: intervalUnit(value.unit) });\n }\n if (type === \"fixed-size-binary\") {\n return Object.freeze({\n type,\n byteWidth: positiveInteger(value.byteWidth ?? value.byte_width, \"byteWidth\"),\n });\n }\n if (type === \"decimal32\" || type === \"decimal64\" || type === \"decimal128\" || type === \"decimal256\") {\n return Object.freeze({\n type,\n precision: positiveInteger(value.precision, \"precision\"),\n scale: integer(value.scale, \"scale\"),\n });\n }\n if (type === \"list\" || type === \"large-list\" || type === \"list-view\" || type === \"large-list-view\") {\n return Object.freeze({ type, field: normalizeField(value.field, depth + 1) });\n }\n if (type === \"fixed-size-list\") {\n return Object.freeze({\n type,\n field: normalizeField(value.field, depth + 1),\n listSize: positiveInteger(value.listSize ?? value.list_size, \"listSize\"),\n });\n }\n if (type === \"struct\") {\n if (!Array.isArray(value.fields)) {\n throw invalidArgument(\"Struct fields must be an array\");\n }\n return Object.freeze({\n type,\n fields: Object.freeze(value.fields.map((field) => normalizeField(field, depth + 1))),\n });\n }\n if (type === \"union\") {\n if (!Array.isArray(value.fields) || (value.mode !== \"sparse\" && value.mode !== \"dense\")) {\n throw invalidArgument(\"Union dataType requires a mode and fields\");\n }\n return Object.freeze({\n type,\n mode: value.mode,\n fields: Object.freeze(value.fields.map((entry) => {\n if (!isRecord(entry)) {\n throw invalidArgument(\"Union field entries must be objects\");\n }\n return Object.freeze({\n typeId: integer(entry.typeId, \"typeId\"),\n field: normalizeField(entry.field, depth + 1),\n });\n })),\n });\n }\n if (type === \"dictionary\") {\n return Object.freeze({\n type,\n indexType: normalizeDataType(value.indexType, depth + 1),\n valueType: normalizeDataType(value.valueType, depth + 1),\n ...(value.ordered === true ? { ordered: true } : {}),\n });\n }\n if (type === \"map\") {\n return Object.freeze({\n type,\n entries: normalizeField(value.entries, depth + 1),\n keysSorted: value.keysSorted === true || value.keys_sorted === true,\n });\n }\n if (type === \"run-end-encoded\") {\n return Object.freeze({\n type,\n runEnds: normalizeField(value.runEnds ?? value.run_ends, depth + 1),\n values: normalizeField(value.values, depth + 1),\n });\n }\n if (type === \"extension\") {\n if (typeof value.name !== \"string\" || value.name.length === 0) {\n throw invalidArgument(\"Arrow extension name must be a non-empty string\");\n }\n return Object.freeze({\n type,\n name: value.name,\n ...(typeof value.metadata === \"string\" ? { metadata: value.metadata } : {}),\n storageType: normalizeDataType(value.storageType, depth + 1),\n });\n }\n throw invalidArgument(`Unknown Arrow data type: ${type}`);\n}\n\nfunction normalizeField(value: unknown, depth: number): ArrowField {\n if (!isRecord(value)) {\n throw invalidArgument(\"Arrow field must be an object\");\n }\n const metadata = isRecord(value.metadata)\n ? Object.freeze(Object.fromEntries(Object.entries(value.metadata).map(([key, entry]) => [key, String(entry)])))\n : undefined;\n return Object.freeze({\n name: typeof value.name === \"string\" ? value.name : \"\",\n nullable: value.nullable !== false,\n dataType: normalizeDataType(value.dataType, depth),\n ...(metadata ? { metadata } : {}),\n });\n}\n\nfunction validateWireBatch(\n range: Readonly<ReturnedRange>,\n buffers: readonly Uint8Array[],\n columns: readonly WireTableBatchColumn[],\n): void {\n validateRange(range);\n if (columns.length !== range.columnCount) {\n throw invalidArgument(\n `Batch has ${columns.length} columns; expected ${range.columnCount}`,\n );\n }\n for (const [index, column] of columns.entries()) {\n validateDisplay(column.display, range.rowCount, buffers, column.columnId);\n validateNative(column.native, buffers, 0, `columns[${index}].native`);\n if (column.native.length < range.rowCount) {\n throw invalidArgument(`Column ${column.columnId} is shorter than the returned range`);\n }\n }\n}\n\nfunction validateDisplay(\n display: DisplayColumnDescriptor,\n rows: number,\n buffers: readonly Uint8Array[],\n columnId: string,\n): void {\n const offset = display.offset ?? 0;\n assertNonNegativeSafeInteger(offset, \"display offset\");\n const offsets = regionView(display.offsets, buffers, \"display offsets\");\n if (offsets.byteLength < (offset + rows + 1) * 4) {\n throw invalidArgument(`Column ${columnId} has incomplete display offsets`);\n }\n const data = regionView(display.data, buffers, \"display data\");\n if (display.validity) {\n const validity = regionView(display.validity, buffers, \"display validity\");\n if (validity.byteLength < Math.ceil((offset + rows) / 8)) {\n throw invalidArgument(`Column ${columnId} has an incomplete display validity bitmap`);\n }\n }\n let previous = 0;\n for (let index = offset; index <= offset + rows; index += 1) {\n const next = readUnsignedOffset(offsets, index, 4);\n if (next < previous || next > data.byteLength) {\n throw invalidArgument(`Column ${columnId} has invalid display offsets`);\n }\n previous = next;\n }\n}\n\nfunction validateNative(\n descriptor: NativeColumnDescriptor,\n buffers: readonly Uint8Array[],\n depth: number,\n name: string,\n): void {\n if (depth >= MAX_NESTING_DEPTH) {\n throw invalidArgument(`Native column nesting may not exceed ${MAX_NESTING_DEPTH}`);\n }\n assertNonNegativeSafeInteger(descriptor.length, `${name}.length`);\n assertNonNegativeSafeInteger(descriptor.offset ?? 0, `${name}.offset`);\n normalizeDataType(descriptor.dataType, depth);\n const regions = [\n descriptor.validity,\n descriptor.values,\n descriptor.offsets,\n descriptor.sizes,\n descriptor.data,\n descriptor.typeIds,\n descriptor.unionOffsets,\n ...(descriptor.variadicBuffers ?? []),\n ];\n for (const region of regions) {\n if (region) {\n regionView(region, buffers, name);\n }\n }\n for (const [index, child] of (descriptor.children ?? []).entries()) {\n validateNative(child, buffers, depth + 1, `${name}.children[${index}]`);\n }\n if (descriptor.dictionary) {\n validateNative(descriptor.dictionary, buffers, depth + 1, `${name}.dictionary`);\n }\n if (descriptor.runEnds) {\n validateNative(descriptor.runEnds, buffers, depth + 1, `${name}.runEnds`);\n }\n}\n\nfunction decodeNativeValue(\n descriptor: NativeColumnDescriptor,\n logicalIndex: number,\n buffers: readonly Uint8Array[],\n depth: number,\n): NativeValue | null {\n if (depth >= MAX_NESTING_DEPTH) {\n throw invalidArgument(`Native value nesting may not exceed ${MAX_NESTING_DEPTH}`);\n }\n if (logicalIndex < 0 || logicalIndex >= descriptor.length) {\n throw invalidArgument(\"Native value index is outside its descriptor\");\n }\n const physicalIndex = (descriptor.offset ?? 0) + logicalIndex;\n if (!validAt(descriptor.validity, physicalIndex, buffers)) {\n return null;\n }\n const type = unwrapExtension(descriptor.dataType);\n switch (type.type) {\n case \"null\":\n return null;\n case \"unknown\": {\n const bytes = decodeVariableBytes(descriptor, buffers, physicalIndex, 4);\n return UTF8_DECODER.decode(bytes);\n }\n case \"boolean\": {\n const values = requiredRegion(descriptor.values, buffers, \"boolean values\");\n const bitIndex = (descriptor.values?.bitOffset ?? 0) + physicalIndex;\n return (values[bitIndex >>> 3]! & (1 << (bitIndex & 7))) !== 0;\n }\n case \"int8\": return readNumber(descriptor, buffers, physicalIndex, 1, \"signed\");\n case \"uint8\": return readNumber(descriptor, buffers, physicalIndex, 1, \"unsigned\");\n case \"int16\": return readNumber(descriptor, buffers, physicalIndex, 2, \"signed\");\n case \"uint16\": return readNumber(descriptor, buffers, physicalIndex, 2, \"unsigned\");\n case \"int32\": return readNumber(descriptor, buffers, physicalIndex, 4, \"signed\");\n case \"uint32\": return readNumber(descriptor, buffers, physicalIndex, 4, \"unsigned\");\n case \"int64\": return readBigInt(descriptor, buffers, physicalIndex, true);\n case \"uint64\": return readBigInt(descriptor, buffers, physicalIndex, false);\n case \"float16\": return decodeFloat16(readNumber(descriptor, buffers, physicalIndex, 2, \"unsigned\"));\n case \"float32\": return readFloat(descriptor, buffers, physicalIndex, 4);\n case \"float64\": return readFloat(descriptor, buffers, physicalIndex, 8);\n case \"utf8\":\n case \"large-utf8\": {\n const bytes = decodeVariableBytes(descriptor, buffers, physicalIndex, type.type === \"large-utf8\" ? 8 : 4);\n return UTF8_DECODER.decode(bytes);\n }\n case \"binary\":\n case \"large-binary\":\n return decodeVariableBytes(descriptor, buffers, physicalIndex, type.type === \"large-binary\" ? 8 : 4).slice();\n case \"utf8-view\":\n return UTF8_DECODER.decode(decodeViewBytes(descriptor, buffers, physicalIndex));\n case \"binary-view\":\n return decodeViewBytes(descriptor, buffers, physicalIndex).slice();\n case \"fixed-size-binary\": {\n const data = requiredRegion(descriptor.data ?? descriptor.values, buffers, \"fixed-size binary data\");\n const start = physicalIndex * type.byteWidth;\n return checkedSlice(data, start, start + type.byteWidth, \"fixed-size binary data\").slice();\n }\n case \"decimal32\":\n case \"decimal64\":\n case \"decimal128\":\n case \"decimal256\": {\n const width = { decimal32: 4, decimal64: 8, decimal128: 16, decimal256: 32 }[type.type];\n return Object.freeze({\n kind: \"decimal\",\n unscaled: readSignedLittleEndian(requiredRegion(descriptor.values, buffers, \"decimal values\"), physicalIndex * width, width),\n precision: type.precision,\n scale: type.scale,\n });\n }\n case \"date32\":\n return Object.freeze({ kind: \"date32\", value: readNumber(descriptor, buffers, physicalIndex, 4, \"signed\") });\n case \"date64\":\n return Object.freeze({ kind: \"date64\", value: readBigInt(descriptor, buffers, physicalIndex, true), unit: \"millisecond\" });\n case \"time32\":\n return Object.freeze({ kind: \"time32\", value: readNumber(descriptor, buffers, physicalIndex, 4, \"signed\"), unit: type.unit });\n case \"time64\":\n return Object.freeze({ kind: \"time64\", value: readBigInt(descriptor, buffers, physicalIndex, true), unit: type.unit });\n case \"timestamp\":\n return Object.freeze({\n kind: \"timestamp\",\n value: readBigInt(descriptor, buffers, physicalIndex, true),\n unit: type.unit,\n ...(type.timezone === undefined ? {} : { timezone: type.timezone }),\n });\n case \"duration\":\n return Object.freeze({ kind: \"duration\", value: readBigInt(descriptor, buffers, physicalIndex, true), unit: type.unit });\n case \"interval\":\n return decodeInterval(descriptor, buffers, physicalIndex, type.unit);\n case \"list\":\n case \"large-list\":\n case \"list-view\":\n case \"large-list-view\":\n case \"map\":\n return decodeListLike(descriptor, buffers, physicalIndex, type, depth);\n case \"fixed-size-list\": {\n const child = requiredChild(descriptor, 0, \"fixed-size list\");\n const start = physicalIndex * type.listSize;\n return Object.freeze(Array.from(\n { length: type.listSize },\n (_, index) => decodeNativeValue(child, start + index - (child.offset ?? 0), buffers, depth + 1),\n ));\n }\n case \"struct\": {\n const result: Record<string, NativeValue | null> = {};\n for (let index = 0; index < type.fields.length; index += 1) {\n const child = requiredChild(descriptor, index, \"struct\");\n result[type.fields[index]!.name] = decodeNativeValue(\n child,\n physicalIndex - (child.offset ?? 0),\n buffers,\n depth + 1,\n );\n }\n return Object.freeze(result);\n }\n case \"union\": {\n const typeIds = requiredRegion(descriptor.typeIds, buffers, \"union type ids\");\n if (physicalIndex >= typeIds.byteLength) {\n throw invalidArgument(\"Union type id is out of bounds\");\n }\n const typeId = dataViewFor(typeIds).getInt8(physicalIndex);\n const fieldIndex = type.fields.findIndex((entry) => entry.typeId === typeId);\n if (fieldIndex < 0) {\n throw invalidArgument(`Union type id ${typeId} has no child`);\n }\n const child = requiredChild(descriptor, fieldIndex, \"union\");\n const childPhysical = type.mode === \"dense\"\n ? readSignedOffset(requiredRegion(descriptor.unionOffsets ?? descriptor.offsets, buffers, \"union offsets\"), physicalIndex, 4)\n : physicalIndex;\n return Object.freeze({\n kind: \"union\",\n typeId,\n value: decodeNativeValue(child, childPhysical - (child.offset ?? 0), buffers, depth + 1),\n });\n }\n case \"dictionary\": {\n const keys = descriptor.children?.[0] ?? descriptor;\n const dictionary = descriptor.dictionary ?? descriptor.children?.[1];\n if (!dictionary || !keys) {\n throw invalidArgument(\"Dictionary descriptor has no dictionary values\");\n }\n const index = readIndex(keys, buffers, physicalIndex, type.indexType);\n if (index < 0 || index >= dictionary.length) {\n throw invalidArgument(\"Dictionary index is out of bounds\");\n }\n return decodeNativeValue(dictionary, index, buffers, depth + 1);\n }\n case \"run-end-encoded\": {\n const runEnds = descriptor.runEnds ?? descriptor.children?.[0];\n const values = descriptor.children?.[descriptor.runEnds ? 0 : 1];\n if (!runEnds || !values) {\n throw invalidArgument(\"Run-end encoded descriptor is incomplete\");\n }\n const logicalPosition = physicalIndex + 1;\n let run = 0;\n while (run < runEnds.length && numericIndexValue(runEnds, buffers, run) < logicalPosition) {\n run += 1;\n }\n if (run >= values.length) {\n throw invalidArgument(\"Run-end encoded value is out of bounds\");\n }\n return decodeNativeValue(values, run, buffers, depth + 1);\n }\n case \"extension\":\n // unwrapExtension makes this unreachable while retaining exhaustive typing.\n throw invalidArgument(\"Nested extension data type could not be unwrapped\");\n }\n}\n\nfunction decodeListLike(\n descriptor: NativeColumnDescriptor,\n buffers: readonly Uint8Array[],\n physicalIndex: number,\n type: Extract<ArrowDataType, { type: \"list\" | \"large-list\" | \"list-view\" | \"large-list-view\" | \"map\" }>,\n depth: number,\n): NativeValue {\n const width = type.type === \"large-list\" || type.type === \"large-list-view\" ? 8 : 4;\n const offsets = requiredRegion(descriptor.offsets, buffers, \"list offsets\");\n const start = readSignedOffset(offsets, physicalIndex, width);\n const end = type.type === \"list-view\" || type.type === \"large-list-view\"\n ? start + readSignedOffset(requiredRegion(descriptor.sizes, buffers, \"list sizes\"), physicalIndex, width)\n : readSignedOffset(offsets, physicalIndex + 1, width);\n if (start < 0 || end < start) {\n throw invalidArgument(\"List offsets are invalid\");\n }\n const child = requiredChild(descriptor, 0, type.type);\n const values: NativeListValue = Object.freeze(Array.from(\n { length: end - start },\n (_, index) => decodeNativeValue(child, start + index - (child.offset ?? 0), buffers, depth + 1),\n ));\n if (type.type !== \"map\") {\n return values;\n }\n return Object.freeze(values.map((entry: NativeValue | null) => {\n if (!isRecord(entry)) {\n throw invalidArgument(\"Map entries must decode from a struct\");\n }\n const record = entry as NativeStructValue;\n const entryType = type.entries.dataType;\n const fields = entryType.type === \"struct\" ? entryType.fields : [];\n const keyName = fields[0]?.name ?? \"key\";\n const valueName = fields[1]?.name ?? \"value\";\n return Object.freeze({\n key: record[keyName] ?? null,\n value: record[valueName] ?? null,\n });\n }));\n}\n\nfunction decodeInterval(\n descriptor: NativeColumnDescriptor,\n buffers: readonly Uint8Array[],\n index: number,\n unit: IntervalUnit,\n): IntervalValue {\n const values = requiredRegion(descriptor.values, buffers, \"interval values\");\n const view = dataViewFor(values);\n if (unit === \"year-month\") {\n ensureViewRange(view, index * 4, 4, \"year-month interval\");\n return Object.freeze({ kind: \"interval\", unit, months: view.getInt32(index * 4, true) });\n }\n if (unit === \"day-time\") {\n const offset = index * 8;\n ensureViewRange(view, offset, 8, \"day-time interval\");\n return Object.freeze({\n kind: \"interval\",\n unit,\n days: view.getInt32(offset, true),\n milliseconds: view.getInt32(offset + 4, true),\n });\n }\n const offset = index * 16;\n ensureViewRange(view, offset, 16, \"month-day-nano interval\");\n return Object.freeze({\n kind: \"interval\",\n unit,\n months: view.getInt32(offset, true),\n days: view.getInt32(offset + 4, true),\n nanoseconds: view.getBigInt64(offset + 8, true),\n });\n}\n\nfunction decodeVariableBytes(\n descriptor: NativeColumnDescriptor,\n buffers: readonly Uint8Array[],\n index: number,\n offsetWidth: 4 | 8,\n): Uint8Array {\n const offsets = requiredRegion(descriptor.offsets, buffers, \"variable offsets\");\n const data = requiredRegion(descriptor.data ?? descriptor.values, buffers, \"variable data\");\n const start = readUnsignedOffset(offsets, index, offsetWidth);\n const end = readUnsignedOffset(offsets, index + 1, offsetWidth);\n return checkedSlice(data, start, end, \"variable data\");\n}\n\nfunction decodeViewBytes(\n descriptor: NativeColumnDescriptor,\n buffers: readonly Uint8Array[],\n index: number,\n): Uint8Array {\n const views = requiredRegion(descriptor.values, buffers, \"view values\");\n const view = dataViewFor(views);\n const offset = index * 16;\n ensureViewRange(view, offset, 16, \"view value\");\n const length = view.getInt32(offset, true);\n if (length < 0) {\n throw invalidArgument(\"View length must be non-negative\");\n }\n if (length <= 12) {\n return checkedSlice(views, offset + 4, offset + 4 + length, \"inline view\");\n }\n const bufferIndex = view.getInt32(offset + 8, true);\n const dataOffset = view.getInt32(offset + 12, true);\n const data = descriptor.variadicBuffers?.[bufferIndex];\n if (!data || dataOffset < 0) {\n throw invalidArgument(\"View references an invalid variadic buffer\");\n }\n return checkedSlice(regionView(data, buffers, \"view data\"), dataOffset, dataOffset + length, \"view data\");\n}\n\nfunction readNumber(\n descriptor: NativeColumnDescriptor,\n buffers: readonly Uint8Array[],\n index: number,\n width: 1 | 2 | 4,\n signedness: \"signed\" | \"unsigned\",\n): number {\n const values = requiredRegion(descriptor.values, buffers, \"numeric values\");\n const view = dataViewFor(values);\n const offset = index * width;\n ensureViewRange(view, offset, width, \"numeric value\");\n if (width === 1) return signedness === \"signed\" ? view.getInt8(offset) : view.getUint8(offset);\n if (width === 2) return signedness === \"signed\" ? view.getInt16(offset, true) : view.getUint16(offset, true);\n return signedness === \"signed\" ? view.getInt32(offset, true) : view.getUint32(offset, true);\n}\n\nfunction readFloat(\n descriptor: NativeColumnDescriptor,\n buffers: readonly Uint8Array[],\n index: number,\n width: 4 | 8,\n): number {\n const values = requiredRegion(descriptor.values, buffers, \"floating-point values\");\n const view = dataViewFor(values);\n const offset = index * width;\n ensureViewRange(view, offset, width, \"floating-point value\");\n return width === 4 ? view.getFloat32(offset, true) : view.getFloat64(offset, true);\n}\n\nfunction readBigInt(\n descriptor: NativeColumnDescriptor,\n buffers: readonly Uint8Array[],\n index: number,\n signed: boolean,\n): bigint {\n const values = requiredRegion(descriptor.values, buffers, \"64-bit values\");\n const view = dataViewFor(values);\n const offset = index * 8;\n ensureViewRange(view, offset, 8, \"64-bit value\");\n return signed ? view.getBigInt64(offset, true) : view.getBigUint64(offset, true);\n}\n\nfunction readIndex(\n descriptor: NativeColumnDescriptor,\n buffers: readonly Uint8Array[],\n index: number,\n dataType: ArrowDataType,\n): number {\n const type = unwrapExtension(dataType).type;\n let value: number | bigint;\n if (type === \"int8\") value = readNumber(descriptor, buffers, index, 1, \"signed\");\n else if (type === \"uint8\") value = readNumber(descriptor, buffers, index, 1, \"unsigned\");\n else if (type === \"int16\") value = readNumber(descriptor, buffers, index, 2, \"signed\");\n else if (type === \"uint16\") value = readNumber(descriptor, buffers, index, 2, \"unsigned\");\n else if (type === \"int32\") value = readNumber(descriptor, buffers, index, 4, \"signed\");\n else if (type === \"uint32\") value = readNumber(descriptor, buffers, index, 4, \"unsigned\");\n else if (type === \"int64\") value = readBigInt(descriptor, buffers, index, true);\n else if (type === \"uint64\") value = readBigInt(descriptor, buffers, index, false);\n else throw invalidArgument(\"Dictionary index type must be an integer\");\n const numeric = typeof value === \"bigint\" ? Number(value) : value;\n if (!Number.isSafeInteger(numeric)) {\n throw invalidArgument(\"Dictionary index exceeds the JavaScript safe integer range\");\n }\n return numeric;\n}\n\nfunction numericIndexValue(\n descriptor: NativeColumnDescriptor,\n buffers: readonly Uint8Array[],\n index: number,\n): number {\n const type = unwrapExtension(descriptor.dataType);\n return readIndex({ ...descriptor, dataType: { type: \"dictionary\", indexType: type, valueType: { type: \"null\" } } }, buffers, index, type);\n}\n\nfunction readSignedLittleEndian(bytes: Uint8Array, offset: number, width: number): bigint {\n const slice = checkedSlice(bytes, offset, offset + width, \"signed integer\");\n let value = 0n;\n for (let index = slice.byteLength - 1; index >= 0; index -= 1) {\n value = (value << 8n) | BigInt(slice[index]!);\n }\n const sign = 1n << BigInt(width * 8 - 1);\n return (value & sign) === 0n ? value : value - (1n << BigInt(width * 8));\n}\n\nfunction readUnsignedOffset(bytes: Uint8Array, index: number, width: 4 | 8): number {\n const value = readOffset(bytes, index, width, false);\n if (value < 0) {\n throw invalidArgument(\"Offset must be non-negative\");\n }\n return value;\n}\n\nfunction readSignedOffset(bytes: Uint8Array, index: number, width: 4 | 8): number {\n return readOffset(bytes, index, width, true);\n}\n\nfunction dataViewFor(bytes: Uint8Array): DataView {\n // Uint8Array.buffer is an ArrayBufferLike object (ArrayBuffer or\n // SharedArrayBuffer). The nested numeric maps avoid allocating a string key\n // on every primitive decode while preserving distinct subview boundaries.\n const backing = bytes.buffer as unknown as object;\n let byOffset = DATA_VIEW_CACHE.get(backing);\n if (byOffset === undefined) {\n byOffset = new Map();\n DATA_VIEW_CACHE.set(backing, byOffset);\n }\n let byLength = byOffset.get(bytes.byteOffset);\n if (byLength === undefined) {\n byLength = new Map();\n byOffset.set(bytes.byteOffset, byLength);\n }\n let view = byLength.get(bytes.byteLength);\n if (view === undefined) {\n view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n byLength.set(bytes.byteLength, view);\n }\n return view;\n}\n\nfunction readOffset(bytes: Uint8Array, index: number, width: 4 | 8, signed: boolean): number {\n const view = dataViewFor(bytes);\n const offset = index * width;\n ensureViewRange(view, offset, width, \"offset\");\n const value = width === 4\n ? signed ? view.getInt32(offset, true) : view.getUint32(offset, true)\n : signed ? view.getBigInt64(offset, true) : view.getBigUint64(offset, true);\n const numeric = typeof value === \"bigint\" ? Number(value) : value;\n if (!Number.isSafeInteger(numeric)) {\n throw invalidArgument(\"Offset exceeds the JavaScript safe integer range\");\n }\n return numeric;\n}\n\nfunction validAt(\n validity: BatchBufferRegion | undefined,\n index: number,\n buffers: readonly Uint8Array[],\n): boolean {\n if (!validity) return true;\n const bitmap = regionView(validity, buffers, \"validity bitmap\");\n const bitIndex = (validity.bitOffset ?? 0) + index;\n if (bitIndex < 0 || (bitIndex >>> 3) >= bitmap.byteLength) {\n throw invalidArgument(\"Validity bitmap index is out of bounds\");\n }\n return (bitmap[bitIndex >>> 3]! & (1 << (bitIndex & 7))) !== 0;\n}\n\nfunction requiredRegion(\n region: BatchBufferRegion | undefined,\n buffers: readonly Uint8Array[],\n name: string,\n): Uint8Array {\n if (!region) throw invalidArgument(`${name} are missing`);\n return regionView(region, buffers, name);\n}\n\nfunction regionView(\n region: BatchBufferRegion,\n buffers: readonly Uint8Array[],\n name: string,\n): Uint8Array {\n if (!isRecord(region) || !Number.isSafeInteger(region.buffer) || region.buffer < 0) {\n throw invalidArgument(`${name} references an invalid buffer`);\n }\n const buffer = buffers[region.buffer];\n if (!buffer) throw invalidArgument(`${name} references a missing buffer`);\n const byteOffset = region.byteOffset ?? 0;\n const byteLength = region.byteLength ?? buffer.byteLength - byteOffset;\n if (\n !Number.isSafeInteger(byteOffset)\n || byteOffset < 0\n || !Number.isSafeInteger(byteLength)\n || byteLength < 0\n || byteOffset + byteLength > buffer.byteLength\n ) {\n throw invalidArgument(`${name} region is outside its buffer`);\n }\n return buffer.subarray(byteOffset, byteOffset + byteLength);\n}\n\nfunction requiredChild(descriptor: NativeColumnDescriptor, index: number, name: string): NativeColumnDescriptor {\n const child = descriptor.children?.[index];\n if (!child) throw invalidArgument(`${name} descriptor has no child ${index}`);\n return child;\n}\n\nfunction checkedSlice(bytes: Uint8Array, start: number, end: number, name: string): Uint8Array {\n if (!Number.isSafeInteger(start) || !Number.isSafeInteger(end) || start < 0 || end < start || end > bytes.byteLength) {\n throw invalidArgument(`${name} slice is out of bounds`);\n }\n return bytes.subarray(start, end);\n}\n\nfunction ensureViewRange(view: DataView, offset: number, width: number, name: string): void {\n if (offset < 0 || offset + width > view.byteLength) {\n throw invalidArgument(`${name} is out of bounds`);\n }\n}\n\nfunction unwrapExtension(dataType: ArrowDataType): ArrowDataType {\n let current = dataType;\n for (let depth = 0; current.type === \"extension\"; depth += 1) {\n if (depth >= MAX_NESTING_DEPTH) throw invalidArgument(\"Extension nesting is too deep\");\n current = current.storageType;\n }\n return current;\n}\n\nfunction freezeWireColumn(column: WireTableBatchColumn): WireTableBatchColumn {\n return Object.freeze({\n columnId: column.columnId,\n native: freezeNative(column.native),\n display: Object.freeze({\n ...column.display,\n data: freezeRegion(column.display.data),\n offsets: freezeRegion(column.display.offsets),\n ...(column.display.validity ? { validity: freezeRegion(column.display.validity) } : {}),\n }),\n });\n}\n\nfunction freezeNative(descriptor: NativeColumnDescriptor): NativeColumnDescriptor {\n const freezeOptionalRegion = (region: BatchBufferRegion | undefined) => region ? freezeRegion(region) : undefined;\n return Object.freeze({\n ...descriptor,\n dataType: freezeDataType(descriptor.dataType),\n ...(freezeOptionalRegion(descriptor.validity) ? { validity: freezeOptionalRegion(descriptor.validity)! } : {}),\n ...(freezeOptionalRegion(descriptor.values) ? { values: freezeOptionalRegion(descriptor.values)! } : {}),\n ...(freezeOptionalRegion(descriptor.offsets) ? { offsets: freezeOptionalRegion(descriptor.offsets)! } : {}),\n ...(freezeOptionalRegion(descriptor.sizes) ? { sizes: freezeOptionalRegion(descriptor.sizes)! } : {}),\n ...(freezeOptionalRegion(descriptor.data) ? { data: freezeOptionalRegion(descriptor.data)! } : {}),\n ...(freezeOptionalRegion(descriptor.typeIds) ? { typeIds: freezeOptionalRegion(descriptor.typeIds)! } : {}),\n ...(freezeOptionalRegion(descriptor.unionOffsets) ? { unionOffsets: freezeOptionalRegion(descriptor.unionOffsets)! } : {}),\n ...(descriptor.variadicBuffers\n ? { variadicBuffers: Object.freeze(descriptor.variadicBuffers.map(freezeRegion)) }\n : {}),\n ...(descriptor.children\n ? { children: Object.freeze(descriptor.children.map(freezeNative)) }\n : {}),\n ...(descriptor.dictionary ? { dictionary: freezeNative(descriptor.dictionary) } : {}),\n ...(descriptor.runEnds ? { runEnds: freezeNative(descriptor.runEnds) } : {}),\n });\n}\n\nfunction freezeRegion(region: BatchBufferRegion): BatchBufferRegion {\n return Object.freeze({ ...region });\n}\n\nfunction freezeDataType(dataType: ArrowDataType): ArrowDataType {\n return normalizeDataTypeUnchecked(dataType, 0);\n}\n\nfunction normalizeDataTypeUnchecked(value: ArrowDataType, depth: number): ArrowDataType {\n // Public construction already validates; metadata/batch normalization may\n // arrive from protocol values, so use the same validator for one canonical shape.\n return normalizeDataType(value, depth);\n}\n\nfunction timeUnit(value: unknown): TimeUnit {\n if (value === \"second\" || value === \"millisecond\" || value === \"microsecond\" || value === \"nanosecond\") {\n return value;\n }\n throw invalidArgument(\"Arrow time unit is invalid\");\n}\n\nfunction intervalUnit(value: unknown): IntervalUnit {\n if (value === \"year-month\" || value === \"day-time\" || value === \"month-day-nano\") return value;\n throw invalidArgument(\"Arrow interval unit is invalid\");\n}\n\nfunction decodeFloat16(bits: number): number {\n const sign = (bits & 0x8000) === 0 ? 1 : -1;\n const exponent = (bits >>> 10) & 0x1f;\n const fraction = bits & 0x03ff;\n if (exponent === 0) return sign * 2 ** -14 * (fraction / 1024);\n if (exponent === 0x1f) return fraction === 0 ? sign * Infinity : Number.NaN;\n return sign * 2 ** (exponent - 15) * (1 + fraction / 1024);\n}\n\nfunction normalizeCellLimit(value: number | undefined): number {\n const maxCells = value ?? DEFAULT_TO_ROWS_CELL_LIMIT;\n assertPositiveSafeInteger(maxCells, \"maxCells\");\n return maxCells;\n}\n\nfunction assertCellLimit(rows: number, columns: number, maxCells: number): void {\n const cellCount = rows * columns;\n if (!Number.isSafeInteger(cellCount) || cellCount > maxCells) {\n throw new TabularkError(\n \"RESOURCE_LIMIT\",\n `Decoding ${cellCount} cells exceeds the toRows limit of ${maxCells}`,\n {\n details: {\n resource: \"row-materialization-cells\",\n required: cellCount,\n available: maxCells,\n cellCount,\n maxCells,\n },\n },\n );\n }\n}\n\nfunction integer(value: unknown, name: string): number {\n if (!Number.isSafeInteger(value)) throw invalidArgument(`${name} must be a safe integer`);\n return value as number;\n}\n\nfunction positiveInteger(value: unknown, name: string): number {\n const result = integer(value, name);\n if (result <= 0) throw invalidArgument(`${name} must be positive`);\n return result;\n}\n\nfunction asUint8Array(value: WireBatchBuffer): Uint8Array {\n if (value instanceof ArrayBuffer) return new Uint8Array(value);\n return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);\n}\n\nfunction isRecord(value: unknown): value is Record<string, any> {\n return typeof value === \"object\" && value !== null;\n}\n\nexport function assertNonNegativeSafeInteger(value: unknown, name: string): asserts value is number {\n if (!Number.isSafeInteger(value) || (value as number) < 0) {\n throw invalidArgument(`${name} must be a non-negative safe integer`, { name, value });\n }\n}\n\nexport function assertPositiveSafeInteger(value: unknown, name: string): asserts value is number {\n if (!Number.isSafeInteger(value) || (value as number) <= 0) {\n throw invalidArgument(`${name} must be a positive safe integer`, { name, value });\n }\n}\n", "import type { TableMetadata } from \"../model.js\";\n\nexport const DEFAULT_ROW_HEIGHT = 28;\nexport const DEFAULT_HEADER_HEIGHT = 36;\nexport const DEFAULT_ROW_HEADER_WIDTH = 64;\nexport const DEFAULT_COLUMN_WIDTH = 160;\nexport const DEFAULT_MIN_COLUMN_WIDTH = 64;\nexport const DEFAULT_MAX_COLUMN_WIDTH = 640;\nexport const DEFAULT_SCROLL_PIXEL_LIMIT = 16_000_000;\nexport const DEFAULT_OVERSCAN_ROWS = 8;\nexport const DEFAULT_OVERSCAN_COLUMNS = 1;\n\n/** A zero-based table coordinate. */\nexport interface CellPosition {\n readonly rowIndex: number;\n readonly columnIndex: number;\n}\n\n/** A zero-based, half-open rectangular table range. */\nexport interface GridRange {\n readonly rowStart: number;\n readonly rowEnd: number;\n readonly columnStart: number;\n readonly columnEnd: number;\n}\n\nexport interface TableSelection {\n readonly anchor: Readonly<CellPosition>;\n readonly focus: Readonly<CellPosition>;\n readonly range: Readonly<GridRange>;\n}\n\nexport interface PixelRect {\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n}\n\nexport interface IndexRange {\n readonly start: number;\n readonly end: number;\n}\n\nexport interface ScrollAxisLayout {\n readonly logicalContentSize: number;\n readonly logicalViewportSize: number;\n readonly logicalOffset: number;\n readonly logicalMaxOffset: number;\n readonly physicalContentSize: number;\n readonly physicalOffset: number;\n readonly physicalMaxOffset: number;\n readonly compressed: boolean;\n}\n\nexport interface VisibleColumn {\n readonly index: number;\n readonly id: string;\n readonly name: string;\n /** Viewport-relative left edge in CSS pixels. */\n readonly x: number;\n readonly width: number;\n /** True when the column is pinned at the workbook's frozen boundary. */\n readonly frozen: boolean;\n}\n\nexport interface VisibleRow {\n readonly index: number;\n /** Viewport-relative top edge in CSS pixels. */\n readonly y: number;\n readonly height: number;\n /** True when the row is pinned at the workbook's frozen boundary. */\n readonly frozen: boolean;\n}\n\nexport interface SparseAxisOverride {\n readonly index: number;\n readonly size: number;\n /** Cumulative size delta through and including this override. */\n readonly cumulativeDelta: number;\n}\n\n/** Compact geometry for a potentially million-row spreadsheet axis. */\nexport interface SparseAxisGeometry {\n readonly count: number;\n readonly defaultSize: number;\n readonly contentSize: number;\n readonly overrides: readonly Readonly<SparseAxisOverride>[];\n}\n\nexport interface TableLayout {\n readonly width: number;\n readonly height: number;\n readonly devicePixelRatio: number;\n readonly rowHeight: number;\n readonly headerHeight: number;\n readonly rowHeaderWidth: number;\n readonly bodyWidth: number;\n readonly bodyHeight: number;\n readonly rowCount: number;\n readonly columnCount: number;\n readonly rows: Readonly<{\n readonly visible: Readonly<IndexRange>;\n readonly overscan: Readonly<IndexRange>;\n }>;\n readonly columns: Readonly<{\n readonly visible: Readonly<IndexRange>;\n readonly overscan: Readonly<IndexRange>;\n }>;\n readonly visibleColumns: readonly Readonly<VisibleColumn>[];\n readonly overscanColumns: readonly Readonly<VisibleColumn>[];\n readonly visibleRows: readonly Readonly<VisibleRow>[];\n readonly overscanRows: readonly Readonly<VisibleRow>[];\n /** Effective widths use zero for workbook-hidden columns. */\n readonly effectiveColumnWidths: readonly number[];\n readonly rowGeometry: Readonly<SparseAxisGeometry>;\n readonly frozenRowCount: number;\n readonly frozenColumnCount: number;\n readonly frozenRowExtent: number;\n readonly frozenColumnExtent: number;\n /** Frozen segments are loaded separately when the scroll window is distant. */\n readonly frozenRowRange: Readonly<IndexRange>;\n readonly frozenColumnRange: Readonly<IndexRange>;\n readonly horizontal: Readonly<ScrollAxisLayout>;\n readonly vertical: Readonly<ScrollAxisLayout>;\n /** Spacer dimensions for a native scroll host, including sticky headers. */\n readonly spacerWidth: number;\n readonly spacerHeight: number;\n}\n\nexport type HitTestResult =\n | Readonly<{ kind: \"outside\" }>\n | Readonly<{ kind: \"corner\" }>\n | Readonly<{ kind: \"column-header\"; columnIndex: number }>\n | Readonly<{ kind: \"column-resize\"; columnIndex: number; boundaryX: number }>\n | Readonly<{ kind: \"row-header\"; rowIndex: number }>\n | Readonly<{ kind: \"cell\"; rowIndex: number; columnIndex: number }>;\n\nexport type CellLoadState =\n | Readonly<{ status: \"loading\" }>\n | Readonly<{ status: \"unavailable\" }>\n | Readonly<{ status: \"loaded\"; value: string | null }>;\n\nexport type TableViewStatus = \"loading\" | \"ready\" | \"error\" | \"closed\";\n\nexport interface TableViewSnapshot {\n readonly generation: number;\n readonly status: TableViewStatus;\n readonly metadata: Readonly<TableMetadata>;\n readonly layout: Readonly<TableLayout>;\n readonly activeCell: Readonly<CellPosition> | null;\n readonly selection: Readonly<TableSelection> | null;\n readonly error?: unknown;\n}\n\nexport interface ViewportUpdate {\n readonly width: number;\n readonly height: number;\n /** Native scroll-host offset in CSS pixels. */\n readonly scrollLeft: number;\n /** Native scroll-host offset in CSS pixels. */\n readonly scrollTop: number;\n readonly devicePixelRatio?: number;\n}\n\nexport interface TableControllerOptions {\n readonly rowHeight?: number;\n readonly headerHeight?: number;\n readonly rowHeaderWidth?: number;\n readonly columnWidth?: number;\n readonly minColumnWidth?: number;\n readonly maxColumnWidth?: number;\n readonly columnWidths?: Readonly<Record<string, number>>;\n readonly scrollPixelLimit?: number;\n readonly overscanRows?: number;\n readonly overscanColumns?: number;\n /** Hard bound for decoded render/cache cells. */\n readonly maxWindowCells?: number;\n}\n\nexport type NavigationCommand =\n | \"left\"\n | \"right\"\n | \"up\"\n | \"down\"\n | \"page-up\"\n | \"page-down\"\n | \"row-start\"\n | \"row-end\"\n | \"table-start\"\n | \"table-end\";\n\nexport interface SetActiveCellOptions {\n readonly extendSelection?: boolean;\n readonly scrollIntoView?: boolean;\n}\n\nexport interface MoveActiveCellOptions extends SetActiveCellOptions {}\n", "import { invalidArgument } from \"../errors.js\";\nimport type { PresentationAxisEntry, TableMetadata } from \"../model.js\";\nimport {\n DEFAULT_COLUMN_WIDTH,\n DEFAULT_HEADER_HEIGHT,\n DEFAULT_OVERSCAN_COLUMNS,\n DEFAULT_OVERSCAN_ROWS,\n DEFAULT_ROW_HEADER_WIDTH,\n DEFAULT_ROW_HEIGHT,\n DEFAULT_SCROLL_PIXEL_LIMIT,\n type GridRange,\n type HitTestResult,\n type IndexRange,\n type PixelRect,\n type ScrollAxisLayout,\n type SparseAxisGeometry,\n type TableLayout,\n type ViewportUpdate,\n type VisibleColumn,\n type VisibleRow,\n} from \"./types.js\";\n\nexport interface LayoutOptions {\n readonly rowHeight?: number;\n readonly headerHeight?: number;\n readonly rowHeaderWidth?: number;\n readonly scrollPixelLimit?: number;\n readonly overscanRows?: number;\n readonly overscanColumns?: number;\n readonly rowEntries?: readonly PresentationAxisEntry[];\n readonly hiddenColumns?: readonly boolean[];\n readonly frozenRows?: number;\n readonly frozenColumns?: number;\n}\n\nexport function createTableLayout(\n metadata: Readonly<TableMetadata>,\n columnWidths: readonly number[],\n viewport: ViewportUpdate,\n options: LayoutOptions = {},\n): Readonly<TableLayout> {\n const rowHeight = positiveFinite(options.rowHeight ?? DEFAULT_ROW_HEIGHT, \"rowHeight\");\n const headerHeight = nonNegativeFinite(\n options.headerHeight ?? DEFAULT_HEADER_HEIGHT,\n \"headerHeight\",\n );\n const rowHeaderWidth = nonNegativeFinite(\n options.rowHeaderWidth ?? DEFAULT_ROW_HEADER_WIDTH,\n \"rowHeaderWidth\",\n );\n const scrollPixelLimit = positiveFinite(\n options.scrollPixelLimit ?? DEFAULT_SCROLL_PIXEL_LIMIT,\n \"scrollPixelLimit\",\n );\n const overscanRows = nonNegativeInteger(\n options.overscanRows ?? DEFAULT_OVERSCAN_ROWS,\n \"overscanRows\",\n );\n const overscanColumns = nonNegativeInteger(\n options.overscanColumns ?? DEFAULT_OVERSCAN_COLUMNS,\n \"overscanColumns\",\n );\n const width = nonNegativeFinite(viewport.width, \"viewport.width\");\n const height = nonNegativeFinite(viewport.height, \"viewport.height\");\n const devicePixelRatio = positiveFinite(\n viewport.devicePixelRatio ?? 1,\n \"viewport.devicePixelRatio\",\n );\n const columnCount = metadata.schema.columns.length;\n if (columnWidths.length !== columnCount) {\n throw invalidArgument(\n `columnWidths has ${columnWidths.length} entries; expected ${columnCount}`,\n );\n }\n for (let index = 0; index < columnWidths.length; index += 1) {\n positiveFinite(columnWidths[index]!, `columnWidths[${index}]`);\n }\n const hiddenColumns = options.hiddenColumns ?? [];\n if (hiddenColumns.length !== 0 && hiddenColumns.length !== columnCount) {\n throw invalidArgument(\n `hiddenColumns has ${hiddenColumns.length} entries; expected ${columnCount}`,\n );\n }\n const effectiveColumnWidths = Object.freeze(columnWidths.map(\n (width, index) => hiddenColumns[index] === true ? 0 : width,\n ));\n\n const rowCount = extentValue(metadata.extent.rows);\n const frozenRowCount = Math.min(\n rowCount,\n nonNegativeInteger(options.frozenRows ?? 0, \"frozenRows\"),\n );\n const frozenColumnCount = Math.min(\n columnCount,\n nonNegativeInteger(options.frozenColumns ?? 0, \"frozenColumns\"),\n );\n const bodyWidth = Math.max(0, width - rowHeaderWidth);\n const bodyHeight = Math.max(0, height - headerHeight);\n const prefixes = columnOffsets(effectiveColumnWidths);\n const rowGeometry = createSparseAxisGeometry(\n rowCount,\n rowHeight,\n options.rowEntries ?? [],\n );\n const logicalWidth = prefixes[prefixes.length - 1] ?? 0;\n const logicalHeight = rowGeometry.contentSize;\n const horizontal = createScrollAxis(\n logicalWidth,\n bodyWidth,\n viewport.scrollLeft,\n scrollPixelLimit,\n );\n const vertical = createScrollAxis(\n logicalHeight,\n bodyHeight,\n viewport.scrollTop,\n scrollPixelLimit,\n );\n const visibleRows = visibleRowRange(\n rowGeometry,\n vertical.logicalOffset,\n bodyHeight,\n );\n const visibleColumns = visibleColumnRange(\n prefixes,\n horizontal.logicalOffset,\n bodyWidth,\n );\n const overscanRowRange = expandRange(visibleRows, overscanRows, rowCount);\n const overscanColumnRange = expandRange(visibleColumns, overscanColumns, columnCount);\n const frozenRowExtent = axisPosition(rowGeometry, frozenRowCount);\n const frozenColumnExtent = prefixes[frozenColumnCount] ?? 0;\n const frozenRowRange = frozenRowCount === 0\n ? Object.freeze({ start: 0, end: 0 })\n : clampRangeEnd(\n visibleRowRange(rowGeometry, 0, Math.min(bodyHeight, frozenRowExtent)),\n frozenRowCount,\n );\n const frozenColumnRange = frozenColumnCount === 0\n ? Object.freeze({ start: 0, end: 0 })\n : clampRangeEnd(\n visibleColumnRange(prefixes, 0, Math.min(bodyWidth, frozenColumnExtent)),\n frozenColumnCount,\n );\n\n return Object.freeze({\n width,\n height,\n devicePixelRatio,\n rowHeight,\n headerHeight,\n rowHeaderWidth,\n bodyWidth,\n bodyHeight,\n rowCount,\n columnCount,\n rows: Object.freeze({ visible: visibleRows, overscan: overscanRowRange }),\n columns: Object.freeze({ visible: visibleColumns, overscan: overscanColumnRange }),\n visibleColumns: materializeColumns(\n metadata,\n effectiveColumnWidths,\n prefixes,\n visibleColumns,\n frozenColumnRange,\n rowHeaderWidth,\n horizontal.logicalOffset,\n frozenColumnCount,\n ),\n overscanColumns: materializeColumns(\n metadata,\n effectiveColumnWidths,\n prefixes,\n overscanColumnRange,\n frozenColumnRange,\n rowHeaderWidth,\n horizontal.logicalOffset,\n frozenColumnCount,\n ),\n visibleRows: materializeRows(\n rowGeometry,\n visibleRows,\n frozenRowRange,\n headerHeight,\n vertical.logicalOffset,\n frozenRowCount,\n ),\n overscanRows: materializeRows(\n rowGeometry,\n overscanRowRange,\n frozenRowRange,\n headerHeight,\n vertical.logicalOffset,\n frozenRowCount,\n ),\n effectiveColumnWidths,\n rowGeometry,\n frozenRowCount,\n frozenColumnCount,\n frozenRowExtent,\n frozenColumnExtent,\n frozenRowRange,\n frozenColumnRange,\n horizontal,\n vertical,\n spacerWidth: rowHeaderWidth + horizontal.physicalContentSize,\n spacerHeight: headerHeight + vertical.physicalContentSize,\n });\n}\n\nexport function createScrollAxis(\n logicalContentSize: number,\n logicalViewportSize: number,\n physicalOffset: number,\n pixelLimit = DEFAULT_SCROLL_PIXEL_LIMIT,\n): Readonly<ScrollAxisLayout> {\n nonNegativeFinite(logicalContentSize, \"logicalContentSize\");\n nonNegativeFinite(logicalViewportSize, \"logicalViewportSize\");\n positiveFinite(pixelLimit, \"pixelLimit\");\n const logicalMaxOffset = Math.max(0, logicalContentSize - logicalViewportSize);\n const largestUsableSize = Math.max(pixelLimit, logicalViewportSize + 1);\n const physicalContentSize = Math.min(logicalContentSize, largestUsableSize);\n const physicalMaxOffset = Math.max(0, physicalContentSize - logicalViewportSize);\n const normalizedPhysicalOffset = clampFinite(physicalOffset, 0, physicalMaxOffset);\n const compressed = logicalMaxOffset > physicalMaxOffset;\n const logicalOffset = physicalMaxOffset === 0\n ? 0\n : compressed\n ? (normalizedPhysicalOffset / physicalMaxOffset) * logicalMaxOffset\n : normalizedPhysicalOffset;\n return Object.freeze({\n logicalContentSize,\n logicalViewportSize,\n logicalOffset,\n logicalMaxOffset,\n physicalContentSize,\n physicalOffset: normalizedPhysicalOffset,\n physicalMaxOffset,\n compressed,\n });\n}\n\nexport function logicalToPhysicalOffset(axis: ScrollAxisLayout, logicalOffset: number): number {\n const normalized = clampFinite(logicalOffset, 0, axis.logicalMaxOffset);\n if (!axis.compressed) {\n return Math.min(normalized, axis.physicalMaxOffset);\n }\n return axis.logicalMaxOffset === 0\n ? 0\n : (normalized / axis.logicalMaxOffset) * axis.physicalMaxOffset;\n}\n\nexport function physicalToLogicalOffset(axis: ScrollAxisLayout, physicalOffset: number): number {\n const normalized = clampFinite(physicalOffset, 0, axis.physicalMaxOffset);\n if (!axis.compressed) {\n return Math.min(normalized, axis.logicalMaxOffset);\n }\n return axis.physicalMaxOffset === 0\n ? 0\n : (normalized / axis.physicalMaxOffset) * axis.logicalMaxOffset;\n}\n\nexport function hitTest(\n layout: TableLayout,\n x: number,\n y: number,\n _columnWidths: readonly number[],\n resizeHandleWidth = 6,\n): HitTestResult {\n if (!Number.isFinite(x) || !Number.isFinite(y) || x < 0 || y < 0\n || x >= layout.width || y >= layout.height) {\n return Object.freeze({ kind: \"outside\" });\n }\n const columnWidths = layout.effectiveColumnWidths;\n if (x < layout.rowHeaderWidth && y < layout.headerHeight) {\n return Object.freeze({ kind: \"corner\" });\n }\n if (y < layout.headerHeight) {\n const offsets = columnOffsets(columnWidths);\n const logicalX = x - layout.rowHeaderWidth + layout.horizontal.logicalOffset;\n const nextBoundary = lowerBound(offsets, logicalX);\n const handleWidth = Math.max(0, resizeHandleWidth);\n for (const boundaryIndex of [nextBoundary, nextBoundary - 1]) {\n if (boundaryIndex <= 0 || boundaryIndex >= offsets.length) {\n continue;\n }\n const boundaryX = layout.rowHeaderWidth\n + offsets[boundaryIndex]!\n - layout.horizontal.logicalOffset;\n if (Math.abs(x - boundaryX) <= handleWidth) {\n return Object.freeze({\n kind: \"column-resize\",\n columnIndex: boundaryIndex - 1,\n boundaryX,\n });\n }\n }\n const columnIndex = columnAtViewportX(layout, x, columnWidths);\n if (columnIndex === null) {\n return Object.freeze({ kind: \"outside\" });\n }\n return Object.freeze({ kind: \"column-header\", columnIndex });\n }\n const rowIndex = rowAtViewportY(layout, y);\n if (rowIndex === null) {\n return Object.freeze({ kind: \"outside\" });\n }\n if (x < layout.rowHeaderWidth) {\n return Object.freeze({ kind: \"row-header\", rowIndex });\n }\n const columnIndex = columnAtViewportX(layout, x, columnWidths);\n return columnIndex === null\n ? Object.freeze({ kind: \"outside\" })\n : Object.freeze({ kind: \"cell\", rowIndex, columnIndex });\n}\n\nexport function cellRect(\n layout: TableLayout,\n _columnWidths: readonly number[],\n rowIndex: number,\n columnIndex: number,\n): Readonly<PixelRect> {\n const columnWidths = layout.effectiveColumnWidths;\n const offsets = columnOffsets(columnWidths);\n const rowOffset = axisPosition(layout.rowGeometry, rowIndex);\n const columnOffset = offsets[columnIndex] ?? 0;\n return Object.freeze({\n x: layout.rowHeaderWidth + columnOffset\n - (columnIndex < layout.frozenColumnCount ? 0 : layout.horizontal.logicalOffset),\n y: layout.headerHeight + rowOffset\n - (rowIndex < layout.frozenRowCount ? 0 : layout.vertical.logicalOffset),\n width: columnWidths[columnIndex] ?? 0,\n height: axisSize(layout.rowGeometry, rowIndex),\n });\n}\n\nexport function columnHeaderRect(\n layout: TableLayout,\n _columnWidths: readonly number[],\n columnIndex: number,\n): Readonly<PixelRect> {\n const columnWidths = layout.effectiveColumnWidths;\n const offsets = columnOffsets(columnWidths);\n return Object.freeze({\n x: layout.rowHeaderWidth + offsets[columnIndex]!\n - (columnIndex < layout.frozenColumnCount ? 0 : layout.horizontal.logicalOffset),\n y: 0,\n width: columnWidths[columnIndex] ?? 0,\n height: layout.headerHeight,\n });\n}\n\nexport function rowHeaderRect(layout: TableLayout, rowIndex: number): Readonly<PixelRect> {\n const rowOffset = axisPosition(layout.rowGeometry, rowIndex);\n return Object.freeze({\n x: 0,\n y: layout.headerHeight + rowOffset\n - (rowIndex < layout.frozenRowCount ? 0 : layout.vertical.logicalOffset),\n width: layout.rowHeaderWidth,\n height: axisSize(layout.rowGeometry, rowIndex),\n });\n}\n\nexport function selectionRect(\n layout: TableLayout,\n _columnWidths: readonly number[],\n range: GridRange,\n): Readonly<PixelRect> | null {\n const columnWidths = layout.effectiveColumnWidths;\n if (range.rowStart >= range.rowEnd || range.columnStart >= range.columnEnd) {\n return null;\n }\n const offsets = columnOffsets(columnWidths);\n const columnStart = clampInteger(range.columnStart, 0, columnWidths.length);\n const columnEnd = clampInteger(range.columnEnd, columnStart, columnWidths.length);\n const rowStart = clampInteger(range.rowStart, 0, layout.rowCount);\n const rowEnd = clampInteger(range.rowEnd, rowStart, layout.rowCount);\n if (columnStart === columnEnd || rowStart === rowEnd) {\n return null;\n }\n const frozenColumns = columnEnd <= layout.frozenColumnCount;\n const frozenRows = rowEnd <= layout.frozenRowCount;\n const rowStartOffset = axisPosition(layout.rowGeometry, rowStart);\n const rowEndOffset = axisPosition(layout.rowGeometry, rowEnd);\n return Object.freeze({\n x: layout.rowHeaderWidth + offsets[columnStart]!\n - (frozenColumns ? 0 : layout.horizontal.logicalOffset),\n y: layout.headerHeight + rowStartOffset\n - (frozenRows ? 0 : layout.vertical.logicalOffset),\n width: offsets[columnEnd]! - offsets[columnStart]!,\n height: rowEndOffset - rowStartOffset,\n });\n}\n\nexport function columnOffsets(columnWidths: readonly number[]): readonly number[] {\n const offsets = new Array<number>(columnWidths.length + 1);\n offsets[0] = 0;\n for (let index = 0; index < columnWidths.length; index += 1) {\n offsets[index + 1] = offsets[index]! + (columnWidths[index] ?? DEFAULT_COLUMN_WIDTH);\n }\n return offsets;\n}\n\nexport function extentValue(extent: TableMetadata[\"extent\"][\"rows\"]): number {\n return extent.kind === \"unknown\" ? 0 : extent.value;\n}\n\n/** Builds a compact sparse axis without allocating one entry per worksheet row. */\nexport function createSparseAxisGeometry(\n count: number,\n defaultSize: number,\n entries: readonly PresentationAxisEntry[] = [],\n): Readonly<SparseAxisGeometry> {\n nonNegativeInteger(count, \"axis count\");\n positiveFinite(defaultSize, \"axis defaultSize\");\n const byIndex = new Map<number, number>();\n for (const entry of entries) {\n if (!entry || !Number.isSafeInteger(entry.index) || entry.index < 0 || entry.index >= count) {\n continue;\n }\n if (entry.hidden === true) {\n byIndex.set(entry.index, 0);\n continue;\n }\n if (entry.size !== undefined) {\n if (!Number.isFinite(entry.size) || entry.size < 0) {\n continue;\n }\n byIndex.set(entry.index, entry.size);\n }\n }\n let cumulativeDelta = 0;\n const overrides = [...byIndex.entries()]\n .sort(([left], [right]) => left - right)\n .map(([index, size]) => {\n cumulativeDelta += size - defaultSize;\n return Object.freeze({ index, size, cumulativeDelta });\n });\n const contentSize = count * defaultSize + cumulativeDelta;\n return Object.freeze({\n count,\n defaultSize,\n contentSize: Math.max(0, contentSize),\n overrides: Object.freeze(overrides),\n });\n}\n\n/** Logical offset at the start of an axis index. */\nexport function axisPosition(geometry: SparseAxisGeometry, index: number): number {\n const normalized = clampInteger(index, 0, geometry.count);\n const overrideIndex = lowerBoundOverride(geometry.overrides, normalized);\n const delta = overrideIndex === 0 ? 0 : geometry.overrides[overrideIndex - 1]!.cumulativeDelta;\n return normalized * geometry.defaultSize + delta;\n}\n\n/** Effective axis extent, zero when a row/column is hidden. */\nexport function axisSize(geometry: SparseAxisGeometry, index: number): number {\n if (!Number.isSafeInteger(index) || index < 0 || index >= geometry.count) {\n return 0;\n }\n const match = sparseOverrideAt(geometry, index);\n return match?.size ?? geometry.defaultSize;\n}\n\n/** Finds the visible axis index containing a logical pixel offset. */\nexport function axisIndexAtOffset(geometry: SparseAxisGeometry, offset: number): number | null {\n if (!Number.isFinite(offset) || offset < 0 || offset >= geometry.contentSize || geometry.count === 0) {\n return null;\n }\n let low = 0;\n let high = geometry.count;\n while (low < high) {\n const middle = Math.floor((low + high) / 2);\n if (axisPosition(geometry, middle + 1) <= offset) {\n low = middle + 1;\n } else {\n high = middle;\n }\n }\n for (let index = low; index < geometry.count; index += 1) {\n const size = axisSize(geometry, index);\n const start = axisPosition(geometry, index);\n if (size > 0 && offset >= start && offset < start + size) {\n return index;\n }\n if (start > offset) {\n return null;\n }\n }\n return null;\n}\n\nexport function nextVisibleAxisIndex(\n geometry: SparseAxisGeometry,\n from: number,\n direction: -1 | 1 = 1,\n): number | null {\n for (\n let index = clampInteger(from, 0, Math.max(0, geometry.count - 1));\n index >= 0 && index < geometry.count;\n index += direction\n ) {\n if (axisSize(geometry, index) > 0) {\n return index;\n }\n }\n return null;\n}\n\nfunction sparseOverrideAt(\n geometry: SparseAxisGeometry,\n index: number,\n): Readonly<SparseAxisGeometry[\"overrides\"][number]> | undefined {\n const low = lowerBoundOverride(geometry.overrides, index);\n const candidate = geometry.overrides[low];\n return candidate?.index === index ? candidate : undefined;\n}\n\nfunction lowerBoundOverride(\n entries: readonly Readonly<SparseAxisGeometry[\"overrides\"][number]>[],\n target: number,\n): number {\n let low = 0;\n let high = entries.length;\n while (low < high) {\n const middle = Math.floor((low + high) / 2);\n if (entries[middle]!.index < target) low = middle + 1;\n else high = middle;\n }\n return low;\n}\n\nfunction clampRangeEnd(range: IndexRange, end: number): Readonly<IndexRange> {\n return Object.freeze({\n start: Math.min(range.start, end),\n end: Math.min(range.end, end),\n });\n}\n\nfunction visibleRowRange(\n geometry: SparseAxisGeometry,\n scrollTop: number,\n viewportHeight: number,\n): Readonly<IndexRange> {\n if (geometry.count === 0 || viewportHeight <= 0 || geometry.contentSize <= 0) {\n return Object.freeze({ start: 0, end: 0 });\n }\n const start = axisIndexAtOffset(geometry, scrollTop);\n if (start === null) {\n return Object.freeze({ start: geometry.count, end: geometry.count });\n }\n const last = axisIndexAtOffset(\n geometry,\n Math.max(\n scrollTop,\n Math.min(geometry.contentSize, scrollTop + viewportHeight)\n - Math.max(1e-7, Math.abs(scrollTop + viewportHeight) * Number.EPSILON * 4),\n ),\n );\n return Object.freeze({\n start,\n end: last === null ? start + 1 : Math.min(geometry.count, last + 1),\n });\n}\n\nfunction visibleColumnRange(\n offsets: readonly number[],\n scrollLeft: number,\n viewportWidth: number,\n): Readonly<IndexRange> {\n const count = Math.max(0, offsets.length - 1);\n if (count === 0 || viewportWidth <= 0) {\n return Object.freeze({ start: 0, end: 0 });\n }\n const start = columnAtLogicalX(offsets, scrollLeft) ?? count;\n const end = Math.min(count, lowerBound(offsets, scrollLeft + viewportWidth));\n return Object.freeze({ start, end: Math.max(start, end) });\n}\n\nfunction expandRange(range: IndexRange, amount: number, limit: number): Readonly<IndexRange> {\n return Object.freeze({\n start: Math.max(0, range.start - amount),\n end: Math.min(limit, range.end + amount),\n });\n}\n\nfunction materializeColumns(\n metadata: Readonly<TableMetadata>,\n widths: readonly number[],\n offsets: readonly number[],\n range: IndexRange,\n frozenRange: IndexRange,\n rowHeaderWidth: number,\n scrollLeft: number,\n frozenColumnCount: number,\n): readonly Readonly<VisibleColumn>[] {\n const indexes = rangeIndexes(range, frozenRange);\n const columns: VisibleColumn[] = [];\n for (const index of indexes) {\n const column = metadata.schema.columns[index]!;\n const width = widths[index] ?? 0;\n if (width <= 0) {\n continue;\n }\n const frozen = index < frozenColumnCount;\n columns.push(Object.freeze({\n index,\n id: column.id,\n name: column.name,\n x: rowHeaderWidth + offsets[index]! - (frozen ? 0 : scrollLeft),\n width,\n frozen,\n }));\n }\n return Object.freeze(columns);\n}\n\nfunction materializeRows(\n geometry: SparseAxisGeometry,\n range: IndexRange,\n frozenRange: IndexRange,\n headerHeight: number,\n scrollTop: number,\n frozenRowCount: number,\n): readonly Readonly<VisibleRow>[] {\n const rows: VisibleRow[] = [];\n for (const index of rangeIndexes(range, frozenRange)) {\n const height = axisSize(geometry, index);\n if (height <= 0) {\n continue;\n }\n const frozen = index < frozenRowCount;\n rows.push(Object.freeze({\n index,\n y: headerHeight + axisPosition(geometry, index) - (frozen ? 0 : scrollTop),\n height,\n frozen,\n }));\n }\n return Object.freeze(rows);\n}\n\nfunction rangeIndexes(primary: IndexRange, frozen: IndexRange): readonly number[] {\n const indexes = new Set<number>();\n for (let index = primary.start; index < primary.end; index += 1) {\n indexes.add(index);\n }\n for (let index = frozen.start; index < frozen.end; index += 1) {\n indexes.add(index);\n }\n return Object.freeze([...indexes].sort((left, right) => left - right));\n}\n\nfunction columnAtViewportX(\n layout: TableLayout,\n x: number,\n columnWidths: readonly number[],\n): number | null {\n if (x < layout.rowHeaderWidth) {\n return null;\n }\n const bodyX = x - layout.rowHeaderWidth;\n if (bodyX < Math.min(layout.bodyWidth, layout.frozenColumnExtent)) {\n const frozen = columnAtLogicalX(columnOffsets(columnWidths), bodyX);\n if (frozen !== null && frozen < layout.frozenColumnCount) {\n return frozen;\n }\n }\n return columnAtLogicalX(\n columnOffsets(columnWidths),\n bodyX + layout.horizontal.logicalOffset,\n );\n}\n\nfunction columnAtLogicalX(offsets: readonly number[], x: number): number | null {\n const count = Math.max(0, offsets.length - 1);\n if (x < 0 || count === 0 || x >= offsets[count]!) {\n return null;\n }\n let low = 0;\n let high = count;\n while (low < high) {\n const middle = Math.floor((low + high) / 2);\n if (offsets[middle + 1]! <= x) {\n low = middle + 1;\n } else {\n high = middle;\n }\n }\n return low;\n}\n\nfunction rowAtViewportY(layout: TableLayout, y: number): number | null {\n const bodyY = y - layout.headerHeight;\n if (bodyY < Math.min(layout.bodyHeight, layout.frozenRowExtent)) {\n const frozen = axisIndexAtOffset(layout.rowGeometry, bodyY);\n if (frozen !== null && frozen < layout.frozenRowCount) {\n return frozen;\n }\n }\n return axisIndexAtOffset(\n layout.rowGeometry,\n bodyY + layout.vertical.logicalOffset,\n );\n}\n\nfunction lowerBound(values: readonly number[], target: number): number {\n let low = 0;\n let high = values.length;\n while (low < high) {\n const middle = Math.floor((low + high) / 2);\n if (values[middle]! < target) {\n low = middle + 1;\n } else {\n high = middle;\n }\n }\n return low;\n}\n\nfunction positiveFinite(value: number, name: string): number {\n if (!Number.isFinite(value) || value <= 0) {\n throw invalidArgument(`${name} must be a positive finite number`);\n }\n return value;\n}\n\nfunction nonNegativeFinite(value: number, name: string): number {\n if (!Number.isFinite(value) || value < 0) {\n throw invalidArgument(`${name} must be a non-negative finite number`);\n }\n return value;\n}\n\nfunction nonNegativeInteger(value: number, name: string): number {\n if (!Number.isSafeInteger(value) || value < 0) {\n throw invalidArgument(`${name} must be a non-negative safe integer`);\n }\n return value;\n}\n\nfunction clampFinite(value: number, minimum: number, maximum: number): number {\n if (!Number.isFinite(value)) {\n return minimum;\n }\n return Math.min(maximum, Math.max(minimum, value));\n}\n\nfunction clampInteger(value: number, minimum: number, maximum: number): number {\n if (!Number.isFinite(value)) {\n return minimum;\n }\n return Math.min(maximum, Math.max(minimum, Math.trunc(value)));\n}\n", "import { invalidArgument } from \"../errors.js\";\nimport type {\n CellPosition,\n GridRange,\n NavigationCommand,\n TableSelection,\n} from \"./types.js\";\n\nexport function createSelection(\n anchor: CellPosition,\n focus: CellPosition = anchor,\n): Readonly<TableSelection> {\n assertCellPosition(anchor, \"anchor\");\n assertCellPosition(focus, \"focus\");\n const normalizedAnchor = Object.freeze({ ...anchor });\n const normalizedFocus = Object.freeze({ ...focus });\n return Object.freeze({\n anchor: normalizedAnchor,\n focus: normalizedFocus,\n range: selectionRange(normalizedAnchor, normalizedFocus),\n });\n}\n\nexport function selectionRange(anchor: CellPosition, focus: CellPosition): Readonly<GridRange> {\n return Object.freeze({\n rowStart: Math.min(anchor.rowIndex, focus.rowIndex),\n rowEnd: Math.max(anchor.rowIndex, focus.rowIndex) + 1,\n columnStart: Math.min(anchor.columnIndex, focus.columnIndex),\n columnEnd: Math.max(anchor.columnIndex, focus.columnIndex) + 1,\n });\n}\n\nexport function containsCell(range: GridRange, cell: CellPosition): boolean {\n return cell.rowIndex >= range.rowStart\n && cell.rowIndex < range.rowEnd\n && cell.columnIndex >= range.columnStart\n && cell.columnIndex < range.columnEnd;\n}\n\nexport function clampCell(\n cell: CellPosition,\n rowCount: number,\n columnCount: number,\n): Readonly<CellPosition> | null {\n if (rowCount <= 0 || columnCount <= 0) {\n return null;\n }\n return Object.freeze({\n rowIndex: clampInteger(cell.rowIndex, 0, rowCount - 1),\n columnIndex: clampInteger(cell.columnIndex, 0, columnCount - 1),\n });\n}\n\nexport function moveCell(\n cell: CellPosition,\n command: NavigationCommand,\n rowCount: number,\n columnCount: number,\n pageRowCount: number,\n): Readonly<CellPosition> | null {\n const current = clampCell(cell, rowCount, columnCount);\n if (current === null) {\n return null;\n }\n const page = Math.max(1, Math.floor(pageRowCount));\n switch (command) {\n case \"left\":\n return clampCell({ rowIndex: current.rowIndex, columnIndex: current.columnIndex - 1 }, rowCount, columnCount);\n case \"right\":\n return clampCell({ rowIndex: current.rowIndex, columnIndex: current.columnIndex + 1 }, rowCount, columnCount);\n case \"up\":\n return clampCell({ rowIndex: current.rowIndex - 1, columnIndex: current.columnIndex }, rowCount, columnCount);\n case \"down\":\n return clampCell({ rowIndex: current.rowIndex + 1, columnIndex: current.columnIndex }, rowCount, columnCount);\n case \"page-up\":\n return clampCell({ rowIndex: current.rowIndex - page, columnIndex: current.columnIndex }, rowCount, columnCount);\n case \"page-down\":\n return clampCell({ rowIndex: current.rowIndex + page, columnIndex: current.columnIndex }, rowCount, columnCount);\n case \"row-start\":\n return Object.freeze({ rowIndex: current.rowIndex, columnIndex: 0 });\n case \"row-end\":\n return Object.freeze({ rowIndex: current.rowIndex, columnIndex: columnCount - 1 });\n case \"table-start\":\n return Object.freeze({ rowIndex: 0, columnIndex: 0 });\n case \"table-end\":\n return Object.freeze({ rowIndex: rowCount - 1, columnIndex: columnCount - 1 });\n }\n}\n\nexport function assertCellPosition(value: CellPosition, name: string): void {\n if (!Number.isSafeInteger(value.rowIndex) || value.rowIndex < 0) {\n throw invalidArgument(`${name}.rowIndex must be a non-negative safe integer`);\n }\n if (!Number.isSafeInteger(value.columnIndex) || value.columnIndex < 0) {\n throw invalidArgument(`${name}.columnIndex must be a non-negative safe integer`);\n }\n}\n\nfunction clampInteger(value: number, minimum: number, maximum: number): number {\n if (!Number.isFinite(value)) {\n return minimum;\n }\n return Math.min(maximum, Math.max(minimum, Math.trunc(value)));\n}\n", "import type { TableHandle, TableEvent, Unsubscribe } from \"../client.js\";\nimport { TabularkError, closedError, invalidArgument } from \"../errors.js\";\nimport {\n MAX_RANGE_CELLS,\n type MergedCellRegion,\n type PresentationAxisEntry,\n type RangeRequest,\n type SpreadsheetPresentation,\n type TableBatch,\n} from \"../model.js\";\nimport {\n axisPosition,\n axisSize,\n cellRect,\n columnOffsets,\n createTableLayout,\n extentValue,\n hitTest,\n logicalToPhysicalOffset,\n nextVisibleAxisIndex,\n selectionRect,\n type LayoutOptions,\n} from \"./layout.js\";\nimport { assertCellPosition, clampCell, createSelection, moveCell } from \"./selection.js\";\nimport {\n DEFAULT_COLUMN_WIDTH,\n DEFAULT_MAX_COLUMN_WIDTH,\n DEFAULT_MIN_COLUMN_WIDTH,\n type CellLoadState,\n type CellPosition,\n type GridRange,\n type HitTestResult,\n type MoveActiveCellOptions,\n type NavigationCommand,\n type PixelRect,\n type SetActiveCellOptions,\n type TableControllerOptions,\n type TableSelection,\n type TableViewSnapshot,\n type ViewportUpdate,\n} from \"./types.js\";\n\nconst DEFAULT_MAX_WINDOW_CELLS = 100_000;\n\ninterface LoadedWindow {\n readonly range: Readonly<GridRange>;\n readonly rows: readonly (readonly (string | null)[])[];\n}\n\ninterface NormalizedOptions extends LayoutOptions {\n readonly columnWidth: number;\n readonly minColumnWidth: number;\n readonly maxColumnWidth: number;\n readonly columnWidths: Readonly<Record<string, number>>;\n readonly maxWindowCells: number;\n}\n\nexport interface TableViewController {\n readonly metadata: TableHandle[\"metadata\"];\n readonly columnWidths: readonly number[];\n readonly minColumnWidth: number;\n readonly maxColumnWidth: number;\n getSnapshot(): Readonly<TableViewSnapshot>;\n subscribe(listener: (snapshot: Readonly<TableViewSnapshot>) => void): Unsubscribe;\n updateViewport(viewport: ViewportUpdate): void;\n setActiveCell(cell: CellPosition, options?: SetActiveCellOptions): void;\n extendSelection(cell: CellPosition, options?: Omit<SetActiveCellOptions, \"extendSelection\">): void;\n setSelection(anchor: CellPosition, focus?: CellPosition): void;\n clearSelection(): void;\n moveActive(command: NavigationCommand, options?: MoveActiveCellOptions): void;\n ensureCellVisible(cell: CellPosition): void;\n ensureColumnVisible(columnIndex: number): void;\n resizeColumn(columnIndex: number, width: number): void;\n autosizeColumn(columnIndex: number, measuredWidth: number): void;\n /** Applies validated static worksheet geometry in one controller generation. */\n applySpreadsheetPresentation(presentation: SpreadsheetPresentation): void;\n /** Updates merge interaction geometry for the currently loaded presentation window. */\n setMergedCells(regions: readonly MergedCellRegion[]): void;\n hitTest(x: number, y: number, resizeHandleWidth?: number): HitTestResult;\n cellRect(cell: CellPosition): Readonly<PixelRect>;\n selectionRect(selection?: TableSelection | null): Readonly<PixelRect> | null;\n getCell(rowIndex: number, columnIndex: number): CellLoadState;\n copySelection(options?: { readonly signal?: AbortSignal }): Promise<string>;\n dispose(): void;\n}\n\nclass Controller implements TableViewController {\n readonly #table: TableHandle;\n readonly #options: NormalizedOptions;\n readonly #listeners = new Set<(snapshot: Readonly<TableViewSnapshot>) => void>();\n readonly #unsubscribe: Unsubscribe;\n #viewport: Required<ViewportUpdate> = {\n width: 0,\n height: 0,\n scrollLeft: 0,\n scrollTop: 0,\n devicePixelRatio: 1,\n };\n #columnWidths: number[];\n #hiddenColumns: boolean[];\n #presentationRows: readonly PresentationAxisEntry[] = [];\n #frozenRows = 0;\n #frozenColumns = 0;\n #mergedCells: readonly MergedCellRegion[] = [];\n #snapshot: Readonly<TableViewSnapshot>;\n #activeCell: Readonly<CellPosition> | null = null;\n #selection: Readonly<TableSelection> | null = null;\n #windows: readonly LoadedWindow[] = [];\n #loadingRanges: readonly Readonly<GridRange>[] = [];\n #requestAbort: AbortController | null = null;\n #generation = 0;\n #loadQueued = false;\n #disposed = false;\n #tableClosed = false;\n\n constructor(table: TableHandle, options: TableControllerOptions) {\n this.#table = table;\n this.#options = normalizeOptions(options);\n this.#columnWidths = initialColumnWidths(table.metadata, this.#options);\n this.#hiddenColumns = Array.from({ length: this.#columnWidths.length }, () => false);\n const layout = createTableLayout(\n table.metadata,\n this.#columnWidths,\n this.#viewport,\n this.#layoutOptions(),\n );\n this.#snapshot = Object.freeze({\n generation: this.#generation,\n status: \"loading\",\n metadata: table.metadata,\n layout,\n activeCell: null,\n selection: null,\n });\n this.#unsubscribe = table.subscribe((event) => this.#handleTableEvent(event));\n }\n\n get metadata(): TableHandle[\"metadata\"] {\n return this.#table.metadata;\n }\n\n get columnWidths(): readonly number[] {\n return Object.freeze([...this.#columnWidths]);\n }\n\n get minColumnWidth(): number {\n return this.#options.minColumnWidth;\n }\n\n get maxColumnWidth(): number {\n return this.#options.maxColumnWidth;\n }\n\n getSnapshot(): Readonly<TableViewSnapshot> {\n return this.#snapshot;\n }\n\n subscribe(listener: (snapshot: Readonly<TableViewSnapshot>) => void): Unsubscribe {\n this.#assertOpen();\n this.#listeners.add(listener);\n return () => this.#listeners.delete(listener);\n }\n\n updateViewport(viewport: ViewportUpdate): void {\n this.#assertOpen();\n const normalized = normalizeViewport(viewport);\n if (sameViewport(normalized, this.#viewport)) {\n return;\n }\n this.#viewport = normalized;\n this.#advanceGeneration();\n }\n\n setActiveCell(cell: CellPosition, options: SetActiveCellOptions = {}): void {\n this.#assertOpen();\n assertCellPosition(cell, \"cell\");\n const clamped = clampCell(\n cell,\n this.#snapshot.layout.rowCount,\n this.#snapshot.layout.columnCount,\n );\n if (clamped === null) {\n return;\n }\n const next = this.#visibleCell(this.#mergeAnchor(clamped), 1, 1);\n if (next === null) return;\n const anchor = options.extendSelection && this.#selection !== null\n ? this.#selection.anchor\n : next;\n this.#activeCell = next;\n this.#selection = createMergedSelection(anchor, next, this.#mergedCells);\n if (options.scrollIntoView !== false && this.#scrollCellIntoView(next)) {\n this.#advanceGeneration();\n return;\n }\n this.#publish();\n }\n\n extendSelection(\n cell: CellPosition,\n options: Omit<SetActiveCellOptions, \"extendSelection\"> = {},\n ): void {\n this.setActiveCell(cell, { ...options, extendSelection: true });\n }\n\n setSelection(anchor: CellPosition, focus: CellPosition = anchor): void {\n this.#assertOpen();\n assertCellPosition(anchor, \"anchor\");\n assertCellPosition(focus, \"focus\");\n const rawAnchor = clampCell(\n anchor,\n this.#snapshot.layout.rowCount,\n this.#snapshot.layout.columnCount,\n );\n const rawFocus = clampCell(\n focus,\n this.#snapshot.layout.rowCount,\n this.#snapshot.layout.columnCount,\n );\n if (rawAnchor === null || rawFocus === null) {\n this.clearSelection();\n return;\n }\n const clampedAnchor = this.#visibleCell(this.#mergeAnchor(rawAnchor), 1, 1);\n const clampedFocus = this.#visibleCell(this.#mergeAnchor(rawFocus), 1, 1);\n if (clampedAnchor === null || clampedFocus === null) {\n this.clearSelection();\n return;\n }\n this.#activeCell = clampedFocus;\n this.#selection = createMergedSelection(clampedAnchor, clampedFocus, this.#mergedCells);\n this.#publish();\n }\n\n clearSelection(): void {\n this.#assertOpen();\n if (this.#selection === null) {\n return;\n }\n this.#selection = null;\n this.#publish();\n }\n\n moveActive(command: NavigationCommand, options: MoveActiveCellOptions = {}): void {\n this.#assertOpen();\n const current = this.#activeCell ?? { rowIndex: 0, columnIndex: 0 };\n const origin = navigationOrigin(current, command, this.#mergedCells);\n const moved = moveCell(\n origin,\n command,\n this.#snapshot.layout.rowCount,\n this.#snapshot.layout.columnCount,\n Math.max(1, this.#snapshot.layout.visibleRows.filter((row) => !row.frozen).length),\n );\n const [rowDirection, columnDirection] = navigationDirections(command);\n const next = moved === null\n ? null\n : this.#visibleCell(this.#mergeAnchor(moved), rowDirection, columnDirection);\n if (next !== null) {\n this.setActiveCell(next, options);\n }\n }\n\n ensureCellVisible(cell: CellPosition): void {\n this.#assertOpen();\n assertCellPosition(cell, \"cell\");\n const next = clampCell(\n cell,\n this.#snapshot.layout.rowCount,\n this.#snapshot.layout.columnCount,\n );\n if (next !== null && this.#scrollCellIntoView(next)) {\n this.#advanceGeneration();\n }\n }\n\n ensureColumnVisible(columnIndex: number): void {\n this.#assertOpen();\n assertColumnIndex(columnIndex, this.#columnWidths.length);\n if (this.#scrollColumnIntoView(columnIndex)) {\n this.#advanceGeneration();\n }\n }\n\n resizeColumn(columnIndex: number, width: number): void {\n this.#assertOpen();\n assertColumnIndex(columnIndex, this.#columnWidths.length);\n const normalized = clampWidth(width, this.#options);\n if (this.#columnWidths[columnIndex] === normalized) {\n return;\n }\n this.#columnWidths[columnIndex] = normalized;\n this.#advanceGeneration();\n }\n\n autosizeColumn(columnIndex: number, measuredWidth: number): void {\n this.resizeColumn(columnIndex, measuredWidth);\n }\n\n applySpreadsheetPresentation(presentation: SpreadsheetPresentation): void {\n this.#assertOpen();\n if (presentation.kind !== \"spreadsheet-v1\" || presentation.tableId !== this.metadata.tableId) {\n throw invalidArgument(\"presentation must belong to the controller table\");\n }\n const nextWidths = [...this.#columnWidths];\n const hiddenColumns = Array.from({ length: nextWidths.length }, () => false);\n for (const entry of presentation.columns) {\n if (!Number.isSafeInteger(entry.index) || entry.index < 0 || entry.index >= nextWidths.length) {\n continue;\n }\n hiddenColumns[entry.index] = entry.hidden === true;\n if (entry.size !== undefined && Number.isFinite(entry.size) && entry.size > 0) {\n nextWidths[entry.index] = clampWidth(entry.size, this.#options);\n }\n }\n this.#columnWidths = nextWidths;\n this.#hiddenColumns = hiddenColumns;\n this.#presentationRows = Object.freeze(presentation.rows.map((entry) => Object.freeze({ ...entry })));\n this.#frozenRows = presentation.frozenRows;\n this.#frozenColumns = presentation.frozenColumns;\n this.#mergedCells = [];\n this.#advanceGeneration();\n this.#normalizeInteractionForPresentation();\n this.#publish();\n }\n\n setMergedCells(regions: readonly MergedCellRegion[]): void {\n this.#assertOpen();\n const normalized = normalizeMergedCells(\n regions,\n this.#snapshot.layout.rowCount,\n this.#snapshot.layout.columnCount,\n );\n if (sameMergedCells(normalized, this.#mergedCells)) {\n return;\n }\n this.#mergedCells = normalized;\n this.#normalizeInteractionForPresentation();\n // A merge may intersect the viewport while its value anchor is far\n // outside the ordinary visible/overscan windows. Start a new generation\n // so those anchors are requested along with the visible cells.\n this.#advanceGeneration();\n }\n\n hitTest(x: number, y: number, resizeHandleWidth?: number): HitTestResult {\n const result = hitTest(\n this.#snapshot.layout,\n x,\n y,\n this.#columnWidths,\n resizeHandleWidth,\n );\n if (result.kind !== \"cell\") {\n return result;\n }\n const anchor = this.#mergeAnchor(result);\n return Object.freeze({ kind: \"cell\", ...anchor });\n }\n\n cellRect(cell: CellPosition): Readonly<PixelRect> {\n assertCellPosition(cell, \"cell\");\n if (cell.rowIndex >= this.#snapshot.layout.rowCount\n || cell.columnIndex >= this.#snapshot.layout.columnCount) {\n throw invalidArgument(\"cell must be inside the current table extent\");\n }\n return cellRect(\n this.#snapshot.layout,\n this.#columnWidths,\n cell.rowIndex,\n cell.columnIndex,\n );\n }\n\n selectionRect(selection: TableSelection | null = this.#selection): Readonly<PixelRect> | null {\n return selection === null\n ? null\n : selectionRect(this.#snapshot.layout, this.#columnWidths, selection.range);\n }\n\n getCell(rowIndex: number, columnIndex: number): CellLoadState {\n if (!isValidCell(rowIndex, columnIndex, this.#snapshot.layout.rowCount, this.#columnWidths.length)) {\n return Object.freeze({ status: \"unavailable\" });\n }\n for (const window of this.#windows) {\n if (rangeContains(window.range, rowIndex, columnIndex)) {\n return Object.freeze({\n status: \"loaded\",\n value: window.rows[rowIndex - window.range.rowStart]![columnIndex - window.range.columnStart]!,\n });\n }\n }\n for (const range of this.#loadingRanges) {\n if (rangeContains(range, rowIndex, columnIndex)) {\n return Object.freeze({ status: \"loading\" });\n }\n }\n return Object.freeze({ status: \"unavailable\" });\n }\n\n async copySelection(options: { readonly signal?: AbortSignal } = {}): Promise<string> {\n this.#assertOpen();\n const selection = this.#selection;\n if (selection === null) {\n return \"\";\n }\n const request = gridRangeToRequest(selection.range);\n assertWindowCellLimit(request, MAX_RANGE_CELLS, \"selection\");\n const batch = await this.#table.readRange(\n request,\n options.signal ? { signal: options.signal } : {},\n );\n return rowsToTsv(batchRows(batch));\n }\n\n dispose(): void {\n if (this.#disposed) {\n return;\n }\n this.#disposed = true;\n this.#requestAbort?.abort();\n this.#requestAbort = null;\n this.#unsubscribe();\n this.#listeners.clear();\n this.#windows = [];\n this.#loadingRanges = [];\n this.#snapshot = Object.freeze({\n ...this.#snapshot,\n status: \"closed\",\n activeCell: null,\n selection: null,\n });\n }\n\n #advanceGeneration(): void {\n this.#generation += 1;\n this.#requestAbort?.abort();\n this.#requestAbort = null;\n this.#loadingRanges = [];\n this.#rebuildSnapshot(\"loading\");\n this.#queueLoad();\n }\n\n #queueLoad(): void {\n if (this.#loadQueued || this.#disposed) {\n return;\n }\n this.#loadQueued = true;\n queueMicrotask(() => {\n this.#loadQueued = false;\n if (!this.#disposed) {\n void this.#loadGeneration(this.#generation);\n }\n });\n }\n\n async #loadGeneration(generation: number): Promise<void> {\n let visible: readonly Readonly<GridRange>[];\n let overscan: readonly Readonly<GridRange>[];\n try {\n ({ visible, overscan } = layoutRanges(\n this.#snapshot.layout,\n this.#options.maxWindowCells,\n this.#mergedCells,\n ));\n } catch (error) {\n if (!this.#disposed && generation === this.#generation) {\n this.#loadingRanges = [];\n this.#rebuildSnapshot(\"error\", error);\n }\n return;\n }\n if (visible.length === 0) {\n this.#windows = [];\n this.#loadingRanges = [];\n this.#rebuildSnapshot(\"ready\");\n return;\n }\n const abort = new AbortController();\n this.#requestAbort = abort;\n const ranges = Object.freeze([\n ...visible,\n ...overscan.filter((candidate) => !visible.some(\n (required) => rangeContainsRange(candidate, required) && sameGridRange(candidate, required),\n )),\n ]);\n this.#loadingRanges = Object.freeze(ranges);\n this.#publish();\n let loaded: LoadedWindow[] = [];\n try {\n for (let index = 0; index < ranges.length; index += 1) {\n const range = ranges[index]!;\n const batch = await this.#table.readRange(\n gridRangeToRequest(range),\n { signal: abort.signal },\n );\n if (this.#disposed || generation !== this.#generation || abort.signal.aborted) {\n return;\n }\n const returnedRange = batchGridRange(batch);\n if (returnedRange.rowStart < returnedRange.rowEnd\n && returnedRange.columnStart < returnedRange.columnEnd) {\n const window = Object.freeze({ range: returnedRange, rows: batchRows(batch) });\n loaded = [window, ...loaded.filter(\n (candidate) => !rangeContainsRange(returnedRange, candidate.range),\n )];\n }\n this.#windows = Object.freeze([...loaded]);\n this.#loadingRanges = Object.freeze(ranges.slice(index + 1));\n this.#rebuildSnapshot(\"ready\");\n }\n } catch (error) {\n if (this.#disposed || generation !== this.#generation || abort.signal.aborted\n || (error instanceof TabularkError && error.code === \"CANCELLED\")) {\n return;\n }\n this.#loadingRanges = [];\n this.#rebuildSnapshot(\"error\", error);\n } finally {\n if (this.#requestAbort === abort) {\n this.#requestAbort = null;\n }\n }\n }\n\n #scrollCellIntoView(cell: CellPosition): boolean {\n const layout = this.#snapshot.layout;\n const offsets = columnOffsets(layout.effectiveColumnWidths);\n const cellLeft = offsets[cell.columnIndex]!;\n const cellRight = offsets[cell.columnIndex + 1]!;\n const cellTop = axisPosition(layout.rowGeometry, cell.rowIndex);\n const cellBottom = cellTop + axisSize(layout.rowGeometry, cell.rowIndex);\n const logicalLeft = cell.columnIndex < layout.frozenColumnCount\n ? layout.horizontal.logicalOffset\n : revealOffset(\n layout.horizontal.logicalOffset,\n layout.bodyWidth,\n cellLeft,\n cellRight,\n layout.horizontal.logicalMaxOffset,\n );\n const logicalTop = cell.rowIndex < layout.frozenRowCount\n ? layout.vertical.logicalOffset\n : revealOffset(\n layout.vertical.logicalOffset,\n layout.bodyHeight,\n cellTop,\n cellBottom,\n layout.vertical.logicalMaxOffset,\n );\n const scrollLeft = logicalToPhysicalOffset(layout.horizontal, logicalLeft);\n const scrollTop = logicalToPhysicalOffset(layout.vertical, logicalTop);\n if (scrollLeft === this.#viewport.scrollLeft && scrollTop === this.#viewport.scrollTop) {\n return false;\n }\n this.#viewport = Object.freeze({ ...this.#viewport, scrollLeft, scrollTop });\n return true;\n }\n\n #scrollColumnIntoView(columnIndex: number): boolean {\n const layout = this.#snapshot.layout;\n const offsets = columnOffsets(layout.effectiveColumnWidths);\n const logicalLeft = columnIndex < layout.frozenColumnCount\n ? layout.horizontal.logicalOffset\n : revealOffset(\n layout.horizontal.logicalOffset,\n layout.bodyWidth,\n offsets[columnIndex]!,\n offsets[columnIndex + 1]!,\n layout.horizontal.logicalMaxOffset,\n );\n const scrollLeft = logicalToPhysicalOffset(layout.horizontal, logicalLeft);\n if (scrollLeft === this.#viewport.scrollLeft) {\n return false;\n }\n this.#viewport = Object.freeze({ ...this.#viewport, scrollLeft });\n return true;\n }\n\n #handleTableEvent(event: TableEvent): void {\n if (this.#disposed) {\n return;\n }\n switch (event.type) {\n case \"metadata\": {\n const previousMetadata = this.#snapshot.metadata;\n this.#columnWidths = reconcileColumnWidths(\n previousMetadata,\n event.metadata,\n this.#columnWidths,\n this.#options,\n );\n const hiddenById = new Map(previousMetadata.schema.columns.map(\n (column, index) => [column.id, this.#hiddenColumns[index] === true] as const,\n ));\n this.#hiddenColumns = event.metadata.schema.columns.map(\n (column) => hiddenById.get(column.id) === true,\n );\n this.#advanceGeneration();\n this.#clampInteraction();\n this.#publish();\n break;\n }\n case \"runtimeError\":\n this.#requestAbort?.abort();\n this.#requestAbort = null;\n this.#loadingRanges = [];\n this.#rebuildSnapshot(\"error\", event.error);\n break;\n case \"closed\":\n this.#tableClosed = true;\n this.#requestAbort?.abort();\n this.#requestAbort = null;\n this.#loadingRanges = [];\n if (this.#snapshot.status !== \"error\") {\n this.#rebuildSnapshot(\"closed\");\n }\n break;\n case \"warning\":\n break;\n }\n }\n\n #clampInteraction(): void {\n if (this.#activeCell === null) {\n return;\n }\n const rowCount = extentValue(this.#table.metadata.extent.rows);\n const columnCount = this.#table.metadata.schema.columns.length;\n const rawActive = clampCell(this.#activeCell, rowCount, columnCount);\n const nextActive = rawActive === null\n ? null\n : this.#visibleCell(this.#mergeAnchor(rawActive), 1, 1);\n if (nextActive === null) {\n this.#activeCell = null;\n this.#selection = null;\n return;\n }\n this.#activeCell = nextActive;\n if (this.#selection !== null) {\n const rawAnchor = clampCell(this.#selection.anchor, rowCount, columnCount)!;\n const rawFocus = clampCell(this.#selection.focus, rowCount, columnCount)!;\n const anchor = this.#visibleCell(this.#mergeAnchor(rawAnchor), 1, 1);\n const focus = this.#visibleCell(this.#mergeAnchor(rawFocus), 1, 1);\n this.#selection = anchor === null || focus === null\n ? null\n : createMergedSelection(anchor, focus, this.#mergedCells);\n }\n }\n\n #layoutOptions(): LayoutOptions {\n return Object.freeze({\n ...this.#options,\n rowEntries: this.#presentationRows,\n hiddenColumns: this.#hiddenColumns,\n frozenRows: this.#frozenRows,\n frozenColumns: this.#frozenColumns,\n });\n }\n\n #mergeAnchor(cell: CellPosition): Readonly<CellPosition> {\n const region = mergeContaining(this.#mergedCells, cell);\n return region === undefined\n ? Object.freeze({ rowIndex: cell.rowIndex, columnIndex: cell.columnIndex })\n : Object.freeze({ rowIndex: region.rowStart, columnIndex: region.columnStart });\n }\n\n #visibleCell(\n cell: CellPosition,\n rowDirection: -1 | 1,\n columnDirection: -1 | 1,\n ): Readonly<CellPosition> | null {\n const layout = this.#snapshot.layout;\n const row = nextVisibleAxisIndex(layout.rowGeometry, cell.rowIndex, rowDirection)\n ?? nextVisibleAxisIndex(layout.rowGeometry, cell.rowIndex, rowDirection === 1 ? -1 : 1);\n if (row === null) return null;\n const column = nextVisibleColumn(\n layout.effectiveColumnWidths,\n cell.columnIndex,\n columnDirection,\n ) ?? nextVisibleColumn(\n layout.effectiveColumnWidths,\n cell.columnIndex,\n columnDirection === 1 ? -1 : 1,\n );\n return column === null ? null : Object.freeze({ rowIndex: row, columnIndex: column });\n }\n\n #normalizeInteractionForPresentation(): void {\n this.#clampInteraction();\n }\n\n #rebuildSnapshot(status: TableViewSnapshot[\"status\"], error?: unknown): void {\n const layout = createTableLayout(\n this.#table.metadata,\n this.#columnWidths,\n this.#viewport,\n this.#layoutOptions(),\n );\n this.#viewport = Object.freeze({\n ...this.#viewport,\n scrollLeft: layout.horizontal.physicalOffset,\n scrollTop: layout.vertical.physicalOffset,\n });\n this.#snapshot = Object.freeze({\n generation: this.#generation,\n status,\n metadata: this.#table.metadata,\n layout,\n activeCell: this.#activeCell,\n selection: this.#selection,\n ...(error === undefined ? {} : { error }),\n });\n this.#emit();\n }\n\n #publish(): void {\n this.#snapshot = Object.freeze({\n ...this.#snapshot,\n activeCell: this.#activeCell,\n selection: this.#selection,\n });\n this.#emit();\n }\n\n #emit(): void {\n for (const listener of this.#listeners) {\n try {\n listener(this.#snapshot);\n } catch (error) {\n if (typeof reportError === \"function\") {\n reportError(error);\n }\n }\n }\n }\n\n #assertOpen(): void {\n if (this.#disposed || this.#tableClosed || this.#snapshot.status === \"closed\") {\n throw closedError(\"Table view controller\");\n }\n }\n}\n\nexport function createTableController(\n table: TableHandle,\n options: TableControllerOptions = {},\n): TableViewController {\n if (!table || typeof table.readRange !== \"function\" || typeof table.subscribe !== \"function\") {\n throw invalidArgument(\"table must be a TableHandle\");\n }\n return new Controller(table, options);\n}\n\nfunction normalizeMergedCells(\n regions: readonly MergedCellRegion[],\n rowCount: number,\n columnCount: number,\n): readonly MergedCellRegion[] {\n const unique = new Map<string, MergedCellRegion>();\n for (const region of regions) {\n if (\n !region\n || !Number.isSafeInteger(region.rowStart)\n || !Number.isSafeInteger(region.rowEnd)\n || !Number.isSafeInteger(region.columnStart)\n || !Number.isSafeInteger(region.columnEnd)\n || region.rowStart < 0\n || region.columnStart < 0\n || region.rowEnd <= region.rowStart\n || region.columnEnd <= region.columnStart\n || region.rowEnd > rowCount\n || region.columnEnd > columnCount\n ) {\n continue;\n }\n const frozen = Object.freeze({ ...region });\n unique.set(mergeKey(frozen), frozen);\n }\n return Object.freeze([...unique.values()].sort(\n (left, right) => left.rowStart - right.rowStart\n || left.columnStart - right.columnStart\n || left.rowEnd - right.rowEnd\n || left.columnEnd - right.columnEnd,\n ));\n}\n\nfunction sameMergedCells(\n left: readonly MergedCellRegion[],\n right: readonly MergedCellRegion[],\n): boolean {\n return left.length === right.length\n && left.every((region, index) => mergeKey(region) === mergeKey(right[index]!));\n}\n\nfunction mergeKey(region: MergedCellRegion): string {\n return `${region.rowStart}:${region.rowEnd}:${region.columnStart}:${region.columnEnd}`;\n}\n\nfunction mergeContaining(\n regions: readonly MergedCellRegion[],\n cell: CellPosition,\n): MergedCellRegion | undefined {\n return regions.find((region) => (\n cell.rowIndex >= region.rowStart\n && cell.rowIndex < region.rowEnd\n && cell.columnIndex >= region.columnStart\n && cell.columnIndex < region.columnEnd\n ));\n}\n\nfunction createMergedSelection(\n anchor: CellPosition,\n focus: CellPosition,\n regions: readonly MergedCellRegion[],\n): Readonly<TableSelection> {\n const selection = createSelection(anchor, focus);\n let range = selection.range;\n for (;;) {\n let expanded = range;\n for (const region of regions) {\n if (!rangesIntersect(expanded, region)) continue;\n expanded = Object.freeze({\n rowStart: Math.min(expanded.rowStart, region.rowStart),\n rowEnd: Math.max(expanded.rowEnd, region.rowEnd),\n columnStart: Math.min(expanded.columnStart, region.columnStart),\n columnEnd: Math.max(expanded.columnEnd, region.columnEnd),\n });\n }\n if (sameGridRange(range, expanded)) break;\n range = expanded;\n }\n return Object.freeze({ ...selection, range });\n}\n\nfunction rangesIntersect(left: GridRange, right: MergedCellRegion): boolean {\n return left.rowStart < right.rowEnd\n && left.rowEnd > right.rowStart\n && left.columnStart < right.columnEnd\n && left.columnEnd > right.columnStart;\n}\n\nfunction navigationOrigin(\n current: CellPosition,\n command: NavigationCommand,\n regions: readonly MergedCellRegion[],\n): Readonly<CellPosition> {\n const merge = mergeContaining(regions, current);\n if (merge === undefined) return current;\n if (command === \"right\") {\n return Object.freeze({ rowIndex: current.rowIndex, columnIndex: merge.columnEnd - 1 });\n }\n if (command === \"down\" || command === \"page-down\") {\n return Object.freeze({ rowIndex: merge.rowEnd - 1, columnIndex: current.columnIndex });\n }\n return current;\n}\n\nfunction navigationDirections(command: NavigationCommand): readonly [-1 | 1, -1 | 1] {\n switch (command) {\n case \"left\":\n case \"row-start\":\n return [1, -1];\n case \"up\":\n case \"page-up\":\n return [-1, 1];\n case \"table-start\":\n return [-1, -1];\n default:\n return [1, 1];\n }\n}\n\nfunction nextVisibleColumn(\n widths: readonly number[],\n from: number,\n direction: -1 | 1,\n): number | null {\n for (\n let index = Math.min(widths.length - 1, Math.max(0, from));\n index >= 0 && index < widths.length;\n index += direction\n ) {\n if ((widths[index] ?? 0) > 0) return index;\n }\n return null;\n}\n\nfunction normalizeOptions(options: TableControllerOptions): NormalizedOptions {\n const minColumnWidth = positiveFinite(\n options.minColumnWidth ?? DEFAULT_MIN_COLUMN_WIDTH,\n \"minColumnWidth\",\n );\n const maxColumnWidth = positiveFinite(\n options.maxColumnWidth ?? DEFAULT_MAX_COLUMN_WIDTH,\n \"maxColumnWidth\",\n );\n if (maxColumnWidth < minColumnWidth) {\n throw invalidArgument(\"maxColumnWidth must be greater than or equal to minColumnWidth\");\n }\n const maxWindowCells = positiveInteger(\n options.maxWindowCells ?? DEFAULT_MAX_WINDOW_CELLS,\n \"maxWindowCells\",\n );\n if (maxWindowCells > MAX_RANGE_CELLS) {\n throw invalidArgument(`maxWindowCells cannot exceed ${MAX_RANGE_CELLS}`);\n }\n return Object.freeze({\n ...(options.rowHeight === undefined ? {} : { rowHeight: options.rowHeight }),\n ...(options.headerHeight === undefined ? {} : { headerHeight: options.headerHeight }),\n ...(options.rowHeaderWidth === undefined ? {} : { rowHeaderWidth: options.rowHeaderWidth }),\n ...(options.scrollPixelLimit === undefined ? {} : { scrollPixelLimit: options.scrollPixelLimit }),\n ...(options.overscanRows === undefined ? {} : { overscanRows: options.overscanRows }),\n ...(options.overscanColumns === undefined ? {} : { overscanColumns: options.overscanColumns }),\n columnWidth: positiveFinite(options.columnWidth ?? DEFAULT_COLUMN_WIDTH, \"columnWidth\"),\n minColumnWidth,\n maxColumnWidth,\n columnWidths: Object.freeze({ ...(options.columnWidths ?? {}) }),\n maxWindowCells,\n });\n}\n\nfunction initialColumnWidths(\n metadata: TableHandle[\"metadata\"],\n options: NormalizedOptions,\n): number[] {\n return metadata.schema.columns.map((column) => clampWidth(\n options.columnWidths[column.id] ?? options.columnWidth,\n options,\n ));\n}\n\nfunction reconcileColumnWidths(\n previousMetadata: TableHandle[\"metadata\"],\n nextMetadata: TableHandle[\"metadata\"],\n previousWidths: readonly number[],\n options: NormalizedOptions,\n): number[] {\n const byId = new Map(previousMetadata.schema.columns.map(\n (column, index) => [column.id, previousWidths[index]!] as const,\n ));\n return nextMetadata.schema.columns.map((column) => clampWidth(\n byId.get(column.id) ?? options.columnWidths[column.id] ?? options.columnWidth,\n options,\n ));\n}\n\nfunction normalizeViewport(viewport: ViewportUpdate): Required<ViewportUpdate> {\n return Object.freeze({\n width: nonNegativeFinite(viewport.width, \"viewport.width\"),\n height: nonNegativeFinite(viewport.height, \"viewport.height\"),\n scrollLeft: nonNegativeFinite(viewport.scrollLeft, \"viewport.scrollLeft\"),\n scrollTop: nonNegativeFinite(viewport.scrollTop, \"viewport.scrollTop\"),\n devicePixelRatio: positiveFinite(viewport.devicePixelRatio ?? 1, \"viewport.devicePixelRatio\"),\n });\n}\n\nfunction layoutRanges(\n layout: TableViewSnapshot[\"layout\"],\n maxCells: number,\n mergedCells: readonly MergedCellRegion[] = [],\n): Readonly<{\n visible: readonly Readonly<GridRange>[];\n overscan: readonly Readonly<GridRange>[];\n}> {\n const visible = windowRectangles(\n layout.rows.visible,\n layout.columns.visible,\n layout.frozenRowRange,\n layout.frozenColumnRange,\n );\n const anchors = mergeAnchorRanges(mergedCells, visible);\n const visibleWithAnchors = Object.freeze([\n ...visible,\n ...anchors.filter((anchor) => !visible.some((range) => rangeContainsRange(range, anchor))),\n ]);\n const visibleCellCount = visibleWithAnchors.reduce(\n (total, range) => total + rangeCellCount(range),\n 0,\n );\n if (visibleCellCount > maxCells) {\n throw new TabularkError(\n \"RESOURCE_LIMIT\",\n `The viewport contains ${visibleCellCount} cells; the window limit is ${maxCells}`,\n {\n details: {\n resource: \"viewport-cells\",\n required: visibleCellCount,\n available: maxCells,\n visibleCellCount,\n maxCells,\n },\n },\n );\n }\n const fullOverscan = windowRectangles(\n layout.rows.overscan,\n layout.columns.overscan,\n layout.frozenRowRange,\n layout.frozenColumnRange,\n );\n const overscanCellCount = fullOverscan.reduce(\n (total, range) => total + rangeCellCount(range),\n 0,\n );\n const overscanWithAnchors = Object.freeze([\n ...fullOverscan,\n ...anchors.filter((anchor) => !fullOverscan.some(\n (range) => rangeContainsRange(range, anchor),\n )),\n ]);\n return Object.freeze({\n visible: visibleWithAnchors,\n overscan: overscanCellCount + anchors.length <= maxCells\n ? overscanWithAnchors\n : visibleWithAnchors,\n });\n}\n\nfunction mergeAnchorRanges(\n mergedCells: readonly MergedCellRegion[],\n visible: readonly Readonly<GridRange>[],\n): readonly Readonly<GridRange>[] {\n const anchors = new Map<string, Readonly<GridRange>>();\n for (const region of mergedCells) {\n if (!visible.some((range) => rangesIntersect(range, region))) continue;\n const range = Object.freeze({\n rowStart: region.rowStart,\n rowEnd: region.rowStart + 1,\n columnStart: region.columnStart,\n columnEnd: region.columnStart + 1,\n });\n anchors.set(`${range.rowStart}:${range.columnStart}`, range);\n }\n return Object.freeze([...anchors.values()]);\n}\n\nfunction windowRectangles(\n rows: Readonly<{ start: number; end: number }>,\n columns: Readonly<{ start: number; end: number }>,\n frozenRows: Readonly<{ start: number; end: number }>,\n frozenColumns: Readonly<{ start: number; end: number }>,\n): readonly Readonly<GridRange>[] {\n const rowBands = mergeIndexBands(rows, frozenRows);\n const columnBands = mergeIndexBands(columns, frozenColumns);\n const rectangles: GridRange[] = [];\n for (const row of rowBands) {\n for (const column of columnBands) {\n rectangles.push(Object.freeze({\n rowStart: row.start,\n rowEnd: row.end,\n columnStart: column.start,\n columnEnd: column.end,\n }));\n }\n }\n return Object.freeze(rectangles);\n}\n\nfunction mergeIndexBands(\n primary: Readonly<{ start: number; end: number }>,\n frozen: Readonly<{ start: number; end: number }>,\n): readonly Readonly<{ start: number; end: number }>[] {\n const bands = [primary, frozen]\n .filter((range) => range.start < range.end)\n .sort((left, right) => left.start - right.start);\n if (bands.length <= 1) return Object.freeze(bands.map((range) => Object.freeze({ ...range })));\n const [first, second] = bands as [typeof primary, typeof primary];\n return first.end >= second.start\n ? Object.freeze([Object.freeze({ start: first.start, end: Math.max(first.end, second.end) })])\n : Object.freeze(bands.map((range) => Object.freeze({ ...range })));\n}\n\nfunction gridRangeToRequest(range: GridRange): Readonly<RangeRequest> {\n return Object.freeze({\n rowStart: range.rowStart,\n rowCount: range.rowEnd - range.rowStart,\n columnStart: range.columnStart,\n columnCount: range.columnEnd - range.columnStart,\n });\n}\n\nfunction batchGridRange(batch: TableBatch): Readonly<GridRange> {\n return Object.freeze({\n rowStart: batch.range.rowStart,\n rowEnd: batch.range.rowStart + batch.range.rowCount,\n columnStart: batch.range.columnStart,\n columnEnd: batch.range.columnStart + batch.range.columnCount,\n });\n}\n\nfunction batchRows(batch: TableBatch): readonly (readonly (string | null)[])[] {\n return Object.freeze(batch.toDisplayRows({\n maxCells: Math.max(1, batch.range.rowCount * batch.range.columnCount),\n }).map((row) => Object.freeze(row)));\n}\n\nfunction rowsToTsv(rows: readonly (readonly (string | null)[])[]): string {\n return rows.map((row) => row.map(tsvField).join(\"\\t\")).join(\"\\n\");\n}\n\nfunction tsvField(value: string | null): string {\n if (value === null) {\n return \"\";\n }\n return /[\\t\\r\\n\"]/.test(value) ? `\"${value.replaceAll('\"', '\"\"')}\"` : value;\n}\n\nfunction revealOffset(\n current: number,\n viewportSize: number,\n itemStart: number,\n itemEnd: number,\n maximum: number,\n): number {\n if (viewportSize <= 0 || itemStart < current) {\n return Math.min(maximum, Math.max(0, itemStart));\n }\n if (itemEnd > current + viewportSize) {\n return Math.min(maximum, Math.max(0, itemEnd - viewportSize));\n }\n return current;\n}\n\nfunction rangeContains(range: GridRange, rowIndex: number, columnIndex: number): boolean {\n return rowIndex >= range.rowStart && rowIndex < range.rowEnd\n && columnIndex >= range.columnStart && columnIndex < range.columnEnd;\n}\n\nfunction rangeContainsRange(container: GridRange, candidate: GridRange): boolean {\n return candidate.rowStart >= container.rowStart\n && candidate.rowEnd <= container.rowEnd\n && candidate.columnStart >= container.columnStart\n && candidate.columnEnd <= container.columnEnd;\n}\n\nfunction rangeCellCount(range: GridRange): number {\n return (range.rowEnd - range.rowStart) * (range.columnEnd - range.columnStart);\n}\n\nfunction sameGridRange(left: GridRange, right: GridRange | null): boolean {\n return right !== null\n && left.rowStart === right.rowStart\n && left.rowEnd === right.rowEnd\n && left.columnStart === right.columnStart\n && left.columnEnd === right.columnEnd;\n}\n\nfunction sameViewport(left: Required<ViewportUpdate>, right: Required<ViewportUpdate>): boolean {\n return left.width === right.width\n && left.height === right.height\n && left.scrollLeft === right.scrollLeft\n && left.scrollTop === right.scrollTop\n && left.devicePixelRatio === right.devicePixelRatio;\n}\n\nfunction isValidCell(\n rowIndex: number,\n columnIndex: number,\n rowCount: number,\n columnCount: number,\n): boolean {\n return Number.isSafeInteger(rowIndex) && rowIndex >= 0 && rowIndex < rowCount\n && Number.isSafeInteger(columnIndex) && columnIndex >= 0 && columnIndex < columnCount;\n}\n\nfunction assertColumnIndex(columnIndex: number, columnCount: number): void {\n if (!Number.isSafeInteger(columnIndex) || columnIndex < 0 || columnIndex >= columnCount) {\n throw invalidArgument(`columnIndex must be between 0 and ${Math.max(0, columnCount - 1)}`);\n }\n}\n\nfunction assertWindowCellLimit(request: RangeRequest, limit: number, label: string): void {\n const cells = request.rowCount * request.columnCount;\n if (!Number.isSafeInteger(cells) || cells > limit) {\n throw new TabularkError(\n \"RESOURCE_LIMIT\",\n `The ${label} contains ${cells} cells; the limit is ${limit}`,\n {\n details: {\n resource: \"view-window-cells\",\n required: cells,\n available: limit,\n cells,\n limit,\n },\n },\n );\n }\n}\n\nfunction clampWidth(width: number, options: NormalizedOptions): number {\n if (!Number.isFinite(width)) {\n throw invalidArgument(\"column width must be a finite number\");\n }\n return Math.min(options.maxColumnWidth, Math.max(options.minColumnWidth, width));\n}\n\nfunction positiveFinite(value: number, name: string): number {\n if (!Number.isFinite(value) || value <= 0) {\n throw invalidArgument(`${name} must be a positive finite number`);\n }\n return value;\n}\n\nfunction nonNegativeFinite(value: number, name: string): number {\n if (!Number.isFinite(value) || value < 0) {\n throw invalidArgument(`${name} must be a non-negative finite number`);\n }\n return value;\n}\n\nfunction positiveInteger(value: number, name: string): number {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw invalidArgument(`${name} must be a positive safe integer`);\n }\n return value;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["width", "columnIndex", "clampInteger", "positiveFinite", "nonNegativeFinite", "range"]
|
|
7
|
+
}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { type ByteRange, type RangeSource } from "./range-source.js";
|
|
2
|
+
/** The phase in which dynamic request headers are evaluated. */
|
|
3
|
+
export type HttpHeaderPhase = "probe" | "read";
|
|
4
|
+
export interface HttpHeaderContext {
|
|
5
|
+
readonly phase: HttpHeaderPhase;
|
|
6
|
+
readonly range?: ByteRange;
|
|
7
|
+
readonly signal: AbortSignal;
|
|
8
|
+
}
|
|
9
|
+
/** Static headers or a per-request (for example, rotating-auth) provider. */
|
|
10
|
+
export type HttpHeaders = HeadersInit | ((context: HttpHeaderContext) => HeadersInit | Promise<HeadersInit>);
|
|
11
|
+
export interface BoundedDownloadFallback {
|
|
12
|
+
readonly mode: "bounded-download";
|
|
13
|
+
/** Maximum full-response bytes the caller explicitly permits. */
|
|
14
|
+
readonly maxBytes: number;
|
|
15
|
+
}
|
|
16
|
+
export type HttpValidationStrength = "strong" | "weak" | "etag" | "last-modified";
|
|
17
|
+
/** Optional retry spelling accepted by the HTTP helper. */
|
|
18
|
+
export interface HttpRetryOptions {
|
|
19
|
+
/** Total attempts, including the first request. */
|
|
20
|
+
readonly maxAttempts?: number;
|
|
21
|
+
/** Alias for maxAttempts. */
|
|
22
|
+
readonly attempts?: number;
|
|
23
|
+
/** Attempts after the first request. */
|
|
24
|
+
readonly maxRetries?: number;
|
|
25
|
+
readonly baseDelayMs?: number;
|
|
26
|
+
readonly maxDelayMs?: number;
|
|
27
|
+
}
|
|
28
|
+
/** Options for {@link httpRangeSource}. */
|
|
29
|
+
export interface HttpRangeSourceOptions {
|
|
30
|
+
/** Static headers or a function evaluated for every probe/read attempt. */
|
|
31
|
+
readonly headers?: HttpHeaders;
|
|
32
|
+
/** Alias for callers that prefer an explicit dynamic-header name. */
|
|
33
|
+
readonly getHeaders?: (context: HttpHeaderContext) => HeadersInit | Promise<HeadersInit>;
|
|
34
|
+
readonly credentials?: RequestCredentials;
|
|
35
|
+
/** Injected fetch implementation, useful for SSR/tests. */
|
|
36
|
+
readonly fetch?: HttpFetch;
|
|
37
|
+
/** Defaults to strong ETag, with Last-Modified + length as a weak fallback. */
|
|
38
|
+
readonly validation?: HttpValidationStrength;
|
|
39
|
+
/** Compatibility alias for validation. */
|
|
40
|
+
readonly validator?: HttpValidationStrength;
|
|
41
|
+
/** Maximum simultaneous range reads (1–4, defaults to 1). */
|
|
42
|
+
readonly maxConcurrency?: number;
|
|
43
|
+
/** Number of retries after the first attempt (defaults to 2; 3 total attempts). */
|
|
44
|
+
readonly retries?: number;
|
|
45
|
+
readonly maxRetries?: number;
|
|
46
|
+
readonly retry?: HttpRetryOptions;
|
|
47
|
+
/** Explicit total-attempts spelling; takes precedence over retries. */
|
|
48
|
+
readonly maxAttempts?: number;
|
|
49
|
+
/** Explicitly permits a small full response when range requests are unavailable. */
|
|
50
|
+
readonly fallback?: BoundedDownloadFallback;
|
|
51
|
+
/** Optional logical display name. It is never sent in diagnostics. */
|
|
52
|
+
readonly name?: string;
|
|
53
|
+
/** Alias for name. */
|
|
54
|
+
readonly sourceName?: string;
|
|
55
|
+
}
|
|
56
|
+
/** Fetch-compatible function accepted by the HTTP adapter. */
|
|
57
|
+
export type HttpFetch = (input: RequestInfo | URL, init?: RequestInit) => Response | Promise<Response>;
|
|
58
|
+
/**
|
|
59
|
+
* Creates a stable remote byte-range source.
|
|
60
|
+
*
|
|
61
|
+
* No request is made until `open()` is called. Each open performs an
|
|
62
|
+
* independent capability probe and returns an independent reader, allowing a
|
|
63
|
+
* source to be reopened after a dataset is closed.
|
|
64
|
+
*/
|
|
65
|
+
export declare function httpRangeSource(url: string | URL, options?: HttpRangeSourceOptions): RangeSource;
|