@choochmeque/tauri-windows-bundle 0.1.5 → 0.1.7

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/README.md CHANGED
@@ -47,9 +47,12 @@ npx @choochmeque/tauri-windows-bundle init
47
47
  This creates:
48
48
  - `src-tauri/gen/windows/bundle.config.json` - MSIX-specific configuration
49
49
  - `src-tauri/gen/windows/AppxManifest.xml.template` - Manifest template
50
- - `src-tauri/gen/windows/Assets/` - Placeholder icons
50
+ - `src-tauri/gen/windows/Assets/` - Icons (copied from `src-tauri/icons/` or placeholders)
51
+ - Adds `@choochmeque/tauri-windows-bundle` as devDependency
51
52
  - Adds `tauri:windows:build` script to package.json
52
53
 
54
+ **Note:** If Tauri icons exist in `src-tauri/icons/`, they are automatically copied. The wide tile (310x150) is generated by centering the square icon.
55
+
53
56
  ### Configure
54
57
 
55
58
  Edit `src-tauri/gen/windows/bundle.config.json`:
@@ -110,6 +113,8 @@ npx @choochmeque/tauri-windows-bundle build [options]
110
113
  --arch <archs> Architectures (comma-separated: x64,arm64) [default: x64]
111
114
  --release Build in release mode
112
115
  --min-windows <ver> Minimum Windows version [default: 10.0.17763.0]
116
+ --runner <runner> Build runner (cargo, pnpm, npm, yarn, bun) [default: cargo]
117
+ --verbose Show full build output instead of spinner
113
118
 
114
119
  npx @choochmeque/tauri-windows-bundle extension list
115
120
  -p, --path <path> Path to Tauri project
package/dist/cli.js CHANGED
@@ -2,6 +2,7 @@
2
2
  import { Command } from 'commander';
3
3
  import * as fs from 'node:fs';
4
4
  import * as path from 'node:path';
5
+ import { Jimp } from 'jimp';
5
6
  import { fileURLToPath } from 'node:url';
6
7
  import { glob } from 'glob';
7
8
  import { exec, spawn } from 'node:child_process';
@@ -101,18 +102,80 @@ function generateGitignore(windowsDir) {
101
102
  fs.writeFileSync(gitignorePath, content);
102
103
  }
103
104
 
