From 23871385d52a251601905c86883e938c029ab2b7 Mon Sep 17 00:00:00 2001 From: jaipaljadeja Date: Sat, 22 Feb 2025 16:45:03 +0530 Subject: [PATCH 1/5] indexer: fix startingBlock validation --- packages/indexer/src/indexer.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/indexer/src/indexer.ts b/packages/indexer/src/indexer.ts index 1f34928f..ff271343 100644 --- a/packages/indexer/src/indexer.ts +++ b/packages/indexer/src/indexer.ts @@ -225,9 +225,13 @@ export async function run( if (indexer.options.startingCursor) { startingCursor = indexer.options.startingCursor; } else if (indexer.options.startingBlock !== undefined) { - startingCursor = { - orderKey: indexer.options.startingBlock, - }; + if (indexer.options.startingBlock === 0n) { + startingCursor = undefined; + } else if (indexer.options.startingBlock > 0n) { + startingCursor = { + orderKey: indexer.options.startingBlock - 1n, + }; + } } // if factory mode we add a empty filter at the end of the filter array. From e581e4c708b27e2eeecfe509f346652396b68c73 Mon Sep 17 00:00:00 2001 From: jaipaljadeja Date: Sat, 22 Feb 2025 19:57:04 +0530 Subject: [PATCH 2/5] cli: fix noIndexer flag --- packages/cli/src/cli/commands/init.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/cli/src/cli/commands/init.ts b/packages/cli/src/cli/commands/init.ts index 7eb444d0..4b27383e 100644 --- a/packages/cli/src/cli/commands/init.ts +++ b/packages/cli/src/cli/commands/init.ts @@ -18,23 +18,19 @@ export default defineCommand({ default: "ts", alias: "l", }, - "no-create-indexer": { + noIndexer: { type: "boolean", description: "Do not create an indexer after initialization", default: false, }, }, async run({ args }) { - const { - dir: targetDir, - "no-create-indexer": noCreateIndexer, - language, - } = args; + const { dir: targetDir, noIndexer, language } = args; await initializeProject({ argTargetDir: targetDir, argLanguage: language, - argNoCreateIndexer: noCreateIndexer, + argNoCreateIndexer: noIndexer, }); }, }); From a19c786d99e3fdec3e63d3a4cc5145f37c28e348 Mon Sep 17 00:00:00 2001 From: jaipaljadeja Date: Sat, 22 Feb 2025 19:59:00 +0530 Subject: [PATCH 3/5] cli: check for indexer file existence in prompt --- packages/cli/src/create/add.ts | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/create/add.ts b/packages/cli/src/create/add.ts index cd64d8b4..8776f73e 100644 --- a/packages/cli/src/create/add.ts +++ b/packages/cli/src/create/add.ts @@ -1,3 +1,4 @@ +import path from "node:path"; import consola from "consola"; import prompts from "prompts"; import { cyan, red, reset } from "./colors"; @@ -18,6 +19,7 @@ import { import type { Chain, IndexerOptions, Network, Storage } from "./types"; import { cancelOperation, + checkFileExists, convertKebabToCamelCase, getApibaraConfigLanguage, getPackageManager, @@ -88,8 +90,19 @@ export async function addIndexer({ message: reset("Indexer ID:"), initial: argIndexerId ?? "my-indexer", validate: (id) => - validateIndexerId(id) || - "Invalid indexer ID cannot be empty and must be in kebab-case format", + validateIndexerId(id) + ? checkFileExists( + path.join( + process.cwd(), + "indexers", + `${id}.indexer.${language === "typescript" ? "ts" : "js"}`, + ), + ).then(({ exists }) => + exists + ? `Indexer ${cyan(`${id}.indexer.${language === "typescript" ? "ts" : "js"}`)} already exists` + : true, + ) + : "Invalid indexer ID, it cannot be empty and must be in kebab-case format", }, { type: argChain ? null : "select", @@ -195,13 +208,13 @@ export async function addIndexer({ packageManager: pkgManager.name, }; - updateApibaraConfigFile(options); + await updateApibaraConfigFile(options); consola.success( `Updated ${cyan("apibara.config." + (language === "typescript" ? "ts" : "js"))}`, ); - updatePackageJson(options); + await updatePackageJson(options); consola.success(`Updated ${cyan("package.json")}`); From 8ef6c7fb3c387d83e19df154856825de5acf6ef2 Mon Sep 17 00:00:00 2001 From: jaipaljadeja Date: Sat, 22 Feb 2025 19:59:42 +0530 Subject: [PATCH 4/5] cli: create indexers directory on init --- packages/cli/src/create/init.ts | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/packages/cli/src/create/init.ts b/packages/cli/src/create/init.ts index 0eb140a4..e398ffaa 100644 --- a/packages/cli/src/create/init.ts +++ b/packages/cli/src/create/init.ts @@ -13,6 +13,7 @@ import type { Language } from "./types"; import { cancelOperation, emptyDir, + formatFile, getLanguageFromAlias, getPackageManager, isEmpty, @@ -121,30 +122,40 @@ export async function initializeProject({ consola.info(`Initializing project in ${argTargetDir}\n\n`); // Generate package.json + const packageJsonPath = path.join(root, "package.json"); const packageJson = generatePackageJson(isTs); fs.writeFileSync( - path.join(root, "package.json"), + packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n", ); + await formatFile(packageJsonPath); consola.success("Created ", cyan("package.json")); // Generate tsconfig.json if TypeScript if (isTs) { + const tsConfigPath = path.join(root, "tsconfig.json"); const tsConfig = generateTsConfig(); - fs.writeFileSync( - path.join(root, "tsconfig.json"), - JSON.stringify(tsConfig, null, 2) + "\n", - ); + fs.writeFileSync(tsConfigPath, JSON.stringify(tsConfig, null, 2) + "\n"); + await formatFile(tsConfigPath); consola.success("Created ", cyan("tsconfig.json")); } + const apibaraConfigPath = path.join(root, `apibara.config.${configExt}`); // Generate apibara.config const apibaraConfig = generateApibaraConfig(isTs); - fs.writeFileSync( - path.join(root, `apibara.config.${configExt}`), - apibaraConfig, - ); - consola.success("Created ", cyan(`apibara.config.${configExt}`), "\n\n"); + fs.writeFileSync(apibaraConfigPath, apibaraConfig); + await formatFile(apibaraConfigPath); + consola.success("Created ", cyan(`apibara.config.${configExt}`)); + + // Create "indexers" directory if not exists + const indexersDir = path.join(root, "indexers"); + if (!fs.existsSync(indexersDir)) { + fs.mkdirSync(indexersDir, { recursive: true }); + consola.success(`Created ${cyan("indexers")} directory`); + } + + console.log("\n"); + consola.ready(green("Project initialized successfully")); console.log(); From fee62121d20c94c9321aa112075267168d0175c9 Mon Sep 17 00:00:00 2001 From: jaipaljadeja Date: Sat, 22 Feb 2025 20:02:42 +0530 Subject: [PATCH 5/5] cli: add prettier formatting for files --- ...-b2bba30d-fe14-4236-830e-49c35d5e973a.json | 7 +++ ...-f4a63aad-bcfe-435c-9522-12e7c8c95a4e.json | 7 +++ packages/cli/package.json | 1 + packages/cli/src/create/constants.ts | 18 +++--- packages/cli/src/create/templates.ts | 55 ++++++++++--------- packages/cli/src/create/utils.ts | 10 ++++ pnpm-lock.yaml | 53 ++++++++++++++++++ 7 files changed, 116 insertions(+), 35 deletions(-) create mode 100644 change/@apibara-indexer-b2bba30d-fe14-4236-830e-49c35d5e973a.json create mode 100644 change/apibara-f4a63aad-bcfe-435c-9522-12e7c8c95a4e.json diff --git a/change/@apibara-indexer-b2bba30d-fe14-4236-830e-49c35d5e973a.json b/change/@apibara-indexer-b2bba30d-fe14-4236-830e-49c35d5e973a.json new file mode 100644 index 00000000..5ad194d8 --- /dev/null +++ b/change/@apibara-indexer-b2bba30d-fe14-4236-830e-49c35d5e973a.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "indexer: fix startingBlock validation", + "packageName": "@apibara/indexer", + "email": "jadejajaipal5@gmail.com", + "dependentChangeType": "patch" +} diff --git a/change/apibara-f4a63aad-bcfe-435c-9522-12e7c8c95a4e.json b/change/apibara-f4a63aad-bcfe-435c-9522-12e7c8c95a4e.json new file mode 100644 index 00000000..8685e6f4 --- /dev/null +++ b/change/apibara-f4a63aad-bcfe-435c-9522-12e7c8c95a4e.json @@ -0,0 +1,7 @@ +{ + "type": "prerelease", + "comment": "cli: prettier formatting and noIndexer flag", + "packageName": "apibara", + "email": "jadejajaipal5@gmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/cli/package.json b/packages/cli/package.json index b7c56414..ff9079ba 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -109,6 +109,7 @@ "perfect-debounce": "^1.0.0", "picocolors": "^1.1.1", "pkg-types": "^1.1.3", + "prettier": "^3.5.2", "prompts": "^2.4.2", "rollup": "^4.18.1", "rollup-plugin-esbuild": "^6.1.1", diff --git a/packages/cli/src/create/constants.ts b/packages/cli/src/create/constants.ts index deff89ef..76ff5b08 100644 --- a/packages/cli/src/create/constants.ts +++ b/packages/cli/src/create/constants.ts @@ -66,17 +66,17 @@ export const storages: StorageDataType[] = [ export const packageVersions = { // Required Dependencies - apibara: "^2.1.0-beta.1", - "@apibara/indexer": "^2.1.0-beta.1", - "@apibara/protocol": "^2.1.0-beta.1", + apibara: "^2.1.0-beta.2", + "@apibara/indexer": "^2.1.0-beta.2", + "@apibara/protocol": "^2.1.0-beta.2", // Chain Dependencies - "@apibara/evm": "^2.1.0-beta.1", - "@apibara/beaconchain": "^2.1.0-beta.1", - "@apibara/starknet": "^2.1.0-beta.1", + "@apibara/evm": "^2.1.0-beta.2", + "@apibara/beaconchain": "^2.1.0-beta.2", + "@apibara/starknet": "^2.1.0-beta.2", // Storage Dependencies - "@apibara/plugin-drizzle": "^2.1.0-beta.1", - "@apibara/plugin-mongo": "^2.1.0-beta.1", - "@apibara/plugin-sqlite": "^2.1.0-beta.1", + "@apibara/plugin-drizzle": "^2.1.0-beta.2", + "@apibara/plugin-mongo": "^2.1.0-beta.2", + "@apibara/plugin-sqlite": "^2.1.0-beta.2", // Postgres Dependencies "@electric-sql/pglite": "^0.2.17", "drizzle-orm": "^0.37.0", diff --git a/packages/cli/src/create/templates.ts b/packages/cli/src/create/templates.ts index d9064fb0..4b0bd066 100644 --- a/packages/cli/src/create/templates.ts +++ b/packages/cli/src/create/templates.ts @@ -5,7 +5,7 @@ import { type ObjectLiteralExpression, Project, SyntaxKind } from "ts-morph"; import { cyan, green, magenta, yellow } from "./colors"; import { packageVersions } from "./constants"; import type { IndexerOptions } from "./types"; -import { checkFileExists, getDnaUrl } from "./utils"; +import { checkFileExists, formatFile, getDnaUrl } from "./utils"; export function generatePackageJson(isTypeScript: boolean) { return { @@ -78,19 +78,19 @@ export function generateIndexer({ chain, language, }: IndexerOptions) { - return `${ - chain === "ethereum" - ? `import { EvmStream } from "@apibara/evm";` - : chain === "beaconchain" - ? `import { BeaconChainStream } from "@apibara/beaconchain";` - : chain === "starknet" - ? `import { StarknetStream } from "@apibara/starknet";` - : "" - } -import { defineIndexer } from "@apibara/indexer"; + return `import { defineIndexer } from "@apibara/indexer"; +import { useLogger } from "@apibara/indexer/plugins"; ${storage === "postgres" ? `import { drizzleStorage } from "@apibara/plugin-drizzle";` : ""} +${ + chain === "ethereum" + ? `import { EvmStream } from "@apibara/evm";` + : chain === "beaconchain" + ? `import { BeaconChainStream } from "@apibara/beaconchain";` + : chain === "starknet" + ? `import { StarknetStream } from "@apibara/starknet";` + : "" +} ${language === "typescript" ? `import type { ApibaraRuntimeConfig } from "apibara/types";` : ""} -import { useLogger } from "@apibara/indexer/plugins"; ${ storage === "postgres" ? `import { getDrizzlePgDatabase } from "../lib/db";` @@ -169,17 +169,19 @@ export async function createIndexerFile(options: IndexerOptions) { fs.mkdirSync(path.dirname(indexerFilePath), { recursive: true }); fs.writeFileSync(indexerFilePath, indexerContent); + + await formatFile(indexerFilePath); } -export function updatePackageJson({ +export async function updatePackageJson({ cwd, chain, storage, language, }: IndexerOptions) { - const packageJson = JSON.parse( - fs.readFileSync(path.join(cwd, "package.json"), "utf8"), - ); + const packageJsonPath = path.join(cwd, "package.json"); + + const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8")); if (chain === "ethereum") { packageJson.dependencies["@apibara/evm"] = packageVersions["@apibara/evm"]; @@ -212,13 +214,12 @@ export function updatePackageJson({ } } - fs.writeFileSync( - path.join(cwd, "package.json"), - JSON.stringify(packageJson, null, 2), - ); + fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2)); + + await formatFile(packageJsonPath); } -export function updateApibaraConfigFile({ +export async function updateApibaraConfigFile({ indexerId, cwd, chain, @@ -279,11 +280,7 @@ export function updateApibaraConfigFile({ // Save the changes sourceFile.saveSync(); - sourceFile.formatText({ - tabSize: 2, - insertSpaceAfterOpeningAndBeforeClosingEmptyBraces: true, - insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true, - }); + await formatFile(pathToConfig); } export async function createDrizzleStorageFiles(options: IndexerOptions) { @@ -325,6 +322,8 @@ export default { fs.writeFileSync(drizzleConfigPath, drizzleConfigContent); + await formatFile(drizzleConfigPath); + consola.success(`Created ${cyan(drizzleConfigFileName)}`); } @@ -365,6 +364,8 @@ export {}; fs.mkdirSync(path.dirname(schemaPath), { recursive: true }); fs.writeFileSync(schemaPath, schemaContent); + await formatFile(schemaPath); + consola.success(`Created ${cyan("lib/schema.ts")}`); } @@ -420,6 +421,8 @@ export function getDrizzlePgDatabase(connectionString${language === "typescript" fs.mkdirSync(path.dirname(dbPath), { recursive: true }); fs.writeFileSync(dbPath, dbContent); + await formatFile(dbPath); + consola.success(`Created ${cyan(`lib/${dbFileName}`)}`); } diff --git a/packages/cli/src/create/utils.ts b/packages/cli/src/create/utils.ts index 4578f974..f9fbcd45 100644 --- a/packages/cli/src/create/utils.ts +++ b/packages/cli/src/create/utils.ts @@ -1,5 +1,6 @@ import fs from "node:fs"; import path, { basename } from "node:path"; +import * as prettier from "prettier"; import prompts from "prompts"; import { blue, cyan, red, yellow } from "./colors"; import { dnaUrls, networks } from "./constants"; @@ -410,3 +411,12 @@ function pkgFromUserAgent(userAgent: string | undefined): PkgInfo | undefined { version: pkgSpecArr[1], }; } + +export async function formatFile(path: string) { + const file = fs.readFileSync(path, "utf8"); + const formatted = await prettier.format(file, { + filepath: path, + tabWidth: 2, + }); + fs.writeFileSync(path, formatted); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c5e49c66..ba087d93 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -188,6 +188,49 @@ importers: specifier: ^5.6.2 version: 5.6.2 + examples/temp: + dependencies: + '@apibara/indexer': + specifier: workspace:* + version: link:../../packages/indexer + '@apibara/plugin-drizzle': + specifier: workspace:* + version: link:../../packages/plugin-drizzle + '@apibara/protocol': + specifier: workspace:* + version: link:../../packages/protocol + '@apibara/starknet': + specifier: workspace:* + version: link:../../packages/starknet + '@electric-sql/pglite': + specifier: ^0.2.17 + version: 0.2.17 + apibara: + specifier: workspace:* + version: link:../../packages/cli + drizzle-kit: + specifier: ^0.29.0 + version: 0.29.1 + drizzle-orm: + specifier: ^0.37.0 + version: 0.37.0(@electric-sql/pglite@0.2.17)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.11)(@types/pg@8.11.10)(better-sqlite3@11.5.0)(pg@8.13.1)(postgres@3.4.4) + pg: + specifier: ^8.13.1 + version: 8.13.1 + devDependencies: + '@rollup/plugin-typescript': + specifier: ^11.1.6 + version: 11.1.6(rollup@4.34.8)(tslib@2.6.3)(typescript@5.6.2) + '@types/node': + specifier: ^20.5.2 + version: 20.14.0 + '@types/pg': + specifier: ^8.11.10 + version: 8.11.10 + typescript: + specifier: ^5.6.2 + version: 5.6.2 + packages/beaconchain: dependencies: '@apibara/evm': @@ -299,6 +342,9 @@ importers: pkg-types: specifier: ^1.1.3 version: 1.1.3 + prettier: + specifier: ^3.5.2 + version: 3.5.2 prompts: specifier: ^2.4.2 version: 2.4.2 @@ -3347,6 +3393,11 @@ packages: engines: {node: '>=10'} hasBin: true + prettier@3.5.2: + resolution: {integrity: sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg==} + engines: {node: '>=14'} + hasBin: true + pretty-bytes@6.1.1: resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} engines: {node: ^14.13.1 || >=16.0.0} @@ -6402,6 +6453,8 @@ snapshots: tar-fs: 2.1.1 tunnel-agent: 0.6.0 + prettier@3.5.2: {} + pretty-bytes@6.1.1: {} pretty-format@29.7.0: