@sig-net/midnight-serde 0.12.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.
package/README.md ADDED
@@ -0,0 +1,106 @@
1
+ # @sig-net/midnight-serde
2
+
3
+ TypeScript twin of Compact's builtin `serialize<T, N>` / `deserialize<T, N>`
4
+ pair (CompactStandardLibrary). Produce bytes off-chain that a contract reads
5
+ with one `deserialize<T, N>` call, and decode bytes a contract produced with
6
+ `serialize<T, N>`. Zero runtime dependencies.
7
+
8
+ Every claim is pinned byte-for-byte against COMPILED circuits: the fixture
9
+ contract in [`tests/fixtures/serde-fixtures.compact`](tests/fixtures/serde-fixtures.compact)
10
+ wraps the builtins over structs exercising all supported types and combos, and
11
+ the tests assert twin/circuit equality in both directions. A second,
12
+ independent oracle backs the serialize direction: `toBinaryRepr` from
13
+ `@midnight-ntwrk/compact-runtime` (test-only, never a runtime dependency)
14
+ must agree with the twin on every shape, including the shapes compactc cannot
15
+ compile `serialize<T, N>` for.
16
+
17
+ ## Use
18
+
19
+ Describe the Compact type as a descriptor tree, then encode/decode values.
20
+ Declare descriptors `as const satisfies CompactType` and the value types are
21
+ INFERRED from the descriptor (`CompactValueOf<T>`), both in and out, so no
22
+ casts and no hand-written interfaces:
23
+
24
+ ```ts
25
+ import { compactSerialize, compactDeserialize, type CompactType } from "@sig-net/midnight-serde";
26
+
27
+ // Compact: struct Result { ok: Boolean; amount: Uint<128>; }
28
+ const RESULT = {
29
+ kind: "struct",
30
+ fields: [
31
+ { name: "ok", type: { kind: "boolean" } },
32
+ { name: "amount", type: { kind: "uint", bits: 128 } },
33
+ ],
34
+ } as const satisfies CompactType;
35
+
36
+ // serialize<Result, 128> twin: packed value at the start, zero-padded to 128.
37
+ // The value parameter is compile-time checked against the descriptor.
38
+ const bytes = compactSerialize(RESULT, { ok: true, amount: 4242n }, 128);
39
+
40
+ // deserialize<Result, 128> twin.
41
+ const value = compactDeserialize(RESULT, bytes);
42
+ // ^? { ok: boolean; amount: bigint }
43
+ ```
44
+
45
+ A descriptor widened to `CompactType` still works and degrades to the loose
46
+ `CompactValue` union.
47
+
48
+ ## Types and layout
49
+
50
+ Fields and elements pack in declaration order, little-endian, natural widths,
51
+ no gaps, no length prefixes. Every serializable Compact type has a descriptor
52
+ kind (`Opaque<...>` is the one exclusion: compactc itself rejects it as "not
53
+ a serializable type"):
54
+
55
+ | Compact type | Descriptor | Packed width | Value type |
56
+ | --- | --- | --- | --- |
57
+ | `Boolean` | `{ kind: 'boolean' }` | 1 byte (0x00/0x01) | `boolean` |
58
+ | `Uint<w>` (sized) | `{ kind: 'uint', bits: w }` | ceil(w / 8), w at most 248 | `bigint` |
59
+ | `Uint<0..n>` (bounded) | `{ kind: 'uint', bound: n }` | byte length of n - 1 | `bigint` |
60
+ | `Field` | `{ kind: 'field' }` | 32 bytes, value below the Fr modulus | `bigint` |
61
+ | `Bytes<n>` | `{ kind: 'bytes', length: n }` | n, raw | `Uint8Array` |
62
+ | enum | `{ kind: 'enum', variants: k }` | byte length of k - 1 | `number` (index) |
63
+ | `Vector<n, T>` | `{ kind: 'vector', length: n, element }` | n elements, unprefixed | `T[]` |
64
+ | `[T1, ..., Tn]` (tuple) | `{ kind: 'tuple', elements }` | elements back to back | TS tuple |
65
+ | struct | `{ kind: 'struct', fields }` | fields back to back | plain object |
66
+
67
+ The `Uint<0..n>` upper bound is EXCLUSIVE, per the language reference: the
68
+ values are 0 to n - 1, so `Uint<0..1000>` is 2 bytes and `Uint<8>` is the same
69
+ type as `Uint<0..256>`. An enum is `Uint<0..variants>` under the hood. That
70
+ width rule makes some legal types ZERO bytes wide: `Uint<0..1>`,
71
+ single-variant enums, `Bytes<0>`, `Vector<0, T>`, the empty tuple and the
72
+ empty struct all occupy no space (circuit-pinned).
73
+
74
+ `serialize<T, N>` places the packed value at the start of `Bytes<N>` and
75
+ zero-pads on the right. N below the packed size is a compile error in Compact
76
+ and a thrown error here.
77
+
78
+ ## Divergences from the circuit
79
+
80
+ Both are strict-by-default on DECODE, and both are pinned by tests. Bytes a
81
+ circuit produced never trigger either one, since `serialize<T, N>` only ever
82
+ writes zero padding and 0x00/0x01 booleans:
83
+
84
+ - **Padding:** the circuit ignores bytes in the padding region entirely, the
85
+ twin rejects non-zero padding. Pass `{ ignorePadding: true }` to
86
+ `compactDeserialize` to mirror the circuit exactly.
87
+ - **Booleans:** the circuit decodes ANY byte other than 0x01 as `false`
88
+ (0x02..0xff included), the twin rejects bytes above 1.
89
+
90
+ Everything else mirrors the circuit exactly, including rejections:
91
+ out-of-range bounded Uint, enum and Field encodings throw in-circuit and
92
+ throw here (all pinned by the tests).
93
+
94
+ Known compactc 0.33 limits (pinned by the tests): `serialize<T, N>` crashes
95
+ the COMPILER on vectors of structs, vectors of vectors, and struct nesting
96
+ deeper than one level. `deserialize<T, N>` handles all of those, so contracts
97
+ can still READ such payloads from off-chain encoders. Tuples are unaffected:
98
+ `serialize<[Pair, Boolean], N>` compiles fine.
99
+
100
+ ## Develop
101
+
102
+ ```bash
103
+ yarn compile # compile the fixture contract (needed before test/build)
104
+ yarn test # pin the twin against the compiled circuits + toBinaryRepr
105
+ yarn build # typecheck + emit ./dist for publishing
106
+ ```
@@ -0,0 +1,13 @@
1
+ import type { CompactType, CompactValueOf } from './types.ts';
2
+ export interface CompactDeserializeOptions {
3
+ /** Skip the all-zero check on bytes after the packed value (circuit behaviour). */
4
+ ignorePadding?: boolean;
5
+ }
6
+ /**
7
+ * Inverse of `compactSerialize`: decode the packed prefix of `bytes`.
8
+ *
9
+ * The return type is derived from the descriptor (see `CompactValueOf`), so a
10
+ * literal descriptor yields a fully typed value with no cast at the call site.
11
+ */
12
+ export declare function compactDeserialize<const T extends CompactType>(type: T, bytes: Uint8Array, options?: CompactDeserializeOptions): CompactValueOf<T>;
13
+ //# sourceMappingURL=deserialize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deserialize.d.ts","sourceRoot":"","sources":["../src/deserialize.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,WAAW,EAAgB,cAAc,EAAE,MAAM,YAAY,CAAC;AAI5E,MAAM,WAAW,yBAAyB;IACxC,mFAAmF;IACnF,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,CAAC,CAAC,SAAS,WAAW,EAC5D,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,UAAU,EACjB,OAAO,GAAE,yBAA8B,GACtC,cAAc,CAAC,CAAC,CAAC,CAiBnB"}
@@ -0,0 +1,140 @@
1
+ // Byte-exact twin of Compact's builtin `deserialize<T, N>` from
2
+ // CompactStandardLibrary, pinned against compiled circuits by tests/.
3
+ //
4
+ // Two deliberate divergences from the circuit, both strict-by-default
5
+ // (garbage in a buffer means corruption or mis-framing, and failing loudly
6
+ // off-chain is the safer default):
7
+ // - PADDING: the circuit IGNORES bytes in the padding region entirely
8
+ // (pinned by tests), while this decoder rejects non-zero padding. Pass
9
+ // `{ ignorePadding: true }` to mirror the circuit.
10
+ // - BOOLEANS: the circuit decodes ANY byte other than 0x01 as false, so
11
+ // 0x02..0xff all quietly become false (pinned by tests), while this
12
+ // decoder rejects bytes above 1.
13
+ // Circuit-produced bytes never trigger either divergence: `serialize<T, N>`
14
+ // only writes zero padding and 0x00/0x01 booleans.
15
+ //
16
+ // Everything else mirrors the circuit exactly, including its rejections: the
17
+ // descriptor is fully validated (src/validate.ts) and the input buffer
18
+ // type-checked before any decoding, and out-of-range Uint, enum and Field
19
+ // encodings all throw exactly where the circuit throws (pinned by tests).
20
+ import { FIELD_MODULUS } from "./types.js";
21
+ import { packedSize, uintBound, uintName } from "./serialize.js";
22
+ import { assertCompactType, assertUnreachable } from "./validate.js";
23
+ /**
24
+ * Inverse of `compactSerialize`: decode the packed prefix of `bytes`.
25
+ *
26
+ * The return type is derived from the descriptor (see `CompactValueOf`), so a
27
+ * literal descriptor yields a fully typed value with no cast at the call site.
28
+ */
29
+ export function compactDeserialize(type, bytes, options = {}) {
30
+ assertCompactType(type);
31
+ if (!(bytes instanceof Uint8Array)) {
32
+ throw new Error('bytes must be a Uint8Array');
33
+ }
34
+ const [value, consumed] = decodeFrom(bytes, 0, type, 'value');
35
+ if (!options.ignorePadding) {
36
+ for (let i = consumed; i < bytes.length; i++) {
37
+ if (bytes[i] !== 0) {
38
+ throw new Error(`non-zero padding byte 0x${bytes[i].toString(16)} at offset ${i} ` +
39
+ `(pass ignorePadding to mirror the circuit, which reads only the packed prefix)`);
40
+ }
41
+ }
42
+ }
43
+ return value;
44
+ }
45
+ function decodeFrom(bytes, offset, type, label) {
46
+ const need = packedSize(type);
47
+ if (offset + need > bytes.length) {
48
+ throw new Error(`${label}: needs ${need} bytes at offset ${offset}, buffer has ${bytes.length}`);
49
+ }
50
+ switch (type.kind) {
51
+ case 'boolean': {
52
+ const b = bytes[offset];
53
+ // Stricter than the circuit, which decodes any byte != 0x01 as false
54
+ // (see the header comment).
55
+ if (b > 1)
56
+ throw new Error(`${label}: invalid boolean byte 0x${b.toString(16)}`);
57
+ return [b === 1, offset + 1];
58
+ }
59
+ case 'uint': {
60
+ const bound = uintBound(type);
61
+ const size = packedSize(type);
62
+ const value = readUintLE(bytes, offset, size);
63
+ // Mirrors the circuit, which rejects encodings at or above the bound
64
+ // (pinned by tests via the bounded fixture; only reachable for sized
65
+ // uints when the width is not byte-aligned).
66
+ if (value >= bound) {
67
+ throw new Error(`${label}: encoding ${value} exceeds ${uintName(type)}`);
68
+ }
69
+ return [value, offset + size];
70
+ }
71
+ case 'field': {
72
+ const value = readUintLE(bytes, offset, 32);
73
+ // The circuit rejects out-of-range Field encodings at runtime too
74
+ // (pinned by tests): mirror it.
75
+ if (value >= FIELD_MODULUS) {
76
+ throw new Error(`${label}: encoding ${value} is not below the Field modulus`);
77
+ }
78
+ return [value, offset + 32];
79
+ }
80
+ case 'bytes':
81
+ return [bytes.slice(offset, offset + type.length), offset + type.length];
82
+ case 'enum': {
83
+ const size = packedSize(type);
84
+ const value = readUintLE(bytes, offset, size);
85
+ // Mirrors the circuit's variant-index range check (pinned by tests).
86
+ if (value >= BigInt(type.variants)) {
87
+ throw new Error(`${label}: encoding ${value} exceeds the last variant index ${type.variants - 1}`);
88
+ }
89
+ return [Number(value), offset + size];
90
+ }
91
+ case 'vector': {
92
+ const elements = [];
93
+ let cursor = offset;
94
+ for (let i = 0; i < type.length; i++) {
95
+ const [element, next] = decodeFrom(bytes, cursor, type.element, `${label}[${i}]`);
96
+ elements.push(element);
97
+ cursor = next;
98
+ }
99
+ return [elements, cursor];
100
+ }
101
+ case 'tuple': {
102
+ const elements = [];
103
+ let cursor = offset;
104
+ type.elements.forEach((element, i) => {
105
+ const [decoded, next] = decodeFrom(bytes, cursor, element, `${label}[${i}]`);
106
+ elements.push(decoded);
107
+ cursor = next;
108
+ });
109
+ return [elements, cursor];
110
+ }
111
+ case 'struct': {
112
+ const value = {};
113
+ let cursor = offset;
114
+ for (const field of type.fields) {
115
+ const [fieldValue, next] = decodeFrom(bytes, cursor, field.type, `${label}.${field.name}`);
116
+ // defineProperty, not assignment: a field named '__proto__' is a
117
+ // legal Compact identifier, and plain assignment would hit the
118
+ // prototype setter and silently drop it.
119
+ Object.defineProperty(value, field.name, {
120
+ value: fieldValue,
121
+ enumerable: true,
122
+ writable: true,
123
+ configurable: true,
124
+ });
125
+ cursor = next;
126
+ }
127
+ return [value, cursor];
128
+ }
129
+ default:
130
+ return assertUnreachable(type, label);
131
+ }
132
+ }
133
+ function readUintLE(bytes, offset, size) {
134
+ let v = 0n;
135
+ for (let i = size - 1; i >= 0; i--) {
136
+ v = (v << 8n) | BigInt(bytes[offset + i]);
137
+ }
138
+ return v;
139
+ }
140
+ //# sourceMappingURL=deserialize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deserialize.js","sourceRoot":"","sources":["../src/deserialize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export { FIELD_MODULUS, MAX_UINT_BITS, MAX_UINT_BOUND, type CompactBooleanType, type CompactUintType, type CompactSizedUintType, type CompactBoundedUintType, type CompactFieldType, type CompactBytesType, type CompactEnumType, type CompactVectorType, type CompactTupleType, type CompactStructType, type CompactType, type CompactValue, type CompactValueOf, } from './types.ts';
2
+ export { compactSerialize, compactSerializedSize } from './serialize.ts';
3
+ export { assertCompactType, isCompactType } from './validate.ts';
4
+ export { compactDeserialize, type CompactDeserializeOptions, } from './deserialize.ts';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,aAAa,EACb,cAAc,EACd,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,cAAc,GACpB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEzE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEjE,OAAO,EACL,kBAAkB,EAClB,KAAK,yBAAyB,GAC/B,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export { FIELD_MODULUS, MAX_UINT_BITS, MAX_UINT_BOUND, } from "./types.js";
2
+ export { compactSerialize, compactSerializedSize } from "./serialize.js";
3
+ export { assertCompactType, isCompactType } from "./validate.js";
4
+ export { compactDeserialize, } from "./deserialize.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,aAAa,EACb,cAAc,GAcf,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEzE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEjE,OAAO,EACL,kBAAkB,GAEnB,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { CompactType, CompactUintType, CompactValueOf } from './types.ts';
2
+ /** The EXCLUSIVE upper bound of a uint descriptor, whichever form it uses. */
3
+ export declare function uintBound(type: CompactUintType): bigint;
4
+ /**
5
+ * Packed byte size of an ALREADY-VALIDATED descriptor. Package-internal: the
6
+ * public {@link compactSerializedSize} validates first.
7
+ */
8
+ export declare function packedSize(type: CompactType): number;
9
+ /** Packed byte size of a type, before `serialize<T, N>`'s right zero-padding. */
10
+ export declare function compactSerializedSize(type: CompactType): number;
11
+ /**
12
+ * Byte-exact twin of `serialize<T, padTo>(value)`. With `padTo` omitted the
13
+ * packed value is returned unpadded, matching `serialize<T, packedSize>`.
14
+ *
15
+ * The value parameter is typed from the descriptor (see `CompactValueOf`), so
16
+ * a literal descriptor gets compile-time checking of the value shape, and the
17
+ * same shape is enforced again at runtime.
18
+ */
19
+ export declare function compactSerialize<const T extends CompactType>(type: T, value: CompactValueOf<T>, padTo?: number): Uint8Array;
20
+ /** Display name of a uint descriptor in its own declaration form. */
21
+ export declare function uintName(type: CompactUintType): string;
22
+ //# sourceMappingURL=serialize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialize.d.ts","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAgB,cAAc,EAAE,MAAM,YAAY,CAAC;AAc7F,8EAA8E;AAC9E,wBAAgB,SAAS,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAIvD;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAqBpD;AAED,iFAAiF;AACjF,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAG/D;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,CAAC,SAAS,WAAW,EAC1D,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EACxB,KAAK,CAAC,EAAE,MAAM,GACb,UAAU,CAeZ;AA8GD,qEAAqE;AACrE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAItD"}
@@ -0,0 +1,206 @@
1
+ // Byte-exact twin of Compact's builtin `serialize<T, N>` from
2
+ // CompactStandardLibrary, pinned against compiled circuits by tests/.
3
+ //
4
+ // Layout rules (compactc 0.33 / language 0.25):
5
+ // - struct fields and tuple elements are packed in declaration order, no
6
+ // alignment gaps
7
+ // - every value is little-endian at its NATURAL width (see src/types.ts);
8
+ // bounded uints and enums are as wide as their largest legal value, which
9
+ // makes `Uint<0..1>` and single-variant enums ZERO bytes wide
10
+ // - `serialize<T, N>` places the packed value at the START of `Bytes<N>` and
11
+ // zero-pads on the right; N below the packed size is a compile error, and
12
+ // this module throws on the same condition.
13
+ //
14
+ // Compact is a strict protocol, so this module is too: every public entry
15
+ // point runs the full recursive descriptor validation (src/validate.ts)
16
+ // before touching a byte, every value is range- and shape-checked at runtime,
17
+ // and every switch has a throwing backstop for anything that slips past the
18
+ // type system.
19
+ import { FIELD_MODULUS } from "./types.js";
20
+ import { assertCompactType, assertUnreachable } from "./validate.js";
21
+ /** Byte length of the largest legal value, given the EXCLUSIVE bound. 0 for a bound of 1. */
22
+ function widthOfBound(bound) {
23
+ let max = bound - 1n;
24
+ let width = 0;
25
+ while (max > 0n) {
26
+ width++;
27
+ max >>= 8n;
28
+ }
29
+ return width;
30
+ }
31
+ /** The EXCLUSIVE upper bound of a uint descriptor, whichever form it uses. */
32
+ export function uintBound(type) {
33
+ return 'bits' in type && type.bits !== undefined
34
+ ? 1n << BigInt(type.bits)
35
+ : BigInt(type.bound);
36
+ }
37
+ /**
38
+ * Packed byte size of an ALREADY-VALIDATED descriptor. Package-internal: the
39
+ * public {@link compactSerializedSize} validates first.
40
+ */
41
+ export function packedSize(type) {
42
+ switch (type.kind) {
43
+ case 'boolean':
44
+ return 1;
45
+ case 'uint':
46
+ return widthOfBound(uintBound(type));
47
+ case 'field':
48
+ return 32;
49
+ case 'bytes':
50
+ return type.length;
51
+ case 'enum':
52
+ return widthOfBound(BigInt(type.variants));
53
+ case 'vector':
54
+ return type.length * packedSize(type.element);
55
+ case 'tuple':
56
+ return type.elements.reduce((sum, e) => sum + packedSize(e), 0);
57
+ case 'struct':
58
+ return type.fields.reduce((sum, f) => sum + packedSize(f.type), 0);
59
+ default:
60
+ return assertUnreachable(type, 'packedSize');
61
+ }
62
+ }
63
+ /** Packed byte size of a type, before `serialize<T, N>`'s right zero-padding. */
64
+ export function compactSerializedSize(type) {
65
+ assertCompactType(type);
66
+ return packedSize(type);
67
+ }
68
+ /**
69
+ * Byte-exact twin of `serialize<T, padTo>(value)`. With `padTo` omitted the
70
+ * packed value is returned unpadded, matching `serialize<T, packedSize>`.
71
+ *
72
+ * The value parameter is typed from the descriptor (see `CompactValueOf`), so
73
+ * a literal descriptor gets compile-time checking of the value shape, and the
74
+ * same shape is enforced again at runtime.
75
+ */
76
+ export function compactSerialize(type, value, padTo) {
77
+ assertCompactType(type);
78
+ if (padTo !== undefined && (!Number.isInteger(padTo) || padTo < 0)) {
79
+ throw new Error(`padTo must be a non-negative integer, got ${String(padTo)}`);
80
+ }
81
+ const size = packedSize(type);
82
+ const total = padTo ?? size;
83
+ if (total < size) {
84
+ throw new Error(`padTo ${total} is below the packed size ${size} (a compile error in Compact too)`);
85
+ }
86
+ const out = new Uint8Array(total);
87
+ encodeInto(out, 0, type, value, 'value');
88
+ return out;
89
+ }
90
+ function encodeInto(out, offset, type, value, label) {
91
+ switch (type.kind) {
92
+ case 'boolean': {
93
+ if (typeof value !== 'boolean')
94
+ throw new Error(`${label}: expected boolean`);
95
+ out[offset] = value ? 1 : 0;
96
+ return offset + 1;
97
+ }
98
+ case 'uint': {
99
+ if (typeof value !== 'bigint')
100
+ throw new Error(`${label}: expected bigint`);
101
+ const bound = uintBound(type);
102
+ const size = widthOfBound(bound);
103
+ if (value >= bound) {
104
+ throw new Error(`${label}: value ${value} exceeds ${uintName(type)}`);
105
+ }
106
+ writeUintLE(out, offset, value, size, label);
107
+ return offset + size;
108
+ }
109
+ case 'field': {
110
+ if (typeof value !== 'bigint')
111
+ throw new Error(`${label}: expected bigint`);
112
+ if (value >= FIELD_MODULUS) {
113
+ throw new Error(`${label}: value ${value} is not below the Field modulus`);
114
+ }
115
+ writeUintLE(out, offset, value, 32, label);
116
+ return offset + 32;
117
+ }
118
+ case 'bytes': {
119
+ if (!(value instanceof Uint8Array))
120
+ throw new Error(`${label}: expected Uint8Array`);
121
+ if (value.length !== type.length) {
122
+ throw new Error(`${label}: expected exactly ${type.length} bytes, got ${value.length}`);
123
+ }
124
+ out.set(value, offset);
125
+ return offset + type.length;
126
+ }
127
+ case 'enum': {
128
+ // Matches the generated bindings: enum values are numbers (the index).
129
+ if (typeof value !== 'number' || !Number.isInteger(value)) {
130
+ throw new Error(`${label}: expected an integer number (enum variant index)`);
131
+ }
132
+ const size = widthOfBound(BigInt(type.variants));
133
+ if (value < 0 || value >= type.variants) {
134
+ throw new Error(`${label}: variant index ${value} is outside 0..${type.variants - 1}`);
135
+ }
136
+ writeUintLE(out, offset, BigInt(value), size, label);
137
+ return offset + size;
138
+ }
139
+ case 'vector': {
140
+ if (!Array.isArray(value))
141
+ throw new Error(`${label}: expected array`);
142
+ if (value.length !== type.length) {
143
+ throw new Error(`${label}: expected exactly ${type.length} elements, got ${value.length}`);
144
+ }
145
+ let cursor = offset;
146
+ value.forEach((element, i) => {
147
+ cursor = encodeInto(out, cursor, type.element, element, `${label}[${i}]`);
148
+ });
149
+ return cursor;
150
+ }
151
+ case 'tuple': {
152
+ if (!Array.isArray(value))
153
+ throw new Error(`${label}: expected array (tuple)`);
154
+ if (value.length !== type.elements.length) {
155
+ throw new Error(`${label}: expected exactly ${type.elements.length} elements, got ${value.length}`);
156
+ }
157
+ let cursor = offset;
158
+ type.elements.forEach((element, i) => {
159
+ cursor = encodeInto(out, cursor, element, value[i], `${label}[${i}]`);
160
+ });
161
+ return cursor;
162
+ }
163
+ case 'struct': {
164
+ if (typeof value !== 'object' ||
165
+ value === null ||
166
+ Array.isArray(value) ||
167
+ value instanceof Uint8Array) {
168
+ throw new Error(`${label}: expected an object`);
169
+ }
170
+ let cursor = offset;
171
+ for (const field of type.fields) {
172
+ // Own-property lookup: field names like 'toString' or '__proto__'
173
+ // are legal Compact identifiers and must not resolve through the
174
+ // JS prototype chain.
175
+ if (!Object.hasOwn(value, field.name)) {
176
+ throw new Error(`${label}: missing field '${field.name}'`);
177
+ }
178
+ const fieldValue = value[field.name];
179
+ cursor = encodeInto(out, cursor, field.type, fieldValue, `${label}.${field.name}`);
180
+ }
181
+ return cursor;
182
+ }
183
+ default:
184
+ return assertUnreachable(type, label);
185
+ }
186
+ }
187
+ /** Display name of a uint descriptor in its own declaration form. */
188
+ export function uintName(type) {
189
+ return 'bits' in type && type.bits !== undefined
190
+ ? `Uint<${type.bits}>`
191
+ : `Uint<0..${type.bound}>`;
192
+ }
193
+ function writeUintLE(out, offset, value, size, label) {
194
+ if (value < 0n) {
195
+ throw new Error(`${label}: negative values cannot be Compact-serialized (got ${value})`);
196
+ }
197
+ if (value >> BigInt(size * 8) !== 0n) {
198
+ throw new Error(`${label}: value ${value} does not fit in ${size} bytes`);
199
+ }
200
+ let v = value;
201
+ for (let i = 0; i < size; i++) {
202
+ out[offset + i] = Number(v & 0xffn);
203
+ v >>= 8n;
204
+ }
205
+ }
206
+ //# sourceMappingURL=serialize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialize.js","sourceRoot":"","sources":["../src/serialize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,132 @@
1
+ /**
2
+ * The BLS12-381 scalar field modulus. A Compact `Field` value must be below
3
+ * it. Matches `maxField + 1n` exported by @midnight-ntwrk/compact-runtime.
4
+ */
5
+ export declare const FIELD_MODULUS = 52435875175126190479447740508185965837690552500527637822603658699938581184513n;
6
+ /** Maximum `Uint` width accepted by compactc 0.33 (bits). */
7
+ export declare const MAX_UINT_BITS = 248;
8
+ /**
9
+ * Maximum EXCLUSIVE bound of a Compact `Uint<0..n>`: 2^248, i.e. one above
10
+ * the language reference's maximum Uint value 256^31 - 1.
11
+ */
12
+ export declare const MAX_UINT_BOUND: bigint;
13
+ /** Compact `Boolean`: 1 byte, 0x00 or 0x01. */
14
+ export interface CompactBooleanType {
15
+ readonly kind: 'boolean';
16
+ }
17
+ /** Compact `Uint<bits>` (sized): ceil(bits / 8) bytes little-endian, bits 1..248. */
18
+ export interface CompactSizedUintType {
19
+ readonly kind: 'uint';
20
+ readonly bits: number;
21
+ }
22
+ /**
23
+ * Compact `Uint<0..bound>` (bounded): values 0 (inclusive) to `bound`
24
+ * EXCLUSIVE, per the language reference. Width is the byte length of
25
+ * `bound - 1`, so `Uint<0..1000>` is 2 bytes and `Uint<0..1>` is ZERO bytes
26
+ * (both circuit-pinned). A number `bound` must be a safe integer; use a
27
+ * bigint beyond 2^53.
28
+ */
29
+ export interface CompactBoundedUintType {
30
+ readonly kind: 'uint';
31
+ readonly bound: number | bigint;
32
+ }
33
+ /**
34
+ * A Compact unsigned integer, in either declaration form. `Uint<w>` is the
35
+ * same type as `Uint<0..2^w>`, so `{ bits: w }` and `{ bound: 1n << w }`
36
+ * describe identical layouts and ranges.
37
+ */
38
+ export type CompactUintType = CompactSizedUintType | CompactBoundedUintType;
39
+ /** Compact `Field`: 32 bytes little-endian, value below {@link FIELD_MODULUS}. */
40
+ export interface CompactFieldType {
41
+ readonly kind: 'field';
42
+ }
43
+ /** Compact `Bytes<length>`: raw bytes, copied verbatim. `Bytes<0>` is legal. */
44
+ export interface CompactBytesType {
45
+ readonly kind: 'bytes';
46
+ readonly length: number;
47
+ }
48
+ /**
49
+ * A Compact enum: the variant INDEX packed exactly like
50
+ * `Uint<0..variants>`, i.e. byte length of `variants - 1` (one byte up to
51
+ * 256 variants, ZERO bytes for a single-variant enum; circuit-pinned).
52
+ * Values are numbers, matching the generated contract bindings.
53
+ */
54
+ export interface CompactEnumType {
55
+ readonly kind: 'enum';
56
+ readonly variants: number;
57
+ }
58
+ /**
59
+ * Compact `Vector<length, element>`: elements back to back, no length
60
+ * prefix. `Vector<0, T>` is legal and zero bytes wide.
61
+ */
62
+ export interface CompactVectorType {
63
+ readonly kind: 'vector';
64
+ readonly length: number;
65
+ readonly element: CompactType;
66
+ }
67
+ /**
68
+ * A Compact tuple `[T1, ..., Tn]`: elements packed in order, no gaps, no
69
+ * prefix, exactly like a struct without field names. `Vector<n, T>` is the
70
+ * homogeneous special case. Values are TypeScript arrays/tuples, matching
71
+ * the generated contract bindings. The empty tuple `[]` is legal and zero
72
+ * bytes wide.
73
+ */
74
+ export interface CompactTupleType {
75
+ readonly kind: 'tuple';
76
+ readonly elements: readonly CompactType[];
77
+ }
78
+ /**
79
+ * A Compact struct: fields packed in declaration order, no gaps, flattened.
80
+ * A struct with no fields is legal and zero bytes wide.
81
+ */
82
+ export interface CompactStructType {
83
+ readonly kind: 'struct';
84
+ readonly fields: readonly {
85
+ readonly name: string;
86
+ readonly type: CompactType;
87
+ }[];
88
+ }
89
+ export type CompactType = CompactBooleanType | CompactUintType | CompactFieldType | CompactBytesType | CompactEnumType | CompactVectorType | CompactTupleType | CompactStructType;
90
+ /**
91
+ * The TypeScript value shapes descriptors map to, matching the generated
92
+ * contract bindings: `Boolean` is boolean, `Uint`/`Field` are bigint, an
93
+ * enum is a number (the variant index), `Bytes` is Uint8Array, `Vector` and
94
+ * tuples are arrays, a struct is a plain object.
95
+ */
96
+ export type CompactValue = boolean | bigint | number | Uint8Array | CompactValue[] | {
97
+ [field: string]: CompactValue;
98
+ };
99
+ /**
100
+ * The precise TypeScript value type of a descriptor. Declare descriptors
101
+ * `as const satisfies CompactType` (or as a plain literal) and both
102
+ * `compactSerialize` and `compactDeserialize` type their values exactly:
103
+ *
104
+ * ```ts
105
+ * const RESULT = {
106
+ * kind: "struct",
107
+ * fields: [
108
+ * { name: "ok", type: { kind: "boolean" } },
109
+ * { name: "amount", type: { kind: "uint", bits: 128 } },
110
+ * ],
111
+ * } as const satisfies CompactType;
112
+ *
113
+ * const value = compactDeserialize(RESULT, bytes);
114
+ * // ^? { ok: boolean; amount: bigint }
115
+ * ```
116
+ *
117
+ * A descriptor WIDENED to `CompactType` degrades gracefully to
118
+ * {@link CompactValue}.
119
+ */
120
+ /**
121
+ * Maps a tuple of descriptors to the tuple of their value types. A separate
122
+ * alias with its own type parameter so the mapped type is homomorphic (an
123
+ * inline `keyof T['elements']` would map method keys too, not just indices).
124
+ */
125
+ type CompactTupleValueOf<E extends readonly CompactType[]> = number extends E['length'] ? CompactValue[] : {
126
+ -readonly [I in keyof E]: CompactValueOf<E[I]>;
127
+ };
128
+ export type CompactValueOf<T extends CompactType> = T extends CompactBooleanType ? boolean : T extends CompactUintType | CompactFieldType ? bigint : T extends CompactEnumType ? number : T extends CompactBytesType ? Uint8Array : T extends CompactVectorType ? CompactValueOf<T['element']>[] : T extends CompactTupleType ? CompactTupleValueOf<T['elements']> : T extends CompactStructType ? {
129
+ -readonly [F in T['fields'][number] as F['name']]: CompactValueOf<F['type']>;
130
+ } : never;
131
+ export {};
132
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,22 @@
1
+ // Type descriptors for Compact circuit types, the runtime mirror of what a
2
+ // contract declares at compile time. A descriptor tree fully determines the
3
+ // byte layout of Compact's builtin `serialize<T, N>` / `deserialize<T, N>`
4
+ // pair, so off-chain code can produce or consume the exact bytes a circuit
5
+ // reads or writes.
6
+ //
7
+ // Coverage: every serializable Compact type has a descriptor kind. The only
8
+ // exclusion is `Opaque<...>`, which compactc itself rejects with
9
+ // "Opaque<...> is not a serializable type".
10
+ /**
11
+ * The BLS12-381 scalar field modulus. A Compact `Field` value must be below
12
+ * it. Matches `maxField + 1n` exported by @midnight-ntwrk/compact-runtime.
13
+ */
14
+ export const FIELD_MODULUS = 0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001n;
15
+ /** Maximum `Uint` width accepted by compactc 0.33 (bits). */
16
+ export const MAX_UINT_BITS = 248;
17
+ /**
18
+ * Maximum EXCLUSIVE bound of a Compact `Uint<0..n>`: 2^248, i.e. one above
19
+ * the language reference's maximum Uint value 256^31 - 1.
20
+ */
21
+ export const MAX_UINT_BOUND = 1n << 248n;
22
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,4EAA4E;AAC5E,2EAA2E;AAC3E,2EAA2E;AAC3E,mBAAmB;AACnB,EAAE;AACF,4EAA4E;AAC5E,iEAAiE;AACjE,4CAA4C;AAE5C;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GACxB,mEAAmE,CAAC;AAEtE,6DAA6D;AAC7D,MAAM,CAAC,MAAM,aAAa,GAAG,GAAG,CAAC;AAEjC;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,IAAI,IAAI,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { CompactType } from './types.ts';
2
+ /**
3
+ * Assert that `type` is a structurally valid {@link CompactType}, recursively.
4
+ * Rejects unknown kinds, unexpected extra keys (typo protection), out-of-range
5
+ * widths and lengths, empty or duplicate struct field names, and any
6
+ * non-object node. Error messages carry the path to the offending node.
7
+ */
8
+ export declare function assertCompactType(type: unknown, label?: string): asserts type is CompactType;
9
+ /** Boolean form of {@link assertCompactType}. */
10
+ export declare function isCompactType(type: unknown): type is CompactType;
11
+ /**
12
+ * Exhaustiveness backstop for descriptor switches. Statically `value` is
13
+ * `never` (every kind handled); at runtime it still throws on anything that
14
+ * slipped past validation instead of falling through to undefined behaviour.
15
+ */
16
+ export declare function assertUnreachable(value: never, label: string): never;
17
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAqB9C;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,OAAO,EACb,KAAK,SAAS,GACb,OAAO,CAAC,IAAI,IAAI,WAAW,CA8H7B;AAED,iDAAiD;AACjD,wBAAgB,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,WAAW,CAOhE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,CAGpE"}
@@ -0,0 +1,155 @@
1
+ // Strict runtime validation of CompactType descriptors. TypeScript checks
2
+ // descriptors at compile time, but descriptors can also arrive from plain JS,
3
+ // JSON, or casts, and Compact is a strict protocol: a malformed descriptor
4
+ // must throw immediately with a path to the offending node, never produce
5
+ // bytes. Every public entry point of this package validates its descriptor
6
+ // through here before doing any work.
7
+ import { MAX_UINT_BITS, MAX_UINT_BOUND } from "./types.js";
8
+ /** The exact keys allowed on each descriptor kind: extra keys are rejected. */
9
+ const KIND_KEYS = {
10
+ boolean: ['kind'],
11
+ uint: ['kind', 'bits', 'bound'],
12
+ field: ['kind'],
13
+ bytes: ['kind', 'length'],
14
+ enum: ['kind', 'variants'],
15
+ vector: ['kind', 'length', 'element'],
16
+ tuple: ['kind', 'elements'],
17
+ struct: ['kind', 'fields'],
18
+ };
19
+ function assertNonNegativeInteger(value, label) {
20
+ if (typeof value !== 'number' || !Number.isInteger(value) || value < 0) {
21
+ throw new Error(`${label} must be a non-negative integer, got ${String(value)}`);
22
+ }
23
+ }
24
+ /**
25
+ * Assert that `type` is a structurally valid {@link CompactType}, recursively.
26
+ * Rejects unknown kinds, unexpected extra keys (typo protection), out-of-range
27
+ * widths and lengths, empty or duplicate struct field names, and any
28
+ * non-object node. Error messages carry the path to the offending node.
29
+ */
30
+ export function assertCompactType(type, label = 'type') {
31
+ if (typeof type !== 'object' || type === null || Array.isArray(type)) {
32
+ throw new Error(`${label}: descriptor must be a plain object`);
33
+ }
34
+ const record = type;
35
+ const kind = record.kind;
36
+ // Object.hasOwn, not `in`: `in` walks the prototype chain, so kinds like
37
+ // 'toString' would slip past and die later with a confusing TypeError.
38
+ if (typeof kind !== 'string' || !Object.hasOwn(KIND_KEYS, kind)) {
39
+ throw new Error(`${label}: unknown descriptor kind ${JSON.stringify(kind)} ` +
40
+ `(expected 'boolean' | 'uint' | 'field' | 'bytes' | 'enum' | 'vector' | 'tuple' | 'struct')`);
41
+ }
42
+ for (const key of Object.keys(record)) {
43
+ if (!KIND_KEYS[kind].includes(key)) {
44
+ throw new Error(`${label}: unexpected key '${key}' on a '${kind}' descriptor`);
45
+ }
46
+ }
47
+ switch (kind) {
48
+ case 'boolean':
49
+ case 'field':
50
+ return;
51
+ case 'uint': {
52
+ const hasBits = record.bits !== undefined;
53
+ const hasBound = record.bound !== undefined;
54
+ if (hasBits === hasBound) {
55
+ throw new Error(`${label}: a uint descriptor needs exactly one of 'bits' (sized Uint<w>) ` +
56
+ `or 'bound' (bounded Uint<0..n>)`);
57
+ }
58
+ if (hasBits) {
59
+ const bits = record.bits;
60
+ if (typeof bits !== 'number' ||
61
+ !Number.isInteger(bits) ||
62
+ bits < 1 ||
63
+ bits > MAX_UINT_BITS) {
64
+ throw new Error(`${label}: uint bits must be an integer in 1..${MAX_UINT_BITS}, got ${String(bits)}`);
65
+ }
66
+ return;
67
+ }
68
+ const bound = record.bound;
69
+ if (typeof bound === 'number' && !Number.isSafeInteger(bound)) {
70
+ throw new Error(`${label}: a number uint bound must be a safe integer (use a bigint ` +
71
+ `beyond 2^53), got ${String(bound)}`);
72
+ }
73
+ if (typeof bound !== 'number' && typeof bound !== 'bigint') {
74
+ throw new Error(`${label}: uint bound must be a number or bigint, got ${String(bound)}`);
75
+ }
76
+ if (BigInt(bound) < 1n || BigInt(bound) > MAX_UINT_BOUND) {
77
+ throw new Error(`${label}: uint bound must be in 1..2^248 (the bound is EXCLUSIVE, ` +
78
+ `matching Uint<0..n>), got ${String(bound)}`);
79
+ }
80
+ return;
81
+ }
82
+ case 'bytes':
83
+ assertNonNegativeInteger(record.length, `${label}: bytes length`);
84
+ return;
85
+ case 'enum': {
86
+ const variants = record.variants;
87
+ if (typeof variants !== 'number' || !Number.isSafeInteger(variants) || variants < 1) {
88
+ throw new Error(`${label}: enum variants must be a positive integer, got ${String(variants)}`);
89
+ }
90
+ return;
91
+ }
92
+ case 'vector':
93
+ assertNonNegativeInteger(record.length, `${label}: vector length`);
94
+ assertCompactType(record.element, `${label}.element`);
95
+ return;
96
+ case 'tuple': {
97
+ const elements = record.elements;
98
+ if (!Array.isArray(elements)) {
99
+ throw new Error(`${label}: tuple elements must be an array`);
100
+ }
101
+ elements.forEach((element, i) => {
102
+ assertCompactType(element, `${label}.elements[${i}]`);
103
+ });
104
+ return;
105
+ }
106
+ case 'struct': {
107
+ const fields = record.fields;
108
+ if (!Array.isArray(fields)) {
109
+ throw new Error(`${label}: struct fields must be an array`);
110
+ }
111
+ const seen = new Set();
112
+ fields.forEach((field, i) => {
113
+ const fieldLabel = `${label}.fields[${i}]`;
114
+ if (typeof field !== 'object' || field === null || Array.isArray(field)) {
115
+ throw new Error(`${fieldLabel}: field must be a plain object`);
116
+ }
117
+ const fieldRecord = field;
118
+ for (const key of Object.keys(fieldRecord)) {
119
+ if (key !== 'name' && key !== 'type') {
120
+ throw new Error(`${fieldLabel}: unexpected key '${key}' on a struct field`);
121
+ }
122
+ }
123
+ if (typeof fieldRecord.name !== 'string' || fieldRecord.name.length === 0) {
124
+ throw new Error(`${fieldLabel}: field name must be a non-empty string`);
125
+ }
126
+ if (seen.has(fieldRecord.name)) {
127
+ throw new Error(`${fieldLabel}: duplicate field name '${fieldRecord.name}'`);
128
+ }
129
+ seen.add(fieldRecord.name);
130
+ assertCompactType(fieldRecord.type, `${fieldLabel}.type`);
131
+ });
132
+ return;
133
+ }
134
+ }
135
+ }
136
+ /** Boolean form of {@link assertCompactType}. */
137
+ export function isCompactType(type) {
138
+ try {
139
+ assertCompactType(type);
140
+ return true;
141
+ }
142
+ catch {
143
+ return false;
144
+ }
145
+ }
146
+ /**
147
+ * Exhaustiveness backstop for descriptor switches. Statically `value` is
148
+ * `never` (every kind handled); at runtime it still throws on anything that
149
+ * slipped past validation instead of falling through to undefined behaviour.
150
+ */
151
+ export function assertUnreachable(value, label) {
152
+ const kind = value?.kind;
153
+ throw new Error(`${label}: unhandled descriptor kind ${JSON.stringify(kind)}`);
154
+ }
155
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../src/validate.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,8EAA8E;AAC9E,2EAA2E;AAC3E,0EAA0E;AAC1E,2EAA2E;AAC3E,sCAAsC;AAGtC,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE3D,+EAA+E;AAC/E,MAAM,SAAS,GAAsC;IACnD,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC;IAC/B,KAAK,EAAE,CAAC,MAAM,CAAC;IACf,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC;IACzB,IAAI,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC;IAC1B,MAAM,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,SAAS,CAAC;IACrC,KAAK,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC;IAC3B,MAAM,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC;CAC3B,CAAC;AAEF,SAAS,wBAAwB,CAAC,KAAc,EAAE,KAAa;IAC7D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;QACvE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,wCAAwC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACnF,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAC/B,IAAa,EACb,KAAK,GAAG,MAAM;IAEd,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,qCAAqC,CAAC,CAAC;IACjE,CAAC;IACD,MAAM,MAAM,GAAG,IAA+B,CAAC;IAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACzB,yEAAyE;IACzE,uEAAuE;IACvE,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,6BAA6B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG;YAC1D,4FAA4F,CAC/F,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACtC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,qBAAqB,GAAG,WAAW,IAAI,cAAc,CAAC,CAAC;QACjF,CAAC;IACH,CAAC;IAED,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,SAAS,CAAC;QACf,KAAK,OAAO;YACV,OAAO;QAET,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC;YAC1C,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC;YAC5C,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,kEAAkE;oBACxE,iCAAiC,CACpC,CAAC;YACJ,CAAC;YACD,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;gBACzB,IACE,OAAO,IAAI,KAAK,QAAQ;oBACxB,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC;oBACvB,IAAI,GAAG,CAAC;oBACR,IAAI,GAAG,aAAa,EACpB,CAAC;oBACD,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,wCAAwC,aAAa,SAAS,MAAM,CAAC,IAAI,CAAC,EAAE,CACrF,CAAC;gBACJ,CAAC;gBACD,OAAO;YACT,CAAC;YACD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;YAC3B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC9D,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,6DAA6D;oBACnE,qBAAqB,MAAM,CAAC,KAAK,CAAC,EAAE,CACvC,CAAC;YACJ,CAAC;YACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC3D,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,gDAAgD,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC3F,CAAC;YACD,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,cAAc,EAAE,CAAC;gBACzD,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,4DAA4D;oBAClE,6BAA6B,MAAM,CAAC,KAAK,CAAC,EAAE,CAC/C,CAAC;YACJ,CAAC;YACD,OAAO;QACT,CAAC;QAED,KAAK,OAAO;YACV,wBAAwB,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,KAAK,gBAAgB,CAAC,CAAC;YAClE,OAAO;QAET,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;YACjC,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,EAAE,CAAC;gBACpF,MAAM,IAAI,KAAK,CACb,GAAG,KAAK,mDAAmD,MAAM,CAAC,QAAQ,CAAC,EAAE,CAC9E,CAAC;YACJ,CAAC;YACD,OAAO;QACT,CAAC;QAED,KAAK,QAAQ;YACX,wBAAwB,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,KAAK,iBAAiB,CAAC,CAAC;YACnE,iBAAiB,CAAC,MAAM,CAAC,OAAO,EAAE,GAAG,KAAK,UAAU,CAAC,CAAC;YACtD,OAAO;QAET,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;YACjC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC7B,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,mCAAmC,CAAC,CAAC;YAC/D,CAAC;YACD,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAgB,EAAE,CAAC,EAAE,EAAE;gBACvC,iBAAiB,CAAC,OAAO,EAAE,GAAG,KAAK,aAAa,CAAC,GAAG,CAAC,CAAC;YACxD,CAAC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;YAC7B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3B,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,kCAAkC,CAAC,CAAC;YAC9D,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;YAC/B,MAAM,CAAC,OAAO,CAAC,CAAC,KAAc,EAAE,CAAC,EAAE,EAAE;gBACnC,MAAM,UAAU,GAAG,GAAG,KAAK,WAAW,CAAC,GAAG,CAAC;gBAC3C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;oBACxE,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,gCAAgC,CAAC,CAAC;gBACjE,CAAC;gBACD,MAAM,WAAW,GAAG,KAAgC,CAAC;gBACrD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;oBAC3C,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;wBACrC,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,qBAAqB,GAAG,qBAAqB,CAAC,CAAC;oBAC9E,CAAC;gBACH,CAAC;gBACD,IAAI,OAAO,WAAW,CAAC,IAAI,KAAK,QAAQ,IAAI,WAAW,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBAC1E,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,yCAAyC,CAAC,CAAC;gBAC1E,CAAC;gBACD,IAAI,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;oBAC/B,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,2BAA2B,WAAW,CAAC,IAAI,GAAG,CAAC,CAAC;gBAC/E,CAAC;gBACD,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;gBAC3B,iBAAiB,CAAC,WAAW,CAAC,IAAI,EAAE,GAAG,UAAU,OAAO,CAAC,CAAC;YAC5D,CAAC,CAAC,CAAC;YACH,OAAO;QACT,CAAC;IACH,CAAC;AACH,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,aAAa,CAAC,IAAa;IACzC,IAAI,CAAC;QACH,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAY,EAAE,KAAa;IAC3D,MAAM,IAAI,GAAI,KAAmC,EAAE,IAAI,CAAC;IACxD,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,+BAA+B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACjF,CAAC"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@sig-net/midnight-serde",
3
+ "version": "0.12.0",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "https://github.com/sig-net/midnight-integration",
7
+ "directory": "packages/midnight-serde"
8
+ },
9
+ "type": "module",
10
+ "description": "TypeScript twin of Compact's builtin serialize<T, N> / deserialize<T, N> byte layout, pinned byte-for-byte against compiled circuits.",
11
+ "//exports": "Local dev consumes raw TS source. `publishConfig.exports` below swaps this to the emitted ./dist at publish time, so npm consumers get JS + .d.ts while the monorepo keeps resolving to src.",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "scripts": {
22
+ "compile": "compact compile --skip-zk --feature-zkir-v3 tests/fixtures/serde-fixtures.compact tests/fixtures/managed",
23
+ "build": "rm -rf dist && tsc -p tsconfig.json && tsc -p tsconfig.build.json",
24
+ "prepack": "yarn build",
25
+ "test": "vitest run"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public",
29
+ "main": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "default": "./dist/index.js"
35
+ }
36
+ }
37
+ },
38
+ "devDependencies": {
39
+ "@midnight-ntwrk/compact-runtime": "0.18.0-rc.1",
40
+ "@types/node": "^26.1.0",
41
+ "typescript": "^6.0.3",
42
+ "vitest": "^4.1.9"
43
+ },
44
+ "main": "./dist/index.js",
45
+ "types": "./dist/index.d.ts"
46
+ }