apibara 2.1.0-beta.3 → 2.1.0-beta.30

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 (81) hide show
  1. package/dist/chunks/add.mjs +16 -8
  2. package/dist/chunks/build.mjs +4 -2
  3. package/dist/chunks/dev.mjs +44 -14
  4. package/dist/chunks/init.mjs +11 -7
  5. package/dist/chunks/prepare.mjs +4 -2
  6. package/dist/chunks/start.mjs +14 -4
  7. package/dist/chunks/write-project-info.mjs +50 -0
  8. package/dist/cli/index.mjs +2 -1
  9. package/dist/core/index.mjs +98 -68
  10. package/dist/create/index.d.mts +2 -1
  11. package/dist/create/index.d.ts +2 -1
  12. package/dist/create/index.mjs +142 -112
  13. package/dist/hooks/index.mjs +1 -1
  14. package/dist/rolldown/index.d.mts +7 -0
  15. package/dist/rolldown/index.d.ts +7 -0
  16. package/dist/rolldown/index.mjs +159 -0
  17. package/dist/runtime/dev.mjs +14 -4
  18. package/dist/runtime/internal/app.d.ts +6 -1
  19. package/dist/runtime/internal/app.mjs +50 -19
  20. package/dist/runtime/internal/helper.d.ts +12 -0
  21. package/dist/runtime/internal/helper.mjs +33 -0
  22. package/dist/runtime/project-info.d.ts +3 -0
  23. package/dist/runtime/project-info.mjs +53 -0
  24. package/dist/runtime/start.mjs +18 -4
  25. package/dist/shared/apibara.63c9a277.mjs +29 -0
  26. package/dist/shared/apibara.730bb1e4.mjs +17 -0
  27. package/dist/types/index.d.mts +23 -19
  28. package/dist/types/index.d.ts +23 -19
  29. package/package.json +13 -16
  30. package/src/cli/commands/add.ts +16 -7
  31. package/src/cli/commands/build.ts +5 -2
  32. package/src/cli/commands/dev.ts +56 -13
  33. package/src/cli/commands/init.ts +12 -7
  34. package/src/cli/commands/prepare.ts +4 -2
  35. package/src/cli/commands/start.ts +16 -3
  36. package/src/cli/commands/write-project-info.ts +56 -0
  37. package/src/cli/common.ts +33 -1
  38. package/src/cli/index.ts +2 -0
  39. package/src/core/apibara.ts +5 -0
  40. package/src/core/build/build.ts +13 -5
  41. package/src/core/build/dev.ts +44 -23
  42. package/src/core/build/error.ts +9 -14
  43. package/src/core/build/prepare.ts +5 -3
  44. package/src/core/build/prod.ts +25 -16
  45. package/src/core/build/types.ts +11 -1
  46. package/src/core/config/defaults.ts +3 -0
  47. package/src/core/config/loader.ts +13 -7
  48. package/src/core/config/resolvers/preset.resolver.ts +3 -0
  49. package/src/core/config/update.ts +1 -1
  50. package/src/create/add.ts +10 -9
  51. package/src/create/constants.ts +10 -11
  52. package/src/create/init.ts +8 -5
  53. package/src/create/templates.ts +130 -102
  54. package/src/hooks/useRuntimeConfig.ts +1 -1
  55. package/src/rolldown/config.ts +111 -0
  56. package/src/rolldown/index.ts +2 -0
  57. package/src/rolldown/plugins/config.ts +17 -0
  58. package/src/{rollup → rolldown}/plugins/indexers.ts +3 -3
  59. package/src/rolldown/plugins/instrumentation.ts +68 -0
  60. package/src/runtime/dev.ts +16 -4
  61. package/src/runtime/internal/app.ts +66 -25
  62. package/src/runtime/internal/helper.ts +55 -0
  63. package/src/runtime/project-info.ts +72 -0
  64. package/src/runtime/start.ts +21 -4
  65. package/src/types/config.ts +23 -12
  66. package/src/types/hooks.ts +8 -5
  67. package/src/types/index.ts +1 -1
  68. package/src/types/rolldown.ts +5 -0
  69. package/src/types/virtual/config.d.ts +4 -1
  70. package/src/types/virtual/indexers.d.ts +4 -1
  71. package/src/types/virtual/instrumentation.d.ts +4 -0
  72. package/dist/rollup/index.d.mts +0 -6
  73. package/dist/rollup/index.d.ts +0 -6
  74. package/dist/rollup/index.mjs +0 -150
  75. package/dist/shared/apibara.1b515d04.mjs +0 -8
  76. package/src/core/config/resolvers/runtime-config.resolver.ts +0 -6
  77. package/src/rollup/config.ts +0 -87
  78. package/src/rollup/index.ts +0 -2
  79. package/src/rollup/plugins/config.ts +0 -12
  80. package/src/rollup/plugins/esm-shim.ts +0 -69
  81. package/src/types/rollup.ts +0 -8