104
- async function generateAssets(windowsDir) {
105
+ // Map MSIX asset names to Tauri icon names
106
+ const TAURI_ICON_MAP = {
107
+ 'StoreLogo.png': 'StoreLogo.png',
108
+ 'Square44x44Logo.png': 'Square44x44Logo.png',
109
+ 'Square150x150Logo.png': 'Square150x150Logo.png',
110
+ 'LargeTile.png': 'Square310x310Logo.png',
111
+ };
112
+ function getTauriIconsDir(projectRoot) {
113
+ return path.join(projectRoot, 'src-tauri', 'icons');
114
+ }
115
+ async function generateAssets(windowsDir, projectRoot) {
105
116
  const assetsDir = path.join(windowsDir, 'Assets');
106
117
  fs.mkdirSync(assetsDir, { recursive: true });
118
+ const tauriIconsDir = projectRoot ? getTauriIconsDir(projectRoot) : null;
119
+ let copiedFromTauri = false;
107
120
  for (const asset of MSIX_ASSETS) {
108
121
  const width = asset.width || asset.size || 50;
109
122
  const height = asset.height || asset.size || 50;
110
123
  const assetPath = path.join(assetsDir, asset.name);
111
- // Generate a simple placeholder PNG
112
- const pngData = createPlaceholderPng(width, height);
113
- fs.writeFileSync(assetPath, pngData);
124
+ // Check if we can copy from Tauri icons
125
+ const tauriIconName = TAURI_ICON_MAP[asset.name];
126
+ const tauriIconPath = tauriIconsDir && tauriIconName ? path.join(tauriIconsDir, tauriIconName) : null;
127
+ if (tauriIconPath && fs.existsSync(tauriIconPath)) {
128
+ fs.copyFileSync(tauriIconPath, assetPath);
129
+ copiedFromTauri = true;
130
+ }
131
+ else if (asset.name === 'Wide310x150Logo.png' && tauriIconsDir) {
132
+ // Generate wide tile from square icon
133
+ const generated = await generateWideTile(tauriIconsDir, assetPath);
134
+ if (!generated) {
135
+ const pngData = createPlaceholderPng(width, height);
136
+ fs.writeFileSync(assetPath, pngData);
137
+ }
138
+ else {
139
+ copiedFromTauri = true;
140
+ }
141
+ }
142
+ else {
143
+ // Fall back to placeholder
144
+ const pngData = createPlaceholderPng(width, height);
145
+ fs.writeFileSync(assetPath, pngData);
146
+ }
147
+ }
148
+ if (copiedFromTauri) {
149
+ console.log(' Copied assets from src-tauri/icons');
150
+ }
151
+ else {
152
+ console.log(' Generated placeholder assets - replace with real icons before publishing');
114
153
  }
115
- console.log(' Generated placeholder assets - replace with real icons before publishing');
154
+ return copiedFromTauri;
155
+ }
156
+ async function generateWideTile(tauriIconsDir, outputPath) {
157
+ // Try to find a square icon to use as source
158
+ const sourceIcons = ['Square150x150Logo.png', 'Square142x142Logo.png', 'icon.png', '128x128.png'];
159
+ for (const iconName of sourceIcons) {
160
+ const iconPath = path.join(tauriIconsDir, iconName);
161
+ if (fs.existsSync(iconPath)) {
162
+ try {
163
+ const image = await Jimp.read(iconPath);
164
+ const iconSize = 150; // Height of the wide tile
165
+ const resized = image.clone().resize({ w: iconSize, h: iconSize });
166
+ // Create 310x150 canvas with transparent background
167
+ const canvas = new Jimp({ width: 310, height: 150, color: 0x00000000 });
168
+ const x = Math.floor((310 - iconSize) / 2);
169
+ canvas.composite(resized, x, 0);
170
+ await canvas.write(outputPath);
171
+ return true;
172
+ }
173
+ catch {
174
+ // Try next icon
175
+ }
176
+ }
177
+ }
178
+ return false;
116
179
  }
117
180
  function createPlaceholderPng(width, height) {
118
181
  // Create a minimal valid PNG file (solid gray square)
@@ -225,6 +288,10 @@ function findPackageRoot(startDir) {
225
288
  const PACKAGE_ROOT = findPackageRoot(__dirname$1);
226
289
  const TEMPLATES_DIR = path.join(PACKAGE_ROOT, 'templates');
227
290
  const EXTENSIONS_DIR = path.join(TEMPLATES_DIR, 'extensions');
291
+ function getPackageVersion() {
292
+ const pkg = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, 'package.json'), 'utf-8'));
293
+ return pkg.version;
294
+ }
228
295
  function loadTemplate(templatePath) {
229
296
  return fs.readFileSync(templatePath, 'utf-8');
230
297
  }
@@ -410,7 +477,14 @@ function generateExtensions(config) {
410
477
  return ` <Extensions>\n${extensions.join('\n\n')}\n </Extensions>`;
411
478
  }
412
479
  function generateCapabilities(capabilities) {
413
- return capabilities.map((cap) => ` <Capability Name="${cap}" />`).join('\n');
480
+ const caps = [];
481
+ // runFullTrust is always required for Tauri apps using Windows.FullTrustApplication
482
+ caps.push(' <rescap:Capability Name="runFullTrust" />');
483
+ // Add user-specified capabilities
484
+ for (const cap of capabilities) {
485
+ caps.push(` <Capability Name="${cap}" />`);
486
+ }
487
+ return caps.join('\n');
414
488
  }
