@oussema_mili/test-pkg-123 1.1.22

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.

Potentially problematic release.


This version of @oussema_mili/test-pkg-123 might be problematic. Click here for more details.

Files changed (49) hide show
  1. package/LICENSE +29 -0
  2. package/README.md +220 -0
  3. package/auth-callback.html +97 -0
  4. package/auth.js +276 -0
  5. package/cli-commands.js +1923 -0
  6. package/containerManager.js +304 -0
  7. package/daemon/agentRunner.js +429 -0
  8. package/daemon/daemonEntry.js +64 -0
  9. package/daemon/daemonManager.js +271 -0
  10. package/daemon/logManager.js +227 -0
  11. package/dist/styles.css +504 -0
  12. package/docker-actions/apps.js +3938 -0
  13. package/docker-actions/config-transformer.js +380 -0
  14. package/docker-actions/containers.js +355 -0
  15. package/docker-actions/general.js +171 -0
  16. package/docker-actions/images.js +1128 -0
  17. package/docker-actions/logs.js +224 -0
  18. package/docker-actions/metrics.js +270 -0
  19. package/docker-actions/registry.js +1100 -0
  20. package/docker-actions/setup-tasks.js +859 -0
  21. package/docker-actions/terminal.js +247 -0
  22. package/docker-actions/volumes.js +696 -0
  23. package/helper-functions.js +193 -0
  24. package/index.html +83 -0
  25. package/index.js +341 -0
  26. package/package.json +82 -0
  27. package/postcss.config.mjs +5 -0
  28. package/scripts/release.sh +212 -0
  29. package/setup/setupWizard.js +403 -0
  30. package/store/agentSessionStore.js +51 -0
  31. package/store/agentStore.js +113 -0
  32. package/store/configStore.js +171 -0
  33. package/store/daemonStore.js +217 -0
  34. package/store/deviceCredentialStore.js +107 -0
  35. package/store/npmTokenStore.js +65 -0
  36. package/store/registryStore.js +329 -0
  37. package/store/setupState.js +147 -0
  38. package/styles.css +1 -0
  39. package/utils/appLogger.js +223 -0
  40. package/utils/deviceInfo.js +98 -0
  41. package/utils/ecrAuth.js +225 -0
  42. package/utils/encryption.js +112 -0
  43. package/utils/envSetup.js +44 -0
  44. package/utils/errorHandler.js +327 -0
  45. package/utils/portUtils.js +59 -0
  46. package/utils/prerequisites.js +323 -0
  47. package/utils/prompts.js +318 -0
  48. package/utils/ssl-certificates.js +256 -0
  49. package/websocket-server.js +415 -0
