@apibara/indexer 2.1.0-beta.5 → 2.1.0-beta.50

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.
Files changed (70) hide show
  1. package/dist/index.cjs +134 -41
  2. package/dist/index.cjs.map +1 -0
  3. package/dist/index.d.cts +8 -1
  4. package/dist/index.d.mts +8 -1
  5. package/dist/index.d.ts +8 -1
  6. package/dist/index.mjs +125 -34
  7. package/dist/index.mjs.map +1 -0
  8. package/dist/internal/index.cjs +1 -0
  9. package/dist/internal/index.cjs.map +1 -0
  10. package/dist/internal/index.mjs +1 -0
  11. package/dist/internal/index.mjs.map +1 -0
  12. package/dist/internal/plugins.cjs +5 -5
  13. package/dist/internal/plugins.cjs.map +1 -0
  14. package/dist/internal/plugins.d.cts +1 -1
  15. package/dist/internal/plugins.d.mts +1 -1
  16. package/dist/internal/plugins.d.ts +1 -1
  17. package/dist/internal/plugins.mjs +3 -3
  18. package/dist/internal/plugins.mjs.map +1 -0
  19. package/dist/internal/testing.cjs +35 -14
  20. package/dist/internal/testing.cjs.map +1 -0
  21. package/dist/internal/testing.d.cts +16 -12
  22. package/dist/internal/testing.d.mts +16 -12
  23. package/dist/internal/testing.d.ts +16 -12
  24. package/dist/internal/testing.mjs +33 -12
  25. package/dist/internal/testing.mjs.map +1 -0
  26. package/dist/plugins/index.cjs +4 -4
  27. package/dist/plugins/index.cjs.map +1 -0
  28. package/dist/plugins/index.d.cts +2 -2
  29. package/dist/plugins/index.d.mts +2 -2
  30. package/dist/plugins/index.d.ts +2 -2
  31. package/dist/plugins/index.mjs +4 -4
  32. package/dist/plugins/index.mjs.map +1 -0
  33. package/dist/shared/{indexer.2416906c.cjs → indexer.03c9f151.cjs} +8 -5
  34. package/dist/shared/indexer.03c9f151.cjs.map +1 -0
  35. package/dist/shared/{indexer.ff25c953.mjs → indexer.2673dcb1.mjs} +7 -4
  36. package/dist/shared/indexer.2673dcb1.mjs.map +1 -0
  37. package/dist/shared/{indexer.077335f3.cjs → indexer.479ae593.cjs} +6 -0
  38. package/dist/shared/indexer.479ae593.cjs.map +1 -0
  39. package/dist/shared/{indexer.fedcd831.d.cts → indexer.4ef52548.d.cts} +40 -23
  40. package/dist/shared/{indexer.fedcd831.d.mts → indexer.4ef52548.d.mts} +40 -23
  41. package/dist/shared/{indexer.fedcd831.d.ts → indexer.4ef52548.d.ts} +40 -23
  42. package/dist/shared/{indexer.a55ad619.mjs → indexer.75773ef1.mjs} +6 -1
  43. package/dist/shared/indexer.75773ef1.mjs.map +1 -0
  44. package/dist/testing/index.cjs +19 -10
  45. package/dist/testing/index.cjs.map +1 -0
  46. package/dist/testing/index.d.cts +11 -7
  47. package/dist/testing/index.d.mts +11 -7
  48. package/dist/testing/index.d.ts +11 -7
  49. package/dist/testing/index.mjs +20 -11
  50. package/dist/testing/index.mjs.map +1 -0
  51. package/dist/vcr/index.cjs +3 -1
  52. package/dist/vcr/index.cjs.map +1 -0
  53. package/dist/vcr/index.d.cts +1 -1
  54. package/dist/vcr/index.d.mts +1 -1
  55. package/dist/vcr/index.d.ts +1 -1
  56. package/dist/vcr/index.mjs +3 -1
  57. package/dist/vcr/index.mjs.map +1 -0
  58. package/package.json +3 -3
  59. package/src/index.ts +1 -0
  60. package/src/indexer.ts +151 -50
  61. package/src/internal/testing.ts +67 -23
  62. package/src/otel.ts +29 -2
  63. package/src/plugins/context.ts +1 -1
  64. package/src/plugins/logger.ts +11 -2
  65. package/src/testing/index.ts +30 -6
  66. package/src/utils/index.ts +21 -0
  67. package/dist/shared/indexer.601ceab0.cjs +0 -7
  68. package/dist/shared/indexer.9b21ddd2.mjs +0 -5
  69. package/src/compose.test.ts +0 -76
  70. package/src/indexer.test.ts +0 -430
package/dist/index.mjs CHANGED
@@ -1,9 +1,10 @@
1
- import { ClientError, Status } from '@apibara/protocol';
1
+ import { ClientError, ServerError, Status } from '@apibara/protocol';
2
2
  import consola from 'consola';
3
3
  import { createHooks, createDebugger } from 'hookable';
4
4
  import assert from 'node:assert';
5
- import { i as indexerAsyncContext, u as useIndexerContext } from './shared/indexer.a55ad619.mjs';
6
- import { trace } from '@opentelemetry/api';
5
+ import { u as useIndexerContext, i as indexerAsyncContext } from './shared/indexer.75773ef1.mjs';
6
+ import { trace, metrics } from '@opentelemetry/api';
7
+ import { useInternalContext } from './internal/plugins.mjs';
7
8
  import 'node:async_hooks';
8
9
  import 'unctx';
9
10
 
@@ -36,7 +37,47 @@ function compose(middleware) {
36
37
  };
37
38
  }
38
39
 
39
- const tracer = trace.getTracer("@apibara/indexer");
40
+ function createTracer() {
41
+ return trace.getTracer("@apibara/indexer");
42
+ }
43
+ function createIndexerMetrics() {
44
+ const meter = metrics.getMeter("@apibara/indexer");
45
+ const currentBlockGauge = meter.createGauge("current_block", {
46
+ description: "Current block number being processed",
47
+ unit: "{block}"
48
+ });
49
+ const processedBlockCounter = meter.createCounter("processed_blocks", {
50
+ description: "Number of blocks processed",
51
+ unit: "{blocks}"
52
+ });
53
+ const reorgCounter = meter.createCounter("reorgs", {
54
+ description: "Number of reorgs (invalidate messages) received",
55
+ unit: "{reorgs}"
56
+ });
57
+ return {
58
+ currentBlockGauge,
59
+ processedBlockCounter,
60
+ reorgCounter
61
+ };
62
+ }
63
+
64
+ function reloadIndexer() {
65
+ const context = useIndexerContext();
66
+ context._reload = true;
67
+ }
68
+ function reloadIfNeeded() {
69
+ const context = useIndexerContext();
70
+ if (context._reload) {
71
+ context._reload = false;
72
+ throw new ReloadIndexerRequest();
73
+ }
74
+ }
75
+ class ReloadIndexerRequest extends Error {
76
+ constructor(message) {
77
+ super(message);
78
+ this.name = "ReloadIndexerRequest";
79
+ }
80
+ }
40
81
 
