@corpus-core/colibri-stateless 0.7.6 → 0.7.9

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/c4w.wasm ADDED
Binary file
package/chains.d.ts ADDED
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Copyright (c) 2025 corpus.core
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ * this software and associated documentation files (the "Software"), to deal in
6
+ * the Software without restriction, including without limitation the rights to
7
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ * the Software, and to permit persons to whom the Software is furnished to do so,
9
+ * subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all
12
+ * copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ *
21
+ * SPDX-License-Identifier: MIT
22
+ */
23
+ import { Config as C4Config, ChainConfig } from './types.js';
24
+ export declare const default_config: {
25
+ [key: string]: {
26
+ alias: string[];
27
+ beacon_apis: string[];
28
+ rpcs: string[];
29
+ prover: string[];
30
+ checkpointz: string[];
31
+ pollingInterval: number;
32
+ };
33
+ };
34
+ export declare function get_chain_id(chain_id: string): number;
35
+ export declare function chain_conf(config: C4Config, chainId: number | string): ChainConfig | undefined;
36
+ export declare const defaultChainConfig: {
37
+ [key: string]: {
38
+ alias: string[];
39
+ beacon_apis: string[];
40
+ rpcs: string[];
41
+ prover: string[];
42
+ checkpointz: string[];
43
+ pollingInterval: number;
44
+ };
45
+ };
46
+ export declare const resolveChainId: typeof get_chain_id;
47
+ export declare const getChainConfig: typeof chain_conf;
package/chains.js ADDED
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Copyright (c) 2025 corpus.core
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ * this software and associated documentation files (the "Software"), to deal in
6
+ * the Software without restriction, including without limitation the rights to
7
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ * the Software, and to permit persons to whom the Software is furnished to do so,
9
+ * subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all
12
+ * copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ *
21
+ * SPDX-License-Identifier: MIT
22
+ */
23
+ export const default_config = {
24
+ '1': {
25
+ alias: ["mainnet", "eth", "0x1"],
26
+ beacon_apis: ["https://lodestar-mainnet.chainsafe.io"],
27
+ rpcs: ["https://rpc.ankr.com/eth"],
28
+ prover: ["https://mainnet1.colibri-proof.tech"],
29
+ checkpointz: [], //"https://sync-mainnet.beaconcha.in", "https://beaconstate.info", "https://sync.invis.tools", "https://beaconstate.ethstaker.cc"],
30
+ pollingInterval: 12000,
31
+ },
32
+ '11155111': {
33
+ alias: ["sepolia", "0xaa36a7"],
34
+ beacon_apis: ["https://ethereum-sepolia-beacon-api.publicnode.com"],
35
+ rpcs: ["https://ethereum-sepolia-rpc.publicnode.com"],
36
+ prover: ["https://sepolia.colibri-proof.tech"],
37
+ checkpointz: [], // No public checkpointz for Sepolia yet
38
+ pollingInterval: 12000,
39
+ },
40
+ '100': {
41
+ alias: ["gnosis", "xdai", "0x64"],
42
+ beacon_apis: ["https://gnosis.colibri-proof.tech"],
43
+ rpcs: ["https://rpc.ankr.com/gnosis"],
44
+ prover: ["https://gnosis.colibri-proof.tech"],
45
+ checkpointz: [], // TODO: Add Gnosis checkpointz servers
46
+ pollingInterval: 5000,
47
+ },
48
+ '10200': {
49
+ alias: ["chiado", "0x27d8"],
50
+ beacon_apis: ["https://gnosis-chiado-beacon-api.publicnode.com"],
51
+ rpcs: ["https://gnosis-chiado-rpc.publicnode.com"],
52
+ prover: ["https://chiado.colibri-proof.tech"],
53
+ checkpointz: [], // No public checkpointz for Chiado yet
54
+ pollingInterval: 5000,
55
+ },
56
+ };
57
+ export function get_chain_id(chain_id) {
58
+ const chain_id_num = parseInt(chain_id);
59
+ if (!isNaN(chain_id_num))
60
+ return chain_id_num;
61
+ for (const chain in default_config) {
62
+ if (default_config[chain].alias.includes(chain_id))
63
+ return parseInt(chain);
64
+ }
65
+ throw new Error("Invalid chain id: " + chain_id);
66
+ }
67
+ export function chain_conf(config, chainId) {
68
+ const k = config?.chains?.[chainId];
69
+ if (k)
70
+ return k;
71
+ const k2 = default_config[chainId + ''];
72
+ if (k2)
73
+ return k2;
74
+ return undefined;
75
+ }
76
+ // Friendly aliases (optional, keep compatibility with planned naming)
77
+ export const defaultChainConfig = default_config;
78
+ export const resolveChainId = get_chain_id;
79
+ export const getChainConfig = chain_conf;
package/http.d.ts ADDED
@@ -0,0 +1,30 @@
1
+ import { Config as C4Config, DataRequest } from './types.js';
2
+ export type AcceptKind = 'json' | 'octet';
3
+ /**
4
+ * @param servers List of base URLs
5
+ * @param path Optional path to append to server URL
6
+ * @param method HTTP method
7
+ * @param payload Optional JSON payload (POST)
8
+ * @param accept Response type hint
9
+ * @param excludeMask Bitmask to skip servers by index
10
+ * @return Uint8Array of response bytes and nodeIndex used
11
+ */
12
+ export declare function fetch_from_servers(servers: string[], path: string, method: 'GET' | 'POST', payload?: any, accept?: AcceptKind, excludeMask?: number): Promise<{
13
+ data: Uint8Array;
14
+ nodeIndex: number;
15
+ }>;
16
+ /**
17
+ * Posts a JSON-RPC payload across multiple URLs and returns result or proof bytes.
18
+ * @param urls Ordered list of RPC endpoints
19
+ * @param payload JSON-RPC payload (id will be set to 1 if not provided)
20
+ * @param as_proof Expect octet-stream (true) or JSON result (false)
21
+ * @return result value for JSON or raw bytes for proofs
22
+ */
23
+ export declare function fetch_rpc(urls: string[], payload: any, as_proof?: boolean): Promise<any>;
24
+ /**
25
+ * Handles a C4 data request by fetching from configured servers, setting the
26
+ * response or error back into the C context, and leveraging cache if present.
27
+ * @param req DataRequest descriptor from C
28
+ * @param conf Colibri configuration
29
+ */
30
+ export declare function handle_request(req: DataRequest, conf: C4Config): Promise<void>;
package/http.js ADDED
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Copyright (c) 2025 corpus.core
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ * this software and associated documentation files (the "Software"), to deal in
6
+ * the Software without restriction, including without limitation the rights to
7
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ * the Software, and to permit persons to whom the Software is furnished to do so,
9
+ * subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all
12
+ * copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ *
21
+ * SPDX-License-Identifier: MIT
22
+ */
23
+ import { getC4w, as_char_ptr, copy_to_c } from './wasm.js';
24
+ function joinPath(base, path) {
25
+ if (!path)
26
+ return base;
27
+ if (!path.length)
28
+ return base;
29
+ return base + (path.startsWith('/') ? path : '/' + path);
30
+ }
31
+ /**
32
+ * @param servers List of base URLs
33
+ * @param path Optional path to append to server URL
34
+ * @param method HTTP method
35
+ * @param payload Optional JSON payload (POST)
36
+ * @param accept Response type hint
37
+ * @param excludeMask Bitmask to skip servers by index
38
+ * @return Uint8Array of response bytes and nodeIndex used
39
+ */
40
+ export async function fetch_from_servers(servers, path, method, payload, accept = 'json', excludeMask = 0) {
41
+ let lastError = 'All nodes failed';
42
+ let nodeIndex = 0;
43
+ for (const server of servers) {
44
+ if (excludeMask & (1 << nodeIndex)) {
45
+ nodeIndex++;
46
+ continue;
47
+ }
48
+ try {
49
+ const response = await fetch(joinPath(server, path), {
50
+ method,
51
+ body: payload ? JSON.stringify(payload) : undefined,
52
+ headers: {
53
+ 'Content-Type': 'application/json',
54
+ 'Accept': accept === 'json' ? 'application/json' : 'application/octet-stream',
55
+ },
56
+ });
57
+ if (!response.ok) {
58
+ lastError = `HTTP error! Status: ${response.status}, Details: ${await response.text()}`;
59
+ nodeIndex++;
60
+ continue;
61
+ }
62
+ const bytes = await response.blob().then(b => b.arrayBuffer());
63
+ return { data: new Uint8Array(bytes), nodeIndex };
64
+ }
65
+ catch (e) {
66
+ lastError = (e instanceof Error) ? e.message : String(e);
67
+ }
68
+ nodeIndex++;
69
+ }
70
+ throw new Error(lastError);
71
+ }
72
+ // --- Higher level helpers used by Colibri client ---
73
+ function log(msg) {
74
+ console.error(msg);
75
+ }
76
+ /**
77
+ * Posts a JSON-RPC payload across multiple URLs and returns result or proof bytes.
78
+ * @param urls Ordered list of RPC endpoints
79
+ * @param payload JSON-RPC payload (id will be set to 1 if not provided)
80
+ * @param as_proof Expect octet-stream (true) or JSON result (false)
81
+ * @return result value for JSON or raw bytes for proofs
82
+ */
83
+ export async function fetch_rpc(urls, payload, as_proof = false) {
84
+ let last_error = 'All nodes failed';
85
+ for (const url of urls) {
86
+ const response = await fetch(url, {
87
+ method: 'POST',
88
+ body: JSON.stringify({ id: 1, jsonrpc: '2.0', ...payload }),
89
+ headers: {
90
+ 'Content-Type': 'application/json',
91
+ 'Accept': as_proof ? 'application/octet-stream' : 'application/json',
92
+ },
93
+ });
94
+ if (response.ok) {
95
+ if (!as_proof) {
96
+ const res = await response.json();
97
+ if (res.error) {
98
+ last_error = res.error?.message || res.error;
99
+ continue;
100
+ }
101
+ return res.result;
102
+ }
103
+ const bytes = await response.blob().then(blob => blob.arrayBuffer());
104
+ return new Uint8Array(bytes);
105
+ }
106
+ else {
107
+ last_error = `HTTP error! Status: ${response.status}, Details: ${await response.text()}`;
108
+ }
109
+ }
110
+ throw new Error(last_error);
111
+ }
112
+ /**
113
+ * Handles a C4 data request by fetching from configured servers, setting the
114
+ * response or error back into the C context, and leveraging cache if present.
115
+ * @param req DataRequest descriptor from C
116
+ * @param conf Colibri configuration
117
+ */
118
+ export async function handle_request(req, conf) {
119
+ const free_buffers = [];
120
+ let servers = [];
121
+ switch (req.type) {
122
+ case 'checkpointz':
123
+ servers = [...(conf.checkpointz || []), ...(conf.beacon_apis || []), ...(conf.prover || [])];
124
+ break;
125
+ case 'beacon_api':
126
+ servers = [...(conf.beacon_apis || []), ...(conf.prover || [])];
127
+ break;
128
+ case 'prover':
129
+ servers = [...(conf.prover || [])];
130
+ break;
131
+ default:
132
+ servers = conf.rpcs || [...((conf.prover || []).map(p => p + (p.endsWith('/') ? '' : '/') + 'unverified_rpc'))];
133
+ break;
134
+ }
135
+ const c4w = await getC4w();
136
+ let path = (req.type == 'eth_rpc' && req.payload)
137
+ ? `rpc: ${req.payload?.method}(${req.payload?.params.join(',')})`
138
+ : req.url;
139
+ let cacheable = conf.cache && conf.cache.cacheable(req);
140
+ if (cacheable && conf.cache) {
141
+ const data = conf.cache.get(req);
142
+ if (data) {
143
+ if (conf.debug)
144
+ log(`::: ${path} (len=${data.length} bytes) CACHED`);
145
+ c4w._c4w_req_set_response(req.req_ptr, copy_to_c(data, c4w), data.length, 0);
146
+ return;
147
+ }
148
+ }
149
+ try {
150
+ const accept = req.encoding == 'json' ? 'json' : 'octet';
151
+ const { data, nodeIndex } = await fetch_from_servers(servers, req.url || '', req.method, req.payload, accept, req.exclude_mask);
152
+ c4w._c4w_req_set_response(req.req_ptr, copy_to_c(data, c4w), data.length, nodeIndex);
153
+ if (conf.debug)
154
+ log(`::: ${path} (len=${data.length} bytes) FETCHED`);
155
+ if (conf.cache && cacheable)
156
+ conf.cache.set(req, data);
157
+ }
158
+ catch (e) {
159
+ const last_error = (e instanceof Error) ? e.message : String(e);
160
+ c4w._c4w_req_set_error(req.req_ptr, as_char_ptr(last_error, c4w, free_buffers), 0);
161
+ if (conf.debug)
162
+ log(`::: ${path} (Error: ${last_error})`);
163
+ }
164
+ finally {
165
+ free_buffers.forEach(ptr => c4w._free(ptr));
166
+ }
167
+ }
package/index.d.ts CHANGED
@@ -27,31 +27,43 @@ import Strategy from './strategy.js';
27
27
  export { Strategy };
