@btoon/js 0.0.0-stage → 0.1.0

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 (64) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +328 -2
  3. package/dist/cjs/constants.d.ts +34 -0
  4. package/dist/cjs/constants.js +32 -0
  5. package/dist/cjs/core.d.ts +15 -0
  6. package/dist/cjs/core.js +275 -0
  7. package/dist/cjs/decode.d.ts +10 -0
  8. package/dist/cjs/decode.js +554 -0
  9. package/dist/cjs/encode.d.ts +2 -0
  10. package/dist/cjs/encode.js +946 -0
  11. package/dist/cjs/errors.d.ts +53 -0
  12. package/dist/cjs/errors.js +45 -0
  13. package/dist/cjs/index.d.ts +68 -0
  14. package/dist/cjs/index.js +86 -0
  15. package/dist/cjs/inflate.d.ts +9 -0
  16. package/dist/cjs/inflate.js +353 -0
  17. package/dist/cjs/node.d.ts +64 -0
  18. package/dist/cjs/node.js +82 -0
  19. package/dist/cjs/options.d.ts +95 -0
  20. package/dist/cjs/options.js +128 -0
  21. package/dist/cjs/package.json +3 -0
  22. package/dist/cjs/platform-node.d.ts +3 -0
  23. package/dist/cjs/platform-node.js +132 -0
  24. package/dist/cjs/platform-portable.d.ts +7 -0
  25. package/dist/cjs/platform-portable.js +16 -0
  26. package/dist/cjs/sha256.d.ts +5 -0
  27. package/dist/cjs/sha256.js +141 -0
  28. package/dist/cjs/utf8.d.ts +19 -0
  29. package/dist/cjs/utf8.js +107 -0
  30. package/dist/cjs/values.d.ts +58 -0
  31. package/dist/cjs/values.js +129 -0
  32. package/dist/cjs/web.d.ts +25 -0
  33. package/dist/cjs/web.js +151 -0
  34. package/dist/esm/constants.d.ts +34 -0
  35. package/dist/esm/constants.js +29 -0
  36. package/dist/esm/core.d.ts +15 -0
  37. package/dist/esm/core.js +269 -0
  38. package/dist/esm/decode.d.ts +10 -0
  39. package/dist/esm/decode.js +549 -0
  40. package/dist/esm/encode.d.ts +2 -0
  41. package/dist/esm/encode.js +943 -0
  42. package/dist/esm/errors.d.ts +53 -0
  43. package/dist/esm/errors.js +39 -0
  44. package/dist/esm/index.d.ts +68 -0
  45. package/dist/esm/index.js +74 -0
  46. package/dist/esm/inflate.d.ts +9 -0
  47. package/dist/esm/inflate.js +349 -0
  48. package/dist/esm/node.d.ts +64 -0
  49. package/dist/esm/node.js +70 -0
  50. package/dist/esm/options.d.ts +95 -0
  51. package/dist/esm/options.js +124 -0
  52. package/dist/esm/platform-node.d.ts +3 -0
  53. package/dist/esm/platform-node.js +96 -0
  54. package/dist/esm/platform-portable.d.ts +7 -0
  55. package/dist/esm/platform-portable.js +13 -0
  56. package/dist/esm/sha256.d.ts +5 -0
  57. package/dist/esm/sha256.js +136 -0
  58. package/dist/esm/utf8.d.ts +19 -0
  59. package/dist/esm/utf8.js +99 -0
  60. package/dist/esm/values.d.ts +58 -0
  61. package/dist/esm/values.js +120 -0
  62. package/dist/esm/web.d.ts +25 -0
  63. package/dist/esm/web.js +143 -0
  64. package/package.json +85 -4
