create-eclesia-indexer 1.0.11 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -23,11 +23,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
 
24
24
  //#endregion
25
25
  let node_fs = require("node:fs");
26
- node_fs = __toESM(node_fs);
27
26
  let node_path = require("node:path");
28
27
  node_path = __toESM(node_path);
29
28
  let node_url = require("node:url");
30
- node_url = __toESM(node_url);
31
29
  let picocolors = require("picocolors");
32
30
  picocolors = __toESM(picocolors);
33
31
  let enquirer = require("enquirer");
@@ -38,8 +36,7 @@ fs_extra = __toESM(fs_extra);
38
36
  //#region src/create-indexer.ts
39
37
  const { prompt } = enquirer.default;
40
38
  const { ensureDirSync, copySync, writeFileSync, readFileSync } = fs_extra.default;
41
- const __filename$2 = (0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href);
42
- const __dirname$1 = (0, node_path.dirname)(__filename$2);
39
+ const __dirname$1 = (0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
43
40
  const availableModules = [
44
41
  {
45
42
  name: "Auth",
@@ -181,7 +178,7 @@ async function gatherProjectInfo(initialProjectName) {
181
178
  }]);
182
179
  answers1.genesisPath = genesisPathQuestion.genesisPath ? node_path.default.resolve(genesisPathQuestion.genesisPath) : null;
183
180
  } else answers1.genesisPath = null;
