latex-stickies 1.3.6 → 1.3.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 +2 -0
- package/bin/latex-stickies.js +21 -10
- package/package.json +2 -1
- package/scripts/brand-electron.js +41 -13
- package/src/main.js +26 -10
- package/src/store.js +10 -1
package/README.md
CHANGED
|
@@ -146,6 +146,7 @@ npm test # unit suites
|
|
|
146
146
|
npm run vendor # rebuild the bundled libraries
|
|
147
147
|
npm run icon # rebuild the app icon from assets/icon-master.png
|
|
148
148
|
npm run demo # re-record assets/demo.gif from the real app (needs ffmpeg)
|
|
149
|
+
npm run verify # install the packed tarball and check what a user gets
|
|
149
150
|
npm run dist # build a macOS .app and .dmg
|
|
150
151
|
```
|
|
151
152
|
|
|
@@ -158,6 +159,7 @@ node scripts/smoke.js --lifecycle # closing every note behaves per platform
|
|
|
158
159
|
node scripts/render-check.js # the first-run note renders correctly
|
|
159
160
|
node scripts/ghost-check.js # autocomplete suggests, and Tab accepts
|
|
160
161
|
node scripts/snapshot-check.js # a long note is captured whole
|
|
162
|
+
node scripts/verify-install.js # the install path, end to end (macOS)
|
|
161
163
|
```
|
|
162
164
|
|
|
163
165
|
The renderer loads over `file://` under a strict content-security policy, so
|
package/bin/latex-stickies.js
CHANGED
|
@@ -10,8 +10,29 @@
|
|
|
10
10
|
const { spawn } = require('child_process');
|
|
11
11
|
const path = require('path');
|
|
12
12
|
|
|
13
|
+
// Name the Electron shell before resolving it, not only at install time.
|
|
14
|
+
//
|
|
15
|
+
// postinstall scripts are increasingly blocked -- npm warns about them by
|
|
16
|
+
// default now, and plenty of people and companies set ignore-scripts -- and a
|
|
17
|
+
// user who installs with them off gets "Electron" in their Dock. Doing it here
|
|
18
|
+
// as well means the name is right by the time macOS reads the bundle, whatever
|
|
19
|
+
// happened during the install. It returns immediately once done.
|
|
20
|
+
//
|
|
21
|
+
// Strictly before require('electron'): branding renames the executable and
|
|
22
|
+
// rewrites the path.txt that require reads, so a path captured first points at
|
|
23
|
+
// a file that no longer exists and the launch fails with ENOENT. That cost a
|
|
24
|
+
// release -- every first launch after upgrading failed, and only the second
|
|
25
|
+
// worked.
|
|
26
|
+
try {
|
|
27
|
+
require('../scripts/brand-electron.js');
|
|
28
|
+
} catch (_) { /* cosmetic: never block a launch over the name */ }
|
|
29
|
+
|
|
13
30
|
let electron;
|
|
14
31
|
try {
|
|
32
|
+
// Branding resolved the electron module itself, so it is already in Node's
|
|
33
|
+
// module cache holding the path from before the rename. Drop it and read it
|
|
34
|
+
// again, or the launch spawns a file that no longer exists.
|
|
35
|
+
delete require.cache[require.resolve('electron')];
|
|
15
36
|
electron = require('electron');
|
|
16
37
|
} catch (_) {
|
|
17
38
|
console.error(
|
|
@@ -21,16 +42,6 @@ try {
|
|
|
21
42
|
process.exit(1);
|
|
22
43
|
}
|
|
23
44
|
|
|
24
|
-
// Name the Electron shell before launching it, not only at install time.
|
|
25
|
-
// postinstall scripts are increasingly blocked -- npm warns about them by
|
|
26
|
-
// default now, and plenty of people and companies set ignore-scripts -- and a
|
|
27
|
-
// user who installs with them off gets "Electron" in their Dock. Doing it here
|
|
28
|
-
// as well means the name is right by the time macOS reads the bundle, whatever
|
|
29
|
-
// happened during the install. It returns immediately once done.
|
|
30
|
-
try {
|
|
31
|
-
require('../scripts/brand-electron.js');
|
|
32
|
-
} catch (_) { /* cosmetic: never block a launch over the name */ }
|
|
33
|
-
|
|
34
45
|
const appDir = path.join(__dirname, '..');
|
|
35
46
|
const child = spawn(electron, [appDir, ...process.argv.slice(2)], {
|
|
36
47
|
detached: true,
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "latex-stickies",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.7",
|
|
4
4
|
"description": "Sticky notes for your desktop that render LaTeX and Markdown.",
|
|
5
5
|
"main": "src/main.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"start": "electron .",
|
|
8
8
|
"test": "node scripts/test.js",
|
|
9
|
+
"verify": "node scripts/verify-install.js",
|
|
9
10
|
"vendor": "node scripts/vendor.js",
|
|
10
11
|
"icon": "node scripts/make-icon.js",
|
|
11
12
|
"demo": "node scripts/make-demo.js",
|
|
@@ -49,6 +49,35 @@ function refreshLaunchServices(appPath) {
|
|
|
49
49
|
} catch (_) { /* the name is still right; only the cache is stale */ }
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Puts our icon in the bundle, and says whether it had to.
|
|
54
|
+
*
|
|
55
|
+
* The bundle icon is what macOS shows before the app is running -- in Finder,
|
|
56
|
+
* in Cmd-Tab, and in the Dock at launch -- so app.dock.setIcon() alone is not
|
|
57
|
+
* enough. Compared byte for byte rather than copied blindly, because a copy
|
|
58
|
+
* invalidates the signature and costs a re-sign every launch.
|
|
59
|
+
*/
|
|
60
|
+
function copyIcon(appPath) {
|
|
61
|
+
const icon = path.join(__dirname, '..', 'build', 'icon.icns');
|
|
62
|
+
const target = path.join(appPath, 'Contents', 'Resources', 'electron.icns');
|
|
63
|
+
if (!fs.existsSync(icon) || !fs.existsSync(target)) return false;
|
|
64
|
+
if (fs.readFileSync(icon).equals(fs.readFileSync(target))) return false;
|
|
65
|
+
fs.copyFileSync(icon, target);
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Re-signs the bundle. Required, not optional: any edit under Contents/
|
|
71
|
+
* invalidates the ad-hoc signature, and macOS refuses to launch a bundle whose
|
|
72
|
+
* signature does not match its contents.
|
|
73
|
+
*/
|
|
74
|
+
function resign(appPath) {
|
|
75
|
+
execFileSync('codesign', ['--force', '--deep', '--sign', '-', appPath], {
|
|
76
|
+
stdio: 'ignore',
|
|
77
|
+
});
|
|
78
|
+
execFileSync('codesign', ['--verify', appPath], { stdio: 'ignore' });
|
|
79
|
+
}
|
|
80
|
+
|
|
52
81
|
function main() {
|
|
53
82
|
if (process.platform !== 'darwin') return; // only macOS names apps this way
|
|
54
83
|
|
|
@@ -76,7 +105,16 @@ function main() {
|
|
|
76
105
|
if (read('CFBundleName') === NAME
|
|
77
106
|
&& read('CFBundleIdentifier') === APP_ID
|
|
78
107
|
&& fs.existsSync(binary)) {
|
|
79
|
-
//
|
|
108
|
+
// Named already, but the icon may still be an old one: someone who
|
|
109
|
+
// installed an earlier version has a bundle branded with that version's
|
|
110
|
+
// artwork, and every upgrade since has taken this path and left it there.
|
|
111
|
+
if (copyIcon(appPath)) {
|
|
112
|
+
resign(appPath);
|
|
113
|
+
refreshLaunchServices(appPath);
|
|
114
|
+
console.log('updated the icon on the Electron shell');
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
// Otherwise a wrong name in the Dock can only be a stale cache.
|
|
80
118
|
refreshLaunchServices(appPath);
|
|
81
119
|
// Say so rather than exiting in silence. A user reporting "the Dock still
|
|
82
120
|
// says Electron" needs to know whether the rename failed or whether they
|
|
@@ -118,18 +156,8 @@ function main() {
|
|
|
118
156
|
fs.writeFileSync(pathTxt, `Electron.app/Contents/MacOS/${NAME}`);
|
|
119
157
|
}
|
|
120
158
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const target = path.join(appPath, 'Contents', 'Resources', 'electron.icns');
|
|
124
|
-
if (fs.existsSync(icon) && fs.existsSync(target)) fs.copyFileSync(icon, target);
|
|
125
|
-
|
|
126
|
-
// Required: the edits above invalidate the ad-hoc signature, and macOS
|
|
127
|
-
// refuses to launch a bundle whose signature does not match its contents.
|
|
128
|
-
execFileSync('codesign', ['--force', '--deep', '--sign', '-', appPath], {
|
|
129
|
-
stdio: 'ignore',
|
|
130
|
-
});
|
|
131
|
-
execFileSync('codesign', ['--verify', appPath], { stdio: 'ignore' });
|
|
132
|
-
|
|
159
|
+
copyIcon(appPath);
|
|
160
|
+
resign(appPath);
|
|
133
161
|
refreshLaunchServices(appPath);
|
|
134
162
|
|
|
135
163
|
console.log(`named the Electron shell "${NAME}"`);
|
package/src/main.js
CHANGED
|
@@ -473,11 +473,23 @@ let quitting = false;
|
|
|
473
473
|
*/
|
|
474
474
|
function prepareToExit() {
|
|
475
475
|
quitting = true;
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
476
|
+
// Nothing here may throw. The caller's next statement is process.exit(), and
|
|
477
|
+
// an exception thrown on the way out skips it -- leaving exactly the
|
|
478
|
+
// invisible, unreachable process this whole path exists to prevent. Saving
|
|
479
|
+
// is worth attempting; it is not worth staying alive for.
|
|
480
|
+
try {
|
|
481
|
+
if (stopWatchingNotes) {
|
|
482
|
+
stopWatchingNotes();
|
|
483
|
+
stopWatchingNotes = null;
|
|
484
|
+
}
|
|
485
|
+
} catch (err) {
|
|
486
|
+
console.error('could not stop watching the notes folder', err);
|
|
487
|
+
}
|
|
488
|
+
try {
|
|
489
|
+
store.saveNow();
|
|
490
|
+
} catch (err) {
|
|
491
|
+
console.error('could not save on the way out', err);
|
|
479
492
|
}
|
|
480
|
-
store.saveNow();
|
|
481
493
|
}
|
|
482
494
|
|
|
483
495
|
function watchNotesFolder() {
|
|
@@ -490,12 +502,16 @@ function watchNotesFolder() {
|
|
|
490
502
|
}
|
|
491
503
|
|
|
492
504
|
app.whenReady().then(async () => {
|
|
493
|
-
// Run from npm there is no .app bundle to carry the icon, so
|
|
494
|
-
// the generic Electron atom in the Dock. Set it explicitly.
|
|
495
|
-
//
|
|
496
|
-
//
|
|
497
|
-
//
|
|
498
|
-
|
|
505
|
+
// Run from npm there is no .app bundle of our own to carry the icon, so
|
|
506
|
+
// macOS would show the generic Electron atom in the Dock. Set it explicitly.
|
|
507
|
+
//
|
|
508
|
+
// Keyed on the file existing, not on app.isPackaged. Naming the Dock entry
|
|
509
|
+
// means renaming the executable inside the vendored Electron.app, and
|
|
510
|
+
// isPackaged is derived from that executable's name -- so an npm install
|
|
511
|
+
// started reporting itself as packaged, this branch stopped running, and
|
|
512
|
+
// fixing the name cost the icon. A packaged build has no build/ directory
|
|
513
|
+
// inside it, which is the same condition, tested directly.
|
|
514
|
+
if (process.platform === 'darwin' && app.dock && fs.existsSync(ICON)) {
|
|
499
515
|
try {
|
|
500
516
|
const image = nativeImage.createFromBuffer(fs.readFileSync(ICON));
|
|
501
517
|
if (!image.isEmpty()) app.dock.setIcon(image);
|
package/src/store.js
CHANGED
|
@@ -20,7 +20,16 @@ const { app } = require('electron');
|
|
|
20
20
|
const fs = require('fs');
|
|
21
21
|
const path = require('path');
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Where the notes live.
|
|
25
|
+
*
|
|
26
|
+
* The override exists for harnesses. On macOS Electron resolves the documents
|
|
27
|
+
* folder through the OS rather than $HOME, so a test that redirects HOME still
|
|
28
|
+
* reads and writes the real notes -- which is how a verification run ended up
|
|
29
|
+
* touching them.
|
|
30
|
+
*/
|
|
31
|
+
const DIR = process.env.LATEX_STICKIES_NOTES_DIR
|
|
32
|
+
|| path.join(app.getPath('documents'), 'LaTeX Stickies');
|
|
24
33
|
const INDEX = path.join(DIR, '.stickies.json');
|
|
25
34
|
/** The old single-file store, migrated from once and then left alone. */
|
|
26
35
|
const LEGACY = path.join(app.getPath('userData'), 'notes.json');
|