@minnowdb/core 0.6.9 → 0.7.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 (103) hide show
  1. package/dist/block-format/block.js +254 -325
  2. package/dist/block-format/checksum.js +30 -52
  3. package/dist/block-format/codecs.js +112 -125
  4. package/dist/block-format/column.js +187 -205
  5. package/dist/block-format/index.js +5 -1
  6. package/dist/block-format/physical.js +371 -387
  7. package/dist/block-format/types.js +4 -1
  8. package/dist/block-format/unicode.js +30 -39
  9. package/dist/date-value.d.ts +5 -0
  10. package/dist/date-value.js +71 -41
  11. package/dist/engine/artifact-cache.js +106 -116
  12. package/dist/engine/batch.js +36 -44
  13. package/dist/engine/buffered-writer.js +156 -158
  14. package/dist/engine/byte-estimates.js +20 -22
  15. package/dist/engine/cache-limits.js +24 -25
  16. package/dist/engine/cancellation.js +5 -3
  17. package/dist/engine/catalog.js +64 -73
  18. package/dist/engine/client.js +715 -780
  19. package/dist/engine/database.js +15952 -18465
  20. package/dist/engine/defaults.js +104 -111
  21. package/dist/engine/errors.js +113 -128
  22. package/dist/engine/fts.js +233 -280
  23. package/dist/engine/group-index.js +287 -321
  24. package/dist/engine/index.js +23 -12
  25. package/dist/engine/join-index.js +177 -186
  26. package/dist/engine/keyed-live.js +168 -173
  27. package/dist/engine/live-api.js +0 -1
  28. package/dist/engine/live-equal.js +32 -37
  29. package/dist/engine/live.js +603 -647
  30. package/dist/engine/memory.js +109 -111
  31. package/dist/engine/optimizer.d.ts +19 -1
  32. package/dist/engine/optimizer.js +2642 -2515
  33. package/dist/engine/point-read.d.ts +4 -2
  34. package/dist/engine/point-read.js +121 -171
  35. package/dist/engine/query-api.js +12 -3
  36. package/dist/engine/query-cache.js +61 -69
  37. package/dist/engine/query.d.ts +45 -0
  38. package/dist/engine/query.js +8506 -9375
  39. package/dist/engine/result-wire.js +221 -252
  40. package/dist/engine/schema-wire.js +97 -112
  41. package/dist/engine/schema.js +1099 -1254
  42. package/dist/engine/sort-keys.js +315 -389
  43. package/dist/engine/sql-domains.d.ts +7 -1
  44. package/dist/engine/sql-domains.js +648 -734
  45. package/dist/engine/sql-driver.js +0 -1
  46. package/dist/engine/sql-functions.d.ts +11 -0
  47. package/dist/engine/sql-functions.js +1092 -0
  48. package/dist/engine/sql-json.js +199 -218
  49. package/dist/engine/sql-semantics.d.ts +25 -4
  50. package/dist/engine/sql-semantics.js +579 -513
  51. package/dist/engine/typed-live.js +271 -293
  52. package/dist/engine/vector.d.ts +7 -1
  53. package/dist/engine/vector.js +4513 -4580
  54. package/dist/engine/worker-host.d.ts +8 -63
  55. package/dist/engine/worker-host.js +28 -1130
  56. package/dist/engine/worker-indexeddb.d.ts +1 -0
  57. package/dist/engine/worker-indexeddb.js +3 -0
  58. package/dist/engine/worker-memory.d.ts +1 -0
  59. package/dist/engine/worker-memory.js +3 -0
  60. package/dist/engine/worker-opfs.d.ts +1 -0
  61. package/dist/engine/worker-opfs.js +3 -0
  62. package/dist/engine/worker-server.d.ts +93 -0
  63. package/dist/engine/worker-server.js +999 -0
  64. package/dist/engine/worker-store-indexeddb.d.ts +2 -0
  65. package/dist/engine/worker-store-indexeddb.js +11 -0
  66. package/dist/engine/worker-store-memory.d.ts +2 -0
  67. package/dist/engine/worker-store-memory.js +6 -0
  68. package/dist/engine/worker-store-opfs.d.ts +2 -0
  69. package/dist/engine/worker-store-opfs.js +9 -0
  70. package/dist/engine/worker.js +0 -12
  71. package/dist/engine/write-block-planner.js +93 -100
  72. package/dist/plan/index.js +15 -16
  73. package/dist/plan/model.d.ts +9 -1
  74. package/dist/plan/model.js +20 -27
  75. package/dist/storage/index.js +0 -12
  76. package/dist/storage/indexeddb.js +11776 -13171
  77. package/dist/storage/memory.js +1198 -1241
  78. package/dist/storage/opfs/files.js +238 -295
  79. package/dist/storage/opfs/index.js +9 -3
  80. package/dist/storage/opfs/leader.js +4386 -4856
  81. package/dist/storage/opfs/rpc.js +223 -259
  82. package/dist/storage/opfs/snapshot-ledger.js +219 -260
  83. package/dist/storage/opfs/store.js +884 -1003
  84. package/dist/storage/persistence.js +59 -74
  85. package/dist/storage/snapshot-stream.js +788 -826
  86. package/dist/storage/snapshot.js +36 -37
  87. package/dist/storage/toolkit/extents.js +444 -520
  88. package/dist/storage/toolkit/index.js +28 -29
  89. package/dist/storage/toolkit/record-core.js +5792 -6377
  90. package/dist/storage/toolkit/sync-file.js +34 -42
  91. package/dist/storage/toolkit/wal.js +92 -127
  92. package/dist/storage/toolkit/wire.js +232 -256
  93. package/dist/storage/types.js +2952 -3228
  94. package/dist/testing/block-store-conformance.js +1556 -1629
  95. package/dist/testing/index.js +310 -291
  96. package/dist/testing/opfs-shim.js +280 -312
  97. package/dist/testing/simulator.js +496 -534
  98. package/dist/testing/sqllogictest.js +425 -365
  99. package/dist/transactions/index.js +1464 -1712
  100. package/dist/worker-protocol/index.js +70 -69
  101. package/package.json +20 -2
  102. package/postgres-feature-profile.json +15 -5
  103. package/sql-feature-matrix.json +252 -2
