@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.
Files changed (68) hide show
  1. package/LICENSE +25 -25
  2. package/README.md +1166 -1166
  3. package/actions/autopublish.old.js +293 -293
  4. package/actions/config.js +182 -182
  5. package/actions/create.js +466 -466
  6. package/actions/help.js +164 -164
  7. package/actions/iris/buildStage.js +874 -874
  8. package/actions/iris/delete.js +256 -256
  9. package/actions/iris/dev.js +391 -391
  10. package/actions/iris/index.js +6 -6
  11. package/actions/iris/link.js +375 -375
  12. package/actions/iris/recover.js +268 -268
  13. package/actions/main.js +80 -80
  14. package/actions/publish.js +1420 -1420
  15. package/actions/pull.js +684 -684
  16. package/actions/setup.js +148 -148
  17. package/actions/status.js +17 -17
  18. package/actions/update.js +248 -248
  19. package/bin/magentrix.js +393 -393
  20. package/package.json +55 -55
  21. package/utils/assetPaths.js +158 -158
  22. package/utils/autopublishLock.js +77 -77
  23. package/utils/cacher.js +206 -206
  24. package/utils/cli/checkInstanceUrl.js +76 -74
  25. package/utils/cli/helpers/compare.js +282 -282
  26. package/utils/cli/helpers/ensureApiKey.js +63 -63
  27. package/utils/cli/helpers/ensureCredentials.js +68 -68
  28. package/utils/cli/helpers/ensureInstanceUrl.js +75 -75
  29. package/utils/cli/writeRecords.js +262 -262
  30. package/utils/compare.js +135 -135
  31. package/utils/compress.js +17 -17
  32. package/utils/config.js +527 -527
  33. package/utils/debug.js +144 -144
  34. package/utils/diagnostics/testPublishLogic.js +96 -96
  35. package/utils/diff.js +49 -49
  36. package/utils/downloadAssets.js +291 -291
  37. package/utils/filetag.js +115 -115
  38. package/utils/hash.js +14 -14
  39. package/utils/iris/backup.js +411 -411
  40. package/utils/iris/builder.js +541 -541
  41. package/utils/iris/config-reader.js +664 -664
  42. package/utils/iris/deleteHelper.js +150 -150
  43. package/utils/iris/errors.js +537 -537
  44. package/utils/iris/linker.js +601 -601
  45. package/utils/iris/lock.js +360 -360
  46. package/utils/iris/validation.js +360 -360
  47. package/utils/iris/validator.js +281 -281
  48. package/utils/iris/zipper.js +248 -248
  49. package/utils/logger.js +291 -291
  50. package/utils/magentrix/api/assets.js +220 -220
  51. package/utils/magentrix/api/auth.js +107 -107
  52. package/utils/magentrix/api/createEntity.js +61 -61
  53. package/utils/magentrix/api/deleteEntity.js +55 -55
  54. package/utils/magentrix/api/iris.js +251 -251
  55. package/utils/magentrix/api/meqlQuery.js +36 -36
  56. package/utils/magentrix/api/retrieveEntity.js +86 -86
  57. package/utils/magentrix/api/updateEntity.js +66 -66
  58. package/utils/magentrix/fetch.js +168 -168
  59. package/utils/merge.js +22 -22
  60. package/utils/permissionError.js +70 -70
  61. package/utils/preferences.js +40 -40
  62. package/utils/progress.js +469 -469
  63. package/utils/spinner.js +43 -43
  64. package/utils/template.js +52 -52
  65. package/utils/updateFileBase.js +121 -121
  66. package/utils/workspaces.js +108 -108
  67. package/vars/config.js +11 -11
  68. package/vars/global.js +50 -50
