@btoon/js 0.0.0-stage → 0.1.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 (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,64 @@
1
+ /**
2
+ * BTOON for JavaScript and TypeScript — Node.js entry point (also used by Bun). Same API
3
+ * as the portable entry; synchronous compression and signing use `node:zlib` (zlib,
4
+ * Brotli, and Zstandard where Node.js has it) and `node:crypto`.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ import { type BinaryInput } from './core.js';
9
+ import type { DecodeOptions, EncodeOptions } from './options.js';
10
+ export { SPEC_VERSION, VERSION } from './constants.js';
11
+ export type { BinaryInput } from './core.js';
12
+ export { BtoonError, type BtoonErrorCode } from './errors.js';
13
+ export type { Codec, CodecRegistry, CompressionAlgorithm, DecodeOptions, EncodeOptions } from './options.js';
14
+ export { Ext, Timestamp } from './values.js';
15
+ /**
16
+ * Encodes a value as canonical BTOON (SPEC §4): identical values produce identical bytes
17
+ * in every conforming implementation.
18
+ *
19
+ * Accepted values: `null`/`undefined` (nil), booleans, numbers (safe integers as integers,
20
+ * everything else — including `-0`, `NaN` and integral values beyond ±2^53 — as float64),
21
+ * `bigint`, strings (must not contain lone surrogates), `Uint8Array`/`ArrayBuffer`/other
22
+ * typed arrays and `DataView` (binary), `Float32Array`/`Float64Array` (float vectors),
23
+ * arrays, plain objects and `Map`s with string keys (maps, keys sorted by UTF-8 bytes),
24
+ * `Date` and {@link Timestamp} (timestamps), and {@link Ext}. Any other object is encoded
25
+ * the way `JSON.stringify` sees it: the result of its `toJSON()` method if it has one
26
+ * (called once), otherwise a map of its own enumerable string-keyed properties; `Number`,
27
+ * `String`, `Boolean` and `BigInt` wrapper objects are unwrapped. Functions and symbols are
28
+ * rejected. Arrays of uniform objects use the tabular encoding when it is smaller.
29
+ *
30
+ * With `compress` or `hmacKey`, the document is wrapped in a compression and/or signed
31
+ * envelope, layered as sign(compress(document)).
32
+ *
33
+ * @throws {BtoonError} `invalid_argument` for functions, symbols or invalid options, `max_depth`
34
+ * for values nested deeper than `maxDepth` (including cycles), `invalid_utf8` for strings
35
+ * with lone surrogates, `unsupported_compression` if the algorithm has no synchronous
36
+ * implementation here (see `encodeAsync` and `options.codecs`).
37
+ */
38
+ export declare function encode(value: unknown, options?: EncodeOptions): Uint8Array<ArrayBuffer>;
39
+ /**
40
+ * Decodes one BTOON document, enforcing SPEC §7: bounds-checked reads, a nesting limit,
41
+ * no allocation beyond what the input justifies, strict UTF-8, unique map keys and no
42
+ * trailing bytes. Compression envelopes are decompressed (with the output capped at the
43
+ * declared size and `maxDecompressedSize`); with `hmacKey` the signature is verified before
44
+ * anything is parsed.
45
+ *
46
+ * Maps decode to plain objects. A `"__proto__"` key becomes an own property (as with
47
+ * `JSON.parse`); it never changes an object's prototype.
48
+ *
49
+ * @throws {BtoonError} with the SPEC §7 error code describing the problem.
50
+ */
51
+ export declare function decode(data: BinaryInput, options?: DecodeOptions): unknown;
52
+ /**
53
+ * Like {@link encode}, but compresses with `CompressionStream` (when the runtime supports
54
+ * the algorithm) and signs with WebCrypto, falling back to the synchronous implementations.
55
+ * Rejects with a {@link BtoonError}.
56
+ */
57
+ export declare function encodeAsync(value: unknown, options?: EncodeOptions): Promise<Uint8Array<ArrayBuffer>>;
58
+ /**
59
+ * Like {@link decode}, but decompresses with `DecompressionStream` (when the runtime
60
+ * supports the algorithm) and verifies signatures with `crypto.subtle.verify`, falling back
61
+ * to the synchronous implementations. The input is copied first, so the caller may reuse
62
+ * its buffer immediately. Rejects with a {@link BtoonError}.
63
+ */
64
+ export declare function decodeAsync(data: BinaryInput, options?: DecodeOptions): Promise<unknown>;
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Timestamp = exports.Ext = exports.BtoonError = exports.VERSION = exports.SPEC_VERSION = void 0;
4
+ exports.encode = encode;
5
+ exports.decode = decode;
6
+ exports.encodeAsync = encodeAsync;
7
+ exports.decodeAsync = decodeAsync;
8
+ /**
9
+ * BTOON for JavaScript and TypeScript — Node.js entry point (also used by Bun). Same API
10
+ * as the portable entry; synchronous compression and signing use `node:zlib` (zlib,
11
+ * Brotli, and Zstandard where Node.js has it) and `node:crypto`.
12
+ *
13
+ * @packageDocumentation
14
+ */
15
+ const core_js_1 = require("./core.js");
16
+ const platform_node_js_1 = require("./platform-node.js");
17
+ var constants_js_1 = require("./constants.js");
18
+ Object.defineProperty(exports, "SPEC_VERSION", { enumerable: true, get: function () { return constants_js_1.SPEC_VERSION; } });
19
+ Object.defineProperty(exports, "VERSION", { enumerable: true, get: function () { return constants_js_1.VERSION; } });
20
+ var errors_js_1 = require("./errors.js");
21
+ Object.defineProperty(exports, "BtoonError", { enumerable: true, get: function () { return errors_js_1.BtoonError; } });
22
+ var values_js_1 = require("./values.js");
23
+ Object.defineProperty(exports, "Ext", { enumerable: true, get: function () { return values_js_1.Ext; } });
24
+ Object.defineProperty(exports, "Timestamp", { enumerable: true, get: function () { return values_js_1.Timestamp; } });
25
+ /**
26
+ * Encodes a value as canonical BTOON (SPEC §4): identical values produce identical bytes
27
+ * in every conforming implementation.
28
+ *
29
+ * Accepted values: `null`/`undefined` (nil), booleans, numbers (safe integers as integers,
30
+ * everything else — including `-0`, `NaN` and integral values beyond ±2^53 — as float64),
31
+ * `bigint`, strings (must not contain lone surrogates), `Uint8Array`/`ArrayBuffer`/other
32
+ * typed arrays and `DataView` (binary), `Float32Array`/`Float64Array` (float vectors),
33
+ * arrays, plain objects and `Map`s with string keys (maps, keys sorted by UTF-8 bytes),
34
+ * `Date` and {@link Timestamp} (timestamps), and {@link Ext}. Any other object is encoded
35
+ * the way `JSON.stringify` sees it: the result of its `toJSON()` method if it has one
36
+ * (called once), otherwise a map of its own enumerable string-keyed properties; `Number`,
37
+ * `String`, `Boolean` and `BigInt` wrapper objects are unwrapped. Functions and symbols are
38
+ * rejected. Arrays of uniform objects use the tabular encoding when it is smaller.
39
+ *
40
+ * With `compress` or `hmacKey`, the document is wrapped in a compression and/or signed
41
+ * envelope, layered as sign(compress(document)).
42
+ *
43
+ * @throws {BtoonError} `invalid_argument` for functions, symbols or invalid options, `max_depth`
44
+ * for values nested deeper than `maxDepth` (including cycles), `invalid_utf8` for strings
45
+ * with lone surrogates, `unsupported_compression` if the algorithm has no synchronous
46
+ * implementation here (see `encodeAsync` and `options.codecs`).
47
+ */
48
+ function encode(value, options) {
49
+ return (0, core_js_1.encodeWith)(value, options, platform_node_js_1.nodePlatform);
50
+ }
51
+ /**
52
+ * Decodes one BTOON document, enforcing SPEC §7: bounds-checked reads, a nesting limit,
53
+ * no allocation beyond what the input justifies, strict UTF-8, unique map keys and no
54
+ * trailing bytes. Compression envelopes are decompressed (with the output capped at the
55
+ * declared size and `maxDecompressedSize`); with `hmacKey` the signature is verified before
56
+ * anything is parsed.
57
+ *
58
+ * Maps decode to plain objects. A `"__proto__"` key becomes an own property (as with
59
+ * `JSON.parse`); it never changes an object's prototype.
60
+ *
61
+ * @throws {BtoonError} with the SPEC §7 error code describing the problem.
62
+ */
63
+ function decode(data, options) {
64
+ return (0, core_js_1.decodeWith)(data, options, platform_node_js_1.nodePlatform);
65
+ }
66
+ /**
67
+ * Like {@link encode}, but compresses with `CompressionStream` (when the runtime supports
68
+ * the algorithm) and signs with WebCrypto, falling back to the synchronous implementations.
69
+ * Rejects with a {@link BtoonError}.
70
+ */
71
+ function encodeAsync(value, options) {
72
+ return (0, core_js_1.encodeAsyncWith)(value, options, platform_node_js_1.nodePlatform);
73
+ }
74
+ /**
75
+ * Like {@link decode}, but decompresses with `DecompressionStream` (when the runtime
76
+ * supports the algorithm) and verifies signatures with `crypto.subtle.verify`, falling back
77
+ * to the synchronous implementations. The input is copied first, so the caller may reuse
78
+ * its buffer immediately. Rejects with a {@link BtoonError}.
79
+ */
80
+ function decodeAsync(data, options) {
81
+ return (0, core_js_1.decodeAsyncWith)(data, options, platform_node_js_1.nodePlatform);
82
+ }
@@ -0,0 +1,95 @@
1
+ /** Compression algorithms of the envelope (SPEC §6). Only `zlib` is mandatory. */
2
+ export type CompressionAlgorithm = 'zlib' | 'lz4' | 'zstd' | 'brotli' | 'snappy';
3
+ /**
4
+ * A user-supplied compression codec (see {@link CodecRegistry}). Either function may be
5
+ * synchronous or return a Promise; synchronous `encode`/`decode` accept only synchronous
6
+ * results.
7
+ */
8
+ export interface Codec {
9
+ /**
10
+ * Compress a whole document. The output must be the payload format SPEC §6 requires for
11
+ * the algorithm: an RFC 1950 zlib stream, an LZ4 *block* (no frame), a Zstandard frame,
12
+ * a Brotli stream, or raw Snappy.
13
+ */
14
+ compress?(data: Uint8Array): Uint8Array | Promise<Uint8Array>;
15
+ /**
16
+ * Decompress a payload. `uncompressedSize` is the size declared by the envelope, already
17
+ * checked against `maxDecompressedSize`; implementations must not produce more than that
18
+ * (LZ4 block decoders need it as the output size). The result must be exactly that long.
19
+ */
20
+ decompress?(data: Uint8Array, uncompressedSize: number): Uint8Array | Promise<Uint8Array>;
21
+ }
22
+ /**
23
+ * Compression codecs supplied by the caller, keyed by algorithm. A codec here takes
24
+ * precedence over the built-in implementations, so this is how to add LZ4 or Snappy, or
25
+ * synchronous zlib compression in browsers (for example with `fflate`).
26
+ */
27
+ export type CodecRegistry = {
28
+ readonly [A in CompressionAlgorithm]?: Codec;
29
+ };
30
+ /** Options of `encode` / `encodeAsync`. */
31
+ export interface EncodeOptions {
32
+ /** Wrap the document in a compression envelope (SPEC §6). Default `false`. */
33
+ compress?: boolean;
34
+ /** Algorithm used when `compress` is true. Default `'zlib'`. Has no effect unless `compress` is true. */
35
+ compression?: CompressionAlgorithm;
36
+ /** Use the tabular (columnar) encoding where SPEC §5.6.2's size rule says so. Default `true`. */
37
+ autoTabular?: boolean;
38
+ /** Maximum container nesting; deeper or cyclic values throw `max_depth`. Default `128`. */
39
+ maxDepth?: number;
40
+ /** Sign the output with HMAC-SHA256 (SPEC §8). A string is used as its UTF-8 bytes. Must not be empty. */
41
+ hmacKey?: Uint8Array | string;
42
+ /** Caller-supplied compression codecs. */
43
+ codecs?: CodecRegistry;
44
+ }
45
+ /** Options of `decode` / `decodeAsync`. */
46
+ export interface DecodeOptions {
47
+ /**
48
+ * SPEC §7 strict mode. Default `true`. Non-strict mode allows trailing bytes and
49
+ * duplicate keys (last wins) and replaces invalid UTF-8 with U+FFFD; bounds, depth and
50
+ * allocation checks are never relaxed.
51
+ */
52
+ strict?: boolean;
53
+ /** Maximum container nesting; deeper input throws `max_depth`. Default `128`. */
54
+ maxDepth?: number;
55
+ /** Largest accepted `uncompressed_size` of a compression envelope, in bytes. Default 256 MiB. */
56
+ maxDecompressedSize?: number;
57
+ /** Accept compression envelopes. Default `true`; when `false` they throw `invalid_envelope`. */
58
+ autoDecompress?: boolean;
59
+ /** Require a signed envelope and verify it (SPEC §8) before parsing. Must not be empty. */
60
+ hmacKey?: Uint8Array | string;
61
+ /**
62
+ * How timestamp (-1), date (-2) and datetime (-3) values decode. `'date'` (default):
63
+ * `Date` (millisecond precision, offset dropped; instants outside the range of `Date`
64
+ * become `Timestamp`). `'object'`: always {@link Timestamp}, with full precision.
65
+ */
66
+ timestamps?: 'date' | 'object';
67
+ /**
68
+ * `'auto'` (default): integers decode to `number` when they are safe integers and to
69
+ * `bigint` otherwise. `'always'`: integers written with a 64-bit marker (uint64/int64)
70
+ * or as a bigint extension always decode to `bigint`.
71
+ */
72
+ bigint?: 'auto' | 'always';
73
+ /** Caller-supplied compression codecs. */
74
+ codecs?: CodecRegistry;
75
+ }
76
+ export interface EncodeConfig {
77
+ compress: boolean;
78
+ algorithm: CompressionAlgorithm;
79
+ autoTabular: boolean;
80
+ maxDepth: number;
81
+ hmacKey: Uint8Array | undefined;
82
+ codecs: CodecRegistry | undefined;
83
+ }
84
+ export interface DecodeConfig {
85
+ strict: boolean;
86
+ maxDepth: number;
87
+ maxDecompressedSize: number;
88
+ autoDecompress: boolean;
89
+ hmacKey: Uint8Array | undefined;
90
+ timestampObjects: boolean;
91
+ bigintAlways: boolean;
92
+ codecs: CodecRegistry | undefined;
93
+ }
94
+ export declare function encodeConfig(options: EncodeOptions | undefined): EncodeConfig;
95
+ export declare function decodeConfig(options: DecodeOptions | undefined): DecodeConfig;
@@ -0,0 +1,128 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.encodeConfig = encodeConfig;
4
+ exports.decodeConfig = decodeConfig;
5
+ const constants_js_1 = require("./constants.js");
6
+ const errors_js_1 = require("./errors.js");
7
+ const utf8_js_1 = require("./utf8.js");
8
+ const values_js_1 = require("./values.js");
9
+ const DEFAULT_ENCODE = Object.freeze({
10
+ compress: false,
11
+ algorithm: 'zlib',
12
+ autoTabular: true,
13
+ maxDepth: constants_js_1.DEFAULT_MAX_DEPTH,
14
+ hmacKey: undefined,
15
+ codecs: undefined,
16
+ });
17
+ const DEFAULT_DECODE = Object.freeze({
18
+ strict: true,
19
+ maxDepth: constants_js_1.DEFAULT_MAX_DEPTH,
20
+ maxDecompressedSize: constants_js_1.DEFAULT_MAX_DECOMPRESSED_SIZE,
21
+ autoDecompress: true,
22
+ hmacKey: undefined,
23
+ timestampObjects: false,
24
+ bigintAlways: false,
25
+ codecs: undefined,
26
+ });
27
+ function optionsObject(options, what) {
28
+ if (options === undefined || options === null)
29
+ return undefined;
30
+ if (typeof options !== 'object')
31
+ throw (0, errors_js_1.fail)('invalid_argument', `${what} options must be an object`);
32
+ return options;
33
+ }
34
+ function bool(o, name, dflt) {
35
+ const v = o[name];
36
+ if (v === undefined)
37
+ return dflt;
38
+ if (typeof v !== 'boolean')
39
+ throw (0, errors_js_1.fail)('invalid_argument', `option ${name} must be a boolean`);
40
+ return v;
41
+ }
42
+ function count(o, name, dflt) {
43
+ const v = o[name];
44
+ if (v === undefined)
45
+ return dflt;
46
+ if (typeof v !== 'number' || !Number.isSafeInteger(v) || v < 0) {
47
+ throw (0, errors_js_1.fail)('invalid_argument', `option ${name} must be a non-negative integer`);
48
+ }
49
+ return v;
50
+ }
51
+ function oneOf(o, name, allowed, dflt) {
52
+ const v = o[name];
53
+ if (v === undefined)
54
+ return dflt;
55
+ if (typeof v !== 'string' || !allowed.includes(v)) {
56
+ throw (0, errors_js_1.fail)('invalid_argument', `option ${name} must be one of ${allowed.map((a) => `'${a}'`).join(', ')}`);
57
+ }
58
+ return v;
59
+ }
60
+ function hmacKey(o) {
61
+ const v = o.hmacKey;
62
+ if (v === undefined)
63
+ return undefined;
64
+ let key;
65
+ if (typeof v === 'string') {
66
+ if (!(0, utf8_js_1.isWellFormed)(v))
67
+ throw (0, errors_js_1.fail)('invalid_argument', 'hmacKey string contains a lone surrogate');
68
+ key = new TextEncoder().encode(v);
69
+ }
70
+ else if ((0, values_js_1.isUint8Array)(v)) {
71
+ key = Uint8Array.prototype.slice.call(v); // private copy: immune to later mutation
72
+ }
73
+ else {
74
+ throw (0, errors_js_1.fail)('invalid_argument', 'option hmacKey must be a Uint8Array or a string');
75
+ }
76
+ if (key.length === 0)
77
+ throw (0, errors_js_1.fail)('invalid_argument', 'option hmacKey must not be empty');
78
+ return key;
79
+ }
80
+ function codecs(o) {
81
+ const v = o.codecs;
82
+ if (v === undefined)
83
+ return undefined;
84
+ if (typeof v !== 'object' || v === null)
85
+ throw (0, errors_js_1.fail)('invalid_argument', 'option codecs must be an object');
86
+ for (const name of constants_js_1.ALGORITHM_NAMES) {
87
+ const c = v[name];
88
+ if (c === undefined)
89
+ continue;
90
+ if (typeof c !== 'object' || c === null)
91
+ throw (0, errors_js_1.fail)('invalid_argument', `codecs.${name} must be an object`);
92
+ for (const fn of ['compress', 'decompress']) {
93
+ const f = c[fn];
94
+ if (f !== undefined && typeof f !== 'function') {
95
+ throw (0, errors_js_1.fail)('invalid_argument', `codecs.${name}.${fn} must be a function`);
96
+ }
97
+ }
98
+ }
99
+ return v;
100
+ }
101
+ function encodeConfig(options) {
102
+ const o = optionsObject(options, 'encode');
103
+ if (o === undefined)
104
+ return DEFAULT_ENCODE;
105
+ return {
106
+ compress: bool(o, 'compress', false),
107
+ algorithm: oneOf(o, 'compression', constants_js_1.ALGORITHM_NAMES, 'zlib'),
108
+ autoTabular: bool(o, 'autoTabular', true),
109
+ maxDepth: count(o, 'maxDepth', constants_js_1.DEFAULT_MAX_DEPTH),
110
+ hmacKey: hmacKey(o),
111
+ codecs: codecs(o),
112
+ };
113
+ }
114
+ function decodeConfig(options) {
115
+ const o = optionsObject(options, 'decode');
116
+ if (o === undefined)
117
+ return DEFAULT_DECODE;
118
+ return {
119
+ strict: bool(o, 'strict', true),
120
+ maxDepth: count(o, 'maxDepth', constants_js_1.DEFAULT_MAX_DEPTH),
121
+ maxDecompressedSize: count(o, 'maxDecompressedSize', constants_js_1.DEFAULT_MAX_DECOMPRESSED_SIZE),
122
+ autoDecompress: bool(o, 'autoDecompress', true),
123
+ hmacKey: hmacKey(o),
124
+ timestampObjects: oneOf(o, 'timestamps', ['date', 'object'], 'date') === 'object',
125
+ bigintAlways: oneOf(o, 'bigint', ['auto', 'always'], 'auto') === 'always',
126
+ codecs: codecs(o),
127
+ };
128
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
@@ -0,0 +1,3 @@
1
+ import type { Platform } from './core.js';
2
+ /** Node.js (and Bun): node:zlib for zlib, Brotli and Zstandard; node:crypto for HMAC. */
3
+ export declare const nodePlatform: Platform;
@@ -0,0 +1,132 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.nodePlatform = void 0;
37
+ const node_crypto_1 = require("node:crypto");
38
+ const zlib = __importStar(require("node:zlib"));
39
+ const errors_js_1 = require("./errors.js");
40
+ const inflate_js_1 = require("./inflate.js");
41
+ function nodeFn(name) {
42
+ const f = zlib[name];
43
+ return typeof f === 'function' ? f : undefined;
44
+ }
45
+ function plain(b) {
46
+ return new Uint8Array(b.buffer, b.byteOffset, b.byteLength);
47
+ }
48
+ /**
49
+ * Wraps a node:zlib `*Sync` decompressor: output is capped at the declared size
50
+ * (`maxOutputLength`), and input left over after the end of the stream is rejected.
51
+ */
52
+ function decompressor(alg, fn, extra) {
53
+ if (fn === undefined)
54
+ return undefined;
55
+ return (data, size) => {
56
+ let r;
57
+ try {
58
+ r = fn(data, { ...extra?.(size), info: true, maxOutputLength: Math.max(1, size) });
59
+ }
60
+ catch (e) {
61
+ if (e.code === 'ERR_BUFFER_TOO_LARGE') {
62
+ throw (0, errors_js_1.fail)('invalid_envelope', `${alg} payload decompresses to more than the declared size`, e);
63
+ }
64
+ throw (0, errors_js_1.fail)('invalid_envelope', `${alg} payload is corrupt: ${e.message}`, e);
65
+ }
66
+ let out;
67
+ let consumed;
68
+ if (r instanceof Uint8Array) {
69
+ out = r;
70
+ }
71
+ else {
72
+ const info = r;
73
+ out = info.buffer;
74
+ consumed = info.engine?.bytesWritten;
75
+ }
76
+ if (typeof consumed === 'number') {
77
+ if (consumed !== data.length)
78
+ throw (0, errors_js_1.fail)('invalid_envelope', `${alg} payload has trailing bytes`);
79
+ }
80
+ else if (alg === 'zlib') {
81
+ // A runtime that doesn't report consumed input: the stream must end in its Adler-32.
82
+ const n = data.length;
83
+ const trailer = n >= 4 ? ((data[n - 4] << 24) | (data[n - 3] << 16) | (data[n - 2] << 8) | data[n - 1]) >>> 0 : -1;
84
+ if (trailer !== (0, inflate_js_1.adler32)(out))
85
+ throw (0, errors_js_1.fail)('invalid_envelope', 'zlib payload has trailing bytes');
86
+ }
87
+ return plain(out);
88
+ };
89
+ }
90
+ function compressor(fn, options) {
91
+ if (fn === undefined)
92
+ return undefined;
93
+ return (data) => plain(fn(data, options));
94
+ }
95
+ const decompress = {};
96
+ const compress = {};
97
+ decompress.zlib = decompressor('zlib', nodeFn('inflateSync'));
98
+ compress.zlib = compressor(nodeFn('deflateSync'), { level: 6 });
99
+ const brotliQuality = zlib.constants?.BROTLI_PARAM_QUALITY;
100
+ if (brotliQuality !== undefined) {
101
+ decompress.brotli = decompressor('brotli', nodeFn('brotliDecompressSync'));
102
+ compress.brotli = compressor(nodeFn('brotliCompressSync'), { params: { [brotliQuality]: 6 } });
103
+ }
104
+ // node:zlib has Zstandard from Node.js 22.15 / 23.8. SPEC §6: bound the decoder's memory
105
+ // by rejecting frames whose window exceeds max(8 MiB, min(uncompressed_size, 128 MiB)).
106
+ const zstdWindowLogMax = zlib.constants?.ZSTD_d_windowLogMax;
107
+ decompress.zstd = decompressor('zstd', nodeFn('zstdDecompressSync'), (size) => zstdWindowLogMax === undefined
108
+ ? {}
109
+ : { params: { [zstdWindowLogMax]: Math.ceil(Math.log2(Math.max(8 << 20, Math.min(size, 128 << 20)))) } });
110
+ compress.zstd = compressor(nodeFn('zstdCompressSync'), {});
111
+ for (const alg of Object.keys(decompress)) {
112
+ if (decompress[alg] === undefined)
113
+ delete decompress[alg];
114
+ }
115
+ for (const alg of Object.keys(compress)) {
116
+ if (compress[alg] === undefined)
117
+ delete compress[alg];
118
+ }
119
+ /** Node.js (and Bun): node:zlib for zlib, Brotli and Zstandard; node:crypto for HMAC. */
120
+ exports.nodePlatform = {
121
+ decompress,
122
+ compress,
123
+ hmac(key, parts) {
124
+ const h = (0, node_crypto_1.createHmac)('sha256', key);
125
+ for (const p of parts)
126
+ h.update(p);
127
+ return plain(h.digest());
128
+ },
129
+ equal(a, b) {
130
+ return a.length === b.length && (0, node_crypto_1.timingSafeEqual)(a, b);
131
+ },
132
+ };
@@ -0,0 +1,7 @@
1
+ import type { Platform } from './core.js';
2
+ /**
3
+ * Environments without Node.js built-ins (browsers, Deno, workers): synchronous zlib
4
+ * decompression and HMAC-SHA256 in pure JavaScript. Synchronous compression needs a
5
+ * caller-supplied codec; encodeAsync uses CompressionStream instead.
6
+ */
7
+ export declare const portablePlatform: Platform;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.portablePlatform = void 0;
4
+ const inflate_js_1 = require("./inflate.js");
5
+ const sha256_js_1 = require("./sha256.js");
6
+ /**
7
+ * Environments without Node.js built-ins (browsers, Deno, workers): synchronous zlib
8
+ * decompression and HMAC-SHA256 in pure JavaScript. Synchronous compression needs a
9
+ * caller-supplied codec; encodeAsync uses CompressionStream instead.
10
+ */
11
+ exports.portablePlatform = {
12
+ decompress: { zlib: inflate_js_1.inflateZlib },
13
+ compress: {},
14
+ hmac: sha256_js_1.hmacSha256,
15
+ equal: sha256_js_1.timingSafeEqual,
16
+ };
@@ -0,0 +1,5 @@
1
+ export declare function sha256(data: Uint8Array): Uint8Array;
2
+ /** HMAC-SHA256 over the concatenation of `parts` (no copy of the parts is made). */
3
+ export declare function hmacSha256(key: Uint8Array, parts: readonly Uint8Array[]): Uint8Array;
4
+ /** Compares two byte strings in time that depends only on their length. */
5
+ export declare function timingSafeEqual(a: Uint8Array, b: Uint8Array): boolean;