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,9 +1,10 @@
1
+ import path, { basename } from 'node:path';
1
2
  import consola$1, { consola } from 'consola';
2
3
  import prompts from 'prompts';
3
4
  import colors from 'picocolors';
4
5
  import fs from 'node:fs';
5
- import path, { basename } from 'node:path';
6
6
  import { Project, SyntaxKind } from 'ts-morph';
7
+ import * as prettier from 'prettier';
7
8
 
8
9
  const {
9
10
  blue,
@@ -56,17 +57,17 @@ const storages = [
56
57
  ];
57
58
  const packageVersions = {
58
59
  // Required Dependencies
59
- apibara: "^2.1.0-beta.1",
60
- "@apibara/indexer": "^2.1.0-beta.1",
61
- "@apibara/protocol": "^2.1.0-beta.1",
60
+ apibara: "next",
61
+ "@apibara/indexer": "next",
62
+ "@apibara/protocol": "next",
62
63
  // Chain Dependencies
63
- "@apibara/evm": "^2.1.0-beta.1",
64
- "@apibara/beaconchain": "^2.1.0-beta.1",
65
- "@apibara/starknet": "^2.1.0-beta.1",
64
+ "@apibara/evm": "next",
65
+ "@apibara/beaconchain": "next",
66
+ "@apibara/starknet": "next",
66
67
  // Storage Dependencies
67
- "@apibara/plugin-drizzle": "^2.1.0-beta.1",
68
- "@apibara/plugin-mongo": "^2.1.0-beta.1",
69
- "@apibara/plugin-sqlite": "^2.1.0-beta.1",
68
+ "@apibara/plugin-drizzle": "next",
69
+ "@apibara/plugin-mongo": "next",
70
+ "@apibara/plugin-sqlite": "next",
70
71
  // Postgres Dependencies
71
72
  "@electric-sql/pglite": "^0.2.17",
72
73
  "drizzle-orm": "^0.37.0",
@@ -75,7 +76,6 @@ const packageVersions = {
75
76
  "drizzle-kit": "^0.29.0",
76
77
  // Typescript Dependencies
77
78
  typescript: "^5.6.2",
78
- "@rollup/plugin-typescript": "^11.1.6",
79
79
  "@types/node": "^20.5.2"
80
80
  };
81
81
  const dnaUrls = {
@@ -369,6 +369,14 @@ function pkgFromUserAgent(userAgent) {
369
369
  version: pkgSpecArr[1]
370
370
  };
371
371
  }
372
+ async function formatFile(path2) {
373
+ const file = fs.readFileSync(path2, "utf8");
374
+ const formatted = await prettier.format(file, {
375
+ filepath: path2,
376
+ tabWidth: 2
377
+ });
378
+ fs.writeFileSync(path2, formatted);
379
+ }
372
380
 
373
381
  function generatePackageJson(isTypeScript) {
374
382
  return {
@@ -377,7 +385,7 @@ function generatePackageJson(isTypeScript) {
377
385
  private: true,
378
386
  type: "module",
379
387
  scripts: {
380
- prepare: "apibara prepare",
388
+ ...isTypeScript && { prepare: "apibara prepare" },
381
389
  dev: "apibara dev",
382
390
  start: "apibara start",
383
391
  build: "apibara build",
@@ -390,7 +398,6 @@ function generatePackageJson(isTypeScript) {
390
398
  },
391
399
  devDependencies: {
392
400
  ...isTypeScript && {
393
- "@rollup/plugin-typescript": packageVersions["@rollup/plugin-typescript"],
394
401
  "@types/node": packageVersions["@types/node"],
395
402
  typescript: packageVersions.typescript
396
403
  }
@@ -418,13 +425,10 @@ function generateTsConfig() {
418
425
  };
419
426
  }
420
427
  function generateApibaraConfig(isTypeScript) {
421
- return `${isTypeScript ? 'import typescript from "@rollup/plugin-typescript";\nimport type { Plugin } from "apibara/rollup";\n' : ""}import { defineConfig } from "apibara/config";
428
+ return `import { defineConfig } from "apibara/config";
422
429
 
423
430
  export default defineConfig({
424
- runtimeConfig: {},${isTypeScript ? `
425
- rollupConfig: {
426
- plugins: [typescript()${isTypeScript ? " as Plugin" : ""}],
427
- },` : ""}
431
+ runtimeConfig: {},
428
432
  });
429
433
  `;
430
434
  }
@@ -434,18 +438,22 @@ function generateIndexer({
434
438
  chain,
435
439
  language
436
440
  }) {
437
- return `${chain === "ethereum" ? `import { EvmStream } from "@apibara/evm";` : chain === "beaconchain" ? `import { BeaconChainStream } from "@apibara/beaconchain";` : chain === "starknet" ? `import { StarknetStream } from "@apibara/starknet";` : ""}
438
- import { defineIndexer } from "@apibara/indexer";
441
+ return `import { defineIndexer } from "@apibara/indexer";
442
+ import { useLogger } from "@apibara/indexer/plugins";
439
443
  ${storage === "postgres" ? `import { drizzleStorage } from "@apibara/plugin-drizzle";` : ""}
444
+ ${storage === "postgres" ? `import { drizzle } from "@apibara/plugin-drizzle";` : ""}
445
+ ${chain === "ethereum" ? `import { EvmStream } from "@apibara/evm";` : chain === "beaconchain" ? `import { BeaconChainStream } from "@apibara/beaconchain";` : chain === "starknet" ? `import { StarknetStream } from "@apibara/starknet";` : ""}
440
446
  ${language === "typescript" ? `import type { ApibaraRuntimeConfig } from "apibara/types";` : ""}
441
- import { useLogger } from "@apibara/indexer/plugins";
442
- ${storage === "postgres" ? `import { getDrizzlePgDatabase } from "../lib/db";` : ""}
447
+ ${storage === "postgres" ? `import * as schema from "../lib/schema";` : ""}
443
448
 
444
449
 
445
450
  export default function (runtimeConfig${language === "typescript" ? ": ApibaraRuntimeConfig" : ""}) {
446
451
  const indexerId = "${indexerId}";
447
452
  const { startingBlock, streamUrl${storage === "postgres" ? ", postgresConnectionString" : ""} } = runtimeConfig[indexerId];
448
- ${storage === "postgres" ? "const { db } = getDrizzlePgDatabase(postgresConnectionString);" : ""}
453
+ ${storage === "postgres" ? `const db = drizzle({
454
+ schema,
455
+ connectionString: postgresConnectionString,
456
+ });` : ""}
449
457
 
450
458
  return defineIndexer(${chain === "ethereum" ? "EvmStream" : chain === "beaconchain" ? "BeaconChainStream" : chain === "starknet" ? "StarknetStream" : ""})({
451
459
  streamUrl,
@@ -454,7 +462,7 @@ export default function (runtimeConfig${language === "typescript" ? ": ApibaraRu
454
462
  filter: {
455
463
  header: "always",
456
464
  },
457
- plugins: [${storage === "postgres" ? "drizzleStorage({ db, persistState: true })" : ""}],
465
+ plugins: [${storage === "postgres" ? "drizzleStorage({ db, migrate: { migrationsFolder: './drizzle' } })" : ""}],
458
466
  async transform({ endCursor, finality }) {
459
467
  const logger = useLogger();
460
468
 
@@ -466,14 +474,12 @@ export default function (runtimeConfig${language === "typescript" ? ": ApibaraRu
466
474
  );
467
475
 
468
476
  ${storage === "postgres" ? `// Example snippet to insert data into db using drizzle with postgres
469
- // const { db } = useDrizzleStorage();
470
- // const { logs } = block;
471
- // for (const log of logs) {
472
- // await db.insert(exampleTable).values({
473
- // number: Number(endCursor?.orderKey),
474
- // hash: log.transactionHash,
475
- // });
476
- // }` : ""}
477
+ // const { db: database } = useDrizzleStorage();
478
+
479
+ // await database.insert(schema.cursorTable).values({
480
+ // endCursor: Number(endCursor?.orderKey),
481
+ // uniqueKey: \`\${endCursor?.uniqueKey}\`,
482
+ // });` : ""}
477
483
  },
478
484
  });
479
485
  }
@@ -493,16 +499,16 @@ async function createIndexerFile(options) {
493
499
  const indexerContent = generateIndexer(options);
494
500
  fs.mkdirSync(path.dirname(indexerFilePath), { recursive: true });
495
501
  fs.writeFileSync(indexerFilePath, indexerContent);
502
+ await formatFile(indexerFilePath);
496
503
  }
497
- function updatePackageJson({
504
+ async function updatePackageJson({
498
505
  cwd,
499
506
  chain,
500
507
  storage,
501
508
  language
502
509
  }) {
503
- const packageJson = JSON.parse(
504
- fs.readFileSync(path.join(cwd, "package.json"), "utf8")
505
- );
510
+ const packageJsonPath = path.join(cwd, "package.json");
511
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
506
512
  if (chain === "ethereum") {
507
513
  packageJson.dependencies["@apibara/evm"] = packageVersions["@apibara/evm"];
508
514
  } else if (chain === "beaconchain") {
@@ -522,12 +528,10 @@ function updatePackageJson({
522
528
  packageJson.devDependencies["@types/pg"] = packageVersions["@types/pg"];
523
529
  }
524
530
  }
525
- fs.writeFileSync(
526
- path.join(cwd, "package.json"),
527
- JSON.stringify(packageJson, null, 2)
528
- );
531
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
532
+ await formatFile(packageJsonPath);
529
533
  }
530
- function updateApibaraConfigFile({
534
+ async function updateApibaraConfigFile({
531
535
  indexerId,
532
536
  cwd,
533
537
  chain,
@@ -571,14 +575,10 @@ function updateApibaraConfigFile({
571
575
  });
572
576
  }
573
577
  sourceFile.saveSync();
574
- sourceFile.formatText({
575
- tabSize: 2,
576
- insertSpaceAfterOpeningAndBeforeClosingEmptyBraces: true,
577
- insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true
578
- });
578
+ await formatFile(pathToConfig);
579
579
  }
580
580
  async function createDrizzleStorageFiles(options) {
581
- const { cwd, language, storage } = options;
581
+ const { cwd, language, storage, indexerId } = options;
582
582
  if (storage !== "postgres")
583
583
  return;
584
584
  const fileExtension = language === "typescript" ? "ts" : "js";
@@ -592,14 +592,15 @@ async function createDrizzleStorageFiles(options) {
592
592
  const drizzleConfigContent = `${language === "typescript" ? 'import type { Config } from "drizzle-kit";' : ""}
593
593
 
594
594
  export default {
595
- schema: "./lib/schema.ts",
595
+ schema: "./lib/schema.${fileExtension}",
596
596
  out: "./drizzle",
597
597
  dialect: "postgresql",
598
598
  dbCredentials: {
599
- url: process.env["POSTGRES_CONNECTION_STRING"] ?? "",
599
+ url: process.env["POSTGRES_CONNECTION_STRING"] ?? "memory://${indexerId}",
600
600
  },
601
601
  }${language === "typescript" ? " satisfies Config" : ""};`;
602
602
  fs.writeFileSync(drizzleConfigPath, drizzleConfigContent);
603
+ await formatFile(drizzleConfigPath);
603
604
  consola.success(`Created ${cyan(drizzleConfigFileName)}`);
604
605
  }
605
606
  const schemaFileName = `schema.${fileExtension}`;
@@ -610,63 +611,23 @@ export default {
610
611
  fileName: `lib/${schemaFileName}`
611
612
  });
612
613
  if (!schemaExists || schemaOverwrite) {
613
- const schemaContent = `// --- Add your pg table schemas here ----
614
+ const schemaContent = `// --- Add your pg table schemas here ----
614
615
 
615
616
  // import { bigint, pgTable, text, uuid } from "drizzle-orm/pg-core";
616
617
 
617
- // export const exampleTable = pgTable("example_table", {
618
+ // export const cursorTable = pgTable("cursor_table", {
618
619
  // id: uuid("id").primaryKey().defaultRandom(),
619
- // number: bigint("number", { mode: "number" }),
620
- // hash: text("hash"),
620
+ // endCursor: bigint("end_cursor", { mode: "number" }),
621
+ // uniqueKey: text("unique_key"),
621
622
  // });
622
623
 
623
624
  export {};
624
625
  `;
625
626
  fs.mkdirSync(path.dirname(schemaPath), { recursive: true });
626
627
  fs.writeFileSync(schemaPath, schemaContent);
628
+ await formatFile(schemaPath);
627
629
  consola.success(`Created ${cyan("lib/schema.ts")}`);
628
630
  }
629
- const dbFileName = `db.${fileExtension}`;
630
- const dbPath = path.join(cwd, "lib", dbFileName);
631
- const { exists: dbExists, overwrite: dbOverwrite } = await checkFileExists(
632
- dbPath,
633
- {
634
- askPrompt: true,
635
- fileName: `lib/${dbFileName}`,
636
- allowIgnore: true
637
- }
638
- );
639
- if (!dbExists || dbOverwrite) {
640
- const dbContent = `import * as schema from "./schema";
641
- import { drizzle as nodePgDrizzle } from "drizzle-orm/node-postgres";
642
- import { drizzle as pgLiteDrizzle } from "drizzle-orm/pglite";
643
- import pg from "pg";
644
-
645
-
646
- export function getDrizzlePgDatabase(connectionString${language === "typescript" ? ": string" : ""}) {
647
- // Create pglite instance
648
- if (connectionString.includes("memory")) {
649
- return {
650
- db: pgLiteDrizzle({
651
- schema,
652
- connection: {
653
- dataDir: connectionString,
654
- },
655
- }),
656
- };
657
- }
658
-
659
- // Create node-postgres instance
660
- const pool = new pg.Pool({
661
- connectionString,
662
- });
663
-
664
- return { db: nodePgDrizzle(pool, { schema }) };
665
- }`;
666
- fs.mkdirSync(path.dirname(dbPath), { recursive: true });
667
- fs.writeFileSync(dbPath, dbContent);
668
- consola.success(`Created ${cyan(`lib/${dbFileName}`)}`);
669
- }
670
631
  console.log("\n");
671
632
  if (!schemaExists || schemaOverwrite) {
672
633
  consola.info(
@@ -682,15 +643,15 @@ ${yellow(`
682
643
 
683
644
  import { bigint, pgTable, text, uuid } from "drizzle-orm/pg-core";
684
645
 
685
- export const exampleTable = pgTable("example_table", {
646
+ export const cursorTable = pgTable("cursor_table", {
686
647
  id: uuid("id").primaryKey().defaultRandom(),
687
- number: bigint("number", { mode: "number" }),
688
- hash: text("hash"),
648
+ endCursor: bigint("end_cursor", { mode: "number" }),
649
+ uniqueKey: text("unique_key"),
689
650
  });`)}`);
690
651
  console.log("\n");
691
652
  }
692
653
  consola.info(
693
- `Run ${green(`${options.packageManager} run drizzle:generate`)} & ${green(`${options.packageManager} run drizzle:migrate`)} to generate and apply migrations.`
654
+ `Run ${green(`${options.packageManager}${options.packageManager === "npm" ? " run" : ""} drizzle:generate`)} & ${green(`${options.packageManager}${options.packageManager === "npm" ? " run" : ""} drizzle:migrate`)} to generate and apply migrations.`
694
655
  );
695
656
  }
696
657
  async function createStorageRelatedFiles(options) {
@@ -699,6 +660,90 @@ async function createStorageRelatedFiles(options) {
699
660
  await createDrizzleStorageFiles(options);
700
661
  }
701
662
  }
663
+ const gitIgnoreItems = [
664
+ {
665
+ isRecommended: false,
666
+ value: "node_modules"
667
+ },
668
+ {
669
+ isRecommended: false,
670
+ value: "dist"
671
+ },
672
+ {
673
+ isRecommended: true,
674
+ description: "build and dev files of apibara",
675
+ value: ".apibara"
676
+ },
677
+ {
678
+ isRecommended: false,
679
+ value: ".env"
680
+ },
681
+ {
682
+ isRecommended: false,
683
+ description: "for mac users",
684
+ value: ".DS_Store"
685
+ }
686
+ ];
687
+ async function createGitIgnoreFile(cwd) {
688
+ const gitIgnorePath = path.join(cwd, ".gitignore");
689
+ if (fs.existsSync(gitIgnorePath)) {
690
+ const result = await prompts([
691
+ {
692
+ type: "select",
693
+ name: "overwrite",
694
+ message: `${cyan(".gitignore")} already exists. Please choose how to proceed:`,
695
+ initial: 0,
696
+ choices: [
697
+ {
698
+ title: "Choose items to append in your .gitignore",
699
+ value: "append"
700
+ },
701
+ {
702
+ title: "Keep original",
703
+ value: "ignore"
704
+ },
705
+ {
706
+ title: "Overwrite",
707
+ value: "overwrite"
708
+ }
709
+ ]
710
+ },
711
+ {
712
+ type: (overwrite2) => overwrite2 === "append" ? "multiselect" : null,
713
+ name: "ignoreItems",
714
+ message: "Choose items to append in your .gitignore",
715
+ choices: gitIgnoreItems.map((item) => ({
716
+ title: `${yellow(item.value)}${item.description ? ` - ${item.description}` : ""}${item.isRecommended ? ` ${green("(recommended)")}` : ""}`,
717
+ value: item.value
718
+ }))
719
+ }
720
+ ]);
721
+ const { overwrite, ignoreItems } = result;
722
+ if (overwrite === "append" && ignoreItems.length > 0) {
723
+ const gitIgnoreContent = fs.readFileSync(gitIgnorePath, "utf8");
724
+ fs.writeFileSync(
725
+ gitIgnorePath,
726
+ `${gitIgnoreContent}
727
+ ${result.ignoreItems.join("\n")}`
728
+ );
729
+ consola.success(`Updated ${cyan(".gitignore")}`);
730
+ return;
731
+ }
732
+ if (overwrite === "overwrite") {
733
+ fs.writeFileSync(
734
+ gitIgnorePath,
735
+ gitIgnoreItems.map((item) => item.value).join("\n")
736
+ );
737
+ consola.success(`Updated ${cyan(".gitignore")}`);
738
+ return;
739
+ }
740
+ }
741
+ fs.writeFileSync(
742
+ gitIgnorePath,
743
+ gitIgnoreItems.map((item) => item.value).join("\n")
744
+ );
745
+ consola.success(`Created ${cyan(".gitignore")}`);
746
+ }
702
747
 
703
748
  async function initializeProject({
704
749
  argTargetDir,
@@ -776,36 +821,43 @@ async function initializeProject({
776
821
  consola$1.info(`Initializing project in ${argTargetDir}
777
822
 
778
823
  `);
824
+ const packageJsonPath = path.join(root, "package.json");
779
825
  const packageJson = generatePackageJson(isTs);
780
826
  fs.writeFileSync(
781
- path.join(root, "package.json"),
827
+ packageJsonPath,
782
828
  JSON.stringify(packageJson, null, 2) + "\n"
783
829
  );
784
- consola$1.success("Created ", cyan("package.json"));
830
+ await formatFile(packageJsonPath);
831
+ consola$1.success("Created", cyan("package.json"));
785
832
  if (isTs) {
833
+ const tsConfigPath = path.join(root, "tsconfig.json");
786
834
  const tsConfig = generateTsConfig();
787
- fs.writeFileSync(
788
- path.join(root, "tsconfig.json"),
789
- JSON.stringify(tsConfig, null, 2) + "\n"
790
- );
791
- consola$1.success("Created ", cyan("tsconfig.json"));
835
+ fs.writeFileSync(tsConfigPath, JSON.stringify(tsConfig, null, 2) + "\n");
836
+ await formatFile(tsConfigPath);
837
+ consola$1.success("Created", cyan("tsconfig.json"));
792
838
  }
793
- const apibaraConfig = generateApibaraConfig(isTs);
794
- fs.writeFileSync(
795
- path.join(root, `apibara.config.${configExt}`),
796
- apibaraConfig
797
- );
798
- consola$1.success("Created ", cyan(`apibara.config.${configExt}`), "\n\n");
839
+ const apibaraConfigPath = path.join(root, `apibara.config.${configExt}`);
840
+ const apibaraConfig = generateApibaraConfig();
841
+ fs.writeFileSync(apibaraConfigPath, apibaraConfig);
842
+ await formatFile(apibaraConfigPath);
843
+ consola$1.success("Created", cyan(`apibara.config.${configExt}`));
844
+ const indexersDir = path.join(root, "indexers");
845
+ if (!fs.existsSync(indexersDir)) {
846
+ fs.mkdirSync(indexersDir, { recursive: true });
847
+ consola$1.success(`Created ${cyan("indexers")} directory`);
848
+ }
849
+ await createGitIgnoreFile(root);
850
+ console.log("\n");
799
851
  consola$1.ready(green("Project initialized successfully"));
800
852
  console.log();
801
853
  if (!argNoCreateIndexer) {
802
854
  consola$1.info("Let's create an indexer\n");
803
- await addIndexer({});
855
+ await addIndexer({ argRootDir: argTargetDir });
804
856
  } else {
805
857
  const pkgManager = getPackageManager();
806
858
  consola$1.info(
807
859
  "Run ",
808
- green(`${pkgManager.name} run install`),
860
+ green(`${pkgManager.name} install`),
809
861
  " to install all dependencies"
810
862
  );
811
863
  }
@@ -816,9 +868,11 @@ async function addIndexer({
816
868
  argChain,
817
869
  argNetwork,
818
870
  argStorage,
819
- argDnaUrl
871
+ argDnaUrl,
872
+ argRootDir
820
873
  }) {
821
- const configExists = hasApibaraConfig(process.cwd());
874
+ const cwd = path.join(process.cwd(), argRootDir ?? ".");
875
+ const configExists = hasApibaraConfig(cwd);
822
876
  if (!configExists) {
823
877
  consola$1.error("No apibara.config found in the current directory.");
824
878
  const prompt_initialize = await prompts({
@@ -842,7 +896,7 @@ async function addIndexer({
842
896
  );
843
897
  }
844
898
  }
845
- const language = getApibaraConfigLanguage(process.cwd());
899
+ const language = getApibaraConfigLanguage(cwd);
846
900
  validateIndexerId(argIndexerId, true);
847
901
  validateChain(argChain, true);
848
902
  validateNetwork(argChain, argNetwork, true);
@@ -855,7 +909,15 @@ async function addIndexer({
855
909
  name: "prompt_indexerId",
856
910
  message: reset("Indexer ID:"),
857
911
  initial: argIndexerId ?? "my-indexer",
858
- validate: (id) => validateIndexerId(id) || "Invalid indexer ID cannot be empty and must be in kebab-case format"
912
+ validate: (id) => validateIndexerId(id) ? checkFileExists(
913
+ path.join(
914
+ cwd,
915
+ "indexers",
916
+ `${id}.indexer.${language === "typescript" ? "ts" : "js"}`
917
+ )
918
+ ).then(
919
+ ({ exists }) => exists ? `Indexer ${cyan(`${id}.indexer.${language === "typescript" ? "ts" : "js"}`)} already exists` : true
920
+ ) : "Invalid indexer ID, it cannot be empty and must be in kebab-case format"
859
921
  },
860
922
  {
861
923
  type: argChain ? null : "select",
@@ -931,7 +993,7 @@ async function addIndexer({
931
993
  const indexerFileId = argIndexerId ?? prompt_indexerId;
932
994
  const pkgManager = getPackageManager();
933
995
  const options = {
934
- cwd: process.cwd(),
996
+ cwd,
935
997
  indexerFileId,
936
998
  indexerId: convertKebabToCamelCase(indexerFileId),
937
999
  chain: argChain ?? prompt_chain?.name,
@@ -941,11 +1003,11 @@ async function addIndexer({
941
1003
  language,
942
1004
  packageManager: pkgManager.name
943
1005
  };
944
- updateApibaraConfigFile(options);
1006
+ await updateApibaraConfigFile(options);
945
1007
  consola$1.success(
946
1008
  `Updated ${cyan("apibara.config." + (language === "typescript" ? "ts" : "js"))}`
947
1009
  );
948
- updatePackageJson(options);
1010
+ await updatePackageJson(options);
949
1011
  consola$1.success(`Updated ${cyan("package.json")}`);
950
1012
  await createIndexerFile(options);
951
1013
  consola$1.success(
@@ -953,8 +1015,10 @@ async function addIndexer({
953
1015
  );
954
1016
  await createStorageRelatedFiles(options);
955
1017
  console.log();
1018
+ const baseCommand = `${options.packageManager} install`;
1019
+ const tsCommand = `${baseCommand} && ${options.packageManager} run prepare`;
956
1020
  consola$1.info(
957
- `Before running the indexer, run ${cyan(`${options.packageManager} run install`)}${language === "typescript" ? " & " + cyan(`${options.packageManager} run prepare`) : ""}`
1021
+ `Before running the indexer, run ${cyan(language === "typescript" ? tsCommand : baseCommand)}`
958
1022
  );
959
1023
  }
960
1024
 
@@ -1,5 +1,7 @@
1
+ import { d as deserialize } from '../shared/apibara.af330c7d.mjs';
2
+
1
3
  function useRuntimeConfig() {
2
- return JSON.parse(process.env.APIBARA_RUNTIME_CONFIG || "{}");
4
+ return deserialize(process.env.APIBARA_RUNTIME_CONFIG || "{}");
3
5
  }
4
6
 
5
7
  export { useRuntimeConfig };
@@ -0,0 +1,7 @@
1
+ import { Apibara } from 'apibara/types';
2
+ import { RolldownOptions } from 'rolldown';
3
+ export { Plugin } from 'rolldown';
4
+
5
+ declare function getRolldownConfig(apibara: Apibara): RolldownOptions;
6
+
7
+ export { getRolldownConfig };
@@ -0,0 +1,7 @@
1
+ import { Apibara } from 'apibara/types';
2
+ import { RolldownOptions } from 'rolldown';
3
+ export { Plugin } from 'rolldown';
4
+
5
+ declare function getRolldownConfig(apibara: Apibara): RolldownOptions;
6
+
7
+ export { getRolldownConfig };
@@ -0,0 +1,126 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { builtinModules } from 'node:module';
3
+ import replace from '@rollup/plugin-replace';
4
+ import defu from 'defu';
5
+ import { join } from 'pathe';
6
+ import { s as serialize } from '../shared/apibara.af330c7d.mjs';
7
+ import virtual from '@rollup/plugin-virtual';
8
+ import { hash } from 'ohash';
9
+
10
+ function appConfig(apibara) {
11
+ return virtual({
12
+ "#apibara-internal-virtual/config": `
13
+ const serializedConfig = \`process.env.APIBARA_CONFIG\`;
14
+
15
+ if (serializedConfig === undefined || serializedConfig === "") {
16
+ throw new Error("APIBARA_CONFIG is not defined");
17
+ }
18
+
19
+ function deserialize(str) {
20
+ return JSON.parse(str, (_, value) =>
21
+ typeof value === "string" && value.match(/^\\d+n$/)
22
+ ? BigInt(value.slice(0, -1))
23
+ : value,
24
+ );
25
+ }
26
+
27
+ export const config = deserialize(serializedConfig);
28
+ `
29
+ });
30
+ }
31
+
32
+ function indexers(apibara) {
33
+ const indexers2 = [...new Set(apibara.indexers)];
34
+ return virtual({
35
+ "#apibara-internal-virtual/indexers": `
36
+ ${indexers2.map((i) => `import * as _${hash(i)} from '${i.indexer}';`).join("\n")}
37
+
38
+ export const indexers = [
39
+ ${indexers2.map((i) => `{ name: "${i.name}", indexer: _${hash(i)} }`).join(",\n")}
40
+ ];
41
+ `
42
+ });
43
+ }
44
+
45
+ const runtimeDependencies = [
46
+ "better-sqlite3",
47
+ "@electric-sql/pglite",
48
+ "pg",
49
+ // https://socket.io/docs/v4/server-installation/#additional-packages
50
+ "utf-8-validate",
51
+ "bufferutil",
52
+ "node-fetch"
53
+ ];
54
+ function getRolldownConfig(apibara) {
55
+ const extensions = [
56
+ ".ts",
57
+ ".mjs",
58
+ ".js",
59
+ ".json",
60
+ ".node",
61
+ ".tsx",
62
+ ".jsx"
63
+ ];
64
+ const tsConfigExists = existsSync(
65
+ join(apibara.options.rootDir, "tsconfig.json")
66
+ );
67
+ const rolldownConfig = defu(
68
+ // biome-ignore lint/suspicious/noExplicitAny: apibara.options.rolldownConfig is typed
69
+ apibara.options.rolldownConfig,
70
+ {
71
+ platform: "node",
72
+ input: apibara.options.entry,
73
+ output: {
74
+ dir: join(apibara.options.outputDir || "./.apibara/build"),
75
+ format: "esm",
76
+ entryFileNames: "[name].mjs",
77
+ chunkFileNames: "chunks/[name]-[hash].mjs",
78
+ sourcemap: true
79
+ },
80
+ plugins: [],
81
+ onwarn(warning, rolldownWarn) {
82
+ if (!["CIRCULAR_DEPENDENCY", "EVAL", "THIS_IS_UNDEFINED"].includes(
83
+ warning.code || ""
84
+ ) && !warning.message.includes("Unsupported source map comment") && !warning.message.includes("@__PURE__") && !warning.message.includes("/*#__PURE__*/")) {
85
+ rolldownWarn(warning);
86
+ }
87
+ },
88
+ resolve: {
89
+ extensions,
90
+ preferBuiltins: !!apibara.options.node,
91
+ mainFields: ["main"],
92
+ exportConditions: apibara.options.exportConditions,
93
+ tsconfigFilename: tsConfigExists ? "tsconfig.json" : void 0
94
+ },
95
+ treeshake: true,
96
+ external: [...builtinModules, ...runtimeDependencies]
97
+ }
98
+ );
99
+ rolldownConfig.plugins?.push(
100
+ replace({
101
+ preventAssignment: true,
102
+ values: {
103
+ "process.env.APIBARA_CONFIG": getSerializedRuntimeConfig(apibara)
104
+ }
105
+ })
106
+ );
107
+ rolldownConfig.plugins?.push(indexers(apibara));
108
+ rolldownConfig.plugins?.push(appConfig());
109
+ return rolldownConfig;
110
+ }
111
+ function getSerializedRuntimeConfig(apibara) {
112
+ try {
113
+ return serialize({
114
+ runtimeConfig: apibara.options.runtimeConfig,
115
+ preset: apibara.options.preset,
116
+ presets: apibara.options.presets
117
+ });
118
+ } catch (error) {
119
+ throw new Error(
120
+ "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.",
121
+ { cause: error }
122
+ );
123
+ }
124
+ }
125
+
126
+ export { getRolldownConfig };