apibara 2.1.0-beta.4 → 2.1.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.
Files changed (119) hide show
  1. package/dist/chunks/add.mjs +16 -8
  2. package/dist/chunks/add.mjs.map +1 -0
  3. package/dist/chunks/build.mjs +4 -2
  4. package/dist/chunks/build.mjs.map +1 -0
  5. package/dist/chunks/dev.mjs +55 -21
  6. package/dist/chunks/dev.mjs.map +1 -0
  7. package/dist/chunks/init.mjs +11 -7
  8. package/dist/chunks/init.mjs.map +1 -0
  9. package/dist/chunks/prepare.mjs +4 -2
  10. package/dist/chunks/prepare.mjs.map +1 -0
  11. package/dist/chunks/start.mjs +16 -4
  12. package/dist/chunks/start.mjs.map +1 -0
  13. package/dist/chunks/write-project-info.mjs +51 -0
  14. package/dist/chunks/write-project-info.mjs.map +1 -0
  15. package/dist/cli/index.mjs +3 -1
  16. package/dist/cli/index.mjs.map +1 -0
  17. package/dist/common/index.d.mts +33 -0
  18. package/dist/common/index.d.ts +33 -0
  19. package/dist/common/index.mjs +91 -0
  20. package/dist/common/index.mjs.map +1 -0
  21. package/dist/config/index.mjs +1 -0
  22. package/dist/config/index.mjs.map +1 -0
  23. package/dist/core/index.mjs +134 -69
  24. package/dist/core/index.mjs.map +1 -0
  25. package/dist/create/index.d.mts +2 -1
  26. package/dist/create/index.d.ts +2 -1
  27. package/dist/create/index.mjs +168 -139
  28. package/dist/create/index.mjs.map +1 -0
  29. package/dist/hooks/index.mjs +6 -1
  30. package/dist/hooks/index.mjs.map +1 -0
  31. package/dist/indexer/index.d.ts +1 -0
  32. package/dist/indexer/index.mjs +1 -0
  33. package/dist/indexer/plugins.d.ts +1 -0
  34. package/dist/indexer/plugins.mjs +1 -0
  35. package/dist/indexer/testing.d.ts +1 -0
  36. package/dist/indexer/testing.mjs +1 -0
  37. package/dist/indexer/vcr.d.ts +1 -0
  38. package/dist/indexer/vcr.mjs +1 -0
  39. package/dist/rolldown/index.d.mts +7 -0
  40. package/dist/rolldown/index.d.ts +7 -0
  41. package/dist/rolldown/index.mjs +141 -0
  42. package/dist/rolldown/index.mjs.map +1 -0
  43. package/dist/runtime/dev.mjs +39 -17
  44. package/dist/runtime/internal/app.d.ts +14 -1
  45. package/dist/runtime/internal/app.mjs +26 -21
  46. package/dist/runtime/project-info.d.ts +3 -0
  47. package/dist/runtime/project-info.mjs +67 -0
  48. package/dist/runtime/start.mjs +78 -11
  49. package/dist/shared/apibara.730bb1e4.mjs +18 -0
  50. package/dist/shared/apibara.730bb1e4.mjs.map +1 -0
  51. package/dist/types/index.d.mts +24 -20
  52. package/dist/types/index.d.ts +24 -20
  53. package/dist/types/index.mjs +1 -0
  54. package/dist/types/index.mjs.map +1 -0
  55. package/package.json +33 -16
  56. package/src/cli/commands/add.ts +16 -7
  57. package/src/cli/commands/build.ts +5 -2
  58. package/src/cli/commands/dev.ts +64 -20
  59. package/src/cli/commands/init.ts +12 -7
  60. package/src/cli/commands/prepare.ts +4 -3
  61. package/src/cli/commands/start.ts +18 -3
  62. package/src/cli/commands/write-project-info.ts +56 -0
  63. package/src/cli/index.ts +2 -0
  64. package/src/common/cli.ts +40 -0
  65. package/src/common/constants.ts +6 -0
  66. package/src/common/helper.ts +86 -0
  67. package/src/common/index.ts +3 -0
  68. package/src/core/apibara.ts +7 -2
  69. package/src/core/build/build.ts +13 -5
  70. package/src/core/build/dev.ts +46 -23
  71. package/src/core/build/error.ts +9 -14
  72. package/src/core/build/prepare.ts +5 -3
  73. package/src/core/build/prod.ts +25 -16
  74. package/src/core/build/types.ts +11 -1
  75. package/src/core/config/defaults.ts +3 -0
  76. package/src/core/config/loader.ts +15 -7
  77. package/src/core/config/resolvers/runtime.resolver.ts +44 -0
  78. package/src/core/config/update.ts +6 -2
  79. package/src/core/scan.ts +1 -1
  80. package/src/create/add.ts +14 -20
  81. package/src/create/constants.ts +5 -7
  82. package/src/create/init.ts +8 -5
  83. package/src/create/templates.ts +144 -116
  84. package/src/create/types.ts +3 -0
  85. package/src/create/utils.ts +20 -7
  86. package/src/hooks/useRuntimeConfig.ts +4 -1
  87. package/src/indexer/index.ts +1 -0
  88. package/src/indexer/plugins.ts +1 -0
  89. package/src/indexer/testing.ts +1 -0
  90. package/src/indexer/vcr.ts +1 -0
  91. package/src/rolldown/config.ts +86 -0
  92. package/src/rolldown/index.ts +2 -0
  93. package/src/{rollup → rolldown}/plugins/indexers.ts +3 -3
  94. package/src/rolldown/plugins/instrumentation.ts +68 -0
  95. package/src/rolldown/plugins/static-config.ts +21 -0
  96. package/src/runtime/dev.ts +49 -19
  97. package/src/runtime/internal/app.ts +42 -29
  98. package/src/runtime/project-info.ts +90 -0
  99. package/src/runtime/start.ts +91 -11
  100. package/src/types/config.ts +27 -13
  101. package/src/types/hooks.ts +8 -5
  102. package/src/types/index.ts +1 -1
  103. package/src/types/rolldown.ts +5 -0
  104. package/src/types/virtual/indexers.d.ts +4 -1
  105. package/src/types/virtual/instrumentation.d.ts +4 -0
  106. package/src/types/virtual/static-config.d.ts +4 -0
  107. package/dist/rollup/index.d.mts +0 -6
  108. package/dist/rollup/index.d.ts +0 -6
  109. package/dist/rollup/index.mjs +0 -150
  110. package/dist/shared/apibara.1b515d04.mjs +0 -8
  111. package/src/cli/common.ts +0 -8
  112. package/src/core/config/resolvers/preset.resolver.ts +0 -9
  113. package/src/core/config/resolvers/runtime-config.resolver.ts +0 -6
  114. package/src/rollup/config.ts +0 -87
  115. package/src/rollup/index.ts +0 -2
  116. package/src/rollup/plugins/config.ts +0 -12
  117. package/src/rollup/plugins/esm-shim.ts +0 -69
  118. package/src/types/rollup.ts +0 -8
  119. package/src/types/virtual/config.d.ts +0 -3