41
82
  function defineIndexer(streamConfig) {
42
83
  return (config) => ({
@@ -67,24 +108,30 @@ async function runWithReconnect(client, indexer, options = {}) {
67
108
  const maxRetries = options.maxRetries ?? 10;
68
109
  const retryDelay = options.retryDelay ?? 1e3;
69
110
  const maxWait = options.maxWait ?? 3e4;
70
- const runOptions = {
71
- onConnect() {
72
- retryCount = 0;
73
- }
74
- };
75
111
  while (true) {
112
+ const abortController = new AbortController();
113
+ const runOptions = {
114
+ onConnect() {
115
+ retryCount = 0;
116
+ },
117
+ abortSignal: abortController.signal
118
+ };
76
119
  try {
77
120
  await run(client, indexer, runOptions);
121
+ abortController.abort();
78
122
  return;
79
123
  } catch (error) {
80
124
  retryCount++;
81
- if (error instanceof ClientError) {
125
+ abortController.abort();
126
+ if (error instanceof ClientError || error instanceof ServerError) {
127
+ const isServerError = error instanceof ServerError;
82
128
  if (error.code === Status.INTERNAL) {
83
129
  if (retryCount < maxRetries) {
84
130
  consola.error(
85
- "Internal server error, reconnecting...",
86
- error.message
131
+ `Internal ${isServerError ? "server" : "client"} error: ${error.message}`
87
132
  );
133
+ consola.start("Reconnecting...");
134
+ console.log();
88
135
  const delay = Math.random() * (retryDelay * 0.2) + retryDelay;
89
136
  await new Promise(
90
137
  (resolve) => setTimeout(resolve, Math.min(retryCount * delay, maxWait))
@@ -100,8 +147,16 @@ async function runWithReconnect(client, indexer, options = {}) {
100
147
  async function run(client, indexer, runOptions = {}) {
101
148
  await indexerAsyncContext.callAsync({}, async () => {
102
149
  const context = useIndexerContext();
103
- const middleware = await registerMiddleware(indexer);
104
- await indexer.hooks.callHook("run:before");
150
+ if (indexer.options.debug) {
151
+ context.debug = true;
152
+ }
153
+ const { abortSignal } = runOptions;
154
+ await indexer.hooks.callHook("plugins:init", { abortSignal });
155
+ const middleware = await registerMiddleware(indexer, abortSignal);
156
+ const indexerMetrics = createIndexerMetrics();
157
+ const tracer = createTracer();
158
+ await indexer.hooks.callHook("run:before", { abortSignal });
159
+ const { indexerName: indexerId } = useInternalContext();
105
160
  const isFactoryMode = indexer.options.factory !== void 0;
106
161
  let startingCursor;
107
162
  if (indexer.options.startingCursor) {
@@ -115,19 +170,23 @@ async function run(client, indexer, runOptions = {}) {
115
170
  };
116
171
  }
117
172
  }
118
- const request = indexer.streamConfig.Request.make({
173
+ const request = {
119
174
  filter: isFactoryMode ? [indexer.options.filter, {}] : [indexer.options.filter],
120
175
  finality: indexer.options.finality,
121
176
  startingCursor
122
- });
177
+ };
123
178
  const options = {};
124
- await indexer.hooks.callHook("connect:before", { request, options });
179
+ await indexer.hooks.callHook("connect:before", {
180
+ request,
181
+ options,
182
+ abortSignal
183
+ });
125
184
  let mainFilter;
126
185
  if (isFactoryMode) {
127
186
  mainFilter = request.filter[1];
128
187
  }
129
188
  let stream = client.streamData(request, options)[Symbol.asyncIterator]();
130
- await indexer.hooks.callHook("connect:after", { request });
189
+ await indexer.hooks.callHook("connect:after", { request, abortSignal });
131
190
  let onConnectCalled = false;
132
191
  while (true) {
133
192
  const { value: message, done } = await stream.next();
@@ -140,39 +199,52 @@ async function run(client, indexer, runOptions = {}) {
140
199
  await runOptions.onConnect();
141
200
  }
142
201
  }
143
- await indexer.hooks.callHook("message", { message });
202
+ await indexer.hooks.callHook("message", { message, abortSignal });
144
203
  switch (message._tag) {
145
204
  case "data": {
146
205
  await tracer.startActiveSpan("message data", async (span) => {
147
206
  const blocks = message.data.data;
148
- const { cursor, endCursor, finality } = message.data;
207
+ const { cursor, endCursor, finality, production } = message.data;
149
208
  context.cursor = cursor;
150
209
  context.endCursor = endCursor;
151
210
  context.finality = finality;
211
+ indexerMetrics.currentBlockGauge.record(
212
+ Number(endCursor?.orderKey),
213
+ {
214
+ indexer_id: indexerId
215
+ }
216
+ );
217
+ reloadIfNeeded();
152
218
  await middleware(context, async () => {
153
219
  let block;
154
- if (isFactoryMode) {
220
+ if (isFactoryMode && finality !== "pending") {
155
221
  assert(indexer.options.factory !== void 0);
156
222
  const [factoryBlock, mainBlock] = blocks;
157
223
  block = mainBlock;
158
224
  if (factoryBlock !== null) {
159
225
  const { filter } = await indexer.options.factory({
160
226
  block: factoryBlock,
161
- context
227
+ cursor,
228
+ endCursor,
229
+ finality,
230
+ production,
231
+ context,
232
+ abortSignal
162
233
  });
163
234
  if (filter) {
164
235
  mainFilter = indexer.streamConfig.mergeFilter(
165
236
  mainFilter,
166
237
  filter
167
238
  );
168
- const request2 = indexer.streamConfig.Request.make({
239
+ const request2 = {
169
240
  filter: [indexer.options.filter, mainFilter],
170
241
  finality: indexer.options.finality,
171
242
  startingCursor: cursor
172
- });
243
+ };
173
244
  await indexer.hooks.callHook("connect:factory", {
174
245
  request: request2,
175
- endCursor
246
+ endCursor,
247
+ abortSignal
176
248
  });
177
249
  stream = client.streamData(request2, options)[Symbol.asyncIterator]();
178
250
  const { value: message2 } = await stream.next();
@@ -191,14 +263,20 @@ async function run(client, indexer, runOptions = {}) {
191
263
  cursor,
192
264
  endCursor,
193
265
  finality,
194
- context
266
+ production,
267
+ context,
268
+ abortSignal
195
269
  });
196
270
  span2.end();
197
271
  });
198
272
  }
199
273
  });
274
+ reloadIfNeeded();
200
275
  span.end();
201
276
  });
277
+ indexerMetrics.processedBlockCounter.add(1, {
278
+ indexer_id: indexerId
279
+ });
202
280
  context.cursor = void 0;
203
281
  context.endCursor = void 0;
204
282
  context.finality = void 0;
@@ -206,21 +284,32 @@ async function run(client, indexer, runOptions = {}) {
206
284
  }
207
285
  case "invalidate": {
208
286
  await tracer.startActiveSpan("message invalidate", async (span) => {
209
- await indexer.hooks.callHook("message:invalidate", { message });
287
+ indexerMetrics.reorgCounter.add(1, {
288
+ indexer_id: indexerId
289
+ });
290
+ await indexer.hooks.callHook("message:invalidate", {
291
+ message: message.invalidate,
292
+ abortSignal
293
+ });
210
294
  span.end();
211
295
  });
212
296
  break;
213
297
  }
214
298
  case "finalize": {
215
299
  await tracer.startActiveSpan("message finalize", async (span) => {
216
- await indexer.hooks.callHook("message:finalize", { message });
300
+ await indexer.hooks.callHook("message:finalize", {
301
+ message: message.finalize,
302
+ abortSignal
303
+ });
217
304
  span.end();
218
305
  });
219
306
  break;
220
307
  }
221
308
  case "heartbeat": {
222
309
  await tracer.startActiveSpan("message heartbeat", async (span) => {
223
- await indexer.hooks.callHook("message:heartbeat", { message });
310
+ reloadIfNeeded();
311
+ await indexer.hooks.callHook("message:heartbeat", { abortSignal });
312
+ reloadIfNeeded();
224
313
  span.end();
225
314
  });
226
315
  break;
@@ -240,7 +329,8 @@ async function run(client, indexer, runOptions = {}) {
240
329
  }
241
330
  }
242
331
  await indexer.hooks.callHook("message:systemMessage", {
243
- message
332
+ message: message.systemMessage,
333
+ abortSignal
244
334
  });
245
335
  span.end();
246
336
  }
@@ -252,20 +342,21 @@ async function run(client, indexer, runOptions = {}) {
252
342
  throw new Error("not implemented");
253
343
  }
254
344
  }
255
- await indexer.hooks.callHook("run:after");
256
345
  }
346
+ await indexer.hooks.callHook("run:after", { abortSignal });
257
347
  });
258
348
  }
259
- async function registerMiddleware(indexer) {
349
+ async function registerMiddleware(indexer, abortSignal) {
260
350
  const middleware = [];
261
351
  const use = (fn) => {
262
352
  middleware.push(fn);
263
353
  };
264
- await indexer.hooks.callHook("handler:middleware", { use });
354
+ await indexer.hooks.callHook("handler:middleware", { use, abortSignal });
265
355
  const composed = compose(middleware);
266
356
  return async function _composedIndexerMiddleware(context, next) {
267
357
  await composed(context, next);
268
358
  };
269
359
  }
270
360
 
271
- export { createIndexer, defineIndexer, run, runWithReconnect, useIndexerContext };
361
+ export { ReloadIndexerRequest, createIndexer, defineIndexer, reloadIndexer, run, runWithReconnect, useIndexerContext };
362
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":["../src/compose.ts","../src/otel.ts","../src/utils/index.ts","../src/indexer.ts"],"sourcesContent":["/*\n * MIT License\n *\n * Copyright (c) 2021 - present, Yusuke Wada and Hono contributors\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n */\n\nimport type { IndexerContext } from \"./context\";\n\nexport type NextFunction = () => Promise<void>;\nexport type MiddlewareFunction<C> = (\n context: C,\n next: NextFunction,\n) => Promise<void>;\n\nexport function compose<C extends IndexerContext>(\n middleware: MiddlewareFunction<C>[],\n): (context: C, next?: NextFunction) => Promise<void> {\n return (context, next) => {\n let index = -1;\n\n return dispatch(0);\n\n /// Dispatch the middleware functions.\n async function dispatch(i: number): Promise<void> {\n if (i <= index) {\n throw new Error(\"next() called multiple times\");\n }\n index = i;\n\n let handler: MiddlewareFunction<C> | undefined;\n\n if (i >= middleware.length) {\n if (next) {\n await next();\n }\n\n return;\n }\n\n if (middleware[i]) {\n handler = middleware[i];\n } else {\n handler = i === middleware.length ? next : undefined;\n }\n\n if (!handler) {\n throw new Error(\"Handler not found\");\n }\n\n await handler(context, () => dispatch(i + 1));\n }\n };\n}\n","import { metrics, trace } from \"@opentelemetry/api\";\n\nexport function createTracer() {\n return trace.getTracer(\"@apibara/indexer\");\n}\n\nexport function createIndexerMetrics() {\n const meter = metrics.getMeter(\"@apibara/indexer\");\n\n const currentBlockGauge = meter.createGauge(\"current_block\", {\n description: \"Current block number being processed\",\n unit: \"{block}\",\n });\n\n const processedBlockCounter = meter.createCounter(\"processed_blocks\", {\n description: \"Number of blocks processed\",\n unit: \"{blocks}\",\n });\n\n const reorgCounter = meter.createCounter(\"reorgs\", {\n description: \"Number of reorgs (invalidate messages) received\",\n unit: \"{reorgs}\",\n });\n\n return {\n currentBlockGauge,\n processedBlockCounter,\n reorgCounter,\n };\n}\n","import { useIndexerContext } from \"../context\";\n\nexport function reloadIndexer() {\n const context = useIndexerContext();\n context._reload = true;\n}\n\nexport function reloadIfNeeded() {\n const context = useIndexerContext();\n if (context._reload) {\n context._reload = false;\n throw new ReloadIndexerRequest();\n }\n}\n\nexport class ReloadIndexerRequest extends Error {\n constructor(message?: string) {\n super(message);\n this.name = \"ReloadIndexerRequest\";\n }\n}\n","import {\n type Client,\n ClientError,\n type CreateClientOptions,\n type Cursor,\n type DataFinality,\n type DataProduction,\n type Finalize,\n type Invalidate,\n ServerError,\n Status,\n type StreamConfig,\n type StreamDataOptions,\n type StreamDataRequest,\n type StreamDataResponse,\n type SystemMessage,\n} from \"@apibara/protocol\";\nimport consola from \"consola\";\nimport {\n type Hookable,\n type NestedHooks,\n createDebugger,\n createHooks,\n} from \"hookable\";\n\nimport assert from \"node:assert\";\nimport { type MiddlewareFunction, type NextFunction, compose } from \"./compose\";\nimport {\n type IndexerContext,\n indexerAsyncContext,\n useIndexerContext,\n} from \"./context\";\nimport { createIndexerMetrics, createTracer } from \"./otel\";\nimport type { IndexerPlugin } from \"./plugins\";\nimport { useInternalContext } from \"./plugins/context\";\nimport { reloadIfNeeded } from \"./utils\";\n\nexport type UseMiddlewareFunction = (\n fn: MiddlewareFunction<IndexerContext>,\n) => void;\n\nexport interface IndexerHooks<TFilter, TBlock> {\n \"plugins:init\": ({ abortSignal }: { abortSignal?: AbortSignal }) => void;\n \"run:before\": ({ abortSignal }: { abortSignal?: AbortSignal }) => void;\n \"run:after\": ({ abortSignal }: { abortSignal?: AbortSignal }) => void;\n \"connect:before\": ({\n request,\n options,\n }: {\n request: StreamDataRequest<TFilter>;\n options: StreamDataOptions;\n abortSignal?: AbortSignal;\n }) => void;\n \"connect:after\": ({\n request,\n }: {\n request: StreamDataRequest<TFilter>;\n abortSignal?: AbortSignal;\n }) => void;\n \"connect:factory\": ({\n request,\n endCursor,\n abortSignal,\n }: {\n request: StreamDataRequest<TFilter>;\n endCursor?: Cursor;\n abortSignal?: AbortSignal;\n }) => void;\n \"handler:middleware\": ({\n use,\n abortSignal,\n }: { use: UseMiddlewareFunction; abortSignal?: AbortSignal }) => void;\n message: ({\n message,\n abortSignal,\n }: {\n message: StreamDataResponse<TBlock>;\n abortSignal?: AbortSignal;\n }) => void;\n \"message:invalidate\": ({\n message,\n abortSignal,\n }: { message: Invalidate; abortSignal?: AbortSignal }) => void;\n \"message:finalize\": ({\n message,\n abortSignal,\n }: { message: Finalize; abortSignal?: AbortSignal }) => void;\n \"message:heartbeat\": ({ abortSignal }: { abortSignal?: AbortSignal }) => void;\n \"message:systemMessage\": ({\n message,\n abortSignal,\n }: { message: SystemMessage; abortSignal?: AbortSignal }) => void;\n}\n\nexport type IndexerStartingCursor =\n | {\n startingCursor?: never;\n startingBlock: bigint;\n }\n | {\n startingCursor: Cursor;\n startingBlock?: never;\n }\n | {\n startingCursor?: never;\n startingBlock?: never;\n };\n\nexport type HandlerArgs<TBlock> = {\n block: TBlock;\n cursor?: Cursor | undefined;\n endCursor?: Cursor | undefined;\n finality: DataFinality;\n production: DataProduction;\n context: IndexerContext;\n abortSignal?: AbortSignal;\n};\n\nexport type IndexerConfig<TFilter, TBlock> = {\n streamUrl: string;\n filter: TFilter;\n finality?: DataFinality;\n clientOptions?: CreateClientOptions;\n factory?: (args: HandlerArgs<TBlock>) => Promise<{\n filter?: TFilter;\n }>;\n transform: (args: HandlerArgs<TBlock>) => Promise<void>;\n hooks?: NestedHooks<IndexerHooks<TFilter, TBlock>>;\n plugins?: ReadonlyArray<IndexerPlugin<TFilter, TBlock>>;\n debug?: boolean;\n} & IndexerStartingCursor;\n\nexport type IndexerWithStreamConfig<TFilter, TBlock> = IndexerConfig<\n TFilter,\n TBlock\n> & {\n streamConfig: StreamConfig<TFilter, TBlock>;\n};\n\nexport function defineIndexer<TFilter, TBlock>(\n streamConfig: StreamConfig<TFilter, TBlock>,\n) {\n return (\n config: IndexerConfig<TFilter, TBlock>,\n ): IndexerWithStreamConfig<TFilter, TBlock> => ({\n streamConfig,\n ...config,\n });\n}\n\nexport interface Indexer<TFilter, TBlock> {\n streamConfig: StreamConfig<TFilter, TBlock>;\n options: IndexerConfig<TFilter, TBlock>;\n hooks: Hookable<IndexerHooks<TFilter, TBlock>>;\n}\n\nexport function createIndexer<TFilter, TBlock>({\n streamConfig,\n ...options\n}: IndexerWithStreamConfig<TFilter, TBlock>) {\n const indexer: Indexer<TFilter, TBlock> = {\n options,\n streamConfig,\n hooks: createHooks<IndexerHooks<TFilter, TBlock>>(),\n };\n\n if (indexer.options.debug) {\n createDebugger(indexer.hooks, { tag: \"indexer\" });\n }\n\n indexer.hooks.addHooks(indexer.options.hooks ?? {});\n\n for (const plugin of indexer.options.plugins ?? []) {\n plugin(indexer);\n }\n\n return indexer;\n}\n\nexport interface ReconnectOptions {\n maxRetries?: number;\n retryDelay?: number;\n maxWait?: number;\n}\n\nexport async function runWithReconnect<TFilter, TBlock>(\n client: Client<TFilter, TBlock>,\n indexer: Indexer<TFilter, TBlock>,\n options: ReconnectOptions = {},\n) {\n let retryCount = 0;\n\n const maxRetries = options.maxRetries ?? 10;\n const retryDelay = options.retryDelay ?? 1_000;\n const maxWait = options.maxWait ?? 30_000;\n\n while (true) {\n const abortController = new AbortController();\n\n const runOptions: RunOptions = {\n onConnect() {\n retryCount = 0;\n },\n abortSignal: abortController.signal,\n };\n\n try {\n await run(client, indexer, runOptions);\n abortController.abort();\n return;\n } catch (error) {\n // Only reconnect on internal/server errors.\n // All other errors should be rethrown.\n\n retryCount++;\n\n abortController.abort();\n\n if (error instanceof ClientError || error instanceof ServerError) {\n const isServerError = error instanceof ServerError;\n\n if (error.code === Status.INTERNAL) {\n if (retryCount < maxRetries) {\n consola.error(\n `Internal ${isServerError ? \"server\" : \"client\"} error: ${\n error.message\n }`,\n );\n consola.start(\"Reconnecting...\");\n console.log();\n\n // Add jitter to the retry delay to avoid all clients retrying at the same time.\n const delay = Math.random() * (retryDelay * 0.2) + retryDelay;\n await new Promise((resolve) =>\n setTimeout(resolve, Math.min(retryCount * delay, maxWait)),\n );\n\n continue;\n }\n }\n }\n throw error;\n }\n }\n}\n\nexport interface RunOptions {\n onConnect?: () => void | Promise<void>;\n abortSignal?: AbortSignal;\n}\n\nexport async function run<TFilter, TBlock>(\n client: Client<TFilter, TBlock>,\n indexer: Indexer<TFilter, TBlock>,\n runOptions: RunOptions = {},\n) {\n await indexerAsyncContext.callAsync({}, async () => {\n const context = useIndexerContext();\n\n if (indexer.options.debug) {\n context.debug = true;\n }\n\n const { abortSignal } = runOptions;\n\n await indexer.hooks.callHook(\"plugins:init\", { abortSignal });\n\n const middleware = await registerMiddleware(indexer, abortSignal);\n\n const indexerMetrics = createIndexerMetrics();\n const tracer = createTracer();\n\n await indexer.hooks.callHook(\"run:before\", { abortSignal });\n\n const { indexerName: indexerId } = useInternalContext();\n\n const isFactoryMode = indexer.options.factory !== undefined;\n\n // Give priority to startingCursor over startingBlock.\n let startingCursor: Cursor | undefined;\n if (indexer.options.startingCursor) {\n startingCursor = indexer.options.startingCursor;\n } else if (indexer.options.startingBlock !== undefined) {\n if (indexer.options.startingBlock === 0n) {\n startingCursor = undefined;\n } else if (indexer.options.startingBlock > 0n) {\n startingCursor = {\n orderKey: indexer.options.startingBlock - 1n,\n };\n }\n }\n\n // if factory mode we add a empty filter at the end of the filter array.\n const request = {\n filter: isFactoryMode\n ? [indexer.options.filter, {} as TFilter]\n : [indexer.options.filter],\n finality: indexer.options.finality,\n startingCursor,\n } as StreamDataRequest<TFilter>;\n\n const options: StreamDataOptions = {};\n\n await indexer.hooks.callHook(\"connect:before\", {\n request,\n options,\n abortSignal,\n });\n\n // store main filter, so later it can be merged\n let mainFilter: TFilter;\n if (isFactoryMode) {\n mainFilter = request.filter[1];\n }\n\n let stream: AsyncIterator<\n StreamDataResponse<TBlock>,\n StreamDataResponse<TBlock>\n > = client.streamData(request, options)[Symbol.asyncIterator]();\n\n await indexer.hooks.callHook(\"connect:after\", { request, abortSignal });\n\n let onConnectCalled = false;\n\n while (true) {\n const { value: message, done } = await stream.next();\n\n if (done) {\n break;\n }\n\n if (!onConnectCalled) {\n onConnectCalled = true;\n if (runOptions.onConnect) {\n await runOptions.onConnect();\n }\n }\n\n await indexer.hooks.callHook(\"message\", { message, abortSignal });\n\n switch (message._tag) {\n case \"data\": {\n await tracer.startActiveSpan(\"message data\", async (span) => {\n const blocks = message.data.data;\n const { cursor, endCursor, finality, production } = message.data;\n\n context.cursor = cursor;\n context.endCursor = endCursor;\n context.finality = finality;\n\n // Record current block number being processed\n indexerMetrics.currentBlockGauge.record(\n Number(endCursor?.orderKey),\n {\n indexer_id: indexerId,\n },\n );\n\n reloadIfNeeded();\n\n await middleware(context, async () => {\n let block: TBlock | null;\n\n // when factory mode\n if (isFactoryMode && finality !== \"pending\") {\n assert(indexer.options.factory !== undefined);\n\n const [factoryBlock, mainBlock] = blocks;\n\n block = mainBlock;\n\n if (factoryBlock !== null) {\n const { filter } = await indexer.options.factory({\n block: factoryBlock,\n cursor,\n endCursor,\n finality,\n production,\n context,\n abortSignal,\n });\n\n // write returned data from factory function if filter is not defined\n if (filter) {\n // when filter is defined\n // merge old and new filters\n mainFilter = indexer.streamConfig.mergeFilter(\n mainFilter,\n filter,\n );\n\n // create request with new filters\n const request = {\n filter: [indexer.options.filter, mainFilter],\n finality: indexer.options.finality,\n startingCursor: cursor,\n } as StreamDataRequest<TFilter>;\n\n await indexer.hooks.callHook(\"connect:factory\", {\n request,\n endCursor,\n abortSignal,\n });\n\n // create new stream with new request\n stream = client\n .streamData(request, options)\n [Symbol.asyncIterator]();\n\n const { value: message } = await stream.next();\n\n assert(message._tag === \"data\");\n\n const [_factoryBlock, _block] = message.data.data;\n\n block = _block;\n }\n }\n } else {\n // when not in factory mode\n block = blocks[0];\n }\n\n // if block is not null\n if (block) {\n await tracer.startActiveSpan(\"handler\", async (span) => {\n await indexer.options.transform({\n block,\n cursor,\n endCursor,\n finality,\n production,\n context,\n abortSignal,\n });\n\n span.end();\n });\n }\n });\n\n reloadIfNeeded();\n\n span.end();\n });\n\n // Record processed block metric\n indexerMetrics.processedBlockCounter.add(1, {\n indexer_id: indexerId,\n });\n\n context.cursor = undefined;\n context.endCursor = undefined;\n context.finality = undefined;\n\n break;\n }\n case \"invalidate\": {\n await tracer.startActiveSpan(\"message invalidate\", async (span) => {\n // Record reorg metric\n indexerMetrics.reorgCounter.add(1, {\n indexer_id: indexerId,\n });\n await indexer.hooks.callHook(\"message:invalidate\", {\n message: message.invalidate,\n abortSignal,\n });\n span.end();\n });\n break;\n }\n case \"finalize\": {\n await tracer.startActiveSpan(\"message finalize\", async (span) => {\n await indexer.hooks.callHook(\"message:finalize\", {\n message: message.finalize,\n abortSignal,\n });\n span.end();\n });\n break;\n }\n case \"heartbeat\": {\n await tracer.startActiveSpan(\"message heartbeat\", async (span) => {\n reloadIfNeeded();\n\n await indexer.hooks.callHook(\"message:heartbeat\", { abortSignal });\n reloadIfNeeded();\n\n span.end();\n });\n break;\n }\n case \"systemMessage\": {\n await tracer.startActiveSpan(\n \"message systemMessage\",\n async (span) => {\n switch (message.systemMessage.output?._tag) {\n case \"stderr\": {\n consola.warn(message.systemMessage.output.stderr);\n break;\n }\n case \"stdout\": {\n consola.info(message.systemMessage.output.stdout);\n break;\n }\n default: {\n }\n }\n\n await indexer.hooks.callHook(\"message:systemMessage\", {\n message: message.systemMessage,\n abortSignal,\n });\n span.end();\n },\n );\n break;\n }\n default: {\n consola.warn(\"unexpected message\", message);\n throw new Error(\"not implemented\");\n }\n }\n }\n\n await indexer.hooks.callHook(\"run:after\", { abortSignal });\n });\n}\n\nasync function registerMiddleware<TFilter, TBlock>(\n indexer: Indexer<TFilter, TBlock>,\n abortSignal?: AbortSignal,\n): Promise<MiddlewareFunction<IndexerContext>> {\n const middleware: MiddlewareFunction<IndexerContext>[] = [];\n const use = (fn: MiddlewareFunction<IndexerContext>) => {\n middleware.push(fn);\n };\n\n await indexer.hooks.callHook(\"handler:middleware\", { use, abortSignal });\n\n const composed = compose(middleware);\n\n // Return a named function to help debugging\n return async function _composedIndexerMiddleware(\n context: IndexerContext,\n next?: NextFunction,\n ) {\n await composed(context, next);\n };\n}\n"],"names":["request","message","span"],"mappings":"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"}
@@ -8,3 +8,4 @@ function generateIndexerId(fileBasedName, identifier) {
8
8
  }
9
9
 
10
10
  exports.generateIndexerId = generateIndexerId;
11
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../../src/internal/index.ts"],"sourcesContent":["export function generateIndexerId(fileBasedName: string, identifier?: string) {\n return `indexer_${fileBasedName}_${identifier || \"default\"}`.replace(\n /[^a-zA-Z0-9_]/g,\n \"_\",\n );\n}\n"],"names":[],"mappings":";;AAAgB,SAAA,iBAAA,CAAkB,eAAuB,UAAqB,EAAA;AAC5E,EAAA,OAAO,CAAW,QAAA,EAAA,aAAa,CAAI,CAAA,EAAA,UAAA,IAAc,SAAS,CAAG,CAAA,CAAA,OAAA;AAAA,IAC3D,gBAAA;AAAA,IACA,GAAA;AAAA,GACF,CAAA;AACF;;;;"}
@@ -6,3 +6,4 @@ function generateIndexerId(fileBasedName, identifier) {
6
6
  }
7
7
 
8
8
  export { generateIndexerId };
9
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sources":["../../src/internal/index.ts"],"sourcesContent":["export function generateIndexerId(fileBasedName: string, identifier?: string) {\n return `indexer_${fileBasedName}_${identifier || \"default\"}`.replace(\n /[^a-zA-Z0-9_]/g,\n \"_\",\n );\n}\n"],"names":[],"mappings":"AAAgB,SAAA,iBAAA,CAAkB,eAAuB,UAAqB,EAAA;AAC5E,EAAA,OAAO,CAAW,QAAA,EAAA,aAAa,CAAI,CAAA,EAAA,UAAA,IAAc,SAAS,CAAG,CAAA,CAAA,OAAA;AAAA,IAC3D,gBAAA;AAAA,IACA,GAAA;AAAA,GACF,CAAA;AACF;;;;"}
@@ -1,16 +1,15 @@
1
1
  'use strict';
2
2
 
3
- const context = require('../shared/indexer.077335f3.cjs');
4
- const config = require('../shared/indexer.601ceab0.cjs');
3
+ const config = require('../shared/indexer.479ae593.cjs');
5
4
  require('node:async_hooks');
6
5
  require('unctx');
7
6
 
8
7
  const INTERNAL_CONTEXT_PROPERTY = "_internal";
9
8
  function internalContext(values) {
10
9
  return config.defineIndexerPlugin((indexer) => {
11
- indexer.hooks.hook("run:before", () => {
10
+ indexer.hooks.hook("plugins:init", () => {
12
11
  try {
13
- const ctx = context.useIndexerContext();
12
+ const ctx = config.useIndexerContext();
14
13
  ctx[INTERNAL_CONTEXT_PROPERTY] = {
15
14
  ...ctx[INTERNAL_CONTEXT_PROPERTY] || {},
16
15
  ...values
@@ -24,7 +23,7 @@ function internalContext(values) {
24
23
  });
25
24
  }
26
25
  function useInternalContext() {
27
- const ctx = context.useIndexerContext();
26
+ const ctx = config.useIndexerContext();
28
27
  if (ctx[INTERNAL_CONTEXT_PROPERTY] === void 0) {
29
28
  throw new Error(
30
29
  "Internal context is not available, possibly 'internalContext' plugin is missing!"
@@ -36,3 +35,4 @@ function useInternalContext() {
36
35
  exports.INTERNAL_CONTEXT_PROPERTY = INTERNAL_CONTEXT_PROPERTY;
37
36
  exports.internalContext = internalContext;
38
37
  exports.useInternalContext = useInternalContext;
38
+ //# sourceMappingURL=plugins.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugins.cjs","sources":["../../src/plugins/context.ts"],"sourcesContent":["import { useIndexerContext } from \"../context\";\nimport { defineIndexerPlugin } from \"./config\";\n\nexport const INTERNAL_CONTEXT_PROPERTY = \"_internal\";\n\nexport function internalContext<TFilter, TBlock, TTxnParams>(\n values: Record<string, unknown>,\n) {\n return defineIndexerPlugin<TFilter, TBlock>((indexer) => {\n indexer.hooks.hook(\"plugins:init\", () => {\n try {\n const ctx = useIndexerContext();\n ctx[INTERNAL_CONTEXT_PROPERTY] = {\n ...(ctx[INTERNAL_CONTEXT_PROPERTY] || {}),\n ...values,\n };\n } catch (error) {\n throw new Error(\"Failed to set internal context\", {\n cause: error,\n });\n }\n });\n });\n}\n\nexport type InternalContext = {\n indexerName: string;\n availableIndexers: string[];\n};\n\nexport function useInternalContext(): InternalContext {\n const ctx = useIndexerContext();\n\n if (ctx[INTERNAL_CONTEXT_PROPERTY] === undefined) {\n throw new Error(\n \"Internal context is not available, possibly 'internalContext' plugin is missing!\",\n );\n }\n return ctx[INTERNAL_CONTEXT_PROPERTY];\n}\n"],"names":["defineIndexerPlugin","useIndexerContext"],"mappings":";;;;;;AAGO,MAAM,yBAA4B,GAAA,YAAA;AAElC,SAAS,gBACd,MACA,EAAA;AACA,EAAO,OAAAA,0BAAA,CAAqC,CAAC,OAAY,KAAA;AACvD,IAAQ,OAAA,CAAA,KAAA,CAAM,IAAK,CAAA,cAAA,EAAgB,MAAM;AACvC,MAAI,IAAA;AACF,QAAA,MAAM,MAAMC,wBAAkB,EAAA,CAAA;AAC9B,QAAA,GAAA,CAAI,yBAAyB,CAAI,GAAA;AAAA,UAC/B,GAAI,GAAA,CAAI,yBAAyB,CAAA,IAAK,EAAC;AAAA,UACvC,GAAG,MAAA;AAAA,SACL,CAAA;AAAA,eACO,KAAO,EAAA;AACd,QAAM,MAAA,IAAI,MAAM,gCAAkC,EAAA;AAAA,UAChD,KAAO,EAAA,KAAA;AAAA,SACR,CAAA,CAAA;AAAA,OACH;AAAA,KACD,CAAA,CAAA;AAAA,GACF,CAAA,CAAA;AACH,CAAA;AAOO,SAAS,kBAAsC,GAAA;AACpD,EAAA,MAAM,MAAMA,wBAAkB,EAAA,CAAA;AAE9B,EAAI,IAAA,GAAA,CAAI,yBAAyB,CAAA,KAAM,KAAW,CAAA,EAAA;AAChD,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,kFAAA;AAAA,KACF,CAAA;AAAA,GACF;AACA,EAAA,OAAO,IAAI,yBAAyB,CAAA,CAAA;AACtC;;;;;;"}
@@ -1,4 +1,4 @@
1
- import { b as IndexerPlugin } from '../shared/indexer.fedcd831.cjs';
1
+ import { i as IndexerPlugin } from '../shared/indexer.4ef52548.cjs';
2
2
  import '@apibara/protocol';
3
3
  import 'hookable';
4
4
 
@@ -1,4 +1,4 @@
1
- import { b as IndexerPlugin } from '../shared/indexer.fedcd831.mjs';
1
+ import { i as IndexerPlugin } from '../shared/indexer.4ef52548.mjs';
2
2
  import '@apibara/protocol';
3
3
  import 'hookable';
4
4
 
@@ -1,4 +1,4 @@
1
- import { b as IndexerPlugin } from '../shared/indexer.fedcd831.js';
1
+ import { i as IndexerPlugin } from '../shared/indexer.4ef52548.js';
2
2
  import '@apibara/protocol';
3
3
  import 'hookable';
4
4
 
@@ -1,12 +1,11 @@
1
- import { u as useIndexerContext } from '../shared/indexer.a55ad619.mjs';
2
- import { d as defineIndexerPlugin } from '../shared/indexer.9b21ddd2.mjs';
1
+ import { d as defineIndexerPlugin, u as useIndexerContext } from '../shared/indexer.75773ef1.mjs';
3
2
  import 'node:async_hooks';
4
3
  import 'unctx';
5
4
 
6
5
  const INTERNAL_CONTEXT_PROPERTY = "_internal";
7
6
  function internalContext(values) {
8
7
  return defineIndexerPlugin((indexer) => {
9
- indexer.hooks.hook("run:before", () => {
8
+ indexer.hooks.hook("plugins:init", () => {
10
9
  try {
11
10
  const ctx = useIndexerContext();
12
11
  ctx[INTERNAL_CONTEXT_PROPERTY] = {
@@ -32,3 +31,4 @@ function useInternalContext() {
32
31
  }
33
32
 
34
33
  export { INTERNAL_CONTEXT_PROPERTY, internalContext, useInternalContext };
34
+ //# sourceMappingURL=plugins.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugins.mjs","sources":["../../src/plugins/context.ts"],"sourcesContent":["import { useIndexerContext } from \"../context\";\nimport { defineIndexerPlugin } from \"./config\";\n\nexport const INTERNAL_CONTEXT_PROPERTY = \"_internal\";\n\nexport function internalContext<TFilter, TBlock, TTxnParams>(\n values: Record<string, unknown>,\n) {\n return defineIndexerPlugin<TFilter, TBlock>((indexer) => {\n indexer.hooks.hook(\"plugins:init\", () => {\n try {\n const ctx = useIndexerContext();\n ctx[INTERNAL_CONTEXT_PROPERTY] = {\n ...(ctx[INTERNAL_CONTEXT_PROPERTY] || {}),\n ...values,\n };\n } catch (error) {\n throw new Error(\"Failed to set internal context\", {\n cause: error,\n });\n }\n });\n });\n}\n\nexport type InternalContext = {\n indexerName: string;\n availableIndexers: string[];\n};\n\nexport function useInternalContext(): InternalContext {\n const ctx = useIndexerContext();\n\n if (ctx[INTERNAL_CONTEXT_PROPERTY] === undefined) {\n throw new Error(\n \"Internal context is not available, possibly 'internalContext' plugin is missing!\",\n );\n }\n return ctx[INTERNAL_CONTEXT_PROPERTY];\n}\n"],"names":[],"mappings":";;;;AAGO,MAAM,yBAA4B,GAAA,YAAA;AAElC,SAAS,gBACd,MACA,EAAA;AACA,EAAO,OAAA,mBAAA,CAAqC,CAAC,OAAY,KAAA;AACvD,IAAQ,OAAA,CAAA,KAAA,CAAM,IAAK,CAAA,cAAA,EAAgB,MAAM;AACvC,MAAI,IAAA;AACF,QAAA,MAAM,MAAM,iBAAkB,EAAA,CAAA;AAC9B,QAAA,GAAA,CAAI,yBAAyB,CAAI,GAAA;AAAA,UAC/B,GAAI,GAAA,CAAI,yBAAyB,CAAA,IAAK,EAAC;AAAA,UACvC,GAAG,MAAA;AAAA,SACL,CAAA;AAAA,eACO,KAAO,EAAA;AACd,QAAM,MAAA,IAAI,MAAM,gCAAkC,EAAA;AAAA,UAChD,KAAO,EAAA,KAAA;AAAA,SACR,CAAA,CAAA;AAAA,OACH;AAAA,KACD,CAAA,CAAA;AAAA,GACF,CAAA,CAAA;AACH,CAAA;AAOO,SAAS,kBAAsC,GAAA;AACpD,EAAA,MAAM,MAAM,iBAAkB,EAAA,CAAA;AAE9B,EAAI,IAAA,GAAA,CAAI,yBAAyB,CAAA,KAAM,KAAW,CAAA,EAAA;AAChD,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,kFAAA;AAAA,KACF,CAAA;AAAA,GACF;AACA,EAAA,OAAO,IAAI,yBAAyB,CAAA,CAAA;AACtC;;;;"}
@@ -2,37 +2,50 @@
2
2
 
3
3
  const protocol = require('@apibara/protocol');
4
4
  const testing = require('@apibara/protocol/testing');
5
- const context = require('../shared/indexer.077335f3.cjs');
5
+ const config = require('../shared/indexer.479ae593.cjs');
6
6
  const index = require('../index.cjs');
7
- const config = require('../shared/indexer.601ceab0.cjs');
8
- require('consola');
7
+ const logger = require('../shared/indexer.03c9f151.cjs');
9
8
  const internal_plugins = require('./plugins.cjs');
10
9
  require('node:async_hooks');
11
10
  require('unctx');
11
+ require('consola');
12
12
  require('hookable');
13
13
  require('node:assert');
14
14
  require('@opentelemetry/api');
15
15
 
16
16
  function generateMockMessages(count = 10, options) {
17
- const invalidateAt = options?.invalidate;
18
- const finalizeAt = options?.finalize;
19
17
  const messages = [];
18
+ const baseBlockNumber = options?.baseBlockNumber ?? BigInt(5e6);
19
+ const invalidateConfigs = options?.invalidate ? Array.isArray(options.invalidate) ? options.invalidate : [options.invalidate] : [];
20
+ const finalizeConfigs = options?.finalize ? Array.isArray(options.finalize) ? options.finalize : [options.finalize] : [];
20
21
  for (let i = 0; i < count; i++) {
21
- if (invalidateAt && i === invalidateAt.invalidateTriggerIndex) {
22
+ const currentBlockNumber = baseBlockNumber + BigInt(i);
23
+ const uniqueKey = uniqueKeyFromOrderKey(currentBlockNumber);
24
+ const invalidateConfig = invalidateConfigs.find(
25
+ (cfg) => cfg.invalidateTriggerIndex === i
26
+ );
27
+ const finalizeConfig = finalizeConfigs.find(
28
+ (cfg) => cfg.finalizeTriggerIndex === i
29
+ );
30
+ if (invalidateConfig) {
31
+ const invalidateToBlock = baseBlockNumber + BigInt(invalidateConfig.invalidateFromIndex);
22
32
  messages.push({
23
33
  _tag: "invalidate",
24
34
  invalidate: {
25
35
  cursor: {
26
- orderKey: BigInt(5e6 + invalidateAt.invalidateFromIndex)
36
+ orderKey: invalidateToBlock,
37
+ uniqueKey: options?.uniqueKey ? uniqueKeyFromOrderKey(invalidateToBlock) : void 0
27
38
  }
28
39
  }
29
40
  });
30
- } else if (finalizeAt && i === finalizeAt.finalizeTriggerIndex) {
41
+ } else if (finalizeConfig) {
42
+ const finalizedToBlock = baseBlockNumber + BigInt(finalizeConfig.finalizeToIndex);
31
43
  messages.push({
32
44
  _tag: "finalize",
33
45
  finalize: {
34
46
  cursor: {
35
- orderKey: BigInt(5e6 + finalizeAt.finalizeToIndex)
47
+ orderKey: finalizedToBlock,
48
+ uniqueKey: options?.uniqueKey ? uniqueKeyFromOrderKey(finalizedToBlock) : void 0
36
49
  }
37
50
  }
38
51
  });
@@ -40,10 +53,13 @@ function generateMockMessages(count = 10, options) {
40
53
  messages.push({
41
54
  _tag: "data",
42
55
  data: {
43
- cursor: { orderKey: BigInt(5e6 + i - 1) },
56
+ cursor: { orderKey: currentBlockNumber - 1n },
44
57
  finality: "accepted",
45
- data: [{ data: `${5e6 + i}` }],
46
- endCursor: { orderKey: BigInt(5e6 + i) },
58
+ data: [{ data: `${baseBlockNumber + BigInt(i)}` }],
59
+ endCursor: {
60
+ orderKey: currentBlockNumber,
61
+ uniqueKey: options?.uniqueKey ? uniqueKey : void 0
62
+ },
47
63
  production: "backfill"
48
64
  }
49
65
  });
@@ -51,6 +67,9 @@ function generateMockMessages(count = 10, options) {
51
67
  }
52
68
  return messages;
53
69
  }
70
+ function uniqueKeyFromOrderKey(orderKey) {
71
+ return `0xff00${orderKey.toString()}`;
72
+ }
54
73
  function getMockIndexer(params) {
55
74
  const { internalContext: contextParams, override } = params ?? {};
56
75
  const { plugins, ...rest } = override ?? {};
@@ -62,6 +81,7 @@ function getMockIndexer(params) {
62
81
  async transform() {
63
82
  },
64
83
  plugins: [
84
+ logger.logger(),
65
85
  internal_plugins.internalContext(
66
86
  contextParams ?? {
67
87
  availableIndexers: ["testing"],
@@ -108,11 +128,12 @@ function mockSink({
108
128
  });
109
129
  }
110
130
  function useMockSink() {
111
- const context$1 = context.useIndexerContext();
112
- return { output: context$1.output };
131
+ const context = config.useIndexerContext();
132
+ return { output: context.output };
113
133
  }
114
134
 
115
135
  exports.generateMockMessages = generateMockMessages;
116
136
  exports.getMockIndexer = getMockIndexer;
117
137
  exports.mockSink = mockSink;
118
138
  exports.useMockSink = useMockSink;
139
+ //# sourceMappingURL=testing.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testing.cjs","sources":["../../src/internal/testing.ts"],"sourcesContent":["import { type Finalize, type Invalidate, isCursor } from \"@apibara/protocol\";\nimport {\n type MockBlock,\n type MockFilter,\n MockStream,\n type MockStreamResponse,\n} from \"@apibara/protocol/testing\";\nimport { useIndexerContext } from \"../context\";\nimport { type IndexerConfig, createIndexer, defineIndexer } from \"../indexer\";\nimport { defineIndexerPlugin, logger } from \"../plugins\";\nimport { type InternalContext, internalContext } from \"./plugins\";\n\nexport type InvalidateConfig = {\n invalidateFromIndex: number;\n invalidateTriggerIndex: number;\n};\n\nexport type FinalizeConfig = {\n finalizeToIndex: number;\n finalizeTriggerIndex: number;\n};\n\nexport type MockMessagesOptions = {\n invalidate?: InvalidateConfig | InvalidateConfig[];\n finalize?: FinalizeConfig | FinalizeConfig[];\n uniqueKey?: boolean;\n baseBlockNumber?: bigint;\n};\n\nexport function generateMockMessages(\n count = 10,\n options?: MockMessagesOptions,\n): MockStreamResponse[] {\n const messages: MockStreamResponse[] = [];\n const baseBlockNumber = options?.baseBlockNumber ?? BigInt(5_000_000);\n\n const invalidateConfigs = options?.invalidate\n ? Array.isArray(options.invalidate)\n ? options.invalidate\n : [options.invalidate]\n : [];\n\n const finalizeConfigs = options?.finalize\n ? Array.isArray(options.finalize)\n ? options.finalize\n : [options.finalize]\n : [];\n\n for (let i = 0; i < count; i++) {\n const currentBlockNumber = baseBlockNumber + BigInt(i);\n const uniqueKey = uniqueKeyFromOrderKey(currentBlockNumber);\n\n const invalidateConfig = invalidateConfigs.find(\n (cfg) => cfg.invalidateTriggerIndex === i,\n );\n const finalizeConfig = finalizeConfigs.find(\n (cfg) => cfg.finalizeTriggerIndex === i,\n );\n\n if (invalidateConfig) {\n const invalidateToBlock =\n baseBlockNumber + BigInt(invalidateConfig.invalidateFromIndex);\n messages.push({\n _tag: \"invalidate\",\n invalidate: {\n cursor: {\n orderKey: invalidateToBlock,\n uniqueKey: options?.uniqueKey\n ? uniqueKeyFromOrderKey(invalidateToBlock)\n : undefined,\n },\n } as Invalidate,\n });\n } else if (finalizeConfig) {\n const finalizedToBlock =\n baseBlockNumber + BigInt(finalizeConfig.finalizeToIndex);\n messages.push({\n _tag: \"finalize\",\n finalize: {\n cursor: {\n orderKey: finalizedToBlock,\n uniqueKey: options?.uniqueKey\n ? uniqueKeyFromOrderKey(finalizedToBlock)\n : undefined,\n },\n } as Finalize,\n });\n } else {\n messages.push({\n _tag: \"data\",\n data: {\n cursor: { orderKey: currentBlockNumber - 1n },\n finality: \"accepted\",\n data: [{ data: `${baseBlockNumber + BigInt(i)}` }],\n endCursor: {\n orderKey: currentBlockNumber,\n uniqueKey: options?.uniqueKey ? uniqueKey : undefined,\n },\n production: \"backfill\",\n },\n });\n }\n }\n\n return messages;\n}\n\nfunction uniqueKeyFromOrderKey(orderKey: bigint): `0x${string}` {\n return `0xff00${orderKey.toString()}`;\n}\n\ntype MockIndexerParams = {\n internalContext?: InternalContext;\n override?: Partial<IndexerConfig<MockFilter, MockBlock>>;\n};\n\nexport function getMockIndexer(params?: MockIndexerParams) {\n const { internalContext: contextParams, override } = params ?? {};\n const { plugins, ...rest } = override ?? {};\n\n return createIndexer(\n defineIndexer(MockStream)({\n streamUrl: \"https://sepolia.ethereum.a5a.ch\",\n finality: \"accepted\",\n filter: {},\n async transform() {},\n plugins: [\n logger(),\n internalContext(\n contextParams ??\n ({\n availableIndexers: [\"testing\"],\n indexerName: \"testing\",\n } as InternalContext),\n ),\n ...(plugins ?? []),\n ],\n ...(rest ?? {}),\n }),\n );\n}\n\nexport type MockRet = {\n data: string;\n};\n\n/**\n * A mock sink used for testing. The indexer function can write to the output array.\n * The indexer context is optionally written to the metadata object.\n */\nexport function mockSink<TFilter, TBlock>({\n output,\n metadata,\n}: { output: unknown[]; metadata?: Record<string, unknown> }) {\n return defineIndexerPlugin<TFilter, TBlock>((indexer) => {\n indexer.hooks.hook(\"connect:before\", ({ request }) => {\n if (metadata?.lastCursor && isCursor(metadata.lastCursor)) {\n request.startingCursor = metadata.lastCursor;\n }\n\n if (metadata?.lastFilter) {\n request.filter[1] = metadata.lastFilter as TFilter;\n }\n });\n\n indexer.hooks.hook(\"connect:factory\", ({ request, endCursor }) => {\n if (request.filter[1]) {\n if (metadata) {\n metadata.lastCursor = endCursor;\n metadata.lastFilter = request.filter[1];\n }\n }\n });\n\n indexer.hooks.hook(\"handler:middleware\", ({ use }) => {\n use(async (context, next) => {\n context.output = output;\n await next();\n context.output = null;\n\n if (metadata) {\n metadata.lastCursor = context.endCursor;\n }\n });\n });\n });\n}\n\nexport function useMockSink(): { output: unknown[] } {\n const context = useIndexerContext();\n return { output: context.output };\n}\n"],"names":["createIndexer","defineIndexer","MockStream","logger","internalContext","defineIndexerPlugin","isCursor","useIndexerContext"],"mappings":";;;;;;;;;;;;;;;AA6BgB,SAAA,oBAAA,CACd,KAAQ,GAAA,EAAA,EACR,OACsB,EAAA;AACtB,EAAA,MAAM,WAAiC,EAAC,CAAA;AACxC,EAAA,MAAM,eAAkB,GAAA,OAAA,EAAS,eAAmB,IAAA,MAAA,CAAO,GAAS,CAAA,CAAA;AAEpE,EAAA,MAAM,iBAAoB,GAAA,OAAA,EAAS,UAC/B,GAAA,KAAA,CAAM,QAAQ,OAAQ,CAAA,UAAU,CAC9B,GAAA,OAAA,CAAQ,UACR,GAAA,CAAC,OAAQ,CAAA,UAAU,IACrB,EAAC,CAAA;AAEL,EAAA,MAAM,eAAkB,GAAA,OAAA,EAAS,QAC7B,GAAA,KAAA,CAAM,QAAQ,OAAQ,CAAA,QAAQ,CAC5B,GAAA,OAAA,CAAQ,QACR,GAAA,CAAC,OAAQ,CAAA,QAAQ,IACnB,EAAC,CAAA;AAEL,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,KAAA,EAAO,CAAK,EAAA,EAAA;AAC9B,IAAM,MAAA,kBAAA,GAAqB,eAAkB,GAAA,MAAA,CAAO,CAAC,CAAA,CAAA;AACrD,IAAM,MAAA,SAAA,GAAY,sBAAsB,kBAAkB,CAAA,CAAA;AAE1D,IAAA,MAAM,mBAAmB,iBAAkB,CAAA,IAAA;AAAA,MACzC,CAAC,GAAQ,KAAA,GAAA,CAAI,sBAA2B,KAAA,CAAA;AAAA,KAC1C,CAAA;AACA,IAAA,MAAM,iBAAiB,eAAgB,CAAA,IAAA;AAAA,MACrC,CAAC,GAAQ,KAAA,GAAA,CAAI,oBAAyB,KAAA,CAAA;AAAA,KACxC,CAAA;AAEA,IAAA,IAAI,gBAAkB,EAAA;AACpB,MAAA,MAAM,iBACJ,GAAA,eAAA,GAAkB,MAAO,CAAA,gBAAA,CAAiB,mBAAmB,CAAA,CAAA;AAC/D,MAAA,QAAA,CAAS,IAAK,CAAA;AAAA,QACZ,IAAM,EAAA,YAAA;AAAA,QACN,UAAY,EAAA;AAAA,UACV,MAAQ,EAAA;AAAA,YACN,QAAU,EAAA,iBAAA;AAAA,YACV,SAAW,EAAA,OAAA,EAAS,SAChB,GAAA,qBAAA,CAAsB,iBAAiB,CACvC,GAAA,KAAA,CAAA;AAAA,WACN;AAAA,SACF;AAAA,OACD,CAAA,CAAA;AAAA,eACQ,cAAgB,EAAA;AACzB,MAAA,MAAM,gBACJ,GAAA,eAAA,GAAkB,MAAO,CAAA,cAAA,CAAe,eAAe,CAAA,CAAA;AACzD,MAAA,QAAA,CAAS,IAAK,CAAA;AAAA,QACZ,IAAM,EAAA,UAAA;AAAA,QACN,QAAU,EAAA;AAAA,UACR,MAAQ,EAAA;AAAA,YACN,QAAU,EAAA,gBAAA;AAAA,YACV,SAAW,EAAA,OAAA,EAAS,SAChB,GAAA,qBAAA,CAAsB,gBAAgB,CACtC,GAAA,KAAA,CAAA;AAAA,WACN;AAAA,SACF;AAAA,OACD,CAAA,CAAA;AAAA,KACI,MAAA;AACL,MAAA,QAAA,CAAS,IAAK,CAAA;AAAA,QACZ,IAAM,EAAA,MAAA;AAAA,QACN,IAAM,EAAA;AAAA,UACJ,MAAQ,EAAA,EAAE,QAAU,EAAA,kBAAA,GAAqB,EAAG,EAAA;AAAA,UAC5C,QAAU,EAAA,UAAA;AAAA,UACV,IAAA,EAAM,CAAC,EAAE,IAAM,EAAA,CAAA,EAAG,kBAAkB,MAAO,CAAA,CAAC,CAAC,CAAA,CAAA,EAAI,CAAA;AAAA,UACjD,SAAW,EAAA;AAAA,YACT,QAAU,EAAA,kBAAA;AAAA,YACV,SAAA,EAAW,OAAS,EAAA,SAAA,GAAY,SAAY,GAAA,KAAA,CAAA;AAAA,WAC9C;AAAA,UACA,UAAY,EAAA,UAAA;AAAA,SACd;AAAA,OACD,CAAA,CAAA;AAAA,KACH;AAAA,GACF;AAEA,EAAO,OAAA,QAAA,CAAA;AACT,CAAA;AAEA,SAAS,sBAAsB,QAAiC,EAAA;AAC9D,EAAO,OAAA,CAAA,MAAA,EAAS,QAAS,CAAA,QAAA,EAAU,CAAA,CAAA,CAAA;AACrC,CAAA;AAOO,SAAS,eAAe,MAA4B,EAAA;AACzD,EAAA,MAAM,EAAE,eAAiB,EAAA,aAAA,EAAe,QAAS,EAAA,GAAI,UAAU,EAAC,CAAA;AAChE,EAAA,MAAM,EAAE,OAAS,EAAA,GAAG,IAAK,EAAA,GAAI,YAAY,EAAC,CAAA;AAE1C,EAAO,OAAAA,mBAAA;AAAA,IACLC,mBAAA,CAAcC,kBAAU,CAAE,CAAA;AAAA,MACxB,SAAW,EAAA,iCAAA;AAAA,MACX,QAAU,EAAA,UAAA;AAAA,MACV,QAAQ,EAAC;AAAA,MACT,MAAM,SAAY,GAAA;AAAA,OAAC;AAAA,MACnB,OAAS,EAAA;AAAA,QACPC,aAAO,EAAA;AAAA,QACPC,gCAAA;AAAA,UACE,aACG,IAAA;AAAA,YACC,iBAAA,EAAmB,CAAC,SAAS,CAAA;AAAA,YAC7B,WAAa,EAAA,SAAA;AAAA,WACf;AAAA,SACJ;AAAA,QACA,GAAI,WAAW,EAAC;AAAA,OAClB;AAAA,MACA,GAAI,QAAQ,EAAC;AAAA,KACd,CAAA;AAAA,GACH,CAAA;AACF,CAAA;AAUO,SAAS,QAA0B,CAAA;AAAA,EACxC,MAAA;AAAA,EACA,QAAA;AACF,CAA8D,EAAA;AAC5D,EAAO,OAAAC,0BAAA,CAAqC,CAAC,OAAY,KAAA;AACvD,IAAA,OAAA,CAAQ,MAAM,IAAK,CAAA,gBAAA,EAAkB,CAAC,EAAE,SAAc,KAAA;AACpD,MAAA,IAAI,QAAU,EAAA,UAAA,IAAcC,iBAAS,CAAA,QAAA,CAAS,UAAU,CAAG,EAAA;AACzD,QAAA,OAAA,CAAQ,iBAAiB,QAAS,CAAA,UAAA,CAAA;AAAA,OACpC;AAEA,MAAA,IAAI,UAAU,UAAY,EAAA;AACxB,QAAQ,OAAA,CAAA,MAAA,CAAO,CAAC,CAAA,GAAI,QAAS,CAAA,UAAA,CAAA;AAAA,OAC/B;AAAA,KACD,CAAA,CAAA;AAED,IAAA,OAAA,CAAQ,MAAM,IAAK,CAAA,iBAAA,EAAmB,CAAC,EAAE,OAAA,EAAS,WAAgB,KAAA;AAChE,MAAI,IAAA,OAAA,CAAQ,MAAO,CAAA,CAAC,CAAG,EAAA;AACrB,QAAA,IAAI,QAAU,EAAA;AACZ,UAAA,QAAA,CAAS,UAAa,GAAA,SAAA,CAAA;AACtB,UAAS,QAAA,CAAA,UAAA,GAAa,OAAQ,CAAA,MAAA,CAAO,CAAC,CAAA,CAAA;AAAA,SACxC;AAAA,OACF;AAAA,KACD,CAAA,CAAA;AAED,IAAA,OAAA,CAAQ,MAAM,IAAK,CAAA,oBAAA,EAAsB,CAAC,EAAE,KAAU,KAAA;AACpD,MAAI,GAAA,CAAA,OAAO,SAAS,IAAS,KAAA;AAC3B,QAAA,OAAA,CAAQ,MAAS,GAAA,MAAA,CAAA;AACjB,QAAA,MAAM,IAAK,EAAA,CAAA;AACX,QAAA,OAAA,CAAQ,MAAS,GAAA,IAAA,CAAA;AAEjB,QAAA,IAAI,QAAU,EAAA;AACZ,UAAA,QAAA,CAAS,aAAa,OAAQ,CAAA,SAAA,CAAA;AAAA,SAChC;AAAA,OACD,CAAA,CAAA;AAAA,KACF,CAAA,CAAA;AAAA,GACF,CAAA,CAAA;AACH,CAAA;AAEO,SAAS,WAAqC,GAAA;AACnD,EAAA,MAAM,UAAUC,wBAAkB,EAAA,CAAA;AAClC,EAAO,OAAA,EAAE,MAAQ,EAAA,OAAA,CAAQ,MAAO,EAAA,CAAA;AAClC;;;;;;;"}