seabox 0.1.1 → 0.2.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/.mocharc.json +6 -6
- package/LICENSE.MD +21 -21
- package/README.md +310 -310
- package/bin/seabox-rebuild.mjs +88 -88
- package/bin/seabox.mjs +150 -147
- package/lib/blob.mjs +104 -104
- package/lib/bootstrap.cjs +756 -753
- package/lib/build-cache.mjs +199 -199
- package/lib/build.mjs +77 -77
- package/lib/config.mjs +243 -243
- package/lib/crypto-assets.mjs +125 -125
- package/lib/diagnostics.mjs +203 -203
- package/lib/entry-bundler.mjs +64 -64
- package/lib/fetch-node.mjs +172 -172
- package/lib/index.mjs +26 -26
- package/lib/inject.mjs +106 -106
- package/lib/manifest.mjs +100 -100
- package/lib/multi-target-builder.mjs +697 -705
- package/lib/native-scanner.mjs +203 -203
- package/lib/obfuscate.mjs +51 -51
- package/lib/require-shim.mjs +113 -113
- package/lib/rolldown-bundler.mjs +411 -411
- package/lib/unsign.cjs +197 -169
- package/package.json +61 -61
package/lib/crypto-assets.mjs
CHANGED
|
@@ -1,125 +1,125 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* crypto-assets.mjs
|
|
3
|
-
* Asset encryption/decryption utilities for SEA applications.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import crypto from 'crypto';
|
|
7
|
-
import fs from 'fs';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Generate a random encryption key.
|
|
11
|
-
* @returns {Buffer} - 32-byte key for AES-256
|
|
12
|
-
*/
|
|
13
|
-
export function generateEncryptionKey() {
|
|
14
|
-
return crypto.randomBytes(32);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Encrypt asset data using AES-256-GCM.
|
|
19
|
-
* @param {Buffer} data - Asset data to encrypt
|
|
20
|
-
* @param {Buffer} key - 32-byte encryption key
|
|
21
|
-
* @returns {Buffer} - Encrypted data with IV and auth tag prepended
|
|
22
|
-
*/
|
|
23
|
-
export function encryptAsset(data, key) {
|
|
24
|
-
// Generate a random IV for this encryption
|
|
25
|
-
const iv = crypto.randomBytes(16);
|
|
26
|
-
|
|
27
|
-
// Create cipher
|
|
28
|
-
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
|
|
29
|
-
|
|
30
|
-
// Encrypt the data
|
|
31
|
-
const encrypted = Buffer.concat([
|
|
32
|
-
cipher.update(data),
|
|
33
|
-
cipher.final()
|
|
34
|
-
]);
|
|
35
|
-
|
|
36
|
-
// Get the authentication tag
|
|
37
|
-
const authTag = cipher.getAuthTag();
|
|
38
|
-
|
|
39
|
-
// Format: [IV (16 bytes)] + [Auth Tag (16 bytes)] + [Encrypted Data]
|
|
40
|
-
return Buffer.concat([iv, authTag, encrypted]);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Decrypt asset data using AES-256-GCM.
|
|
45
|
-
* @param {Buffer} encryptedData - Encrypted data with IV and auth tag prepended
|
|
46
|
-
* @param {Buffer} key - 32-byte encryption key
|
|
47
|
-
* @returns {Buffer} - Decrypted data
|
|
48
|
-
*/
|
|
49
|
-
export function decryptAsset(encryptedData, key) {
|
|
50
|
-
// Extract IV, auth tag, and encrypted content
|
|
51
|
-
const iv = encryptedData.slice(0, 16);
|
|
52
|
-
const authTag = encryptedData.slice(16, 32);
|
|
53
|
-
const encrypted = encryptedData.slice(32);
|
|
54
|
-
|
|
55
|
-
// Create decipher
|
|
56
|
-
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
|
|
57
|
-
decipher.setAuthTag(authTag);
|
|
58
|
-
|
|
59
|
-
// Decrypt the data
|
|
60
|
-
const decrypted = Buffer.concat([
|
|
61
|
-
decipher.update(encrypted),
|
|
62
|
-
decipher.final()
|
|
63
|
-
]);
|
|
64
|
-
|
|
65
|
-
return decrypted;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Encrypt multiple assets.
|
|
70
|
-
* @param {Array} assets - Assets to encrypt
|
|
71
|
-
* @param {Buffer} key - Encryption key
|
|
72
|
-
* @param {string[]} [excludePatterns] - Patterns to exclude from encryption
|
|
73
|
-
* @returns {Map<string, Buffer>} - Map of asset key to encrypted content
|
|
74
|
-
*/
|
|
75
|
-
export function encryptAssets(assets, key, excludePatterns = []) {
|
|
76
|
-
const encrypted = new Map();
|
|
77
|
-
|
|
78
|
-
for (const asset of assets) {
|
|
79
|
-
// Skip binaries
|
|
80
|
-
if (asset.isBinary) {
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Check if this asset should be excluded from encryption
|
|
85
|
-
let shouldExclude = false;
|
|
86
|
-
for (const pattern of excludePatterns) {
|
|
87
|
-
if (asset.assetKey.includes(pattern) || asset.assetKey.endsWith(pattern)) {
|
|
88
|
-
shouldExclude = true;
|
|
89
|
-
break;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (shouldExclude) {
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Get asset content
|
|
98
|
-
const content = asset.content || fs.readFileSync(asset.sourcePath);
|
|
99
|
-
|
|
100
|
-
// Encrypt it
|
|
101
|
-
const encryptedContent = encryptAsset(content, key);
|
|
102
|
-
encrypted.set(asset.assetKey, encryptedContent);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return encrypted;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Generate a more obfuscated version of the key embedding code.
|
|
110
|
-
* @param {Buffer} key - Encryption key
|
|
111
|
-
* @returns {string} - Obfuscated JavaScript code
|
|
112
|
-
*/
|
|
113
|
-
export function keyToObfuscatedCode(key) {
|
|
114
|
-
// Convert to array of byte values
|
|
115
|
-
const bytes = Array.from(key);
|
|
116
|
-
|
|
117
|
-
// Create a simple XOR mask
|
|
118
|
-
const xorMask = 0x5A;
|
|
119
|
-
|
|
120
|
-
// XOR each byte with the mask
|
|
121
|
-
const masked = bytes.map(b => b ^ xorMask);
|
|
122
|
-
|
|
123
|
-
// Return code that reconstructs the key
|
|
124
|
-
return `Buffer.from([${masked.join(',')}].map(b => b ^ 0x${xorMask.toString(16)}))`;
|
|
125
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* crypto-assets.mjs
|
|
3
|
+
* Asset encryption/decryption utilities for SEA applications.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import crypto from 'crypto';
|
|
7
|
+
import fs from 'fs';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Generate a random encryption key.
|
|
11
|
+
* @returns {Buffer} - 32-byte key for AES-256
|
|
12
|
+
*/
|
|
13
|
+
export function generateEncryptionKey() {
|
|
14
|
+
return crypto.randomBytes(32);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Encrypt asset data using AES-256-GCM.
|
|
19
|
+
* @param {Buffer} data - Asset data to encrypt
|
|
20
|
+
* @param {Buffer} key - 32-byte encryption key
|
|
21
|
+
* @returns {Buffer} - Encrypted data with IV and auth tag prepended
|
|
22
|
+
*/
|
|
23
|
+
export function encryptAsset(data, key) {
|
|
24
|
+
// Generate a random IV for this encryption
|
|
25
|
+
const iv = crypto.randomBytes(16);
|
|
26
|
+
|
|
27
|
+
// Create cipher
|
|
28
|
+
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
|
|
29
|
+
|
|
30
|
+
// Encrypt the data
|
|
31
|
+
const encrypted = Buffer.concat([
|
|
32
|
+
cipher.update(data),
|
|
33
|
+
cipher.final()
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
// Get the authentication tag
|
|
37
|
+
const authTag = cipher.getAuthTag();
|
|
38
|
+
|
|
39
|
+
// Format: [IV (16 bytes)] + [Auth Tag (16 bytes)] + [Encrypted Data]
|
|
40
|
+
return Buffer.concat([iv, authTag, encrypted]);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Decrypt asset data using AES-256-GCM.
|
|
45
|
+
* @param {Buffer} encryptedData - Encrypted data with IV and auth tag prepended
|
|
46
|
+
* @param {Buffer} key - 32-byte encryption key
|
|
47
|
+
* @returns {Buffer} - Decrypted data
|
|
48
|
+
*/
|
|
49
|
+
export function decryptAsset(encryptedData, key) {
|
|
50
|
+
// Extract IV, auth tag, and encrypted content
|
|
51
|
+
const iv = encryptedData.slice(0, 16);
|
|
52
|
+
const authTag = encryptedData.slice(16, 32);
|
|
53
|
+
const encrypted = encryptedData.slice(32);
|
|
54
|
+
|
|
55
|
+
// Create decipher
|
|
56
|
+
const decipher = crypto.createDecipheriv('aes-256-gcm', key, iv);
|
|
57
|
+
decipher.setAuthTag(authTag);
|
|
58
|
+
|
|
59
|
+
// Decrypt the data
|
|
60
|
+
const decrypted = Buffer.concat([
|
|
61
|
+
decipher.update(encrypted),
|
|
62
|
+
decipher.final()
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
return decrypted;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Encrypt multiple assets.
|
|
70
|
+
* @param {Array} assets - Assets to encrypt
|
|
71
|
+
* @param {Buffer} key - Encryption key
|
|
72
|
+
* @param {string[]} [excludePatterns] - Patterns to exclude from encryption
|
|
73
|
+
* @returns {Map<string, Buffer>} - Map of asset key to encrypted content
|
|
74
|
+
*/
|
|
75
|
+
export function encryptAssets(assets, key, excludePatterns = []) {
|
|
76
|
+
const encrypted = new Map();
|
|
77
|
+
|
|
78
|
+
for (const asset of assets) {
|
|
79
|
+
// Skip binaries
|
|
80
|
+
if (asset.isBinary) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Check if this asset should be excluded from encryption
|
|
85
|
+
let shouldExclude = false;
|
|
86
|
+
for (const pattern of excludePatterns) {
|
|
87
|
+
if (asset.assetKey.includes(pattern) || asset.assetKey.endsWith(pattern)) {
|
|
88
|
+
shouldExclude = true;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (shouldExclude) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Get asset content
|
|
98
|
+
const content = asset.content || fs.readFileSync(asset.sourcePath);
|
|
99
|
+
|
|
100
|
+
// Encrypt it
|
|
101
|
+
const encryptedContent = encryptAsset(content, key);
|
|
102
|
+
encrypted.set(asset.assetKey, encryptedContent);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return encrypted;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Generate a more obfuscated version of the key embedding code.
|
|
110
|
+
* @param {Buffer} key - Encryption key
|
|
111
|
+
* @returns {string} - Obfuscated JavaScript code
|
|
112
|
+
*/
|
|
113
|
+
export function keyToObfuscatedCode(key) {
|
|
114
|
+
// Convert to array of byte values
|
|
115
|
+
const bytes = Array.from(key);
|
|
116
|
+
|
|
117
|
+
// Create a simple XOR mask
|
|
118
|
+
const xorMask = 0x5A;
|
|
119
|
+
|
|
120
|
+
// XOR each byte with the mask
|
|
121
|
+
const masked = bytes.map(b => b ^ xorMask);
|
|
122
|
+
|
|
123
|
+
// Return code that reconstructs the key
|
|
124
|
+
return `Buffer.from([${masked.join(',')}].map(b => b ^ 0x${xorMask.toString(16)}))`;
|
|
125
|
+
}
|
package/lib/diagnostics.mjs
CHANGED
|
@@ -1,203 +1,203 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* diagnostics.mjs
|
|
3
|
-
* Centralized console output formatting for CLI tooling.
|
|
4
|
-
* Provides consistent formatting, indentation, and styling.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Output levels
|
|
9
|
-
*/
|
|
10
|
-
export const Level = {
|
|
11
|
-
ERROR: 'error',
|
|
12
|
-
WARN: 'warn',
|
|
13
|
-
INFO: 'info',
|
|
14
|
-
SUCCESS: 'success',
|
|
15
|
-
VERBOSE: 'verbose'
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Formatting utilities
|
|
20
|
-
*/
|
|
21
|
-
const colors = {
|
|
22
|
-
reset: '\x1b[0m',
|
|
23
|
-
red: '\x1b[31m',
|
|
24
|
-
green: '\x1b[32m',
|
|
25
|
-
yellow: '\x1b[33m',
|
|
26
|
-
blue: '\x1b[34m',
|
|
27
|
-
gray: '\x1b[90m'
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
function withColor(text, color) {
|
|
31
|
-
return `${color}${text}${colors.reset}`;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Global verbose flag
|
|
36
|
-
*/
|
|
37
|
-
let verboseEnabled = false;
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Enable or disable verbose output
|
|
41
|
-
* @param {boolean} enabled
|
|
42
|
-
*/
|
|
43
|
-
export function setVerbose(enabled) {
|
|
44
|
-
verboseEnabled = enabled;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Core logging function
|
|
49
|
-
* @param {string} message
|
|
50
|
-
* @param {string} prefix
|
|
51
|
-
* @param {number} indent
|
|
52
|
-
*/
|
|
53
|
-
function log(message, prefix = '', indent = 0) {
|
|
54
|
-
const indentation = ' '.repeat(indent);
|
|
55
|
-
console.log(`${indentation}${prefix}${message}`);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Print section header
|
|
60
|
-
* @param {string} title
|
|
61
|
-
*/
|
|
62
|
-
export function header(title) {
|
|
63
|
-
console.log(`\n${title}`);
|
|
64
|
-
console.log('='.repeat(40));
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Print sub-header
|
|
69
|
-
* @param {string} title
|
|
70
|
-
*/
|
|
71
|
-
export function subheader(title) {
|
|
72
|
-
console.log(`\n${title}`);
|
|
73
|
-
console.log('-'.repeat(40));
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Print step with number
|
|
78
|
-
* @param {number} step
|
|
79
|
-
* @param {number} total
|
|
80
|
-
* @param {string} message
|
|
81
|
-
*/
|
|
82
|
-
export function step(step, total, message) {
|
|
83
|
-
log(`[${step}/${total}] ${message}`);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Print build step
|
|
88
|
-
* @param {number} buildNum
|
|
89
|
-
* @param {number} stepNum
|
|
90
|
-
* @param {string} message
|
|
91
|
-
*/
|
|
92
|
-
export function buildStep(buildNum, stepNum, message) {
|
|
93
|
-
log(`[${buildNum}.${stepNum}] ${message}`, '', 1);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Print success message
|
|
98
|
-
* @param {string} message
|
|
99
|
-
* @param {number} indent
|
|
100
|
-
*/
|
|
101
|
-
export function success(message, indent = 1) {
|
|
102
|
-
log(withColor(`[✓] ${message}`, colors.green), '', indent);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* Print info message
|
|
107
|
-
* @param {string} message
|
|
108
|
-
* @param {number} indent
|
|
109
|
-
*/
|
|
110
|
-
export function info(message, indent = 0) {
|
|
111
|
-
log(message, '', indent);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Print warning
|
|
116
|
-
* @param {string} message
|
|
117
|
-
* @param {number} indent
|
|
118
|
-
*/
|
|
119
|
-
export function warn(message, indent = 1) {
|
|
120
|
-
log(withColor(`[!] ${message}`, colors.yellow), '', indent);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Print error
|
|
125
|
-
* @param {string} message
|
|
126
|
-
* @param {number} indent
|
|
127
|
-
*/
|
|
128
|
-
export function error(message, indent = 0) {
|
|
129
|
-
console.error(`${' '.repeat(indent)}${withColor(`[X] ${message}`, colors.red)}`);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Print verbose message (only if verbose enabled)
|
|
134
|
-
* @param {string} message
|
|
135
|
-
* @param {number} indent
|
|
136
|
-
*/
|
|
137
|
-
export function verbose(message, indent = 2) {
|
|
138
|
-
if (verboseEnabled) {
|
|
139
|
-
log(withColor(message, colors.gray), '', indent);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Print list item
|
|
145
|
-
* @param {string} message
|
|
146
|
-
* @param {number} indent
|
|
147
|
-
*/
|
|
148
|
-
export function listItem(message, indent = 1) {
|
|
149
|
-
log(`- ${message}`, '', indent);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/**
|
|
153
|
-
* Print numbered list item
|
|
154
|
-
* @param {number} num
|
|
155
|
-
* @param {string} message
|
|
156
|
-
* @param {number} indent
|
|
157
|
-
*/
|
|
158
|
-
export function numberedItem(num, message, indent = 1) {
|
|
159
|
-
log(`${num}. ${message}`, '', indent);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Print section separator
|
|
164
|
-
*/
|
|
165
|
-
export function separator() {
|
|
166
|
-
console.log('');
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Print final summary
|
|
171
|
-
* @param {string} message
|
|
172
|
-
*/
|
|
173
|
-
export function summary(message) {
|
|
174
|
-
console.log('');
|
|
175
|
-
console.log('='.repeat(40));
|
|
176
|
-
log(withColor(message, colors.green));
|
|
177
|
-
console.log('='.repeat(40));
|
|
178
|
-
console.log('');
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Format file size in human-readable format
|
|
183
|
-
* @param {number} bytes
|
|
184
|
-
* @returns {string}
|
|
185
|
-
*/
|
|
186
|
-
export function formatSize(bytes) {
|
|
187
|
-
const mb = bytes / 1024 / 1024;
|
|
188
|
-
if (mb >= 1) {
|
|
189
|
-
return `${mb.toFixed(2)} MB`;
|
|
190
|
-
}
|
|
191
|
-
const kb = bytes / 1024;
|
|
192
|
-
return `${kb.toFixed(2)} KB`;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Format target string
|
|
197
|
-
* @param {string} platform
|
|
198
|
-
* @param {string} arch
|
|
199
|
-
* @returns {string}
|
|
200
|
-
*/
|
|
201
|
-
export function formatTarget(platform, arch) {
|
|
202
|
-
return `${platform}-${arch}`;
|
|
203
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* diagnostics.mjs
|
|
3
|
+
* Centralized console output formatting for CLI tooling.
|
|
4
|
+
* Provides consistent formatting, indentation, and styling.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Output levels
|
|
9
|
+
*/
|
|
10
|
+
export const Level = {
|
|
11
|
+
ERROR: 'error',
|
|
12
|
+
WARN: 'warn',
|
|
13
|
+
INFO: 'info',
|
|
14
|
+
SUCCESS: 'success',
|
|
15
|
+
VERBOSE: 'verbose'
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Formatting utilities
|
|
20
|
+
*/
|
|
21
|
+
const colors = {
|
|
22
|
+
reset: '\x1b[0m',
|
|
23
|
+
red: '\x1b[31m',
|
|
24
|
+
green: '\x1b[32m',
|
|
25
|
+
yellow: '\x1b[33m',
|
|
26
|
+
blue: '\x1b[34m',
|
|
27
|
+
gray: '\x1b[90m'
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
function withColor(text, color) {
|
|
31
|
+
return `${color}${text}${colors.reset}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Global verbose flag
|
|
36
|
+
*/
|
|
37
|
+
let verboseEnabled = false;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Enable or disable verbose output
|
|
41
|
+
* @param {boolean} enabled
|
|
42
|
+
*/
|
|
43
|
+
export function setVerbose(enabled) {
|
|
44
|
+
verboseEnabled = enabled;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Core logging function
|
|
49
|
+
* @param {string} message
|
|
50
|
+
* @param {string} prefix
|
|
51
|
+
* @param {number} indent
|
|
52
|
+
*/
|
|
53
|
+
function log(message, prefix = '', indent = 0) {
|
|
54
|
+
const indentation = ' '.repeat(indent);
|
|
55
|
+
console.log(`${indentation}${prefix}${message}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Print section header
|
|
60
|
+
* @param {string} title
|
|
61
|
+
*/
|
|
62
|
+
export function header(title) {
|
|
63
|
+
console.log(`\n${title}`);
|
|
64
|
+
console.log('='.repeat(40));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Print sub-header
|
|
69
|
+
* @param {string} title
|
|
70
|
+
*/
|
|
71
|
+
export function subheader(title) {
|
|
72
|
+
console.log(`\n${title}`);
|
|
73
|
+
console.log('-'.repeat(40));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Print step with number
|
|
78
|
+
* @param {number} step
|
|
79
|
+
* @param {number} total
|
|
80
|
+
* @param {string} message
|
|
81
|
+
*/
|
|
82
|
+
export function step(step, total, message) {
|
|
83
|
+
log(`[${step}/${total}] ${message}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Print build step
|
|
88
|
+
* @param {number} buildNum
|
|
89
|
+
* @param {number} stepNum
|
|
90
|
+
* @param {string} message
|
|
91
|
+
*/
|
|
92
|
+
export function buildStep(buildNum, stepNum, message) {
|
|
93
|
+
log(`[${buildNum}.${stepNum}] ${message}`, '', 1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Print success message
|
|
98
|
+
* @param {string} message
|
|
99
|
+
* @param {number} indent
|
|
100
|
+
*/
|
|
101
|
+
export function success(message, indent = 1) {
|
|
102
|
+
log(withColor(`[✓] ${message}`, colors.green), '', indent);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Print info message
|
|
107
|
+
* @param {string} message
|
|
108
|
+
* @param {number} indent
|
|
109
|
+
*/
|
|
110
|
+
export function info(message, indent = 0) {
|
|
111
|
+
log(message, '', indent);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Print warning
|
|
116
|
+
* @param {string} message
|
|
117
|
+
* @param {number} indent
|
|
118
|
+
*/
|
|
119
|
+
export function warn(message, indent = 1) {
|
|
120
|
+
log(withColor(`[!] ${message}`, colors.yellow), '', indent);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Print error
|
|
125
|
+
* @param {string} message
|
|
126
|
+
* @param {number} indent
|
|
127
|
+
*/
|
|
128
|
+
export function error(message, indent = 0) {
|
|
129
|
+
console.error(`${' '.repeat(indent)}${withColor(`[X] ${message}`, colors.red)}`);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Print verbose message (only if verbose enabled)
|
|
134
|
+
* @param {string} message
|
|
135
|
+
* @param {number} indent
|
|
136
|
+
*/
|
|
137
|
+
export function verbose(message, indent = 2) {
|
|
138
|
+
if (verboseEnabled) {
|
|
139
|
+
log(withColor(message, colors.gray), '', indent);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Print list item
|
|
145
|
+
* @param {string} message
|
|
146
|
+
* @param {number} indent
|
|
147
|
+
*/
|
|
148
|
+
export function listItem(message, indent = 1) {
|
|
149
|
+
log(`- ${message}`, '', indent);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Print numbered list item
|
|
154
|
+
* @param {number} num
|
|
155
|
+
* @param {string} message
|
|
156
|
+
* @param {number} indent
|
|
157
|
+
*/
|
|
158
|
+
export function numberedItem(num, message, indent = 1) {
|
|
159
|
+
log(`${num}. ${message}`, '', indent);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Print section separator
|
|
164
|
+
*/
|
|
165
|
+
export function separator() {
|
|
166
|
+
console.log('');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Print final summary
|
|
171
|
+
* @param {string} message
|
|
172
|
+
*/
|
|
173
|
+
export function summary(message) {
|
|
174
|
+
console.log('');
|
|
175
|
+
console.log('='.repeat(40));
|
|
176
|
+
log(withColor(message, colors.green));
|
|
177
|
+
console.log('='.repeat(40));
|
|
178
|
+
console.log('');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Format file size in human-readable format
|
|
183
|
+
* @param {number} bytes
|
|
184
|
+
* @returns {string}
|
|
185
|
+
*/
|
|
186
|
+
export function formatSize(bytes) {
|
|
187
|
+
const mb = bytes / 1024 / 1024;
|
|
188
|
+
if (mb >= 1) {
|
|
189
|
+
return `${mb.toFixed(2)} MB`;
|
|
190
|
+
}
|
|
191
|
+
const kb = bytes / 1024;
|
|
192
|
+
return `${kb.toFixed(2)} KB`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Format target string
|
|
197
|
+
* @param {string} platform
|
|
198
|
+
* @param {string} arch
|
|
199
|
+
* @returns {string}
|
|
200
|
+
*/
|
|
201
|
+
export function formatTarget(platform, arch) {
|
|
202
|
+
return `${platform}-${arch}`;
|
|
203
|
+
}
|