@@ -0,0 +1,318 @@
1
+ import inquirer from 'inquirer';
2
+ import ora from 'ora';
3
+ import chalk from 'chalk';
4
+
5
+ /**
6
+ * Prompt for registration token
7
+ *
8
+ * @param {string} fenwaveUrl - Fenwave URL to display
9
+ * @returns {Promise<string>} Registration token
10
+ */
11
+ export async function promptRegistrationToken(fenwaveUrl) {
12
+ console.log(chalk.blue('\n📝 Registration Token Required\n'));
13
+ console.log(chalk.gray(`Get your token from: ${fenwaveUrl}/agent-installer\n`));
14
+
15
+ const answers = await inquirer.prompt([
16
+ {
17
+ type: 'password',
18
+ name: 'token',
19
+ message: 'Enter your registration token:',
20
+ mask: '*',
21
+ validate: (input) => {
22
+ if (!input || input.trim().length === 0) {
23
+ return 'Registration token is required';
24
+ }
25
+ if (input.length < 32) {
26
+ return 'Invalid token format';
27
+ }
28
+ return true;
29
+ },
30
+ },
31
+ ]);
32
+
33
+ return answers.token.trim();
34
+ }
35
+
36
+ /**
37
+ * Prompt for confirmation
38
+ *
39
+ * @param {string} message - Confirmation message
40
+ * @param {boolean} defaultValue - Default value (true/false)
41
+ * @returns {Promise<boolean>} User's answer
42
+ */
43
+ export async function promptConfirmation(message, defaultValue = true) {
44
+ const answers = await inquirer.prompt([
45
+ {
46
+ type: 'confirm',
47
+ name: 'confirmed',
48
+ message,
49
+ default: defaultValue,
50
+ },
51
+ ]);
52
+
53
+ return answers.confirmed;
54
+ }
55
+
56
+ /**
57
+ * Prompt for Docker registry configuration
58
+ *
59
+ * @returns {Promise<Object>} Registry configuration
60
+ */
61
+ export async function promptDockerRegistries() {
62
+ console.log(chalk.blue('\n🐳 Docker Registry Configuration\n'));
63
+
64
+ const answers = await inquirer.prompt([
65
+ {
66
+ type: 'confirm',
67
+ name: 'configureEcr',
68
+ message: 'Configure AWS ECR for Fenwave images?',
69
+ default: true,
70
+ },
71
+ {
72
+ type: 'input',
73
+ name: 'awsRegion',
74
+ message: 'AWS Region:',
75
+ default: 'eu-west-1',
76
+ when: (answers) => answers.configureEcr,
77
+ validate: (input) => {
78
+ if (!input || input.trim().length === 0) {
79
+ return 'AWS Region is required';
80
+ }
81
+ return true;
82
+ },
83
+ },
84
+ {
85
+ type: 'confirm',
86
+ name: 'addCustomRegistry',
87
+ message: 'Add custom Docker registry?',
88
+ default: false,
89
+ },
90
+ ]);
91
+
92
+ const registries = [];
93
+
94
+ if (answers.configureEcr) {
95
+ registries.push({
96
+ type: 'ecr',
97
+ region: answers.awsRegion,
98
+ });
99
+ }
100
+
101
+ if (answers.addCustomRegistry) {
102
+ const customRegistry = await inquirer.prompt([
103
+ {
104
+ type: 'input',
105
+ name: 'url',
106
+ message: 'Registry URL:',
107
+ validate: (input) => {
108
+ if (!input || input.trim().length === 0) {
109
+ return 'Registry URL is required';
110
+ }
111
+ return true;
112
+ },
113
+ },
114
+ {
115
+ type: 'input',
116
+ name: 'username',
117
+ message: 'Username:',
118
+ },
119
+ {
120
+ type: 'password',
121
+ name: 'password',
122
+ message: 'Password:',
123
+ mask: '*',
124
+ },
125
+ ]);
126
+
127
+ registries.push({
128
+ type: 'custom',
129
+ ...customRegistry,
130
+ });
131
+ }
132
+
133
+ return registries;
134
+ }
135
+
136
+ /**
137
+ * Prompt for choice from a list
138
+ *
139
+ * @param {string} message - Prompt message
140
+ * @param {Array} choices - Array of choices
141
+ * @param {string} defaultChoice - Default choice
142
+ * @returns {Promise<string>} Selected choice
143
+ */
144
+ export async function promptChoice(message, choices, defaultChoice) {
145
+ const answers = await inquirer.prompt([
146
+ {
147
+ type: 'list',
148
+ name: 'choice',
149
+ message,
150
+ choices,
151
+ default: defaultChoice,
152
+ },
153
+ ]);
154
+
155
+ return answers.choice;
156
+ }
157
+
158
+ /**
159
+ * Prompt for text input
160
+ *
161
+ * @param {string} message - Prompt message
162
+ * @param {string} defaultValue - Default value
163
+ * @param {Function} validate - Validation function
164
+ * @returns {Promise<string>} User input
165
+ */
166
+ export async function promptInput(message, defaultValue, validate) {
167
+ const answers = await inquirer.prompt([
168
+ {
169
+ type: 'input',
170
+ name: 'input',
171
+ message,
172
+ default: defaultValue,
173
+ validate,
174
+ },
175
+ ]);
176
+
177
+ return answers.input;
178
+ }
179
+
180
+ /**
181
+ * Display progress with spinner
182
+ *
183
+ * @param {string} message - Progress message
184
+ * @param {Promise} promise - Promise to await
185
+ * @returns {Promise} Result of the promise
186
+ */
187
+ export async function displayProgress(message, promise) {
188
+ const spinner = ora(message).start();
189
+
190
+ try {
191
+ const result = await promise;
192
+ spinner.succeed(chalk.green(message));
193
+ return result;
194
+ } catch (error) {
195
+ spinner.fail(chalk.red(`${message} - ${error.message}`));
196
+ throw error;
197
+ }
198
+ }
199
+
200
+ /**
201
+ * Display success message
202
+ *
203
+ * @param {string} message - Success message
204
+ */
205
+ export function displaySuccess(message) {
206
+ console.log(chalk.green('✅ ' + message));
207
+ }
208
+
209
+ /**
210
+ * Display error message
211
+ *
212
+ * @param {string} message - Error message
213
+ */
214
+ export function displayError(message) {
215
+ console.log(chalk.red('❌ ' + message));
216
+ }
217
+
218
+ /**
219
+ * Display warning message
220
+ *
221
+ * @param {string} message - Warning message
222
+ */
223
+ export function displayWarning(message) {
224
+ console.log(chalk.yellow('⚠️ ' + message));
225
+ }
226
+
227
+ /**
228
+ * Display info message
229
+ *
230
+ * @param {string} message - Info message
231
+ */
232
+ export function displayInfo(message) {
233
+ console.log(chalk.blue('ℹ️ ' + message));
234
+ }
235
+
236
+ /**
237
+ * Display header with decorative border
238
+ *
239
+ * @param {string} title - Header title
240
+ */
241
+ export function displayHeader(title) {
242
+ const border = '━'.repeat(70);
243
+ console.log('\n' + chalk.cyan(border));
244
+ console.log(chalk.cyan.bold(` ${title}`));
245
+ console.log(chalk.cyan(border) + '\n');
246
+ }
247
+
248
+ /**
249
+ * Display step indicator
250
+ *
251
+ * @param {number} current - Current step
252
+ * @param {number} total - Total steps
253
+ * @param {string} description - Step description
254
+ */
255
+ export function displayStep(current, total, description) {
256
+ console.log(chalk.bold(`\nStep ${current}/${total}: ${description}`));
257
+ }
258
+
259
+ /**
260
+ * Display a list of items
261
+ *
262
+ * @param {Array} items - Items to display
263
+ * @param {string} prefix - Prefix for each item (default: ' • ')
264
+ */
265
+ export function displayList(items, prefix = ' • ') {
266
+ items.forEach((item) => {
267
+ console.log(chalk.gray(prefix + item));
268
+ });
269
+ }
270
+
271
+ /**
272
+ * Display key-value pairs
273
+ *
274
+ * @param {Object} data - Data to display
275
+ * @param {string} indent - Indentation (default: ' ')
276
+ */
277
+ export function displayKeyValue(data, indent = ' ') {
278
+ Object.entries(data).forEach(([key, value]) => {
279
+ console.log(chalk.gray(`${indent}${key}: `) + chalk.white(value));
280
+ });
281
+ }
282
+
283
+ /**
284
+ * Clear console
285
+ */
286
+ export function clearConsole() {
287
+ console.clear();
288
+ }
289
+
290
+ /**
291
+ * Prompt for backend URL
292
+ *
293
+ * @param {string} defaultUrl - Default backend URL
294
+ * @returns {Promise<string>} Backend URL
295
+ */
296
+ export async function promptBackendUrl(defaultUrl = 'http://localhost:7007') {
297
+ const answers = await inquirer.prompt([
298
+ {
299
+ type: 'input',
300
+ name: 'url',
301
+ message: 'Fenwave Backend URL:',
302
+ default: defaultUrl,
303
+ validate: (input) => {
304
+ if (!input || input.trim().length === 0) {
305
+ return 'Backend URL is required';
306
+ }
307
+ try {
308
+ new URL(input);
309
+ return true;
310
+ } catch (error) {
311
+ return 'Invalid URL format';
312
+ }
313
+ },
314
+ },
315
+ ]);
316
+
317
+ return answers.url.trim();
318
+ }
@@ -0,0 +1,256 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import os from "os";
4
+ import { exec } from "child_process";
5
+ import { promisify } from "util";
6
+
7
+ const execAsync = promisify(exec);
8
+
9
+ // Directory for storing generated certificates
10
+ const CERTS_DIR = path.join(os.homedir(), ".fenwave", "certs");
11
+
12
+ /**
13
+ * Ensure the certificates directory exists
14
+ */
15
+ function ensureCertsDir() {
16
+ if (!fs.existsSync(CERTS_DIR)) {
17
+ fs.mkdirSync(CERTS_DIR, { recursive: true });
18
+ }
19
+ }
20
+
21
+ /**
22
+ * Check if mkcert is installed and available
23
+ * @returns {Promise<{installed: boolean, version?: string, error?: string}>}
24
+ */
25
+ export async function checkMkcertInstalled() {
26
+ try {
27
+ const { stdout } = await execAsync("mkcert -version");
28
+ return {
29
+ installed: true,
30
+ version: stdout.trim(),
31
+ };
32
+ } catch (error) {
33
+ return {
34
+ installed: false,
35
+ error: "mkcert is not installed. Install it with: brew install mkcert (macOS) or see https://github.com/FiloSottile/mkcert",
36
+ };
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Install the mkcert CA to the system trust store
42
+ * This allows browsers to trust locally-generated certificates
43
+ * @returns {Promise<{success: boolean, message: string, caPath?: string}>}
44
+ */
45
+ export async function installMkcertCA() {
46
+ try {
47
+ // Run mkcert -install to add CA to system trust store
48
+ await execAsync("mkcert -install");
49
+
50
+ // Get the CA root directory
51
+ const { stdout: caRootDir } = await execAsync("mkcert -CAROOT");
52
+ const caDir = caRootDir.trim();
53
+ const caPath = path.join(caDir, "rootCA.pem");
54
+
55
+ // Copy CA to our certs directory for easy access
56
+ ensureCertsDir();
57
+ const localCAPath = path.join(CERTS_DIR, "rootCA.pem");
58
+
59
+ if (fs.existsSync(caPath)) {
60
+ fs.copyFileSync(caPath, localCAPath);
61
+ }
62
+
63
+ return {
64
+ success: true,
65
+ message: "mkcert CA installed successfully",
66
+ caPath: localCAPath,
67
+ };
68
+ } catch (error) {
69
+ return {
70
+ success: false,
71
+ message: `Failed to install mkcert CA: ${error.message}`,
72
+ };
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Get the path to the mkcert CA certificate
78
+ * @returns {Promise<{success: boolean, caPath?: string, error?: string}>}
79
+ */
80
+ export async function getMkcertCAPath() {
81
+ try {
82
+ const { stdout: caRootDir } = await execAsync("mkcert -CAROOT");
83
+ const caDir = caRootDir.trim();
84
+ const caPath = path.join(caDir, "rootCA.pem");
85
+
86
+ // Also check our local copy
87
+ const localCAPath = path.join(CERTS_DIR, "rootCA.pem");
88
+
89
+ if (fs.existsSync(localCAPath)) {
90
+ return { success: true, caPath: localCAPath };
91
+ }
92
+
93
+ if (fs.existsSync(caPath)) {
94
+ // Copy to local for consistency
95
+ ensureCertsDir();
96
+ fs.copyFileSync(caPath, localCAPath);
97
+ return { success: true, caPath: localCAPath };
98
+ }
99
+
100
+ return {
101
+ success: false,
102
+ error: "mkcert CA not found. Run 'mkcert -install' first.",
103
+ };
104
+ } catch (error) {
105
+ return {
106
+ success: false,
107
+ error: `Failed to get mkcert CA path: ${error.message}`,
108
+ };
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Derive a certificate name from domain(s)
114
+ * @param {string[]} domains - Array of domain names
115
+ * @returns {string} Sanitized certificate name
116
+ */
117
+ function deriveCertName(domains) {
118
+ if (!domains || domains.length === 0) {
119
+ return "localhost";
120
+ }
121
+
122
+ // Use first domain, remove wildcards and sanitize
123
+ const firstDomain = domains[0]
124
+ .replace(/^\*\./, "") // Remove leading wildcard
125
+ .replace(/[^a-zA-Z0-9.-]/g, "-") // Replace invalid chars
126
+ .toLowerCase();
127
+
128
+ return firstDomain || "localhost";
129
+ }
130
+
131
+ /**
132
+ * Generate SSL certificates for the specified domains
133
+ * @param {string[]} domains - Array of domain names (e.g., ["example.local", "*.example.local"])
134
+ * @param {string} [certName] - Optional certificate file prefix
135
+ * @returns {Promise<{success: boolean, certPath?: string, keyPath?: string, message: string}>}
136
+ */
137
+ export async function generateCertificates(domains, certName) {
138
+ if (!domains || domains.length === 0) {
139
+ return {
140
+ success: false,
141
+ message: "No domains specified for certificate generation",
142
+ };
143
+ }
144
+
145
+ // Check mkcert is installed
146
+ const mkcertCheck = await checkMkcertInstalled();
147
+ if (!mkcertCheck.installed) {
148
+ return {
149
+ success: false,
150
+ message: mkcertCheck.error,
151
+ };
152
+ }
153
+
154
+ ensureCertsDir();
155
+
156
+ // Derive or use provided cert name
157
+ const name = certName || deriveCertName(domains);
158
+ const certPath = path.join(CERTS_DIR, `${name}.pem`);
159
+ const keyPath = path.join(CERTS_DIR, `${name}-key.pem`);
160
+
161
+ try {
162
+ // Build mkcert command
163
+ // mkcert -cert-file <cert> -key-file <key> domain1 domain2 ...
164
+ const domainsArg = domains.map(d => `"${d}"`).join(" ");
165
+ const command = `mkcert -cert-file "${certPath}" -key-file "${keyPath}" ${domainsArg}`;
166
+
167
+ const { stdout, stderr } = await execAsync(command);
168
+
169
+ // Verify files were created
170
+ if (!fs.existsSync(certPath) || !fs.existsSync(keyPath)) {
171
+ return {
172
+ success: false,
173
+ message: "Certificate files were not created",
174
+ };
175
+ }
176
+
177
+ return {
178
+ success: true,
179
+ certPath,
180
+ keyPath,
181
+ message: `Generated certificates for: ${domains.join(", ")}`,
182
+ output: stdout || stderr,
183
+ };
184
+ } catch (error) {
185
+ return {
186
+ success: false,
187
+ message: `Failed to generate certificates: ${error.message}`,
188
+ };
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Get paths to existing certificates
194
+ * @param {string} certName - Certificate name/prefix
195
+ * @returns {{certPath: string, keyPath: string, caPath: string, exists: boolean}}
196
+ */
197
+ export function getCertificatePaths(certName) {
198
+ const certPath = path.join(CERTS_DIR, `${certName}.pem`);
199
+ const keyPath = path.join(CERTS_DIR, `${certName}-key.pem`);
200
+ const caPath = path.join(CERTS_DIR, "rootCA.pem");
201
+
202
+ return {
203
+ certPath,
204
+ keyPath,
205
+ caPath,
206
+ exists: fs.existsSync(certPath) && fs.existsSync(keyPath),
207
+ };
208
+ }
209
+
210
+ /**
211
+ * Check if certificates exist for a given name
212
+ * @param {string} certName - Certificate name/prefix
213
+ * @returns {boolean}
214
+ */
215
+ export function certificatesExist(certName) {
216
+ const { exists } = getCertificatePaths(certName);
217
+ return exists;
218
+ }
219
+
220
+ /**
221
+ * Delete certificates for a given name
222
+ * @param {string} certName - Certificate name/prefix
223
+ * @returns {{success: boolean, message: string}}
224
+ */
225
+ export function deleteCertificates(certName) {
226
+ const { certPath, keyPath } = getCertificatePaths(certName);
227
+
228
+ try {
229
+ if (fs.existsSync(certPath)) {
230
+ fs.unlinkSync(certPath);
231
+ }
232
+ if (fs.existsSync(keyPath)) {
233
+ fs.unlinkSync(keyPath);
234
+ }
235
+ return {
236
+ success: true,
237
+ message: `Deleted certificates for: ${certName}`,
238
+ };
239
+ } catch (error) {
240
+ return {
241
+ success: false,
242
+ message: `Failed to delete certificates: ${error.message}`,
243
+ };
244
+ }
245
+ }
246
+
247
+ export default {
248
+ checkMkcertInstalled,
249
+ installMkcertCA,
250
+ getMkcertCAPath,
251
+ generateCertificates,
252
+ getCertificatePaths,
253
+ certificatesExist,
254
+ deleteCertificates,
255
+ CERTS_DIR,
256
+ };