415
489
  function generateClsid(seed) {
416
490
  // Generate a deterministic GUID-like string from the seed
@@ -447,20 +521,25 @@ async function init(options) {
447
521
  // Generate AppxManifest.xml template
448
522
  generateManifestTemplate(windowsDir);
449
523
  console.log(' Created AppxManifest.xml.template');
450
- // Generate placeholder assets
451
- await generateAssets(windowsDir);
524
+ // Generate assets (copy from src-tauri/icons or generate placeholders)
525
+ const assetsCopied = await generateAssets(windowsDir, projectRoot);
452
526
  // Generate .gitignore
453
527
  generateGitignore(windowsDir);
454
- // Update package.json with build script
528
+ // Update package.json with devDependency and build script
455
529
  updatePackageJson(projectRoot);
456
- console.log(' Added tauri:windows:build script to package.json');
457
530
  console.log('\n Windows bundle configuration created!');
458
531
  console.log(`\nNext steps:`);
459
- console.log(` 1. Edit src-tauri/gen/windows/bundle.config.json`);
532
+ console.log(` 1. Run: pnpm install`);
533
+ console.log(` 2. Edit src-tauri/gen/windows/bundle.config.json`);
460
534
  console.log(` - Set your publisher CN (from your code signing certificate)`);
461
535
  console.log(` - Set your publisher display name`);
462
- console.log(` 2. Replace placeholder icons in src-tauri/gen/windows/Assets/`);
463
- console.log(` 3. Run: pnpm tauri:windows:build`);
536
+ if (!assetsCopied) {
537
+ console.log(` 3. Replace placeholder icons in src-tauri/gen/windows/Assets/`);
538
+ console.log(` 4. Run: pnpm tauri:windows:build`);
539
+ }
540
+ else {
541
+ console.log(` 3. Run: pnpm tauri:windows:build`);
542
+ }
464
543
  }
465
544
  function updatePackageJson(projectRoot) {
466
545
  const packageJsonPath = path.join(projectRoot, 'package.json');
@@ -471,13 +550,16 @@ function updatePackageJson(projectRoot) {
471
550
  try {
472
551
  const content = fs.readFileSync(packageJsonPath, 'utf-8');
473
552
  const pkg = JSON.parse(content);
474
- if (!pkg.scripts) {
475
- pkg.scripts = {};
476
- }
553
+ // Add devDependency
554
+ pkg.devDependencies = pkg.devDependencies || {};
555
+ pkg.devDependencies['@choochmeque/tauri-windows-bundle'] = `^${getPackageVersion()}`;
556
+ // Add script
557
+ pkg.scripts = pkg.scripts || {};
477
558
  if (!pkg.scripts['tauri:windows:build']) {
478
559
  pkg.scripts['tauri:windows:build'] = 'tauri-windows-bundle build';
479
- fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2) + '\n');
480
560
  }
561
+ fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2) + '\n');
562
+ console.log(' Updated package.json with devDependency and build script');
481
563
  }
