@apibara/indexer 2.0.0-beta.4 → 2.0.0-beta.41
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 +278 -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 +267 -0
- 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 +118 -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 +113 -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.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 +66 -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 +60 -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 +43 -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 +125 -186
- package/src/indexer.ts +274 -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 +58 -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,78 @@
|
|
|
1
|
+
import fs$1 from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { run } from '../index.mjs';
|
|
4
|
+
import assert from 'node:assert';
|
|
5
|
+
import fs from 'node:fs';
|
|
6
|
+
import { MockClient } from '@apibara/protocol/testing';
|
|
7
|
+
import '@apibara/protocol';
|
|
8
|
+
import 'consola';
|
|
9
|
+
import 'hookable';
|
|
10
|
+
import '../shared/indexer.a55ad619.mjs';
|
|
11
|
+
import 'node:async_hooks';
|
|
12
|
+
import 'unctx';
|
|
13
|
+
import '@opentelemetry/api';
|
|
14
|
+
|
|
15
|
+
function deserialize(str) {
|
|
16
|
+
return JSON.parse(
|
|
17
|
+
str,
|
|
18
|
+
(_, value) => typeof value === "string" && value.match(/^\d+n$/) ? BigInt(value.slice(0, -1)) : value
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
function serialize(obj) {
|
|
22
|
+
return JSON.stringify(
|
|
23
|
+
obj,
|
|
24
|
+
(_, value) => typeof value === "bigint" ? `${value.toString()}n` : value,
|
|
25
|
+
" "
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
function isCassetteAvailable(vcrConfig, cassetteName) {
|
|
29
|
+
const filePath = path.join(vcrConfig.cassetteDir, `${cassetteName}.json`);
|
|
30
|
+
return fs.existsSync(filePath);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function record(vcrConfig, client, indexer, cassetteOptions) {
|
|
34
|
+
const messages = [];
|
|
35
|
+
indexer.hooks.addHooks({
|
|
36
|
+
"connect:before"({ options, request }) {
|
|
37
|
+
request.startingCursor = cassetteOptions.startingCursor;
|
|
38
|
+
options.endingCursor = cassetteOptions.endingCursor;
|
|
39
|
+
},
|
|
40
|
+
message({ message }) {
|
|
41
|
+
messages.push(message);
|
|
42
|
+
},
|
|
43
|
+
async "run:after"() {
|
|
44
|
+
const output = {
|
|
45
|
+
filter: indexer.options.filter,
|
|
46
|
+
messages
|
|
47
|
+
};
|
|
48
|
+
await fs$1.mkdir(vcrConfig.cassetteDir, { recursive: true });
|
|
49
|
+
const filePath = path.join(
|
|
50
|
+
vcrConfig.cassetteDir,
|
|
51
|
+
`${cassetteOptions.name}.json`
|
|
52
|
+
);
|
|
53
|
+
await fs$1.writeFile(filePath, serialize(output), { flag: "w" });
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
await run(client, indexer);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function replay(vcrConfig, indexer, cassetteName) {
|
|
60
|
+
const client = loadCassette(vcrConfig, cassetteName);
|
|
61
|
+
await run(client, indexer);
|
|
62
|
+
}
|
|
63
|
+
function loadCassette(vcrConfig, cassetteName) {
|
|
64
|
+
const filePath = path.join(vcrConfig.cassetteDir, `${cassetteName}.json`);
|
|
65
|
+
const data = fs.readFileSync(filePath, "utf8");
|
|
66
|
+
const cassetteData = deserialize(data);
|
|
67
|
+
const { filter, messages } = cassetteData;
|
|
68
|
+
return new MockClient((request, options) => {
|
|
69
|
+
assert.deepStrictEqual(
|
|
70
|
+
request.filter,
|
|
71
|
+
[filter],
|
|
72
|
+
"Indexer and cassette filter mismatch. Hint: delete the cassette and run again."
|
|
73
|
+
);
|
|
74
|
+
return messages;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export { deserialize, isCassetteAvailable, loadCassette, record, replay, serialize };
|
package/package.json
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@apibara/indexer",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.41",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"src",
|
|
8
|
+
"README.md"
|
|
9
|
+
],
|
|
6
10
|
"main": "./dist/index.mjs",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
7
12
|
"exports": {
|
|
8
13
|
".": {
|
|
9
14
|
"types": "./dist/index.d.ts",
|
|
@@ -11,56 +16,63 @@
|
|
|
11
16
|
"require": "./dist/index.cjs",
|
|
12
17
|
"default": "./dist/index.mjs"
|
|
13
18
|
},
|
|
14
|
-
"./sinks/sqlite": {
|
|
15
|
-
"types": "./dist/sinks/sqlite.d.ts",
|
|
16
|
-
"import": "./dist/sinks/sqlite.mjs",
|
|
17
|
-
"require": "./dist/sinks/sqlite.cjs",
|
|
18
|
-
"default": "./dist/sinks/sqlite.mjs"
|
|
19
|
-
},
|
|
20
|
-
"./sinks/csv": {
|
|
21
|
-
"types": "./dist/sinks/csv.d.ts",
|
|
22
|
-
"import": "./dist/sinks/csv.mjs",
|
|
23
|
-
"require": "./dist/sinks/csv.cjs",
|
|
24
|
-
"default": "./dist/sinks/csv.mjs"
|
|
25
|
-
},
|
|
26
|
-
"./sinks/drizzle": {
|
|
27
|
-
"types": "./dist/sinks/drizzle/index.d.ts",
|
|
28
|
-
"import": "./dist/sinks/drizzle/index.mjs",
|
|
29
|
-
"require": "./dist/sinks/drizzle/index.cjs",
|
|
30
|
-
"default": "./dist/sinks/drizzle/index.mjs"
|
|
31
|
-
},
|
|
32
19
|
"./testing": {
|
|
33
20
|
"types": "./dist/testing/index.d.ts",
|
|
34
21
|
"import": "./dist/testing/index.mjs",
|
|
35
22
|
"require": "./dist/testing/index.cjs",
|
|
36
23
|
"default": "./dist/testing/index.mjs"
|
|
24
|
+
},
|
|
25
|
+
"./vcr": {
|
|
26
|
+
"types": "./dist/vcr/index.d.ts",
|
|
27
|
+
"import": "./dist/vcr/index.mjs",
|
|
28
|
+
"require": "./dist/vcr/index.cjs",
|
|
29
|
+
"default": "./dist/vcr/index.mjs"
|
|
30
|
+
},
|
|
31
|
+
"./plugins": {
|
|
32
|
+
"types": "./dist/plugins/index.d.ts",
|
|
33
|
+
"import": "./dist/plugins/index.mjs",
|
|
34
|
+
"require": "./dist/plugins/index.cjs",
|
|
35
|
+
"default": "./dist/plugins/index.mjs"
|
|
36
|
+
},
|
|
37
|
+
"./internal": {
|
|
38
|
+
"types": "./dist/internal/index.d.ts",
|
|
39
|
+
"import": "./dist/internal/index.mjs",
|
|
40
|
+
"require": "./dist/internal/index.cjs",
|
|
41
|
+
"default": "./dist/internal/index.mjs"
|
|
42
|
+
},
|
|
43
|
+
"./internal/testing": {
|
|
44
|
+
"types": "./dist/internal/testing.d.ts",
|
|
45
|
+
"import": "./dist/internal/testing.mjs",
|
|
46
|
+
"require": "./dist/internal/testing.cjs",
|
|
47
|
+
"default": "./dist/internal/testing.mjs"
|
|
48
|
+
},
|
|
49
|
+
"./internal/plugins": {
|
|
50
|
+
"types": "./dist/internal/plugins.d.ts",
|
|
51
|
+
"import": "./dist/internal/plugins.mjs",
|
|
52
|
+
"require": "./dist/internal/plugins.cjs",
|
|
53
|
+
"default": "./dist/internal/plugins.mjs"
|
|
37
54
|
}
|
|
38
55
|
},
|
|
39
|
-
"publishConfig": {},
|
|
40
56
|
"scripts": {
|
|
41
57
|
"build": "unbuild",
|
|
42
|
-
"lint": "biome check .",
|
|
43
58
|
"typecheck": "tsc --noEmit",
|
|
59
|
+
"lint": "biome check .",
|
|
44
60
|
"lint:fix": "pnpm lint --write",
|
|
45
61
|
"test": "vitest",
|
|
46
|
-
"test:ci": "vitest run"
|
|
47
|
-
"format": "biome format . --write"
|
|
62
|
+
"test:ci": "vitest run"
|
|
48
63
|
},
|
|
49
64
|
"devDependencies": {
|
|
65
|
+
"@electric-sql/pglite": "^0.2.14",
|
|
50
66
|
"@types/better-sqlite3": "^7.6.11",
|
|
51
67
|
"@types/node": "^20.14.0",
|
|
52
68
|
"@types/pg": "^8.11.10",
|
|
53
|
-
"better-sqlite3": "^11.1.2",
|
|
54
|
-
"csv-stringify": "^6.5.0",
|
|
55
|
-
"drizzle-orm": "^0.33.0",
|
|
56
|
-
"pg": "^8.12.0",
|
|
57
|
-
"postgres-range": "^1.1.4",
|
|
58
69
|
"unbuild": "^2.0.0",
|
|
59
70
|
"vitest": "^1.6.0"
|
|
60
71
|
},
|
|
61
72
|
"dependencies": {
|
|
62
|
-
"@apibara/protocol": "2.0.0-beta.
|
|
73
|
+
"@apibara/protocol": "2.0.0-beta.41",
|
|
63
74
|
"@opentelemetry/api": "^1.9.0",
|
|
75
|
+
"ci-info": "^4.1.0",
|
|
64
76
|
"consola": "^3.2.3",
|
|
65
77
|
"hookable": "^5.5.3",
|
|
66
78
|
"klona": "^2.0.6",
|
|
@@ -68,16 +80,6 @@
|
|
|
68
80
|
"unctx": "^2.3.1"
|
|
69
81
|
},
|
|
70
82
|
"peerDependencies": {
|
|
71
|
-
"better-sqlite3": "^11.1.2",
|
|
72
|
-
"csv-stringify": "^6.5.0",
|
|
73
|
-
"drizzle-orm": "^0.33.0",
|
|
74
|
-
"postgres-range": "^1.1.4",
|
|
75
83
|
"vitest": "^1.6.0"
|
|
76
|
-
}
|
|
77
|
-
"files": [
|
|
78
|
-
"dist",
|
|
79
|
-
"src",
|
|
80
|
-
"README.md"
|
|
81
|
-
],
|
|
82
|
-
"types": "./dist/index.d.ts"
|
|
84
|
+
}
|
|
83
85
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { type MiddlewareFunction, type NextFunction, compose } from "./compose";
|
|
3
|
+
|
|
4
|
+
type C = {
|
|
5
|
+
bag: Record<string, unknown>;
|
|
6
|
+
finalized: boolean;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
type MiddlewareTuple = MiddlewareFunction<C>;
|
|
10
|
+
|
|
11
|
+
describe("compose", () => {
|
|
12
|
+
async function a(context: C, next: NextFunction) {
|
|
13
|
+
context.bag.log = "log";
|
|
14
|
+
await next();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function b(context: C, next: NextFunction) {
|
|
18
|
+
await next();
|
|
19
|
+
context.bag.headers = "custom-header";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function c(context: C, next: NextFunction) {
|
|
23
|
+
context.bag.xxx = "yyy";
|
|
24
|
+
await next();
|
|
25
|
+
context.bag.zzz = context.bag.xxx;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function handler(context: C, next: NextFunction) {
|
|
29
|
+
context.bag.log = `${context.bag.log} message`;
|
|
30
|
+
await next();
|
|
31
|
+
context.bag.message = "new response";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const middleware: MiddlewareTuple[] = [];
|
|
35
|
+
|
|
36
|
+
middleware.push(a);
|
|
37
|
+
middleware.push(b);
|
|
38
|
+
middleware.push(c);
|
|
39
|
+
middleware.push(handler);
|
|
40
|
+
|
|
41
|
+
it("composes", async () => {
|
|
42
|
+
const context: C = {
|
|
43
|
+
bag: {},
|
|
44
|
+
finalized: false,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const composed = compose<C>(middleware);
|
|
48
|
+
await composed(context);
|
|
49
|
+
|
|
50
|
+
expect(context.bag.log).toBeDefined();
|
|
51
|
+
expect(context.bag.log).toBe("log message");
|
|
52
|
+
expect(context.bag.headers).toBe("custom-header");
|
|
53
|
+
expect(context.bag.xxx).toBe("yyy");
|
|
54
|
+
expect(context.bag.zzz).toBe("yyy");
|
|
55
|
+
expect(context.finalized).toBe(false);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("accepts a next function", async () => {
|
|
59
|
+
const context: C = {
|
|
60
|
+
bag: {},
|
|
61
|
+
finalized: false,
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const composed = compose<C>(middleware);
|
|
65
|
+
await composed(context, async () => {
|
|
66
|
+
context.finalized = true;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
expect(context.bag.log).toBeDefined();
|
|
70
|
+
expect(context.bag.log).toBe("log message");
|
|
71
|
+
expect(context.bag.headers).toBe("custom-header");
|
|
72
|
+
expect(context.bag.xxx).toBe("yyy");
|
|
73
|
+
expect(context.bag.zzz).toBe("yyy");
|
|
74
|
+
expect(context.finalized).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
});
|
package/src/compose.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* MIT License
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2021 - present, Yusuke Wada and Hono contributors
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
* copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
* SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import type { IndexerContext } from "./context";
|
|
26
|
+
|
|
27
|
+
export type NextFunction = () => Promise<void>;
|
|
28
|
+
export type MiddlewareFunction<C> = (
|
|
29
|
+
context: C,
|
|
30
|
+
next: NextFunction,
|
|
31
|
+
) => Promise<void>;
|
|
32
|
+
|
|
33
|
+
export function compose<C extends IndexerContext>(
|
|
34
|
+
middleware: MiddlewareFunction<C>[],
|
|
35
|
+
): (context: C, next?: NextFunction) => Promise<void> {
|
|
36
|
+
return (context, next) => {
|
|
37
|
+
let index = -1;
|
|
38
|
+
|
|
39
|
+
return dispatch(0);
|
|
40
|
+
|
|
41
|
+
/// Dispatch the middleware functions.
|
|
42
|
+
async function dispatch(i: number): Promise<void> {
|
|
43
|
+
if (i <= index) {
|
|
44
|
+
throw new Error("next() called multiple times");
|
|
45
|
+
}
|
|
46
|
+
index = i;
|
|
47
|
+
|
|
48
|
+
let handler: MiddlewareFunction<C> | undefined;
|
|
49
|
+
|
|
50
|
+
if (i >= middleware.length) {
|
|
51
|
+
if (next) {
|
|
52
|
+
await next();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (middleware[i]) {
|
|
59
|
+
handler = middleware[i];
|
|
60
|
+
} else {
|
|
61
|
+
handler = i === middleware.length ? next : undefined;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!handler) {
|
|
65
|
+
throw new Error("Handler not found");
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
await handler(context, () => dispatch(i + 1));
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
package/src/context.ts
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import type { Cursor, DataFinality } from "@apibara/protocol";
|
|
2
3
|
import { getContext } from "unctx";
|
|
3
|
-
import type { Sink } from "./sink";
|
|
4
4
|
|
|
5
5
|
// biome-ignore lint/suspicious/noExplicitAny: context type
|
|
6
|
-
export interface IndexerContext
|
|
7
|
-
sink?: Sink<TTxnParams>;
|
|
8
|
-
sinkTransaction?: TTxnParams;
|
|
9
|
-
}
|
|
6
|
+
export interface IndexerContext extends Record<string, any> {}
|
|
10
7
|
|
|
11
8
|
export const indexerAsyncContext = getContext<IndexerContext>("indexer", {
|
|
12
9
|
asyncContext: true,
|
|
13
10
|
AsyncLocalStorage,
|
|
14
11
|
});
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
export function useIndexerContext() {
|
|
14
|
+
return indexerAsyncContext.use() as IndexerContext;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface MessageMetadataContext extends IndexerContext {
|
|
18
|
+
cursor?: Cursor;
|
|
19
|
+
endCursor?: Cursor;
|
|
20
|
+
finality?: DataFinality;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function useMessageMetadataContext(): MessageMetadataContext {
|
|
24
|
+
return useIndexerContext() as MessageMetadataContext;
|
|
19
25
|
}
|