@akin01/mailgen 0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Akin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,260 @@
1
+ # mailgen
2
+
3
+ High-performance email generator using Markov chains and Bloom filters.
4
+
5
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/akin01/emailgen/ci.yml)](https://github.com/akin01/emailgen/actions)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Features
9
+
10
+ - 🚀 **High Performance** - Generate 250K+ emails per second (Fast Mode)
11
+ - 🎯 **Realistic Names** - Markov chain-based name generation
12
+ - ✅ **Uniqueness Guaranteed** - Bloom filter for efficient duplicate detection
13
+ - 📝 **Custom Wordlists** - Support for custom name and domain lists
14
+ - 🔧 **Configurable** - Multiple email patterns and generation options
15
+ - 💾 **Memory Efficient** - ~1.2 MB for 1 million unique emails
16
+
17
+ ## Installation
18
+
19
+ ### Binary Installation (Recommended)
20
+
21
+ Quickly install the latest binary for your system (Linux, macOS, or Windows):
22
+
23
+ ```bash
24
+ # Linux/macOS (using install script)
25
+ curl -fsSL https://raw.githubusercontent.com/akin01/emailgen/main/install.sh | sudo bash
26
+
27
+ # Windows PowerShell (one-liner, no file download needed)
28
+ powershell -ExecutionPolicy Bypass -Command "iwr -useb https://raw.githubusercontent.com/akin01/emailgen/main/install.ps1 | iex"
29
+
30
+ # Alternative PowerShell syntax
31
+ Invoke-WebRequest -Uri https://raw.githubusercontent.com/akin01/emailgen/main/install.ps1 -UseBasicParsing | Invoke-Expression
32
+ ```
33
+
34
+ ### Build from Source
35
+
36
+ ## Quick Start
37
+
38
+ ### Generate Emails
39
+
40
+ ```bash
41
+ # Generate 1000 emails to stdout
42
+ ./target/release/mailgen --count 1000
43
+
44
+ # Generate 1 million emails to file (Fast Mode)
45
+ ./target/release/mailgen --count 1000000 --output emails.txt --fast
46
+
47
+ # Use custom wordlists
48
+ ./target/release/mailgen --count 10000 \
49
+ --names data/example_names.txt \
50
+ --domains data/example_domains.txt \
51
+ --output emails.txt
52
+ ```
53
+
54
+ ### As a Library
55
+
56
+ Add to your `Cargo.toml`:
57
+
58
+ ```toml
59
+ [dependencies]
60
+ emailgen = { git = "https://github.com/akin01/emailgen" }
61
+ ```
62
+
63
+ ```rust
64
+ use mailgen::EmailGenerator;
65
+
66
+ fn main() {
67
+ // Basic usage
68
+ let mut generator = EmailGenerator::new();
69
+ let email = generator.generate();
70
+ println!("Generated: {}", email);
71
+
72
+ // Generate many emails
73
+ let emails = generator.generate_many(1000);
74
+
75
+ // With custom wordlists
76
+ let names = vec!["John Doe".to_string(), "Jane Smith".to_string()];
77
+ let domains = vec!["example.com".to_string()];
78
+ let mut generator = EmailGenerator::with_names_and_domains(names, domains);
79
+ let emails = generator.generate_many(10000);
80
+ }
81
+ ```
82
+
83
+ ## Performance
84
+
85
+ ### Generation Speed (Actual Benchmarks)
86
+
87
+ | Mode | 10K | 100K | 1M |
88
+ |------|-----|------|-----|
89
+ | **Fast Mode** (`--fast`) | 0.04s | 0.38s | 7.5s |
90
+ | **Default Mode** | 3.9s | 39s | ~6.5 min |
91
+
92
+ **💡 Tip:** Use `--fast` mode for bulk generation (>10K emails) for best performance.
93
+
94
+ ### Memory Usage
95
+
96
+ - **~1.2 MB** for 1 million unique emails (Bloom filter)
97
+
98
+ ### Usage
99
+
100
+ ```bash
101
+ # Fast mode for bulk generation (~250K emails/sec)
102
+ ./target/release/mailgen --count 1000000 --output emails.txt --fast
103
+
104
+ # Default mode with 30% Markov for variety (~2.6K emails/sec)
105
+ ./target/release/mailgen --count 100000 --output emails.txt
106
+
107
+ # Generate to stdout
108
+ ./target/release/mailgen --count 1000 --fast
109
+ ```
110
+
111
+ See [PERFORMANCE.md](PERFORMANCE.md) for detailed benchmarks.
112
+
113
+ ## Usage
114
+
115
+ ### Direct Command Line
116
+
117
+ After installing via the script, `uv`, or `npm`, the `mailgen` command is available directly in your terminal:
118
+
119
+ ```bash
120
+ # Basic usage
121
+ mailgen --count 1000
122
+
123
+ # Fast mode
124
+ mailgen -c 1000000 --fast
125
+ ```
126
+
127
+ ### Command Line Options
128
+
129
+ ```
130
+ USAGE:
131
+ emailgen [OPTIONS]
132
+
133
+ OPTIONS:
134
+ -c, --count <COUNT> Number of emails to generate [default: 1000]
135
+ -o, --output <OUTPUT> Output file path (stdout if not specified)
136
+ -n, --names <NAMES> Path to names wordlist file
137
+ -d, --domains <DOMAINS> Path to domains file
138
+ --min-length <MIN> Minimum username length [default: 5]
139
+ --max-length <MAX> Maximum username length [default: 30]
140
+ --capacity <CAP> Bloom filter capacity [default: 1000000]
141
+ --fpr <FPR> Bloom filter false positive rate [default: 0.01]
142
+ --fast Fast mode (100% wordlist/cached, no Markov)
143
+ --wordlist-percent <PCT> Wordlist name percentage (0-100, default: auto)
144
+ --cache-percent <PCT> Cached name percentage (0-100, default: auto)
145
+ --markov-percent <PCT> Markov generation percentage (0-100, default: 30)
146
+ --stats Show statistics after generation
147
+ -q, --quiet Quiet mode (no output except errors)
148
+ -h, --help Print help
149
+ -V, --version Print version
150
+
151
+ **Features:**
152
+ - **TUI Progress Bar**: Animated text-based progress bar with spinner, percentage, speed, and ETA
153
+ - **Parallel Generation**: Multi-threaded generation (always enabled)
154
+ - **Async I/O**: Asynchronous file writing (always enabled)
155
+
156
+ **Note:** The TUI progress bar animation works best in interactive terminals. When output is redirected, you'll see the final progress state.
157
+ ```
158
+
159
+ ### Name Source Ratios
160
+
161
+ Control the balance between speed and variety:
162
+
163
+ ```bash
164
+ # Specify all three (must add up to 100)
165
+ ./target/release/mailgen --count 100000 --wordlist-percent 35 --cache-percent 35 --markov-percent 30
166
+
167
+ # Specify only one - others auto-calculated
168
+ ./target/release/mailgen --count 100000 --markov-percent 20
169
+ # Auto-calculates: 40% wordlist, 40% cached, 20% Markov
170
+
171
+ ./target/release/mailgen --count 100000 --wordlist-percent 80
172
+ # Auto-calculates: 80% wordlist, 15% cached, 5% Markov
173
+
174
+ ./target/release/mailgen --count 100000 --cache-percent 70
175
+ # Auto-calculates: 25% wordlist, 70% cached, 5% Markov
176
+
177
+ # Specify two - third auto-calculated
178
+ ./target/release/mailgen --count 100000 --wordlist-percent 50 --markov-percent 10
179
+ # Auto-calculates: 50% wordlist, 40% cached, 10% Markov
180
+
181
+ # Fast mode shortcut (50% wordlist, 50% cached, 0% Markov)
182
+ ./target/release/mailgen --count 100000 --fast
183
+ ```
184
+
185
+ | Ratio (wordlist/cache/markov) | Speed | Variety | Use Case |
186
+ |-------------------------------|-------|---------|----------|
187
+ | 100/0/0 | ~260K/sec | Low | Bulk test data |
188
+ | 50/50/0 (--fast) | ~260K/sec | Medium | Fast generation |
189
+ | 35/35/30 (default) | ~2.6K/sec | High | General use with variety |
190
+ | 25/25/50 | ~1.5K/sec | Very High | Maximum variety |
191
+
192
+ ### Examples
193
+
194
+ ```bash
195
+ # Generate 10K emails with stats
196
+ ./target/release/mailgen -c 10000 --stats
197
+
198
+ # Generate with custom wordlists
199
+ ./target/release/mailgen -c 100000 \
200
+ -n names.txt \
201
+ -d domains.txt \
202
+ -o output.txt
203
+
204
+ # Generate with specific constraints
205
+ ./target/release/mailgen -c 50000 \
206
+ --min-length 6 \
207
+ --max-length 20 \
208
+ --capacity 100000 \
209
+ --fpr 0.001
210
+ ```
211
+
212
+ ## Architecture
213
+
214
+ ### Markov Chain Name Generation
215
+
216
+ The email generator uses character-level Markov chains to generate realistic names:
217
+
218
+ 1. **Training**: Names from wordlist are converted to character sequences
219
+ 2. **Generation**: New names are generated by walking the Markov chain
220
+ 3. **Patterns**: Multiple email patterns create variety (first.last, firstlast, etc.)
221
+
222
+ ### Bloom Filter Uniqueness
223
+
224
+ Bloom filters provide space-efficient uniqueness checking:
225
+
226
+ - **Space Efficient**: ~1.14 MB for 1M elements at 1% false positive rate
227
+ - **Fast Operations**: O(k) where k is number of hash functions
228
+ - **No False Negatives**: If it says "not seen", it's definitely unique
229
+ - **Configurable FPR**: Trade memory for accuracy
230
+
231
+ ## Wordlist Format
232
+
233
+ ### Names File
234
+
235
+ One name per line (first + last):
236
+
237
+ ```
238
+ John Smith
239
+ Jane Doe
240
+ Bob Johnson
241
+ ```
242
+
243
+ ### Domains File
244
+
245
+ One domain per line:
246
+
247
+ ```
248
+ gmail.com
249
+ yahoo.com
250
+ example.com
251
+ ```
252
+
253
+ ## License
254
+
255
+ MIT License - see [LICENSE](LICENSE) for details.
256
+
257
+ ## Acknowledgments
258
+
259
+ - [markovify-rs](https://crates.io/crates/markovify-rs) - Markov chain implementation
260
+ - [bloomfilter](https://crates.io/crates/bloomfilter) - Bloom filter implementation
package/bin/mailgen.js ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const os = require('os');
6
+ const { spawnSync } = require('child_process');
7
+
8
+ const binName = os.platform() === 'win32' ? 'emailgen.exe' : 'emailgen';
9
+ const binPath = path.join(__dirname, binName);
10
+
11
+ if (!fs.existsSync(binPath)) {
12
+ console.error('emailgen binary not found. Please reinstall the package.');
13
+ process.exit(1);
14
+ }
15
+
16
+ const result = spawnSync(binPath, process.argv.slice(2), {
17
+ stdio: 'inherit'
18
+ });
19
+
20
+ process.exit(result.status);
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@akin01/mailgen",
3
+ "version": "0.1.0",
4
+ "description": "High-performance email generator using Markov chains and Bloom filters",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "mailgen": "bin/mailgen.js"
8
+ },
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1",
11
+ "postinstall": "node scripts/install.js"
12
+ },
13
+ "files": [
14
+ "bin/",
15
+ "scripts/",
16
+ "README.md",
17
+ "LICENSE"
18
+ ],
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/akin01/emailgen.git"
22
+ },
23
+ "keywords": [
24
+ "email",
25
+ "generator",
26
+ "markov",
27
+ "bloom-filter",
28
+ "cli"
29
+ ],
30
+ "author": "Akin <akinpasha82@gmail.com>",
31
+ "license": "MIT",
32
+ "bugs": {
33
+ "url": "https://github.com/akin01/emailgen/issues"
34
+ },
35
+ "homepage": "https://github.com/akin01/emailgen#readme",
36
+ "engines": {
37
+ "node": ">=12"
38
+ }
39
+ }
@@ -0,0 +1,153 @@
1
+ #!/bin/bash
2
+ # Email Generator Benchmark Script
3
+ #
4
+ # This script runs comprehensive benchmarks for the emailgen project,
5
+ # comparing different generation sizes and measuring performance.
6
+ #
7
+ # Usage:
8
+ # ./scripts/benchmark.sh
9
+ # ./scripts/benchmark.sh --quick # Run quick benchmarks only
10
+ # ./scripts/benchmark.sh --full # Run full benchmarks including 1M generation
11
+
12
+ set -e
13
+
14
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
+ PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
16
+ cd "$PROJECT_DIR"
17
+
18
+ # Colors for output
19
+ RED='\033[0;31m'
20
+ GREEN='\033[0;32m'
21
+ YELLOW='\033[1;33m'
22
+ BLUE='\033[0;34m'
23
+ NC='\033[0m' # No Color
24
+
25
+ # Default settings
26
+ QUICK_MODE=false
27
+ FULL_MODE=false
28
+
29
+ # Parse arguments
30
+ while [[ $# -gt 0 ]]; do
31
+ case $1 in
32
+ --quick|-q)
33
+ QUICK_MODE=true
34
+ shift
35
+ ;;
36
+ --full|-f)
37
+ FULL_MODE=true
38
+ shift
39
+ ;;
40
+ --help|-h)
41
+ echo "Usage: $0 [options]"
42
+ echo ""
43
+ echo "Options:"
44
+ echo " --quick, -q Run quick benchmarks only (no 1M generation)"
45
+ echo " --full, -f Run full benchmarks including 1M email generation"
46
+ echo " --help, -h Show this help message"
47
+ exit 0
48
+ ;;
49
+ *)
50
+ echo "Unknown option: $1"
51
+ exit 1
52
+ ;;
53
+ esac
54
+ done
55
+
56
+ echo -e "${BLUE}============================================${NC}"
57
+ echo -e "${BLUE} Email Generator Performance Benchmarks ${NC}"
58
+ echo -e "${BLUE}============================================${NC}"
59
+ echo ""
60
+
61
+ # Ensure release build exists
62
+ echo -e "${YELLOW}Building release binary...${NC}"
63
+ cargo build --release --quiet 2>/dev/null || cargo build --release
64
+
65
+ echo ""
66
+ echo -e "${YELLOW}Running Criterion benchmarks...${NC}"
67
+ cargo bench --quiet 2>/dev/null || cargo bench
68
+
69
+ echo ""
70
+ echo -e "${BLUE}============================================${NC}"
71
+ echo -e "${BLUE} CLI Generation Benchmarks ${NC}"
72
+ echo -e "${BLUE}============================================${NC}"
73
+ echo ""
74
+
75
+ # Function to run generation benchmark
76
+ run_generation_benchmark() {
77
+ local count=$1
78
+ local label=$2
79
+
80
+ echo -e "${YELLOW}Generating $count emails ($label)...${NC}"
81
+
82
+ local start_time=$(date +%s.%N)
83
+
84
+ # Generate to /dev/null for performance measurement
85
+ cargo run --release --quiet -- --count $count --output /dev/null 2>/dev/null
86
+
87
+ local end_time=$(date +%s.%N)
88
+ local elapsed=$(echo "$end_time - $start_time" | bc)
89
+ local rate=$(echo "scale=0; $count / $elapsed" | bc)
90
+
91
+ echo -e " ${GREEN}✓${NC} Generated $count emails in ${elapsed}s (${rate} emails/sec)"
92
+ }
93
+
94
+ # Quick benchmarks
95
+ echo -e "${BLUE}Quick Benchmarks:${NC}"
96
+ echo "----------------------------------------"
97
+
98
+ run_generation_benchmark 1000 "1K emails"
99
+ run_generation_benchmark 10000 "10K emails"
100
+ run_generation_benchmark 100000 "100K emails"
101
+
102
+ # Full benchmarks
103
+ if [ "$FULL_MODE" = true ] || [ "$QUICK_MODE" = false ]; then
104
+ echo ""
105
+ echo -e "${BLUE}Full Benchmarks:${NC}"
106
+ echo "----------------------------------------"
107
+
108
+ run_generation_benchmark 500000 "500K emails"
109
+
110
+ if [ "$FULL_MODE" = true ]; then
111
+ run_generation_benchmark 1000000 "1M emails"
112
+ fi
113
+ fi
114
+
115
+ echo ""
116
+ echo -e "${BLUE}============================================${NC}"
117
+ echo -e "${BLUE} Memory Usage Analysis ${NC}"
118
+ echo -e "${BLUE}============================================${NC}"
119
+ echo ""
120
+
121
+ # Memory usage test
122
+ echo -e "${YELLOW}Testing memory usage for different capacities:${NC}"
123
+
124
+ for capacity in 10000 100000 1000000; do
125
+ echo ""
126
+ echo "Bloom filter capacity: $capacity"
127
+ cargo run --release --quiet -- --count 1000 --capacity $capacity --stats 2>&1 | grep "Memory usage" || true
128
+ done
129
+
130
+ echo ""
131
+ echo -e "${BLUE}============================================${NC}"
132
+ echo -e "${BLUE} Benchmark Summary ${NC}"
133
+ echo -e "${BLUE}============================================${NC}"
134
+ echo ""
135
+
136
+ # Generate summary
137
+ echo "Performance Targets:"
138
+ echo " ✓ 1K emails: < 0.1 seconds"
139
+ echo " ✓ 10K emails: < 1 second"
140
+ echo " ✓ 100K emails: < 10 seconds"
141
+ echo " ✓ 1M emails: < 100 seconds"
142
+ echo ""
143
+
144
+ echo "Memory Efficiency:"
145
+ echo " ✓ Bloom filter uses ~10-15 MB for 1M emails"
146
+ echo " ✓ False positive rate: 1% (configurable)"
147
+ echo ""
148
+
149
+ echo -e "${GREEN}Benchmarks complete!${NC}"
150
+ echo ""
151
+ echo "For detailed results, see:"
152
+ echo " - target/criterion/report/index.html"
153
+ echo ""
@@ -0,0 +1,36 @@
1
+ #!/bin/bash
2
+ # Quick Email Generation Script
3
+ #
4
+ # Usage:
5
+ # ./scripts/generate.sh [count] [output_file]
6
+ #
7
+ # Examples:
8
+ # ./scripts/generate.sh # Generate 100 emails to stdout
9
+ # ./scripts/generate.sh 1000 # Generate 1K emails to stdout
10
+ # ./scripts/generate.sh 10000 emails.txt # Generate 10K to file
11
+
12
+ set -e
13
+
14
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
+ PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
16
+ cd "$PROJECT_DIR"
17
+
18
+ # Default values
19
+ COUNT=${1:-100}
20
+ OUTPUT=${2:-""}
21
+
22
+ # Build if needed
23
+ if [ ! -f "target/release/emailgen" ]; then
24
+ echo "Building emailgen..."
25
+ cargo build --release --quiet
26
+ fi
27
+
28
+ # Generate
29
+ if [ -n "$OUTPUT" ]; then
30
+ echo "Generating $COUNT emails to $OUTPUT..."
31
+ ./target/release/emailgen --count $COUNT --output "$OUTPUT" --progress
32
+ echo "Done! Generated $COUNT emails."
33
+ echo "File size: $(ls -lh "$OUTPUT" | awk '{print $5}')"
34
+ else
35
+ ./target/release/emailgen --count $COUNT --quiet
36
+ fi
@@ -0,0 +1,103 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const os = require('os');
4
+ const https = require('https');
5
+ const { execSync } = require('child_process');
6
+
7
+ const REPO = "akin01/emailgen";
8
+ const BIN_NAME = os.platform() === 'win32' ? 'emailgen.exe' : 'emailgen';
9
+ const DEST_DIR = path.join(__dirname, '..', 'bin');
10
+
11
+ if (!fs.existsSync(DEST_DIR)) {
12
+ fs.mkdirSync(DEST_DIR, { recursive: true });
13
+ }
14
+
15
+ const getPlatformAsset = () => {
16
+ const platform = os.platform();
17
+ const arch = os.arch();
18
+
19
+ if (platform === 'darwin') {
20
+ if (arch === 'arm64') return `emailgen-macos-aarch64.tar.gz`;
21
+ if (arch === 'x64') return `emailgen-macos-x86_64.tar.gz`;
22
+ }
23
+ if (platform === 'linux') {
24
+ if (arch === 'x64') return `emailgen-linux-x86_64.tar.gz`;
25
+ }
26
+ if (platform === 'win32') {
27
+ if (arch === 'x64') return `emailgen-windows-x86_64.zip`;
28
+ }
29
+
30
+ throw new Error(`Unsupported platform/architecture: ${platform}/${arch}`);
31
+ };
32
+
33
+ const download = (url, dest) => {
34
+ return new Promise((resolve, reject) => {
35
+ const file = fs.createWriteStream(dest);
36
+ https.get(url, (response) => {
37
+ if (response.statusCode === 302 || response.statusCode === 301) {
38
+ download(response.headers.location, dest).then(resolve).catch(reject);
39
+ return;
40
+ }
41
+ if (response.statusCode !== 200) {
42
+ reject(new Error(`Download failed with status code ${response.statusCode}`));
43
+ return;
44
+ }
45
+ response.pipe(file);
46
+ file.on('finish', () => {
47
+ file.close(resolve);
48
+ });
49
+ }).on('error', (err) => {
50
+ fs.unlink(dest, () => {});
51
+ reject(err);
52
+ });
53
+ });
54
+ };
55
+
56
+ const install = async () => {
57
+ try {
58
+ const assetName = getPlatformAsset();
59
+ console.log(`Getting latest release for ${REPO}...`);
60
+
61
+ const apiUrl = `https://api.github.com/repos/${REPO}/releases/latest`;
62
+ const options = {
63
+ headers: { 'User-Agent': 'node.js' }
64
+ };
65
+
66
+ const release = await new Promise((resolve, reject) => {
67
+ https.get(apiUrl, options, (res) => {
68
+ let data = '';
69
+ res.on('data', chunk => data += chunk);
70
+ res.on('end', () => resolve(JSON.parse(data)));
71
+ res.on('error', reject);
72
+ });
73
+ });
74
+
75
+ const tag = release.tag_name;
76
+ const downloadUrl = `https://github.com/${REPO}/releases/download/${tag}/${assetName}`;
77
+ const tempPath = path.join(os.tmpdir(), assetName);
78
+
79
+ console.log(`Downloading ${assetName} from ${tag}...`);
80
+ await download(downloadUrl, tempPath);
81
+
82
+ console.log(`Extracting to ${DEST_DIR}...`);
83
+ if (assetName.endsWith('.zip')) {
84
+ const extractCmd = `powershell Expand-Archive -Path "${tempPath}" -DestinationPath "${DEST_DIR}" -Force`;
85
+ execSync(extractCmd);
86
+ } else {
87
+ const extractCmd = `tar -xzf "${tempPath}" -C "${DEST_DIR}"`;
88
+ execSync(extractCmd);
89
+ }
90
+
91
+ if (os.platform() !== 'win32') {
92
+ fs.chmodSync(path.join(DEST_DIR, BIN_NAME), 0o755);
93
+ }
94
+
95
+ console.log(`Successfully installed emailgen!`);
96
+ fs.unlinkSync(tempPath);
97
+ } catch (err) {
98
+ console.error(`Error during installation: ${err.message}`);
99
+ process.exit(1);
100
+ }
101
+ };
102
+
103
+ install();