@@ -7,14 +7,8 @@ import { loadConfig, watchConfig } from "c12";
7
7
  import { klona } from "klona/full";
8
8
  import { ApibaraDefaults } from "./defaults";
9
9
  import { resolvePathOptions } from "./resolvers/paths.resolver";
10
- import { presetResolver } from "./resolvers/preset.resolver";
11
- import { resolveRuntimeConfigOptions } from "./resolvers/runtime-config.resolver";
12
10
 
13
- const configResolvers = [
14
- resolvePathOptions,
15
- resolveRuntimeConfigOptions,
16
- presetResolver,
17
- ] as const;
11
+ const configResolvers = [resolvePathOptions] as const;
18
12
 
19
13
  export async function loadOptions(
20
14
  configOverrides: ApibaraConfig = {},
@@ -22,9 +16,21 @@ export async function loadOptions(
22
16
  dev = false,
23
17
  ): Promise<ApibaraOptions> {
24
18
  const options = await _loadUserConfig(configOverrides, opts, dev);
19
+
20
+ // Check if the runtimeConfig is serializable
21
+ try {
22
+ JSON.stringify(options.runtimeConfig);
23
+ } catch (error) {
24
+ throw new Error(
25
+ "Non-serializable runtimeConfig. Please ensure the config is serializable.",
26
+ { cause: error },
27
+ );
28
+ }
29
+
25
30
  for (const resolver of configResolvers) {
26
31
  await resolver(options);
27
32
  }
33
+
28
34
  return options;
29
35
  }
30
36
 
@@ -1,6 +1,9 @@
1
1
  import type { ApibaraOptions } from "apibara/types";
2
2
  import defu from "defu";
3
3
 
4
+ /**
5
+ * @note This resolver is not in use currently, as we resolve presets in runtime files.
6
+ */
4
7
  export async function presetResolver(options: ApibaraOptions) {
5
8
  if (options.preset && options.presets?.[options.preset]) {
6
9
  const new_options = defu(options.presets[options.preset], options);
@@ -4,6 +4,6 @@ export async function updateApibaraConfig(
4
4
  apibara: Apibara,
5
5
  _config: ApibaraDynamicConfig,
6
6
  ) {
7
- await apibara.hooks.callHook("rollup:reload");
7
+ await apibara.hooks.callHook("rolldown:reload");
8
8
  apibara.logger.success("Apibara config hot reloaded!");
9
9
  }
package/src/create/add.ts CHANGED
@@ -37,6 +37,7 @@ type Options = {
37
37
  argNetwork?: string;
38
38
  argStorage?: string;
39
39
  argDnaUrl?: string;
40
+ argRootDir?: string;
40
41
  };
41
42
 
42
43
  export async function addIndexer({
@@ -45,8 +46,10 @@ export async function addIndexer({
45
46
  argNetwork,
46
47
  argStorage,
47
48
  argDnaUrl,
49
+ argRootDir,
48
50
  }: Options) {
49
- const configExists = hasApibaraConfig(process.cwd());
51
+ const cwd = path.join(process.cwd(), argRootDir ?? ".");
52
+ const configExists = hasApibaraConfig(cwd);
50
53
 
51
54
  if (!configExists) {
52
55
  consola.error("No apibara.config found in the current directory.");
@@ -74,7 +77,7 @@ export async function addIndexer({
74
77
  }
75
78
  }
76
79
 
77
- const language = getApibaraConfigLanguage(process.cwd());
80
+ const language = getApibaraConfigLanguage(cwd);
78
81
 
79
82
  validateIndexerId(argIndexerId, true);
80
83
  validateChain(argChain, true);
@@ -93,7 +96,7 @@ export async function addIndexer({
93
96
  validateIndexerId(id)
94
97
  ? checkFileExists(
95
98
  path.join(
96
- process.cwd(),
99
+ cwd,
97
100
  "indexers",
98
101
  `${id}.indexer.${language === "typescript" ? "ts" : "js"}`,
99
102
  ),
@@ -197,7 +200,7 @@ export async function addIndexer({
197
200
  const pkgManager = getPackageManager();
198
201
 
199
202
  const options: IndexerOptions = {
200
- cwd: process.cwd(),
203
+ cwd: cwd,
201
204
  indexerFileId,
202
205
  indexerId: convertKebabToCamelCase(indexerFileId),
203
206
  chain: (argChain as Chain) ?? prompt_chain?.name!,
@@ -228,11 +231,9 @@ export async function addIndexer({
228
231
 
229
232
  console.log();
230
233
 
234
+ const baseCommand = `${options.packageManager} install`;
235
+ const tsCommand = `${baseCommand} && ${options.packageManager} run prepare`;
231
236
  consola.info(
232
- `Before running the indexer, run ${cyan(`${options.packageManager} run install`)}${
233
- language === "typescript"
234
- ? " & " + cyan(`${options.packageManager} run prepare`)
235
- : ""
236
- }`,
237
+ `Before running the indexer, run ${cyan(language === "typescript" ? tsCommand : baseCommand)}`,
237
238
  );
238
239
  }
@@ -66,26 +66,25 @@ export const storages: StorageDataType[] = [
66
66
 
67
67
  export const packageVersions = {
68
68
  // Required Dependencies
69
- apibara: "^2.1.0-beta.2",
70
- "@apibara/indexer": "^2.1.0-beta.2",
71
- "@apibara/protocol": "^2.1.0-beta.2",
69
+ apibara: "next",
70
+ "@apibara/indexer": "next",
71
+ "@apibara/protocol": "next",
72
72
  // Chain Dependencies
73
- "@apibara/evm": "^2.1.0-beta.2",
74
- "@apibara/beaconchain": "^2.1.0-beta.2",
75
- "@apibara/starknet": "^2.1.0-beta.2",
73
+ "@apibara/evm": "next",
74
+ "@apibara/beaconchain": "next",
75
+ "@apibara/starknet": "next",
76
76
  // Storage Dependencies
77
- "@apibara/plugin-drizzle": "^2.1.0-beta.2",
78
- "@apibara/plugin-mongo": "^2.1.0-beta.2",
79
- "@apibara/plugin-sqlite": "^2.1.0-beta.2",
77
+ "@apibara/plugin-drizzle": "next",
78
+ "@apibara/plugin-mongo": "next",
79
+ "@apibara/plugin-sqlite": "next",
80
80
  // Postgres Dependencies
81
81
  "@electric-sql/pglite": "^0.2.17",
82
- "drizzle-orm": "^0.37.0",
82
+ "drizzle-orm": "^0.40.1",
83
83
  pg: "^8.13.1",
84
84
  "@types/pg": "^8.11.10",
85
85
  "drizzle-kit": "^0.29.0",
86
86
  // Typescript Dependencies
87
87
  typescript: "^5.6.2",
88
- "@rollup/plugin-typescript": "^11.1.6",
89
88
  "@types/node": "^20.5.2",
90
89
  };
91
90
 
@@ -5,6 +5,7 @@ import prompts from "prompts";
5
5
  import { addIndexer } from "./add";
6
6
  import { cyan, green } from "./colors";
7
7
  import {
8
+ createGitIgnoreFile,
8
9
  generateApibaraConfig,
9
10
  generatePackageJson,
10
11
  generateTsConfig,
@@ -129,7 +130,7 @@ export async function initializeProject({
129
130
  JSON.stringify(packageJson, null, 2) + "\n",
130
131
  );
131
132
  await formatFile(packageJsonPath);
132
- consola.success("Created ", cyan("package.json"));
133
+ consola.success("Created", cyan("package.json"));
133
134
 
134
135
  // Generate tsconfig.json if TypeScript
135
136
  if (isTs) {
@@ -137,7 +138,7 @@ export async function initializeProject({
137
138
  const tsConfig = generateTsConfig();
138
139
  fs.writeFileSync(tsConfigPath, JSON.stringify(tsConfig, null, 2) + "\n");
139
140
  await formatFile(tsConfigPath);
140
- consola.success("Created ", cyan("tsconfig.json"));
141
+ consola.success("Created", cyan("tsconfig.json"));
141
142
  }
142
143
 
143
144
  const apibaraConfigPath = path.join(root, `apibara.config.${configExt}`);
@@ -145,7 +146,7 @@ export async function initializeProject({
145
146
  const apibaraConfig = generateApibaraConfig(isTs);
146
147
  fs.writeFileSync(apibaraConfigPath, apibaraConfig);
147
148
  await formatFile(apibaraConfigPath);
148
- consola.success("Created ", cyan(`apibara.config.${configExt}`));
149
+ consola.success("Created", cyan(`apibara.config.${configExt}`));
149
150
 
150
151
  // Create "indexers" directory if not exists
151
152
  const indexersDir = path.join(root, "indexers");
@@ -154,6 +155,8 @@ export async function initializeProject({
154
155
  consola.success(`Created ${cyan("indexers")} directory`);
155
156
  }
156
157
 
158
+ await createGitIgnoreFile(root);
159
+
157
160
  console.log("\n");
158
161
 
159
162
  consola.ready(green("Project initialized successfully"));
@@ -163,12 +166,12 @@ export async function initializeProject({
163
166
  if (!argNoCreateIndexer) {
164
167
  consola.info("Let's create an indexer\n");
165
168
 
166
- await addIndexer({});
169
+ await addIndexer({ argRootDir: argTargetDir });
167
170
  } else {
168
171
  const pkgManager = getPackageManager();
169
172
  consola.info(
170
173
  "Run ",
171
- green(`${pkgManager.name} run install`),
174
+ green(`${pkgManager.name} install`),
172
175
  " to install all dependencies",
173
176
  );
174
177
  }
@@ -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,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
 
@@ -81,6 +73,7 @@ export function generateIndexer({
81
73
  return `import { defineIndexer } from "@apibara/indexer";
82
74
  import { useLogger } from "@apibara/indexer/plugins";
83
75
  ${storage === "postgres" ? `import { drizzleStorage } from "@apibara/plugin-drizzle";` : ""}
76
+ ${storage === "postgres" ? `import { drizzle } from "@apibara/plugin-drizzle";` : ""}
84
77
  ${
85
78
  chain === "ethereum"
86
79
  ? `import { EvmStream } from "@apibara/evm";`
@@ -91,19 +84,17 @@ ${
91
84
  : ""
92
85
  }
93
86
  ${language === "typescript" ? `import type { ApibaraRuntimeConfig } from "apibara/types";` : ""}
94
- ${
95
- storage === "postgres"
96
- ? `import { getDrizzlePgDatabase } from "../lib/db";`
97
- : ""
98
- }
87
+ ${storage === "postgres" ? `import * as schema from "../lib/schema";` : ""}
99
88
 
100
89
 
101
90
  export default function (runtimeConfig${language === "typescript" ? ": ApibaraRuntimeConfig" : ""}) {
102
91
  const indexerId = "${indexerId}";
103
- const { startingBlock, streamUrl${storage === "postgres" ? ", postgresConnectionString" : ""} } = runtimeConfig[indexerId];
92
+ const { startingBlock, streamUrl } = runtimeConfig[indexerId];
104
93
  ${
105
94
  storage === "postgres"
106
- ? "const { db } = getDrizzlePgDatabase(postgresConnectionString);"
95
+ ? `const db = drizzle({
96
+ schema,
97
+ });`
107
98
  : ""
108
99
  }
109
100
 
@@ -122,7 +113,7 @@ export default function (runtimeConfig${language === "typescript" ? ": ApibaraRu
122
113
  filter: {
123
114
  header: "always",
124
115
  },
125
- plugins: [${storage === "postgres" ? "drizzleStorage({ db, persistState: true })" : ""}],
116
+ plugins: [${storage === "postgres" ? "drizzleStorage({ db, migrate: { migrationsFolder: './drizzle' } })" : ""}],
126
117
  async transform({ endCursor, finality }) {
127
118
  const logger = useLogger();
128
119
 
@@ -136,14 +127,12 @@ export default function (runtimeConfig${language === "typescript" ? ": ApibaraRu
136
127
  ${
137
128
  storage === "postgres"
138
129
  ? `// 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
- // }`
130
+ // const { db: database } = useDrizzleStorage();
131
+
132
+ // await database.insert(schema.cursorTable).values({
133
+ // endCursor: Number(endCursor?.orderKey),
134
+ // uniqueKey: \`\${endCursor?.uniqueKey}\`,
135
+ // });`
147
136
  : ""
148
137
  }
149
138
  },
@@ -235,12 +224,8 @@ export async function updateApibaraConfigFile({
235
224
 
236
225
  const runtimeConfigString = `{
237
226
  startingBlock: 0,
238
- streamUrl: "${dnaUrl ?? getDnaUrl(chain, network)}"${
239
- storage === "postgres"
240
- ? `,
241
- postgresConnectionString: process.env["POSTGRES_CONNECTION_STRING"] ?? "memory://${indexerId}"`
242
- : ""
243
- }}`;
227
+ streamUrl: "${dnaUrl ?? getDnaUrl(chain, network)}"
228
+ }`;
244
229
 
245
230
  const project = new Project();
246
231
  const sourceFile = project.addSourceFileAtPath(pathToConfig);
@@ -284,7 +269,7 @@ export async function updateApibaraConfigFile({
284
269
  }
285
270
 
286
271
  export async function createDrizzleStorageFiles(options: IndexerOptions) {
287
- const { cwd, language, storage } = options;
272
+ const { cwd, language, storage, indexerId } = options;
288
273
 
289
274
  if (storage !== "postgres") return;
290
275
 
@@ -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 {};
@@ -369,63 +354,6 @@ export {};
369
354
  consola.success(`Created ${cyan("lib/schema.ts")}`);
370
355
  }
371
356
 
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}`)}`);
427
- }
428
-
429
357
  console.log("\n");
430
358
 
431
359
  // If schema file is created, show the example
@@ -445,17 +373,17 @@ ${yellow(`
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
+ }
@@ -1,5 +1,5 @@
1
1
  import type { ApibaraRuntimeConfig } from "apibara/types";
2
2
 
3
3
  export function useRuntimeConfig(): ApibaraRuntimeConfig {
4
- return JSON.parse(process.env.APIBARA_RUNTIME_CONFIG || "{}");
4
+ return JSON.parse(process.env.APIBARA_RUNTIME_CONFIG_HOOK_DATA || "{}");
5
5
  }
@@ -0,0 +1,111 @@
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 { appConfig } from "./plugins/config";
13
+ import { indexers } from "./plugins/indexers";
14
+ import { instrumentation } from "./plugins/instrumentation";
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
+ // 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(
83
+ replace({
84
+ preventAssignment: true,
85
+ values: {
86
+ "process.env.APIBARA_CONFIG": getSerializedRuntimeConfig(apibara),
87
+ },
88
+ }) as RolldownPluginOption,
89
+ );
90
+
91
+ rolldownConfig.plugins?.push(instrumentation(apibara));
92
+ rolldownConfig.plugins?.push(indexers(apibara));
93
+ rolldownConfig.plugins?.push(appConfig(apibara));
94
+
95
+ return rolldownConfig;
96
+ }
97
+
98
+ function getSerializedRuntimeConfig(apibara: Apibara) {
99
+ try {
100
+ return JSON.stringify({
101
+ runtimeConfig: apibara.options.runtimeConfig,
102
+ preset: apibara.options.preset,
103
+ presets: apibara.options.presets,
104
+ });
105
+ } catch (error) {
106
+ throw new Error(
107
+ "Failed to serialize runtime config. Please ensure all values in your runtime configuration are JSON serializable.",
108
+ { cause: error },
109
+ );
110
+ }
111
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./config";
2
+ export type { Plugin } from "rolldown";