184
- const questions2 = [
181
+ const answers2 = await prompt([
185
182
  {
186
183
  type: "multiselect",
187
184
  name: "modules",
@@ -221,8 +218,7 @@ async function gatherProjectInfo(initialProjectName) {
221
218
  ],
222
219
  initial: 4
223
220
  }
224
- ];
225
- const answers2 = await prompt(questions2);
221
+ ]);
226
222
  return {
227
223
  ...answers1,
228
224
  ...answers2
@@ -259,6 +255,8 @@ async function copyTemplateFiles(config, targetDir) {
259
255
  }
260
256
  async function processTemplates(config, targetDir) {
261
257
  let polling = false;
258
+ config.enablePrometheus = false;
259
+ config.prometheusPort = 9090;
262
260
  const url = new URL(config.rpcEndpoint);
263
261
  if (url.protocol === "http:" || url.protocol === "https:") polling = true;
264
262
  const templateVars = {
@@ -275,6 +273,8 @@ async function processTemplates(config, targetDir) {
275
273
  MINIMAL: config.minimal ? "true" : "false",
276
274
  START_HEIGHT: config.startHeight.toString(),
277
275
  CHAIN_PREFIX: config.chainPrefix,
276
+ ENABLE_PROMETHEUS: config.enablePrometheus ? "true" : "false",
277
+ PROMETHEUS_PORT: config.prometheusPort.toString(),
278
278
  MODULES_IMPORT: generateModulesImport(config),
279
279
  PACKAGE_MANAGER: config.packageManager,
280
280
  MODULES_INSTANTIATION: generateModulesInstantiation(config),
@@ -352,8 +352,7 @@ async function buildProject(config, targetDir) {
352
352
 
353
353
  //#endregion
354
354
  //#region src/index.ts
355
- const __filename$1 = (0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href);
356
- (0, node_path.dirname)(__filename$1);
355
+ (0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
357
356
  async function main() {
358
357
  console.log();
359
358
  console.log(picocolors.default.cyan("🚀 Welcome to create-eclesia-indexer!"));
package/dist/index.js CHANGED
@@ -9,8 +9,7 @@ import fse from "fs-extra";
9
9
  //#region src/create-indexer.ts
10
10
  const { prompt } = enquirer;
11
11
  const { ensureDirSync, copySync, writeFileSync, readFileSync } = fse;
12
- const __filename$1 = fileURLToPath(import.meta.url);
13
- const __dirname = dirname(__filename$1);
12
+ const __dirname = dirname(fileURLToPath(import.meta.url));
14
13
  const availableModules = [
15
14
  {
16
15
  name: "Auth",
@@ -152,7 +151,7 @@ async function gatherProjectInfo(initialProjectName) {
152
151
  }]);
153
152
  answers1.genesisPath = genesisPathQuestion.genesisPath ? path.resolve(genesisPathQuestion.genesisPath) : null;
154
153
  } else answers1.genesisPath = null;
155
- const questions2 = [
154
+ const answers2 = await prompt([
156
155
  {
157
156
  type: "multiselect",
158
157
  name: "modules",
@@ -192,8 +191,7 @@ async function gatherProjectInfo(initialProjectName) {
192
191
  ],
193
192
  initial: 4
194
193
  }
195
- ];
196
- const answers2 = await prompt(questions2);
194
+ ]);
197
195
  return {
198
196
  ...answers1,
199
197
  ...answers2
@@ -230,6 +228,8 @@ async function copyTemplateFiles(config, targetDir) {
230
228
  }
231
229
  async function processTemplates(config, targetDir) {
232
230
  let polling = false;
231
+ config.enablePrometheus = false;
232
+ config.prometheusPort = 9090;
233
233
  const url = new URL(config.rpcEndpoint);
234
234
  if (url.protocol === "http:" || url.protocol === "https:") polling = true;
235
235
  const templateVars = {
@@ -246,6 +246,8 @@ async function processTemplates(config, targetDir) {
246
246
  MINIMAL: config.minimal ? "true" : "false",
247
247
  START_HEIGHT: config.startHeight.toString(),
248
248
  CHAIN_PREFIX: config.chainPrefix,
249
+ ENABLE_PROMETHEUS: config.enablePrometheus ? "true" : "false",
250
+ PROMETHEUS_PORT: config.prometheusPort.toString(),
249
251
  MODULES_IMPORT: generateModulesImport(config),
250
252
  PACKAGE_MANAGER: config.packageManager,
251
253
  MODULES_INSTANTIATION: generateModulesInstantiation(config),
@@ -323,8 +325,7 @@ async function buildProject(config, targetDir) {
323
325
 
324
326
  //#endregion
325
327
  //#region src/index.ts
326
- const __filename = fileURLToPath(import.meta.url);
327
- dirname(__filename);
328
+ dirname(fileURLToPath(import.meta.url));
328
329
  async function main() {
329
330
  console.log();
330
331
  console.log(colors.cyan("🚀 Welcome to create-eclesia-indexer!"));
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["__filename","imports: string[]","instantiations: string[]","moduleNames: string[]"],"sources":["../src/create-indexer.ts","../src/index.ts"],"sourcesContent":["import enquirer from \"enquirer\";\nconst {\n prompt,\n} = enquirer;\nimport fse from \"fs-extra\";\nconst {\n ensureDirSync, copySync, writeFileSync, readFileSync,\n} = fse;\nimport path, {\n resolve,\n} from \"node:path\";\nimport {\n dirname,\n} from \"node:path\";\nimport {\n fileURLToPath,\n} from \"node:url\";\n\nimport colors from \"picocolors\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\ninterface ProjectConfig {\n projectName: string\n chainName: string\n description: string\n rpcEndpoint: string\n chainPrefix: string\n minimal: boolean\n startHeight: number\n queueSize: number\n logLevel: string\n processGenesis: boolean\n genesisPath: string | null\n modules: string[]\n packageManager: \"npm\" | \"yarn\" | \"pnpm\"\n}\n\nconst availableModules = [\n {\n name: \"Auth\",\n value: \"auth\",\n hint: \"Account and authentication data\",\n },\n {\n name: \"Bank\",\n value: \"bank\",\n hint: \"Token transfers and balances\",\n },\n {\n name: \"Staking\",\n value: \"staking\",\n hint: \"Validator and delegation data\",\n },\n];\n\nconst minimalAvailableModules = [\n {\n name: \"Auth\",\n value: \"auth\",\n hint: \"Account and authentication data\",\n },\n {\n name: \"Bank\",\n value: \"bank\",\n hint: \"Token transfers and balances\",\n },\n];\n\nexport async function createIndexer(initialProjectName?: string): Promise<void> {\n const config = await gatherProjectInfo(initialProjectName);\n const targetDir = resolve(process.cwd(), config.projectName);\n\n console.log(colors.blue(\"📁 Creating project directory...\"));\n ensureDirSync(targetDir);\n\n console.log(colors.blue(\"📋 Copying files...\"));\n await copyTemplateFiles(config, targetDir);\n\n console.log(colors.blue(\"🔧 Processing template variables...\"));\n await processTemplates(config, targetDir);\n\n console.log(colors.blue(\"📦 Installing dependencies...\"));\n await installDependencies(config, targetDir);\n\n console.log(colors.blue(\"📦 Building...\"));\n await buildProject(config, targetDir);\n\n console.log();\n console.log(colors.green(\"🎉 Your indexer is ready!\"));\n console.log();\n console.log(\"Next steps:\");\n console.log(colors.cyan(` cd ${config.projectName}`));\n console.log(colors.cyan(` ${config.packageManager} local-dev:start # To run a self-contained local development environment with Postgres`));\n console.log();\n console.log(\"If you want to run the indexer against an external Postgres database instead of the local development environment, set the database connection string in the .env file.\");\n console.log();\n console.log(colors.cyan(` ${config.packageManager} start # To run the indexer`));\n console.log();\n console.log(\"Happy indexing!\");\n console.log();\n}\n\nasync function gatherProjectInfo(initialProjectName?: string): Promise<ProjectConfig> {\n const questions1 = [\n {\n type: \"input\",\n name: \"projectName\",\n message: \"Project name:\",\n initial: initialProjectName || \"my-indexer\",\n skip: !!initialProjectName,\n },\n {\n type: \"input\",\n name: \"chainName\",\n message: \"Chain name:\",\n initial: \"cosmos-hub\",\n },\n {\n type: \"input\",\n name: \"chainPrefix\",\n message: \"Chain address prefix:\",\n initial: \"cosmos\",\n },\n {\n type: \"input\",\n name: \"description\",\n message: \"Description:\",\n initial: \"A custom Cosmos SDK chain indexer\",\n },\n {\n type: \"input\",\n name: \"rpcEndpoint\",\n message: \"RPC endpoint:\",\n initial: \"https://rpc.cosmos.network\",\n validate: (value: string) => {\n try {\n const url = new URL(value);\n if (url.protocol === \"http:\" || url.protocol === \"https:\" || url.protocol === \"ws:\" || url.protocol === \"wss:\") {\n return true;\n }\n return \"Please enter a valid HTTP/HTTPS/WS/WSS URL.\";\n }\n catch (err) {\n return \"Please enter a valid URL: \" + err;\n }\n },\n },\n {\n type: \"toggle\",\n name: \"minimal\",\n message: \"Minimal block indexing? (Only stores heights)\",\n enabled: \"Yes\",\n disabled: \"No\",\n initial: false,\n },\n {\n type: \"number\",\n name: \"queueSize\",\n message: \"Number of blocks to keep prefetched (queue size):\",\n initial: 200,\n },\n {\n type: \"number\",\n name: \"startHeight\",\n message: \"Height to start indexing from (>1 not compatible with standard modules):\",\n initial: 1,\n },\n ];\n const answers1 = await prompt(questions1) as ProjectConfig;\n if (answers1.startHeight == 1) {\n const genesisQuestion = await prompt([\n {\n type: \"toggle\",\n name: \"processGenesis\",\n message: \"Process genesis file?\",\n enabled: \"Yes\",\n disabled: \"No\",\n },\n ]) as ProjectConfig;\n answers1.processGenesis = genesisQuestion.processGenesis;\n }\n else {\n answers1.processGenesis = false;\n }\n if (answers1.processGenesis) {\n const genesisPathQuestion = await prompt([\n {\n type: \"input\",\n name: \"genesisPath\",\n message: \"Path to genesis file:\",\n initial: \"./genesis.json\",\n validate: (value: string) => {\n try {\n fse.accessSync(value, fse.constants.R_OK);\n return true;\n }\n catch (err) {\n return \"File not found or not readable. Please enter a valid path: \" + err;\n }\n },\n },\n ]) as ProjectConfig;\n answers1.genesisPath = genesisPathQuestion.genesisPath ? path.resolve(genesisPathQuestion.genesisPath) : null;\n }\n else {\n answers1.genesisPath = null;\n }\n const questions2 = [\n {\n type: \"multiselect\",\n name: \"modules\",\n message: \"Select modules to include:\",\n choices: answers1.startHeight == 1 && !answers1.minimal && answers1.processGenesis ? availableModules : minimalAvailableModules,\n initial: answers1.startHeight == 1 && !answers1.minimal && answers1.processGenesis ? [0, 1, 2] : [0, 1],\n },\n {\n type: \"select\",\n name: \"packageManager\",\n message: \"Package manager:\",\n choices: [\n {\n name: \"pnpm\",\n hint: \"recommended\",\n },\n {\n name: \"npm\",\n },\n {\n name: \"yarn\",\n },\n ],\n initial: 0,\n },\n {\n type: \"select\",\n name: \"logLevel\",\n message: \"Log level:\",\n choices: [\"error\", \"warn\", \"info\", \"verbose\", \"debug\", \"silly\"],\n initial: 4,\n },\n ];\n const answers2 = await prompt(questions2) as ProjectConfig;\n return {\n ...answers1,\n ...answers2,\n };\n}\n\nasync function copyTemplateFiles(config: ProjectConfig, targetDir: string): Promise<void> {\n const templatesDir = resolve(__dirname, \"..\", \"templates\", \"basic\");\n if (config.genesisPath) {\n console.log(colors.blue(\"📋 Copying genesis file...\"));\n copySync(config.genesisPath, targetDir + \"/genesis.json\");\n }\n\n console.log(colors.blue(\"📋 Copying template files...\"));\n copySync(templatesDir, targetDir, {\n filter: (src) => {\n if (src.includes(\".template\")) {\n return false;\n }\n if (config.packageManager !== \"pnpm\" && src.includes(\"pnpm-workspace\")) {\n return false;\n }\n if (src.includes(\"Dockerfile\")) {\n return false;\n }\n return true;\n },\n });\n copySync(resolve(templatesDir, \"Dockerfile.\" + config.packageManager), targetDir + \"/Dockerfile\");\n // Copy template files\n const templateFiles = [\"package.json.template\", \"src/index.ts.template\", \"tsconfig.json.template\", \"docker-compose.yml.template\", \"README.md.template\", \".env.template\"];\n\n templateFiles.forEach((templateFile) => {\n const srcPath = resolve(templatesDir, templateFile);\n const destPath = resolve(targetDir, templateFile.replace(\".template\", \"\"));\n\n try {\n copySync(srcPath, destPath);\n }\n catch (_error) {\n // Template file might not exist, that's okay\n }\n });\n}\n\nasync function processTemplates(config: ProjectConfig, targetDir: string): Promise<void> {\n let polling = false;\n const url = new URL(config.rpcEndpoint);\n if (url.protocol === \"http:\" || url.protocol === \"https:\") {\n polling = true;\n }\n const templateVars = {\n PROJECT_NAME: config.projectName,\n CHAIN_NAME: config.chainName,\n DESCRIPTION: config.description,\n RPC_ENDPOINT: config.rpcEndpoint,\n PG_CONNECTION_STRING: \"postgres://postgres:password@postgres:5432/indexer\",\n LOG_LEVEL: config.logLevel,\n QUEUE_SIZE: config.queueSize.toString(),\n USE_POLLING: polling ? \"true\" : \"false\",\n PROCESS_GENESIS: config.processGenesis + \"\",\n GENESIS_PATH: path.resolve(targetDir, \"genesis.json\"),\n MINIMAL: config.minimal ? \"true\" : \"false\",\n START_HEIGHT: config.startHeight.toString(),\n CHAIN_PREFIX: config.chainPrefix,\n MODULES_IMPORT: generateModulesImport(config),\n PACKAGE_MANAGER: config.packageManager,\n MODULES_INSTANTIATION: generateModulesInstantiation(config),\n MODULES_ARRAY: generateModulesArray(config),\n };\n\n const filesToProcess = [\"package.json\", \"src/index.ts\", \"tsconfig.json\", \"docker-compose.yml\", \"README.md\", \"pnpm-workspace.yaml\", \".env\"];\n\n filesToProcess.forEach((file) => {\n const filePath = resolve(targetDir, file);\n\n try {\n let content = readFileSync(filePath, \"utf-8\");\n\n Object.entries(templateVars).forEach(([key, value]) => {\n const regex = new RegExp(`{{${key}}}`, \"g\");\n content = content.replace(regex, value);\n });\n\n writeFileSync(filePath, content);\n }\n catch (_error) {\n // File might not exist, that's okay\n }\n });\n}\n\nfunction generateModulesImport(config: ProjectConfig): string {\n const imports: string[] = [];\n\n imports.push(\" Blocks\");\n if (config.modules.includes(\"Auth\")) {\n imports.push(\" AuthModule\");\n }\n if (config.modules.includes(\"Bank\") && config.startHeight === 1 && config.processGenesis) {\n imports.push(\" BankModule\");\n }\n if (config.modules.includes(\"Staking\") && !config.minimal) {\n imports.push(\" StakingModule\");\n }\n\n return `import {\\n${imports.join(\",\")}\\n} from \"@eclesia/core-modules-pg\";\\n`;\n}\n\nfunction generateModulesInstantiation(config: ProjectConfig): string {\n const instantiations: string[] = [];\n\n if (config.minimal) {\n instantiations.push(\"const blocksModule = new Blocks.MinimalBlocksModule(registry);\");\n }\n else {\n instantiations.push(\"const blocksModule = new Blocks.FullBlocksModule(registry);\");\n }\n if (config.modules.includes(\"Auth\")) {\n instantiations.push(\"const authModule = new AuthModule(registry);\");\n }\n if (config.modules.includes(\"Bank\") && config.startHeight === 1 && config.processGenesis) {\n instantiations.push(\"const bankModule = new BankModule(registry);\");\n }\n if (config.modules.includes(\"Staking\") && !config.minimal) {\n instantiations.push(\"const stakingModule = new StakingModule(registry);\");\n }\n\n return instantiations.join(\"\\n\");\n}\n\nfunction generateModulesArray(config: ProjectConfig): string {\n const moduleNames: string[] = [];\n\n moduleNames.push(\"blocksModule\");\n\n if (config.modules.includes(\"Auth\")) {\n moduleNames.push(\"authModule\");\n }\n if (config.modules.includes(\"Bank\") && config.startHeight === 1 && config.processGenesis) {\n moduleNames.push(\"bankModule\");\n }\n if (config.modules.includes(\"Staking\") && !config.minimal) {\n moduleNames.push(\"stakingModule\");\n }\n return `[${moduleNames.filter(m => !m.includes(\"//\")).join(\", \")}]`;\n}\n\nasync function installDependencies(config: ProjectConfig, targetDir: string): Promise<void> {\n const {\n spawn,\n } = await import(\"node:child_process\");\n\n return new Promise((resolve, reject) => {\n const child = spawn(config.packageManager, [\"install\"], {\n cwd: targetDir,\n stdio: \"inherit\",\n });\n\n child.on(\"close\", (code) => {\n if (code !== 0) {\n reject(new Error(`Package installation failed with code ${code}`));\n }\n else {\n resolve();\n }\n });\n });\n}\n\nasync function buildProject(config: ProjectConfig, targetDir: string): Promise<void> {\n const {\n spawn,\n } = await import(\"node:child_process\");\n\n return new Promise((resolve, reject) => {\n const child = spawn(config.packageManager, [\"run\", \"build\"], {\n cwd: targetDir,\n stdio: \"inherit\",\n });\n\n child.on(\"close\", (code) => {\n if (code !== 0) {\n reject(new Error(`Package installation failed with code ${code}`));\n }\n else {\n resolve();\n }\n });\n });\n}\n","import {\n existsSync,\n} from \"node:fs\";\nimport {\n dirname, resolve,\n} from \"node:path\";\nimport {\n fileURLToPath,\n} from \"node:url\";\n\nimport colors from \"picocolors\";\n\nimport {\n createIndexer,\n} from \"./create-indexer.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nasync function main() {\n console.log();\n console.log(colors.cyan(\"🚀 Welcome to create-eclesia-indexer!\"));\n console.log(colors.gray(\"Scaffolding a new Cosmos SDK chain indexer...\"));\n console.log();\n\n try {\n const projectName = process.argv[2];\n\n if (projectName && existsSync(resolve(process.cwd(), projectName))) {\n console.log(colors.red(`❌ Directory '${projectName}' already exists.`));\n process.exit(1);\n }\n\n await createIndexer(projectName);\n\n console.log();\n console.log(colors.green(\"✅ Indexer created successfully!\"));\n console.log();\n }\n catch (error) {\n console.error(colors.red(\"❌ Error creating indexer:\"), error);\n process.exit(1);\n }\n}\n\nmain().catch((error) => {\n console.error(error);\n process.exit(1);\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["imports: string[]","instantiations: string[]","moduleNames: string[]"],"sources":["../src/create-indexer.ts","../src/index.ts"],"sourcesContent":["import enquirer from \"enquirer\";\nconst {\n prompt,\n} = enquirer;\nimport fse from \"fs-extra\";\nconst {\n ensureDirSync, copySync, writeFileSync, readFileSync,\n} = fse;\nimport path, {\n resolve,\n} from \"node:path\";\nimport {\n dirname,\n} from \"node:path\";\nimport {\n fileURLToPath,\n} from \"node:url\";\n\nimport colors from \"picocolors\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\ninterface ProjectConfig {\n projectName: string\n chainName: string\n description: string\n rpcEndpoint: string\n chainPrefix: string\n minimal: boolean\n startHeight: number\n queueSize: number\n logLevel: string\n processGenesis: boolean\n genesisPath: string | null\n enablePrometheus: boolean\n prometheusPort: number\n modules: string[]\n packageManager: \"npm\" | \"yarn\" | \"pnpm\"\n}\n\nconst availableModules = [\n {\n name: \"Auth\",\n value: \"auth\",\n hint: \"Account and authentication data\",\n },\n {\n name: \"Bank\",\n value: \"bank\",\n hint: \"Token transfers and balances\",\n },\n {\n name: \"Staking\",\n value: \"staking\",\n hint: \"Validator and delegation data\",\n },\n];\n\nconst minimalAvailableModules = [\n {\n name: \"Auth\",\n value: \"auth\",\n hint: \"Account and authentication data\",\n },\n {\n name: \"Bank\",\n value: \"bank\",\n hint: \"Token transfers and balances\",\n },\n];\n\nexport async function createIndexer(initialProjectName?: string): Promise<void> {\n const config = await gatherProjectInfo(initialProjectName);\n const targetDir = resolve(process.cwd(), config.projectName);\n\n console.log(colors.blue(\"📁 Creating project directory...\"));\n ensureDirSync(targetDir);\n\n console.log(colors.blue(\"📋 Copying files...\"));\n await copyTemplateFiles(config, targetDir);\n\n console.log(colors.blue(\"🔧 Processing template variables...\"));\n await processTemplates(config, targetDir);\n\n console.log(colors.blue(\"📦 Installing dependencies...\"));\n await installDependencies(config, targetDir);\n\n console.log(colors.blue(\"📦 Building...\"));\n await buildProject(config, targetDir);\n\n console.log();\n console.log(colors.green(\"🎉 Your indexer is ready!\"));\n console.log();\n console.log(\"Next steps:\");\n console.log(colors.cyan(` cd ${config.projectName}`));\n console.log(colors.cyan(` ${config.packageManager} local-dev:start # To run a self-contained local development environment with Postgres`));\n console.log();\n console.log(\"If you want to run the indexer against an external Postgres database instead of the local development environment, set the database connection string in the .env file.\");\n console.log();\n console.log(colors.cyan(` ${config.packageManager} start # To run the indexer`));\n console.log();\n console.log(\"Happy indexing!\");\n console.log();\n}\n\nasync function gatherProjectInfo(initialProjectName?: string): Promise<ProjectConfig> {\n const questions1 = [\n {\n type: \"input\",\n name: \"projectName\",\n message: \"Project name:\",\n initial: initialProjectName || \"my-indexer\",\n skip: !!initialProjectName,\n },\n {\n type: \"input\",\n name: \"chainName\",\n message: \"Chain name:\",\n initial: \"cosmos-hub\",\n },\n {\n type: \"input\",\n name: \"chainPrefix\",\n message: \"Chain address prefix:\",\n initial: \"cosmos\",\n },\n {\n type: \"input\",\n name: \"description\",\n message: \"Description:\",\n initial: \"A custom Cosmos SDK chain indexer\",\n },\n {\n type: \"input\",\n name: \"rpcEndpoint\",\n message: \"RPC endpoint:\",\n initial: \"https://rpc.cosmos.network\",\n validate: (value: string) => {\n try {\n const url = new URL(value);\n if (url.protocol === \"http:\" || url.protocol === \"https:\" || url.protocol === \"ws:\" || url.protocol === \"wss:\") {\n return true;\n }\n return \"Please enter a valid HTTP/HTTPS/WS/WSS URL.\";\n }\n catch (err) {\n return \"Please enter a valid URL: \" + err;\n }\n },\n },\n {\n type: \"toggle\",\n name: \"minimal\",\n message: \"Minimal block indexing? (Only stores heights)\",\n enabled: \"Yes\",\n disabled: \"No\",\n initial: false,\n },\n {\n type: \"number\",\n name: \"queueSize\",\n message: \"Number of blocks to keep prefetched (queue size):\",\n initial: 200,\n },\n {\n type: \"number\",\n name: \"startHeight\",\n message: \"Height to start indexing from (>1 not compatible with standard modules):\",\n initial: 1,\n },\n ];\n const answers1 = await prompt(questions1) as ProjectConfig;\n if (answers1.startHeight == 1) {\n const genesisQuestion = await prompt([\n {\n type: \"toggle\",\n name: \"processGenesis\",\n message: \"Process genesis file?\",\n enabled: \"Yes\",\n disabled: \"No\",\n },\n ]) as ProjectConfig;\n answers1.processGenesis = genesisQuestion.processGenesis;\n }\n else {\n answers1.processGenesis = false;\n }\n if (answers1.processGenesis) {\n const genesisPathQuestion = await prompt([\n {\n type: \"input\",\n name: \"genesisPath\",\n message: \"Path to genesis file:\",\n initial: \"./genesis.json\",\n validate: (value: string) => {\n try {\n fse.accessSync(value, fse.constants.R_OK);\n return true;\n }\n catch (err) {\n return \"File not found or not readable. Please enter a valid path: \" + err;\n }\n },\n },\n ]) as ProjectConfig;\n answers1.genesisPath = genesisPathQuestion.genesisPath ? path.resolve(genesisPathQuestion.genesisPath) : null;\n }\n else {\n answers1.genesisPath = null;\n }\n const questions2 = [\n {\n type: \"multiselect\",\n name: \"modules\",\n message: \"Select modules to include:\",\n choices: answers1.startHeight == 1 && !answers1.minimal && answers1.processGenesis ? availableModules : minimalAvailableModules,\n initial: answers1.startHeight == 1 && !answers1.minimal && answers1.processGenesis ? [0, 1, 2] : [0, 1],\n },\n {\n type: \"select\",\n name: \"packageManager\",\n message: \"Package manager:\",\n choices: [\n {\n name: \"pnpm\",\n hint: \"recommended\",\n },\n {\n name: \"npm\",\n },\n {\n name: \"yarn\",\n },\n ],\n initial: 0,\n },\n {\n type: \"select\",\n name: \"logLevel\",\n message: \"Log level:\",\n choices: [\"error\", \"warn\", \"info\", \"verbose\", \"debug\", \"silly\"],\n initial: 4,\n },\n ];\n const answers2 = await prompt(questions2) as ProjectConfig;\n return {\n ...answers1,\n ...answers2,\n };\n}\n\nasync function copyTemplateFiles(config: ProjectConfig, targetDir: string): Promise<void> {\n const templatesDir = resolve(__dirname, \"..\", \"templates\", \"basic\");\n if (config.genesisPath) {\n console.log(colors.blue(\"📋 Copying genesis file...\"));\n copySync(config.genesisPath, targetDir + \"/genesis.json\");\n }\n\n console.log(colors.blue(\"📋 Copying template files...\"));\n copySync(templatesDir, targetDir, {\n filter: (src) => {\n if (src.includes(\".template\")) {\n return false;\n }\n if (config.packageManager !== \"pnpm\" && src.includes(\"pnpm-workspace\")) {\n return false;\n }\n if (src.includes(\"Dockerfile\")) {\n return false;\n }\n return true;\n },\n });\n copySync(resolve(templatesDir, \"Dockerfile.\" + config.packageManager), targetDir + \"/Dockerfile\");\n // Copy template files\n const templateFiles = [\"package.json.template\", \"src/index.ts.template\", \"tsconfig.json.template\", \"docker-compose.yml.template\", \"README.md.template\", \".env.template\"];\n\n templateFiles.forEach((templateFile) => {\n const srcPath = resolve(templatesDir, templateFile);\n const destPath = resolve(targetDir, templateFile.replace(\".template\", \"\"));\n\n try {\n copySync(srcPath, destPath);\n }\n catch (_error) {\n // Template file might not exist, that's okay\n }\n });\n}\n\nasync function processTemplates(config: ProjectConfig, targetDir: string): Promise<void> {\n let polling = false;\n config.enablePrometheus = false;\n config.prometheusPort = 9090;\n const url = new URL(config.rpcEndpoint);\n if (url.protocol === \"http:\" || url.protocol === \"https:\") {\n polling = true;\n }\n const templateVars = {\n PROJECT_NAME: config.projectName,\n CHAIN_NAME: config.chainName,\n DESCRIPTION: config.description,\n RPC_ENDPOINT: config.rpcEndpoint,\n PG_CONNECTION_STRING: \"postgres://postgres:password@postgres:5432/indexer\",\n LOG_LEVEL: config.logLevel,\n QUEUE_SIZE: config.queueSize.toString(),\n USE_POLLING: polling ? \"true\" : \"false\",\n PROCESS_GENESIS: config.processGenesis + \"\",\n GENESIS_PATH: path.resolve(targetDir, \"genesis.json\"),\n MINIMAL: config.minimal ? \"true\" : \"false\",\n START_HEIGHT: config.startHeight.toString(),\n CHAIN_PREFIX: config.chainPrefix,\n ENABLE_PROMETHEUS: config.enablePrometheus ? \"true\" : \"false\",\n PROMETHEUS_PORT: config.prometheusPort.toString(),\n MODULES_IMPORT: generateModulesImport(config),\n PACKAGE_MANAGER: config.packageManager,\n MODULES_INSTANTIATION: generateModulesInstantiation(config),\n MODULES_ARRAY: generateModulesArray(config),\n };\n\n const filesToProcess = [\"package.json\", \"src/index.ts\", \"tsconfig.json\", \"docker-compose.yml\", \"README.md\", \"pnpm-workspace.yaml\", \".env\"];\n\n filesToProcess.forEach((file) => {\n const filePath = resolve(targetDir, file);\n\n try {\n let content = readFileSync(filePath, \"utf-8\");\n\n Object.entries(templateVars).forEach(([key, value]) => {\n const regex = new RegExp(`{{${key}}}`, \"g\");\n content = content.replace(regex, value);\n });\n\n writeFileSync(filePath, content);\n }\n catch (_error) {\n // File might not exist, that's okay\n }\n });\n}\n\nfunction generateModulesImport(config: ProjectConfig): string {\n const imports: string[] = [];\n\n imports.push(\" Blocks\");\n if (config.modules.includes(\"Auth\")) {\n imports.push(\" AuthModule\");\n }\n if (config.modules.includes(\"Bank\") && config.startHeight === 1 && config.processGenesis) {\n imports.push(\" BankModule\");\n }\n if (config.modules.includes(\"Staking\") && !config.minimal) {\n imports.push(\" StakingModule\");\n }\n\n return `import {\\n${imports.join(\",\")}\\n} from \"@eclesia/core-modules-pg\";\\n`;\n}\n\nfunction generateModulesInstantiation(config: ProjectConfig): string {\n const instantiations: string[] = [];\n\n if (config.minimal) {\n instantiations.push(\"const blocksModule = new Blocks.MinimalBlocksModule(registry);\");\n }\n else {\n instantiations.push(\"const blocksModule = new Blocks.FullBlocksModule(registry);\");\n }\n if (config.modules.includes(\"Auth\")) {\n instantiations.push(\"const authModule = new AuthModule(registry);\");\n }\n if (config.modules.includes(\"Bank\") && config.startHeight === 1 && config.processGenesis) {\n instantiations.push(\"const bankModule = new BankModule(registry);\");\n }\n if (config.modules.includes(\"Staking\") && !config.minimal) {\n instantiations.push(\"const stakingModule = new StakingModule(registry);\");\n }\n\n return instantiations.join(\"\\n\");\n}\n\nfunction generateModulesArray(config: ProjectConfig): string {\n const moduleNames: string[] = [];\n\n moduleNames.push(\"blocksModule\");\n\n if (config.modules.includes(\"Auth\")) {\n moduleNames.push(\"authModule\");\n }\n if (config.modules.includes(\"Bank\") && config.startHeight === 1 && config.processGenesis) {\n moduleNames.push(\"bankModule\");\n }\n if (config.modules.includes(\"Staking\") && !config.minimal) {\n moduleNames.push(\"stakingModule\");\n }\n return `[${moduleNames.filter(m => !m.includes(\"//\")).join(\", \")}]`;\n}\n\nasync function installDependencies(config: ProjectConfig, targetDir: string): Promise<void> {\n const {\n spawn,\n } = await import(\"node:child_process\");\n\n return new Promise((resolve, reject) => {\n const child = spawn(config.packageManager, [\"install\"], {\n cwd: targetDir,\n stdio: \"inherit\",\n });\n\n child.on(\"close\", (code) => {\n if (code !== 0) {\n reject(new Error(`Package installation failed with code ${code}`));\n }\n else {\n resolve();\n }\n });\n });\n}\n\nasync function buildProject(config: ProjectConfig, targetDir: string): Promise<void> {\n const {\n spawn,\n } = await import(\"node:child_process\");\n\n return new Promise((resolve, reject) => {\n const child = spawn(config.packageManager, [\"run\", \"build\"], {\n cwd: targetDir,\n stdio: \"inherit\",\n });\n\n child.on(\"close\", (code) => {\n if (code !== 0) {\n reject(new Error(`Package installation failed with code ${code}`));\n }\n else {\n resolve();\n }\n });\n });\n}\n","import {\n existsSync,\n} from \"node:fs\";\nimport {\n dirname, resolve,\n} from \"node:path\";\nimport {\n fileURLToPath,\n} from \"node:url\";\n\nimport colors from \"picocolors\";\n\nimport {\n createIndexer,\n} from \"./create-indexer.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nasync function main() {\n console.log();\n console.log(colors.cyan(\"🚀 Welcome to create-eclesia-indexer!\"));\n console.log(colors.gray(\"Scaffolding a new Cosmos SDK chain indexer...\"));\n console.log();\n\n try {\n const projectName = process.argv[2];\n\n if (projectName && existsSync(resolve(process.cwd(), projectName))) {\n console.log(colors.red(`❌ Directory '${projectName}' already exists.`));\n process.exit(1);\n }\n\n await createIndexer(projectName);\n\n console.log();\n console.log(colors.green(\"✅ Indexer created successfully!\"));\n console.log();\n }\n catch (error) {\n console.error(colors.red(\"❌ Error creating indexer:\"), error);\n process.exit(1);\n }\n}\n\nmain().catch((error) => {\n console.error(error);\n process.exit(1);\n});\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-eclesia-indexer",
3
- "version": "1.0.11",
3
+ "version": "1.1.0",
4
4
  "description": "CLI tool to scaffold Cosmos SDK chain indexers using eclesia-indexer-core",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,6 +10,7 @@
10
10
  "build": "tsc --noEmit && tsdown",
11
11
  "lint": "eslint src/**/*.ts",
12
12
  "lint:fix": "eslint src/**/*.ts --fix",
13
+ "typecheck": "tsc --noEmit",
13
14
  "prepublishOnly": "npm run build"
14
15
  },
15
16
  "files": [
@@ -13,6 +13,7 @@ PROCESS_GENESIS={{PROCESS_GENESIS}}
13
13
  MINIMAL={{MINIMAL}}
14
14
  CHAIN_PREFIX={{CHAIN_PREFIX}}
15
15
  USE_POLLING={{USE_POLLING}}
16
-
16
+ ENABLE_PROMETHEUS=false
17
+ PROMETHEUS_PORT=9090
17
18
  # Optional: Start from specific height
18
19
  START_HEIGHT={{START_HEIGHT}}
@@ -28,7 +28,9 @@ services:
28
28
  - CHAIN_PREFIX={{CHAIN_PREFIX}}
29
29
  - START_HEIGHT={{START_HEIGHT}}
30
30
  volumes:
31
- - {{GENESIS_PATH}}:/usr/src/app/genesis.json
31
+ - {{GENESIS_PATH}}:/usr/src/app/genesis.json
32
+ ports:
33
+ - "9090:9090"
32
34
  depends_on:
33
35
  postgres:
34
36
  condition: service_healthy
@@ -29,9 +29,9 @@
29
29
  "@cosmjs/proto-signing": "^0.36.0",
30
30
  "@cosmjs/stargate": "^0.36.0",
31
31
  "@cosmjs/tendermint-rpc": "^0.36.0",
32
- "@eclesia/basic-pg-indexer": "^2.9.9",
33
- "@eclesia/core-modules-pg": "^2.9.9",
34
- "@eclesia/indexer-engine": "^2.9.9",
32
+ "@eclesia/basic-pg-indexer": "^2.10.0",
33
+ "@eclesia/core-modules-pg": "^2.10.0",
34
+ "@eclesia/indexer-engine": "^2.10.0",
35
35
  "bignumber.js": "^9.3.1",
36
36
  "json-with-bigint": "^3.4.4",
37
37
  "pg": "^8.16.3"
@@ -16,7 +16,9 @@ const config: PgIndexerConfig = {
16
16
  pollingInterval: 3000,
17
17
  processGenesis: process.env.PROCESS_GENESIS == "true" || false,
18
18
  minimal: process.env.MINIMAL == "true" || false,
19
- genesisPath: "./genesis.json",
19
+ genesisPath: "./genesis.json",
20
+ enablePrometheus: process.env.ENABLE_PROMETHEUS == "true" || false,
21
+ prometheusPort: Number(process.env.PROMETHEUS_PORT) || {{PROMETHEUS_PORT}},
20
22
  dbConnectionString: process.env.PG_CONNECTION_STRING || "{{PG_CONNECTION_STRING}}",
21
23
  };
22
24