vectorjson 0.4.1 → 0.4.3

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/README.md CHANGED
@@ -30,7 +30,7 @@ for await (const chunk of stream) {
30
30
  }
31
31
  ```
32
32
 
33
- A 50KB tool call streamed in ~12-char chunks means ~4,000 full re-parses — O(n²). At 100KB, Vercel AI SDK spends 6.1 seconds just parsing. Anthropic SDK spends 13.4 seconds.
33
+ A 50KB tool call streamed in ~12-char chunks means ~4,000 full re-parses — O(n²). At 100KB, Vercel AI SDK spends 6.1 seconds just parsing. Anthropic SDK spends 13.4 seconds. Each re-parse also allocates a new string (`buffer += chunk`) and a new object graph — all immediately discarded. That's ~100 MB of throwaway strings for a 50KB payload, plus thousands of intermediate objects, putting heavy pressure on the garbage collector and bloating memory.
34
34
 
35
35
  ## Quick Start
36
36
 
@@ -124,22 +124,23 @@ for await (const chunk of llmStream({ signal: abort.signal })) {
124
124
  }
125
125
  ```
126
126
 
127
- **Worker offload** — parse 2-3× faster in a Worker, transfer results in O(1):
127
+ **Worker offload** — parse in a Worker, transfer in O(1), skip re-parsing on main thread:
128
128
 
129
- VectorJSON's `getRawBuffer()` returns flat bytes `postMessage(buf, [buf])` transfers the backing store pointer in O(1) instead of structured-cloning a full object graph. The main thread lazily accesses only the fields it needs:
129
+ `getTapeBuffer()` exports the SIMD-parsed tape + input as a single packed ArrayBuffer. `postMessage(buf, [buf])` transfers it in O(1). The main thread imports it with `importTape()` zero parsing, just memcpy into a document slot:
130
130
 
131
131
  ```js
132
132
  // In Worker:
133
133
  parser.feed(chunk);
134
- const buf = parser.getRawBuffer();
135
- postMessage(buf, [buf]); // O(1) transfer — moves pointer, no copy
134
+ const tape = parser.getTapeBuffer();
135
+ postMessage(tape, [tape]); // O(1) transfer — moves pointer, no copy
136
136
 
137
137
  // On Main thread:
138
- const result = parse(new Uint8Array(buf)); // lazy Proxy
139
- result.value.name; // only materializes what you touch
138
+ import { importTape } from "vectorjson";
139
+ const obj = importTape(tape); // zero parse tape is already built
140
+ obj.name; // lazy Proxy, same as parse()
140
141
  ```
141
142
 
142
- Worker-side parsing is 2-3× faster than `JSON.parse` at 50 KB+. The transferable ArrayBuffer avoids structured clone overhead, and the lazy Proxy on the main thread means you only pay for the fields you access.
143
+ Worker-side parsing is 2-3× faster than `JSON.parse` at 50 KB+. The transferable ArrayBuffer avoids structured clone overhead. Tape transfer eliminates re-parsing on the main thread entirely **~20× less main-thread blocking** than transferring raw bytes and re-parsing.
143
144
 
144
145
  ## Benchmarks
145
146
 
@@ -463,7 +464,7 @@ JSONL push-based: call `resetForNext()` after each value. JSON5 comments are str
463
464
  All functions are available as direct imports — no `init()` needed:
464
465
 
465
466
  ```js
466
- import { parse, parsePartialJson, deepCompare, createParser, createEventParser, materialize } from "vectorjson";
467
+ import { parse, parsePartialJson, deepCompare, createParser, createEventParser, materialize, importTape } from "vectorjson";
467
468
  ```
468
469
 
469
470
  ### `init(options?): Promise<VectorJSON>`
@@ -528,6 +529,7 @@ interface StreamingParser<T = unknown> {
528
529
  getValue(): T | undefined; // autocompleted partial while incomplete, final when complete
529
530
  getRemaining(): Uint8Array | null;
530
531
  getRawBuffer(): ArrayBuffer | null; // transferable buffer for Worker postMessage
532
+ getTapeBuffer(): ArrayBuffer | null; // packed tape + input for zero-parse transfer
531
533
  getStatus(): FeedStatus;
532
534
  resetForNext(): number; // JSONL: reset for next value, returns remaining byte count
533
535
  destroy(): void;
@@ -611,6 +613,7 @@ interface EventParser {
611
613
  getValue(): unknown | undefined; // undefined while incomplete, throws on parse errors
612
614
  getRemaining(): Uint8Array | null;
613
615
  getRawBuffer(): ArrayBuffer | null; // transferable buffer for Worker postMessage
616
+ getTapeBuffer(): ArrayBuffer | null; // packed tape + input for zero-parse transfer
614
617
  getStatus(): FeedStatus;
615
618
  destroy(): void;
616
619
  [Symbol.asyncIterator](): AsyncIterableIterator<unknown | undefined>; // requires source
@@ -710,6 +713,10 @@ deepCompare(
710
713
 
711
714
  Convert a lazy Proxy into a plain JS object tree. No-op on plain values.
712
715
 
716
+ ### `importTape(buf: ArrayBuffer): unknown`
717
+
718
+ Import a packed tape buffer (from `getTapeBuffer()`) into a lazy Proxy. Skips parsing entirely — the pre-built tape is copied directly into a WASM document slot. Returns the same lazy Proxy as `parse()`.
719
+
713
720
  ## Runtime Support
714
721
 
715
722
  | Runtime | Status | Notes |