@bobfrankston/msger 0.1.414 → 0.1.415
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 +1 -1
- package/cli.js +1 -1
- package/msger-native/bin/msgernative-linux-aarch64 +0 -0
- package/msger-native/bin/msgernative.exe +0 -0
- package/msger-native/builder/postinstall.js +48 -13
- package/package.json +1 -1
- package/shower.d.ts +18 -4
- package/shower.js +72 -14
package/README.md
CHANGED
|
@@ -327,7 +327,7 @@ Options:
|
|
|
327
327
|
-debug, --debug Return debug info (HTML, size, autoSize) in result
|
|
328
328
|
-render, --render [file] Render the page to a bitmap instead of displaying it.
|
|
329
329
|
With <file>, writes the image (.png/.jpg/.bmp by extension);
|
|
330
|
-
without, returns it base64 in result.render. [Windows
|
|
330
|
+
without, returns it base64 in result.render. [Windows, Linux/Pi]
|
|
331
331
|
-noshow, --noshow Don't display the window. With -save, exits after saving.
|
|
332
332
|
Otherwise the WebView still loads + runs scripts so a page
|
|
333
333
|
can post a result via window.ipc.postMessage; only the
|
package/cli.js
CHANGED
|
@@ -52,7 +52,7 @@ Options:
|
|
|
52
52
|
appears on screen. With <file>, writes the image there (format
|
|
53
53
|
from extension: .png/.jpg/.bmp) and the JSON result carries
|
|
54
54
|
{render:{path,width,height,format}}. Without <file>, the image
|
|
55
|
-
is returned base64 in {render:{data,...}}. [Windows
|
|
55
|
+
is returned base64 in {render:{data,...}}. [Windows, Linux/Pi]
|
|
56
56
|
-noshow Don't display the window. With -save, also exits after saving.
|
|
57
57
|
Otherwise the WebView still loads and runs scripts (so a page can
|
|
58
58
|
query the DOM/CSS and post a result via window.ipc.postMessage)
|
|
Binary file
|
|
Binary file
|
|
@@ -229,19 +229,51 @@ if (!isWindows && process.platform === "linux") {
|
|
|
229
229
|
libDirs.some(dir => { try { return fs.existsSync(path.join(dir, so)); } catch { return false; } })
|
|
230
230
|
);
|
|
231
231
|
|
|
232
|
-
|
|
232
|
+
// Emoji font: NOT needed for msger to start, but without one every emoji in
|
|
233
|
+
// a hosted page draws as a tofu box — Linux browsers get emoji from system
|
|
234
|
+
// fonts and nothing bundles them (Bob 2026-08-01: the wallclock app's 📋 and
|
|
235
|
+
// 🧃 were empty boxes on a Pi with zero emoji fonts). Treated as a
|
|
236
|
+
// recommended dependency: installed alongside, never fatal.
|
|
237
|
+
// Keep in sync with hasEmojiFont() in shower.ts.
|
|
238
|
+
const haveEmojiFont = () => {
|
|
239
|
+
// fontconfig is authoritative when present. Probe U+1F4CB CLIPBOARD, not
|
|
240
|
+
// the obvious U+1F600 GRINNING FACE: DejaVu (on every Debian box) covers
|
|
241
|
+
// 1F600 without being an emoji font, so that probe says "present" on a
|
|
242
|
+
// machine that draws every real emoji as tofu. 1F4CB is in every emoji
|
|
243
|
+
// font (Unicode 6.0) and in none of the generic text fonts.
|
|
244
|
+
try {
|
|
245
|
+
const fc = spawnSync("fc-list", [":charset=1f4cb", "family"], { encoding: "utf8" });
|
|
246
|
+
if (fc.status === 0) return fc.stdout.trim().length > 0;
|
|
247
|
+
} catch { /* no fontconfig — fall through to a filename scan */ }
|
|
248
|
+
const fontDirs = [
|
|
249
|
+
"/usr/share/fonts/truetype/noto", "/usr/share/fonts/truetype",
|
|
250
|
+
"/usr/share/fonts/opentype", "/usr/share/fonts",
|
|
251
|
+
path.join(process.env.HOME || "/root", ".local/share/fonts"),
|
|
252
|
+
];
|
|
253
|
+
return fontDirs.some(dir => {
|
|
254
|
+
try { return fs.readdirSync(dir).some(f => /emoji/i.test(f)); } catch { return false; }
|
|
255
|
+
});
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const wanted = [];
|
|
259
|
+
if (!haveWebkit()) wanted.push({ pkg: "libwebkit2gtk-4.1-0", what: "WebKitGTK runtime", required: true });
|
|
260
|
+
if (!haveEmojiFont()) wanted.push({ pkg: "fonts-noto-color-emoji", what: "emoji font", required: false });
|
|
261
|
+
|
|
262
|
+
if (wanted.length) {
|
|
233
263
|
const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
|
|
234
264
|
const hasAptGet = fs.existsSync("/usr/bin/apt-get");
|
|
235
265
|
// `sudo -n true` succeeds only when sudo needs no password.
|
|
236
266
|
const sudoNoPassword = !isRoot && hasAptGet &&
|
|
237
267
|
spawnSync("sudo", ["-n", "true"], { stdio: "ignore" }).status === 0;
|
|
238
268
|
const canInstall = hasAptGet && (isRoot || sudoNoPassword) && process.env.MSGER_SKIP_DEPS !== "1";
|
|
269
|
+
const names = wanted.map(w => w.pkg);
|
|
270
|
+
const missingRequired = wanted.some(w => w.required);
|
|
239
271
|
|
|
240
272
|
if (canInstall) {
|
|
241
273
|
const prefix = isRoot ? [] : ["sudo", "-n"];
|
|
242
|
-
const args = [...prefix, "apt-get", "install", "-y",
|
|
274
|
+
const args = [...prefix, "apt-get", "install", "-y", ...names];
|
|
243
275
|
console.log("");
|
|
244
|
-
console.log(
|
|
276
|
+
console.log(` msger: missing ${wanted.map(w => w.what).join(" + ")} — installing now:`);
|
|
245
277
|
console.log(` ${args.join(" ")}`);
|
|
246
278
|
const run = (a) => spawnSync(a[0], a.slice(1), {
|
|
247
279
|
stdio: "inherit",
|
|
@@ -256,27 +288,30 @@ if (!isWindows && process.platform === "linux") {
|
|
|
256
288
|
res = run(args);
|
|
257
289
|
}
|
|
258
290
|
if (res.status === 0 && haveWebkit()) {
|
|
259
|
-
console.log(" msger:
|
|
291
|
+
console.log(" msger: dependencies installed — msger is ready to run.");
|
|
260
292
|
console.log("");
|
|
261
293
|
} else {
|
|
262
294
|
console.log("");
|
|
263
|
-
console.log(" msger: WARNING — automatic install
|
|
264
|
-
console.log(" Run this by hand
|
|
295
|
+
console.log(" msger: WARNING — automatic dependency install failed.");
|
|
296
|
+
console.log(" Run this by hand:");
|
|
265
297
|
console.log("");
|
|
266
|
-
console.log(
|
|
298
|
+
console.log(` sudo apt install ${names.join(" ")}`);
|
|
267
299
|
console.log("");
|
|
268
300
|
}
|
|
269
301
|
} else {
|
|
270
302
|
console.log("");
|
|
271
|
-
console.log(
|
|
272
|
-
|
|
273
|
-
|
|
303
|
+
console.log(` msger: ${missingRequired ? "WARNING — " : "note: "}missing ${wanted.map(w => w.what).join(" + ")}.`);
|
|
304
|
+
if (missingRequired) {
|
|
305
|
+
console.log(" msger renders with the system webview and cannot");
|
|
306
|
+
console.log(" start without it.");
|
|
307
|
+
} else {
|
|
308
|
+
console.log(" msger runs, but emoji in hosted pages will show");
|
|
309
|
+
console.log(" as empty boxes until a font provides them.");
|
|
310
|
+
}
|
|
274
311
|
console.log("");
|
|
275
|
-
console.log(
|
|
312
|
+
console.log(` sudo apt install ${names.join(" ")}`);
|
|
276
313
|
console.log(" or: msger --install-deps");
|
|
277
314
|
console.log("");
|
|
278
|
-
console.log(" (runtime only; -dev is needed just to build msger)");
|
|
279
|
-
console.log("");
|
|
280
315
|
}
|
|
281
316
|
}
|
|
282
317
|
}
|
package/package.json
CHANGED
package/shower.d.ts
CHANGED
|
@@ -95,10 +95,24 @@ export declare function setAppName(name: string): void;
|
|
|
95
95
|
* provision so Rust's window icon search picks it up. Per-call `icon` in
|
|
96
96
|
* `MessageBoxOptions` still takes precedence. */
|
|
97
97
|
export declare function setAppIcon(iconPath: string): void;
|
|
98
|
-
/** The right
|
|
99
|
-
*
|
|
100
|
-
* install on a machine that only runs it.
|
|
101
|
-
|
|
98
|
+
/** The right packages for this distro. Only runtime pieces — building msger
|
|
99
|
+
* additionally needs the -dev package, which is not msger's business to
|
|
100
|
+
* install on a machine that only runs it.
|
|
101
|
+
*
|
|
102
|
+
* Two dependencies, different weight:
|
|
103
|
+
* - WebKitGTK is *required*: msger renders with the system webview and its
|
|
104
|
+
* binary won't even load without it.
|
|
105
|
+
* - An emoji font is *recommended*: msger runs fine, but every emoji in a
|
|
106
|
+
* hosted page draws as a tofu box, since Linux browsers take emoji from
|
|
107
|
+
* system fonts and nothing bundles them. */
|
|
108
|
+
export declare function webkitInstallCommand(missing?: {
|
|
109
|
+
webkit: boolean;
|
|
110
|
+
emoji: boolean;
|
|
111
|
+
}): string;
|
|
112
|
+
/** Does any installed font provide emoji? fontconfig is authoritative when it
|
|
113
|
+
* is present; otherwise fall back to looking for a font file with "emoji" in
|
|
114
|
+
* the name. Keep in sync with the copy in msger-native/builder/postinstall.js. */
|
|
115
|
+
export declare function hasEmojiFont(): boolean;
|
|
102
116
|
/** `msger --install-deps` — install the WebKitGTK runtime msger links against.
|
|
103
117
|
*
|
|
104
118
|
* Deliberately NOT done from postinstall: an npm script that shells out to
|
package/shower.js
CHANGED
|
@@ -86,20 +86,70 @@ function missingWebkitHint(stderr) {
|
|
|
86
86
|
' msger --install-deps\n' +
|
|
87
87
|
'(runtime only — the -dev package is needed just for building msger.)';
|
|
88
88
|
}
|
|
89
|
-
/** The right
|
|
90
|
-
*
|
|
91
|
-
* install on a machine that only runs it.
|
|
92
|
-
|
|
89
|
+
/** The right packages for this distro. Only runtime pieces — building msger
|
|
90
|
+
* additionally needs the -dev package, which is not msger's business to
|
|
91
|
+
* install on a machine that only runs it.
|
|
92
|
+
*
|
|
93
|
+
* Two dependencies, different weight:
|
|
94
|
+
* - WebKitGTK is *required*: msger renders with the system webview and its
|
|
95
|
+
* binary won't even load without it.
|
|
96
|
+
* - An emoji font is *recommended*: msger runs fine, but every emoji in a
|
|
97
|
+
* hosted page draws as a tofu box, since Linux browsers take emoji from
|
|
98
|
+
* system fonts and nothing bundles them. */
|
|
99
|
+
export function webkitInstallCommand(missing) {
|
|
100
|
+
const need = missing ?? { webkit: !hasWebkitRuntime(), emoji: !hasEmojiFont() };
|
|
93
101
|
const has = (cmd) => fs.existsSync(`/usr/bin/${cmd}`) || fs.existsSync(`/bin/${cmd}`);
|
|
102
|
+
const pick = (mgr) => {
|
|
103
|
+
const names = {
|
|
104
|
+
apt: { webkit: 'libwebkit2gtk-4.1-0', emoji: 'fonts-noto-color-emoji' },
|
|
105
|
+
dnf: { webkit: 'webkit2gtk4.1', emoji: 'google-noto-emoji-color-fonts' },
|
|
106
|
+
pacman: { webkit: 'webkit2gtk-4.1', emoji: 'noto-fonts-emoji' },
|
|
107
|
+
zypper: { webkit: 'libwebkit2gtk-4_1-0', emoji: 'noto-coloremoji-fonts' },
|
|
108
|
+
};
|
|
109
|
+
const verb = { apt: 'apt install', dnf: 'dnf install', pacman: 'pacman -S', zypper: 'zypper install' }[mgr];
|
|
110
|
+
const pkgs = [need.webkit && names[mgr].webkit, need.emoji && names[mgr].emoji].filter(Boolean);
|
|
111
|
+
return `sudo ${verb} ${pkgs.join(' ')}`;
|
|
112
|
+
};
|
|
94
113
|
if (has('apt'))
|
|
95
|
-
return '
|
|
114
|
+
return pick('apt');
|
|
96
115
|
if (has('dnf'))
|
|
97
|
-
return '
|
|
116
|
+
return pick('dnf');
|
|
98
117
|
if (has('pacman'))
|
|
99
|
-
return '
|
|
118
|
+
return pick('pacman');
|
|
100
119
|
if (has('zypper'))
|
|
101
|
-
return '
|
|
102
|
-
return 'install the WebKitGTK 4.1 runtime for your distribution';
|
|
120
|
+
return pick('zypper');
|
|
121
|
+
return 'install the WebKitGTK 4.1 runtime (and an emoji font) for your distribution';
|
|
122
|
+
}
|
|
123
|
+
/** Does any installed font provide emoji? fontconfig is authoritative when it
|
|
124
|
+
* is present; otherwise fall back to looking for a font file with "emoji" in
|
|
125
|
+
* the name. Keep in sync with the copy in msger-native/builder/postinstall.js. */
|
|
126
|
+
export function hasEmojiFont() {
|
|
127
|
+
if (platform() !== 'linux')
|
|
128
|
+
return true;
|
|
129
|
+
try {
|
|
130
|
+
// U+1F4CB CLIPBOARD, not the obvious U+1F600 GRINNING FACE: DejaVu (on
|
|
131
|
+
// every Debian box) covers 1F600 without being an emoji font at all, so
|
|
132
|
+
// probing it reports "present" on a machine that draws every real emoji
|
|
133
|
+
// as tofu. 1F4CB is old enough (Unicode 6.0) that every emoji font has
|
|
134
|
+
// it and absent from the generic text fonts — a clean discriminator.
|
|
135
|
+
const fc = spawnSync('fc-list', [':charset=1f4cb', 'family'], { encoding: 'utf8' });
|
|
136
|
+
if (fc.status === 0)
|
|
137
|
+
return (fc.stdout ?? '').trim().length > 0;
|
|
138
|
+
}
|
|
139
|
+
catch { /* no fontconfig — fall through */ }
|
|
140
|
+
const fontDirs = [
|
|
141
|
+
'/usr/share/fonts/truetype/noto', '/usr/share/fonts/truetype',
|
|
142
|
+
'/usr/share/fonts/opentype', '/usr/share/fonts',
|
|
143
|
+
path.join(process.env.HOME || '/root', '.local/share/fonts'),
|
|
144
|
+
];
|
|
145
|
+
return fontDirs.some(dir => {
|
|
146
|
+
try {
|
|
147
|
+
return fs.readdirSync(dir).some(f => /emoji/i.test(f));
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
});
|
|
103
153
|
}
|
|
104
154
|
/** `msger --install-deps` — install the WebKitGTK runtime msger links against.
|
|
105
155
|
*
|
|
@@ -115,11 +165,14 @@ export function installLinuxDeps() {
|
|
|
115
165
|
console.error('--install-deps is for Linux; nothing to install on ' + platform());
|
|
116
166
|
return 1;
|
|
117
167
|
}
|
|
118
|
-
|
|
119
|
-
|
|
168
|
+
const missing = { webkit: !hasWebkitRuntime(), emoji: !hasEmojiFont() };
|
|
169
|
+
if (!missing.webkit && !missing.emoji) {
|
|
170
|
+
console.log('WebKitGTK runtime and an emoji font are both present — nothing to do.');
|
|
120
171
|
return 0;
|
|
121
172
|
}
|
|
122
|
-
|
|
173
|
+
console.log(`Missing: ${[missing.webkit && 'WebKitGTK runtime', missing.emoji && 'emoji font']
|
|
174
|
+
.filter(Boolean).join(', ')}`);
|
|
175
|
+
const command = webkitInstallCommand(missing);
|
|
123
176
|
if (!command.startsWith('sudo ')) {
|
|
124
177
|
console.error(`msger could not identify this distribution's package manager.\nPlease ${command}.`);
|
|
125
178
|
return 1;
|
|
@@ -134,11 +187,16 @@ export function installLinuxDeps() {
|
|
|
134
187
|
}
|
|
135
188
|
if (res.status !== 0)
|
|
136
189
|
return res.status ?? 1;
|
|
137
|
-
if (!hasWebkitRuntime()) {
|
|
190
|
+
if (missing.webkit && !hasWebkitRuntime()) {
|
|
138
191
|
console.error('Install reported success but the WebKitGTK runtime is still not visible.');
|
|
139
192
|
return 1;
|
|
140
193
|
}
|
|
141
|
-
|
|
194
|
+
// The emoji font is best-effort: say so if it didn't take, but don't fail —
|
|
195
|
+
// msger runs fine without it, pages just lose their emoji.
|
|
196
|
+
if (missing.emoji && !hasEmojiFont()) {
|
|
197
|
+
console.warn('Note: an emoji font still is not visible; emoji in pages may show as boxes.');
|
|
198
|
+
}
|
|
199
|
+
console.log('Dependencies installed — msger is ready to run.');
|
|
142
200
|
return 0;
|
|
143
201
|
}
|
|
144
202
|
/** Is the WebKitGTK runtime msger links against present? Mirrors the check in
|