Skip to content

Conversation

@fracek
Copy link
Contributor

@fracek fracek commented Nov 1, 2024

Context

This PR refactors how the build, dev, and start commands work.

We leverage the Rollup's virtual plugin to generate a list of indexers to build time.
This indexers are then imported by the dev/start command at runtime.

@coderabbitai
Copy link

coderabbitai bot commented Nov 1, 2024

📝 Walkthrough
📝 Walkthrough

Walkthrough

The pull request introduces significant updates to the apibara package, including a new JSON configuration file that specifies a prerelease type and refactors various commands. The build configuration is expanded to include a new runtime module, while the package.json reflects changes in dependencies and exports. New CLI commands for managing indexers are added, and logging is centralized through the apibara.logger. Additionally, several files are deleted or modified to streamline the codebase, enhance type definitions, and improve configuration handling.

Changes

File Path Change Summary
change/apibara-ed31dbbf-efbd-44c6-8eb0-f729dde0acb6.json New JSON configuration added for apibara, specifying release type, comments, contributor email, and change type.
packages/cli/build.config.ts Added new runtime module to the build configuration, updated entries, aliases, and externals.
packages/cli/package.json Updated version, modified exports, restructured dependencies, and enhanced playground script for debugging.
packages/cli/playground/apibara.config.ts Updated runtime configuration with new nested and environment properties; removed previous sink configuration.
packages/cli/playground/indexers/starknet.indexer.ts Updated streamUrl and startingCursor, enhanced logging in the transform function, and removed hooks section.
packages/cli/playground/tsconfig.json Deleted TypeScript configuration file.
packages/cli/runtime-meta.d.ts Added new exported constants pkgDir and runtimeDir.
packages/cli/runtime-meta.mjs Added new exported constants pkgDir and runtimeDir.
packages/cli/src/cli/commands/build.ts Replaced consola logging with apibara.logger, updated entry point configuration.
packages/cli/src/cli/commands/dev.ts Replaced consola logging with apibara.logger, scoped childProcess variable, and updated entry point.
packages/cli/src/cli/commands/prepare.ts Removed consola logging.
packages/cli/src/cli/commands/start.ts Introduced a new start command for initiating indexers with specified arguments.
packages/cli/src/cli/index.ts Added new start sub-command to the CLI configuration.
packages/cli/src/config/index.ts Updated generic type parameters in defineConfig function for stricter typing.
packages/cli/src/core/apibara.ts Added scanIndexers function call and initialized indexers property in apibara object.
packages/cli/src/core/build/build.ts Added hook call before Rollup build process.
packages/cli/src/core/build/dev.ts Added hook call for dev:restart event handling.
packages/cli/src/core/build/prepare.ts Replaced consola logging with apibara.logger.
packages/cli/src/core/build/prod.ts Updated logging and error handling to use apibara.logger.
packages/cli/src/core/build/types.ts Replaced consola logging with apibara.logger and added a new logging statement.
packages/cli/src/core/config/defaults.ts Added new property indexersDir to ApibaraDefaults.
packages/cli/src/core/config/loader.ts Updated _loadUserConfig to conditionally set dev property.
packages/cli/src/core/config/resolvers/runtime-config.resolver.ts Removed addition of default property in resolveRuntimeConfigOptions.
packages/cli/src/core/config/update.ts Renamed parameter in updateApibaraConfig and updated logging to use apibara.logger.
packages/cli/src/core/scan.ts Introduced scanIndexers function for scanning indexer files and extracting their definitions.
packages/cli/src/internal/citty/index.ts Deleted re-exporting module for citty.
packages/cli/src/internal/consola/index.ts Deleted re-exporting module for consola.
packages/cli/src/rollup/config.ts Simplified getRollupConfig function by removing error handling and restructuring the configuration object.
packages/cli/src/rollup/plugins/config.ts Introduced appConfig function to create a virtual module with configuration.
packages/cli/src/rollup/plugins/indexers.ts Introduced indexers function to create a virtual module for unique indexers.
packages/cli/src/runtime/dev.ts Introduced CLI for managing indexers in development, including start command.
packages/cli/src/runtime/index.ts Added export for createIndexer function.
packages/cli/src/runtime/internal/app.ts Introduced functionality for managing indexers with createIndexer function.
packages/cli/src/runtime/start.ts Introduced CLI for starting an indexer, including startCommand.
packages/cli/src/types/apibara.ts Added IndexerDefinition type and updated Apibara interface to include indexers.
packages/cli/src/types/config.ts Updated ApibaraConfig and ApibaraOptions interfaces, removing sink property and adding indexersDir and sourceMap.
packages/cli/src/types/hooks.ts Added dev:restart method to ApibaraHooks interface.
packages/cli/src/types/virtual/config.d.ts Added config constant typed as ApibaraConfig.
packages/cli/src/types/virtual/indexers.d.ts Added IndexerConstructor type alias and indexers constant.
packages/cli/tsconfig.json Updated path mappings in TypeScript configuration.

Possibly related PRs

  • fix build inconsistencies and add example for cli #104: This PR introduces a new JSON configuration file for the apibara package, which is related to the main PR's addition of a JSON configuration file for the same package, indicating a similar focus on configuration management.
  • indexer: update drizzle and drizzle sink #107: This PR updates the drizzle and drizzle sink components within the @apibara/indexer package, which is relevant as the main PR also involves changes to the apibara package, suggesting a broader context of updates across related packages.

Poem

In the meadow, changes bloom,
With apibara breaking gloom.
New commands hop, and logging's bright,
Indexers dance in the soft moonlight.
With paths restructured, all feels right,
A joyful leap, a coder's delight! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@fracek fracek requested a review from jaipaljadeja November 1, 2024 16:10
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 23

🧹 Outside diff range and nitpick comments (22)
packages/cli/runtime-meta.d.ts (1)

1-2: Add JSDoc comments to document the constants' purpose.

While the constant names are descriptive, adding JSDoc comments would improve documentation and provide better IDE support.

+/** The root directory of the package */
 export declare const pkgDir: string;
+/** The directory containing runtime-related files */
 export declare const runtimeDir: string;
packages/cli/src/config/index.ts (1)

4-8: LGTM! Improved type safety with stricter generic defaults.

The change from {} to Record<string, never> as default generic parameters is a good improvement. This makes the type system more strict and prevents accidental property assignments in empty configurations.

This change aligns well with TypeScript best practices and provides better type safety. The stricter typing will help catch potential configuration errors at compile time rather than runtime.

packages/cli/src/types/hooks.ts (1)

7-7: LGTM, but documentation needed for restart hooks.

While the addition of the "dev:restart" hook is appropriate, there are multiple restart-related hooks ("dev:restart", "dev:reload", "rollup:reload", "restart") that could benefit from documentation explaining their distinct purposes and execution order.

Consider adding JSDoc comments to clarify:

+ /** Triggered when the dev process needs to restart (e.g., when Rollup watcher starts/restarts) */
  "dev:restart": () => void;
+ /** Triggered when files need to be reloaded during development */
  "dev:reload": () => void;
+ /** Triggered when Rollup needs to reload configuration */
  "rollup:reload": () => void;
+ /** Triggered for a full restart of the application */
  restart: () => void;
packages/cli/src/core/config/defaults.ts (1)

5-5: Consider adding JSDoc comment for the new config option.

