@magentrix-corp/magentrix-cli 1.3.14 → 1.3.16

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/actions/setup.js CHANGED
@@ -6,6 +6,7 @@ import { ensureVSCodeFileAssociation } from "../utils/preferences.js";
6
6
  import { CWD, EXPORT_ROOT, HASHED_CWD } from "../vars/global.js";
7
7
  import { select } from "@inquirer/prompts";
8
8
  import { registerWorkspace } from "../utils/workspaces.js";
9
+ import debug from '../utils/debug.js';
9
10
 
10
11
  const config = new Config();
11
12
 
@@ -52,6 +53,9 @@ export const setup = async (cliOptions = {}) => {
52
53
  let authSuccess = false;
53
54
  let apiKey, instanceUrl, tokenData;
54
55
 
56
+ debug.log('SETUP', `Starting setup (pathHash: ${HASHED_CWD}, CWD: ${CWD})`);
57
+ debug.log('SETUP', `CLI options provided: apiKey=${cliOptions.apiKey ? 'yes' : 'no'}, instanceUrl=${cliOptions.instanceUrl || 'no'}`);
58
+
55
59
  while (!authSuccess) {
56
60
  // Get API key (from CLI or prompt)
57
61
  apiKey = cliOptions.apiKey
@@ -63,11 +67,15 @@ export const setup = async (cliOptions = {}) => {
63
67
  ? cliOptions.instanceUrl.trim()
64
68
  : await ensureInstanceUrl(true);
65
69
 
70
+ debug.log('SETUP', `Attempting authentication with instance: ${instanceUrl}`);
71
+
66
72
  // Validate credentials by attempting to fetch an access token
67
73
  try {
68
74
  tokenData = await tryAuthenticate(apiKey, instanceUrl);
75
+ debug.log('SETUP', 'Authentication successful');
69
76
  authSuccess = true;
70
77
  } catch (error) {
78
+ debug.log('SETUP', `Authentication failed: ${error.message}`);
71
79
  console.log(error.message);
72
80
  console.log();
73
81
 
@@ -105,6 +113,7 @@ export const setup = async (cliOptions = {}) => {
105
113
  console.log(); // Blank line for spacing
106
114
 
107
115
  // Save values since authentication succeeded
116
+ debug.log('SETUP', `Saving credentials for pathHash: ${HASHED_CWD}`);
108
117
  config.save('instanceUrl', instanceUrl, { global: true, pathHash: HASHED_CWD });
109
118
  console.log('✅ Instance URL saved securely!');
110
119
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magentrix-corp/magentrix-cli",
3
- "version": "1.3.14",
3
+ "version": "1.3.16",
4
4
  "description": "CLI tool for synchronizing local files with Magentrix cloud platform",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -1,3 +1,6 @@
1
+ import { lookup } from 'node:dns/promises';
2
+ import debug from '../debug.js';
3
+
1
4
  /**
2
5
  * Checks if the provided Magentrix instance URL is reachable by making a GET request.
3
6
  * Throws an error if the response status is not 200 (OK), or if there is a network error.
@@ -8,22 +11,64 @@
8
11
  * @returns {Promise<void>} Resolves if the instance is reachable (status 200); otherwise throws.
9
12
  */
10
13
  export const checkInstanceUrl = async (instanceUrl) => {
14
+ debug.log('URL-CHECK', `Checking reachability: GET ${instanceUrl}`);
15
+
16
+ // Resolve DNS first to help diagnose hosts file / local server issues
17
+ const hostname = new URL(instanceUrl).hostname;
18
+ try {
19
+ const { address, family } = await lookup(hostname);
20
+ debug.log('URL-CHECK', `DNS resolved: ${hostname} -> ${address} (IPv${family})`);
21
+ } catch (dnsErr) {
22
+ debug.log('URL-CHECK', `DNS lookup failed for ${hostname}: ${dnsErr.code || dnsErr.message}`);
23
+ }
24
+
25
+ const controller = new AbortController();
26
+ const timeout = setTimeout(() => {
27
+ debug.log('URL-CHECK', `Timeout after 15s — aborting request to ${instanceUrl}. If this is a local server (hosts file), check: (1) IIS has an HTTPS binding on port 443 for this hostname, (2) the SSL certificate is valid/trusted for "${hostname}", (3) Node.js trusts the certificate (self-signed certs require NODE_EXTRA_CA_CERTS or NODE_TLS_REJECT_UNAUTHORIZED=0)`);
28
+ controller.abort();
29
+ }, 15000);
11
30
  try {
12
- // Native fetch is available in Node 18+; for older versions, use node-fetch.
13
31
  const response = await fetch(instanceUrl, {
14
32
  method: "GET",
15
- // You can add a small timeout here using AbortController if needed.
33
+ signal: controller.signal,
16
34
  });
17
35
 
36
+ debug.log('URL-CHECK', `Response: ${response.status} ${response.statusText}`);
37
+
18
38
  if (response.status !== 200) {
19
39
  throw new Error(
20
40
  `Instance URL responded with status ${response.status} (${response.statusText}). Expected 200 OK.`
21
41
  );
22
42
  }
23
43
  } catch (err) {
44
+ // Node's fetch wraps the real error in err.cause (e.g. ENOTFOUND, ECONNREFUSED, ETIMEDOUT)
45
+ const cause = err.cause || {};
46
+ const rootCode = cause.code || '';
47
+ const rootMsg = cause.message || '';
48
+ const isTimeout = err.name === 'AbortError' || rootCode === 'ABORT_ERR';
49
+ const isTLS = rootCode === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' || rootCode === 'CERT_HAS_EXPIRED'
50
+ || rootCode === 'DEPTH_ZERO_SELF_SIGNED_CERT' || rootCode === 'ERR_TLS_CERT_ALTNAME_INVALID'
51
+ || rootCode === 'SELF_SIGNED_CERT_IN_CHAIN' || (rootMsg && rootMsg.includes('certificate'));
52
+
53
+ let detail;
54
+ if (isTimeout) {
55
+ detail = `Connection timed out after 15s. The server at "${hostname}" did not respond. Check the debug log for DNS resolution and troubleshooting hints.`;
56
+ } else if (isTLS) {
57
+ detail = `SSL/TLS error (${rootCode}). If using a local server with a self-signed certificate, set NODE_TLS_REJECT_UNAUTHORIZED=0 or use NODE_EXTRA_CA_CERTS. Detail: ${rootMsg}`;
58
+ } else {
59
+ detail = rootCode ? `${rootCode}: ${rootMsg}` : (err.message || String(err));
60
+ }
61
+
62
+ debug.log('URL-CHECK', `Failed: ${detail}`);
63
+ if (cause.code) debug.log('URL-CHECK', `Error code: ${cause.code}`);
64
+ if (cause.hostname) debug.log('URL-CHECK', `Hostname: ${cause.hostname}`);
65
+ if (err.stack) debug.log('URL-CHECK', `Stack: ${err.stack}`);
66
+
24
67
  // Wrap and re-throw to provide a clear error message.
25
68
  throw new Error(
26
- `Failed to reach instance URL "${instanceUrl}": ${err.message || err}`
69
+ `Failed to reach instance URL "${instanceUrl}": ${detail}`
27
70
  );
71
+ } finally {
72
+ clearTimeout(timeout);
28
73
  }
29
74
  };
@@ -36,7 +36,7 @@ export async function ensureValidCredentials() {
36
36
 
37
37
  // If missing API key or URL, prompt/setup immediately
38
38
  if (!apiKey || !instanceUrl) {
39
- debug.auth('Missing credentials, falling back to setup wizard');
39
+ debug.auth(`Missing credentials for this directory (pathHash: ${HASHED_CWD}). No API key or instance URL found in global config for this workspace. This usually means 'magentrix setup' was never run from this directory, or was run from a different path. Falling back to setup wizard.`);
40
40
  return setup();
41
41
  }
42
42
 
@@ -3,6 +3,7 @@ import Config from "../../config.js";
3
3
  import { checkInstanceUrl } from "../checkInstanceUrl.js";
4
4
  import { withSpinner } from "../../spinner.js";
5
5
  import { HASHED_CWD } from "../../../vars/global.js";
6
+ import debug from '../../debug.js';
6
7
 
7
8
  const config = new Config();
8
9
  const urlRegex = /^https:\/\/[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
@@ -45,13 +46,16 @@ export const ensureInstanceUrl = async (forcePrompt = false) => {
45
46
  const trimmed = inputUrl.trim().replace(/\/+$/, '');
46
47
 
47
48
  // Now check reachability WITH a spinner
49
+ debug.log('SETUP', `User entered instance URL: ${trimmed}`);
48
50
  try {
49
51
  await withSpinner('Checking instance URL...', () =>
50
52
  checkInstanceUrl(trimmed)
51
53
  );
52
54
 
55
+ debug.log('SETUP', `Instance URL reachable: ${trimmed}`);
53
56
  return trimmed;
54
57
  } catch (error) {
58
+ debug.log('SETUP', `Instance URL not reachable: ${trimmed} — ${error.message}`);
55
59
  // Print error AFTER spinner, then re-prompt
56
60
  console.error('❌ Instance URL not reachable. Try again.');
57
61
  }
@@ -84,7 +84,11 @@ export const fetchMagentrix = async ({
84
84
  body: requestBody
85
85
  });
86
86
  } catch (err) {
87
- debug.log('HTTP-ERR', `Network error: ${err.message}`, err.stack);
87
+ const cause = err.cause || {};
88
+ const rootDetail = cause.code ? `${cause.code}: ${cause.message || ''}` : '';
89
+ debug.log('HTTP-ERR', `Network error: ${err.message}${rootDetail ? ` (${rootDetail})` : ''}`);
90
+ if (cause.code) debug.log('HTTP-ERR', `Error code: ${cause.code}, hostname: ${cause.hostname || 'N/A'}`);
91
+ if (err.stack) debug.log('HTTP-ERR', `Stack: ${err.stack}`);
88
92
  const errorObj = {
89
93
  type: 'network',
90
94
  message: `Network error contacting Magentrix API: ${err.message}`,