@aztec/foundation 5.0.0-private.20260319 → 5.0.0-rc.2
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/dest/bigint-buffer/index.d.ts +1 -1
- package/dest/bigint-buffer/index.d.ts.map +1 -1
- package/dest/bigint-buffer/index.js +6 -1
- package/dest/branded-types/block_number.d.ts +3 -3
- package/dest/branded-types/block_number.d.ts.map +1 -1
- package/dest/branded-types/block_number.js +15 -4
- package/dest/branded-types/buffer32_hash.d.ts +27 -0
- package/dest/branded-types/buffer32_hash.d.ts.map +1 -0
- package/dest/branded-types/buffer32_hash.js +12 -0
- package/dest/branded-types/checkpoint_number.d.ts +9 -3
- package/dest/branded-types/checkpoint_number.d.ts.map +1 -1
- package/dest/branded-types/checkpoint_number.js +11 -0
- package/dest/branded-types/epoch.d.ts +2 -2
- package/dest/branded-types/epoch.d.ts.map +1 -1
- package/dest/branded-types/index.d.ts +2 -1
- package/dest/branded-types/index.d.ts.map +1 -1
- package/dest/branded-types/index.js +1 -0
- package/dest/branded-types/index_within_checkpoint.d.ts +2 -2
- package/dest/branded-types/index_within_checkpoint.d.ts.map +1 -1
- package/dest/branded-types/slot.d.ts +5 -2
- package/dest/branded-types/slot.d.ts.map +1 -1
- package/dest/branded-types/slot.js +3 -0
- package/dest/buffer/buffer16.d.ts +3 -1
- package/dest/buffer/buffer16.d.ts.map +1 -1
- package/dest/buffer/buffer32.d.ts +28 -61
- package/dest/buffer/buffer32.d.ts.map +1 -1
- package/dest/buffer/buffer32.js +29 -63
- package/dest/collection/array.d.ts +11 -1
- package/dest/collection/array.d.ts.map +1 -1
- package/dest/collection/array.js +33 -0
- package/dest/collection/index.d.ts +3 -1
- package/dest/collection/index.d.ts.map +1 -1
- package/dest/collection/index.js +2 -0
- package/dest/collection/lru_map.d.ts +41 -0
- package/dest/collection/lru_map.d.ts.map +1 -0
- package/dest/collection/lru_map.js +119 -0
- package/dest/collection/lru_set.d.ts +35 -0
- package/dest/collection/lru_set.d.ts.map +1 -0
- package/dest/collection/lru_set.js +95 -0
- package/dest/committable/committable.js +1 -1
- package/dest/config/env_var.d.ts +2 -2
- package/dest/config/env_var.d.ts.map +1 -1
- package/dest/config/index.d.ts +47 -30
- package/dest/config/index.d.ts.map +1 -1
- package/dest/config/index.js +30 -45
- package/dest/config/network_config.d.ts +11 -55
- package/dest/config/network_config.d.ts.map +1 -1
- package/dest/config/network_name.d.ts +2 -2
- package/dest/config/network_name.d.ts.map +1 -1
- package/dest/config/network_name.js +1 -3
- package/dest/config/secret_value.d.ts +2 -2
- package/dest/config/secret_value.d.ts.map +1 -1
- package/dest/crypto/aes128/index.d.ts +2 -1
- package/dest/crypto/aes128/index.d.ts.map +1 -1
- package/dest/crypto/aes128/index.js +11 -2
- package/dest/crypto/bls/bn254_keystore.d.ts +9 -176
- package/dest/crypto/bls/bn254_keystore.d.ts.map +1 -1
- package/dest/crypto/bls/bn254_keystore.js +0 -17
- package/dest/crypto/poseidon/index.d.ts +1 -1
- package/dest/crypto/poseidon/index.d.ts.map +1 -1
- package/dest/crypto/poseidon/index.js +40 -33
- package/dest/crypto/schnorr/index.d.ts +8 -7
- package/dest/crypto/schnorr/index.d.ts.map +1 -1
- package/dest/crypto/schnorr/index.js +6 -6
- package/dest/crypto/schnorr/signature.d.ts +9 -29
- package/dest/crypto/schnorr/signature.d.ts.map +1 -1
- package/dest/crypto/schnorr/signature.js +20 -36
- package/dest/curves/bls12/field.d.ts +3 -3
- package/dest/curves/bls12/field.d.ts.map +1 -1
- package/dest/curves/bls12/field.js +0 -5
- package/dest/curves/bls12/point.d.ts +2 -2
- package/dest/curves/bls12/point.d.ts.map +1 -1
- package/dest/curves/bn254/field.d.ts +23 -19
- package/dest/curves/bn254/field.d.ts.map +1 -1
- package/dest/curves/bn254/field.js +23 -17
- package/dest/curves/grumpkin/point.d.ts +14 -28
- package/dest/curves/grumpkin/point.d.ts.map +1 -1
- package/dest/curves/grumpkin/point.js +29 -43
- package/dest/eth-address/index.d.ts +2 -2
- package/dest/eth-address/index.d.ts.map +1 -1
- package/dest/eth-address/index.js +0 -3
- package/dest/eth-signature/eth_signature.d.ts +2 -2
- package/dest/eth-signature/eth_signature.d.ts.map +1 -1
- package/dest/fifo/fifo_frame_reader.d.ts +41 -0
- package/dest/fifo/fifo_frame_reader.d.ts.map +1 -0
- package/dest/fifo/fifo_frame_reader.js +74 -0
- package/dest/fifo/index.d.ts +2 -0
- package/dest/fifo/index.d.ts.map +1 -0
- package/dest/fifo/index.js +1 -0
- package/dest/fifo_set/fifo_set.d.ts +15 -0
- package/dest/fifo_set/fifo_set.d.ts.map +1 -0
- package/dest/fifo_set/fifo_set.js +39 -0
- package/dest/fifo_set/index.d.ts +2 -0
- package/dest/fifo_set/index.d.ts.map +1 -0
- package/dest/fifo_set/index.js +1 -0
- package/dest/json-rpc/client/fetch.d.ts +1 -1
- package/dest/json-rpc/client/fetch.d.ts.map +1 -1
- package/dest/json-rpc/client/fetch.js +4 -3
- package/dest/json-rpc/client/safe_json_rpc_client.d.ts +1 -1
- package/dest/json-rpc/client/safe_json_rpc_client.d.ts.map +1 -1
- package/dest/json-rpc/client/safe_json_rpc_client.js +2 -2
- package/dest/json-rpc/client/undici.d.ts +1 -1
- package/dest/json-rpc/client/undici.d.ts.map +1 -1
- package/dest/json-rpc/client/undici.js +5 -3
- package/dest/json-rpc/fixtures/test_state.d.ts +4 -8
- package/dest/json-rpc/fixtures/test_state.d.ts.map +1 -1
- package/dest/json-rpc/fixtures/test_state.js +57 -17
- package/dest/json-rpc/server/safe_json_rpc_server.d.ts +8 -3
- package/dest/json-rpc/server/safe_json_rpc_server.d.ts.map +1 -1
- package/dest/json-rpc/server/safe_json_rpc_server.js +27 -13
- package/dest/log/pino-logger.d.ts +1 -1
- package/dest/log/pino-logger.d.ts.map +1 -1
- package/dest/log/pino-logger.js +17 -2
- package/dest/noir/noir_package_config.d.ts +19 -104
- package/dest/noir/noir_package_config.d.ts.map +1 -1
- package/dest/noir/noir_package_config.js +1 -1
- package/dest/queue/batch_queue.d.ts +1 -1
- package/dest/queue/batch_queue.d.ts.map +1 -1
- package/dest/queue/batch_queue.js +1 -0
- package/dest/retry/index.d.ts +31 -3
- package/dest/retry/index.d.ts.map +1 -1
- package/dest/retry/index.js +44 -2
- package/dest/schemas/api.d.ts +12 -10
- package/dest/schemas/api.d.ts.map +1 -1
- package/dest/schemas/api.js +7 -1
- package/dest/schemas/parse.d.ts +4 -4
- package/dest/schemas/parse.d.ts.map +1 -1
- package/dest/schemas/parse.js +6 -5
- package/dest/schemas/schemas.d.ts +15 -15
- package/dest/schemas/types.d.ts +3 -3
- package/dest/schemas/types.d.ts.map +1 -1
- package/dest/schemas/utils.d.ts +7 -11
- package/dest/schemas/utils.d.ts.map +1 -1
- package/dest/schemas/utils.js +2 -18
- package/dest/serialize/buffer_sink.d.ts +134 -0
- package/dest/serialize/buffer_sink.d.ts.map +1 -0
- package/dest/serialize/buffer_sink.js +297 -0
- package/dest/serialize/index.d.ts +2 -1
- package/dest/serialize/index.d.ts.map +1 -1
- package/dest/serialize/index.js +1 -0
- package/dest/string/index.js +1 -1
- package/dest/timer/index.d.ts +2 -2
- package/dest/timer/index.d.ts.map +1 -1
- package/dest/timer/index.js +1 -1
- package/dest/timer/timeout.d.ts +3 -1
- package/dest/timer/timeout.d.ts.map +1 -1
- package/dest/timer/timeout.js +26 -0
- package/dest/transport/dispatch/create_dispatch_proxy.d.ts +11 -2
- package/dest/transport/dispatch/create_dispatch_proxy.d.ts.map +1 -1
- package/dest/transport/index.d.ts +1 -2
- package/dest/transport/index.d.ts.map +1 -1
- package/dest/transport/index.js +0 -1
- package/dest/trees/balanced_merkle_tree_root.d.ts +2 -3
- package/dest/trees/balanced_merkle_tree_root.d.ts.map +1 -1
- package/dest/trees/balanced_merkle_tree_root.js +2 -3
- package/dest/trees/hasher.d.ts +3 -2
- package/dest/trees/hasher.d.ts.map +1 -1
- package/dest/trees/hasher.js +5 -5
- package/dest/trees/indexed_merkle_tree_calculator.d.ts +1 -1
- package/dest/trees/indexed_merkle_tree_calculator.d.ts.map +1 -1
- package/dest/trees/indexed_merkle_tree_calculator.js +5 -1
- package/dest/trees/membership_witness.d.ts +2 -6
- package/dest/trees/membership_witness.d.ts.map +1 -1
- package/dest/trees/membership_witness.js +0 -9
- package/dest/trees/merkle_tree_calculator.d.ts +4 -2
- package/dest/trees/merkle_tree_calculator.d.ts.map +1 -1
- package/dest/trees/merkle_tree_calculator.js +1 -5
- package/dest/trees/sibling_path.d.ts +5 -4
- package/dest/trees/sibling_path.d.ts.map +1 -1
- package/dest/trees/sibling_path.js +10 -8
- package/dest/trees/unbalanced_merkle_tree_root.d.ts +2 -3
- package/dest/trees/unbalanced_merkle_tree_root.d.ts.map +1 -1
- package/dest/trees/unbalanced_merkle_tree_root.js +2 -3
- package/dest/types/index.d.ts +23 -1
- package/dest/types/index.d.ts.map +1 -1
- package/dest/types/index.js +15 -0
- package/package.json +6 -4
- package/src/bigint-buffer/index.ts +6 -1
- package/src/branded-types/block_number.ts +20 -2
- package/src/branded-types/buffer32_hash.ts +38 -0
- package/src/branded-types/checkpoint_number.ts +16 -1
- package/src/branded-types/epoch.ts +1 -1
- package/src/branded-types/index.ts +1 -0
- package/src/branded-types/index_within_checkpoint.ts +1 -1
- package/src/branded-types/slot.ts +6 -1
- package/src/buffer/buffer16.ts +3 -0
- package/src/buffer/buffer32.ts +39 -68
- package/src/collection/array.ts +34 -0
- package/src/collection/index.ts +2 -0
- package/src/collection/lru_map.ts +143 -0
- package/src/collection/lru_set.ts +115 -0
- package/src/committable/committable.ts +1 -1
- package/src/config/env_var.ts +39 -24
- package/src/config/index.ts +102 -97
- package/src/config/network_name.ts +2 -5
- package/src/config/secret_value.ts +1 -1
- package/src/crypto/aes128/index.ts +11 -2
- package/src/crypto/bls/bn254_keystore.ts +0 -23
- package/src/crypto/poseidon/index.ts +42 -34
- package/src/crypto/schnorr/index.ts +9 -8
- package/src/crypto/schnorr/signature.ts +17 -46
- package/src/curves/bls12/field.ts +0 -7
- package/src/curves/bn254/field.ts +35 -34
- package/src/curves/grumpkin/point.ts +23 -40
- package/src/eth-address/index.ts +0 -4
- package/src/fifo/fifo_frame_reader.ts +98 -0
- package/src/fifo/index.ts +1 -0
- package/src/fifo_set/fifo_set.ts +52 -0
- package/src/fifo_set/index.ts +1 -0
- package/src/json-rpc/client/fetch.ts +4 -3
- package/src/json-rpc/client/safe_json_rpc_client.ts +2 -2
- package/src/json-rpc/client/undici.ts +5 -3
- package/src/json-rpc/fixtures/test_state.ts +10 -10
- package/src/json-rpc/server/safe_json_rpc_server.ts +31 -13
- package/src/log/pino-logger.ts +19 -2
- package/src/noir/noir_package_config.ts +32 -20
- package/src/queue/batch_queue.ts +1 -0
- package/src/retry/index.ts +66 -4
- package/src/schemas/api.ts +25 -25
- package/src/schemas/parse.ts +9 -6
- package/src/schemas/schemas.ts +4 -4
- package/src/schemas/types.ts +2 -2
- package/src/schemas/utils.ts +4 -38
- package/src/serialize/buffer_sink.ts +350 -0
- package/src/serialize/index.ts +1 -0
- package/src/string/index.ts +1 -1
- package/src/timer/index.ts +1 -1
- package/src/timer/timeout.ts +31 -0
- package/src/transport/dispatch/create_dispatch_proxy.ts +11 -1
- package/src/transport/index.ts +0 -1
- package/src/trees/balanced_merkle_tree_root.ts +2 -5
- package/src/trees/hasher.ts +6 -3
- package/src/trees/indexed_merkle_tree_calculator.ts +5 -1
- package/src/trees/membership_witness.ts +0 -8
- package/src/trees/merkle_tree_calculator.ts +4 -10
- package/src/trees/sibling_path.ts +11 -6
- package/src/trees/unbalanced_merkle_tree_root.ts +2 -5
- package/src/types/index.ts +47 -0
- package/dest/crypto/serialize.d.ts +0 -51
- package/dest/crypto/serialize.d.ts.map +0 -1
- package/dest/crypto/serialize.js +0 -68
- package/dest/transport/dispatch/create_dispatch_fn.d.ts +0 -25
- package/dest/transport/dispatch/create_dispatch_fn.d.ts.map +0 -1
- package/dest/transport/dispatch/create_dispatch_fn.js +0 -17
- package/src/crypto/serialize.ts +0 -85
- package/src/transport/dispatch/create_dispatch_fn.ts +0 -35
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/** A Set capped to a fixed number of entries, evicting the oldest inserted value when full. */
|
|
2
|
+
export class FifoSet<T> extends Set<T> {
|
|
3
|
+
private _limit: number | undefined;
|
|
4
|
+
|
|
5
|
+
private constructor(values?: Iterable<T>) {
|
|
6
|
+
super(values);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** Creates a bounded set with a positive integer limit. */
|
|
10
|
+
static withLimit<T>(limit: number, values?: Iterable<T>): FifoSet<T> {
|
|
11
|
+
if (!Number.isSafeInteger(limit) || limit <= 0) {
|
|
12
|
+
throw new TypeError(`FifoSet limit must be a positive safe integer: ${limit}`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const set = new FifoSet(values);
|
|
16
|
+
set._limit = limit;
|
|
17
|
+
set.compact();
|
|
18
|
+
|
|
19
|
+
return set;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
override add(value: T): this {
|
|
23
|
+
super.add(value);
|
|
24
|
+
this.compact();
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Maximum number of entries retained by this set. */
|
|
29
|
+
public get limit(): number {
|
|
30
|
+
return this._limit ?? Infinity;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Evicts oldest entries until the set is within its limit. */
|
|
34
|
+
public compact(): void {
|
|
35
|
+
while (this.size > this.limit) {
|
|
36
|
+
const head = this.values().next();
|
|
37
|
+
if (head.done) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
this.delete(head.value);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Adds a value only if it is absent, returning whether the set changed. */
|
|
45
|
+
public addIfAbsent(value: T): boolean {
|
|
46
|
+
if (this.has(value)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
this.add(value);
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './fifo_set.js';
|
|
@@ -43,17 +43,18 @@ export async function defaultFetch(
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
let responseJson;
|
|
46
|
+
const responseText = await resp.text();
|
|
46
47
|
try {
|
|
47
|
-
responseJson =
|
|
48
|
+
responseJson = JSON.parse(responseText);
|
|
48
49
|
} catch {
|
|
49
50
|
if (!resp.ok) {
|
|
50
51
|
throw new Error(resp.statusText);
|
|
51
52
|
}
|
|
52
|
-
throw new Error(`Failed to parse body as JSON: ${
|
|
53
|
+
throw new Error(`Failed to parse body as JSON: ${responseText}`);
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
if (!resp.ok) {
|
|
56
|
-
const errorMessage = `Error ${resp.status} from server ${host}: ${responseJson
|
|
57
|
+
const errorMessage = `Error ${resp.status} from server ${host}: ${responseJson?.error?.message ?? JSON.stringify(responseJson)}`;
|
|
57
58
|
if (noRetry || (resp.status >= 400 && resp.status < 500)) {
|
|
58
59
|
throw new NoRetryError(errorMessage);
|
|
59
60
|
} else {
|
|
@@ -2,7 +2,7 @@ import { format } from 'util';
|
|
|
2
2
|
|
|
3
3
|
import { type Logger, createLogger } from '../../log/pino-logger.js';
|
|
4
4
|
import { type PromiseWithResolvers, promiseWithResolvers } from '../../promise/utils.js';
|
|
5
|
-
import { type ApiSchema, type ApiSchemaFor, schemaHasMethod } from '../../schemas/api.js';
|
|
5
|
+
import { type ApiSchema, type ApiSchemaFor, getSchemaReturnType, schemaHasMethod } from '../../schemas/api.js';
|
|
6
6
|
import { jsonStringify } from '../convert.js';
|
|
7
7
|
import { type JsonRpcFetch, defaultFetch } from './fetch.js';
|
|
8
8
|
|
|
@@ -236,7 +236,7 @@ export function createSafeJsonRpcClient<T extends object>(
|
|
|
236
236
|
if ([null, undefined, 'null', 'undefined'].includes(response.result)) {
|
|
237
237
|
return;
|
|
238
238
|
}
|
|
239
|
-
return (schema as ApiSchema)[methodName]
|
|
239
|
+
return getSchemaReturnType((schema as ApiSchema)[methodName]).parseAsync(response.result);
|
|
240
240
|
};
|
|
241
241
|
|
|
242
242
|
const clientId = nextClientId++;
|
|
@@ -44,18 +44,20 @@ export function makeUndiciFetch(client = new Agent()): JsonRpcFetch {
|
|
|
44
44
|
let responseJson: any;
|
|
45
45
|
const responseOk = resp.statusCode >= 200 && resp.statusCode <= 299;
|
|
46
46
|
const contentEncoding = resp.headers['content-encoding'];
|
|
47
|
+
let responseText: string;
|
|
47
48
|
try {
|
|
48
49
|
if (contentEncoding === 'gzip') {
|
|
49
50
|
const jsonBuffer = await gunzip(await resp.body.arrayBuffer());
|
|
50
|
-
|
|
51
|
+
responseText = jsonBuffer.toString('utf-8');
|
|
51
52
|
} else {
|
|
52
|
-
|
|
53
|
+
responseText = await resp.body.text();
|
|
53
54
|
}
|
|
55
|
+
responseJson = JSON.parse(responseText);
|
|
54
56
|
} catch {
|
|
55
57
|
if (!responseOk) {
|
|
56
58
|
throw new Error('HTTP ' + resp.statusCode);
|
|
57
59
|
}
|
|
58
|
-
throw new Error(`Failed to parse body as JSON. encoding: ${contentEncoding}, body: ${
|
|
60
|
+
throw new Error(`Failed to parse body as JSON. encoding: ${contentEncoding}, body: ${responseText!}`);
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
if (!responseOk) {
|
|
@@ -130,14 +130,14 @@ export class TestState implements TestStateApi {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
export const TestStateSchema: ApiSchemaFor<TestStateApi> = {
|
|
133
|
-
getNote: z.function(
|
|
134
|
-
getNotes: z.function(
|
|
135
|
-
getNotes2: z.function(
|
|
136
|
-
getNotes3: z.function(
|
|
137
|
-
clear: z.function(
|
|
138
|
-
addNotes: z.function(
|
|
139
|
-
fail: z.function(
|
|
140
|
-
count: z.function(
|
|
141
|
-
getStatus: z.function(
|
|
142
|
-
getTuple: z.function(
|
|
133
|
+
getNote: z.function({ input: z.tuple([z.number()]), output: TestNote.schema.optional() }),
|
|
134
|
+
getNotes: z.function({ input: z.tuple([optional(schemas.Integer)]), output: z.array(TestNote.schema) }),
|
|
135
|
+
getNotes2: z.function({ input: z.tuple([optional(schemas.BigInt)]), output: z.array(TestNote.schema) }),
|
|
136
|
+
getNotes3: z.function({ input: z.tuple([optional(schemas.Integer)]), output: z.array(TestNote.schema) }),
|
|
137
|
+
clear: z.function({ input: z.tuple([]), output: z.void() }),
|
|
138
|
+
addNotes: z.function({ input: z.tuple([z.array(TestNote.schema)]), output: z.array(TestNote.schema) }),
|
|
139
|
+
fail: z.function({ input: z.tuple([]), output: z.void() }),
|
|
140
|
+
count: z.function({ input: z.tuple([]), output: z.number() }),
|
|
141
|
+
getStatus: z.function({ input: z.tuple([]), output: z.object({ status: z.string(), count: schemas.BigInt }) }),
|
|
142
|
+
getTuple: z.function({ input: z.tuple([]), output: z.tuple([z.string(), optional(z.string()), z.number()]) }),
|
|
143
143
|
};
|
|
@@ -10,7 +10,13 @@ import { ZodError } from 'zod';
|
|
|
10
10
|
|
|
11
11
|
import { type Logger, createLogger } from '../../log/index.js';
|
|
12
12
|
import { promiseWithResolvers } from '../../promise/utils.js';
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
type ApiSchema,
|
|
15
|
+
type ApiSchemaFor,
|
|
16
|
+
getSchemaParameters,
|
|
17
|
+
parseWithOptionals,
|
|
18
|
+
schemaHasMethod,
|
|
19
|
+
} from '../../schemas/index.js';
|
|
14
20
|
import { jsonStringify } from '../convert.js';
|
|
15
21
|
import { assert } from '../js_utils.js';
|
|
16
22
|
|
|
@@ -53,8 +59,10 @@ export class SafeJsonRpcServer {
|
|
|
53
59
|
config: Partial<SafeJsonRpcServerConfig> = {},
|
|
54
60
|
/** Health check function */
|
|
55
61
|
private readonly healthCheck: StatusCheckFn = () => true,
|
|
56
|
-
/** Additional middlewares */
|
|
62
|
+
/** Additional Koa middlewares */
|
|
57
63
|
private extraMiddlewares: Application.Middleware[] = [],
|
|
64
|
+
/** Additional per-request diagnostics middlewares */
|
|
65
|
+
private diagnosticsMiddleware?: DiagnosticsMiddleware,
|
|
58
66
|
/** Logger */
|
|
59
67
|
private log = createLogger('json-rpc:server'),
|
|
60
68
|
) {
|
|
@@ -155,7 +163,7 @@ export class SafeJsonRpcServer {
|
|
|
155
163
|
};
|
|
156
164
|
return;
|
|
157
165
|
}
|
|
158
|
-
const resp = await this.processBatch(ctx.request.body);
|
|
166
|
+
const resp = await this.processBatch(ctx.request.body, ctx.request.headers);
|
|
159
167
|
if (Array.isArray(resp)) {
|
|
160
168
|
ctx.status = 200;
|
|
161
169
|
ctx.body = resp;
|
|
@@ -164,7 +172,7 @@ export class SafeJsonRpcServer {
|
|
|
164
172
|
ctx.body = resp;
|
|
165
173
|
}
|
|
166
174
|
} else {
|
|
167
|
-
const resp = await this.processRequest(ctx.request.body);
|
|
175
|
+
const resp = await this.processRequest(ctx.request.body, ctx.request.headers);
|
|
168
176
|
if ('error' in resp) {
|
|
169
177
|
ctx.status = this.config.http200OnError ? 200 : 400;
|
|
170
178
|
}
|
|
@@ -176,11 +184,11 @@ export class SafeJsonRpcServer {
|
|
|
176
184
|
return router;
|
|
177
185
|
}
|
|
178
186
|
|
|
179
|
-
private async processBatch(requests: any[]) {
|
|
187
|
+
private async processBatch(requests: any[], headers: http.IncomingHttpHeaders = {}) {
|
|
180
188
|
if (requests.length === 0) {
|
|
181
189
|
return { jsonrpc: '2.0', error: { code: -32600, message: 'Invalid Request' }, id: null };
|
|
182
190
|
}
|
|
183
|
-
const results = await Promise.allSettled(requests.map(req => this.processRequest(req)));
|
|
191
|
+
const results = await Promise.allSettled(requests.map(req => this.processRequest(req, headers)));
|
|
184
192
|
return results.map(res => {
|
|
185
193
|
if (res.status === 'fulfilled') {
|
|
186
194
|
return res.value;
|
|
@@ -191,7 +199,7 @@ export class SafeJsonRpcServer {
|
|
|
191
199
|
});
|
|
192
200
|
}
|
|
193
201
|
|
|
194
|
-
private async processRequest(request: any) {
|
|
202
|
+
private async processRequest(request: any, headers: http.IncomingHttpHeaders = {}) {
|
|
195
203
|
if (!request || typeof request !== 'object') {
|
|
196
204
|
return { jsonrpc: '2.0', error: { code: -32600, message: 'Invalid Request' }, id: null };
|
|
197
205
|
}
|
|
@@ -206,7 +214,16 @@ export class SafeJsonRpcServer {
|
|
|
206
214
|
return { jsonrpc, id, error: { code: -32601, message: `Method not found: ${method}` } };
|
|
207
215
|
} else {
|
|
208
216
|
try {
|
|
209
|
-
|
|
217
|
+
let result: any;
|
|
218
|
+
|
|
219
|
+
if (this.diagnosticsMiddleware) {
|
|
220
|
+
await this.diagnosticsMiddleware({ id: id ?? null, method, params, headers }, async () => {
|
|
221
|
+
result = await this.proxy.call(method, params);
|
|
222
|
+
});
|
|
223
|
+
} else {
|
|
224
|
+
result = await this.proxy.call(method, params);
|
|
225
|
+
}
|
|
226
|
+
|
|
210
227
|
return { jsonrpc, id, result };
|
|
211
228
|
} catch (err: any) {
|
|
212
229
|
if (err && err instanceof ZodError) {
|
|
@@ -309,7 +326,7 @@ export class SafeJsonProxy<T extends object = any> implements Proxy {
|
|
|
309
326
|
assert(schemaHasMethod(this.schema, methodName), `Method ${methodName} not found in schema`);
|
|
310
327
|
const method = this.handler[methodName as keyof T];
|
|
311
328
|
assert(typeof method === 'function', `Method ${methodName} is not a function`);
|
|
312
|
-
const args = await parseWithOptionals(jsonParams, this.schema[methodName]
|
|
329
|
+
const args = await parseWithOptionals(jsonParams, getSchemaParameters(this.schema[methodName]));
|
|
313
330
|
const ret = await method.apply(this.handler, args);
|
|
314
331
|
this.log.debug(format('response', methodName, ret));
|
|
315
332
|
return ret;
|
|
@@ -377,6 +394,7 @@ function makeAggregateHealthcheck(namedHandlers: NamespacedApiHandlers, log?: Lo
|
|
|
377
394
|
export type SafeJsonRpcServerOptions = Partial<
|
|
378
395
|
SafeJsonRpcServerConfig & {
|
|
379
396
|
healthCheck: StatusCheckFn;
|
|
397
|
+
diagnostic: DiagnosticsMiddleware;
|
|
380
398
|
log: Logger;
|
|
381
399
|
middlewares: Application.Middleware[];
|
|
382
400
|
}
|
|
@@ -391,10 +409,10 @@ export function createNamespacedSafeJsonRpcServer(
|
|
|
391
409
|
handlers: NamespacedApiHandlers,
|
|
392
410
|
options: Omit<SafeJsonRpcServerOptions, 'healthcheck'> = {},
|
|
393
411
|
): SafeJsonRpcServer {
|
|
394
|
-
const { middlewares, log } = options;
|
|
412
|
+
const { diagnostic, middlewares, log } = options;
|
|
395
413
|
const proxy = new NamespacedSafeJsonProxy(handlers);
|
|
396
414
|
const healthCheck = makeAggregateHealthcheck(handlers, log);
|
|
397
|
-
return new SafeJsonRpcServer(proxy, options, healthCheck, middlewares, log);
|
|
415
|
+
return new SafeJsonRpcServer(proxy, options, healthCheck, middlewares, diagnostic, log);
|
|
398
416
|
}
|
|
399
417
|
|
|
400
418
|
export function createSafeJsonRpcServer<T extends object = any>(
|
|
@@ -402,9 +420,9 @@ export function createSafeJsonRpcServer<T extends object = any>(
|
|
|
402
420
|
schema: ApiSchemaFor<T>,
|
|
403
421
|
options: SafeJsonRpcServerOptions = {},
|
|
404
422
|
) {
|
|
405
|
-
const { log, healthCheck, middlewares: extraMiddlewares } = options;
|
|
423
|
+
const { diagnostic, log, healthCheck, middlewares: extraMiddlewares } = options;
|
|
406
424
|
const proxy = new SafeJsonProxy(handler, schema);
|
|
407
|
-
return new SafeJsonRpcServer(proxy, options, healthCheck, extraMiddlewares, log);
|
|
425
|
+
return new SafeJsonRpcServer(proxy, options, healthCheck, extraMiddlewares, diagnostic, log);
|
|
408
426
|
}
|
|
409
427
|
|
|
410
428
|
/**
|
package/src/log/pino-logger.ts
CHANGED
|
@@ -21,6 +21,8 @@ export type LoggerBindings = {
|
|
|
21
21
|
instanceId?: string;
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
+
const MAX_MODULE_NAME_LENGTH = 256;
|
|
25
|
+
|
|
24
26
|
// Allow global hooks for providing default bindings.
|
|
25
27
|
// Used by withLoggerBindings in pino-logger-server to propagate bindings via AsyncLocalStorage.
|
|
26
28
|
type LogBindingsHandler = () => LoggerBindings | undefined;
|
|
@@ -48,7 +50,7 @@ function getBindingsFromHandlers(): LoggerBindings | undefined {
|
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
export function createLogger(module: string, bindings?: LoggerBindings): Logger {
|
|
51
|
-
module = module.replace(/^aztec:/, '');
|
|
53
|
+
module = module.slice(0, MAX_MODULE_NAME_LENGTH).replace(/^aztec:/, '');
|
|
52
54
|
|
|
53
55
|
const resolvedBindings = { ...getBindingsFromHandlers(), ...bindings };
|
|
54
56
|
const actor = resolvedBindings?.actor;
|
|
@@ -375,5 +377,20 @@ export type Logger = { [K in LogLevel]: LogFn } & { /** Error log function */ er
|
|
|
375
377
|
* @returns A string with both the log message and the error message.
|
|
376
378
|
*/
|
|
377
379
|
function formatErr(msg: string, err?: unknown): string {
|
|
378
|
-
|
|
380
|
+
if (!err) {
|
|
381
|
+
return msg;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
try {
|
|
385
|
+
return `${msg}: ${inspect(err)}`;
|
|
386
|
+
} catch {
|
|
387
|
+
// inspect can crash on error objects with broken property descriptors
|
|
388
|
+
try {
|
|
389
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
390
|
+
return `${msg}: ${err instanceof Error ? `${err.name}: ${err.message}` : String(err)}`;
|
|
391
|
+
} catch {
|
|
392
|
+
// if even String(err) fails, return the original message with a note about the error
|
|
393
|
+
return `${msg}: [unserializable error]`;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
379
396
|
}
|
|
@@ -10,26 +10,6 @@ const noirLocalDependencySchema = z.object({
|
|
|
10
10
|
path: z.string(),
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
const noirPackageConfigSchema = z.object({
|
|
14
|
-
package: z.object({
|
|
15
|
-
name: z.string().default(''),
|
|
16
|
-
type: z.enum(['lib', 'contract', 'bin']).default('bin'),
|
|
17
|
-
entry: z.string().optional(),
|
|
18
|
-
description: z.string().optional(),
|
|
19
|
-
authors: z.array(z.string()).optional(),
|
|
20
|
-
// eslint-disable-next-line camelcase
|
|
21
|
-
compiler_version: z.string().optional(),
|
|
22
|
-
backend: z.string().optional(),
|
|
23
|
-
license: z.string().optional(),
|
|
24
|
-
}),
|
|
25
|
-
dependencies: z.record(z.union([noirGitDependencySchema, noirLocalDependencySchema])).default({}),
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Noir package configuration.
|
|
30
|
-
*/
|
|
31
|
-
export type NoirPackageConfig = z.infer<typeof noirPackageConfigSchema>;
|
|
32
|
-
|
|
33
13
|
/**
|
|
34
14
|
* A remote package dependency.
|
|
35
15
|
*/
|
|
@@ -45,6 +25,38 @@ export type NoirLocalDependencyConfig = z.infer<typeof noirLocalDependencySchema
|
|
|
45
25
|
*/
|
|
46
26
|
export type NoirDependencyConfig = NoirGitDependencyConfig | NoirLocalDependencyConfig;
|
|
47
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Noir package configuration.
|
|
30
|
+
*/
|
|
31
|
+
export type NoirPackageConfig = {
|
|
32
|
+
package: {
|
|
33
|
+
name: string;
|
|
34
|
+
type: 'lib' | 'contract' | 'bin';
|
|
35
|
+
entry?: string | undefined;
|
|
36
|
+
description?: string | undefined;
|
|
37
|
+
authors?: string[] | undefined;
|
|
38
|
+
compiler_version?: string | undefined;
|
|
39
|
+
backend?: string | undefined;
|
|
40
|
+
license?: string | undefined;
|
|
41
|
+
};
|
|
42
|
+
dependencies: Record<string, NoirDependencyConfig>;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const noirPackageConfigSchema: z.ZodType<NoirPackageConfig> = z.object({
|
|
46
|
+
package: z.object({
|
|
47
|
+
name: z.string().default(''),
|
|
48
|
+
type: z.enum(['lib', 'contract', 'bin']).default('bin'),
|
|
49
|
+
entry: z.string().optional(),
|
|
50
|
+
description: z.string().optional(),
|
|
51
|
+
authors: z.array(z.string()).optional(),
|
|
52
|
+
// eslint-disable-next-line camelcase
|
|
53
|
+
compiler_version: z.string().optional(),
|
|
54
|
+
backend: z.string().optional(),
|
|
55
|
+
license: z.string().optional(),
|
|
56
|
+
}),
|
|
57
|
+
dependencies: z.record(z.string(), z.union([noirGitDependencySchema, noirLocalDependencySchema])).default({}),
|
|
58
|
+
});
|
|
59
|
+
|
|
48
60
|
/**
|
|
49
61
|
* Checks that an object is a package configuration.
|
|
50
62
|
* @param config - Config to check
|
package/src/queue/batch_queue.ts
CHANGED
package/src/retry/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { TimeoutError } from '../error/index.js';
|
|
2
2
|
import { type Logger, createLogger } from '../log/index.js';
|
|
3
3
|
import { sleep } from '../sleep/index.js';
|
|
4
|
-
import { Timer } from '../timer/index.js';
|
|
4
|
+
import { type DateProvider, Timer } from '../timer/index.js';
|
|
5
5
|
|
|
6
6
|
/** An error that indicates that the operation should not be retried. */
|
|
7
7
|
export class NoRetryError extends Error {}
|
|
@@ -72,6 +72,34 @@ export async function retry<Result>(
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Timeout specification accepted by {@link retryUntil}. Either a plain number of seconds, an explicit
|
|
77
|
+
* `{ timeout }` in seconds, or an absolute `{ deadline }` with an optional {@link DateProvider} used to
|
|
78
|
+
* read the current time. A deadline is converted to the remaining seconds at call time; a deadline that
|
|
79
|
+
* has already passed yields a zero remaining budget, matching the immediate-timeout semantics of a
|
|
80
|
+
* non-positive numeric timeout.
|
|
81
|
+
*/
|
|
82
|
+
export type RetryUntilTimeout = number | { timeout: number } | { deadline: Date; dateProvider?: DateProvider };
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Resolves a {@link RetryUntilTimeout} to a numeric timeout in seconds for the legacy timer-based loop.
|
|
86
|
+
* A numeric/`{ timeout }` value passes through unchanged (0 means never time out, negative times out on the
|
|
87
|
+
* first interval). A `{ deadline }` is the remaining seconds until the deadline; when the deadline is already
|
|
88
|
+
* at or past `now` it resolves to a negative value so the loop times out immediately instead of being read as
|
|
89
|
+
* the never-timeout sentinel 0.
|
|
90
|
+
*/
|
|
91
|
+
function resolveRetryUntilTimeoutSeconds(timeout: RetryUntilTimeout): number {
|
|
92
|
+
if (typeof timeout === 'number') {
|
|
93
|
+
return timeout;
|
|
94
|
+
}
|
|
95
|
+
if ('deadline' in timeout) {
|
|
96
|
+
const now = timeout.dateProvider?.now() ?? Date.now();
|
|
97
|
+
const remainingSeconds = (timeout.deadline.getTime() - now) / 1000;
|
|
98
|
+
return remainingSeconds > 0 ? remainingSeconds : -1;
|
|
99
|
+
}
|
|
100
|
+
return timeout.timeout;
|
|
101
|
+
}
|
|
102
|
+
|
|
75
103
|
/**
|
|
76
104
|
* Retry an asynchronous function until it returns a truthy value or the specified timeout is exceeded.
|
|
77
105
|
* The function is retried periodically with a fixed interval between attempts. The operation can be named for better error messages.
|
|
@@ -79,16 +107,20 @@ export async function retry<Result>(
|
|
|
79
107
|
*
|
|
80
108
|
* @param fn - The asynchronous function to be retried, which should return a truthy value upon success or undefined otherwise.
|
|
81
109
|
* @param name - The optional name of the operation, used for generating timeout error message.
|
|
82
|
-
* @param timeout - The
|
|
110
|
+
* @param timeout - The maximum time to keep retrying before throwing a timeout error. Accepts a number of
|
|
111
|
+
* seconds (0 = never time out), an explicit `{ timeout }` in seconds, or an absolute `{ deadline }` with an
|
|
112
|
+
* optional `dateProvider`. A deadline already in the past times out on the first interval, the same as a
|
|
113
|
+
* zero/negative numeric timeout. Defaults to 0 (never timeout).
|
|
83
114
|
* @param interval - The optional interval, in seconds, between retry attempts. Defaults to 1 second.
|
|
84
115
|
* @returns A Promise that resolves with the successful (truthy) result of the provided function, or rejects if timeout is exceeded.
|
|
85
116
|
*/
|
|
86
117
|
export async function retryUntil<T>(
|
|
87
118
|
fn: () => (T | undefined) | Promise<T | undefined>,
|
|
88
119
|
name = '',
|
|
89
|
-
timeout = 0,
|
|
120
|
+
timeout: RetryUntilTimeout = 0,
|
|
90
121
|
interval = 1,
|
|
91
122
|
) {
|
|
123
|
+
const timeoutSeconds = resolveRetryUntilTimeoutSeconds(timeout);
|
|
92
124
|
const timer = new Timer();
|
|
93
125
|
while (true) {
|
|
94
126
|
const result = await fn();
|
|
@@ -98,12 +130,42 @@ export async function retryUntil<T>(
|
|
|
98
130
|
|
|
99
131
|
await sleep(interval * 1000);
|
|
100
132
|
|
|
101
|
-
if (
|
|
133
|
+
if (timeoutSeconds && timer.s() > timeoutSeconds) {
|
|
102
134
|
throw new TimeoutError(name ? `Timeout awaiting ${name}` : 'Timeout');
|
|
103
135
|
}
|
|
104
136
|
}
|
|
105
137
|
}
|
|
106
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Retry an asynchronous function until it returns a truthy value or the maximum number of retries is exceeded.
|
|
141
|
+
* The function is retried periodically with a fixed interval between attempts.
|
|
142
|
+
*
|
|
143
|
+
* @param fn - The asynchronous function to be retried, which should return a truthy value upon success or undefined otherwise.
|
|
144
|
+
* @param name - The optional name of the operation, used for generating error messages.
|
|
145
|
+
* @param maxRetries - The maximum number of retry attempts before throwing an error.
|
|
146
|
+
* @param retryInterval - The optional interval, in seconds, between retry attempts. Defaults to 1 second.
|
|
147
|
+
* @returns A Promise that resolves with the successful (truthy) result of the provided function, or rejects if retries are exhausted.
|
|
148
|
+
*/
|
|
149
|
+
export async function retryTimes<T>(
|
|
150
|
+
fn: () => (T | undefined) | Promise<T | undefined>,
|
|
151
|
+
name = '',
|
|
152
|
+
maxRetries: number,
|
|
153
|
+
retryInterval = 1,
|
|
154
|
+
) {
|
|
155
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
156
|
+
const result = await fn();
|
|
157
|
+
if (result) {
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
if (attempt < maxRetries) {
|
|
162
|
+
await sleep(retryInterval * 1000);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
throw new Error(name ? `Retries exhausted awaiting ${name}` : 'Retries exhausted');
|
|
167
|
+
}
|
|
168
|
+
|
|
107
169
|
/**
|
|
108
170
|
* Convenience wrapper around retryUntil with fast polling for tests.
|
|
109
171
|
* Uses 10s timeout and 100ms polling interval by default.
|
package/src/schemas/api.ts
CHANGED
|
@@ -2,32 +2,19 @@ import type { z } from 'zod';
|
|
|
2
2
|
|
|
3
3
|
import type { ZodNullableOptional } from './utils.js';
|
|
4
4
|
|
|
5
|
-
// Forces usage of
|
|
6
|
-
type ZodParameterTypeFor<T> = undefined extends T
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
type
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
// The complexity is required to satisfy ZodTuple which requires a fixed length tuple and
|
|
14
|
-
// has a very annoying type of [] | [ZodTypeAny, ...ZodTypeAny], and most types fail to match
|
|
15
|
-
// the second option. While a purely recursive approach works, it fails when trying to deal
|
|
16
|
-
// with optional arguments (ie optional items in the tuple), and ts does not really like them
|
|
17
|
-
// during a recursion and fails with infinite stack depth.
|
|
18
|
-
// This type appears to satisfy everyone. Everyone but me.
|
|
19
|
-
type ZodMapParameterTypes<T> = T extends []
|
|
20
|
-
? []
|
|
21
|
-
: T extends [item: infer Head, ...infer Rest]
|
|
22
|
-
? [ZodParameterTypeFor<Head>, ...{ [K in keyof Rest]: ZodParameterTypeFor<Rest[K]> }]
|
|
23
|
-
: T extends [item?: infer Head, ...infer Rest]
|
|
24
|
-
? [ZodNullableOptional<ZodParameterTypeFor<Head>>, ...{ [K in keyof Rest]: ZodParameterTypeFor<Rest[K]> }]
|
|
25
|
-
: never;
|
|
5
|
+
// Forces usage of schemas that accept nulls for optional parameters.
|
|
6
|
+
type ZodParameterTypeFor<T> = undefined extends T ? ZodNullableOptional<z.ZodType<T, any>> : z.ZodType<T, any>;
|
|
7
|
+
|
|
8
|
+
type ZodReturnTypeFor<T> = z.ZodType<T, any>;
|
|
9
|
+
|
|
10
|
+
type ZodMapParameterTypes<T extends readonly unknown[]> = {
|
|
11
|
+
[K in keyof T]-?: ZodParameterTypeFor<T[K]>;
|
|
12
|
+
};
|
|
26
13
|
|
|
27
14
|
/** Maps all functions in an interface to their schema representation. */
|
|
28
15
|
export type ApiSchemaFor<T> = {
|
|
29
16
|
[K in keyof T]: T[K] extends (...args: infer Args) => Promise<infer Ret>
|
|
30
|
-
? z.ZodFunction<z.ZodTuple<ZodMapParameterTypes<Args>,
|
|
17
|
+
? z.ZodFunction<z.ZodTuple<ZodMapParameterTypes<Args>, null>, ZodReturnTypeFor<Ret>>
|
|
31
18
|
: never;
|
|
32
19
|
};
|
|
33
20
|
|
|
@@ -37,11 +24,24 @@ export type ApiSchema = {
|
|
|
37
24
|
};
|
|
38
25
|
|
|
39
26
|
/** Return whether an API schema defines a valid function schema for a given method name. */
|
|
40
|
-
export function schemaHasMethod
|
|
27
|
+
export function schemaHasMethod<T extends ApiSchema>(
|
|
28
|
+
schema: T,
|
|
29
|
+
methodName: string,
|
|
30
|
+
): methodName is Extract<keyof T, string> {
|
|
41
31
|
return (
|
|
42
32
|
typeof methodName === 'string' &&
|
|
43
33
|
Object.hasOwn(schema, methodName) &&
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
schema[methodName].def.input !== undefined &&
|
|
35
|
+
schema[methodName].def.output !== undefined
|
|
46
36
|
);
|
|
47
37
|
}
|
|
38
|
+
|
|
39
|
+
/** Returns the parameter tuple schema for an API method schema. */
|
|
40
|
+
export function getSchemaParameters<T extends z.ZodFunction<z.ZodTuple<any, any>, z.ZodTypeAny>>(schema: T) {
|
|
41
|
+
return schema.def.input;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Returns the return value schema for an API method schema. */
|
|
45
|
+
export function getSchemaReturnType<T extends z.ZodFunction<z.ZodTuple<any, any>, z.ZodTypeAny>>(schema: T) {
|
|
46
|
+
return schema.def.output;
|
|
47
|
+
}
|
package/src/schemas/parse.ts
CHANGED
|
@@ -4,16 +4,19 @@ import { times } from '../collection/array.js';
|
|
|
4
4
|
|
|
5
5
|
/** Parses the given arguments using a tuple from the provided schemas. */
|
|
6
6
|
export function parse<T extends [] | [z.ZodTypeAny, ...z.ZodTypeAny[]]>(args: IArguments, ...schemas: T) {
|
|
7
|
-
return
|
|
7
|
+
return schemas.length === 0
|
|
8
|
+
? z.tuple([]).parse(args)
|
|
9
|
+
: z.tuple(schemas as [z.ZodTypeAny, ...z.ZodTypeAny[]]).parse(args);
|
|
8
10
|
}
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* Parses the given arguments against a tuple, allowing empty for optional items.
|
|
12
|
-
* @dev Zod doesn't like
|
|
14
|
+
* @dev Zod doesn't like tuples with optional items. See https://github.com/colinhacks/zod/discussions/949.
|
|
13
15
|
*/
|
|
14
|
-
export function parseWithOptionals<T extends z.
|
|
15
|
-
const
|
|
16
|
-
const
|
|
16
|
+
export function parseWithOptionals<T extends z.ZodTuple<any, any>>(args: any[], schema: T): Promise<z.output<T>> {
|
|
17
|
+
const items = schema.def.items;
|
|
18
|
+
const missingCount = items.length - args.length;
|
|
19
|
+
const optionalCount = items.filter(isOptional).length;
|
|
17
20
|
const toParse =
|
|
18
21
|
missingCount > 0 && missingCount <= optionalCount ? args.concat(times(missingCount, () => undefined)) : args;
|
|
19
22
|
return schema.parseAsync(toParse);
|
|
@@ -24,6 +27,6 @@ function isOptional(schema: z.ZodTypeAny) {
|
|
|
24
27
|
return schema.isOptional();
|
|
25
28
|
} catch {
|
|
26
29
|
// See https://github.com/colinhacks/zod/issues/1911
|
|
27
|
-
return schema.
|
|
30
|
+
return schema.def.type === 'optional';
|
|
28
31
|
}
|
|
29
32
|
}
|
package/src/schemas/schemas.ts
CHANGED
|
@@ -44,15 +44,15 @@ export const schemas = {
|
|
|
44
44
|
]),
|
|
45
45
|
|
|
46
46
|
/** Coerces any input to bigint. */
|
|
47
|
-
BigInt: z.union([z.bigint(), z.number(), z.string()]).pipe(z.coerce.bigint()),
|
|
47
|
+
BigInt: z.union([z.bigint(), z.number(), z.string()]).pipe(z.coerce.bigint<string | number | bigint>()),
|
|
48
48
|
|
|
49
49
|
/** Coerces any input to integer number. */
|
|
50
|
-
Integer: z.union([z.bigint(), z.number(), z.string()]).pipe(z.coerce.number().int()),
|
|
50
|
+
Integer: z.union([z.bigint(), z.number(), z.string()]).pipe(z.coerce.number<string | number | bigint>().int()),
|
|
51
51
|
|
|
52
52
|
/** Coerces input to UInt32. */
|
|
53
53
|
UInt32: z.union([z.bigint(), z.number(), z.string()]).pipe(
|
|
54
54
|
z.coerce
|
|
55
|
-
.number()
|
|
55
|
+
.number<string | number | bigint>()
|
|
56
56
|
.int()
|
|
57
57
|
.min(0)
|
|
58
58
|
.max(2 ** 32 - 1),
|
|
@@ -61,7 +61,7 @@ export const schemas = {
|
|
|
61
61
|
/** Coerces input to UInt64. */
|
|
62
62
|
UInt64: z.union([z.bigint(), z.number(), z.string()]).pipe(
|
|
63
63
|
z.coerce
|
|
64
|
-
.bigint()
|
|
64
|
+
.bigint<string | number | bigint>()
|
|
65
65
|
.min(0n)
|
|
66
66
|
.max(2n ** 64n - 1n),
|
|
67
67
|
),
|
package/src/schemas/types.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ZodType } from 'zod';
|
|
2
2
|
|
|
3
|
-
export type ZodFor<T> = ZodType<T, any
|
|
3
|
+
export type ZodFor<T> = ZodType<T, any>;
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Creates a schema validator that enforces all properties of type T are present in the schema.
|
|
@@ -26,7 +26,7 @@ export type ZodFor<T> = ZodType<T, any, any>;
|
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
28
|
export function zodFor<T>() {
|
|
29
|
-
return (schema => schema) as <S extends ZodType<any, any
|
|
29
|
+
return (schema => schema) as <S extends ZodType<any, any>>(
|
|
30
30
|
schema: keyof T extends keyof S['_output']
|
|
31
31
|
? keyof S['_output'] extends keyof T
|
|
32
32
|
? S
|