@magentrix-corp/magentrix-cli 1.3.16 ā 1.3.17
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/LICENSE +25 -25
- package/README.md +1166 -1166
- package/actions/autopublish.old.js +293 -293
- package/actions/config.js +182 -182
- package/actions/create.js +466 -466
- package/actions/help.js +164 -164
- package/actions/iris/buildStage.js +874 -874
- package/actions/iris/delete.js +256 -256
- package/actions/iris/dev.js +391 -391
- package/actions/iris/index.js +6 -6
- package/actions/iris/link.js +375 -375
- package/actions/iris/recover.js +268 -268
- package/actions/main.js +80 -80
- package/actions/publish.js +1420 -1420
- package/actions/pull.js +684 -684
- package/actions/setup.js +148 -148
- package/actions/status.js +17 -17
- package/actions/update.js +248 -248
- package/bin/magentrix.js +393 -393
- package/package.json +55 -55
- package/utils/assetPaths.js +158 -158
- package/utils/autopublishLock.js +77 -77
- package/utils/cacher.js +206 -206
- package/utils/cli/checkInstanceUrl.js +76 -74
- package/utils/cli/helpers/compare.js +282 -282
- package/utils/cli/helpers/ensureApiKey.js +63 -63
- package/utils/cli/helpers/ensureCredentials.js +68 -68
- package/utils/cli/helpers/ensureInstanceUrl.js +75 -75
- package/utils/cli/writeRecords.js +262 -262
- package/utils/compare.js +135 -135
- package/utils/compress.js +17 -17
- package/utils/config.js +527 -527
- package/utils/debug.js +144 -144
- package/utils/diagnostics/testPublishLogic.js +96 -96
- package/utils/diff.js +49 -49
- package/utils/downloadAssets.js +291 -291
- package/utils/filetag.js +115 -115
- package/utils/hash.js +14 -14
- package/utils/iris/backup.js +411 -411
- package/utils/iris/builder.js +541 -541
- package/utils/iris/config-reader.js +664 -664
- package/utils/iris/deleteHelper.js +150 -150
- package/utils/iris/errors.js +537 -537
- package/utils/iris/linker.js +601 -601
- package/utils/iris/lock.js +360 -360
- package/utils/iris/validation.js +360 -360
- package/utils/iris/validator.js +281 -281
- package/utils/iris/zipper.js +248 -248
- package/utils/logger.js +291 -291
- package/utils/magentrix/api/assets.js +220 -220
- package/utils/magentrix/api/auth.js +107 -107
- package/utils/magentrix/api/createEntity.js +61 -61
- package/utils/magentrix/api/deleteEntity.js +55 -55
- package/utils/magentrix/api/iris.js +251 -251
- package/utils/magentrix/api/meqlQuery.js +36 -36
- package/utils/magentrix/api/retrieveEntity.js +86 -86
- package/utils/magentrix/api/updateEntity.js +66 -66
- package/utils/magentrix/fetch.js +168 -168
- package/utils/merge.js +22 -22
- package/utils/permissionError.js +70 -70
- package/utils/preferences.js +40 -40
- package/utils/progress.js +469 -469
- package/utils/spinner.js +43 -43
- package/utils/template.js +52 -52
- package/utils/updateFileBase.js +121 -121
- package/utils/workspaces.js +108 -108
- package/vars/config.js +11 -11
- package/vars/global.js +50 -50
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
import { password } from "@inquirer/prompts";
|
|
2
|
-
import Config from "../../config.js";
|
|
3
|
-
import { HASHED_CWD } from "../../../vars/global.js";
|
|
4
|
-
|
|
5
|
-
const config = new Config();
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Ensures a valid Magentrix API key is available in the global config.
|
|
9
|
-
* - If a key is missing, invalid, or forcePrompt is true, prompts the user to enter one.
|
|
10
|
-
* - Validates that the key is at least 12 characters long and contains no spaces.
|
|
11
|
-
* - Exits the process if the user fails to provide a valid key.
|
|
12
|
-
*
|
|
13
|
-
* @async
|
|
14
|
-
* @param {boolean} [forcePrompt=false] - If true, always prompt for API key, even if one exists.
|
|
15
|
-
* @returns {Promise<string>} The valid API key, either from config or user input.
|
|
16
|
-
*/
|
|
17
|
-
export const ensureApiKey = async (forcePrompt = false) => {
|
|
18
|
-
let apiKey = config.read('apiKey', { global: true, pathHash: HASHED_CWD });
|
|
19
|
-
|
|
20
|
-
// Helper: checks for min length and no spaces
|
|
21
|
-
const isValid = (key) =>
|
|
22
|
-
typeof key === "string" &&
|
|
23
|
-
key.trim().length >= 12 &&
|
|
24
|
-
!/\s/.test(key);
|
|
25
|
-
|
|
26
|
-
if (forcePrompt || !isValid(apiKey)) {
|
|
27
|
-
console.log('\nš Magentrix CLI Setup:');
|
|
28
|
-
|
|
29
|
-
while (true) {
|
|
30
|
-
try {
|
|
31
|
-
const apiKeyInput = await password({
|
|
32
|
-
message: 'Enter your Magentrix API key (no spaces):',
|
|
33
|
-
mask: '*',
|
|
34
|
-
validate: (value) => {
|
|
35
|
-
if (!value || value.trim().length < 12) {
|
|
36
|
-
return "API key must be at least 12 characters.";
|
|
37
|
-
}
|
|
38
|
-
if (/\s/.test(value)) {
|
|
39
|
-
return "API key cannot contain any spaces.";
|
|
40
|
-
}
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
const trimmed = apiKeyInput.trim();
|
|
46
|
-
|
|
47
|
-
if (isValid(trimmed)) {
|
|
48
|
-
return trimmed;
|
|
49
|
-
}
|
|
50
|
-
} catch (error) {
|
|
51
|
-
// Handle Ctrl+C or other cancellation
|
|
52
|
-
if (error.name === 'ExitPromptError') {
|
|
53
|
-
console.error('\nā API key is required. Exiting.');
|
|
54
|
-
process.exit(1);
|
|
55
|
-
}
|
|
56
|
-
throw error;
|
|
57
|
-
}
|
|
58
|
-
// Invalid: will re-prompt.
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return apiKey;
|
|
63
|
-
};
|
|
1
|
+
import { password } from "@inquirer/prompts";
|
|
2
|
+
import Config from "../../config.js";
|
|
3
|
+
import { HASHED_CWD } from "../../../vars/global.js";
|
|
4
|
+
|
|
5
|
+
const config = new Config();
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Ensures a valid Magentrix API key is available in the global config.
|
|
9
|
+
* - If a key is missing, invalid, or forcePrompt is true, prompts the user to enter one.
|
|
10
|
+
* - Validates that the key is at least 12 characters long and contains no spaces.
|
|
11
|
+
* - Exits the process if the user fails to provide a valid key.
|
|
12
|
+
*
|
|
13
|
+
* @async
|
|
14
|
+
* @param {boolean} [forcePrompt=false] - If true, always prompt for API key, even if one exists.
|
|
15
|
+
* @returns {Promise<string>} The valid API key, either from config or user input.
|
|
16
|
+
*/
|
|
17
|
+
export const ensureApiKey = async (forcePrompt = false) => {
|
|
18
|
+
let apiKey = config.read('apiKey', { global: true, pathHash: HASHED_CWD });
|
|
19
|
+
|
|
20
|
+
// Helper: checks for min length and no spaces
|
|
21
|
+
const isValid = (key) =>
|
|
22
|
+
typeof key === "string" &&
|
|
23
|
+
key.trim().length >= 12 &&
|
|
24
|
+
!/\s/.test(key);
|
|
25
|
+
|
|
26
|
+
if (forcePrompt || !isValid(apiKey)) {
|
|
27
|
+
console.log('\nš Magentrix CLI Setup:');
|
|
28
|
+
|
|
29
|
+
while (true) {
|
|
30
|
+
try {
|
|
31
|
+
const apiKeyInput = await password({
|
|
32
|
+
message: 'Enter your Magentrix API key (no spaces):',
|
|
33
|
+
mask: '*',
|
|
34
|
+
validate: (value) => {
|
|
35
|
+
if (!value || value.trim().length < 12) {
|
|
36
|
+
return "API key must be at least 12 characters.";
|
|
37
|
+
}
|
|
38
|
+
if (/\s/.test(value)) {
|
|
39
|
+
return "API key cannot contain any spaces.";
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const trimmed = apiKeyInput.trim();
|
|
46
|
+
|
|
47
|
+
if (isValid(trimmed)) {
|
|
48
|
+
return trimmed;
|
|
49
|
+
}
|
|
50
|
+
} catch (error) {
|
|
51
|
+
// Handle Ctrl+C or other cancellation
|
|
52
|
+
if (error.name === 'ExitPromptError') {
|
|
53
|
+
console.error('\nā API key is required. Exiting.');
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
throw error;
|
|
57
|
+
}
|
|
58
|
+
// Invalid: will re-prompt.
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return apiKey;
|
|
63
|
+
};
|
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
import Config from "../../config.js";
|
|
2
|
-
import { setup } from "../../../actions/setup.js";
|
|
3
|
-
import { HASHED_CWD } from "../../../vars/global.js";
|
|
4
|
-
import { tryAuthenticate } from "../../magentrix/api/auth.js";
|
|
5
|
-
import debug from '../../debug.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Returns true if the token is present and not expired (60 seconds buffer).
|
|
9
|
-
* @param {{ value?: string, validUntil?: string } | undefined} tokenObj
|
|
10
|
-
* @returns {boolean}
|
|
11
|
-
*/
|
|
12
|
-
export function isTokenValid(tokenObj) {
|
|
13
|
-
if (!tokenObj || !tokenObj.value || !tokenObj.validUntil) return false;
|
|
14
|
-
const now = Date.now();
|
|
15
|
-
const expiresAt = Date.parse(tokenObj.validUntil);
|
|
16
|
-
if (isNaN(expiresAt)) return false;
|
|
17
|
-
const SECONDS_BEFORE_EXPIRY = 60 * 1000;
|
|
18
|
-
return expiresAt - now > SECONDS_BEFORE_EXPIRY;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Ensures Magentrix credentials are present and valid, refreshing the token if needed.
|
|
23
|
-
* Prompts user only when needed.
|
|
24
|
-
*
|
|
25
|
-
* @returns {Promise<{ apiKey: string, instanceUrl: string, token: { value: string, validUntil: string } }>}
|
|
26
|
-
*/
|
|
27
|
-
export async function ensureValidCredentials() {
|
|
28
|
-
const config = new Config();
|
|
29
|
-
|
|
30
|
-
// Load from config
|
|
31
|
-
const apiKey = config.read('apiKey', { global: true, pathHash: HASHED_CWD });
|
|
32
|
-
const instanceUrl = config.read('instanceUrl', { global: true, pathHash: HASHED_CWD });
|
|
33
|
-
const token = config.read('token', { global: true, pathHash: HASHED_CWD });
|
|
34
|
-
|
|
35
|
-
debug.auth(`Credential check: apiKey=${apiKey ? 'present' : 'missing'}, instanceUrl=${instanceUrl || '(missing)'}`);
|
|
36
|
-
|
|
37
|
-
// If missing API key or URL, prompt/setup immediately
|
|
38
|
-
if (!apiKey || !instanceUrl) {
|
|
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
|
-
return setup();
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// If token is present and valid, return immediately
|
|
44
|
-
if (isTokenValid(token)) {
|
|
45
|
-
debug.auth(`Existing token is valid (expires: ${token.validUntil})`);
|
|
46
|
-
return { apiKey, instanceUrl, token };
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
debug.auth(`Token ${token ? `expired (was valid until: ${token.validUntil})` : 'missing'}, refreshing...`);
|
|
50
|
-
|
|
51
|
-
// If we have API key & URL but no valid token, try to refresh
|
|
52
|
-
try {
|
|
53
|
-
const result = await tryAuthenticate(apiKey, instanceUrl);
|
|
54
|
-
|
|
55
|
-
if (!result || !result.token || !result.validUntil) {
|
|
56
|
-
throw new Error("Invalid token refresh response");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Save new token and return
|
|
60
|
-
const newToken = { value: result.token, validUntil: result.validUntil };
|
|
61
|
-
config.save('token', newToken, { global: true, pathHash: HASHED_CWD });
|
|
62
|
-
return { apiKey, instanceUrl, token: newToken };
|
|
63
|
-
} catch (err) {
|
|
64
|
-
debug.auth(`Token refresh failed: ${err.message}, falling back to setup wizard`);
|
|
65
|
-
// Failed to refresh, fall back to prompting the user
|
|
66
|
-
return setup();
|
|
67
|
-
}
|
|
68
|
-
}
|
|
1
|
+
import Config from "../../config.js";
|
|
2
|
+
import { setup } from "../../../actions/setup.js";
|
|
3
|
+
import { HASHED_CWD } from "../../../vars/global.js";
|
|
4
|
+
import { tryAuthenticate } from "../../magentrix/api/auth.js";
|
|
5
|
+
import debug from '../../debug.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Returns true if the token is present and not expired (60 seconds buffer).
|
|
9
|
+
* @param {{ value?: string, validUntil?: string } | undefined} tokenObj
|
|
10
|
+
* @returns {boolean}
|
|
11
|
+
*/
|
|
12
|
+
export function isTokenValid(tokenObj) {
|
|
13
|
+
if (!tokenObj || !tokenObj.value || !tokenObj.validUntil) return false;
|
|
14
|
+
const now = Date.now();
|
|
15
|
+
const expiresAt = Date.parse(tokenObj.validUntil);
|
|
16
|
+
if (isNaN(expiresAt)) return false;
|
|
17
|
+
const SECONDS_BEFORE_EXPIRY = 60 * 1000;
|
|
18
|
+
return expiresAt - now > SECONDS_BEFORE_EXPIRY;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Ensures Magentrix credentials are present and valid, refreshing the token if needed.
|
|
23
|
+
* Prompts user only when needed.
|
|
24
|
+
*
|
|
25
|
+
* @returns {Promise<{ apiKey: string, instanceUrl: string, token: { value: string, validUntil: string } }>}
|
|
26
|
+
*/
|
|
27
|
+
export async function ensureValidCredentials() {
|
|
28
|
+
const config = new Config();
|
|
29
|
+
|
|
30
|
+
// Load from config
|
|
31
|
+
const apiKey = config.read('apiKey', { global: true, pathHash: HASHED_CWD });
|
|
32
|
+
const instanceUrl = config.read('instanceUrl', { global: true, pathHash: HASHED_CWD });
|
|
33
|
+
const token = config.read('token', { global: true, pathHash: HASHED_CWD });
|
|
34
|
+
|
|
35
|
+
debug.auth(`Credential check: apiKey=${apiKey ? 'present' : 'missing'}, instanceUrl=${instanceUrl || '(missing)'}`);
|
|
36
|
+
|
|
37
|
+
// If missing API key or URL, prompt/setup immediately
|
|
38
|
+
if (!apiKey || !instanceUrl) {
|
|
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
|
+
return setup();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// If token is present and valid, return immediately
|
|
44
|
+
if (isTokenValid(token)) {
|
|
45
|
+
debug.auth(`Existing token is valid (expires: ${token.validUntil})`);
|
|
46
|
+
return { apiKey, instanceUrl, token };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
debug.auth(`Token ${token ? `expired (was valid until: ${token.validUntil})` : 'missing'}, refreshing...`);
|
|
50
|
+
|
|
51
|
+
// If we have API key & URL but no valid token, try to refresh
|
|
52
|
+
try {
|
|
53
|
+
const result = await tryAuthenticate(apiKey, instanceUrl);
|
|
54
|
+
|
|
55
|
+
if (!result || !result.token || !result.validUntil) {
|
|
56
|
+
throw new Error("Invalid token refresh response");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Save new token and return
|
|
60
|
+
const newToken = { value: result.token, validUntil: result.validUntil };
|
|
61
|
+
config.save('token', newToken, { global: true, pathHash: HASHED_CWD });
|
|
62
|
+
return { apiKey, instanceUrl, token: newToken };
|
|
63
|
+
} catch (err) {
|
|
64
|
+
debug.auth(`Token refresh failed: ${err.message}, falling back to setup wizard`);
|
|
65
|
+
// Failed to refresh, fall back to prompting the user
|
|
66
|
+
return setup();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
import { input } from "@inquirer/prompts";
|
|
2
|
-
import Config from "../../config.js";
|
|
3
|
-
import { checkInstanceUrl } from "../checkInstanceUrl.js";
|
|
4
|
-
import { withSpinner } from "../../spinner.js";
|
|
5
|
-
import { HASHED_CWD } from "../../../vars/global.js";
|
|
6
|
-
import debug from '../../debug.js';
|
|
7
|
-
|
|
8
|
-
const config = new Config();
|
|
9
|
-
const urlRegex = /^https:\/\/[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Ensures a valid Magentrix instance URL is available in the global config.
|
|
13
|
-
* Prompts until user provides a valid, reachable URL or cancels.
|
|
14
|
-
*
|
|
15
|
-
* @async
|
|
16
|
-
* @param {boolean} [forcePrompt=false] - If true, always prompt for instance URL, even if one exists.
|
|
17
|
-
* @returns {Promise<string>} The valid instance URL, either from config or user input.
|
|
18
|
-
*/
|
|
19
|
-
export const ensureInstanceUrl = async (forcePrompt = false) => {
|
|
20
|
-
let instanceUrl = config.read('instanceUrl', { global: true, pathHash: HASHED_CWD });
|
|
21
|
-
|
|
22
|
-
if (
|
|
23
|
-
forcePrompt ||
|
|
24
|
-
!instanceUrl ||
|
|
25
|
-
typeof instanceUrl !== 'string' ||
|
|
26
|
-
!urlRegex.test(instanceUrl.trim())
|
|
27
|
-
) {
|
|
28
|
-
console.log('\nš Magentrix CLI Setup: Instance URL');
|
|
29
|
-
|
|
30
|
-
while (true) {
|
|
31
|
-
try {
|
|
32
|
-
// Prompt: Only validate format, NOT reachability
|
|
33
|
-
const inputUrl = await input({
|
|
34
|
-
message: 'Enter your Magentrix instance URL (e.g., https://example.magentrix.com):',
|
|
35
|
-
validate: (value) => {
|
|
36
|
-
// Automatically strip trailing slashes for validation
|
|
37
|
-
const cleaned = value.trim().replace(/\/+$/, '');
|
|
38
|
-
if (!urlRegex.test(cleaned)) {
|
|
39
|
-
return 'Instance URL must be in the form: https://subdomain.domain.com (no http, no extra path)';
|
|
40
|
-
}
|
|
41
|
-
return true;
|
|
42
|
-
}
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// Trim and automatically strip trailing slashes
|
|
46
|
-
const trimmed = inputUrl.trim().replace(/\/+$/, '');
|
|
47
|
-
|
|
48
|
-
// Now check reachability WITH a spinner
|
|
49
|
-
debug.log('SETUP', `User entered instance URL: ${trimmed}`);
|
|
50
|
-
try {
|
|
51
|
-
await withSpinner('Checking instance URL...', () =>
|
|
52
|
-
checkInstanceUrl(trimmed)
|
|
53
|
-
);
|
|
54
|
-
|
|
55
|
-
debug.log('SETUP', `Instance URL reachable: ${trimmed}`);
|
|
56
|
-
return trimmed;
|
|
57
|
-
} catch (error) {
|
|
58
|
-
debug.log('SETUP', `Instance URL not reachable: ${trimmed} ā ${error.message}`);
|
|
59
|
-
// Print error AFTER spinner, then re-prompt
|
|
60
|
-
console.error('ā Instance URL not reachable. Try again.');
|
|
61
|
-
}
|
|
62
|
-
} catch (error) {
|
|
63
|
-
// Handle Ctrl+C or other cancellation
|
|
64
|
-
if (error.name === 'ExitPromptError') {
|
|
65
|
-
console.error('\nā Instance URL is required. Exiting.');
|
|
66
|
-
process.exit(1);
|
|
67
|
-
}
|
|
68
|
-
throw error;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Trim and automatically strip trailing slashes from existing URL
|
|
74
|
-
return instanceUrl.trim().replace(/\/+$/, '');
|
|
75
|
-
};
|
|
1
|
+
import { input } from "@inquirer/prompts";
|
|
2
|
+
import Config from "../../config.js";
|
|
3
|
+
import { checkInstanceUrl } from "../checkInstanceUrl.js";
|
|
4
|
+
import { withSpinner } from "../../spinner.js";
|
|
5
|
+
import { HASHED_CWD } from "../../../vars/global.js";
|
|
6
|
+
import debug from '../../debug.js';
|
|
7
|
+
|
|
8
|
+
const config = new Config();
|
|
9
|
+
const urlRegex = /^https:\/\/[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Ensures a valid Magentrix instance URL is available in the global config.
|
|
13
|
+
* Prompts until user provides a valid, reachable URL or cancels.
|
|
14
|
+
*
|
|
15
|
+
* @async
|
|
16
|
+
* @param {boolean} [forcePrompt=false] - If true, always prompt for instance URL, even if one exists.
|
|
17
|
+
* @returns {Promise<string>} The valid instance URL, either from config or user input.
|
|
18
|
+
*/
|
|
19
|
+
export const ensureInstanceUrl = async (forcePrompt = false) => {
|
|
20
|
+
let instanceUrl = config.read('instanceUrl', { global: true, pathHash: HASHED_CWD });
|
|
21
|
+
|
|
22
|
+
if (
|
|
23
|
+
forcePrompt ||
|
|
24
|
+
!instanceUrl ||
|
|
25
|
+
typeof instanceUrl !== 'string' ||
|
|
26
|
+
!urlRegex.test(instanceUrl.trim())
|
|
27
|
+
) {
|
|
28
|
+
console.log('\nš Magentrix CLI Setup: Instance URL');
|
|
29
|
+
|
|
30
|
+
while (true) {
|
|
31
|
+
try {
|
|
32
|
+
// Prompt: Only validate format, NOT reachability
|
|
33
|
+
const inputUrl = await input({
|
|
34
|
+
message: 'Enter your Magentrix instance URL (e.g., https://example.magentrix.com):',
|
|
35
|
+
validate: (value) => {
|
|
36
|
+
// Automatically strip trailing slashes for validation
|
|
37
|
+
const cleaned = value.trim().replace(/\/+$/, '');
|
|
38
|
+
if (!urlRegex.test(cleaned)) {
|
|
39
|
+
return 'Instance URL must be in the form: https://subdomain.domain.com (no http, no extra path)';
|
|
40
|
+
}
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Trim and automatically strip trailing slashes
|
|
46
|
+
const trimmed = inputUrl.trim().replace(/\/+$/, '');
|
|
47
|
+
|
|
48
|
+
// Now check reachability WITH a spinner
|
|
49
|
+
debug.log('SETUP', `User entered instance URL: ${trimmed}`);
|
|
50
|
+
try {
|
|
51
|
+
await withSpinner('Checking instance URL...', () =>
|
|
52
|
+
checkInstanceUrl(trimmed)
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
debug.log('SETUP', `Instance URL reachable: ${trimmed}`);
|
|
56
|
+
return trimmed;
|
|
57
|
+
} catch (error) {
|
|
58
|
+
debug.log('SETUP', `Instance URL not reachable: ${trimmed} ā ${error.message}`);
|
|
59
|
+
// Print error AFTER spinner, then re-prompt
|
|
60
|
+
console.error('ā Instance URL not reachable. Try again.');
|
|
61
|
+
}
|
|
62
|
+
} catch (error) {
|
|
63
|
+
// Handle Ctrl+C or other cancellation
|
|
64
|
+
if (error.name === 'ExitPromptError') {
|
|
65
|
+
console.error('\nā Instance URL is required. Exiting.');
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Trim and automatically strip trailing slashes from existing URL
|
|
74
|
+
return instanceUrl.trim().replace(/\/+$/, '');
|
|
75
|
+
};
|