482
564
  catch (error) {
483
565
  console.log(` Warning: Could not update package.json: ${error instanceof Error ? error.message : error}`);
@@ -1,3 +1,4 @@
1
1
  import type { MergedConfig } from '../types.js';
2
+ export declare function getPackageVersion(): string;
2
3
  export declare function generateManifestTemplate(windowsDir: string): void;
3
4
  export declare function generateManifest(config: MergedConfig, arch: string, minVersion: string): string;
@@ -1 +1 @@
1
- export declare function generateAssets(windowsDir: string): Promise<void>;
1
+ export declare function generateAssets(windowsDir: string, projectRoot?: string): Promise<boolean>;
package/dist/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
+ import { Jimp } from 'jimp';
3
4
  import { fileURLToPath } from 'node:url';
4
5
  import { glob } from 'glob';
5
6
  import { exec, spawn } from 'node:child_process';
@@ -99,18 +100,80 @@ function generateGitignore(windowsDir) {
99
100
  fs.writeFileSync(gitignorePath, content);
100
101
  }
101
102
 
102
- async function generateAssets(windowsDir) {
103
+ // Map MSIX asset names to Tauri icon names
104
+ const TAURI_ICON_MAP = {
105
+ 'StoreLogo.png': 'StoreLogo.png',
106
+ 'Square44x44Logo.png': 'Square44x44Logo.png',
107
+ 'Square150x150Logo.png': 'Square150x150Logo.png',
108
+ 'LargeTile.png': 'Square310x310Logo.png',
109
+ };
110
+ function getTauriIconsDir(projectRoot) {
111
+ return path.join(projectRoot, 'src-tauri', 'icons');
112
+ }
113
+ async function generateAssets(windowsDir, projectRoot) {
103
114
  const assetsDir = path.join(windowsDir, 'Assets');
104
115
  fs.mkdirSync(assetsDir, { recursive: true });
116
+ const tauriIconsDir = projectRoot ? getTauriIconsDir(projectRoot) : null;
117
+ let copiedFromTauri = false;
105
118
  for (const asset of MSIX_ASSETS) {
106
119
  const width = asset.width || asset.size || 50;
107
120
  const height = asset.height || asset.size || 50;
108
121
  const assetPath = path.join(assetsDir, asset.name);
109
- // Generate a simple placeholder PNG
110
- const pngData = createPlaceholderPng(width, height);
111
- fs.writeFileSync(assetPath, pngData);
122
+ // Check if we can copy from Tauri icons
123
+ const tauriIconName = TAURI_ICON_MAP[asset.name];
124
+ const tauriIconPath = tauriIconsDir && tauriIconName ? path.join(tauriIconsDir, tauriIconName) : null;
125
+ if (tauriIconPath && fs.existsSync(tauriIconPath)) {
126
+ fs.copyFileSync(tauriIconPath, assetPath);
127
+ copiedFromTauri = true;
128
+ }
129
+ else if (asset.name === 'Wide310x150Logo.png' && tauriIconsDir) {
130
+ // Generate wide tile from square icon
131
+ const generated = await generateWideTile(tauriIconsDir, assetPath);
132
+ if (!generated) {
133
+ const pngData = createPlaceholderPng(width, height);
134
+ fs.writeFileSync(assetPath, pngData);
135
+ }
136
+ else {
137
+ copiedFromTauri = true;
138
+ }
139
+ }
140
+ else {
141
+ // Fall back to placeholder
142
+ const pngData = createPlaceholderPng(width, height);
143
+ fs.writeFileSync(assetPath, pngData);
144
+ }
145
+ }
146
+ if (copiedFromTauri) {
147
+ console.log(' Copied assets from src-tauri/icons');
148
+ }
149
+ else {
150
+ console.log(' Generated placeholder assets - replace with real icons before publishing');
112
151
  }
113
- console.log(' Generated placeholder assets - replace with real icons before publishing');
152
+ return copiedFromTauri;
153
+ }
154
+ async function generateWideTile(tauriIconsDir, outputPath) {
155
+ // Try to find a square icon to use as source
156
+ const sourceIcons = ['Square150x150Logo.png', 'Square142x142Logo.png', 'icon.png', '128x128.png'];
157
+ for (const iconName of sourceIcons) {
158
+ const iconPath = path.join(tauriIconsDir, iconName);
159
+ if (fs.existsSync(iconPath)) {
160
+ try {
161
+ const image = await Jimp.read(iconPath);
162
+ const iconSize = 150; // Height of the wide tile
163
+ const resized = image.clone().resize({ w: iconSize, h: iconSize });
164
+ // Create 310x150 canvas with transparent background
165
+ const canvas = new Jimp({ width: 310, height: 150, color: 0x00000000 });
166
+ const x = Math.floor((310 - iconSize) / 2);
167
+ canvas.composite(resized, x, 0);
168
+ await canvas.write(outputPath);
169
+ return true;
170
+ }
171
+ catch {
172
+ // Try next icon
173
+ }
174
+ }
175
+ }
176
+ return false;
114
177
  }
115
178
  function createPlaceholderPng(width, height) {
116
179
  // Create a minimal valid PNG file (solid gray square)
@@ -223,6 +286,10 @@ function findPackageRoot(startDir) {
223
286
  const PACKAGE_ROOT = findPackageRoot(__dirname$1);
224
287
  const TEMPLATES_DIR = path.join(PACKAGE_ROOT, 'templates');
225
288
  const EXTENSIONS_DIR = path.join(TEMPLATES_DIR, 'extensions');
289
+ function getPackageVersion() {
290
+ const pkg = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, 'package.json'), 'utf-8'));
291
+ return pkg.version;
292
+ }
226
293
  function loadTemplate(templatePath) {
227
294
  return fs.readFileSync(templatePath, 'utf-8');
228
295
  }
@@ -408,7 +475,14 @@ function generateExtensions(config) {
408
475
  return ` <Extensions>\n${extensions.join('\n\n')}\n </Extensions>`;
409
476
  }
410
477
  function generateCapabilities(capabilities) {
411
- return capabilities.map((cap) => ` <Capability Name="${cap}" />`).join('\n');
478
+ const caps = [];
479
+ // runFullTrust is always required for Tauri apps using Windows.FullTrustApplication
480
+ caps.push(' <rescap:Capability Name="runFullTrust" />');
481
+ // Add user-specified capabilities
482
+ for (const cap of capabilities) {
483
+ caps.push(` <Capability Name="${cap}" />`);
484
+ }
485
+ return caps.join('\n');
412
486
  }
413
487
  function generateClsid(seed) {
414
488
  // Generate a deterministic GUID-like string from the seed
@@ -445,20 +519,25 @@ async function init(options) {
445
519
  // Generate AppxManifest.xml template
446
520
  generateManifestTemplate(windowsDir);
447
521
  console.log(' Created AppxManifest.xml.template');
448
- // Generate placeholder assets
449
- await generateAssets(windowsDir);
522
+ // Generate assets (copy from src-tauri/icons or generate placeholders)
523
+ const assetsCopied = await generateAssets(windowsDir, projectRoot);
450
524
  // Generate .gitignore
451
525
  generateGitignore(windowsDir);
452
- // Update package.json with build script
526
+ // Update package.json with devDependency and build script
453
527
  updatePackageJson(projectRoot);
454
- console.log(' Added tauri:windows:build script to package.json');
455
528
  console.log('\n Windows bundle configuration created!');
456
529
  console.log(`\nNext steps:`);
457
- console.log(` 1. Edit src-tauri/gen/windows/bundle.config.json`);
530
+ console.log(` 1. Run: pnpm install`);
531
+ console.log(` 2. Edit src-tauri/gen/windows/bundle.config.json`);
458
532
  console.log(` - Set your publisher CN (from your code signing certificate)`);
459
533
  console.log(` - Set your publisher display name`);
460
- console.log(` 2. Replace placeholder icons in src-tauri/gen/windows/Assets/`);
461
- console.log(` 3. Run: pnpm tauri:windows:build`);
534
+ if (!assetsCopied) {
535
+ console.log(` 3. Replace placeholder icons in src-tauri/gen/windows/Assets/`);
536
+ console.log(` 4. Run: pnpm tauri:windows:build`);
537
+ }
538
+ else {
539
+ console.log(` 3. Run: pnpm tauri:windows:build`);
540
+ }
462
541
  }
463
542
  function updatePackageJson(projectRoot) {
464
543
  const packageJsonPath = path.join(projectRoot, 'package.json');
@@ -469,13 +548,16 @@ function updatePackageJson(projectRoot) {
469
548
  try {
470
549
  const content = fs.readFileSync(packageJsonPath, 'utf-8');
471
550
  const pkg = JSON.parse(content);
472
- if (!pkg.scripts) {
473
- pkg.scripts = {};
474
- }
551
+ // Add devDependency
552
+ pkg.devDependencies = pkg.devDependencies || {};
553
+ pkg.devDependencies['@choochmeque/tauri-windows-bundle'] = `^${getPackageVersion()}`;
554
+ // Add script
555
+ pkg.scripts = pkg.scripts || {};
475
556
  if (!pkg.scripts['tauri:windows:build']) {
476
557
  pkg.scripts['tauri:windows:build'] = 'tauri-windows-bundle build';
477
- fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2) + '\n');
478
558
  }
559
+ fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2) + '\n');
560
+ console.log(' Updated package.json with devDependency and build script');
479
561
  }
