apibara 2.1.0-beta.1 → 2.1.0-beta.11

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.
Files changed (60) hide show
  1. package/dist/chunks/add.mjs +12 -7
  2. package/dist/chunks/dev.mjs +25 -6
  3. package/dist/chunks/init.mjs +3 -7
  4. package/dist/chunks/start.mjs +2 -1
  5. package/dist/core/index.mjs +85 -42
  6. package/dist/create/index.d.mts +2 -1
  7. package/dist/create/index.d.ts +2 -1
  8. package/dist/create/index.mjs +185 -121
  9. package/dist/hooks/index.mjs +3 -1
  10. package/dist/rolldown/index.d.mts +7 -0
  11. package/dist/rolldown/index.d.ts +7 -0
  12. package/dist/rolldown/index.mjs +126 -0
  13. package/dist/runtime/dev.mjs +3 -0
  14. package/dist/runtime/internal/app.d.ts +1 -1
  15. package/dist/runtime/internal/app.mjs +12 -11
  16. package/dist/runtime/start.mjs +5 -0
  17. package/dist/shared/apibara.af330c7d.mjs +15 -0
  18. package/dist/types/index.d.mts +18 -15
  19. package/dist/types/index.d.ts +18 -15
  20. package/package.json +13 -15
  21. package/src/cli/commands/add.ts +12 -6
  22. package/src/cli/commands/dev.ts +27 -5
  23. package/src/cli/commands/init.ts +3 -7
  24. package/src/cli/commands/start.ts +1 -0
  25. package/src/core/build/build.ts +13 -5
  26. package/src/core/build/dev.ts +44 -23
  27. package/src/core/build/error.ts +9 -14
  28. package/src/core/build/prod.ts +15 -10
  29. package/src/core/build/types.ts +8 -0
  30. package/src/core/config/defaults.ts +3 -0
  31. package/src/core/config/resolvers/runtime-config.resolver.ts +21 -2
  32. package/src/core/config/update.ts +1 -1
  33. package/src/create/add.ts +26 -12
  34. package/src/create/constants.ts +9 -10
  35. package/src/create/init.ts +28 -14
  36. package/src/create/templates.ts +154 -118
  37. package/src/create/utils.ts +10 -0
  38. package/src/hooks/useRuntimeConfig.ts +2 -1
  39. package/src/rolldown/config.ts +108 -0
  40. package/src/rolldown/index.ts +2 -0
  41. package/src/rolldown/plugins/config.ts +25 -0
  42. package/src/{rollup → rolldown}/plugins/indexers.ts +3 -3
  43. package/src/runtime/dev.ts +3 -0
  44. package/src/runtime/internal/app.ts +30 -13
  45. package/src/runtime/start.ts +5 -0
  46. package/src/types/config.ts +12 -7
  47. package/src/types/hooks.ts +8 -5
  48. package/src/types/index.ts +1 -1
  49. package/src/types/rolldown.ts +5 -0
  50. package/src/types/virtual/config.d.ts +4 -1
  51. package/src/types/virtual/indexers.d.ts +4 -1
  52. package/src/utils/helper.ts +15 -0
  53. package/dist/rollup/index.d.mts +0 -6
  54. package/dist/rollup/index.d.ts +0 -6
  55. package/dist/rollup/index.mjs +0 -150
  56. package/src/rollup/config.ts +0 -87
  57. package/src/rollup/index.ts +0 -2
  58. package/src/rollup/plugins/config.ts +0 -12
  59. package/src/rollup/plugins/esm-shim.ts +0 -69
  60. package/src/types/rollup.ts +0 -8
@@ -1,11 +1,12 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { consola } from "consola";
4
+ import prompts from "prompts";
4
5
  import { type ObjectLiteralExpression, Project, SyntaxKind } from "ts-morph";
5
6
  import { cyan, green, magenta, yellow } from "./colors";
6
7
  import { packageVersions } from "./constants";
7
8
  import type { IndexerOptions } from "./types";
8
- import { checkFileExists, getDnaUrl } from "./utils";
9
+ import { checkFileExists, formatFile, getDnaUrl } from "./utils";
9
10
 