@@ -1,289 +1,265 @@
1
1
  import { crc32 } from "../../block-format/index.js";
2
2
  import { MAX_ROW_ID_EXCLUSIVE_END, StorageFormatVersionError } from "../types.js";
3
- /**
4
- * Payload encodings for a log-structured adapter's control data: checkpoint files, immutable
5
- * artifact chunks, and the JSON codec write-ahead-log frames carry. Every envelope is
6
- * checksummed so a torn write — the only artifact a crash can leave — is detectable and
7
- * indistinguishable from "not written".
8
- *
9
- * Record payloads are JSON with one extension: bigints (segment row ids, counters, full-text
10
- * posting row ids, compaction rewrite plans) encode as `{"$n":"<decimal>"}`. No record shape
11
- * can produce that object naturally — keys are ids and column names, values are JSON scalars —
12
- * and the reviver only converts an object whose sole key is `$n`.
13
- */
14
- export const LOG_FORMAT_VERSION = 5;
3
+ const LOG_FORMAT_VERSION = 5;
15
4
  const textEncoder = new TextEncoder();
16
5
  const textDecoder = new TextDecoder("utf-8", { fatal: true });
17
- export function encodeRecordJson(value) {
18
- // The replacer costs ~3x on big payloads because it runs per node; most frames carry no
19
- // bigints at all, and stringify announces one by throwing.
20
- let json;
21
- try {
22
- json = JSON.stringify(value);
23
- }
24
- catch {
25
- json = JSON.stringify(value, (_key, entry) => {
26
- if (typeof entry !== "bigint")
27
- return entry;
28
- if (entry < 0n || entry > MAX_ROW_ID_EXCLUSIVE_END) {
29
- throw new RangeError("Record bigint exceeds the unsigned 64-bit persisted range");
30
- }
31
- return { $n: entry.toString() };
32
- });
33
- }
34
- if (typeof json !== "string")
35
- throw new TypeError("Record value is not JSON-serializable");
36
- return textEncoder.encode(json);
37
- }
38
- export function decodeRecordJson(bytes) {
39
- const json = textDecoder.decode(bytes);
40
- return JSON.parse(json, (_key, entry) => {
41
- if (typeof entry === "object" &&
42
- entry !== null &&
43
- !Array.isArray(entry) &&
44
- Object.keys(entry).length === 1 &&
45
- typeof entry.$n === "string") {
46
- const decimal = entry.$n;
47
- if (!/^(?:0|[1-9][0-9]{0,19})$/.test(decimal)) {
48
- throw new TypeError("Record bigint is not a canonical bounded unsigned decimal");
49
- }
50
- const value = BigInt(decimal);
51
- if (value > MAX_ROW_ID_EXCLUSIVE_END) {
52
- throw new RangeError("Record bigint exceeds the unsigned 64-bit persisted range");
53
- }
54
- return value;
55
- }
6
+ function encodeRecordJson(value) {
7
+ let json;
8
+ try {
9
+ json = JSON.stringify(value);
10
+ } catch {
11
+ json = JSON.stringify(value, (_key, entry) => {
12
+ if (typeof entry !== "bigint")
56
13
  return entry;
14
+ if (entry < 0n || entry > MAX_ROW_ID_EXCLUSIVE_END) {
15
+ throw new RangeError("Record bigint exceeds the unsigned 64-bit persisted range");
16
+ }
17
+ return { $n: entry.toString() };
57
18
  });
19
+ }
20
+ if (typeof json !== "string")
21
+ throw new TypeError("Record value is not JSON-serializable");
22
+ return textEncoder.encode(json);
23
+ }
24
+ function decodeRecordJson(bytes) {
25
+ const json = textDecoder.decode(bytes);
26
+ return JSON.parse(json, (_key, entry) => {
27
+ if (typeof entry === "object" && entry !== null && !Array.isArray(entry) && Object.keys(entry).length === 1 && typeof entry.$n === "string") {
28
+ const decimal = entry.$n;
29
+ if (!/^(?:0|[1-9][0-9]{0,19})$/.test(decimal)) {
30
+ throw new TypeError("Record bigint is not a canonical bounded unsigned decimal");
31
+ }
32
+ const value = BigInt(decimal);
33
+ if (value > MAX_ROW_ID_EXCLUSIVE_END) {
34
+ throw new RangeError("Record bigint exceeds the unsigned 64-bit persisted range");
35
+ }
36
+ return value;
37
+ }
38
+ return entry;
39
+ });
58
40
  }
59
41
  const ENVELOPE_HEADER_BYTES = 8 + 4 + 4 + 4;
60
42
  function encodeEnvelope(magic, payload) {
61
- const bytes = new Uint8Array(ENVELOPE_HEADER_BYTES + payload.byteLength);
62
- const view = new DataView(bytes.buffer);
63
- textEncoder.encodeInto(magic, bytes);
64
- view.setUint32(8, LOG_FORMAT_VERSION, true);
65
- view.setUint32(12, payload.byteLength, true);
66
- view.setUint32(16, crc32(payload), true);
67
- bytes.set(payload, ENVELOPE_HEADER_BYTES);
68
- return bytes;
43
+ const bytes = new Uint8Array(ENVELOPE_HEADER_BYTES + payload.byteLength);
44
+ const view = new DataView(bytes.buffer);
45
+ textEncoder.encodeInto(magic, bytes);
46
+ view.setUint32(8, LOG_FORMAT_VERSION, true);
47
+ view.setUint32(12, payload.byteLength, true);
48
+ view.setUint32(16, crc32(payload), true);
49
+ bytes.set(payload, ENVELOPE_HEADER_BYTES);
50
+ return bytes;
69
51
  }
70
- /**
71
- * `undefined` means the bytes are torn or foreign — treat as "not written". A recognized magic
72
- * with an unknown format version throws instead: reading a different layout as the current one
73
- * would silently corrupt or roll back the database.
74
- */
75
52
  function decodeEnvelope(magic, bytes) {
76
- if (bytes.byteLength < ENVELOPE_HEADER_BYTES)
77
- return undefined;
78
- for (let index = 0; index < 8; index += 1) {
79
- if (bytes[index] !== magic.charCodeAt(index))
80
- return undefined;
81
- }
82
- const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
83
- const version = view.getUint32(8, true);
84
- if (version !== LOG_FORMAT_VERSION) {
85
- throw new StorageFormatVersionError("opfs", `envelope/${magic}`, version, LOG_FORMAT_VERSION, version < LOG_FORMAT_VERSION ? "older" : "newer");
86
- }
87
- const payloadLength = view.getUint32(12, true);
88
- if (bytes.byteLength !== ENVELOPE_HEADER_BYTES + payloadLength)
89
- return undefined;
90
- const payload = bytes.subarray(ENVELOPE_HEADER_BYTES, ENVELOPE_HEADER_BYTES + payloadLength);
91
- if (crc32(payload) !== view.getUint32(16, true))
92
- return undefined;
93
- return payload;
53
+ if (bytes.byteLength < ENVELOPE_HEADER_BYTES)
54
+ return void 0;
55
+ for (let index = 0; index < 8; index += 1) {
56
+ if (bytes[index] !== magic.charCodeAt(index))
57
+ return void 0;
58
+ }
59
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
60
+ const version = view.getUint32(8, true);
61
+ if (version !== LOG_FORMAT_VERSION) {
62
+ throw new StorageFormatVersionError("opfs", `envelope/${magic}`, version, LOG_FORMAT_VERSION, version < LOG_FORMAT_VERSION ? "older" : "newer");
63
+ }
64
+ const payloadLength = view.getUint32(12, true);
65
+ if (bytes.byteLength !== ENVELOPE_HEADER_BYTES + payloadLength)
66
+ return void 0;
67
+ const payload = bytes.subarray(ENVELOPE_HEADER_BYTES, ENVELOPE_HEADER_BYTES + payloadLength);
68
+ if (crc32(payload) !== view.getUint32(16, true))
69
+ return void 0;
70
+ return payload;
94
71
  }
95
72
  const CHUNK_MAGIC = "MNWCHNK1";
96
73
  const POSTING_CHUNK_MAGIC = "MNWPOST1";
97
74
  const SYNC_CHECKPOINT_MAGIC = "MNWCKPS1";
98
- /** Immutable artifact payloads (full-text base chunks) inside extents. */
99
- export function encodeChunk(value) {
100
- return encodeEnvelope(CHUNK_MAGIC, encodeRecordJson(value));
75
+ function encodeChunk(value) {
76
+ return encodeEnvelope(CHUNK_MAGIC, encodeRecordJson(value));
101
77
  }
102
- export function decodeChunk(bytes) {
103
- const payload = decodeEnvelope(CHUNK_MAGIC, bytes);
104
- return payload === undefined ? undefined : decodeRecordJson(payload);
78
+ function decodeChunk(bytes) {
79
+ const payload = decodeEnvelope(CHUNK_MAGIC, bytes);
80
+ return payload === void 0 ? void 0 : decodeRecordJson(payload);
105
81
  }
106
- /**
107
- * Compact postings payload for OPFS. Terms are UTF-8 and the already-sorted row locators are
108
- * delta-varints, keeping secondary indexes smaller than the table they accelerate.
109
- * The envelope keeps the same version and checksum guarantees as every other immutable chunk.
110
- */
111
- export function encodePostingChunk(entries) {
112
- const writer = new BinaryWriter();
113
- writer.varuint(BigInt(entries.length));
114
- for (const entry of entries) {
115
- if (entry.rowIds.length !== entry.tf.length) {
116
- throw new TypeError("Posting row IDs and term frequencies must have the same length");
117
- }
118
- const term = textEncoder.encode(entry.term);
119
- if (term.byteLength === 0)
120
- throw new TypeError("Posting terms cannot be empty");
121
- if (entry.rowIds.length === 0)
122
- throw new TypeError("Postings cannot have no row IDs");
123
- writer.varuint(BigInt(term.byteLength));
124
- writer.bytes(term);
125
- writer.varuint(BigInt(entry.rowIds.length));
126
- let previous = 0n;
127
- for (const rowId of entry.rowIds) {
128
- if (rowId <= previous || rowId > MAX_ROW_ID_EXCLUSIVE_END - 1n) {
129
- throw new TypeError("Posting row IDs must be positive, uint64, and strictly sorted");
130
- }
131
- writer.varuint(rowId - previous);
132
- previous = rowId;
133
- }
134
- for (const frequency of entry.tf) {
135
- if (!Number.isSafeInteger(frequency) || frequency <= 0) {
136
- throw new TypeError("Posting term frequencies must be positive whole numbers");
137
- }
138
- writer.varuint(BigInt(frequency));
139
- }
82
+ function encodePostingChunk(entries) {
83
+ const writer = new BinaryWriter();
84
+ writer.varuint(BigInt(entries.length));
85
+ for (const entry of entries) {
86
+ if (entry.rowIds.length !== entry.tf.length) {
87
+ throw new TypeError("Posting row IDs and term frequencies must have the same length");
140
88
  }
141
- return encodeEnvelope(POSTING_CHUNK_MAGIC, writer.finish());
142
- }
143
- /** `undefined` means the bytes are torn or are not a canonical postings envelope. */
144
- export function decodePostingChunk(bytes) {
145
- const payload = decodeEnvelope(POSTING_CHUNK_MAGIC, bytes);
146
- if (payload === undefined)
147
- return undefined;
148
- const reader = new BinaryReader(payload);
149
- const count = reader.safeInteger("posting count");
150
- if (count > Math.floor(reader.remaining / 5)) {
151
- throw new Error("Posting count exceeds the remaining payload");
89
+ const term = textEncoder.encode(entry.term);
90
+ if (term.byteLength === 0)
91
+ throw new TypeError("Posting terms cannot be empty");
92
+ if (entry.rowIds.length === 0)
93
+ throw new TypeError("Postings cannot have no row IDs");
94
+ writer.varuint(BigInt(term.byteLength));
95
+ writer.bytes(term);
96
+ writer.varuint(BigInt(entry.rowIds.length));
97
+ let previous = 0n;
98
+ for (const rowId of entry.rowIds) {
99
+ if (rowId <= previous || rowId > MAX_ROW_ID_EXCLUSIVE_END - 1n) {
100
+ throw new TypeError("Posting row IDs must be positive, uint64, and strictly sorted");
101
+ }
102
+ writer.varuint(rowId - previous);
103
+ previous = rowId;
152
104
  }
153
- const entries = new Array(count);
154
- for (let entryIndex = 0; entryIndex < count; entryIndex += 1) {
155
- const termLength = reader.safeInteger("posting term length");
156
- if (termLength < 1 || termLength > reader.remaining) {
157
- throw new Error("Posting term length exceeds the remaining payload");
158
- }
159
- const term = textDecoder.decode(reader.bytes(termLength));
160
- const rowCount = reader.safeInteger("posting row count");
161
- if (rowCount < 1 || rowCount > Math.floor(reader.remaining / 2)) {
162
- throw new Error("Posting row count exceeds the remaining payload");
163
- }
164
- const rowIds = new Array(rowCount);
165
- let previous = 0n;
166
- for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
167
- previous += reader.varuint();
168
- if (previous < 1n || previous > MAX_ROW_ID_EXCLUSIVE_END - 1n) {
169
- throw new RangeError("Posting row ID exceeds the uint64 range");
170
- }
171
- if (rowIndex > 0 && previous <= (rowIds[rowIndex - 1] ?? 0n)) {
172
- throw new TypeError("Posting row IDs are not strictly sorted");
173
- }
174
- rowIds[rowIndex] = previous;
175
- }
176
- const tf = new Array(rowCount);
177
- for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
178
- const frequency = reader.safeInteger("posting term frequency");
179
- if (frequency <= 0)
180
- throw new TypeError("Posting term frequency must be positive");
181
- tf[rowIndex] = frequency;
182
- }
183
- entries[entryIndex] = { term, rowIds, tf };
105
+ for (const frequency of entry.tf) {
106
+ if (!Number.isSafeInteger(frequency) || frequency <= 0) {
107
+ throw new TypeError("Posting term frequencies must be positive whole numbers");
108
+ }
109
+ writer.varuint(BigInt(frequency));
184
110
  }
185
- if (!reader.done)
186
- throw new Error("Posting chunk has trailing bytes");
187
- return entries;
111
+ }
112
+ return encodeEnvelope(POSTING_CHUNK_MAGIC, writer.finish());
188
113
  }
189
- class BinaryWriter {
190
- #buffer = new Uint8Array(1_024);
191
- #length = 0;
192
- bytes(bytes) {
193
- this.#reserve(bytes.byteLength);
194
- this.#buffer.set(bytes, this.#length);
195
- this.#length += bytes.byteLength;
114
+ function decodePostingChunk(bytes) {
115
+ const payload = decodeEnvelope(POSTING_CHUNK_MAGIC, bytes);
116
+ if (payload === void 0)
117
+ return void 0;
118
+ const reader = new BinaryReader(payload);
119
+ const count = reader.safeInteger("posting count");
120
+ if (count > Math.floor(reader.remaining / 5)) {
121
+ throw new Error("Posting count exceeds the remaining payload");
122
+ }
123
+ const entries = new Array(count);
124
+ for (let entryIndex = 0; entryIndex < count; entryIndex += 1) {
125
+ const termLength = reader.safeInteger("posting term length");
126
+ if (termLength < 1 || termLength > reader.remaining) {
127
+ throw new Error("Posting term length exceeds the remaining payload");
196
128
  }
197
- varuint(value) {
198
- if (value < 0n || value >= MAX_ROW_ID_EXCLUSIVE_END) {
199
- throw new RangeError("A varuint must fit canonical uint64");
200
- }
201
- do {
202
- this.#reserve(1);
203
- const byte = Number(value & 0x7fn);
204
- value >>= 7n;
205
- this.#buffer[this.#length] = value === 0n ? byte : byte | 0x80;
206
- this.#length += 1;
207
- } while (value !== 0n);
129
+ const term = textDecoder.decode(reader.bytes(termLength));
130
+ const rowCount = reader.safeInteger("posting row count");
131
+ if (rowCount < 1 || rowCount > Math.floor(reader.remaining / 2)) {
132
+ throw new Error("Posting row count exceeds the remaining payload");
208
133
  }
209
- finish() {
210
- return this.#buffer.slice(0, this.#length);
134
+ const rowIds = new Array(rowCount);
135
+ let previous = 0n;
136
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
137
+ previous += reader.varuint();
138
+ if (previous < 1n || previous > MAX_ROW_ID_EXCLUSIVE_END - 1n) {
139
+ throw new RangeError("Posting row ID exceeds the uint64 range");
140
+ }
141
+ if (rowIndex > 0 && previous <= (rowIds[rowIndex - 1] ?? 0n)) {
142
+ throw new TypeError("Posting row IDs are not strictly sorted");
143
+ }
144
+ rowIds[rowIndex] = previous;
211
145
  }
212
- #reserve(extra) {
213
- if (!Number.isSafeInteger(extra) || extra < 0)
214
- throw new RangeError("Invalid binary growth");
215
- const needed = this.#length + extra;
216
- if (!Number.isSafeInteger(needed))
217
- throw new RangeError("Binary payload is too large");
218
- if (needed <= this.#buffer.byteLength)
219
- return;
220
- let capacity = this.#buffer.byteLength;
221
- while (capacity < needed) {
222
- const doubled = capacity * 2;
223
- capacity = Number.isSafeInteger(doubled) ? doubled : needed;
224
- }
225
- const grown = new Uint8Array(capacity);
226
- grown.set(this.#buffer);
227
- this.#buffer = grown;
146
+ const tf = new Array(rowCount);
147
+ for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {
148
+ const frequency = reader.safeInteger("posting term frequency");
149
+ if (frequency <= 0)
150
+ throw new TypeError("Posting term frequency must be positive");
151
+ tf[rowIndex] = frequency;
228
152
  }
153
+ entries[entryIndex] = { term, rowIds, tf };
154
+ }
155
+ if (!reader.done)
156
+ throw new Error("Posting chunk has trailing bytes");
157
+ return entries;
229
158
  }
230
- class BinaryReader {
231
- source;
232
- #offset = 0;
233
- constructor(source) {
234
- this.source = source;
235
- }
236
- get done() {
237
- return this.#offset === this.source.byteLength;
238
- }
239
- get remaining() {
240
- return this.source.byteLength - this.#offset;
159
+ class BinaryWriter {
160
+ #buffer = new Uint8Array(1024);
161
+ #length = 0;
162
+ bytes(bytes) {
163
+ this.#reserve(bytes.byteLength);
164
+ this.#buffer.set(bytes, this.#length);
165
+ this.#length += bytes.byteLength;
166
+ }
167
+ varuint(value) {
168
+ if (value < 0n || value >= MAX_ROW_ID_EXCLUSIVE_END) {
169
+ throw new RangeError("A varuint must fit canonical uint64");
241
170
  }
242
- bytes(length) {
243
- if (!Number.isSafeInteger(length) || length < 0 || length > this.remaining)
244
- throw new Error("Posting chunk is truncated");
245
- const bytes = this.source.subarray(this.#offset, this.#offset + length);
246
- this.#offset += length;
247
- return bytes;
171
+ do {
172
+ this.#reserve(1);
173
+ const byte = Number(value & 0x7fn);
174
+ value >>= 7n;
175
+ this.#buffer[this.#length] = value === 0n ? byte : byte | 128;
176
+ this.#length += 1;
177
+ } while (value !== 0n);
178
+ }
179
+ finish() {
180
+ return this.#buffer.slice(0, this.#length);
181
+ }
182
+ #reserve(extra) {
183
+ if (!Number.isSafeInteger(extra) || extra < 0)
184
+ throw new RangeError("Invalid binary growth");
185
+ const needed = this.#length + extra;
186
+ if (!Number.isSafeInteger(needed))
187
+ throw new RangeError("Binary payload is too large");
188
+ if (needed <= this.#buffer.byteLength)
189
+ return;
190
+ let capacity = this.#buffer.byteLength;
191
+ while (capacity < needed) {
192
+ const doubled = capacity * 2;
193
+ capacity = Number.isSafeInteger(doubled) ? doubled : needed;
248
194
  }
249
- varuint() {
250
- let value = 0n;
251
- let shift = 0n;
252
- for (let byteIndex = 0; byteIndex < 10; byteIndex += 1) {
253
- const byte = this.source[this.#offset];
254
- if (byte === undefined)
255
- throw new Error("Posting chunk is truncated");
256
- this.#offset += 1;
257
- if (byteIndex === 9 && (byte & 0xfe) !== 0) {
258
- throw new Error("Posting chunk varuint exceeds uint64");
259
- }
260
- value |= BigInt(byte & 0x7f) << shift;
261
- if ((byte & 0x80) === 0) {
262
- if (byteIndex > 0 && (byte & 0x7f) === 0) {
263
- throw new Error("Posting chunk varuint is overlong");
264
- }
265
- return value;
266
- }
267
- shift += 7n;
195
+ const grown = new Uint8Array(capacity);
196
+ grown.set(this.#buffer);
197
+ this.#buffer = grown;
198
+ }
199
+ }
200
+ class BinaryReader {
201
+ source;
202
+ #offset = 0;
203
+ constructor(source) {
204
+ this.source = source;
205
+ }
206
+ get done() {
207
+ return this.#offset === this.source.byteLength;
208
+ }
209
+ get remaining() {
210
+ return this.source.byteLength - this.#offset;
211
+ }
212
+ bytes(length) {
213
+ if (!Number.isSafeInteger(length) || length < 0 || length > this.remaining)
214
+ throw new Error("Posting chunk is truncated");
215
+ const bytes = this.source.subarray(this.#offset, this.#offset + length);
216
+ this.#offset += length;
217
+ return bytes;
218
+ }
219
+ varuint() {
220
+ let value = 0n;
221
+ let shift = 0n;
222
+ for (let byteIndex = 0; byteIndex < 10; byteIndex += 1) {
223
+ const byte = this.source[this.#offset];
224
+ if (byte === void 0)
225
+ throw new Error("Posting chunk is truncated");
226
+ this.#offset += 1;
227
+ if (byteIndex === 9 && (byte & 254) !== 0) {
228
+ throw new Error("Posting chunk varuint exceeds uint64");
229
+ }
230
+ value |= BigInt(byte & 127) << shift;
231
+ if ((byte & 128) === 0) {
232
+ if (byteIndex > 0 && (byte & 127) === 0) {
233
+ throw new Error("Posting chunk varuint is overlong");
268
234
  }
269
- throw new Error("Posting chunk varuint is too wide");
270
- }
271
- safeInteger(label) {
272
- const value = this.varuint();
273
- if (value > BigInt(Number.MAX_SAFE_INTEGER))
274
- throw new RangeError(`${label} is too large`);
275
- return Number(value);
235
+ return value;
236
+ }
237
+ shift += 7n;
276
238
  }
239
+ throw new Error("Posting chunk varuint is too wide");
240
+ }
241
+ safeInteger(label) {
242
+ const value = this.varuint();
243
+ if (value > BigInt(Number.MAX_SAFE_INTEGER))
244
+ throw new RangeError(`${label} is too large`);
245
+ return Number(value);
246
+ }
277
247
  }
278
- /**
279
- * The leader's checkpoint slots are written synchronously (no compression — that needs an
280
- * await, and the checkpoint must land in the same synchronous run that resets the WAL, or
281
- * frames appended in between would be lost by the reset).
282
- */
283
- export function encodeSyncCheckpoint(state) {
284
- return encodeEnvelope(SYNC_CHECKPOINT_MAGIC, encodeRecordJson(state));
248
+ function encodeSyncCheckpoint(state) {
249
+ return encodeEnvelope(SYNC_CHECKPOINT_MAGIC, encodeRecordJson(state));
285
250
  }
286
- export function decodeSyncCheckpoint(bytes) {
287
- const payload = decodeEnvelope(SYNC_CHECKPOINT_MAGIC, bytes);
288
- return payload === undefined ? undefined : decodeRecordJson(payload);
251
+ function decodeSyncCheckpoint(bytes) {
252
+ const payload = decodeEnvelope(SYNC_CHECKPOINT_MAGIC, bytes);
253
+ return payload === void 0 ? void 0 : decodeRecordJson(payload);
289
254
  }
255
+ export {
256
+ LOG_FORMAT_VERSION,
257
+ decodeChunk,
258
+ decodePostingChunk,
259
+ decodeRecordJson,
260
+ decodeSyncCheckpoint,
261
+ encodeChunk,
262
+ encodePostingChunk,
263
+ encodeRecordJson,
264
+ encodeSyncCheckpoint
265
+ };