480
562
  catch (error) {
481
563
  console.log(` Warning: Could not update package.json: ${error instanceof Error ? error.message : error}`);
@@ -1505,4 +1587,4 @@ async function extensionRemove(type, name, options) {
1505
1587
  }
1506
1588
  }
1507
1589
 
1508
- export { DEFAULT_CAPABILITIES, DEFAULT_MIN_WINDOWS_VERSION, DEFAULT_RUNNER, 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 };
1590
+ export { DEFAULT_CAPABILITIES, DEFAULT_MIN_WINDOWS_VERSION, DEFAULT_RUNNER, 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, getPackageVersion, getWindowsDir, init, prepareAppxContent, readBundleConfig$1 as readBundleConfig, readTauriConfig, toFourPartVersion };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@choochmeque/tauri-windows-bundle",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "MSIX packaging tool for Tauri apps - Windows Store ready bundles",
5
5
  "type": "module",
6
6
  "bin": {
@@ -28,7 +28,8 @@
28
28
  ],
29
29
  "dependencies": {
30
30
  "commander": "^14.0.2",
31
- "glob": "^13.0.0"
31
+ "glob": "^13.0.0",
32
+ "jimp": "^1.6.0"
32
33
  },
33
34
  "devDependencies": {
34
35
  "@eslint/js": "^9.0.0",
@@ -37,11 +38,11 @@
37
38
  "@types/node": "^25.0.3",
38
39
  "@vitest/coverage-v8": "^2.0.0",
39
40
  "eslint": "^9.0.0",
40
- "typescript-eslint": "^8.0.0",
41
41
  "prettier": "^3.0.0",
42
42
  "rollup": "^4.0.0",
43
43
  "tslib": "^2.6.0",
44
44
  "typescript": "^5.3.3",
45
+ "typescript-eslint": "^8.0.0",
45
46
  "vitest": "^2.0.0"
46
47
  },
47
48
  "scripts": {