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.
Files changed (68) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/README.md +316 -128
  3. package/THIRD_PARTY_NOTICES.md +37 -0
  4. package/dist/adapters.d.ts +62 -0
  5. package/dist/arrow.d.ts +3 -0
  6. package/dist/arrow.js +2 -0
  7. package/dist/arrow.js.map +7 -0
  8. package/dist/client.d.ts +145 -0
  9. package/dist/errors.d.ts +25 -0
  10. package/dist/excel.d.ts +3 -0
  11. package/dist/excel.js +2 -0
  12. package/dist/excel.js.map +7 -0
  13. package/dist/experimental.d.ts +13 -0
  14. package/dist/experimental.js +2 -0
  15. package/dist/experimental.js.map +7 -0
  16. package/dist/http.d.ts +65 -0
  17. package/dist/http.js +2 -0
  18. package/dist/http.js.map +7 -0
  19. package/dist/index.d.ts +11 -0
  20. package/dist/index.js +3 -0
  21. package/dist/index.js.map +7 -0
  22. package/dist/model.d.ts +392 -0
  23. package/dist/official-adapter-manifest.d.ts +31 -0
  24. package/dist/parquet.d.ts +3 -0
  25. package/dist/parquet.js +2 -0
  26. package/dist/parquet.js.map +7 -0
  27. package/dist/protocol.d.ts +54 -0
  28. package/dist/range-cache.d.ts +47 -0
  29. package/dist/range-source.d.ts +64 -0
  30. package/dist/rpc-client.d.ts +31 -0
  31. package/dist/source.d.ts +13 -0
  32. package/dist/view/accessible-grid.d.ts +36 -0
  33. package/dist/view/canvas-painter.d.ts +91 -0
  34. package/dist/view/canvas-table-view-public.d.ts +64 -0
  35. package/dist/view/canvas-table-view.d.ts +40 -0
  36. package/dist/view/controller.d.ts +34 -0
  37. package/dist/view/layout.d.ts +34 -0
  38. package/dist/view/selection.d.ts +7 -0
  39. package/dist/view/types.d.ts +184 -0
  40. package/dist/wasm/arrow/tabulark_arrow.d.ts +153 -0
  41. package/dist/wasm/arrow/tabulark_arrow.js +883 -0
  42. package/dist/wasm/arrow/tabulark_arrow_bg.wasm +0 -0
  43. package/dist/wasm/arrow/tabulark_arrow_bg.wasm.d.ts +30 -0
  44. package/dist/wasm/delimited/tabulark_delimited.d.ts +157 -0
  45. package/dist/wasm/delimited/tabulark_delimited.js +952 -0
  46. package/dist/wasm/delimited/tabulark_delimited_bg.wasm +0 -0
  47. package/dist/wasm/delimited/tabulark_delimited_bg.wasm.d.ts +31 -0
  48. package/dist/wasm/excel/tabulark_excel.d.ts +146 -0
  49. package/dist/wasm/excel/tabulark_excel.js +876 -0
  50. package/dist/wasm/excel/tabulark_excel_bg.wasm +0 -0
  51. package/dist/wasm/excel/tabulark_excel_bg.wasm.d.ts +30 -0
  52. package/dist/wasm/parquet/tabulark_parquet.d.ts +146 -0
  53. package/dist/wasm/parquet/tabulark_parquet.js +872 -0
  54. package/dist/wasm/parquet/tabulark_parquet_bg.wasm +0 -0
  55. package/dist/wasm/parquet/tabulark_parquet_bg.wasm.d.ts +30 -0
  56. package/dist/worker/blob-source-accessor.d.ts +10 -0
  57. package/dist/worker/source-accessor.d.ts +76 -0
  58. package/dist/worker/wasm-adapter.d.ts +58 -0
  59. package/dist/worker/worker-errors.d.ts +9 -0
  60. package/dist/worker-range-source.d.ts +1 -0
  61. package/dist/worker-range-source.js +2 -0
  62. package/dist/worker-range-source.js.map +7 -0
  63. package/dist/worker.d.ts +1 -0
  64. package/dist/worker.js +2 -0
  65. package/dist/worker.js.map +7 -0
  66. package/package.json +62 -12
  67. package/js/index.d.ts +0 -18
  68. 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
- > A WebAssembly-first engine for fast, format-agnostic tabular data preview in the browser.
4
-
5
- **One table model for every tabular source.**
6
-
7
- **Status: pre-alpha design and prototyping.**
8
-
9
- > [!IMPORTANT]
10
- > Tabulark is currently in the design and prototyping stage. There is no stable
11
- > public API or production-ready release yet. The architecture, formats, and
12
- > performance characteristics described below are goals, not shipped features.
13
-
14
- ## Why Tabulark?
15
-
16
- Tabular data reaches web applications through many formats, but preview
17
- interfaces repeatedly reimplement parsing, data transfer, caching, and
18
- rendering for each one.
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
- Tabulark is being designed as composable browser infrastructure that presents
21
- those sources through one format-agnostic `Table` model. It is a preview engine,
22
- not a spreadsheet application.
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
- ## Design principles
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
- - One `Table` abstraction for every supported data source.
27
- - Independently loadable source adapters, including format-specific parsers.
28
- - Parsing and data ownership outside the browser main thread, with WebAssembly
29
- as the primary runtime for performance-sensitive components.
30
- - Demand-driven access instead of copying an entire dataset into JavaScript.
31
- - Viewport-oriented rendering, with Canvas as the first planned renderer.
32
- - Framework-neutral, composable building blocks.
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
- ## Target architecture
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
- Data source
38
- -> source adapter
39
- -> Worker / WebAssembly runtime
40
- -> unified Table model and cache
41
- -> viewport query API
42
- -> renderer
43
- -> application UI
265
+ Engine
266
+ └─ DatasetSession
267
+ └─ TableHandle
268
+ └─ TableBatch
44
269
  ```
45
270
 
46
- This architecture is intentionally provisional while the first end-to-end
47
- prototype is being developed.
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
- ## Non-goals
72
-
73
- Tabulark is not intended to be:
74
-
75
- - A spreadsheet editor or Excel replacement.
76
- - A formula calculation or workbook recalculation engine.
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
- Run the local checks:
282
+ ## Verification
94
283
 
95
- ```bash
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
- After the first registry release, consumers will be able to install the base
105
- packages with:
290
+ # Stable exports/declarations, clean package consumers, and Pages assembly
291
+ npm run check
106
292
 
107
- ```bash
108
- cargo add tabulark
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
- ## Repository layout
296
+ # Independent core, Arrow, Parquet, Excel, npm, and Pages delivery budgets
297
+ npm run benchmark:size
113
298
 
114
- ```text
115
- tabulark/
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
- See the [project vision](docs/vision.md) for the long-term design intent and
125
- [release guide](docs/releasing.md) for registry setup and publishing.
126
-
127
- ## Project status
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
- - [ ] Validate the unified `Table` model.
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
- ## Contributing
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
- Tabulark is not yet ready for broad feature contributions. Design discussion,
139
- representative datasets, and concrete browser-preview use cases are welcome in
140
- [GitHub Issues](https://github.com/Ronbb/tabulark/issues).
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
- ## AI-assisted development
327
+ ## Repository map
143
328
 
144
- Tabulark makes extensive use of generative AI throughout project design,
145
- implementation, testing, documentation, and code review. AI-generated output is
146
- treated as a draft rather than trusted work: maintainers remain responsible for
147
- every change, and the same review, testing, security, and licensing standards
148
- apply regardless of how a contribution was produced.
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
- Licensed under either of:
153
-
154
- - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))
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;
@@ -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>;