@hynaweb/stage 1.0.4 ā 1.0.7
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/dummy.html +84 -0
- package/index.js +128 -0
- package/package.json +10 -11
- package/bin/cli.js +0 -96
package/dummy.html
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>HYNA-Stage Test</title>
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
background-color: #030303;
|
|
10
|
+
color: #ffffff;
|
|
11
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
12
|
+
display: flex;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
align-items: center;
|
|
15
|
+
justify-content: center;
|
|
16
|
+
height: 100vh;
|
|
17
|
+
margin: 0;
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
}
|
|
20
|
+
.glow {
|
|
21
|
+
position: absolute;
|
|
22
|
+
width: 300px;
|
|
23
|
+
height: 300px;
|
|
24
|
+
background: #3B82F6;
|
|
25
|
+
border-radius: 50%;
|
|
26
|
+
filter: blur(80px);
|
|
27
|
+
opacity: 0.3;
|
|
28
|
+
z-index: -1;
|
|
29
|
+
}
|
|
30
|
+
.card {
|
|
31
|
+
background: rgba(10, 10, 10, 0.8);
|
|
32
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
33
|
+
padding: 40px;
|
|
34
|
+
border-radius: 20px;
|
|
35
|
+
text-align: center;
|
|
36
|
+
backdrop-filter: blur(10px);
|
|
37
|
+
box-shadow: 0 10px 30px rgba(0,0,0,0.5);
|
|
38
|
+
}
|
|
39
|
+
h1 {
|
|
40
|
+
font-size: 2rem;
|
|
41
|
+
margin-bottom: 10px;
|
|
42
|
+
background: linear-gradient(to right, #60A5FA, #3B82F6);
|
|
43
|
+
-webkit-background-clip: text;
|
|
44
|
+
-webkit-text-fill-color: transparent;
|
|
45
|
+
}
|
|
46
|
+
p {
|
|
47
|
+
color: #9CA3AF;
|
|
48
|
+
margin-bottom: 20px;
|
|
49
|
+
}
|
|
50
|
+
.status {
|
|
51
|
+
display: inline-block;
|
|
52
|
+
padding: 6px 12px;
|
|
53
|
+
background: rgba(34, 197, 94, 0.1);
|
|
54
|
+
color: #22c55e;
|
|
55
|
+
border: 1px solid rgba(34, 197, 94, 0.2);
|
|
56
|
+
border-radius: 20px;
|
|
57
|
+
font-size: 0.85rem;
|
|
58
|
+
font-weight: bold;
|
|
59
|
+
}
|
|
60
|
+
.time {
|
|
61
|
+
margin-top: 20px;
|
|
62
|
+
font-family: monospace;
|
|
63
|
+
color: #6B7280;
|
|
64
|
+
font-size: 0.9rem;
|
|
65
|
+
}
|
|
66
|
+
</style>
|
|
67
|
+
</head>
|
|
68
|
+
<body>
|
|
69
|
+
<div class="glow"></div>
|
|
70
|
+
<div class="card">
|
|
71
|
+
<h1>š HYNA-Stage is LIVE</h1>
|
|
72
|
+
<p>This environment was provisioned in under 5 seconds.</p>
|
|
73
|
+
<div class="status">ā RUNNING</div>
|
|
74
|
+
<div class="time" id="clock">Loading time...</div>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<script>
|
|
78
|
+
setInterval(() => {
|
|
79
|
+
const now = new Date();
|
|
80
|
+
document.getElementById('clock').innerText = 'Server Time: ' + now.toLocaleTimeString();
|
|
81
|
+
}, 1000);
|
|
82
|
+
</script>
|
|
83
|
+
</body>
|
|
84
|
+
</html>
|
package/index.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { program } from 'commander';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import ora from 'ora';
|
|
8
|
+
import inquirer from 'inquirer';
|
|
9
|
+
|
|
10
|
+
const DEPLOY_URL = "https://mczesspakhkomlnmfstw.supabase.co/functions/v1/deploy-stage";
|
|
11
|
+
const DESTROY_URL = "https://mczesspakhkomlnmfstw.supabase.co/functions/v1/destroy-stage";
|
|
12
|
+
|
|
13
|
+
program
|
|
14
|
+
.name('hyna-stage')
|
|
15
|
+
.description('Ephemeral cloud environments in 5 seconds.')
|
|
16
|
+
.version('1.0.7');
|
|
17
|
+
|
|
18
|
+
// āā UP COMMAND āā
|
|
19
|
+
program
|
|
20
|
+
.command('up')
|
|
21
|
+
.description('Deploy a file to a temporary HYNA environment')
|
|
22
|
+
.option('-f, --file <file>', 'File to deploy', 'index.html')
|
|
23
|
+
.option('-k, --key <key>', 'Your HYNA API key')
|
|
24
|
+
.action(async (options) => {
|
|
25
|
+
let apiKey = options.key;
|
|
26
|
+
if (!apiKey) {
|
|
27
|
+
const answers = await inquirer.prompt([
|
|
28
|
+
{
|
|
29
|
+
type: 'input',
|
|
30
|
+
name: 'key',
|
|
31
|
+
message: 'Enter your HYNA API Key:',
|
|
32
|
+
validate: (input) => input.length > 0 ? true : 'API Key is required'
|
|
33
|
+
}
|
|
34
|
+
]);
|
|
35
|
+
apiKey = answers.key;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const filePath = path.resolve(process.cwd(), options.file);
|
|
39
|
+
if (!fs.existsSync(filePath)) {
|
|
40
|
+
console.error(chalk.red(`ā Error: File not found -> ${options.file}`));
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const stats = fs.statSync(filePath);
|
|
45
|
+
const spinner = ora('Spinning up cloud environment...').start();
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
let fileContent = fs.readFileSync(filePath);
|
|
49
|
+
const isLarge = stats.size > 50000;
|
|
50
|
+
|
|
51
|
+
if (isLarge) {
|
|
52
|
+
spinner.text = 'Encoding large file for transport...';
|
|
53
|
+
fileContent = fileContent.toString('base64');
|
|
54
|
+
} else {
|
|
55
|
+
fileContent = fileContent.toString('utf-8');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
spinner.text = 'Deploying to E2B MicroVM...';
|
|
59
|
+
|
|
60
|
+
const response = await fetch(DEPLOY_URL, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: {
|
|
63
|
+
'Content-Type': 'application/json',
|
|
64
|
+
'Authorization': `Bearer ${apiKey}`
|
|
65
|
+
},
|
|
66
|
+
body: JSON.stringify({ apiKey: apiKey, code: fileContent, isBase64: isLarge })
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const data = await response.json();
|
|
70
|
+
if (!response.ok) throw new Error(data.error || `Server responded with ${response.status}`);
|
|
71
|
+
|
|
72
|
+
spinner.succeed(chalk.green('Environment is LIVE!'));
|
|
73
|
+
|
|
74
|
+
console.log('');
|
|
75
|
+
console.log(chalk.bgBlue.white.bold(` š URL: ${data.url} `));
|
|
76
|
+
console.log(chalk.gray(` Sandbox ID: ${data.sandbox_id}`));
|
|
77
|
+
console.log(chalk.gray(` (Auto-destroys in 1 hour)\n`));
|
|
78
|
+
|
|
79
|
+
} catch (err) {
|
|
80
|
+
spinner.fail(chalk.red('Deployment failed'));
|
|
81
|
+
console.error(chalk.red(`\nā ${err.message}\n`));
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
// āā DOWN COMMAND āā
|
|
86
|
+
program
|
|
87
|
+
.command('down')
|
|
88
|
+
.description('Destroy an active environment early')
|
|
89
|
+
.argument('<sandbox_id>', 'The Sandbox ID to destroy')
|
|
90
|
+
.option('-k, --key <key>', 'Your HYNA API key')
|
|
91
|
+
.action(async (sandboxId, options) => {
|
|
92
|
+
let apiKey = options.key;
|
|
93
|
+
if (!apiKey) {
|
|
94
|
+
const answers = await inquirer.prompt([
|
|
95
|
+
{
|
|
96
|
+
type: 'input',
|
|
97
|
+
name: 'key',
|
|
98
|
+
message: 'Enter your HYNA API Key:',
|
|
99
|
+
validate: (input) => input.length > 0 ? true : 'API Key is required'
|
|
100
|
+
}
|
|
101
|
+
]);
|
|
102
|
+
apiKey = answers.key;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const spinner = ora(`Destroying sandbox ${sandboxId}...`).start();
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
const response = await fetch(DESTROY_URL, {
|
|
109
|
+
method: 'POST',
|
|
110
|
+
headers: {
|
|
111
|
+
'Content-Type': 'application/json',
|
|
112
|
+
'Authorization': `Bearer ${apiKey}`
|
|
113
|
+
},
|
|
114
|
+
body: JSON.stringify({ sandbox_id: sandboxId })
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const data = await response.json();
|
|
118
|
+
if (!response.ok) throw new Error(data.error || 'Failed to destroy sandbox');
|
|
119
|
+
|
|
120
|
+
spinner.succeed(chalk.green('Environment destroyed successfully!'));
|
|
121
|
+
console.log(chalk.gray(` The E2B VM has been terminated.\n`));
|
|
122
|
+
} catch (err) {
|
|
123
|
+
spinner.fail(chalk.red('Destroy failed'));
|
|
124
|
+
console.error(chalk.red(`\nā ${err.message}\n`));
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
program.parse();
|
package/package.json
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hynaweb/stage",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
5
|
-
"main": "
|
|
3
|
+
"version": "1.0.7",
|
|
4
|
+
"description": "Ephemeral cloud environments in 5 seconds.",
|
|
5
|
+
"main": "index.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"hyna-stage": "
|
|
7
|
+
"hyna-stage": "./index.js"
|
|
8
8
|
},
|
|
9
|
-
"
|
|
10
|
-
"bin/"
|
|
11
|
-
],
|
|
9
|
+
"type": "module",
|
|
12
10
|
"dependencies": {
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
"chalk": "^5.3.0",
|
|
12
|
+
"commander": "^11.0.0",
|
|
13
|
+
"inquirer": "^9.2.12",
|
|
14
|
+
"ora": "^7.0.1"
|
|
15
|
+
}
|
|
17
16
|
}
|
package/bin/cli.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const axios = require('axios');
|
|
3
|
-
const fs = require('fs');
|
|
4
|
-
const path = require('path');
|
|
5
|
-
const readline = require('readline');
|
|
6
|
-
|
|
7
|
-
const API_URL = 'https://mczesspakhkomlnmfstw.supabase.co/functions/v1/deploy-stage';
|
|
8
|
-
const DESTROY_URL = 'https://mczesspakhkomlnmfstw.supabase.co/functions/v1/destroy-stage';
|
|
9
|
-
const SUPABASE_KEY = 'sb_publishable_sG0q8k6txKHOihBduyr67w_UKfolcvj';
|
|
10
|
-
|
|
11
|
-
const configPath = path.join(require('os').homedir(), '.hyna-stage');
|
|
12
|
-
|
|
13
|
-
async function getApiKey() {
|
|
14
|
-
// Check for --key argument first (Auto-Injection)
|
|
15
|
-
const keyArg = process.argv.find(arg => arg.startsWith('--key='));
|
|
16
|
-
if (keyArg) {
|
|
17
|
-
const key = keyArg.split('=')[1];
|
|
18
|
-
fs.writeFileSync(configPath, key.trim()); // Save it for next time
|
|
19
|
-
return key.trim();
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Check cache
|
|
23
|
-
if (fs.existsSync(configPath)) {
|
|
24
|
-
return fs.readFileSync(configPath, 'utf8').trim();
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// Otherwise prompt
|
|
28
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
29
|
-
return new Promise((resolve) => {
|
|
30
|
-
rl.question('š Enter your HYNA-Stage API Key: ', (key) => {
|
|
31
|
-
fs.writeFileSync(configPath, key.trim());
|
|
32
|
-
rl.close();
|
|
33
|
-
resolve(key.trim());
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async function main() {
|
|
39
|
-
const command = process.argv[2];
|
|
40
|
-
const apiKey = await getApiKey();
|
|
41
|
-
|
|
42
|
-
if (command === 'up') {
|
|
43
|
-
console.log('š Initializing HYNA-Stage...');
|
|
44
|
-
console.log('š¦ Spinning up cloud environment...');
|
|
45
|
-
|
|
46
|
-
try {
|
|
47
|
-
const res = await axios.post(API_URL, {}, {
|
|
48
|
-
headers: {
|
|
49
|
-
'Authorization': 'Bearer ' + apiKey,
|
|
50
|
-
'apikey': SUPABASE_KEY,
|
|
51
|
-
'Content-Type': 'application/json'
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
console.log('\nā
Environment is LIVE!');
|
|
56
|
-
console.log('š URL: \x1b[36m' + res.data.url + '\x1b[0m');
|
|
57
|
-
console.log('š Sandbox ID: ' + res.data.sandbox_id);
|
|
58
|
-
console.log('ā±ļø Auto-destruct in: 1 hour\n');
|
|
59
|
-
|
|
60
|
-
} catch (err) {
|
|
61
|
-
console.error('ā Error:', err.response?.data?.error || err.message);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
else if (command === 'down') {
|
|
65
|
-
const sandboxId = process.argv.find(arg => !arg.startsWith('--') && arg !== 'down' && arg !== 'up');
|
|
66
|
-
|
|
67
|
-
if (!sandboxId) {
|
|
68
|
-
console.error('ā Please provide a sandbox ID: hyna-stage down <sandbox_id>');
|
|
69
|
-
process.exit(1);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
console.log('šļø Destroying sandbox ' + sandboxId + '...');
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
await axios.post(DESTROY_URL, { sandbox_id: sandboxId }, {
|
|
76
|
-
headers: {
|
|
77
|
-
'Authorization': 'Bearer ' + apiKey,
|
|
78
|
-
'apikey': SUPABASE_KEY,
|
|
79
|
-
'Content-Type': 'application/json'
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
console.log('\nā
Environment destroyed successfully.\n');
|
|
84
|
-
|
|
85
|
-
} catch (err) {
|
|
86
|
-
console.error('ā Error:', err.response?.data?.error || err.message);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
console.log('Usage:');
|
|
91
|
-
console.log(' hyna-stage up Spin up a new environment');
|
|
92
|
-
console.log(' hyna-stage down <id> Destroy a specific environment');
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
main();
|