apibara 2.1.0-beta.6 → 2.1.0-beta.8

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.
@@ -9,24 +9,24 @@ const add = defineCommand({
9
9
  args: {
10
10
  indexerId: {
11
11
  type: "positional",
12
- description: "Indexer ID",
12
+ description: "Indexer ID - must be in kebab-case",
13
13
  required: false
14
14
  },
15
15
  chain: {
16
16
  type: "string",
17
- description: "Chain"
17
+ description: "Blockchain - ethereum, beaconchain, starknet"
18
18
  },
19
19
  network: {
20
20
  type: "string",
21
- description: "Network"
21
+ description: "Network - mainnet, sepolia, other"
22
22
  },
23
23
  storage: {
24
24
  type: "string",
25
- description: "Storage"
25
+ description: "Storage - postgres, none"
26
26
  },
27
27
  dnaUrl: {
28
28
  type: "string",
29
- description: "DNA URL"
29
+ description: "DNA URL - https://custom-dna-url.apibara.org"
30
30
  }
31
31
  },
32
32
  async run({ args }) {
@@ -446,15 +446,19 @@ function generateIndexer({
446
446
  return `import { defineIndexer } from "@apibara/indexer";
447
447
  import { useLogger } from "@apibara/indexer/plugins";
448
448
  ${storage === "postgres" ? `import { drizzleStorage } from "@apibara/plugin-drizzle";` : ""}
449
+ ${storage === "postgres" ? `import { drizzle } from "@apibara/plugin-drizzle";` : ""}
449
450
  ${chain === "ethereum" ? `import { EvmStream } from "@apibara/evm";` : chain === "beaconchain" ? `import { BeaconChainStream } from "@apibara/beaconchain";` : chain === "starknet" ? `import { StarknetStream } from "@apibara/starknet";` : ""}
450
451
  ${language === "typescript" ? `import type { ApibaraRuntimeConfig } from "apibara/types";` : ""}
451
- ${storage === "postgres" ? `import { getDrizzlePgDatabase } from "../lib/db";` : ""}
452
+ ${storage === "postgres" ? `import * as schema from "../lib/schema";` : ""}
452
453
 
453
454
 
454
455
  export default function (runtimeConfig${language === "typescript" ? ": ApibaraRuntimeConfig" : ""}) {
455
456
  const indexerId = "${indexerId}";
456
457
  const { startingBlock, streamUrl${storage === "postgres" ? ", postgresConnectionString" : ""} } = runtimeConfig[indexerId];
457
- ${storage === "postgres" ? "const { db } = getDrizzlePgDatabase(postgresConnectionString);" : ""}
458
+ ${storage === "postgres" ? `const db = drizzle({
459
+ schema,
460
+ connectionString: postgresConnectionString,
461
+ });` : ""}
458
462
 
459
463
  return defineIndexer(${chain === "ethereum" ? "EvmStream" : chain === "beaconchain" ? "BeaconChainStream" : chain === "starknet" ? "StarknetStream" : ""})({
460
464
  streamUrl,
@@ -463,7 +467,7 @@ export default function (runtimeConfig${language === "typescript" ? ": ApibaraRu
463
467
  filter: {
464
468
  header: "always",
465
469
  },
466
- plugins: [${storage === "postgres" ? "drizzleStorage({ db, persistState: true })" : ""}],
470
+ plugins: [${storage === "postgres" ? "drizzleStorage({ db, migrate: { migrationsFolder: './drizzle' } })" : ""}],
467
471
  async transform({ endCursor, finality }) {
468
472
  const logger = useLogger();
469
473
 
@@ -475,14 +479,12 @@ export default function (runtimeConfig${language === "typescript" ? ": ApibaraRu
475
479
  );
476
480
 
477
481
  ${storage === "postgres" ? `// Example snippet to insert data into db using drizzle with postgres
478
- // const { db } = useDrizzleStorage();
479
- // const { logs } = block;
480
- // for (const log of logs) {
481
- // await db.insert(exampleTable).values({
482
- // number: Number(endCursor?.orderKey),
483
- // hash: log.transactionHash,
484
- // });
485
- // }` : ""}
482
+ // const { db: database } = useDrizzleStorage();
483
+
484
+ // await database.insert(schema.cursorTable).values({
485
+ // endCursor: Number(endCursor?.orderKey),
486
+ // uniqueKey: \`\${endCursor?.uniqueKey}\`,
487
+ // });` : ""}
486
488
  },
487
489
  });
488
490
  }
@@ -581,7 +583,7 @@ async function updateApibaraConfigFile({
581
583
  await formatFile(pathToConfig);
582
584
  }
583
585
  async function createDrizzleStorageFiles(options) {
584
- const { cwd, language, storage } = options;
586
+ const { cwd, language, storage, indexerId } = options;
585
587
  if (storage !== "postgres")
586
588
  return;
587
589
  const fileExtension = language === "typescript" ? "ts" : "js";
@@ -595,11 +597,11 @@ async function createDrizzleStorageFiles(options) {
595
597
  const drizzleConfigContent = `${language === "typescript" ? 'import type { Config } from "drizzle-kit";' : ""}
596
598
 
597
599
  export default {
598
- schema: "./lib/schema.ts",
600
+ schema: "./lib/schema.${fileExtension}",
599
601
  out: "./drizzle",
600
602
  dialect: "postgresql",
601
603
  dbCredentials: {
602
- url: process.env["POSTGRES_CONNECTION_STRING"] ?? "",
604
+ url: process.env["POSTGRES_CONNECTION_STRING"] ?? "memory://${indexerId}",
603
605
  },
604
606
  }${language === "typescript" ? " satisfies Config" : ""};`;
605
607
  fs.writeFileSync(drizzleConfigPath, drizzleConfigContent);
@@ -614,14 +616,14 @@ export default {
614
616
  fileName: `lib/${schemaFileName}`
615
617
  });
616
618
  if (!schemaExists || schemaOverwrite) {
617
- const schemaContent = `// --- Add your pg table schemas here ----
619
+ const schemaContent = `// --- Add your pg table schemas here ----
618
620
 
619
621
  // import { bigint, pgTable, text, uuid } from "drizzle-orm/pg-core";
620
622
 
621
- // export const exampleTable = pgTable("example_table", {
623
+ // export const cursorTable = pgTable("cursor_table", {
622
624
  // id: uuid("id").primaryKey().defaultRandom(),
623
- // number: bigint("number", { mode: "number" }),
624
- // hash: text("hash"),
625
+ // endCursor: bigint("end_cursor", { mode: "number" }),
626
+ // uniqueKey: text("unique_key"),
625
627
  // });
626
628
 
627
629
  export {};
@@ -631,48 +633,6 @@ export {};
631
633
  await formatFile(schemaPath);
632
634
  consola.success(`Created ${cyan("lib/schema.ts")}`);
633
635
  }
634
- const dbFileName = `db.${fileExtension}`;
635
- const dbPath = path.join(cwd, "lib", dbFileName);
636
- const { exists: dbExists, overwrite: dbOverwrite } = await checkFileExists(
637
- dbPath,
638
- {
639
- askPrompt: true,
640
- fileName: `lib/${dbFileName}`,
641
- allowIgnore: true
642
- }
643
- );
644
- if (!dbExists || dbOverwrite) {
645
- const dbContent = `import * as schema from "./schema";
646
- import { drizzle as nodePgDrizzle } from "drizzle-orm/node-postgres";
647
- import { drizzle as pgLiteDrizzle } from "drizzle-orm/pglite";
648
- import pg from "pg";
649
-
650
-
651
- export function getDrizzlePgDatabase(connectionString${language === "typescript" ? ": string" : ""}) {
652
- // Create pglite instance
653
- if (connectionString.includes("memory")) {
654
- return {
655
- db: pgLiteDrizzle({
656
- schema,
657
- connection: {
658
- dataDir: connectionString,
659
- },
660
- }),
661
- };
662
- }
663
-
664
- // Create node-postgres instance
665
- const pool = new pg.Pool({
666
- connectionString,
667
- });
668
-
669
- return { db: nodePgDrizzle(pool, { schema }) };
670
- }`;
671
- fs.mkdirSync(path.dirname(dbPath), { recursive: true });
672
- fs.writeFileSync(dbPath, dbContent);
673
- await formatFile(dbPath);
674
- consola.success(`Created ${cyan(`lib/${dbFileName}`)}`);
675
- }
676
636
  console.log("\n");
677
637
  if (!schemaExists || schemaOverwrite) {
678
638
  consola.info(
@@ -688,15 +648,15 @@ ${yellow(`
688
648
 
689
649
  import { bigint, pgTable, text, uuid } from "drizzle-orm/pg-core";
690
650
 
691
- export const exampleTable = pgTable("example_table", {
651
+ export const cursorTable = pgTable("cursor_table", {
692
652
  id: uuid("id").primaryKey().defaultRandom(),
693
- number: bigint("number", { mode: "number" }),
694
- hash: text("hash"),
653
+ endCursor: bigint("end_cursor", { mode: "number" }),
654
+ uniqueKey: text("unique_key"),
695
655
  });`)}`);
696
656
  console.log("\n");
697
657
  }
698
658
  consola.info(
699
- `Run ${green(`${options.packageManager} run drizzle:generate`)} & ${green(`${options.packageManager} run drizzle:migrate`)} to generate and apply migrations.`
659
+ `Run ${green(`${options.packageManager}${options.packageManager === "npm" ? " run" : ""} drizzle:generate`)} & ${green(`${options.packageManager}${options.packageManager === "npm" ? " run" : ""} drizzle:migrate`)} to generate and apply migrations.`
700
660
  );
701
661
  }
702
662
  async function createStorageRelatedFiles(options) {
@@ -902,7 +862,7 @@ async function initializeProject({
902
862
  const pkgManager = getPackageManager();
903
863
  consola$1.info(
904
864
  "Run ",
905
- green(`${pkgManager.name} run install`),
865
+ green(`${pkgManager.name} install`),
906
866
  " to install all dependencies"
907
867
  );
908
868
  }
@@ -1058,8 +1018,10 @@ async function addIndexer({
1058
1018
  );
1059
1019
  await createStorageRelatedFiles(options);
1060
1020
  console.log();
1021
+ const baseCommand = `${options.packageManager} install`;
1022
+ const tsCommand = `${baseCommand} && ${options.packageManager} run prepare`;
1061
1023
  consola$1.info(
1062
- `Before running the indexer, run ${cyan(`${options.packageManager} run install`)}${language === "typescript" ? " & " + cyan(`${options.packageManager} run prepare`) : ""}`
1024
+ `Before running the indexer, run ${cyan(language === "typescript" ? tsCommand : baseCommand)}`
1063
1025
  );
1064
1026
  }
1065
1027
 
@@ -56,9 +56,9 @@ export function createIndexer(indexerName, preset) {
56
56
  indexerName,
57
57
  availableIndexers
58
58
  }),
59
+ logger({ logger: reporter }),
59
60
  inMemoryPersistence(),
60
- ...definition.plugins ?? [],
61
- logger({ logger: reporter })
61
+ ...definition.plugins ?? []
62
62
  ];
63
63
  return _createIndexer(definition);
64
64
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apibara",
3
- "version": "2.1.0-beta.6",
3
+ "version": "2.1.0-beta.8",
4
4
  "type": "module",
5
5
  "main": "./dist/core/index.mjs",
6
6
  "exports": {
@@ -76,7 +76,7 @@
76
76
  "playground:start": "pnpm playground start --dir playground --indexer starknet"
77
77
  },
78
78
  "devDependencies": {
79
- "@apibara/starknet": "2.1.0-beta.6",
79
+ "@apibara/starknet": "2.1.0-beta.8",
80
80
  "@types/fs-extra": "^11.0.4",
81
81
  "@types/node": "^20.14.0",
82
82
  "@types/prompts": "^2.4.9",
@@ -87,8 +87,8 @@
87
87
  "vitest": "^1.6.0"
88
88
  },
89
89
  "dependencies": {
90
- "@apibara/indexer": "2.1.0-beta.6",
91
- "@apibara/protocol": "2.1.0-beta.6",
90
+ "@apibara/indexer": "2.1.0-beta.8",
91
+ "@apibara/protocol": "2.1.0-beta.8",
92
92
  "@rollup/plugin-commonjs": "^26.0.1",
93
93
  "@rollup/plugin-json": "^6.1.0",
94
94
  "@rollup/plugin-node-resolve": "^15.2.3",
@@ -10,24 +10,24 @@ export default defineCommand({
10
10
  args: {
11
11
  indexerId: {
12
12
  type: "positional",
13
- description: "Indexer ID",
13
+ description: "Indexer ID - must be in kebab-case",
14
14
  required: false,
15
15
  },
16
16
  chain: {
17
17
  type: "string",
18
- description: "Chain",
18
+ description: "Blockchain - ethereum, beaconchain, starknet",
19
19
  },
20
20
  network: {
21
21
  type: "string",
22
- description: "Network",
22
+ description: "Network - mainnet, sepolia, other",
23
23
  },
24
24
  storage: {
25
25
  type: "string",
26
- description: "Storage",
26
+ description: "Storage - postgres, none",
27
27
  },
28
28
  dnaUrl: {
29
29
  type: "string",
30
- description: "DNA URL",
30
+ description: "DNA URL - https://custom-dna-url.apibara.org",
31
31
  },
32
32
  },
33
33
  async run({ args }) {
package/src/create/add.ts CHANGED
@@ -228,11 +228,9 @@ export async function addIndexer({
228
228
 
229
229
  console.log();
230
230
 
231
+ const baseCommand = `${options.packageManager} install`;
232
+ const tsCommand = `${baseCommand} && ${options.packageManager} run prepare`;
231
233
  consola.info(
232
- `Before running the indexer, run ${cyan(`${options.packageManager} run install`)}${
233
- language === "typescript"
234
- ? " & " + cyan(`${options.packageManager} run prepare`)
235
- : ""
236
- }`,
234
+ `Before running the indexer, run ${cyan(language === "typescript" ? tsCommand : baseCommand)}`,
237
235
  );
238
236
  }
@@ -171,7 +171,7 @@ export async function initializeProject({
171
171
  const pkgManager = getPackageManager();
172
172
  consola.info(
173
173
  "Run ",
174
- green(`${pkgManager.name} run install`),
174
+ green(`${pkgManager.name} install`),
175
175
  " to install all dependencies",
176
176
  );
177
177
  }
@@ -82,6 +82,7 @@ export function generateIndexer({
82
82
  return `import { defineIndexer } from "@apibara/indexer";
83
83
  import { useLogger } from "@apibara/indexer/plugins";
84
84
  ${storage === "postgres" ? `import { drizzleStorage } from "@apibara/plugin-drizzle";` : ""}
85
+ ${storage === "postgres" ? `import { drizzle } from "@apibara/plugin-drizzle";` : ""}
85
86
  ${
86
87
  chain === "ethereum"
87
88
  ? `import { EvmStream } from "@apibara/evm";`
@@ -92,11 +93,7 @@ ${
92
93
  : ""
93
94
  }
94
95
  ${language === "typescript" ? `import type { ApibaraRuntimeConfig } from "apibara/types";` : ""}
95
- ${
96
- storage === "postgres"
97
- ? `import { getDrizzlePgDatabase } from "../lib/db";`
98
- : ""
99
- }
96
+ ${storage === "postgres" ? `import * as schema from "../lib/schema";` : ""}
100
97
 
101
98
 
102
99
  export default function (runtimeConfig${language === "typescript" ? ": ApibaraRuntimeConfig" : ""}) {
@@ -104,7 +101,10 @@ export default function (runtimeConfig${language === "typescript" ? ": ApibaraRu
104
101
  const { startingBlock, streamUrl${storage === "postgres" ? ", postgresConnectionString" : ""} } = runtimeConfig[indexerId];
105
102
  ${
106
103
  storage === "postgres"
107
- ? "const { db } = getDrizzlePgDatabase(postgresConnectionString);"
104
+ ? `const db = drizzle({
105
+ schema,
106
+ connectionString: postgresConnectionString,
107
+ });`
108
108
  : ""
109
109
  }
110
110
 
@@ -123,7 +123,7 @@ export default function (runtimeConfig${language === "typescript" ? ": ApibaraRu
123
123
  filter: {
124
124
  header: "always",
125
125
  },
126
- plugins: [${storage === "postgres" ? "drizzleStorage({ db, persistState: true })" : ""}],
126
+ plugins: [${storage === "postgres" ? "drizzleStorage({ db, migrate: { migrationsFolder: './drizzle' } })" : ""}],
127
127
  async transform({ endCursor, finality }) {
128
128
  const logger = useLogger();
129
129
 
@@ -137,14 +137,12 @@ export default function (runtimeConfig${language === "typescript" ? ": ApibaraRu
137
137
  ${
138
138
  storage === "postgres"
139
139
  ? `// Example snippet to insert data into db using drizzle with postgres
140
- // const { db } = useDrizzleStorage();
141
- // const { logs } = block;
142
- // for (const log of logs) {
143
- // await db.insert(exampleTable).values({
144
- // number: Number(endCursor?.orderKey),
145
- // hash: log.transactionHash,
146
- // });
147
- // }`
140
+ // const { db: database } = useDrizzleStorage();
141
+
142
+ // await database.insert(schema.cursorTable).values({
143
+ // endCursor: Number(endCursor?.orderKey),
144
+ // uniqueKey: \`\${endCursor?.uniqueKey}\`,
145
+ // });`
148
146
  : ""
149
147
  }
150
148
  },
@@ -285,7 +283,7 @@ export async function updateApibaraConfigFile({
285
283
  }
286
284
 
287
285
  export async function createDrizzleStorageFiles(options: IndexerOptions) {
288
- const { cwd, language, storage } = options;
286
+ const { cwd, language, storage, indexerId } = options;
289
287
 
290
288
  if (storage !== "postgres") return;
291
289
 
@@ -313,11 +311,11 @@ export async function createDrizzleStorageFiles(options: IndexerOptions) {
313
311
  const drizzleConfigContent = `${language === "typescript" ? 'import type { Config } from "drizzle-kit";' : ""}
314
312
 
315
313
  export default {
316
- schema: "./lib/schema.ts",
314
+ schema: "./lib/schema.${fileExtension}",
317
315
  out: "./drizzle",
318
316
  dialect: "postgresql",
319
317
  dbCredentials: {
320
- url: process.env["POSTGRES_CONNECTION_STRING"] ?? "",
318
+ url: process.env["POSTGRES_CONNECTION_STRING"] ?? "memory://${indexerId}",
321
319
  },
322
320
  }${language === "typescript" ? " satisfies Config" : ""};`;
323
321
 
@@ -348,14 +346,14 @@ export default {
348
346
  });
349
347
 
350
348
  if (!schemaExists || schemaOverwrite) {
351
- const schemaContent = `// --- Add your pg table schemas here ----
349
+ const schemaContent = `// --- Add your pg table schemas here ----
352
350
 
353
351
  // import { bigint, pgTable, text, uuid } from "drizzle-orm/pg-core";
354
352
 
355
- // export const exampleTable = pgTable("example_table", {
353
+ // export const cursorTable = pgTable("cursor_table", {
356
354
  // id: uuid("id").primaryKey().defaultRandom(),
357
- // number: bigint("number", { mode: "number" }),
358
- // hash: text("hash"),
355
+ // endCursor: bigint("end_cursor", { mode: "number" }),
356
+ // uniqueKey: text("unique_key"),
359
357
  // });
360
358
 
361
359
  export {};
@@ -370,63 +368,6 @@ export {};
370
368
  consola.success(`Created ${cyan("lib/schema.ts")}`);
371
369
  }
372
370
 
373
- /**
374
- *
375
- *
376
- * DB File
377
- *
378
- *
379
- */
380
- const dbFileName = `db.${fileExtension}`;
381
-
382
- const dbPath = path.join(cwd, "lib", dbFileName);
383
-
384
- const { exists: dbExists, overwrite: dbOverwrite } = await checkFileExists(
385
- dbPath,
386
- {
387
- askPrompt: true,
388
- fileName: `lib/${dbFileName}`,
389
- allowIgnore: true,
390
- },
391
- );
392
-
393
- if (!dbExists || dbOverwrite) {
394
- const dbContent = `import * as schema from "./schema";
395
- import { drizzle as nodePgDrizzle } from "drizzle-orm/node-postgres";
396
- import { drizzle as pgLiteDrizzle } from "drizzle-orm/pglite";
397
- import pg from "pg";
398
-
399
-
400
- export function getDrizzlePgDatabase(connectionString${language === "typescript" ? ": string" : ""}) {
401
- // Create pglite instance
402
- if (connectionString.includes("memory")) {
403
- return {
404
- db: pgLiteDrizzle({
405
- schema,
406
- connection: {
407
- dataDir: connectionString,
408
- },
409
- }),
410
- };
411
- }
412
-
413
- // Create node-postgres instance
414
- const pool = new pg.Pool({
415
- connectionString,
416
- });
417
-
418
- return { db: nodePgDrizzle(pool, { schema }) };
419
- }`;
420
-
421
- // create directory if it doesn't exist
422
- fs.mkdirSync(path.dirname(dbPath), { recursive: true });
423
- fs.writeFileSync(dbPath, dbContent);
424
-
425
- await formatFile(dbPath);
426
-
427
- consola.success(`Created ${cyan(`lib/${dbFileName}`)}`);
428
- }
429
-
430
371
  console.log("\n");
431
372
 
432
373
  // If schema file is created, show the example
@@ -446,17 +387,17 @@ ${yellow(`
446
387
 
447
388
  import { bigint, pgTable, text, uuid } from "drizzle-orm/pg-core";
448
389
 
449
- export const exampleTable = pgTable("example_table", {
390
+ export const cursorTable = pgTable("cursor_table", {
450
391
  id: uuid("id").primaryKey().defaultRandom(),
451
- number: bigint("number", { mode: "number" }),
452
- hash: text("hash"),
392
+ endCursor: bigint("end_cursor", { mode: "number" }),
393
+ uniqueKey: text("unique_key"),
453
394
  });`)}`);
454
395
 
455
396
  console.log("\n");
456
397
  }
457
398
 
458
399
  consola.info(
459
- `Run ${green(`${options.packageManager} run drizzle:generate`)} & ${green(`${options.packageManager} run drizzle:migrate`)} to generate and apply migrations.`,
400
+ `Run ${green(`${options.packageManager}${options.packageManager === "npm" ? " run" : ""} drizzle:generate`)} & ${green(`${options.packageManager}${options.packageManager === "npm" ? " run" : ""} drizzle:migrate`)} to generate and apply migrations.`,
460
401
  );
461
402
  }
462
403
 
@@ -72,15 +72,14 @@ export function createIndexer(indexerName: string, preset?: string) {
72
72
 
73
73
  // Put the in-memory persistence plugin first so that it can be overridden by any user-defined
74
74
  // persistence plugin.
75
- // Put the logger last since we want to override any user-defined logger.
76
75
  definition.plugins = [
77
76
  internalContext({
78
77
  indexerName,
79
78
  availableIndexers,
80
79
  } as InternalContext),
80
+ logger({ logger: reporter }),
81
81
  inMemoryPersistence(),
82
82
  ...(definition.plugins ?? []),
83
- logger({ logger: reporter }),
84
83
  ];
85
84
 
86
85
  return _createIndexer(definition);