@hynaweb/stage 1.3.0 → 2.0.1

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/index.js DELETED
@@ -1,189 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- import { program } from 'commander';
4
- import fs from 'fs';
5
- import path from 'path';
6
- import os from 'os'; // Import OS to find the home directory
7
- import chalk from 'chalk';
8
- import ora from 'ora';
9
- import inquirer from 'inquirer';
10
-
11
- const DEPLOY_URL = "https://mczesspakhkomlnmfstw.supabase.co/functions/v1/deploy-stage";
12
- const DESTROY_URL = "https://mczesspakhkomlnmfstw.supabase.co/functions/v1/destroy-stage";
13
-
14
- // Helper function to auto-detect file type
15
- function detectType(file) {
16
- const ext = path.extname(file).toLowerCase();
17
- if (['.html', '.htm', '.css'].includes(ext)) return 'html';
18
- if (['.js', '.cjs', '.mjs'].includes(ext)) return 'node';
19
- if (['.py'].includes(ext)) return 'python';
20
- if (['.java'].includes(ext)) return 'java';
21
- return null; // Unknown extension
22
- }
23
-
24
- // Helper function to save the key to .bashrc
25
- function saveKeyToBashrc(key) {
26
- try {
27
- const bashrcPath = path.join(os.homedir(), '.bashrc');
28
- const saveString = `\n# HynaStage API Key\nexport HYNA_API_KEY="${key}"\n`;
29
-
30
- // Check if it already exists to avoid duplicates
31
- if (fs.existsSync(bashrcPath)) {
32
- const content = fs.readFileSync(bashrcPath, 'utf8');
33
- if (content.includes('HYNA_API_KEY=')) return;
34
- }
35
-
36
- fs.appendFileSync(bashrcPath, saveString);
37
- console.log(chalk.green('✅ API Key saved to ~/.bashrc! You won\'t need to enter it again in new sessions.'));
38
- } catch (e) {
39
- console.log(chalk.yellow('⚠️ Could not save key to .bashrc.'));
40
- }
41
- }
42
-
43
- program
44
- .name('hyna-stage')
45
- .description('Ephemeral cloud environments in 5 seconds.')
46
- .version('1.2.0');
47
-
48
- // ── UP COMMAND ──
49
- program
50
- .command('up')
51
- .description('Deploy a file to a temporary HYNA environment')
52
- .option('-f, --file <file>', 'File to deploy', 'index.html')
53
- .option('-t, --type <type>', 'Force project type (html, node, python, java)')
54
- .option('-k, --key <key>', 'Your HYNA API key (overrides .bashrc)')
55
- .action(async (options) => {
56
-
57
- // 1. Get API Key (CLI Flag -> Env Var -> Prompt & Save)
58
- let apiKey = options.key || process.env.HYNA_API_KEY;
59
-
60
- if (!apiKey) {
61
- const answers = await inquirer.prompt([
62
- {
63
- type: 'input',
64
- name: 'key',
65
- message: 'Enter your HYNA API Key (will be saved for next time):',
66
- validate: (input) => input.length > 0 ? true : 'API Key is required'
67
- }
68
- ]);
69
- apiKey = answers.key;
70
- process.env.HYNA_API_KEY = apiKey; // Set for current session
71
- saveKeyToBashrc(apiKey); // Save for future sessions
72
- }
73
-
74
- // 2. Check if file exists
75
- const filePath = path.resolve(process.cwd(), options.file);
76
- if (!fs.existsSync(filePath)) {
77
- console.error(chalk.red(`❌ Error: File not found -> ${options.file}`));
78
- process.exit(1);
79
- }
80
-
81
- // 3. Determine Project Type
82
- let projectType = options.type || detectType(options.file);
83
-
84
- if (!projectType) {
85
- const typeAnswer = await inquirer.prompt([
86
- {
87
- type: 'list',
88
- name: 'type',
89
- message: 'What is the type of the project?',
90
- choices: ['html', 'node', 'python', 'java']
91
- }
92
- ]);
93
- projectType = typeAnswer.type;
94
- }
95
-
96
- const stats = fs.statSync(filePath);
97
- const spinner = ora(`Spinning up ${projectType.toUpperCase()} environment...`).start();
98
-
99
- try {
100
- let fileContent = fs.readFileSync(filePath);
101
- const isLarge = stats.size > 50000;
102
-
103
- if (isLarge) {
104
- spinner.text = 'Encoding large file for transport...';
105
- fileContent = fileContent.toString('base64');
106
- } else {
107
- fileContent = fileContent.toString('utf-8');
108
- }
109
-
110
- spinner.text = 'Deploying to E2B MicroVM...';
111
-
112
- const response = await fetch(DEPLOY_URL, {
113
- method: 'POST',
114
- headers: {
115
- 'Content-Type': 'application/json',
116
- 'Authorization': `Bearer ${apiKey}`
117
- },
118
- body: JSON.stringify({
119
- apiKey: apiKey,
120
- code: fileContent,
121
- isBase64: isLarge,
122
- type: projectType
123
- })
124
- });
125
-
126
- const data = await response.json();
127
- if (!response.ok) throw new Error(data.error || `Server responded with ${response.status}`);
128
-
129
- spinner.succeed(chalk.green('Environment is LIVE!'));
130
-
131
- console.log('');
132
- console.log(chalk.bgBlue.white.bold(` 🔗 URL: ${data.url} `));
133
- console.log(chalk.gray(` Type: ${data.type}`));
134
- console.log(chalk.gray(` Sandbox ID: ${data.sandbox_id}`));
135
- console.log(chalk.gray(` (Auto-destroys in 1 hour)\n`)); // FIXED: Now says 1 hour
136
-
137
- } catch (err) {
138
- spinner.fail(chalk.red('Deployment failed'));
139
- console.error(chalk.red(`\n❌ ${err.message}\n`));
140
- }
141
- });
142
-
143
- // ── DOWN COMMAND ──
144
- program
145
- .command('down')
146
- .description('Destroy an active environment early')
147
- .argument('<sandbox_id>', 'The Sandbox ID to destroy')
148
- .option('-k, --key <key>', 'Your HYNA API key')
149
- .action(async (sandboxId, options) => {
150
- let apiKey = options.key || process.env.HYNA_API_KEY;
151
-
152
- if (!apiKey) {
153
- const answers = await inquirer.prompt([
154
- {
155
- type: 'input',
156
- name: 'key',
157
- message: 'Enter your HYNA API Key:',
158
- validate: (input) => input.length > 0 ? true : 'API Key is required'
159
- }
160
- ]);
161
- apiKey = answers.key;
162
- process.env.HYNA_API_KEY = apiKey;
163
- saveKeyToBashrc(apiKey);
164
- }
165
-
166
- const spinner = ora(`Destroying sandbox ${sandboxId}...`).start();
167
-
168
- try {
169
- const response = await fetch(DESTROY_URL, {
170
- method: 'POST',
171
- headers: {
172
- 'Content-Type': 'application/json',
173
- 'Authorization': `Bearer ${apiKey}`
174
- },
175
- body: JSON.stringify({ sandbox_id: sandboxId })
176
- });
177
-
178
- const data = await response.json();
179
- if (!response.ok) throw new Error(data.error || 'Failed to destroy sandbox');
180
-
181
- spinner.succeed(chalk.green('Environment destroyed successfully!'));
182
- console.log(chalk.gray(` The E2B VM has been terminated.\n`));
183
- } catch (err) {
184
- spinner.fail(chalk.red('Destroy failed'));
185
- console.error(chalk.red(`\n❌ ${err.message}\n`));
186
- }
187
- });
188
-
189
- program.parse();
package/inject_logo.py DELETED
@@ -1,32 +0,0 @@
1
- import base64
2
- import re
3
- import os
4
-
5
- try:
6
- if not os.path.exists('logo.png'):
7
- print("Error: logo.png not found in this folder!")
8
- exit()
9
-
10
- with open('logo.png', 'rb') as f:
11
- b64 = base64.b64encode(f.read()).decode('utf-8')
12
- data_uri = f"data:image/png;base64,{b64}"
13
-
14
- for filename in ['index.html', 'dashboard.html']:
15
- if not os.path.exists(filename): continue
16
-
17
- with open(filename, 'r') as f:
18
- content = f.read()
19
-
20
- # 1. Replace the standard img tag
21
- content = content.replace('<img src="logo.png" class="nav-logo">', f'<img src="{data_uri}" class="nav-logo">')
22
- content = content.replace('<img src="logo.png" class="hero-logo">', f'<img src="{data_uri}" class="hero-logo">')
23
-
24
- # 2. Replace the fallback SVG block if it exists
25
- content = re.sub(r'<div class="logo-container">.*?</div>', f'<div class="logo-container"><img src="{data_uri}" class="nav-logo"> HYNA-Stage</div>', content, flags=re.DOTALL)
26
-
27
- with open(filename, 'w') as f:
28
- f.write(content)
29
-
30
- print("✅ Success! Logo baked directly into index.html and dashboard.html")
31
- except Exception as e:
32
- print(f"Error: {e}")
package/logo.png DELETED
Binary file