@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,946 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.encodeDocument = encodeDocument;
4
+ // Canonical BTOON encoder (SPEC §4–§5). Everything is appended to one growable buffer;
5
+ // tabular payloads and column lengths are back-patched.
6
+ const constants_js_1 = require("./constants.js");
7
+ const decode_js_1 = require("./decode.js");
8
+ const errors_js_1 = require("./errors.js");
9
+ const utf8_js_1 = require("./utf8.js");
10
+ const values_js_1 = require("./values.js");
11
+ const TWO_32 = 4294967296;
12
+ const TWO_34 = 17179869184;
13
+ const UINT64_MAX = (1n << 64n) - 1n;
14
+ const INT64_MIN = -(1n << 63n);
15
+ const INT63 = 1n << 63n;
16
+ const LITTLE_ENDIAN = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1;
17
+ // Object kinds, in the order the encoder tests for them.
18
+ const K_ARRAY = 1;
19
+ const K_PLAIN = 2;
20
+ const K_VIEW = 3;
21
+ const K_BUFFER = 4;
22
+ const K_DATE = 5;
23
+ const K_MAP = 6;
24
+ const K_TIMESTAMP = 7;
25
+ const K_EXT = 8;
26
+ const K_TOJSON = 9;
27
+ /** A Number, String, Boolean or BigInt wrapper object (unwrapped, as JSON.stringify does). */
28
+ const K_BOXED = 10;
29
+ /** Any other object: encoded like JSON.stringify, as a map of its own enumerable string keys. */
30
+ const K_OBJECT = 11;
31
+ const objectToString = Object.prototype.toString;
32
+ const NOT_BOXED = Symbol('not boxed');
33
+ const BOXES = new Map([
34
+ ['[object Number]', Number.prototype],
35
+ ['[object String]', String.prototype],
36
+ ['[object Boolean]', Boolean.prototype],
37
+ ['[object BigInt]', BigInt.prototype],
38
+ ]);
39
+ /** The primitive inside a wrapper object, checked by internal slot (a spoofed tag fails). */
40
+ function unbox(o, tag = objectToString.call(o)) {
41
+ const proto = BOXES.get(tag);
42
+ if (proto === undefined)
43
+ return NOT_BOXED;
44
+ try {
45
+ return proto.valueOf.call(o);
46
+ }
47
+ catch {
48
+ return NOT_BOXED;
49
+ }
50
+ }
51
+ function classify(o) {
52
+ if (Array.isArray(o))
53
+ return K_ARRAY;
54
+ const proto = Object.getPrototypeOf(o);
55
+ if (proto === Object.prototype || proto === null)
56
+ return K_PLAIN;
57
+ if (ArrayBuffer.isView(o))
58
+ return K_VIEW;
59
+ if (o instanceof Date)
60
+ return K_DATE;
61
+ if (o instanceof Map)
62
+ return K_MAP;
63
+ if ((0, values_js_1.isTimestamp)(o))
64
+ return K_TIMESTAMP;
65
+ if ((0, values_js_1.isExt)(o))
66
+ return K_EXT;
67
+ const tag = objectToString.call(o);
68
+ if (tag === '[object ArrayBuffer]' || tag === '[object SharedArrayBuffer]')
69
+ return K_BUFFER;
70
+ if (tag === '[object Date]')
71
+ return K_DATE; // from another realm
72
+ if (tag === '[object Map]')
73
+ return K_MAP; // from another realm
74
+ if (typeof o.toJSON === 'function')
75
+ return K_TOJSON;
76
+ if (unbox(o, tag) !== NOT_BOXED)
77
+ return K_BOXED;
78
+ return K_OBJECT; // class instances, and plain objects from another realm
79
+ }
80
+ function maxDepthError() {
81
+ return (0, errors_js_1.fail)('max_depth', 'maximum nesting depth exceeded (or the value is cyclic)');
82
+ }
83
+ /** Keys of a value that encodes as a map, or null. Non-string Map keys → null. */
84
+ function mapKeys(v, kind) {
85
+ if (kind === K_PLAIN || kind === K_OBJECT)
86
+ return Object.keys(v);
87
+ if (kind === K_MAP) {
88
+ const keys = [];
89
+ for (const k of Map.prototype.keys.call(v)) {
90
+ if (typeof k !== 'string')
91
+ return null;
92
+ keys.push(k);
93
+ }
94
+ return keys;
95
+ }
96
+ return null;
97
+ }
98
+ function kindOf(v) {
99
+ return typeof v === 'object' && v !== null ? classify(v) : 0;
100
+ }
101
+ function callToJSON(o) {
102
+ return o.toJSON();
103
+ }
104
+ function cell(row, kind, key) {
105
+ return kind === K_MAP ? Map.prototype.get.call(row, key) : row[key];
106
+ }
107
+ /** SPEC §5.6.1 type code of a (resolved) value: the logical type of the first row's cell. */
108
+ function typeCode(v) {
109
+ switch (typeof v) {
110
+ case 'undefined':
111
+ return 0;
112
+ case 'boolean':
113
+ return 1;
114
+ case 'number':
115
+ return Number.isSafeInteger(v) && (v !== 0 || 1 / v > 0) ? 2 : 4;
116
+ case 'bigint':
117
+ if (v >= INT64_MIN && v < INT63)
118
+ return 2;
119
+ if (v >= INT63 && v <= UINT64_MAX)
120
+ return 3;
121
+ return 9;
122
+ case 'string':
123
+ return 5;
124
+ case 'object': {
125
+ if (v === null)
126
+ return 0;
127
+ switch (classify(v)) {
128
+ case K_ARRAY:
129
+ return 7;
130
+ case K_PLAIN:
131
+ case K_MAP:
132
+ case K_OBJECT:
133
+ case K_TOJSON: // a toJSON() result that has toJSON() itself: encoded by its own properties
134
+ return 8;
135
+ case K_BOXED:
136
+ return typeCode(unbox(v));
137
+ case K_EXT:
138
+ // A raw tabular extension is logically an array (its encoding starts like one).
139
+ return v.type === constants_js_1.EXT_TABULAR ? 7 : 9;
140
+ case K_BUFFER:
141
+ return 6;
142
+ case K_VIEW: {
143
+ const tag = v[Symbol.toStringTag];
144
+ return tag === 'Float32Array' || tag === 'Float64Array' ? 9 : 6;
145
+ }
146
+ default:
147
+ return 9;
148
+ }
149
+ }
150
+ default:
151
+ return 9;
152
+ }
153
+ }
154
+ /** Minimal two's-complement big-endian bytes (SPEC §5.4). */
155
+ function bigintBytes(v) {
156
+ let hex;
157
+ if (v >= 0n) {
158
+ hex = v.toString(16);
159
+ if (hex.length & 1)
160
+ hex = '0' + hex;
161
+ if (parseInt(hex.slice(0, 2), 16) >= 0x80)
162
+ hex = '00' + hex;
163
+ }
164
+ else {
165
+ const bytes = ((-v).toString(16).length >> 1) + 2;
166
+ hex = ((1n << BigInt(bytes * 8)) + v).toString(16);
167
+ if (hex.length & 1)
168
+ hex = '0' + hex;
169
+ while (hex.length > 2 && hex.charCodeAt(0) === 0x66 && hex.charCodeAt(1) === 0x66 && parseInt(hex[2], 16) >= 8) {
170
+ hex = hex.slice(2);
171
+ }
172
+ }
173
+ const out = new Uint8Array(hex.length >> 1);
174
+ for (let i = 0; i < out.length; i++)
175
+ out[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
176
+ return out;
177
+ }
178
+ class Encoder {
179
+ constructor(buf, maxDepth, autoTabular) {
180
+ this.pos = 0;
181
+ // Out-parameters of planTabular() when it declines.
182
+ this.items = [];
183
+ this.resolvedUpTo = 0;
184
+ this.buf = buf;
185
+ this.view = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
186
+ this.maxDepth = maxDepth;
187
+ this.autoTabular = autoTabular;
188
+ }
189
+ // --- buffer --------------------------------------------------------------------
190
+ ensure(n) {
191
+ if (this.pos + n > this.buf.length)
192
+ this.grow(n);
193
+ }
194
+ grow(n) {
195
+ const need = this.pos + n;
196
+ let cap = this.buf.length * 2;
197
+ if (cap < need)
198
+ cap = need;
199
+ const next = new Uint8Array(cap);
200
+ next.set(this.buf.subarray(0, this.pos));
201
+ this.buf = next;
202
+ this.view = new DataView(next.buffer);
203
+ }
204
+ u8(b) {
205
+ this.ensure(1);
206
+ this.buf[this.pos++] = b;
207
+ }
208
+ bytes(b) {
209
+ this.ensure(b.length);
210
+ this.buf.set(b, this.pos);
211
+ this.pos += b.length;
212
+ }
213
+ // --- dispatch ------------------------------------------------------------------
214
+ value(v, depth) {
215
+ this.any(v, depth, true);
216
+ }
217
+ /** Encodes a value that already went through toJSON(): no second toJSON() call. */
218
+ resolved(v, depth) {
219
+ this.any(v, depth, false);
220
+ }
221
+ any(v, depth, allowToJSON) {
222
+ switch (typeof v) {
223
+ case 'string':
224
+ this.string(v);
225
+ return;
226
+ case 'number':
227
+ this.number(v);
228
+ return;
229
+ case 'boolean':
230
+ this.u8(v ? 0xc3 : 0xc2);
231
+ return;
232
+ case 'object':
233
+ if (v === null)
234
+ this.u8(0xc0);
235
+ else
236
+ this.object(v, classify(v), depth, allowToJSON);
237
+ return;
238
+ case 'undefined':
239
+ this.u8(0xc0);
240
+ return;
241
+ case 'bigint':
242
+ this.bigint(v);
243
+ return;
244
+ default:
245
+ throw (0, errors_js_1.fail)('invalid_argument', `cannot encode a ${typeof v}`);
246
+ }
247
+ }
248
+ object(o, kind, depth, allowToJSON) {
249
+ switch (kind) {
250
+ case K_ARRAY:
251
+ this.array(o, depth);
252
+ return;
253
+ case K_PLAIN:
254
+ this.plainMap(o, depth);
255
+ return;
256
+ case K_VIEW:
257
+ this.arrayBufferView(o);
258
+ return;
259
+ case K_BUFFER:
260
+ this.binary(new Uint8Array(o));
261
+ return;
262
+ case K_DATE:
263
+ this.timestampMs((0, values_js_1.dateTime)(o));
264
+ return;
265
+ case K_MAP:
266
+ this.mapObject(o, depth);
267
+ return;
268
+ case K_TIMESTAMP:
269
+ this.timestamp(o);
270
+ return;
271
+ case K_EXT:
272
+ this.ext(o, depth);
273
+ return;
274
+ case K_TOJSON:
275
+ // Like JSON.stringify, toJSON() is called once per value: a result that has its own
276
+ // toJSON() is encoded by its own enumerable properties.
277
+ if (allowToJSON)
278
+ this.resolved(callToJSON(o), depth);
279
+ else
280
+ this.plainMap(o, depth);
281
+ return;
282
+ case K_BOXED:
283
+ this.any(unbox(o), depth, allowToJSON);
284
+ return;
285
+ default: // K_OBJECT
286
+ this.plainMap(o, depth);
287
+ }
288
+ }
289
+ // --- scalars -------------------------------------------------------------------
290
+ number(v) {
291
+ // -0 is kept as a float so that its sign survives (SPEC §2).
292
+ if (Number.isSafeInteger(v) && (v !== 0 || 1 / v > 0)) {
293
+ this.int(v);
294
+ return;
295
+ }
296
+ this.ensure(9);
297
+ const p = this.pos;
298
+ this.buf[p] = 0xcb;
299
+ if (v !== v) {
300
+ this.view.setUint32(p + 1, 0x7ff80000);
301
+ this.view.setUint32(p + 5, 0);
302
+ }
303
+ else {
304
+ this.view.setFloat64(p + 1, v);
305
+ }
306
+ this.pos = p + 9;
307
+ }
308
+ /** Smallest integer format for a safe integer (SPEC §4.1). */
309
+ int(v) {
310
+ this.ensure(9);
311
+ const buf = this.buf;
312
+ const p = this.pos;
313
+ if (v >= 0) {
314
+ if (v < 0x80) {
315
+ buf[p] = v;
316
+ this.pos = p + 1;
317
+ }
318
+ else if (v < 0x100) {
319
+ buf[p] = 0xcc;
320
+ buf[p + 1] = v;
321
+ this.pos = p + 2;
322
+ }
323
+ else if (v < 0x10000) {
324
+ buf[p] = 0xcd;
325
+ this.view.setUint16(p + 1, v);
326
+ this.pos = p + 3;
327
+ }
328
+ else if (v < TWO_32) {
329
+ buf[p] = 0xce;
330
+ this.view.setUint32(p + 1, v);
331
+ this.pos = p + 5;
332
+ }
333
+ else {
334
+ buf[p] = 0xcf;
335
+ this.view.setUint32(p + 1, Math.floor(v / TWO_32));
336
+ this.view.setUint32(p + 5, v >>> 0);
337
+ this.pos = p + 9;
338
+ }
339
+ }
340
+ else if (v >= -32) {
341
+ buf[p] = v & 0xff;
342
+ this.pos = p + 1;
343
+ }
344
+ else if (v >= -0x80) {
345
+ buf[p] = 0xd0;
346
+ buf[p + 1] = v & 0xff;
347
+ this.pos = p + 2;
348
+ }
349
+ else if (v >= -0x8000) {
350
+ buf[p] = 0xd1;
351
+ this.view.setInt16(p + 1, v);
352
+ this.pos = p + 3;
353
+ }
354
+ else if (v >= -0x80000000) {
355
+ buf[p] = 0xd2;
356
+ this.view.setInt32(p + 1, v);
357
+ this.pos = p + 5;
358
+ }
359
+ else {
360
+ buf[p] = 0xd3;
361
+ this.view.setInt32(p + 1, Math.floor(v / TWO_32));
362
+ this.view.setUint32(p + 5, v >>> 0);
363
+ this.pos = p + 9;
364
+ }
365
+ }
366
+ bigint(v) {
367
+ if (v >= -0x80000000n && v <= 0xffffffffn) {
368
+ this.int(Number(v));
369
+ return;
370
+ }
371
+ if (v >= 0n ? v <= UINT64_MAX : v >= INT64_MIN) {
372
+ this.ensure(9);
373
+ const p = this.pos;
374
+ if (v >= 0n) {
375
+ this.buf[p] = 0xcf;
376
+ this.view.setBigUint64(p + 1, v);
377
+ }
378
+ else {
379
+ this.buf[p] = 0xd3;
380
+ this.view.setBigInt64(p + 1, v);
381
+ }
382
+ this.pos = p + 9;
383
+ return;
384
+ }
385
+ const b = bigintBytes(v);
386
+ this.extHeader(constants_js_1.EXT_BIGINT, b.length);
387
+ this.bytes(b);
388
+ }
389
+ string(s) {
390
+ const len = s.length;
391
+ if (len < 32) {
392
+ // Short strings: optimistic ASCII pass straight into a fixstr.
393
+ this.ensure(2 + len * 3);
394
+ const buf = this.buf;
395
+ const start = this.pos;
396
+ let p = start + 1;
397
+ let i = 0;
398
+ for (; i < len; i++) {
399
+ const c = s.charCodeAt(i);
400
+ if (c >= 0x80)
401
+ break;
402
+ buf[p++] = c;
403
+ }
404
+ if (i === len) {
405
+ buf[start] = 0xa0 | len;
406
+ this.pos = p;
407
+ return;
408
+ }
409
+ const n = (0, utf8_js_1.utf8Length)(s);
410
+ if (n <= 31) {
411
+ buf[start] = 0xa0 | n;
412
+ this.pos = start + 1;
413
+ }
414
+ else {
415
+ buf[start] = 0xd9;
416
+ buf[start + 1] = n;
417
+ this.pos = start + 2;
418
+ }
419
+ this.utf8(s);
420
+ return;
421
+ }
422
+ if (!(0, utf8_js_1.isWellFormed)(s))
423
+ throw (0, utf8_js_1.loneSurrogateError)();
424
+ const max = len * 3;
425
+ const hdr = max <= 0xff ? 2 : max <= 0xffff ? 3 : 5;
426
+ this.ensure(hdr + max);
427
+ const start = this.pos;
428
+ const { written } = utf8_js_1.textEncoder.encodeInto(s, this.buf.subarray(start + hdr, start + hdr + max));
429
+ const n = written;
430
+ if (n > 0xffffffff)
431
+ throw (0, errors_js_1.fail)('size_limit', 'string longer than 2^32-1 bytes');
432
+ const need = n <= 31 ? 1 : n <= 0xff ? 2 : n <= 0xffff ? 3 : 5;
433
+ if (need !== hdr)
434
+ this.buf.copyWithin(start + need, start + hdr, start + hdr + n);
435
+ this.strHeaderAt(start, n, need);
436
+ this.pos = start + need + n;
437
+ }
438
+ strHeaderAt(p, n, size) {
439
+ const buf = this.buf;
440
+ if (size === 1) {
441
+ buf[p] = 0xa0 | n;
442
+ }
443
+ else if (size === 2) {
444
+ buf[p] = 0xd9;
445
+ buf[p + 1] = n;
446
+ }
447
+ else if (size === 3) {
448
+ buf[p] = 0xda;
449
+ this.view.setUint16(p + 1, n);
450
+ }
451
+ else {
452
+ buf[p] = 0xdb;
453
+ this.view.setUint32(p + 1, n);
454
+ }
455
+ }
456
+ /** Writes the UTF-8 bytes of a well-formed string; the caller reserved the space. */
457
+ utf8(s) {
458
+ const buf = this.buf;
459
+ let p = this.pos;
460
+ for (let i = 0; i < s.length; i++) {
461
+ let c = s.charCodeAt(i);
462
+ if (c < 0x80) {
463
+ buf[p++] = c;
464
+ }
465
+ else if (c < 0x800) {
466
+ buf[p++] = 0xc0 | (c >> 6);
467
+ buf[p++] = 0x80 | (c & 0x3f);
468
+ }
469
+ else if (c < 0xd800 || c > 0xdfff) {
470
+ buf[p++] = 0xe0 | (c >> 12);
471
+ buf[p++] = 0x80 | ((c >> 6) & 0x3f);
472
+ buf[p++] = 0x80 | (c & 0x3f);
473
+ }
474
+ else {
475
+ c = 0x10000 + ((c - 0xd800) << 10) + (s.charCodeAt(++i) - 0xdc00);
476
+ buf[p++] = 0xf0 | (c >> 18);
477
+ buf[p++] = 0x80 | ((c >> 12) & 0x3f);
478
+ buf[p++] = 0x80 | ((c >> 6) & 0x3f);
479
+ buf[p++] = 0x80 | (c & 0x3f);
480
+ }
481
+ }
482
+ this.pos = p;
483
+ }
484
+ /** Raw UTF-8 bytes of a string whose exact byte length `n` is known. */
485
+ utf8Exact(s, n) {
486
+ this.ensure(n);
487
+ if (n < 64) {
488
+ this.utf8(s);
489
+ }
490
+ else {
491
+ utf8_js_1.textEncoder.encodeInto(s, this.buf.subarray(this.pos, this.pos + n));
492
+ this.pos += n;
493
+ }
494
+ }
495
+ binary(b) {
496
+ const n = b.length;
497
+ this.ensure(5);
498
+ const p = this.pos;
499
+ if (n <= 0xff) {
500
+ this.buf[p] = 0xc4;
501
+ this.buf[p + 1] = n;
502
+ this.pos = p + 2;
503
+ }
504
+ else if (n <= 0xffff) {
505
+ this.buf[p] = 0xc5;
506
+ this.view.setUint16(p + 1, n);
507
+ this.pos = p + 3;
508
+ }
509
+ else if (n <= 0xffffffff) {
510
+ this.buf[p] = 0xc6;
511
+ this.view.setUint32(p + 1, n);
512
+ this.pos = p + 5;
513
+ }
514
+ else {
515
+ throw (0, errors_js_1.fail)('size_limit', 'binary longer than 2^32-1 bytes');
516
+ }
517
+ this.bytes(b);
518
+ }
519
+ arrayBufferView(v) {
520
+ const tag = v[Symbol.toStringTag];
521
+ const raw = new Uint8Array(v.buffer, v.byteOffset, v.byteLength);
522
+ if (tag === 'Float32Array' || tag === 'Float64Array') {
523
+ // SPEC §5.5: little-endian payload, NaN bits untouched.
524
+ const n = raw.length;
525
+ this.extHeader(tag === 'Float32Array' ? constants_js_1.EXT_F32_VECTOR : constants_js_1.EXT_F64_VECTOR, n);
526
+ this.ensure(n);
527
+ if (LITTLE_ENDIAN) {
528
+ this.buf.set(raw, this.pos);
529
+ }
530
+ else {
531
+ const size = tag === 'Float32Array' ? 4 : 8;
532
+ for (let i = 0; i < n; i += size) {
533
+ for (let b = 0; b < size; b++)
534
+ this.buf[this.pos + i + b] = raw[i + size - 1 - b];
535
+ }
536
+ }
537
+ this.pos += n;
538
+ return;
539
+ }
540
+ this.binary(raw);
541
+ }
542
+ extHeader(type, n) {
543
+ this.ensure(6);
544
+ const buf = this.buf;
545
+ const p = this.pos;
546
+ const t = type & 0xff;
547
+ let fixed = 0;
548
+ switch (n) {
549
+ case 1:
550
+ fixed = 0xd4;
551
+ break;
552
+ case 2:
553
+ fixed = 0xd5;
554
+ break;
555
+ case 4:
556
+ fixed = 0xd6;
557
+ break;
558
+ case 8:
559
+ fixed = 0xd7;
560
+ break;
561
+ case 16:
562
+ fixed = 0xd8;
563
+ break;
564
+ }
565
+ if (fixed !== 0) {
566
+ buf[p] = fixed;
567
+ buf[p + 1] = t;
568
+ this.pos = p + 2;
569
+ }
570
+ else if (n <= 0xff) {
571
+ buf[p] = 0xc7;
572
+ buf[p + 1] = n;
573
+ buf[p + 2] = t;
574
+ this.pos = p + 3;
575
+ }
576
+ else if (n <= 0xffff) {
577
+ buf[p] = 0xc8;
578
+ this.view.setUint16(p + 1, n);
579
+ buf[p + 3] = t;
580
+ this.pos = p + 4;
581
+ }
582
+ else if (n <= 0xffffffff) {
583
+ buf[p] = 0xc9;
584
+ this.view.setUint32(p + 1, n);
585
+ buf[p + 5] = t;
586
+ this.pos = p + 6;
587
+ }
588
+ else {
589
+ throw (0, errors_js_1.fail)('size_limit', 'extension payload longer than 2^32-1 bytes');
590
+ }
591
+ }
592
+ ext(e, depth) {
593
+ const type = e.type;
594
+ const data = e.data;
595
+ if (typeof type !== 'number' || !Number.isInteger(type) || type < -128 || type > 127) {
596
+ throw (0, errors_js_1.fail)('invalid_argument', 'Ext type must be an integer in [-128, 127]');
597
+ }
598
+ if (!ArrayBuffer.isView(data))
599
+ throw (0, errors_js_1.fail)('invalid_argument', 'Ext data must be a Uint8Array');
600
+ (0, decode_js_1.validateBtoonExt)(type, data, depth, this.maxDepth);
601
+ this.extHeader(type, data.byteLength);
602
+ this.bytes(data);
603
+ }
604
+ // --- timestamps (SPEC §5.1) -------------------------------------------------------
605
+ timestampMs(ms) {
606
+ const sec = Math.floor(ms / 1000);
607
+ this.timestampParts(sec, (ms - sec * 1000) * 1e6);
608
+ }
609
+ timestamp(t) {
610
+ const sec = t.seconds;
611
+ const ns = t.nanoseconds;
612
+ const off = t.offsetMinutes;
613
+ if (typeof sec !== 'bigint' || sec < INT64_MIN || sec >= INT63) {
614
+ throw (0, errors_js_1.fail)('invalid_argument', 'Timestamp seconds must be a bigint in the int64 range');
615
+ }
616
+ if (typeof ns !== 'number' || !Number.isInteger(ns) || ns < 0 || ns >= constants_js_1.NANOS_PER_SECOND) {
617
+ throw (0, errors_js_1.fail)('invalid_argument', 'Timestamp nanoseconds must be an integer in [0, 999999999]');
618
+ }
619
+ if (off !== undefined) {
620
+ if (typeof off !== 'number' || !Number.isInteger(off) || off < -constants_js_1.MAX_OFFSET_MINUTES || off > constants_js_1.MAX_OFFSET_MINUTES) {
621
+ throw (0, errors_js_1.fail)('invalid_argument', 'Timestamp offsetMinutes must be an integer in [-1080, 1080]');
622
+ }
623
+ this.ensure(17);
624
+ const p = this.pos;
625
+ this.buf[p] = 0xc7;
626
+ this.buf[p + 1] = 14;
627
+ this.buf[p + 2] = 0xff;
628
+ this.view.setUint32(p + 3, ns);
629
+ this.view.setBigInt64(p + 7, sec);
630
+ this.view.setInt16(p + 15, off);
631
+ this.pos = p + 17;
632
+ return;
633
+ }
634
+ if (sec >= 0n && sec < 17179869184n) {
635
+ this.timestampParts(Number(sec), ns);
636
+ return;
637
+ }
638
+ this.ensure(15);
639
+ const p = this.pos;
640
+ this.buf[p] = 0xc7;
641
+ this.buf[p + 1] = 12;
642
+ this.buf[p + 2] = 0xff;
643
+ this.view.setUint32(p + 3, ns);
644
+ this.view.setBigInt64(p + 7, sec);
645
+ this.pos = p + 15;
646
+ }
647
+ /** MessagePack timestamp selection for a UTC instant; `sec` is a safe integer. */
648
+ timestampParts(sec, ns) {
649
+ this.ensure(15);
650
+ const buf = this.buf;
651
+ const p = this.pos;
652
+ if (sec >= 0 && sec < TWO_34) {
653
+ if (ns === 0 && sec < TWO_32) {
654
+ buf[p] = 0xd6;
655
+ buf[p + 1] = 0xff;
656
+ this.view.setUint32(p + 2, sec);
657
+ this.pos = p + 6;
658
+ }
659
+ else {
660
+ buf[p] = 0xd7;
661
+ buf[p + 1] = 0xff;
662
+ this.view.setUint32(p + 2, ns * 4 + Math.floor(sec / TWO_32));
663
+ this.view.setUint32(p + 6, sec >>> 0);
664
+ this.pos = p + 10;
665
+ }
666
+ return;
667
+ }
668
+ buf[p] = 0xc7;
669
+ buf[p + 1] = 12;
670
+ buf[p + 2] = 0xff;
671
+ this.view.setUint32(p + 3, ns);
672
+ this.view.setInt32(p + 7, Math.floor(sec / TWO_32));
673
+ this.view.setUint32(p + 11, sec >>> 0);
674
+ this.pos = p + 15;
675
+ }
676
+ // --- containers ------------------------------------------------------------------
677
+ arrayHeader(n) {
678
+ this.ensure(5);
679
+ const p = this.pos;
680
+ if (n <= 15) {
681
+ this.buf[p] = 0x90 | n;
682
+ this.pos = p + 1;
683
+ }
684
+ else if (n <= 0xffff) {
685
+ this.buf[p] = 0xdc;
686
+ this.view.setUint16(p + 1, n);
687
+ this.pos = p + 3;
688
+ }
689
+ else {
690
+ this.buf[p] = 0xdd;
691
+ this.view.setUint32(p + 1, n);
692
+ this.pos = p + 5;
693
+ }
694
+ }
695
+ mapHeader(n) {
696
+ this.ensure(5);
697
+ const p = this.pos;
698
+ if (n <= 15) {
699
+ this.buf[p] = 0x80 | n;
700
+ this.pos = p + 1;
701
+ }
702
+ else if (n <= 0xffff) {
703
+ this.buf[p] = 0xde;
704
+ this.view.setUint16(p + 1, n);
705
+ this.pos = p + 3;
706
+ }
707
+ else {
708
+ this.buf[p] = 0xdf;
709
+ this.view.setUint32(p + 1, n);
710
+ this.pos = p + 5;
711
+ }
712
+ }
713
+ plainMap(o, depth) {
714
+ if (depth >= this.maxDepth)
715
+ throw maxDepthError();
716
+ const keys = Object.keys(o);
717
+ const n = keys.length;
718
+ if (n > 1)
719
+ keys.sort(utf8_js_1.compareUtf8);
720
+ this.mapHeader(n);
721
+ for (let i = 0; i < n; i++) {
722
+ const k = keys[i];
723
+ this.string(k);
724
+ this.value(o[k], depth + 1);
725
+ }
726
+ }
727
+ mapObject(m, depth) {
728
+ if (depth >= this.maxDepth)
729
+ throw maxDepthError();
730
+ const keys = [];
731
+ for (const k of Map.prototype.keys.call(m)) {
732
+ if (typeof k !== 'string')
733
+ throw (0, errors_js_1.fail)('invalid_argument', 'Map keys must be strings');
734
+ keys.push(k);
735
+ }
736
+ const n = keys.length;
737
+ if (n > 1)
738
+ keys.sort(utf8_js_1.compareUtf8);
739
+ this.mapHeader(n);
740
+ for (let i = 0; i < n; i++) {
741
+ const k = keys[i];
742
+ this.string(k);
743
+ this.value(Map.prototype.get.call(m, k), depth + 1);
744
+ }
745
+ }
746
+ array(arr, depth) {
747
+ if (depth >= this.maxDepth)
748
+ throw maxDepthError();
749
+ const n = arr.length;
750
+ let items = arr;
751
+ let resolvedUpTo = 0;
752
+ if (this.autoTabular && n >= 2) {
753
+ const plan = this.planTabular(arr);
754
+ if (plan !== null) {
755
+ this.tabular(plan, depth);
756
+ return;
757
+ }
758
+ items = this.items;
759
+ resolvedUpTo = this.resolvedUpTo;
760
+ this.items = [];
761
+ }
762
+ this.arrayHeader(n);
763
+ for (let i = 0; i < n; i++) {
764
+ if (i < resolvedUpTo)
765
+ this.resolved(items[i], depth + 1);
766
+ else
767
+ this.value(arr[i], depth + 1);
768
+ }
769
+ }
770
+ /**
771
+ * SPEC §5.6.2: qualification and size rule. Elements with toJSON() are resolved here
772
+ * (once); when the array is not tabular, `items[0..resolvedUpTo)` holds the elements
773
+ * already resolved so the plain path doesn't call toJSON() twice.
774
+ */
775
+ planTabular(arr) {
776
+ const n = arr.length;
777
+ let resolved = null;
778
+ let kinds = null; // allocated once the first element qualifies
779
+ let firstKeys = [];
780
+ let keySet = null;
781
+ for (let i = 0; i < n; i++) {
782
+ let row = arr[i];
783
+ let kind = kindOf(row);
784
+ if (kind === K_TOJSON) {
785
+ if (resolved === null)
786
+ resolved = arr.slice(0, i);
787
+ row = callToJSON(row);
788
+ kind = kindOf(row);
789
+ if (kind === K_TOJSON)
790
+ kind = K_OBJECT; // no second toJSON()
791
+ }
792
+ if (resolved !== null)
793
+ resolved[i] = row;
794
+ const keys = mapKeys(row, kind);
795
+ let ok = keys !== null;
796
+ if (ok) {
797
+ if (i === 0) {
798
+ firstKeys = keys;
799
+ ok = firstKeys.length > 0;
800
+ }
801
+ else if (keys.length !== firstKeys.length) {
802
+ ok = false;
803
+ }
804
+ else {
805
+ for (let k = 0; k < keys.length; k++) {
806
+ if (keys[k] !== firstKeys[k]) {
807
+ if (keySet === null)
808
+ keySet = new Set(firstKeys);
809
+ for (let j = 0; j < keys.length; j++) {
810
+ if (!keySet.has(keys[j])) {
811
+ ok = false;
812
+ break;
813
+ }
814
+ }
815
+ break;
816
+ }
817
+ }
818
+ }
819
+ }
820
+ if (!ok)
821
+ return this.decline(arr, resolved, i + 1);
822
+ if (kinds === null)
823
+ kinds = new Uint8Array(n);
824
+ kinds[i] = kind;
825
+ }
826
+ const keys = firstKeys.slice().sort(utf8_js_1.compareUtf8);
827
+ const c = keys.length;
828
+ const lens = new Array(c);
829
+ let perRow = c <= 15 ? 1 : c <= 0xffff ? 3 : 5;
830
+ let overhead = 18;
831
+ for (let k = 0; k < c; k++) {
832
+ const len = (0, utf8_js_1.utf8Length)(keys[k]);
833
+ lens[k] = len;
834
+ perRow += (len <= 31 ? 1 : len <= 0xff ? 2 : len <= 0xffff ? 3 : 5) + len;
835
+ overhead += 9 + len;
836
+ }
837
+ // N * perRow > overhead <=> perRow > floor(overhead / N)
838
+ if (perRow <= Math.floor(overhead / n))
839
+ return this.decline(arr, resolved, n);
840
+ return { rows: resolved ?? arr, kinds: kinds, keys, lens };
841
+ }
842
+ decline(arr, resolved, upTo) {
843
+ this.items = resolved ?? arr;
844
+ this.resolvedUpTo = resolved === null ? 0 : upTo;
845
+ return null;
846
+ }
847
+ tabular(plan, depth) {
848
+ if (depth + 1 >= this.maxDepth)
849
+ throw maxDepthError();
850
+ const { rows, kinds, keys, lens } = plan;
851
+ const n = rows.length;
852
+ const c = keys.length;
853
+ const start = this.pos;
854
+ this.ensure(6 + 12);
855
+ this.pos += 6; // room for the largest ext header; shrunk below
856
+ const payload = this.pos;
857
+ this.view.setUint32(payload, constants_js_1.TABULAR_VERSION);
858
+ this.view.setUint32(payload + 4, c);
859
+ this.view.setUint32(payload + 8, n);
860
+ this.pos += 12;
861
+ for (let k = 0; k < c; k++) {
862
+ this.ensure(4);
863
+ this.view.setUint32(this.pos, lens[k]);
864
+ this.pos += 4;
865
+ this.utf8Exact(keys[k], lens[k]);
866
+ }
867
+ // Type codes describe the first row; resolve its cells once and reuse them below.
868
+ const first = rows[0];
869
+ const firstKind = kinds[0];
870
+ const firstCells = new Array(c);
871
+ const firstResolved = new Uint8Array(c);
872
+ this.ensure(c);
873
+ for (let k = 0; k < c; k++) {
874
+ let v = cell(first, firstKind, keys[k]);
875
+ if (kindOf(v) === K_TOJSON) {
876
+ v = callToJSON(v);
877
+ firstResolved[k] = 1;
878
+ }
879
+ firstCells[k] = v;
880
+ this.buf[this.pos++] = typeCode(v);
881
+ }
882
+ for (let k = 0; k < c; k++) {
883
+ const key = keys[k];
884
+ this.ensure(4);
885
+ const lenPos = this.pos;
886
+ this.pos += 4;
887
+ if (firstResolved[k] === 1)
888
+ this.resolved(firstCells[k], depth + 2);
889
+ else
890
+ this.value(firstCells[k], depth + 2);
891
+ for (let r = 1; r < n; r++)
892
+ this.value(cell(rows[r], kinds[r], key), depth + 2);
893
+ const colLen = this.pos - lenPos - 4;
894
+ if (colLen > 0xffffffff)
895
+ throw (0, errors_js_1.fail)('size_limit', 'tabular column larger than 2^32-1 bytes');
896
+ this.view.setUint32(lenPos, colLen);
897
+ }
898
+ const len = this.pos - payload;
899
+ if (len > 0xffffffff)
900
+ throw (0, errors_js_1.fail)('size_limit', 'tabular payload larger than 2^32-1 bytes');
901
+ const hdr = len <= 0xff ? 3 : len <= 0xffff ? 4 : 6;
902
+ if (hdr < 6) {
903
+ this.buf.copyWithin(start + hdr, payload, this.pos);
904
+ this.pos -= 6 - hdr;
905
+ }
906
+ const buf = this.buf;
907
+ if (hdr === 3) {
908
+ buf[start] = 0xc7;
909
+ buf[start + 1] = len;
910
+ buf[start + 2] = constants_js_1.EXT_TABULAR & 0xff;
911
+ }
912
+ else if (hdr === 4) {
913
+ buf[start] = 0xc8;
914
+ this.view.setUint16(start + 1, len);
915
+ buf[start + 3] = constants_js_1.EXT_TABULAR & 0xff;
916
+ }
917
+ else {
918
+ buf[start] = 0xc9;
919
+ this.view.setUint32(start + 1, len);
920
+ buf[start + 5] = constants_js_1.EXT_TABULAR & 0xff;
921
+ }
922
+ }
923
+ }
924
+ let scratch = null;
925
+ const SCRATCH_MAX = 1 << 20;
926
+ /** Canonical encoding of `value` (no envelopes). */
927
+ function encodeDocument(value, maxDepth, autoTabular) {
928
+ // Reuse one scratch buffer across calls; a re-entrant call (from toJSON) gets its own.
929
+ const buf = scratch ?? new Uint8Array(1024);
930
+ scratch = null;
931
+ const enc = new Encoder(buf, maxDepth, autoTabular);
932
+ try {
933
+ enc.value(value, 0);
934
+ }
935
+ catch (e) {
936
+ if ((0, errors_js_1.isStackOverflow)(e)) {
937
+ throw (0, errors_js_1.fail)('max_depth', 'value nests too deeply for the JavaScript call stack', e);
938
+ }
939
+ throw e;
940
+ }
941
+ finally {
942
+ if (enc.buf.length <= SCRATCH_MAX)
943
+ scratch = enc.buf;
944
+ }
945
+ return enc.buf.slice(0, enc.pos);
946
+ }