@zakkster/lite-bake-stream 1.5.0 → 1.6.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/src/Views.js CHANGED
@@ -1,6 +1,9 @@
1
1
  // @zakkster/lite-bake-stream / Views (internal)
2
2
  // Copyright (c) 2026 Zahary Shinikchiev. MIT.
3
3
  //
4
+ // Error codes:
5
+ // W_BAD_SINK - shared finalizeToSink guard: sink missing write/writeAt or async
6
+ //
4
7
  // One shared helper so every container entry point (deserialize,
5
8
  // Reader.fromBuffer, PreserveReader.fromBuffer) resolves caller-supplied bytes
6
9
  // to an ArrayBuffer by exactly the SAME rule (BS-09). A Uint8Array that is a
@@ -23,3 +26,65 @@ export function toContainerBuffer(input, label) {
23
26
  throw new TypeError(label + ': expected ArrayBuffer or Uint8Array, got ' +
24
27
  (input === null ? 'null' : typeof input));
25
28
  }
29
+
30
+ // ---- streaming sink support (M6) --------------------------------------------
31
+ //
32
+ // A sink is any object with a synchronous write(bytes) method; the streaming
33
+ // (layout:'stream') path additionally needs writeAt(bytes, position) for the
34
+ // single header backpatch. MemorySink is the in-RAM reference implementation
35
+ // that finalize() drives internally so it can return the identical container
36
+ // buffer the classic assembler produced.
37
+
38
+ // Growable in-RAM sink. write() appends; writeAt() places bytes at an absolute
39
+ // position (growing the logical length if needed); toArrayBuffer() returns an
40
+ // EXACT-length ArrayBuffer copy of the bytes written.
41
+ export class MemorySink {
42
+ constructor(hint) {
43
+ const cap = (typeof hint === 'number' && hint > 0) ? hint : 64 * 1024;
44
+ this._buf = new Uint8Array(cap);
45
+ this._len = 0;
46
+ }
47
+ _ensure(need) {
48
+ if (need <= this._buf.length) return;
49
+ let cap = this._buf.length;
50
+ while (cap < need) cap *= 2;
51
+ const next = new Uint8Array(cap);
52
+ next.set(this._buf.subarray(0, this._len));
53
+ this._buf = next;
54
+ }
55
+ write(bytes) {
56
+ this._ensure(this._len + bytes.length);
57
+ this._buf.set(bytes, this._len);
58
+ this._len += bytes.length;
59
+ }
60
+ writeAt(bytes, position) {
61
+ this._ensure(position + bytes.length);
62
+ this._buf.set(bytes, position);
63
+ if (position + bytes.length > this._len) this._len = position + bytes.length;
64
+ }
65
+ toArrayBuffer() {
66
+ return this._buf.buffer.slice(0, this._len);
67
+ }
68
+ }
69
+
70
+ // Cold prologue guard for finalizeToSink (raised as W_BAD_SINK by the writer):
71
+ // the sink must be an object with write(); layout:'stream' also needs writeAt().
72
+ export function validateSink(sink, needsWriteAt, raise) {
73
+ if (sink === null || typeof sink !== 'object') {
74
+ raise('W_BAD_SINK', 'sink must be an object with a write(bytes) method; got ' +
75
+ (sink === null ? 'null' : typeof sink));
76
+ }
77
+ if (typeof sink.write !== 'function') {
78
+ raise('W_BAD_SINK', 'sink is missing a write(bytes) method');
79
+ }
80
+ if (needsWriteAt && typeof sink.writeAt !== 'function') {
81
+ raise('W_BAD_SINK', "sink is missing a writeAt(bytes, position) method required for layout:'stream'");
82
+ }
83
+ }
84
+
85
+ // A sink write that returns a thenable is an async sink; the contract is
86
+ // synchronous, so the writer treats it as a malformed sink (W_BAD_SINK).
87
+ export function isThenable(v) {
88
+ return v !== null && (typeof v === 'object' || typeof v === 'function') &&
89
+ typeof v.then === 'function';
90
+ }