@vibedhost/cli 1.0.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/utils.js ADDED
@@ -0,0 +1,336 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.MAX_PAYLOAD_BYTES = exports.PROJECT_CONFIG_FILE = exports.PROJECT_CONFIG_DIR = exports.GLOBAL_CONFIG_FILE = exports.GLOBAL_CONFIG_DIR = exports.API_BASE_URL = void 0;
7
+ exports.computeBufferSha256 = computeBufferSha256;
8
+ exports.readGlobalConfig = readGlobalConfig;
9
+ exports.writeGlobalConfig = writeGlobalConfig;
10
+ exports.clearGlobalConfig = clearGlobalConfig;
11
+ exports.readProjectConfig = readProjectConfig;
12
+ exports.writeProjectConfig = writeProjectConfig;
13
+ exports.openBrowser = openBrowser;
14
+ exports.scanDirectory = scanDirectory;
15
+ exports.createZipBuffer = createZipBuffer;
16
+ exports.askQuestion = askQuestion;
17
+ exports.inferAppName = inferAppName;
18
+ const fs_1 = __importDefault(require("fs"));
19
+ const path_1 = __importDefault(require("path"));
20
+ const os_1 = __importDefault(require("os"));
21
+ const zlib_1 = __importDefault(require("zlib"));
22
+ const child_process_1 = require("child_process");
23
+ exports.API_BASE_URL = process.env.VIBED_API_URL || "https://www.vibedhost.com";
24
+ exports.GLOBAL_CONFIG_DIR = path_1.default.join(os_1.default.homedir(), ".vibed");
25
+ exports.GLOBAL_CONFIG_FILE = path_1.default.join(exports.GLOBAL_CONFIG_DIR, "config.json");
26
+ exports.PROJECT_CONFIG_DIR = ".vibed";
27
+ exports.PROJECT_CONFIG_FILE = path_1.default.join(".vibed", "config.json");
28
+ exports.MAX_PAYLOAD_BYTES = 50 * 1024 * 1024; // 50MB
29
+ const DEFAULT_IGNORED_DIRS = [
30
+ "node_modules",
31
+ ".git",
32
+ ".next",
33
+ "dist",
34
+ "build",
35
+ ".output",
36
+ ".venv",
37
+ "venv",
38
+ "env",
39
+ "__pycache__",
40
+ ".turbo",
41
+ ".cache",
42
+ ".local",
43
+ ".vibed",
44
+ ".aws",
45
+ ".ssh"
46
+ ];
47
+ const DEFAULT_IGNORED_EXACT_FILES = [
48
+ ".ds_store",
49
+ "thumbs.db",
50
+ ".npmrc",
51
+ ".git-credentials",
52
+ "credentials.json",
53
+ "service-account.json",
54
+ "id_rsa",
55
+ "id_ed25519"
56
+ ];
57
+ const IGNORED_EXTENSIONS_REGEX = /\.(mp4|mov|mkv|avi|iso|tar\.gz|zip|7z|rar|dmg|exe|dll|so|pem|key|pfx|p12|kdbx)$/i;
58
+ const crypto_1 = __importDefault(require("crypto"));
59
+ function computeBufferSha256(buf) {
60
+ return crypto_1.default.createHash("sha256").update(buf).digest("hex");
61
+ }
62
+ function readGlobalConfig() {
63
+ try {
64
+ if (!fs_1.default.existsSync(exports.GLOBAL_CONFIG_FILE))
65
+ return null;
66
+ const raw = fs_1.default.readFileSync(exports.GLOBAL_CONFIG_FILE, "utf-8");
67
+ return JSON.parse(raw);
68
+ }
69
+ catch {
70
+ return null;
71
+ }
72
+ }
73
+ function writeGlobalConfig(config) {
74
+ try {
75
+ if (!fs_1.default.existsSync(exports.GLOBAL_CONFIG_DIR)) {
76
+ fs_1.default.mkdirSync(exports.GLOBAL_CONFIG_DIR, { recursive: true, mode: 0o700 });
77
+ }
78
+ fs_1.default.writeFileSync(exports.GLOBAL_CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
79
+ }
80
+ catch (err) {
81
+ console.error(`Failed to write local configuration: ${err.message}`);
82
+ }
83
+ }
84
+ function clearGlobalConfig() {
85
+ try {
86
+ if (fs_1.default.existsSync(exports.GLOBAL_CONFIG_FILE)) {
87
+ fs_1.default.unlinkSync(exports.GLOBAL_CONFIG_FILE);
88
+ }
89
+ }
90
+ catch { }
91
+ }
92
+ function readProjectConfig(targetDir = process.cwd()) {
93
+ try {
94
+ const configPath = path_1.default.join(targetDir, exports.PROJECT_CONFIG_FILE);
95
+ if (!fs_1.default.existsSync(configPath))
96
+ return null;
97
+ const raw = fs_1.default.readFileSync(configPath, "utf-8");
98
+ return JSON.parse(raw);
99
+ }
100
+ catch {
101
+ return null;
102
+ }
103
+ }
104
+ function writeProjectConfig(config, targetDir = process.cwd()) {
105
+ try {
106
+ const dirPath = path_1.default.join(targetDir, exports.PROJECT_CONFIG_DIR);
107
+ if (!fs_1.default.existsSync(dirPath)) {
108
+ fs_1.default.mkdirSync(dirPath, { recursive: true });
109
+ }
110
+ const configPath = path_1.default.join(targetDir, exports.PROJECT_CONFIG_FILE);
111
+ fs_1.default.writeFileSync(configPath, JSON.stringify(config, null, 2));
112
+ }
113
+ catch { }
114
+ }
115
+ function openBrowser(url) {
116
+ try {
117
+ const parsed = new URL(url);
118
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
119
+ return;
120
+ }
121
+ // Reject shell control characters
122
+ if (/[\r\n"';`$&|<>]/.test(url)) {
123
+ return;
124
+ }
125
+ }
126
+ catch {
127
+ return;
128
+ }
129
+ const platform = process.platform;
130
+ let command = "";
131
+ if (platform === "darwin") {
132
+ command = `open "${url}"`;
133
+ }
134
+ else if (platform === "win32") {
135
+ command = `start "" "${url}"`;
136
+ }
137
+ else {
138
+ command = `xdg-open "${url}"`;
139
+ }
140
+ (0, child_process_1.exec)(command, () => { });
141
+ }
142
+ function scanDirectory(rootDir, currentDir = rootDir, collected = [], bloatFound = {}) {
143
+ const items = fs_1.default.readdirSync(currentDir, { withFileTypes: true });
144
+ let realRootDir = rootDir;
145
+ try {
146
+ realRootDir = fs_1.default.realpathSync(rootDir);
147
+ }
148
+ catch { }
149
+ for (const item of items) {
150
+ const itemName = item.name;
151
+ const fullPath = path_1.default.join(currentDir, itemName);
152
+ const relPath = path_1.default.relative(rootDir, fullPath).replace(/\\/g, "/");
153
+ // Symlink Boundary Guard: Ensure symlinks do not escape project root
154
+ try {
155
+ const lstat = fs_1.default.lstatSync(fullPath);
156
+ if (lstat.isSymbolicLink()) {
157
+ const realPath = fs_1.default.realpathSync(fullPath);
158
+ if (!realPath.startsWith(realRootDir)) {
159
+ continue;
160
+ }
161
+ }
162
+ }
163
+ catch {
164
+ continue;
165
+ }
166
+ if (item.isDirectory()) {
167
+ if (DEFAULT_IGNORED_DIRS.includes(itemName) || itemName.startsWith(".")) {
168
+ // Track directory size for diagnostic reporting
169
+ try {
170
+ const dirStat = getDirectorySize(fullPath);
171
+ bloatFound[itemName] = (bloatFound[itemName] || 0) + dirStat;
172
+ }
173
+ catch { }
174
+ continue;
175
+ }
176
+ scanDirectory(rootDir, fullPath, collected, bloatFound);
177
+ }
178
+ else if (item.isFile()) {
179
+ const lowerName = itemName.toLowerCase();
180
+ if (DEFAULT_IGNORED_EXACT_FILES.includes(lowerName) ||
181
+ lowerName.startsWith(".env") ||
182
+ IGNORED_EXTENSIONS_REGEX.test(lowerName)) {
183
+ continue;
184
+ }
185
+ try {
186
+ const stat = fs_1.default.statSync(fullPath);
187
+ collected.push({
188
+ relativePath: relPath,
189
+ absolutePath: fullPath,
190
+ size: stat.size
191
+ });
192
+ }
193
+ catch { }
194
+ }
195
+ }
196
+ return { files: collected, bloatReport: bloatFound };
197
+ }
198
+ function getDirectorySize(dirPath) {
199
+ let total = 0;
200
+ try {
201
+ const items = fs_1.default.readdirSync(dirPath, { withFileTypes: true });
202
+ for (const item of items) {
203
+ const p = path_1.default.join(dirPath, item.name);
204
+ if (item.isDirectory()) {
205
+ total += getDirectorySize(p);
206
+ }
207
+ else if (item.isFile()) {
208
+ total += fs_1.default.statSync(p).size;
209
+ }
210
+ }
211
+ }
212
+ catch { }
213
+ return total;
214
+ }
215
+ /**
216
+ * Pure zero-dependency in-memory PKZip generator.
217
+ */
218
+ function createZipBuffer(files) {
219
+ const localHeaders = [];
220
+ const centralRecords = [];
221
+ let offset = 0;
222
+ for (const file of files) {
223
+ const fileContent = fs_1.default.readFileSync(file.absolutePath);
224
+ const uncompressedSize = fileContent.length;
225
+ const crc = computeCrc32(fileContent);
226
+ const compressedContent = zlib_1.default.deflateRawSync(fileContent);
227
+ const compressedSize = compressedContent.length;
228
+ const pathBuffer = Buffer.from(file.relativePath, "utf8");
229
+ const pathLength = pathBuffer.length;
230
+ // 1. Local File Header (30 Bytes)
231
+ const localHeader = Buffer.alloc(30 + pathLength);
232
+ localHeader.writeUInt32LE(0x04034b50, 0); // Signature
233
+ localHeader.writeUInt16LE(20, 4); // Version needed
234
+ localHeader.writeUInt16LE(0, 6); // Flags
235
+ localHeader.writeUInt16LE(8, 8); // Compression (Deflate)
236
+ localHeader.writeUInt16LE(0, 10); // Mod time
237
+ localHeader.writeUInt16LE(0, 12); // Mod date
238
+ localHeader.writeUInt32LE(crc, 14); // CRC-32
239
+ localHeader.writeUInt32LE(compressedSize, 18);
240
+ localHeader.writeUInt32LE(uncompressedSize, 22);
241
+ localHeader.writeUInt16LE(pathLength, 26);
242
+ localHeader.writeUInt16LE(0, 28); // Extra field length
243
+ pathBuffer.copy(localHeader, 30);
244
+ localHeaders.push(localHeader, compressedContent);
245
+ // 2. Central Directory Record (46 Bytes)
246
+ const centralRecord = Buffer.alloc(46 + pathLength);
247
+ centralRecord.writeUInt32LE(0x02014b50, 0); // Signature
248
+ centralRecord.writeUInt16LE(20, 4); // Version made by
249
+ centralRecord.writeUInt16LE(20, 6); // Version needed
250
+ centralRecord.writeUInt16LE(0, 8); // Flags
251
+ centralRecord.writeUInt16LE(8, 10); // Compression
252
+ centralRecord.writeUInt16LE(0, 12); // Mod time
253
+ centralRecord.writeUInt16LE(0, 14); // Mod date
254
+ centralRecord.writeUInt32LE(crc, 16); // CRC-32
255
+ centralRecord.writeUInt32LE(compressedSize, 20);
256
+ centralRecord.writeUInt32LE(uncompressedSize, 24);
257
+ centralRecord.writeUInt16LE(pathLength, 28);
258
+ centralRecord.writeUInt16LE(0, 30); // Extra field length
259
+ centralRecord.writeUInt16LE(0, 32); // Comment length
260
+ centralRecord.writeUInt16LE(0, 34); // Disk start
261
+ centralRecord.writeUInt16LE(0, 36); // Internal attr
262
+ centralRecord.writeUInt32LE(0, 38); // External attr
263
+ centralRecord.writeUInt32LE(offset, 42); // Relative offset of local header
264
+ pathBuffer.copy(centralRecord, 46);
265
+ centralRecords.push(centralRecord);
266
+ offset += localHeader.length + compressedContent.length;
267
+ }
268
+ const centralDirBuffer = Buffer.concat(centralRecords);
269
+ const centralDirSize = centralDirBuffer.length;
270
+ const centralDirOffset = offset;
271
+ const totalEntries = files.length;
272
+ // 3. End of Central Directory Record (22 Bytes)
273
+ const eocd = Buffer.alloc(22);
274
+ eocd.writeUInt32LE(0x06054b50, 0); // Signature
275
+ eocd.writeUInt16LE(0, 4); // Disk number
276
+ eocd.writeUInt16LE(0, 6); // Disk with CD
277
+ eocd.writeUInt16LE(totalEntries, 8);
278
+ eocd.writeUInt16LE(totalEntries, 10);
279
+ eocd.writeUInt32LE(centralDirSize, 12);
280
+ eocd.writeUInt32LE(centralDirOffset, 16);
281
+ eocd.writeUInt16LE(0, 20); // Comment length
282
+ return Buffer.concat([...localHeaders, centralDirBuffer, eocd]);
283
+ }
284
+ const CRC_TABLE = new Uint32Array(256);
285
+ for (let i = 0; i < 256; i++) {
286
+ let c = i;
287
+ for (let j = 0; j < 8; j++) {
288
+ c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
289
+ }
290
+ CRC_TABLE[i] = c;
291
+ }
292
+ function computeCrc32(buf) {
293
+ let crc = 0xffffffff;
294
+ for (let i = 0; i < buf.length; i++) {
295
+ crc = CRC_TABLE[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);
296
+ }
297
+ return (crc ^ 0xffffffff) >>> 0;
298
+ }
299
+ const readline_1 = __importDefault(require("readline"));
300
+ function askQuestion(query, defaultValue = "") {
301
+ return new Promise((resolve) => {
302
+ const rl = readline_1.default.createInterface({
303
+ input: process.stdin,
304
+ output: process.stdout,
305
+ });
306
+ const promptText = defaultValue ? `${query} [${defaultValue}]: ` : `${query}: `;
307
+ rl.question(promptText, (answer) => {
308
+ rl.close();
309
+ const trimmed = answer.trim();
310
+ resolve(trimmed || defaultValue);
311
+ });
312
+ });
313
+ }
314
+ function inferAppName(targetDir) {
315
+ try {
316
+ const pkgPath = path_1.default.join(targetDir, "package.json");
317
+ if (fs_1.default.existsSync(pkgPath)) {
318
+ const pkg = JSON.parse(fs_1.default.readFileSync(pkgPath, "utf-8"));
319
+ if (pkg.name) {
320
+ const clean = String(pkg.name)
321
+ .replace(/^@[^/]+\//, "")
322
+ .toLowerCase()
323
+ .replace(/[^a-z0-9-]/g, "-")
324
+ .replace(/(^-|-$)+/g, "");
325
+ if (clean)
326
+ return clean;
327
+ }
328
+ }
329
+ }
330
+ catch { }
331
+ return path_1.default
332
+ .basename(targetDir)
333
+ .toLowerCase()
334
+ .replace(/[^a-z0-9-]/g, "-")
335
+ .replace(/(^-|-$)+/g, "");
336
+ }
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@vibedhost/cli",
3
+ "version": "1.0.0",
4
+ "description": "VibedHost Cloud Engine CLI — Deploy applications to dedicated cloud workspaces directly from your terminal.",
5
+ "main": "./dist/index.js",
6
+ "bin": {
7
+ "vibed": "./dist/index.js",
8
+ "vibedhost": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "prepublishOnly": "npm run build"
13
+ },
14
+ "keywords": [
15
+ "vibedhost",
16
+ "paas",
17
+ "deploy",
18
+ "cloud",
19
+ "vps",
20
+ "nextjs",
21
+ "docker",
22
+ "cli"
23
+ ],
24
+ "author": "VibedHost Cloud Engine",
25
+ "license": "MIT",
26
+ "engines": {
27
+ "node": ">=18.0.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^20.14.0",
31
+ "typescript": "^5.4.5"
32
+ }
33
+ }