@aztec/foundation 0.0.1-commit.f2ce05ee → 0.0.1-commit.f5a9928
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/array/sorted_array.d.ts +6 -1
- package/dest/array/sorted_array.d.ts.map +1 -1
- package/dest/array/sorted_array.js +18 -15
- 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/buffer/index.d.ts +2 -1
- package/dest/buffer/index.d.ts.map +1 -1
- package/dest/buffer/index.js +1 -0
- package/dest/buffer/utils.d.ts +3 -0
- package/dest/buffer/utils.d.ts.map +1 -0
- package/dest/buffer/utils.js +7 -0
- 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 +67 -37
- package/dest/config/index.d.ts.map +1 -1
- package/dest/config/index.js +86 -70
- package/dest/config/network_config.d.ts +15 -41
- package/dest/config/network_config.d.ts.map +1 -1
- package/dest/config/network_config.js +4 -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 +3 -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 +10 -177
- package/dest/crypto/bls/bn254_keystore.d.ts.map +1 -1
- package/dest/crypto/bls/bn254_keystore.js +22 -34
- 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/crypto/secp256k1-signer/utils.d.ts +12 -1
- package/dest/crypto/secp256k1-signer/utils.d.ts.map +1 -1
- package/dest/crypto/secp256k1-signer/utils.js +26 -0
- 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 +24 -19
- package/dest/curves/bn254/field.d.ts.map +1 -1
- package/dest/curves/bn254/field.js +28 -19
- 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 +3 -2
- package/dest/eth-signature/eth_signature.d.ts.map +1 -1
- package/dest/eth-signature/eth_signature.js +7 -2
- 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/iterable/first.d.ts +8 -0
- package/dest/iterable/first.d.ts.map +1 -0
- package/dest/iterable/first.js +11 -0
- package/dest/iterable/index.d.ts +2 -1
- package/dest/iterable/index.d.ts.map +1 -1
- package/dest/iterable/index.js +1 -0
- package/dest/jest/setup.js +24 -0
- package/dest/json-rpc/client/fetch.d.ts +8 -3
- package/dest/json-rpc/client/fetch.d.ts.map +1 -1
- package/dest/json-rpc/client/fetch.js +11 -7
- package/dest/json-rpc/client/safe_json_rpc_client.d.ts +2 -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 +3 -3
- package/dest/json-rpc/client/undici.d.ts +14 -3
- package/dest/json-rpc/client/undici.d.ts.map +1 -1
- package/dest/json-rpc/client/undici.js +47 -14
- 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/api_key_auth.d.ts +19 -0
- package/dest/json-rpc/server/api_key_auth.d.ts.map +1 -0
- package/dest/json-rpc/server/api_key_auth.js +57 -0
- package/dest/json-rpc/server/index.d.ts +2 -1
- package/dest/json-rpc/server/index.d.ts.map +1 -1
- package/dest/json-rpc/server/index.js +1 -0
- package/dest/json-rpc/server/safe_json_rpc_server.d.ts +49 -11
- package/dest/json-rpc/server/safe_json_rpc_server.d.ts.map +1 -1
- package/dest/json-rpc/server/safe_json_rpc_server.js +159 -40
- package/dest/log/aws-logger-config.d.ts +8 -0
- package/dest/log/aws-logger-config.d.ts.map +1 -0
- package/dest/log/aws-logger-config.js +55 -0
- package/dest/log/bigint-utils.d.ts +5 -0
- package/dest/log/bigint-utils.d.ts.map +1 -0
- package/dest/log/bigint-utils.js +21 -0
- package/dest/log/gcloud-logger-config.d.ts +1 -1
- package/dest/log/gcloud-logger-config.d.ts.map +1 -1
- package/dest/log/gcloud-logger-config.js +3 -0
- 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 +31 -6
- 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/promise/running-promise.d.ts +8 -2
- package/dest/promise/running-promise.d.ts.map +1 -1
- package/dest/promise/running-promise.js +17 -5
- package/dest/promise/utils.d.ts +14 -1
- package/dest/promise/utils.d.ts.map +1 -1
- package/dest/promise/utils.js +20 -0
- package/dest/queue/base_memory_queue.d.ts +2 -2
- package/dest/queue/base_memory_queue.d.ts.map +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_reader.d.ts +8 -1
- package/dest/serialize/buffer_reader.d.ts.map +1 -1
- package/dest/serialize/buffer_reader.js +18 -0
- 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/serialize/serialize.d.ts +19 -32
- package/dest/serialize/serialize.d.ts.map +1 -1
- package/dest/serialize/serialize.js +31 -21
- package/dest/sleep/index.d.ts +2 -1
- package/dest/sleep/index.d.ts.map +1 -1
- package/dest/sleep/index.js +10 -1
- package/dest/string/index.js +1 -1
- package/dest/testing/files/index.d.ts +2 -3
- package/dest/testing/files/index.d.ts.map +1 -1
- package/dest/testing/files/index.js +1 -2
- package/dest/timer/date.d.ts +3 -1
- package/dest/timer/date.d.ts.map +1 -1
- package/dest/timer/date.js +4 -0
- 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/transport/transport_client.js +2 -2
- 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 +13 -14
- package/dest/trees/sibling_path.d.ts.map +1 -1
- package/dest/trees/sibling_path.js +23 -28
- 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/array/sorted_array.ts +22 -17
- 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/buffer/index.ts +1 -0
- package/src/buffer/utils.ts +8 -0
- 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 +85 -23
- package/src/config/index.ts +157 -121
- package/src/config/network_config.ts +3 -0
- package/src/config/network_name.ts +6 -6
- package/src/config/secret_value.ts +1 -1
- package/src/crypto/aes128/index.ts +11 -2
- package/src/crypto/bls/bn254_keystore.ts +33 -43
- 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/crypto/secp256k1-signer/utils.ts +32 -0
- package/src/curves/bls12/field.ts +0 -7
- package/src/curves/bn254/field.ts +41 -36
- package/src/curves/grumpkin/point.ts +23 -40
- package/src/eth-address/index.ts +0 -4
- package/src/eth-signature/eth_signature.ts +7 -1
- 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/iterable/first.ts +14 -0
- package/src/iterable/index.ts +1 -0
- package/src/jest/setup.mjs +27 -0
- package/src/json-rpc/client/fetch.ts +19 -5
- package/src/json-rpc/client/safe_json_rpc_client.ts +4 -2
- package/src/json-rpc/client/undici.ts +54 -12
- package/src/json-rpc/fixtures/test_state.ts +10 -10
- package/src/json-rpc/server/api_key_auth.ts +63 -0
- package/src/json-rpc/server/index.ts +1 -0
- package/src/json-rpc/server/safe_json_rpc_server.ts +204 -47
- package/src/log/aws-logger-config.ts +32 -0
- package/src/log/bigint-utils.ts +25 -0
- package/src/log/gcloud-logger-config.ts +5 -0
- package/src/log/pino-logger.ts +37 -6
- package/src/noir/noir_package_config.ts +32 -20
- package/src/promise/running-promise.ts +20 -7
- package/src/promise/utils.ts +31 -0
- package/src/queue/base_memory_queue.ts +1 -1
- 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_reader.ts +20 -0
- package/src/serialize/buffer_sink.ts +350 -0
- package/src/serialize/index.ts +1 -0
- package/src/serialize/serialize.ts +32 -50
- package/src/sleep/index.ts +10 -1
- package/src/string/index.ts +1 -1
- package/src/testing/files/index.ts +1 -2
- package/src/timer/date.ts +6 -0
- 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/transport/transport_client.ts +2 -2
- 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 +24 -30
- 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,57 @@
|
|
|
1
|
+
import { timingSafeEqual } from 'crypto';
|
|
2
|
+
import { sha256 } from '../../crypto/sha256/index.js';
|
|
3
|
+
import { createLogger } from '../../log/index.js';
|
|
4
|
+
const log = createLogger('json-rpc:api-key-auth');
|
|
5
|
+
/**
|
|
6
|
+
* Computes the SHA-256 hash of a string and returns it as a Buffer.
|
|
7
|
+
* @param input - The input string to hash.
|
|
8
|
+
* @returns The SHA-256 hash as a Buffer.
|
|
9
|
+
*/ export function sha256Hash(input) {
|
|
10
|
+
return sha256(Buffer.from(input));
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Creates a Koa middleware that enforces API key authentication on all requests
|
|
14
|
+
* except the health check endpoint (GET /status).
|
|
15
|
+
*
|
|
16
|
+
* The API key can be provided via the `x-api-key` header or the `Authorization: Bearer <key>` header.
|
|
17
|
+
* Comparison is done by hashing the provided key with SHA-256 and comparing against the stored hash.
|
|
18
|
+
*
|
|
19
|
+
* @param apiKeyHash - The SHA-256 hash of the expected API key as a Buffer.
|
|
20
|
+
* @returns A Koa middleware that rejects requests without a valid API key.
|
|
21
|
+
*/ export function getApiKeyAuthMiddleware(apiKeyHash) {
|
|
22
|
+
return async (ctx, next)=>{
|
|
23
|
+
// Allow health check through without auth
|
|
24
|
+
if (ctx.path === '/status' && ctx.method === 'GET') {
|
|
25
|
+
return next();
|
|
26
|
+
}
|
|
27
|
+
const providedKey = ctx.get('x-api-key') || ctx.get('authorization')?.replace(/^Bearer\s+/i, '');
|
|
28
|
+
if (!providedKey) {
|
|
29
|
+
log.warn(`Rejected admin RPC request from ${ctx.ip}: missing API key`);
|
|
30
|
+
ctx.status = 401;
|
|
31
|
+
ctx.body = {
|
|
32
|
+
jsonrpc: '2.0',
|
|
33
|
+
id: null,
|
|
34
|
+
error: {
|
|
35
|
+
code: -32000,
|
|
36
|
+
message: 'Unauthorized: invalid or missing API key'
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const providedHashBuf = sha256Hash(providedKey);
|
|
42
|
+
if (!timingSafeEqual(apiKeyHash, providedHashBuf)) {
|
|
43
|
+
log.warn(`Rejected admin RPC request from ${ctx.ip}: invalid API key`);
|
|
44
|
+
ctx.status = 401;
|
|
45
|
+
ctx.body = {
|
|
46
|
+
jsonrpc: '2.0',
|
|
47
|
+
id: null,
|
|
48
|
+
error: {
|
|
49
|
+
code: -32000,
|
|
50
|
+
message: 'Unauthorized: invalid or missing API key'
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
await next();
|
|
56
|
+
};
|
|
57
|
+
}
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
+
export * from './api_key_auth.js';
|
|
1
2
|
export * from './safe_json_rpc_server.js';
|
|
2
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9qc29uLXJwYy9zZXJ2ZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxtQkFBbUIsQ0FBQztBQUNsQyxjQUFjLDJCQUEyQixDQUFDIn0=
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/json-rpc/server/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/json-rpc/server/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,2BAA2B,CAAC"}
|
|
@@ -8,6 +8,8 @@ export type DiagnosticsData = {
|
|
|
8
8
|
method: string;
|
|
9
9
|
params: any[];
|
|
10
10
|
headers: http.IncomingHttpHeaders;
|
|
11
|
+
requestValidationDurationMs?: number;
|
|
12
|
+
requestValidationSucceeded?: boolean;
|
|
11
13
|
};
|
|
12
14
|
export type DiagnosticsMiddleware = (ctx: DiagnosticsData, next: () => Promise<void>) => Promise<void>;
|
|
13
15
|
export type SafeJsonRpcServerConfig = {
|
|
@@ -17,14 +19,20 @@ export type SafeJsonRpcServerConfig = {
|
|
|
17
19
|
http200OnError: boolean;
|
|
18
20
|
/** The maximum body size the server will accept */
|
|
19
21
|
maxBodySizeBytes: string;
|
|
22
|
+
/** Origins allowed to make credentialed cross-origin requests. An empty list preserves wildcard CORS. */
|
|
23
|
+
corsAllowedOrigins?: string[];
|
|
24
|
+
/** Headers allowed in cross-origin requests. An empty list reflects the requested headers. */
|
|
25
|
+
corsAllowedHeaders?: string[];
|
|
20
26
|
};
|
|
21
27
|
export declare class SafeJsonRpcServer {
|
|
22
28
|
/** The proxy object to delegate requests to */
|
|
23
29
|
private readonly proxy;
|
|
24
30
|
/** Health check function */
|
|
25
31
|
private readonly healthCheck;
|
|
26
|
-
/** Additional middlewares */
|
|
32
|
+
/** Additional Koa middlewares */
|
|
27
33
|
private extraMiddlewares;
|
|
34
|
+
/** Additional per-request diagnostics middlewares */
|
|
35
|
+
private diagnosticsMiddleware?;
|
|
28
36
|
/** Logger */
|
|
29
37
|
private log;
|
|
30
38
|
/**
|
|
@@ -38,10 +46,14 @@ export declare class SafeJsonRpcServer {
|
|
|
38
46
|
proxy: Proxy, config?: Partial<SafeJsonRpcServerConfig>,
|
|
39
47
|
/** Health check function */
|
|
40
48
|
healthCheck?: StatusCheckFn,
|
|
41
|
-
/** Additional middlewares */
|
|
49
|
+
/** Additional Koa middlewares */
|
|
42
50
|
extraMiddlewares?: Application.Middleware[],
|
|
51
|
+
/** Additional per-request diagnostics middlewares */
|
|
52
|
+
diagnosticsMiddleware?: DiagnosticsMiddleware | undefined,
|
|
43
53
|
/** Logger */
|
|
44
54
|
log?: Logger);
|
|
55
|
+
/** Returns the status of this server, including per-component health when the health check reports it. */
|
|
56
|
+
getStatus(): Promise<ServerStatus>;
|
|
45
57
|
isHealthy(): boolean | Promise<boolean>;
|
|
46
58
|
/**
|
|
47
59
|
* Get an express app object.
|
|
@@ -75,10 +87,31 @@ export declare class SafeJsonRpcServer {
|
|
|
75
87
|
*/
|
|
76
88
|
call(methodName: string, jsonParams?: any[]): Promise<any>;
|
|
77
89
|
}
|
|
78
|
-
|
|
90
|
+
/** Health of a single component, along with any details worth surfacing to whoever queries the status endpoint. */
|
|
91
|
+
export type StatusCheckResult = {
|
|
92
|
+
/** Whether the component is healthy. */
|
|
93
|
+
healthy: boolean;
|
|
94
|
+
/** Component-specific information, reported next to the healthy flag. */
|
|
95
|
+
details?: object;
|
|
96
|
+
};
|
|
97
|
+
/** Health check for a component. Returning a plain boolean is shorthand for `{ healthy: <boolean> }`. */
|
|
98
|
+
export type StatusCheckFn = () => boolean | StatusCheckResult | Promise<boolean | StatusCheckResult>;
|
|
99
|
+
/** Health of a component as reported on the status endpoint: its healthy flag flattened with its details. */
|
|
100
|
+
export type ComponentStatus = {
|
|
101
|
+
healthy: boolean;
|
|
102
|
+
} & Record<string, unknown>;
|
|
103
|
+
/** Status of a server as reported on the status endpoint. */
|
|
104
|
+
export type ServerStatus = {
|
|
105
|
+
/** Whether every checked component reported healthy. */
|
|
106
|
+
ok: boolean;
|
|
107
|
+
/** Health of each component keyed by namespace, when the server has component-level health checks. */
|
|
108
|
+
components?: Record<string, ComponentStatus>;
|
|
109
|
+
};
|
|
110
|
+
/** Returns the status of a server. */
|
|
111
|
+
export type ServerStatusFn = () => ServerStatus | Promise<ServerStatus>;
|
|
79
112
|
interface Proxy {
|
|
80
113
|
hasMethod(methodName: string): boolean;
|
|
81
|
-
call(methodName: string, jsonParams?: any[]): Promise<any>;
|
|
114
|
+
call(methodName: string, jsonParams?: any[], onRequestValidated?: (durationMs: number, succeeded: boolean) => void): Promise<any>;
|
|
82
115
|
}
|
|
83
116
|
/**
|
|
84
117
|
* Forwards calls to a handler. Relies on a schema definition to validate and convert inputs
|
|
@@ -95,7 +128,7 @@ export declare class SafeJsonProxy<T extends object = any> implements Proxy {
|
|
|
95
128
|
* @param jsonParams - The RPC parameters.
|
|
96
129
|
* @returns The remote result.
|
|
97
130
|
*/
|
|
98
|
-
call(methodName: string, jsonParams?: any[]): Promise<any>;
|
|
131
|
+
call(methodName: string, jsonParams?: any[], onRequestValidated?: (durationMs: number, succeeded: boolean) => void): Promise<any>;
|
|
99
132
|
hasMethod(methodName: string): boolean;
|
|
100
133
|
}
|
|
101
134
|
export type NamespacedApiHandlers = Record<string, ApiHandler>;
|
|
@@ -103,6 +136,7 @@ export type ApiHandler<T extends object = any> = [T, ApiSchemaFor<T>, StatusChec
|
|
|
103
136
|
export declare function makeHandler<T extends object>(handler: T, schema: ApiSchemaFor<T>): ApiHandler<T>;
|
|
104
137
|
export type SafeJsonRpcServerOptions = Partial<SafeJsonRpcServerConfig & {
|
|
105
138
|
healthCheck: StatusCheckFn;
|
|
139
|
+
diagnostic: DiagnosticsMiddleware;
|
|
106
140
|
log: Logger;
|
|
107
141
|
middlewares: Application.Middleware[];
|
|
108
142
|
}>;
|
|
@@ -114,26 +148,30 @@ export type SafeJsonRpcServerOptions = Partial<SafeJsonRpcServerConfig & {
|
|
|
114
148
|
export declare function createNamespacedSafeJsonRpcServer(handlers: NamespacedApiHandlers, options?: Omit<SafeJsonRpcServerOptions, 'healthcheck'>): SafeJsonRpcServer;
|
|
115
149
|
export declare function createSafeJsonRpcServer<T extends object = any>(handler: T, schema: ApiSchemaFor<T>, options?: SafeJsonRpcServerOptions): SafeJsonRpcServer;
|
|
116
150
|
/**
|
|
117
|
-
* Creates a router for handling a
|
|
118
|
-
*
|
|
151
|
+
* Creates a router for handling a status request that returns a 200 status code when healthy and a 500 otherwise,
|
|
152
|
+
* along with the reported status as a JSON body.
|
|
153
|
+
* @param getCurrentStatus - Function returning the current status of the server.
|
|
119
154
|
* @param apiPrefix - The prefix to use for all api requests
|
|
120
155
|
* @returns - The router for handling status requests.
|
|
121
156
|
*/
|
|
122
|
-
export declare function createStatusRouter(getCurrentStatus:
|
|
157
|
+
export declare function createStatusRouter(getCurrentStatus: ServerStatusFn, apiPrefix?: string): Router<any, {}>;
|
|
123
158
|
/**
|
|
124
159
|
* Wraps a JsonRpcServer in a nodejs http server and starts it.
|
|
125
|
-
* Installs a status router that
|
|
160
|
+
* Installs a status router that reports the status of the server, using its getStatus method when available so that
|
|
161
|
+
* per-component health is included, and falling back to isHealthy otherwise.
|
|
126
162
|
* Returns once starts listening unless noWait is set.
|
|
127
163
|
* @returns A running http server.
|
|
128
164
|
*/
|
|
129
|
-
export declare function startHttpRpcServer(rpcServer: Pick<SafeJsonRpcServer, 'getApp' | 'isHealthy'
|
|
165
|
+
export declare function startHttpRpcServer(rpcServer: Pick<SafeJsonRpcServer, 'getApp' | 'isHealthy'> & Partial<Pick<SafeJsonRpcServer, 'getStatus'>>, options?: {
|
|
130
166
|
host?: string;
|
|
131
167
|
port?: number | string;
|
|
132
168
|
apiPrefix?: string;
|
|
133
169
|
timeoutMs?: number;
|
|
170
|
+
keepAliveTimeoutMs?: number;
|
|
171
|
+
headersTimeoutMs?: number;
|
|
134
172
|
noWait?: boolean;
|
|
135
173
|
}): Promise<http.Server & {
|
|
136
174
|
port: number;
|
|
137
175
|
}>;
|
|
138
176
|
export {};
|
|
139
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
177
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2FmZV9qc29uX3JwY19zZXJ2ZXIuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9qc29uLXJwYy9zZXJ2ZXIvc2FmZV9qc29uX3JwY19zZXJ2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxJQUFJLE1BQU0sTUFBTSxDQUFDO0FBQ3hCLE9BQU8sRUFBRSxLQUFLLE9BQU8sSUFBSSxXQUFXLEVBQWtCLE1BQU0sS0FBSyxDQUFDO0FBR2xFLE9BQU8sTUFBTSxNQUFNLFlBQVksQ0FBQztBQUtoQyxPQUFPLEVBQUUsS0FBSyxNQUFNLEVBQWdCLE1BQU0sb0JBQW9CLENBQUM7QUFFL0QsT0FBTyxFQUVMLEtBQUssWUFBWSxFQUlsQixNQUFNLHdCQUF3QixDQUFDO0FBS2hDLE1BQU0sTUFBTSxlQUFlLEdBQUc7SUFDNUIsRUFBRSxFQUFFLE1BQU0sR0FBRyxNQUFNLEdBQUcsSUFBSSxDQUFDO0lBQzNCLE1BQU0sRUFBRSxNQUFNLENBQUM7SUFDZixNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUM7SUFDZCxPQUFPLEVBQUUsSUFBSSxDQUFDLG1CQUFtQixDQUFDO0lBQ2xDLDJCQUEyQixDQUFDLEVBQUUsTUFBTSxDQUFDO0lBQ3JDLDBCQUEwQixDQUFDLEVBQUUsT0FBTyxDQUFDO0NBQ3RDLENBQUM7QUFFRixNQUFNLE1BQU0scUJBQXFCLEdBQUcsQ0FBQyxHQUFHLEVBQUUsZUFBZSxFQUFFLElBQUksRUFBRSxNQUFNLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7QUFFdkcsTUFBTSxNQUFNLHVCQUF1QixHQUFHO0lBQ3BDLGtEQUFrRDtJQUNsRCxZQUFZLEVBQUUsTUFBTSxDQUFDO0lBQ3JCLHFHQUFxRztJQUNyRyxjQUFjLEVBQUUsT0FBTyxDQUFDO0lBQ3hCLG1EQUFtRDtJQUNuRCxnQkFBZ0IsRUFBRSxNQUFNLENBQUM7SUFDekIseUdBQXlHO0lBQ3pHLGtCQUFr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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"safe_json_rpc_server.d.ts","sourceRoot":"","sources":["../../../src/json-rpc/server/safe_json_rpc_server.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,KAAK,OAAO,IAAI,WAAW,EAAkB,MAAM,KAAK,CAAC;AAGlE,OAAO,MAAM,MAAM,YAAY,CAAC;AAKhC,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,oBAAoB,CAAC;AAE/D,OAAO,
|
|
1
|
+
{"version":3,"file":"safe_json_rpc_server.d.ts","sourceRoot":"","sources":["../../../src/json-rpc/server/safe_json_rpc_server.ts"],"names":[],"mappings":"AACA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,KAAK,OAAO,IAAI,WAAW,EAAkB,MAAM,KAAK,CAAC;AAGlE,OAAO,MAAM,MAAM,YAAY,CAAC;AAKhC,OAAO,EAAE,KAAK,MAAM,EAAgB,MAAM,oBAAoB,CAAC;AAE/D,OAAO,EAEL,KAAK,YAAY,EAIlB,MAAM,wBAAwB,CAAC;AAKhC,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,GAAG,EAAE,CAAC;IACd,OAAO,EAAE,IAAI,CAAC,mBAAmB,CAAC;IAClC,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,0BAA0B,CAAC,EAAE,OAAO,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,CAAC,GAAG,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAEvG,MAAM,MAAM,uBAAuB,GAAG;IACpC,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,qGAAqG;IACrG,cAAc,EAAE,OAAO,CAAC;IACxB,mDAAmD;IACnD,gBAAgB,EAAE,MAAM,CAAC;IACzB,yGAAyG;IACzG,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,8FAA8F;IAC9F,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B,CAAC;AA+BF,qBAAa,iBAAiB;IAU1B,+CAA+C;IAC/C,OAAO,CAAC,QAAQ,CAAC,KAAK;IAEtB,4BAA4B;IAC5B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,iCAAiC;IACjC,OAAO,CAAC,gBAAgB;IACxB,qDAAqD;IACrD,OAAO,CAAC,qBAAqB,CAAC;IAC9B,aAAa;IACb,OAAO,CAAC,GAAG;IAnBb;;;OAGG;IACH,OAAO,CAAC,UAAU,CAAC,CAAc;IAEjC,OAAO,CAAC,MAAM,CAAkC;IAEhD;IACE,+CAA+C;IAC9B,KAAK,EAAE,KAAK,EAC7B,MAAM,GAAE,OAAO,CAAC,uBAAuB,CAAM;IAC7C,4BAA4B;IACX,WAAW,GAAE,aAA0B;IACxD,iCAAiC;IACzB,gBAAgB,GAAE,WAAW,CAAC,UAAU,EAAO;IACvD,qDAAqD;IAC7C,qBAAqB,CAAC,mCAAuB;IACrD,aAAa;IACL,GAAG,SAAkC,EAS9C;IAED,0GAA0G;IACnG,SAAS,IAAI,OAAO,CAAC,YAAY,CAAC,CAKxC;IAEM,SAAS,IAAI,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAE7C;IAED;;;;OAIG;IACI,MAAM,CAAC,MAAM,SAAK,qEAqFxB;IAED;;;;OAIG;IACH,OAAO,CAAC,SAAS;YAsCH,YAAY;YAeZ,cAAc;IAuD5B;;;;OAIG;IACI,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,SAAK,GAAG,IAAI,CAQ5C;IAED;;OAEG;IACI,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAc3B;IAED;;;;;OAKG;IACU,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,GAAE,GAAG,EAAO,gBAE3D;CACF;AAED,mHAAmH;AACnH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,yGAAyG;AACzG,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,GAAG,iBAAiB,GAAG,OAAO,CAAC,OAAO,GAAG,iBAAiB,CAAC,CAAC;AAErG,6GAA6G;AAC7G,MAAM,MAAM,eAAe,GAAG;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE7E,6DAA6D;AAC7D,MAAM,MAAM,YAAY,GAAG;IACzB,wDAAwD;IACxD,EAAE,EAAE,OAAO,CAAC;IACZ,sGAAsG;IACtG,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;CAC9C,CAAC;AAEF,sCAAsC;AACtC,MAAM,MAAM,cAAc,GAAG,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;AAMxE,UAAU,KAAK;IACb,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;IACvC,IAAI,CACF,UAAU,EAAE,MAAM,EAClB,UAAU,CAAC,EAAE,GAAG,EAAE,EAClB,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,KAAK,IAAI,GACpE,OAAO,CAAC,GAAG,CAAC,CAAC;CACjB;AAED;;;GAGG;AACH,qBAAa,aAAa,CAAC,CAAC,SAAS,MAAM,GAAG,GAAG,CAAE,YAAW,KAAK;IAK/D,OAAO,CAAC,OAAO;IAJjB,OAAO,CAAC,GAAG,CAAkC;IAC7C,OAAO,CAAC,MAAM,CAAY;IAE1B,YACU,OAAO,EAAE,CAAC,EAClB,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EAGxB;IAED;;;;;OAKG;IACU,IAAI,CACf,UAAU,EAAE,MAAM,EAClB,UAAU,GAAE,GAAG,EAAO,EACtB,kBAAkB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,KAAK,IAAI,gBAoBtE;IAEM,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAE5C;CACF;AA8BD,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAE/D,MAAM,MAAM,UAAU,CAAC,CAAC,SAAS,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC;AAEtF,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAEhG;AAwBD,MAAM,MAAM,wBAAwB,GAAG,OAAO,CAC5C,uBAAuB,GAAG;IACxB,WAAW,EAAE,aAAa,CAAC;IAC3B,UAAU,EAAE,qBAAqB,CAAC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,WAAW,CAAC,UAAU,EAAE,CAAC;CACvC,CACF,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,iCAAiC,CAC/C,QAAQ,EAAE,qBAAqB,EAC/B,OAAO,GAAE,IAAI,CAAC,wBAAwB,EAAE,aAAa,CAAM,GAC1D,iBAAiB,CAKnB;AAED,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,MAAM,GAAG,GAAG,EAC5D,OAAO,EAAE,CAAC,EACV,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,EACvB,OAAO,GAAE,wBAA6B,qBAKvC;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,gBAAgB,EAAE,cAAc,EAAE,SAAS,SAAK,mBAelF;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,IAAI,CAAC,iBAAiB,EAAE,QAAQ,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,iBAAiB,EAAE,WAAW,CAAC,CAAC,EAC1G,OAAO,GAAE;IACP,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;CACb,GACL,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAiCzC"}
|
|
@@ -8,40 +8,71 @@ import { format, inspect } from 'util';
|
|
|
8
8
|
import { ZodError } from 'zod';
|
|
9
9
|
import { createLogger } from '../../log/index.js';
|
|
10
10
|
import { promiseWithResolvers } from '../../promise/utils.js';
|
|
11
|
-
import { parseWithOptionals, schemaHasMethod } from '../../schemas/index.js';
|
|
11
|
+
import { getSchemaParameters, parseWithOptionals, schemaHasMethod } from '../../schemas/index.js';
|
|
12
|
+
import { Timer } from '../../timer/index.js';
|
|
12
13
|
import { jsonStringify } from '../convert.js';
|
|
13
14
|
import { assert } from '../js_utils.js';
|
|
14
15
|
const defaultServerConfig = {
|
|
15
16
|
http200OnError: false,
|
|
16
17
|
maxBatchSize: 100,
|
|
17
|
-
maxBodySizeBytes: '1mb'
|
|
18
|
+
maxBodySizeBytes: '1mb',
|
|
19
|
+
corsAllowedOrigins: [],
|
|
20
|
+
corsAllowedHeaders: []
|
|
18
21
|
};
|
|
22
|
+
function normalizeCorsOrigin(origin) {
|
|
23
|
+
if (origin === '*') {
|
|
24
|
+
return origin;
|
|
25
|
+
}
|
|
26
|
+
const url = new URL(origin);
|
|
27
|
+
if (![
|
|
28
|
+
'http:',
|
|
29
|
+
'https:'
|
|
30
|
+
].includes(url.protocol)) {
|
|
31
|
+
throw new Error(`Invalid CORS origin protocol: ${origin}`);
|
|
32
|
+
}
|
|
33
|
+
if (url.username || url.password || url.pathname !== '' && url.pathname !== '/' || url.search || url.hash) {
|
|
34
|
+
throw new Error(`CORS allowed origin must not include credentials, a path, query parameters, or a fragment: ${origin}`);
|
|
35
|
+
}
|
|
36
|
+
return url.origin;
|
|
37
|
+
}
|
|
19
38
|
export class SafeJsonRpcServer {
|
|
20
39
|
proxy;
|
|
21
40
|
healthCheck;
|
|
22
41
|
extraMiddlewares;
|
|
42
|
+
diagnosticsMiddleware;
|
|
23
43
|
log;
|
|
24
44
|
/**
|
|
25
45
|
* The HTTP server accepting remote requests.
|
|
26
46
|
* This member field is initialized when the server is started.
|
|
27
47
|
*/ httpServer;
|
|
28
48
|
config;
|
|
29
|
-
constructor(/** The proxy object to delegate requests to */ proxy, config = {}, /** Health check function */ healthCheck = ()=>true, /** Additional middlewares */ extraMiddlewares = [], /** Logger */ log = createLogger('json-rpc:server')){
|
|
49
|
+
constructor(/** The proxy object to delegate requests to */ proxy, config = {}, /** Health check function */ healthCheck = ()=>true, /** Additional Koa middlewares */ extraMiddlewares = [], /** Additional per-request diagnostics middlewares */ diagnosticsMiddleware, /** Logger */ log = createLogger('json-rpc:server')){
|
|
30
50
|
this.proxy = proxy;
|
|
31
51
|
this.healthCheck = healthCheck;
|
|
32
52
|
this.extraMiddlewares = extraMiddlewares;
|
|
53
|
+
this.diagnosticsMiddleware = diagnosticsMiddleware;
|
|
33
54
|
this.log = log;
|
|
34
55
|
this.config = {
|
|
35
56
|
...defaultServerConfig,
|
|
36
57
|
...config
|
|
37
58
|
};
|
|
59
|
+
this.config.corsAllowedOrigins = this.config.corsAllowedOrigins.map(normalizeCorsOrigin);
|
|
38
60
|
// handle empty string
|
|
39
61
|
if (!this.config.maxBodySizeBytes) {
|
|
40
62
|
this.config.maxBodySizeBytes = defaultServerConfig.maxBodySizeBytes;
|
|
41
63
|
}
|
|
42
64
|
}
|
|
65
|
+
/** Returns the status of this server, including per-component health when the health check reports it. */ getStatus() {
|
|
66
|
+
return Promise.resolve(this.healthCheck()).then((result)=>{
|
|
67
|
+
const { healthy, details } = normalizeStatusCheckResult(result);
|
|
68
|
+
return {
|
|
69
|
+
ok: healthy,
|
|
70
|
+
...details
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
}
|
|
43
74
|
isHealthy() {
|
|
44
|
-
return this.
|
|
75
|
+
return this.getStatus().then((status)=>status.ok);
|
|
45
76
|
}
|
|
46
77
|
/**
|
|
47
78
|
* Get an express app object.
|
|
@@ -81,7 +112,7 @@ export class SafeJsonRpcServer {
|
|
|
81
112
|
jsonrpc: '2.0',
|
|
82
113
|
id: null,
|
|
83
114
|
error: {
|
|
84
|
-
code: -
|
|
115
|
+
code: -32603,
|
|
85
116
|
message: err.message ?? 'Internal error'
|
|
86
117
|
}
|
|
87
118
|
};
|
|
@@ -113,6 +144,32 @@ export class SafeJsonRpcServer {
|
|
|
113
144
|
br: false
|
|
114
145
|
}));
|
|
115
146
|
app.use(jsonResponse);
|
|
147
|
+
const corsAllowedHeaders = this.config.corsAllowedHeaders.length > 0 ? {
|
|
148
|
+
allowHeaders: this.config.corsAllowedHeaders
|
|
149
|
+
} : {};
|
|
150
|
+
if (this.config.corsAllowedOrigins.length === 0) {
|
|
151
|
+
app.use(cors(corsAllowedHeaders));
|
|
152
|
+
} else {
|
|
153
|
+
const allowedOrigins = new Set(this.config.corsAllowedOrigins);
|
|
154
|
+
const allowAnyOrigin = allowedOrigins.has('*');
|
|
155
|
+
app.use(cors({
|
|
156
|
+
origin: (ctx)=>{
|
|
157
|
+
const origin = ctx.get('Origin');
|
|
158
|
+
if (!origin) {
|
|
159
|
+
return '';
|
|
160
|
+
}
|
|
161
|
+
if (allowAnyOrigin) {
|
|
162
|
+
return origin;
|
|
163
|
+
}
|
|
164
|
+
if (allowedOrigins.has(origin)) {
|
|
165
|
+
return origin;
|
|
166
|
+
}
|
|
167
|
+
return '';
|
|
168
|
+
},
|
|
169
|
+
credentials: true,
|
|
170
|
+
...corsAllowedHeaders
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
116
173
|
for (const middleware of this.extraMiddlewares){
|
|
117
174
|
app.use(middleware);
|
|
118
175
|
}
|
|
@@ -123,7 +180,6 @@ export class SafeJsonRpcServer {
|
|
|
123
180
|
'json'
|
|
124
181
|
]
|
|
125
182
|
}));
|
|
126
|
-
app.use(cors());
|
|
127
183
|
app.use(router.routes());
|
|
128
184
|
app.use(router.allowedMethods());
|
|
129
185
|
return app;
|
|
@@ -151,7 +207,7 @@ export class SafeJsonRpcServer {
|
|
|
151
207
|
};
|
|
152
208
|
return;
|
|
153
209
|
}
|
|
154
|
-
const resp = await this.processBatch(ctx.request.body);
|
|
210
|
+
const resp = await this.processBatch(ctx.request.body, ctx.request.headers);
|
|
155
211
|
if (Array.isArray(resp)) {
|
|
156
212
|
ctx.status = 200;
|
|
157
213
|
ctx.body = resp;
|
|
@@ -160,7 +216,7 @@ export class SafeJsonRpcServer {
|
|
|
160
216
|
ctx.body = resp;
|
|
161
217
|
}
|
|
162
218
|
} else {
|
|
163
|
-
const resp = await this.processRequest(ctx.request.body);
|
|
219
|
+
const resp = await this.processRequest(ctx.request.body, ctx.request.headers);
|
|
164
220
|
if ('error' in resp) {
|
|
165
221
|
ctx.status = this.config.http200OnError ? 200 : 400;
|
|
166
222
|
}
|
|
@@ -169,7 +225,7 @@ export class SafeJsonRpcServer {
|
|
|
169
225
|
});
|
|
170
226
|
return router;
|
|
171
227
|
}
|
|
172
|
-
async processBatch(requests) {
|
|
228
|
+
async processBatch(requests, headers = {}) {
|
|
173
229
|
if (requests.length === 0) {
|
|
174
230
|
return {
|
|
175
231
|
jsonrpc: '2.0',
|
|
@@ -180,7 +236,7 @@ export class SafeJsonRpcServer {
|
|
|
180
236
|
id: null
|
|
181
237
|
};
|
|
182
238
|
}
|
|
183
|
-
const results = await Promise.allSettled(requests.map((req)=>this.processRequest(req)));
|
|
239
|
+
const results = await Promise.allSettled(requests.map((req)=>this.processRequest(req, headers)));
|
|
184
240
|
return results.map((res)=>{
|
|
185
241
|
if (res.status === 'fulfilled') {
|
|
186
242
|
return res.value;
|
|
@@ -189,14 +245,14 @@ export class SafeJsonRpcServer {
|
|
|
189
245
|
return {
|
|
190
246
|
jsonrpc: '2.0',
|
|
191
247
|
error: {
|
|
192
|
-
code: -
|
|
193
|
-
message: '
|
|
248
|
+
code: -32603,
|
|
249
|
+
message: 'Internal error'
|
|
194
250
|
},
|
|
195
251
|
id: null
|
|
196
252
|
};
|
|
197
253
|
});
|
|
198
254
|
}
|
|
199
|
-
async processRequest(request) {
|
|
255
|
+
async processRequest(request, headers = {}) {
|
|
200
256
|
if (!request || typeof request !== 'object') {
|
|
201
257
|
return {
|
|
202
258
|
jsonrpc: '2.0',
|
|
@@ -230,11 +286,31 @@ export class SafeJsonRpcServer {
|
|
|
230
286
|
};
|
|
231
287
|
} else {
|
|
232
288
|
try {
|
|
233
|
-
|
|
289
|
+
let result;
|
|
290
|
+
if (this.diagnosticsMiddleware) {
|
|
291
|
+
const diagnosticsData = {
|
|
292
|
+
id: id ?? null,
|
|
293
|
+
method,
|
|
294
|
+
params,
|
|
295
|
+
headers
|
|
296
|
+
};
|
|
297
|
+
await this.diagnosticsMiddleware(diagnosticsData, async ()=>{
|
|
298
|
+
result = await this.proxy.call(method, params, (durationMs, succeeded)=>{
|
|
299
|
+
diagnosticsData.requestValidationDurationMs = durationMs;
|
|
300
|
+
diagnosticsData.requestValidationSucceeded = succeeded;
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
} else {
|
|
304
|
+
result = await this.proxy.call(method, params);
|
|
305
|
+
}
|
|
306
|
+
// Coerce an undefined return value to null so the response always carries a `result` key.
|
|
307
|
+
// JSON.stringify drops undefined-valued keys, which would otherwise produce a JSON-RPC
|
|
308
|
+
// response with neither `result` nor `error` — a spec violation that leaves callers unable
|
|
309
|
+
// to distinguish "not found" from a malformed response.
|
|
234
310
|
return {
|
|
235
311
|
jsonrpc,
|
|
236
312
|
id,
|
|
237
|
-
result
|
|
313
|
+
result: result ?? null
|
|
238
314
|
};
|
|
239
315
|
} catch (err) {
|
|
240
316
|
if (err && err instanceof ZodError) {
|
|
@@ -307,6 +383,11 @@ export class SafeJsonRpcServer {
|
|
|
307
383
|
return await this.proxy.call(methodName, jsonParams);
|
|
308
384
|
}
|
|
309
385
|
}
|
|
386
|
+
function normalizeStatusCheckResult(result) {
|
|
387
|
+
return typeof result === 'boolean' ? {
|
|
388
|
+
healthy: result
|
|
389
|
+
} : result;
|
|
390
|
+
}
|
|
310
391
|
/**
|
|
311
392
|
* Forwards calls to a handler. Relies on a schema definition to validate and convert inputs
|
|
312
393
|
* before forwarding calls, and then converts outputs into JSON using default conversions.
|
|
@@ -324,13 +405,21 @@ export class SafeJsonRpcServer {
|
|
|
324
405
|
* @param methodName - The RPC method.
|
|
325
406
|
* @param jsonParams - The RPC parameters.
|
|
326
407
|
* @returns The remote result.
|
|
327
|
-
*/ async call(methodName, jsonParams = []) {
|
|
408
|
+
*/ async call(methodName, jsonParams = [], onRequestValidated) {
|
|
328
409
|
this.log.debug(format(`request`, methodName, jsonParams));
|
|
329
|
-
assert(Array.isArray(jsonParams), `Params to ${methodName} is not an array: ${jsonParams}`);
|
|
330
410
|
assert(schemaHasMethod(this.schema, methodName), `Method ${methodName} not found in schema`);
|
|
331
411
|
const method = this.handler[methodName];
|
|
332
412
|
assert(typeof method === 'function', `Method ${methodName} is not a function`);
|
|
333
|
-
const
|
|
413
|
+
const validationTimer = new Timer();
|
|
414
|
+
let args;
|
|
415
|
+
try {
|
|
416
|
+
assert(Array.isArray(jsonParams), `Params to ${methodName} is not an array: ${jsonParams}`);
|
|
417
|
+
args = await parseWithOptionals(jsonParams, getSchemaParameters(this.schema[methodName]));
|
|
418
|
+
onRequestValidated?.(validationTimer.ms(), true);
|
|
419
|
+
} catch (error) {
|
|
420
|
+
onRequestValidated?.(validationTimer.ms(), false);
|
|
421
|
+
throw error;
|
|
422
|
+
}
|
|
334
423
|
const ret = await method.apply(this.handler, args);
|
|
335
424
|
this.log.debug(format('response', methodName, ret));
|
|
336
425
|
return ret;
|
|
@@ -346,12 +435,12 @@ class NamespacedSafeJsonProxy {
|
|
|
346
435
|
this.proxies[namespace] = new SafeJsonProxy(handler, schema);
|
|
347
436
|
}
|
|
348
437
|
}
|
|
349
|
-
call(namespacedMethodName, jsonParams = []) {
|
|
438
|
+
call(namespacedMethodName, jsonParams = [], onRequestValidated) {
|
|
350
439
|
const [namespace, methodName] = namespacedMethodName.split('_', 2);
|
|
351
440
|
assert(namespace && methodName, `Invalid namespaced method name: ${namespacedMethodName}`);
|
|
352
441
|
const handler = this.proxies[namespace];
|
|
353
442
|
assert(handler, `Namespace not found: ${namespace}`);
|
|
354
|
-
return handler.call(methodName, jsonParams);
|
|
443
|
+
return handler.call(methodName, jsonParams, onRequestValidated);
|
|
355
444
|
}
|
|
356
445
|
hasMethod(namespacedMethodName) {
|
|
357
446
|
const [namespace, methodName] = namespacedMethodName.split('_', 2);
|
|
@@ -368,19 +457,34 @@ export function makeHandler(handler, schema) {
|
|
|
368
457
|
function makeAggregateHealthcheck(namedHandlers, log) {
|
|
369
458
|
return async ()=>{
|
|
370
459
|
try {
|
|
371
|
-
const
|
|
460
|
+
const entries = await Promise.all(Object.entries(namedHandlers).map(async ([name, [, , healthCheck]])=>{
|
|
461
|
+
const { healthy, details } = normalizeStatusCheckResult(healthCheck ? await healthCheck() : true);
|
|
462
|
+
return [
|
|
372
463
|
name,
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
464
|
+
{
|
|
465
|
+
healthy,
|
|
466
|
+
...details
|
|
467
|
+
}
|
|
468
|
+
];
|
|
469
|
+
}));
|
|
470
|
+
const components = Object.fromEntries(entries);
|
|
471
|
+
const failed = entries.filter(([, status])=>!status.healthy).map(([name])=>name);
|
|
376
472
|
if (failed.length > 0) {
|
|
377
|
-
log?.warn(`Health check failed for ${failed.
|
|
378
|
-
|
|
473
|
+
log?.warn(`Health check failed for ${failed.join(', ')}`, {
|
|
474
|
+
components
|
|
475
|
+
});
|
|
379
476
|
}
|
|
380
|
-
return
|
|
477
|
+
return {
|
|
478
|
+
healthy: failed.length === 0,
|
|
479
|
+
details: {
|
|
480
|
+
components
|
|
481
|
+
}
|
|
482
|
+
};
|
|
381
483
|
} catch (err) {
|
|
382
484
|
log?.error(`Error during health check`, err);
|
|
383
|
-
return
|
|
485
|
+
return {
|
|
486
|
+
healthy: false
|
|
487
|
+
};
|
|
384
488
|
}
|
|
385
489
|
};
|
|
386
490
|
}
|
|
@@ -389,19 +493,20 @@ function makeAggregateHealthcheck(namedHandlers, log) {
|
|
|
389
493
|
* @param servers - List of handlers to be combined.
|
|
390
494
|
* @returns A single JsonRpcServer with namespaced methods.
|
|
391
495
|
*/ export function createNamespacedSafeJsonRpcServer(handlers, options = {}) {
|
|
392
|
-
const { middlewares, log } = options;
|
|
496
|
+
const { diagnostic, middlewares, log } = options;
|
|
393
497
|
const proxy = new NamespacedSafeJsonProxy(handlers);
|
|
394
498
|
const healthCheck = makeAggregateHealthcheck(handlers, log);
|
|
395
|
-
return new SafeJsonRpcServer(proxy, options, healthCheck, middlewares, log);
|
|
499
|
+
return new SafeJsonRpcServer(proxy, options, healthCheck, middlewares, diagnostic, log);
|
|
396
500
|
}
|
|
397
501
|
export function createSafeJsonRpcServer(handler, schema, options = {}) {
|
|
398
|
-
const { log, healthCheck, middlewares: extraMiddlewares } = options;
|
|
502
|
+
const { diagnostic, log, healthCheck, middlewares: extraMiddlewares } = options;
|
|
399
503
|
const proxy = new SafeJsonProxy(handler, schema);
|
|
400
|
-
return new SafeJsonRpcServer(proxy, options, healthCheck, extraMiddlewares, log);
|
|
504
|
+
return new SafeJsonRpcServer(proxy, options, healthCheck, extraMiddlewares, diagnostic, log);
|
|
401
505
|
}
|
|
402
506
|
/**
|
|
403
|
-
* Creates a router for handling a
|
|
404
|
-
*
|
|
507
|
+
* Creates a router for handling a status request that returns a 200 status code when healthy and a 500 otherwise,
|
|
508
|
+
* along with the reported status as a JSON body.
|
|
509
|
+
* @param getCurrentStatus - Function returning the current status of the server.
|
|
405
510
|
* @param apiPrefix - The prefix to use for all api requests
|
|
406
511
|
* @returns - The router for handling status requests.
|
|
407
512
|
*/ export function createStatusRouter(getCurrentStatus, apiPrefix = '') {
|
|
@@ -409,30 +514,44 @@ export function createSafeJsonRpcServer(handler, schema, options = {}) {
|
|
|
409
514
|
prefix: `${apiPrefix}`
|
|
410
515
|
});
|
|
411
516
|
router.get('/status', async (ctx)=>{
|
|
412
|
-
let
|
|
517
|
+
let status;
|
|
413
518
|
try {
|
|
414
|
-
|
|
519
|
+
status = await getCurrentStatus();
|
|
415
520
|
} catch {
|
|
416
|
-
|
|
521
|
+
status = {
|
|
522
|
+
ok: false
|
|
523
|
+
};
|
|
417
524
|
}
|
|
418
|
-
ctx.status = ok ? 200 : 500;
|
|
525
|
+
ctx.status = status.ok === true ? 200 : 500;
|
|
526
|
+
ctx.type = 'application/json';
|
|
527
|
+
ctx.body = status;
|
|
419
528
|
});
|
|
420
529
|
return router;
|
|
421
530
|
}
|
|
422
531
|
/**
|
|
423
532
|
* Wraps a JsonRpcServer in a nodejs http server and starts it.
|
|
424
|
-
* Installs a status router that
|
|
533
|
+
* Installs a status router that reports the status of the server, using its getStatus method when available so that
|
|
534
|
+
* per-component health is included, and falling back to isHealthy otherwise.
|
|
425
535
|
* Returns once starts listening unless noWait is set.
|
|
426
536
|
* @returns A running http server.
|
|
427
537
|
*/ export async function startHttpRpcServer(rpcServer, options = {}) {
|
|
428
538
|
const app = rpcServer.getApp(options.apiPrefix);
|
|
429
|
-
const
|
|
539
|
+
const getStatus = rpcServer.getStatus ? rpcServer.getStatus.bind(rpcServer) : async ()=>({
|
|
540
|
+
ok: await rpcServer.isHealthy() === true
|
|
541
|
+
});
|
|
542
|
+
const statusRouter = createStatusRouter(getStatus, options.apiPrefix);
|
|
430
543
|
app.use(statusRouter.routes()).use(statusRouter.allowedMethods());
|
|
431
544
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
432
545
|
const httpServer = http.createServer(app.callback());
|
|
433
546
|
if (options.timeoutMs) {
|
|
434
547
|
httpServer.timeout = options.timeoutMs;
|
|
435
548
|
}
|
|
549
|
+
if (options.keepAliveTimeoutMs !== undefined) {
|
|
550
|
+
httpServer.keepAliveTimeout = options.keepAliveTimeoutMs;
|
|
551
|
+
}
|
|
552
|
+
if (options.headersTimeoutMs !== undefined) {
|
|
553
|
+
httpServer.headersTimeout = options.headersTimeoutMs;
|
|
554
|
+
}
|
|
436
555
|
const { promise, resolve } = promiseWithResolvers();
|
|
437
556
|
const listenPort = options.port ? typeof options.port === 'string' ? parseInt(options.port) : options.port : 0;
|
|
438
557
|
httpServer.listen({
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Pino configuration that adds OpenTelemetry severity fields understood by CloudWatch Logs. */
|
|
2
|
+
export declare const AWSCloudLoggerConfig: {
|
|
3
|
+
messageKey: string;
|
|
4
|
+
formatters: {
|
|
5
|
+
level(label: string, level: number): object;
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXdzLWxvZ2dlci1jb25maWcuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9sb2cvYXdzLWxvZ2dlci1jb25maWcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBdUJBLGdHQUFnRztBQUNoRyxlQUFPLE1BQU0sb0JBQW9COzs7OztDQU9ILENBQUMifQ==
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aws-logger-config.d.ts","sourceRoot":"","sources":["../../src/log/aws-logger-config.ts"],"names":[],"mappings":"AAuBA,gGAAgG;AAChG,eAAO,MAAM,oBAAoB;;;;;CAOH,CAAC"}
|