@@ -1,248 +1,248 @@
1
- import { mkdirSync, rmSync, writeFileSync, readFileSync, existsSync, readdirSync, statSync, chmodSync } from 'node:fs';
2
- import { tmpdir } from 'node:os';
3
- import { join, basename } from 'node:path';
4
- import { randomUUID, createHash } from 'node:crypto';
5
- import archiver from 'archiver';
6
- import extractZip from 'extract-zip';
7
-
8
- // System/hidden files that should never be included in IRIS app zips or hashes
9
- const IGNORED_FILES = new Set(['.DS_Store', 'Thumbs.db', 'desktop.ini']);
10
-
11
- /**
12
- * Recursively fix permissions on extracted files.
13
- * Sets directories to 0o755 and files to 0o644.
14
- * This ensures the current user can read/write/delete the files.
15
- *
16
- * @param {string} dir - Directory to fix permissions for
17
- */
18
- function fixPermissions(dir) {
19
- if (!existsSync(dir)) return;
20
-
21
- try {
22
- const stat = statSync(dir);
23
- if (stat.isDirectory()) {
24
- chmodSync(dir, 0o755);
25
- const entries = readdirSync(dir);
26
- for (const entry of entries) {
27
- fixPermissions(join(dir, entry));
28
- }
29
- } else {
30
- chmodSync(dir, 0o644);
31
- }
32
- } catch {
33
- // Ignore permission errors - best effort
34
- }
35
- }
36
-
37
- /**
38
- * Create a zip file from a build directory with proper Iris structure.
39
- * The zip will contain a single root folder with the app slug.
40
- *
41
- * @param {string} distPath - Path to the build output directory (e.g., ./dist)
42
- * @param {string} appSlug - Slug for the app (becomes the root folder in zip)
43
- * @returns {Promise<Buffer>} - The zip file as a Buffer
44
- */
45
- export async function createIrisZip(distPath, appSlug) {
46
- return new Promise((resolve, reject) => {
47
- const chunks = [];
48
-
49
- const archive = archiver('zip', {
50
- zlib: { level: 9 } // Maximum compression
51
- });
52
-
53
- archive.on('data', (chunk) => {
54
- chunks.push(chunk);
55
- });
56
-
57
- archive.on('error', (err) => {
58
- reject(err);
59
- });
60
-
61
- archive.on('end', () => {
62
- resolve(Buffer.concat(chunks));
63
- });
64
-
65
- // Add the dist directory contents under the app slug folder
66
- // This creates the structure: appSlug/remoteEntry.js, appSlug/assets/...
67
- // Filter out OS-generated system files (.DS_Store, Thumbs.db, etc.)
68
- archive.directory(distPath, appSlug, (entry) =>
69
- IGNORED_FILES.has(basename(entry.name)) ? false : entry
70
- );
71
-
72
- archive.finalize();
73
- });
74
- }
75
-
76
- /**
77
- * Extract a zip buffer to a directory.
78
- *
79
- * @param {Buffer} zipBuffer - The zip file as a Buffer
80
- * @param {string} outputDir - Directory to extract to
81
- * @returns {Promise<string>} - Path to the extracted directory
82
- */
83
- export async function extractIrisZip(zipBuffer, outputDir) {
84
- // Create a temporary file to hold the zip
85
- const tempDir = join(tmpdir(), `iris-extract-${randomUUID()}`);
86
- const tempZipPath = join(tempDir, 'temp.zip');
87
-
88
- try {
89
- // Create temp directory
90
- mkdirSync(tempDir, { recursive: true });
91
-
92
- // Write buffer to temp file
93
- writeFileSync(tempZipPath, zipBuffer);
94
-
95
- // Ensure output directory exists
96
- mkdirSync(outputDir, { recursive: true });
97
-
98
- // Extract
99
- await extractZip(tempZipPath, { dir: outputDir });
100
-
101
- // Fix permissions so files can be deleted/modified later
102
- fixPermissions(outputDir);
103
-
104
- return outputDir;
105
- } finally {
106
- // Cleanup temp directory
107
- try {
108
- rmSync(tempDir, { recursive: true, force: true });
109
- } catch {
110
- // Ignore cleanup errors
111
- }
112
- }
113
- }
114
-
115
- /**
116
- * Get the size of a buffer in human-readable format.
117
- *
118
- * @param {number} bytes - Size in bytes
119
- * @returns {string} - Human-readable size (e.g., "1.2 MB")
120
- */
121
- export function formatFileSize(bytes) {
122
- if (bytes === 0) return '0 B';
123
-
124
- const units = ['B', 'KB', 'MB', 'GB'];
125
- const k = 1024;
126
- const i = Math.floor(Math.log(bytes) / Math.log(k));
127
-
128
- if (i === 0) return `${bytes} ${units[0]}`;
129
-
130
- return `${(bytes / Math.pow(k, i)).toFixed(1)} ${units[i]}`;
131
- }
132
-
133
- /**
134
- * Count files in a directory recursively.
135
- *
136
- * @param {string} dir - Directory path
137
- * @returns {number} - Number of files
138
- */
139
- export function countFiles(dir) {
140
- if (!existsSync(dir)) return 0;
141
-
142
- let count = 0;
143
-
144
- function walk(currentDir) {
145
- const entries = readdirSync(currentDir);
146
- for (const entry of entries) {
147
- const fullPath = join(currentDir, entry);
148
- const stat = statSync(fullPath);
149
- if (stat.isDirectory()) {
150
- walk(fullPath);
151
- } else {
152
- count++;
153
- }
154
- }
155
- }
156
-
157
- walk(dir);
158
- return count;
159
- }
160
-
161
- /**
162
- * Calculate total size of files in a directory recursively.
163
- *
164
- * @param {string} dir - Directory path
165
- * @returns {number} - Total size in bytes
166
- */
167
- export function calculateDirSize(dir) {
168
- if (!existsSync(dir)) return 0;
169
-
170
- let totalSize = 0;
171
-
172
- function walk(currentDir) {
173
- const entries = readdirSync(currentDir);
174
- for (const entry of entries) {
175
- const fullPath = join(currentDir, entry);
176
- const stat = statSync(fullPath);
177
- if (stat.isDirectory()) {
178
- walk(fullPath);
179
- } else {
180
- totalSize += stat.size;
181
- }
182
- }
183
- }
184
-
185
- walk(dir);
186
- return totalSize;
187
- }
188
-
189
- /**
190
- * Get list of all files in a directory recursively with relative paths.
191
- *
192
- * @param {string} dir - Directory path
193
- * @param {string} basePath - Base path for relative path calculation
194
- * @returns {string[]} - Array of relative file paths
195
- */
196
- export function getFilesRecursive(dir, basePath = dir) {
197
- if (!existsSync(dir)) return [];
198
-
199
- const files = [];
200
-
201
- function walk(currentDir) {
202
- const entries = readdirSync(currentDir);
203
- for (const entry of entries) {
204
- // Skip OS-generated system files
205
- if (IGNORED_FILES.has(entry)) continue;
206
-
207
- const fullPath = join(currentDir, entry);
208
- const stat = statSync(fullPath);
209
- if (stat.isDirectory()) {
210
- walk(fullPath);
211
- } else {
212
- const relativePath = fullPath.slice(basePath.length + 1);
213
- files.push(relativePath);
214
- }
215
- }
216
- }
217
-
218
- walk(dir);
219
- return files;
220
- }
221
-
222
- /**
223
- * Calculate a content hash for an entire Iris app folder.
224
- * Hashes all file contents and their relative paths to detect any changes.
225
- *
226
- * @param {string} dir - Directory path to the Iris app
227
- * @returns {string} - SHA256 hash of all files
228
- */
229
- export function hashIrisAppFolder(dir) {
230
- if (!existsSync(dir)) return '';
231
-
232
- const hash = createHash('sha256');
233
- const files = getFilesRecursive(dir).sort(); // Sort for consistent ordering
234
-
235
- for (const relativePath of files) {
236
- const fullPath = join(dir, relativePath);
237
- try {
238
- const content = readFileSync(fullPath);
239
- // Include the relative path in the hash so renames are detected
240
- hash.update(relativePath);
241
- hash.update(content);
242
- } catch {
243
- // Skip files we can't read
244
- }
245
- }
246
-
247
- return hash.digest('hex');
248
- }
1
+ import { mkdirSync, rmSync, writeFileSync, readFileSync, existsSync, readdirSync, statSync, chmodSync } from 'node:fs';
2
+ import { tmpdir } from 'node:os';
3
+ import { join, basename } from 'node:path';
4
+ import { randomUUID, createHash } from 'node:crypto';
5
+ import archiver from 'archiver';
6
+ import extractZip from 'extract-zip';
7
+
8
+ // System/hidden files that should never be included in IRIS app zips or hashes
9
+ const IGNORED_FILES = new Set(['.DS_Store', 'Thumbs.db', 'desktop.ini']);
10
+
11
+ /**
12
+ * Recursively fix permissions on extracted files.
13
+ * Sets directories to 0o755 and files to 0o644.
14
+ * This ensures the current user can read/write/delete the files.
15
+ *
16
+ * @param {string} dir - Directory to fix permissions for
17
+ */
18
+ function fixPermissions(dir) {
19
+ if (!existsSync(dir)) return;
20
+
21
+ try {
22
+ const stat = statSync(dir);
23
+ if (stat.isDirectory()) {
24
+ chmodSync(dir, 0o755);
25
+ const entries = readdirSync(dir);
26
+ for (const entry of entries) {
27
+ fixPermissions(join(dir, entry));
28
+ }
29
+ } else {
30
+ chmodSync(dir, 0o644);
31
+ }
32
+ } catch {
33
+ // Ignore permission errors - best effort
34
+ }
35
+ }
36
+
37
+ /**
38
+ * Create a zip file from a build directory with proper Iris structure.
39
+ * The zip will contain a single root folder with the app slug.
40
+ *
41
+ * @param {string} distPath - Path to the build output directory (e.g., ./dist)
42
+ * @param {string} appSlug - Slug for the app (becomes the root folder in zip)
43
+ * @returns {Promise<Buffer>} - The zip file as a Buffer
44
+ */
45
+ export async function createIrisZip(distPath, appSlug) {
46
+ return new Promise((resolve, reject) => {
47
+ const chunks = [];
48
+
49
+ const archive = archiver('zip', {
50
+ zlib: { level: 9 } // Maximum compression
51
+ });
52
+
53
+ archive.on('data', (chunk) => {
54
+ chunks.push(chunk);
55
+ });
56
+
57
+ archive.on('error', (err) => {
58
+ reject(err);
59
+ });
60
+
61
+ archive.on('end', () => {
62
+ resolve(Buffer.concat(chunks));
63
+ });
64
+
65
+ // Add the dist directory contents under the app slug folder
66
+ // This creates the structure: appSlug/remoteEntry.js, appSlug/assets/...
67
+ // Filter out OS-generated system files (.DS_Store, Thumbs.db, etc.)
68
+ archive.directory(distPath, appSlug, (entry) =>
69
+ IGNORED_FILES.has(basename(entry.name)) ? false : entry
70
+ );
71
+
72
+ archive.finalize();
73
+ });
74
+ }
75
+
76
+ /**
77
+ * Extract a zip buffer to a directory.
78
+ *
79
+ * @param {Buffer} zipBuffer - The zip file as a Buffer
80
+ * @param {string} outputDir - Directory to extract to
81
+ * @returns {Promise<string>} - Path to the extracted directory
82
+ */
83
+ export async function extractIrisZip(zipBuffer, outputDir) {
84
+ // Create a temporary file to hold the zip
85
+ const tempDir = join(tmpdir(), `iris-extract-${randomUUID()}`);
86
+ const tempZipPath = join(tempDir, 'temp.zip');
87
+
88
+ try {
89
+ // Create temp directory
90
+ mkdirSync(tempDir, { recursive: true });
91
+
92
+ // Write buffer to temp file
93
+ writeFileSync(tempZipPath, zipBuffer);
94
+
95
+ // Ensure output directory exists
96
+ mkdirSync(outputDir, { recursive: true });
97
+
98
+ // Extract
99
+ await extractZip(tempZipPath, { dir: outputDir });
100
+
101
+ // Fix permissions so files can be deleted/modified later
102
+ fixPermissions(outputDir);
103
+
104
+ return outputDir;
105
+ } finally {
106
+ // Cleanup temp directory
107
+ try {
108
+ rmSync(tempDir, { recursive: true, force: true });
109
+ } catch {
110
+ // Ignore cleanup errors
111
+ }
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Get the size of a buffer in human-readable format.
117
+ *
118
+ * @param {number} bytes - Size in bytes
119
+ * @returns {string} - Human-readable size (e.g., "1.2 MB")
120
+ */
121
+ export function formatFileSize(bytes) {
122
+ if (bytes === 0) return '0 B';
123
+
124
+ const units = ['B', 'KB', 'MB', 'GB'];
125
+ const k = 1024;
126
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
127
+
128
+ if (i === 0) return `${bytes} ${units[0]}`;
129
+
130
+ return `${(bytes / Math.pow(k, i)).toFixed(1)} ${units[i]}`;
131
+ }
132
+
133
+ /**
134
+ * Count files in a directory recursively.
135
+ *
136
+ * @param {string} dir - Directory path
137
+ * @returns {number} - Number of files
138
+ */
139
+ export function countFiles(dir) {
140
+ if (!existsSync(dir)) return 0;
141
+
142
+ let count = 0;
143
+
144
+ function walk(currentDir) {
145
+ const entries = readdirSync(currentDir);
146
+ for (const entry of entries) {
147
+ const fullPath = join(currentDir, entry);
148
+ const stat = statSync(fullPath);
149
+ if (stat.isDirectory()) {
150
+ walk(fullPath);
151
+ } else {
152
+ count++;
153
+ }
154
+ }
155
+ }
156
+
157
+ walk(dir);
158
+ return count;
159
+ }
160
+
161
+ /**
162
+ * Calculate total size of files in a directory recursively.
163
+ *
164
+ * @param {string} dir - Directory path
165
+ * @returns {number} - Total size in bytes
166
+ */
167
+ export function calculateDirSize(dir) {
168
+ if (!existsSync(dir)) return 0;
169
+
170
+ let totalSize = 0;
171
+
172
+ function walk(currentDir) {
173
+ const entries = readdirSync(currentDir);
174
+ for (const entry of entries) {
175
+ const fullPath = join(currentDir, entry);
176
+ const stat = statSync(fullPath);
177
+ if (stat.isDirectory()) {
178
+ walk(fullPath);
179
+ } else {
180
+ totalSize += stat.size;
181
+ }
182
+ }
183
+ }
184
+
185
+ walk(dir);
186
+ return totalSize;
187
+ }
188
+
189
+ /**
190
+ * Get list of all files in a directory recursively with relative paths.
191
+ *
192
+ * @param {string} dir - Directory path
193
+ * @param {string} basePath - Base path for relative path calculation
194
+ * @returns {string[]} - Array of relative file paths
195
+ */
196
+ export function getFilesRecursive(dir, basePath = dir) {
197
+ if (!existsSync(dir)) return [];
198
+
199
+ const files = [];
200
+
201
+ function walk(currentDir) {
202
+ const entries = readdirSync(currentDir);
203
+ for (const entry of entries) {
204
+ // Skip OS-generated system files
205
+ if (IGNORED_FILES.has(entry)) continue;
206
+
207
+ const fullPath = join(currentDir, entry);
208
+ const stat = statSync(fullPath);
209
+ if (stat.isDirectory()) {
210
+ walk(fullPath);
211
+ } else {
212
+ const relativePath = fullPath.slice(basePath.length + 1);
213
+ files.push(relativePath);
214
+ }
215
+ }
216
+ }
217
+
218
+ walk(dir);
219
+ return files;
220
+ }
221
+
222
+ /**
223
+ * Calculate a content hash for an entire Iris app folder.
224
+ * Hashes all file contents and their relative paths to detect any changes.
225
+ *
226
+ * @param {string} dir - Directory path to the Iris app
227
+ * @returns {string} - SHA256 hash of all files
228
+ */
229
+ export function hashIrisAppFolder(dir) {
230
+ if (!existsSync(dir)) return '';
231
+
232
+ const hash = createHash('sha256');
233
+ const files = getFilesRecursive(dir).sort(); // Sort for consistent ordering
234
+
235
+ for (const relativePath of files) {
236
+ const fullPath = join(dir, relativePath);
237
+ try {
238
+ const content = readFileSync(fullPath);
239
+ // Include the relative path in the hash so renames are detected
240
+ hash.update(relativePath);
241
+ hash.update(content);
242
+ } catch {
243
+ // Skip files we can't read
244
+ }
245
+ }
246
+
247
+ return hash.digest('hex');
248
+ }