@choochmeque/tauri-windows-bundle 0.1.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/dist/index.js ADDED
@@ -0,0 +1,1406 @@
1
+ import * as fs from 'node:fs';
2
+ import * as path from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { glob } from 'glob';
5
+ import { exec } from 'node:child_process';
6
+ import { promisify } from 'node:util';
7
+ import * as readline from 'node:readline';
8
+
9
+ const MSIX_ASSETS = [
10
+ { name: 'StoreLogo.png', size: 50 },
11
+ { name: 'Square44x44Logo.png', size: 44 },
12
+ { name: 'Square150x150Logo.png', size: 150 },
13
+ { name: 'Wide310x150Logo.png', width: 310, height: 150 },
14
+ { name: 'LargeTile.png', size: 310 },
15
+ ];
16
+ const DEFAULT_MIN_WINDOWS_VERSION = '10.0.17763.0';
17
+ const DEFAULT_CAPABILITIES = ['internetClient'];
18
+
19
+ function findProjectRoot(startDir) {
20
+ let dir = startDir || process.cwd();
21
+ while (dir !== path.dirname(dir)) {
22
+ // Check for tauri.conf.json in src-tauri
23
+ const tauriConfPath = path.join(dir, 'src-tauri', 'tauri.conf.json');
24
+ if (fs.existsSync(tauriConfPath)) {
25
+ return dir;
26
+ }
27
+ // Check for package.json as fallback
28
+ const packageJsonPath = path.join(dir, 'package.json');
29
+ if (fs.existsSync(packageJsonPath)) {
30
+ // Verify it's a Tauri project
31
+ if (fs.existsSync(path.join(dir, 'src-tauri'))) {
32
+ return dir;
33
+ }
34
+ }
35
+ dir = path.dirname(dir);
36
+ }
37
+ throw new Error('Could not find Tauri project root. Make sure you are in a Tauri project directory.');
38
+ }
39
+ function readTauriConfig(projectRoot) {
40
+ const configPath = path.join(projectRoot, 'src-tauri', 'tauri.conf.json');
41
+ if (!fs.existsSync(configPath)) {
42
+ throw new Error(`tauri.conf.json not found at ${configPath}`);
43
+ }
44
+ try {
45
+ const content = fs.readFileSync(configPath, 'utf-8');
46
+ return JSON.parse(content);
47
+ }
48
+ catch (error) {
49
+ throw new Error(`Failed to parse tauri.conf.json: ${error instanceof Error ? error.message : error}`);
50
+ }
51
+ }
52
+ function readBundleConfig$1(windowsDir) {
53
+ const configPath = path.join(windowsDir, 'bundle.config.json');
54
+ if (!fs.existsSync(configPath)) {
55
+ throw new Error(`bundle.config.json not found. Run 'tauri-windows-bundle init' first.`);
56
+ }
57
+ try {
58
+ const content = fs.readFileSync(configPath, 'utf-8');
59
+ return JSON.parse(content);
60
+ }
61
+ catch (error) {
62
+ throw new Error(`Failed to parse bundle.config.json: ${error instanceof Error ? error.message : error}`);
63
+ }
64
+ }
65
+ function getWindowsDir(projectRoot) {
66
+ return path.join(projectRoot, 'src-tauri', 'gen', 'windows');
67
+ }
68
+ function toFourPartVersion(version) {
69
+ const parts = version.split('.');
70
+ while (parts.length < 4)
71
+ parts.push('0');
72
+ return parts.slice(0, 4).join('.');
73
+ }
74
+
75
+ function generateBundleConfig(windowsDir, _tauriConfig) {
76
+ const config = {
77
+ publisher: 'CN=YourCompany',
78
+ publisherDisplayName: 'Your Company Name',
79
+ capabilities: DEFAULT_CAPABILITIES,
80
+ extensions: {
81
+ shareTarget: false,
82
+ fileAssociations: [],
83
+ protocolHandlers: [],
84
+ },
85
+ signing: {
86
+ pfx: null,
87
+ pfxPassword: null,
88
+ },
89
+ };
90
+ const configPath = path.join(windowsDir, 'bundle.config.json');
91
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
92
+ }
93
+ function generateGitignore(windowsDir) {
94
+ const gitignorePath = path.join(windowsDir, '.gitignore');
95
+ const content = `# Generated files
96
+ # Keep bundle.config.json and templates in git
97
+ `;
98
+ fs.writeFileSync(gitignorePath, content);
99
+ }
100
+
101
+ async function generateAssets(windowsDir) {
102
+ const assetsDir = path.join(windowsDir, 'Assets');
103
+ fs.mkdirSync(assetsDir, { recursive: true });
104
+ for (const asset of MSIX_ASSETS) {
105
+ const width = asset.width || asset.size || 50;
106
+ const height = asset.height || asset.size || 50;
107
+ const assetPath = path.join(assetsDir, asset.name);
108
+ // Generate a simple placeholder PNG
109
+ const pngData = createPlaceholderPng(width, height);
110
+ fs.writeFileSync(assetPath, pngData);
111
+ }
112
+ console.log(' Generated placeholder assets - replace with real icons before publishing');
113
+ }
114
+ function createPlaceholderPng(width, height) {
115
+ // Create a minimal valid PNG file (solid gray square)
116
+ // PNG signature
117
+ const signature = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]);
118
+ // IHDR chunk
119
+ const ihdrData = Buffer.alloc(13);
120
+ ihdrData.writeUInt32BE(width, 0);
121
+ ihdrData.writeUInt32BE(height, 4);
122
+ ihdrData.writeUInt8(8, 8); // bit depth
123
+ ihdrData.writeUInt8(2, 9); // color type (RGB)
124
+ ihdrData.writeUInt8(0, 10); // compression
125
+ ihdrData.writeUInt8(0, 11); // filter
126
+ ihdrData.writeUInt8(0, 12); // interlace
127
+ const ihdrChunk = createChunk('IHDR', ihdrData);
128
+ // IDAT chunk - raw image data (gray pixels)
129
+ const rawData = [];
130
+ for (let y = 0; y < height; y++) {
131
+ rawData.push(0); // filter byte
132
+ for (let x = 0; x < width; x++) {
133
+ rawData.push(128, 128, 128); // gray RGB
134
+ }
135
+ }
136
+ // Simple deflate compression (store block)
137
+ const uncompressed = Buffer.from(rawData);
138
+ const compressed = deflateStore(uncompressed);
139
+ const idatChunk = createChunk('IDAT', compressed);
140
+ // IEND chunk
141
+ const iendChunk = createChunk('IEND', Buffer.alloc(0));
142
+ return Buffer.concat([signature, ihdrChunk, idatChunk, iendChunk]);
143
+ }
144
+ function createChunk(type, data) {
145
+ const length = Buffer.alloc(4);
146
+ length.writeUInt32BE(data.length, 0);
147
+ const typeBuffer = Buffer.from(type, 'ascii');
148
+ const crcData = Buffer.concat([typeBuffer, data]);
149
+ const crc = crc32(crcData);
150
+ const crcBuffer = Buffer.alloc(4);
151
+ crcBuffer.writeUInt32BE(crc >>> 0, 0);
152
+ return Buffer.concat([length, typeBuffer, data, crcBuffer]);
153
+ }
154
+ function deflateStore(data) {
155
+ // Zlib header + store blocks
156
+ const result = [0x78, 0x01]; // zlib header
157
+ let remaining = data.length;
158
+ let offset = 0;
159
+ while (remaining > 0) {
160
+ const blockSize = Math.min(remaining, 65535);
161
+ const isLast = remaining <= 65535;
162
+ result.push(isLast ? 0x01 : 0x00); // BFINAL + BTYPE=00
163
+ result.push(blockSize & 0xff);
164
+ result.push((blockSize >> 8) & 0xff);
165
+ result.push(~blockSize & 0xff);
166
+ result.push((~blockSize >> 8) & 0xff);
167
+ for (let i = 0; i < blockSize; i++) {
168
+ result.push(data[offset + i]);
169
+ }
170
+ offset += blockSize;
171
+ remaining -= blockSize;
172
+ }
173
+ // Adler-32 checksum
174
+ const adler = adler32(data);
175
+ result.push((adler >> 24) & 0xff);
176
+ result.push((adler >> 16) & 0xff);
177
+ result.push((adler >> 8) & 0xff);
178
+ result.push(adler & 0xff);
179
+ return Buffer.from(result);
180
+ }
181
+ function crc32(data) {
182
+ let crc = 0xffffffff;
183
+ for (let i = 0; i < data.length; i++) {
184
+ crc ^= data[i];
185
+ for (let j = 0; j < 8; j++) {
186
+ crc = crc & 1 ? (crc >>> 1) ^ 0xedb88320 : crc >>> 1;
187
+ }
188
+ }
189
+ return crc ^ 0xffffffff;
190
+ }
191
+ function adler32(data) {
192
+ let a = 1;
193
+ let b = 0;
194
+ for (let i = 0; i < data.length; i++) {
195
+ a = (a + data[i]) % 65521;
196
+ b = (b + a) % 65521;
197
+ }
198
+ return (b << 16) | a;
199
+ }
200
+
201
+ function replaceTemplateVariables(template, variables) {
202
+ let result = template;
203
+ for (const [key, value] of Object.entries(variables)) {
204
+ const placeholder = `{{${key}}}`;
205
+ result = result.replaceAll(placeholder, value);
206
+ }
207
+ return result;
208
+ }
209
+
210
+ const __filename$1 = fileURLToPath(import.meta.url);
211
+ const __dirname$1 = path.dirname(__filename$1);
212
+ function findPackageRoot(startDir) {
213
+ let dir = startDir;
214
+ while (dir !== path.dirname(dir)) {
215
+ if (fs.existsSync(path.join(dir, 'package.json'))) {
216
+ return dir;
217
+ }
218
+ dir = path.dirname(dir);
219
+ }
220
+ throw new Error('Could not find package root');
221
+ }
222
+ const PACKAGE_ROOT = findPackageRoot(__dirname$1);
223
+ const TEMPLATES_DIR = path.join(PACKAGE_ROOT, 'templates');
224
+ const EXTENSIONS_DIR = path.join(TEMPLATES_DIR, 'extensions');
225
+ function loadTemplate(templatePath) {
226
+ return fs.readFileSync(templatePath, 'utf-8');
227
+ }
228
+ function getManifestTemplate() {
229
+ return loadTemplate(path.join(TEMPLATES_DIR, 'AppxManifest.xml.template'));
230
+ }
231
+ function getExtensionTemplate(name) {
232
+ return loadTemplate(path.join(EXTENSIONS_DIR, `${name}.xml`));
233
+ }
234
+ function generateManifestTemplate(windowsDir) {
235
+ const templatePath = path.join(windowsDir, 'AppxManifest.xml.template');
236
+ const template = getManifestTemplate();
237
+ fs.writeFileSync(templatePath, template);
238
+ }
239
+ function generateManifest(config, arch, minVersion) {
240
+ const variables = {
241
+ PACKAGE_NAME: config.identifier.replace(/\./g, ''),
242
+ PUBLISHER: config.publisher,
243
+ VERSION: config.version,
244
+ ARCH: arch,
245
+ DISPLAY_NAME: config.displayName,
246
+ PUBLISHER_DISPLAY_NAME: config.publisherDisplayName,
247
+ MIN_VERSION: minVersion,
248
+ EXECUTABLE: `${config.displayName.replace(/\s+/g, '')}.exe`,
249
+ DESCRIPTION: config.description || config.displayName,
250
+ EXTENSIONS: generateExtensions(config),
251
+ CAPABILITIES: generateCapabilities(config.capabilities || []),
252
+ };
253
+ return replaceTemplateVariables(getManifestTemplate(), variables);
254
+ }
255
+ function generateExtensions(config) {
256
+ const extensions = [];
257
+ if (config.extensions?.shareTarget) {
258
+ const template = getExtensionTemplate('share-target');
259
+ extensions.push(template.trimEnd());
260
+ }
261
+ if (config.extensions?.fileAssociations) {
262
+ const template = getExtensionTemplate('file-association');
263
+ for (const assoc of config.extensions.fileAssociations) {
264
+ const fileTypes = assoc.extensions
265
+ .map((ext) => ` <uap:FileType>${ext}</uap:FileType>`)
266
+ .join('\n');
267
+ const result = replaceTemplateVariables(template, {
268
+ NAME: assoc.name,
269
+ FILE_TYPES: fileTypes,
270
+ });
271
+ extensions.push(result.trimEnd());
272
+ }
273
+ }
274
+ if (config.extensions?.protocolHandlers) {
275
+ const template = getExtensionTemplate('protocol');
276
+ for (const handler of config.extensions.protocolHandlers) {
277
+ const result = replaceTemplateVariables(template, {
278
+ NAME: handler.name,
279
+ DISPLAY_NAME: handler.displayName || handler.name,
280
+ });
281
+ extensions.push(result.trimEnd());
282
+ }
283
+ }
284
+ if (config.extensions?.startupTask?.enabled) {
285
+ const template = getExtensionTemplate('startup-task');
286
+ const taskId = config.extensions.startupTask.taskId || 'StartupTask';
287
+ const result = replaceTemplateVariables(template, {
288
+ TASK_ID: taskId,
289
+ DISPLAY_NAME: config.displayName,
290
+ });
291
+ extensions.push(result.trimEnd());
292
+ }
293
+ if (config.extensions?.contextMenus) {
294
+ const template = getExtensionTemplate('context-menu');
295
+ for (const menu of config.extensions.contextMenus) {
296
+ const fileTypes = menu.fileTypes
297
+ .map((ft) => ` <desktop:FileType>${ft}</desktop:FileType>`)
298
+ .join('\n');
299
+ const result = replaceTemplateVariables(template, {
300
+ NAME: menu.name,
301
+ FILE_TYPES: fileTypes,
302
+ });
303
+ extensions.push(result.trimEnd());
304
+ }
305
+ }
306
+ if (config.extensions?.backgroundTasks) {
307
+ const template = getExtensionTemplate('background-task');
308
+ for (const task of config.extensions.backgroundTasks) {
309
+ const triggerType = task.type === 'timer'
310
+ ? 'TimeTrigger'
311
+ : task.type === 'systemEvent'
312
+ ? 'SystemTrigger'
313
+ : 'PushNotificationTrigger';
314
+ const result = replaceTemplateVariables(template, {
315
+ ENTRY_POINT: task.name,
316
+ TRIGGER_TYPE: triggerType,
317
+ });
318
+ extensions.push(result.trimEnd());
319
+ }
320
+ }
321
+ if (config.extensions?.appExecutionAliases) {
322
+ const template = getExtensionTemplate('app-execution-alias');
323
+ const executable = `${config.displayName.replace(/\s+/g, '')}.exe`;
324
+ for (const alias of config.extensions.appExecutionAliases) {
325
+ const result = replaceTemplateVariables(template, {
326
+ ALIAS: alias.alias.endsWith('.exe') ? alias.alias : `${alias.alias}.exe`,
327
+ EXECUTABLE: executable,
328
+ });
329
+ extensions.push(result.trimEnd());
330
+ }
331
+ }
332
+ if (config.extensions?.appServices) {
333
+ const template = getExtensionTemplate('app-service');
334
+ for (const service of config.extensions.appServices) {
335
+ const result = replaceTemplateVariables(template, {
336
+ NAME: service.name,
337
+ });
338
+ extensions.push(result.trimEnd());
339
+ }
340
+ }
341
+ if (config.extensions?.toastActivation) {
342
+ const template = getExtensionTemplate('toast-activation');
343
+ // Generate a CLSID from the identifier
344
+ const clsid = generateClsid(config.identifier + '.toast');
345
+ const result = replaceTemplateVariables(template, {
346
+ CLSID: clsid,
347
+ });
348
+ extensions.push(result.trimEnd());
349
+ }
350
+ if (config.extensions?.autoplayHandlers) {
351
+ for (const handler of config.extensions.autoplayHandlers) {
352
+ if (handler.contentEvent) {
353
+ const template = getExtensionTemplate('autoplay');
354
+ const result = replaceTemplateVariables(template, {
355
+ VERB: handler.verb,
356
+ ACTION_DISPLAY_NAME: handler.actionDisplayName,
357
+ CONTENT_EVENT: handler.contentEvent,
358
+ });
359
+ extensions.push(result.trimEnd());
360
+ }
361
+ if (handler.deviceEvent) {
362
+ const template = getExtensionTemplate('autoplay-device');
363
+ const result = replaceTemplateVariables(template, {
364
+ VERB: handler.verb,
365
+ ACTION_DISPLAY_NAME: handler.actionDisplayName,
366
+ DEVICE_EVENT: handler.deviceEvent,
367
+ });
368
+ extensions.push(result.trimEnd());
369
+ }
370
+ }
371
+ }
372
+ if (config.extensions?.printTaskSettings) {
373
+ const template = getExtensionTemplate('print-task-settings');
374
+ extensions.push(template.trimEnd());
375
+ }
376
+ if (config.extensions?.thumbnailHandlers) {
377
+ const template = getExtensionTemplate('thumbnail-handler');
378
+ for (const handler of config.extensions.thumbnailHandlers) {
379
+ const fileTypes = handler.fileTypes
380
+ .map((ext) => ` <uap:FileType>${ext}</uap:FileType>`)
381
+ .join('\n');
382
+ const result = replaceTemplateVariables(template, {
383
+ NAME: `thumbnail-${handler.clsid.replace(/[{}]/g, '').slice(0, 8)}`,
384
+ FILE_TYPES: fileTypes,
385
+ CLSID: handler.clsid,
386
+ });
387
+ extensions.push(result.trimEnd());
388
+ }
389
+ }
390
+ if (config.extensions?.previewHandlers) {
391
+ const template = getExtensionTemplate('preview-handler');
392
+ for (const handler of config.extensions.previewHandlers) {
393
+ const fileTypes = handler.fileTypes
394
+ .map((ext) => ` <uap:FileType>${ext}</uap:FileType>`)
395
+ .join('\n');
396
+ const result = replaceTemplateVariables(template, {
397
+ NAME: `preview-${handler.clsid.replace(/[{}]/g, '').slice(0, 8)}`,
398
+ FILE_TYPES: fileTypes,
399
+ CLSID: handler.clsid,
400
+ });
401
+ extensions.push(result.trimEnd());
402
+ }
403
+ }
404
+ return extensions.length > 0 ? extensions.join('\n\n') : '';
405
+ }
406
+ function generateCapabilities(capabilities) {
407
+ return capabilities.map((cap) => ` <Capability Name="${cap}" />`).join('\n');
408
+ }
409
+ function generateClsid(seed) {
410
+ // Generate a deterministic GUID-like string from the seed
411
+ let hash = 0;
412
+ for (let i = 0; i < seed.length; i++) {
413
+ const char = seed.charCodeAt(i);
414
+ hash = (hash << 5) - hash + char;
415
+ hash = hash & hash;
416
+ }
417
+ const hex = Math.abs(hash).toString(16).padStart(8, '0');
418
+ const hex2 = Math.abs(hash * 31)
419
+ .toString(16)
420
+ .padStart(8, '0');
421
+ const hex3 = Math.abs(hash * 37)
422
+ .toString(16)
423
+ .padStart(8, '0');
424
+ const hex4 = Math.abs(hash * 41)
425
+ .toString(16)
426
+ .padStart(12, '0');
427
+ return `{${hex.slice(0, 8)}-${hex2.slice(0, 4)}-${hex2.slice(4, 8)}-${hex3.slice(0, 4)}-${hex4.slice(0, 12)}}`.toUpperCase();
428
+ }
429
+
430
+ async function init(options) {
431
+ console.log('Initializing Windows bundle configuration...\n');
432
+ const projectRoot = findProjectRoot(options.path);
433
+ readTauriConfig(projectRoot);
434
+ const windowsDir = getWindowsDir(projectRoot);
435
+ // Create directories
436
+ fs.mkdirSync(path.join(windowsDir, 'Assets'), { recursive: true });
437
+ fs.mkdirSync(path.join(windowsDir, 'extensions'), { recursive: true });
438
+ // Generate bundle.config.json
439
+ generateBundleConfig(windowsDir);
440
+ console.log(' Created bundle.config.json');
441
+ // Generate AppxManifest.xml template
442
+ generateManifestTemplate(windowsDir);
443
+ console.log(' Created AppxManifest.xml.template');
444
+ // Generate placeholder assets
445
+ await generateAssets(windowsDir);
446
+ // Generate .gitignore
447
+ generateGitignore(windowsDir);
448
+ // Update package.json with build script
449
+ updatePackageJson(projectRoot);
450
+ console.log(' Added tauri:windows:build script to package.json');
451
+ console.log('\n Windows bundle configuration created!');
452
+ console.log(`\nNext steps:`);
453
+ console.log(` 1. Edit src-tauri/gen/windows/bundle.config.json`);
454
+ console.log(` - Set your publisher CN (from your code signing certificate)`);
455
+ console.log(` - Set your publisher display name`);
456
+ console.log(` 2. Replace placeholder icons in src-tauri/gen/windows/Assets/`);
457
+ console.log(` 3. Run: pnpm tauri:windows:build`);
458
+ }
459
+ function updatePackageJson(projectRoot) {
460
+ const packageJsonPath = path.join(projectRoot, 'package.json');
461
+ if (!fs.existsSync(packageJsonPath)) {
462
+ console.log(' Warning: package.json not found, skipping script update');
463
+ return;
464
+ }
465
+ try {
466
+ const content = fs.readFileSync(packageJsonPath, 'utf-8');
467
+ const pkg = JSON.parse(content);
468
+ if (!pkg.scripts) {
469
+ pkg.scripts = {};
470
+ }
471
+ if (!pkg.scripts['tauri:windows:build']) {
472
+ pkg.scripts['tauri:windows:build'] = 'tauri-windows-bundle build';
473
+ fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2) + '\n');
474
+ }
475
+ }
476
+ catch (error) {
477
+ console.log(` Warning: Could not update package.json: ${error instanceof Error ? error.message : error}`);
478
+ }
479
+ }
480
+
481
+ function prepareAppxContent(projectRoot, arch, config, tauriConfig, minVersion) {
482
+ const target = arch === 'x64' ? 'x86_64-pc-windows-msvc' : 'aarch64-pc-windows-msvc';
483
+ const buildDir = path.join(projectRoot, 'target', target, 'release');
484
+ const appxDir = path.join(projectRoot, 'target', 'appx', arch);
485
+ // Create directories
486
+ fs.mkdirSync(path.join(appxDir, 'Assets'), { recursive: true });
487
+ // Copy exe
488
+ const exeName = `${config.displayName.replace(/\s+/g, '')}.exe`;
489
+ const srcExe = path.join(buildDir, exeName);
490
+ if (!fs.existsSync(srcExe)) {
491
+ throw new Error(`Executable not found: ${srcExe}`);
492
+ }
493
+ fs.copyFileSync(srcExe, path.join(appxDir, exeName));
494
+ // Generate AppxManifest.xml
495
+ const manifest = generateManifest(config, arch, minVersion);
496
+ fs.writeFileSync(path.join(appxDir, 'AppxManifest.xml'), manifest);
497
+ // Copy MSIX Assets
498
+ const windowsAssetsDir = path.join(projectRoot, 'src-tauri', 'gen', 'windows', 'Assets');
499
+ if (fs.existsSync(windowsAssetsDir)) {
500
+ fs.cpSync(windowsAssetsDir, path.join(appxDir, 'Assets'), {
501
+ recursive: true,
502
+ });
503
+ }
504
+ // Copy bundled resources from tauri.conf.json
505
+ copyBundledResources(projectRoot, appxDir, tauriConfig);
506
+ return appxDir;
507
+ }
508
+ function copyBundledResources(projectRoot, appxDir, tauriConfig) {
509
+ const resources = tauriConfig.bundle?.resources;
510
+ if (!resources || resources.length === 0)
511
+ return;
512
+ const srcDir = path.join(projectRoot, 'src-tauri');
513
+ for (const resource of resources) {
514
+ if (typeof resource === 'string') {
515
+ // Glob pattern like "assets/*" or specific file
516
+ const files = glob.sync(resource, { cwd: srcDir });
517
+ for (const file of files) {
518
+ const src = path.join(srcDir, file);
519
+ const dest = path.join(appxDir, file);
520
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
521
+ if (fs.statSync(src).isDirectory()) {
522
+ fs.cpSync(src, dest, { recursive: true });
523
+ }
524
+ else {
525
+ fs.copyFileSync(src, dest);
526
+ }
527
+ }
528
+ }
529
+ else if (typeof resource === 'object' && resource.src && resource.target) {
530
+ const src = path.join(srcDir, resource.src);
531
+ const dest = path.join(appxDir, resource.target);
532
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
533
+ if (fs.statSync(src).isDirectory()) {
534
+ fs.cpSync(src, dest, { recursive: true });
535
+ }
536
+ else {
537
+ fs.copyFileSync(src, dest);
538
+ }
539
+ }
540
+ }
541
+ }
542
+
543
+ const execPromise = promisify(exec);
544
+ async function execAsync(command, options) {
545
+ const result = await execPromise(command, { ...options, encoding: 'utf8' });
546
+ return { stdout: result.stdout, stderr: result.stderr };
547
+ }
548
+ async function isMsixbundleCliInstalled() {
549
+ try {
550
+ await execAsync('msixbundle-cli --version');
551
+ return true;
552
+ }
553
+ catch {
554
+ return false;
555
+ }
556
+ }
557
+ async function getMsixbundleCliVersion() {
558
+ try {
559
+ const result = await execAsync('msixbundle-cli --version');
560
+ // Output format: "msixbundle-cli 1.0.0" or just "1.0.0"
561
+ const match = result.stdout.trim().match(/(\d+\.\d+\.\d+)/);
562
+ return match ? match[1] : null;
563
+ }
564
+ catch {
565
+ return null;
566
+ }
567
+ }
568
+ function isVersionSufficient(version, minVersion) {
569
+ const parse = (v) => v.split('.').map((n) => parseInt(n, 10));
570
+ const [major, minor, patch] = parse(version);
571
+ const [minMajor, minMinor, minPatch] = parse(minVersion);
572
+ if (major > minMajor)
573
+ return true;
574
+ if (major < minMajor)
575
+ return false;
576
+ if (minor > minMinor)
577
+ return true;
578
+ if (minor < minMinor)
579
+ return false;
580
+ return patch >= minPatch;
581
+ }
582
+ const MIN_MSIXBUNDLE_CLI_VERSION = '1.0.0';
583
+ async function promptInstall(message) {
584
+ const rl = readline.createInterface({
585
+ input: process.stdin,
586
+ output: process.stdout,
587
+ });
588
+ return new Promise((resolve) => {
589
+ rl.question(`${message} [y/N] `, (answer) => {
590
+ rl.close();
591
+ resolve(answer.toLowerCase() === 'y');
592
+ });
593
+ });
594
+ }
595
+
596
+ async function build(options) {
597
+ console.log('Building MSIX package...\n');
598
+ // Check if msixbundle-cli is installed
599
+ if (!(await isMsixbundleCliInstalled())) {
600
+ const shouldInstall = await promptInstall('msixbundle-cli is required but not installed.\n' + 'Install it now? (requires Rust/Cargo)');
601
+ if (shouldInstall) {
602
+ console.log('Installing msixbundle-cli...');
603
+ try {
604
+ await execAsync('cargo install msixbundle-cli');
605
+ console.log(' msixbundle-cli installed\n');
606
+ }
607
+ catch (error) {
608
+ console.error('Failed to install msixbundle-cli:', error);
609
+ console.log('\nInstall manually: cargo install msixbundle-cli');
610
+ console.log('Or from: https://github.com/Choochmeque/msixbundle-rs');
611
+ process.exit(1);
612
+ }
613
+ }
614
+ else {
615
+ console.log('\nInstall manually: cargo install msixbundle-cli');
616
+ console.log('Or from: https://github.com/Choochmeque/msixbundle-rs');
617
+ process.exit(1);
618
+ }
619
+ }
620
+ // Check msixbundle-cli version
621
+ const version = await getMsixbundleCliVersion();
622
+ if (!version) {
623
+ console.error('Could not determine msixbundle-cli version');
624
+ process.exit(1);
625
+ }
626
+ if (!isVersionSufficient(version, MIN_MSIXBUNDLE_CLI_VERSION)) {
627
+ console.error(`msixbundle-cli version ${version} is too old. Minimum required: ${MIN_MSIXBUNDLE_CLI_VERSION}`);
628
+ console.log('Update with: cargo install msixbundle-cli --force');
629
+ process.exit(1);
630
+ }
631
+ const projectRoot = findProjectRoot();
632
+ const windowsDir = getWindowsDir(projectRoot);
633
+ // Read configs
634
+ const tauriConfig = readTauriConfig(projectRoot);
635
+ const bundleConfig = readBundleConfig$1(windowsDir);
636
+ // Merge config
637
+ const config = {
638
+ displayName: tauriConfig.productName || 'App',
639
+ version: toFourPartVersion(tauriConfig.version || '1.0.0'),
640
+ description: tauriConfig.bundle?.shortDescription || '',
641
+ identifier: tauriConfig.identifier || 'com.example.app',
642
+ ...bundleConfig,
643
+ };
644
+ // Architectures from CLI flag
645
+ const architectures = options.arch?.split(',') || ['x64'];
646
+ const minVersion = options.minWindows || DEFAULT_MIN_WINDOWS_VERSION;
647
+ const appxDirs = [];
648
+ for (const arch of architectures) {
649
+ console.log(`Building for ${arch}...`);
650
+ // Build Tauri app
651
+ const target = arch === 'x64' ? 'x86_64-pc-windows-msvc' : 'aarch64-pc-windows-msvc';
652
+ const releaseFlag = options.release ? '--release' : '';
653
+ try {
654
+ console.log(` Running: cargo tauri build --target ${target} ${releaseFlag}`);
655
+ await execAsync(`cargo tauri build --target ${target} ${releaseFlag}`.trim(), {
656
+ cwd: projectRoot,
657
+ });
658
+ }
659
+ catch (error) {
660
+ console.error(`Failed to build for ${arch}:`, error);
661
+ process.exit(1);
662
+ }
663
+ // Prepare AppxContent directory
664
+ console.log(` Preparing AppxContent for ${arch}...`);
665
+ const appxDir = prepareAppxContent(projectRoot, arch, config, tauriConfig, minVersion);
666
+ appxDirs.push({ arch, dir: appxDir });
667
+ console.log(` AppxContent ready: ${appxDir}`);
668
+ }
669
+ // Call msixbundle-cli
670
+ console.log('\nCreating MSIX package...');
671
+ const outDir = path.join(projectRoot, 'target', 'msix');
672
+ const args = [
673
+ '--out-dir',
674
+ outDir,
675
+ ...appxDirs.flatMap(({ arch, dir }) => [`--dir-${arch}`, dir]),
676
+ ];
677
+ // Signing
678
+ if (bundleConfig.signing?.pfx) {
679
+ args.push('--pfx', bundleConfig.signing.pfx);
680
+ const password = bundleConfig.signing.pfxPassword || process.env.MSIX_PFX_PASSWORD;
681
+ if (password) {
682
+ args.push('--pfx-password', password);
683
+ }
684
+ }
685
+ else if (tauriConfig.bundle?.windows?.certificateThumbprint) {
686
+ args.push('--thumbprint', tauriConfig.bundle.windows.certificateThumbprint);
687
+ }
688
+ try {
689
+ console.log(` Running: msixbundle-cli ${args.join(' ')}`);
690
+ const result = await execAsync(`msixbundle-cli ${args.join(' ')}`);
691
+ if (result.stdout)
692
+ console.log(result.stdout);
693
+ }
694
+ catch (error) {
695
+ console.error('Failed to create MSIX:', error);
696
+ process.exit(1);
697
+ }
698
+ console.log('\n MSIX bundle created!');
699
+ console.log(`Output: ${outDir}`);
700
+ }
701
+
702
+ function readBundleConfig(windowsDir) {
703
+ const configPath = path.join(windowsDir, 'bundle.config.json');
704
+ if (!fs.existsSync(configPath)) {
705
+ throw new Error(`bundle.config.json not found. Run 'tauri-windows-bundle init' first.`);
706
+ }
707
+ return JSON.parse(fs.readFileSync(configPath, 'utf-8'));
708
+ }
709
+ function writeBundleConfig(windowsDir, config) {
710
+ const configPath = path.join(windowsDir, 'bundle.config.json');
711
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
712
+ }
713
+ function prompt(question) {
714
+ const rl = readline.createInterface({
715
+ input: process.stdin,
716
+ output: process.stdout,
717
+ });
718
+ return new Promise((resolve) => {
719
+ rl.question(question, (answer) => {
720
+ rl.close();
721
+ resolve(answer.trim());
722
+ });
723
+ });
724
+ }
725
+ async function extensionList(options) {
726
+ const projectRoot = findProjectRoot(options.path);
727
+ const windowsDir = getWindowsDir(projectRoot);
728
+ const config = readBundleConfig(windowsDir);
729
+ console.log('\nConfigured extensions:\n');
730
+ // Share Target
731
+ const shareTarget = config.extensions?.shareTarget ?? false;
732
+ console.log(` Share Target: ${shareTarget ? 'enabled' : 'disabled'}`);
733
+ // File Associations
734
+ const fileAssociations = config.extensions?.fileAssociations ?? [];
735
+ if (fileAssociations.length > 0) {
736
+ console.log('\n File Associations:');
737
+ for (const assoc of fileAssociations) {
738
+ console.log(` - ${assoc.name}: ${assoc.extensions.join(', ')}`);
739
+ }
740
+ }
741
+ else {
742
+ console.log('\n File Associations: none');
743
+ }
744
+ // Protocol Handlers
745
+ const protocolHandlers = config.extensions?.protocolHandlers ?? [];
746
+ if (protocolHandlers.length > 0) {
747
+ console.log('\n Protocol Handlers:');
748
+ for (const handler of protocolHandlers) {
749
+ console.log(` - ${handler.name}:// (${handler.displayName || handler.name})`);
750
+ }
751
+ }
752
+ else {
753
+ console.log('\n Protocol Handlers: none');
754
+ }
755
+ // Startup Task
756
+ const startupTask = config.extensions?.startupTask;
757
+ console.log(`\n Startup Task: ${startupTask?.enabled ? 'enabled' : 'disabled'}`);
758
+ // Context Menus
759
+ const contextMenus = config.extensions?.contextMenus ?? [];
760
+ if (contextMenus.length > 0) {
761
+ console.log('\n Context Menus:');
762
+ for (const menu of contextMenus) {
763
+ console.log(` - ${menu.name}: ${menu.fileTypes.join(', ')}`);
764
+ }
765
+ }
766
+ else {
767
+ console.log('\n Context Menus: none');
768
+ }
769
+ // Background Tasks
770
+ const backgroundTasks = config.extensions?.backgroundTasks ?? [];
771
+ if (backgroundTasks.length > 0) {
772
+ console.log('\n Background Tasks:');
773
+ for (const task of backgroundTasks) {
774
+ console.log(` - ${task.name} (${task.type})`);
775
+ }
776
+ }
777
+ else {
778
+ console.log('\n Background Tasks: none');
779
+ }
780
+ // App Execution Aliases
781
+ const aliases = config.extensions?.appExecutionAliases ?? [];
782
+ if (aliases.length > 0) {
783
+ console.log('\n App Execution Aliases:');
784
+ for (const alias of aliases) {
785
+ console.log(` - ${alias.alias}`);
786
+ }
787
+ }
788
+ else {
789
+ console.log('\n App Execution Aliases: none');
790
+ }
791
+ // App Services
792
+ const appServices = config.extensions?.appServices ?? [];
793
+ if (appServices.length > 0) {
794
+ console.log('\n App Services:');
795
+ for (const service of appServices) {
796
+ console.log(` - ${service.name}`);
797
+ }
798
+ }
799
+ else {
800
+ console.log('\n App Services: none');
801
+ }
802
+ // Toast Activation
803
+ const toastActivation = config.extensions?.toastActivation;
804
+ console.log(`\n Toast Activation: ${toastActivation ? 'enabled' : 'disabled'}`);
805
+ // Autoplay Handlers
806
+ const autoplayHandlers = config.extensions?.autoplayHandlers ?? [];
807
+ if (autoplayHandlers.length > 0) {
808
+ console.log('\n Autoplay Handlers:');
809
+ for (const handler of autoplayHandlers) {
810
+ console.log(` - ${handler.verb}: ${handler.actionDisplayName}`);
811
+ }
812
+ }
813
+ else {
814
+ console.log('\n Autoplay Handlers: none');
815
+ }
816
+ // Print Task Settings
817
+ const printTaskSettings = config.extensions?.printTaskSettings;
818
+ console.log(`\n Print Task Settings: ${printTaskSettings ? 'enabled' : 'disabled'}`);
819
+ // Thumbnail Handlers
820
+ const thumbnailHandlers = config.extensions?.thumbnailHandlers ?? [];
821
+ if (thumbnailHandlers.length > 0) {
822
+ console.log('\n Thumbnail Handlers:');
823
+ for (const handler of thumbnailHandlers) {
824
+ console.log(` - ${handler.fileTypes.join(', ')}`);
825
+ }
826
+ }
827
+ else {
828
+ console.log('\n Thumbnail Handlers: none');
829
+ }
830
+ // Preview Handlers
831
+ const previewHandlers = config.extensions?.previewHandlers ?? [];
832
+ if (previewHandlers.length > 0) {
833
+ console.log('\n Preview Handlers:');
834
+ for (const handler of previewHandlers) {
835
+ console.log(` - ${handler.fileTypes.join(', ')}`);
836
+ }
837
+ }
838
+ else {
839
+ console.log('\n Preview Handlers: none');
840
+ }
841
+ console.log('');
842
+ }
843
+ async function extensionAddFileAssociation(options) {
844
+ const projectRoot = findProjectRoot(options.path);
845
+ const windowsDir = getWindowsDir(projectRoot);
846
+ const config = readBundleConfig(windowsDir);
847
+ console.log('\nAdd File Association\n');
848
+ const name = await prompt('Association name (e.g., myfiles): ');
849
+ if (!name) {
850
+ console.log('Cancelled.');
851
+ return;
852
+ }
853
+ const extensionsInput = await prompt('File extensions (comma-separated, e.g., .myf,.myx): ');
854
+ if (!extensionsInput) {
855
+ console.log('Cancelled.');
856
+ return;
857
+ }
858
+ const extensions = extensionsInput.split(',').map((ext) => {
859
+ ext = ext.trim();
860
+ return ext.startsWith('.') ? ext : `.${ext}`;
861
+ });
862
+ const description = await prompt('Description (optional): ');
863
+ const fileAssociation = {
864
+ name,
865
+ extensions,
866
+ };
867
+ if (description) {
868
+ fileAssociation.description = description;
869
+ }
870
+ if (!config.extensions) {
871
+ config.extensions = {};
872
+ }
873
+ if (!config.extensions.fileAssociations) {
874
+ config.extensions.fileAssociations = [];
875
+ }
876
+ // Check for duplicate
877
+ const existing = config.extensions.fileAssociations.find((a) => a.name === name);
878
+ if (existing) {
879
+ console.log(`\nFile association '${name}' already exists. Updating...`);
880
+ Object.assign(existing, fileAssociation);
881
+ }
882
+ else {
883
+ config.extensions.fileAssociations.push(fileAssociation);
884
+ }
885
+ writeBundleConfig(windowsDir, config);
886
+ console.log(`\nFile association '${name}' added successfully.`);
887
+ }
888
+ async function extensionAddProtocol(options) {
889
+ const projectRoot = findProjectRoot(options.path);
890
+ const windowsDir = getWindowsDir(projectRoot);
891
+ const config = readBundleConfig(windowsDir);
892
+ console.log('\nAdd Protocol Handler\n');
893
+ const name = await prompt('Protocol name (e.g., myapp): ');
894
+ if (!name) {
895
+ console.log('Cancelled.');
896
+ return;
897
+ }
898
+ const displayName = await prompt(`Display name (default: ${name}): `);
899
+ const protocolHandler = {
900
+ name,
901
+ };
902
+ if (displayName) {
903
+ protocolHandler.displayName = displayName;
904
+ }
905
+ if (!config.extensions) {
906
+ config.extensions = {};
907
+ }
908
+ if (!config.extensions.protocolHandlers) {
909
+ config.extensions.protocolHandlers = [];
910
+ }
911
+ // Check for duplicate
912
+ const existing = config.extensions.protocolHandlers.find((p) => p.name === name);
913
+ if (existing) {
914
+ console.log(`\nProtocol handler '${name}' already exists. Updating...`);
915
+ Object.assign(existing, protocolHandler);
916
+ }
917
+ else {
918
+ config.extensions.protocolHandlers.push(protocolHandler);
919
+ }
920
+ writeBundleConfig(windowsDir, config);
921
+ console.log(`\nProtocol handler '${name}://' added successfully.`);
922
+ }
923
+ async function extensionEnableShareTarget(options) {
924
+ const projectRoot = findProjectRoot(options.path);
925
+ const windowsDir = getWindowsDir(projectRoot);
926
+ const config = readBundleConfig(windowsDir);
927
+ if (!config.extensions) {
928
+ config.extensions = {};
929
+ }
930
+ config.extensions.shareTarget = true;
931
+ writeBundleConfig(windowsDir, config);
932
+ console.log('\nShare Target enabled.');
933
+ }
934
+ async function extensionDisableShareTarget(options) {
935
+ const projectRoot = findProjectRoot(options.path);
936
+ const windowsDir = getWindowsDir(projectRoot);
937
+ const config = readBundleConfig(windowsDir);
938
+ if (!config.extensions) {
939
+ config.extensions = {};
940
+ }
941
+ config.extensions.shareTarget = false;
942
+ writeBundleConfig(windowsDir, config);
943
+ console.log('\nShare Target disabled.');
944
+ }
945
+ async function extensionEnableStartupTask(options) {
946
+ const projectRoot = findProjectRoot(options.path);
947
+ const windowsDir = getWindowsDir(projectRoot);
948
+ const config = readBundleConfig(windowsDir);
949
+ if (!config.extensions) {
950
+ config.extensions = {};
951
+ }
952
+ config.extensions.startupTask = { enabled: true };
953
+ writeBundleConfig(windowsDir, config);
954
+ console.log('\nStartup Task enabled. App will run on Windows login.');
955
+ }
956
+ async function extensionDisableStartupTask(options) {
957
+ const projectRoot = findProjectRoot(options.path);
958
+ const windowsDir = getWindowsDir(projectRoot);
959
+ const config = readBundleConfig(windowsDir);
960
+ if (!config.extensions) {
961
+ config.extensions = {};
962
+ }
963
+ config.extensions.startupTask = { enabled: false };
964
+ writeBundleConfig(windowsDir, config);
965
+ console.log('\nStartup Task disabled.');
966
+ }
967
+ async function extensionAddContextMenu(options) {
968
+ const projectRoot = findProjectRoot(options.path);
969
+ const windowsDir = getWindowsDir(projectRoot);
970
+ const config = readBundleConfig(windowsDir);
971
+ console.log('\nAdd Context Menu\n');
972
+ const name = await prompt('Menu item name (e.g., open-with-myapp): ');
973
+ if (!name) {
974
+ console.log('Cancelled.');
975
+ return;
976
+ }
977
+ const fileTypesInput = await prompt('File types (comma-separated, e.g., *, .txt, .doc): ');
978
+ if (!fileTypesInput) {
979
+ console.log('Cancelled.');
980
+ return;
981
+ }
982
+ const fileTypes = fileTypesInput.split(',').map((t) => t.trim());
983
+ const displayName = await prompt('Display name (shown in menu): ');
984
+ const contextMenu = {
985
+ name,
986
+ fileTypes,
987
+ };
988
+ if (displayName) {
989
+ contextMenu.displayName = displayName;
990
+ }
991
+ if (!config.extensions) {
992
+ config.extensions = {};
993
+ }
994
+ if (!config.extensions.contextMenus) {
995
+ config.extensions.contextMenus = [];
996
+ }
997
+ const existing = config.extensions.contextMenus.find((m) => m.name === name);
998
+ if (existing) {
999
+ console.log(`\nContext menu '${name}' already exists. Updating...`);
1000
+ Object.assign(existing, contextMenu);
1001
+ }
1002
+ else {
1003
+ config.extensions.contextMenus.push(contextMenu);
1004
+ }
1005
+ writeBundleConfig(windowsDir, config);
1006
+ console.log(`\nContext menu '${name}' added successfully.`);
1007
+ }
1008
+ async function extensionAddBackgroundTask(options) {
1009
+ const projectRoot = findProjectRoot(options.path);
1010
+ const windowsDir = getWindowsDir(projectRoot);
1011
+ const config = readBundleConfig(windowsDir);
1012
+ console.log('\nAdd Background Task\n');
1013
+ const name = await prompt('Task name (e.g., sync-task): ');
1014
+ if (!name) {
1015
+ console.log('Cancelled.');
1016
+ return;
1017
+ }
1018
+ console.log('Task types:');
1019
+ console.log(' 1. timer - Runs periodically');
1020
+ console.log(' 2. systemEvent - Runs on system events');
1021
+ console.log(' 3. pushNotification - Runs on push notification');
1022
+ const typeInput = await prompt('Task type (1/2/3): ');
1023
+ const typeMap = {
1024
+ '1': 'timer',
1025
+ '2': 'systemEvent',
1026
+ '3': 'pushNotification',
1027
+ timer: 'timer',
1028
+ systemevent: 'systemEvent',
1029
+ pushnotification: 'pushNotification',
1030
+ };
1031
+ const taskType = typeMap[typeInput.toLowerCase()];
1032
+ if (!taskType) {
1033
+ console.log('Invalid task type. Cancelled.');
1034
+ return;
1035
+ }
1036
+ const backgroundTask = {
1037
+ name,
1038
+ type: taskType,
1039
+ };
1040
+ if (!config.extensions) {
1041
+ config.extensions = {};
1042
+ }
1043
+ if (!config.extensions.backgroundTasks) {
1044
+ config.extensions.backgroundTasks = [];
1045
+ }
1046
+ const existing = config.extensions.backgroundTasks.find((t) => t.name === name);
1047
+ if (existing) {
1048
+ console.log(`\nBackground task '${name}' already exists. Updating...`);
1049
+ Object.assign(existing, backgroundTask);
1050
+ }
1051
+ else {
1052
+ config.extensions.backgroundTasks.push(backgroundTask);
1053
+ }
1054
+ writeBundleConfig(windowsDir, config);
1055
+ console.log(`\nBackground task '${name}' (${taskType}) added successfully.`);
1056
+ }
1057
+ async function extensionAddAppExecutionAlias(options) {
1058
+ const projectRoot = findProjectRoot(options.path);
1059
+ const windowsDir = getWindowsDir(projectRoot);
1060
+ const config = readBundleConfig(windowsDir);
1061
+ console.log('\nAdd App Execution Alias\n');
1062
+ const alias = await prompt('Alias name (e.g., myapp): ');
1063
+ if (!alias) {
1064
+ console.log('Cancelled.');
1065
+ return;
1066
+ }
1067
+ const appAlias = { alias };
1068
+ if (!config.extensions) {
1069
+ config.extensions = {};
1070
+ }
1071
+ if (!config.extensions.appExecutionAliases) {
1072
+ config.extensions.appExecutionAliases = [];
1073
+ }
1074
+ const existing = config.extensions.appExecutionAliases.find((a) => a.alias === alias);
1075
+ if (existing) {
1076
+ console.log(`\nAlias '${alias}' already exists.`);
1077
+ return;
1078
+ }
1079
+ config.extensions.appExecutionAliases.push(appAlias);
1080
+ writeBundleConfig(windowsDir, config);
1081
+ console.log(`\nApp execution alias '${alias}' added. You can run your app from command line.`);
1082
+ }
1083
+ async function extensionAddAppService(options) {
1084
+ const projectRoot = findProjectRoot(options.path);
1085
+ const windowsDir = getWindowsDir(projectRoot);
1086
+ const config = readBundleConfig(windowsDir);
1087
+ console.log('\nAdd App Service\n');
1088
+ const name = await prompt('Service name (e.g., com.myapp.service): ');
1089
+ if (!name) {
1090
+ console.log('Cancelled.');
1091
+ return;
1092
+ }
1093
+ const appService = { name };
1094
+ if (!config.extensions) {
1095
+ config.extensions = {};
1096
+ }
1097
+ if (!config.extensions.appServices) {
1098
+ config.extensions.appServices = [];
1099
+ }
1100
+ const existing = config.extensions.appServices.find((s) => s.name === name);
1101
+ if (existing) {
1102
+ console.log(`\nApp service '${name}' already exists.`);
1103
+ return;
1104
+ }
1105
+ config.extensions.appServices.push(appService);
1106
+ writeBundleConfig(windowsDir, config);
1107
+ console.log(`\nApp service '${name}' added. Other apps can now call into your app.`);
1108
+ }
1109
+ async function extensionEnableToastActivation(options) {
1110
+ const projectRoot = findProjectRoot(options.path);
1111
+ const windowsDir = getWindowsDir(projectRoot);
1112
+ const config = readBundleConfig(windowsDir);
1113
+ if (!config.extensions) {
1114
+ config.extensions = {};
1115
+ }
1116
+ config.extensions.toastActivation = { activationType: 'foreground' };
1117
+ writeBundleConfig(windowsDir, config);
1118
+ console.log('\nToast Activation enabled. Your app will handle toast notification clicks.');
1119
+ }
1120
+ async function extensionDisableToastActivation(options) {
1121
+ const projectRoot = findProjectRoot(options.path);
1122
+ const windowsDir = getWindowsDir(projectRoot);
1123
+ const config = readBundleConfig(windowsDir);
1124
+ if (config.extensions) {
1125
+ delete config.extensions.toastActivation;
1126
+ }
1127
+ writeBundleConfig(windowsDir, config);
1128
+ console.log('\nToast Activation disabled.');
1129
+ }
1130
+ async function extensionAddAutoplay(options) {
1131
+ const projectRoot = findProjectRoot(options.path);
1132
+ const windowsDir = getWindowsDir(projectRoot);
1133
+ const config = readBundleConfig(windowsDir);
1134
+ console.log('\nAdd Autoplay Handler\n');
1135
+ const verb = await prompt('Verb (e.g., open, play): ');
1136
+ if (!verb) {
1137
+ console.log('Cancelled.');
1138
+ return;
1139
+ }
1140
+ const actionDisplayName = await prompt('Action display name (e.g., Open with MyApp): ');
1141
+ if (!actionDisplayName) {
1142
+ console.log('Cancelled.');
1143
+ return;
1144
+ }
1145
+ console.log('Event type:');
1146
+ console.log(' 1. Content event (e.g., PlayMusicFilesOnArrival)');
1147
+ console.log(' 2. Device event (e.g., WPD\\ImageSource)');
1148
+ const eventType = await prompt('Event type (1/2): ');
1149
+ const handler = { verb, actionDisplayName };
1150
+ if (eventType === '1') {
1151
+ const contentEvent = await prompt('Content event (e.g., PlayMusicFilesOnArrival): ');
1152
+ if (!contentEvent) {
1153
+ console.log('Cancelled.');
1154
+ return;
1155
+ }
1156
+ handler.contentEvent = contentEvent;
1157
+ }
1158
+ else if (eventType === '2') {
1159
+ const deviceEvent = await prompt('Device event (e.g., WPD\\\\ImageSource): ');
1160
+ if (!deviceEvent) {
1161
+ console.log('Cancelled.');
1162
+ return;
1163
+ }
1164
+ handler.deviceEvent = deviceEvent;
1165
+ }
1166
+ else {
1167
+ console.log('Invalid event type. Cancelled.');
1168
+ return;
1169
+ }
1170
+ if (!config.extensions) {
1171
+ config.extensions = {};
1172
+ }
1173
+ if (!config.extensions.autoplayHandlers) {
1174
+ config.extensions.autoplayHandlers = [];
1175
+ }
1176
+ config.extensions.autoplayHandlers.push(handler);
1177
+ writeBundleConfig(windowsDir, config);
1178
+ console.log(`\nAutoplay handler '${verb}' added.`);
1179
+ }
1180
+ async function extensionEnablePrintTaskSettings(options) {
1181
+ const projectRoot = findProjectRoot(options.path);
1182
+ const windowsDir = getWindowsDir(projectRoot);
1183
+ const config = readBundleConfig(windowsDir);
1184
+ if (!config.extensions) {
1185
+ config.extensions = {};
1186
+ }
1187
+ config.extensions.printTaskSettings = { displayName: 'Print Settings' };
1188
+ writeBundleConfig(windowsDir, config);
1189
+ console.log('\nPrint Task Settings enabled.');
1190
+ }
1191
+ async function extensionDisablePrintTaskSettings(options) {
1192
+ const projectRoot = findProjectRoot(options.path);
1193
+ const windowsDir = getWindowsDir(projectRoot);
1194
+ const config = readBundleConfig(windowsDir);
1195
+ if (config.extensions) {
1196
+ delete config.extensions.printTaskSettings;
1197
+ }
1198
+ writeBundleConfig(windowsDir, config);
1199
+ console.log('\nPrint Task Settings disabled.');
1200
+ }
1201
+ async function extensionAddThumbnailHandler(options) {
1202
+ const projectRoot = findProjectRoot(options.path);
1203
+ const windowsDir = getWindowsDir(projectRoot);
1204
+ const config = readBundleConfig(windowsDir);
1205
+ console.log('\nAdd Thumbnail Handler\n');
1206
+ const clsid = await prompt('CLSID (e.g., {12345678-1234-1234-1234-123456789012}): ');
1207
+ if (!clsid) {
1208
+ console.log('Cancelled.');
1209
+ return;
1210
+ }
1211
+ const fileTypesInput = await prompt('File types (comma-separated, e.g., .myf,.myx): ');
1212
+ if (!fileTypesInput) {
1213
+ console.log('Cancelled.');
1214
+ return;
1215
+ }
1216
+ const fileTypes = fileTypesInput.split(',').map((t) => t.trim());
1217
+ const handler = { clsid, fileTypes };
1218
+ if (!config.extensions) {
1219
+ config.extensions = {};
1220
+ }
1221
+ if (!config.extensions.thumbnailHandlers) {
1222
+ config.extensions.thumbnailHandlers = [];
1223
+ }
1224
+ config.extensions.thumbnailHandlers.push(handler);
1225
+ writeBundleConfig(windowsDir, config);
1226
+ console.log(`\nThumbnail handler added for ${fileTypes.join(', ')}.`);
1227
+ }
1228
+ async function extensionAddPreviewHandler(options) {
1229
+ const projectRoot = findProjectRoot(options.path);
1230
+ const windowsDir = getWindowsDir(projectRoot);
1231
+ const config = readBundleConfig(windowsDir);
1232
+ console.log('\nAdd Preview Handler\n');
1233
+ const clsid = await prompt('CLSID (e.g., {12345678-1234-1234-1234-123456789012}): ');
1234
+ if (!clsid) {
1235
+ console.log('Cancelled.');
1236
+ return;
1237
+ }
1238
+ const fileTypesInput = await prompt('File types (comma-separated, e.g., .myf,.myx): ');
1239
+ if (!fileTypesInput) {
1240
+ console.log('Cancelled.');
1241
+ return;
1242
+ }
1243
+ const fileTypes = fileTypesInput.split(',').map((t) => t.trim());
1244
+ const handler = { clsid, fileTypes };
1245
+ if (!config.extensions) {
1246
+ config.extensions = {};
1247
+ }
1248
+ if (!config.extensions.previewHandlers) {
1249
+ config.extensions.previewHandlers = [];
1250
+ }
1251
+ config.extensions.previewHandlers.push(handler);
1252
+ writeBundleConfig(windowsDir, config);
1253
+ console.log(`\nPreview handler added for ${fileTypes.join(', ')}.`);
1254
+ }
1255
+ async function extensionRemove(type, name, options) {
1256
+ const projectRoot = findProjectRoot(options.path);
1257
+ const windowsDir = getWindowsDir(projectRoot);
1258
+ const config = readBundleConfig(windowsDir);
1259
+ if (!config.extensions) {
1260
+ console.log('\nNo extensions configured.');
1261
+ return;
1262
+ }
1263
+ switch (type) {
1264
+ case 'file-association': {
1265
+ if (!config.extensions.fileAssociations) {
1266
+ console.log('\nNo file associations configured.');
1267
+ return;
1268
+ }
1269
+ const index = config.extensions.fileAssociations.findIndex((a) => a.name === name);
1270
+ if (index === -1) {
1271
+ console.log(`\nFile association '${name}' not found.`);
1272
+ return;
1273
+ }
1274
+ config.extensions.fileAssociations.splice(index, 1);
1275
+ writeBundleConfig(windowsDir, config);
1276
+ console.log(`\nFile association '${name}' removed.`);
1277
+ break;
1278
+ }
1279
+ case 'protocol': {
1280
+ if (!config.extensions.protocolHandlers) {
1281
+ console.log('\nNo protocol handlers configured.');
1282
+ return;
1283
+ }
1284
+ const index = config.extensions.protocolHandlers.findIndex((p) => p.name === name);
1285
+ if (index === -1) {
1286
+ console.log(`\nProtocol handler '${name}' not found.`);
1287
+ return;
1288
+ }
1289
+ config.extensions.protocolHandlers.splice(index, 1);
1290
+ writeBundleConfig(windowsDir, config);
1291
+ console.log(`\nProtocol handler '${name}' removed.`);
1292
+ break;
1293
+ }
1294
+ case 'context-menu': {
1295
+ if (!config.extensions.contextMenus) {
1296
+ console.log('\nNo context menus configured.');
1297
+ return;
1298
+ }
1299
+ const index = config.extensions.contextMenus.findIndex((m) => m.name === name);
1300
+ if (index === -1) {
1301
+ console.log(`\nContext menu '${name}' not found.`);
1302
+ return;
1303
+ }
1304
+ config.extensions.contextMenus.splice(index, 1);
1305
+ writeBundleConfig(windowsDir, config);
1306
+ console.log(`\nContext menu '${name}' removed.`);
1307
+ break;
1308
+ }
1309
+ case 'background-task': {
1310
+ if (!config.extensions.backgroundTasks) {
1311
+ console.log('\nNo background tasks configured.');
1312
+ return;
1313
+ }
1314
+ const index = config.extensions.backgroundTasks.findIndex((t) => t.name === name);
1315
+ if (index === -1) {
1316
+ console.log(`\nBackground task '${name}' not found.`);
1317
+ return;
1318
+ }
1319
+ config.extensions.backgroundTasks.splice(index, 1);
1320
+ writeBundleConfig(windowsDir, config);
1321
+ console.log(`\nBackground task '${name}' removed.`);
1322
+ break;
1323
+ }
1324
+ case 'app-execution-alias': {
1325
+ if (!config.extensions.appExecutionAliases) {
1326
+ console.log('\nNo app execution aliases configured.');
1327
+ return;
1328
+ }
1329
+ const index = config.extensions.appExecutionAliases.findIndex((a) => a.alias === name);
1330
+ if (index === -1) {
1331
+ console.log(`\nApp execution alias '${name}' not found.`);
1332
+ return;
1333
+ }
1334
+ config.extensions.appExecutionAliases.splice(index, 1);
1335
+ writeBundleConfig(windowsDir, config);
1336
+ console.log(`\nApp execution alias '${name}' removed.`);
1337
+ break;
1338
+ }
1339
+ case 'app-service': {
1340
+ if (!config.extensions.appServices) {
1341
+ console.log('\nNo app services configured.');
1342
+ return;
1343
+ }
1344
+ const index = config.extensions.appServices.findIndex((s) => s.name === name);
1345
+ if (index === -1) {
1346
+ console.log(`\nApp service '${name}' not found.`);
1347
+ return;
1348
+ }
1349
+ config.extensions.appServices.splice(index, 1);
1350
+ writeBundleConfig(windowsDir, config);
1351
+ console.log(`\nApp service '${name}' removed.`);
1352
+ break;
1353
+ }
1354
+ case 'autoplay': {
1355
+ if (!config.extensions.autoplayHandlers) {
1356
+ console.log('\nNo autoplay handlers configured.');
1357
+ return;
1358
+ }
1359
+ const index = config.extensions.autoplayHandlers.findIndex((h) => h.verb === name);
1360
+ if (index === -1) {
1361
+ console.log(`\nAutoplay handler '${name}' not found.`);
1362
+ return;
1363
+ }
1364
+ config.extensions.autoplayHandlers.splice(index, 1);
1365
+ writeBundleConfig(windowsDir, config);
1366
+ console.log(`\nAutoplay handler '${name}' removed.`);
1367
+ break;
1368
+ }
1369
+ case 'thumbnail-handler': {
1370
+ if (!config.extensions.thumbnailHandlers) {
1371
+ console.log('\nNo thumbnail handlers configured.');
1372
+ return;
1373
+ }
1374
+ const index = config.extensions.thumbnailHandlers.findIndex((h) => h.clsid === name);
1375
+ if (index === -1) {
1376
+ console.log(`\nThumbnail handler '${name}' not found.`);
1377
+ return;
1378
+ }
1379
+ config.extensions.thumbnailHandlers.splice(index, 1);
1380
+ writeBundleConfig(windowsDir, config);
1381
+ console.log(`\nThumbnail handler removed.`);
1382
+ break;
1383
+ }
1384
+ case 'preview-handler': {
1385
+ if (!config.extensions.previewHandlers) {
1386
+ console.log('\nNo preview handlers configured.');
1387
+ return;
1388
+ }
1389
+ const index = config.extensions.previewHandlers.findIndex((h) => h.clsid === name);
1390
+ if (index === -1) {
1391
+ console.log(`\nPreview handler '${name}' not found.`);
1392
+ return;
1393
+ }
1394
+ config.extensions.previewHandlers.splice(index, 1);
1395
+ writeBundleConfig(windowsDir, config);
1396
+ console.log(`\nPreview handler removed.`);
1397
+ break;
1398
+ }
1399
+ default:
1400
+ console.log(`\nUnknown extension type: ${type}`);
1401
+ console.log('Valid types: file-association, protocol, context-menu, background-task, ' +
1402
+ 'app-execution-alias, app-service, autoplay, thumbnail-handler, preview-handler');
1403
+ }
1404
+ }
1405
+
1406
+ export { DEFAULT_CAPABILITIES, DEFAULT_MIN_WINDOWS_VERSION, MSIX_ASSETS, build, extensionAddAppExecutionAlias, extensionAddAppService, extensionAddAutoplay, extensionAddBackgroundTask, extensionAddContextMenu, extensionAddFileAssociation, extensionAddPreviewHandler, extensionAddProtocol, extensionAddThumbnailHandler, extensionDisablePrintTaskSettings, extensionDisableShareTarget, extensionDisableStartupTask, extensionDisableToastActivation, extensionEnablePrintTaskSettings, extensionEnableShareTarget, extensionEnableStartupTask, extensionEnableToastActivation, extensionList, extensionRemove, findProjectRoot, generateManifest, generateManifestTemplate, getWindowsDir, init, prepareAppxContent, readBundleConfig$1 as readBundleConfig, readTauriConfig, toFourPartVersion };