@apibara/indexer 2.1.0-beta.2 → 2.1.0-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +53 -15
- package/dist/index.mjs +42 -4
- package/dist/internal/plugins.cjs +3 -4
- package/dist/internal/plugins.mjs +1 -2
- package/dist/internal/testing.cjs +24 -10
- package/dist/internal/testing.d.cts +2 -0
- package/dist/internal/testing.d.mts +2 -0
- package/dist/internal/testing.d.ts +2 -0
- package/dist/internal/testing.mjs +22 -8
- package/dist/plugins/index.cjs +3 -4
- package/dist/plugins/index.mjs +3 -4
- package/dist/shared/{indexer.077335f3.cjs → indexer.479ae593.cjs} +5 -0
- package/dist/shared/{indexer.a55ad619.mjs → indexer.75773ef1.mjs} +5 -1
- package/dist/shared/{indexer.ff25c953.mjs → indexer.98a921a7.mjs} +1 -2
- package/dist/shared/{indexer.2416906c.cjs → indexer.a09fa402.cjs} +3 -4
- package/dist/testing/index.cjs +9 -5
- package/dist/testing/index.d.cts +3 -2
- package/dist/testing/index.d.mts +3 -2
- package/dist/testing/index.d.ts +3 -2
- package/dist/testing/index.mjs +9 -5
- package/dist/vcr/index.cjs +2 -1
- package/dist/vcr/index.mjs +2 -1
- package/package.json +3 -3
- package/src/indexer.ts +25 -2
- package/src/internal/testing.ts +30 -7
- package/src/otel.ts +29 -2
- package/src/testing/index.ts +11 -0
- package/dist/shared/indexer.601ceab0.cjs +0 -7
- package/dist/shared/indexer.9b21ddd2.mjs +0 -5
package/dist/index.cjs
CHANGED
|
@@ -4,8 +4,9 @@ const protocol = require('@apibara/protocol');
|
|
|
4
4
|
const consola = require('consola');
|
|
5
5
|
const hookable = require('hookable');
|
|
6
6
|
const assert = require('node:assert');
|
|
7
|
-
const
|
|
7
|
+
const config = require('./shared/indexer.479ae593.cjs');
|
|
8
8
|
const api = require('@opentelemetry/api');
|
|
9
|
+
const internal_plugins = require('./internal/plugins.cjs');
|
|
9
10
|
require('node:async_hooks');
|
|
10
11
|
require('unctx');
|
|
11
12
|
|
|
@@ -43,7 +44,29 @@ function compose(middleware) {
|
|
|
43
44
|
};
|
|
44
45
|
}
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
function createTracer() {
|
|
48
|
+
return api.trace.getTracer("@apibara/indexer");
|
|
49
|
+
}
|
|
50
|
+
function createIndexerMetrics() {
|
|
51
|
+
const meter = api.metrics.getMeter("@apibara/indexer");
|
|
52
|
+
const currentBlockGauge = meter.createGauge("current_block", {
|
|
53
|
+
description: "Current block number being processed",
|
|
54
|
+
unit: "{block}"
|
|
55
|
+
});
|
|
56
|
+
const processedBlockCounter = meter.createCounter("processed_blocks", {
|
|
57
|
+
description: "Number of blocks processed",
|
|
58
|
+
unit: "{blocks}"
|
|
59
|
+
});
|
|
60
|
+
const reorgCounter = meter.createCounter("reorgs", {
|
|
61
|
+
description: "Number of reorgs (invalidate messages) received",
|
|
62
|
+
unit: "{reorgs}"
|
|
63
|
+
});
|
|
64
|
+
return {
|
|
65
|
+
currentBlockGauge,
|
|
66
|
+
processedBlockCounter,
|
|
67
|
+
reorgCounter
|
|
68
|
+
};
|
|
69
|
+
}
|
|
47
70
|
|
|
48
71
|
function defineIndexer(streamConfig) {
|
|
49
72
|
return (config) => ({
|
|
@@ -105,10 +128,13 @@ async function runWithReconnect(client, indexer, options = {}) {
|
|
|
105
128
|
}
|
|
106
129
|
}
|
|
107
130
|
async function run(client, indexer, runOptions = {}) {
|
|
108
|
-
await
|
|
109
|
-
const context
|
|
131
|
+
await config.indexerAsyncContext.callAsync({}, async () => {
|
|
132
|
+
const context = config.useIndexerContext();
|
|
110
133
|
const middleware = await registerMiddleware(indexer);
|
|
134
|
+
const indexerMetrics = createIndexerMetrics();
|
|
135
|
+
const tracer = createTracer();
|
|
111
136
|
await indexer.hooks.callHook("run:before");
|
|
137
|
+
const { indexerName: indexerId } = internal_plugins.useInternalContext();
|
|
112
138
|
const isFactoryMode = indexer.options.factory !== void 0;
|
|
113
139
|
let startingCursor;
|
|
114
140
|
if (indexer.options.startingCursor) {
|
|
@@ -153,19 +179,25 @@ async function run(client, indexer, runOptions = {}) {
|
|
|
153
179
|
await tracer.startActiveSpan("message data", async (span) => {
|
|
154
180
|
const blocks = message.data.data;
|
|
155
181
|
const { cursor, endCursor, finality } = message.data;
|
|
156
|
-
context
|
|
157
|
-
context
|
|
158
|
-
context
|
|
159
|
-
|
|
182
|
+
context.cursor = cursor;
|
|
183
|
+
context.endCursor = endCursor;
|
|
184
|
+
context.finality = finality;
|
|
185
|
+
indexerMetrics.currentBlockGauge.record(
|
|
186
|
+
Number(endCursor?.orderKey),
|
|
187
|
+
{
|
|
188
|
+
indexer_id: indexerId
|
|
189
|
+
}
|
|
190
|
+
);
|
|
191
|
+
await middleware(context, async () => {
|
|
160
192
|
let block;
|
|
161
|
-
if (isFactoryMode) {
|
|
193
|
+
if (isFactoryMode && finality !== "pending") {
|
|
162
194
|
assert__default(indexer.options.factory !== void 0);
|
|
163
195
|
const [factoryBlock, mainBlock] = blocks;
|
|
164
196
|
block = mainBlock;
|
|
165
197
|
if (factoryBlock !== null) {
|
|
166
198
|
const { filter } = await indexer.options.factory({
|
|
167
199
|
block: factoryBlock,
|
|
168
|
-
context
|
|
200
|
+
context
|
|
169
201
|
});
|
|
170
202
|
if (filter) {
|
|
171
203
|
mainFilter = indexer.streamConfig.mergeFilter(
|
|
@@ -198,7 +230,7 @@ async function run(client, indexer, runOptions = {}) {
|
|
|
198
230
|
cursor,
|
|
199
231
|
endCursor,
|
|
200
232
|
finality,
|
|
201
|
-
context
|
|
233
|
+
context
|
|
202
234
|
});
|
|
203
235
|
span2.end();
|
|
204
236
|
});
|
|
@@ -206,13 +238,19 @@ async function run(client, indexer, runOptions = {}) {
|
|
|
206
238
|
});
|
|
207
239
|
span.end();
|
|
208
240
|
});
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
241
|
+
indexerMetrics.processedBlockCounter.add(1, {
|
|
242
|
+
indexer_id: indexerId
|
|
243
|
+
});
|
|
244
|
+
context.cursor = void 0;
|
|
245
|
+
context.endCursor = void 0;
|
|
246
|
+
context.finality = void 0;
|
|
212
247
|
break;
|
|
213
248
|
}
|
|
214
249
|
case "invalidate": {
|
|
215
250
|
await tracer.startActiveSpan("message invalidate", async (span) => {
|
|
251
|
+
indexerMetrics.reorgCounter.add(1, {
|
|
252
|
+
indexer_id: indexerId
|
|
253
|
+
});
|
|
216
254
|
await indexer.hooks.callHook("message:invalidate", { message });
|
|
217
255
|
span.end();
|
|
218
256
|
});
|
|
@@ -275,7 +313,7 @@ async function registerMiddleware(indexer) {
|
|
|
275
313
|
};
|
|
276
314
|
}
|
|
277
315
|
|
|
278
|
-
exports.useIndexerContext =
|
|
316
|
+
exports.useIndexerContext = config.useIndexerContext;
|
|
279
317
|
exports.createIndexer = createIndexer;
|
|
280
318
|
exports.defineIndexer = defineIndexer;
|
|
281
319
|
exports.run = run;
|
package/dist/index.mjs
CHANGED
|
@@ -2,8 +2,9 @@ import { ClientError, 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.
|
|
6
|
-
import { trace } from '@opentelemetry/api';
|
|
5
|
+
import { i as indexerAsyncContext, u as useIndexerContext } 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,29 @@ function compose(middleware) {
|
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
39
|
|
|
39
|
-
|
|
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
|
+
}
|
|
40
63
|
|
|
41
64
|
function defineIndexer(streamConfig) {
|
|
42
65
|
return (config) => ({
|
|
@@ -101,7 +124,10 @@ async function run(client, indexer, runOptions = {}) {
|
|
|
101
124
|
await indexerAsyncContext.callAsync({}, async () => {
|
|
102
125
|
const context = useIndexerContext();
|
|
103
126
|
const middleware = await registerMiddleware(indexer);
|
|
127
|
+
const indexerMetrics = createIndexerMetrics();
|
|
128
|
+
const tracer = createTracer();
|
|
104
129
|
await indexer.hooks.callHook("run:before");
|
|
130
|
+
const { indexerName: indexerId } = useInternalContext();
|
|
105
131
|
const isFactoryMode = indexer.options.factory !== void 0;
|
|
106
132
|
let startingCursor;
|
|
107
133
|
if (indexer.options.startingCursor) {
|
|
@@ -149,9 +175,15 @@ async function run(client, indexer, runOptions = {}) {
|
|
|
149
175
|
context.cursor = cursor;
|
|
150
176
|
context.endCursor = endCursor;
|
|
151
177
|
context.finality = finality;
|
|
178
|
+
indexerMetrics.currentBlockGauge.record(
|
|
179
|
+
Number(endCursor?.orderKey),
|
|
180
|
+
{
|
|
181
|
+
indexer_id: indexerId
|
|
182
|
+
}
|
|
183
|
+
);
|
|
152
184
|
await middleware(context, async () => {
|
|
153
185
|
let block;
|
|
154
|
-
if (isFactoryMode) {
|
|
186
|
+
if (isFactoryMode && finality !== "pending") {
|
|
155
187
|
assert(indexer.options.factory !== void 0);
|
|
156
188
|
const [factoryBlock, mainBlock] = blocks;
|
|
157
189
|
block = mainBlock;
|
|
@@ -199,6 +231,9 @@ async function run(client, indexer, runOptions = {}) {
|
|
|
199
231
|
});
|
|
200
232
|
span.end();
|
|
201
233
|
});
|
|
234
|
+
indexerMetrics.processedBlockCounter.add(1, {
|
|
235
|
+
indexer_id: indexerId
|
|
236
|
+
});
|
|
202
237
|
context.cursor = void 0;
|
|
203
238
|
context.endCursor = void 0;
|
|
204
239
|
context.finality = void 0;
|
|
@@ -206,6 +241,9 @@ async function run(client, indexer, runOptions = {}) {
|
|
|
206
241
|
}
|
|
207
242
|
case "invalidate": {
|
|
208
243
|
await tracer.startActiveSpan("message invalidate", async (span) => {
|
|
244
|
+
indexerMetrics.reorgCounter.add(1, {
|
|
245
|
+
indexer_id: indexerId
|
|
246
|
+
});
|
|
209
247
|
await indexer.hooks.callHook("message:invalidate", { message });
|
|
210
248
|
span.end();
|
|
211
249
|
});
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
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
|
|
|
@@ -10,7 +9,7 @@ function internalContext(values) {
|
|
|
10
9
|
return config.defineIndexerPlugin((indexer) => {
|
|
11
10
|
indexer.hooks.hook("run:before", () => {
|
|
12
11
|
try {
|
|
13
|
-
const ctx =
|
|
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 =
|
|
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!"
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { u as useIndexerContext } from '../shared/indexer.
|
|
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
|
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
const protocol = require('@apibara/protocol');
|
|
4
4
|
const testing = require('@apibara/protocol/testing');
|
|
5
|
-
const
|
|
5
|
+
const config = require('../shared/indexer.479ae593.cjs');
|
|
6
6
|
const index = require('../index.cjs');
|
|
7
|
-
const
|
|
8
|
-
require('consola');
|
|
7
|
+
const logger = require('../shared/indexer.a09fa402.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');
|
|
@@ -17,22 +17,29 @@ function generateMockMessages(count = 10, options) {
|
|
|
17
17
|
const invalidateAt = options?.invalidate;
|
|
18
18
|
const finalizeAt = options?.finalize;
|
|
19
19
|
const messages = [];
|
|
20
|
+
const baseBlockNumber = options?.baseBlockNumber ?? BigInt(5e6);
|
|
20
21
|
for (let i = 0; i < count; i++) {
|
|
22
|
+
const currentBlockNumber = baseBlockNumber + BigInt(i);
|
|
23
|
+
const uniqueKey = uniqueKeyFromOrderKey(currentBlockNumber);
|
|
21
24
|
if (invalidateAt && i === invalidateAt.invalidateTriggerIndex) {
|
|
25
|
+
const invalidateToBlock = baseBlockNumber + BigInt(invalidateAt.invalidateFromIndex);
|
|
22
26
|
messages.push({
|
|
23
27
|
_tag: "invalidate",
|
|
24
28
|
invalidate: {
|
|
25
29
|
cursor: {
|
|
26
|
-
orderKey:
|
|
30
|
+
orderKey: invalidateToBlock,
|
|
31
|
+
uniqueKey: options?.uniqueKey ? uniqueKeyFromOrderKey(invalidateToBlock) : void 0
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
34
|
});
|
|
30
35
|
} else if (finalizeAt && i === finalizeAt.finalizeTriggerIndex) {
|
|
36
|
+
const fianlizedToBlock = baseBlockNumber + BigInt(finalizeAt.finalizeToIndex);
|
|
31
37
|
messages.push({
|
|
32
38
|
_tag: "finalize",
|
|
33
39
|
finalize: {
|
|
34
40
|
cursor: {
|
|
35
|
-
orderKey:
|
|
41
|
+
orderKey: fianlizedToBlock,
|
|
42
|
+
uniqueKey: options?.uniqueKey ? uniqueKeyFromOrderKey(fianlizedToBlock) : void 0
|
|
36
43
|
}
|
|
37
44
|
}
|
|
38
45
|
});
|
|
@@ -40,10 +47,13 @@ function generateMockMessages(count = 10, options) {
|
|
|
40
47
|
messages.push({
|
|
41
48
|
_tag: "data",
|
|
42
49
|
data: {
|
|
43
|
-
cursor: { orderKey:
|
|
50
|
+
cursor: { orderKey: currentBlockNumber - 1n },
|
|
44
51
|
finality: "accepted",
|
|
45
|
-
data: [{ data: `${
|
|
46
|
-
endCursor: {
|
|
52
|
+
data: [{ data: `${baseBlockNumber + BigInt(i)}` }],
|
|
53
|
+
endCursor: {
|
|
54
|
+
orderKey: currentBlockNumber,
|
|
55
|
+
uniqueKey: options?.uniqueKey ? uniqueKey : void 0
|
|
56
|
+
},
|
|
47
57
|
production: "backfill"
|
|
48
58
|
}
|
|
49
59
|
});
|
|
@@ -51,6 +61,9 @@ function generateMockMessages(count = 10, options) {
|
|
|
51
61
|
}
|
|
52
62
|
return messages;
|
|
53
63
|
}
|
|
64
|
+
function uniqueKeyFromOrderKey(orderKey) {
|
|
65
|
+
return `0xff00${orderKey.toString()}`;
|
|
66
|
+
}
|
|
54
67
|
function getMockIndexer(params) {
|
|
55
68
|
const { internalContext: contextParams, override } = params ?? {};
|
|
56
69
|
const { plugins, ...rest } = override ?? {};
|
|
@@ -62,6 +75,7 @@ function getMockIndexer(params) {
|
|
|
62
75
|
async transform() {
|
|
63
76
|
},
|
|
64
77
|
plugins: [
|
|
78
|
+
logger.logger(),
|
|
65
79
|
internal_plugins.internalContext(
|
|
66
80
|
contextParams ?? {
|
|
67
81
|
availableIndexers: ["testing"],
|
|
@@ -108,8 +122,8 @@ function mockSink({
|
|
|
108
122
|
});
|
|
109
123
|
}
|
|
110
124
|
function useMockSink() {
|
|
111
|
-
const context
|
|
112
|
-
return { output: context
|
|
125
|
+
const context = config.useIndexerContext();
|
|
126
|
+
return { output: context.output };
|
|
113
127
|
}
|
|
114
128
|
|
|
115
129
|
exports.generateMockMessages = generateMockMessages;
|
|
@@ -13,6 +13,8 @@ type MockMessagesOptions = {
|
|
|
13
13
|
finalizeToIndex: number;
|
|
14
14
|
finalizeTriggerIndex: number;
|
|
15
15
|
};
|
|
16
|
+
uniqueKey?: boolean;
|
|
17
|
+
baseBlockNumber?: bigint;
|
|
16
18
|
};
|
|
17
19
|
declare function generateMockMessages(count?: number, options?: MockMessagesOptions): MockStreamResponse[];
|
|
18
20
|
type MockIndexerParams = {
|
|
@@ -13,6 +13,8 @@ type MockMessagesOptions = {
|
|
|
13
13
|
finalizeToIndex: number;
|
|
14
14
|
finalizeTriggerIndex: number;
|
|
15
15
|
};
|
|
16
|
+
uniqueKey?: boolean;
|
|
17
|
+
baseBlockNumber?: bigint;
|
|
16
18
|
};
|
|
17
19
|
declare function generateMockMessages(count?: number, options?: MockMessagesOptions): MockStreamResponse[];
|
|
18
20
|
type MockIndexerParams = {
|
|
@@ -13,6 +13,8 @@ type MockMessagesOptions = {
|
|
|
13
13
|
finalizeToIndex: number;
|
|
14
14
|
finalizeTriggerIndex: number;
|
|
15
15
|
};
|
|
16
|
+
uniqueKey?: boolean;
|
|
17
|
+
baseBlockNumber?: bigint;
|
|
16
18
|
};
|
|
17
19
|
declare function generateMockMessages(count?: number, options?: MockMessagesOptions): MockStreamResponse[];
|
|
18
20
|
type MockIndexerParams = {
|
|
@@ -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.
|
|
3
|
+
import { d as defineIndexerPlugin, u as useIndexerContext } from '../shared/indexer.75773ef1.mjs';
|
|
4
4
|
import { createIndexer, defineIndexer } from '../index.mjs';
|
|
5
|
-
import {
|
|
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:
|
|
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:
|
|
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:
|
|
48
|
+
cursor: { orderKey: currentBlockNumber - 1n },
|
|
42
49
|
finality: "accepted",
|
|
43
|
-
data: [{ data: `${
|
|
44
|
-
endCursor: {
|
|
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"],
|
package/dist/plugins/index.cjs
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const config = require('../shared/indexer.
|
|
4
|
-
const logger = require('../shared/indexer.
|
|
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) => {
|
package/dist/plugins/index.mjs
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { d as defineIndexerPlugin } from '../shared/indexer.
|
|
2
|
-
export { l as logger, u as useLogger } from '../shared/indexer.
|
|
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
|
-
|
|
12
|
+
function defineIndexerPlugin(def) {
|
|
13
|
+
return def;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export { defineIndexerPlugin as d, indexerAsyncContext as i, useIndexerContext as u };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { consola } from 'consola';
|
|
2
|
-
import { u as useIndexerContext } from './indexer.
|
|
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
|
|
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 =
|
|
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 =
|
|
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;
|
package/dist/testing/index.cjs
CHANGED
|
@@ -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.
|
|
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
|
}
|
package/dist/testing/index.d.cts
CHANGED
|
@@ -2,11 +2,12 @@ import { I as IndexerWithStreamConfig } from '../shared/indexer.fedcd831.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<
|
|
10
|
+
}): Promise<VcrResult>;
|
|
10
11
|
};
|
|
11
12
|
|
|
12
|
-
export { createVcr };
|
|
13
|
+
export { type VcrResult, createVcr };
|
package/dist/testing/index.d.mts
CHANGED
|
@@ -2,11 +2,12 @@ import { I as IndexerWithStreamConfig } from '../shared/indexer.fedcd831.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<
|
|
10
|
+
}): Promise<VcrResult>;
|
|
10
11
|
};
|
|
11
12
|
|
|
12
|
-
export { createVcr };
|
|
13
|
+
export { type VcrResult, createVcr };
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -2,11 +2,12 @@ import { I as IndexerWithStreamConfig } from '../shared/indexer.fedcd831.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<
|
|
10
|
+
}): Promise<VcrResult>;
|
|
10
11
|
};
|
|
11
12
|
|
|
12
|
-
export { createVcr };
|
|
13
|
+
export { type VcrResult, createVcr };
|
package/dist/testing/index.mjs
CHANGED
|
@@ -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.
|
|
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
|
}
|
package/dist/vcr/index.cjs
CHANGED
|
@@ -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.
|
|
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
|
|
package/dist/vcr/index.mjs
CHANGED
|
@@ -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.
|
|
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
|
+
"version": "2.1.0-beta.20",
|
|
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.
|
|
73
|
+
"@apibara/protocol": "2.1.0-beta.20",
|
|
74
74
|
"@opentelemetry/api": "^1.9.0",
|
|
75
75
|
"ci-info": "^4.1.0",
|
|
76
|
-
"consola": "^3.2
|
|
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
|
@@ -28,8 +28,9 @@ import {
|
|
|
28
28
|
indexerAsyncContext,
|
|
29
29
|
useIndexerContext,
|
|
30
30
|
} from "./context";
|
|
31
|
-
import {
|
|
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>,
|
|
@@ -216,8 +217,13 @@ export async function run<TFilter, TBlock>(
|
|
|
216
217
|
const context = useIndexerContext();
|
|
217
218
|
const middleware = await registerMiddleware(indexer);
|
|
218
219
|
|
|
220
|
+
const indexerMetrics = createIndexerMetrics();
|
|
221
|
+
const tracer = createTracer();
|
|
222
|
+
|
|
219
223
|
await indexer.hooks.callHook("run:before");
|
|
220
224
|
|
|
225
|
+
const { indexerName: indexerId } = useInternalContext();
|
|
226
|
+
|
|
221
227
|
const isFactoryMode = indexer.options.factory !== undefined;
|
|
222
228
|
|
|
223
229
|
// Give priority to startingCursor over startingBlock.
|
|
@@ -288,11 +294,19 @@ export async function run<TFilter, TBlock>(
|
|
|
288
294
|
context.endCursor = endCursor;
|
|
289
295
|
context.finality = finality;
|
|
290
296
|
|
|
297
|
+
// Record current block number being processed
|
|
298
|
+
indexerMetrics.currentBlockGauge.record(
|
|
299
|
+
Number(endCursor?.orderKey),
|
|
300
|
+
{
|
|
301
|
+
indexer_id: indexerId,
|
|
302
|
+
},
|
|
303
|
+
);
|
|
304
|
+
|
|
291
305
|
await middleware(context, async () => {
|
|
292
306
|
let block: TBlock | null;
|
|
293
307
|
|
|
294
308
|
// when factory mode
|
|
295
|
-
if (isFactoryMode) {
|
|
309
|
+
if (isFactoryMode && finality !== "pending") {
|
|
296
310
|
assert(indexer.options.factory !== undefined);
|
|
297
311
|
|
|
298
312
|
const [factoryBlock, mainBlock] = blocks;
|
|
@@ -364,6 +378,11 @@ export async function run<TFilter, TBlock>(
|
|
|
364
378
|
span.end();
|
|
365
379
|
});
|
|
366
380
|
|
|
381
|
+
// Record processed block metric
|
|
382
|
+
indexerMetrics.processedBlockCounter.add(1, {
|
|
383
|
+
indexer_id: indexerId,
|
|
384
|
+
});
|
|
385
|
+
|
|
367
386
|
context.cursor = undefined;
|
|
368
387
|
context.endCursor = undefined;
|
|
369
388
|
context.finality = undefined;
|
|
@@ -372,6 +391,10 @@ export async function run<TFilter, TBlock>(
|
|
|
372
391
|
}
|
|
373
392
|
case "invalidate": {
|
|
374
393
|
await tracer.startActiveSpan("message invalidate", async (span) => {
|
|
394
|
+
// Record reorg metric
|
|
395
|
+
indexerMetrics.reorgCounter.add(1, {
|
|
396
|
+
indexer_id: indexerId,
|
|
397
|
+
});
|
|
375
398
|
await indexer.hooks.callHook("message:invalidate", { message });
|
|
376
399
|
span.end();
|
|
377
400
|
});
|
package/src/internal/testing.ts
CHANGED
|
@@ -5,10 +5,9 @@ import {
|
|
|
5
5
|
MockStream,
|
|
6
6
|
type MockStreamResponse,
|
|
7
7
|
} from "@apibara/protocol/testing";
|
|
8
|
-
|
|
9
8
|
import { useIndexerContext } from "../context";
|
|
10
9
|
import { type IndexerConfig, createIndexer, defineIndexer } from "../indexer";
|
|
11
|
-
import { defineIndexerPlugin } from "../plugins";
|
|
10
|
+
import { defineIndexerPlugin, logger } from "../plugins";
|
|
12
11
|
import { type InternalContext, internalContext } from "./plugins";
|
|
13
12
|
|
|
14
13
|
export type MockMessagesOptions = {
|
|
@@ -20,6 +19,8 @@ export type MockMessagesOptions = {
|
|
|
20
19
|
finalizeToIndex: number;
|
|
21
20
|
finalizeTriggerIndex: number;
|
|
22
21
|
};
|
|
22
|
+
uniqueKey?: boolean;
|
|
23
|
+
baseBlockNumber?: bigint;
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
export function generateMockMessages(
|
|
@@ -30,22 +31,36 @@ export function generateMockMessages(
|
|
|
30
31
|
const finalizeAt = options?.finalize;
|
|
31
32
|
const messages: MockStreamResponse[] = [];
|
|
32
33
|
|
|
34
|
+
const baseBlockNumber = options?.baseBlockNumber ?? BigInt(5_000_000);
|
|
35
|
+
|
|
33
36
|
for (let i = 0; i < count; i++) {
|
|
37
|
+
const currentBlockNumber = baseBlockNumber + BigInt(i);
|
|
38
|
+
const uniqueKey = uniqueKeyFromOrderKey(currentBlockNumber);
|
|
34
39
|
if (invalidateAt && i === invalidateAt.invalidateTriggerIndex) {
|
|
40
|
+
const invalidateToBlock =
|
|
41
|
+
baseBlockNumber + BigInt(invalidateAt.invalidateFromIndex);
|
|
35
42
|
messages.push({
|
|
36
43
|
_tag: "invalidate",
|
|
37
44
|
invalidate: {
|
|
38
45
|
cursor: {
|
|
39
|
-
orderKey:
|
|
46
|
+
orderKey: invalidateToBlock,
|
|
47
|
+
uniqueKey: options?.uniqueKey
|
|
48
|
+
? uniqueKeyFromOrderKey(invalidateToBlock)
|
|
49
|
+
: undefined,
|
|
40
50
|
},
|
|
41
51
|
},
|
|
42
52
|
} as Invalidate);
|
|
43
53
|
} else if (finalizeAt && i === finalizeAt.finalizeTriggerIndex) {
|
|
54
|
+
const fianlizedToBlock =
|
|
55
|
+
baseBlockNumber + BigInt(finalizeAt.finalizeToIndex);
|
|
44
56
|
messages.push({
|
|
45
57
|
_tag: "finalize",
|
|
46
58
|
finalize: {
|
|
47
59
|
cursor: {
|
|
48
|
-
orderKey:
|
|
60
|
+
orderKey: fianlizedToBlock,
|
|
61
|
+
uniqueKey: options?.uniqueKey
|
|
62
|
+
? uniqueKeyFromOrderKey(fianlizedToBlock)
|
|
63
|
+
: undefined,
|
|
49
64
|
},
|
|
50
65
|
},
|
|
51
66
|
} as Finalize);
|
|
@@ -53,10 +68,13 @@ export function generateMockMessages(
|
|
|
53
68
|
messages.push({
|
|
54
69
|
_tag: "data",
|
|
55
70
|
data: {
|
|
56
|
-
cursor: { orderKey:
|
|
71
|
+
cursor: { orderKey: currentBlockNumber - 1n },
|
|
57
72
|
finality: "accepted",
|
|
58
|
-
data: [{ data: `${
|
|
59
|
-
endCursor: {
|
|
73
|
+
data: [{ data: `${baseBlockNumber + BigInt(i)}` }],
|
|
74
|
+
endCursor: {
|
|
75
|
+
orderKey: currentBlockNumber,
|
|
76
|
+
uniqueKey: options?.uniqueKey ? uniqueKey : undefined,
|
|
77
|
+
},
|
|
60
78
|
production: "backfill",
|
|
61
79
|
},
|
|
62
80
|
});
|
|
@@ -66,6 +84,10 @@ export function generateMockMessages(
|
|
|
66
84
|
return messages;
|
|
67
85
|
}
|
|
68
86
|
|
|
87
|
+
function uniqueKeyFromOrderKey(orderKey: bigint): `0x${string}` {
|
|
88
|
+
return `0xff00${orderKey.toString()}`;
|
|
89
|
+
}
|
|
90
|
+
|
|
69
91
|
type MockIndexerParams = {
|
|
70
92
|
internalContext?: InternalContext;
|
|
71
93
|
override?: Partial<IndexerConfig<MockFilter, MockBlock>>;
|
|
@@ -82,6 +104,7 @@ export function getMockIndexer(params?: MockIndexerParams) {
|
|
|
82
104
|
filter: {},
|
|
83
105
|
async transform() {},
|
|
84
106
|
plugins: [
|
|
107
|
+
logger(),
|
|
85
108
|
internalContext(
|
|
86
109
|
contextParams ??
|
|
87
110
|
({
|
package/src/otel.ts
CHANGED
|
@@ -1,3 +1,30 @@
|
|
|
1
|
-
import { trace } from "@opentelemetry/api";
|
|
1
|
+
import { metrics, trace } from "@opentelemetry/api";
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export function createTracer() {
|
|
4
|
+
return trace.getTracer("@apibara/indexer");
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function createIndexerMetrics() {
|
|
8
|
+
const meter = metrics.getMeter("@apibara/indexer");
|
|
9
|
+
|
|
10
|
+
const currentBlockGauge = meter.createGauge("current_block", {
|
|
11
|
+
description: "Current block number being processed",
|
|
12
|
+
unit: "{block}",
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const processedBlockCounter = meter.createCounter("processed_blocks", {
|
|
16
|
+
description: "Number of blocks processed",
|
|
17
|
+
unit: "{blocks}",
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const reorgCounter = meter.createCounter("reorgs", {
|
|
21
|
+
description: "Number of reorgs (invalidate messages) received",
|
|
22
|
+
unit: "{reorgs}",
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
currentBlockGauge,
|
|
27
|
+
processedBlockCounter,
|
|
28
|
+
reorgCounter,
|
|
29
|
+
};
|
|
30
|
+
}
|
package/src/testing/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createClient } from "@apibara/protocol";
|
|
2
2
|
import ci from "ci-info";
|
|
3
|
+
import { useIndexerContext } from "../context";
|
|
3
4
|
import { type IndexerWithStreamConfig, createIndexer } from "../indexer";
|
|
4
5
|
import { type InternalContext, internalContext } from "../plugins/context";
|
|
5
6
|
import { logger } from "../plugins/logger";
|
|
@@ -8,7 +9,11 @@ import { isCassetteAvailable } from "../vcr/helper";
|
|
|
8
9
|
import { record } from "../vcr/record";
|
|
9
10
|
import { replay } from "../vcr/replay";
|
|
10
11
|
|
|
12
|
+
export type VcrResult = Record<string, unknown>;
|
|
13
|
+
|
|
11
14
|
export function createVcr() {
|
|
15
|
+
let result: VcrResult;
|
|
16
|
+
|
|
12
17
|
return {
|
|
13
18
|
async run<TFilter, TBlock>(
|
|
14
19
|
cassetteName: string,
|
|
@@ -40,6 +45,10 @@ export function createVcr() {
|
|
|
40
45
|
|
|
41
46
|
const indexer = createIndexer(indexerConfig);
|
|
42
47
|
|
|
48
|
+
indexer.hooks.hook("run:after", () => {
|
|
49
|
+
result = useIndexerContext();
|
|
50
|
+
});
|
|
51
|
+
|
|
43
52
|
if (!isCassetteAvailable(vcrConfig, cassetteName)) {
|
|
44
53
|
if (ci.isCI) {
|
|
45
54
|
throw new Error("Cannot record cassette in CI");
|
|
@@ -53,6 +62,8 @@ export function createVcr() {
|
|
|
53
62
|
} else {
|
|
54
63
|
await replay(vcrConfig, indexer, cassetteName);
|
|
55
64
|
}
|
|
65
|
+
|
|
66
|
+
return result;
|
|
56
67
|
},
|
|
57
68
|
};
|
|
58
69
|
}
|