@apibara/indexer 2.1.0-beta.3 → 2.1.0-beta.30

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 (46) hide show
  1. package/dist/index.cjs +70 -26
  2. package/dist/index.d.cts +1 -1
  3. package/dist/index.d.mts +1 -1
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.mjs +60 -16
  6. package/dist/internal/plugins.cjs +3 -4
  7. package/dist/internal/plugins.d.cts +1 -1
  8. package/dist/internal/plugins.d.mts +1 -1
  9. package/dist/internal/plugins.d.ts +1 -1
  10. package/dist/internal/plugins.mjs +1 -2
  11. package/dist/internal/testing.cjs +24 -10
  12. package/dist/internal/testing.d.cts +5 -3
  13. package/dist/internal/testing.d.mts +5 -3
  14. package/dist/internal/testing.d.ts +5 -3
  15. package/dist/internal/testing.mjs +22 -8
  16. package/dist/plugins/index.cjs +3 -4
  17. package/dist/plugins/index.d.cts +2 -2
  18. package/dist/plugins/index.d.mts +2 -2
  19. package/dist/plugins/index.d.ts +2 -2
  20. package/dist/plugins/index.mjs +3 -4
  21. package/dist/shared/{indexer.077335f3.cjs → indexer.479ae593.cjs} +5 -0
  22. package/dist/shared/{indexer.a55ad619.mjs → indexer.75773ef1.mjs} +5 -1
  23. package/dist/shared/{indexer.fedcd831.d.cts → indexer.7668fe34.d.cts} +2 -4
  24. package/dist/shared/{indexer.fedcd831.d.mts → indexer.7668fe34.d.mts} +2 -4
  25. package/dist/shared/{indexer.fedcd831.d.ts → indexer.7668fe34.d.ts} +2 -4
  26. package/dist/shared/{indexer.ff25c953.mjs → indexer.98a921a7.mjs} +1 -2
  27. package/dist/shared/{indexer.2416906c.cjs → indexer.a09fa402.cjs} +3 -4
  28. package/dist/testing/index.cjs +9 -5
  29. package/dist/testing/index.d.cts +4 -3
  30. package/dist/testing/index.d.mts +4 -3
  31. package/dist/testing/index.d.ts +4 -3
  32. package/dist/testing/index.mjs +9 -5
  33. package/dist/vcr/index.cjs +2 -1
  34. package/dist/vcr/index.d.cts +1 -1
  35. package/dist/vcr/index.d.mts +1 -1
  36. package/dist/vcr/index.d.ts +1 -1
  37. package/dist/vcr/index.mjs +2 -1
  38. package/package.json +3 -3
  39. package/src/indexer.ts +47 -15
  40. package/src/internal/testing.ts +34 -11
  41. package/src/otel.ts +29 -2
  42. package/src/testing/index.ts +11 -0
  43. package/dist/shared/indexer.601ceab0.cjs +0 -7
  44. package/dist/shared/indexer.9b21ddd2.mjs +0 -5
  45. package/src/compose.test.ts +0 -76
  46. package/src/indexer.test.ts +0 -430
@@ -1,12 +1,12 @@
1
1
  import { isCursor } from '@apibara/protocol';
2
2
  import { MockStream } from '@apibara/protocol/testing';
3
- import { u as useIndexerContext } from '../shared/indexer.a55ad619.mjs';
3
+ import { d as defineIndexerPlugin, u as useIndexerContext } from '../shared/indexer.75773ef1.mjs';
4
4
  import { createIndexer, defineIndexer } from '../index.mjs';
5
- import { d as defineIndexerPlugin } from '../shared/indexer.9b21ddd2.mjs';
6
- import 'consola';
5
+ import { l as logger } from '../shared/indexer.98a921a7.mjs';
7
6
  import { internalContext } from './plugins.mjs';
8
7
  import 'node:async_hooks';
9
8
  import 'unctx';
9
+ import 'consola';
10
10
  import 'hookable';
11
11
  import 'node:assert';
12
12
  import '@opentelemetry/api';