Adding documentation for the indexersDir configuration would help users understand its purpose and relationship with the build system.

 export const ApibaraDefaults: ApibaraConfig = {
   rootDir: ".",
+  /** Directory containing indexer definitions, used during build time to generate the indexer list. */
   indexersDir: "indexers",
packages/cli/src/core/build/prepare.ts (1)

Line range hint 5-16: Consider enhancing error handling for directory operations.

While the current implementation relies on Promise rejections, consider adding explicit error handling for directory operations to provide more informative error messages to users.

Here's a suggested improvement:

 export async function prepare(apibara: Apibara) {
-  await prepareDir(apibara.options.buildDir);
-  await prepareDir(apibara.options.outputDir);
+  try {
+    await prepareDir(apibara.options.buildDir);
+    await prepareDir(apibara.options.outputDir);
+    apibara.logger.success("Output directory cleaned");
+  } catch (error) {
+    apibara.logger.error(`Failed to prepare directories: ${error.message}`);
+    throw error;
+  }
-  apibara.logger.success("Output directory cleaned");
 }

 async function prepareDir(dir: string) {
-  await fsp.mkdir(dir, { recursive: true });
-  await fse.emptyDir(dir);
+  try {
+    await fsp.mkdir(dir, { recursive: true });
+    await fse.emptyDir(dir);
+  } catch (error) {
+    throw new Error(`Failed to prepare directory ${dir}: ${error.message}`);
+  }
 }
packages/cli/src/rollup/plugins/indexers.ts (1)

4-5: Add input validation and document the deduplication purpose.

While the deduplication logic is correct, consider adding:

  1. Input validation for apibara.indexers
  2. Documentation explaining why deduplication is necessary

Consider this improvement:

 export function indexers(apibara: Apibara) {
+  if (!Array.isArray(apibara.indexers)) {
+    throw new Error('apibara.indexers must be an array');
+  }
+  // Deduplicate indexers to prevent multiple imports of the same module
   const indexers = [...new Set(apibara.indexers)];
packages/cli/src/types/apibara.ts (1)

6-11: Enhance type definition documentation and constraints.

While the type definition is clear, consider these improvements:

  1. Add JSDoc comments with more detailed descriptions
  2. Consider using a more specific type for the indexer path property

Here's a suggested improvement:

+/**
+ * Represents an indexer configuration within the Apibara system.
+ */
 export type IndexerDefinition = {
+  /**
+   * Unique identifier for the indexer.
+   * This name is used to reference the indexer in CLI commands.
+   */
   name: string;
+  /**
+   * Relative or absolute path to the indexer implementation file.
+   * The file should export the indexer configuration.
+   */
   indexer: string;
 };
packages/cli/src/core/build/prod.ts (1)

Line range hint 18-18: Enhance error message for missing output configuration.

Consider providing more context in the error message to help users troubleshoot configuration issues.

-      throw new Error("No output options specified in Rollup config");
+      throw new Error("No output options specified in Rollup config. Please define either a single output option or an array of outputs in your configuration.");
packages/cli/src/core/apibara.ts (1)

24-24: Consider type safety for indexers array

While initializing indexers as an empty array is correct, consider explicitly typing it for better type safety and documentation.

-    indexers: [],
+    indexers: Array<IndexerDefinition> = [],

Please ensure IndexerDefinition type is imported from the appropriate module.

packages/cli/build.config.ts (1)

32-38: Consider documenting the runtime-meta.mjs purpose

The runtime-meta.mjs file is referenced outside the src directory, which is an unusual pattern. Consider:

  1. Adding a comment explaining its purpose and relationship to the runtime module
  2. Documenting why it needs to be external to the src directory
packages/cli/src/core/scan.ts (1)

5-5: Consider making the constant immutable.

To prevent accidental modifications, consider making the array readonly.

-const INDEXER_EXTENSIONS = [".indexer.ts", ".indexer.js"];
+const INDEXER_EXTENSIONS = Object.freeze([".indexer.ts", ".indexer.js"]) as readonly string[];
packages/cli/src/runtime/start.ts (2)

36-44: Consider aligning CLI name with project branding.

The name "indexer-runner" might not align with the Apibara branding. Consider using "apibara" or a similar brand-aligned name.

 export const mainCli = defineCommand({
   meta: {
-    name: "indexer-runner",
+    name: "apibara",
     description: "Run an indexer",
   },
   subCommands: {
     start: () => startCommand,
   },
 });

46-48: Remove unnecessary default export.

The empty default export serves no purpose and can be removed.

 runMain(mainCli);
-
-export default {};
packages/cli/src/cli/commands/start.ts (2)

20-23: Consider adding validation for the preset argument.

The preset argument accepts any string value without validation. Consider adding allowed values or a validation function to ensure only supported presets are used.

 preset: {
   type: "string",
   description: "The preset to use",
+  validate: (value: string) => ["preset1", "preset2"].includes(value),
+  options: ["preset1", "preset2"],
 },

43-43: Consider using unique build directories for concurrent runs.

Using a fixed build directory (.apibara/build) could cause issues if multiple instances of the CLI are running simultaneously.

Consider:

  1. Using a unique directory per run (e.g., including a timestamp or UUID)
  2. Implementing a cleanup mechanism for old builds
  3. Adding a lock mechanism to prevent concurrent builds
packages/cli/src/core/config/loader.ts (2)

Line range hint 28-29: Address the linting issue instead of ignoring it.

The code uses biome-ignore lint: noParameterAssign to suppress a linting warning about parameter reassignment. Consider refactoring to avoid parameter mutation.

-  // biome-ignore lint: noParameterAssign
-  configOverrides = klona(configOverrides);
+  const clonedOverrides = klona(configOverrides);

Then update subsequent uses of configOverrides to use clonedOverrides.


Line range hint 28-54: Consider splitting configuration loading and processing.

The _loadUserConfig function handles multiple responsibilities:

  1. Configuration loading
  2. Deep cloning
  3. Metadata attachment
  4. Dev mode handling

This could make the function harder to maintain as more features are added.

Consider splitting this into smaller, focused functions:

async function loadRawConfig(overrides: ApibaraConfig, opts: LoadConfigOptions) {
  return (opts.watch ? watchConfig : loadConfig)({...});
}

function processLoadedConfig(
  loadedConfig: LoadResult<ApibaraConfig>,
  overrides: ApibaraConfig,
  dev: boolean
): ApibaraOptions {
  const options = klona(loadedConfig.config);
  options._config = overrides;
  options._c12 = loadedConfig;
  options.dev = dev;
  return options;
}

This would make the code more maintainable and easier to test.

packages/cli/src/types/config.ts (1)

63-64: Add JSDoc comment for the indexersDir property

While the addition of indexersDir aligns with the PR's objectives, adding a JSDoc comment would help users understand its purpose and expected value.

+ /** Directory containing the indexer definitions */
  indexersDir: string;
packages/cli/src/cli/commands/dev.ts (1)

Line range hint 101-116: Consider enhancing error handling for child process.

While the process exit code is logged, there's no handling of process spawn errors or unexpected terminations.

Consider adding error handling:

 childProcess = spawn("node", childArgs, {
   stdio: "inherit",
 });

+childProcess.on("error", (error) => {
+  apibara.logger.error(`Failed to start indexers: ${error.message}`);
+});
+
 childProcess.on("close", (code) => {
   if (code !== null) {
-    apibara.logger.log(`Indexers process exited with code ${code}`);
+    if (code === 0) {
+      apibara.logger.success("Indexers process completed successfully");
+    } else {
+      apibara.logger.error(`Indexers process failed with code ${code}`);
+    }
   }
 });
packages/cli/src/core/build/types.ts (2)

Line range hint 11-83: Add error handling for type generation operations.

The type generation logic lacks proper error handling for file operations and type generation. Consider adding try-catch blocks and error logging to handle potential failures gracefully.

Here's a suggested improvement for the file operations:

-  await Promise.all(
-    buildFiles.map(async (file) => {
-      const _file = resolve(apibara.options.buildDir, file.path);
-      await fsp.mkdir(dirname(_file), { recursive: true });
-      await fsp.writeFile(_file, file.contents);
-    }),
-  );
+  try {
+    await Promise.all(
+      buildFiles.map(async (file) => {
+        const _file = resolve(apibara.options.buildDir, file.path);
+        try {
+          await fsp.mkdir(dirname(_file), { recursive: true });
+          await fsp.writeFile(_file, file.contents);
+        } catch (err) {
+          apibara.logger.error(`Failed to write file ${file.path}: ${err.message}`);
+          throw err;
+        }
+      }),
+    );
+  } catch (err) {
+    apibara.logger.error('Type generation failed');
+    throw err;
+  }

Line range hint 84-133: Consider refactoring path handling logic for better maintainability.

The path handling logic, particularly for TSConfig generation, is complex and could benefit from:

  1. Moving the relativeWithDot utility to a separate utilities file
  2. Creating dedicated functions for path normalization
  3. Adding documentation for the path manipulation logic

Consider creating a new utility file packages/cli/src/core/utils/path.ts:

/**
 * Ensures a path starts with './' if it's not already a relative path
 * @param from - The base directory path
 * @param to - The target path to make relative
 * @returns A properly formatted relative path
 */
export function relativeWithDot(from: string, to: string) {
  const rel = relative(from, to);
  return RELATIVE_RE.test(rel) ? rel : `./${rel}`;
}

/**
 * Normalizes TSConfig paths by converting absolute paths to relative
 * @param tsconfigDir - The directory containing tsconfig
 * @param paths - Array of paths to normalize
 */
export async function normalizeTSConfigPaths(tsconfigDir: string, paths: string[]) {
  return Promise.all(
    paths.map(async (path) => {
      if (!isAbsolute(path)) {
        return path;
      }
      const stats = await fsp.stat(path).catch(() => null);
      return relativeWithDot(
        tsconfigDir,
        stats?.isFile() ? path.replace(/(?<=\w)\.\w+$/g, "") : path,
      );
    }),
  );
}

Also applies to: 136-141

packages/cli/src/runtime/dev.ts (1)

64-64: Consider removing unnecessary default export

The default export of an empty object may not be necessary if it is not used elsewhere.

You can remove the default export if it's not needed:

- export default {};
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between d3aec5a and e021f45.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (40)
  • change/apibara-ed31dbbf-efbd-44c6-8eb0-f729dde0acb6.json (1 hunks)
  • packages/cli/build.config.ts (2 hunks)
  • packages/cli/package.json (4 hunks)
  • packages/cli/playground/apibara.config.ts (1 hunks)
  • packages/cli/playground/indexers/starknet.indexer.ts (2 hunks)
  • packages/cli/playground/tsconfig.json (0 hunks)
  • packages/cli/runtime-meta.d.ts (1 hunks)
  • packages/cli/runtime-meta.mjs (1 hunks)
  • packages/cli/src/cli/commands/build.ts (2 hunks)
  • packages/cli/src/cli/commands/dev.ts (5 hunks)
  • packages/cli/src/cli/commands/prepare.ts (0 hunks)
  • packages/cli/src/cli/commands/start.ts (1 hunks)
  • packages/cli/src/cli/index.ts (1 hunks)
  • packages/cli/src/config/index.ts (1 hunks)
  • packages/cli/src/core/apibara.ts (3 hunks)
  • packages/cli/src/core/build/build.ts (1 hunks)
  • packages/cli/src/core/build/dev.ts (1 hunks)
  • packages/cli/src/core/build/prepare.ts (1 hunks)
  • packages/cli/src/core/build/prod.ts (2 hunks)
  • packages/cli/src/core/build/types.ts (2 hunks)
  • packages/cli/src/core/config/defaults.ts (1 hunks)
  • packages/cli/src/core/config/loader.ts (1 hunks)
  • packages/cli/src/core/config/resolvers/runtime-config.resolver.ts (1 hunks)
  • packages/cli/src/core/config/update.ts (1 hunks)
  • packages/cli/src/core/scan.ts (1 hunks)
  • packages/cli/src/internal/citty/index.ts (0 hunks)
  • packages/cli/src/internal/consola/index.ts (0 hunks)
  • packages/cli/src/rollup/config.ts (3 hunks)
  • packages/cli/src/rollup/plugins/config.ts (1 hunks)
  • packages/cli/src/rollup/plugins/indexers.ts (1 hunks)
  • packages/cli/src/runtime/dev.ts (1 hunks)
  • packages/cli/src/runtime/index.ts (1 hunks)
  • packages/cli/src/runtime/internal/app.ts (1 hunks)
  • packages/cli/src/runtime/start.ts (1 hunks)
  • packages/cli/src/types/apibara.ts (1 hunks)
  • packages/cli/src/types/config.ts (3 hunks)
  • packages/cli/src/types/hooks.ts (1 hunks)
  • packages/cli/src/types/virtual/config.d.ts (1 hunks)
  • packages/cli/src/types/virtual/indexers.d.ts (1 hunks)
  • packages/cli/tsconfig.json (1 hunks)
💤 Files with no reviewable changes (4)
  • packages/cli/playground/tsconfig.json
  • packages/cli/src/cli/commands/prepare.ts
  • packages/cli/src/internal/citty/index.ts
  • packages/cli/src/internal/consola/index.ts
✅ Files skipped from review due to trivial changes (3)
  • change/apibara-ed31dbbf-efbd-44c6-8eb0-f729dde0acb6.json
  • packages/cli/src/runtime/index.ts
  • packages/cli/src/types/virtual/config.d.ts
🔇 Additional comments (51)
packages/cli/runtime-meta.d.ts (1)

1-2: Verify consistent path resolution across the codebase.

The declarations look good. Let's verify that these constants are used consistently for path resolution.

✅ Verification successful

Based on the results, I can now generate the final response:

Path resolution is consistent across the codebase

The verification shows that:

  • runtimeDir is consistently used with join from the pathe package for resolving runtime-related paths in CLI commands
  • pkgDir is properly defined using fileURLToPath for package-level path resolution
  • Other path resolution methods (path.join, path.resolve) are used in different packages for different purposes, not conflicting with these constants
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of pkgDir and runtimeDir constants
# Expected: These constants should be used for path resolution and not mixed with other path resolution methods

# Check how these constants are used in path resolution
echo "Checking usage of pkgDir and runtimeDir..."
rg -A 3 "pkgDir|runtimeDir"

# Check for potential inconsistent path resolution methods
echo "Checking for other path resolution methods..."
ast-grep --pattern 'path.join($$$)' 
ast-grep --pattern 'path.resolve($$$)'

Length of output: 3063

packages/cli/runtime-meta.mjs (3)

1-1: LGTM! Using the recommended import for URL handling.

The use of node:url protocol ensures consistent resolution of the built-in module across different Node.js versions.


3-3: LGTM! Correct implementation of package directory resolution.

The implementation correctly resolves the package directory using fileURLToPath and import.meta.url, which is the recommended approach for ES modules.


5-7: Verify runtime directory existence during build.

While the path resolution is implemented correctly, we should ensure the dist/runtime/ directory exists when these paths are used.

Let's verify the directory structure:

Consider adding a build step to ensure this directory exists:

+// Add to your build script
+import { mkdir } from 'node:fs/promises';
+await mkdir(runtimeDir, { recursive: true });
packages/cli/src/rollup/plugins/config.ts (2)

1-2: LGTM! Imports are correctly structured.

The imports are well-organized, using proper type imports for better tree-shaking.


4-10: 🛠️ Refactor suggestion

Verify sensitive data handling and add validation.

The function stringifies the entire options object without filtering sensitive data or validating its structure.

Let's check for potential sensitive data in the options:

Consider these improvements:

  1. Add options validation
  2. Filter out sensitive data before stringifying
  3. Add type safety for the options structure

Here's a suggested implementation:

import virtual from "@rollup/plugin-virtual";
import type { Apibara } from "apibara/types";

function sanitizeOptions(options: unknown) {
  // Add validation and sanitization logic
  if (!options || typeof options !== 'object') {
    throw new Error('Invalid options');
  }
  // Deep clone and remove sensitive fields
  return JSON.parse(JSON.stringify(options, (_, value) => 
    // Example: mask sensitive field values
    typeof value === 'string' && /password|secret|key|token/i.test(_) 
      ? '[REDACTED]' 
      : value
  ));
}

export function appConfig(apibara: Apibara) {
  const safeOptions = sanitizeOptions(apibara.options);
  return virtual({
    "#apibara-internal-virtual/config": `
    export const config = ${JSON.stringify(safeOptions, null, 
      process.env.NODE_ENV === 'production' ? 0 : 2)};
    `,
  });
}
packages/cli/playground/apibara.config.ts (1)

3-13: LGTM! Configuration structure is clean and well-organized.

The configuration structure with separate sections for base config and presets provides good flexibility for different environments.

packages/cli/src/core/config/defaults.ts (1)

5-5: Verify compatibility of default indexers directory.

The addition of indexersDir aligns well with the refactoring goals. However, let's verify that the default "indexers" path works correctly with the existing project structure.

✅ Verification successful

Let me gather more specific information about the actual indexer file locations and usage patterns.


Let me try a different approach to find indexer file patterns and their usage.


Based on the results, I can now generate the final response:

Default indexers directory is compatible with existing structure

The default indexersDir: "indexers" aligns perfectly with the current codebase organization, as evidenced by:

  • Example indexer files in examples/cli/indexers/
  • Playground indexers in packages/cli/playground/indexers/

These existing implementations already follow the proposed default directory structure, confirming its compatibility with the project.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if any existing indexer files are already using a different directory structure
fd -t f -e ts -e js --full-path indexer

Length of output: 1967


Script:

#!/bin/bash
# Check for actual indexer file patterns and their locations
rg -l "\.indexer\.(ts|js)$"

# Look for any imports or references to indexer paths in CLI code
rg -g '*.ts' -g '*.js' "indexers.*\.(ts|js)" packages/cli/

Length of output: 90


Script:

#!/bin/bash
# Find indexer files in examples and playground directories
fd -t f ".*indexer\.(ts|js)$"

# Look for code that loads or processes indexer files
ast-grep --pattern 'from "$_/indexers/$_"'
ast-grep --pattern 'require("$_/indexers/$_")'

Length of output: 365

packages/cli/src/core/build/prepare.ts (1)

9-9: LGTM! Consistent with centralized logging approach.

The change aligns with the PR's objective of centralizing logging through apibara.logger.

Let's verify the logger interface implementation:

✅ Verification successful

Based on the extensive search results, I can now generate the final response:

Logger implementation verified and consistent across codebase

The apibara.logger usage is consistent throughout the codebase and properly implemented:

  • Defined in core/apibara.ts as part of the Apibara interface with consola integration
  • Used consistently for logging with standard methods (success, info, warn, error)
  • Follows unified logging pattern across all CLI operations and build processes
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the apibara logger interface and its usage across the codebase
# Expected: Find the logger interface definition and consistent usage pattern

# Search for logger interface definition
echo "Searching for logger interface definition..."
ast-grep --pattern 'interface $_ {
  $$$
  success($_): $_
  $$$
}'

# Search for logger usage patterns
echo "Searching for logger usage patterns..."
rg "logger\.(success|info|warn|error)"

Length of output: 1275


Script:

#!/bin/bash
# Let's verify the logger type definition and its usage pattern
# by checking the imports and type definitions

# Search for apibara type imports and logger type definitions
echo "Searching for apibara type imports..."
rg "from ['\"]@apibara/types['\"]" -A 3

# Search for logger type declarations
echo "Searching for logger type declarations..."
ast-grep --pattern 'type $_ = {
  $$$
  logger: $_
  $$$
}'

# Search for any potential logger interface declarations
echo "Searching for logger interfaces..."
ast-grep --pattern 'interface Logger {
  $$$
}'

Length of output: 414


Script:

#!/bin/bash
# Let's try a different approach to find logger-related types and interfaces
# by searching for more generic patterns and examining the apibara context

# Search for any interface or type with logger-related methods
echo "Searching for logger-related interfaces..."
ast-grep --pattern 'interface $_ {
  success($_): void;
}'

# Look for apibara context type definitions
echo "Searching for apibara context..."
rg "apibara" --type ts -B 2 -A 2

# Check the actual usage context
echo "Checking logger usage context..."
rg "import.*apibara" --type ts -A 3

Length of output: 69277

packages/cli/src/types/virtual/indexers.d.ts (2)

10-10: LGTM! Verify virtual module integration.

The empty array is correctly typed and will serve as a placeholder for Rollup's virtual plugin to populate at build time.

#!/bin/bash
# Description: Verify the virtual module integration with Rollup

# Look for Rollup configuration that handles this virtual module
echo "Checking Rollup configuration for virtual module handling:"
rg -l "indexers.*virtual" packages/cli

# Look for code that consumes this virtual module
echo -e "\nChecking usage of the virtual module:"
rg -l "from ['\"].*virtual/indexers['\"]" packages/cli/src

1-2: Verify import path resolution.

The import paths look correct, but let's verify that they resolve properly, especially the local import from "apibara/types".

✅ Verification successful

Import paths are correctly configured and used

The verification shows that:

  • @apibara/indexer is properly declared as a workspace dependency
  • ApibaraRuntimeConfig is defined in packages/cli/src/types/runtime.ts and is correctly imported by other files
  • Both types (IndexerWithStreamConfig and ApibaraRuntimeConfig) are actively used in the codebase
  • The import paths align with the project's structure and TypeScript module resolution
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the imported types exist in the specified locations

# Check if the @apibara/indexer package is properly declared in package.json
echo "Checking @apibara/indexer in package.json:"
jq '.dependencies["@apibara/indexer"] // .devDependencies["@apibara/indexer"]' packages/cli/package.json

# Look for the local types file
echo -e "\nLocating apibara/types definition:"
fd -e ts -e d.ts "apibara.ts|types.ts|types.d.ts" packages/cli/src/types

Length of output: 546


Script:

#!/bin/bash
# Let's verify the imports more thoroughly

# Check package.json for dependencies
echo "Checking package.json for @apibara/indexer:"
cat packages/cli/package.json | jq '.dependencies["@apibara/indexer"] // .devDependencies["@apibara/indexer"]'

# Search for apibara types definition
echo -e "\nSearching for apibara types definition:"
fd "types.ts" "types.d.ts" packages/cli/src

# Check if IndexerWithStreamConfig type is used elsewhere
echo -e "\nChecking usage of IndexerWithStreamConfig:"
rg "IndexerWithStreamConfig" packages/cli/src

# Check if ApibaraRuntimeConfig type is used elsewhere
echo -e "\nChecking usage of ApibaraRuntimeConfig:"
rg "ApibaraRuntimeConfig" packages/cli/src

# Look for any potential type definition files in the project
echo -e "\nLooking for type definitions:"
fd -e d.ts . packages/cli/src/types

Length of output: 1835

packages/cli/src/core/build/build.ts (2)

8-8: LGTM! Good code structure.

The added blank lines improve readability by clearly separating the configuration, hook execution, and build logic sections.

Also applies to: 10-10


9-9: LGTM! Verify hook implementation across consumers.

The hook implementation is well-structured and follows common patterns. The "rollup:before" hook provides a good extension point for pre-build customizations.

Let's verify the hook usage across the codebase:

✅ Verification successful

Let me gather more information about the hook implementation and its usage.


Let me check the hook system implementation in the Apibara class to understand how hooks are managed.


Based on the gathered information, I can now provide the final response:

Hook implementation is correctly integrated and safe to use

The "rollup:before" hook is:

  • Properly defined in the type system (ApibaraHooks interface)
  • Correctly initialized using the hookable library in the Apibara class
  • Used appropriately in the build process with proper typing
  • Designed to allow plugins to modify the Rollup configuration before build
  • Safely integrated with the existing plugin system

The hook system is initialized during Apibara instance creation and supports custom hooks through options.hooks, making it extensible for users while maintaining type safety.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for hook registrations and potential consumers
# Expected: Find files registering handlers for "rollup:before" hook

# Search for hook registrations
echo "Searching for rollup:before hook registrations..."
rg -l "rollup:before"

# Search for potential hook setup patterns
echo "Searching for hook setup patterns..."
ast-grep --pattern 'hooks.addHook($HOOK_NAME, $_)'

Length of output: 335


Script:

#!/bin/bash
# Check the hook definition and any existing consumers
echo "Checking hook definition in types/hooks.ts..."
cat packages/cli/src/types/hooks.ts

echo -e "\nSearching for any hook consumers or setup..."
rg -A 5 -B 5 "rollup:before"

# Look for any plugin or middleware registration patterns
echo -e "\nSearching for plugin registrations that might use hooks..."
rg -l "plugin|middleware|hooks?.register|hooks?.add"

Length of output: 3004


Script:

#!/bin/bash
# Check the Apibara class implementation for hook system
echo "Checking Apibara class implementation..."
cat packages/cli/src/core/apibara.ts