@@ -1,6 +1,7 @@
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";
@@ -14,21 +15,18 @@ 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",
21
22
  ...(isTypeScript && { typecheck: "tsc --noEmit" }),
22
23
  },
23
24
  dependencies: {
24
- "@apibara/indexer": packageVersions["@apibara/indexer"],
25
25
  "@apibara/protocol": packageVersions["@apibara/protocol"],
26
26
  apibara: packageVersions.apibara,
27
27
  },
28
28
  devDependencies: {
29
29
  ...(isTypeScript && {
30
- "@rollup/plugin-typescript":
31
- packageVersions["@rollup/plugin-typescript"],
32
30
  "@types/node": packageVersions["@types/node"],
33
31
  typescript: packageVersions.typescript,
34
32
  }),
@@ -58,17 +56,10 @@ export function generateTsConfig() {
58
56
  }
59
57
 
60
58
  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";
59
+ return `import { defineConfig } from "apibara/config";
62
60
 
63
61
  export default defineConfig({
64
- runtimeConfig: {},${
65
- isTypeScript
66
- ? `
67
- rollupConfig: {
68
- plugins: [typescript()${isTypeScript ? " as Plugin" : ""}],
69
- },`
70
- : ""
71
- }
62
+ runtimeConfig: {},
72
63
  });\n`;
73
64
  }
