@oussema_mili/test-pkg-123 1.1.41 → 1.1.43

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/cli-commands.js CHANGED
@@ -893,27 +893,11 @@ function setupCLICommands(program, startServerFunction) {
893
893
  { timeout: 10000 },
894
894
  );
895
895
 
896
- // Debug: Log the actual response
897
- console.log(chalk.gray('\n Debug - Backend response:'), JSON.stringify(response.data, null, 2));
898
-
899
- // Try to get userEntityRef from backend, fallback to session, then "unknown"
900
- let userEntityRef = response.data.userEntityRef;
901
-
902
- if (!userEntityRef || userEntityRef === 'unknown') {
903
- const session = loadSession();
904
- if (session && isSessionValid(session) && session.userEntityRef) {
905
- userEntityRef = session.userEntityRef;
906
- console.log(chalk.gray(' Using userEntityRef from session: ' + userEntityRef));
907
- } else {
908
- userEntityRef = "unknown";
909
- }
910
- }
911
-
912
896
  // Save credentials
913
897
  saveDeviceCredential({
914
898
  deviceId: response.data.deviceId,
915
899
  deviceCredential: response.data.deviceCredential,
916
- userEntityRef: userEntityRef,
900
+ userEntityRef: response.data.userEntityRef || "unknown",
917
901
  deviceName: deviceMetadata.deviceName,
918
902
  platform: deviceMetadata.platform,
919
903
  agentVersion: deviceMetadata.agentVersion,
@@ -2,9 +2,11 @@ import os from 'os';
2
2
  import { spawn, exec } from 'child_process';
3
3
  import path from 'path';
4
4
  import chalk from 'chalk';
5
- import { loadConfig } from './store/configStore.js';
5
+ import { loadConfig, DEFAULT_WS_PORT, DEFAULT_CONTAINER_PORT } from './store/configStore.js';
6
+ import { getDaemonState } from './store/daemonStore.js';
7
+ import { findAvailableContainerPort } from './utils/portUtils.js';
6
8
 
7
- // Load configuration
9
+ // Load static configuration (ports are resolved dynamically)
8
10
  const config = loadConfig();
9
11
  const CONTAINER_NAME = config.containerName;
10
12
  const AGENT_ROOT_DIR = config.agentRootDir;
@@ -13,10 +15,24 @@ const HOST_DATA_DIR = path.join(os.homedir(), AGENT_ROOT_DIR, REGISTRIES_DIR);
13
15
  const HOST_FW_DIR = path.join(os.homedir(), AGENT_ROOT_DIR);
14
16
  const CONTAINER_DATA_DIR = config.containerDataDir;
15
17
  const CONTAINER_FW_DIR = '/app/.fenwave';
16
- const APP_PORT = config.containerPort;
17
- const WS_PORT = config.wsPort;
18
18
  const DOCKER_IMAGE = config.dockerImage;
19
19
 
20
+ /**
21
+ * Get the current WebSocket port (from daemon state or config)
22
+ */
23
+ function getCurrentWsPort() {
24
+ const state = getDaemonState();
25
+ return state?.port || config.wsPort || DEFAULT_WS_PORT;
26
+ }
27
+
28
+ /**
29
+ * Get the current container port (from daemon state or config)
30
+ */
31
+ function getCurrentContainerPort() {
32
+ const state = getDaemonState();
33
+ return state?.containerPort || config.containerPort || DEFAULT_CONTAINER_PORT;
34
+ }
35
+
20
36
  /**
21
37
  * Container Manager for Fenwave DevApp
22
38
  */
@@ -147,9 +163,26 @@ class ContainerManager {
147
163
 
148
164
  /**
149
165
  * Start the Fenwave DevApp container
166
+ * @param {Object} options - Start options
167
+ * @param {number} options.wsPort - WebSocket port to connect to
168
+ * @param {number} options.containerPort - Port to expose the container on (0 for auto-assign)
150
169
  */
151
- async startContainer() {
170
+ async startContainer(options = {}) {
152
171
  try {
172
+ // Get ports - use provided values, daemon state, config, or defaults
173
+ const WS_PORT = options.wsPort || getCurrentWsPort();
174
+ let APP_PORT = options.containerPort || getCurrentContainerPort();
175
+
176
+ // If containerPort is 0, find an available port
177
+ if (APP_PORT === 0) {
178
+ try {
179
+ APP_PORT = await findAvailableContainerPort(DEFAULT_CONTAINER_PORT);
180
+ console.log(chalk.blue(`📍 Auto-assigned container port: ${APP_PORT}`));
181
+ } catch (error) {
182
+ throw new Error(`Failed to find available container port: ${error.message}`);
183
+ }
184
+ }
185
+
153
186
  // Check Docker availability
154
187
  const dockerAvailable = await this.checkDockerAvailable();
155
188
  if (!dockerAvailable) {
@@ -223,13 +256,14 @@ class ContainerManager {
223
256
  runProcess.on('close', (code) => {
224
257
  if (code === 0) {
225
258
  this.isRunning = true;
259
+ this.currentContainerPort = APP_PORT; // Store the actual port used
226
260
  console.log(chalk.green('✅ Container started successfully'));
227
261
  console.log(chalk.gray(` Image: ${DOCKER_IMAGE}`));
228
262
  console.log(chalk.gray(` Container: ${CONTAINER_NAME}`));
229
263
  console.log(chalk.gray(` Port: ${APP_PORT}`));
230
264
  console.log(chalk.gray(` Data volume: ${HOST_DATA_DIR} -> ${CONTAINER_DATA_DIR}`));
231
265
  console.log(chalk.gray(` Token volume: ${HOST_FW_DIR} -> ${CONTAINER_FW_DIR}`));
232
- resolve();
266
+ resolve(APP_PORT); // Return the actual port used
233
267
  } else {
234
268
  console.error(chalk.red('❌ Failed to start container:'));
235
269
  if (errorOutput) {
@@ -275,11 +309,19 @@ class ContainerManager {
275
309
  return {
276
310
  isRunning: running,
277
311
  containerName: CONTAINER_NAME,
278
- port: APP_PORT,
312
+ port: this.currentContainerPort || getCurrentContainerPort(),
279
313
  dataDirectory: HOST_DATA_DIR,
280
314
  };
281
315
  }
282
316
 
317
+ /**
318
+ * Get the current container port
319
+ * @returns {number} The current container port
320
+ */
321
+ getContainerPort() {
322
+ return this.currentContainerPort || getCurrentContainerPort();
323
+ }
324
+
283
325
  /**
284
326
  * Show container logs
285
327
  */
@@ -10,7 +10,7 @@ import { setupWebSocketServer, readWsToken } from '../websocket-server.js';
10
10
  import containerManager from '../containerManager.js';
11
11
  import registryStore from '../store/registryStore.js';
12
12
  import agentStore from '../store/agentStore.js';
13
- import { loadConfig } from '../store/configStore.js';
13
+ import { loadConfig, DEFAULT_WS_PORT, DEFAULT_CONTAINER_PORT } from '../store/configStore.js';
14
14
  import { initializeAgentStartTime } from '../docker-actions/general.js';
15
15
  import { checkAppHasBeenRun } from '../docker-actions/apps.js';
16
16
  import {
@@ -34,7 +34,6 @@ import { createLogger, writeLog } from './logManager.js';
34
34
  // Load configuration
35
35
  const config = loadConfig();
36
36
  const BACKEND_URL = config.backendUrl;
37
- const CONTAINER_PORT = config.containerPort;
38
37
 
39
38
  // Store active connections
40
39
  const clients = new Map();
@@ -261,12 +260,17 @@ async function gracefulShutdown(signal = 'SIGTERM', drainTimeout = 10000) {
261
260
  /**
262
261
  * Run the agent in the current process
263
262
  * @param {Object} options - Options
264
- * @param {number} options.preferredPort - Preferred WebSocket port
263
+ * @param {number} options.preferredPort - Preferred WebSocket port (0 for auto-assign)
264
+ * @param {number} options.preferredContainerPort - Preferred container port (0 for auto-assign)
265
265
  * @param {boolean} options.isDaemon - Whether running as daemon
266
266
  * @returns {Promise<Object>} Server instances
267
267
  */
268
268
  export async function runAgent(options = {}) {
269
- const { preferredPort = config.wsPort, isDaemon = false } = options;
269
+ const {
270
+ preferredPort = config.wsPort || DEFAULT_WS_PORT,
271
+ preferredContainerPort = config.containerPort || DEFAULT_CONTAINER_PORT,
272
+ isDaemon = false
273
+ } = options;
270
274
 
271
275
  // Check for existing session
272
276
  log('Checking for existing session...');
@@ -290,12 +294,16 @@ export async function runAgent(options = {}) {
290
294
  throw new Error('Another instance of the agent is already running.');
291
295
  }
292
296
 
293
- // Find available port
297
+ // Find available port for WebSocket
294
298
  let actualPort;
295
299
  try {
296
- actualPort = await findAvailablePort(preferredPort);
297
- if (actualPort !== preferredPort) {
300
+ // If preferredPort is 0, find any available port starting from default
301
+ const startPort = preferredPort === 0 ? DEFAULT_WS_PORT : preferredPort;
302
+ actualPort = await findAvailablePort(startPort);
303
+ if (actualPort !== preferredPort && preferredPort !== 0) {
298
304
  log(`Port ${preferredPort} is in use, using port ${actualPort}`, 'warn');
305
+ } else if (preferredPort === 0) {
306
+ log(`Auto-assigned WebSocket port: ${actualPort}`);
299
307
  }
300
308
  } catch (error) {
301
309
  releaseLock();
@@ -305,14 +313,19 @@ export async function runAgent(options = {}) {
305
313
  // Initialize registry store
306
314
  await registryStore.initialize();
307
315
 
308
- // Start container
316
+ // Start container with dynamic ports
309
317
  log('Starting container...');
318
+ let actualContainerPort = preferredContainerPort;
310
319
  try {
311
- await containerManager.startContainer();
312
- log('Container started successfully');
320
+ actualContainerPort = await containerManager.startContainer({
321
+ wsPort: actualPort,
322
+ containerPort: preferredContainerPort,
323
+ });
324
+ log(`Container started successfully on port ${actualContainerPort}`);
313
325
  } catch (containerError) {
314
326
  log(`Failed to start container: ${containerError.message}`, 'warn');
315
327
  log('Starting agent without container...');
328
+ actualContainerPort = preferredContainerPort || DEFAULT_CONTAINER_PORT;
316
329
  }
317
330
 
318
331
  // Create HTTP server with download endpoint handler
@@ -393,6 +406,7 @@ export async function runAgent(options = {}) {
393
406
  saveDaemonState({
394
407
  pid: process.pid,
395
408
  port: actualPort,
409
+ containerPort: actualContainerPort,
396
410
  startTime: new Date().toISOString(),
397
411
  status: 'running',
398
412
  userEntityRef: session.userEntityRef,
@@ -435,7 +449,7 @@ export async function runAgent(options = {}) {
435
449
  console.log(chalk.green(' Fenwave Agent Started Successfully'));
436
450
  console.log(chalk.green('='.repeat(66) + '\n'));
437
451
  console.log(chalk.white(' Fenwave DevApp Dashboard:'));
438
- console.log(chalk.cyan(` http://localhost:${CONTAINER_PORT}\n`));
452
+ console.log(chalk.cyan(` http://localhost:${actualContainerPort}\n`));
439
453
  console.log(chalk.white(' WebSocket Server:'));
440
454
  console.log(chalk.cyan(` ws://localhost:${actualPort}\n`));
441
455
  console.log(chalk.white(' User:'));
package/dist/styles.css CHANGED
@@ -179,6 +179,9 @@
179
179
  .relative {
180
180
  position: relative;
181
181
  }
182
+ .static {
183
+ position: static;
184
+ }
182
185
  .container {
183
186
  width: 100%;
184
187
  @media (width >= 40rem) {
@@ -5,7 +5,7 @@ import util from 'util';
5
5
  import fs from 'fs';
6
6
  import path from 'path';
7
7
  import os from 'os';
8
- import { loadConfig } from '../store/configStore.js';
8
+ import { loadConfig, DEFAULT_WS_PORT } from '../store/configStore.js';
9
9
  import { getDaemonState } from '../store/daemonStore.js';
10
10
 
11
11
  const execPromise = util.promisify(exec);
@@ -23,7 +23,7 @@ function getAgentPort() {
23
23
  return state.port;
24
24
  }
25
25
  const config = loadConfig();
26
- return config.wsPort || 3001;
26
+ return config.wsPort || DEFAULT_WS_PORT;
27
27
  }
28
28
 
29
29
  // Cache for docker system df result to avoid concurrent operations
package/index.html CHANGED
@@ -12,6 +12,10 @@
12
12
  <script>
13
13
  // Store WebSocket token in localStorage for App Builder to use
14
14
  // These values are injected by the agent server
15
+ // Default ports: WS=3001, Container=3003 (may vary if ports are in use)
16
+ const DEFAULT_WS_PORT = "3001";
17
+ const DEFAULT_CONTAINER_PORT = "3003";
18
+
15
19
  const wsToken = new URLSearchParams(window.location.search).get(
16
20
  "wsToken",
17
21
  );
@@ -22,8 +26,8 @@
22
26
 
23
27
  if (wsToken) {
24
28
  localStorage.setItem("fenwave-ws-token", wsToken);
25
- localStorage.setItem("fenwave-ws-port", wsPort || "3001");
26
- localStorage.setItem("fenwave-container-port", containerPort || "3003");
29
+ localStorage.setItem("fenwave-ws-port", wsPort || DEFAULT_WS_PORT);
30
+ localStorage.setItem("fenwave-container-port", containerPort || DEFAULT_CONTAINER_PORT);
27
31
  }
28
32
  </script>
29
33
  <style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oussema_mili/test-pkg-123",
3
- "version": "1.1.41",
3
+ "version": "1.1.43",
4
4
  "description": "Fenwave Docker Agent and CLI",
5
5
  "keywords": [
6
6
  "fenwave",
@@ -6,7 +6,6 @@ import {
6
6
  displayPrerequisites,
7
7
  getMissingPrerequisites,
8
8
  } from "../utils/prerequisites.js";
9
- import { loadSession, isSessionValid } from "../auth.js";
10
9
  import {
11
10
  promptRegistrationToken,
12
11
  promptConfirmation,
@@ -255,27 +254,11 @@ export class SetupWizard {
255
254
  { timeout: 10000 }
256
255
  );
257
256
 
258
- // Debug: Log the actual response to understand what backend returns
259
- console.log(chalk.gray(' Debug - Backend response:'), JSON.stringify(response.data, null, 2));
260
-
261
- // Try to get userEntityRef from backend, fallback to session, then "unknown"
262
- let userEntityRef = response.data.userEntityRef;
263
-
264
- if (!userEntityRef || userEntityRef === 'unknown') {
265
- const session = loadSession();
266
- if (session && isSessionValid(session) && session.userEntityRef) {
267
- userEntityRef = session.userEntityRef;
268
- console.log(chalk.gray(' Using userEntityRef from session: ' + userEntityRef));
269
- } else {
270
- userEntityRef = "unknown";
271
- }
272
- }
273
-
274
257
  return {
275
258
  deviceId: response.data.deviceId,
276
259
  deviceCredential: response.data.deviceCredential,
277
260
  registryConfig: response.data.registryConfig,
278
- userEntityRef: userEntityRef,
261
+ userEntityRef: response.data.userEntityRef || "unknown",
279
262
  };
280
263
  } catch (error) {
281
264
  if (error.response?.status === 401) {
@@ -384,22 +367,11 @@ export class SetupWizard {
384
367
  console.log("");
385
368
  displayHeader("Setup Summary");
386
369
 
387
- // Use session userEntityRef if device credential has unknown
388
- let displayUser = registrationData.userEntityRef;
389
- if (!displayUser || displayUser === "unknown") {
390
- const session = loadSession();
391
- if (session && isSessionValid(session) && session.userEntityRef) {
392
- displayUser = session.userEntityRef;
393
- } else {
394
- displayUser = "N/A";
395
- }
396
- }
397
-
398
370
  displayKeyValue({
399
371
  "Device ID": registrationData.deviceId,
400
372
  "Device Name": registrationData.deviceName || "N/A",
401
373
  Platform: registrationData.platform || "N/A",
402
- User: displayUser,
374
+ User: registrationData.userEntityRef || "N/A",
403
375
  });
404
376
 
405
377
  console.log("");
@@ -6,6 +6,13 @@ const FENWAVE_DIR = path.join(os.homedir(), ".fenwave");
6
6
  const CONFIG_DIR = path.join(FENWAVE_DIR, "config");
7
7
  const CONFIG_FILE = path.join(CONFIG_DIR, "agent.json");
8
8
 
9
+ /**
10
+ * Default port values (used when no port is specified)
11
+ * Set to 0 to use a random available port
12
+ */
13
+ export const DEFAULT_WS_PORT = 3001;
14
+ export const DEFAULT_CONTAINER_PORT = 3003;
15
+
9
16
  /**
10
17
  * Default configuration values
11
18
  */
@@ -16,16 +23,16 @@ const DEFAULT_CONFIG = {
16
23
 
17
24
  // Container Configuration
18
25
  containerName: "fenwave-devapp",
19
- containerPort: 3003,
20
- wsPort: 3001,
26
+ containerPort: DEFAULT_CONTAINER_PORT,
27
+ wsPort: DEFAULT_WS_PORT,
21
28
 
22
29
  // Directory Configuration
23
30
  agentRootDir: ".fenwave",
24
31
  registriesDir: "registries",
25
32
  containerDataDir: "/data",
26
33
 
27
- // Docker Image (GHCR - public registry, no auth required)
28
- dockerImage: "ghcr.io/fenleap/fenwave/dev-app:latest",
34
+ // Docker Image (Docker Hub - testing, will be moved to GHCR later)
35
+ dockerImage: "oussemamili/dev-app:latest",
29
36
 
30
37
  // Other Settings
31
38
  authTimeoutMs: 60000,
package/utils/envSetup.js CHANGED
@@ -22,10 +22,13 @@ export function ensureEnvironmentFiles(agentDir, showFoundMessages = false) {
22
22
  // Check and create .env.agent for agent if not exists
23
23
  const agentEnvPath = path.join(fenwareConfigDir, ".env.agent");
24
24
  if (!fs.existsSync(agentEnvPath)) {
25
+ // Note: WS_PORT and CONTAINER_PORT can be set to 0 for auto-assignment
26
+ // or left empty to use defaults (3001 and 3003)
25
27
  const defaultAgentEnv = `BACKEND_URL=http://localhost:7007
26
28
  FRONTEND_URL=http://localhost:3000
27
- WS_PORT=3001
28
- CONTAINER_PORT=3003
29
+ # Port configuration (leave empty for defaults: 3001/3003, set to 0 for random available port)
30
+ WS_PORT=
31
+ CONTAINER_PORT=
29
32
  AGENT_ROOT_DIR=.fenwave
30
33
  REGISTRIES_DIR=registries
31
34
  AUTH_TIMEOUT_MS=60000
@@ -1,5 +1,9 @@
1
1
  import net from 'net';
2
2
 
3
+ // Default ports (can be overridden via environment or config)
4
+ export const DEFAULT_WS_PORT = 3001;
5
+ export const DEFAULT_CONTAINER_PORT = 3003;
6
+
3
7
  /**
4
8
  * Check if a port is available
5
9
  * @param {number} port - Port number to check
@@ -28,12 +32,12 @@ export async function isPortAvailable(port) {
28
32
 
29
33
  /**
30
34
  * Find an available port starting from a given port
31
- * @param {number} startPort - Starting port number (default: 3001)
35
+ * @param {number} startPort - Starting port number (default: DEFAULT_WS_PORT)
32
36
  * @param {number} maxAttempts - Maximum number of ports to try (default: 10)
33
37
  * @returns {Promise<number>} Available port number
34
38
  * @throws {Error} If no available port found in range
35
39
  */
36
- export async function findAvailablePort(startPort = 3001, maxAttempts = 10) {
40
+ export async function findAvailablePort(startPort = DEFAULT_WS_PORT, maxAttempts = 10) {
37
41
  for (let i = 0; i < maxAttempts; i++) {
38
42
  const port = startPort + i;
39
43
  if (await isPortAvailable(port)) {
@@ -52,8 +56,37 @@ export async function isPortInUse(port) {
52
56
  return !(await isPortAvailable(port));
53
57
  }
54
58
 
59
+ /**
60
+ * Find an available port for container, starting from a given port
61
+ * @param {number} startPort - Starting port number (default: DEFAULT_CONTAINER_PORT)
62
+ * @param {number} maxAttempts - Maximum number of ports to try (default: 10)
63
+ * @returns {Promise<number>} Available port number
64
+ */
65
+ export async function findAvailableContainerPort(startPort = DEFAULT_CONTAINER_PORT, maxAttempts = 10) {
66
+ return findAvailablePort(startPort, maxAttempts);
67
+ }
68
+
69
+ /**
70
+ * Find a random available port in the ephemeral range
71
+ * @returns {Promise<number>} Available port number
72
+ */
73
+ export async function findRandomAvailablePort() {
74
+ return new Promise((resolve, reject) => {
75
+ const server = net.createServer();
76
+ server.listen(0, '127.0.0.1', () => {
77
+ const { port } = server.address();
78
+ server.close(() => resolve(port));
79
+ });
80
+ server.on('error', reject);
81
+ });
82
+ }
83
+
55
84
  export default {
56
85
  isPortAvailable,
57
86
  findAvailablePort,
87
+ findAvailableContainerPort,
88
+ findRandomAvailablePort,
58
89
  isPortInUse,
90
+ DEFAULT_WS_PORT,
91
+ DEFAULT_CONTAINER_PORT,
59
92
  };
@@ -1,5 +0,0 @@
1
- export default {
2
- plugins: {
3
- "@tailwindcss/postcss": {},
4
- },
5
- };