apibara 2.0.0-beta.4 → 2.0.0-beta.40
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/chunks/build.mjs +28 -0
- package/dist/chunks/dev.mjs +100 -0
- package/dist/chunks/prepare.mjs +21 -0
- package/dist/chunks/start.mjs +56 -0
- package/dist/cli/index.d.mts +5 -0
- package/dist/cli/index.d.ts +5 -0
- package/dist/cli/index.mjs +19 -0
- package/dist/config/index.d.mts +5 -0
- package/dist/config/index.d.ts +5 -0
- package/dist/config/index.mjs +5 -0
- package/dist/core/index.d.mts +11 -0
- package/dist/core/index.d.ts +11 -0
- package/dist/core/index.mjs +310 -0
- package/dist/hooks/index.d.mts +5 -0
- package/dist/hooks/index.d.ts +5 -0
- package/dist/hooks/index.mjs +5 -0
- package/dist/rollup/index.d.mts +5 -0
- package/dist/rollup/index.d.ts +5 -0
- package/dist/rollup/index.mjs +150 -0
- package/dist/runtime/dev.d.ts +3 -0
- package/dist/runtime/dev.mjs +55 -0
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/index.mjs +2 -0
- package/dist/runtime/internal/app.d.ts +2 -0
- package/dist/runtime/internal/app.mjs +56 -0
- package/dist/runtime/internal/logger.d.ts +14 -0
- package/dist/runtime/internal/logger.mjs +45 -0
- package/dist/runtime/start.d.ts +3 -0
- package/dist/runtime/start.mjs +41 -0
- package/dist/shared/apibara.1b515d04.mjs +8 -0
- package/dist/types/index.d.mts +90 -0
- package/dist/types/index.d.ts +90 -0
- package/dist/types/index.mjs +1 -0
- package/package.json +28 -8
- package/runtime-meta.d.ts +2 -0
- package/runtime-meta.mjs +7 -0
- package/src/cli/commands/build.ts +5 -3
- package/src/cli/commands/dev.ts +29 -19
- package/src/cli/commands/prepare.ts +0 -2
- package/src/cli/commands/start.ts +61 -0
- package/src/cli/index.ts +1 -0
- package/src/config/index.ts +5 -4
- package/src/core/apibara.ts +4 -2
- package/src/core/build/build.ts +2 -0
- package/src/core/build/dev.ts +1 -0
- package/src/core/build/prepare.ts +5 -2
- package/src/core/build/prod.ts +10 -6
- package/src/core/build/types.ts +4 -95
- package/src/core/config/defaults.ts +1 -4
- package/src/core/config/loader.ts +1 -0
- package/src/core/config/resolvers/runtime-config.resolver.ts +1 -1
- package/src/core/config/update.ts +2 -3
- package/src/core/path.ts +11 -0
- package/src/core/scan.ts +40 -0
- package/src/rollup/config.ts +67 -188
- package/src/rollup/plugins/config.ts +12 -0
- package/src/rollup/plugins/esm-shim.ts +69 -0
- package/src/rollup/plugins/indexers.ts +17 -0
- package/src/runtime/dev.ts +64 -0
- package/src/runtime/index.ts +2 -0
- package/src/runtime/internal/app.ts +78 -0
- package/src/runtime/internal/logger.ts +70 -0
- package/src/runtime/start.ts +48 -0
- package/src/types/apibara.ts +8 -0
- package/src/types/config.ts +28 -27
- package/src/types/hooks.ts +1 -0
- package/src/types/virtual/config.d.ts +3 -0
- package/src/types/virtual/indexers.d.ts +10 -0
package/src/rollup/config.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import { existsSync } from "node:fs";
|
|
2
1
|
import { builtinModules } from "node:module";
|
|
3
2
|
import commonjs from "@rollup/plugin-commonjs";
|
|
4
3
|
import json from "@rollup/plugin-json";
|
|
5
4
|
import { nodeResolve } from "@rollup/plugin-node-resolve";
|
|
6
|
-
import typescript from "@rollup/plugin-typescript";
|
|
7
5
|
import type { Apibara, RollupConfig } from "apibara/types";
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
6
|
+
import { join } from "pathe";
|
|
7
|
+
import type { OutputPluginOption } from "rollup";
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
import defu from "defu";
|
|
10
|
+
import { appConfig } from "./plugins/config";
|
|
11
|
+
import { esmShim } from "./plugins/esm-shim";
|
|
12
|
+
import { indexers } from "./plugins/indexers";
|
|
13
|
+
|
|
14
|
+
const runtimeDependencies = ["better-sqlite3", "@electric-sql/pglite"];
|
|
15
|
+
|
|
16
|
+
export function getRollupConfig(apibara: Apibara): RollupConfig {
|
|
15
17
|
const extensions: string[] = [
|
|
16
18
|
".ts",
|
|
17
19
|
".mjs",
|
|
@@ -22,187 +24,64 @@ export const getRollupConfig = (
|
|
|
22
24
|
".jsx",
|
|
23
25
|
];
|
|
24
26
|
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
try {
|
|
39
|
-
indexerFiles = fsExtra
|
|
40
|
-
.readdirSync(indexerDir)
|
|
41
|
-
.filter((file) => file.endsWith(".indexer.ts"));
|
|
42
|
-
if (indexerFiles.length === 0) {
|
|
43
|
-
console.warn(`No indexer files found in ${indexerDir}`);
|
|
44
|
-
}
|
|
45
|
-
} catch (error) {
|
|
46
|
-
console.error(`Error reading indexers directory: ${error}`);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const indexerImports = indexerFiles
|
|
50
|
-
.map(
|
|
51
|
-
(file, index) =>
|
|
52
|
-
`import indexer${index} from '${join(indexerDir, file)}';`,
|
|
53
|
-
)
|
|
54
|
-
.join("\n");
|
|
55
|
-
|
|
56
|
-
// Generate main.ts content
|
|
57
|
-
const mainContent = `
|
|
58
|
-
import { createClient } from "@apibara/protocol";
|
|
59
|
-
import { createIndexer, run } from "@apibara/indexer";
|
|
60
|
-
import consola from "consola";
|
|
61
|
-
import { defineCommand, runMain } from "citty";
|
|
62
|
-
import config from './${configPath}';
|
|
63
|
-
|
|
64
|
-
${indexerImports}
|
|
65
|
-
|
|
66
|
-
const indexers = {
|
|
67
|
-
${indexerFiles
|
|
68
|
-
.map(
|
|
69
|
-
(file, index) => `'${basename(file, ".indexer.ts")}': indexer${index},`,
|
|
70
|
-
)
|
|
71
|
-
.join("\n ")}
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
const command = defineCommand({
|
|
75
|
-
meta: {
|
|
76
|
-
name: "run-indexers",
|
|
77
|
-
description: "Run Apibara indexers",
|
|
78
|
-
},
|
|
79
|
-
args: {
|
|
80
|
-
indexers: {
|
|
81
|
-
type: "string",
|
|
82
|
-
description: "Comma-separated list of indexers to run",
|
|
83
|
-
},
|
|
84
|
-
preset: {
|
|
85
|
-
type: "string",
|
|
86
|
-
description: "Preset to use",
|
|
87
|
-
},
|
|
88
|
-
sink: {
|
|
89
|
-
type: "string",
|
|
90
|
-
description: "Sink to use",
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
async run({ args }) {
|
|
94
|
-
const selectedIndexers = args.indexers ? args.indexers.split(',') : Object.keys(indexers);
|
|
95
|
-
const preset = args.preset || config.preset || 'default';
|
|
96
|
-
const sinkName = args.sink || 'default';
|
|
97
|
-
|
|
98
|
-
// Apply preset
|
|
99
|
-
let runtimeConfig = { ...config.runtimeConfig };
|
|
100
|
-
if (preset && config.presets && config.presets[preset]) {
|
|
101
|
-
runtimeConfig = { ...runtimeConfig, ...config.presets[preset].runtimeConfig };
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Get sink function
|
|
105
|
-
const sinkFunction = config.sink?.[sinkName];
|
|
106
|
-
if (!sinkFunction) {
|
|
107
|
-
throw new Error(\`Sink \${sinkName} not found\`);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
await Promise.all(selectedIndexers.map(async (name) => {
|
|
111
|
-
if (!indexers[name]) {
|
|
112
|
-
console.error(\`Indexer \${name} not found\`);
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const indexerConfig = indexers[name]
|
|
117
|
-
const indexer = typeof indexerConfig === 'function'
|
|
118
|
-
? await createIndexer(indexerConfig(runtimeConfig))
|
|
119
|
-
: createIndexer(indexerConfig);
|
|
120
|
-
|
|
121
|
-
const client = createClient(indexer.streamConfig, indexer.options.streamUrl);
|
|
122
|
-
const sink = sinkFunction();
|
|
123
|
-
|
|
124
|
-
try {
|
|
125
|
-
consola.log("Running Indexer: ", name);
|
|
126
|
-
await run(client, indexer, sink);
|
|
127
|
-
} catch (error) {
|
|
128
|
-
consola.error(\`Error in indexer \${name}:\`, error);
|
|
129
|
-
}
|
|
130
|
-
}));
|
|
131
|
-
},
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
runMain(command);
|
|
135
|
-
`;
|
|
136
|
-
|
|
137
|
-
return {
|
|
138
|
-
input: {
|
|
139
|
-
main: "virtual:main.ts",
|
|
140
|
-
},
|
|
141
|
-
output: {
|
|
142
|
-
dir: join(apibara.options.outputDir || "./.apibara/build"),
|
|
143
|
-
format: "esm",
|
|
144
|
-
exports: "auto",
|
|
145
|
-
entryFileNames: "[name].mjs",
|
|
146
|
-
chunkFileNames: "chunks/[name]-[hash].mjs",
|
|
147
|
-
generatedCode: {
|
|
148
|
-
constBindings: true,
|
|
149
|
-
},
|
|
150
|
-
sourcemap: true,
|
|
151
|
-
sourcemapExcludeSources: true,
|
|
152
|
-
sourcemapIgnoreList(relativePath, sourcemapPath) {
|
|
153
|
-
return relativePath.includes("node_modules");
|
|
154
|
-
},
|
|
155
|
-
},
|
|
156
|
-
plugins: [
|
|
157
|
-
{
|
|
158
|
-
name: "virtual",
|
|
159
|
-
resolveId(id) {
|
|
160
|
-
if (id === "virtual:main.ts") {
|
|
161
|
-
return id;
|
|
162
|
-
}
|
|
163
|
-
return null;
|
|
27
|
+
const rollupConfig: RollupConfig & { plugins: OutputPluginOption[] } = defu(
|
|
28
|
+
// biome-ignore lint/suspicious/noExplicitAny: apibara.options.rollupConfig is typed
|
|
29
|
+
apibara.options.rollupConfig as any,
|
|
30
|
+
<RollupConfig>{
|
|
31
|
+
input: apibara.options.entry,
|
|
32
|
+
output: {
|
|
33
|
+
dir: join(apibara.options.outputDir || "./.apibara/build"),
|
|
34
|
+
format: "esm",
|
|
35
|
+
exports: "auto",
|
|
36
|
+
entryFileNames: "[name].mjs",
|
|
37
|
+
chunkFileNames: "chunks/[name]-[hash].mjs",
|
|
38
|
+
generatedCode: {
|
|
39
|
+
constBindings: true,
|
|
164
40
|
},
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
return null;
|
|
41
|
+
sourcemap: true,
|
|
42
|
+
sourcemapExcludeSources: true,
|
|
43
|
+
sourcemapIgnoreList(relativePath, sourcemapPath) {
|
|
44
|
+
return relativePath.includes("node_modules");
|
|
170
45
|
},
|
|
171
46
|
},
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
],
|
|
188
|
-
onwarn(warning, rollupWarn) {
|
|
189
|
-
if (
|
|
190
|
-
!["CIRCULAR_DEPENDENCY", "EVAL"].includes(warning.code || "") &&
|
|
191
|
-
!warning.message.includes("Unsupported source map comment") &&
|
|
192
|
-
!warning.message.includes("@__PURE__")
|
|
193
|
-
) {
|
|
194
|
-
rollupWarn(warning);
|
|
195
|
-
}
|
|
47
|
+
plugins: [],
|
|
48
|
+
onwarn(warning, rollupWarn) {
|
|
49
|
+
if (
|
|
50
|
+
!["CIRCULAR_DEPENDENCY", "EVAL", "THIS_IS_UNDEFINED"].includes(
|
|
51
|
+
warning.code || "",
|
|
52
|
+
) &&
|
|
53
|
+
!warning.message.includes("Unsupported source map comment") &&
|
|
54
|
+
!warning.message.includes("@__PURE__") &&
|
|
55
|
+
!warning.message.includes("/*#__PURE__*/")
|
|
56
|
+
) {
|
|
57
|
+
rollupWarn(warning);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
treeshake: true,
|
|
61
|
+
external: [...builtinModules, ...runtimeDependencies],
|
|
196
62
|
},
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
"
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
rollupConfig.plugins.push(esmShim());
|
|
66
|
+
rollupConfig.plugins.push(json());
|
|
67
|
+
|
|
68
|
+
rollupConfig.plugins.push(
|
|
69
|
+
commonjs({
|
|
70
|
+
strictRequires: true,
|
|
71
|
+
requireReturnsDefault: "auto",
|
|
72
|
+
...apibara.options.commonJS,
|
|
73
|
+
}),
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
rollupConfig.plugins.push(
|
|
77
|
+
nodeResolve({
|
|
78
|
+
extensions,
|
|
79
|
+
preferBuiltins: true,
|
|
80
|
+
mainFields: ["main"],
|
|
81
|
+
}),
|
|
82
|
+
);
|
|
83
|
+
rollupConfig.plugins.push(indexers(apibara));
|
|
84
|
+
rollupConfig.plugins.push(appConfig(apibara));
|
|
85
|
+
|
|
86
|
+
return rollupConfig;
|
|
87
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import virtual from "@rollup/plugin-virtual";
|
|
2
|
+
import type { Apibara } from "apibara/types";
|
|
3
|
+
|
|
4
|
+
export function appConfig(apibara: Apibara) {
|
|
5
|
+
return virtual({
|
|
6
|
+
"#apibara-internal-virtual/config": `
|
|
7
|
+
import * as projectConfig from '${apibara.options._c12.configFile}';
|
|
8
|
+
|
|
9
|
+
export const config = projectConfig.default;
|
|
10
|
+
`,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import MagicString from "magic-string";
|
|
2
|
+
import type { Plugin } from "rollup";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* An alternative to @rollup/plugin-esm-shim
|
|
6
|
+
*/
|
|
7
|
+
export function esmShim(): Plugin {
|
|
8
|
+
const ESMShim = `
|
|
9
|
+
// -- Shims --
|
|
10
|
+
import cjsUrl from 'node:url';
|
|
11
|
+
import cjsPath from 'node:path';
|
|
12
|
+
const __filename = cjsUrl.fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = cjsPath.dirname(__filename);
|
|
14
|
+
// -- End Shims --
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
const CJSyntaxRegex = /__filename|__dirname/;
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
name: "esm-shim",
|
|
21
|
+
|
|
22
|
+
renderChunk(code, _chunk, opts) {
|
|
23
|
+
if (opts.format === "es") {
|
|
24
|
+
if (code.includes(ESMShim) || !CJSyntaxRegex.test(code)) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let endIndexOfLastImport = -1;
|
|
29
|
+
|
|
30
|
+
// Find the last import statement and its ending index
|
|
31
|
+
for (const match of code.matchAll(/^import\s.*';$/gm)) {
|
|
32
|
+
if (match.length === 0 || typeof match.index !== "number") {
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
endIndexOfLastImport = match.index + match[0].length;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const s = new MagicString(code);
|
|
40
|
+
s.appendRight(endIndexOfLastImport, ESMShim);
|
|
41
|
+
|
|
42
|
+
const sourceMap = s.generateMap({
|
|
43
|
+
includeContent: true,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
let sourcesContent: string[] | undefined;
|
|
47
|
+
if (Array.isArray(sourceMap.sourcesContent)) {
|
|
48
|
+
sourcesContent = [];
|
|
49
|
+
for (let i = 0; i < sourceMap.sourcesContent.length; i++) {
|
|
50
|
+
const content = sourceMap.sourcesContent[i];
|
|
51
|
+
if (typeof content === "string") {
|
|
52
|
+
sourcesContent.push(content);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
code: s.toString(),
|
|
59
|
+
map: {
|
|
60
|
+
...sourceMap,
|
|
61
|
+
sourcesContent,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return null;
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import virtual from "@rollup/plugin-virtual";
|
|
2
|
+
import type { Apibara } from "apibara/types";
|
|
3
|
+
import { hash } from "ohash";
|
|
4
|
+
|
|
5
|
+
export function indexers(apibara: Apibara) {
|
|
6
|
+
const indexers = [...new Set(apibara.indexers)];
|
|
7
|
+
|
|
8
|
+
return virtual({
|
|
9
|
+
"#apibara-internal-virtual/indexers": `
|
|
10
|
+
${indexers.map((i) => `import _${hash(i)} from '${i.indexer}';`).join("\n")}
|
|
11
|
+
|
|
12
|
+
export const indexers = [
|
|
13
|
+
${indexers.map((i) => `{ name: "${i.name}", indexer: _${hash(i)} }`).join(",\n")}
|
|
14
|
+
];
|
|
15
|
+
`,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { runWithReconnect } from "@apibara/indexer";
|
|
2
|
+
import { createClient } from "@apibara/protocol";
|
|
3
|
+
import { defineCommand, runMain } from "citty";
|
|
4
|
+
import { availableIndexers, createIndexer } from "./internal/app";
|
|
5
|
+
|
|
6
|
+
const startCommand = defineCommand({
|
|
7
|
+
meta: {
|
|
8
|
+
name: "start",
|
|
9
|
+
description: "Start the indexer",
|
|
10
|
+
},
|
|
11
|
+
args: {
|
|
12
|
+
indexers: {
|
|
13
|
+
type: "string",
|
|
14
|
+
description: "Which indexers to run",
|
|
15
|
+
},
|
|
16
|
+
preset: {
|
|
17
|
+
type: "string",
|
|
18
|
+
description: "Preset to use",
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
async run({ args }) {
|
|
22
|
+
const { indexers: indexersArgs, preset } = args;
|
|
23
|
+
|
|
24
|
+
let selectedIndexers = availableIndexers;
|
|
25
|
+
if (indexersArgs) {
|
|
26
|
+
selectedIndexers = indexersArgs.split(",");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
for (const indexer of selectedIndexers) {
|
|
30
|
+
if (!availableIndexers.includes(indexer)) {
|
|
31
|
+
throw new Error(
|
|
32
|
+
`Specified indexer "${indexer}" but it was not defined`,
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
await Promise.all(
|
|
38
|
+
selectedIndexers.map(async (indexer) => {
|
|
39
|
+
const indexerInstance = createIndexer(indexer, preset);
|
|
40
|
+
|
|
41
|
+
const client = createClient(
|
|
42
|
+
indexerInstance.streamConfig,
|
|
43
|
+
indexerInstance.options.streamUrl,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
await runWithReconnect(client, indexerInstance);
|
|
47
|
+
}),
|
|
48
|
+
);
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
export const mainCli = defineCommand({
|
|
53
|
+
meta: {
|
|
54
|
+
name: "indexer-dev-runner",
|
|
55
|
+
description: "Run indexer in dev mode",
|
|
56
|
+
},
|
|
57
|
+
subCommands: {
|
|
58
|
+
start: () => startCommand,
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
runMain(mainCli);
|
|
63
|
+
|
|
64
|
+
export default {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { createIndexer as _createIndexer } from "@apibara/indexer";
|
|
2
|
+
import {
|
|
3
|
+
type InternalContext,
|
|
4
|
+
internalContext,
|
|
5
|
+
} from "@apibara/indexer/internal/plugins";
|
|
6
|
+
import {
|
|
7
|
+
type ConsolaReporter,
|
|
8
|
+
inMemoryPersistence,
|
|
9
|
+
logger,
|
|
10
|
+
} from "@apibara/indexer/plugins";
|
|
11
|
+
import { config } from "#apibara-internal-virtual/config";
|
|
12
|
+
import { indexers } from "#apibara-internal-virtual/indexers";
|
|
13
|
+
import { createLogger } from "./logger";
|
|
14
|
+
|
|
15
|
+
export const availableIndexers = indexers.map((i) => i.name);
|
|
16
|
+
|
|
17
|
+
export function createIndexer(indexerName: string, preset?: string) {
|
|
18
|
+
let runtimeConfig: Record<string, unknown> = { ...config.runtimeConfig };
|
|
19
|
+
|
|
20
|
+
if (preset) {
|
|
21
|
+
if (config.presets === undefined) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
`Specified preset "${preset}" but no presets were defined`,
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (config.presets[preset] === undefined) {
|
|
28
|
+
throw new Error(`Specified preset "${preset}" but it was not defined`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const presetValue = config.presets[preset] as {
|
|
32
|
+
runtimeConfig: Record<string, unknown>;
|
|
33
|
+
};
|
|
34
|
+
runtimeConfig = { ...runtimeConfig, ...presetValue.runtimeConfig };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const indexerDefinition = indexers.find((i) => i.name === indexerName);
|
|
38
|
+
|
|
39
|
+
if (indexerDefinition === undefined) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`Specified indexer "${indexerName}" but it was not defined`,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const definition =
|
|
46
|
+
typeof indexerDefinition.indexer === "function"
|
|
47
|
+
? indexerDefinition.indexer(runtimeConfig)
|
|
48
|
+
: indexerDefinition.indexer;
|
|
49
|
+
|
|
50
|
+
let reporter: ConsolaReporter = createLogger({
|
|
51
|
+
indexer: indexerName,
|
|
52
|
+
preset,
|
|
53
|
+
indexers: availableIndexers,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (config.logger) {
|
|
57
|
+
reporter = config.logger({
|
|
58
|
+
indexer: indexerName,
|
|
59
|
+
preset,
|
|
60
|
+
indexers: availableIndexers,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Put the in-memory persistence plugin first so that it can be overridden by any user-defined
|
|
65
|
+
// persistence plugin.
|
|
66
|
+
// Put the logger last since we want to override any user-defined logger.
|
|
67
|
+
definition.plugins = [
|
|
68
|
+
internalContext({
|
|
69
|
+
indexerName,
|
|
70
|
+
availableIndexers,
|
|
71
|
+
} as InternalContext),
|
|
72
|
+
inMemoryPersistence(),
|
|
73
|
+
...(definition.plugins ?? []),
|
|
74
|
+
logger({ logger: reporter }),
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
return _createIndexer(definition);
|
|
78
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ConsolaOptions,
|
|
3
|
+
ConsolaReporter,
|
|
4
|
+
LogLevel,
|
|
5
|
+
LogObject,
|
|
6
|
+
LogType,
|
|
7
|
+
} from "consola";
|
|
8
|
+
import { type ColorName, colors, getColor } from "consola/utils";
|
|
9
|
+
import { murmurHash } from "ohash";
|
|
10
|
+
|
|
11
|
+
const INDEXER_COLOR_MAP = [
|
|
12
|
+
colors.red,
|
|
13
|
+
colors.green,
|
|
14
|
+
colors.yellow,
|
|
15
|
+
colors.blue,
|
|
16
|
+
colors.magenta,
|
|
17
|
+
colors.cyan,
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
const TYPE_COLOR_MAP: { [k in LogType]?: string } = {
|
|
21
|
+
info: "cyan",
|
|
22
|
+
fail: "red",
|
|
23
|
+
success: "green",
|
|
24
|
+
ready: "green",
|
|
25
|
+
start: "magenta",
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const LEVEL_COLOR_MAP: { [k in LogLevel]?: string } = {
|
|
29
|
+
0: "red",
|
|
30
|
+
1: "yellow",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const MAX_INDEXER_NAME_LENGTH = 20;
|
|
34
|
+
|
|
35
|
+
class DefaultReporter implements ConsolaReporter {
|
|
36
|
+
private tag: string;
|
|
37
|
+
|
|
38
|
+
constructor(indexer: string, indexers: string[], preset?: string) {
|
|
39
|
+
const color =
|
|
40
|
+
INDEXER_COLOR_MAP[murmurHash(indexer) % INDEXER_COLOR_MAP.length];
|
|
41
|
+
|
|
42
|
+
const presetLength = preset ? preset.length : 0;
|
|
43
|
+
|
|
44
|
+
const longestIndexerName =
|
|
45
|
+
Math.max(...indexers.map((i) => i.length), indexer.length) + presetLength;
|
|
46
|
+
|
|
47
|
+
const paddedIndexer = `${indexer}${preset ? `:${preset} ` : ""}`
|
|
48
|
+
.padEnd(longestIndexerName, " ")
|
|
49
|
+
.slice(0, Math.min(longestIndexerName, MAX_INDEXER_NAME_LENGTH));
|
|
50
|
+
|
|
51
|
+
this.tag = color(`${paddedIndexer} |`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
log(logObj: LogObject, ctx: { options: ConsolaOptions }) {
|
|
55
|
+
const { args } = logObj;
|
|
56
|
+
const typeColor =
|
|
57
|
+
TYPE_COLOR_MAP[logObj.type] || LEVEL_COLOR_MAP[logObj.level] || "gray";
|
|
58
|
+
|
|
59
|
+
const type = getColor(typeColor as ColorName, "white")(logObj.type);
|
|
60
|
+
console.log(`${this.tag} ${type}`, ...args);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function createLogger({
|
|
65
|
+
indexer,
|
|
66
|
+
indexers,
|
|
67
|
+
preset,
|
|
68
|
+
}: { indexer: string; indexers: string[]; preset?: string }) {
|
|
69
|
+
return new DefaultReporter(indexer, indexers, preset);
|
|
70
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { runWithReconnect } from "@apibara/indexer";
|
|
2
|
+
import { createClient } from "@apibara/protocol";
|
|
3
|
+
import { defineCommand, runMain } from "citty";
|
|
4
|
+
import { createIndexer } from "./internal/app";
|
|
5
|
+
|
|
6
|
+
const startCommand = defineCommand({
|
|
7
|
+
meta: {
|
|
8
|
+
name: "start",
|
|
9
|
+
description: "Start the indexer",
|
|
10
|
+
},
|
|
11
|
+
args: {
|
|
12
|
+
indexer: {
|
|
13
|
+
type: "string",
|
|
14
|
+
description: "Indexer name",
|
|
15
|
+
required: true,
|
|
16
|
+
},
|
|
17
|
+
preset: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "Preset to use",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
async run({ args }) {
|
|
23
|
+
const { indexer, preset } = args;
|
|
24
|
+
|
|
25
|
+
const indexerInstance = createIndexer(indexer, preset);
|
|
26
|
+
|
|
27
|
+
const client = createClient(
|
|
28
|
+
indexerInstance.streamConfig,
|
|
29
|
+
indexerInstance.options.streamUrl,
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
await runWithReconnect(client, indexerInstance);
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const mainCli = defineCommand({
|
|
37
|
+
meta: {
|
|
38
|
+
name: "indexer-runner",
|
|
39
|
+
description: "Run an indexer",
|
|
40
|
+
},
|
|
41
|
+
subCommands: {
|
|
42
|
+
start: () => startCommand,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
runMain(mainCli);
|
|
47
|
+
|
|
48
|
+
export default {};
|
package/src/types/apibara.ts
CHANGED
|
@@ -3,9 +3,17 @@ import type { Hookable } from "hookable";
|
|
|
3
3
|
import type { ApibaraDynamicConfig, ApibaraOptions } from "./config";
|
|
4
4
|
import type { ApibaraHooks } from "./hooks";
|
|
5
5
|
|
|
6
|
+
export type IndexerDefinition = {
|
|
7
|
+
// Name of the indexer.
|
|
8
|
+
name: string;
|
|
9
|
+
// Path to the indexer file.
|
|
10
|
+
indexer: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
6
13
|
export interface Apibara {
|
|
7
14
|
options: ApibaraOptions;
|
|
8
15
|
hooks: Hookable<ApibaraHooks>;
|
|
16
|
+
indexers: IndexerDefinition[];
|
|
9
17
|
logger: ConsolaInstance;
|
|
10
18
|
close: () => Promise<void>;
|
|
11
19
|
updateConfig: (config: ApibaraDynamicConfig) => void | Promise<void>;
|