# Look for any plugin implementations that might use the rollup:before hook
echo -e "\nChecking rollup plugin implementations..."
cat packages/cli/src/rollup/plugins/indexers.ts
cat packages/cli/src/rollup/plugins/config.ts

Length of output: 2036

packages/cli/src/cli/index.ts (1)

12-12: LGTM! The start command integration follows the established pattern.

The implementation correctly lazy-loads the start command using dynamic import, consistent with other commands.

Let's verify the start command implementation exists:

✅ Verification successful

Start command implementation exists and follows the expected pattern

The verification confirms that the start command implementation exists at the expected location: packages/cli/src/cli/commands/start.ts, matching the import path in the CLI entry point.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the start command implementation exists
# Expect: The start command implementation file should exist

# Check if the start command implementation exists
fd --type f "start.ts$" "packages/cli/src/cli/commands"

Length of output: 94

packages/cli/src/rollup/plugins/indexers.ts (2)

1-2: LGTM: Imports are correctly typed and aligned with PR objectives.

The imports provide the necessary dependencies for creating a virtual Rollup plugin and ensuring proper TypeScript type checking.


7-15: ⚠️ Potential issue

Add validation for indexer names and paths.

The virtual module generation could be more robust:

  1. Indexer names should be validated as they're used as variable names
  2. Indexer paths should be validated to prevent injection
  3. Consider adding error handling for failed imports

Let's verify the current usage of indexer names and paths:

Suggested improvement:

 export function indexers(apibara: Apibara) {
   if (!Array.isArray(apibara.indexers)) {
     throw new Error('apibara.indexers must be an array');
   }
+  // Validate indexer names and paths
+  apibara.indexers.forEach(({ name, indexer }) => {
+    if (!/^[a-zA-Z_$][0-9a-zA-Z_$]*$/.test(name)) {
+      throw new Error(`Invalid indexer name: ${name}`);
+    }
+    if (typeof indexer !== 'string' || !indexer.trim()) {
+      throw new Error(`Invalid indexer path for ${name}`);
+    }
+  });
   const indexers = [...new Set(apibara.indexers)];

   return virtual({
     "#apibara-internal-virtual/indexers": `
+    // Handle potential import failures
+    const loadedIndexers = [];
     ${indexers.map((i) => `import ${i.name} from '${i.indexer}';`).join("\n")}

     export const indexers = [
       ${indexers.map((i) => `{ name: "${i.name}", indexer: ${i.name} }`).join(",\n")}
     ];
     `,
   });
 }
packages/cli/tsconfig.json (2)

Line range hint 1-24: Verify removal of old internal path mappings.

The removal of apibara/internal/consola and apibara/internal/citty path mappings looks good, but we should verify no references remain.

Let's check for any remaining references:

#!/bin/bash
# Description: Verify no references remain to removed internal modules

# Test: Check for any remaining references to old internal paths
echo "Checking for remaining references to removed internal modules..."
rg -l "apibara/internal/(consola|citty)"

# Test: Check if the old internal directories were properly removed
echo "Checking if old internal directories were removed..."
fd -t d "consola|citty" src/internal

16-17: LGTM! Path mappings align with the runtime refactoring.

The new path mappings are well-structured:

  • apibara/runtime/meta for runtime metadata
  • #apibara-internal-virtual/* for build-time generated indexer lists

Let's verify the usage of these new paths:

✅ Verification successful

Path mappings are correctly configured and actively used

The verification confirms:

  • apibara/runtime/meta is imported in build, dev, and start commands
  • #apibara-internal-virtual/* is used in runtime/internal/app.ts for config and indexers
  • No references to old internal modules (consola/citty) remain
  • Path mappings in tsconfig.json are consistent with the codebase structure
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of new path mappings and ensure they're properly referenced

# Test: Check if runtime-meta directory exists and is referenced
echo "Checking runtime-meta references..."
rg -l "apibara/runtime/meta"

# Test: Check for virtual type imports
echo "Checking virtual type imports..."
rg -l "#apibara-internal-virtual"

Length of output: 435


Script:

#!/bin/bash
# Let's verify the path mappings more thoroughly

# Check if runtime-meta directory exists
echo "Checking runtime-meta directory..."
fd -t d "runtime-meta"

# Check for any TypeScript/JavaScript files importing from runtime-meta
echo "Checking runtime-meta imports..."
rg -t ts -t js "from ['\"]apibara/runtime/meta['\"]"
rg -t ts -t js "require\(['\"]apibara/runtime/meta['\"]"

# Check for virtual type imports in TypeScript files
echo "Checking virtual type imports..."
rg -t ts "from ['\"]#apibara-internal-virtual/"
rg -t ts "require\(['\"]#apibara-internal-virtual/"

# Check for any remaining references to old internal modules
echo "Checking old internal module references..."
rg -t ts -t js "from ['\"]apibara/internal/(consola|citty)['\"]"
rg -t ts -t js "require\(['\"]apibara/internal/(consola|citty)['\"]"

# List all path mappings in tsconfig files to see the complete picture
echo "Checking all tsconfig path mappings..."
fd -t f "tsconfig.*json" --exec cat {} | jq -r '.compilerOptions.paths // empty'

Length of output: 1753

packages/cli/src/types/apibara.ts (1)

16-16: Verify indexers array initialization.

The addition of the indexers property aligns well with the PR objectives. However, we should verify how this array is initialized and handled in the implementation.

Let's check the initialization handling:

✅ Verification successful

Indexers array initialization is properly handled

The array is correctly initialized and managed throughout the codebase:

  • Default initialization with empty array in core/apibara.ts
  • Reset functionality in core/scan.ts
  • Proper type definitions and usage in rollup plugins and CLI commands
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check how the indexers array is initialized and used

# Look for Apibara class/object initialization
ast-grep --pattern 'new Apibara({ $$ })' || ast-grep --pattern 'createApibara({ $$ })'

# Look for indexers array usage
rg -l "indexers\:" --type ts

Length of output: 158


Script:

#!/bin/bash
# Search for indexers property usage with correct regex
rg "indexers:" --type ts

# Look for Apibara interface/type usage
ast-grep --pattern 'interface Apibara {
  $$$
}'

# Look for object creation or initialization with indexers
rg "indexers.*\[" --type ts -A 2

Length of output: 2525

packages/cli/src/cli/commands/build.ts (3)

2-2: LGTM: Clean import of runtime metadata.

The addition of runtimeDir import aligns with the PR's objective of managing indexers at build time.


20-20: LGTM: Standardized logging implementation.

The switch to apibara.logger aligns with the centralized logging approach being implemented across the codebase.


22-22: Verify the existence of start.mjs in runtime directory.

The entry point configuration looks correct, but let's verify the existence of the start.mjs file.

packages/cli/src/core/build/prod.ts (1)

8-8: LGTM! Verify logger initialization.

The logging message is clear and appropriate. The change aligns well with the centralized logging approach.

Let's verify the logger initialization:

✅ Verification successful

Logger is properly initialized and used consistently

The logger is correctly initialized in the createApibara function using consola.withTag("apibara") and is consistently used throughout the codebase. The usage in packages/cli/src/core/build/prod.ts follows the established pattern and is safe to use since the logger is guaranteed to be available as part of the Apibara instance.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the logger is properly initialized before use
# Expect: Logger initialization in main CLI setup

# Search for logger initialization
rg -l "logger.*=.*createLogger|new.*Logger" 

# Search for logger configuration
rg -l "logger.*config|configureLogger"

Length of output: 125


Script:

#!/bin/bash
# Let's check the actual logger initialization and usage patterns

# Check the content of the config update file first
cat packages/cli/src/core/config/update.ts

# Search for logger-related imports and usage
rg -A 3 "import.*logger|logger\." 

# Search for apibara logger specifically
rg -A 3 "apibara.*logger"

Length of output: 9248


Script:

#!/bin/bash
# Let's check where the Apibara type is defined and how the logger is initialized

# Check the Apibara type definition
cat packages/cli/src/types.ts

# Also check main CLI entry points for initialization
rg -l "new Apibara|createApibara"

Length of output: 345


Script:

#!/bin/bash
# Let's examine the Apibara class and its initialization

# Check the core Apibara implementation
cat packages/cli/src/core/apibara.ts

# Check how it's used in the core index
cat packages/cli/src/core/index.ts

Length of output: 1197

packages/cli/src/core/apibara.ts (2)

11-11: LGTM: Clean import statement

The import statement for scanIndexers is properly placed with other imports and follows the project's import style.


Line range hint 13-36: Verify initialization order

The current initialization sequence is:

  1. Load options
  2. Create context with hooks
  3. Add hooks
  4. Scan indexers

This seems logical, but we should verify that scanIndexers doesn't depend on any hooks that might be added after its execution.

#!/bin/bash
# Check if scanIndexers uses any hooks
rg -A 5 "hooks\." src/core/scan.ts

# Check for any hook registrations related to indexers
rg -A 5 "addHook.*index" 
packages/cli/playground/indexers/starknet.indexer.ts (1)

13-13: Document the rationale for the new starting block.

The orderKey has been increased by 10x from 80,000 to 800,000. This significant change in the starting point needs documentation to explain:

  • Why this specific block number was chosen
  • Whether any important historical data between these blocks can be skipped
  • Impact on existing data processing pipelines
packages/cli/build.config.ts (3)

5-13: LGTM: Runtime module addition

The addition of the "runtime" module to the modules array is clean and maintains alphabetical order.


40-43: LGTM: Externals configuration

The externals configuration correctly includes the new runtime meta module and maintains consistency with the alias configuration.


26-26: Verify the runtime module structure

The runtime module uses a directory-based input which suggests it may contain multiple files. Let's verify the structure and ensure all necessary files are included in the build.

✅ Verification successful

Runtime module structure is well-organized and complete

The runtime module structure is properly organized with:

  • Main entry point: src/runtime/index.ts
  • Core functionality files: dev.ts, start.ts
  • Internal components: internal/app.ts

The build configuration correctly includes the entire runtime directory for ESM format bundling, which will package all these files appropriately.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the runtime module structure and contents

# Check the runtime source directory structure
echo "Runtime source directory structure:"
fd . "src/runtime" -t f

# Check for any potential entry points or index files
echo -e "\nPotential entry points:"
rg -l "export" "src/runtime"

Length of output: 345


Script:

#!/bin/bash
# Let's first check if the runtime directory exists in the repository
echo "Searching for runtime directory:"
fd runtime

# Check for any files with 'runtime' in their path
echo -e "\nFiles with 'runtime' in path:"
fd . -t f | rg -i runtime

# Let's also check the build config file to understand the context better
echo -e "\nBuild config content:"
cat packages/cli/build.config.ts

Length of output: 1921

packages/cli/src/core/scan.ts (1)

1-40: Verify indexer file naming consistency across the codebase.

Let's ensure all indexer files follow the expected naming pattern.

✅ Verification successful

Let me try a different approach to verify the indexer files in the codebase.


Based on the results, I can now generate a final response.

The .indexer.ts naming convention is correctly enforced

Looking at the codebase, all actual indexer files follow the .indexer.ts naming convention as seen in the examples:

  • examples/cli/indexers/starknet.indexer.ts
  • packages/cli/playground/indexers/starknet.indexer.ts

Other files that import or use indexer-related code are utility files, tests, or implementation files that support the indexer functionality but are not indexers themselves. The scanIndexers function's naming convention check is appropriate and working as intended.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential indexer files that don't follow the naming convention

# Find all .ts and .js files that might be indexers but don't follow the convention
echo "Files that might be indexers but don't follow the naming convention:"
rg -g "*.{ts,js}" -l "export\s+class.*extends\s+Indexer" | grep -v "\.indexer\.(ts|js)$" || true

# List all properly named indexer files for reference
echo -e "\nProperly named indexer files:"
fd -e ts -e js . | grep "\.indexer\.(ts|js)$" || true

Length of output: 377


Script:

#!/bin/bash
# Let's check for any class that extends Indexer to find all indexer files
echo "All files containing Indexer classes:"
ast-grep --pattern 'class $_ extends Indexer { $$$ }'

# Also check for imports of Indexer to ensure we don't miss any
echo -e "\nFiles importing Indexer:"
rg "import.*Indexer" -A 2

Length of output: 6978

packages/cli/src/runtime/start.ts (2)

1-4: LGTM: Clean and well-organized imports.

The imports are appropriately scoped, with a clear separation between external dependencies and internal modules.


4-4: Verify integration with Rollup's virtual plugin.

The PR objectives mention using Rollup's virtual plugin to generate indexer lists at build time. Let's verify how createIndexer integrates with this system.

Also applies to: 25-25

✅ Verification successful

Let me gather more information about the virtual plugin implementation and its connection to the indexer.


Integration with Rollup's virtual plugin is properly implemented

The virtual plugin integration is correctly implemented:

  • The indexers.ts plugin generates a virtual module that imports and exports all registered indexers
  • The createIndexer function in app.ts works with the configuration provided by the virtual config plugin
  • Both plugins use @rollup/plugin-virtual to inject the required code at build time
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check how createIndexer is implemented and where the indexer list is generated
echo "Checking createIndexer implementation:"
ast-grep --pattern 'function createIndexer' -A 10

echo "\nChecking Rollup configuration for virtual plugin:"
rg -l "rollup.*virtual" --type ts

Length of output: 373


Script:

#!/bin/bash
# Check the virtual plugin implementation in indexers.ts
echo "Checking virtual plugin implementation:"
cat packages/cli/src/rollup/plugins/indexers.ts

echo "\nChecking createIndexer implementation in app.ts:"
rg -A 10 "export function createIndexer" packages/cli/src/runtime/internal/app.ts

echo "\nChecking config plugin usage:"
cat packages/cli/src/rollup/plugins/config.ts

Length of output: 1569

packages/cli/src/runtime/internal/app.ts (2)

1-6: LGTM! Clean imports and useful constant export.

The imports are well-organized, and the availableIndexers constant provides a convenient way to access the list of available indexers.


3-4: Verify virtual module setup.

The code relies on virtual modules generated at build time. Let's verify their setup.

✅ Verification successful

Virtual module setup is correctly implemented

The virtual modules are properly configured:

  • Virtual module plugins are correctly implemented in packages/cli/src/rollup/plugins/ for both config and indexers
  • Type definitions are present in packages/cli/src/types/virtual/
  • The virtual imports are properly aliased in the TypeScript configuration
  • Both virtual modules export the expected constants with correct types
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the virtual modules are properly configured in the build setup

# Check for virtual module configuration in rollup config
rg -l "apibara-internal-virtual" -g "rollup.config.*"

# Check for the indexers virtual module implementation
rg "export const indexers" -A 5

Length of output: 763


Script:

#!/bin/bash
# Let's check for the virtual module configuration in the build setup more thoroughly

# Check for virtual module aliases or configuration in package.json
rg "apibara-internal-virtual" -g "package.json"

# Check for virtual module setup in build configuration files
fd -e js -e ts -e json "rollup|vite|webpack|tsconfig" -x rg "apibara-internal-virtual" {}

# Check the config virtual module implementation
rg "export const config" -A 5

# Look for virtual module plugin setup
ast-grep --pattern 'virtual($$$)'

Length of output: 1673

packages/cli/src/types/config.ts (4)

18-22: LGTM! Improved type safety with Record<string, never>

The change from empty object type to Record<string, never> is a good improvement. This makes the type more explicit and prevents accidental property access, which was possible with the empty object type.


41-45: LGTM! Consistent type parameter changes

The type parameter changes mirror those in ApibaraConfig, maintaining consistency throughout the type system.


Line range hint 18-74: Document breaking changes in CHANGELOG

This update introduces breaking changes:

  1. Type parameter defaults changed from empty object type to Record<string, never>
  2. New required indexersDir property in ApibaraOptions

Please ensure these changes are documented in the CHANGELOG.

#!/bin/bash
# Description: Check if CHANGELOG exists and contains relevant entries

# Test: Look for CHANGELOG files
fd -g 'CHANGELOG*' -t f

