mirinjs 0.1.0-alpha.12 → 0.1.0-alpha.14

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/updater.ts +48 -8
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mirinjs",
3
- "version": "0.1.0-alpha.12",
3
+ "version": "0.1.0-alpha.14",
4
4
  "description": "Build desktop apps with Bun, TypeScript, and Chromium (CEF). The Bun-native Electron alternative.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/updater.ts CHANGED
@@ -29,6 +29,8 @@ import { runtime } from "./runtime.ts";
29
29
  import { loadCodec } from "./codec.ts";
30
30
 
31
31
  const IS_WINDOWS = process.platform === "win32";
32
+ const IS_LINUX = process.platform === "linux";
33
+ const IS_MAC = process.platform === "darwin";
32
34
 
33
35
  export type UpdaterStatus =
34
36
  | "idle"
@@ -118,7 +120,7 @@ export class Updater {
118
120
  if (!v) return null;
119
121
  this.#setStatus("checking");
120
122
  try {
121
- const url = `${v.baseUrl.replace(/\/$/, "")}/${this.#prefix()}-update.json?t=${Date.now()}`;
123
+ const url = `${this.#baseUrl(v)}/${this.#prefix()}-update.json?t=${Date.now()}`;
122
124
  const res = await fetch(url, { redirect: "follow" });
123
125
  if (!res.ok) throw new Error(`manifest ${res.status}`);
124
126
  const m = (await res.json()) as Manifest;
@@ -156,7 +158,7 @@ export class Updater {
156
158
  rmSync(work, { recursive: true, force: true });
157
159
  mkdirSync(work, { recursive: true });
158
160
 
159
- const base = v.baseUrl.replace(/\/$/, "");
161
+ const base = this.#baseUrl(v);
160
162
  const newTar = join(work, "new.tar");
161
163
  const cachedTar = join(tarsDir, `${v.version}.tar`);
162
164
  const patch = m.patches?.find((p) => p.fromVersion === v.version);
@@ -187,11 +189,12 @@ export class Updater {
187
189
  rmSync(keepTar, { force: true });
188
190
  renameSync(newTar, keepTar);
189
191
  await $`tar -xf ${keepTar} -C ${work}`.quiet();
190
- // The packaged unit: a flat app folder on Windows, an `.app` on macOS.
191
- const staged = join(work, IS_WINDOWS ? v.name : `${v.name}.app`);
192
+ // The packaged unit: a flat app folder on Windows/Linux, an `.app` on macOS.
193
+ const staged = join(work, IS_WINDOWS || IS_LINUX ? v.name : `${v.name}.app`);
192
194
  if (!existsSync(staged)) throw new Error(`extracted bundle not found at ${staged}`);
193
195
 
194
- if (!IS_WINDOWS) {
196
+ // codesign is macOS-only; Windows and Linux have no equivalent step here.
197
+ if (IS_MAC) {
195
198
  const verify = await $`codesign --verify --deep --strict ${staged}`.quiet().nothrow();
196
199
  if (verify.exitCode !== 0)
197
200
  throw new Error("codesign verification failed on the downloaded update");
@@ -217,8 +220,9 @@ export class Updater {
217
220
  this.#setStatus("applying");
218
221
  try {
219
222
  // The running app folder: macOS `.app` is Contents/Resources/../.. ; Windows
220
- // is the exe dir, i.e. resources/.. . A detached helper waits for this process
221
- // to exit (the exe/bundle is locked while running), swaps the folder, relaunches.
223
+ // and Linux are the exe dir, i.e. resources/.. . A detached helper waits for
224
+ // this process to exit (the exe/bundle is locked while running), swaps the
225
+ // folder, relaunches.
222
226
  if (IS_WINDOWS) {
223
227
  const runningApp = join(this.#resourcesDir()!, "..");
224
228
  const name = this.#version()!.name;
@@ -274,6 +278,31 @@ export class Updater {
274
278
  stderr: "ignore",
275
279
  });
276
280
  await launcher.exited;
281
+ } else if (IS_LINUX) {
282
+ // Linux is a flat layout like Windows: the app folder is resources/.. (the
283
+ // exe dir), not ../.. (that's the macOS `.app`). The relaunch binary is the
284
+ // host executable, named after the app. A detached, new-session helper waits
285
+ // for the host to exit, swaps the folder, and relaunches from it.
286
+ const runningApp = join(this.#resourcesDir()!, "..");
287
+ const name = this.#version()!.name;
288
+ const bin = join(runningApp, name);
289
+ const script = [
290
+ `APP=${sh(runningApp)}`,
291
+ `NEW=${sh(this.#staged)}`,
292
+ `BIN=${sh(bin)}`,
293
+ `PID=${process.pid}`,
294
+ `while kill -0 "$PID" 2>/dev/null; do sleep 0.2; done`,
295
+ `sleep 0.3`,
296
+ `rm -rf "$APP"`,
297
+ `mv "$NEW" "$APP"`,
298
+ `chmod +x "$BIN" 2>/dev/null || true`,
299
+ `setsid "$BIN" >/dev/null 2>&1 < /dev/null &`,
300
+ ].join("\n");
301
+ Bun.spawn(["/bin/sh", "-c", script], {
302
+ stdin: "ignore",
303
+ stdout: "ignore",
304
+ stderr: "ignore",
305
+ }).unref();
277
306
  } else {
278
307
  const runningApp = join(this.#resourcesDir()!, "..", "..");
279
308
  const script = [
@@ -381,15 +410,26 @@ export class Updater {
381
410
  }
382
411
 
383
412
  #prefix(): string {
384
- const platform = IS_WINDOWS ? "win32" : "darwin";
413
+ const platform = IS_WINDOWS ? "win32" : IS_LINUX ? "linux" : "darwin";
385
414
  return `${this.#version()!.channel}-${platform}-${process.arch}`;
386
415
  }
387
416
 
417
+ /** The release host to poll. `MIRIN_UPDATE_BASE_URL` overrides the embedded
418
+ * `baseUrl` (for local end-to-end testing against a throwaway server). */
419
+ #baseUrl(v: VersionInfo): string {
420
+ return (process.env.MIRIN_UPDATE_BASE_URL ?? v.baseUrl).replace(/\/$/, "");
421
+ }
422
+
388
423
  #supportDir(v: VersionInfo): string {
389
424
  if (IS_WINDOWS) {
390
425
  const base = process.env.LOCALAPPDATA ?? join(homedir(), "AppData", "Local");
391
426
  return join(base, v.identifier, v.channel);
392
427
  }
428
+ if (IS_LINUX) {
429
+ // XDG base dir spec: $XDG_DATA_HOME, defaulting to ~/.local/share.
430
+ const base = process.env.XDG_DATA_HOME || join(homedir(), ".local", "share");
431
+ return join(base, v.identifier, v.channel);
432
+ }
393
433
  return join(homedir(), "Library", "Application Support", v.identifier, v.channel);
394
434
  }
395
435