@mutmutco/installer-launcher 1.3.0 → 1.3.1
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/dist/launcher.js +37 -14
- package/dist/launcher.sea.cjs +24 -1
- package/dist/refresh.js +6 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -245,7 +245,7 @@ atomically only after convergence succeeds. On failure or interrupted startup it
|
|
|
245
245
|
consumer rollback before allowing another install or forwarding. Failed rollback stays pending.
|
|
246
246
|
A crash after shared commit completes the receipt instead of reverting the committed product.
|
|
247
247
|
Host registration is not atomic: failures can leave host references to retained candidates.
|
|
248
|
-
|
|
248
|
+
After a committed promotion the launcher removes candidate folders `state.json` no longer references (the active one is kept; symlinks and junctions are skipped; a failed delete is logged). A failed activation keeps its candidate.
|
|
249
249
|
An orphan lock-recovery guard fails closed and needs operator diagnosis.
|
|
250
250
|
|
|
251
251
|
For already-shipped old launchers, copy the exact file exported by
|
package/dist/launcher.js
CHANGED
|
@@ -6,7 +6,7 @@ import { randomUUID as randomUUID4 } from "node:crypto";
|
|
|
6
6
|
|
|
7
7
|
// src/acquisition.ts
|
|
8
8
|
import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
|
|
9
|
-
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4, unlinkSync, realpathSync as realpathSync2 } from "node:fs";
|
|
9
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync4, unlinkSync, realpathSync as realpathSync2, readdirSync, lstatSync, rmSync as rmSync4 } from "node:fs";
|
|
10
10
|
import { join as join4, resolve, relative as relative2, isAbsolute as isAbsolute2, dirname as dirname2 } from "node:path";
|
|
11
11
|
|
|
12
12
|
// src/runtime.ts
|
|
@@ -617,6 +617,28 @@ async function recoverAcquisition(dir, run2, env) {
|
|
|
617
617
|
else if (existsSync5(statePath(dir))) unlinkSync(statePath(dir));
|
|
618
618
|
unlinkSync(pendingPath(dir));
|
|
619
619
|
}
|
|
620
|
+
function reapCandidates(dir) {
|
|
621
|
+
const keep = readState(dir)?.acquired?.candidate;
|
|
622
|
+
if (!keep) return;
|
|
623
|
+
const base = join4(dir, "candidates");
|
|
624
|
+
let names;
|
|
625
|
+
try {
|
|
626
|
+
names = readdirSync(base);
|
|
627
|
+
} catch {
|
|
628
|
+
return;
|
|
629
|
+
}
|
|
630
|
+
for (const name of names) {
|
|
631
|
+
if (name === keep || !/^[a-zA-Z0-9_-]+$/.test(name)) continue;
|
|
632
|
+
try {
|
|
633
|
+
const path = join4(base, name);
|
|
634
|
+
const info = lstatSync(path);
|
|
635
|
+
if (!info.isDirectory() || info.isSymbolicLink()) continue;
|
|
636
|
+
rmSync4(path, { recursive: true, force: true });
|
|
637
|
+
} catch (error) {
|
|
638
|
+
console.error(`launcher: could not remove old candidate ${name}: ${error.message}`);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
}
|
|
620
642
|
async function installAcquisition(dir, candidate, version, acquisition, options) {
|
|
621
643
|
if (!acquisition.platforms.includes(`${process.platform}-${process.arch}`)) throw new Error("this product does not support this platform");
|
|
622
644
|
const root = candidateRoot(dir, candidate);
|
|
@@ -673,11 +695,12 @@ async function installAcquisition(dir, candidate, version, acquisition, options)
|
|
|
673
695
|
throw error;
|
|
674
696
|
}
|
|
675
697
|
unlinkSync(pendingPath(dir));
|
|
698
|
+
reapCandidates(dir);
|
|
676
699
|
}
|
|
677
700
|
|
|
678
701
|
// src/index.ts
|
|
679
702
|
import { spawn as spawn2, spawnSync as spawnSync4 } from "node:child_process";
|
|
680
|
-
import { existsSync as existsSync8, readFileSync as readFileSync8, statSync as statSync2, mkdtempSync as mkdtempSync2, unlinkSync as unlinkSync2, rmdirSync, mkdirSync as mkdirSync6, renameSync as renameSync5, rmSync as
|
|
703
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8, statSync as statSync2, mkdtempSync as mkdtempSync2, unlinkSync as unlinkSync2, rmdirSync, mkdirSync as mkdirSync6, renameSync as renameSync5, rmSync as rmSync7, writeFileSync as writeFileSync8 } from "node:fs";
|
|
681
704
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
682
705
|
import { dirname as dirname4, join as join7, resolve as resolve3 } from "node:path";
|
|
683
706
|
import { isSea } from "node:sea";
|
|
@@ -1554,7 +1577,7 @@ var rowTitle = (row) => `${row.surface}${row.aspect ? ` ${row.aspect}` : ""}${ro
|
|
|
1554
1577
|
|
|
1555
1578
|
// src/autoupdate.ts
|
|
1556
1579
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
1557
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync6, rmSync as
|
|
1580
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync6, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "node:fs";
|
|
1558
1581
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
1559
1582
|
import { join as join5 } from "node:path";
|
|
1560
1583
|
function schedulePlatform(override) {
|
|
@@ -1649,20 +1672,20 @@ function disableSchedule(config, options = {}) {
|
|
|
1649
1672
|
if (result.code !== 0 && !/cannot find|does not exist/i.test(`${result.stdout} ${result.stderr}`)) {
|
|
1650
1673
|
throw new Error(`Could not turn auto-update off: ${firstLine(result.stdout || result.stderr) || `exit ${result.code}`}`);
|
|
1651
1674
|
}
|
|
1652
|
-
|
|
1675
|
+
rmSync5(join5(options.stateDir ?? defaultProductDir(config.product), HIDDEN_SCRIPT), { force: true });
|
|
1653
1676
|
return;
|
|
1654
1677
|
}
|
|
1655
1678
|
if (platform === "darwin") {
|
|
1656
1679
|
const label2 = scheduleLabel(config);
|
|
1657
1680
|
exec("launchctl", ["bootout", `gui/${process.getuid?.() ?? 501}/${label2}`]);
|
|
1658
|
-
|
|
1681
|
+
rmSync5(join5(home, "Library", "LaunchAgents", `${label2}.plist`), { force: true });
|
|
1659
1682
|
return;
|
|
1660
1683
|
}
|
|
1661
1684
|
const label = scheduleLabel(config);
|
|
1662
1685
|
const dir = join5(home, ".config", "systemd", "user");
|
|
1663
1686
|
exec("systemctl", ["--user", "disable", "--now", `${label}.timer`]);
|
|
1664
|
-
|
|
1665
|
-
|
|
1687
|
+
rmSync5(join5(dir, `${label}.service`), { force: true });
|
|
1688
|
+
rmSync5(join5(dir, `${label}.timer`), { force: true });
|
|
1666
1689
|
}
|
|
1667
1690
|
function querySchedule(config, options = {}) {
|
|
1668
1691
|
const platform = schedulePlatform(options.platform);
|
|
@@ -2041,7 +2064,7 @@ async function ensureFreshToken(config, dir, fetchImpl = fetch) {
|
|
|
2041
2064
|
|
|
2042
2065
|
// src/refresh.ts
|
|
2043
2066
|
import { execFile } from "node:child_process";
|
|
2044
|
-
import { accessSync, chmodSync, constants, existsSync as existsSync7, lstatSync, readdirSync, readFileSync as readFileSync7, realpathSync as realpathSync3, renameSync as renameSync4, rmSync as
|
|
2067
|
+
import { accessSync, chmodSync, constants, existsSync as existsSync7, lstatSync as lstatSync2, readdirSync as readdirSync2, readFileSync as readFileSync7, realpathSync as realpathSync3, renameSync as renameSync4, rmSync as rmSync6, statSync, writeFileSync as writeFileSync7 } from "node:fs";
|
|
2045
2068
|
import { homedir } from "node:os";
|
|
2046
2069
|
import { basename, dirname as dirname3, join as join6, resolve as resolve2 } from "node:path";
|
|
2047
2070
|
var LAUNCHER_RECORD_FILE = "launcher.json";
|
|
@@ -2157,14 +2180,14 @@ function removeStale(file) {
|
|
|
2157
2180
|
const prefix = `${basename(file)}.old-`;
|
|
2158
2181
|
let names;
|
|
2159
2182
|
try {
|
|
2160
|
-
names =
|
|
2183
|
+
names = readdirSync2(dirname3(file));
|
|
2161
2184
|
} catch {
|
|
2162
2185
|
return;
|
|
2163
2186
|
}
|
|
2164
2187
|
for (const name of names) {
|
|
2165
2188
|
if (!name.startsWith(prefix)) continue;
|
|
2166
2189
|
try {
|
|
2167
|
-
|
|
2190
|
+
rmSync6(join6(dirname3(file), name), { force: true });
|
|
2168
2191
|
} catch {
|
|
2169
2192
|
}
|
|
2170
2193
|
}
|
|
@@ -2177,7 +2200,7 @@ async function refreshLauncher(target, options = {}) {
|
|
|
2177
2200
|
const productDir = options.productDir ?? defaultProductDir(target.product);
|
|
2178
2201
|
const recorded = recordedPath(productDir);
|
|
2179
2202
|
const file = options.path ?? (recorded && existsSync7(recorded) ? recorded : installedPath(target, productDir, platform));
|
|
2180
|
-
if (!existsSync7(file) ||
|
|
2203
|
+
if (!existsSync7(file) || lstatSync2(file).isSymbolicLink()) return null;
|
|
2181
2204
|
if (!options.dryRun) removeStale(file);
|
|
2182
2205
|
const from = await (options.readVersion ?? ((path) => runVersion(path, target.bin)))(file);
|
|
2183
2206
|
if (!from) return null;
|
|
@@ -2226,7 +2249,7 @@ async function refreshLauncher(target, options = {}) {
|
|
|
2226
2249
|
if (moved && !existsSync7(file)) renameSync4(moved, file);
|
|
2227
2250
|
} catch {
|
|
2228
2251
|
}
|
|
2229
|
-
|
|
2252
|
+
rmSync6(next, { force: true });
|
|
2230
2253
|
return arm("fail", from, "The launcher could not be replaced.");
|
|
2231
2254
|
}
|
|
2232
2255
|
return arm("ok", record.version, "");
|
|
@@ -2236,7 +2259,7 @@ async function refreshLauncher(target, options = {}) {
|
|
|
2236
2259
|
}
|
|
2237
2260
|
|
|
2238
2261
|
// src/index.ts
|
|
2239
|
-
var LAUNCHER_VERSION = true ? "1.3.
|
|
2262
|
+
var LAUNCHER_VERSION = true ? "1.3.1" : readVersionFromPackage();
|
|
2240
2263
|
function defaultPrint(message) {
|
|
2241
2264
|
process.stdout.write(`${message}
|
|
2242
2265
|
`);
|
|
@@ -2758,7 +2781,7 @@ async function installOrUpdateRun(config, dir, options, print, update, flags2, m
|
|
|
2758
2781
|
}
|
|
2759
2782
|
const target = join7(dir, "payload");
|
|
2760
2783
|
mkdirSync6(dir, { recursive: true });
|
|
2761
|
-
|
|
2784
|
+
rmSync7(target, { recursive: true, force: true });
|
|
2762
2785
|
renameSync5(join7(candidateDir, "payload"), target);
|
|
2763
2786
|
writeState(dir, { version, updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
2764
2787
|
installer.phase("download", { seconds: (Date.now() - started) / 1e3 });
|
package/dist/launcher.sea.cjs
CHANGED
|
@@ -650,6 +650,28 @@ async function recoverAcquisition(dir, run2, env) {
|
|
|
650
650
|
else if ((0, import_node_fs5.existsSync)(statePath(dir))) (0, import_node_fs5.unlinkSync)(statePath(dir));
|
|
651
651
|
(0, import_node_fs5.unlinkSync)(pendingPath(dir));
|
|
652
652
|
}
|
|
653
|
+
function reapCandidates(dir) {
|
|
654
|
+
const keep = readState(dir)?.acquired?.candidate;
|
|
655
|
+
if (!keep) return;
|
|
656
|
+
const base = (0, import_node_path4.join)(dir, "candidates");
|
|
657
|
+
let names;
|
|
658
|
+
try {
|
|
659
|
+
names = (0, import_node_fs5.readdirSync)(base);
|
|
660
|
+
} catch {
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
for (const name of names) {
|
|
664
|
+
if (name === keep || !/^[a-zA-Z0-9_-]+$/.test(name)) continue;
|
|
665
|
+
try {
|
|
666
|
+
const path = (0, import_node_path4.join)(base, name);
|
|
667
|
+
const info = (0, import_node_fs5.lstatSync)(path);
|
|
668
|
+
if (!info.isDirectory() || info.isSymbolicLink()) continue;
|
|
669
|
+
(0, import_node_fs5.rmSync)(path, { recursive: true, force: true });
|
|
670
|
+
} catch (error) {
|
|
671
|
+
console.error(`launcher: could not remove old candidate ${name}: ${error.message}`);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
}
|
|
653
675
|
async function installAcquisition(dir, candidate, version, acquisition, options) {
|
|
654
676
|
if (!acquisition.platforms.includes(`${process.platform}-${process.arch}`)) throw new Error("this product does not support this platform");
|
|
655
677
|
const root = candidateRoot(dir, candidate);
|
|
@@ -706,6 +728,7 @@ async function installAcquisition(dir, candidate, version, acquisition, options)
|
|
|
706
728
|
throw error;
|
|
707
729
|
}
|
|
708
730
|
(0, import_node_fs5.unlinkSync)(pendingPath(dir));
|
|
731
|
+
reapCandidates(dir);
|
|
709
732
|
}
|
|
710
733
|
|
|
711
734
|
// src/index.ts
|
|
@@ -2269,7 +2292,7 @@ async function refreshLauncher(target, options = {}) {
|
|
|
2269
2292
|
}
|
|
2270
2293
|
|
|
2271
2294
|
// src/index.ts
|
|
2272
|
-
var LAUNCHER_VERSION = true ? "1.3.
|
|
2295
|
+
var LAUNCHER_VERSION = true ? "1.3.1" : readVersionFromPackage();
|
|
2273
2296
|
function defaultPrint(message) {
|
|
2274
2297
|
process.stdout.write(`${message}
|
|
2275
2298
|
`);
|
package/dist/refresh.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
// src/refresh.ts
|
|
2
2
|
import { execFile } from "node:child_process";
|
|
3
|
-
import { accessSync, chmodSync, constants, existsSync as existsSync2, lstatSync, readdirSync, readFileSync as readFileSync2, realpathSync as realpathSync2, renameSync, rmSync, statSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
3
|
+
import { accessSync, chmodSync, constants, existsSync as existsSync2, lstatSync as lstatSync2, readdirSync as readdirSync2, readFileSync as readFileSync2, realpathSync as realpathSync2, renameSync, rmSync as rmSync2, statSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { basename, dirname as dirname2, join as join3, resolve as resolve2 } from "node:path";
|
|
6
6
|
|
|
7
7
|
// src/acquisition.ts
|
|
8
8
|
import { createHash as createHash2, randomUUID } from "node:crypto";
|
|
9
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, realpathSync } from "node:fs";
|
|
9
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, realpathSync, readdirSync, lstatSync, rmSync } from "node:fs";
|
|
10
10
|
import { join as join2, resolve, relative, isAbsolute, dirname } from "node:path";
|
|
11
11
|
|
|
12
12
|
// src/download.ts
|
|
@@ -290,14 +290,14 @@ function removeStale(file) {
|
|
|
290
290
|
const prefix = `${basename(file)}.old-`;
|
|
291
291
|
let names;
|
|
292
292
|
try {
|
|
293
|
-
names =
|
|
293
|
+
names = readdirSync2(dirname2(file));
|
|
294
294
|
} catch {
|
|
295
295
|
return;
|
|
296
296
|
}
|
|
297
297
|
for (const name of names) {
|
|
298
298
|
if (!name.startsWith(prefix)) continue;
|
|
299
299
|
try {
|
|
300
|
-
|
|
300
|
+
rmSync2(join3(dirname2(file), name), { force: true });
|
|
301
301
|
} catch {
|
|
302
302
|
}
|
|
303
303
|
}
|
|
@@ -310,7 +310,7 @@ async function refreshLauncher(target, options = {}) {
|
|
|
310
310
|
const productDir = options.productDir ?? defaultProductDir(target.product);
|
|
311
311
|
const recorded = recordedPath(productDir);
|
|
312
312
|
const file = options.path ?? (recorded && existsSync2(recorded) ? recorded : installedPath(target, productDir, platform));
|
|
313
|
-
if (!existsSync2(file) ||
|
|
313
|
+
if (!existsSync2(file) || lstatSync2(file).isSymbolicLink()) return null;
|
|
314
314
|
if (!options.dryRun) removeStale(file);
|
|
315
315
|
const from = await (options.readVersion ?? ((path) => runVersion(path, target.bin)))(file);
|
|
316
316
|
if (!from) return null;
|
|
@@ -359,7 +359,7 @@ async function refreshLauncher(target, options = {}) {
|
|
|
359
359
|
if (moved && !existsSync2(file)) renameSync(moved, file);
|
|
360
360
|
} catch {
|
|
361
361
|
}
|
|
362
|
-
|
|
362
|
+
rmSync2(next, { force: true });
|
|
363
363
|
return arm("fail", from, "The launcher could not be replaced.");
|
|
364
364
|
}
|
|
365
365
|
return arm("ok", record.version, "");
|
package/package.json
CHANGED