@bobfrankston/msger 0.1.319 → 0.1.321
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.
|
Binary file
|
|
Binary file
|
|
@@ -2,9 +2,14 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* msger-native postinstall:
|
|
4
4
|
* 1. Copy binary from target/release/ to bin/ (if newer — after cargo build)
|
|
5
|
-
* 2. Create timestamped copy
|
|
6
|
-
*
|
|
5
|
+
* 2. Create timestamped copy in the PER-USER bin dir (not node_modules)
|
|
6
|
+
* so the locked previous-version exe doesn't block npm's aside-dir cleanup
|
|
7
|
+
* on upgrade — npm only manages the stable msgernative.exe in bin/.
|
|
8
|
+
* 3. Clean up old timestamped copies in the user dir (skip if locked)
|
|
7
9
|
* 4. Set binary permissions on Linux/Mac
|
|
10
|
+
*
|
|
11
|
+
* NOTE: keep this in sync with `getUserBinDir()` in shower.ts — same path
|
|
12
|
+
* convention so the launcher finds what postinstall just wrote.
|
|
8
13
|
*/
|
|
9
14
|
import fs from "fs";
|
|
10
15
|
import path from "path";
|
|
@@ -32,6 +37,18 @@ if (isWindows) {
|
|
|
32
37
|
const srcBinary = path.join(binDir, `${baseName}${ext}`);
|
|
33
38
|
const buildBinary = path.join(nativeDir, "target", "release", `${baseName}${ext}`);
|
|
34
39
|
|
|
40
|
+
function getUserBinDir() {
|
|
41
|
+
if (isWindows) {
|
|
42
|
+
const base = process.env.LOCALAPPDATA || path.join(process.env.USERPROFILE || ".", "AppData", "Local");
|
|
43
|
+
return path.join(base, "msger", "bin");
|
|
44
|
+
}
|
|
45
|
+
const xdg = process.env.XDG_DATA_HOME;
|
|
46
|
+
const base = xdg || path.join(process.env.HOME || ".", ".local", "share");
|
|
47
|
+
return path.join(base, "msger", "bin");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const userBinDir = getUserBinDir();
|
|
51
|
+
|
|
35
52
|
// Step 1: Copy from target/release/ → bin/ if build output is newer
|
|
36
53
|
if (fs.existsSync(buildBinary)) {
|
|
37
54
|
const buildTime = fs.statSync(buildBinary).mtimeMs;
|
|
@@ -47,9 +64,10 @@ if (fs.existsSync(buildBinary)) {
|
|
|
47
64
|
}
|
|
48
65
|
}
|
|
49
66
|
|
|
50
|
-
// Step 2: Create timestamped copy
|
|
67
|
+
// Step 2: Create timestamped copy in the user bin dir (NOT node_modules)
|
|
68
|
+
try { fs.mkdirSync(userBinDir, { recursive: true }); } catch { /* exists */ }
|
|
51
69
|
const stamp = Date.now();
|
|
52
|
-
const versionedBinary = path.join(
|
|
70
|
+
const versionedBinary = path.join(userBinDir, `${baseName}-${stamp}${ext}`);
|
|
53
71
|
if (fs.existsSync(srcBinary)) {
|
|
54
72
|
try {
|
|
55
73
|
fs.copyFileSync(srcBinary, versionedBinary);
|
|
@@ -58,12 +76,25 @@ if (fs.existsSync(srcBinary)) {
|
|
|
58
76
|
}
|
|
59
77
|
}
|
|
60
78
|
|
|
61
|
-
// Step
|
|
79
|
+
// Step 3a: Clean up old timestamped copies in the user bin dir (keep the one
|
|
80
|
+
// we just created). Locked copies are silently skipped — they get cleaned up
|
|
81
|
+
// on the next install once their owning process has exited.
|
|
82
|
+
const pattern = new RegExp(`^${baseName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}-(\\d+)${ext.replace('.', '\\.')}$`);
|
|
62
83
|
try {
|
|
63
|
-
const
|
|
64
|
-
for (const f of fs.readdirSync(binDir)) {
|
|
84
|
+
for (const f of fs.readdirSync(userBinDir)) {
|
|
65
85
|
if (f.match(pattern) && f !== path.basename(versionedBinary)) {
|
|
66
|
-
try { fs.unlinkSync(path.join(
|
|
86
|
+
try { fs.unlinkSync(path.join(userBinDir, f)); } catch { /* locked */ }
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} catch { /* user dir didn't exist or unreadable */ }
|
|
90
|
+
|
|
91
|
+
// Step 3b: Migrate-and-clean any stale timestamped copies still living inside
|
|
92
|
+
// node_modules from older installs. They serve no purpose now and may be the
|
|
93
|
+
// EPERM blocker on upgrade.
|
|
94
|
+
try {
|
|
95
|
+
for (const f of fs.readdirSync(binDir)) {
|
|
96
|
+
if (f.match(pattern)) {
|
|
97
|
+
try { fs.unlinkSync(path.join(binDir, f)); } catch { /* locked */ }
|
|
67
98
|
}
|
|
68
99
|
}
|
|
69
100
|
} catch { /* ignore */ }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/msger",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.321",
|
|
4
4
|
"description": "Fast, lightweight, cross-platform message box - Rust-powered alternative to msgview",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -25,8 +25,7 @@
|
|
|
25
25
|
"prerelease:local": "git add -A && (git diff-index --quiet HEAD || git commit -m \"Pre-release commit\")",
|
|
26
26
|
"preversion": "npm run build:ts && npm run build:native && git add -A",
|
|
27
27
|
"release": "npm run prerelease:local && npm version patch && npm publish --quiet",
|
|
28
|
-
"installer": "npm run release && node utils/install-latest.ts"
|
|
29
|
-
"postversion": "git push && git push --tags"
|
|
28
|
+
"installer": "npm run release && node utils/install-latest.ts"
|
|
30
29
|
},
|
|
31
30
|
"keywords": [
|
|
32
31
|
"message-box",
|
package/shower.js
CHANGED
|
@@ -47,12 +47,31 @@ export function closeMessageBox(pid) {
|
|
|
47
47
|
* @param options Message box configuration
|
|
48
48
|
* @returns MessageBoxHandle with result promise
|
|
49
49
|
*/
|
|
50
|
-
/**
|
|
51
|
-
*
|
|
50
|
+
/** Per-user bin dir for timestamped exe copies. Storing them OUTSIDE
|
|
51
|
+
* node_modules avoids npm's EPERM cleanup warnings on upgrade — npm tries to
|
|
52
|
+
* delete the previous package's `.msger-<rand>/` aside-dir but the running
|
|
53
|
+
* exe inside it is locked. Keeping timestamped copies here means npm only
|
|
54
|
+
* manages the stable `msgernative.exe` (which isn't the one being executed),
|
|
55
|
+
* so it's never locked. */
|
|
56
|
+
function getUserBinDir() {
|
|
57
|
+
const isWindows = platform() === 'win32';
|
|
58
|
+
if (isWindows) {
|
|
59
|
+
const base = process.env.LOCALAPPDATA || path.join(process.env.USERPROFILE || '.', 'AppData', 'Local');
|
|
60
|
+
return path.join(base, 'msger', 'bin');
|
|
61
|
+
}
|
|
62
|
+
const xdg = process.env.XDG_DATA_HOME;
|
|
63
|
+
const base = xdg || path.join(process.env.HOME || '.', '.local', 'share');
|
|
64
|
+
return path.join(base, 'msger', 'bin');
|
|
65
|
+
}
|
|
66
|
+
/** Resolve the native binary path. Prefers a timestamped copy in the per-user
|
|
67
|
+
* bin dir (immune to npm-upgrade locks). Falls back to the package's bundled
|
|
68
|
+
* unversioned binary when no per-user copy exists yet — first launch after a
|
|
69
|
+
* fresh install before postinstall has copied one out. */
|
|
52
70
|
function resolveBinaryPath() {
|
|
53
71
|
const isWindows = platform() === 'win32';
|
|
54
72
|
const arch = process.arch;
|
|
55
|
-
const
|
|
73
|
+
const pkgBinDir = path.join(import.meta.dirname, 'msger-native', 'bin');
|
|
74
|
+
const userBinDir = getUserBinDir();
|
|
56
75
|
let baseName;
|
|
57
76
|
let ext;
|
|
58
77
|
if (isWindows) {
|
|
@@ -67,18 +86,29 @@ function resolveBinaryPath() {
|
|
|
67
86
|
baseName = 'msgernative';
|
|
68
87
|
ext = '';
|
|
69
88
|
}
|
|
70
|
-
|
|
89
|
+
const pattern = new RegExp(`^${baseName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}-(\\d+)${ext.replace('.', '\\.')}$`);
|
|
90
|
+
// Prefer per-user timestamped copy
|
|
91
|
+
try {
|
|
92
|
+
const matches = fs.readdirSync(userBinDir)
|
|
93
|
+
.filter(f => pattern.test(f))
|
|
94
|
+
.sort()
|
|
95
|
+
.reverse();
|
|
96
|
+
if (matches.length > 0)
|
|
97
|
+
return path.join(userBinDir, matches[0]);
|
|
98
|
+
}
|
|
99
|
+
catch { /* user dir doesn't exist yet — fall through */ }
|
|
100
|
+
// Legacy: timestamped copies inside the package (older installs that ran
|
|
101
|
+
// the old postinstall). Still honored so a half-migrated tree keeps working.
|
|
71
102
|
try {
|
|
72
|
-
const
|
|
73
|
-
const matches = fs.readdirSync(binDir)
|
|
103
|
+
const matches = fs.readdirSync(pkgBinDir)
|
|
74
104
|
.filter(f => pattern.test(f))
|
|
75
105
|
.sort()
|
|
76
106
|
.reverse();
|
|
77
107
|
if (matches.length > 0)
|
|
78
|
-
return path.join(
|
|
108
|
+
return path.join(pkgBinDir, matches[0]);
|
|
79
109
|
}
|
|
80
110
|
catch { /* fall through */ }
|
|
81
|
-
return path.join(
|
|
111
|
+
return path.join(pkgBinDir, `${baseName}${ext}`);
|
|
82
112
|
}
|
|
83
113
|
function createMessageBoxHandle(options) {
|
|
84
114
|
const binaryPath = resolveBinaryPath();
|
|
Binary file
|