@@ -0,0 +1,554 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.plainBytes = plainBytes;
4
+ exports.decodeDocument = decodeDocument;
5
+ exports.validateBtoonExt = validateBtoonExt;
6
+ // Hardened BTOON decoder (SPEC §7). Invariants:
7
+ // * every read is bounds-checked against `end` (no reads past the input);
8
+ // * containers are depth-limited (max_depth) — no unbounded recursion;
9
+ // * nothing is allocated beyond what the remaining input could encode.
10
+ const constants_js_1 = require("./constants.js");
11
+ const errors_js_1 = require("./errors.js");
12
+ const utf8_js_1 = require("./utf8.js");
13
+ const values_js_1 = require("./values.js");
14
+ const TWO_32 = 4294967296;
15
+ const LITTLE_ENDIAN = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1;
16
+ const MAX_DATE_SECONDS = constants_js_1.MAX_DATE_MS / 1000;
17
+ const hasOwn = Object.prototype.hasOwnProperty;
18
+ const fromCharCode = String.fromCharCode;
19
+ // Map keys repeat across records, so short ASCII keys are cached. A hit is verified
20
+ // byte-for-byte, so a collision only costs a miss; the cached strings are already
21
+ // internalized, which also makes the property stores cheaper.
22
+ const KEY_CACHE_SIZE = 4096;
23
+ const KEY_CACHE_MAX_LEN = 16;
24
+ const keyCache = new Array(KEY_CACHE_SIZE).fill(undefined);
25
+ const HEX = [];
26
+ for (let i = 0; i < 256; i++)
27
+ HEX.push((i < 16 ? '0' : '') + i.toString(16));
28
+ /** Sets `obj[key] = value` as an own data property; `__proto__` never touches the prototype. */
29
+ function setProperty(obj, key, value) {
30
+ if (key === '__proto__') {
31
+ Object.defineProperty(obj, key, { value, writable: true, enumerable: true, configurable: true });
32
+ }
33
+ else {
34
+ obj[key] = value;
35
+ }
36
+ }
37
+ function floorDiv(a, b) {
38
+ let q = a / b;
39
+ let r = a % b;
40
+ if (r < 0n) {
41
+ r += b;
42
+ q -= 1n;
43
+ }
44
+ return [q, r];
45
+ }
46
+ /** A plain Uint8Array view of the same bytes (Buffer.prototype.slice does not copy). */
47
+ function plainBytes(b) {
48
+ return Object.getPrototypeOf(b) === Uint8Array.prototype ? b : new Uint8Array(b.buffer, b.byteOffset, b.byteLength);
49
+ }
50
+ class Decoder {
51
+ constructor(bytes, strict, maxDepth, tsObjects, bigAlways) {
52
+ this.pos = 0;
53
+ this.bytes = plainBytes(bytes);
54
+ this.view = new DataView(this.bytes.buffer, this.bytes.byteOffset, this.bytes.byteLength);
55
+ this.end = this.bytes.length;
56
+ this.strict = strict;
57
+ this.maxDepth = maxDepth;
58
+ this.tsObjects = tsObjects;
59
+ this.bigAlways = bigAlways;
60
+ }
61
+ err(code, message, at = this.pos) {
62
+ return (0, errors_js_1.fail)(code, `${message} (at byte ${at})`);
63
+ }
64
+ need(n) {
65
+ if (this.end - this.pos < n)
66
+ throw this.err('truncated', 'unexpected end of input');
67
+ }
68
+ u8() {
69
+ this.need(1);
70
+ return this.bytes[this.pos++];
71
+ }
72
+ u16() {
73
+ this.need(2);
74
+ const v = this.view.getUint16(this.pos);
75
+ this.pos += 2;
76
+ return v;
77
+ }
78
+ u32() {
79
+ this.need(4);
80
+ const v = this.view.getUint32(this.pos);
81
+ this.pos += 4;
82
+ return v;
83
+ }
84
+ value(depth) {
85
+ if (this.pos >= this.end)
86
+ throw this.err('truncated', 'unexpected end of input');
87
+ const m = this.bytes[this.pos++];
88
+ if (m < 0x80)
89
+ return m;
90
+ if (m >= 0xe0)
91
+ return m - 0x100;
92
+ if (m < 0x90)
93
+ return this.map(m & 0x0f, depth);
94
+ if (m < 0xa0)
95
+ return this.array(m & 0x0f, depth);
96
+ if (m < 0xc0)
97
+ return this.str(m & 0x1f);
98
+ const view = this.view;
99
+ let v;
100
+ switch (m) {
101
+ case 0xc0:
102
+ return null;
103
+ case 0xc2:
104
+ return false;
105
+ case 0xc3:
106
+ return true;
107
+ case 0xc4:
108
+ return this.bin(this.u8());
109
+ case 0xc5:
110
+ return this.bin(this.u16());
111
+ case 0xc6:
112
+ return this.bin(this.u32());
113
+ case 0xc7:
114
+ return this.ext(this.u8(), depth);
115
+ case 0xc8:
116
+ return this.ext(this.u16(), depth);
117
+ case 0xc9:
118
+ return this.ext(this.u32(), depth);
119
+ case 0xca:
120
+ this.need(4);
121
+ v = view.getFloat32(this.pos);
122
+ this.pos += 4;
123
+ return v;
124
+ case 0xcb:
125
+ this.need(8);
126
+ v = view.getFloat64(this.pos);
127
+ this.pos += 8;
128
+ return v;
129
+ case 0xcc:
130
+ return this.u8();
131
+ case 0xcd:
132
+ return this.u16();
133
+ case 0xce:
134
+ return this.u32();
135
+ case 0xcf:
136
+ return this.uint64();
137
+ case 0xd0:
138
+ this.need(1);
139
+ return view.getInt8(this.pos++);
140
+ case 0xd1:
141
+ this.need(2);
142
+ v = view.getInt16(this.pos);
143
+ this.pos += 2;
144
+ return v;
145
+ case 0xd2:
146
+ this.need(4);
147
+ v = view.getInt32(this.pos);
148
+ this.pos += 4;
149
+ return v;
150
+ case 0xd3:
151
+ return this.int64();
152
+ case 0xd4:
153
+ return this.ext(1, depth);
154
+ case 0xd5:
155
+ return this.ext(2, depth);
156
+ case 0xd6:
157
+ return this.ext(4, depth);
158
+ case 0xd7:
159
+ return this.ext(8, depth);
160
+ case 0xd8:
161
+ return this.ext(16, depth);
162
+ case 0xd9:
163
+ return this.str(this.u8());
164
+ case 0xda:
165
+ return this.str(this.u16());
166
+ case 0xdb:
167
+ return this.str(this.u32());
168
+ case 0xdc:
169
+ return this.array(this.u16(), depth);
170
+ case 0xdd:
171
+ return this.array(this.u32(), depth);
172
+ case 0xde:
173
+ return this.map(this.u16(), depth);
174
+ case 0xdf:
175
+ return this.map(this.u32(), depth);
176
+ default: // 0xc1
177
+ throw this.err('invalid_marker', 'reserved marker 0xc1', this.pos - 1);
178
+ }
179
+ }
180
+ uint64() {
181
+ this.need(8);
182
+ const p = this.pos;
183
+ this.pos += 8;
184
+ const hi = this.view.getUint32(p);
185
+ if (!this.bigAlways && hi < 0x200000)
186
+ return hi * TWO_32 + this.view.getUint32(p + 4);
187
+ return this.view.getBigUint64(p);
188
+ }
189
+ int64() {
190
+ this.need(8);
191
+ const p = this.pos;
192
+ this.pos += 8;
193
+ if (!this.bigAlways) {
194
+ // Exact whenever the result is a safe integer; never safe-looking when it isn't.
195
+ const v = this.view.getInt32(p) * TWO_32 + this.view.getUint32(p + 4);
196
+ if (Number.isSafeInteger(v))
197
+ return v;
198
+ }
199
+ return this.view.getBigInt64(p);
200
+ }
201
+ str(len) {
202
+ if (len > this.end - this.pos)
203
+ throw this.err('truncated', 'string runs past the end of input');
204
+ const s = (0, utf8_js_1.decodeUtf8)(this.bytes, this.pos, len, this.strict);
205
+ if (s === undefined)
206
+ throw this.err('invalid_utf8', 'string is not valid UTF-8');
207
+ this.pos += len;
208
+ return s;
209
+ }
210
+ bin(len) {
211
+ if (len > this.end - this.pos)
212
+ throw this.err('truncated', 'binary runs past the end of input');
213
+ const b = this.bytes.slice(this.pos, this.pos + len);
214
+ this.pos += len;
215
+ return b;
216
+ }
217
+ array(n, depth) {
218
+ if (depth >= this.maxDepth)
219
+ throw this.err('max_depth', 'maximum nesting depth exceeded');
220
+ // Every element takes at least one byte.
221
+ if (n > this.end - this.pos)
222
+ throw this.err('truncated', 'array length exceeds the remaining input');
223
+ const a = new Array(n);
224
+ for (let i = 0; i < n; i++)
225
+ a[i] = this.value(depth + 1);
226
+ return a;
227
+ }
228
+ key() {
229
+ if (this.pos >= this.end)
230
+ throw this.err('truncated', 'unexpected end of input');
231
+ const m = this.bytes[this.pos];
232
+ let len;
233
+ if (m >= 0xa0 && m <= 0xbf) {
234
+ this.pos++;
235
+ len = m & 0x1f;
236
+ }
237
+ else if (m === 0xd9) {
238
+ this.pos++;
239
+ len = this.u8();
240
+ }
241
+ else if (m === 0xda) {
242
+ this.pos++;
243
+ len = this.u16();
244
+ }
245
+ else if (m === 0xdb) {
246
+ this.pos++;
247
+ len = this.u32();
248
+ }
249
+ else {
250
+ throw this.err('non_string_key', 'map key is not a string');
251
+ }
252
+ if (len <= KEY_CACHE_MAX_LEN && len <= this.end - this.pos) {
253
+ const bytes = this.bytes;
254
+ const p = this.pos;
255
+ let h = len;
256
+ let high = 0;
257
+ for (let i = p; i < p + len; i++) {
258
+ const b = bytes[i];
259
+ h = (Math.imul(h, 31) + b) | 0;
260
+ high |= b;
261
+ }
262
+ if (high < 0x80) {
263
+ const slot = h & (KEY_CACHE_SIZE - 1);
264
+ let s = keyCache[slot];
265
+ if (s !== undefined && s.length === len) {
266
+ let i = 0;
267
+ while (i < len && s.charCodeAt(i) === bytes[p + i])
268
+ i++;
269
+ if (i === len) {
270
+ this.pos = p + len;
271
+ return s;
272
+ }
273
+ }
274
+ s = len === 0 ? '' : fromCharCode.apply(null, bytes.subarray(p, p + len));
275
+ keyCache[slot] = s;
276
+ this.pos = p + len;
277
+ return s;
278
+ }
279
+ }
280
+ return this.str(len);
281
+ }
282
+ map(n, depth) {
283
+ if (depth >= this.maxDepth)
284
+ throw this.err('max_depth', 'maximum nesting depth exceeded');
285
+ // Every entry takes at least two bytes.
286
+ if (n > (this.end - this.pos) / 2)
287
+ throw this.err('truncated', 'map length exceeds the remaining input');
288
+ const obj = {};
289
+ // While keys arrive strictly increasing (as in canonical input) none can repeat; after
290
+ // the first out-of-order key every key is checked against the object.
291
+ let prev = '';
292
+ let ordered = true;
293
+ for (let i = 0; i < n; i++) {
294
+ const k = this.key();
295
+ const v = this.value(depth + 1);
296
+ if (ordered && (i === 0 || prev < k)) {
297
+ prev = k;
298
+ }
299
+ else {
300
+ ordered = false;
301
+ // Decoded values are never undefined, so this skips hasOwn for fresh keys.
302
+ if (obj[k] !== undefined && hasOwn.call(obj, k) && this.strict) {
303
+ throw this.err('duplicate_key', `duplicate map key ${JSON.stringify(k)}`);
304
+ }
305
+ }
306
+ setProperty(obj, k, v);
307
+ }
308
+ return obj;
309
+ }
310
+ ext(len, depth) {
311
+ this.need(1);
312
+ const type = this.view.getInt8(this.pos++);
313
+ if (len > this.end - this.pos)
314
+ throw this.err('truncated', 'extension payload runs past the end of input');
315
+ const start = this.pos;
316
+ this.pos = start + len;
317
+ return this.extValue(type, start, len, depth);
318
+ }
319
+ /** Interprets the payload `bytes[start, start+len)` of an extension of `type`. */
320
+ extValue(type, start, len, depth) {
321
+ const view = this.view;
322
+ const bad = (what) => this.err('invalid_extension', what, start);
323
+ switch (type) {
324
+ case constants_js_1.EXT_TIMESTAMP: {
325
+ let sec;
326
+ let ns;
327
+ let off;
328
+ switch (len) {
329
+ case 4:
330
+ sec = view.getUint32(start);
331
+ ns = 0;
332
+ break;
333
+ case 8: {
334
+ const hi = view.getUint32(start);
335
+ ns = hi >>> 2;
336
+ sec = (hi & 3) * TWO_32 + view.getUint32(start + 4);
337
+ break;
338
+ }
339
+ case 12:
340
+ case 14:
341
+ ns = view.getUint32(start);
342
+ sec = view.getBigInt64(start + 4);
343
+ if (len === 14) {
344
+ off = view.getInt16(start + 12);
345
+ if (off < -constants_js_1.MAX_OFFSET_MINUTES || off > constants_js_1.MAX_OFFSET_MINUTES)
346
+ throw bad('timestamp offset out of range');
347
+ }
348
+ break;
349
+ default:
350
+ throw bad('invalid timestamp length');
351
+ }
352
+ if (ns >= constants_js_1.NANOS_PER_SECOND)
353
+ throw bad('timestamp nanoseconds out of range');
354
+ return this.instant(sec, ns, off);
355
+ }
356
+ case constants_js_1.EXT_DATE: {
357
+ if (len !== 8)
358
+ throw bad('invalid date length');
359
+ const ms = view.getBigInt64(start);
360
+ if (!this.tsObjects && ms <= BigInt(constants_js_1.MAX_DATE_MS) && ms >= -BigInt(constants_js_1.MAX_DATE_MS))
361
+ return new Date(Number(ms));
362
+ const [s, r] = floorDiv(ms, 1000n);
363
+ return new values_js_1.Timestamp(s, Number(r) * 1e6);
364
+ }
365
+ case constants_js_1.EXT_DATETIME: {
366
+ if (len !== 8)
367
+ throw bad('invalid datetime length');
368
+ const ns = view.getBigInt64(start);
369
+ if (!this.tsObjects)
370
+ return new Date(Number(floorDiv(ns, 1000000n)[0]));
371
+ const [s, r] = floorDiv(ns, 1000000000n);
372
+ return new values_js_1.Timestamp(s, Number(r));
373
+ }
374
+ case constants_js_1.EXT_BIGINT:
375
+ if (len === 0)
376
+ throw bad('empty bigint');
377
+ return this.bigint(start, len);
378
+ case constants_js_1.EXT_F32_VECTOR:
379
+ case constants_js_1.EXT_F64_VECTOR: {
380
+ const size = type === constants_js_1.EXT_F32_VECTOR ? 4 : 8;
381
+ if (len % size !== 0)
382
+ throw bad(`float${size * 8} vector length is not a multiple of ${size}`);
383
+ // Always a fresh, aligned copy: never a view into the input.
384
+ const out = type === constants_js_1.EXT_F32_VECTOR ? new Float32Array(len / 4) : new Float64Array(len / 8);
385
+ const raw = new Uint8Array(out.buffer);
386
+ raw.set(this.bytes.subarray(start, start + len));
387
+ if (!LITTLE_ENDIAN) {
388
+ for (let i = 0; i < len; i += size)
389
+ raw.subarray(i, i + size).reverse();
390
+ }
391
+ return out;
392
+ }
393
+ case constants_js_1.EXT_TABULAR:
394
+ return this.tabular(start, len, depth);
395
+ default:
396
+ return new values_js_1.Ext(type, this.bytes.slice(start, start + len));
397
+ }
398
+ }
399
+ /** A timestamp as a Date (default) or a Timestamp (`timestamps: 'object'`, or out of Date range). */
400
+ instant(sec, ns, off) {
401
+ if (!this.tsObjects) {
402
+ const s = typeof sec === 'number' ? sec : sec <= BigInt(MAX_DATE_SECONDS) && sec >= -BigInt(MAX_DATE_SECONDS) ? Number(sec) : NaN;
403
+ const ms = s * 1000 + Math.floor(ns / 1e6);
404
+ if (ms <= constants_js_1.MAX_DATE_MS && ms >= -constants_js_1.MAX_DATE_MS)
405
+ return new Date(ms);
406
+ }
407
+ return new values_js_1.Timestamp(sec, ns, off);
408
+ }
409
+ bigint(start, len) {
410
+ const bytes = this.bytes;
411
+ let v;
412
+ try {
413
+ let hex = '';
414
+ if (len <= 64) {
415
+ for (let i = start; i < start + len; i++)
416
+ hex += HEX[bytes[i]];
417
+ }
418
+ else {
419
+ const parts = new Array(len);
420
+ for (let i = 0; i < len; i++)
421
+ parts[i] = HEX[bytes[start + i]];
422
+ hex = parts.join('');
423
+ }
424
+ v = BigInt('0x' + hex);
425
+ if (bytes[start] >= 0x80)
426
+ v -= 1n << BigInt(len * 8);
427
+ }
428
+ catch (e) {
429
+ throw (0, errors_js_1.fail)('size_limit', `bigint too large for this JavaScript engine (at byte ${start})`, e);
430
+ }
431
+ if (!this.bigAlways && v >= -0x1fffffffffffffn && v <= 0x1fffffffffffffn)
432
+ return Number(v);
433
+ return v;
434
+ }
435
+ tabular(start, len, depth) {
436
+ if (depth + 1 >= this.maxDepth)
437
+ throw this.err('max_depth', 'maximum nesting depth exceeded', start);
438
+ const view = this.view;
439
+ const end = start + len;
440
+ let p = start;
441
+ const bad = (what) => this.err('invalid_tabular', what, p);
442
+ if (end - p < 12)
443
+ throw bad('tabular payload truncated');
444
+ const version = view.getUint32(p);
445
+ const cols = view.getUint32(p + 4);
446
+ const rowCount = view.getUint32(p + 8);
447
+ p += 12;
448
+ if (version !== constants_js_1.TABULAR_VERSION)
449
+ throw bad(`unsupported tabular version ${version}`);
450
+ if (cols === 0 && rowCount > 0)
451
+ throw bad('tabular rows without columns');
452
+ // Each column needs at least 9 bytes: name length, type code, column length.
453
+ if (cols > (end - p) / 9)
454
+ throw bad('tabular column count exceeds the payload');
455
+ const names = new Array(cols);
456
+ for (let c = 0; c < cols; c++) {
457
+ if (end - p < 4)
458
+ throw bad('tabular payload truncated');
459
+ const n = view.getUint32(p);
460
+ p += 4;
461
+ if (n > end - p)
462
+ throw bad('tabular column name runs past the payload');
463
+ const name = (0, utf8_js_1.decodeUtf8)(this.bytes, p, n, this.strict);
464
+ if (name === undefined)
465
+ throw this.err('invalid_utf8', 'column name is not valid UTF-8', p);
466
+ names[c] = name;
467
+ p += n;
468
+ }
469
+ if (new Set(names).size !== cols)
470
+ throw bad('duplicate tabular column name');
471
+ if (cols > end - p)
472
+ throw bad('tabular payload truncated');
473
+ p += cols; // type codes are informational (SPEC §5.6.1)
474
+ // Every cell is at least one byte.
475
+ if (rowCount * cols > end - p)
476
+ throw bad('tabular row count exceeds the payload');
477
+ const rows = new Array(rowCount);
478
+ for (let r = 0; r < rowCount; r++)
479
+ rows[r] = {};
480
+ const savedEnd = this.end;
481
+ for (let c = 0; c < cols; c++) {
482
+ if (end - p < 4)
483
+ throw bad('tabular payload truncated');
484
+ const colLen = view.getUint32(p);
485
+ p += 4;
486
+ if (colLen > end - p)
487
+ throw bad('tabular column runs past the payload');
488
+ const colEnd = p + colLen;
489
+ const name = names[c];
490
+ this.pos = p;
491
+ this.end = colEnd;
492
+ try {
493
+ if (name === '__proto__') {
494
+ for (let r = 0; r < rowCount; r++)
495
+ setProperty(rows[r], name, this.value(depth + 2));
496
+ }
497
+ else {
498
+ for (let r = 0; r < rowCount; r++)
499
+ rows[r][name] = this.value(depth + 2);
500
+ }
501
+ }
502
+ catch (e) {
503
+ if (e instanceof errors_js_1.BtoonError && e.code === 'truncated') {
504
+ throw (0, errors_js_1.fail)('invalid_tabular', `tabular column holds fewer values than rows (at byte ${this.pos})`, e);
505
+ }
506
+ throw e;
507
+ }
508
+ if (this.pos !== colEnd)
509
+ throw this.err('invalid_tabular', 'tabular column length mismatch');
510
+ p = colEnd;
511
+ }
512
+ this.end = savedEnd;
513
+ if (p !== end)
514
+ throw bad('trailing bytes in tabular payload');
515
+ this.pos = end;
516
+ return rows;
517
+ }
518
+ }
519
+ /** Decodes one bare BTOON document (no envelopes). */
520
+ function decodeDocument(bytes, cfg) {
521
+ const d = new Decoder(bytes, cfg.strict, cfg.maxDepth, cfg.timestampObjects, cfg.bigintAlways);
522
+ let v;
523
+ try {
524
+ v = d.value(0);
525
+ }
526
+ catch (e) {
527
+ if ((0, errors_js_1.isStackOverflow)(e))
528
+ throw (0, errors_js_1.fail)('max_depth', 'input nests too deeply for the JavaScript call stack', e);
529
+ throw e;
530
+ }
531
+ if (d.pos !== d.end && cfg.strict)
532
+ throw d.err('trailing_data', 'trailing bytes after the top-level value');
533
+ return v;
534
+ }
535
+ /**
536
+ * Used by the encoder: an `Ext` that carries a BTOON-defined id must hold a payload a
537
+ * strict decoder accepts, so the encoder never emits a document decoders reject.
538
+ */
539
+ function validateBtoonExt(type, data, depth, maxDepth = constants_js_1.DEFAULT_MAX_DEPTH) {
540
+ if (!((type <= constants_js_1.EXT_TIMESTAMP && type >= constants_js_1.EXT_F64_VECTOR) || type === constants_js_1.EXT_TABULAR))
541
+ return;
542
+ const d = new Decoder(data, true, maxDepth, true, true);
543
+ try {
544
+ d.extValue(type, 0, d.end, depth);
545
+ }
546
+ catch (e) {
547
+ if (e instanceof errors_js_1.BtoonError) {
548
+ throw (0, errors_js_1.fail)('invalid_argument', `Ext(${type}) does not hold a valid payload for that BTOON type: ${e.message}`, e);
549
+ }
550
+ if ((0, errors_js_1.isStackOverflow)(e))
551
+ throw (0, errors_js_1.fail)('max_depth', 'Ext payload nests too deeply', e);
552
+ throw e;
553
+ }
554
+ }
@@ -0,0 +1,2 @@
1
+ /** Canonical encoding of `value` (no envelopes). */
2
+ export declare function encodeDocument(value: unknown, maxDepth: number, autoTabular: boolean): Uint8Array<ArrayBuffer>;