@bobfrankston/msger 0.1.325 → 0.1.327

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/index.d.ts CHANGED
@@ -1 +1 @@
1
- export { showMessageBox, showService, ServiceHandle, MessageBoxOptions, MessageBoxResult } from "./shower.js";
1
+ export { showMessageBox, showService, ServiceHandle, MessageBoxOptions, MessageBoxResult, setAppName } from "./shower.js";
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // Export showMessageBox and types for use as a library
2
- export { showMessageBox, showService, ServiceHandle } from "./shower.js";
2
+ export { showMessageBox, showService, ServiceHandle, setAppName } from "./shower.js";
3
3
  // If run directly (e.g., `node .` or `node index.js`), run the CLI
4
4
  // @ts-ignore - import.meta.main is available in Node.js 20+
5
5
  if (import.meta.main) {
@@ -76,6 +76,20 @@ if (fs.existsSync(srcBinary)) {
76
76
  }
77
77
  }
78
78
 
79
+ // Step 2b: Create/update a stable-name hardlink so the launcher always uses
80
+ // the same path. Taskbar pins and AUMID grouping depend on a fixed exe path.
81
+ // Hardlink shares inode with the timestamped copy — deleting the old link
82
+ // doesn't affect a running process (it holds its own file handle).
83
+ const stableLink = path.join(userBinDir, `${baseName}${ext}`);
84
+ try {
85
+ // Remove old link (may point to previous version)
86
+ try { fs.unlinkSync(stableLink); } catch { /* didn't exist */ }
87
+ fs.linkSync(versionedBinary, stableLink);
88
+ } catch (e) {
89
+ // Hardlink failed (cross-device, locked, etc.) — copy as fallback
90
+ try { fs.copyFileSync(versionedBinary, stableLink); } catch { /* */ }
91
+ }
92
+
79
93
  // Step 3a: Clean up old timestamped copies in the user bin dir (keep the one
80
94
  // we just created). Locked copies are silently skipped — they get cleaned up
81
95
  // on the next install once their owning process has exited.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/msger",
3
- "version": "0.1.325",
3
+ "version": "0.1.327",
4
4
  "description": "Fast, lightweight, cross-platform message box - Rust-powered alternative to msgview",
5
5
  "type": "module",
6
6
  "main": "./index.js",
package/shower.d.ts CHANGED
@@ -61,6 +61,9 @@ export interface MessageBoxResult {
61
61
  autoSize: boolean;
62
62
  };
63
63
  }
64
+ /** Set the app name used for the per-user binary directory.
65
+ * Call before showService/showMessageBox — e.g. `setAppName("mailx")`. */
66
+ export declare function setAppName(name: string): void;
64
67
  /**
65
68
  * Show a message box dialog using native Rust implementation (extended version)
66
69
  * @param options Message box configuration
package/shower.js CHANGED
@@ -53,15 +53,22 @@ export function closeMessageBox(pid) {
53
53
  * exe inside it is locked. Keeping timestamped copies here means npm only
54
54
  * manages the stable `msgernative.exe` (which isn't the one being executed),
55
55
  * so it's never locked. */
56
+ /** App name for per-user bin dir. Set via `setAppName()` so each app using
57
+ * msger gets its own binary path (%LOCALAPPDATA%\<appName>\bin\) and thus
58
+ * its own taskbar identity. Defaults to "msger" for standalone use. */
59
+ let _appName = "msger";
60
+ /** Set the app name used for the per-user binary directory.
61
+ * Call before showService/showMessageBox — e.g. `setAppName("mailx")`. */
62
+ export function setAppName(name) { _appName = name; }
56
63
  function getUserBinDir() {
57
64
  const isWindows = platform() === 'win32';
58
65
  if (isWindows) {
59
66
  const base = process.env.LOCALAPPDATA || path.join(process.env.USERPROFILE || '.', 'AppData', 'Local');
60
- return path.join(base, 'msger', 'bin');
67
+ return path.join(base, _appName, 'bin');
61
68
  }
62
69
  const xdg = process.env.XDG_DATA_HOME;
63
70
  const base = xdg || path.join(process.env.HOME || '.', '.local', 'share');
64
- return path.join(base, 'msger', 'bin');
71
+ return path.join(base, _appName, 'bin');
65
72
  }
66
73
  /** Resolve the native binary path. Prefers a timestamped copy in the per-user
67
74
  * bin dir (immune to npm-upgrade locks). Falls back to the package's bundled
@@ -86,8 +93,13 @@ function resolveBinaryPath() {
86
93
  baseName = 'msgernative';
87
94
  ext = '';
88
95
  }
96
+ // Prefer the stable-name hardlink in the user dir — same path every time,
97
+ // so taskbar pins and AUMID grouping don't break on updates.
98
+ const stableLink = path.join(userBinDir, `${baseName}${ext}`);
99
+ if (fs.existsSync(stableLink))
100
+ return stableLink;
89
101
  const pattern = new RegExp(`^${baseName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}-(\\d+)${ext.replace('.', '\\.')}$`);
90
- // Prefer per-user timestamped copy
102
+ // Fallback: per-user timestamped copy (pre-hardlink installs)
91
103
  try {
92
104
  const matches = fs.readdirSync(userBinDir)
93
105
  .filter(f => pattern.test(f))