74-74: Document sourceMap property and verify build configuration

Please add documentation for the sourceMap property. Also, ensure that the Rollup configuration correctly handles this option.

packages/cli/src/core/build/dev.ts (1)

56-56: LGTM! Verify hook implementation.

The addition of the dev:restart hook is well-placed, being called at the start of the Rollup watcher lifecycle. This aligns with the PR's objective of refactoring the build commands.

Let's verify the hook implementation and its consumers:

✅ Verification successful

✓ Hook implementation verified and properly used

The dev:restart hook is correctly implemented:

  • Defined in types: packages/cli/src/types/hooks.ts
  • Called in build process: packages/cli/src/core/build/dev.ts
  • Consumed in dev command: packages/cli/src/cli/commands/dev.ts
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the dev:restart hook implementation and usage
# Expected: Find the hook definition and any consumers

# Test 1: Find the hook definition in types
echo "Searching for hook definition..."
rg -t typescript "dev:restart" --glob "**/types/**"

# Test 2: Find hook consumers
echo "Searching for hook consumers..."
rg -t typescript "dev:restart" --glob "!**/build/dev.ts"

Length of output: 326


Script:

#!/bin/bash
# Let's try with ripgrep without type filtering since typescript type is not recognized
echo "Searching for hook definition..."
rg "dev:restart" --glob "**/*.{ts,tsx,d.ts}"

# Let's also check for any hook registration patterns
echo "Searching for hook registration patterns..."
ast-grep --pattern 'hooks.addHook("dev:restart"'

Length of output: 495

packages/cli/package.json (4)

66-66: LGTM: Enhanced debugging capability.

The addition of CONSOLA_LEVEL=debug improves the development experience by providing more detailed logging information.


Line range hint 2-2: Verify breaking changes documentation for v2 release.

The version bump to 2.0.0-beta.11 indicates breaking changes. Please ensure these changes are properly documented.

#!/bin/bash
# Description: Check for breaking changes documentation

# Look for changelog or migration guide
echo "Checking for changelog or migration guide..."
fd -t f "CHANGELOG|MIGRATION|BREAKING" --max-depth 2

# Check for breaking change documentation in README
echo "Checking README for breaking changes..."
rg -i "breaking.?changes?|migration|upgrade" "README.md"

35-49: Verify runtime exports structure and patterns.

The new runtime exports follow good practices for dual package hazard prevention by explicitly declaring types. However, let's verify that all runtime modules are properly structured.

✅ Verification successful

Runtime exports are properly structured and used consistently

The runtime exports in package.json are correctly configured and align with the actual codebase structure:

  • Runtime meta files exist at the package root (runtime-meta.d.ts, runtime-meta.mjs)
  • Runtime-related source files are properly organized under src/
  • Runtime imports are consistently used across build, dev, and start commands
  • The exports follow the dual package hazard prevention pattern with proper type declarations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify runtime directory structure and exports

# Check if runtime directory exists and contains expected files
echo "Checking runtime directory structure..."
fd -t f -e mjs -e d.ts . "packages/cli/dist/runtime"

# Verify no unexpected runtime exports
echo "Checking for unexpected runtime exports..."
rg -g "!package.json" "from ['\"]\\.\\./runtime" "packages/cli"

Length of output: 413


Script:

#!/bin/bash
# Let's verify the runtime-related files and their structure differently

# Check for runtime-related files in the CLI package
echo "Checking runtime-related files in CLI package..."
fd -t f "runtime" "packages/cli"

# Look for runtime imports/exports patterns
echo "Checking runtime import/export patterns..."
rg "runtime" "packages/cli/package.json" -A 2 -B 2

# Check source files that might use runtime
echo "Checking runtime usage in source files..."
rg "from ['\"].*runtime" "packages/cli/src"

Length of output: 1563


73-73: Verify dependency changes and usage.

The dependency changes align with the PR objectives, particularly the addition of Rollup plugins. However, let's verify their usage:

Also applies to: 89-89, 103-103

✅ Verification successful

Dependencies are correctly placed and actively used

The verification shows that:

  • @rollup/plugin-virtual is actively used in plugins/indexers.ts and plugins/config.ts
  • rollup-plugin-esbuild is used in rollup/config.ts
  • @apibara/starknet is used in playground examples and makes sense as a dev dependency since it's used for testing/development purposes
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify new dependencies are being used

echo "Checking @rollup/plugin-virtual usage..."
rg "from ['\"]\@rollup/plugin-virtual" 

echo "Checking rollup-plugin-esbuild usage..."
rg "from ['\"](rollup-plugin-esbuild|esbuild)"

echo "Checking @apibara/starknet usage in tests..."
rg "from ['\"]\@apibara/starknet" 

Length of output: 299


Script:

#!/bin/bash
# Let's try a more thorough search for these dependencies

echo "Checking @rollup/plugin-virtual imports..."
rg -l "[@]rollup/plugin-virtual"

echo "Checking rollup-plugin-esbuild imports..."
rg -l "rollup-plugin-esbuild"

echo "Checking direct esbuild imports..."
rg -l "esbuild['\"]"

echo "Checking @apibara/starknet imports..."
rg -l "[@]apibara/starknet"

# Let's also check package.json to see where these are listed
echo "Checking package.json entries..."
fd "package.json" --exec grep -l "rollup\|esbuild\|apibara"

Length of output: 1810


Script:

#!/bin/bash
# Let's check the actual usage context of these dependencies

echo "Checking @rollup/plugin-virtual usage context..."
rg -A 5 "[@]rollup/plugin-virtual" packages/cli/src/rollup/plugins/

echo "Checking rollup-plugin-esbuild usage context..."
rg -A 5 "rollup-plugin-esbuild" packages/cli/src/rollup/config.ts

echo "Checking @apibara/starknet usage in CLI package..."
rg -A 5 "[@]apibara/starknet" packages/cli/

Length of output: 2523

packages/cli/src/cli/commands/dev.ts (4)

3-3: LGTM! Import changes enhance cross-platform compatibility.

The addition of runtimeDir from runtime metadata and using pathe for path operations improves the code's portability.

Also applies to: 6-6


35-38: LGTM! Improved variable scoping.

Moving apibara and childProcess declarations into the function scope enhances encapsulation and prevents potential issues with shared state.


41-44: LGTM! Enhanced logging and proper resource cleanup.

The implementation properly handles:

  • Centralized logging through apibara.logger
  • Cleanup of watchers before reloading
  • Configuration of the entry point to use build-time generated files

Also applies to: 79-79


85-91: LGTM! Well-structured hook for indexer lifecycle management.

The new "dev:restart" hook provides clean shutdown of indexers before restart, preventing orphaned processes.

packages/cli/src/core/build/types.ts (1)

9-9: LGTM: Logging changes align with centralization effort.

The replacement of consola with apibara.logger and the addition of a start message improve the logging consistency and provide better visibility into the type generation process.

Also applies to: 134-134

packages/cli/src/rollup/config.ts (3)

75-76: LGTM on adding indexers and appConfig plugins

The addition of the indexers and appConfig plugins to the Rollup configuration enhances the build process by incorporating dynamic indexer imports and application configuration. The plugins are correctly implemented and integrated.


44-46: ⚠️ Potential issue

Reconsider ignoring the THIS_IS_UNDEFINED warning

The onwarn function now ignores the THIS_IS_UNDEFINED warning. Suppressing this warning might hide potential issues where this is undefined in ES module contexts. Please ensure that ignoring this warning does not mask unintended behavior, especially in strict mode or when targeting newer JavaScript versions.

Run the following script to identify occurrences where this might be used in a way that could lead to undefined values:

#!/bin/bash
# Description: Find top-level usages of `this` which may cause `THIS_IS_UNDEFINED` warnings.

# Test: Search for top-level `this` usage. Expectation: No top-level `this` references.
rg --type js --type ts --glob '!node_modules/*' -U -w '\bthis\b' .

13-13: Update function signature and ensure dependent code is updated

The getRollupConfig function signature has changed with the removal of the dev parameter. Please ensure that all calls to this function are updated to match the new signature to prevent any runtime errors.

Run the following script to identify any function calls that still use the old signature:

✅ Verification successful

Let me try a different search pattern to find calls to getRollupConfig:


No updates needed for function calls

The search results show that getRollupConfig is only called once in packages/cli/src/core/build/build.ts and it's already using the new signature with a single apibara parameter. No other calls to this function exist in the codebase, so no updates are required.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find all calls to getRollupConfig with more than one argument.

# Test: Search for function calls to getRollupConfig with at least two arguments.
rg 'getRollupConfig\(\s*[^,\s]+,\s*[^,\s]+\s*\)'

Length of output: 12495


Script:

#!/bin/bash
# Search for any calls to getRollupConfig function
rg "getRollupConfig\(" --type ts --type js -A 2

Length of output: 497