@@ -15,22 +15,29 @@ function generateMockMessages(count = 10, options) {
15
15
  const invalidateAt = options?.invalidate;
16
16
  const finalizeAt = options?.finalize;
17
17
  const messages = [];
18
+ const baseBlockNumber = options?.baseBlockNumber ?? BigInt(5e6);
18
19
  for (let i = 0; i < count; i++) {
20
+ const currentBlockNumber = baseBlockNumber + BigInt(i);
21
+ const uniqueKey = uniqueKeyFromOrderKey(currentBlockNumber);
19
22
  if (invalidateAt && i === invalidateAt.invalidateTriggerIndex) {
23
+ const invalidateToBlock = baseBlockNumber + BigInt(invalidateAt.invalidateFromIndex);
20
24
  messages.push({
21
25
  _tag: "invalidate",
22
26
  invalidate: {
23
27
  cursor: {
24
- orderKey: BigInt(5e6 + invalidateAt.invalidateFromIndex)
28
+ orderKey: invalidateToBlock,
29
+ uniqueKey: options?.uniqueKey ? uniqueKeyFromOrderKey(invalidateToBlock) : void 0
25
30
  }
26
31
  }
27
32
  });
28
33
  } else if (finalizeAt && i === finalizeAt.finalizeTriggerIndex) {
34
+ const fianlizedToBlock = baseBlockNumber + BigInt(finalizeAt.finalizeToIndex);
29
35
  messages.push({
30
36
  _tag: "finalize",
31
37
  finalize: {
32
38
  cursor: {
33
- orderKey: BigInt(5e6 + finalizeAt.finalizeToIndex)
39
+ orderKey: fianlizedToBlock,
40
+ uniqueKey: options?.uniqueKey ? uniqueKeyFromOrderKey(fianlizedToBlock) : void 0
34
41
  }
35
42
  }
36
43
  });
@@ -38,10 +45,13 @@ function generateMockMessages(count = 10, options) {
38
45
  messages.push({
39
46
  _tag: "data",
40
47
  data: {
41
- cursor: { orderKey: BigInt(5e6 + i - 1) },
48
+ cursor: { orderKey: currentBlockNumber - 1n },
42
49
  finality: "accepted",
43
- data: [{ data: `${5e6 + i}` }],
44
- endCursor: { orderKey: BigInt(5e6 + i) },
50
+ data: [{ data: `${baseBlockNumber + BigInt(i)}` }],
51
+ endCursor: {
52
+ orderKey: currentBlockNumber,
53
+ uniqueKey: options?.uniqueKey ? uniqueKey : void 0
54
+ },
45
55
  production: "backfill"
46
56
  }
47
57
  });
@@ -49,6 +59,9 @@ function generateMockMessages(count = 10, options) {
49
59
  }
50
60
  return messages;
51
61
  }
62
+ function uniqueKeyFromOrderKey(orderKey) {
63
+ return `0xff00${orderKey.toString()}`;
64
+ }
52
65
  function getMockIndexer(params) {
53
66
  const { internalContext: contextParams, override } = params ?? {};
54
67
  const { plugins, ...rest } = override ?? {};
@@ -60,6 +73,7 @@ function getMockIndexer(params) {
60
73
  async transform() {
61
74
  },
62
75
  plugins: [
76
+ logger(),
63
77
  internalContext(
64
78
  contextParams ?? {
65
79
  availableIndexers: ["testing"],
@@ -1,12 +1,11 @@
1
1
  'use strict';
2
2
 
3
- const config = require('../shared/indexer.601ceab0.cjs');
4
- const logger = require('../shared/indexer.2416906c.cjs');
3
+ const config = require('../shared/indexer.479ae593.cjs');
4
+ const logger = require('../shared/indexer.a09fa402.cjs');
5
5
  const protocol = require('@apibara/protocol');
6
- require('consola');
7
- require('../shared/indexer.077335f3.cjs');
8
6
  require('node:async_hooks');
9
7
  require('unctx');
8
+ require('consola');
10
9
 
11
10
  function inMemoryPersistence() {
12
11
  return config.defineIndexerPlugin((indexer) => {
@@ -1,5 +1,5 @@
1
- import { b as IndexerPlugin } from '../shared/indexer.fedcd831.cjs';
2
- export { d as defineIndexerPlugin } from '../shared/indexer.fedcd831.cjs';
1
+ import { b as IndexerPlugin } from '../shared/indexer.7668fe34.cjs';
2
+ export { d as defineIndexerPlugin } from '../shared/indexer.7668fe34.cjs';
3
3
  import { ConsolaReporter, ConsolaInstance } from 'consola';
4
4
  export { ConsolaInstance, ConsolaReporter } from 'consola';
5
5
  import '@apibara/protocol';
@@ -1,5 +1,5 @@
1
- import { b as IndexerPlugin } from '../shared/indexer.fedcd831.mjs';
2
- export { d as defineIndexerPlugin } from '../shared/indexer.fedcd831.mjs';
1
+ import { b as IndexerPlugin } from '../shared/indexer.7668fe34.mjs';
2
+ export { d as defineIndexerPlugin } from '../shared/indexer.7668fe34.mjs';
3
3
  import { ConsolaReporter, ConsolaInstance } from 'consola';
4
4
  export { ConsolaInstance, ConsolaReporter } from 'consola';
5
5
  import '@apibara/protocol';
@@ -1,5 +1,5 @@
1
- import { b as IndexerPlugin } from '../shared/indexer.fedcd831.js';
2
- export { d as defineIndexerPlugin } from '../shared/indexer.fedcd831.js';
1
+ import { b as IndexerPlugin } from '../shared/indexer.7668fe34.js';
2
+ export { d as defineIndexerPlugin } from '../shared/indexer.7668fe34.js';
3
3
  import { ConsolaReporter, ConsolaInstance } from 'consola';
4
4
  export { ConsolaInstance, ConsolaReporter } from 'consola';
5
5
  import '@apibara/protocol';
@@ -1,10 +1,9 @@
1
- import { d as defineIndexerPlugin } from '../shared/indexer.9b21ddd2.mjs';
2
- export { l as logger, u as useLogger } from '../shared/indexer.ff25c953.mjs';
1
+ import { d as defineIndexerPlugin } from '../shared/indexer.75773ef1.mjs';
2
+ export { l as logger, u as useLogger } from '../shared/indexer.98a921a7.mjs';
3
3
  import { isCursor } from '@apibara/protocol';
4
- import 'consola';
5
- import '../shared/indexer.a55ad619.mjs';
6
4
  import 'node:async_hooks';
7
5
  import 'unctx';
6
+ import 'consola';
8
7
 
9
8
  function inMemoryPersistence() {
10
9
  return defineIndexerPlugin((indexer) => {
@@ -11,5 +11,10 @@ function useIndexerContext() {
11
11
  return indexerAsyncContext.use();
12
12
  }
13
13
 
14
+ function defineIndexerPlugin(def) {
15
+ return def;
16
+ }
17
+
18
+ exports.defineIndexerPlugin = defineIndexerPlugin;
14
19
  exports.indexerAsyncContext = indexerAsyncContext;
15
20
  exports.useIndexerContext = useIndexerContext;
@@ -9,4 +9,8 @@ function useIndexerContext() {
9
9
  return indexerAsyncContext.use();
10
10
  }
11
11
 
12
- export { indexerAsyncContext as i, useIndexerContext as u };
12
+ function defineIndexerPlugin(def) {
13
+ return def;
14
+ }
15
+
16
+ export { defineIndexerPlugin as d, indexerAsyncContext as i, useIndexerContext as u };
@@ -1,4 +1,4 @@
1
- import { StreamDataRequest, StreamDataOptions, Cursor, StreamDataResponse, Invalidate, Finalize, Heartbeat, SystemMessage, DataFinality, StreamConfig, Client } from '@apibara/protocol';
1
+ import { StreamDataRequest, StreamDataOptions, Cursor, StreamDataResponse, Invalidate, Finalize, SystemMessage, DataFinality, StreamConfig, Client } from '@apibara/protocol';
2
2
  import { NestedHooks, Hookable } from 'hookable';
3
3
 
4
4
  interface IndexerContext extends Record<string, any> {
@@ -38,9 +38,7 @@ interface IndexerHooks<TFilter, TBlock> {
38
38
  "message:finalize": ({ message }: {
39
39
  message: Finalize;
40
40
  }) => void;
41
- "message:heartbeat": ({ message }: {
42
- message: Heartbeat;
43
- }) => void;
41
+ "message:heartbeat": () => void;
44
42
  "message:systemMessage": ({ message }: {
45
43
  message: SystemMessage;
46
44
  }) => void;
@@ -1,4 +1,4 @@
1
- import { StreamDataRequest, StreamDataOptions, Cursor, StreamDataResponse, Invalidate, Finalize, Heartbeat, SystemMessage, DataFinality, StreamConfig, Client } from '@apibara/protocol';
1
+ import { StreamDataRequest, StreamDataOptions, Cursor, StreamDataResponse, Invalidate, Finalize, SystemMessage, DataFinality, StreamConfig, Client } from '@apibara/protocol';
2
2
  import { NestedHooks, Hookable } from 'hookable';
3
3
 
4
4
  interface IndexerContext extends Record<string, any> {
@@ -38,9 +38,7 @@ interface IndexerHooks<TFilter, TBlock> {
38
38
  "message:finalize": ({ message }: {
39
39
  message: Finalize;
40
40
  }) => void;
41
- "message:heartbeat": ({ message }: {
42
- message: Heartbeat;
43
- }) => void;
41
+ "message:heartbeat": () => void;
44
42
  "message:systemMessage": ({ message }: {
45
43
  message: SystemMessage;
46
44
  }) => void;
@@ -1,4 +1,4 @@
1
- import { StreamDataRequest, StreamDataOptions, Cursor, StreamDataResponse, Invalidate, Finalize, Heartbeat, SystemMessage, DataFinality, StreamConfig, Client } from '@apibara/protocol';
1
+ import { StreamDataRequest, StreamDataOptions, Cursor, StreamDataResponse, Invalidate, Finalize, SystemMessage, DataFinality, StreamConfig, Client } from '@apibara/protocol';
2
2
  import { NestedHooks, Hookable } from 'hookable';
3
3
 
4
4
  interface IndexerContext extends Record<string, any> {
@@ -38,9 +38,7 @@ interface IndexerHooks<TFilter, TBlock> {
38
38
  "message:finalize": ({ message }: {
39
39
  message: Finalize;
40
40
  }) => void;
41
- "message:heartbeat": ({ message }: {
42
- message: Heartbeat;
43
- }) => void;
41
+ "message:heartbeat": () => void;
44
42
  "message:systemMessage": ({ message }: {
45
43
  message: SystemMessage;
46
44
  }) => void;
@@ -1,6 +1,5 @@
1
1
  import { consola } from 'consola';
2
- import { u as useIndexerContext } from './indexer.a55ad619.mjs';
3
- import { d as defineIndexerPlugin } from './indexer.9b21ddd2.mjs';
2
+ import { d as defineIndexerPlugin, u as useIndexerContext } from './indexer.75773ef1.mjs';
4
3
 
5
4
  function logger({
6
5
  logger: logger2
@@ -1,15 +1,14 @@
1
1
  'use strict';
2
2
 
3
3
  const consola = require('consola');
4
- const context = require('./indexer.077335f3.cjs');
5
- const config = require('./indexer.601ceab0.cjs');
4
+ const config = require('./indexer.479ae593.cjs');
6
5
 
7
6
  function logger({
8
7
  logger: logger2
9
8
  } = {}) {
10
9
  return config.defineIndexerPlugin((indexer) => {
11
10
  indexer.hooks.hook("run:before", () => {
12
- const ctx = context.useIndexerContext();
11
+ const ctx = config.useIndexerContext();
13
12
  if (logger2) {
14
13
  ctx.logger = consola.consola.create({ reporters: [logger2] });
15
14
  } else {
@@ -19,7 +18,7 @@ function logger({
19
18
  });
20
19
  }
21
20
  function useLogger() {
22
- const ctx = context.useIndexerContext();
21
+ const ctx = config.useIndexerContext();
23
22
  if (!ctx?.logger)
24
23
  throw new Error("Logger plugin is not available in context");
25
24
  return ctx.logger;
@@ -2,18 +2,17 @@
2
2
 
3
3
  const protocol = require('@apibara/protocol');
4
4
  const ci = require('ci-info');
5
+ const config = require('../shared/indexer.479ae593.cjs');
5
6
  const index = require('../index.cjs');
6
7
  const internal_plugins = require('../internal/plugins.cjs');
7
- const logger = require('../shared/indexer.2416906c.cjs');
8
+ const logger = require('../shared/indexer.a09fa402.cjs');
8
9
  const vcr_index = require('../vcr/index.cjs');
10
+ require('node:async_hooks');
11
+ require('unctx');
9
12
  require('consola');
10
13
  require('hookable');
11
14
  require('node:assert');
12
- require('../shared/indexer.077335f3.cjs');
13
- require('node:async_hooks');
14
- require('unctx');
15
15
  require('@opentelemetry/api');
16
- require('../shared/indexer.601ceab0.cjs');
17
16
  require('node:fs/promises');
18
17
  require('node:path');
19
18
  require('node:fs');
@@ -24,6 +23,7 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
24
23
  const ci__default = /*#__PURE__*/_interopDefaultCompat(ci);
25
24
 
26
25
  function createVcr() {
26
+ let result;
27
27
  return {
28
28
  async run(cassetteName, indexerConfig, range) {
29
29
  const vcrConfig = {
@@ -47,6 +47,9 @@ function createVcr() {
47
47
  ...indexerConfig.plugins ?? []
48
48
  ];
49
49
  const indexer = index.createIndexer(indexerConfig);
50
+ indexer.hooks.hook("run:after", () => {
51
+ result = config.useIndexerContext();
52
+ });
50
53
  if (!vcr_index.isCassetteAvailable(vcrConfig, cassetteName)) {
51
54
  if (ci__default.isCI) {
52
55
  throw new Error("Cannot record cassette in CI");
@@ -59,6 +62,7 @@ function createVcr() {
59
62
  } else {
60
63
  await vcr_index.replay(vcrConfig, indexer, cassetteName);
61
64
  }
65
+ return result;
62
66
  }
63
67
  };
64
68
  }
@@ -1,12 +1,13 @@
1
- import { I as IndexerWithStreamConfig } from '../shared/indexer.fedcd831.cjs';
1
+ import { I as IndexerWithStreamConfig } from '../shared/indexer.7668fe34.cjs';
2
2
  import '@apibara/protocol';
3
3
  import 'hookable';
4
4
 
5
+ type VcrResult = Record<string, unknown>;
5
6
  declare function createVcr(): {
6
7
  run<TFilter, TBlock>(cassetteName: string, indexerConfig: IndexerWithStreamConfig<TFilter, TBlock>, range: {
7
8
  fromBlock: bigint;
8
9
  toBlock: bigint;
9
- }): Promise<void>;
10
+ }): Promise<VcrResult>;
10
11
  };
11
12
 
12
- export { createVcr };
13
+ export { type VcrResult, createVcr };
@@ -1,12 +1,13 @@
1
- import { I as IndexerWithStreamConfig } from '../shared/indexer.fedcd831.mjs';
1
+ import { I as IndexerWithStreamConfig } from '../shared/indexer.7668fe34.mjs';
2
2
  import '@apibara/protocol';
3
3
  import 'hookable';
4
4
 
5
+ type VcrResult = Record<string, unknown>;
5
6
  declare function createVcr(): {
6
7
  run<TFilter, TBlock>(cassetteName: string, indexerConfig: IndexerWithStreamConfig<TFilter, TBlock>, range: {
7
8
  fromBlock: bigint;
8
9
  toBlock: bigint;
9
- }): Promise<void>;
10
+ }): Promise<VcrResult>;
10
11
  };
11
12
 
12
- export { createVcr };
13
+ export { type VcrResult, createVcr };
@@ -1,12 +1,13 @@
1
- import { I as IndexerWithStreamConfig } from '../shared/indexer.fedcd831.js';
1
+ import { I as IndexerWithStreamConfig } from '../shared/indexer.7668fe34.js';
2
2
  import '@apibara/protocol';
3
3
  import 'hookable';
4
4
 
5
+ type VcrResult = Record<string, unknown>;
5
6
  declare function createVcr(): {
6
7
  run<TFilter, TBlock>(cassetteName: string, indexerConfig: IndexerWithStreamConfig<TFilter, TBlock>, range: {
7
8
  fromBlock: bigint;
8
9
  toBlock: bigint;
9
- }): Promise<void>;
10
+ }): Promise<VcrResult>;
10
11
  };
11
12
 
12
- export { createVcr };
13
+ export { type VcrResult, createVcr };
@@ -1,23 +1,23 @@
1
1
  import { createClient } from '@apibara/protocol';
2
2
  import ci from 'ci-info';
3
+ import { u as useIndexerContext } from '../shared/indexer.75773ef1.mjs';
3
4
  import { createIndexer } from '../index.mjs';
4
5
  import { internalContext } from '../internal/plugins.mjs';
5
- import { l as logger } from '../shared/indexer.ff25c953.mjs';
6
+ import { l as logger } from '../shared/indexer.98a921a7.mjs';
6
7
  import { isCassetteAvailable, record, replay } from '../vcr/index.mjs';
8
+ import 'node:async_hooks';
9
+ import 'unctx';
7
10
  import 'consola';
8
11
  import 'hookable';
9
12
  import 'node:assert';
10
- import '../shared/indexer.a55ad619.mjs';
11
- import 'node:async_hooks';
12
- import 'unctx';
13
13
  import '@opentelemetry/api';
14
- import '../shared/indexer.9b21ddd2.mjs';
15
14
  import 'node:fs/promises';
16
15
  import 'node:path';
17
16
  import 'node:fs';
18
17
  import '@apibara/protocol/testing';
19
18
 
20
19
  function createVcr() {
20
+ let result;
21
21
  return {
22
22
  async run(cassetteName, indexerConfig, range) {
23
23
  const vcrConfig = {
@@ -41,6 +41,9 @@ function createVcr() {
41
41
  ...indexerConfig.plugins ?? []
42
42
  ];
43
43
  const indexer = createIndexer(indexerConfig);
44
+ indexer.hooks.hook("run:after", () => {
45
+ result = useIndexerContext();
46
+ });
44
47
  if (!isCassetteAvailable(vcrConfig, cassetteName)) {
45
48
  if (ci.isCI) {
46
49
  throw new Error("Cannot record cassette in CI");
@@ -53,6 +56,7 @@ function createVcr() {
53
56
  } else {
54
57
  await replay(vcrConfig, indexer, cassetteName);
55
58
  }
59
+ return result;
56
60
  }
57
61
  };
58
62
  }
@@ -9,10 +9,11 @@ const testing = require('@apibara/protocol/testing');
9
9
  require('@apibara/protocol');
10
10
  require('consola');
11
11
  require('hookable');
12
- require('../shared/indexer.077335f3.cjs');
12
+ require('../shared/indexer.479ae593.cjs');
13
13
  require('node:async_hooks');
14
14
  require('unctx');
15
15
  require('@opentelemetry/api');
16
+ require('../internal/plugins.cjs');
16
17
 
17
18
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
18
19
 
@@ -1,5 +1,5 @@
1
1
  import { Cursor, StreamDataResponse, Client } from '@apibara/protocol';
2
- import { a as Indexer } from '../shared/indexer.fedcd831.cjs';
2
+ import { a as Indexer } from '../shared/indexer.7668fe34.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 { a as Indexer } from '../shared/indexer.fedcd831.mjs';
2
+ import { a as Indexer } from '../shared/indexer.7668fe34.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 { a as Indexer } from '../shared/indexer.fedcd831.js';
2
+ import { a as Indexer } from '../shared/indexer.7668fe34.js';
3
3
  import 'hookable';
4
4
 
5
5
  type VcrConfig = {
@@ -7,10 +7,11 @@ import { MockClient } from '@apibara/protocol/testing';
7
7
  import '@apibara/protocol';
8
8
  import 'consola';
9
9
  import 'hookable';
10
- import '../shared/indexer.a55ad619.mjs';
10
+ import '../shared/indexer.75773ef1.mjs';
11
11
  import 'node:async_hooks';
12
12
  import 'unctx';
13
13
  import '@opentelemetry/api';
14
+ import '../internal/plugins.mjs';
14
15
 
15
16
  function deserialize(str) {
16
17
  return JSON.parse(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apibara/indexer",
3
- "version": "2.1.0-beta.3",
3
+ "version": "2.1.0-beta.30",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -70,10 +70,10 @@
70
70
  "vitest": "^1.6.0"
71
71
  },
72
72
  "dependencies": {
73
- "@apibara/protocol": "2.1.0-beta.3",
73
+ "@apibara/protocol": "2.1.0-beta.30",
74
74
  "@opentelemetry/api": "^1.9.0",
75
75
  "ci-info": "^4.1.0",
76
- "consola": "^3.2.3",
76
+ "consola": "^3.4.2",
77
77
  "hookable": "^5.5.3",
78
78
  "klona": "^2.0.6",
79
79
  "nice-grpc": "^2.1.8",
package/src/indexer.ts CHANGED
@@ -4,8 +4,8 @@ import {
4
4
  type Cursor,
5
5
  type DataFinality,
6
6
  type Finalize,
7
- type Heartbeat,
8
7
  type Invalidate,
8
+ ServerError,
9
9
  Status,
10
10
  type StreamConfig,
11
11
  type StreamDataOptions,
@@ -28,8 +28,9 @@ import {
28
28
  indexerAsyncContext,
29
29
  useIndexerContext,
30
30
  } from "./context";
31
- import { tracer } from "./otel";
31
+ import { createIndexerMetrics, createTracer } from "./otel";
32
32
  import type { IndexerPlugin } from "./plugins";
33
+ import { useInternalContext } from "./plugins/context";
33
34
 
34
35
  export type UseMiddlewareFunction = (
35
36
  fn: MiddlewareFunction<IndexerContext>,
@@ -59,7 +60,7 @@ export interface IndexerHooks<TFilter, TBlock> {
59
60
  message: ({ message }: { message: StreamDataResponse<TBlock> }) => void;
60
61
  "message:invalidate": ({ message }: { message: Invalidate }) => void;
61
62
  "message:finalize": ({ message }: { message: Finalize }) => void;
62
- "message:heartbeat": ({ message }: { message: Heartbeat }) => void;
63
+ "message:heartbeat": () => void;
63
64
  "message:systemMessage": ({ message }: { message: SystemMessage }) => void;
64
65
  }
65
66
 
@@ -179,13 +180,18 @@ export async function runWithReconnect<TFilter, TBlock>(
179
180
 
180
181
  retryCount++;
181
182
 
182
- if (error instanceof ClientError) {
183
+ if (error instanceof ClientError || error instanceof ServerError) {
184
+ const isServerError = error instanceof ServerError;
185
+
183
186
  if (error.code === Status.INTERNAL) {
184
187
  if (retryCount < maxRetries) {
185
188
  consola.error(
186
- "Internal server error, reconnecting...",
187
- error.message,
189
+ `Internal ${isServerError ? "server" : "client"} error: ${
190
+ error.message
191
+ }`,
188
192
  );
193
+ consola.start("Reconnecting...");
194
+ console.log();
189
195
 
190
196
  // Add jitter to the retry delay to avoid all clients retrying at the same time.
191
197
  const delay = Math.random() * (retryDelay * 0.2) + retryDelay;
@@ -216,8 +222,13 @@ export async function run<TFilter, TBlock>(
216
222
  const context = useIndexerContext();
217
223
  const middleware = await registerMiddleware(indexer);
218
224
 
225
+ const indexerMetrics = createIndexerMetrics();
226
+ const tracer = createTracer();
227
+
219
228
  await indexer.hooks.callHook("run:before");
220
229
 
230
+ const { indexerName: indexerId } = useInternalContext();
231
+
221
232
  const isFactoryMode = indexer.options.factory !== undefined;
222
233
 
223
234
  // Give priority to startingCursor over startingBlock.
@@ -235,13 +246,13 @@ export async function run<TFilter, TBlock>(
235
246
  }
236
247
 
237
248
  // if factory mode we add a empty filter at the end of the filter array.
238
- const request = indexer.streamConfig.Request.make({
249
+ const request = {
239
250
  filter: isFactoryMode
240
251
  ? [indexer.options.filter, {} as TFilter]
241
252
  : [indexer.options.filter],
242
253
  finality: indexer.options.finality,
243
254
  startingCursor,
244
- });
255
+ } as StreamDataRequest<TFilter>;
245
256
 
246
257
  const options: StreamDataOptions = {};
247
258
 
@@ -288,11 +299,19 @@ export async function run<TFilter, TBlock>(
288
299
  context.endCursor = endCursor;
289
300
  context.finality = finality;
290
301
 
302
+ // Record current block number being processed
303
+ indexerMetrics.currentBlockGauge.record(
304
+ Number(endCursor?.orderKey),
305
+ {
306
+ indexer_id: indexerId,
307
+ },
308
+ );
309
+
291
310
  await middleware(context, async () => {
292
311
  let block: TBlock | null;
293
312
 
294
313
  // when factory mode
295
- if (isFactoryMode) {
314
+ if (isFactoryMode && finality !== "pending") {
296
315
  assert(indexer.options.factory !== undefined);
297
316
 
298
317
  const [factoryBlock, mainBlock] = blocks;
@@ -315,11 +334,11 @@ export async function run<TFilter, TBlock>(
315
334
  );
316
335
 
317
336
  // create request with new filters
318
- const request = indexer.streamConfig.Request.make({
337
+ const request = {
319
338
  filter: [indexer.options.filter, mainFilter],
320
339
  finality: indexer.options.finality,
321
340
  startingCursor: cursor,
322
- });
341
+ } as StreamDataRequest<TFilter>;
323
342
 
324
343
  await indexer.hooks.callHook("connect:factory", {
325
344
  request,
@@ -364,6 +383,11 @@ export async function run<TFilter, TBlock>(
364
383
  span.end();
365
384
  });
366
385
 
386
+ // Record processed block metric
387
+ indexerMetrics.processedBlockCounter.add(1, {
388
+ indexer_id: indexerId,
389
+ });
390
+
367
391
  context.cursor = undefined;
368
392
  context.endCursor = undefined;
369
393
  context.finality = undefined;
@@ -372,21 +396,29 @@ export async function run<TFilter, TBlock>(
372
396
  }
373
397
  case "invalidate": {
374
398
  await tracer.startActiveSpan("message invalidate", async (span) => {
375
- await indexer.hooks.callHook("message:invalidate", { message });
399
+ // Record reorg metric
400
+ indexerMetrics.reorgCounter.add(1, {
401
+ indexer_id: indexerId,
402
+ });
403
+ await indexer.hooks.callHook("message:invalidate", {
404
+ message: message.invalidate,
405
+ });
376
406
  span.end();
377
407
  });
378
408
  break;
379
409
  }
380
410
  case "finalize": {
381
411
  await tracer.startActiveSpan("message finalize", async (span) => {
382
- await indexer.hooks.callHook("message:finalize", { message });
412
+ await indexer.hooks.callHook("message:finalize", {
413
+ message: message.finalize,
414
+ });
383
415
  span.end();
384
416
  });
385
417
  break;
386
418
  }
387
419
  case "heartbeat": {
388
420
  await tracer.startActiveSpan("message heartbeat", async (span) => {
389
- await indexer.hooks.callHook("message:heartbeat", { message });
421
+ await indexer.hooks.callHook("message:heartbeat");
390
422
  span.end();
391
423
  });
392
424
  break;
@@ -409,7 +441,7 @@ export async function run<TFilter, TBlock>(
409
441
  }
410
442
 
411
443
  await indexer.hooks.callHook("message:systemMessage", {
412
- message,
444
+ message: message.systemMessage,
413
445
  });
414
446
  span.end();
415
447
  },