10
11
  export function generatePackageJson(isTypeScript: boolean) {
11
12
  return {
@@ -14,7 +15,7 @@ export function generatePackageJson(isTypeScript: boolean) {
14
15
  private: true,
15
16
  type: "module",
16
17
  scripts: {
17
- prepare: "apibara prepare",
18
+ ...(isTypeScript && { prepare: "apibara prepare" }),
18
19
  dev: "apibara dev",
19
20
  start: "apibara start",
20
21
  build: "apibara build",
@@ -27,8 +28,6 @@ export function generatePackageJson(isTypeScript: boolean) {
27
28
  },
28
29
  devDependencies: {
29
30
  ...(isTypeScript && {
30
- "@rollup/plugin-typescript":
31
- packageVersions["@rollup/plugin-typescript"],
32
31
  "@types/node": packageVersions["@types/node"],
33
32
  typescript: packageVersions.typescript,
34
33
  }),
@@ -58,17 +57,10 @@ export function generateTsConfig() {
58
57
  }
59
58
 
60
59
  export function generateApibaraConfig(isTypeScript: boolean) {
61
- return `${isTypeScript ? 'import typescript from "@rollup/plugin-typescript";\nimport type { Plugin } from "apibara/rollup";\n' : ""}import { defineConfig } from "apibara/config";
60
+ return `import { defineConfig } from "apibara/config";
62
61
 
63
62
  export default defineConfig({
64
- runtimeConfig: {},${
65
- isTypeScript
66
- ? `
67
- rollupConfig: {
68
- plugins: [typescript()${isTypeScript ? " as Plugin" : ""}],
69
- },`
70
- : ""
71
- }
63
+ runtimeConfig: {},
72
64
  });\n`;
73
65
  }
74
66
 
@@ -78,24 +70,21 @@ export function generateIndexer({
78
70
  chain,
79
71
  language,
80
72
  }: IndexerOptions) {
81
- return `${
82
- chain === "ethereum"
83
- ? `import { EvmStream } from "@apibara/evm";`
84
- : chain === "beaconchain"
85
- ? `import { BeaconChainStream } from "@apibara/beaconchain";`
86
- : chain === "starknet"
87
- ? `import { StarknetStream } from "@apibara/starknet";`
88
- : ""
89
- }
90
- import { defineIndexer } from "@apibara/indexer";
91
- ${storage === "postgres" ? `import { drizzleStorage } from "@apibara/plugin-drizzle";` : ""}
92
- ${language === "typescript" ? `import type { ApibaraRuntimeConfig } from "apibara/types";` : ""}
73
+ return `import { defineIndexer } from "@apibara/indexer";
93
74
  import { useLogger } from "@apibara/indexer/plugins";
75
+ ${storage === "postgres" ? `import { drizzleStorage } from "@apibara/plugin-drizzle";` : ""}
76
+ ${storage === "postgres" ? `import { drizzle } from "@apibara/plugin-drizzle";` : ""}
94
77
  ${
95
- storage === "postgres"
96
- ? `import { getDrizzlePgDatabase } from "../lib/db";`
97
- : ""
78
+ chain === "ethereum"
79
+ ? `import { EvmStream } from "@apibara/evm";`
80
+ : chain === "beaconchain"
81
+ ? `import { BeaconChainStream } from "@apibara/beaconchain";`
82
+ : chain === "starknet"
83
+ ? `import { StarknetStream } from "@apibara/starknet";`
84
+ : ""
98
85
  }
86
+ ${language === "typescript" ? `import type { ApibaraRuntimeConfig } from "apibara/types";` : ""}
87
+ ${storage === "postgres" ? `import * as schema from "../lib/schema";` : ""}
99
88
 
100
89
 
101
90
  export default function (runtimeConfig${language === "typescript" ? ": ApibaraRuntimeConfig" : ""}) {
@@ -103,7 +92,10 @@ export default function (runtimeConfig${language === "typescript" ? ": ApibaraRu
103
92
  const { startingBlock, streamUrl${storage === "postgres" ? ", postgresConnectionString" : ""} } = runtimeConfig[indexerId];
104
93
  ${
105
94
  storage === "postgres"
106
- ? "const { db } = getDrizzlePgDatabase(postgresConnectionString);"
95
+ ? `const db = drizzle({
96
+ schema,
97
+ connectionString: postgresConnectionString,
98
+ });`
107
99
  : ""
108
100
  }
109
101
 
@@ -122,7 +114,7 @@ export default function (runtimeConfig${language === "typescript" ? ": ApibaraRu
122
114
  filter: {
123
115
  header: "always",
124
116
  },
125
- plugins: [${storage === "postgres" ? "drizzleStorage({ db, persistState: true })" : ""}],
117
+ plugins: [${storage === "postgres" ? "drizzleStorage({ db, migrate: { migrationsFolder: './drizzle' } })" : ""}],
126
118
  async transform({ endCursor, finality }) {
127
119
  const logger = useLogger();
128
120
 
@@ -136,14 +128,12 @@ export default function (runtimeConfig${language === "typescript" ? ": ApibaraRu
136
128
  ${
137
129
  storage === "postgres"
138
130
  ? `// Example snippet to insert data into db using drizzle with postgres
139
- // const { db } = useDrizzleStorage();
140
- // const { logs } = block;
141
- // for (const log of logs) {
142
- // await db.insert(exampleTable).values({
143
- // number: Number(endCursor?.orderKey),
144
- // hash: log.transactionHash,
145
- // });
146
- // }`
131
+ // const { db: database } = useDrizzleStorage();
132
+
133
+ // await database.insert(schema.cursorTable).values({
134
+ // endCursor: Number(endCursor?.orderKey),
135
+ // uniqueKey: \`\${endCursor?.uniqueKey}\`,
136
+ // });`
147
137
  : ""
148
138
  }
149
139
  },
@@ -169,17 +159,19 @@ export async function createIndexerFile(options: IndexerOptions) {
169
159
 
170
160
  fs.mkdirSync(path.dirname(indexerFilePath), { recursive: true });
171
161
  fs.writeFileSync(indexerFilePath, indexerContent);
162
+
163
+ await formatFile(indexerFilePath);
172
164
  }
173
165
 
174
- export function updatePackageJson({
166
+ export async function updatePackageJson({
175
167
  cwd,
176
168
  chain,
177
169
  storage,
178
170
  language,
179
171
  }: IndexerOptions) {
180
- const packageJson = JSON.parse(
181
- fs.readFileSync(path.join(cwd, "package.json"), "utf8"),
182
- );
172
+ const packageJsonPath = path.join(cwd, "package.json");
173
+
174
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
183
175
 
184
176
  if (chain === "ethereum") {
185
177
  packageJson.dependencies["@apibara/evm"] = packageVersions["@apibara/evm"];
@@ -212,13 +204,12 @@ export function updatePackageJson({
212
204
  }
213
205
  }
214
206
 
215
- fs.writeFileSync(
216
- path.join(cwd, "package.json"),
217
- JSON.stringify(packageJson, null, 2),
218
- );
207
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
208
+
209
+ await formatFile(packageJsonPath);
219
210
  }
220
211
 
221
- export function updateApibaraConfigFile({
212
+ export async function updateApibaraConfigFile({
222
213
  indexerId,
223
214
  cwd,
224
215
  chain,
@@ -279,15 +270,11 @@ export function updateApibaraConfigFile({
279
270
  // Save the changes
280
271
  sourceFile.saveSync();
281
272
 
282
- sourceFile.formatText({
283
- tabSize: 2,
284
- insertSpaceAfterOpeningAndBeforeClosingEmptyBraces: true,
285
- insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
286
- });
273
+ await formatFile(pathToConfig);
287
274
  }
288
275
 
289
276
  export async function createDrizzleStorageFiles(options: IndexerOptions) {
290
- const { cwd, language, storage } = options;
277
+ const { cwd, language, storage, indexerId } = options;
291
278
 
292
279
  if (storage !== "postgres") return;
293
280
 
@@ -315,16 +302,18 @@ export async function createDrizzleStorageFiles(options: IndexerOptions) {
315
302
  const drizzleConfigContent = `${language === "typescript" ? 'import type { Config } from "drizzle-kit";' : ""}
316
303
 
317
304
  export default {
318
- schema: "./lib/schema.ts",
305
+ schema: "./lib/schema.${fileExtension}",
319
306
  out: "./drizzle",
320
307
  dialect: "postgresql",
321
308
  dbCredentials: {
322
- url: process.env["POSTGRES_CONNECTION_STRING"] ?? "",
309
+ url: process.env["POSTGRES_CONNECTION_STRING"] ?? "memory://${indexerId}",
323
310
  },
324
311
  }${language === "typescript" ? " satisfies Config" : ""};`;
325
312
 
326
313
  fs.writeFileSync(drizzleConfigPath, drizzleConfigContent);
327
314
 
315
+ await formatFile(drizzleConfigPath);
316
+
328
317
  consola.success(`Created ${cyan(drizzleConfigFileName)}`);
329
318
  }
330
319
 
@@ -348,14 +337,14 @@ export default {
348
337
  });
349
338
 
350
339
  if (!schemaExists || schemaOverwrite) {
351
- const schemaContent = `// --- Add your pg table schemas here ----
340
+ const schemaContent = `// --- Add your pg table schemas here ----
352
341
 
353
342
  // import { bigint, pgTable, text, uuid } from "drizzle-orm/pg-core";
354
343
 
355
- // export const exampleTable = pgTable("example_table", {
344
+ // export const cursorTable = pgTable("cursor_table", {
356
345
  // id: uuid("id").primaryKey().defaultRandom(),
357
- // number: bigint("number", { mode: "number" }),
358
- // hash: text("hash"),
346
+ // endCursor: bigint("end_cursor", { mode: "number" }),
347
+ // uniqueKey: text("unique_key"),
359
348
  // });
360
349
 
361
350
  export {};
@@ -365,62 +354,9 @@ export {};
365
354
  fs.mkdirSync(path.dirname(schemaPath), { recursive: true });
366
355
  fs.writeFileSync(schemaPath, schemaContent);
367
356
 
368
- consola.success(`Created ${cyan("lib/schema.ts")}`);
369
- }
370
-
371
- /**
372
- *
373
- *
374
- * DB File
375
- *
376
- *
377
- */
378
- const dbFileName = `db.${fileExtension}`;
379
-
380
- const dbPath = path.join(cwd, "lib", dbFileName);
357
+ await formatFile(schemaPath);
381
358
 
382
- const { exists: dbExists, overwrite: dbOverwrite } = await checkFileExists(
383
- dbPath,
384
- {
385
- askPrompt: true,
386
- fileName: `lib/${dbFileName}`,
387
- allowIgnore: true,
388
- },
389
- );
390
-
391
- if (!dbExists || dbOverwrite) {
392
- const dbContent = `import * as schema from "./schema";
393
- import { drizzle as nodePgDrizzle } from "drizzle-orm/node-postgres";
394
- import { drizzle as pgLiteDrizzle } from "drizzle-orm/pglite";
395
- import pg from "pg";
396
-
397
-
398
- export function getDrizzlePgDatabase(connectionString${language === "typescript" ? ": string" : ""}) {
399
- // Create pglite instance
400
- if (connectionString.includes("memory")) {
401
- return {
402
- db: pgLiteDrizzle({
403
- schema,
404
- connection: {
405
- dataDir: connectionString,
406
- },
407
- }),
408
- };
409
- }
410
-
411
- // Create node-postgres instance
412
- const pool = new pg.Pool({
413
- connectionString,
414
- });
415
-
416
- return { db: nodePgDrizzle(pool, { schema }) };
417
- }`;
418
-
419
- // create directory if it doesn't exist
420
- fs.mkdirSync(path.dirname(dbPath), { recursive: true });
421
- fs.writeFileSync(dbPath, dbContent);
422
-
423
- consola.success(`Created ${cyan(`lib/${dbFileName}`)}`);
359
+ consola.success(`Created ${cyan("lib/schema.ts")}`);
424
360
  }
425
361
 
426
362
  console.log("\n");
@@ -442,17 +378,17 @@ ${yellow(`
442
378
 
443
379
  import { bigint, pgTable, text, uuid } from "drizzle-orm/pg-core";
444
380
 
445
- export const exampleTable = pgTable("example_table", {
381
+ export const cursorTable = pgTable("cursor_table", {
446
382
  id: uuid("id").primaryKey().defaultRandom(),
447
- number: bigint("number", { mode: "number" }),
448
- hash: text("hash"),
383
+ endCursor: bigint("end_cursor", { mode: "number" }),
384
+ uniqueKey: text("unique_key"),
449
385
  });`)}`);
450
386
 
451
387
  console.log("\n");
452
388
  }
453
389
 
454
390
  consola.info(
455
- `Run ${green(`${options.packageManager} run drizzle:generate`)} & ${green(`${options.packageManager} run drizzle:migrate`)} to generate and apply migrations.`,
391
+ `Run ${green(`${options.packageManager}${options.packageManager === "npm" ? " run" : ""} drizzle:generate`)} & ${green(`${options.packageManager}${options.packageManager === "npm" ? " run" : ""} drizzle:migrate`)} to generate and apply migrations.`,
456
392
  );
457
393
  }
458
394
 
@@ -463,3 +399,103 @@ export async function createStorageRelatedFiles(options: IndexerOptions) {
463
399
  await createDrizzleStorageFiles(options);
464
400
  }
465
401
  }
402
+
403
+ const gitIgnoreItems: {
404
+ isRecommended: boolean;
405
+ description?: string;
406
+ value: string;
407
+ }[] = [
408
+ {
409
+ isRecommended: false,
410
+ value: "node_modules",
411
+ },
412
+ {
413
+ isRecommended: false,
414
+ value: "dist",
415
+ },
416
+ {
417
+ isRecommended: true,
418
+ description: "build and dev files of apibara",
419
+ value: ".apibara",
420
+ },
421
+ {
422
+ isRecommended: false,
423
+ value: ".env",
424
+ },
425
+ {
426
+ isRecommended: false,
427
+ description: "for mac users",
428
+ value: ".DS_Store",
429
+ },
430
+ ];
431
+
432
+ export async function createGitIgnoreFile(cwd: string) {
433
+ const gitIgnorePath = path.join(cwd, ".gitignore");
434
+
435
+ if (fs.existsSync(gitIgnorePath)) {
436
+ const result = await prompts([
437
+ {
438
+ type: "select",
439
+ name: "overwrite",
440
+ message: `${cyan(".gitignore")} already exists. Please choose how to proceed:`,
441
+ initial: 0,
442
+ choices: [
443
+ {
444
+ title: "Choose items to append in your .gitignore",
445
+ value: "append",
446
+ },
447
+ {
448
+ title: "Keep original",
449
+ value: "ignore",
450
+ },
451
+ {
452
+ title: "Overwrite",
453
+ value: "overwrite",
454
+ },
455
+ ],
456
+ },
457
+ {
458
+ type: (overwrite: "append" | "ignore" | "overwrite") =>
459
+ overwrite === "append" ? "multiselect" : null,
460
+ name: "ignoreItems",
461
+ message: "Choose items to append in your .gitignore",
462
+ choices: gitIgnoreItems.map((item) => ({
463
+ title: `${yellow(item.value)}${
464
+ item.description ? ` - ${item.description}` : ""
465
+ }${item.isRecommended ? ` ${green("(recommended)")}` : ""}`,
466
+ value: item.value,
467
+ })),
468
+ },
469
+ ]);
470
+
471
+ const { overwrite, ignoreItems } = result as {
472
+ overwrite: "append" | "ignore" | "overwrite";
473
+ ignoreItems: string[];
474
+ };
475
+
476
+ if (overwrite === "append" && ignoreItems.length > 0) {
477
+ const gitIgnoreContent = fs.readFileSync(gitIgnorePath, "utf8");
478
+ fs.writeFileSync(
479
+ gitIgnorePath,
480
+ `${gitIgnoreContent}\n${result.ignoreItems.join("\n")}`,
481
+ );
482
+ consola.success(`Updated ${cyan(".gitignore")}`);
483
+ return;
484
+ }
485
+
486
+ if (overwrite === "overwrite") {
487
+ fs.writeFileSync(
488
+ gitIgnorePath,
489
+ gitIgnoreItems.map((item) => item.value).join("\n"),
490
+ );
491
+ consola.success(`Updated ${cyan(".gitignore")}`);
492
+ return;
493
+ }
494
+ }
495
+
496
+ fs.writeFileSync(
497
+ gitIgnorePath,
498
+ gitIgnoreItems.map((item) => item.value).join("\n"),
499
+ );
500
+ consola.success(`Created ${cyan(".gitignore")}`);
501
+ }
@@ -1,5 +1,6 @@
1
1
  import fs from "node:fs";
2
2
  import path, { basename } from "node:path";
3
+ import * as prettier from "prettier";
3
4
  import prompts from "prompts";
4
5
  import { blue, cyan, red, yellow } from "./colors";
5
6
  import { dnaUrls, networks } from "./constants";
@@ -410,3 +411,12 @@ function pkgFromUserAgent(userAgent: string | undefined): PkgInfo | undefined {
410
411
  version: pkgSpecArr[1],
411
412
  };
412
413
  }
414
+
415
+ export async function formatFile(path: string) {
416
+ const file = fs.readFileSync(path, "utf8");
417
+ const formatted = await prettier.format(file, {
418
+ filepath: path,
419
+ tabWidth: 2,
420
+ });
421
+ fs.writeFileSync(path, formatted);
422
+ }
@@ -1,5 +1,6 @@
1
1
  import type { ApibaraRuntimeConfig } from "apibara/types";
2
+ import { deserialize } from "../utils/helper";
2
3
 
3
4
  export function useRuntimeConfig(): ApibaraRuntimeConfig {
4
- return JSON.parse(process.env.APIBARA_RUNTIME_CONFIG || "{}");
5
+ return deserialize(process.env.APIBARA_RUNTIME_CONFIG || "{}");
5
6
  }
@@ -0,0 +1,108 @@
1
+ import { existsSync } from "node:fs";
2
+ import { builtinModules } from "node:module";
3
+ import replace from "@rollup/plugin-replace";
4
+ import type { Apibara } from "apibara/types";
5
+ import defu from "defu";
6
+ import { join } from "pathe";
7
+ import type {
8
+ ConfigExport,
9
+ RolldownOptions,
10
+ RolldownPluginOption,
11
+ } from "rolldown";
12
+ import { serialize } from "../utils/helper";
13
+ import { appConfig } from "./plugins/config";
14
+ import { indexers } from "./plugins/indexers";
15
+
16
+ const runtimeDependencies = [
17
+ "better-sqlite3",
18
+ "@electric-sql/pglite",
19
+ "pg",
20
+ // https://socket.io/docs/v4/server-installation/#additional-packages
21
+ "utf-8-validate",
22
+ "bufferutil",
23
+ "node-fetch",
24
+ ];
25
+
26
+ export function getRolldownConfig(apibara: Apibara): RolldownOptions {
27
+ const extensions: string[] = [
28
+ ".ts",
29
+ ".mjs",
30
+ ".js",
31
+ ".json",
32
+ ".node",
33
+ ".tsx",
34
+ ".jsx",
35
+ ];
36
+
37
+ const tsConfigExists = existsSync(
38
+ join(apibara.options.rootDir, "tsconfig.json"),
39
+ );
40
+
41
+ const rolldownConfig: RolldownOptions & {
42
+ plugins: RolldownPluginOption[];
43
+ } = defu(
44
+ // biome-ignore lint/suspicious/noExplicitAny: apibara.options.rolldownConfig is typed
45
+ apibara.options.rolldownConfig as any,
46
+ <ConfigExport>{
47
+ platform: "node",
48
+ input: apibara.options.entry,
49
+ output: {
50
+ dir: join(apibara.options.outputDir || "./.apibara/build"),
51
+ format: "esm",
52
+ entryFileNames: "[name].mjs",
53
+ chunkFileNames: "chunks/[name]-[hash].mjs",
54
+ sourcemap: true,
55
+ },
56
+ plugins: [],
57
+ onwarn(warning, rolldownWarn) {
58
+ if (
59
+ !["CIRCULAR_DEPENDENCY", "EVAL", "THIS_IS_UNDEFINED"].includes(
60
+ warning.code || "",
61
+ ) &&
62
+ !warning.message.includes("Unsupported source map comment") &&
63
+ !warning.message.includes("@__PURE__") &&
64
+ !warning.message.includes("/*#__PURE__*/")
65
+ ) {
66
+ rolldownWarn(warning);
67
+ }
68
+ },
69
+ resolve: {
70
+ extensions,
71
+ preferBuiltins: !!apibara.options.node,
72
+ mainFields: ["main"],
73
+ exportConditions: apibara.options.exportConditions,
74
+ tsconfigFilename: tsConfigExists ? "tsconfig.json" : undefined,
75
+ },
76
+ treeshake: true,
77
+ external: [...builtinModules, ...runtimeDependencies],
78
+ },
79
+ );
80
+
81
+ rolldownConfig.plugins?.push(
82
+ replace({
83
+ preventAssignment: true,
84
+ values: {
85
+ "process.env.APIBARA_CONFIG": getSerializedRuntimeConfig(apibara),
86
+ },
87
+ }) as RolldownPluginOption,
88
+ );
89
+ rolldownConfig.plugins?.push(indexers(apibara));
90
+ rolldownConfig.plugins?.push(appConfig(apibara));
91
+
92
+ return rolldownConfig;
93
+ }
94
+
95
+ function getSerializedRuntimeConfig(apibara: Apibara) {
96
+ try {
97
+ return serialize({
98
+ runtimeConfig: apibara.options.runtimeConfig,
99
+ preset: apibara.options.preset,
100
+ presets: apibara.options.presets,
101
+ });
102
+ } catch (error) {
103
+ throw new Error(
104
+ "Failed to serialize runtime config. Please ensure all values in your runtime configuration are JSON serializable. BigInt values are supported, but functions, symbols, etc. are not. Check your configuration for non-serializable values.",
105
+ { cause: error },
106
+ );
107
+ }
108
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./config";
2
+ export type { Plugin } from "rolldown";
@@ -0,0 +1,25 @@
1
+ import virtual from "@rollup/plugin-virtual";
2
+ import type { Apibara } from "apibara/types";
3
+ import type { RolldownPluginOption } from "rolldown";
4
+
5
+ export function appConfig(apibara: Apibara) {
6
+ return virtual({
7
+ "#apibara-internal-virtual/config": `
8
+ const serializedConfig = \`process.env.APIBARA_CONFIG\`;
9
+
10
+ if (serializedConfig === undefined || serializedConfig === "") {
11
+ throw new Error("APIBARA_CONFIG is not defined");
12
+ }
13
+
14
+ function deserialize(str) {
15
+ return JSON.parse(str, (_, value) =>
16
+ typeof value === "string" && value.match(/^\\d+n$/)
17
+ ? BigInt(value.slice(0, -1))
18
+ : value,
19
+ );
20
+ }
21
+
22
+ export const config = deserialize(serializedConfig);
23
+ `,
24
+ }) as RolldownPluginOption;
25
+ }
@@ -1,17 +1,17 @@
1
1
  import virtual from "@rollup/plugin-virtual";
2
2
  import type { Apibara } from "apibara/types";
3
3
  import { hash } from "ohash";
4
+ import type { RolldownPluginOption } from "rolldown";
4
5
 
5
6
  export function indexers(apibara: Apibara) {
6
7
  const indexers = [...new Set(apibara.indexers)];
7
-
8
8
  return virtual({
9
9
  "#apibara-internal-virtual/indexers": `
10
- ${indexers.map((i) => `import _${hash(i)} from '${i.indexer}';`).join("\n")}
10
+ ${indexers.map((i) => `import * as _${hash(i)} from '${i.indexer}';`).join("\n")}
11
11
 
12
12
  export const indexers = [
13
13
  ${indexers.map((i) => `{ name: "${i.name}", indexer: _${hash(i)} }`).join(",\n")}
14
14
  ];
15
15
  `,
16
- });
16
+ }) as RolldownPluginOption;
17
17
  }
@@ -37,6 +37,9 @@ const startCommand = defineCommand({
37
37
  await Promise.all(
38
38
  selectedIndexers.map(async (indexer) => {
39
39
  const indexerInstance = createIndexer(indexer, preset);
40
+ if (!indexerInstance) {
41
+ return;
42
+ }
40
43
 
41
44
  const client = createClient(
42
45
  indexerInstance.streamConfig,