@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,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
|
-
|
|
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}": ${
|
|
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(
|
|
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
|
}
|
package/utils/magentrix/fetch.js
CHANGED
|
@@ -84,7 +84,11 @@ export const fetchMagentrix = async ({
|
|
|
84
84
|
body: requestBody
|
|
85
85
|
});
|
|
86
86
|
} catch (err) {
|
|
87
|
-
|
|
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}`,
|