74
65
 
@@ -78,9 +69,10 @@ export function generateIndexer({
78
69
  chain,
79
70
  language,
80
71
  }: IndexerOptions) {
81
- return `import { defineIndexer } from "@apibara/indexer";
82
- import { useLogger } from "@apibara/indexer/plugins";
72
+ return `import { defineIndexer } from "apibara/indexer";
73
+ import { useLogger } from "apibara/plugins";
83
74
  ${storage === "postgres" ? `import { drizzleStorage } from "@apibara/plugin-drizzle";` : ""}
75
+ ${storage === "postgres" ? `import { drizzle } from "@apibara/plugin-drizzle";` : ""}
84
76
  ${
85
77
  chain === "ethereum"
86
78
  ? `import { EvmStream } from "@apibara/evm";`
@@ -91,19 +83,16 @@ ${
91
83
  : ""
92
84
  }
93
85
  ${language === "typescript" ? `import type { ApibaraRuntimeConfig } from "apibara/types";` : ""}
94
- ${
95
- storage === "postgres"
96
- ? `import { getDrizzlePgDatabase } from "../lib/db";`
97
- : ""
98
- }
86
+ ${storage === "postgres" ? `import * as schema from "../lib/schema";` : ""}
99
87
 
100
88
 
101
89
  export default function (runtimeConfig${language === "typescript" ? ": ApibaraRuntimeConfig" : ""}) {
102
- const indexerId = "${indexerId}";
103
- const { startingBlock, streamUrl${storage === "postgres" ? ", postgresConnectionString" : ""} } = runtimeConfig[indexerId];
90
+ const { startingBlock, streamUrl } = runtimeConfig["${indexerId}"];
104
91
  ${
105
92
  storage === "postgres"
106
- ? "const { db } = getDrizzlePgDatabase(postgresConnectionString);"
93
+ ? `const db = drizzle({
94
+ schema,
95
+ });`
107
96
  : ""
108
97
  }
109
98
 
@@ -120,9 +109,9 @@ export default function (runtimeConfig${language === "typescript" ? ": ApibaraRu
120
109
  finality: "accepted",
121
110
  startingBlock: BigInt(startingBlock),
122
111
  filter: {
123
- header: "always",
112
+ ${chain === "ethereum" ? "logs: []," : chain === "starknet" ? "events: []," : ""}
124
113
  },
125
- plugins: [${storage === "postgres" ? "drizzleStorage({ db, persistState: true })" : ""}],
114
+ plugins: [${storage === "postgres" ? "drizzleStorage({ db, migrate: { migrationsFolder: './drizzle' } })" : ""}],
126
115
  async transform({ endCursor, finality }) {
127
116
  const logger = useLogger();
128
117
 
@@ -136,14 +125,12 @@ export default function (runtimeConfig${language === "typescript" ? ": ApibaraRu
136
125
  ${
137
126
  storage === "postgres"
138
127
  ? `// 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
- // }`
128
+ // const { db: database } = useDrizzleStorage();
129
+
130
+ // await database.insert(schema.cursorTable).values({
131
+ // endCursor: Number(endCursor?.orderKey),
132
+ // uniqueKey: \`\${endCursor?.uniqueKey}\`,
133
+ // });`
147
134
  : ""
148
135
  }
149
136
  },
@@ -156,7 +143,7 @@ export async function createIndexerFile(options: IndexerOptions) {
156
143
  const indexerFilePath = path.join(
157
144
  options.cwd,
158
145
  "indexers",
159
- `${options.indexerFileId}.indexer.${options.language === "typescript" ? "ts" : "js"}`,
146
+ `${options.indexerFileId}.indexer.${options.extension}`,
160
147
  );
161
148
 
162
149
  const { exists, overwrite } = await checkFileExists(indexerFilePath, {
@@ -227,20 +214,14 @@ export async function updateApibaraConfigFile({
227
214
  language,
228
215
  network,
229
216
  dnaUrl,
217
+ extension,
230
218
  }: IndexerOptions) {
231
- const pathToConfig = path.join(
232
- cwd,
233
- `apibara.config.${language === "typescript" ? "ts" : "js"}`,
234
- );
219
+ const pathToConfig = path.join(cwd, `apibara.config.${extension}`);
235
220
 
236
221
  const runtimeConfigString = `{
237
222
  startingBlock: 0,
238
- streamUrl: "${dnaUrl ?? getDnaUrl(chain, network)}"${
239
- storage === "postgres"
240
- ? `,
241
- postgresConnectionString: process.env["POSTGRES_CONNECTION_STRING"] ?? "memory://${indexerId}"`
242
- : ""
243
- }}`;
223
+ streamUrl: "${dnaUrl ?? getDnaUrl(chain, network)}"
224
+ }`;
244
225
 
245
226
  const project = new Project();
246
227
  const sourceFile = project.addSourceFileAtPath(pathToConfig);
@@ -284,12 +265,16 @@ export async function updateApibaraConfigFile({
284
265
  }
285
266
 
286
267
  export async function createDrizzleStorageFiles(options: IndexerOptions) {
287
- const { cwd, language, storage } = options;
268
+ const {
269
+ cwd,
270
+ language,
271
+ storage,
272
+ indexerId,
273
+ extension: fileExtension,
274
+ } = options;
288
275
 
289
276
  if (storage !== "postgres") return;
290
277
 
291
- const fileExtension = language === "typescript" ? "ts" : "js";
292
-
293
278
  /**
294
279
  *
295
280
  *
@@ -312,11 +297,11 @@ export async function createDrizzleStorageFiles(options: IndexerOptions) {
312
297
  const drizzleConfigContent = `${language === "typescript" ? 'import type { Config } from "drizzle-kit";' : ""}
313
298
 
314
299
  export default {
315
- schema: "./lib/schema.ts",
300
+ schema: "./lib/schema.${fileExtension}",
316
301
  out: "./drizzle",
317
302
  dialect: "postgresql",
318
303
  dbCredentials: {
319
- url: process.env["POSTGRES_CONNECTION_STRING"] ?? "",
304
+ url: process.env["POSTGRES_CONNECTION_STRING"] ?? "memory://${indexerId}",
320
305
  },
321
306
  }${language === "typescript" ? " satisfies Config" : ""};`;
322
307
 
@@ -347,14 +332,14 @@ export default {
347
332
  });
348
333
 
349
334
  if (!schemaExists || schemaOverwrite) {
350
- const schemaContent = `// --- Add your pg table schemas here ----
335
+ const schemaContent = `// --- Add your pg table schemas here ----
351
336
 
352
337
  // import { bigint, pgTable, text, uuid } from "drizzle-orm/pg-core";
353
338
 
354
- // export const exampleTable = pgTable("example_table", {
339
+ // export const cursorTable = pgTable("cursor_table", {
355
340
  // id: uuid("id").primaryKey().defaultRandom(),
356
- // number: bigint("number", { mode: "number" }),
357
- // hash: text("hash"),
341
+ // endCursor: bigint("end_cursor", { mode: "number" }),
342
+ // uniqueKey: text("unique_key"),
358
343
  // });
359
344
 
360
345
  export {};
@@ -366,64 +351,7 @@ export {};
366
351
 
367
352
  await formatFile(schemaPath);
368
353
 
369
- consola.success(`Created ${cyan("lib/schema.ts")}`);
370
- }
371
-
372
- /**
373
- *
374
- *
375
- * DB File
376
- *
377
- *
378
- */
379
- const dbFileName = `db.${fileExtension}`;
380
-
381
- const dbPath = path.join(cwd, "lib", dbFileName);
382
-
383
- const { exists: dbExists, overwrite: dbOverwrite } = await checkFileExists(
384
- dbPath,
385
- {
386
- askPrompt: true,
387
- fileName: `lib/${dbFileName}`,
388
- allowIgnore: true,
389
- },
390
- );
391
-
392
- if (!dbExists || dbOverwrite) {
393
- const dbContent = `import * as schema from "./schema";
394
- import { drizzle as nodePgDrizzle } from "drizzle-orm/node-postgres";
395
- import { drizzle as pgLiteDrizzle } from "drizzle-orm/pglite";
396
- import pg from "pg";
397
-
398
-
399
- export function getDrizzlePgDatabase(connectionString${language === "typescript" ? ": string" : ""}) {
400
- // Create pglite instance
401
- if (connectionString.includes("memory")) {
402
- return {
403
- db: pgLiteDrizzle({
404
- schema,
405
- connection: {
406
- dataDir: connectionString,
407
- },
408
- }),
409
- };
410
- }
411
-
412
- // Create node-postgres instance
413
- const pool = new pg.Pool({
414
- connectionString,
415
- });
416
-
417
- return { db: nodePgDrizzle(pool, { schema }) };
418
- }`;
419
-
420
- // create directory if it doesn't exist
421
- fs.mkdirSync(path.dirname(dbPath), { recursive: true });
422
- fs.writeFileSync(dbPath, dbContent);
423
-
424
- await formatFile(dbPath);
425
-
426
- consola.success(`Created ${cyan(`lib/${dbFileName}`)}`);
354
+ consola.success(`Created ${cyan(`lib/${schemaFileName}`)}`);
427
355
  }
428
356
 
429
357
  console.log("\n");
@@ -440,22 +368,22 @@ export function getDrizzlePgDatabase(connectionString${language === "typescript"
440
368
 
441
369
  ${yellow(`
442
370
  ┌──────────────────────────────────────────┐
443
- │ lib/schema.ts
371
+ │ lib/schema
444
372
  └──────────────────────────────────────────┘
445
373
 
446
374
  import { bigint, pgTable, text, uuid } from "drizzle-orm/pg-core";
447
375
 
448
- export const exampleTable = pgTable("example_table", {
376
+ export const cursorTable = pgTable("cursor_table", {
449
377
  id: uuid("id").primaryKey().defaultRandom(),
450
- number: bigint("number", { mode: "number" }),
451
- hash: text("hash"),
378
+ endCursor: bigint("end_cursor", { mode: "number" }),
379
+ uniqueKey: text("unique_key"),
452
380
  });`)}`);
453
381
 
454
382
  console.log("\n");
455
383
  }
456
384
 
457
385
  consola.info(
458
- `Run ${green(`${options.packageManager} run drizzle:generate`)} & ${green(`${options.packageManager} run drizzle:migrate`)} to generate and apply migrations.`,
386
+ `Run ${green(`${options.packageManager}${options.packageManager === "npm" ? " run" : ""} drizzle:generate`)} & ${green(`${options.packageManager}${options.packageManager === "npm" ? " run" : ""} drizzle:migrate`)} to generate and apply migrations.`,
459
387
  );
460
388
  }
461
389
 
@@ -466,3 +394,103 @@ export async function createStorageRelatedFiles(options: IndexerOptions) {
466
394
  await createDrizzleStorageFiles(options);
467
395
  }
468
396
  }
397
+
398
+ const gitIgnoreItems: {
399
+ isRecommended: boolean;
400
+ description?: string;
401
+ value: string;
402
+ }[] = [
403
+ {
404
+ isRecommended: false,
405
+ value: "node_modules",
406
+ },
407
+ {
408
+ isRecommended: false,
409
+ value: "dist",
410
+ },
411
+ {
412
+ isRecommended: true,
413
+ description: "build and dev files of apibara",
414
+ value: ".apibara",
415
+ },
416
+ {
417
+ isRecommended: false,
418
+ value: ".env",
419
+ },
420
+ {
421
+ isRecommended: false,
422
+ description: "for mac users",
423
+ value: ".DS_Store",
424
+ },
425
+ ];
426
+
427
+ export async function createGitIgnoreFile(cwd: string) {
428
+ const gitIgnorePath = path.join(cwd, ".gitignore");
429
+
430
+ if (fs.existsSync(gitIgnorePath)) {
431
+ const result = await prompts([
432
+ {
433
+ type: "select",
434
+ name: "overwrite",
435
+ message: `${cyan(".gitignore")} already exists. Please choose how to proceed:`,
436
+ initial: 0,
437
+ choices: [
438
+ {
439
+ title: "Choose items to append in your .gitignore",
440
+ value: "append",
441
+ },
442
+ {
443
+ title: "Keep original",
444
+ value: "ignore",
445
+ },
446
+ {
447
+ title: "Overwrite",
448
+ value: "overwrite",
449
+ },
450
+ ],
451
+ },
452
+ {
453
+ type: (overwrite: "append" | "ignore" | "overwrite") =>
454
+ overwrite === "append" ? "multiselect" : null,
455
+ name: "ignoreItems",
456
+ message: "Choose items to append in your .gitignore",
457
+ choices: gitIgnoreItems.map((item) => ({
458
+ title: `${yellow(item.value)}${
459
+ item.description ? ` - ${item.description}` : ""
460
+ }${item.isRecommended ? ` ${green("(recommended)")}` : ""}`,
461
+ value: item.value,
462
+ })),
463
+ },
464
+ ]);
465
+
466
+ const { overwrite, ignoreItems } = result as {
467
+ overwrite: "append" | "ignore" | "overwrite";
468
+ ignoreItems: string[];
469
+ };
470
+
471
+ if (overwrite === "append" && ignoreItems.length > 0) {
472
+ const gitIgnoreContent = fs.readFileSync(gitIgnorePath, "utf8");
473
+ fs.writeFileSync(
474
+ gitIgnorePath,
475
+ `${gitIgnoreContent}\n${result.ignoreItems.join("\n")}`,
476
+ );
477
+ consola.success(`Updated ${cyan(".gitignore")}`);
478
+ return;
479
+ }
480
+
481
+ if (overwrite === "overwrite") {
482
+ fs.writeFileSync(
483
+ gitIgnorePath,
484
+ gitIgnoreItems.map((item) => item.value).join("\n"),
485
+ );
486
+ consola.success(`Updated ${cyan(".gitignore")}`);
487
+ return;
488
+ }
489
+ }
490
+
491
+ fs.writeFileSync(
492
+ gitIgnorePath,
493
+ gitIgnoreItems.map((item) => item.value).join("\n"),
494
+ );
495
+ consola.success(`Created ${cyan(".gitignore")}`);
496
+ }
@@ -16,6 +16,8 @@ export type Network =
16
16
 
17
17
  export type Storage = "postgres" | "none";
18
18
 
19
+ export type FileExtension = "js" | "ts" | "mjs";
20
+
19
21
  export type IndexerOptions = {
20
22
  cwd: string;
21
23
  indexerFileId: string;
@@ -26,6 +28,7 @@ export type IndexerOptions = {
26
28
  dnaUrl?: string;
27
29
  packageManager: string;
28
30
  language: Language;
31
+ extension: FileExtension;
29
32
  };
30
33
 
31
34
  export type PkgInfo = {
@@ -4,7 +4,7 @@ import * as prettier from "prettier";
4
4
  import prompts from "prompts";
5
5
  import { blue, cyan, red, yellow } from "./colors";
6
6
  import { dnaUrls, networks } from "./constants";
7
- import type { Chain, Language, Network, PkgInfo } from "./types";
7
+ import type { Chain, FileExtension, Language, Network, PkgInfo } from "./types";
8
8
 
9
9
  export function isEmpty(path: string) {
10
10
  const files = fs.readdirSync(path);
@@ -31,7 +31,8 @@ export function validateLanguage(language?: string, throwError = false) {
31
31
  language === "typescript" ||
32
32
  language === "ts" ||
33
33
  language === "javascript" ||
34
- language === "js"
34
+ language === "js" ||
35
+ language === "mjs"
35
36
  ) {
36
37
  return true;
37
38
  }
@@ -49,7 +50,7 @@ export function getLanguageFromAlias(alias: string): Language {
49
50
  if (alias === "ts" || alias === "typescript") {
50
51
  return "typescript";
51
52
  }
52
- if (alias === "js" || alias === "javascript") {
53
+ if (alias === "js" || alias === "javascript" || alias === "mjs") {
53
54
  return "javascript";
54
55
  }
55
56
 
@@ -184,19 +185,31 @@ export function validateDnaUrl(dnaUrl?: string, throwError = false) {
184
185
  export function hasApibaraConfig(cwd: string): boolean {
185
186
  const configPathJS = path.join(cwd, "apibara.config.js");
186
187
  const configPathTS = path.join(cwd, "apibara.config.ts");
188
+ const configPathMJS = path.join(cwd, "apibara.config.mjs");
187
189
 
188
- return fs.existsSync(configPathJS) || fs.existsSync(configPathTS);
190
+ return (
191
+ fs.existsSync(configPathJS) ||
192
+ fs.existsSync(configPathTS) ||
193
+ fs.existsSync(configPathMJS)
194
+ );
189
195
  }
190
196
 
191
- export function getApibaraConfigLanguage(cwd: string): Language {
197
+ export function getApibaraConfigLanguage(cwd: string): {
198
+ language: Language;
199
+ extension: FileExtension;
200
+ } {
192
201
  const configPathJS = path.join(cwd, "apibara.config.js");
193
202
  const configPathTS = path.join(cwd, "apibara.config.ts");
203
+ const configPathMJS = path.join(cwd, "apibara.config.mjs");
194
204
 
205
+ if (fs.existsSync(configPathMJS)) {
206
+ return { language: "javascript", extension: "mjs" };
207
+ }
195
208
  if (fs.existsSync(configPathJS)) {
196
- return "javascript";
209
+ return { language: "javascript", extension: "js" };
197
210
  }
198
211
  if (fs.existsSync(configPathTS)) {
199
- return "typescript";
212
+ return { language: "typescript", extension: "ts" };
200
213
  }
201
214
 
202
215
  throw new Error(red("✖") + " No apibara.config found");
@@ -1,5 +1,8 @@
1
+ import { ENV_INTERNAL_APIBARA_PROCESSED_RUNTIME } from "apibara/common";
1
2
  import type { ApibaraRuntimeConfig } from "apibara/types";
2
3
 
3
4
  export function useRuntimeConfig(): ApibaraRuntimeConfig {
4
- return JSON.parse(process.env.APIBARA_RUNTIME_CONFIG || "{}");
5
+ return JSON.parse(
6
+ process.env[ENV_INTERNAL_APIBARA_PROCESSED_RUNTIME] || "{}",
7
+ );
5
8
  }
@@ -0,0 +1 @@
1
+ export * from "@apibara/indexer";
@@ -0,0 +1 @@
1
+ export * from "@apibara/indexer/plugins";
@@ -0,0 +1 @@
1
+ export * from "@apibara/indexer/testing";
@@ -0,0 +1 @@
1
+ export * from "@apibara/indexer/vcr";
@@ -0,0 +1,86 @@
1
+ import { existsSync } from "node:fs";
2
+ import { builtinModules } from "node:module";
3
+ import type { Apibara } from "apibara/types";
4
+ import defu from "defu";
5
+ import { join } from "pathe";
6
+ import type {
7
+ ConfigExport,
8
+ RolldownOptions,
9
+ RolldownPluginOption,
10
+ } from "rolldown";
11
+ import { indexers } from "./plugins/indexers";
12
+ import { instrumentation } from "./plugins/instrumentation";
13
+ import { staticConfig } from "./plugins/static-config";
14
+
15
+ const runtimeDependencies = [
16
+ "better-sqlite3",
17
+ "@electric-sql/pglite",
18
+ "pg",
19
+ // https://socket.io/docs/v4/server-installation/#additional-packages
20
+ "utf-8-validate",
21
+ "bufferutil",
22
+ "fsevents",
23
+ // was giving unresolved import warnings from `node-fetch` library.
24
+ "encoding",
25
+ ];
26
+
27
+ export function getRolldownConfig(apibara: Apibara): RolldownOptions {
28
+ const extensions: string[] = [
29
+ ".ts",
30
+ ".mjs",
31
+ ".js",
32
+ ".json",
33
+ ".node",
34
+ ".tsx",
35
+ ".jsx",
36
+ ];
37
+
38
+ const tsConfigExists = existsSync(
39
+ join(apibara.options.rootDir, "tsconfig.json"),
40
+ );
41
+
42
+ const rolldownConfig: RolldownOptions & {
43
+ plugins: RolldownPluginOption[];
44
+ } = defu(
45
+ // biome-ignore lint/suspicious/noExplicitAny: apibara.options.rolldownConfig is typed
46
+ apibara.options.rolldownConfig as any,
47
+ <ConfigExport>{
48
+ platform: "node",
49
+ input: apibara.options.entry,
50
+ output: {
51
+ dir: join(apibara.options.outputDir || "./.apibara/build"),
52
+ format: "esm",
53
+ entryFileNames: "[name].mjs",
54
+ chunkFileNames: "chunks/[name]-[hash].mjs",
55
+ sourcemap: true,
56
+ },
57
+ plugins: [],
58
+ onwarn(warning, rolldownWarn) {
59
+ if (
60
+ !["CIRCULAR_DEPENDENCY", "EVAL", "THIS_IS_UNDEFINED"].includes(
61
+ warning.code || "",
62
+ ) &&
63
+ !warning.message.includes("Unsupported source map comment") &&
64
+ !warning.message.includes("@__PURE__") &&
65
+ !warning.message.includes("/*#__PURE__*/")
66
+ ) {
67
+ rolldownWarn(warning);
68
+ }
69
+ },
70
+ resolve: {
71
+ extensions,
72
+ preferBuiltins: !!apibara.options.node,
73
+ mainFields: ["main"],
74
+ exportConditions: apibara.options.exportConditions,
75
+ tsconfigFilename: tsConfigExists ? "tsconfig.json" : undefined,
76
+ },
77
+ treeshake: true,
78
+ external: [...builtinModules, ...runtimeDependencies],
79
+ },
80
+ );
81
+
82
+ rolldownConfig.plugins?.push(staticConfig(apibara));
83
+ rolldownConfig.plugins?.push(instrumentation(apibara));
84
+ rolldownConfig.plugins?.push(indexers(apibara));
85
+ return rolldownConfig;
86
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./config";
2
+ export type { Plugin } from "rolldown";
@@ -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
  }
@@ -0,0 +1,68 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import virtual from "@rollup/plugin-virtual";
4
+ import type { Apibara } from "apibara/types";
5
+ import type { RolldownPluginOption } from "rolldown";
6
+
7
+ export function instrumentation(apibara: Apibara) {
8
+ const instrumentationPath = join(
9
+ apibara.options._c12.cwd!,
10
+ `instrumentation.${apibara.options._c12.configFile?.endsWith(".ts") ? "ts" : apibara.options._c12.configFile?.endsWith(".mjs") ? "mjs" : "js"}`,
11
+ );
12
+
13
+ if (!existsSync(instrumentationPath)) {
14
+ return virtual({
15
+ "#apibara-internal-virtual/instrumentation": `
16
+ let register = undefined;
17
+ let logger = undefined;
18
+
19
+ export { register, logger };
20
+ `,
21
+ }) as RolldownPluginOption;
22
+ }
23
+
24
+ /**
25
+ * We are importing the instrumentation file inline with "require" instead of "import" at the top of the file to avoid warnings from rolldown
26
+ * when some methods are not defined in the instrumentation file.
27
+ *
28
+ * Example warning:
29
+ *
30
+ * [IMPORT_IS_UNDEFINED] Warning: Import `logger` will always be undefined because there is no matching export in 'instrumentation.ts'
31
+ * ╭─[virtual:#apibara-internal-virtual/instrumentation:11:35]
32
+ * │
33
+ * 11 │ if (instrumentation && typeof instrumentation.logger === "function") {
34
+ * │ ───────────┬──────────
35
+ * │ ╰────────────
36
+ * ────╯
37
+
38
+ * [IMPORT_IS_UNDEFINED] Warning: Import `logger` will always be undefined because there is no matching export in 'instrumentation.ts'
39
+ * ╭─[virtual:#apibara-internal-virtual/instrumentation:12:16]
40
+ * │
41
+ * 12 │ logger = instrumentation.logger;
42
+ * │ ───────────┬──────────
43
+ * │ ╰────────────
44
+ * ────╯
45
+ */
46
+ return virtual({
47
+ "#apibara-internal-virtual/instrumentation": `
48
+ let register = undefined;
49
+ let logger = undefined;
50
+
51
+ try {
52
+ const instrumentation = require('${instrumentationPath}');
53
+
54
+ if (instrumentation?.register && typeof instrumentation.register === "function") {
55
+ register = instrumentation.register;
56
+ }
57
+
58
+ if (instrumentation?.logger && typeof instrumentation.logger === "function") {
59
+ logger = instrumentation.logger;
60
+ }
61
+ } catch {
62
+ // Silently handle any require errors
63
+ }
64
+
65
+ export { register, logger };
66
+ `,
67
+ }) as RolldownPluginOption;
68
+ }