Comment on lines 3 to 6
export async function resolveRuntimeConfigOptions(options: ApibaraOptions) {
options.runtimeConfig = { ...options.runtimeConfig, default: "value" };
options.runtimeConfig = { ...options.runtimeConfig };
process.env.APIBARA_RUNTIME_CONFIG = JSON.stringify(options.runtimeConfig);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider adding runtime type validation.

Since this function handles configuration that affects runtime behavior, it would be beneficial to add runtime type validation to ensure the configuration object meets expected requirements.

Consider using a validation library like zod or implementing a type guard:

interface RuntimeConfig {
  // define expected runtime config properties
}

function isValidRuntimeConfig(config: unknown): config is RuntimeConfig {
  // implement validation logic
  return typeof config === 'object' && config !== null;
}

export async function resolveRuntimeConfigOptions(options: ApibaraOptions) {
  const runtimeConfig = options.runtimeConfig ?? {};
  if (!isValidRuntimeConfig(runtimeConfig)) {
    throw new Error('Invalid runtime configuration provided');
  }
  options.runtimeConfig = { ...runtimeConfig };
  process.env.APIBARA_RUNTIME_CONFIG = JSON.stringify(options.runtimeConfig);
}

Comment on lines +4 to 5
options.runtimeConfig = { ...options.runtimeConfig };
process.env.APIBARA_RUNTIME_CONFIG = JSON.stringify(options.runtimeConfig);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add null check for runtimeConfig property.

The current implementation might throw an error if options.runtimeConfig is undefined. Consider adding a default empty object to ensure safe property spreading.

Apply this diff to add null safety:

- options.runtimeConfig = { ...options.runtimeConfig };
+ options.runtimeConfig = { ...(options.runtimeConfig ?? {}) };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
options.runtimeConfig = { ...options.runtimeConfig };
process.env.APIBARA_RUNTIME_CONFIG = JSON.stringify(options.runtimeConfig);
options.runtimeConfig = { ...(options.runtimeConfig ?? {}) };
process.env.APIBARA_RUNTIME_CONFIG = JSON.stringify(options.runtimeConfig);

export async function updateApibaraConfig(
apibara: Apibara,
config: ApibaraDynamicConfig,
_config: ApibaraDynamicConfig,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Consider removing the unused parameter.

The _config parameter is marked as unused with an underscore prefix. If this parameter isn't needed for the function's operation, consider removing it to improve code clarity.

export async function updateApibaraConfig(
-  apibara: Apibara,
-  _config: ApibaraDynamicConfig,
+  apibara: Apibara,
) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
_config: ApibaraDynamicConfig,
apibara: Apibara,

Comment on lines 3 to 9
export async function updateApibaraConfig(
apibara: Apibara,
config: ApibaraDynamicConfig,
_config: ApibaraDynamicConfig,
) {
await apibara.hooks.callHook("rollup:reload");
consola.success("Apibara config hot reloaded!");
apibara.logger.success("Apibara config hot reloaded!");
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Function name could be more descriptive.

The function name updateApibaraConfig suggests it updates configuration, but it actually triggers a Rollup reload and doesn't use the config parameter. Consider renaming to better reflect its purpose, such as reloadRollupConfig or triggerConfigReload.

-export async function updateApibaraConfig(
+export async function reloadRollupConfig(
   apibara: Apibara,
-  _config: ApibaraDynamicConfig,
) {
   await apibara.hooks.callHook("rollup:reload");
   apibara.logger.success("Apibara config hot reloaded!");
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function updateApibaraConfig(
apibara: Apibara,
config: ApibaraDynamicConfig,
_config: ApibaraDynamicConfig,
) {
await apibara.hooks.callHook("rollup:reload");
consola.success("Apibara config hot reloaded!");
apibara.logger.success("Apibara config hot reloaded!");
}
export async function reloadRollupConfig(
apibara: Apibara,
) {
await apibara.hooks.callHook("rollup:reload");
apibara.logger.success("Apibara config hot reloaded!");
}

Comment on lines +10 to +12
fromEnv: {
nodeEnv: process.env.NODE_ENV,
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider adding type safety and validation for environment variables.

The direct use of process.env.NODE_ENV could lead to runtime issues if the environment variable is undefined. Consider:

  1. Adding type safety
  2. Providing a default value
  3. Validating allowed values
    fromEnv: {
-      nodeEnv: process.env.NODE_ENV,
+      nodeEnv: process.env.NODE_ENV ?? 'development',
    },

You might also want to add a type guard:

const validateNodeEnv = (env: string | undefined): env is 'development' | 'production' | 'test' => {
  return env === 'development' || env === 'production' || env === 'test';
};

// Usage
nodeEnv: validateNodeEnv(process.env.NODE_ENV) 
  ? process.env.NODE_ENV 
  : 'development',

Comment on lines 31 to 38
apibara.logger.start("Building");

apibara.options.entry = join(runtimeDir, "start.mjs");

await prepare(apibara);
await writeTypes(apibara);
await build(apibara);
await apibara.close();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add error handling and improve logging.

The build process lacks error handling and could benefit from more detailed logging to help diagnose build failures.

-apibara.logger.start("Building");
+apibara.logger.start("Starting build process");
 
 apibara.options.entry = join(runtimeDir, "start.mjs");
 
+try {
+  apibara.logger.info("Preparing build environment");
   await prepare(apibara);
+  apibara.logger.info("Generating TypeScript types");
   await writeTypes(apibara);
+  apibara.logger.info("Building indexer");
   await build(apibara);
+  apibara.logger.success("Build completed successfully");
+} catch (error) {
+  apibara.logger.error("Build failed", error);
+  process.exit(1);
+}
 await apibara.close();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
apibara.logger.start("Building");
apibara.options.entry = join(runtimeDir, "start.mjs");
await prepare(apibara);
await writeTypes(apibara);
await build(apibara);
await apibara.close();
apibara.logger.start("Starting build process");
apibara.options.entry = join(runtimeDir, "start.mjs");
try {
apibara.logger.info("Preparing build environment");
await prepare(apibara);
apibara.logger.info("Generating TypeScript types");
await writeTypes(apibara);
apibara.logger.info("Building indexer");
await build(apibara);
apibara.logger.success("Build completed successfully");
} catch (error) {
apibara.logger.error("Build failed", error);
process.exit(1);
}
await apibara.close();

Comment on lines +50 to +59
spawn("node", childArgs, {
stdio: "inherit",
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Implement proper process management.

The child process spawning lacks error handling and proper cleanup mechanisms. This could lead to orphaned processes or unhandled errors.

-spawn("node", childArgs, {
-  stdio: "inherit",
-});
+const child = spawn("node", childArgs, {
+  stdio: "inherit",
+});
+
+child.on("error", (error) => {
+  apibara.logger.error("Failed to start indexer", error);
+  process.exit(1);
+});
+
+// Handle parent process exit
+process.on("SIGTERM", () => {
+  child.kill("SIGTERM");
+});
+
+process.on("SIGINT", () => {
+  child.kill("SIGINT");
+});
+
+child.on("exit", (code) => {
+  process.exit(code ?? 0);
+});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
spawn("node", childArgs, {
stdio: "inherit",
});
const child = spawn("node", childArgs, {
stdio: "inherit",
});
child.on("error", (error) => {
apibara.logger.error("Failed to start indexer", error);
process.exit(1);
});
// Handle parent process exit
process.on("SIGTERM", () => {
child.kill("SIGTERM");
});
process.on("SIGINT", () => {
child.kill("SIGINT");
});
child.on("exit", (code) => {
process.exit(code ?? 0);
});

Comment on lines +56 to 59

if (dev) {
options.dev = dev;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Ensure consistent object shape by always setting the dev flag.

Currently, options.dev is only set when dev is true. This can lead to inconsistent object shapes which might cause issues with type checking or downstream code that expects the property to exist.

Consider always setting the flag:

-  if (dev) {
-    options.dev = dev;
-  }
+  options.dev = dev;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (dev) {
options.dev = dev;
}
options.dev = dev;

Comment on lines +38 to +47
selectedIndexers.map(async (indexer) => {
const indexerInstance = createIndexer(indexer, preset);

const client = createClient(
indexerInstance.streamConfig,
indexerInstance.options.streamUrl,
);

await run(client, indexerInstance);
}),
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance user feedback by adding logging when indexers start and finish

Adding logging statements will help users track which indexers are running and when they complete.

Apply this diff to add logging:

  selectedIndexers.map(async (indexer) => {
+     console.log(`Starting indexer: ${indexer}`);
      const indexerInstance = createIndexer(indexer, preset);

      const client = createClient(
        indexerInstance.streamConfig,
        indexerInstance.options.streamUrl,
      );

      await run(client, indexerInstance);
+     console.log(`Indexer ${indexer} has completed.`);
    }),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
selectedIndexers.map(async (indexer) => {
const indexerInstance = createIndexer(indexer, preset);
const client = createClient(
indexerInstance.streamConfig,
indexerInstance.options.streamUrl,
);
await run(client, indexerInstance);
}),
selectedIndexers.map(async (indexer) => {
console.log(`Starting indexer: ${indexer}`);
const indexerInstance = createIndexer(indexer, preset);
const client = createClient(
indexerInstance.streamConfig,
indexerInstance.options.streamUrl,
);
await run(client, indexerInstance);
console.log(`Indexer ${indexer} has completed.`);
}),

Comment on lines +37 to +49
await Promise.all(
selectedIndexers.map(async (indexer) => {
const indexerInstance = createIndexer(indexer, preset);

const client = createClient(
indexerInstance.streamConfig,
indexerInstance.options.streamUrl,
);

await run(client, indexerInstance);
}),
);
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle errors when running indexers in parallel

Currently, if one indexer fails, the Promise.all will reject, causing all indexers to stop. Consider handling errors for individual indexers to ensure that one failure doesn't interrupt the execution of other indexers.

Apply this diff to handle errors gracefully:

-     await Promise.all(
+     await Promise.allSettled(
        selectedIndexers.map(async (indexer) => {
          const indexerInstance = createIndexer(indexer, preset);

          const client = createClient(
            indexerInstance.streamConfig,
            indexerInstance.options.streamUrl,
          );

-         await run(client, indexerInstance);
+         try {
+           await run(client, indexerInstance);
+         } catch (error) {
+           console.error(`Indexer ${indexer} failed with error:`, error);
+         }
        }),
      );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await Promise.all(
selectedIndexers.map(async (indexer) => {
const indexerInstance = createIndexer(indexer, preset);
const client = createClient(
indexerInstance.streamConfig,
indexerInstance.options.streamUrl,
);
await run(client, indexerInstance);
}),
);
},
await Promise.allSettled(
selectedIndexers.map(async (indexer) => {
const indexerInstance = createIndexer(indexer, preset);
const client = createClient(
indexerInstance.streamConfig,
indexerInstance.options.streamUrl,
);
try {
await run(client, indexerInstance);
} catch (error) {
console.error(`Indexer ${indexer} failed with error:`, error);
}
}),
);
},

Comment on lines 35 to 37
await prepare(apibara);
await writeTypes(apibara);
await build(apibara);
Copy link
Member

@jaipaljadeja jaipaljadeja Nov 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO when user runs apibara start command, it should just run the build files generated from apibara build and not build it again and run it. What you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I was unsure about this too. I think you're right and we should print an error message if the user hasn't built the app first (like Next.js does, message included for reference).

   ▲ Next.js 15.0.2
   - Local:        http://localhost:3000

 ✓ Starting...
Error: Could not find a production build in the '.next' directory. Try building your app with 'next build' before starting the production server. https://nextjs.org/docs/messages/production-start-no-build-id
    at setupFsCheck (/home/fra/.local/share/pnpm/store/v3/tmp/dlx-122690/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/next/dist/server/lib/router-utils/filesystem.js:149:19)
    at async initialize (/home/fra/.local/share/pnpm/store/v3/tmp/dlx-122690/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/next/dist/server/lib/router-server.js:65:23)
    at async Server.<anonymous> (/home/fra/.local/share/pnpm/store/v3/tmp/dlx-122690/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/next/dist/server/lib/start-server.js:266:36)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW love that Next.js has an "errors" section in their docs. We should do that too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should improve the output of the build command to match nitro.


ℹ Using 2024-04-03 as fallback.                                                                                                                                                                 nitro 19:39:25
  Please specify compatibility date to avoid unwanted behavior changes:
     - Add compatibilityDate: '2024-11-02' to the config file.
     - Or set COMPATIBILITY_DATE=2024-11-02 environment variable.

✔ Generated public .output/public                                                                                                                                                               nitro 19:39:25
ℹ Building Nitro Server (preset: node-server, compatibility date: 2024-04-03)                                                                                                                   nitro 19:39:25
✔ Nitro Server built                                                                                                                                                                            nitro 19:39:26
  ├─ .output/server/chunks/nitro/nitro.mjs (163 kB) (39 kB gzip)
  ├─ .output/server/chunks/nitro/nitro.mjs.map (4.61 kB) (875 B gzip)
  ├─ .output/server/chunks/routes/index.mjs (310 B) (212 B gzip)
  ├─ .output/server/chunks/routes/index.mjs.map (208 B) (150 B gzip)
  ├─ .output/server/index.mjs (267 B) (183 B gzip)
  └─ .output/server/package.json (89 B) (95 B gzip)
Σ Total size: 168 kB (40.5 kB gzip)
✔ You can preview this build using node .output/server/index.mjs   

@fracek
Copy link
Contributor Author

fracek commented Nov 2, 2024

I updated the PR to fix that issue and improve the output.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (7)
packages/cli/src/core/path.ts (2)

4-11: LGTM! Consider enhancing the documentation.

The implementation is clean and focused. However, the documentation could be more comprehensive.

Consider expanding the JSDoc comment like this:

 /** Return a (possibly highlighted) path relative to the current working directory.
  *
+ * @param path - The absolute or relative path to process
+ * @param highlight - Whether to apply cyan color highlighting to the path
+ * @returns The path relative to CWD, optionally highlighted in cyan
  *
  * From nitrojs/nitro.
  */

8-11: Consider adding input validation.

The function could benefit from basic input validation to handle edge cases gracefully.

Consider adding validation:

 export function prettyPath(path: string, highlight = true) {
+  if (typeof path !== 'string' || path.trim().length === 0) {
+    throw new Error('Path must be a non-empty string');
+  }
   const rel = relative(process.cwd(), path);
   return highlight ? colors.cyan(rel) : rel;
 }
examples/cli/package.json (1)

10-11: Consider adding format command for consistency.

While the lint and lint:fix commands are correctly configured, consider adding a separate format command for better separation of concerns. Biome supports both linting and formatting, and it's a common practice to separate these operations.

Add these commands:

   "scripts": {
     "build": "apibara build",
     "dev": "apibara dev",
     "start": "apibara start",
     "lint": "biome check .",
-    "lint:fix": "pnpm lint --write"
+    "lint:fix": "pnpm lint --apply",
+    "format": "biome format .",
+    "format:fix": "pnpm format --write"
   },
examples/cli/indexers/starknet.indexer.ts (2)

Line range hint 27-29: Align logging with new apibara logger framework

The transform function is using console.log while the codebase is moving towards using the apibara logging framework. Consider updating this to maintain consistency with the new logging standards.

-    async transform({ block: { header } }) {
-      console.log("Transforming block ", header?.blockNumber);
+    async transform({ block: { header } }, { logger }) {
+      logger.info("transforming block", { blockNumber: header?.blockNumber });
     },

Line range hint 6-6: Update runtime config logging to use apibara logger

The runtime config logging should also use the new apibara logging framework instead of console.log.

-  console.log("--> Starknet Indexer Runtime Config: ", runtimeConfig);
+  runtimeConfig.logger.debug("starknet indexer runtime config", { config: runtimeConfig });
package.json (1)

Line range hint 1-47: Consider addressing the removed format script.

The format script has been removed, but code formatting is still important. Consider either:

  1. Adding format functionality to the lint:fix script
  2. Documenting how formatting should be handled
  3. Re-implementing the format script using pnpm

Would you like me to propose an implementation for a new format script using pnpm?

packages/cli/src/cli/commands/start.ts (1)

25-38: Consider adding root directory validation and centralizing path configuration.

While the setup works, consider these improvements:

  1. Validate that the root directory exists and is accessible
  2. Move the .apibara/build path to a centralized configuration
 const rootDir = resolve((args.dir || args._dir || ".") as string);
+if (!fse.existsSync(rootDir)) {
+  apibara.logger.error(`Directory ${rootDir} does not exist`);
+  process.exit(1);
+}

 const apibara = await createApibara({
   rootDir,
 });
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between e021f45 and fe62c6c.

📒 Files selected for processing (14)
  • examples/cli/indexers/starknet.indexer.ts (1 hunks)
  • examples/cli/package.json (1 hunks)
  • flake.nix (1 hunks)
  • package.json (1 hunks)
  • packages/cli/package.json (4 hunks)
  • packages/cli/src/cli/commands/build.ts (2 hunks)
  • packages/cli/src/cli/commands/dev.ts (5 hunks)
  • packages/cli/src/cli/commands/start.ts (1 hunks)
  • packages/cli/src/core/build/prepare.ts (1 hunks)
  • packages/cli/src/core/build/prod.ts (2 hunks)
  • packages/cli/src/core/build/types.ts (2 hunks)
  • packages/cli/src/core/path.ts (1 hunks)
  • packages/cli/src/core/scan.ts (1 hunks)
  • packages/indexer/package.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • packages/cli/src/cli/commands/build.ts
  • packages/cli/src/cli/commands/dev.ts
  • packages/cli/src/core/build/prepare.ts
  • packages/cli/src/core/build/prod.ts
  • packages/cli/src/core/build/types.ts
  • packages/cli/src/core/scan.ts
🔇 Additional comments (12)
examples/cli/package.json (1)

7-9: Verify the apibara CLI commands exist.

The new build, dev, and start commands align with the PR objectives of refactoring these commands.

Let's verify these commands are properly exported:

✅ Verification successful

The apibara CLI commands are properly implemented

The verification confirms that the build, dev, and start commands are properly implemented in the CLI:

  • Commands are defined in packages/cli/src/cli/commands/:
    • build.ts - implements the build command
    • dev.ts - implements the dev command
    • start.ts - implements the start command
  • All commands are properly registered in packages/cli/src/cli/index.ts using the citty framework
  • The CLI is exposed through the bin entry in packages/cli/package.json as apibara
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the apibara CLI commands exist in the codebase

# Test: Search for command definitions
rg -A 5 'new Command\(' 'packages/cli/src'

Length of output: 42


Script:

#!/bin/bash
# Let's try different approaches to find CLI command definitions

# Search for command-related files and patterns
echo "=== Searching for command files ==="
fd -t f . packages/cli/src

echo -e "\n=== Searching for command patterns ==="
rg -i "command|program" packages/cli/src

echo -e "\n=== Checking package.json for bin entries ==="
cat packages/cli/package.json

echo -e "\n=== Looking for CLI entry points ==="
rg -l "#!/usr/bin/env node" .

Length of output: 6924

flake.nix (1)

16-16: Please clarify the security implications of enabling MADNESS_ALLOW_LDD.

The addition of this environment variable raises several concerns:

  1. The variable name suggests it enables ldd functionality, which could have security implications if misused.
  2. The "MADNESS" prefix suggests this might be a temporary workaround.

Could you please:

  1. Document the purpose of this variable
  2. Confirm if this is a temporary solution
  3. Explain any security considerations

Let's check if this variable is documented or used elsewhere:

examples/cli/indexers/starknet.indexer.ts (2)

Line range hint 7-26: Core indexer configuration looks good

The indexer configuration is well-structured with proper filter setup for Transfer events. The use of type-safe contract address and event selector calculation is a good practice.


12-12: Verify the significant increase in orderKey

The orderKey has been increased by 10x (from 80,000n to 800,000n). This significant jump in the starting point could potentially skip important historical data. Please confirm if this increase is intentional and won't impact data consistency or dependent systems.

✅ Verification successful

The orderKey change is part of a coordinated update

Based on the git history, the change from 80,000n to 800,000n is part of a coordinated update across multiple Starknet indexer configurations. The change appears in multiple files and was implemented consistently:

  • examples/cli/indexers/starknet.indexer.ts
  • examples/starknet-client/src/main.ts
  • packages/cli/playground/indexers/starknet.indexer.ts

The change also coincides with updates to the streamUrl from a local endpoint to the official preview endpoint (https://starknet.preview.apibara.org), suggesting this was part of a planned infrastructure upgrade.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other orderKey configurations to ensure consistency
rg -g '*.ts' -g '*.js' --no-heading "orderKey.*800_000n" 

Length of output: 270


Script:

#!/bin/bash
# Let's check the git history to understand if this change was coordinated across files
git log -p --all | rg -A 5 -B 5 "orderKey.*[0-9]+_000n"

Length of output: 15829

package.json (1)

12-13: Verify CI/CD pipeline compatibility with pnpm lint commands.

While switching from turbo to pnpm for lint commands is valid, ensure that CI/CD pipelines and documentation are updated accordingly.

✅ Verification successful

CI/CD pipeline is already compatible with pnpm lint commands

The CI/CD pipeline in .github/workflows/build.yml is already using pnpm lint command, and all other workflow files are consistently using pnpm. The change from turbo to pnpm for lint commands is properly aligned with the existing CI/CD configuration.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any CI/CD configurations that might reference the old turbo lint commands

# Test: Search for turbo lint references in CI configs
rg -g '*.{yml,yaml}' 'turbo.*lint' .github/

Length of output: 45


Script:

#!/bin/bash
# Let's broaden our search to find any CI/CD configurations and workflow files
# that might reference linting commands

# Check for any lint-related commands in CI configs
rg -g '*.{yml,yaml}' -i 'lint|eslint' .github/

# Also check for any pnpm commands in CI configs
rg -g '*.{yml,yaml}' 'pnpm' .github/

# Let's also check the root package.json to see the full scripts configuration
cat package.json

Length of output: 2194

packages/cli/src/cli/commands/start.ts (2)

1-24: LGTM: Well-structured command definition.

The command structure is clean with appropriate imports and well-defined arguments.


57-59: Process management improvements needed.

The current implementation lacks proper error handling and cleanup for the child process.

packages/indexer/package.json (3)

74-74: LGTM: test:ci command retained.

The test:ci command is appropriately configured to run tests in CI environment.


Line range hint 13-66: Verify runtime module accessibility.

The exports configuration properly isolates different modules, but given that the PR objectives mention utilizing Rollup's virtual plugin for indexers at build time, we should verify that the necessary runtime modules are properly exposed.

Let's check the runtime module configuration:

#!/bin/bash
# Description: Verify runtime module configuration

# Test 1: Look for runtime-related imports in the codebase
echo "Checking runtime module usage..."
rg -g '!package*.json' "from.*@apibara/indexer/.*runtime"

# Test 2: Check for Rollup configuration files that might need updating
echo "Checking Rollup configuration..."
fd "rollup.config|vite.config"

71-71: Verify Biome linter configuration and migration.

The linting tool has been changed to Biome. While this is a good choice for its speed and features, we should ensure proper migration.

Let's verify the Biome setup:

✅ Verification successful

Let me gather more information to verify the Biome setup properly.


Let me check the content of the Biome configuration to ensure it's properly set up.


Biome linter setup is properly configured

The migration to Biome appears to be complete and well-configured:

  • A root-level biome.json exists with comprehensive configuration
  • No conflicting ESLint/Prettier configs found in the repository
  • The configuration includes proper rules, formatting options, and ignore patterns
  • The lint script in packages/indexer/package.json correctly uses the Biome CLI
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check Biome configuration and rules

# Test 1: Check if Biome config exists
echo "Checking for Biome configuration..."
fd "biome.json|.biome.json"

# Test 2: Check for any remaining old linter configs that should be removed
echo "Checking for potential conflicting linter configs..."
fd ".eslintrc|.prettierrc"

Length of output: 242


Script:

#!/bin/bash
# Let's check the root directory for Biome configuration
echo "Checking root directory for Biome config..."
ls -la biome.json .biome.json 2>/dev/null || true

# Check package-specific Biome config
echo -e "\nChecking package-specific Biome config..."
ls -la packages/indexer/biome.json packages/indexer/.biome.json 2>/dev/null || true

# Look for any ESLint/Prettier related dependencies in package.json
echo -e "\nChecking for old linter dependencies..."
grep -E "eslint|prettier" packages/indexer/package.json || true

# Check for any existing Biome dependencies
echo -e "\nChecking for Biome dependencies..."
grep -E "@biomejs|biome" packages/indexer/package.json || true

Length of output: 697


Script:

#!/bin/bash
# Check the content of root Biome config
echo "Content of root biome.json:"
cat biome.json

# Check if there are any remaining ESLint/Prettier config files in the monorepo
echo -e "\nChecking for any remaining linter config files in the entire repo..."
fd -H "\.eslintrc|\.prettierrc|\.eslintignore|\.prettierignore" --no-ignore

Length of output: 1255

packages/cli/package.json (2)

73-73: Consider updating esbuild to latest version.

The dependency changes align well with the PR objectives:

  • Moving @apibara/starknet to devDependencies is appropriate if it's only needed for development
  • Adding Rollup plugins supports the new build-time indexer list generation

However, [email protected] is not the latest version. Consider updating unless there's a specific reason for this version.

Let's check for potential compatibility issues with the latest esbuild:

#!/bin/bash
# Description: Check esbuild usage and compatibility

# Look for esbuild-specific configuration or usage
rg "esbuild" --type ts

Also applies to: 89-89, 103-103


66-66: Document environment variables used in scripts.

The script changes look good and align with the command refactoring. Consider documenting the purpose of environment variables like JITI_ESM_RESOLVE=1 in the README or developer documentation.

Let's check if these variables are documented:

Also applies to: 70-70

Comment on lines +40 to +45
if (!fse.existsSync(entry)) {
apibara.logger.error(
`Output directory ${outputDir} does not exist. Try building the indexer with "apibara build" first.`,
);
return process.exit(1);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance error messaging for missing build.

As discussed in the PR comments, the error message could be improved to match the Next.js style and point to documentation.

 if (!fse.existsSync(entry)) {
   apibara.logger.error(
-    `Output directory ${outputDir} does not exist. Try building the indexer with "apibara build" first.`,
+    [
+      `Could not find a production build in the '${outputDir}' directory.`,
+      `Try building your app with 'apibara build' before starting the indexer.`,
+      `https://docs.apibara.com/errors/no-production-build`
+    ].join('\n')
   );
   return process.exit(1);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!fse.existsSync(entry)) {
apibara.logger.error(
`Output directory ${outputDir} does not exist. Try building the indexer with "apibara build" first.`,
);
return process.exit(1);
}
if (!fse.existsSync(entry)) {
apibara.logger.error(
[
`Could not find a production build in the '${outputDir}' directory.`,
`Try building your app with 'apibara build' before starting the indexer.`,
`https://docs.apibara.com/errors/no-production-build`
].join('\n')
);
return process.exit(1);
}

Comment on lines +35 to +49
"./runtime": {
"types": "./dist/runtime/index.d.ts",
"import": "./dist/runtime/index.mjs"
},
"./internal/citty": {
"import": "./dist/internal/citty/index.mjs",
"types": "./dist/internal/citty/index.d.ts"
"./runtime/meta": {
"types": "./runtime-meta.d.ts",
"import": "./runtime-meta.mjs"
},
"./runtime/*": {
"types": "./dist/runtime/*.d.ts",
"import": "./dist/runtime/*.mjs"
},
"./dist/runtime/*": {
"types": "./dist/runtime/*.d.ts",
"import": "./dist/runtime/*.mjs"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Runtime exports configuration needs adjustment

The exports configuration in package.json references files in the dist directory, but the source files are currently only present in src/runtime. The runtime-meta.* files are correctly placed at the package root, but:

  • ./dist/runtime/*.d.ts and ./dist/runtime/*.mjs paths don't exist yet
  • The source files exist at:
    • src/runtime/dev.ts
    • src/runtime/index.ts
    • src/runtime/start.ts
    • src/runtime/internal/app.ts

Either:

  1. The build process needs to be set up to generate the dist files, or
  2. The exports configuration needs to be updated to match the current structure
🔗 Analysis chain

LGTM! Verify runtime directory structure.

The new runtime-related exports are well-structured and consistent with the existing pattern. The wildcard exports will enable flexible runtime module loading as needed for the command refactoring.

Let's verify the runtime directory structure matches the exports configuration:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify runtime directory structure exists as expected

# Check if runtime directory and type definitions exist
fd -t d "runtime$" "packages/cli/(src|dist)"
fd -t f ".*\.d\.ts$" -p "packages/cli/dist/runtime"

Length of output: 322


Script:

#!/bin/bash
# Let's try a different approach to verify the runtime-related files and structure

# Check src directory structure
fd -t d "runtime" "packages/cli/src"

# Check for runtime-related source files
fd -t f ".*\.(ts|js|mjs)$" "packages/cli/src/runtime"

# Check for runtime meta files
fd "runtime-meta" "packages/cli"

# List all files in packages/cli to understand the structure
ls -la packages/cli/

Length of output: 1103

@fracek fracek force-pushed the cli-rollup-refactor branch from 6c72c6a to c05f2e5 Compare November 2, 2024 19:41
@fracek fracek force-pushed the cli-rollup-refactor branch from c05f2e5 to a84b1f5 Compare November 2, 2024 19:44
@fracek fracek force-pushed the cli-rollup-refactor branch from a84b1f5 to c4c53a8 Compare November 2, 2024 19:48
@fracek fracek requested a review from jaipaljadeja November 2, 2024 19:49
@fracek fracek force-pushed the cli-rollup-refactor branch from 899c633 to 44326f4 Compare November 3, 2024 10:16
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (12)
examples/cli-js/apibara.config.mjs (2)

4-7: Add documentation for runtime configuration values.

The purpose and expected values for test and check configuration options are not documented. Consider:

  1. Adding JSDoc comments to explain each configuration option
  2. Using TypeScript or providing type information through JSDoc if possible

Example improvement:

 export default defineConfig({
+  /** Runtime configuration options */
   runtimeConfig: {
+    /** @type {number} Test configuration value */
     test: 123,
+    /** @type {string} Check configuration value */
     check: "something",
   },

1-15: Consider adding runtime configuration validation.

Since this configuration file defines runtime values that will be used by the CLI commands, consider:

  1. Adding runtime validation to ensure required values are present
  2. Implementing type checking for configuration values
  3. Adding schema validation to catch configuration errors early

This would help prevent runtime errors and provide better error messages to users.

examples/cli-js/indexers/starknet.indexer.js (1)

5-20: Consider environment configuration and error handling improvements.

While the basic setup is functional, there are several areas that could be improved:

  1. The streamUrl and contract address are hardcoded. Consider moving these to environment variables or configuration files for better maintainability and environment flexibility.
  2. The starting block number (800,000) should be documented with a comment explaining its significance.
  3. Consider adding validation for the contract address format.

Here's a suggested improvement:

+import { config } from 'dotenv';
+
+// Load environment variables
+config();
+
+// Validate contract address
+const CONTRACT_ADDRESS = process.env.STARKNET_CONTRACT_ADDRESS ||
+  "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7";
+if (!/^0x[0-9a-fA-F]{64}$/.test(CONTRACT_ADDRESS)) {
+  throw new Error('Invalid contract address format');
+}
+
 export default defineIndexer(StarknetStream)({
-  streamUrl: "https://starknet.preview.apibara.org",
+  streamUrl: process.env.STARKNET_STREAM_URL || "https://starknet.preview.apibara.org",
   finality: "accepted",
   startingCursor: {
+    // Start indexing from block 800,000 (Goerli testnet deployment block)
     orderKey: 800_000n,
   },
   filter: {
     events: [
       {
-        address:
-          "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
+        address: CONTRACT_ADDRESS,
         keys: [hash.getSelectorFromName("Transfer")],
         includeReceipt: true,
       },
     ],
   },
.github/workflows/build.yml (1)

46-46: Consider adding a comment for test exclusions.

While the build step has a helpful comment explaining the exclusions, the test step would benefit from similar documentation.

-        run: pnpm test:ci --filter=!./examples/cli --filter=!./examples/cli-js
+        # Exclude examples/cli since it requires the cli to be built.
+        run: pnpm test:ci --filter=!./examples/cli --filter=!./examples/cli-js
packages/cli/src/runtime/dev.ts (3)

6-20: Enhance argument definitions with validation and defaults

Consider improving the argument definitions for better user experience and validation:

 args: {
   indexers: {
     type: "string",
-    description: "Which indexers to run",
+    description: "Comma-separated list of indexers to run (e.g., 'indexer1,indexer2')",
+    default: undefined,
   },
   preset: {
     type: "string",
-    description: "Preset to use",
+    description: "Configuration preset name to apply",
+    required: false,
+    default: "default",
   },
 },

52-60: Enhance CLI metadata description

The current description could be more informative about the development mode capabilities and use cases.

 meta: {
   name: "indexer-dev-runner",
-  description: "Run indexer in dev mode",
+  description: "Development environment runner for Apibara indexers with hot-reload support",
 },

64-64: Remove unnecessary default export

The empty default export serves no purpose and can be removed.

-export default {};
packages/cli/src/rollup/config.ts (2)

Line range hint 24-54: Consider extracting the RollupConfig type extension.

While the inline type extension RollupConfig & { plugins: OutputPluginOption[] } works, it would be cleaner to define this as a separate type.

+type ExtendedRollupConfig = RollupConfig & { plugins: OutputPluginOption[] };
+
-  const rollupConfig: RollupConfig & { plugins: OutputPluginOption[] } = {
+  const rollupConfig: ExtendedRollupConfig = {

Line range hint 13-79: Well-structured refactor using virtual plugins.

The refactoring improves the codebase by:

  1. Using Rollup's virtual plugins for dynamic content generation
  2. Maintaining a clear separation of concerns between build configuration and plugin logic
  3. Providing better type safety through explicit typing

This approach will make it easier to maintain and extend the build process in the future.

packages/cli/package.json (1)

66-66: Consider making the indexer parameter configurable.

The playground:start script now hardcodes the starknet indexer. Consider making this configurable through an environment variable to maintain flexibility.

-    "playground:start": "pnpm playground start --dir playground --indexer starknet"
+    "playground:start": "pnpm playground start --dir playground --indexer ${INDEXER:-starknet}"

Also applies to: 70-70

packages/cli/src/runtime/internal/app.ts (2)

18-20: Enhance error message to list available presets

When an invalid preset is specified, consider including the list of available presets in the error message to assist users.

Apply this diff to improve the error message:

      if (config.presets[preset] === undefined) {
        throw new Error(
-         `Specified preset "${preset}" but it was not defined`
+         `Specified preset "${preset}" is not defined. Available presets are: ${Object.keys(config.presets).join(', ')}`
        );
      }

31-33: Include available indexers in the error message

If an invalid indexer name is provided, enhance the error message by listing the available indexers to guide users.

Apply this diff to improve the error message:

      if (indexerDefinition === undefined) {
        throw new Error(
-         `Specified indexer "${indexerName}" but it was not defined`
+         `Specified indexer "${indexerName}" is not defined. Available indexers are: ${availableIndexers.join(', ')}`
        );
      }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 94fa282 and 44326f4.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (52)
  • .github/workflows/build.yml (1 hunks)
  • change/@apibara-indexer-843e6831-307c-49b1-bf59-833803a4a27f.json (1 hunks)
  • change/apibara-ed31dbbf-efbd-44c6-8eb0-f729dde0acb6.json (1 hunks)
  • examples/cli-js/apibara.config.mjs (1 hunks)
  • examples/cli-js/indexers/starknet.indexer.js (1 hunks)
  • examples/cli-js/package.json (1 hunks)
  • examples/cli/apibara.config.ts (0 hunks)
  • examples/cli/indexers/starknet.indexer.ts (1 hunks)
  • examples/cli/package.json (1 hunks)
  • flake.nix (1 hunks)
  • package.json (1 hunks)
  • packages/cli/build.config.ts (2 hunks)
  • packages/cli/package.json (4 hunks)
  • packages/cli/playground/apibara.config.ts (1 hunks)
  • packages/cli/playground/indexers/starknet.indexer.ts (2 hunks)
  • packages/cli/playground/tsconfig.json (0 hunks)
  • packages/cli/runtime-meta.d.ts (1 hunks)
  • packages/cli/runtime-meta.mjs (1 hunks)
  • packages/cli/src/cli/commands/build.ts (2 hunks)
  • packages/cli/src/cli/commands/dev.ts (5 hunks)
  • packages/cli/src/cli/commands/prepare.ts (0 hunks)
  • packages/cli/src/cli/commands/start.ts (1 hunks)
  • packages/cli/src/cli/index.ts (1 hunks)
  • packages/cli/src/config/index.ts (1 hunks)
  • packages/cli/src/core/apibara.ts (3 hunks)
  • packages/cli/src/core/build/build.ts (1 hunks)
  • packages/cli/src/core/build/dev.ts (1 hunks)
  • packages/cli/src/core/build/prepare.ts (1 hunks)
  • packages/cli/src/core/build/prod.ts (2 hunks)
  • packages/cli/src/core/build/types.ts (2 hunks)
  • packages/cli/src/core/config/defaults.ts (1 hunks)
  • packages/cli/src/core/config/loader.ts (1 hunks)
  • packages/cli/src/core/config/resolvers/runtime-config.resolver.ts (1 hunks)
  • packages/cli/src/core/config/update.ts (1 hunks)
  • packages/cli/src/core/path.ts (1 hunks)
  • packages/cli/src/core/scan.ts (1 hunks)
  • packages/cli/src/internal/citty/index.ts (0 hunks)
  • packages/cli/src/internal/consola/index.ts (0 hunks)
  • packages/cli/src/rollup/config.ts (3 hunks)
  • packages/cli/src/rollup/plugins/config.ts (1 hunks)
  • packages/cli/src/rollup/plugins/indexers.ts (1 hunks)
  • packages/cli/src/runtime/dev.ts (1 hunks)
  • packages/cli/src/runtime/index.ts (1 hunks)
  • packages/cli/src/runtime/internal/app.ts (1 hunks)
  • packages/cli/src/runtime/start.ts (1 hunks)
  • packages/cli/src/types/apibara.ts (1 hunks)
  • packages/cli/src/types/config.ts (3 hunks)
  • packages/cli/src/types/hooks.ts (1 hunks)
  • packages/cli/src/types/virtual/config.d.ts (1 hunks)
  • packages/cli/src/types/virtual/indexers.d.ts (1 hunks)
  • packages/cli/tsconfig.json (1 hunks)
  • packages/indexer/package.json (1 hunks)
💤 Files with no reviewable changes (5)
  • examples/cli/apibara.config.ts
  • packages/cli/playground/tsconfig.json
  • packages/cli/src/cli/commands/prepare.ts
  • packages/cli/src/internal/citty/index.ts
  • packages/cli/src/internal/consola/index.ts
✅ Files skipped from review due to trivial changes (3)
  • change/@apibara-indexer-843e6831-307c-49b1-bf59-833803a4a27f.json
  • examples/cli-js/package.json
  • packages/cli/runtime-meta.d.ts
🚧 Files skipped from review as they are similar to previous changes (36)
  • change/apibara-ed31dbbf-efbd-44c6-8eb0-f729dde0acb6.json
  • examples/cli/indexers/starknet.indexer.ts
  • examples/cli/package.json
  • flake.nix
  • package.json
  • packages/cli/playground/apibara.config.ts
  • packages/cli/playground/indexers/starknet.indexer.ts
  • packages/cli/runtime-meta.mjs
  • packages/cli/src/cli/commands/build.ts
  • packages/cli/src/cli/commands/dev.ts
  • packages/cli/src/cli/commands/start.ts
  • packages/cli/src/cli/index.ts
  • packages/cli/src/config/index.ts
  • packages/cli/src/core/apibara.ts
  • packages/cli/src/core/build/build.ts
  • packages/cli/src/core/build/dev.ts
  • packages/cli/src/core/build/prepare.ts
  • packages/cli/src/core/build/prod.ts
  • packages/cli/src/core/build/types.ts
  • packages/cli/src/core/config/defaults.ts
  • packages/cli/src/core/config/loader.ts
  • packages/cli/src/core/config/resolvers/runtime-config.resolver.ts
  • packages/cli/src/core/config/update.ts
  • packages/cli/src/core/path.ts
  • packages/cli/src/core/scan.ts
  • packages/cli/src/rollup/plugins/config.ts
  • packages/cli/src/rollup/plugins/indexers.ts
  • packages/cli/src/runtime/index.ts
  • packages/cli/src/runtime/start.ts
  • packages/cli/src/types/apibara.ts
  • packages/cli/src/types/config.ts
  • packages/cli/src/types/hooks.ts
  • packages/cli/src/types/virtual/config.d.ts
  • packages/cli/src/types/virtual/indexers.d.ts
  • packages/cli/tsconfig.json
  • packages/indexer/package.json
🔇 Additional comments (15)
examples/cli-js/apibara.config.mjs (2)

1-3: LGTM! Good use of ES modules and configuration helper.

The use of defineConfig from apibara/config is a good practice as it likely provides type checking and validation for the configuration object.


8-14: Verify and document preset usage.

While the preset structure allows for environment-specific configurations, it's not clear:

  1. When and how these presets are applied
  2. How this relates to the build, dev, and start commands mentioned in the PR objectives

Let's check how presets are used in the codebase:

✅ Verification successful

Presets are used to override configuration at runtime via CLI commands

The verification reveals that presets are properly integrated into the CLI commands:

  1. Presets can be applied via the --preset flag in both dev and start commands
  2. When a preset is specified, the configuration is merged using defu with preset values taking precedence
  3. In development mode, preset changes trigger a reload of the configuration

The preset in your configuration will be accessible when:

  • Running apibara dev --preset dev
  • Running apibara start --indexer <name> --preset dev
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for preset usage in command implementations
rg -l "preset" | grep -i "command\|cli"

# Search for documentation about presets
fd -g "*.md" -x grep -l "preset" {} \;

Length of output: 502


Script:

#!/bin/bash
# Check preset implementation in the config loader and resolver
cat packages/cli/src/core/config/resolvers/preset.resolver.ts
echo "---"
# Check how presets are used in dev and start commands
cat packages/cli/src/cli/commands/dev.ts
echo "---"
cat packages/cli/src/cli/commands/start.ts

Length of output: 5327

examples/cli-js/indexers/starknet.indexer.js (2)

1-3: LGTM: Imports are appropriate and necessary.

The imports are correctly structured and include all required dependencies for the indexer functionality.


17-17: Review performance impact of includeReceipt.

Setting includeReceipt: true will fetch additional data for each event, which might impact performance when processing many events.

Let's check if there are any performance considerations in the documentation or related files:

✅ Verification successful

The previous results show that includeReceipt is used in multiple indexers and tests, but we need to understand its implementation and documentation to assess its performance impact. Let's check the interface definition and surrounding documentation.


Based on the documentation and code analysis, I can now provide a final response:

Setting includeReceipt: true has minimal performance impact

The includeReceipt option is a standard filter parameter that only includes the transaction receipt when retrieving events. From the documentation:

  • It defaults to false, making it an opt-in feature
  • It only fetches the receipt for the specific transaction that emitted the matched event
  • It's commonly used alongside other similar options like includeTransaction and includeEvents

Since this is in an example indexer and the receipt data is necessary for processing Transfer events, the performance overhead is justified and expected.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for documentation or examples related to includeReceipt usage
rg -l "includeReceipt" | xargs rg -A 5 -B 5 "includeReceipt.*true"

# Search for performance-related documentation
rg -i "performance|optimization" README.md docs/

Length of output: 8026


Script:

#!/bin/bash
# Let's check the filter interface and any documentation about includeReceipt
ast-grep --pattern 'interface $_ {
  $$$
  includeReceipt$_
  $$$
}'

# Let's also check if there are any comments or documentation about performance
rg -B 5 -A 5 "includeReceipt" packages/starknet/src/

Length of output: 26280

packages/cli/build.config.ts (4)

5-13: LGTM: Module array updated correctly.

The addition of the "runtime" module is consistent with the PR objectives and follows the existing naming convention.


40-43: LGTM: Externals configuration is properly updated.

The externals array correctly includes the new runtime meta module while preserving the existing module externals. The ordering ensures proper module resolution.


31-38: Verify runtime-meta.mjs file existence and location.

The alias configuration points to runtime-meta.mjs in the parent directory. This is a critical dependency that needs to be verified.

✅ Verification successful

Runtime meta file exists and is correctly configured

The runtime-meta.mjs file exists in the expected location and exports the necessary path configurations for runtime functionality. The alias configuration in build.config.ts correctly points to this file.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify runtime-meta.mjs file existence and content

# Check if the runtime-meta.mjs file exists
if [ -f "packages/cli/runtime-meta.mjs" ]; then
    echo "runtime-meta.mjs exists. Contents:"
    cat packages/cli/runtime-meta.mjs
else
    echo "runtime-meta.mjs not found!"
fi

Length of output: 453


26-26: Verify runtime module directory structure.

The runtime module uses a directory input (./src/runtime/) unlike other entries that specify individual files. Please ensure the directory structure exists and contains the necessary files.

✅ Verification successful

The previous script didn't provide clear output, so let's try a different approach to verify the runtime directory structure and its references in the codebase. This will help us understand if the directory input configuration is valid and necessary.


Runtime directory structure is valid and appropriate for directory-based entry

The runtime module directory structure exists and contains multiple TypeScript files (dev.ts, index.ts, start.ts) and an internal subdirectory, justifying the directory-based build entry configuration. The ESM format is also appropriate as this appears to be a modern JavaScript/TypeScript module structure.

  • packages/cli/src/runtime/
    • dev.ts
    • index.ts
    • start.ts
    • internal/app.ts
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the runtime module directory structure

# Check if the runtime directory exists and list its contents
if [ -d "packages/cli/src/runtime" ]; then
    echo "Runtime directory exists. Contents:"
    ls -la packages/cli/src/runtime/
else
    echo "Runtime directory not found!"
fi

Length of output: 453


Script:

#!/bin/bash
# Let's verify the runtime directory structure using fd and check its contents
fd . packages/cli/src/runtime

# Also check if there are any references to runtime directory in the codebase
rg -l "runtime" packages/cli/src

Length of output: 650

.github/workflows/build.yml (2)

41-42: LGTM! Clear explanation for build exclusions.

The comment clearly explains why examples/cli is excluded from the build process, which helps future maintainers understand the dependency relationship.


41-46: Verify the impact of excluding these directories.

The exclusion of examples/cli and examples/cli-js from both build and test processes seems intentional based on the PR objectives of refactoring CLI commands. However, let's verify that these examples are tested elsewhere or have their own CI workflows.

✅ Verification successful

Let me gather more specific information about these CLI examples to understand their testing setup better.


Based on the gathered information, I can now provide a final response:

The exclusion of CLI examples from build and test processes is correct and intentional

The examples/cli and examples/cli-js directories are demonstration projects that depend on the main CLI package being built first. This is evident from their package.json files which:

  • Are marked as "private": true
  • Have apibara as a workspace dependency
  • Only contain build/dev/start scripts that use the apibara CLI tool
  • Don't contain any test scripts

These examples are also explicitly ignored in the root package.json's beachball configuration:

"beachball": {
    "ignorePatterns": [
      "examples/**"
    ]
}
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if examples/cli and examples/cli-js have their own workflows
# or are tested in a different way

# Look for other workflow files that might handle these examples
fd -e yml -e yaml . .github/workflows -x cat {} \; | grep -A 5 "examples/cli"

# Check if these directories have their own test scripts
fd package.json -e json . examples/cli examples/cli-js -x jq -r '.scripts | select(.test != null)'

Length of output: 2113


Script:

#!/bin/bash
# Check the package.json files specifically in the CLI example directories
fd package.json . examples/cli examples/cli-js -x cat {}

# Look for any README or documentation that might explain the testing strategy
fd README.md . examples/cli examples/cli-js -x cat {}

# Check if these are integration test examples that might be intentionally excluded
rg -A 5 "examples/cli" . --type md --type txt

Length of output: 23069

packages/cli/src/runtime/dev.ts (2)

1-5: LGTM! Dependencies are well-organized

The imports are clean and necessary for the functionality being implemented.


1-64: Verify CLI integration and type definitions

Please ensure:

  1. The dev runner commands are properly registered in the main CLI configuration
  2. The indexer type definitions include the cleanup method for graceful shutdown
packages/cli/src/rollup/config.ts (1)

6-13: LGTM! Clean import organization and simplified function signature.

The changes improve the code by:

  • Using pathe for cross-platform path handling
  • Adding necessary imports for the new plugin system
  • Simplifying the function signature by removing the unused dev parameter
packages/cli/package.json (2)

35-49: Verify virtual plugin configuration for runtime exports.

The runtime exports configuration aligns with the PR objective of using Rollup's virtual plugin. However, we should verify that the virtual plugin is properly configured to generate the expected files.

#!/bin/bash
# Description: Verify virtual plugin configuration in build setup

# Check for virtual plugin configuration in build files
rg -A 5 "@rollup/plugin-virtual" "packages/cli/src"

# Check if runtime meta files are generated
fd "runtime-meta" "packages/cli"

73-73: LGTM! Dependencies are well-structured.

The dependency changes align well with the PR objectives:

  • Moving @apibara/starknet to devDependencies is appropriate
  • Adding rollup plugins supports the new build-time indexer generation

Also applies to: 89-89, 103-103

Comment on lines +21 to +23
async transform({ block: { header } }) {
console.log("Transforming block ", header?.blockNumber);
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance transform function with structured logging and error handling.

The current transform function uses basic console.log and lacks error handling. Consider using a structured logger and adding proper error handling.

Here's a suggested improvement:

-  async transform({ block: { header } }) {
-    console.log("Transforming block ", header?.blockNumber);
+  async transform({ block: { header, events } }) {
+    try {
+      const blockNumber = header?.blockNumber;
+      if (!blockNumber) {
+        throw new Error('Block number is undefined');
+      }
+
+      console.log({
+        level: 'info',
+        message: 'Transforming block',
+        blockNumber: blockNumber.toString(),
+        eventsCount: events?.length ?? 0,
+      });
+
+      // Process events here
+    } catch (error) {
+      console.error({
+        level: 'error',
+        message: 'Failed to transform block',
+        error: error.message,
+        blockNumber: header?.blockNumber?.toString(),
+      });
+      throw error; // Re-throw to ensure the indexer handles the error
+    }
   },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async transform({ block: { header } }) {
console.log("Transforming block ", header?.blockNumber);
},
async transform({ block: { header, events } }) {
try {
const blockNumber = header?.blockNumber;
if (!blockNumber) {
throw new Error('Block number is undefined');
}
console.log({
level: 'info',
message: 'Transforming block',
blockNumber: blockNumber.toString(),
eventsCount: events?.length ?? 0,
});
// Process events here
} catch (error) {
console.error({
level: 'error',
message: 'Failed to transform block',
error: error.message,
blockNumber: header?.blockNumber?.toString(),
});
throw error; // Re-throw to ensure the indexer handles the error
}
},

Comment on lines +21 to +49
async run({ args }) {
const { indexers: indexersArgs, preset } = args;

let selectedIndexers = availableIndexers;
if (indexersArgs) {
selectedIndexers = indexersArgs.split(",");
}

for (const indexer of selectedIndexers) {
if (!availableIndexers.includes(indexer)) {
throw new Error(
`Specified indexer "${indexer}" but it was not defined`,
);
}
}

await Promise.all(
selectedIndexers.map(async (indexer) => {
const indexerInstance = createIndexer(indexer, preset);

const client = createClient(
indexerInstance.streamConfig,
indexerInstance.options.streamUrl,
);

await run(client, indexerInstance);
}),
);
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add graceful shutdown handling

The command should handle process termination signals (SIGINT, SIGTERM) to ensure indexers can clean up resources properly before shutting down.

 async run({ args }) {
   const { indexers: indexersArgs, preset } = args;
+  const runningIndexers = new Set();
+
+  // Handle graceful shutdown
+  const cleanup = async () => {
+    console.log('\nShutting down indexers...');
+    // Allow indexers to implement a cleanup method
+    for (const indexer of runningIndexers) {
+      try {
+        await indexer.cleanup?.();
+      } catch (error) {
+        console.error(`Error cleaning up indexer:`, error);
+      }
+    }
+    process.exit(0);
+  };
+
+  process.on('SIGINT', cleanup);
+  process.on('SIGTERM', cleanup);

   let selectedIndexers = availableIndexers;
   // ... rest of the code

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines 57 to 76
rollupConfig.plugins.push(commonjs());
rollupConfig.plugins.push(json());

rollupConfig.plugins.push(
nodeResolve({
extensions,
preferBuiltins: true,
mainFields: ["main"],
}),
);

rollupConfig.plugins.push(
esbuild({
target: "es2022",
sourceMap: apibara.options.sourceMap,
}),
);

rollupConfig.plugins.push(indexers(apibara));
rollupConfig.plugins.push(appConfig(apibara));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Plugin configuration needs attention

The verification revealed some issues that need to be addressed:

  • The rollup-plugin-esbuild is imported but not declared in package.json dependencies
  • The appConfig plugin is imported from "./plugins/config" but the file doesn't exist in the codebase
  • The indexers plugin is properly implemented using @rollup/plugin-virtual
🔗 Analysis chain

Verify plugin order and dependencies.

The plugin order looks correct, with commonjs and json before nodeResolve. The addition of esbuild, indexers, and appConfig plugins aligns with the PR objectives.

Let's verify the dependencies and plugin usage:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if all required dependencies are properly declared
grep -A 10 '"dependencies"' packages/cli/package.json
grep -A 10 '"devDependencies"' packages/cli/package.json

# Verify the new plugins are properly exported
fd -e ts -e js "plugins/(config|indexers)" packages/cli/src/rollup/

Length of output: 837


Script:

#!/bin/bash
# Let's verify the plugin imports and their existence in the codebase
ast-grep --pattern 'import { $_ } from "@rollup/plugin-$_"'

# Check for the custom plugins implementation
fd -e ts "indexers|appConfig" packages/cli/src/rollup/
cat $(fd -e ts "indexers|appConfig" packages/cli/src/rollup/)

Length of output: 741


Script:

#!/bin/bash
# Let's check for esbuild plugin import and appConfig implementation
rg "import.*esbuild.*from" -A 2
fd -e ts "appConfig" packages/cli/src/rollup/
cat $(fd -e ts "appConfig" packages/cli/src/rollup/)

Length of output: 556

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Outside diff range and nitpick comments (6)
examples/cli/indexers/starknet.indexer.ts (2)

10-10: Replace console.log with structured logging

Consider using apibara.logger instead of console.log for consistent logging across the codebase.

-  console.log("--> Starknet Indexer Runtime Config: ", runtimeConfig);
+  apibara.logger.info("starknet indexer runtime config", { config: runtimeConfig });

Line range hint 29-31: Replace console.log in transform function

For consistency with the project's logging standards, replace console.log with structured logging.

   async transform({ block: { header } }) {
-      console.log("Transforming block ", header?.blockNumber);
+      apibara.logger.debug("transforming block", { blockNumber: header?.blockNumber });
   }
packages/cli/src/rollup/plugins/esm-shim.ts (4)

17-17: Refine CommonJS syntax detection for accurate matching

The regular expression /__filename|__dirname/ may match unintended substrings within other variable names (e.g., my__dirnameVar). To ensure accurate detection of __filename and __dirname, use word boundaries:

-const CJSyntaxRegex = /__filename|__dirname/;
+const CJSyntaxRegex = /\b(__filename|__dirname)\b/;

24-24: Prevent multiple shims from being inserted

Relying on code.includes(ESMShim) to check if the shim has already been inserted may not be reliable, especially if code formatting changes. To ensure the shim isn't inserted multiple times, consider setting a flag or modifying the logic to track insertion more robustly.


46-55: Simplify source map sourcesContent handling

Manually filtering sourcesContent for strings may be unnecessary if sourceMap.sourcesContent is already correctly structured. You can simplify this section by directly using sourceMap.sourcesContent:

-let sourcesContent: string[] | undefined;
-if (Array.isArray(sourceMap.sourcesContent)) {
-  sourcesContent = [];
-  for (let i = 0; i < sourceMap.sourcesContent.length; i++) {
-    const content = sourceMap.sourcesContent[i];
-    if (typeof content === "string") {
-      sourcesContent.push(content);
-    }
-  }
-}
+const sourcesContent = sourceMap.sourcesContent;

4-6: Provide rationale for custom ESM shim implementation

The comment indicates this plugin is an alternative to @rollup/plugin-esm-shim. Providing additional context on why a custom implementation is necessary—such as specific limitations or issues with the existing plugin—would help maintainers understand the reasoning behind this decision.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 44326f4 and 7039ff0.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • examples/cli/indexers/starknet.indexer.ts (1 hunks)
  • examples/cli/package.json (2 hunks)
  • examples/indexer/package.json (1 hunks)
  • packages/cli/package.json (4 hunks)
  • packages/cli/src/rollup/config.ts (2 hunks)
  • packages/cli/src/rollup/plugins/esm-shim.ts (1 hunks)
  • packages/cli/src/types/config.ts (4 hunks)
  • packages/indexer/package.json (2 hunks)
✅ Files skipped from review due to trivial changes (1)
  • examples/indexer/package.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/cli/src/rollup/config.ts
  • packages/indexer/package.json
🔇 Additional comments (11)
examples/cli/package.json (1)

17-17: Consider aligning type definitions version with the main package.

The @types/better-sqlite3 (^7.6.11) and better-sqlite3 (^11.5.0) versions are significantly different. This version mismatch might lead to type definition inconsistencies.

Let's check if this is a known issue:

Consider:

  1. Verifying if type definitions for version 11.x are available
  2. If not, document any known type inconsistencies
  3. Set up a reminder to update types when they become available

Also applies to: 26-26

examples/cli/indexers/starknet.indexer.ts (4)

10-11: Verify the intended use of in-memory database

The current implementation uses an in-memory SQLite database which won't persist data between restarts. If this is an example/testing setup, consider adding a comment to clarify the intention. For production use, consider using a file-based database.

+  // Using in-memory database for example purposes only
+  // For production, consider using a file-based database
   const database = new Database(":memory:");

18-18: LGTM: SQLite persistence plugin configuration

The SQLite persistence plugin is correctly configured with the database instance.


Line range hint 19-27: LGTM: Event filter configuration

The filter configuration correctly targets Transfer events from the specified contract address.


15-17: ⚠️ Potential issue

Verify the significant change in startingCursor orderKey

The orderKey has been increased from 80,000n to 800,000n (10x increase). Please verify this change won't skip important historical data.

✅ Verification successful

The orderKey change to 800_000n is consistent with other Starknet indexers

The value of 800_000n is already being used in other Starknet indexers across the codebase:

  • examples/cli-js/indexers/starknet.indexer.js
  • packages/cli/playground/indexers/starknet.indexer.ts
  • examples/starknet-client/src/main.ts

This appears to be a standardization of the starting point for Starknet indexers, updating from the previous value of 80_000n seen in examples/starknet-indexer/src/indexer.ts. The change is intentional and aligned with other implementations.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other instances of startingCursor configuration
# to ensure consistency across the codebase
rg -A 2 "startingCursor.*orderKey" --type typescript

Length of output: 89


Script:

#!/bin/bash
# Search for startingCursor configuration using ripgrep without file type filter
rg -A 2 "startingCursor.*orderKey"

Length of output: 1481


Script:

#!/bin/bash
# Find all TypeScript files and search for startingCursor
fd -e ts | xargs rg -A 2 "startingCursor.*orderKey"

Length of output: 1498


Script:

#!/bin/bash
# Use ast-grep to find object literals containing startingCursor
ast-grep --pattern 'startingCursor: {
  orderKey: $_
}'

Length of output: 57


Script:

#!/bin/bash
# Look for any configuration files that might contain orderKey settings
rg -A 2 "orderKey.*[0-9]+"

Length of output: 19410

packages/cli/src/types/config.ts (3)

19-23: LGTM: Improved type safety with explicit empty record type.

The change from {} to Record<string, never> as default type parameter is a good improvement. This makes the type constraints more explicit and provides better type inference in TypeScript.

Also applies to: 42-46


75-75: Verify the implementation of new Rollup configuration options.

The addition of sourceMap and commonJS options enhances build configuration flexibility. However, we should verify their proper implementation in the build process.

Let's check the implementation:

Also applies to: 77-77

✅ Verification successful

Both sourceMap and commonJS options are properly implemented in the build configuration

The verification shows that both options are correctly handled in the build process:

  • sourceMap is properly implemented in packages/cli/src/rollup/config.ts where it's passed directly to the Rollup configuration: sourceMap: apibara.options.sourceMap
  • commonJS options are correctly forwarded in the same file: ...apibara.options.commonJS
  • Source map generation is also properly supported in the ESM shim plugin (packages/cli/src/rollup/plugins/esm-shim.ts)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify Rollup configuration handling

# Check how sourceMap option is used
echo "Checking sourceMap implementation:"
rg -A 5 "sourceMap.*config" 

# Check CommonJS configuration handling
echo "Checking commonJS implementation:"
ast-grep --pattern 'commonJS.*options'

Length of output: 310


Script:

#!/bin/bash
# Let's try a broader search for Rollup configuration handling

# Search for sourceMap usage in the codebase
echo "Checking sourceMap usage:"
rg -A 5 "sourceMap"

# Search for commonJS related configuration
echo "Checking commonJS configuration:"
rg -A 5 "commonJS"

# Look for Rollup configuration setup
echo "Checking Rollup configuration setup:"
rg -A 10 "rollup.*config"

# Search for build configuration files
echo "Searching for build configuration files:"
fd -e js -e ts "rollup.config"

Length of output: 3653


64-65: Verify the integration of the new required indexersDir property.

The addition of indexersDir aligns with the PR's objective of managing indexers at build time. However, being a required property means existing configurations need updates.

Let's verify the integration:

✅ Verification successful

The new indexersDir property is properly integrated and has sensible defaults

The property is well integrated into the codebase:

  • Has a default value of "indexers" in defaults.ts
  • Used correctly in scan.ts to locate and load indexer files
  • Properly handles non-existent directories with clear error messages
  • Supports both .indexer.ts and .indexer.js file extensions
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check usage and implementation of indexersDir

# Check how indexersDir is used in the codebase
echo "Checking indexersDir usage:"
rg -A 5 "indexersDir" 

# Look for potential configuration files that need updates
echo "Checking configuration files:"
fd -e config.ts -e config.js

Length of output: 310


Script:

#!/bin/bash
# Let's try a more comprehensive search

# Check for indexersDir usage across the codebase
echo "Checking indexersDir references:"
rg "indexersDir"

# Check for config type usage and implementations
echo "Checking config type usage:"
rg -l "Config" --type typescript

# Look for test configurations
echo "Checking test configurations:"
fd -e test.ts -e test.js

# Check for configuration examples or defaults
echo "Checking for configuration examples:"
fd "default" -e ts -e js

Length of output: 1671


Script:

#!/bin/bash
# Let's check the implementation details and default configuration

# Check the default configuration implementation
echo "Default configuration content:"
cat packages/cli/src/core/config/defaults.ts

# Check how the config is used in scan.ts
echo "Scan implementation:"
cat packages/cli/src/core/scan.ts

# Look for any configuration examples in documentation
echo "Configuration documentation:"
fd README -e md | xargs cat

Length of output: 6994

packages/cli/package.json (3)

35-49: Skip comment about runtime exports configuration.

A previous review already covers the concerns about runtime exports configuration and dist directory structure.


73-73: LGTM! Dependencies align with the refactoring goals.

The dependency changes support the PR objectives:

  • Added Rollup plugins for build-time generation of indexer list
  • Correctly moved @apibara/starknet to devDependencies
  • Added necessary build tools (magic-string, rollup-plugin-esbuild)

Also applies to: 89-89, 99-99, 104-104


66-66: LGTM! Verify the playground scripts functionality.

The script changes align well with the PR objectives:

  • Added debug logging for better development experience
  • Updated start command to use the starknet indexer

Let's verify the playground scripts are properly configured:

Also applies to: 70-70

✅ Verification successful

Let me gather more information about the playground script configuration to verify its functionality.


Let me check the playground configuration file and indexers directory content to complete the verification.


Let me check the starknet indexer implementation to complete the verification.


Playground script configuration is properly set up

The verification confirms that:

  • The playground directory exists with the required configuration and starknet indexer
  • The CLI entry point (packages/cli/src/cli/index.ts) is correctly referenced in the playground script
  • Debug level addition (CONSOLA_LEVEL=debug) will work with the consola logger used in the starknet indexer
  • The environment setup (JITI_ESM_RESOLVE=1 and NODE_OPTIONS) is appropriate for the ESM-based implementation

The playground script changes are well-aligned with the codebase structure and will provide the intended development experience.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify playground scripts configuration
# Check if the playground directory and indexer exist

# Check for playground directory
fd -t d "playground$" .

# Check for starknet indexer references
rg "starknet.*indexer" -A 3

Length of output: 777


Script:

#!/bin/bash
# Check the playground script implementation and dependencies

# Check playground directory contents
ls -la packages/cli/playground/

# Look for playground script references in source
rg "playground" -A 3 packages/cli/src/

# Check for jiti usage and configuration
rg "jiti" -A 3 packages/cli/src/

Length of output: 337


Script:

#!/bin/bash
# Check playground configuration and indexers

# Check playground config content
cat packages/cli/playground/apibara.config.ts

# Check indexers directory content
ls -la packages/cli/playground/indexers/

# Look for CLI entry point referenced in playground script
cat packages/cli/src/cli/index.ts

Length of output: 1127


Script:

#!/bin/bash
# Check starknet indexer implementation

# Check starknet indexer content
cat packages/cli/playground/indexers/starknet.indexer.ts

# Look for any dev command implementation since it's used in playground
cat packages/cli/src/cli/commands/dev.ts

Length of output: 4458

Comment on lines +6 to +12
"scripts": {
"build": "apibara build",
"dev": "apibara dev",
"start": "apibara start",
"lint": "biome check .",
"lint:fix": "pnpm lint --write"
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codebase verification

Based on the search results, I can now generate the final response since I have enough information to verify the documentation of the commands.

Commands need documentation

The new scripts (build, dev, start, lint) are not properly documented. While the CLI commands have basic descriptions in the code, there is no user-facing documentation:

  • The @apibara/cli package README is empty with just "TODO" placeholders
  • The CLI help text only provides minimal descriptions
  • No documentation found in docs directory
🔗 Analysis chain

LGTM! Verify command documentation.

The new scripts align well with the PR objectives for refactoring the build, dev, and start commands. The addition of linting scripts with Biome is also a good practice for code quality.

Let's verify if these commands are documented:


Let me try another search strategy to verify the documentation of these commands.


Let me try one more search to find CLI command documentation in the source code.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if these commands are documented in README or CLI help
fd -t f "README.md" -X cat {} | rg -A 5 "(?:build|dev|start) command"

Length of output: 449


Script:

#!/bin/bash
# Search for documentation in different locations
echo "=== Searching in README files ==="
fd -t f "README" -X cat {}

echo -e "\n=== Searching in docs directory ==="
fd -t f . -e md -p docs/ -X cat {}

echo -e "\n=== Searching for CLI help text ==="
ast-grep --pattern 'program
  .command($_)
  .description($_)'

Length of output: 5760


Script:

#!/bin/bash
# Search for CLI command definitions
echo "=== Searching for command definitions ==="
rg -A 3 "\.command\(['\"](?:build|dev|start)['\"].*\)" --type ts

echo -e "\n=== Checking CLI package for documentation ==="
fd -t f . -p "packages/cli" -X cat {}

Length of output: 44122

Comment on lines +31 to +37
for (const match of code.matchAll(/^import\s.*';$/gm)) {
if (match.length === 0 || typeof match.index !== "number") {
continue;
}

endIndexOfLastImport = match.index + match[0].length;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Enhance regex to accurately match all import statements

The regular expression used in code.matchAll(/^import\s.*';$/gm) may not match all valid import statements. It misses cases such as:

  • Imports using double quotes: import something from "module";

  • Imports without semicolons: import something from 'module'

  • Imports spanning multiple lines:

    import {
      something,
      anotherThing
    } from 'module';

Consider using a parser like @babel/parser or enhancing the regex to handle these scenarios. An improved regex might be:

-for (const match of code.matchAll(/^import\s.*';$/gm)) {
+for (const match of code.matchAll(/^import\s.*?from\s.*?['"];?$/gm)) {

However, using a parser would provide more accuracy and maintainability.

Comment on lines +28 to +40
let endIndexOfLastImport = -1;

// Find the last import statement and its ending index
for (const match of code.matchAll(/^import\s.*';$/gm)) {
if (match.length === 0 || typeof match.index !== "number") {
continue;
}

endIndexOfLastImport = match.index + match[0].length;
}

const s = new MagicString(code);
s.appendRight(endIndexOfLastImport, ESMShim);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle cases with no import statements to prevent errors

If no import statements are found, endIndexOfLastImport remains -1, leading s.appendRight(-1, ESMShim) to insert the shim at the end of the string or potentially cause an error. To ensure the shim is inserted correctly when there are no import statements, consider checking for this case:

 if (endIndexOfLastImport !== -1) {
   s.appendRight(endIndexOfLastImport, ESMShim);
+} else {
+  // No imports found; insert shim at the beginning
+  s.prepend(ESMShim);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let endIndexOfLastImport = -1;
// Find the last import statement and its ending index
for (const match of code.matchAll(/^import\s.*';$/gm)) {
if (match.length === 0 || typeof match.index !== "number") {
continue;
}
endIndexOfLastImport = match.index + match[0].length;
}
const s = new MagicString(code);
s.appendRight(endIndexOfLastImport, ESMShim);
let endIndexOfLastImport = -1;
// Find the last import statement and its ending index
for (const match of code.matchAll(/^import\s.*';$/gm)) {
if (match.length === 0 || typeof match.index !== "number") {
continue;
}
endIndexOfLastImport = match.index + match[0].length;
}
const s = new MagicString(code);
if (endIndexOfLastImport !== -1) {
s.appendRight(endIndexOfLastImport, ESMShim);
} else {
// No imports found; insert shim at the beginning
s.prepend(ESMShim);
}

Copy link
Member

@jaipaljadeja jaipaljadeja left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So good! Thank you so much!!

@jaipaljadeja jaipaljadeja merged commit c5c284f into apibara:main Nov 4, 2024
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants