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
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Tabulark are documented here. The project follows
|
|
4
|
+
[Semantic Versioning](https://semver.org/).
|
|
5
|
+
|
|
6
|
+
## 0.2.1
|
|
7
|
+
|
|
8
|
+
- Read partial viewports from oversized Parquet row groups page by page instead
|
|
9
|
+
of staging every projected column chunk. Lazy reads enforce cumulative page
|
|
10
|
+
decompression, bounded page tracking and header parsing, compressed-cache
|
|
11
|
+
peak, and decoder-restart limits before returning data to parquet-rs.
|
|
12
|
+
- Bound nested Arrow display previews without changing their native values;
|
|
13
|
+
oversized list, struct, map, and union text ends with an explicit
|
|
14
|
+
`... [truncated]` marker.
|
|
15
|
+
- Add a separately built, experimental document-preview source package with a
|
|
16
|
+
Worker-isolated PDFium page pipeline, bounded RGBA page rendering, and an
|
|
17
|
+
accessible framework-free paged view. It is not part of the stable root npm
|
|
18
|
+
exports or official tabular-adapter manifest.
|
|
19
|
+
|
|
20
|
+
## 0.2.0
|
|
21
|
+
|
|
22
|
+
- Add bounded structured diagnostics and independent diagnostic subscriptions.
|
|
23
|
+
- Add logical dataset/table capability snapshots and opt-in privacy-safe
|
|
24
|
+
performance samples.
|
|
25
|
+
- Add Canvas `colorScheme` support with dynamic dark mode and forced-colors
|
|
26
|
+
precedence.
|
|
27
|
+
- Add opt-in `sourceMode: "large"` for local Blob/File inputs through exactly
|
|
28
|
+
`2^31` bytes across CSV, Arrow File, Parquet, XLSX, and XLS; ArrayBuffer and
|
|
29
|
+
automatic-mode limits remain unchanged.
|
|
30
|
+
- Add the stable `RangeSource` capability to every official format. Readers
|
|
31
|
+
validate exact lengths and snapshots, support independent reopen/close
|
|
32
|
+
lifecycles, and address at most `4,294,967,295` bytes (`2^32 - 1`).
|
|
33
|
+
- Add `tabulark/http` with a `GET Range: bytes=0-0` capability probe, strict
|
|
34
|
+
`Content-Range` and validator checks, bounded transient retries, dynamic
|
|
35
|
+
headers/credentials, and an explicit bounded-download fallback. Network and
|
|
36
|
+
authentication remain on the main thread; no URL, headers, validator, or
|
|
37
|
+
snapshot ID is exposed in Worker messages, errors, or performance samples.
|
|
38
|
+
- Add source-range request coalescing, dataset singleflight, a byte-budgeted
|
|
39
|
+
range LRU, four-way maximum provider concurrency, exact reader cleanup, and
|
|
40
|
+
cross-thread memory slices (75% Worker, 12.5% source staging, 12.5%
|
|
41
|
+
retained batches/fallback).
|
|
42
|
+
- Add `SOURCE_UNAVAILABLE`, `SOURCE_CHANGED`, and `RANGE_UNSUPPORTED` source
|
|
43
|
+
errors. Extend `PerformanceSample` with `sourceReads` and
|
|
44
|
+
`sourceCacheHitBytes`; `cacheHit` remains the logical batch-cache metric.
|
|
45
|
+
- Move every official adapter to private Worker protocol v4 and adapter ABI v3
|
|
46
|
+
resumable operations with checked revisions, bounded multi-range actions,
|
|
47
|
+
cooperative no-I/O yields, and one-transfer batch output.
|
|
48
|
+
- Make the main thread the sole decoded-batch cache owner, with immutable
|
|
49
|
+
backings, logical-table keys, singleflight misses, and independent caller
|
|
50
|
+
cancellation. Remove the Worker decoded LRU.
|
|
51
|
+
- Add Rust/WASM resource ledgers and native cache admission/reclamation
|
|
52
|
+
evidence, including 100-cycle lifecycle and WebAssembly-memory high-water
|
|
53
|
+
gates.
|
|
54
|
+
- Add incremental Arrow File/Stream indexing, coalesced Parquet projection
|
|
55
|
+
reads, and Rust range-backed ZIP64/CFB Excel container indexing. Excel
|
|
56
|
+
compacts only required workbook content into its bounded compatibility
|
|
57
|
+
parser.
|
|
58
|
+
- Add release-blocking Chromium, Firefox, and WebKit functional projects.
|
|
59
|
+
Chromium additionally owns pixel, performance, real-clipboard, and exact
|
|
60
|
+
2 GiB evidence.
|
|
61
|
+
- Add paired baseline performance gates, shipped-JavaScript shrinkage gates,
|
|
62
|
+
and a native five-container exact-size generator/workflow.
|
|
63
|
+
- Add HTTP contract, virtual/sparse 4 GiB−1, cancellation/lifecycle,
|
|
64
|
+
concurrency, cache, CORS, retry, validator-change, and explicit-fallback
|
|
65
|
+
release evidence in Chromium, Firefox, and WebKit. Keep a separate measured
|
|
66
|
+
raw/Brotli size budget for the new `/http` entry point.
|
|
67
|
+
- Remove the private TypeScript large-XLSX parser and its shipped artifact.
|
|
68
|
+
|
|
69
|
+
Version 0.1.1 was never tagged or published; its compatible work is included
|
|
70
|
+
in 0.2.0. The immutable `v0.1.0` tag is unchanged.
|
|
71
|
+
|
|
72
|
+
## 0.1.0
|
|
73
|
+
|
|
74
|
+
- Establish the stable browser-facing API and the official local-format adapter
|
|
75
|
+
host.
|
|
76
|
+
- Add local Apache Parquet and Excel (BIFF8/XLSX) preview adapters.
|
|
77
|
+
- Add spreadsheet presentation metadata for the Canvas view.
|
|
78
|
+
|
|
79
|
+
## 0.0.4
|
|
80
|
+
|
|
81
|
+
Published before the 0.1.0 release train.
|
package/README.md
CHANGED
|
@@ -1,157 +1,345 @@
|
|
|
1
1
|
# Tabulark
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
>
|
|
10
|
-
>
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
3
|
+
> **Status: 0.2.1.** The immutable `v0.1.0` tag and its registry/Pages
|
|
4
|
+
> evidence remain recorded in
|
|
5
|
+
> [the release evidence](docs/release-0.1.0-evidence.md); that tag is never
|
|
6
|
+
> moved or reused. Version 0.2 adds bounded local and remote range sources,
|
|
7
|
+
> structured diagnostics and capabilities, performance observation, and
|
|
8
|
+
> synchronized Canvas themes without changing the documented 0.1.0 calling
|
|
9
|
+
> patterns. Local `sourceMode: "large"` remains capped at 2 GiB; a validated
|
|
10
|
+
> `RangeSource` may address at most `4,294,967,295` bytes (`2^32 - 1`).
|
|
11
|
+
|
|
12
|
+
Tabulark is a WebAssembly-first browser primitive for previewing tabular data
|
|
13
|
+
without uploading it. Local bytes stay local; an explicit `RangeSource` can
|
|
14
|
+
read a remote object through a main-thread broker without giving its URL,
|
|
15
|
+
credentials, or headers to the Worker. A module Worker owns parsing, bounded
|
|
16
|
+
byte access, adapter state, cancellation, and cleanup. A Canvas viewport
|
|
17
|
+
renders visible cells while a bounded semantic grid supplies keyboard and
|
|
18
|
+
screen-reader access.
|
|
19
|
+
|
|
20
|
+
[Try the playground](https://ronbb.github.io/tabulark/) · [Architecture](docs/architecture.md) · [API stability](docs/api-stability.md) · [Testing](docs/testing.md)
|
|
21
|
+
|
|
22
|
+
## Supported local formats
|
|
23
|
+
|
|
24
|
+
The 0.2.1 source tree contains four official adapters. Each adapter
|
|
25
|
+
is a separate, lazily loaded WebAssembly artifact; creating an engine loads no
|
|
26
|
+
WASM and opening one format does not fetch unused artifacts.
|
|
27
|
+
|
|
28
|
+
| Format | Official ID | Stable entry point | 0.2 contract |
|
|
29
|
+
| --- | --- | --- | --- |
|
|
30
|
+
| CSV/TSV | `tabulark:delimited` | `tabulark` | Explicit delimiter, header, and strict/lenient modes |
|
|
31
|
+
| Arrow IPC | `tabulark:arrow-ipc` | `tabulark/arrow` | File/Stream; none, LZ4, and Zstd IPC compression |
|
|
32
|
+
| Parquet | `tabulark:parquet` | `tabulark/parquet` | Range-driven row-group/column projection and the documented codec set |
|
|
33
|
+
| Excel | `tabulark:excel` | `tabulark/excel` | Excel 97–2003 BIFF8 XLS and OOXML XLSX, including static presentation |
|
|
34
|
+
|
|
35
|
+
Arbitrary adapter/module URLs, public third-party adapters, persistent caches,
|
|
36
|
+
ReadableStream sources, formula calculation, editing, and document-level Excel
|
|
37
|
+
round-tripping are outside 0.2. Remote input is available only through the
|
|
38
|
+
explicit `RangeSource` contract (or the opt-in `tabulark/http` helper).
|
|
39
|
+
|
|
40
|
+
## Install and build
|
|
41
|
+
|
|
42
|
+
The npm package has no production JavaScript dependencies. Its desktop release
|
|
43
|
+
gate covers Chromium, Firefox, and WebKit, and it requires Node 20 or newer to
|
|
44
|
+
build from source. Rust 1.85 is the minimum supported Rust version.
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
npm ci
|
|
48
|
+
npm run build
|
|
49
|
+
npm run check
|
|
50
|
+
npm run test:browser
|
|
51
|
+
```
|
|
19
52
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
53
|
+
`npm run build` creates six public JavaScript entry points, a generic Worker,
|
|
54
|
+
and independent Delimited, Arrow, Parquet, and Excel WASM artifacts under
|
|
55
|
+
`dist/wasm/`.
|
|
56
|
+
|
|
57
|
+
## Stable JavaScript API
|
|
58
|
+
|
|
59
|
+
Register only the adapters an engine may use. The allow-list is immutable for
|
|
60
|
+
that engine's lifetime. Local inputs are `File`, `Blob`, and `ArrayBuffer`; an
|
|
61
|
+
explicit `RangeSource` is the bounded remote (or application-owned) source
|
|
62
|
+
capability.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { createEngine, delimitedAdapter } from "tabulark";
|
|
66
|
+
import { arrowIpcAdapter } from "tabulark/arrow";
|
|
67
|
+
import { parquetAdapter } from "tabulark/parquet";
|
|
68
|
+
import { excelAdapter } from "tabulark/excel";
|
|
69
|
+
import { httpRangeSource } from "tabulark/http";
|
|
70
|
+
|
|
71
|
+
const engine = await createEngine({
|
|
72
|
+
adapters: [delimitedAdapter, arrowIpcAdapter, parquetAdapter, excelAdapter],
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
const csv = await engine.open(csvFile, {
|
|
76
|
+
adapter: delimitedAdapter,
|
|
77
|
+
sourceMode: "auto", // use "large" for a local File/Blob up to 2 GiB
|
|
78
|
+
adapterOptions: {
|
|
79
|
+
dialect: "csv",
|
|
80
|
+
header: "first-row",
|
|
81
|
+
mode: "lenient",
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const parquet = await engine.open(parquetFile, {
|
|
86
|
+
adapter: parquetAdapter,
|
|
87
|
+
adapterOptions: { sourceName: parquetFile.name },
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const workbook = await engine.open(excelFile, {
|
|
91
|
+
adapter: excelAdapter,
|
|
92
|
+
adapterOptions: { format: "auto", sourceName: excelFile.name },
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const remote = httpRangeSource("https://data.example.test/table.parquet", {
|
|
96
|
+
credentials: "include",
|
|
97
|
+
validation: "strong", // ETag, or Last-Modified + length when permitted
|
|
98
|
+
maxConcurrency: 2,
|
|
99
|
+
});
|
|
100
|
+
const remoteTable = await engine.open(remote, {
|
|
101
|
+
adapter: parquetAdapter,
|
|
102
|
+
});
|
|
103
|
+
```
|
|
23
104
|
|
|
24
|
-
|
|
105
|
+
In the stable API, adapter selection is explicit. Excel's `format: "auto"` and Arrow's
|
|
106
|
+
`container: "auto"` inspect source bytes; filename extensions never select or
|
|
107
|
+
authenticate a format.
|
|
108
|
+
|
|
109
|
+
The bundled playground is a convenience layer: it uses the local file name,
|
|
110
|
+
MIME type, and (when needed) a bounded signature read to choose the explicit
|
|
111
|
+
adapter call for you. Applications using the stable API should continue to
|
|
112
|
+
select and register an adapter themselves.
|
|
113
|
+
|
|
114
|
+
`ArrayBuffer` ownership is retained by default. Set `transferInput: true` only
|
|
115
|
+
when intentionally detaching an `ArrayBuffer`; using it with a `Blob` or
|
|
116
|
+
`File` returns `INVALID_ARGUMENT`.
|
|
117
|
+
|
|
118
|
+
`sourceMode: "auto"` keeps the conservative source policy. The opt-in
|
|
119
|
+
`sourceMode: "large"` path accepts only a local `File`/`Blob` no larger than
|
|
120
|
+
exactly `2,147,483,648` bytes (`2^31`, 2 GiB); it does not raise the existing
|
|
121
|
+
`ArrayBuffer` staging limit or allocate a work set proportional to the file. A
|
|
122
|
+
larger source fails before an open request is sent to the Worker, with
|
|
123
|
+
`RESOURCE_LIMIT` details containing `resource`, `requiredBytes`, and
|
|
124
|
+
`availableBytes`.
|
|
125
|
+
|
|
126
|
+
`RangeSource` readers report an exact size and snapshot validator and return
|
|
127
|
+
exactly the requested bytes. `TabularkEngine.open()` creates an independent
|
|
128
|
+
reader for each open and closes it exactly once on failure, cancellation, or
|
|
129
|
+
dataset/engine close. `sourceMode` and `transferInput` are rejected for a
|
|
130
|
+
`RangeSource`. The source ceiling is exactly `4,294,967,295` bytes; a 4 GiB
|
|
131
|
+
source is rejected before adapter startup. The Worker receives only an opaque
|
|
132
|
+
source handle, size, and bounded transferable byte buffers. Provider requests
|
|
133
|
+
are merged for overlap/adjacency, limited to four concurrent reads, and
|
|
134
|
+
covered by a dataset range-cache/singleflight layer.
|
|
135
|
+
|
|
136
|
+
The `tabulark/http` helper probes with `GET Range: bytes=0-0`, requires a
|
|
137
|
+
precise `Content-Range` and a trusted ETag (or an explicitly allowed weak
|
|
138
|
+
Last-Modified-plus-length validator), and revalidates every `206` response.
|
|
139
|
+
Retries are bounded and limited to transient network/status failures. A full
|
|
140
|
+
download is never implicit: `fallback: { mode: "bounded-download", maxBytes }`
|
|
141
|
+
must be supplied and must fit both that bound and the engine staging budget.
|
|
142
|
+
Error messages and performance samples omit URLs, query strings, headers,
|
|
143
|
+
validators, and snapshot identifiers.
|
|
144
|
+
|
|
145
|
+
The exact-boundary local-file release gate covers five real containers: CSV,
|
|
146
|
+
Arrow File, Parquet, XLSX, and XLS. Each fixture is exactly `2^31` bytes and
|
|
147
|
+
the test reads the final bounded window ending at byte `2^31 - 1`. Remote
|
|
148
|
+
RangeSource gates separately use a virtual/sparse source at
|
|
149
|
+
`4,294,967,295` bytes and exercise non-adjacent offsets above `2^31` without
|
|
150
|
+
allocating oversized browser fixtures. Overflow and 4 GiB rejection are
|
|
151
|
+
checked before adapter startup.
|
|
152
|
+
|
|
153
|
+
### Tables, logical batches, and presentation
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
const table = await workbook.openTable(workbook.tables[0].id);
|
|
157
|
+
const batch = await table.readRange({
|
|
158
|
+
rowStart: 0,
|
|
159
|
+
rowCount: 100,
|
|
160
|
+
columnStart: 0,
|
|
161
|
+
columnCount: table.metadata.schema.columns.length,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const nativeRows = batch.toRows();
|
|
165
|
+
const displayRows = batch.toDisplayRows();
|
|
166
|
+
const presentation = await table.getPresentation();
|
|
167
|
+
const visiblePresentation = await table.readPresentationRange(batch.range);
|
|
168
|
+
```
|
|
25
169
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
170
|
+
The stable `TableBatch` exposes logical data, its returned range, columns, and
|
|
171
|
+
logical accessors. WASM buffer regions, wire descriptors, protocol versions,
|
|
172
|
+
adapter ABI versions, and physical batch layout are private implementation
|
|
173
|
+
details.
|
|
174
|
+
|
|
175
|
+
`toRows()` preserves native values such as `bigint`, `Uint8Array`, decimals,
|
|
176
|
+
temporal values, lists, structs, maps, and unions. `toDisplayRows()` returns
|
|
177
|
+
only `(string | null)[][]` for rendering, accessibility, sizing, and copy.
|
|
178
|
+
|
|
179
|
+
Excel tables can return a `spreadsheet-v1` presentation. It includes sheet
|
|
180
|
+
visibility, frozen rows/columns, sparse row and column sizes/hidden state, a
|
|
181
|
+
deduplicated static style table, range-aligned style IDs, and intersecting
|
|
182
|
+
merged cells. Styles cover number formats, fonts, colors, fills, borders, and
|
|
183
|
+
alignment. The high-level Canvas view uses presentation automatically:
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
const view = createCanvasTableView({
|
|
187
|
+
container,
|
|
188
|
+
table,
|
|
189
|
+
presentation: "auto", // default; use "ignore" for logical data only
|
|
190
|
+
});
|
|
191
|
+
```
|
|
33
192
|
|
|
34
|
-
|
|
193
|
+
Forced-colors mode overrides workbook colors while retaining dimensions,
|
|
194
|
+
merges, alignment, and font emphasis.
|
|
195
|
+
|
|
196
|
+
Low-level painter, controller, layout, hit-testing, and selection primitives
|
|
197
|
+
live under `tabulark/experimental` and carry no compatibility promise.
|
|
198
|
+
|
|
199
|
+
## Format behavior
|
|
200
|
+
|
|
201
|
+
### Parquet
|
|
202
|
+
|
|
203
|
+
Each file exposes one table. The adapter reads the footer and metadata first,
|
|
204
|
+
then only row groups and top-level projected columns intersecting a request; it
|
|
205
|
+
does not stage the full file. Supported compression is uncompressed, Snappy,
|
|
206
|
+
Gzip, Brotli, LZ4, LZ4_RAW, and Zstd. INT96 becomes a timezone-free nanosecond
|
|
207
|
+
timestamp. LZO, encrypted Parquet, and experimental Variant/Geo types return
|
|
208
|
+
`UNSUPPORTED_FEATURE`.
|
|
209
|
+
|
|
210
|
+
All promised Parquet codecs in the official WebAssembly adapter use Rust
|
|
211
|
+
implementations. Arrow/Parquet 59.1.0 calls the narrow `zstd` 0.13 bulk API
|
|
212
|
+
directly, so the workspace supplies a Rust 1.85-compatible implementation of
|
|
213
|
+
that API backed by pinned `ruzstd` 0.8.1. The release gate proves the official
|
|
214
|
+
Arrow and Parquet WASM graphs contain neither `zstd-sys` nor `zstd-safe`.
|
|
215
|
+
|
|
216
|
+
Cargo removes workspace patches when it publishes a crate. Therefore the
|
|
217
|
+
experimental crates.io Rust features deliberately do not enable upstream's
|
|
218
|
+
Zstd feature; Zstd is part of the stable JavaScript/WASM format contract, not
|
|
219
|
+
the experimental Rust API contract. This prevents a crates.io consumer from
|
|
220
|
+
silently receiving a C-backed implementation.
|
|
221
|
+
|
|
222
|
+
### Excel
|
|
223
|
+
|
|
224
|
+
Each worksheet becomes a table in workbook order with an ID such as
|
|
225
|
+
`sheet-0`. Hidden and very-hidden worksheets remain addressable and preserve
|
|
226
|
+
visibility. Chart, dialog, and macro sheets are skipped with a warning.
|
|
227
|
+
|
|
228
|
+
Columns are named A, B, …; the first row is always data; empty cells are null.
|
|
229
|
+
Excel values are display strings (`typedValues=false`). Formula cells use only
|
|
230
|
+
their cached result—Tabulark never executes formulas—and missing cached values
|
|
231
|
+
become null with a warning. Merged cells use the top-left value as their anchor.
|
|
232
|
+
|
|
233
|
+
XLS support is deliberately limited to BIFF8. Earlier BIFF, XLSM, XLSB, ODS,
|
|
234
|
+
and encrypted workbooks return `UNSUPPORTED_FEATURE`. XLS and XLSX share the
|
|
235
|
+
same bounded static-presentation subset.
|
|
236
|
+
|
|
237
|
+
For large XLSX, Rust indexes ZIP/ZIP64 metadata and fetches the workbook,
|
|
238
|
+
relationships, shared resources, and selected worksheet ranges. For large XLS,
|
|
239
|
+
Rust indexes CFB/DIFAT/FAT/miniFAT/directory data and fetches the referenced
|
|
240
|
+
Workbook/Book stream ranges. In both cases it compacts only the needed content
|
|
241
|
+
into a bounded workbook for the existing Calamine compatibility parser. This
|
|
242
|
+
does not imply a custom XML/BIFF checkpoint engine or worksheet tile store.
|
|
243
|
+
|
|
244
|
+
## Memory, cache, and lifecycle
|
|
245
|
+
|
|
246
|
+
The main thread owns the only decoded-batch cache. It stores immutable backing
|
|
247
|
+
objects keyed by dataset, logical table, revision, schema version, and
|
|
248
|
+
normalized range; each API call receives a fresh logical facade. Concurrent
|
|
249
|
+
identical misses are singleflight operations. Cancelling one caller does not
|
|
250
|
+
cancel work shared by others, while cancelling every waiter sends one Worker
|
|
251
|
+
cancel. A table handle may close without discarding its logical-table backing;
|
|
252
|
+
dataset close or a revision/schema change evicts it.
|
|
253
|
+
|
|
254
|
+
The Worker coordinates the engine-wide quota across adapters. Inside each
|
|
255
|
+
Rust/WASM runtime, a checked ledger distinguishes persistent state, active
|
|
256
|
+
operations, ingress/output, reclaimable native cache, and caller-owned
|
|
257
|
+
telemetry. Admission clears soft native cache and retries once before returning
|
|
258
|
+
`RESOURCE_LIMIT`, whose details identify required and available capacity.
|
|
259
|
+
ZIP/CFB entries, decompression, worksheet dimensions, cells, styles, layout,
|
|
260
|
+
merged regions, Parquet pages, and decoded batches remain bounded.
|
|
261
|
+
|
|
262
|
+
Handles are nested and cleanup cascades downward:
|
|
35
263
|
|
|
36
264
|
```text
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
-> viewport query API
|
|
42
|
-
-> renderer
|
|
43
|
-
-> application UI
|
|
265
|
+
Engine
|
|
266
|
+
└─ DatasetSession
|
|
267
|
+
└─ TableHandle
|
|
268
|
+
└─ TableBatch
|
|
44
269
|
```
|
|
45
270
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
## Current scaffold
|
|
50
|
-
|
|
51
|
-
The repository currently contains:
|
|
52
|
-
|
|
53
|
-
- A minimal Rust crate with an experimental `TableShape` value type.
|
|
54
|
-
- A minimal ESM npm entry point with matching shape metadata.
|
|
55
|
-
- Version synchronization and package dry-run checks.
|
|
56
|
-
- GitHub Actions prepared for OIDC-based publication to crates.io and npm after
|
|
57
|
-
the initial registry bootstrap and Trusted Publisher configuration.
|
|
58
|
-
|
|
59
|
-
No parser, Worker runtime, WebAssembly bridge, cache, or renderer has been
|
|
60
|
-
implemented yet.
|
|
61
|
-
|
|
62
|
-
## Planned data sources
|
|
63
|
-
|
|
64
|
-
CSV and TSV are intended to be the first reference adapters. Longer-term
|
|
65
|
-
candidates include XLSX, XLS, Parquet, Apache Arrow, Feather, SQLite query
|
|
66
|
-
results, DuckDB query results, and third-party data sources.
|
|
67
|
-
|
|
68
|
-
A format should not be considered supported until a released adapter is backed
|
|
69
|
-
by compatibility tests.
|
|
271
|
+
Close operations are idempotent. Closing a dataset closes its tables; closing
|
|
272
|
+
an engine closes every dataset. Cancellation and close races settle once, and
|
|
273
|
+
reservations are released on success, failure, cancellation, and close.
|
|
70
274
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
- A VBA, macro, or arbitrary workbook-code runtime.
|
|
78
|
-
- A pixel-perfect implementation of every Office document feature.
|
|
79
|
-
- A pivot table, chart authoring, BI, or database product.
|
|
80
|
-
- A mandatory all-formats bundle or complete application framework.
|
|
81
|
-
|
|
82
|
-
Editing, analysis, and application-specific UI may be built on top of Tabulark,
|
|
83
|
-
but they are outside the core project's scope.
|
|
84
|
-
|
|
85
|
-
## Development
|
|
86
|
-
|
|
87
|
-
Requirements:
|
|
88
|
-
|
|
89
|
-
- Rust 1.85 or later.
|
|
90
|
-
- Node.js 20 or later.
|
|
91
|
-
- npm 10 or later.
|
|
275
|
+
```ts
|
|
276
|
+
view.destroy();
|
|
277
|
+
await table.close();
|
|
278
|
+
await workbook.close();
|
|
279
|
+
await engine.close();
|
|
280
|
+
```
|
|
92
281
|
|
|
93
|
-
|
|
282
|
+
## Verification
|
|
94
283
|
|
|
95
|
-
```
|
|
284
|
+
```sh
|
|
285
|
+
# Rust 1.85/stable, Clippy, all features, lifecycle, fixtures, fuzz seeds
|
|
96
286
|
cargo fmt --all --check
|
|
97
287
|
cargo clippy --workspace --all-targets --all-features -- -D warnings
|
|
98
|
-
cargo test --workspace --all-features
|
|
99
|
-
cargo package --allow-dirty --locked
|
|
100
|
-
npm ci
|
|
101
|
-
npm run check
|
|
102
|
-
```
|
|
288
|
+
cargo test --workspace --all-features --locked
|
|
103
289
|
|
|
104
|
-
|
|
105
|
-
|
|
290
|
+
# Stable exports/declarations, clean package consumers, and Pages assembly
|
|
291
|
+
npm run check
|
|
106
292
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
npm install tabulark
|
|
110
|
-
```
|
|
293
|
+
# Real module Worker/WASM, Canvas, ARIA, keyboard, copy, and forced-colors
|
|
294
|
+
npm run test:browser
|
|
111
295
|
|
|
112
|
-
|
|
296
|
+
# Independent core, Arrow, Parquet, Excel, npm, and Pages delivery budgets
|
|
297
|
+
npm run benchmark:size
|
|
113
298
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
├── src/ # Rust crate
|
|
117
|
-
├── js/ # Browser-facing ESM package entry point
|
|
118
|
-
├── test/ # JavaScript tests
|
|
119
|
-
├── scripts/ # Repository validation scripts
|
|
120
|
-
├── docs/ # Vision and release documentation
|
|
121
|
-
└── .github/workflows/ # CI and registry publication
|
|
299
|
+
# Parquet/XLS/XLSX cold-open, range-read, and Chromium memory evidence
|
|
300
|
+
npm run benchmark:formats
|
|
122
301
|
```
|
|
123
302
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
303
|
+
Chromium, Firefox, and WebKit are all release-blocking desktop functional gates.
|
|
304
|
+
Chromium additionally owns exact pixel snapshots, performance comparison, real
|
|
305
|
+
Clipboard API coverage, and the exact-2-GiB workflow. Firefox and WebKit cover
|
|
306
|
+
the four adapters, lifecycle, Blob ranges, themes, ARIA, input behavior, copy
|
|
307
|
+
through a deterministic clipboard seam, and Pages smoke. The Pages post-deploy
|
|
308
|
+
smoke opens CSV, Arrow IPC, Parquet, XLS, and XLSX and asserts that only used
|
|
309
|
+
adapter artifacts were requested.
|
|
128
310
|
|
|
129
|
-
|
|
130
|
-
- [ ] Define the parser and Worker protocol.
|
|
131
|
-
- [ ] Implement a reference CSV/TSV parser.
|
|
132
|
-
- [ ] Prototype viewport-driven Canvas rendering.
|
|
133
|
-
- [ ] Publish the first crates.io and npm packages.
|
|
134
|
-
- [ ] Stabilize extension APIs.
|
|
311
|
+
## Stability and release
|
|
135
312
|
|
|
136
|
-
|
|
313
|
+
The root, `/arrow`, `/parquet`, `/excel`, and `/http` entry points are stable
|
|
314
|
+
for 0.2.x. (`/experimental` remains explicitly unstable.)
|
|
315
|
+
Version 0.2 preserves the documented 0.1.0 calls and adds diagnostics,
|
|
316
|
+
capability queries, performance observation, `SourceMode`, and Canvas themes.
|
|
317
|
+
Rust APIs, Worker protocol v4, adapter ABI v3, wire DTOs, batch layout v1, and
|
|
318
|
+
`/experimental` remain experimental/private.
|
|
137
319
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
320
|
+
The `v0.1.0` tag is immutable and must never be moved or reused. npm and
|
|
321
|
+
crates.io publishing is serialized behind protected GitHub Environments with
|
|
322
|
+
required reviewer approval; recovery finalizes artifacts without republishing.
|
|
323
|
+
See
|
|
324
|
+
[docs/releasing.md](docs/releasing.md) for the immutable-release and patch
|
|
325
|
+
recovery policy.
|
|
141
326
|
|
|
142
|
-
##
|
|
327
|
+
## Repository map
|
|
143
328
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
329
|
+
```text
|
|
330
|
+
src/ shared Rust model, protocol, and native adapters
|
|
331
|
+
crates/tabulark-*-wasm/ four independently built WASM entry crates
|
|
332
|
+
js/ stable API, HTTP/range broker, private Worker host,
|
|
333
|
+
batches, and view
|
|
334
|
+
examples/csv-preview/ static six-format Playground
|
|
335
|
+
test/fixtures/ pinned format fixtures and provenance
|
|
336
|
+
test/browser/ three-browser behavior, Chromium visual/performance, and Pages smoke
|
|
337
|
+
test/performance/ performance and per-artifact delivery budgets
|
|
338
|
+
docs/ architecture, testing, stability, and release policy
|
|
339
|
+
```
|
|
149
340
|
|
|
150
341
|
## License
|
|
151
342
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
- MIT License ([LICENSE-MIT](LICENSE-MIT))
|
|
156
|
-
|
|
157
|
-
at your option.
|
|
343
|
+
Dual-licensed under [MIT](LICENSE-MIT) or [Apache-2.0](LICENSE-APACHE).
|
|
344
|
+
Shipped third-party material is listed in
|
|
345
|
+
[THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
The optional `tabulark/arrow` and `tabulark/parquet` WebAssembly artifacts use
|
|
4
|
+
Apache Arrow Rust 59.1.0. This includes the `arrow-*` crates used for logical
|
|
5
|
+
arrays and IPC plus the `parquet` crate. Apache Arrow Rust is distributed under
|
|
6
|
+
Apache-2.0, with some Arrow component crates additionally carrying MIT terms.
|
|
7
|
+
|
|
8
|
+
Arrow IPC and Parquet compression support uses `brotli` (BSD-3-Clause AND MIT),
|
|
9
|
+
`flate2` (MIT OR Apache-2.0), `lz4_flex` (MIT), `snap` (BSD-3-Clause), and
|
|
10
|
+
`ruzstd` 0.8.1 (MIT). A narrow in-tree compatibility crate exposes
|
|
11
|
+
the `zstd` 0.13 bulk API required by Arrow/Parquet while remaining Rust-only;
|
|
12
|
+
its hashing dependency is `twox-hash` (MIT). `zstd-sys` and `zstd-safe` are not
|
|
13
|
+
part of the official production WebAssembly dependency graph.
|
|
14
|
+
|
|
15
|
+
The optional `tabulark/excel` artifact uses `calamine` 0.35.0 (MIT) for
|
|
16
|
+
workbook values, formulas, and worksheet discovery. Its bounded container and
|
|
17
|
+
static-presentation readers also use `cfb` (MIT), `zip` (MIT), and `quick-xml`
|
|
18
|
+
(MIT).
|
|
19
|
+
|
|
20
|
+
The Arrow IPC integration fixture under `test/fixtures/arrow/v1` is copied
|
|
21
|
+
byte-for-byte from `apache/arrow-testing` at the revision recorded in its
|
|
22
|
+
`provenance.json`. The exact upstream Apache-2.0 license is stored next to the
|
|
23
|
+
fixture.
|
|
24
|
+
|
|
25
|
+
The independent Parquet fixture under `test/fixtures/parquet/v1` is copied
|
|
26
|
+
byte-for-byte from `apache/parquet-testing` at the pinned revision recorded in
|
|
27
|
+
its `provenance.json`. Its Apache-2.0 license is stored next to the fixture.
|
|
28
|
+
|
|
29
|
+
The independent XLSX fixture under `test/fixtures/excel/v1` is copied
|
|
30
|
+
byte-for-byte from the XlsxWriter comparison corpus at the pinned revision
|
|
31
|
+
recorded in its `provenance.json`. XlsxWriter is distributed under BSD-2-Clause;
|
|
32
|
+
the upstream license is stored next to the fixture.
|
|
33
|
+
|
|
34
|
+
The complete dependency versions and checksums are locked in `Cargo.lock`.
|
|
35
|
+
`cargo deny check advisories licenses` is a release gate, and the release workflow emits
|
|
36
|
+
an SPDX SBOM. Nothing in this notice changes the license terms supplied by an
|
|
37
|
+
upstream project.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type OfficialAdapterId } from "./official-adapter-manifest.js";
|
|
2
|
+
export type { OfficialAdapterId } from "./official-adapter-manifest.js";
|
|
3
|
+
export type DelimitedDialect = "csv" | "tsv";
|
|
4
|
+
export type HeaderMode = "first-row" | "none";
|
|
5
|
+
export type ParseMode = "lenient" | "strict";
|
|
6
|
+
/** Options understood by the built-in delimited adapter. */
|
|
7
|
+
export interface DelimitedAdapterOptions {
|
|
8
|
+
/** Defaults to `csv`. No filename-based selection is performed. */
|
|
9
|
+
readonly dialect?: DelimitedDialect;
|
|
10
|
+
readonly header?: HeaderMode;
|
|
11
|
+
readonly mode?: ParseMode;
|
|
12
|
+
/** One ASCII delimiter byte. Overrides the dialect default when supplied. */
|
|
13
|
+
readonly delimiter?: string;
|
|
14
|
+
/** Optional display name for the source. */
|
|
15
|
+
readonly sourceName?: string;
|
|
16
|
+
}
|
|
17
|
+
export type ArrowIpcContainer = "auto" | "file" | "stream";
|
|
18
|
+
/** Options understood by the built-in Arrow IPC adapter. */
|
|
19
|
+
export interface ArrowIpcAdapterOptions {
|
|
20
|
+
/** Defaults to `auto`; format detection belongs to the Arrow adapter. */
|
|
21
|
+
readonly container?: ArrowIpcContainer;
|
|
22
|
+
/** Optional display name for the source. */
|
|
23
|
+
readonly sourceName?: string;
|
|
24
|
+
}
|
|
25
|
+
/** Options understood by the built-in Parquet adapter. */
|
|
26
|
+
export interface ParquetAdapterOptions {
|
|
27
|
+
/** Optional display name for the source. */
|
|
28
|
+
readonly sourceName?: string;
|
|
29
|
+
}
|
|
30
|
+
export type ExcelFormat = "auto" | "xls" | "xlsx";
|
|
31
|
+
/** Options understood by the built-in Excel adapter. */
|
|
32
|
+
export interface ExcelAdapterOptions {
|
|
33
|
+
/** Defaults to `auto`; the adapter identifies the file from its signature. */
|
|
34
|
+
readonly format?: ExcelFormat;
|
|
35
|
+
/** Optional display name for the source. */
|
|
36
|
+
readonly sourceName?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A frozen descriptor for one built-in adapter.
|
|
40
|
+
*
|
|
41
|
+
* Descriptors select a named official artifact only. They are deliberately not
|
|
42
|
+
* factories and cannot carry a module URL or a third-party implementation.
|
|
43
|
+
*/
|
|
44
|
+
export interface AdapterDescriptor<Id extends OfficialAdapterId = OfficialAdapterId, Options = unknown> {
|
|
45
|
+
readonly id: Id;
|
|
46
|
+
readonly kind: "official";
|
|
47
|
+
/** Carries the option type without exposing a runtime extension point. */
|
|
48
|
+
readonly __options?: Options;
|
|
49
|
+
}
|
|
50
|
+
export interface AdapterRegistration {
|
|
51
|
+
readonly id: OfficialAdapterId;
|
|
52
|
+
}
|
|
53
|
+
/** The built-in RFC-style delimited text adapter. */
|
|
54
|
+
export declare const delimitedAdapter: AdapterDescriptor<"tabulark:delimited", DelimitedAdapterOptions>;
|
|
55
|
+
/** @internal Used by the stable `/arrow` entrypoint. */
|
|
56
|
+
export declare function createArrowIpcAdapter(): AdapterDescriptor<"tabulark:arrow-ipc", ArrowIpcAdapterOptions>;
|
|
57
|
+
/** @internal Used by the stable `/parquet` entrypoint. */
|
|
58
|
+
export declare function createParquetAdapter(): AdapterDescriptor<"tabulark:parquet", ParquetAdapterOptions>;
|
|
59
|
+
/** @internal Used by the stable `/excel` entrypoint. */
|
|
60
|
+
export declare function createExcelAdapter(): AdapterDescriptor<"tabulark:excel", ExcelAdapterOptions>;
|
|
61
|
+
/** @internal Validates and extracts the non-public Worker registration. */
|
|
62
|
+
export declare function resolveOfficialAdapter(value: unknown): AdapterRegistration | undefined;
|
package/dist/arrow.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { type ArrowIpcAdapterOptions, type ArrowIpcContainer } from "./adapters.js";
|
|
2
|
+
/** Opens Apache Arrow IPC File or Stream input through the lazy official Arrow artifact. */
|
|
3
|
+
export declare const arrowIpcAdapter: import("./adapters.js").AdapterDescriptor<"tabulark:arrow-ipc", import("./adapters.js").ArrowIpcAdapterOptions>;
|