28
28
  export { ProviderRpcError, RequestArguments, Cache, C4Config, DataRequest, C4MethodType as MethodType, ProviderMessage, EthSubscribeSubscriptionType, EthNewFilterType };
29
29
  export { TransactionVerifier, PrototypeProtection } from './transactionVerifier.js';
30
- export declare function handle_request(req: DataRequest, conf: C4Config): Promise<void>;
31
30
  export default class C4Client {
32
31
  config: C4Config;
33
32
  private eventEmitter;
34
33
  private connectionState;
35
34
  private subscriptionManager;
35
+ private initMap;
36
+ private flags;
36
37
  private static readonly CRITICAL_METHODS;
38
+ /**
39
+ * Creates a new Colibri client instance.
40
+ *
41
+ * Example:
42
+ * ```ts
43
+ * import Colibri from '@corpus-core/colibri-stateless';
44
+ * const client = new Colibri({ chainId: 1 });
45
+ * const blockNumber = await client.request({ method: 'eth_blockNumber' });
46
+ * ```
47
+ *
48
+ * @param config Optional partial configuration; user config overrides defaults.
49
+ */
37
50
  constructor(config?: Partial<C4Config>);
38
- private getProverConfig;
39
- private get flags();
51
+ private fetch_checkpointz;
40
52
  /**
41
- * checks, whether the rpc-method is supported or proofable.
53
+ * Checks whether the RPC method is supported or proofable.
42
54
  * @param method - The method to check
43
55
  * @returns The method type
44
56
  */
45
57
  getMethodSupport(method: string): Promise<C4MethodType>;
46
58
  /**
47
- * creates a proof for the given method and arguments
59
+ * Creates a proof for the given method and arguments.
48
60
  * @param method - The method to create a proof for
49
61
  * @param args - The arguments to create a proof for
50
62
  * @returns The proof
51
63
  */
52
64
  createProof(method: string, args: any[]): Promise<Uint8Array>;
53
65
  /**
54
- * verifies a proof for the given method and arguments
66
+ * Verifies a proof for the given method and arguments.
55
67
  * @param method - The method to verify the proof for
56
68
  * @param args - The arguments to verify the proof for
57
69
  * @param proof - The proof to verify
@@ -59,10 +71,10 @@ export default class C4Client {
59
71
  */
60
72
  verifyProof(method: string, args: any[], proof: Uint8Array): Promise<any>;
61
73
  /**
62
- * executes a rpc-method, which includes
63
- * -creating or fetching the proof
64
- * -verifying the proof
65
- * -returning the result
74
+ * Executes an RPC method. This includes:
75
+ * - Creating or fetching the proof
76
+ * - Verifying the proof
77
+ * - Returning the result
66
78
  * @param method - The method to execute
67
79
  * @param args - The arguments to execute the method with
68
80
  * @returns The result
@@ -70,6 +82,18 @@ export default class C4Client {
70
82
  rpc(method: string, args: any[], method_type?: C4MethodType): Promise<any>;
71
83
  static register_storage(storage: C4Storage): Promise<void>;
72
84
  request(args: RequestArguments): Promise<unknown>;
85
+ /**
86
+ * Registers an event listener on the Colibri client.
87
+ * @param event Event name (e.g. 'connect', 'disconnect', 'message')
88
+ * @param callback Callback invoked with event data
89
+ * @return This client for chaining
90
+ */
73
91
  on(event: string, callback: (data: any) => void): this;
92
+ /**
93
+ * Removes a previously registered event listener from the Colibri client.
94
+ * @param event Event name
95
+ * @param callback Same function reference passed to on()
96
+ * @return This client for chaining
97
+ */
74
98
  removeListener(event: string, callback: (data: any) => void): this;
75
99
  }