@apibara/indexer 2.0.0-beta.9 → 2.1.0-beta.10
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 +271 -39
- package/dist/index.d.cts +1 -16
- package/dist/index.d.mts +1 -16
- package/dist/index.d.ts +1 -16
- package/dist/index.mjs +262 -25
- package/dist/internal/index.cjs +10 -0
- package/dist/internal/index.d.cts +3 -0
- package/dist/internal/index.d.mts +3 -0
- package/dist/internal/index.d.ts +3 -0
- package/dist/internal/index.mjs +8 -0
- package/dist/internal/plugins.cjs +38 -0
- package/dist/internal/plugins.d.cts +13 -0
- package/dist/internal/plugins.d.mts +13 -0
- package/dist/internal/plugins.d.ts +13 -0
- package/dist/internal/plugins.mjs +34 -0
- package/dist/internal/testing.cjs +120 -0
- package/dist/internal/testing.d.cts +42 -0
- package/dist/internal/testing.d.mts +42 -0
- package/dist/internal/testing.d.ts +42 -0
- package/dist/internal/testing.mjs +115 -0
- package/dist/plugins/index.cjs +39 -3
- package/dist/plugins/index.d.cts +16 -2
- package/dist/plugins/index.d.mts +16 -2
- package/dist/plugins/index.d.ts +16 -2
- package/dist/plugins/index.mjs +36 -3
- package/dist/shared/indexer.077335f3.cjs +15 -0
- package/dist/shared/indexer.2416906c.cjs +29 -0
- package/dist/shared/indexer.601ceab0.cjs +7 -0
- package/dist/shared/indexer.9b21ddd2.mjs +5 -0
- package/dist/shared/indexer.a55ad619.mjs +12 -0
- package/dist/shared/indexer.fedcd831.d.cts +100 -0
- package/dist/shared/indexer.fedcd831.d.mts +100 -0
- package/dist/shared/indexer.fedcd831.d.ts +100 -0
- package/dist/shared/indexer.ff25c953.mjs +26 -0
- package/dist/testing/index.cjs +56 -49
- package/dist/testing/index.d.cts +9 -36
- package/dist/testing/index.d.mts +9 -36
- package/dist/testing/index.d.ts +9 -36
- package/dist/testing/index.mjs +51 -46
- package/dist/vcr/index.cjs +84 -17
- package/dist/vcr/index.d.cts +16 -7
- package/dist/vcr/index.d.mts +16 -7
- package/dist/vcr/index.d.ts +16 -7
- package/dist/vcr/index.mjs +75 -11
- package/package.json +22 -42
- package/src/compose.test.ts +76 -0
- package/src/compose.ts +71 -0
- package/src/context.ts +14 -8
- package/src/index.ts +0 -5
- package/src/indexer.test.ts +125 -186
- package/src/indexer.ts +278 -151
- package/src/internal/index.ts +6 -0
- package/src/internal/plugins.ts +1 -0
- package/src/internal/testing.ts +148 -0
- package/src/plugins/config.ts +4 -4
- package/src/plugins/context.ts +40 -0
- package/src/plugins/index.ts +8 -1
- package/src/plugins/logger.ts +30 -0
- package/src/plugins/persistence.ts +24 -187
- package/src/testing/index.ts +69 -3
- package/src/vcr/record.ts +5 -3
- package/src/vcr/replay.ts +8 -18
- package/dist/plugins/kv.cjs +0 -131
- package/dist/plugins/kv.d.cts +0 -32
- package/dist/plugins/kv.d.mts +0 -32
- package/dist/plugins/kv.d.ts +0 -32
- package/dist/plugins/kv.mjs +0 -124
- package/dist/plugins/persistence.cjs +0 -182
- package/dist/plugins/persistence.d.cts +0 -50
- package/dist/plugins/persistence.d.mts +0 -50
- package/dist/plugins/persistence.d.ts +0 -50
- package/dist/plugins/persistence.mjs +0 -179
- package/dist/shared/indexer.2c23c9cd.mjs +0 -35
- package/dist/shared/indexer.318d3617.cjs +0 -47
- package/dist/shared/indexer.36530330.mjs +0 -249
- package/dist/shared/indexer.500fd281.d.cts +0 -23
- package/dist/shared/indexer.541d43eb.cjs +0 -266
- package/dist/shared/indexer.93d6b2eb.mjs +0 -17
- package/dist/shared/indexer.a8b7ab1f.cjs +0 -25
- package/dist/shared/indexer.b9c8f0d8.d.cts +0 -19
- package/dist/shared/indexer.b9c8f0d8.d.mts +0 -19
- package/dist/shared/indexer.b9c8f0d8.d.ts +0 -19
- package/dist/shared/indexer.c7ed6b83.d.cts +0 -82
- package/dist/shared/indexer.e1856641.d.mts +0 -23
- package/dist/shared/indexer.e4f2430f.d.ts +0 -23
- package/dist/shared/indexer.e8bd138d.d.mts +0 -82
- package/dist/shared/indexer.f761abcd.d.ts +0 -82
- package/dist/sinks/csv.cjs +0 -85
- package/dist/sinks/csv.d.cts +0 -66
- package/dist/sinks/csv.d.mts +0 -66
- package/dist/sinks/csv.d.ts +0 -66
- package/dist/sinks/csv.mjs +0 -78
- package/dist/sinks/drizzle/index.cjs +0 -212
- package/dist/sinks/drizzle/index.d.cts +0 -153
- package/dist/sinks/drizzle/index.d.mts +0 -153
- package/dist/sinks/drizzle/index.d.ts +0 -153
- package/dist/sinks/drizzle/index.mjs +0 -198
- package/dist/sinks/sqlite.cjs +0 -90
- package/dist/sinks/sqlite.d.cts +0 -71
- package/dist/sinks/sqlite.d.mts +0 -71
- package/dist/sinks/sqlite.d.ts +0 -71
- package/dist/sinks/sqlite.mjs +0 -87
- package/src/hooks/index.ts +0 -2
- package/src/hooks/useKVStore.ts +0 -12
- package/src/hooks/useSink.ts +0 -13
- package/src/plugins/kv.test.ts +0 -120
- package/src/plugins/kv.ts +0 -132
- package/src/plugins/persistence.test.ts +0 -151
- package/src/sink.ts +0 -36
- package/src/sinks/csv.test.ts +0 -65
- package/src/sinks/csv.ts +0 -159
- package/src/sinks/drizzle/Int8Range.ts +0 -52
- package/src/sinks/drizzle/delete.ts +0 -42
- package/src/sinks/drizzle/drizzle.test.ts +0 -239
- package/src/sinks/drizzle/drizzle.ts +0 -115
- package/src/sinks/drizzle/index.ts +0 -6
- package/src/sinks/drizzle/insert.ts +0 -42
- package/src/sinks/drizzle/select.ts +0 -44
- package/src/sinks/drizzle/transaction.ts +0 -49
- package/src/sinks/drizzle/update.ts +0 -47
- package/src/sinks/drizzle/utils.ts +0 -99
- package/src/sinks/sqlite.test.ts +0 -99
- package/src/sinks/sqlite.ts +0 -170
- package/src/testing/helper.ts +0 -13
- package/src/testing/indexer.ts +0 -35
- package/src/testing/setup.ts +0 -59
- package/src/testing/vcr.ts +0 -54
package/dist/index.cjs
CHANGED
|
@@ -1,50 +1,282 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
require('
|
|
8
|
-
require('
|
|
9
|
-
require('klona/full');
|
|
10
|
-
require('consola');
|
|
11
|
-
require('hookable');
|
|
12
|
-
require('node:assert');
|
|
13
|
-
require('node:fs');
|
|
14
|
-
require('@apibara/protocol/testing');
|
|
3
|
+
const protocol = require('@apibara/protocol');
|
|
4
|
+
const consola = require('consola');
|
|
5
|
+
const hookable = require('hookable');
|
|
6
|
+
const assert = require('node:assert');
|
|
7
|
+
const context = require('./shared/indexer.077335f3.cjs');
|
|
8
|
+
const api = require('@opentelemetry/api');
|
|
15
9
|
require('node:async_hooks');
|
|
16
10
|
require('unctx');
|
|
17
|
-
require('@opentelemetry/api');
|
|
18
11
|
|
|
19
|
-
function
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
12
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
13
|
+
|
|
14
|
+
const consola__default = /*#__PURE__*/_interopDefaultCompat(consola);
|
|
15
|
+
const assert__default = /*#__PURE__*/_interopDefaultCompat(assert);
|
|
16
|
+
|
|
17
|
+
function compose(middleware) {
|
|
18
|
+
return (context, next) => {
|
|
19
|
+
let index = -1;
|
|
20
|
+
return dispatch(0);
|
|
21
|
+
async function dispatch(i) {
|
|
22
|
+
if (i <= index) {
|
|
23
|
+
throw new Error("next() called multiple times");
|
|
24
|
+
}
|
|
25
|
+
index = i;
|
|
26
|
+
let handler;
|
|
27
|
+
if (i >= middleware.length) {
|
|
28
|
+
if (next) {
|
|
29
|
+
await next();
|
|
30
|
+
}
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (middleware[i]) {
|
|
34
|
+
handler = middleware[i];
|
|
35
|
+
} else {
|
|
36
|
+
handler = i === middleware.length ? next : void 0;
|
|
37
|
+
}
|
|
38
|
+
if (!handler) {
|
|
39
|
+
throw new Error("Handler not found");
|
|
40
|
+
}
|
|
41
|
+
await handler(context, () => dispatch(i + 1));
|
|
42
|
+
}
|
|
43
|
+
};
|
|
24
44
|
}
|
|
25
45
|
|
|
26
|
-
|
|
27
|
-
|
|
46
|
+
const tracer = api.trace.getTracer("@apibara/indexer");
|
|
47
|
+
|
|
48
|
+
function defineIndexer(streamConfig) {
|
|
49
|
+
return (config) => ({
|
|
50
|
+
streamConfig,
|
|
51
|
+
...config
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function createIndexer({
|
|
55
|
+
streamConfig,
|
|
56
|
+
...options
|
|
28
57
|
}) {
|
|
29
|
-
|
|
30
|
-
|
|
58
|
+
const indexer = {
|
|
59
|
+
options,
|
|
60
|
+
streamConfig,
|
|
61
|
+
hooks: hookable.createHooks()
|
|
62
|
+
};
|
|
63
|
+
if (indexer.options.debug) {
|
|
64
|
+
hookable.createDebugger(indexer.hooks, { tag: "indexer" });
|
|
65
|
+
}
|
|
66
|
+
indexer.hooks.addHooks(indexer.options.hooks ?? {});
|
|
67
|
+
for (const plugin of indexer.options.plugins ?? []) {
|
|
68
|
+
plugin(indexer);
|
|
31
69
|
}
|
|
32
|
-
return
|
|
70
|
+
return indexer;
|
|
71
|
+
}
|
|
72
|
+
async function runWithReconnect(client, indexer, options = {}) {
|
|
73
|
+
let retryCount = 0;
|
|
74
|
+
const maxRetries = options.maxRetries ?? 10;
|
|
75
|
+
const retryDelay = options.retryDelay ?? 1e3;
|
|
76
|
+
const maxWait = options.maxWait ?? 3e4;
|
|
77
|
+
const runOptions = {
|
|
78
|
+
onConnect() {
|
|
79
|
+
retryCount = 0;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
while (true) {
|
|
83
|
+
try {
|
|
84
|
+
await run(client, indexer, runOptions);
|
|
85
|
+
return;
|
|
86
|
+
} catch (error) {
|
|
87
|
+
retryCount++;
|
|
88
|
+
if (error instanceof protocol.ClientError) {
|
|
89
|
+
if (error.code === protocol.Status.INTERNAL) {
|
|
90
|
+
if (retryCount < maxRetries) {
|
|
91
|
+
consola__default.error(
|
|
92
|
+
"Internal server error, reconnecting...",
|
|
93
|
+
error.message
|
|
94
|
+
);
|
|
95
|
+
const delay = Math.random() * (retryDelay * 0.2) + retryDelay;
|
|
96
|
+
await new Promise(
|
|
97
|
+
(resolve) => setTimeout(resolve, Math.min(retryCount * delay, maxWait))
|
|
98
|
+
);
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async function run(client, indexer, runOptions = {}) {
|
|
108
|
+
await context.indexerAsyncContext.callAsync({}, async () => {
|
|
109
|
+
const context$1 = context.useIndexerContext();
|
|
110
|
+
const middleware = await registerMiddleware(indexer);
|
|
111
|
+
await indexer.hooks.callHook("run:before");
|
|
112
|
+
const isFactoryMode = indexer.options.factory !== void 0;
|
|
113
|
+
let startingCursor;
|
|
114
|
+
if (indexer.options.startingCursor) {
|
|
115
|
+
startingCursor = indexer.options.startingCursor;
|
|
116
|
+
} else if (indexer.options.startingBlock !== void 0) {
|
|
117
|
+
if (indexer.options.startingBlock === 0n) {
|
|
118
|
+
startingCursor = void 0;
|
|
119
|
+
} else if (indexer.options.startingBlock > 0n) {
|
|
120
|
+
startingCursor = {
|
|
121
|
+
orderKey: indexer.options.startingBlock - 1n
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const request = indexer.streamConfig.Request.make({
|
|
126
|
+
filter: isFactoryMode ? [indexer.options.filter, {}] : [indexer.options.filter],
|
|
127
|
+
finality: indexer.options.finality,
|
|
128
|
+
startingCursor
|
|
129
|
+
});
|
|
130
|
+
const options = {};
|
|
131
|
+
await indexer.hooks.callHook("connect:before", { request, options });
|
|
132
|
+
let mainFilter;
|
|
133
|
+
if (isFactoryMode) {
|
|
134
|
+
mainFilter = request.filter[1];
|
|
135
|
+
}
|
|
136
|
+
let stream = client.streamData(request, options)[Symbol.asyncIterator]();
|
|
137
|
+
await indexer.hooks.callHook("connect:after", { request });
|
|
138
|
+
let onConnectCalled = false;
|
|
139
|
+
while (true) {
|
|
140
|
+
const { value: message, done } = await stream.next();
|
|
141
|
+
if (done) {
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
if (!onConnectCalled) {
|
|
145
|
+
onConnectCalled = true;
|
|
146
|
+
if (runOptions.onConnect) {
|
|
147
|
+
await runOptions.onConnect();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
await indexer.hooks.callHook("message", { message });
|
|
151
|
+
switch (message._tag) {
|
|
152
|
+
case "data": {
|
|
153
|
+
await tracer.startActiveSpan("message data", async (span) => {
|
|
154
|
+
const blocks = message.data.data;
|
|
155
|
+
const { cursor, endCursor, finality } = message.data;
|
|
156
|
+
context$1.cursor = cursor;
|
|
157
|
+
context$1.endCursor = endCursor;
|
|
158
|
+
context$1.finality = finality;
|
|
159
|
+
await middleware(context$1, async () => {
|
|
160
|
+
let block;
|
|
161
|
+
if (isFactoryMode) {
|
|
162
|
+
assert__default(indexer.options.factory !== void 0);
|
|
163
|
+
const [factoryBlock, mainBlock] = blocks;
|
|
164
|
+
block = mainBlock;
|
|
165
|
+
if (factoryBlock !== null) {
|
|
166
|
+
const { filter } = await indexer.options.factory({
|
|
167
|
+
block: factoryBlock,
|
|
168
|
+
context: context$1
|
|
169
|
+
});
|
|
170
|
+
if (filter) {
|
|
171
|
+
mainFilter = indexer.streamConfig.mergeFilter(
|
|
172
|
+
mainFilter,
|
|
173
|
+
filter
|
|
174
|
+
);
|
|
175
|
+
const request2 = indexer.streamConfig.Request.make({
|
|
176
|
+
filter: [indexer.options.filter, mainFilter],
|
|
177
|
+
finality: indexer.options.finality,
|
|
178
|
+
startingCursor: cursor
|
|
179
|
+
});
|
|
180
|
+
await indexer.hooks.callHook("connect:factory", {
|
|
181
|
+
request: request2,
|
|
182
|
+
endCursor
|
|
183
|
+
});
|
|
184
|
+
stream = client.streamData(request2, options)[Symbol.asyncIterator]();
|
|
185
|
+
const { value: message2 } = await stream.next();
|
|
186
|
+
assert__default(message2._tag === "data");
|
|
187
|
+
const [_factoryBlock, _block] = message2.data.data;
|
|
188
|
+
block = _block;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
} else {
|
|
192
|
+
block = blocks[0];
|
|
193
|
+
}
|
|
194
|
+
if (block) {
|
|
195
|
+
await tracer.startActiveSpan("handler", async (span2) => {
|
|
196
|
+
await indexer.options.transform({
|
|
197
|
+
block,
|
|
198
|
+
cursor,
|
|
199
|
+
endCursor,
|
|
200
|
+
finality,
|
|
201
|
+
context: context$1
|
|
202
|
+
});
|
|
203
|
+
span2.end();
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
span.end();
|
|
208
|
+
});
|
|
209
|
+
context$1.cursor = void 0;
|
|
210
|
+
context$1.endCursor = void 0;
|
|
211
|
+
context$1.finality = void 0;
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
case "invalidate": {
|
|
215
|
+
await tracer.startActiveSpan("message invalidate", async (span) => {
|
|
216
|
+
await indexer.hooks.callHook("message:invalidate", { message });
|
|
217
|
+
span.end();
|
|
218
|
+
});
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
case "finalize": {
|
|
222
|
+
await tracer.startActiveSpan("message finalize", async (span) => {
|
|
223
|
+
await indexer.hooks.callHook("message:finalize", { message });
|
|
224
|
+
span.end();
|
|
225
|
+
});
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
case "heartbeat": {
|
|
229
|
+
await tracer.startActiveSpan("message heartbeat", async (span) => {
|
|
230
|
+
await indexer.hooks.callHook("message:heartbeat", { message });
|
|
231
|
+
span.end();
|
|
232
|
+
});
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
case "systemMessage": {
|
|
236
|
+
await tracer.startActiveSpan(
|
|
237
|
+
"message systemMessage",
|
|
238
|
+
async (span) => {
|
|
239
|
+
switch (message.systemMessage.output?._tag) {
|
|
240
|
+
case "stderr": {
|
|
241
|
+
consola__default.warn(message.systemMessage.output.stderr);
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
case "stdout": {
|
|
245
|
+
consola__default.info(message.systemMessage.output.stdout);
|
|
246
|
+
break;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
await indexer.hooks.callHook("message:systemMessage", {
|
|
250
|
+
message
|
|
251
|
+
});
|
|
252
|
+
span.end();
|
|
253
|
+
}
|
|
254
|
+
);
|
|
255
|
+
break;
|
|
256
|
+
}
|
|
257
|
+
default: {
|
|
258
|
+
consola__default.warn("unexpected message", message);
|
|
259
|
+
throw new Error("not implemented");
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
await indexer.hooks.callHook("run:after");
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
async function registerMiddleware(indexer) {
|
|
267
|
+
const middleware = [];
|
|
268
|
+
const use = (fn) => {
|
|
269
|
+
middleware.push(fn);
|
|
270
|
+
};
|
|
271
|
+
await indexer.hooks.callHook("handler:middleware", { use });
|
|
272
|
+
const composed = compose(middleware);
|
|
273
|
+
return async function _composedIndexerMiddleware(context, next) {
|
|
274
|
+
await composed(context, next);
|
|
275
|
+
};
|
|
33
276
|
}
|
|
34
277
|
|
|
35
|
-
exports.
|
|
36
|
-
exports.
|
|
37
|
-
exports.
|
|
38
|
-
exports.
|
|
39
|
-
exports.
|
|
40
|
-
exports.run = vcr_index.run;
|
|
41
|
-
exports.DefaultSink = sink.DefaultSink;
|
|
42
|
-
exports.Sink = sink.Sink;
|
|
43
|
-
exports.defaultSink = sink.defaultSink;
|
|
44
|
-
exports.deserialize = helper.deserialize;
|
|
45
|
-
exports.isCassetteAvailable = helper.isCassetteAvailable;
|
|
46
|
-
exports.serialize = helper.serialize;
|
|
47
|
-
exports.useIndexerContext = helper.useIndexerContext;
|
|
48
|
-
exports.defineIndexerPlugin = plugins_index.defineIndexerPlugin;
|
|
49
|
-
exports.useKVStore = useKVStore;
|
|
50
|
-
exports.useSink = useSink;
|
|
278
|
+
exports.useIndexerContext = context.useIndexerContext;
|
|
279
|
+
exports.createIndexer = createIndexer;
|
|
280
|
+
exports.defineIndexer = defineIndexer;
|
|
281
|
+
exports.run = run;
|
|
282
|
+
exports.runWithReconnect = runWithReconnect;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export { f as Indexer, c as IndexerConfig, b as IndexerHooks, I as IndexerPlugin, d as IndexerWithStreamConfig, g as createIndexer, e as defineIndexer, h as defineIndexerPlugin, r as run, u as useIndexerContext } from './shared/indexer.c7ed6b83.cjs';
|
|
3
|
-
export { D as DefaultSink, S as Sink, a as SinkCursorParams, b as SinkData, d as defaultSink } from './shared/indexer.b9c8f0d8.cjs';
|
|
4
|
-
export { C as CassetteOptions, V as VcrConfig, a as VcrReplayResult, l as loadCassette, r as replay } from './shared/indexer.500fd281.cjs';
|
|
5
|
-
export { CassetteDataType, deserialize, isCassetteAvailable, record, serialize } from './vcr/index.cjs';
|
|
6
|
-
import { KVStore } from './plugins/kv.cjs';
|
|
1
|
+
export { a as Indexer, c as IndexerConfig, e as IndexerHooks, f as IndexerStartingCursor, I as IndexerWithStreamConfig, R as ReconnectOptions, i as RunOptions, U as UseMiddlewareFunction, h as createIndexer, g as defineIndexer, j as run, r as runWithReconnect, u as useIndexerContext } from './shared/indexer.fedcd831.cjs';
|
|
7
2
|
import '@apibara/protocol';
|
|
8
3
|
import 'hookable';
|
|
9
|
-
import 'better-sqlite3';
|
|
10
|
-
|
|
11
|
-
type UseKVStoreResult = InstanceType<typeof KVStore>;
|
|
12
|
-
declare function useKVStore(): UseKVStoreResult;
|
|
13
|
-
|
|
14
|
-
declare function useSink<TTxnParams>({ context, }: {
|
|
15
|
-
context: IndexerContext<TTxnParams>;
|
|
16
|
-
}): NonNullable<TTxnParams>;
|
|
17
|
-
|
|
18
|
-
export { type UseKVStoreResult, useKVStore, useSink };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export { f as Indexer, c as IndexerConfig, b as IndexerHooks, I as IndexerPlugin, d as IndexerWithStreamConfig, g as createIndexer, e as defineIndexer, h as defineIndexerPlugin, r as run, u as useIndexerContext } from './shared/indexer.e8bd138d.mjs';
|
|
3
|
-
export { D as DefaultSink, S as Sink, a as SinkCursorParams, b as SinkData, d as defaultSink } from './shared/indexer.b9c8f0d8.mjs';
|
|
4
|
-
export { C as CassetteOptions, V as VcrConfig, a as VcrReplayResult, l as loadCassette, r as replay } from './shared/indexer.e1856641.mjs';
|
|
5
|
-
export { CassetteDataType, deserialize, isCassetteAvailable, record, serialize } from './vcr/index.mjs';
|
|
6
|
-
import { KVStore } from './plugins/kv.mjs';
|
|
1
|
+
export { a as Indexer, c as IndexerConfig, e as IndexerHooks, f as IndexerStartingCursor, I as IndexerWithStreamConfig, R as ReconnectOptions, i as RunOptions, U as UseMiddlewareFunction, h as createIndexer, g as defineIndexer, j as run, r as runWithReconnect, u as useIndexerContext } from './shared/indexer.fedcd831.mjs';
|
|
7
2
|
import '@apibara/protocol';
|
|
8
3
|
import 'hookable';
|
|
9
|
-
import 'better-sqlite3';
|
|
10
|
-
|
|
11
|
-
type UseKVStoreResult = InstanceType<typeof KVStore>;
|
|
12
|
-
declare function useKVStore(): UseKVStoreResult;
|
|
13
|
-
|
|
14
|
-
declare function useSink<TTxnParams>({ context, }: {
|
|
15
|
-
context: IndexerContext<TTxnParams>;
|
|
16
|
-
}): NonNullable<TTxnParams>;
|
|
17
|
-
|
|
18
|
-
export { type UseKVStoreResult, useKVStore, useSink };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export { f as Indexer, c as IndexerConfig, b as IndexerHooks, I as IndexerPlugin, d as IndexerWithStreamConfig, g as createIndexer, e as defineIndexer, h as defineIndexerPlugin, r as run, u as useIndexerContext } from './shared/indexer.f761abcd.js';
|
|
3
|
-
export { D as DefaultSink, S as Sink, a as SinkCursorParams, b as SinkData, d as defaultSink } from './shared/indexer.b9c8f0d8.js';
|
|
4
|
-
export { C as CassetteOptions, V as VcrConfig, a as VcrReplayResult, l as loadCassette, r as replay } from './shared/indexer.e4f2430f.js';
|
|
5
|
-
export { CassetteDataType, deserialize, isCassetteAvailable, record, serialize } from './vcr/index.js';
|
|
6
|
-
import { KVStore } from './plugins/kv.js';
|
|
1
|
+
export { a as Indexer, c as IndexerConfig, e as IndexerHooks, f as IndexerStartingCursor, I as IndexerWithStreamConfig, R as ReconnectOptions, i as RunOptions, U as UseMiddlewareFunction, h as createIndexer, g as defineIndexer, j as run, r as runWithReconnect, u as useIndexerContext } from './shared/indexer.fedcd831.js';
|
|
7
2
|
import '@apibara/protocol';
|
|
8
3
|
import 'hookable';
|
|
9
|
-
import 'better-sqlite3';
|
|
10
|
-
|
|
11
|
-
type UseKVStoreResult = InstanceType<typeof KVStore>;
|
|
12
|
-
declare function useKVStore(): UseKVStoreResult;
|
|
13
|
-
|
|
14
|
-
declare function useSink<TTxnParams>({ context, }: {
|
|
15
|
-
context: IndexerContext<TTxnParams>;
|
|
16
|
-
}): NonNullable<TTxnParams>;
|
|
17
|
-
|
|
18
|
-
export { type UseKVStoreResult, useKVStore, useSink };
|
package/dist/index.mjs
CHANGED
|
@@ -1,34 +1,271 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import '
|
|
7
|
-
import 'node:path';
|
|
8
|
-
import 'klona/full';
|
|
9
|
-
import 'consola';
|
|
10
|
-
import 'hookable';
|
|
11
|
-
import 'node:assert';
|
|
12
|
-
import 'node:fs';
|
|
13
|
-
import '@apibara/protocol/testing';
|
|
1
|
+
import { ClientError, Status } from '@apibara/protocol';
|
|
2
|
+
import consola from 'consola';
|
|
3
|
+
import { createHooks, createDebugger } from 'hookable';
|
|
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';
|
|
14
7
|
import 'node:async_hooks';
|
|
15
8
|
import 'unctx';
|
|
16
|
-
import '@opentelemetry/api';
|
|
17
9
|
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
10
|
+
function compose(middleware) {
|
|
11
|
+
return (context, next) => {
|
|
12
|
+
let index = -1;
|
|
13
|
+
return dispatch(0);
|
|
14
|
+
async function dispatch(i) {
|
|
15
|
+
if (i <= index) {
|
|
16
|
+
throw new Error("next() called multiple times");
|
|
17
|
+
}
|
|
18
|
+
index = i;
|
|
19
|
+
let handler;
|
|
20
|
+
if (i >= middleware.length) {
|
|
21
|
+
if (next) {
|
|
22
|
+
await next();
|
|
23
|
+
}
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (middleware[i]) {
|
|
27
|
+
handler = middleware[i];
|
|
28
|
+
} else {
|
|
29
|
+
handler = i === middleware.length ? next : void 0;
|
|
30
|
+
}
|
|
31
|
+
if (!handler) {
|
|
32
|
+
throw new Error("Handler not found");
|
|
33
|
+
}
|
|
34
|
+
await handler(context, () => dispatch(i + 1));
|
|
35
|
+
}
|
|
36
|
+
};
|
|
23
37
|
}
|
|
24
38
|
|
|
25
|
-
|
|
26
|
-
|
|
39
|
+
const tracer = trace.getTracer("@apibara/indexer");
|
|
40
|
+
|
|
41
|
+
function defineIndexer(streamConfig) {
|
|
42
|
+
return (config) => ({
|
|
43
|
+
streamConfig,
|
|
44
|
+
...config
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function createIndexer({
|
|
48
|
+
streamConfig,
|
|
49
|
+
...options
|
|
27
50
|
}) {
|
|
28
|
-
|
|
29
|
-
|
|
51
|
+
const indexer = {
|
|
52
|
+
options,
|
|
53
|
+
streamConfig,
|
|
54
|
+
hooks: createHooks()
|
|
55
|
+
};
|
|
56
|
+
if (indexer.options.debug) {
|
|
57
|
+
createDebugger(indexer.hooks, { tag: "indexer" });
|
|
30
58
|
}
|
|
31
|
-
|
|
59
|
+
indexer.hooks.addHooks(indexer.options.hooks ?? {});
|
|
60
|
+
for (const plugin of indexer.options.plugins ?? []) {
|
|
61
|
+
plugin(indexer);
|
|
62
|
+
}
|
|
63
|
+
return indexer;
|
|
64
|
+
}
|
|
65
|
+
async function runWithReconnect(client, indexer, options = {}) {
|
|
66
|
+
let retryCount = 0;
|
|
67
|
+
const maxRetries = options.maxRetries ?? 10;
|
|
68
|
+
const retryDelay = options.retryDelay ?? 1e3;
|
|
69
|
+
const maxWait = options.maxWait ?? 3e4;
|
|
70
|
+
const runOptions = {
|
|
71
|
+
onConnect() {
|
|
72
|
+
retryCount = 0;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
while (true) {
|
|
76
|
+
try {
|
|
77
|
+
await run(client, indexer, runOptions);
|
|
78
|
+
return;
|
|
79
|
+
} catch (error) {
|
|
80
|
+
retryCount++;
|
|
81
|
+
if (error instanceof ClientError) {
|
|
82
|
+
if (error.code === Status.INTERNAL) {
|
|
83
|
+
if (retryCount < maxRetries) {
|
|
84
|
+
consola.error(
|
|
85
|
+
"Internal server error, reconnecting...",
|
|
86
|
+
error.message
|
|
87
|
+
);
|
|
88
|
+
const delay = Math.random() * (retryDelay * 0.2) + retryDelay;
|
|
89
|
+
await new Promise(
|
|
90
|
+
(resolve) => setTimeout(resolve, Math.min(retryCount * delay, maxWait))
|
|
91
|
+
);
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
async function run(client, indexer, runOptions = {}) {
|
|
101
|
+
await indexerAsyncContext.callAsync({}, async () => {
|
|
102
|
+
const context = useIndexerContext();
|
|
103
|
+
const middleware = await registerMiddleware(indexer);
|
|
104
|
+
await indexer.hooks.callHook("run:before");
|
|
105
|
+
const isFactoryMode = indexer.options.factory !== void 0;
|
|
106
|
+
let startingCursor;
|
|
107
|
+
if (indexer.options.startingCursor) {
|
|
108
|
+
startingCursor = indexer.options.startingCursor;
|
|
109
|
+
} else if (indexer.options.startingBlock !== void 0) {
|
|
110
|
+
if (indexer.options.startingBlock === 0n) {
|
|
111
|
+
startingCursor = void 0;
|
|
112
|
+
} else if (indexer.options.startingBlock > 0n) {
|
|
113
|
+
startingCursor = {
|
|
114
|
+
orderKey: indexer.options.startingBlock - 1n
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const request = indexer.streamConfig.Request.make({
|
|
119
|
+
filter: isFactoryMode ? [indexer.options.filter, {}] : [indexer.options.filter],
|
|
120
|
+
finality: indexer.options.finality,
|
|
121
|
+
startingCursor
|
|
122
|
+
});
|
|
123
|
+
const options = {};
|
|
124
|
+
await indexer.hooks.callHook("connect:before", { request, options });
|
|
125
|
+
let mainFilter;
|
|
126
|
+
if (isFactoryMode) {
|
|
127
|
+
mainFilter = request.filter[1];
|
|
128
|
+
}
|
|
129
|
+
let stream = client.streamData(request, options)[Symbol.asyncIterator]();
|
|
130
|
+
await indexer.hooks.callHook("connect:after", { request });
|
|
131
|
+
let onConnectCalled = false;
|
|
132
|
+
while (true) {
|
|
133
|
+
const { value: message, done } = await stream.next();
|
|
134
|
+
if (done) {
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
if (!onConnectCalled) {
|
|
138
|
+
onConnectCalled = true;
|
|
139
|
+
if (runOptions.onConnect) {
|
|
140
|
+
await runOptions.onConnect();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
await indexer.hooks.callHook("message", { message });
|
|
144
|
+
switch (message._tag) {
|
|
145
|
+
case "data": {
|
|
146
|
+
await tracer.startActiveSpan("message data", async (span) => {
|
|
147
|
+
const blocks = message.data.data;
|
|
148
|
+
const { cursor, endCursor, finality } = message.data;
|
|
149
|
+
context.cursor = cursor;
|
|
150
|
+
context.endCursor = endCursor;
|
|
151
|
+
context.finality = finality;
|
|
152
|
+
await middleware(context, async () => {
|
|
153
|
+
let block;
|
|
154
|
+
if (isFactoryMode) {
|
|
155
|
+
assert(indexer.options.factory !== void 0);
|
|
156
|
+
const [factoryBlock, mainBlock] = blocks;
|
|
157
|
+
block = mainBlock;
|
|
158
|
+
if (factoryBlock !== null) {
|
|
159
|
+
const { filter } = await indexer.options.factory({
|
|
160
|
+
block: factoryBlock,
|
|
161
|
+
context
|
|
162
|
+
});
|
|
163
|
+
if (filter) {
|
|
164
|
+
mainFilter = indexer.streamConfig.mergeFilter(
|
|
165
|
+
mainFilter,
|
|
166
|
+
filter
|
|
167
|
+
);
|
|
168
|
+
const request2 = indexer.streamConfig.Request.make({
|
|
169
|
+
filter: [indexer.options.filter, mainFilter],
|
|
170
|
+
finality: indexer.options.finality,
|
|
171
|
+
startingCursor: cursor
|
|
172
|
+
});
|
|
173
|
+
await indexer.hooks.callHook("connect:factory", {
|
|
174
|
+
request: request2,
|
|
175
|
+
endCursor
|
|
176
|
+
});
|
|
177
|
+
stream = client.streamData(request2, options)[Symbol.asyncIterator]();
|
|
178
|
+
const { value: message2 } = await stream.next();
|
|
179
|
+
assert(message2._tag === "data");
|
|
180
|
+
const [_factoryBlock, _block] = message2.data.data;
|
|
181
|
+
block = _block;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
block = blocks[0];
|
|
186
|
+
}
|
|
187
|
+
if (block) {
|
|
188
|
+
await tracer.startActiveSpan("handler", async (span2) => {
|
|
189
|
+
await indexer.options.transform({
|
|
190
|
+
block,
|
|
191
|
+
cursor,
|
|
192
|
+
endCursor,
|
|
193
|
+
finality,
|
|
194
|
+
context
|
|
195
|
+
});
|
|
196
|
+
span2.end();
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
span.end();
|
|
201
|
+
});
|
|
202
|
+
context.cursor = void 0;
|
|
203
|
+
context.endCursor = void 0;
|
|
204
|
+
context.finality = void 0;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
case "invalidate": {
|
|
208
|
+
await tracer.startActiveSpan("message invalidate", async (span) => {
|
|
209
|
+
await indexer.hooks.callHook("message:invalidate", { message });
|
|
210
|
+
span.end();
|
|
211
|
+
});
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
case "finalize": {
|
|
215
|
+
await tracer.startActiveSpan("message finalize", async (span) => {
|
|
216
|
+
await indexer.hooks.callHook("message:finalize", { message });
|
|
217
|
+
span.end();
|
|
218
|
+
});
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
case "heartbeat": {
|
|
222
|
+
await tracer.startActiveSpan("message heartbeat", async (span) => {
|
|
223
|
+
await indexer.hooks.callHook("message:heartbeat", { message });
|
|
224
|
+
span.end();
|
|
225
|
+
});
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
case "systemMessage": {
|
|
229
|
+
await tracer.startActiveSpan(
|
|
230
|
+
"message systemMessage",
|
|
231
|
+
async (span) => {
|
|
232
|
+
switch (message.systemMessage.output?._tag) {
|
|
233
|
+
case "stderr": {
|
|
234
|
+
consola.warn(message.systemMessage.output.stderr);
|
|
235
|
+
break;
|
|
236
|
+
}
|
|
237
|
+
case "stdout": {
|
|
238
|
+
consola.info(message.systemMessage.output.stdout);
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
await indexer.hooks.callHook("message:systemMessage", {
|
|
243
|
+
message
|
|
244
|
+
});
|
|
245
|
+
span.end();
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
default: {
|
|
251
|
+
consola.warn("unexpected message", message);
|
|
252
|
+
throw new Error("not implemented");
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
await indexer.hooks.callHook("run:after");
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
async function registerMiddleware(indexer) {
|
|
260
|
+
const middleware = [];
|
|
261
|
+
const use = (fn) => {
|
|
262
|
+
middleware.push(fn);
|
|
263
|
+
};
|
|
264
|
+
await indexer.hooks.callHook("handler:middleware", { use });
|
|
265
|
+
const composed = compose(middleware);
|
|
266
|
+
return async function _composedIndexerMiddleware(context, next) {
|
|
267
|
+
await composed(context, next);
|
|
268
|
+
};
|
|
32
269
|
}
|
|
33
270
|
|
|
34
|
-
export {
|
|
271
|
+
export { createIndexer, defineIndexer, run, runWithReconnect, useIndexerContext };
|