@magentrix-corp/magentrix-cli 1.0.0
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 -0
- package/README.md +471 -0
- package/actions/autopublish.js +283 -0
- package/actions/autopublish.old.js +293 -0
- package/actions/autopublish.v2.js +447 -0
- package/actions/create.js +329 -0
- package/actions/help.js +165 -0
- package/actions/main.js +81 -0
- package/actions/publish.js +567 -0
- package/actions/pull.js +139 -0
- package/actions/setup.js +61 -0
- package/actions/status.js +17 -0
- package/bin/magentrix.js +159 -0
- package/package.json +61 -0
- package/utils/cacher.js +112 -0
- package/utils/cli/checkInstanceUrl.js +29 -0
- package/utils/cli/helpers/compare.js +281 -0
- package/utils/cli/helpers/ensureApiKey.js +57 -0
- package/utils/cli/helpers/ensureCredentials.js +60 -0
- package/utils/cli/helpers/ensureInstanceUrl.js +63 -0
- package/utils/cli/writeRecords.js +223 -0
- package/utils/compare.js +135 -0
- package/utils/compress.js +18 -0
- package/utils/config.js +451 -0
- package/utils/diff.js +49 -0
- package/utils/downloadAssets.js +75 -0
- package/utils/filetag.js +115 -0
- package/utils/hash.js +14 -0
- package/utils/magentrix/api/assets.js +145 -0
- package/utils/magentrix/api/auth.js +56 -0
- package/utils/magentrix/api/createEntity.js +61 -0
- package/utils/magentrix/api/deleteEntity.js +55 -0
- package/utils/magentrix/api/meqlQuery.js +31 -0
- package/utils/magentrix/api/retrieveEntity.js +32 -0
- package/utils/magentrix/api/updateEntity.js +66 -0
- package/utils/magentrix/fetch.js +154 -0
- package/utils/merge.js +22 -0
- package/utils/preferences.js +40 -0
- package/utils/spinner.js +43 -0
- package/utils/template.js +52 -0
- package/utils/updateFileBase.js +103 -0
- package/vars/config.js +1 -0
- package/vars/global.js +33 -0
package/actions/setup.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ensureApiKey } from "../utils/cli/helpers/ensureApiKey.js";
|
|
2
|
+
import { ensureInstanceUrl } from "../utils/cli/helpers/ensureInstanceUrl.js";
|
|
3
|
+
import Config from "../utils/config.js";
|
|
4
|
+
import { getAccessToken, tryAuthenticate } from "../utils/magentrix/api/auth.js";
|
|
5
|
+
import { ensureVSCodeFileAssociation } from "../utils/preferences.js";
|
|
6
|
+
import { EXPORT_ROOT, HASHED_CWD } from "../vars/global.js";
|
|
7
|
+
|
|
8
|
+
const config = new Config();
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Runs the global setup for the Magentrix CLI.
|
|
12
|
+
*
|
|
13
|
+
* Prompts the user for their API key and instance URL if needed,
|
|
14
|
+
* validates credentials by attempting authentication,
|
|
15
|
+
* and saves them to the global config if successful.
|
|
16
|
+
*
|
|
17
|
+
* @async
|
|
18
|
+
* @param {boolean} [forceNewData=false] - If true, always prompt for new data, even if values exist.
|
|
19
|
+
* @returns {Promise<{apiKey: string, instanceUrl: string}>} The saved API key and instance URL.
|
|
20
|
+
* @throws {Error} If authentication fails with provided credentials.
|
|
21
|
+
*/
|
|
22
|
+
export const setup = async () => {
|
|
23
|
+
// Prompt for API key and Instance URL if missing or if forceNewData is true
|
|
24
|
+
const apiKey = await ensureApiKey(true);
|
|
25
|
+
const instanceUrl = await ensureInstanceUrl(true);
|
|
26
|
+
|
|
27
|
+
// Validate credentials by attempting to fetch an access token
|
|
28
|
+
const tokenData = await tryAuthenticate(apiKey, instanceUrl);
|
|
29
|
+
|
|
30
|
+
console.log(); // Blank line for spacing
|
|
31
|
+
|
|
32
|
+
// Save values since authentication succeeded
|
|
33
|
+
config.save('instanceUrl', instanceUrl, { global: true, pathHash: HASHED_CWD });
|
|
34
|
+
console.log('✅ Instance URL saved securely!');
|
|
35
|
+
|
|
36
|
+
config.save('apiKey', apiKey, { global: true, pathHash: HASHED_CWD });
|
|
37
|
+
console.log('✅ API key saved securely!');
|
|
38
|
+
|
|
39
|
+
config.save(
|
|
40
|
+
'token',
|
|
41
|
+
{ value: tokenData.token, validUntil: tokenData.validUntil },
|
|
42
|
+
{ global: true, pathHash: HASHED_CWD }
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// Set up the editor
|
|
46
|
+
await ensureVSCodeFileAssociation('./');
|
|
47
|
+
|
|
48
|
+
console.log(); // Blank line for spacing
|
|
49
|
+
|
|
50
|
+
console.log('🎉 Setup complete.');
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
apiKey,
|
|
54
|
+
instanceUrl,
|
|
55
|
+
token: {
|
|
56
|
+
value: tokenData.token,
|
|
57
|
+
validUntil: tokenData.validUntil
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { showCurrentConflicts } from "../utils/cli/helpers/compare.js";
|
|
2
|
+
import { ensureValidCredentials } from "../utils/cli/helpers/ensureCredentials.js";
|
|
3
|
+
import { withSpinner } from "../utils/spinner.js";
|
|
4
|
+
import { EXPORT_ROOT } from "../vars/global.js";
|
|
5
|
+
|
|
6
|
+
export const status = async () => {
|
|
7
|
+
// Clear the terminal
|
|
8
|
+
process.stdout.write('\x1Bc');
|
|
9
|
+
|
|
10
|
+
const credentials = await withSpinner('Authenticating...', async () => {
|
|
11
|
+
return await ensureValidCredentials();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
console.log();
|
|
15
|
+
|
|
16
|
+
await showCurrentConflicts(EXPORT_ROOT, credentials.instanceUrl, credentials.token.value, true)
|
|
17
|
+
};
|
package/bin/magentrix.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Imports
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { VERSION } from '../vars/config.js';
|
|
7
|
+
import { setup } from '../actions/setup.js';
|
|
8
|
+
import { main } from '../actions/main.js';
|
|
9
|
+
import { pull } from '../actions/pull.js';
|
|
10
|
+
import { create } from '../actions/create.js';
|
|
11
|
+
import { autoPublish } from '../actions/autopublish.js';
|
|
12
|
+
import { status } from '../actions/status.js';
|
|
13
|
+
import { cacheDir, recacheFileIdIndex } from '../utils/cacher.js';
|
|
14
|
+
import { EXPORT_ROOT } from '../vars/global.js';
|
|
15
|
+
import { publish } from '../actions/publish.js';
|
|
16
|
+
|
|
17
|
+
// ── Middleware ────────────────────────────────
|
|
18
|
+
async function preMiddleware() {
|
|
19
|
+
await recacheFileIdIndex(EXPORT_ROOT);
|
|
20
|
+
await cacheDir(EXPORT_ROOT);
|
|
21
|
+
}
|
|
22
|
+
async function postMiddleware() {
|
|
23
|
+
await cacheDir(EXPORT_ROOT);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const withMiddleware = ({ pre, post }) => (fn) => async (...args) => {
|
|
27
|
+
if (pre) await pre(...args);
|
|
28
|
+
await fn(...args);
|
|
29
|
+
if (post) await post(...args);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// ── CLI Setup ────────────────────────────────
|
|
33
|
+
const program = new Command();
|
|
34
|
+
program
|
|
35
|
+
.name('magentrix')
|
|
36
|
+
.description('Manage Magentrix assets and automation')
|
|
37
|
+
.version(VERSION)
|
|
38
|
+
.configureHelp({
|
|
39
|
+
formatHelp: (cmd, helper) => {
|
|
40
|
+
const divider = chalk.gray('━'.repeat(60));
|
|
41
|
+
const titleBar = chalk.bold.bgBlue.white(' Magentrix CLI ');
|
|
42
|
+
const version = chalk.dim(`v${VERSION}`);
|
|
43
|
+
|
|
44
|
+
let help = `\n${divider}\n${titleBar} ${version}\n${divider}\n\n`;
|
|
45
|
+
help += `${chalk.dim('Manage Magentrix assets and automation')}\n\n`;
|
|
46
|
+
|
|
47
|
+
// Usage section
|
|
48
|
+
help += `${chalk.bold.yellow('USAGE')}\n`;
|
|
49
|
+
help += ` ${chalk.cyan('magentrix')} ${chalk.dim('<command> [options]')}\n\n`;
|
|
50
|
+
|
|
51
|
+
// Commands section
|
|
52
|
+
help += `${chalk.bold.yellow('COMMANDS')}\n`;
|
|
53
|
+
const commands = [
|
|
54
|
+
{ name: 'setup', desc: 'Configure your Magentrix API key', icon: '⚙️ ' },
|
|
55
|
+
{ name: 'pull', desc: 'Pull files from the remote server', icon: '📥 ' },
|
|
56
|
+
{ name: 'create', desc: 'Create files locally', icon: '✨ ' },
|
|
57
|
+
{ name: 'status', desc: 'Show file conflicts and sync status', icon: '📊 ' },
|
|
58
|
+
{ name: 'publish', desc: 'Publish pending changes to the remote server', icon: '📤 ' },
|
|
59
|
+
{ name: 'autopublish', desc: 'Watch & sync changes in real time', icon: '🔄 ' }
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const maxNameLen = Math.max(...commands.map(c => c.name.length));
|
|
63
|
+
commands.forEach(cmd => {
|
|
64
|
+
const padding = ' '.repeat(maxNameLen - cmd.name.length);
|
|
65
|
+
help += ` ${cmd.icon}${chalk.cyan.bold(cmd.name)}${padding} ${chalk.dim(cmd.desc)}\n`;
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
help += `\n${chalk.bold.yellow('OPTIONS')}\n`;
|
|
69
|
+
help += ` ${chalk.cyan('-V, --version')} ${chalk.dim('Output the version number')}\n`;
|
|
70
|
+
help += ` ${chalk.cyan('-h, --help')} ${chalk.dim('Display this help message')}\n`;
|
|
71
|
+
|
|
72
|
+
help += `\n${chalk.bold.yellow('EXAMPLES')}\n`;
|
|
73
|
+
help += ` ${chalk.dim('# Initial setup')}\n`;
|
|
74
|
+
help += ` ${chalk.cyan('magentrix setup')}\n\n`;
|
|
75
|
+
help += ` ${chalk.dim('# Pull remote files')}\n`;
|
|
76
|
+
help += ` ${chalk.cyan('magentrix pull')}\n\n`;
|
|
77
|
+
help += ` ${chalk.dim('# Auto-sync on file changes')}\n`;
|
|
78
|
+
help += ` ${chalk.cyan('magentrix autopublish')}\n`;
|
|
79
|
+
|
|
80
|
+
help += `\n${divider}\n`;
|
|
81
|
+
|
|
82
|
+
return help;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const withDefault = withMiddleware({ pre: preMiddleware, post: postMiddleware });
|
|
87
|
+
|
|
88
|
+
// ── Error Handlers ───────────────────────────
|
|
89
|
+
program.showHelpAfterError(false);
|
|
90
|
+
program.configureOutput({
|
|
91
|
+
outputError: (str, write) => {
|
|
92
|
+
// Custom error message for unknown options
|
|
93
|
+
if (str.includes('unknown option')) {
|
|
94
|
+
const match = str.match(/'([^']+)'/);
|
|
95
|
+
const option = match ? match[1] : str;
|
|
96
|
+
|
|
97
|
+
console.error(`\n${chalk.bgRed.white.bold(' ERROR ')} ${chalk.redBright('Unknown option:')} ${chalk.bold(option)}`);
|
|
98
|
+
console.error(`${chalk.yellow('💡 Tip:')} Run ${chalk.cyan('magentrix --help')} to see available options.\n`);
|
|
99
|
+
}
|
|
100
|
+
// Custom error message for unknown commands
|
|
101
|
+
else if (str.includes('unknown command')) {
|
|
102
|
+
const match = str.match(/'([^']+)'/);
|
|
103
|
+
const command = match ? match[1] : str;
|
|
104
|
+
|
|
105
|
+
console.error(`\n${chalk.bgRed.white.bold(' ERROR ')} ${chalk.redBright('Unknown command:')} ${chalk.bold(command)}`);
|
|
106
|
+
console.error(`${chalk.yellow('💡 Tip:')} Run ${chalk.cyan('magentrix --help')} to see available commands.\n`);
|
|
107
|
+
}
|
|
108
|
+
// Generic errors
|
|
109
|
+
else {
|
|
110
|
+
console.error(`\n${chalk.bgRed.white.bold(' ERROR ')} ${chalk.redBright(str.trim())}\n`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// ── Commands ─────────────────────────────────
|
|
116
|
+
program.command('setup').description('Configure your Magentrix API key').action(withDefault(setup));
|
|
117
|
+
program.command('pull').description('Pull files from the remote server').action(withDefault(pull));
|
|
118
|
+
program.command('create').description('Create files locally').action(withDefault(create));
|
|
119
|
+
program.command('status').description('Show file conflicts').action(withDefault(status));
|
|
120
|
+
program.command('autopublish').description('Watch & sync changes in real time').action(withDefault(autoPublish));
|
|
121
|
+
program.command('publish').description('Publish pending changes to the remote server').action(withDefault(publish));
|
|
122
|
+
|
|
123
|
+
// ── Unknown Command Handler ──────────────────
|
|
124
|
+
program.argument('[command]', 'command to run').action((cmd) => {
|
|
125
|
+
const runMain = async () => {
|
|
126
|
+
await preMiddleware();
|
|
127
|
+
await main();
|
|
128
|
+
await postMiddleware();
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
if (cmd) {
|
|
132
|
+
console.log(`\n${chalk.bgRed.white.bold(' ERROR ')} ${chalk.redBright(`Unknown command:`)} ${chalk.bold(cmd)}\n`);
|
|
133
|
+
console.log(`${chalk.yellow('💡 Tip:')} Run ${chalk.cyan('magentrix --help')} to view available commands.\n`);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
} else {
|
|
136
|
+
runMain().catch(handleFatal);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// ── Global Error Handler ─────────────────────
|
|
141
|
+
function handleFatal(err) {
|
|
142
|
+
const divider = chalk.gray('──────────────────────────────────────────────');
|
|
143
|
+
const header = `${chalk.bgRed.white.bold(' FATAL ERROR ')}`;
|
|
144
|
+
|
|
145
|
+
console.error(`\n${divider}\n${header}`);
|
|
146
|
+
console.error(`${chalk.redBright(err?.message || 'An unexpected error occurred.')}\n`);
|
|
147
|
+
|
|
148
|
+
if (process.env.DEBUG === 'true' && err?.stack) {
|
|
149
|
+
console.error(chalk.dim(err.stack));
|
|
150
|
+
console.error();
|
|
151
|
+
} else {
|
|
152
|
+
console.log(`${chalk.yellow('💡 Run with')} ${chalk.cyan('DEBUG=true')} ${chalk.yellow('for full details.')}`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
console.log(divider + '\n');
|
|
156
|
+
process.exit(1);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
program.parseAsync(process.argv).catch(handleFatal);
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@magentrix-corp/magentrix-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI tool for synchronizing local files with Magentrix cloud platform",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"magentrix": "./bin/magentrix.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"magentrix",
|
|
15
|
+
"cli",
|
|
16
|
+
"sync",
|
|
17
|
+
"cloud",
|
|
18
|
+
"automation",
|
|
19
|
+
"development-tools"
|
|
20
|
+
],
|
|
21
|
+
"author": "Magentrix Corporation",
|
|
22
|
+
"license": "UNLICENSED",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/Mangoz1x/MagentrixCLI.git"
|
|
26
|
+
},
|
|
27
|
+
"bugs": {
|
|
28
|
+
"url": "https://github.com/Mangoz1x/MagentrixCLI/issues"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://github.com/Mangoz1x/MagentrixCLI#readme",
|
|
31
|
+
"engines": {
|
|
32
|
+
"node": ">=20.0.0"
|
|
33
|
+
},
|
|
34
|
+
"publishConfig": {
|
|
35
|
+
"access": "public"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"bin/",
|
|
39
|
+
"actions/",
|
|
40
|
+
"utils/",
|
|
41
|
+
"vars/",
|
|
42
|
+
"README.md",
|
|
43
|
+
"LICENSE"
|
|
44
|
+
],
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@inquirer/prompts": "^7.6.0",
|
|
47
|
+
"chalk": "^5.4.1",
|
|
48
|
+
"chokidar": "^4.0.3",
|
|
49
|
+
"commander": "^14.0.0",
|
|
50
|
+
"diff": "^8.0.2",
|
|
51
|
+
"extract-zip": "^2.0.1",
|
|
52
|
+
"fuzzy": "^0.1.3",
|
|
53
|
+
"inquirer": "^12.7.0",
|
|
54
|
+
"node-diff3": "^3.1.2",
|
|
55
|
+
"ora": "^8.2.0",
|
|
56
|
+
"pako": "^2.1.0",
|
|
57
|
+
"prompts": "^2.4.2",
|
|
58
|
+
"readline-sync": "^1.4.10",
|
|
59
|
+
"uuid": "^11.1.0"
|
|
60
|
+
}
|
|
61
|
+
}
|
package/utils/cacher.js
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import Config from './config.js';
|
|
4
|
+
import { findFileByTag, getFileTag, isPathLinkedToTagByLastKnownPath, setFileTag } from './filetag.js';
|
|
5
|
+
import { compressString } from './compress.js';
|
|
6
|
+
import { sha256 } from './hash.js';
|
|
7
|
+
import { EXPORT_ROOT } from '../vars/global.js';
|
|
8
|
+
|
|
9
|
+
const config = new Config();
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Recursively caches all files in a directory with tagging and content snapshotting
|
|
13
|
+
* @param {string} dir - Directory to cache
|
|
14
|
+
* @returns {Promise<void>}
|
|
15
|
+
*/
|
|
16
|
+
export const cacheDir = async (dir) => {
|
|
17
|
+
if (!fs.existsSync(dir)) return;
|
|
18
|
+
|
|
19
|
+
const absDir = path.resolve(dir);
|
|
20
|
+
const files = await walkFiles(absDir);
|
|
21
|
+
|
|
22
|
+
const cache = config.read('cachedFiles', { global: false, filename: 'fileCache.json' }) || {};
|
|
23
|
+
|
|
24
|
+
for (const file of files) {
|
|
25
|
+
const stats = fs.statSync(file);
|
|
26
|
+
if (!stats.isFile()) continue;
|
|
27
|
+
|
|
28
|
+
const checkFileTag = async (retry = true) => {
|
|
29
|
+
// Check file tag
|
|
30
|
+
const tag = await getFileTag(file);
|
|
31
|
+
|
|
32
|
+
if (!tag) {
|
|
33
|
+
// Try to repair if there is a tag linked to that path
|
|
34
|
+
const dirLinkedTag = isPathLinkedToTagByLastKnownPath(file);
|
|
35
|
+
if (dirLinkedTag && retry) {
|
|
36
|
+
await setFileTag(file, dirLinkedTag);
|
|
37
|
+
return await checkFileTag(false);
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return tag;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const tag = await checkFileTag();
|
|
46
|
+
if (!tag) {
|
|
47
|
+
// There may not be a tag if the user manually created a file
|
|
48
|
+
// console.warn(`Warning: failed to tag file: ${file}`);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const content = fs.readFileSync(file, 'utf8');
|
|
53
|
+
const objectId = tag; // Use the tag so we don't get duplicates
|
|
54
|
+
|
|
55
|
+
cache[objectId] = {
|
|
56
|
+
tag,
|
|
57
|
+
lastKnownPath: file,
|
|
58
|
+
contentHash: sha256(content),
|
|
59
|
+
compressedContent: compressString(content),
|
|
60
|
+
size: stats.size,
|
|
61
|
+
mtimeMs: stats.mtimeMs,
|
|
62
|
+
dev: stats.dev,
|
|
63
|
+
ino: stats.ino
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
config.save('cachedFiles', cache, { global: false, filename: 'fileCache.json' });
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const recacheFileIdIndex = async (dir) => {
|
|
71
|
+
const files = await walkFiles(dir);
|
|
72
|
+
if (!files || files?.length < 1) return;
|
|
73
|
+
|
|
74
|
+
for (const file of files) {
|
|
75
|
+
const tag = await getFileTag(file);
|
|
76
|
+
if (!tag) continue;
|
|
77
|
+
|
|
78
|
+
// Update the index id cache
|
|
79
|
+
const lastKnownPath = findFileByTag(tag);
|
|
80
|
+
if (lastKnownPath !== file) {
|
|
81
|
+
await setFileTag(file, tag);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Recursively walks a directory and returns all file paths
|
|
88
|
+
* @param {string} dir
|
|
89
|
+
* @returns {Promise<string[]>}
|
|
90
|
+
*/
|
|
91
|
+
export async function walkFiles(dir, settings) {
|
|
92
|
+
const ignore = settings?.ignore || [];
|
|
93
|
+
|
|
94
|
+
if (!fs.existsSync(dir)) return;
|
|
95
|
+
let entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
96
|
+
let paths = [];
|
|
97
|
+
|
|
98
|
+
for (const entry of entries) {
|
|
99
|
+
if (ignore.find(p => entry.path.startsWith(p) || entry.path === p)) {
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const fullPath = path.join(dir, entry.name);
|
|
104
|
+
if (entry.isDirectory()) {
|
|
105
|
+
paths.push(...await walkFiles(fullPath, settings));
|
|
106
|
+
} else if (entry.isFile()) {
|
|
107
|
+
paths.push(fullPath);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return paths;
|
|
112
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if the provided Magentrix instance URL is reachable by making a GET request.
|
|
3
|
+
* Throws an error if the response status is not 200 (OK), or if there is a network error.
|
|
4
|
+
*
|
|
5
|
+
* @async
|
|
6
|
+
* @param {string} instanceUrl - The https://subdomain.magentrixcloud.com URL to check.
|
|
7
|
+
* @throws {Error} Throws if the instance is unreachable or does not return 200 OK.
|
|
8
|
+
* @returns {Promise<void>} Resolves if the instance is reachable (status 200); otherwise throws.
|
|
9
|
+
*/
|
|
10
|
+
export const checkInstanceUrl = async (instanceUrl) => {
|
|
11
|
+
try {
|
|
12
|
+
// Native fetch is available in Node 18+; for older versions, use node-fetch.
|
|
13
|
+
const response = await fetch(instanceUrl, {
|
|
14
|
+
method: "GET",
|
|
15
|
+
// You can add a small timeout here using AbortController if needed.
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
if (response.status !== 200) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
`Instance URL responded with status ${response.status} (${response.statusText}). Expected 200 OK.`
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
} catch (err) {
|
|
24
|
+
// Wrap and re-throw to provide a clear error message.
|
|
25
|
+
throw new Error(
|
|
26
|
+
`Failed to reach instance URL "${instanceUrl}": ${err.message || err}`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
};
|