@apibara/indexer 2.1.0-beta.40 → 2.1.0-beta.41

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.
@@ -13,35 +13,51 @@ declare function defineIndexerPlugin<TFilter, TBlock>(def: IndexerPlugin<TFilter
13
13
 
14
14
  type UseMiddlewareFunction = (fn: MiddlewareFunction<IndexerContext>) => void;
15
15
  interface IndexerHooks<TFilter, TBlock> {
16
- "plugins:init": () => void;
17
- "run:before": () => void;
18
- "run:after": () => void;
16
+ "plugins:init": ({ abortSignal }: {
17
+ abortSignal?: AbortSignal;
18
+ }) => void;
19
+ "run:before": ({ abortSignal }: {
20
+ abortSignal?: AbortSignal;
21
+ }) => void;
22
+ "run:after": ({ abortSignal }: {
23
+ abortSignal?: AbortSignal;
24
+ }) => void;
19
25
  "connect:before": ({ request, options, }: {
20
26
  request: StreamDataRequest<TFilter>;
21
27
  options: StreamDataOptions;
28
+ abortSignal?: AbortSignal;
22
29
  }) => void;
23
30
  "connect:after": ({ request, }: {
24
31
  request: StreamDataRequest<TFilter>;
32
+ abortSignal?: AbortSignal;
25
33
  }) => void;
26
- "connect:factory": ({ request, endCursor, }: {
34
+ "connect:factory": ({ request, endCursor, abortSignal, }: {
27
35
  request: StreamDataRequest<TFilter>;
28
36
  endCursor?: Cursor;
37
+ abortSignal?: AbortSignal;
29
38
  }) => void;
30
- "handler:middleware": ({ use }: {
39
+ "handler:middleware": ({ use, abortSignal, }: {
31
40
  use: UseMiddlewareFunction;
41
+ abortSignal?: AbortSignal;
32
42
  }) => void;
33
- message: ({ message }: {
43
+ message: ({ message, abortSignal, }: {
34
44
  message: StreamDataResponse<TBlock>;
45
+ abortSignal?: AbortSignal;
35
46
  }) => void;
36
- "message:invalidate": ({ message }: {
47
+ "message:invalidate": ({ message, abortSignal, }: {
37
48
  message: Invalidate;
49
+ abortSignal?: AbortSignal;
38
50
  }) => void;
39
- "message:finalize": ({ message }: {
51
+ "message:finalize": ({ message, abortSignal, }: {
40
52
  message: Finalize;
53
+ abortSignal?: AbortSignal;
54
+ }) => void;
55
+ "message:heartbeat": ({ abortSignal }: {
56
+ abortSignal?: AbortSignal;
41
57
  }) => void;
42
- "message:heartbeat": () => void;
43
- "message:systemMessage": ({ message }: {
58
+ "message:systemMessage": ({ message, abortSignal, }: {
44
59
  message: SystemMessage;
60
+ abortSignal?: AbortSignal;
45
61
  }) => void;
46
62
  }
47
63
  type IndexerStartingCursor = {
@@ -61,6 +77,7 @@ type HandlerArgs<TBlock> = {
61
77
  finality: DataFinality;
62
78
  production: DataProduction;
63
79
  context: IndexerContext;
80
+ abortSignal?: AbortSignal;
64
81
  };
65
82
  type IndexerConfig<TFilter, TBlock> = {
66
83
  streamUrl: string;
@@ -93,7 +110,8 @@ interface ReconnectOptions {
93
110
  declare function runWithReconnect<TFilter, TBlock>(client: Client<TFilter, TBlock>, indexer: Indexer<TFilter, TBlock>, options?: ReconnectOptions): Promise<void>;
94
111
  interface RunOptions {
95
112
  onConnect?: () => void | Promise<void>;
113
+ abortSignal?: AbortSignal;
96
114
  }
97
115
  declare function run<TFilter, TBlock>(client: Client<TFilter, TBlock>, indexer: Indexer<TFilter, TBlock>, runOptions?: RunOptions): Promise<void>;
98
116
 
99
- export { type HandlerArgs as H, type IndexerWithStreamConfig as I, type ReconnectOptions as R, type UseMiddlewareFunction as U, type IndexerHooks as a, type Indexer as b, type IndexerPlugin as c, type IndexerConfig as d, defineIndexerPlugin as e, type IndexerStartingCursor as f, defineIndexer as g, createIndexer as h, type RunOptions as i, run as j, runWithReconnect as r, useIndexerContext as u };
117
+ export { type HandlerArgs as H, type IndexerHooks as I, type ReconnectOptions as R, type UseMiddlewareFunction as U, type IndexerStartingCursor as a, type IndexerConfig as b, type IndexerWithStreamConfig as c, defineIndexer as d, type Indexer as e, createIndexer as f, type RunOptions as g, run as h, type IndexerPlugin as i, defineIndexerPlugin as j, runWithReconnect as r, useIndexerContext as u };
@@ -13,35 +13,51 @@ declare function defineIndexerPlugin<TFilter, TBlock>(def: IndexerPlugin<TFilter
13
13
 
14
14
  type UseMiddlewareFunction = (fn: MiddlewareFunction<IndexerContext>) => void;
15
15
  interface IndexerHooks<TFilter, TBlock> {
16
- "plugins:init": () => void;
17
- "run:before": () => void;
18
- "run:after": () => void;
16
+ "plugins:init": ({ abortSignal }: {
17
+ abortSignal?: AbortSignal;
18
+ }) => void;
19
+ "run:before": ({ abortSignal }: {
20
+ abortSignal?: AbortSignal;
21
+ }) => void;
22
+ "run:after": ({ abortSignal }: {
23
+ abortSignal?: AbortSignal;
24
+ }) => void;
19
25
  "connect:before": ({ request, options, }: {
20
26
  request: StreamDataRequest<TFilter>;
21
27
  options: StreamDataOptions;
28
+ abortSignal?: AbortSignal;
22
29
  }) => void;
23
30
  "connect:after": ({ request, }: {
24
31
  request: StreamDataRequest<TFilter>;
32
+ abortSignal?: AbortSignal;
25
33
  }) => void;
26
- "connect:factory": ({ request, endCursor, }: {
34
+ "connect:factory": ({ request, endCursor, abortSignal, }: {
27
35
  request: StreamDataRequest<TFilter>;
28
36
  endCursor?: Cursor;
37
+ abortSignal?: AbortSignal;
29
38
  }) => void;
30
- "handler:middleware": ({ use }: {
39
+ "handler:middleware": ({ use, abortSignal, }: {
31
40
  use: UseMiddlewareFunction;
41
+ abortSignal?: AbortSignal;
32
42
  }) => void;
33
- message: ({ message }: {
43
+ message: ({ message, abortSignal, }: {
34
44
  message: StreamDataResponse<TBlock>;
45
+ abortSignal?: AbortSignal;
35
46
  }) => void;
36
- "message:invalidate": ({ message }: {
47
+ "message:invalidate": ({ message, abortSignal, }: {
37
48
  message: Invalidate;
49
+ abortSignal?: AbortSignal;
38
50
  }) => void;
39
- "message:finalize": ({ message }: {
51
+ "message:finalize": ({ message, abortSignal, }: {
40
52
  message: Finalize;
53
+ abortSignal?: AbortSignal;
54
+ }) => void;
55
+ "message:heartbeat": ({ abortSignal }: {
56
+ abortSignal?: AbortSignal;
41
57
  }) => void;
42
- "message:heartbeat": () => void;
43
- "message:systemMessage": ({ message }: {
58
+ "message:systemMessage": ({ message, abortSignal, }: {
44
59
  message: SystemMessage;
60
+ abortSignal?: AbortSignal;
45
61
  }) => void;
46
62
  }
47
63
  type IndexerStartingCursor = {
@@ -61,6 +77,7 @@ type HandlerArgs<TBlock> = {
61
77
  finality: DataFinality;
62
78
  production: DataProduction;
63
79
  context: IndexerContext;
80
+ abortSignal?: AbortSignal;
64
81
  };
65
82
  type IndexerConfig<TFilter, TBlock> = {
66
83
  streamUrl: string;
@@ -93,7 +110,8 @@ interface ReconnectOptions {
93
110
  declare function runWithReconnect<TFilter, TBlock>(client: Client<TFilter, TBlock>, indexer: Indexer<TFilter, TBlock>, options?: ReconnectOptions): Promise<void>;
94
111
  interface RunOptions {
95
112
  onConnect?: () => void | Promise<void>;
113
+ abortSignal?: AbortSignal;
96
114
  }
97
115
  declare function run<TFilter, TBlock>(client: Client<TFilter, TBlock>, indexer: Indexer<TFilter, TBlock>, runOptions?: RunOptions): Promise<void>;
98
116
 
99
- export { type HandlerArgs as H, type IndexerWithStreamConfig as I, type ReconnectOptions as R, type UseMiddlewareFunction as U, type IndexerHooks as a, type Indexer as b, type IndexerPlugin as c, type IndexerConfig as d, defineIndexerPlugin as e, type IndexerStartingCursor as f, defineIndexer as g, createIndexer as h, type RunOptions as i, run as j, runWithReconnect as r, useIndexerContext as u };
117
+ export { type HandlerArgs as H, type IndexerHooks as I, type ReconnectOptions as R, type UseMiddlewareFunction as U, type IndexerStartingCursor as a, type IndexerConfig as b, type IndexerWithStreamConfig as c, defineIndexer as d, type Indexer as e, createIndexer as f, type RunOptions as g, run as h, type IndexerPlugin as i, defineIndexerPlugin as j, runWithReconnect as r, useIndexerContext as u };
@@ -1,5 +1,5 @@
1
1
  import { NestedHooks } from 'hookable';
2
- import { I as IndexerWithStreamConfig, a as IndexerHooks } from '../shared/indexer.806c605c.cjs';
2
+ import { c as IndexerWithStreamConfig, I as IndexerHooks } from '../shared/indexer.4ef52548.cjs';
3
3
  import '@apibara/protocol';
4
4
 
5
5
  type VcrResult = Record<string, unknown>;
@@ -1,5 +1,5 @@
1
1
  import { NestedHooks } from 'hookable';
2
- import { I as IndexerWithStreamConfig, a as IndexerHooks } from '../shared/indexer.806c605c.mjs';
2
+ import { c as IndexerWithStreamConfig, I as IndexerHooks } from '../shared/indexer.4ef52548.mjs';
3
3
  import '@apibara/protocol';
4
4
 
5
5
  type VcrResult = Record<string, unknown>;
@@ -1,5 +1,5 @@
1
1
  import { NestedHooks } from 'hookable';
2
- import { I as IndexerWithStreamConfig, a as IndexerHooks } from '../shared/indexer.806c605c.js';
2
+ import { c as IndexerWithStreamConfig, I as IndexerHooks } from '../shared/indexer.4ef52548.js';
3
3
  import '@apibara/protocol';
4
4
 
5
5
  type VcrResult = Record<string, unknown>;
@@ -1,5 +1,5 @@
1
1
  import { Cursor, StreamDataResponse, Client } from '@apibara/protocol';
2
- import { b as Indexer } from '../shared/indexer.806c605c.cjs';
2
+ import { e as Indexer } from '../shared/indexer.4ef52548.cjs';
3
3
  import 'hookable';
4
4
 
5
5
  type VcrConfig = {
@@ -1,5 +1,5 @@
1
1
  import { Cursor, StreamDataResponse, Client } from '@apibara/protocol';
2
- import { b as Indexer } from '../shared/indexer.806c605c.mjs';
2
+ import { e as Indexer } from '../shared/indexer.4ef52548.mjs';
3
3
  import 'hookable';
4
4
 
5
5
  type VcrConfig = {
@@ -1,5 +1,5 @@
1
1
  import { Cursor, StreamDataResponse, Client } from '@apibara/protocol';
2
- import { b as Indexer } from '../shared/indexer.806c605c.js';
2
+ import { e as Indexer } from '../shared/indexer.4ef52548.js';
3
3
  import 'hookable';
4
4
 
5
5
  type VcrConfig = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apibara/indexer",
3
- "version": "2.1.0-beta.40",
3
+ "version": "2.1.0-beta.41",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -70,7 +70,7 @@
70
70
  "vitest": "^1.6.0"
71
71
  },
72
72
  "dependencies": {
73
- "@apibara/protocol": "2.1.0-beta.40",
73
+ "@apibara/protocol": "2.1.0-beta.41",
74
74
  "@opentelemetry/api": "^1.9.0",
75
75
  "ci-info": "^4.1.0",
76
76
  "consola": "^3.4.2",
package/src/index.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from "./indexer";
2
2
  export { useIndexerContext } from "./context";
3
+ export { reloadIndexer, ReloadIndexerRequest } from "./utils";
package/src/indexer.ts CHANGED
@@ -33,40 +33,63 @@ import {
33
33
  import { createIndexerMetrics, createTracer } from "./otel";
34
34
  import type { IndexerPlugin } from "./plugins";
35
35
  import { useInternalContext } from "./plugins/context";
36
+ import { reloadIfNeeded } from "./utils";
36
37
 
37
38
  export type UseMiddlewareFunction = (
38
39
  fn: MiddlewareFunction<IndexerContext>,
39
40
  ) => void;
40
41
 
41
42
  export interface IndexerHooks<TFilter, TBlock> {
42
- "plugins:init": () => void;
43
- "run:before": () => void;
44
- "run:after": () => void;
43
+ "plugins:init": ({ abortSignal }: { abortSignal?: AbortSignal }) => void;
44
+ "run:before": ({ abortSignal }: { abortSignal?: AbortSignal }) => void;
45
+ "run:after": ({ abortSignal }: { abortSignal?: AbortSignal }) => void;
45
46
  "connect:before": ({
46
47
  request,
47
48
  options,
48
49
  }: {
49
50
  request: StreamDataRequest<TFilter>;
50
51
  options: StreamDataOptions;
52
+ abortSignal?: AbortSignal;
51
53
  }) => void;
52
54
  "connect:after": ({
53
55
  request,
54
56
  }: {
55
57
  request: StreamDataRequest<TFilter>;
58
+ abortSignal?: AbortSignal;
56
59
  }) => void;
57
60
  "connect:factory": ({
58
61
  request,
59
62
  endCursor,
63
+ abortSignal,
60
64
  }: {
61
65
  request: StreamDataRequest<TFilter>;
62
66
  endCursor?: Cursor;
67
+ abortSignal?: AbortSignal;
63
68
  }) => void;
64
- "handler:middleware": ({ use }: { use: UseMiddlewareFunction }) => void;
65
- message: ({ message }: { message: StreamDataResponse<TBlock> }) => void;
66
- "message:invalidate": ({ message }: { message: Invalidate }) => void;
67
- "message:finalize": ({ message }: { message: Finalize }) => void;
68
- "message:heartbeat": () => void;
69
- "message:systemMessage": ({ message }: { message: SystemMessage }) => void;
69
+ "handler:middleware": ({
70
+ use,
71
+ abortSignal,
72
+ }: { use: UseMiddlewareFunction; abortSignal?: AbortSignal }) => void;
73
+ message: ({
74
+ message,
75
+ abortSignal,
76
+ }: {
77
+ message: StreamDataResponse<TBlock>;
78
+ abortSignal?: AbortSignal;
79
+ }) => void;
80
+ "message:invalidate": ({
81
+ message,
82
+ abortSignal,
83
+ }: { message: Invalidate; abortSignal?: AbortSignal }) => void;
84
+ "message:finalize": ({
85
+ message,
86
+ abortSignal,
87
+ }: { message: Finalize; abortSignal?: AbortSignal }) => void;
88
+ "message:heartbeat": ({ abortSignal }: { abortSignal?: AbortSignal }) => void;
89
+ "message:systemMessage": ({
90
+ message,
91
+ abortSignal,
92
+ }: { message: SystemMessage; abortSignal?: AbortSignal }) => void;
70
93
  }
71
94
 
72
95
  export type IndexerStartingCursor =
@@ -90,6 +113,7 @@ export type HandlerArgs<TBlock> = {
90
113
  finality: DataFinality;
91
114
  production: DataProduction;
92
115
  context: IndexerContext;
116
+ abortSignal?: AbortSignal;
93
117
  };
94
118
 
95
119
  export type IndexerConfig<TFilter, TBlock> = {
@@ -170,15 +194,19 @@ export async function runWithReconnect<TFilter, TBlock>(
170
194
  const retryDelay = options.retryDelay ?? 1_000;
171
195
  const maxWait = options.maxWait ?? 30_000;
172
196
 
173
- const runOptions: RunOptions = {
174
- onConnect() {
175
- retryCount = 0;
176
- },
177
- };
178
-
179
197
  while (true) {
198
+ const abortController = new AbortController();
199
+
200
+ const runOptions: RunOptions = {
201
+ onConnect() {
202
+ retryCount = 0;
203
+ },
204
+ abortSignal: abortController.signal,
205
+ };
206
+
180
207
  try {
181
208
  await run(client, indexer, runOptions);
209
+ abortController.abort();
182
210
  return;
183
211
  } catch (error) {
184
212
  // Only reconnect on internal/server errors.
@@ -186,6 +214,8 @@ export async function runWithReconnect<TFilter, TBlock>(
186
214
 
187
215
  retryCount++;
188
216
 
217
+ abortController.abort();
218
+
189
219
  if (error instanceof ClientError || error instanceof ServerError) {
190
220
  const isServerError = error instanceof ServerError;
191
221
 
@@ -209,7 +239,6 @@ export async function runWithReconnect<TFilter, TBlock>(
209
239
  }
210
240
  }
211
241
  }
212
-
213
242
  throw error;
214
243
  }
215
244
  }
@@ -217,6 +246,7 @@ export async function runWithReconnect<TFilter, TBlock>(
217
246
 
218
247
  export interface RunOptions {
219
248
  onConnect?: () => void | Promise<void>;
249
+ abortSignal?: AbortSignal;
220
250
  }
221
251
 
222
252
  export async function run<TFilter, TBlock>(
@@ -231,14 +261,16 @@ export async function run<TFilter, TBlock>(
231
261
  context.debug = true;
232
262
  }
233
263
 
234
- await indexer.hooks.callHook("plugins:init");
264
+ const { abortSignal } = runOptions;
265
+
266
+ await indexer.hooks.callHook("plugins:init", { abortSignal });
235
267
 
236
- const middleware = await registerMiddleware(indexer);
268
+ const middleware = await registerMiddleware(indexer, abortSignal);
237
269
 
238
270
  const indexerMetrics = createIndexerMetrics();
239
271
  const tracer = createTracer();
240
272
 
241
- await indexer.hooks.callHook("run:before");
273
+ await indexer.hooks.callHook("run:before", { abortSignal });
242
274
 
243
275
  const { indexerName: indexerId } = useInternalContext();
244
276
 
@@ -269,7 +301,11 @@ export async function run<TFilter, TBlock>(
269
301
 
270
302
  const options: StreamDataOptions = {};
271
303
 
272
- await indexer.hooks.callHook("connect:before", { request, options });
304
+ await indexer.hooks.callHook("connect:before", {
305
+ request,
306
+ options,
307
+ abortSignal,
308
+ });
273
309
 
274
310
  // store main filter, so later it can be merged
275
311
  let mainFilter: TFilter;
@@ -282,7 +318,7 @@ export async function run<TFilter, TBlock>(
282
318
  StreamDataResponse<TBlock>
283
319
  > = client.streamData(request, options)[Symbol.asyncIterator]();
284
320
 
285
- await indexer.hooks.callHook("connect:after", { request });
321
+ await indexer.hooks.callHook("connect:after", { request, abortSignal });
286
322
 
287
323
  let onConnectCalled = false;
288
324
 
@@ -300,7 +336,7 @@ export async function run<TFilter, TBlock>(
300
336
  }
301
337
  }
302
338
 
303
- await indexer.hooks.callHook("message", { message });
339
+ await indexer.hooks.callHook("message", { message, abortSignal });
304
340
 
305
341
  switch (message._tag) {
306
342
  case "data": {
@@ -320,6 +356,8 @@ export async function run<TFilter, TBlock>(
320
356
  },
321
357
  );
322
358
 
359
+ reloadIfNeeded();
360
+
323
361
  await middleware(context, async () => {
324
362
  let block: TBlock | null;
325
363
 
@@ -339,6 +377,7 @@ export async function run<TFilter, TBlock>(
339
377
  finality,
340
378
  production,
341
379
  context,
380
+ abortSignal,
342
381
  });
343
382
 
344
383
  // write returned data from factory function if filter is not defined
@@ -360,6 +399,7 @@ export async function run<TFilter, TBlock>(
360
399
  await indexer.hooks.callHook("connect:factory", {
361
400
  request,
362
401
  endCursor,
402
+ abortSignal,
363
403
  });
364
404
 
365
405
  // create new stream with new request
@@ -391,6 +431,7 @@ export async function run<TFilter, TBlock>(
391
431
  finality,
392
432
  production,
393
433
  context,
434
+ abortSignal,
394
435
  });
395
436
 
396
437
  span.end();
@@ -398,6 +439,8 @@ export async function run<TFilter, TBlock>(
398
439
  }
399
440
  });
400
441
 
442
+ reloadIfNeeded();
443
+
401
444
  span.end();
402
445
  });
403
446
 
@@ -420,6 +463,7 @@ export async function run<TFilter, TBlock>(
420
463
  });
421
464
  await indexer.hooks.callHook("message:invalidate", {
422
465
  message: message.invalidate,
466
+ abortSignal,
423
467
  });
424
468
  span.end();
425
469
  });
@@ -429,6 +473,7 @@ export async function run<TFilter, TBlock>(
429
473
  await tracer.startActiveSpan("message finalize", async (span) => {
430
474
  await indexer.hooks.callHook("message:finalize", {
431
475
  message: message.finalize,
476
+ abortSignal,
432
477
  });
433
478
  span.end();
434
479
  });
@@ -436,7 +481,11 @@ export async function run<TFilter, TBlock>(
436
481
  }
437
482
  case "heartbeat": {
438
483
  await tracer.startActiveSpan("message heartbeat", async (span) => {
439
- await indexer.hooks.callHook("message:heartbeat");
484
+ reloadIfNeeded();
485
+
486
+ await indexer.hooks.callHook("message:heartbeat", { abortSignal });
487
+ reloadIfNeeded();
488
+
440
489
  span.end();
441
490
  });
442
491
  break;
@@ -460,6 +509,7 @@ export async function run<TFilter, TBlock>(
460
509
 
461
510
  await indexer.hooks.callHook("message:systemMessage", {
462
511
  message: message.systemMessage,
512
+ abortSignal,
463
513
  });
464
514
  span.end();
465
515
  },
@@ -471,21 +521,22 @@ export async function run<TFilter, TBlock>(
471
521
  throw new Error("not implemented");
472
522
  }
473
523
  }
474
-
475
- await indexer.hooks.callHook("run:after");
476
524
  }
525
+
526
+ await indexer.hooks.callHook("run:after", { abortSignal });
477
527
  });
478
528
  }
479
529
 
480
530
  async function registerMiddleware<TFilter, TBlock>(
481
531
  indexer: Indexer<TFilter, TBlock>,
532
+ abortSignal?: AbortSignal,
482
533
  ): Promise<MiddlewareFunction<IndexerContext>> {
483
534
  const middleware: MiddlewareFunction<IndexerContext>[] = [];
484
535
  const use = (fn: MiddlewareFunction<IndexerContext>) => {
485
536
  middleware.push(fn);
486
537
  };
487
538
 
488
- await indexer.hooks.callHook("handler:middleware", { use });
539
+ await indexer.hooks.callHook("handler:middleware", { use, abortSignal });
489
540
 
490
541
  const composed = compose(middleware);
491
542
 
@@ -10,15 +10,19 @@ import { type IndexerConfig, createIndexer, defineIndexer } from "../indexer";
10
10
  import { defineIndexerPlugin, logger } from "../plugins";
11
11
  import { type InternalContext, internalContext } from "./plugins";
12
12
 
13
+ export type InvalidateConfig = {
14
+ invalidateFromIndex: number;
15
+ invalidateTriggerIndex: number;
16
+ };
17
+
18
+ export type FinalizeConfig = {
19
+ finalizeToIndex: number;
20
+ finalizeTriggerIndex: number;
21
+ };
22
+
13
23
  export type MockMessagesOptions = {
14
- invalidate?: {
15
- invalidateFromIndex: number;
16
- invalidateTriggerIndex: number;
17
- };
18
- finalize?: {
19
- finalizeToIndex: number;
20
- finalizeTriggerIndex: number;
21
- };
24
+ invalidate?: InvalidateConfig | InvalidateConfig[];
25
+ finalize?: FinalizeConfig | FinalizeConfig[];
22
26
  uniqueKey?: boolean;
23
27
  baseBlockNumber?: bigint;
24
28
  };
@@ -27,18 +31,35 @@ export function generateMockMessages(
27
31
  count = 10,
28
32
  options?: MockMessagesOptions,
29
33
  ): MockStreamResponse[] {
30
- const invalidateAt = options?.invalidate;
31
- const finalizeAt = options?.finalize;
32
34
  const messages: MockStreamResponse[] = [];
33
-
34
35
  const baseBlockNumber = options?.baseBlockNumber ?? BigInt(5_000_000);
35
36
 
37
+ const invalidateConfigs = options?.invalidate
38
+ ? Array.isArray(options.invalidate)
39
+ ? options.invalidate
40
+ : [options.invalidate]
41
+ : [];
42
+
43
+ const finalizeConfigs = options?.finalize
44
+ ? Array.isArray(options.finalize)
45
+ ? options.finalize
46
+ : [options.finalize]
47
+ : [];
48
+
36
49
  for (let i = 0; i < count; i++) {
37
50
  const currentBlockNumber = baseBlockNumber + BigInt(i);
38
51
  const uniqueKey = uniqueKeyFromOrderKey(currentBlockNumber);
39
- if (invalidateAt && i === invalidateAt.invalidateTriggerIndex) {
52
+
53
+ const invalidateConfig = invalidateConfigs.find(
54
+ (cfg) => cfg.invalidateTriggerIndex === i,
55
+ );
56
+ const finalizeConfig = finalizeConfigs.find(
57
+ (cfg) => cfg.finalizeTriggerIndex === i,
58
+ );
59
+
60
+ if (invalidateConfig) {
40
61
  const invalidateToBlock =
41
- baseBlockNumber + BigInt(invalidateAt.invalidateFromIndex);
62
+ baseBlockNumber + BigInt(invalidateConfig.invalidateFromIndex);
42
63
  messages.push({
43
64
  _tag: "invalidate",
44
65
  invalidate: {
@@ -50,16 +71,16 @@ export function generateMockMessages(
50
71
  },
51
72
  } as Invalidate,
52
73
  });
53
- } else if (finalizeAt && i === finalizeAt.finalizeTriggerIndex) {
54
- const fianlizedToBlock =
55
- baseBlockNumber + BigInt(finalizeAt.finalizeToIndex);
74
+ } else if (finalizeConfig) {
75
+ const finalizedToBlock =
76
+ baseBlockNumber + BigInt(finalizeConfig.finalizeToIndex);
56
77
  messages.push({
57
78
  _tag: "finalize",
58
79
  finalize: {
59
80
  cursor: {
60
- orderKey: fianlizedToBlock,
81
+ orderKey: finalizedToBlock,
61
82
  uniqueKey: options?.uniqueKey
62
- ? uniqueKeyFromOrderKey(fianlizedToBlock)
83
+ ? uniqueKeyFromOrderKey(finalizedToBlock)
63
84
  : undefined,
64
85
  },
65
86
  } as Finalize,
@@ -0,0 +1,21 @@
1
+ import { useIndexerContext } from "../context";
2
+
3
+ export function reloadIndexer() {
4
+ const context = useIndexerContext();
5
+ context._reload = true;
6
+ }
7
+
8
+ export function reloadIfNeeded() {
9
+ const context = useIndexerContext();
10
+ if (context._reload) {
11
+ context._reload = false;
12
+ throw new ReloadIndexerRequest();
13
+ }
14
+ }
15
+
16
+ export class ReloadIndexerRequest extends Error {
17
+ constructor(message?: string) {
18
+ super(message);
19
+ this.name = "ReloadIndexerRequest";
20
+ }
21
+ }