@paimaexample/npm-midnight-indexer 0.3.15

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/README.md ADDED
@@ -0,0 +1,211 @@
1
+ # Midnight Indexer
2
+
3
+ A Node.js package that downloads and runs the [Midnight](https://midnight.network) Indexer. The indexer requires a running Midnight Node to function properly.
4
+
5
+ ## Overview
6
+
7
+ This package provides flexible execution options for the Midnight Indexer:
8
+
9
+ - **Docker mode**: Runs the indexer in a Docker container (recommended)
10
+ - **Binary mode**: Downloads and runs the native binary locally (Linux only)
11
+
12
+ ### Platform Support
13
+
14
+ | Platform | Docker | Binary |
15
+ |----------|--------|--------|
16
+ | macOS | ✅ Yes | ❌ No |
17
+ | Linux | ✅ Yes | ✅ Yes |
18
+ | Windows | ❌ No | ❌ No |
19
+
20
+ > **Note**: On macOS, only Docker execution is supported. Binary execution will automatically fall back to Docker or show an error.
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ npm install npm-midnight-indexer
26
+ ```
27
+
28
+ ## Prerequisites
29
+
30
+ ### For Docker Mode
31
+ - Docker installed and running
32
+ - `APP__INFRA__SECRET` environment variable (required)
33
+
34
+ ### For Binary Mode
35
+ - Supported platform (Linux/Windows)
36
+ - Local Midnight Node and Proof Server running on standard ports
37
+ - `APP__INFRA__SECRET` environment variable (required)
38
+
39
+ ## Usage
40
+
41
+ ### Command Line Options
42
+
43
+ ```bash
44
+ node index.js [options] [args...]
45
+ ```
46
+
47
+ **Options:**
48
+ - `--docker` - Force Docker execution
49
+ - `--binary` - Force binary execution (not available on macOS)
50
+ - `--help` - Show help information
51
+
52
+ **Examples:**
53
+
54
+ ```bash
55
+ # Force Docker usage
56
+ APP__INFRA__SECRET=mysecret node index.js --docker
57
+
58
+ # Force binary usage (Linux/Windows only)
59
+ APP__INFRA__SECRET=mysecret node index.js --binary
60
+
61
+ # Interactive mode - prompts for Docker vs binary choice
62
+ APP__INFRA__SECRET=mysecret node index.js
63
+
64
+ # Show help
65
+ node index.js --help
66
+ ```
67
+
68
+ ## Environment Variables
69
+
70
+ The indexer supports several environment variables with different defaults based on execution mode:
71
+
72
+ | Variable | Required | Docker Default | Binary Default | Description |
73
+ |----------|----------|----------------|----------------|-------------|
74
+ | `APP__INFRA__SECRET` | Yes | - | - | Secret key for the application |
75
+ | `LEDGER_NETWORK_ID` | No | `Undeployed` | `Undeployed` | Ledger network identifier |
76
+ | `SUBSTRATE_NODE_WS_URL` | No | `ws://node:9944` | `ws://localhost:9944` | Substrate node WebSocket URL |
77
+ | `FEATURES_WALLET_ENABLED` | No | `true` | `true` | Enable wallet features |
78
+ | `APP__INFRA__PROOF_SERVER__URL` | No | `http://proof-server:6300` | `http://localhost:6300` | Proof server URL |
79
+ | `APP__INFRA__NODE__URL` | No | `ws://node:9944` | `ws://localhost:9944` | Node WebSocket URL |
80
+
81
+ ### Environment Variable Examples
82
+
83
+ ```bash
84
+ # Minimal Docker setup
85
+ APP__INFRA__SECRET=A5F07FCAC914A181EC0998CCCA68312DA5F07FCAC914A181EC0998CCCA68312D \
86
+ node index.js --docker
87
+
88
+ # Custom configuration
89
+ APP__INFRA__SECRET=mysecret \
90
+ LEDGER_NETWORK_ID=CustomNetwork \
91
+ SUBSTRATE_NODE_WS_URL=ws://localhost:9944 \
92
+ APP__INFRA__PROOF_SERVER__URL=http://localhost:6300 \
93
+ node index.js --docker
94
+
95
+ # Binary mode (uses localhost defaults automatically)
96
+ APP__INFRA__SECRET=mysecret node index.js --binary
97
+ ```
98
+
99
+ ## Docker Mode Details
100
+
101
+ When using Docker mode, the indexer:
102
+
103
+ 1. **Pulls the latest image**: `midnightntwrk/indexer-standalone`
104
+ 2. **Maps port 8088**: Container port 8088 → Host port 8088
105
+ 3. **Uses container networking**: Defaults work with Docker Compose setups
106
+ 4. **Auto-cleanup**: Removes existing containers before starting new ones
107
+
108
+ ### Docker Command Generated
109
+
110
+ The package generates Docker commands similar to:
111
+
112
+ ```bash
113
+ docker run --rm --name midnight-local-indexer \
114
+ -p 8088:8088 \
115
+ -e LEDGER_NETWORK_ID=Undeployed \
116
+ -e SUBSTRATE_NODE_WS_URL=ws://node:9944 \
117
+ -e APP__INFRA__SECRET=A5F07FCAC914A181EC0998CCCA68312DA5F07FCAC914A181EC0998CCCA68312D \
118
+ -e FEATURES_WALLET_ENABLED=true \
119
+ -e APP__INFRA__PROOF_SERVER__URL=http://proof-server:6300 \
120
+ -e APP__INFRA__NODE__URL=ws://node:9944 \
121
+ midnightntwrk/indexer-standalone
122
+ ```
123
+
124
+ ## Binary Mode Details
125
+
126
+ When using binary mode, the indexer:
127
+
128
+ 1. **Downloads platform-specific binary** if not already present
129
+ 2. **Uses localhost URLs** for all service connections
130
+ 3. **Runs natively** on the host system
131
+
132
+ ### Supported Binary Platforms
133
+
134
+ - Linux ARM64 (`linux-arm64`)
135
+ - Linux AMD64 (`linux-amd64`)
136
+ - macOS ARM64 (`macos-arm64`) - **Docker only**
137
+
138
+ ## Troubleshooting
139
+
140
+ ### Common Issues
141
+
142
+ **"Docker is not installed or not available"**
143
+ - Install Docker Desktop or Docker Engine
144
+ - Ensure Docker is running
145
+ - Check Docker is accessible from command line: `docker --version`
146
+
147
+ **"APP__INFRA__SECRET environment variable is required"**
148
+ - Set the secret: `export APP__INFRA__SECRET=your_secret_here`
149
+ - Or pass inline: `APP__INFRA__SECRET=your_secret node index.js --docker`
150
+ - Required for both Docker and binary execution modes
151
+
152
+ **"Binary execution is not supported on macOS"**
153
+ - Use `--docker` flag or run without flags to use Docker automatically
154
+ - Install Docker if not already installed
155
+
156
+ **"Failed to start midnight-indexer"**
157
+ - Check if ports 8088, 6300, 9944 are available
158
+ - Verify Midnight Node is running and accessible
159
+ - Check environment variables are correctly set
160
+
161
+ ### Logs and Debugging
162
+
163
+ The indexer outputs detailed logs including:
164
+ - Download progress for binaries
165
+ - Docker pull progress
166
+ - Process IDs and status
167
+ - Error messages with suggestions
168
+
169
+ ## Development
170
+
171
+ ### Package Structure
172
+
173
+ ```
174
+ npm-midnight-indexer/
175
+ ├── index.js # Main entry point
176
+ ├── binary.js # Binary download logic
177
+ ├── docker.js # Docker execution logic
178
+ ├── run_midnight_indexer.js # Binary execution logic
179
+ ├── package.json # Package configuration
180
+ └── README.md # This file
181
+ ```
182
+
183
+ ### Testing
184
+
185
+ ```bash
186
+ # Test Docker detection
187
+ node -e "const { checkIfDockerExists } = require('./docker.js'); checkIfDockerExists().then(console.log)"
188
+
189
+ # Test help
190
+ node index.js --help
191
+
192
+ # Test platform detection
193
+ node -e "console.log('Platform:', require('os').platform())"
194
+ ```
195
+
196
+ ## License
197
+
198
+ ISC
199
+
200
+ ## Support
201
+
202
+ For issues related to:
203
+ - **This package**: Open an issue in the repository
204
+ - **Midnight Protocol**: Visit [midnight.network](https://midnight.network)
205
+ - **Docker**: Check [Docker documentation](https://docs.docker.com/)
206
+
207
+ ## Related Links
208
+
209
+ - [Midnight Network](https://midnight.network)
210
+ - [Docker Hub - Midnight Indexer](https://hub.docker.com/r/midnightntwrk/indexer-standalone)
211
+ - [Node.js](https://nodejs.org/)
package/binary.js ADDED
@@ -0,0 +1,79 @@
1
+ const os = require("os");
2
+ const fs = require("fs");
3
+ const axios = require("axios");
4
+ const extract = require("extract-zip");
5
+ const path = require("path");
6
+
7
+ function getPlatform() {
8
+ let platform = os.platform();
9
+ const arch = os.arch();
10
+
11
+ if (platform === "darwin") {
12
+ // For macOS, return the full platform-arch combination
13
+ if (arch === "arm64") {
14
+ return "macos-arm64";
15
+ } else if (arch === "x64") {
16
+ return "macos-amd64"; // Will not be in supportedPlatforms, so will fall back to Docker
17
+ } else {
18
+ return `macos-${arch}`;
19
+ }
20
+ } else {
21
+ // For Linux and other platforms, only arch is needed
22
+ if (arch === "x64") {
23
+ return "amd64";
24
+ }
25
+ return arch;
26
+ }
27
+ }
28
+
29
+ function getBinaryUrl() {
30
+ const platform = getPlatform();
31
+ const supportedPlatforms = require("./package.json").supportedPlatforms;
32
+
33
+ // Check if platform is supported
34
+ if (!supportedPlatforms.includes(platform)) {
35
+ throw new Error(`Unsupported platform: ${platform}`);
36
+ }
37
+
38
+ // Special handling for macOS platforms
39
+ if (platform.startsWith("macos")) {
40
+ return `https://paima-midnight.nyc3.cdn.digitaloceanspaces.com/binaries/indexer-standalone-${platform}.zip`;
41
+ }
42
+
43
+ // For Linux and other platforms, use the existing pattern
44
+ return `https://paima-midnight.nyc3.cdn.digitaloceanspaces.com/binaries/indexer-standalone-${platform}.zip`;
45
+ }
46
+
47
+ async function downloadAndSaveBinary() {
48
+ const url = getBinaryUrl();
49
+ try {
50
+ const response = await axios.get(url, { responseType: "stream" });
51
+ const writer = fs.createWriteStream(path.join(__dirname, "indexer-standalone.zip"));
52
+
53
+ response.data.pipe(writer);
54
+
55
+ return new Promise((resolve, reject) => {
56
+ writer.on('finish', resolve);
57
+ writer.on('error', reject);
58
+ });
59
+ } catch (error) {
60
+ console.error("Error downloading binary:", error);
61
+ throw error;
62
+ }
63
+ }
64
+
65
+ async function unzipBinary() {
66
+ await extract(path.join(__dirname, "indexer-standalone.zip"), {
67
+ dir: path.join(__dirname, "indexer-standalone"),
68
+ });
69
+ fs.unlinkSync(path.join(__dirname, "indexer-standalone.zip"));
70
+ }
71
+
72
+ async function binary() {
73
+ await downloadAndSaveBinary();
74
+ await unzipBinary();
75
+ }
76
+
77
+ module.exports = {
78
+ binary,
79
+ };
package/docker.js ADDED
@@ -0,0 +1,164 @@
1
+ const { spawn, exec } = require('child_process');
2
+ const { promisify } = require('util');
3
+ const execAsync = promisify(exec);
4
+
5
+ /**
6
+ * Checks if Docker is installed and available on the system
7
+ * @returns {Promise<boolean>} True if Docker is available, false otherwise
8
+ */
9
+ async function checkIfDockerExists() {
10
+ try {
11
+ await execAsync('docker --version');
12
+ return true;
13
+ } catch (error) {
14
+ return false;
15
+ }
16
+ }
17
+
18
+ /**
19
+ * Pulls the latest midnight indexer Docker image
20
+ * @returns {Promise<void>}
21
+ */
22
+ async function pullDockerImage() {
23
+ const imageName = 'midnightntwrk/indexer-standalone';
24
+
25
+ console.log(`Pulling Docker image: ${imageName}`);
26
+
27
+ return new Promise((resolve, reject) => {
28
+ const childProcess = spawn('docker', ['pull', imageName], {
29
+ stdio: 'inherit'
30
+ });
31
+
32
+ childProcess.on('exit', (code) => {
33
+ if (code === 0) {
34
+ console.log('Docker image pulled successfully');
35
+ resolve();
36
+ } else {
37
+ reject(new Error(`Docker pull failed with exit code ${code}`));
38
+ }
39
+ });
40
+
41
+ childProcess.on('error', (error) => {
42
+ reject(new Error(`Failed to pull Docker image: ${error.message}`));
43
+ });
44
+ });
45
+ }
46
+
47
+ /**
48
+ * Runs the midnight indexer Docker container
49
+ * @param {Object} env - Environment variables to pass to the container
50
+ * @param {Array} args - Arguments to pass to the container
51
+ * @returns {ChildProcess} The spawned Docker process
52
+ */
53
+ function runDockerContainer(env = process.env, args = []) {
54
+ const imageName = 'midnightntwrk/indexer-standalone';
55
+ const containerName = 'midnight-local-indexer';
56
+
57
+ // Stop and remove existing container if it exists
58
+ try {
59
+ require('child_process').execSync(`docker stop ${containerName} 2>/dev/null || true`, { stdio: 'ignore' });
60
+ require('child_process').execSync(`docker rm ${containerName} 2>/dev/null || true`, { stdio: 'ignore' });
61
+ } catch (error) {
62
+ // Ignore errors - container might not exist
63
+ }
64
+
65
+ // Build Docker run command arguments
66
+ const dockerArgs = ['run'];
67
+
68
+ // Add container name (remove existing container if it exists)
69
+ dockerArgs.push('--rm'); // Automatically remove container when it exits
70
+ dockerArgs.push('--name', containerName);
71
+
72
+ // Intelligent port mapping - default to 8088:8088 if not specified
73
+ const defaultPort = '8088:8088';
74
+ let portMapping = defaultPort;
75
+
76
+ // Check if port is specified in args
77
+ const portArgIndex = args.findIndex(arg => arg.includes('--port') || arg.includes('-p'));
78
+ if (portArgIndex !== -1 && args[portArgIndex + 1]) {
79
+ const specifiedPort = args[portArgIndex + 1];
80
+ portMapping = `${specifiedPort}:${specifiedPort}`;
81
+ // Remove port args from the args array as they're handled by Docker
82
+ args.splice(portArgIndex, 2);
83
+ }
84
+
85
+ dockerArgs.push('-p', portMapping);
86
+
87
+ // Add environment variables
88
+ const requiredEnvVars = [
89
+ 'LEDGER_NETWORK_ID',
90
+ 'SUBSTRATE_NODE_WS_URL',
91
+ 'APP__INFRA__SECRET',
92
+ 'FEATURES_WALLET_ENABLED',
93
+ 'APP__INFRA__PROOF_SERVER__URL',
94
+ 'APP__INFRA__NODE__URL'
95
+ ];
96
+
97
+ // Set default values for Docker environment variables (using container network names)
98
+ const envDefaults = {
99
+ 'LEDGER_NETWORK_ID': env.LEDGER_NETWORK_ID || 'Undeployed',
100
+ 'SUBSTRATE_NODE_WS_URL': env.SUBSTRATE_NODE_WS_URL || 'ws://node:9944',
101
+ 'APP__INFRA__SECRET': env.APP__INFRA__SECRET,
102
+ 'FEATURES_WALLET_ENABLED': env.FEATURES_WALLET_ENABLED || 'true',
103
+ 'APP__INFRA__PROOF_SERVER__URL': env.APP__INFRA__PROOF_SERVER__URL || 'http://proof-server:6300',
104
+ 'APP__INFRA__NODE__URL': env.APP__INFRA__NODE__URL || 'ws://node:9944'
105
+ };
106
+
107
+ // Validate that SECRET is provided
108
+ if (!envDefaults['APP__INFRA__SECRET']) {
109
+ throw new Error('APP__INFRA__SECRET environment variable is required');
110
+ }
111
+
112
+ // Add environment variables to Docker command
113
+ Object.entries(envDefaults).forEach(([key, value]) => {
114
+ if (value) {
115
+ dockerArgs.push('-e', `${key}=${value}`);
116
+ }
117
+ });
118
+
119
+ // Add any additional environment variables from env object
120
+ Object.entries(env).forEach(([key, value]) => {
121
+ if (!requiredEnvVars.includes(key) && value) {
122
+ dockerArgs.push('-e', `${key}=${value}`);
123
+ }
124
+ });
125
+
126
+ // Add the image name
127
+ dockerArgs.push(imageName);
128
+
129
+ // Add any remaining arguments
130
+ if (args.length > 0) {
131
+ dockerArgs.push(...args);
132
+ }
133
+
134
+ console.log(`Starting Docker container: docker ${dockerArgs.join(' ')}`);
135
+
136
+ const childProcess = spawn('docker', dockerArgs, {
137
+ stdio: 'inherit'
138
+ });
139
+
140
+ childProcess.on('spawn', () => {
141
+ console.log(`Docker container started with PID: ${childProcess.pid}`);
142
+ console.log(`Container accessible on port: ${portMapping.split(':')[0]}`);
143
+ });
144
+
145
+ childProcess.on('error', (error) => {
146
+ console.error('Failed to start Docker container:', error);
147
+ });
148
+
149
+ childProcess.on('exit', (code, signal) => {
150
+ if (code !== null) {
151
+ console.log(`Docker container exited with code: ${code}`);
152
+ } else {
153
+ console.log(`Docker container terminated by signal: ${signal}`);
154
+ }
155
+ });
156
+
157
+ return childProcess;
158
+ }
159
+
160
+ module.exports = {
161
+ checkIfDockerExists,
162
+ pullDockerImage,
163
+ runDockerContainer
164
+ };
package/index.js ADDED
@@ -0,0 +1,305 @@
1
+ const { binary } = require("./binary");
2
+ const { runMidnightIndexer } = require("./run_midnight_indexer");
3
+ const { checkIfDockerExists, pullDockerImage, runDockerContainer } = require(
4
+ "./docker",
5
+ );
6
+ const fs = require("fs");
7
+ const path = require("path");
8
+ const readline = require("readline");
9
+ const os = require("os");
10
+
11
+ function checkIfBinaryExists() {
12
+ return fs.existsSync(
13
+ path.join(__dirname, "indexer-standalone", "indexer-standalone"),
14
+ );
15
+ }
16
+
17
+ /**
18
+ * Checks if the current platform supports binary execution
19
+ * @returns {boolean} True if binary execution is supported
20
+ */
21
+ function isBinarySupported() {
22
+ const platform = os.platform();
23
+ const arch = os.arch();
24
+
25
+ // Check if the current platform-arch combination is supported
26
+ const supportedPlatforms = require("./package.json").supportedPlatforms;
27
+
28
+ let platformString;
29
+ if (platform === "darwin") {
30
+ platformString = arch === "x64" ? "macos-amd64" : `macos-${arch}`;
31
+ } else {
32
+ platformString = arch === "x64" ? "amd64" : arch;
33
+ }
34
+
35
+ return supportedPlatforms.includes(platformString);
36
+ }
37
+
38
+ /**
39
+ * Prompts the user to choose between Docker and binary execution
40
+ * @returns {Promise<boolean>} True if user chooses Docker, false for binary
41
+ */
42
+ function promptUserForDockerChoice() {
43
+ const rl = readline.createInterface({
44
+ input: process.stdin,
45
+ output: process.stdout,
46
+ });
47
+
48
+ return new Promise((resolve) => {
49
+ rl.question(
50
+ "Docker is available. Would you like to use Docker instead of downloading the binary? (y/n): ",
51
+ (answer) => {
52
+ rl.close();
53
+ resolve(answer.toLowerCase() === "y" || answer.toLowerCase() === "yes");
54
+ },
55
+ );
56
+ });
57
+ }
58
+
59
+ /**
60
+ * Shows usage information
61
+ */
62
+ function showUsage() {
63
+ console.log(`
64
+ Usage: node index.js [options] [args...]
65
+
66
+ Options:
67
+ --docker Force use of Docker container
68
+ --binary Force use of binary execution (supports Linux and macOS arm64)
69
+ --help Show this help message
70
+
71
+ Environment Variables:
72
+ APP__INFRA__SECRET Required: Secret key for the application
73
+ LEDGER_NETWORK_ID Optional: Ledger network ID (default: Undeployed)
74
+ SUBSTRATE_NODE_WS_URL Optional: Substrate node WebSocket URL
75
+ (Docker default: ws://node:9944, Binary default: ws://localhost:9944)
76
+ FEATURES_WALLET_ENABLED Optional: Enable wallet features (default: true)
77
+ APP__INFRA__PROOF_SERVER__URL Optional: Proof server URL
78
+ (Docker default: http://proof-server:6300, Binary default: http://localhost:6300)
79
+ APP__INFRA__NODE__URL Optional: Node URL
80
+ (Docker default: ws://node:9944, Binary default: ws://localhost:9944)
81
+
82
+ Note: macOS Intel users will automatically use Docker. macOS arm64 supports both binary and Docker execution.
83
+
84
+ Examples:
85
+ APP__INFRA__SECRET=mysecret node index.js --docker # Use Docker
86
+ APP__INFRA__SECRET=mysecret node index.js --binary # Use binary (if supported)
87
+ APP__INFRA__SECRET=mysecret node index.js # Interactive mode (or auto-Docker on unsupported platforms)
88
+ node index.js --help # Show this help
89
+ `);
90
+ }
91
+
92
+ /**
93
+ * Parses command line arguments to extract flags and remaining args
94
+ * @param {Array} args - Command line arguments
95
+ * @returns {Object} Object containing useDocker, useBinary flags and remaining args
96
+ */
97
+ function parseFlags(args) {
98
+ const flags = {
99
+ useDocker: false,
100
+ useBinary: false,
101
+ showHelp: false,
102
+ remainingArgs: [],
103
+ };
104
+
105
+ for (let i = 0; i < args.length; i++) {
106
+ if (args[i] === "--docker") {
107
+ flags.useDocker = true;
108
+ } else if (args[i] === "--binary") {
109
+ flags.useBinary = true;
110
+ } else if (args[i] === "--help" || args[i] === "-h") {
111
+ flags.showHelp = true;
112
+ } else {
113
+ flags.remainingArgs.push(args[i]);
114
+ }
115
+ }
116
+
117
+ return flags;
118
+ }
119
+
120
+ async function runWithDocker(env, args) {
121
+ console.log("Using Docker to run midnight indexer...");
122
+
123
+ try {
124
+ // Pull the latest image
125
+ await pullDockerImage();
126
+
127
+ // Run the container
128
+ return runDockerContainer(env, args);
129
+ } catch (error) {
130
+ console.error("Failed to run with Docker:", error.message);
131
+ console.log("Falling back to binary execution...");
132
+ return runWithBinary(env, args);
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Sets appropriate defaults for binary execution (localhost-based)
138
+ * @param {Object} env - Original environment variables
139
+ * @returns {Object} Environment variables with localhost defaults
140
+ */
141
+ function setBinaryDefaults(env) {
142
+ const binaryEnv = { ...env };
143
+
144
+ // Set localhost-based defaults for binary execution
145
+ if (!binaryEnv.LEDGER_NETWORK_ID) {
146
+ binaryEnv.LEDGER_NETWORK_ID = "Undeployed";
147
+ }
148
+ if (!binaryEnv.SUBSTRATE_NODE_WS_URL) {
149
+ binaryEnv.SUBSTRATE_NODE_WS_URL = "ws://localhost:9944";
150
+ }
151
+ if (!binaryEnv.FEATURES_WALLET_ENABLED) {
152
+ binaryEnv.FEATURES_WALLET_ENABLED = "true";
153
+ }
154
+ if (!binaryEnv.APP__INFRA__PROOF_SERVER__URL) {
155
+ binaryEnv.APP__INFRA__PROOF_SERVER__URL = "http://localhost:6300";
156
+ }
157
+ if (!binaryEnv.APP__INFRA__NODE__URL) {
158
+ binaryEnv.APP__INFRA__NODE__URL = "ws://localhost:9944";
159
+ }
160
+
161
+ return binaryEnv;
162
+ }
163
+
164
+ async function runWithBinary(env, args) {
165
+ console.log("Using binary to run midnight indexer...");
166
+
167
+ // Check for required environment variable
168
+ if (!env.APP__INFRA__SECRET) {
169
+ console.error("Error: APP__INFRA__SECRET environment variable is required");
170
+ console.log("Please set APP__INFRA__SECRET=<your_secret> and run again");
171
+ process.exit(1);
172
+ }
173
+
174
+ if (!checkIfBinaryExists()) {
175
+ console.log("Binary not found, downloading...");
176
+ await binary();
177
+ }
178
+
179
+ // Set appropriate localhost defaults for binary execution
180
+ const binaryEnv = setBinaryDefaults(env);
181
+
182
+ return runMidnightIndexer(binaryEnv, args);
183
+ }
184
+
185
+ async function main(args) {
186
+ const flags = parseFlags(args);
187
+ const env = process.env;
188
+
189
+ // Show help if requested
190
+ if (flags.showHelp) {
191
+ showUsage();
192
+ process.exit(0);
193
+ }
194
+
195
+ // If both flags are provided, show error
196
+ if (flags.useDocker && flags.useBinary) {
197
+ console.error(
198
+ "Error: Cannot use both --docker and --binary flags simultaneously",
199
+ );
200
+ process.exit(1);
201
+ }
202
+
203
+ // If --docker flag is explicitly provided
204
+ if (flags.useDocker) {
205
+ const dockerAvailable = await checkIfDockerExists();
206
+ if (!dockerAvailable) {
207
+ console.error("Error: Docker is not installed or not available");
208
+ console.log("Please install Docker or use the --binary flag");
209
+ process.exit(1);
210
+ }
211
+
212
+ // Check for required environment variable
213
+ if (!env.APP__INFRA__SECRET) {
214
+ console.error(
215
+ "Error: APP__INFRA__SECRET environment variable is required",
216
+ );
217
+ console.log(
218
+ "Please set APP__INFRA__SECRET=<your_secret> when running with --docker",
219
+ );
220
+ process.exit(1);
221
+ }
222
+
223
+ return runWithDocker(env, flags.remainingArgs);
224
+ }
225
+
226
+ // If --binary flag is explicitly provided
227
+ if (flags.useBinary) {
228
+ if (!isBinarySupported()) {
229
+ console.error(
230
+ "Error: Binary execution is not supported on this platform",
231
+ );
232
+ console.log(
233
+ "Please use --docker flag instead, or run without flags to use Docker automatically",
234
+ );
235
+ process.exit(1);
236
+ }
237
+ return runWithBinary(env, flags.remainingArgs);
238
+ }
239
+
240
+ // No explicit flag provided - determine best execution method
241
+ const dockerAvailable = await checkIfDockerExists();
242
+ const binarySupported = isBinarySupported();
243
+
244
+ // If binary is not supported on this platform, try Docker
245
+ if (!binarySupported) {
246
+ if (!dockerAvailable) {
247
+ console.error(
248
+ "Error: Binary execution is not supported on this platform and Docker is not installed or available",
249
+ );
250
+ console.log(
251
+ "Please install Docker or ensure your platform is supported for binary execution",
252
+ );
253
+ process.exit(1);
254
+ }
255
+ console.log(
256
+ "Binary execution not supported on this platform - using Docker",
257
+ );
258
+
259
+ // Check for required environment variable
260
+ if (!env.APP__INFRA__SECRET) {
261
+ console.error(
262
+ "Error: APP__INFRA__SECRET environment variable is required",
263
+ );
264
+ console.log("Please set APP__INFRA__SECRET=<your_secret> and run again");
265
+ process.exit(1);
266
+ }
267
+
268
+ return runWithDocker(env, flags.remainingArgs);
269
+ }
270
+
271
+ // On supported platforms, prompt user if Docker is available
272
+ if (dockerAvailable) {
273
+ const useDocker = await promptUserForDockerChoice();
274
+ if (useDocker) {
275
+ // Check for required environment variable
276
+ if (!env.APP__INFRA__SECRET) {
277
+ console.error(
278
+ "Error: APP__INFRA__SECRET environment variable is required",
279
+ );
280
+ console.log(
281
+ "Please set APP__INFRA__SECRET=<your_secret> and run again",
282
+ );
283
+ process.exit(1);
284
+ }
285
+ return runWithDocker(env, flags.remainingArgs);
286
+ }
287
+ }
288
+
289
+ // Default to binary execution (only on supported platforms)
290
+ return runWithBinary(env, flags.remainingArgs);
291
+ }
292
+
293
+ // Handle unhandled promise rejections
294
+ process.on("unhandledRejection", (error) => {
295
+ console.error("Unhandled promise rejection:", error);
296
+ process.exit(1);
297
+ });
298
+
299
+ // Handle SIGINT (Ctrl+C) gracefully
300
+ process.on("SIGINT", () => {
301
+ console.log("\nShutting down gracefully...");
302
+ process.exit(0);
303
+ });
304
+
305
+ main(process.argv.slice(2));
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "@paimaexample/npm-midnight-indexer",
3
+ "version": "0.3.15",
4
+ "description": "Downloads and runs the Midnight Indexer. It needs a running Midnight Node",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "bin": {
10
+ "npm-midnight-indexer": "index.js"
11
+ },
12
+ "author": "Paima Studios",
13
+ "license": "ISC",
14
+ "supportedPlatforms": [
15
+ "linux-arm64",
16
+ "linux-amd64",
17
+ "macos-arm64"
18
+ ],
19
+ "dependencies": {
20
+ "axios": "^1.10.0",
21
+ "axios-proxy-builder": "^0.1.2",
22
+ "extract-zip": "^2.0.1"
23
+ }
24
+ }
@@ -0,0 +1,40 @@
1
+ const { spawn } = require('child_process');
2
+ const path = require('path');
3
+
4
+ /**
5
+ * Executes the midnight-indexer binary as a child process
6
+ * @param {Object} env - Environment variables to pass to the child process
7
+ * @param {Array} args - Optional arguments to pass to the binary
8
+ * @returns {ChildProcess} The spawned child process
9
+ */
10
+ function runMidnightIndexer(env = process.env, args = []) {
11
+ const binaryPath = path.join(__dirname, 'indexer-standalone', 'indexer-standalone');
12
+
13
+ console.log(`Starting midnight-indexer binary at: ${binaryPath}`);
14
+
15
+ const childProcess = spawn(binaryPath, args, {
16
+ env: env,
17
+ stdio: 'inherit', // Inherit stdin, stdout, stderr from parent process
18
+ cwd: path.join(__dirname, 'indexer-standalone') // Run from inside the midnight-indexer directory
19
+ });
20
+
21
+ childProcess.on('spawn', () => {
22
+ console.log(`midnight-indexer process spawned with PID: ${childProcess.pid}`);
23
+ });
24
+
25
+ childProcess.on('error', (error) => {
26
+ console.error('Failed to start midnight-indexer:', error);
27
+ });
28
+
29
+ childProcess.on('exit', (code, signal) => {
30
+ if (code !== null) {
31
+ console.log(`midnight-indexer process exited with code: ${code}`);
32
+ } else {
33
+ console.log(`midnight-indexer process terminated by signal: ${signal}`);
34
+ }
35
+ });
36
+
37
+ return childProcess;
38
+ }
39
+
40
+ module.exports = { runMidnightIndexer };