plusui-native 0.2.106 → 0.2.108

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.
@@ -1,351 +1,351 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Cross-Platform Resource Embedder for PlusUI
5
- *
6
- * Embeds frontend assets and icons into the binary for single-executable distribution:
7
- * - Windows: Generates .rc file with RCDATA resources
8
- * - macOS: Copies resources to app bundle
9
- * - Linux: Generates C++ header with binary data
10
- */
11
-
12
- import { readFile, writeFile, readdir, mkdir, stat, copyFile } from 'fs/promises';
13
- import { existsSync, statSync } from 'fs';
14
- import { join, relative, basename, extname, dirname } from 'path';
15
- import { createHash } from 'crypto';
16
-
17
- class ResourceEmbedder {
18
- constructor(options = {}) {
19
- this.verbose = options.verbose || false;
20
- this.compression = options.compression !== false;
21
- }
22
-
23
- log(msg) {
24
- if (this.verbose) console.log(msg);
25
- }
26
-
27
- /**
28
- * Get all files recursively from a directory
29
- */
30
- async getAllFiles(dirPath, arrayOfFiles = []) {
31
- const files = await readdir(dirPath);
32
-
33
- for (const file of files) {
34
- const filePath = join(dirPath, file);
35
- const s = await stat(filePath);
36
-
37
- if (s.isDirectory()) {
38
- arrayOfFiles = await this.getAllFiles(filePath, arrayOfFiles);
39
- } else {
40
- arrayOfFiles.push(filePath);
41
- }
42
- }
43
-
44
- return arrayOfFiles;
45
- }
46
-
47
- /**
48
- * Generate Windows .rc resource file
49
- */
50
- async generateWindowsRC(assetsDir, outputPath) {
51
- console.log(' 🪟 Generating Windows resource file (.rc)...');
52
-
53
- if (!existsSync(assetsDir)) {
54
- console.log(' āš ļø Assets directory not found, skipping');
55
- return;
56
- }
57
-
58
- const files = await this.getAllFiles(assetsDir);
59
- let rcContent = `// Auto-generated by PlusUI - DO NOT EDIT
60
- // Embedded resources for single-executable distribution
61
-
62
- #include <windows.h>
63
-
64
- `;
65
-
66
- let count = 0;
67
- const resources = [];
68
-
69
- for (const file of files) {
70
- const relPath = relative(assetsDir, file).replace(/\\/g, '/');
71
- const resourceId = `IDR_${relPath.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`;
72
- const winPath = file.replace(/\//g, '\\\\');
73
-
74
- // Store for manifest
75
- resources.push({ id: resourceId, path: relPath, file });
76
-
77
- rcContent += `${resourceId} RCDATA "${winPath}"\n`;
78
- count++;
79
- }
80
-
81
- // Add icon if exists
82
- const iconPaths = [
83
- join(assetsDir, 'icons', 'windows', 'app.ico'),
84
- join(assetsDir, 'icon.ico'),
85
- ];
86
-
87
- for (const iconPath of iconPaths) {
88
- if (existsSync(iconPath)) {
89
- rcContent += `\n// Application icon\nIDI_APP_ICON ICON "${iconPath.replace(/\//g, '\\\\')}"\n`;
90
- console.log(` āœ“ Added app icon: ${basename(iconPath)}`);
91
- break;
92
- }
93
- }
94
-
95
- await mkdir(dirname(outputPath), { recursive: true });
96
- await writeFile(outputPath, rcContent);
97
-
98
- // Generate resource manifest (C++ header)
99
- await this.generateResourceManifest(resources, outputPath.replace('.rc', '_manifest.hpp'));
100
-
101
- console.log(` āœ“ Created ${basename(outputPath)} (${count} resources)`);
102
- return outputPath;
103
- }
104
-
105
- /**
106
- * Generate C++ header with resource manifest
107
- */
108
- async generateResourceManifest(resources, outputPath) {
109
- let content = `// Auto-generated by PlusUI - DO NOT EDIT
110
- #pragma once
111
-
112
- #include <string>
113
- #include <unordered_map>
114
-
115
- namespace plusui {
116
- namespace resources {
117
-
118
- // Resource ID to path mapping
119
- static const std::unordered_map<std::string, int> RESOURCE_MAP = {
120
- `;
121
-
122
- let idCounter = 100;
123
- for (const res of resources) {
124
- content += ` {"${res.path}", ${idCounter}},\n`;
125
- idCounter++;
126
- }
127
-
128
- content += `};
129
-
130
- // Get resource data from embedded resources
131
- #ifdef _WIN32
132
- #include <windows.h>
133
- inline std::string getResource(const std::string& path) {
134
- auto it = RESOURCE_MAP.find(path);
135
- if (it == RESOURCE_MAP.end()) return "";
136
-
137
- HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(it->second), RT_RCDATA);
138
- if (!hRes) return "";
139
-
140
- HGLOBAL hData = LoadResource(NULL, hRes);
141
- if (!hData) return "";
142
-
143
- DWORD size = SizeofResource(NULL, hRes);
144
- const char* data = static_cast<const char*>(LockResource(hData));
145
-
146
- return std::string(data, size);
147
- }
148
- #else
149
- inline std::string getResource(const std::string& path) {
150
- // Use embedded data from binary (see embedded_resources.hpp)
151
- extern const std::unordered_map<std::string, std::pair<const unsigned char*, size_t>>& EMBEDDED_DATA;
152
- auto it = EMBEDDED_DATA.find(path);
153
- if (it == EMBEDDED_DATA.end()) return "";
154
- return std::string(reinterpret_cast<const char*>(it->second.first), it->second.second);
155
- }
156
- #endif
157
-
158
- } // namespace resources
159
- } // namespace plusui
160
- `;
161
-
162
- await writeFile(outputPath, content);
163
- console.log(` āœ“ Created resource manifest`);
164
- }
165
-
166
- /**
167
- * Generate Linux/macOS binary embedding header
168
- */
169
- async generateBinaryHeader(assetsDir, outputPath) {
170
- console.log(' 🐧 Generating binary embedded resources...');
171
-
172
- if (!existsSync(assetsDir)) {
173
- console.log(' āš ļø Assets directory not found, skipping');
174
- return;
175
- }
176
-
177
- const files = await this.getAllFiles(assetsDir);
178
-
179
- let content = `// Auto-generated by PlusUI - DO NOT EDIT
180
- #pragma once
181
-
182
- #include <unordered_map>
183
- #include <utility>
184
- #include <string>
185
-
186
- namespace plusui {
187
- namespace resources {
188
-
189
- `;
190
-
191
- let count = 0;
192
- const dataMap = [];
193
-
194
- for (const file of files) {
195
- const relPath = relative(assetsDir, file).replace(/\\/g, '/');
196
- const varName = `ASSET_${relPath.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`;
197
- const data = await readFile(file);
198
-
199
- content += `// ${relPath}\nstatic const unsigned char ${varName}[] = {\n`;
200
-
201
- for (let i = 0; i < data.length; i++) {
202
- if (i % 16 === 0) content += ' ';
203
- content += `0x${data[i].toString(16).padStart(2, '0')}`;
204
- if (i < data.length - 1) content += ',';
205
- if ((i + 1) % 16 === 0 || i === data.length - 1) content += '\n';
206
- else content += ' ';
207
- }
208
-
209
- content += `};\nstatic const size_t ${varName}_LEN = ${data.length};\n\n`;
210
-
211
- dataMap.push({ path: relPath, varName, size: data.length });
212
- count++;
213
- }
214
-
215
- // Generate lookup map
216
- content += `// Resource lookup map\nstatic const std::unordered_map<std::string, std::pair<const unsigned char*, size_t>> EMBEDDED_DATA = {\n`;
217
-
218
- for (const item of dataMap) {
219
- content += ` {"${item.path}", {${item.varName}, ${item.varName}_LEN}},\n`;
220
- }
221
-
222
- content += `};\n\n`;
223
-
224
- // Add convenience function
225
- content += `inline std::string getResource(const std::string& path) {
226
- auto it = EMBEDDED_DATA.find(path);
227
- if (it == EMBEDDED_DATA.end()) return "";
228
- return std::string(reinterpret_cast<const char*>(it->second.first), it->second.second);
229
- }
230
-
231
- } // namespace resources
232
- } // namespace plusui
233
- `;
234
-
235
- await mkdir(dirname(outputPath), { recursive: true });
236
- await writeFile(outputPath, content);
237
-
238
- console.log(` āœ“ Created ${basename(outputPath)} (${count} resources)`);
239
- return outputPath;
240
- }
241
-
242
- /**
243
- * Generate macOS app bundle resources
244
- */
245
- async generateMacOSBundle(assetsDir, bundlePath) {
246
- console.log(' šŸŽ Copying resources to macOS bundle...');
247
-
248
- if (!existsSync(assetsDir)) {
249
- console.log(' āš ļø Assets directory not found, skipping');
250
- return;
251
- }
252
-
253
- const resourcesDir = join(bundlePath, 'Contents', 'Resources');
254
- await mkdir(resourcesDir, { recursive: true });
255
-
256
- const files = await this.getAllFiles(assetsDir);
257
- let count = 0;
258
-
259
- for (const file of files) {
260
- const relPath = relative(assetsDir, file);
261
- const dest = join(resourcesDir, relPath);
262
- await mkdir(dirname(dest), { recursive: true });
263
- await copyFile(file, dest);
264
- count++;
265
- }
266
-
267
- // Copy icon if exists
268
- const iconPath = join(assetsDir, 'icons', 'macos', 'app.icns');
269
- if (existsSync(iconPath)) {
270
- await copyFile(iconPath, join(resourcesDir, 'app.icns'));
271
- console.log(` āœ“ Added app icon`);
272
- }
273
-
274
- console.log(` āœ“ Copied ${count} resources to bundle`);
275
- }
276
-
277
- /**
278
- * Main embed function - chooses platform
279
- */
280
- async embed(assetsDir, outputDir, platform = process.platform) {
281
- console.log(`\nšŸ“¦ Embedding resources for ${platform}...\n`);
282
-
283
- await mkdir(outputDir, { recursive: true });
284
-
285
- switch (platform) {
286
- case 'win32':
287
- return await this.generateWindowsRC(
288
- assetsDir,
289
- join(outputDir, 'resources.rc')
290
- );
291
-
292
- case 'darwin':
293
- // macOS uses both binary embedding and bundle resources
294
- await this.generateBinaryHeader(
295
- assetsDir,
296
- join(outputDir, 'embedded_resources.hpp')
297
- );
298
- // Bundle copying happens at app bundle creation time
299
- break;
300
-
301
- case 'linux':
302
- return await this.generateBinaryHeader(
303
- assetsDir,
304
- join(outputDir, 'embedded_resources.hpp')
305
- );
306
-
307
- default:
308
- throw new Error(`Unsupported platform: ${platform}`);
309
- }
310
-
311
- console.log('\n✨ Resource embedding complete!\n');
312
- }
313
-
314
- /**
315
- * Embed for all platforms
316
- */
317
- async embedAll(assetsDir, outputDir) {
318
- console.log('\nšŸ“¦ Embedding resources for all platforms...\n');
319
-
320
- await this.embed(assetsDir, join(outputDir, 'windows'), 'win32');
321
- await this.embed(assetsDir, join(outputDir, 'linux'), 'linux');
322
- await this.embed(assetsDir, join(outputDir, 'darwin'), 'darwin');
323
-
324
- console.log('\n✨ All platforms complete!\n');
325
- }
326
- }
327
-
328
- // CLI
329
- if (import.meta.url === `file://${process.argv[1]}`) {
330
- const args = process.argv.slice(2);
331
- const command = args[0];
332
- const assetsDir = args[1] || join(process.cwd(), 'frontend', 'dist');
333
- const outputDir = args[2] || join(process.cwd(), 'generated', 'resources');
334
-
335
- const embedder = new ResourceEmbedder({ verbose: true });
336
-
337
- if (command === 'all') {
338
- embedder.embedAll(assetsDir, outputDir).catch(err => {
339
- console.error('āŒ Error:', err.message);
340
- process.exit(1);
341
- });
342
- } else {
343
- const platform = command || process.platform;
344
- embedder.embed(assetsDir, outputDir, platform).catch(err => {
345
- console.error('āŒ Error:', err.message);
346
- process.exit(1);
347
- });
348
- }
349
- }
350
-
351
- export { ResourceEmbedder };
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Cross-Platform Resource Embedder for PlusUI
5
+ *
6
+ * Embeds frontend assets and icons into the binary for single-executable distribution:
7
+ * - Windows: Generates .rc file with RCDATA resources
8
+ * - macOS: Copies resources to app bundle
9
+ * - Linux: Generates C++ header with binary data
10
+ */
11
+
12
+ import { readFile, writeFile, readdir, mkdir, stat, copyFile } from 'fs/promises';
13
+ import { existsSync, statSync } from 'fs';
14
+ import { join, relative, basename, extname, dirname } from 'path';
15
+ import { createHash } from 'crypto';
16
+
17
+ class ResourceEmbedder {
18
+ constructor(options = {}) {
19
+ this.verbose = options.verbose || false;
20
+ this.compression = options.compression !== false;
21
+ }
22
+
23
+ log(msg) {
24
+ if (this.verbose) console.log(msg);
25
+ }
26
+
27
+ /**
28
+ * Get all files recursively from a directory
29
+ */
30
+ async getAllFiles(dirPath, arrayOfFiles = []) {
31
+ const files = await readdir(dirPath);
32
+
33
+ for (const file of files) {
34
+ const filePath = join(dirPath, file);
35
+ const s = await stat(filePath);
36
+
37
+ if (s.isDirectory()) {
38
+ arrayOfFiles = await this.getAllFiles(filePath, arrayOfFiles);
39
+ } else {
40
+ arrayOfFiles.push(filePath);
41
+ }
42
+ }
43
+
44
+ return arrayOfFiles;
45
+ }
46
+
47
+ /**
48
+ * Generate Windows .rc resource file
49
+ */
50
+ async generateWindowsRC(assetsDir, outputPath) {
51
+ console.log(' 🪟 Generating Windows resource file (.rc)...');
52
+
53
+ if (!existsSync(assetsDir)) {
54
+ console.log(' āš ļø Assets directory not found, skipping');
55
+ return;
56
+ }
57
+
58
+ const files = await this.getAllFiles(assetsDir);
59
+ let rcContent = `// Auto-generated by PlusUI - DO NOT EDIT
60
+ // Embedded resources for single-executable distribution
61
+
62
+ #include <windows.h>
63
+
64
+ `;
65
+
66
+ let count = 0;
67
+ const resources = [];
68
+
69
+ for (const file of files) {
70
+ const relPath = relative(assetsDir, file).replace(/\\/g, '/');
71
+ const resourceId = `IDR_${relPath.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`;
72
+ const winPath = file.replace(/\//g, '\\\\');
73
+
74
+ // Store for manifest
75
+ resources.push({ id: resourceId, path: relPath, file });
76
+
77
+ rcContent += `${resourceId} RCDATA "${winPath}"\n`;
78
+ count++;
79
+ }
80
+
81
+ // Add icon if exists
82
+ const iconPaths = [
83
+ join(assetsDir, 'icons', 'windows', 'app.ico'),
84
+ join(assetsDir, 'icon.ico'),
85
+ ];
86
+
87
+ for (const iconPath of iconPaths) {
88
+ if (existsSync(iconPath)) {
89
+ rcContent += `\n// Application icon\nIDI_APP_ICON ICON "${iconPath.replace(/\//g, '\\\\')}"\n`;
90
+ console.log(` āœ“ Added app icon: ${basename(iconPath)}`);
91
+ break;
92
+ }
93
+ }
94
+
95
+ await mkdir(dirname(outputPath), { recursive: true });
96
+ await writeFile(outputPath, rcContent);
97
+
98
+ // Generate resource manifest (C++ header)
99
+ await this.generateResourceManifest(resources, outputPath.replace('.rc', '_manifest.hpp'));
100
+
101
+ console.log(` āœ“ Created ${basename(outputPath)} (${count} resources)`);
102
+ return outputPath;
103
+ }
104
+
105
+ /**
106
+ * Generate C++ header with resource manifest
107
+ */
108
+ async generateResourceManifest(resources, outputPath) {
109
+ let content = `// Auto-generated by PlusUI - DO NOT EDIT
110
+ #pragma once
111
+
112
+ #include <string>
113
+ #include <unordered_map>
114
+
115
+ namespace plusui {
116
+ namespace resources {
117
+
118
+ // Resource ID to path mapping
119
+ static const std::unordered_map<std::string, int> RESOURCE_MAP = {
120
+ `;
121
+
122
+ let idCounter = 100;
123
+ for (const res of resources) {
124
+ content += ` {"${res.path}", ${idCounter}},\n`;
125
+ idCounter++;
126
+ }
127
+
128
+ content += `};
129
+
130
+ // Get resource data from embedded resources
131
+ #ifdef _WIN32
132
+ #include <windows.h>
133
+ inline std::string getResource(const std::string& path) {
134
+ auto it = RESOURCE_MAP.find(path);
135
+ if (it == RESOURCE_MAP.end()) return "";
136
+
137
+ HRSRC hRes = FindResource(NULL, MAKEINTRESOURCE(it->second), RT_RCDATA);
138
+ if (!hRes) return "";
139
+
140
+ HGLOBAL hData = LoadResource(NULL, hRes);
141
+ if (!hData) return "";
142
+
143
+ DWORD size = SizeofResource(NULL, hRes);
144
+ const char* data = static_cast<const char*>(LockResource(hData));
145
+
146
+ return std::string(data, size);
147
+ }
148
+ #else
149
+ inline std::string getResource(const std::string& path) {
150
+ // Use embedded data from binary (see embedded_resources.hpp)
151
+ extern const std::unordered_map<std::string, std::pair<const unsigned char*, size_t>>& EMBEDDED_DATA;
152
+ auto it = EMBEDDED_DATA.find(path);
153
+ if (it == EMBEDDED_DATA.end()) return "";
154
+ return std::string(reinterpret_cast<const char*>(it->second.first), it->second.second);
155
+ }
156
+ #endif
157
+
158
+ } // namespace resources
159
+ } // namespace plusui
160
+ `;
161
+
162
+ await writeFile(outputPath, content);
163
+ console.log(` āœ“ Created resource manifest`);
164
+ }
165
+
166
+ /**
167
+ * Generate Linux/macOS binary embedding header
168
+ */
169
+ async generateBinaryHeader(assetsDir, outputPath) {
170
+ console.log(' 🐧 Generating binary embedded resources...');
171
+
172
+ if (!existsSync(assetsDir)) {
173
+ console.log(' āš ļø Assets directory not found, skipping');
174
+ return;
175
+ }
176
+
177
+ const files = await this.getAllFiles(assetsDir);
178
+
179
+ let content = `// Auto-generated by PlusUI - DO NOT EDIT
180
+ #pragma once
181
+
182
+ #include <unordered_map>
183
+ #include <utility>
184
+ #include <string>
185
+
186
+ namespace plusui {
187
+ namespace resources {
188
+
189
+ `;
190
+
191
+ let count = 0;
192
+ const dataMap = [];
193
+
194
+ for (const file of files) {
195
+ const relPath = relative(assetsDir, file).replace(/\\/g, '/');
196
+ const varName = `ASSET_${relPath.replace(/[^a-zA-Z0-9]/g, '_').toUpperCase()}`;
197
+ const data = await readFile(file);
198
+
199
+ content += `// ${relPath}\nstatic const unsigned char ${varName}[] = {\n`;
200
+
201
+ for (let i = 0; i < data.length; i++) {
202
+ if (i % 16 === 0) content += ' ';
203
+ content += `0x${data[i].toString(16).padStart(2, '0')}`;
204
+ if (i < data.length - 1) content += ',';
205
+ if ((i + 1) % 16 === 0 || i === data.length - 1) content += '\n';
206
+ else content += ' ';
207
+ }
208
+
209
+ content += `};\nstatic const size_t ${varName}_LEN = ${data.length};\n\n`;
210
+
211
+ dataMap.push({ path: relPath, varName, size: data.length });
212
+ count++;
213
+ }
214
+
215
+ // Generate lookup map
216
+ content += `// Resource lookup map\nstatic const std::unordered_map<std::string, std::pair<const unsigned char*, size_t>> EMBEDDED_DATA = {\n`;
217
+
218
+ for (const item of dataMap) {
219
+ content += ` {"${item.path}", {${item.varName}, ${item.varName}_LEN}},\n`;
220
+ }
221
+
222
+ content += `};\n\n`;
223
+
224
+ // Add convenience function
225
+ content += `inline std::string getResource(const std::string& path) {
226
+ auto it = EMBEDDED_DATA.find(path);
227
+ if (it == EMBEDDED_DATA.end()) return "";
228
+ return std::string(reinterpret_cast<const char*>(it->second.first), it->second.second);
229
+ }
230
+
231
+ } // namespace resources
232
+ } // namespace plusui
233
+ `;
234
+
235
+ await mkdir(dirname(outputPath), { recursive: true });
236
+ await writeFile(outputPath, content);
237
+
238
+ console.log(` āœ“ Created ${basename(outputPath)} (${count} resources)`);
239
+ return outputPath;
240
+ }
241
+
242
+ /**
243
+ * Generate macOS app bundle resources
244
+ */
245
+ async generateMacOSBundle(assetsDir, bundlePath) {
246
+ console.log(' šŸŽ Copying resources to macOS bundle...');
247
+
248
+ if (!existsSync(assetsDir)) {
249
+ console.log(' āš ļø Assets directory not found, skipping');
250
+ return;
251
+ }
252
+
253
+ const resourcesDir = join(bundlePath, 'Contents', 'Resources');
254
+ await mkdir(resourcesDir, { recursive: true });
255
+
256
+ const files = await this.getAllFiles(assetsDir);
257
+ let count = 0;
258
+
259
+ for (const file of files) {
260
+ const relPath = relative(assetsDir, file);
261
+ const dest = join(resourcesDir, relPath);
262
+ await mkdir(dirname(dest), { recursive: true });
263
+ await copyFile(file, dest);
264
+ count++;
265
+ }
266
+
267
+ // Copy icon if exists
268
+ const iconPath = join(assetsDir, 'icons', 'macos', 'app.icns');
269
+ if (existsSync(iconPath)) {
270
+ await copyFile(iconPath, join(resourcesDir, 'app.icns'));
271
+ console.log(` āœ“ Added app icon`);
272
+ }
273
+
274
+ console.log(` āœ“ Copied ${count} resources to bundle`);
275
+ }
276
+
277
+ /**
278
+ * Main embed function - chooses platform
279
+ */
280
+ async embed(assetsDir, outputDir, platform = process.platform) {
281
+ console.log(`\nšŸ“¦ Embedding resources for ${platform}...\n`);
282
+
283
+ await mkdir(outputDir, { recursive: true });
284
+
285
+ switch (platform) {
286
+ case 'win32':
287
+ return await this.generateWindowsRC(
288
+ assetsDir,
289
+ join(outputDir, 'resources.rc')
290
+ );
291
+
292
+ case 'darwin':
293
+ // macOS uses both binary embedding and bundle resources
294
+ await this.generateBinaryHeader(
295
+ assetsDir,
296
+ join(outputDir, 'embedded_resources.hpp')
297
+ );
298
+ // Bundle copying happens at app bundle creation time
299
+ break;
300
+
301
+ case 'linux':
302
+ return await this.generateBinaryHeader(
303
+ assetsDir,
304
+ join(outputDir, 'embedded_resources.hpp')
305
+ );
306
+
307
+ default:
308
+ throw new Error(`Unsupported platform: ${platform}`);
309
+ }
310
+
311
+ console.log('\n✨ Resource embedding complete!\n');
312
+ }
313
+
314
+ /**
315
+ * Embed for all platforms
316
+ */
317
+ async embedAll(assetsDir, outputDir) {
318
+ console.log('\nšŸ“¦ Embedding resources for all platforms...\n');
319
+
320
+ await this.embed(assetsDir, join(outputDir, 'windows'), 'win32');
321
+ await this.embed(assetsDir, join(outputDir, 'linux'), 'linux');
322
+ await this.embed(assetsDir, join(outputDir, 'darwin'), 'darwin');
323
+
324
+ console.log('\n✨ All platforms complete!\n');
325
+ }
326
+ }
327
+
328
+ // CLI
329
+ if (import.meta.url === `file://${process.argv[1]}`) {
330
+ const args = process.argv.slice(2);
331
+ const command = args[0];
332
+ const assetsDir = args[1] || join(process.cwd(), 'frontend', 'dist');
333
+ const outputDir = args[2] || join(process.cwd(), 'generated', 'resources');
334
+
335
+ const embedder = new ResourceEmbedder({ verbose: true });
336
+
337
+ if (command === 'all') {
338
+ embedder.embedAll(assetsDir, outputDir).catch(err => {
339
+ console.error('āŒ Error:', err.message);
340
+ process.exit(1);
341
+ });
342
+ } else {
343
+ const platform = command || process.platform;
344
+ embedder.embed(assetsDir, outputDir, platform).catch(err => {
345
+ console.error('āŒ Error:', err.message);
346
+ process.exit(1);
347
+ });
348
+ }
349
+ }
350
+
351
+ export { ResourceEmbedder };