@apibara/indexer 2.0.0-beta.3 → 2.0.0-beta.31
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 +270 -0
- package/dist/index.d.cts +3 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.mjs +259 -0
- package/dist/internal/testing.cjs +109 -0
- package/dist/internal/testing.d.cts +40 -0
- package/dist/internal/testing.d.mts +40 -0
- package/dist/internal/testing.d.ts +40 -0
- package/dist/internal/testing.mjs +104 -0
- package/dist/plugins/index.cjs +43 -0
- package/dist/plugins/index.d.cts +18 -0
- package/dist/plugins/index.d.mts +18 -0
- package/dist/plugins/index.d.ts +18 -0
- package/dist/plugins/index.mjs +38 -0
- 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.8939ecc8.d.cts +91 -0
- package/dist/shared/indexer.8939ecc8.d.mts +91 -0
- package/dist/shared/indexer.8939ecc8.d.ts +91 -0
- package/dist/shared/indexer.9b21ddd2.mjs +5 -0
- package/dist/shared/indexer.a55ad619.mjs +12 -0
- package/dist/shared/indexer.ff25c953.mjs +26 -0
- package/dist/testing/index.cjs +58 -0
- package/dist/testing/index.d.cts +12 -0
- package/dist/testing/index.d.mts +12 -0
- package/dist/testing/index.d.ts +12 -0
- package/dist/testing/index.mjs +52 -0
- package/dist/vcr/index.cjs +92 -0
- package/dist/vcr/index.d.cts +27 -0
- package/dist/vcr/index.d.mts +27 -0
- package/dist/vcr/index.d.ts +27 -0
- package/dist/vcr/index.mjs +78 -0
- package/package.json +31 -41
- 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 +109 -186
- package/src/indexer.ts +244 -144
- package/src/internal/testing.ts +135 -0
- package/src/plugins/config.ts +4 -4
- 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 +50 -3
- package/src/vcr/record.ts +6 -4
- package/src/vcr/replay.ts +8 -18
- 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 -39
- 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 -36
- 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
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { a as IndexerPlugin, b as IndexerConfig, c as Indexer } from '../shared/indexer.8939ecc8.mjs';
|
|
2
|
+
import { MockStreamResponse, MockFilter, MockBlock } from '@apibara/protocol/testing';
|
|
3
|
+
import '@apibara/protocol';
|
|
4
|
+
import 'hookable';
|
|
5
|
+
|
|
6
|
+
type MockMessagesOptions = {
|
|
7
|
+
invalidate?: {
|
|
8
|
+
invalidateFromIndex: number;
|
|
9
|
+
invalidateTriggerIndex: number;
|
|
10
|
+
};
|
|
11
|
+
finalize?: {
|
|
12
|
+
finalizeToIndex: number;
|
|
13
|
+
finalizeTriggerIndex: number;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
declare function generateMockMessages(count?: number, options?: MockMessagesOptions): MockStreamResponse[];
|
|
17
|
+
declare function getMockIndexer({ plugins, override, }?: {
|
|
18
|
+
plugins?: ReadonlyArray<IndexerPlugin<MockFilter, MockBlock>>;
|
|
19
|
+
override?: Partial<IndexerConfig<MockFilter, MockBlock>>;
|
|
20
|
+
}): Indexer<{
|
|
21
|
+
readonly filter?: string | undefined;
|
|
22
|
+
}, {
|
|
23
|
+
readonly data?: string | undefined;
|
|
24
|
+
}>;
|
|
25
|
+
type MockRet = {
|
|
26
|
+
data: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* A mock sink used for testing. The indexer function can write to the output array.
|
|
30
|
+
* The indexer context is optionally written to the metadata object.
|
|
31
|
+
*/
|
|
32
|
+
declare function mockSink<TFilter, TBlock>({ output, metadata, }: {
|
|
33
|
+
output: unknown[];
|
|
34
|
+
metadata?: Record<string, unknown>;
|
|
35
|
+
}): IndexerPlugin<TFilter, TBlock>;
|
|
36
|
+
declare function useMockSink(): {
|
|
37
|
+
output: unknown[];
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export { type MockMessagesOptions, type MockRet, generateMockMessages, getMockIndexer, mockSink, useMockSink };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { a as IndexerPlugin, b as IndexerConfig, c as Indexer } from '../shared/indexer.8939ecc8.js';
|
|
2
|
+
import { MockStreamResponse, MockFilter, MockBlock } from '@apibara/protocol/testing';
|
|
3
|
+
import '@apibara/protocol';
|
|
4
|
+
import 'hookable';
|
|
5
|
+
|
|
6
|
+
type MockMessagesOptions = {
|
|
7
|
+
invalidate?: {
|
|
8
|
+
invalidateFromIndex: number;
|
|
9
|
+
invalidateTriggerIndex: number;
|
|
10
|
+
};
|
|
11
|
+
finalize?: {
|
|
12
|
+
finalizeToIndex: number;
|
|
13
|
+
finalizeTriggerIndex: number;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
declare function generateMockMessages(count?: number, options?: MockMessagesOptions): MockStreamResponse[];
|
|
17
|
+
declare function getMockIndexer({ plugins, override, }?: {
|
|
18
|
+
plugins?: ReadonlyArray<IndexerPlugin<MockFilter, MockBlock>>;
|
|
19
|
+
override?: Partial<IndexerConfig<MockFilter, MockBlock>>;
|
|
20
|
+
}): Indexer<{
|
|
21
|
+
readonly filter?: string | undefined;
|
|
22
|
+
}, {
|
|
23
|
+
readonly data?: string | undefined;
|
|
24
|
+
}>;
|
|
25
|
+
type MockRet = {
|
|
26
|
+
data: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* A mock sink used for testing. The indexer function can write to the output array.
|
|
30
|
+
* The indexer context is optionally written to the metadata object.
|
|
31
|
+
*/
|
|
32
|
+
declare function mockSink<TFilter, TBlock>({ output, metadata, }: {
|
|
33
|
+
output: unknown[];
|
|
34
|
+
metadata?: Record<string, unknown>;
|
|
35
|
+
}): IndexerPlugin<TFilter, TBlock>;
|
|
36
|
+
declare function useMockSink(): {
|
|
37
|
+
output: unknown[];
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export { type MockMessagesOptions, type MockRet, generateMockMessages, getMockIndexer, mockSink, useMockSink };
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { isCursor } from '@apibara/protocol';
|
|
2
|
+
import { MockStream } from '@apibara/protocol/testing';
|
|
3
|
+
import { u as useIndexerContext } from '../shared/indexer.a55ad619.mjs';
|
|
4
|
+
import { createIndexer, defineIndexer } from '../index.mjs';
|
|
5
|
+
import { d as defineIndexerPlugin } from '../shared/indexer.9b21ddd2.mjs';
|
|
6
|
+
import 'consola';
|
|
7
|
+
import 'node:async_hooks';
|
|
8
|
+
import 'unctx';
|
|
9
|
+
import 'hookable';
|
|
10
|
+
import 'node:assert';
|
|
11
|
+
import '@opentelemetry/api';
|
|
12
|
+
|
|
13
|
+
function generateMockMessages(count = 10, options) {
|
|
14
|
+
const invalidateAt = options?.invalidate;
|
|
15
|
+
const finalizeAt = options?.finalize;
|
|
16
|
+
const messages = [];
|
|
17
|
+
for (let i = 0; i < count; i++) {
|
|
18
|
+
if (invalidateAt && i === invalidateAt.invalidateTriggerIndex) {
|
|
19
|
+
messages.push({
|
|
20
|
+
_tag: "invalidate",
|
|
21
|
+
invalidate: {
|
|
22
|
+
cursor: {
|
|
23
|
+
orderKey: BigInt(5e6 + invalidateAt.invalidateFromIndex)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
} else if (finalizeAt && i === finalizeAt.finalizeTriggerIndex) {
|
|
28
|
+
messages.push({
|
|
29
|
+
_tag: "finalize",
|
|
30
|
+
finalize: {
|
|
31
|
+
cursor: {
|
|
32
|
+
orderKey: BigInt(5e6 + finalizeAt.finalizeToIndex)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
} else {
|
|
37
|
+
messages.push({
|
|
38
|
+
_tag: "data",
|
|
39
|
+
data: {
|
|
40
|
+
cursor: { orderKey: BigInt(5e6 + i - 1) },
|
|
41
|
+
finality: "accepted",
|
|
42
|
+
data: [{ data: `${5e6 + i}` }],
|
|
43
|
+
endCursor: { orderKey: BigInt(5e6 + i) }
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return messages;
|
|
49
|
+
}
|
|
50
|
+
function getMockIndexer({
|
|
51
|
+
plugins,
|
|
52
|
+
override
|
|
53
|
+
} = {}) {
|
|
54
|
+
return createIndexer(
|
|
55
|
+
defineIndexer(MockStream)({
|
|
56
|
+
streamUrl: "https://sepolia.ethereum.a5a.ch",
|
|
57
|
+
finality: "accepted",
|
|
58
|
+
filter: {},
|
|
59
|
+
async transform({ block: { data }, context }) {
|
|
60
|
+
},
|
|
61
|
+
plugins,
|
|
62
|
+
...override
|
|
63
|
+
})
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
function mockSink({
|
|
67
|
+
output,
|
|
68
|
+
metadata
|
|
69
|
+
}) {
|
|
70
|
+
return defineIndexerPlugin((indexer) => {
|
|
71
|
+
indexer.hooks.hook("connect:before", ({ request }) => {
|
|
72
|
+
if (metadata?.lastCursor && isCursor(metadata.lastCursor)) {
|
|
73
|
+
request.startingCursor = metadata.lastCursor;
|
|
74
|
+
}
|
|
75
|
+
if (metadata?.lastFilter) {
|
|
76
|
+
request.filter[1] = metadata.lastFilter;
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
indexer.hooks.hook("connect:factory", ({ request, endCursor }) => {
|
|
80
|
+
if (request.filter[1]) {
|
|
81
|
+
if (metadata) {
|
|
82
|
+
metadata.lastCursor = endCursor;
|
|
83
|
+
metadata.lastFilter = request.filter[1];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
indexer.hooks.hook("handler:middleware", ({ use }) => {
|
|
88
|
+
use(async (context, next) => {
|
|
89
|
+
context.output = output;
|
|
90
|
+
await next();
|
|
91
|
+
context.output = null;
|
|
92
|
+
if (metadata) {
|
|
93
|
+
metadata.lastCursor = context.endCursor;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
function useMockSink() {
|
|
100
|
+
const context = useIndexerContext();
|
|
101
|
+
return { output: context.output };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export { generateMockMessages, getMockIndexer, mockSink, useMockSink };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const config = require('../shared/indexer.601ceab0.cjs');
|
|
4
|
+
const logger = require('../shared/indexer.2416906c.cjs');
|
|
5
|
+
const protocol = require('@apibara/protocol');
|
|
6
|
+
require('consola');
|
|
7
|
+
require('../shared/indexer.077335f3.cjs');
|
|
8
|
+
require('node:async_hooks');
|
|
9
|
+
require('unctx');
|
|
10
|
+
|
|
11
|
+
function inMemoryPersistence() {
|
|
12
|
+
return config.defineIndexerPlugin((indexer) => {
|
|
13
|
+
let lastCursor;
|
|
14
|
+
let lastFilter;
|
|
15
|
+
indexer.hooks.hook("connect:before", ({ request }) => {
|
|
16
|
+
if (lastCursor) {
|
|
17
|
+
request.startingCursor = lastCursor;
|
|
18
|
+
}
|
|
19
|
+
if (lastFilter) {
|
|
20
|
+
request.filter[1] = lastFilter;
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
indexer.hooks.hook("connect:factory", ({ request, endCursor }) => {
|
|
24
|
+
if (request.filter[1]) {
|
|
25
|
+
lastCursor = endCursor;
|
|
26
|
+
lastFilter = request.filter[1];
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
indexer.hooks.hook("handler:middleware", ({ use }) => {
|
|
30
|
+
use(async (context, next) => {
|
|
31
|
+
await next();
|
|
32
|
+
if (context.endCursor && protocol.isCursor(context.endCursor)) {
|
|
33
|
+
lastCursor = context.endCursor;
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
exports.defineIndexerPlugin = config.defineIndexerPlugin;
|
|
41
|
+
exports.logger = logger.logger;
|
|
42
|
+
exports.useLogger = logger.useLogger;
|
|
43
|
+
exports.inMemoryPersistence = inMemoryPersistence;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { a as IndexerPlugin } from '../shared/indexer.8939ecc8.cjs';
|
|
2
|
+
export { d as defineIndexerPlugin } from '../shared/indexer.8939ecc8.cjs';
|
|
3
|
+
import { ConsolaReporter, ConsolaInstance } from 'consola';
|
|
4
|
+
export { ConsolaInstance, ConsolaReporter } from 'consola';
|
|
5
|
+
import '@apibara/protocol';
|
|
6
|
+
import 'hookable';
|
|
7
|
+
|
|
8
|
+
declare function logger<TFilter, TBlock, TTxnParams>({ logger, }?: {
|
|
9
|
+
logger?: ConsolaReporter;
|
|
10
|
+
}): IndexerPlugin<TFilter, TBlock>;
|
|
11
|
+
declare function useLogger(): ConsolaInstance;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A plugin that persists the last cursor and filter to memory.
|
|
15
|
+
*/
|
|
16
|
+
declare function inMemoryPersistence<TFilter, TBlock>(): IndexerPlugin<TFilter, TBlock>;
|
|
17
|
+
|
|
18
|
+
export { IndexerPlugin, inMemoryPersistence, logger, useLogger };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { a as IndexerPlugin } from '../shared/indexer.8939ecc8.mjs';
|
|
2
|
+
export { d as defineIndexerPlugin } from '../shared/indexer.8939ecc8.mjs';
|
|
3
|
+
import { ConsolaReporter, ConsolaInstance } from 'consola';
|
|
4
|
+
export { ConsolaInstance, ConsolaReporter } from 'consola';
|
|
5
|
+
import '@apibara/protocol';
|
|
6
|
+
import 'hookable';
|
|
7
|
+
|
|
8
|
+
declare function logger<TFilter, TBlock, TTxnParams>({ logger, }?: {
|
|
9
|
+
logger?: ConsolaReporter;
|
|
10
|
+
}): IndexerPlugin<TFilter, TBlock>;
|
|
11
|
+
declare function useLogger(): ConsolaInstance;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A plugin that persists the last cursor and filter to memory.
|
|
15
|
+
*/
|
|
16
|
+
declare function inMemoryPersistence<TFilter, TBlock>(): IndexerPlugin<TFilter, TBlock>;
|
|
17
|
+
|
|
18
|
+
export { IndexerPlugin, inMemoryPersistence, logger, useLogger };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { a as IndexerPlugin } from '../shared/indexer.8939ecc8.js';
|
|
2
|
+
export { d as defineIndexerPlugin } from '../shared/indexer.8939ecc8.js';
|
|
3
|
+
import { ConsolaReporter, ConsolaInstance } from 'consola';
|
|
4
|
+
export { ConsolaInstance, ConsolaReporter } from 'consola';
|
|
5
|
+
import '@apibara/protocol';
|
|
6
|
+
import 'hookable';
|
|
7
|
+
|
|
8
|
+
declare function logger<TFilter, TBlock, TTxnParams>({ logger, }?: {
|
|
9
|
+
logger?: ConsolaReporter;
|
|
10
|
+
}): IndexerPlugin<TFilter, TBlock>;
|
|
11
|
+
declare function useLogger(): ConsolaInstance;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* A plugin that persists the last cursor and filter to memory.
|
|
15
|
+
*/
|
|
16
|
+
declare function inMemoryPersistence<TFilter, TBlock>(): IndexerPlugin<TFilter, TBlock>;
|
|
17
|
+
|
|
18
|
+
export { IndexerPlugin, inMemoryPersistence, logger, useLogger };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { d as defineIndexerPlugin } from '../shared/indexer.9b21ddd2.mjs';
|
|
2
|
+
export { l as logger, u as useLogger } from '../shared/indexer.ff25c953.mjs';
|
|
3
|
+
import { isCursor } from '@apibara/protocol';
|
|
4
|
+
import 'consola';
|
|
5
|
+
import '../shared/indexer.a55ad619.mjs';
|
|
6
|
+
import 'node:async_hooks';
|
|
7
|
+
import 'unctx';
|
|
8
|
+
|
|
9
|
+
function inMemoryPersistence() {
|
|
10
|
+
return defineIndexerPlugin((indexer) => {
|
|
11
|
+
let lastCursor;
|
|
12
|
+
let lastFilter;
|
|
13
|
+
indexer.hooks.hook("connect:before", ({ request }) => {
|
|
14
|
+
if (lastCursor) {
|
|
15
|
+
request.startingCursor = lastCursor;
|
|
16
|
+
}
|
|
17
|
+
if (lastFilter) {
|
|
18
|
+
request.filter[1] = lastFilter;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
indexer.hooks.hook("connect:factory", ({ request, endCursor }) => {
|
|
22
|
+
if (request.filter[1]) {
|
|
23
|
+
lastCursor = endCursor;
|
|
24
|
+
lastFilter = request.filter[1];
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
indexer.hooks.hook("handler:middleware", ({ use }) => {
|
|
28
|
+
use(async (context, next) => {
|
|
29
|
+
await next();
|
|
30
|
+
if (context.endCursor && isCursor(context.endCursor)) {
|
|
31
|
+
lastCursor = context.endCursor;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export { defineIndexerPlugin, inMemoryPersistence };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const node_async_hooks = require('node:async_hooks');
|
|
4
|
+
const unctx = require('unctx');
|
|
5
|
+
|
|
6
|
+
const indexerAsyncContext = unctx.getContext("indexer", {
|
|
7
|
+
asyncContext: true,
|
|
8
|
+
AsyncLocalStorage: node_async_hooks.AsyncLocalStorage
|
|
9
|
+
});
|
|
10
|
+
function useIndexerContext() {
|
|
11
|
+
return indexerAsyncContext.use();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
exports.indexerAsyncContext = indexerAsyncContext;
|
|
15
|
+
exports.useIndexerContext = useIndexerContext;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const consola = require('consola');
|
|
4
|
+
const context = require('./indexer.077335f3.cjs');
|
|
5
|
+
const config = require('./indexer.601ceab0.cjs');
|
|
6
|
+
|
|
7
|
+
function logger({
|
|
8
|
+
logger: logger2
|
|
9
|
+
} = {}) {
|
|
10
|
+
return config.defineIndexerPlugin((indexer) => {
|
|
11
|
+
indexer.hooks.hook("run:before", () => {
|
|
12
|
+
const ctx = context.useIndexerContext();
|
|
13
|
+
if (logger2) {
|
|
14
|
+
ctx.logger = consola.consola.create({ reporters: [logger2] });
|
|
15
|
+
} else {
|
|
16
|
+
ctx.logger = consola.consola.create({});
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function useLogger() {
|
|
22
|
+
const ctx = context.useIndexerContext();
|
|
23
|
+
if (!ctx?.logger)
|
|
24
|
+
throw new Error("Logger plugin is not available in context");
|
|
25
|
+
return ctx.logger;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
exports.logger = logger;
|
|
29
|
+
exports.useLogger = useLogger;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { StreamDataRequest, StreamDataOptions, Cursor, StreamDataResponse, Invalidate, Finalize, Heartbeat, SystemMessage, DataFinality, StreamConfig, Client } from '@apibara/protocol';
|
|
2
|
+
import { NestedHooks, Hookable } from 'hookable';
|
|
3
|
+
|
|
4
|
+
interface IndexerContext extends Record<string, any> {
|
|
5
|
+
}
|
|
6
|
+
declare function useIndexerContext(): IndexerContext;
|
|
7
|
+
|
|
8
|
+
type NextFunction = () => Promise<void>;
|
|
9
|
+
type MiddlewareFunction<C> = (context: C, next: NextFunction) => Promise<void>;
|
|
10
|
+
|
|
11
|
+
type IndexerPlugin<TFilter, TBlock> = (indexer: Indexer<TFilter, TBlock>) => void;
|
|
12
|
+
declare function defineIndexerPlugin<TFilter, TBlock>(def: IndexerPlugin<TFilter, TBlock>): IndexerPlugin<TFilter, TBlock>;
|
|
13
|
+
|
|
14
|
+
type UseMiddlewareFunction = (fn: MiddlewareFunction<IndexerContext>) => void;
|
|
15
|
+
interface IndexerHooks<TFilter, TBlock> {
|
|
16
|
+
"run:before": () => void;
|
|
17
|
+
"run:after": () => void;
|
|
18
|
+
"connect:before": ({ request, options, }: {
|
|
19
|
+
request: StreamDataRequest<TFilter>;
|
|
20
|
+
options: StreamDataOptions;
|
|
21
|
+
}) => void;
|
|
22
|
+
"connect:after": ({ request, }: {
|
|
23
|
+
request: StreamDataRequest<TFilter>;
|
|
24
|
+
}) => void;
|
|
25
|
+
"connect:factory": ({ request, endCursor, }: {
|
|
26
|
+
request: StreamDataRequest<TFilter>;
|
|
27
|
+
endCursor?: Cursor;
|
|
28
|
+
}) => void;
|
|
29
|
+
"handler:middleware": ({ use }: {
|
|
30
|
+
use: UseMiddlewareFunction;
|
|
31
|
+
}) => void;
|
|
32
|
+
message: ({ message }: {
|
|
33
|
+
message: StreamDataResponse<TBlock>;
|
|
34
|
+
}) => void;
|
|
35
|
+
"message:invalidate": ({ message }: {
|
|
36
|
+
message: Invalidate;
|
|
37
|
+
}) => void;
|
|
38
|
+
"message:finalize": ({ message }: {
|
|
39
|
+
message: Finalize;
|
|
40
|
+
}) => void;
|
|
41
|
+
"message:heartbeat": ({ message }: {
|
|
42
|
+
message: Heartbeat;
|
|
43
|
+
}) => void;
|
|
44
|
+
"message:systemMessage": ({ message }: {
|
|
45
|
+
message: SystemMessage;
|
|
46
|
+
}) => void;
|
|
47
|
+
}
|
|
48
|
+
interface IndexerConfig<TFilter, TBlock> {
|
|
49
|
+
streamUrl: string;
|
|
50
|
+
filter: TFilter;
|
|
51
|
+
finality?: DataFinality;
|
|
52
|
+
startingCursor?: Cursor;
|
|
53
|
+
factory?: ({ block, context, }: {
|
|
54
|
+
block: TBlock;
|
|
55
|
+
context: IndexerContext;
|
|
56
|
+
}) => Promise<{
|
|
57
|
+
filter?: TFilter;
|
|
58
|
+
}>;
|
|
59
|
+
transform: (args: {
|
|
60
|
+
block: TBlock;
|
|
61
|
+
cursor?: Cursor | undefined;
|
|
62
|
+
endCursor?: Cursor | undefined;
|
|
63
|
+
finality: DataFinality;
|
|
64
|
+
context: IndexerContext;
|
|
65
|
+
}) => Promise<void>;
|
|
66
|
+
hooks?: NestedHooks<IndexerHooks<TFilter, TBlock>>;
|
|
67
|
+
plugins?: ReadonlyArray<IndexerPlugin<TFilter, TBlock>>;
|
|
68
|
+
debug?: boolean;
|
|
69
|
+
}
|
|
70
|
+
interface IndexerWithStreamConfig<TFilter, TBlock> extends IndexerConfig<TFilter, TBlock> {
|
|
71
|
+
streamConfig: StreamConfig<TFilter, TBlock>;
|
|
72
|
+
}
|
|
73
|
+
declare function defineIndexer<TFilter, TBlock>(streamConfig: StreamConfig<TFilter, TBlock>): (config: IndexerConfig<TFilter, TBlock>) => IndexerWithStreamConfig<TFilter, TBlock>;
|
|
74
|
+
interface Indexer<TFilter, TBlock> {
|
|
75
|
+
streamConfig: StreamConfig<TFilter, TBlock>;
|
|
76
|
+
options: IndexerConfig<TFilter, TBlock>;
|
|
77
|
+
hooks: Hookable<IndexerHooks<TFilter, TBlock>>;
|
|
78
|
+
}
|
|
79
|
+
declare function createIndexer<TFilter, TBlock>({ streamConfig, ...options }: IndexerWithStreamConfig<TFilter, TBlock>): Indexer<TFilter, TBlock>;
|
|
80
|
+
interface ReconnectOptions {
|
|
81
|
+
maxRetries?: number;
|
|
82
|
+
retryDelay?: number;
|
|
83
|
+
maxWait?: number;
|
|
84
|
+
}
|
|
85
|
+
declare function runWithReconnect<TFilter, TBlock>(client: Client<TFilter, TBlock>, indexer: Indexer<TFilter, TBlock>, options?: ReconnectOptions): Promise<void>;
|
|
86
|
+
interface RunOptions {
|
|
87
|
+
onConnect?: () => void | Promise<void>;
|
|
88
|
+
}
|
|
89
|
+
declare function run<TFilter, TBlock>(client: Client<TFilter, TBlock>, indexer: Indexer<TFilter, TBlock>, runOptions?: RunOptions): Promise<void>;
|
|
90
|
+
|
|
91
|
+
export { type IndexerWithStreamConfig as I, type ReconnectOptions as R, type UseMiddlewareFunction as U, type IndexerPlugin as a, type IndexerConfig as b, type Indexer as c, defineIndexerPlugin as d, type IndexerHooks as e, defineIndexer as f, createIndexer as g, type RunOptions as h, run as i, runWithReconnect as r, useIndexerContext as u };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { StreamDataRequest, StreamDataOptions, Cursor, StreamDataResponse, Invalidate, Finalize, Heartbeat, SystemMessage, DataFinality, StreamConfig, Client } from '@apibara/protocol';
|
|
2
|
+
import { NestedHooks, Hookable } from 'hookable';
|
|
3
|
+
|
|
4
|
+
interface IndexerContext extends Record<string, any> {
|
|
5
|
+
}
|
|
6
|
+
declare function useIndexerContext(): IndexerContext;
|
|
7
|
+
|
|
8
|
+
type NextFunction = () => Promise<void>;
|
|
9
|
+
type MiddlewareFunction<C> = (context: C, next: NextFunction) => Promise<void>;
|
|
10
|
+
|
|
11
|
+
type IndexerPlugin<TFilter, TBlock> = (indexer: Indexer<TFilter, TBlock>) => void;
|
|
12
|
+
declare function defineIndexerPlugin<TFilter, TBlock>(def: IndexerPlugin<TFilter, TBlock>): IndexerPlugin<TFilter, TBlock>;
|
|
13
|
+
|
|
14
|
+
type UseMiddlewareFunction = (fn: MiddlewareFunction<IndexerContext>) => void;
|
|
15
|
+
interface IndexerHooks<TFilter, TBlock> {
|
|
16
|
+
"run:before": () => void;
|
|
17
|
+
"run:after": () => void;
|
|
18
|
+
"connect:before": ({ request, options, }: {
|
|
19
|
+
request: StreamDataRequest<TFilter>;
|
|
20
|
+
options: StreamDataOptions;
|
|
21
|
+
}) => void;
|
|
22
|
+
"connect:after": ({ request, }: {
|
|
23
|
+
request: StreamDataRequest<TFilter>;
|
|
24
|
+
}) => void;
|
|
25
|
+
"connect:factory": ({ request, endCursor, }: {
|
|
26
|
+
request: StreamDataRequest<TFilter>;
|
|
27
|
+
endCursor?: Cursor;
|
|
28
|
+
}) => void;
|
|
29
|
+
"handler:middleware": ({ use }: {
|
|
30
|
+
use: UseMiddlewareFunction;
|
|
31
|
+
}) => void;
|
|
32
|
+
message: ({ message }: {
|
|
33
|
+
message: StreamDataResponse<TBlock>;
|
|
34
|
+
}) => void;
|
|
35
|
+
"message:invalidate": ({ message }: {
|
|
36
|
+
message: Invalidate;
|
|
37
|
+
}) => void;
|
|
38
|
+
"message:finalize": ({ message }: {
|
|
39
|
+
message: Finalize;
|
|
40
|
+
}) => void;
|
|
41
|
+
"message:heartbeat": ({ message }: {
|
|
42
|
+
message: Heartbeat;
|
|
43
|
+
}) => void;
|
|
44
|
+
"message:systemMessage": ({ message }: {
|
|
45
|
+
message: SystemMessage;
|
|
46
|
+
}) => void;
|
|
47
|
+
}
|
|
48
|
+
interface IndexerConfig<TFilter, TBlock> {
|
|
49
|
+
streamUrl: string;
|
|
50
|
+
filter: TFilter;
|
|
51
|
+
finality?: DataFinality;
|
|
52
|
+
startingCursor?: Cursor;
|
|
53
|
+
factory?: ({ block, context, }: {
|
|
54
|
+
block: TBlock;
|
|
55
|
+
context: IndexerContext;
|
|
56
|
+
}) => Promise<{
|
|
57
|
+
filter?: TFilter;
|
|
58
|
+
}>;
|
|
59
|
+
transform: (args: {
|
|
60
|
+
block: TBlock;
|
|
61
|
+
cursor?: Cursor | undefined;
|
|
62
|
+
endCursor?: Cursor | undefined;
|
|
63
|
+
finality: DataFinality;
|
|
64
|
+
context: IndexerContext;
|
|
65
|
+
}) => Promise<void>;
|
|
66
|
+
hooks?: NestedHooks<IndexerHooks<TFilter, TBlock>>;
|
|
67
|
+
plugins?: ReadonlyArray<IndexerPlugin<TFilter, TBlock>>;
|
|
68
|
+
debug?: boolean;
|
|
69
|
+
}
|
|
70
|
+
interface IndexerWithStreamConfig<TFilter, TBlock> extends IndexerConfig<TFilter, TBlock> {
|
|
71
|
+
streamConfig: StreamConfig<TFilter, TBlock>;
|
|
72
|
+
}
|
|
73
|
+
declare function defineIndexer<TFilter, TBlock>(streamConfig: StreamConfig<TFilter, TBlock>): (config: IndexerConfig<TFilter, TBlock>) => IndexerWithStreamConfig<TFilter, TBlock>;
|
|
74
|
+
interface Indexer<TFilter, TBlock> {
|
|
75
|
+
streamConfig: StreamConfig<TFilter, TBlock>;
|
|
76
|
+
options: IndexerConfig<TFilter, TBlock>;
|
|
77
|
+
hooks: Hookable<IndexerHooks<TFilter, TBlock>>;
|
|
78
|
+
}
|
|
79
|
+
declare function createIndexer<TFilter, TBlock>({ streamConfig, ...options }: IndexerWithStreamConfig<TFilter, TBlock>): Indexer<TFilter, TBlock>;
|
|
80
|
+
interface ReconnectOptions {
|
|
81
|
+
maxRetries?: number;
|
|
82
|
+
retryDelay?: number;
|
|
83
|
+
maxWait?: number;
|
|
84
|
+
}
|
|
85
|
+
declare function runWithReconnect<TFilter, TBlock>(client: Client<TFilter, TBlock>, indexer: Indexer<TFilter, TBlock>, options?: ReconnectOptions): Promise<void>;
|
|
86
|
+
interface RunOptions {
|
|
87
|
+
onConnect?: () => void | Promise<void>;
|
|
88
|
+
}
|
|
89
|
+
declare function run<TFilter, TBlock>(client: Client<TFilter, TBlock>, indexer: Indexer<TFilter, TBlock>, runOptions?: RunOptions): Promise<void>;
|
|
90
|
+
|
|
91
|
+
export { type IndexerWithStreamConfig as I, type ReconnectOptions as R, type UseMiddlewareFunction as U, type IndexerPlugin as a, type IndexerConfig as b, type Indexer as c, defineIndexerPlugin as d, type IndexerHooks as e, defineIndexer as f, createIndexer as g, type RunOptions as h, run as i, runWithReconnect as r, useIndexerContext as u };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { StreamDataRequest, StreamDataOptions, Cursor, StreamDataResponse, Invalidate, Finalize, Heartbeat, SystemMessage, DataFinality, StreamConfig, Client } from '@apibara/protocol';
|
|
2
|
+
import { NestedHooks, Hookable } from 'hookable';
|
|
3
|
+
|
|
4
|
+
interface IndexerContext extends Record<string, any> {
|
|
5
|
+
}
|
|
6
|
+
declare function useIndexerContext(): IndexerContext;
|
|
7
|
+
|
|
8
|
+
type NextFunction = () => Promise<void>;
|
|
9
|
+
type MiddlewareFunction<C> = (context: C, next: NextFunction) => Promise<void>;
|
|
10
|
+
|
|
11
|
+
type IndexerPlugin<TFilter, TBlock> = (indexer: Indexer<TFilter, TBlock>) => void;
|
|
12
|
+
declare function defineIndexerPlugin<TFilter, TBlock>(def: IndexerPlugin<TFilter, TBlock>): IndexerPlugin<TFilter, TBlock>;
|
|
13
|
+
|
|
14
|
+
type UseMiddlewareFunction = (fn: MiddlewareFunction<IndexerContext>) => void;
|
|
15
|
+
interface IndexerHooks<TFilter, TBlock> {
|
|
16
|
+
"run:before": () => void;
|
|
17
|
+
"run:after": () => void;
|
|
18
|
+
"connect:before": ({ request, options, }: {
|
|
19
|
+
request: StreamDataRequest<TFilter>;
|
|
20
|
+
options: StreamDataOptions;
|
|
21
|
+
}) => void;
|
|
22
|
+
"connect:after": ({ request, }: {
|
|
23
|
+
request: StreamDataRequest<TFilter>;
|
|
24
|
+
}) => void;
|
|
25
|
+
"connect:factory": ({ request, endCursor, }: {
|
|
26
|
+
request: StreamDataRequest<TFilter>;
|
|
27
|
+
endCursor?: Cursor;
|
|
28
|
+
}) => void;
|
|
29
|
+
"handler:middleware": ({ use }: {
|
|
30
|
+
use: UseMiddlewareFunction;
|
|
31
|
+
}) => void;
|
|
32
|
+
message: ({ message }: {
|
|
33
|
+
message: StreamDataResponse<TBlock>;
|
|
34
|
+
}) => void;
|
|
35
|
+
"message:invalidate": ({ message }: {
|
|
36
|
+
message: Invalidate;
|
|
37
|
+
}) => void;
|
|
38
|
+
"message:finalize": ({ message }: {
|
|
39
|
+
message: Finalize;
|
|
40
|
+
}) => void;
|
|
41
|
+
"message:heartbeat": ({ message }: {
|
|
42
|
+
message: Heartbeat;
|
|
43
|
+
}) => void;
|
|
44
|
+
"message:systemMessage": ({ message }: {
|
|
45
|
+
message: SystemMessage;
|
|
46
|
+
}) => void;
|
|
47
|
+
}
|
|
48
|
+
interface IndexerConfig<TFilter, TBlock> {
|
|
49
|
+
streamUrl: string;
|
|
50
|
+
filter: TFilter;
|
|
51
|
+
finality?: DataFinality;
|
|
52
|
+
startingCursor?: Cursor;
|
|
53
|
+
factory?: ({ block, context, }: {
|
|
54
|
+
block: TBlock;
|
|
55
|
+
context: IndexerContext;
|
|
56
|
+
}) => Promise<{
|
|
57
|
+
filter?: TFilter;
|
|
58
|
+
}>;
|
|
59
|
+
transform: (args: {
|
|
60
|
+
block: TBlock;
|
|
61
|
+
cursor?: Cursor | undefined;
|
|
62
|
+
endCursor?: Cursor | undefined;
|
|
63
|
+
finality: DataFinality;
|
|
64
|
+
context: IndexerContext;
|
|
65
|
+
}) => Promise<void>;
|
|
66
|
+
hooks?: NestedHooks<IndexerHooks<TFilter, TBlock>>;
|
|
67
|
+
plugins?: ReadonlyArray<IndexerPlugin<TFilter, TBlock>>;
|
|
68
|
+
debug?: boolean;
|
|
69
|
+
}
|
|
70
|
+
interface IndexerWithStreamConfig<TFilter, TBlock> extends IndexerConfig<TFilter, TBlock> {
|
|
71
|
+
streamConfig: StreamConfig<TFilter, TBlock>;
|
|
72
|
+
}
|
|
73
|
+
declare function defineIndexer<TFilter, TBlock>(streamConfig: StreamConfig<TFilter, TBlock>): (config: IndexerConfig<TFilter, TBlock>) => IndexerWithStreamConfig<TFilter, TBlock>;
|
|
74
|
+
interface Indexer<TFilter, TBlock> {
|
|
75
|
+
streamConfig: StreamConfig<TFilter, TBlock>;
|
|
76
|
+
options: IndexerConfig<TFilter, TBlock>;
|
|
77
|
+
hooks: Hookable<IndexerHooks<TFilter, TBlock>>;
|
|
78
|
+
}
|
|
79
|
+
declare function createIndexer<TFilter, TBlock>({ streamConfig, ...options }: IndexerWithStreamConfig<TFilter, TBlock>): Indexer<TFilter, TBlock>;
|
|
80
|
+
interface ReconnectOptions {
|
|
81
|
+
maxRetries?: number;
|
|
82
|
+
retryDelay?: number;
|
|
83
|
+
maxWait?: number;
|
|
84
|
+
}
|
|
85
|
+
declare function runWithReconnect<TFilter, TBlock>(client: Client<TFilter, TBlock>, indexer: Indexer<TFilter, TBlock>, options?: ReconnectOptions): Promise<void>;
|
|
86
|
+
interface RunOptions {
|
|
87
|
+
onConnect?: () => void | Promise<void>;
|
|
88
|
+
}
|
|
89
|
+
declare function run<TFilter, TBlock>(client: Client<TFilter, TBlock>, indexer: Indexer<TFilter, TBlock>, runOptions?: RunOptions): Promise<void>;
|
|
90
|
+
|
|
91
|
+
export { type IndexerWithStreamConfig as I, type ReconnectOptions as R, type UseMiddlewareFunction as U, type IndexerPlugin as a, type IndexerConfig as b, type Indexer as c, defineIndexerPlugin as d, type IndexerHooks as e, defineIndexer as f, createIndexer as g, type RunOptions as h, run as i, runWithReconnect as r, useIndexerContext as u };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { getContext } from 'unctx';
|
|
3
|
+
|
|
4
|
+
const indexerAsyncContext = getContext("indexer", {
|
|
5
|
+
asyncContext: true,
|
|
6
|
+
AsyncLocalStorage
|
|
7
|
+
});
|
|
8
|
+
function useIndexerContext() {
|
|
9
|
+
return indexerAsyncContext.use();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { indexerAsyncContext as i, useIndexerContext as u };
|