univo 0.2.15 → 0.2.17

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/dist/cli.mjs CHANGED
@@ -4,8 +4,8 @@ import open from 'open';
4
4
  import { config } from 'dotenv';
5
5
  import { WebSocket } from 'partysocket';
6
6
  import { defineCommand, runMain } from 'citty';
7
- import { h as http } from './shared/univo.O0SoVQWh.mjs';
8
- import { c as createLogger, v as version, g as name } from './shared/univo.BgwFxZpJ.mjs';
7
+ import { h as http } from './shared/univo.DgQqsZEe.mjs';
8
+ import { c as createLogger, v as version, b as name } from './shared/univo.BMmU53c6.mjs';
9
9
 
10
10
  const log = createLogger({ quiet: false });
11
11
  const dev = defineCommand({
@@ -18,39 +18,47 @@ const dev = defineCommand({
18
18
  },
19
19
  async run(ctx) {
20
20
  try {
21
- if (!ctx.args.url.startsWith("http://")) throw new Error("`url` must start with http://");
22
- config();
21
+ if (!ctx.args.url.startsWith("http://")) {
22
+ throw new Error("`url` must start with http://");
23
+ }
24
+ config({ quiet: true });
23
25
  const localSigningKey = process.env.UNIVO_SIGNING_KEY;
24
- if (localSigningKey === void 0) throw new Error("Please provide a UNIVO_SIGNING_KEY environment variable");
26
+ if (localSigningKey === void 0) {
27
+ throw new Error("Please provide a UNIVO_SIGNING_KEY environment variable");
28
+ }
25
29
  const client = http(ctx.args.url, { signingKey: localSigningKey });
26
- const [events, metadata] = await Promise.all([
27
- client.request({ method: "private_getEvents", params: [] }),
28
- client.request({ method: "private_getMetadata", params: [] })
29
- ]);
30
+ await client.request({ method: "private_getMetadata", params: [] }).catch(() => {
31
+ throw new Error(`Failed to connect to ${ctx.args.url}. Check that your server is running on the correct port.`);
32
+ });
30
33
  const remoteSigningKey = crypto.randomUUID();
31
34
  const url = `https://tunnel-univo.app/v1/${crypto.randomUUID()}`;
32
35
  const endpoint = {
33
36
  url,
34
- events,
35
- metadata,
36
37
  signing_key: remoteSigningKey
37
38
  };
38
- const data = btoa(JSON.stringify(endpoint));
39
- await open(`https://univo.app/dev/${data}`);
39
+ const encoder = new TextEncoder();
40
+ const data = encoder.encode(JSON.stringify(endpoint));
41
+ const encoded = data.toBase64({ alphabet: "base64url", omitPadding: true });
42
+ await open(`https://univo.app/dev/${encoded}`);
40
43
  const ws$1 = new WebSocket(url, [], { WebSocket: ws });
41
44
  ws$1.binaryType = "arraybuffer";
42
- ws$1.onerror = (event) => log.error(event.message);
43
- ws$1.onopen = () => log.info(`Dev server started for ${ctx.args.url}`);
44
- ws$1.onclose = () => log.info(`Dev server closed for ${ctx.args.url}`);
45
+ ws$1.onerror = (event) => {
46
+ log.error(event.message);
47
+ };
48
+ ws$1.onopen = () => {
49
+ log.info(`Dev server started for ${ctx.args.url}`);
50
+ };
51
+ ws$1.onclose = () => {
52
+ log.info(`Dev server closed for ${ctx.args.url}`);
53
+ };
45
54
  ws$1.onmessage = async (event) => {
46
55
  try {
47
- const request = JSON.parse(event.data);
48
- log.info(`Received request ${request.id}:${request.method}`);
49
- const response = await client.request(request);
50
- ws$1.send(JSON.stringify(response));
51
- } catch (error) {
52
- const response = { jsonrpc: "2.0", id: null, error: { code: 0, message: "Invalid request" } };
53
- ws$1.send(JSON.stringify(response));
56
+ const json = JSON.parse(event.data);
57
+ log.debug(`Received request (${json.id}) for method '${json.method}'`);
58
+ const result = await client.request({ method: json.method, params: json.params });
59
+ ws$1.send(JSON.stringify({ jsonrpc: "2.0", id: json.id, result }));
60
+ } catch {
61
+ ws$1.send(JSON.stringify({ jsonrpc: "2.0", id: null, error: { code: 0, message: "Invalid request" } }));
54
62
  }
55
63
  };
56
64
  } catch (error) {
package/dist/index.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- export { B as Block, E as Event, a as Filter, H as Head, I as Indexer, M as Metadata, R as Result, i as indexer, m as matchFilter } from './shared/univo.CjvLVVxo.mjs';
1
+ export { B as Block, E as Event, a as Filter, H as Head, I as Indexer, M as Metadata, R as Result, i as indexer } from './shared/univo.DdHfpTWq.mjs';
2
2
  import '@storagesdk/core';
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { B as Block, E as Event, a as Filter, H as Head, I as Indexer, M as Metadata, R as Result, i as indexer, m as matchFilter } from './shared/univo.CjvLVVxo.js';
1
+ export { B as Block, E as Event, a as Filter, H as Head, I as Indexer, M as Metadata, R as Result, i as indexer } from './shared/univo.DdHfpTWq.js';
2
2
  import '@storagesdk/core';
package/dist/index.mjs CHANGED
@@ -1,9 +1,98 @@
1
1
  import { StorageError } from '@storagesdk/core';
2
- import { c as createException, a as catchException, l as local, g as getException } from './shared/univo.O0SoVQWh.mjs';
3
- import { c as createLogger, r as retry, v as version, h as hexToNumber, i as isHexEqual, d as decompress, a as decoder, n as normalizeHex, b as compress } from './shared/univo.BgwFxZpJ.mjs';
2
+ import { g as getException, c as createException, a as catchException, l as local } from './shared/univo.DgQqsZEe.mjs';
3
+ import { c as createLogger, d as decompress, e as decoder, r as retry, v as version, h as hexToNumber, a as isHexEqual, f as normalizeHex, g as compress } from './shared/univo.BMmU53c6.mjs';
4
4
  import 'ws';
5
5
  import 'partysocket';
6
6
 
7
+ function createServer(opts) {
8
+ const log = createLogger({ quiet: opts.quiet, prefix: "[server]" });
9
+ const http = async (req) => {
10
+ let body_buffer;
11
+ try {
12
+ body_buffer = await req.arrayBuffer();
13
+ } catch {
14
+ return Response.json(
15
+ { jsonrpc: "2.0", id: null, error: { code: 0, message: "Invalid request body" } },
16
+ //
17
+ { status: 400 }
18
+ );
19
+ }
20
+ const authorization = req.headers.get("Authorization");
21
+ const authenticated = authorization === `Bearer ${opts.signingKey}`;
22
+ let body_string;
23
+ if (req.headers.get("Content-Encoding") === "gzip") {
24
+ if (!authorization) {
25
+ return Response.json(
26
+ { jsonrpc: "2.0", id: null, error: { code: 0, message: "No bearer token provided" } },
27
+ //
28
+ { status: 400 }
29
+ );
30
+ }
31
+ if (!authenticated) {
32
+ return Response.json(
33
+ { jsonrpc: "2.0", id: null, error: { code: 0, message: "Invalid bearer token" } },
34
+ //
35
+ { status: 400 }
36
+ );
37
+ }
38
+ body_string = await decompress(body_buffer);
39
+ } else {
40
+ body_string = decoder.decode(body_buffer);
41
+ }
42
+ let json;
43
+ try {
44
+ json = JSON.parse(body_string);
45
+ } catch {
46
+ return Response.json(
47
+ { jsonrpc: "2.0", id: null, error: { code: 0, message: "Malformed JSON request body" } },
48
+ //
49
+ { status: 400 }
50
+ );
51
+ }
52
+ if (json.method.startsWith("private_")) {
53
+ if (!authorization) {
54
+ return Response.json(
55
+ { jsonrpc: "2.0", id: json.id, error: { code: 0, message: "No bearer token provided" } },
56
+ //
57
+ { status: 400 }
58
+ );
59
+ }
60
+ if (authorization !== `Bearer ${opts.signingKey}`) {
61
+ return Response.json(
62
+ { jsonrpc: "2.0", id: json.id, error: { code: 0, message: "Invalid bearer token" } },
63
+ //
64
+ { status: 400 }
65
+ );
66
+ }
67
+ }
68
+ try {
69
+ const result = await opts.transport.request({ method: json.method, params: json.params });
70
+ return Response.json({ jsonrpc: "2.0", id: json.id, result });
71
+ } catch (error) {
72
+ const message = getException(error);
73
+ if (message) {
74
+ log.error(message);
75
+ return Response.json(
76
+ { jsonrpc: "2.0", id: json.id, error: { code: 0, message } },
77
+ //
78
+ { status: 400 }
79
+ );
80
+ }
81
+ if (error instanceof Error) {
82
+ log.error(error.message);
83
+ }
84
+ return Response.json(
85
+ { jsonrpc: "2.0", id: json.id, error: { code: 0, message: "Internal server error" } },
86
+ //
87
+ { status: 500 }
88
+ );
89
+ }
90
+ };
91
+ return {
92
+ http
93
+ };
94
+ }
95
+
7
96
  function matchFilter(block, filter) {
8
97
  if (!chainValid(block, filter)) return false;
9
98
  if (!toBlockValid(block, filter)) return false;
@@ -164,6 +253,62 @@ function indexer(opts) {
164
253
  const indexerHeight = hexToNumber(stored.number) - 1;
165
254
  return Math.min(indexerHeight, finalizedHeight);
166
255
  };
256
+ const public_writeUnfinalizedHead = async (head) => {
257
+ log.debug("Received unfinalized head...");
258
+ const blocks_start = Date.now();
259
+ const [finalizedBlock, block] = await Promise.all([
260
+ getBlock({ chain: head.chain, number: "finalized" }),
261
+ getBlock({ chain: head.chain, number: head.number, hash: head.hash })
262
+ ]);
263
+ if (block === null) {
264
+ return;
265
+ }
266
+ if (finalizedBlock === null) {
267
+ log.debug("Failed to determine finalized height when processing unfinalized heads");
268
+ throw new Error(GetBlockError);
269
+ }
270
+ const finalizedHeight = hexToNumber(finalizedBlock.eth_getBlockByNumber.number);
271
+ if (hexToNumber(head.number) <= finalizedHeight) {
272
+ return;
273
+ }
274
+ log.debug(`Loaded block in ${Date.now() - blocks_start}ms`);
275
+ const metadata_start = Date.now();
276
+ await metadata.blocks.upsert([block]);
277
+ log.debug(`Persisted block to metadata in ${Date.now() - metadata_start}ms`);
278
+ const events_start = Date.now();
279
+ const promises = events_grouped_by_storage_map.entries().map(async ([storage, grouped_events]) => {
280
+ const batch = [];
281
+ for (const event2 of grouped_events) {
282
+ try {
283
+ if (!event2.filters.some((filter) => matchFilter(block, filter))) {
284
+ log.debug(`Block matches no filters for event ${event2.id}`);
285
+ continue;
286
+ }
287
+ const events = event2.handler(block);
288
+ for (const event3 of events) {
289
+ batch.push(event3);
290
+ }
291
+ } catch (error) {
292
+ log.error(`Failed to run your 'handler' for event ${event2.id}`);
293
+ throw error;
294
+ }
295
+ }
296
+ if (batch.length > 0) {
297
+ const start = Date.now();
298
+ await retry(() => storage.upsert(batch), 2).catch((error) => {
299
+ for (const event2 of grouped_events) {
300
+ log.error(`Failed to run your 'upsert' handler for event ${event2.id}`);
301
+ }
302
+ throw error;
303
+ });
304
+ for (const event2 of grouped_events) {
305
+ log.debug(`Recorded ${batch.length} ${event2.id} in ${Date.now() - start}ms`);
306
+ }
307
+ }
308
+ });
309
+ await Promise.all(promises);
310
+ log.debug(`Wrote head in ${Date.now() - events_start}ms`);
311
+ };
167
312
  const public_writeUnfinalizedHeads = async (heads) => {
168
313
  if (heads.length === 0) {
169
314
  return log.debug("No heads received, returning...");
@@ -345,7 +490,9 @@ function indexer(opts) {
345
490
  return log.debug("No new heads received, returning...");
346
491
  }
347
492
  if (hexToNumber(firstNewHead.number) !== indexerHeight + 1) {
348
- throw new Error("Client advanced too far. Heads received are greater than the indexer height");
493
+ throw new Error(
494
+ `Client advanced too far (${hexToNumber(firstNewHead.number)}). Heads received are greater than the first new head ${indexerHeight + 1}`
495
+ );
349
496
  }
350
497
  for (const head of newHeads) {
351
498
  const processed = await metadata.blocks.getBlocksByNumber(head.chain, head.number);
@@ -698,10 +845,21 @@ function indexer(opts) {
698
845
  });
699
846
  return { results: results_array, keys: filtered_keys };
700
847
  };
848
+ const event = (event2) => {
849
+ if (!/^[A-Za-z0-9_-]+$/.test(event2.id)) {
850
+ throw new Error(`Invalid event id \`${event2.id}\`. Only characters A-Z, a-z, 0-9, underscores, and hyphens are permitted.`);
851
+ }
852
+ all_events.push(event2);
853
+ const group = events_grouped_by_storage_map.get(event2.storage) ?? [];
854
+ group.push(event2);
855
+ events_grouped_by_storage_map.set(event2.storage, group);
856
+ return event2;
857
+ };
701
858
  const rpc = {
702
859
  request: {
703
860
  public_getFinalizedHeight,
704
861
  public_writeFinalizedHeads,
862
+ public_writeUnfinalizedHead,
705
863
  public_writeUnfinalizedHeads,
706
864
  public_deleteReorganisedHead,
707
865
  private_getEvents,
@@ -711,105 +869,17 @@ function indexer(opts) {
711
869
  },
712
870
  subscribe: {}
713
871
  };
714
- const transport = local(rpc);
715
- const handler = async (req) => {
716
- let body_buffer;
717
- try {
718
- body_buffer = await req.arrayBuffer();
719
- } catch {
720
- return Response.json(
721
- { jsonrpc: "2.0", id: null, error: { code: 0, message: "Invalid request body" } },
722
- //
723
- { status: 400 }
724
- );
725
- }
726
- const authorization = req.headers.get("Authorization");
727
- const authenticated = authorization === `Bearer ${opts.signingKey}`;
728
- let body_string;
729
- if (req.headers.get("Content-Encoding") === "gzip") {
730
- if (!authorization) {
731
- return Response.json(
732
- { jsonrpc: "2.0", id: null, error: { code: 0, message: "No bearer token provided" } },
733
- //
734
- { status: 400 }
735
- );
736
- }
737
- if (!authenticated) {
738
- return Response.json(
739
- { jsonrpc: "2.0", id: null, error: { code: 0, message: "Invalid bearer token" } },
740
- //
741
- { status: 400 }
742
- );
743
- }
744
- body_string = await decompress(body_buffer);
745
- } else {
746
- body_string = decoder.decode(body_buffer);
747
- }
748
- let json;
749
- try {
750
- json = JSON.parse(body_string);
751
- } catch {
752
- return Response.json(
753
- { jsonrpc: "2.0", id: null, error: { code: 0, message: "Malformed JSON request body" } },
754
- //
755
- { status: 400 }
756
- );
757
- }
758
- if (json.method.startsWith("private_")) {
759
- if (!authorization) {
760
- return Response.json(
761
- { jsonrpc: "2.0", id: json.id, error: { code: 0, message: "No bearer token provided" } },
762
- //
763
- { status: 400 }
764
- );
765
- }
766
- if (authorization !== `Bearer ${opts.signingKey}`) {
767
- return Response.json(
768
- { jsonrpc: "2.0", id: json.id, error: { code: 0, message: "Invalid bearer token" } },
769
- //
770
- { status: 400 }
771
- );
772
- }
773
- }
774
- try {
775
- const result = await transport.request({ method: json.method, params: json.params });
776
- return Response.json({ jsonrpc: "2.0", id: json.id, result });
777
- } catch (error) {
778
- const message = getException(error);
779
- if (message) {
780
- log.error(message);
781
- return Response.json(
782
- { jsonrpc: "2.0", id: json.id, error: { code: 0, message } },
783
- //
784
- { status: 400 }
785
- );
786
- }
787
- if (error instanceof Error) {
788
- log.error(error.message);
789
- }
790
- return Response.json(
791
- { jsonrpc: "2.0", id: json.id, error: { code: 0, message: "Internal server error" } },
792
- //
793
- { status: 500 }
794
- );
795
- }
796
- };
797
- const event = (event2) => {
798
- if (!/^[A-Za-z0-9_-]+$/.test(event2.id)) {
799
- throw new Error(`Invalid event id \`${event2.id}\`. Only characters A-Z, a-z, 0-9, underscores, and hyphens are permitted.`);
800
- }
801
- all_events.push(event2);
802
- const group = events_grouped_by_storage_map.get(event2.storage) ?? [];
803
- group.push(event2);
804
- events_grouped_by_storage_map.set(event2.storage, group);
805
- return event2;
806
- };
872
+ const server = createServer({
873
+ transport: local(rpc),
874
+ quiet: opts.quiet ?? false,
875
+ signingKey: opts.signingKey
876
+ });
807
877
  const indexer2 = {
808
878
  ...rpc,
809
879
  event,
810
- fetch: handler
880
+ fetch: server.http
811
881
  };
812
882
  return indexer2;
813
883
  }
814
884
 
815
- export { indexer, matchFilter };
885
+ export { indexer };
@@ -1,6 +1,6 @@
1
1
  import { NodeRpc, IndexerRpc } from './rpc.mjs';
2
2
  import { Transport } from './transport.mjs';
3
- import './shared/univo.CjvLVVxo.mjs';
3
+ import './shared/univo.DdHfpTWq.mjs';
4
4
  import '@storagesdk/core';
5
5
 
6
6
  type RealtimeOptions = {
@@ -1,6 +1,6 @@
1
1
  import { NodeRpc, IndexerRpc } from './rpc.js';
2
2
  import { Transport } from './transport.js';
3
- import './shared/univo.CjvLVVxo.js';
3
+ import './shared/univo.DdHfpTWq.js';
4
4
  import '@storagesdk/core';
5
5
 
6
6
  type RealtimeOptions = {
package/dist/realtime.mjs CHANGED
@@ -1,17 +1,27 @@
1
- import { c as createLogger, e as iife, h as hexToNumber, f as numberToHex, m as mutex, r as retry, i as isHexEqual } from './shared/univo.BgwFxZpJ.mjs';
1
+ import { c as createLogger, i as iife, h as hexToNumber, n as numberToHex, m as mutex, r as retry, a as isHexEqual } from './shared/univo.BMmU53c6.mjs';
2
2
 
3
- const MAX_LENGTH = 1e4;
4
3
  function defineBlockchain(opts) {
5
4
  const log = createLogger({ quiet: opts.quiet });
6
5
  const chain = [];
6
+ function getHeadBlock() {
7
+ const block = chain[chain.length - 1];
8
+ if (block === void 0) {
9
+ throw new Error("Expected non-empty chain when retrieving latest block");
10
+ }
11
+ return block;
12
+ }
13
+ function getTailBlock() {
14
+ const block = chain[0];
15
+ if (block === void 0) {
16
+ throw new Error("Expected non-empty chain when retrieving oldest block");
17
+ }
18
+ return block;
19
+ }
7
20
  function setHeadBlock(newBlock) {
8
21
  chain.push(newBlock);
9
22
  if (opts.onBlockAdded) {
10
23
  opts.onBlockAdded(newBlock);
11
24
  }
12
- if (chain.length > MAX_LENGTH) {
13
- chain.shift();
14
- }
15
25
  }
16
26
  function removeHeadBlock() {
17
27
  const head = chain.pop();
@@ -22,25 +32,19 @@ function defineBlockchain(opts) {
22
32
  opts.onBlockReorganised(head);
23
33
  }
24
34
  }
25
- function getHeadBlock() {
26
- const block = chain[chain.length - 1];
27
- if (block === void 0) {
28
- throw new Error("Expected non-empty chain when retrieving latest block");
35
+ async function prune(tail) {
36
+ if (hexToNumber(tail.number) >= hexToNumber(getHeadBlock().number)) {
37
+ throw new Error("Cannot remove head block");
29
38
  }
30
- return block;
31
- }
32
- function getOldestBlock() {
33
- const block = chain[0];
34
- if (block === void 0) {
35
- throw new Error("Expected non-empty chain when retrieving oldest block");
39
+ while (hexToNumber(tail.number) > hexToNumber(getTailBlock().number)) {
40
+ chain.shift();
36
41
  }
37
- return block;
38
42
  }
39
43
  async function reconcile(newBlock) {
40
44
  if (chain.length === 0) {
41
45
  return setHeadBlock(newBlock);
42
46
  }
43
- if (hexToNumber(newBlock.number) < hexToNumber(getOldestBlock().number)) {
47
+ if (hexToNumber(newBlock.number) < hexToNumber(getTailBlock().number)) {
44
48
  log.info(`Received block ${hexToNumber(newBlock.number)} older than our local chain`);
45
49
  throw new Error("Not implemented");
46
50
  }
@@ -74,6 +78,7 @@ function defineBlockchain(opts) {
74
78
  }
75
79
  return {
76
80
  chain,
81
+ prune: mutex(prune),
77
82
  reconcile: mutex(reconcile)
78
83
  };
79
84
  }
@@ -92,31 +97,25 @@ function realtime(opts) {
92
97
  opts.node.request({ method: "eth_getBlockByNumber", params: ["latest", false] }),
93
98
  opts.indexer.request({ method: "public_getFinalizedHeight", params: [chain] })
94
99
  ]);
95
- let pending = [];
96
100
  const latest = defineBlockchain({
97
101
  getBlockByHash,
98
102
  quiet: opts.quiet ?? false,
99
103
  onBlockAdded: async (head) => {
100
104
  try {
101
105
  log.debug("Received unfinalized head");
102
- pending.push(head);
103
- const heads = pending.map((head2) => ({ chain, ...head2 }));
104
- await opts.indexer.request({ method: "public_writeUnfinalizedHeads", params: [heads] });
105
- log.debug(`Delivered ${heads.length} unfinalized head(s)`);
106
- pending = pending.filter((head2) => {
107
- return !heads.some((_head) => {
108
- return isHexEqual(head2.hash, _head.hash);
109
- });
110
- });
106
+ await retry(() => opts.indexer.request({ method: "public_writeUnfinalizedHead", params: [{ chain, ...head }] }), 2);
107
+ log.debug("Delivered unfinalized head");
111
108
  } catch (error) {
112
109
  if (error instanceof Error) {
113
- log.warn(`Failed to write heads: ${error.message}`);
110
+ log.warn(`Failed to write unfinalized head: ${error.message}`);
114
111
  }
115
112
  }
116
113
  },
117
114
  onBlockReorganised: async (head) => {
118
115
  try {
116
+ log.debug("Received reorganised head");
119
117
  await retry(() => opts.indexer.request({ method: "public_deleteReorganisedHead", params: [{ chain, ...head }] }), 2);
118
+ log.debug("Delivered reorganised head");
120
119
  } catch (error) {
121
120
  if (error instanceof Error) {
122
121
  log.warn(`Failed to write reorganised head: ${error.message}`);
@@ -194,6 +193,16 @@ function realtime(opts) {
194
193
  log.debug(`Delivered ${newHeads.length} finalized head(s)`);
195
194
  indexerHeight = hexToNumber(finalizedBlock.number);
196
195
  log.debug(`Updated indexer height to ${indexerHeight}`);
196
+ await indexer.prune({
197
+ number: finalizedBlock.number,
198
+ hash: finalizedBlock.hash,
199
+ parent_hash: finalizedBlock.parentHash
200
+ });
201
+ await latest.prune({
202
+ number: finalizedBlock.number,
203
+ hash: finalizedBlock.hash,
204
+ parent_hash: finalizedBlock.parentHash
205
+ });
197
206
  } catch (error) {
198
207
  if (error instanceof Error) {
199
208
  log.error(`Failed to reconcile finalized head: ${error.message}`);
package/dist/rpc.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { H as Head, M as Metadata, F as Flatten, a as Filter, B as Block, R as Result } from './shared/univo.CjvLVVxo.mjs';
1
+ import { H as Head, M as Metadata, F as Flatten, a as Filter, B as Block, R as Result } from './shared/univo.DdHfpTWq.mjs';
2
2
  import '@storagesdk/core';
3
3
 
4
4
  type Rpc = {
@@ -54,6 +54,10 @@ type IndexerRpc = {
54
54
  * Accepts a reorganised block and deletes all related events from storage
55
55
  */
56
56
  public_deleteReorganisedHead: (head: Head) => Promise<void>;
57
+ /**
58
+ * Accepts an unfinalized head and writes all events to storage
59
+ */
60
+ public_writeUnfinalizedHead: (head: Head) => Promise<void>;
57
61
  /**
58
62
  * Accepts a list of the latest block heads and writes all events to storage
59
63
  */
package/dist/rpc.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { H as Head, M as Metadata, F as Flatten, a as Filter, B as Block, R as Result } from './shared/univo.CjvLVVxo.js';
1
+ import { H as Head, M as Metadata, F as Flatten, a as Filter, B as Block, R as Result } from './shared/univo.DdHfpTWq.js';
2
2
  import '@storagesdk/core';
3
3
 
4
4
  type Rpc = {
@@ -54,6 +54,10 @@ type IndexerRpc = {
54
54
  * Accepts a reorganised block and deletes all related events from storage
55
55
  */
56
56
  public_deleteReorganisedHead: (head: Head) => Promise<void>;
57
+ /**
58
+ * Accepts an unfinalized head and writes all events to storage
59
+ */
60
+ public_writeUnfinalizedHead: (head: Head) => Promise<void>;
57
61
  /**
58
62
  * Accepts a list of the latest block heads and writes all events to storage
59
63
  */
@@ -1,5 +1,5 @@
1
1
  const name = "univo";
2
- const version = "0.2.15";
2
+ const version = "0.2.17";
3
3
 
4
4
  function createLogger(opts) {
5
5
  let prefix = `[${name}@${version}]`;
@@ -93,4 +93,4 @@ const normalizeHex = (hex, length) => {
93
93
  return `0x${hex.slice(2).toLowerCase().padStart(length, "0")}`;
94
94
  };
95
95
 
96
- export { decoder as a, compress as b, createLogger as c, decompress as d, iife as e, numberToHex as f, name as g, hexToNumber as h, isHexEqual as i, raise as j, mutex as m, normalizeHex as n, retry as r, version as v };
96
+ export { isHexEqual as a, name as b, createLogger as c, decompress as d, decoder as e, normalizeHex as f, compress as g, hexToNumber as h, iife as i, raise as j, mutex as m, numberToHex as n, retry as r, version as v };
@@ -38,7 +38,6 @@ type Filter = {
38
38
  /** Index blocks that involve this address */
39
39
  address?: `0x${string}`;
40
40
  };
41
- declare function matchFilter(block: Block, filter: Filter): boolean;
42
41
  /**
43
42
  * Events -----------------------------------------------------------------------------------------------------------------------------------
44
43
  */
@@ -192,6 +191,7 @@ declare function indexer<TBlock extends Block>(opts: IndexerOptions<TBlock>): {
192
191
  request: {
193
192
  public_getFinalizedHeight: (chain: `0x${string}`) => Promise<number>;
194
193
  public_deleteReorganisedHead: (head: Head) => Promise<void>;
194
+ public_writeUnfinalizedHead: (head: Head) => Promise<void>;
195
195
  public_writeUnfinalizedHeads: (heads: Head[]) => Promise<void>;
196
196
  public_writeFinalizedHeads: (heads: Head[]) => Promise<void>;
197
197
  private_getMetadata: () => Promise<Metadata>;
@@ -216,5 +216,5 @@ declare function indexer<TBlock extends Block>(opts: IndexerOptions<TBlock>): {
216
216
  subscribe: Record<string, never>;
217
217
  };
218
218
 
219
- export { indexer as i, matchFilter as m };
219
+ export { indexer as i };
220
220
  export type { Block as B, Event as E, Flatten as F, Head as H, Indexer as I, Metadata as M, Result as R, Filter as a };
@@ -38,7 +38,6 @@ type Filter = {
38
38
  /** Index blocks that involve this address */
39
39
  address?: `0x${string}`;
40
40
  };
41
- declare function matchFilter(block: Block, filter: Filter): boolean;
42
41
  /**
43
42
  * Events -----------------------------------------------------------------------------------------------------------------------------------
44
43
  */
@@ -192,6 +191,7 @@ declare function indexer<TBlock extends Block>(opts: IndexerOptions<TBlock>): {
192
191
  request: {
193
192
  public_getFinalizedHeight: (chain: `0x${string}`) => Promise<number>;
194
193
  public_deleteReorganisedHead: (head: Head) => Promise<void>;
194
+ public_writeUnfinalizedHead: (head: Head) => Promise<void>;
195
195
  public_writeUnfinalizedHeads: (heads: Head[]) => Promise<void>;
196
196
  public_writeFinalizedHeads: (heads: Head[]) => Promise<void>;
197
197
  private_getMetadata: () => Promise<Metadata>;
@@ -216,5 +216,5 @@ declare function indexer<TBlock extends Block>(opts: IndexerOptions<TBlock>): {
216
216
  subscribe: Record<string, never>;
217
217
  };
218
218
 
219
- export { indexer as i, matchFilter as m };
219
+ export { indexer as i };
220
220
  export type { Block as B, Event as E, Flatten as F, Head as H, Indexer as I, Metadata as M, Result as R, Filter as a };
@@ -1,6 +1,6 @@
1
1
  import ws from 'ws';
2
2
  import { WebSocket } from 'partysocket';
3
- import { b as compress, j as raise, c as createLogger } from './univo.BgwFxZpJ.mjs';
3
+ import { g as compress, j as raise, c as createLogger } from './univo.BMmU53c6.mjs';
4
4
 
5
5
  function createException(message) {
6
6
  return `univo:${message}`;
@@ -22,6 +22,7 @@ function getException(unknown) {
22
22
  }
23
23
  }
24
24
 
25
+ const DEFAULT_TIMEOUT = 60 * 1e3;
25
26
  const UnknownMethodError = createException("The requested RPC method does not exist on the provided implementation");
26
27
  function local(rpc) {
27
28
  const request = async (opts) => {
@@ -114,7 +115,7 @@ function wss(url, opts = {}) {
114
115
  const timeout = setTimeout(() => {
115
116
  requests.delete(body.id);
116
117
  reject(new Error("wss request timed out after 30 seconds"));
117
- }, 30 * 1e3);
118
+ }, DEFAULT_TIMEOUT);
118
119
  requests.set(body.id, (data) => {
119
120
  clearTimeout(timeout);
120
121
  requests.delete(body.id);
@@ -194,7 +195,7 @@ function http(url, opts = {}) {
194
195
  headers.set("Content-Encoding", "gzip");
195
196
  headers.set("Authorization", `Bearer ${opts.signingKey}`);
196
197
  }
197
- const res = await fetch(url, { headers, body, method: "POST", signal: AbortSignal.timeout(30 * 1e3) }).catch((cause) => {
198
+ const res = await fetch(url, { headers, body, method: "POST", signal: AbortSignal.timeout(DEFAULT_TIMEOUT) }).catch((cause) => {
198
199
  throw new Error(ClientConnectionError, { cause });
199
200
  });
200
201
  if (!res.ok || res.status < 200 || res.status >= 300) {
@@ -1,5 +1,5 @@
1
1
  import { Rpc } from './rpc.mjs';
2
- import './shared/univo.CjvLVVxo.mjs';
2
+ import './shared/univo.DdHfpTWq.mjs';
3
3
  import '@storagesdk/core';
4
4
 
5
5
  type Protocol = "http" | "wss" | "local";
@@ -1,5 +1,5 @@
1
1
  import { Rpc } from './rpc.js';
2
- import './shared/univo.CjvLVVxo.js';
2
+ import './shared/univo.DdHfpTWq.js';
3
3
  import '@storagesdk/core';
4
4
 
5
5
  type Protocol = "http" | "wss" | "local";
@@ -1,4 +1,4 @@
1
1
  import 'ws';
2
2
  import 'partysocket';
3
- export { h as http, l as local, w as wss } from './shared/univo.O0SoVQWh.mjs';
4
- import './shared/univo.BgwFxZpJ.mjs';
3
+ export { h as http, l as local, w as wss } from './shared/univo.DgQqsZEe.mjs';
4
+ import './shared/univo.BMmU53c6.mjs';
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "univo",
3
3
  "license": "MIT",
4
4
  "type": "module",
5
- "version": "0.2.15",
5
+ "version": "0.2.17",
6
6
  "sideEffects": false,
7
7
  "module": "./dist/index.mjs",
8
8
  "types": "./dist/index.d.ts",