@zixt/host 0.0.85 → 0.0.86

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/dist/index.js +114 -17
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -31,7 +31,7 @@ import { homedir as homedir3 } from "node:os";
31
31
  // package.json
32
32
  var package_default = {
33
33
  name: "@zixt/host",
34
- version: "0.0.85",
34
+ version: "0.0.86",
35
35
  type: "module",
36
36
  exports: {
37
37
  ".": "./src/client.ts",
@@ -25828,14 +25828,26 @@ setTimeout(() => { if (!launched) fail(); }, 130000).unref();
25828
25828
  var InstallerContainmentError = class extends Error {
25829
25829
  name = "InstallerContainmentError";
25830
25830
  };
25831
+ function describeInstallerExit(code, signal) {
25832
+ if (signal !== null) return `was killed by ${signal}`;
25833
+ if (code === null) return "ended without reporting an exit code";
25834
+ return `exited with code ${code}`;
25835
+ }
25831
25836
  async function installRelease(version2, options = {}) {
25832
- if (!VERSION_DIR.test(version2)) return null;
25837
+ const fail = (reason, detail) => {
25838
+ options.onFailure?.({ version: version2, reason, detail });
25839
+ return null;
25840
+ };
25841
+ if (!VERSION_DIR.test(version2)) {
25842
+ return fail("unsupported_version", "that is not a release name this Host can install");
25843
+ }
25833
25844
  const platform = options.platform ?? process.platform;
25834
25845
  const root = options.root ?? versionsRoot();
25835
25846
  const prefix = join8(root, version2);
25836
25847
  const entry = installedReleaseEntry(version2, root);
25837
25848
  if (await validReleaseAtPrefix(prefix, version2)) return entry;
25838
- if (options.signal?.aborted) return null;
25849
+ if (options.signal?.aborted)
25850
+ return fail("cancelled", "this Host was stopping before npm started");
25839
25851
  const installerCommand = options.installerCommand ?? await resolveInstallerCommand({ platform });
25840
25852
  await mkdir5(root, { recursive: true, mode: 448 });
25841
25853
  const staging = join8(root, `.install-${version2}-${process.pid}-${crypto.randomUUID()}`);
@@ -25870,9 +25882,12 @@ async function installRelease(version2, options = {}) {
25870
25882
  let child;
25871
25883
  try {
25872
25884
  child = spawnInstaller(staging, version2);
25873
- } catch {
25885
+ } catch (error52) {
25874
25886
  await rm5(staging, { recursive: true, force: true }).catch(() => void 0);
25875
- return null;
25887
+ return fail(
25888
+ "installer_unavailable",
25889
+ `${installerCommand} could not be started (${error52 instanceof Error ? error52.message : "unknown error"})`
25890
+ );
25876
25891
  }
25877
25892
  let resolveChildExited;
25878
25893
  const childExited = new Promise((resolveExit) => {
@@ -25894,6 +25909,8 @@ async function installRelease(version2, options = {}) {
25894
25909
  installerContainmentSetupError = error52;
25895
25910
  return null;
25896
25911
  }) : Promise.resolve(null);
25912
+ const timeoutMs = options.timeoutMs ?? INSTALL_TIMEOUT_MS;
25913
+ const outcome = { code: null, signal: null, timedOut: false, spawnError: null };
25897
25914
  const installed = await new Promise((resolve18, reject3) => {
25898
25915
  let finished = false;
25899
25916
  let cleanupStarted = false;
@@ -25948,13 +25965,21 @@ async function installRelease(version2, options = {}) {
25948
25965
  }
25949
25966
  })();
25950
25967
  };
25951
- const timer = setTimeout(requestCleanup, options.timeoutMs ?? INSTALL_TIMEOUT_MS);
25968
+ const timer = setTimeout(() => {
25969
+ outcome.timedOut = true;
25970
+ requestCleanup();
25971
+ }, timeoutMs);
25952
25972
  timer.unref?.();
25953
- child.once("error", () => {
25973
+ child.once("error", (error52) => {
25974
+ outcome.spawnError = error52.message;
25954
25975
  observeExit();
25955
25976
  requestCleanup();
25956
25977
  });
25957
- child.once("exit", (code) => {
25978
+ child.once("exit", (code, signal) => {
25979
+ if (!usesWindowsInstallerGuardian) {
25980
+ outcome.code = code;
25981
+ outcome.signal = signal;
25982
+ }
25958
25983
  observeExit();
25959
25984
  if (usesWindowsInstallerGuardian) {
25960
25985
  requestCleanup();
@@ -25974,6 +25999,9 @@ async function installRelease(version2, options = {}) {
25974
25999
  }
25975
26000
  const code = message.code;
25976
26001
  if (code !== null && (typeof code !== "number" || !Number.isInteger(code))) return;
26002
+ outcome.code = code;
26003
+ const signal = message.signal;
26004
+ outcome.signal = typeof signal === "string" ? signal : null;
25977
26005
  successfulCleanupResult = code === 0;
25978
26006
  requestCleanup();
25979
26007
  });
@@ -26004,8 +26032,32 @@ async function installRelease(version2, options = {}) {
26004
26032
  if (options.signal?.aborted) requestCleanup();
26005
26033
  });
26006
26034
  try {
26007
- if (options.signal?.aborted || !installed || !await validReleaseAtPrefix(staging, version2)) {
26008
- return null;
26035
+ if (options.signal?.aborted) {
26036
+ return fail("cancelled", "this Host was stopping before the install finished");
26037
+ }
26038
+ if (!installed) {
26039
+ if (outcome.timedOut) {
26040
+ return fail(
26041
+ "installer_timed_out",
26042
+ `${installerCommand} was still running after ${Math.round(timeoutMs / 1e3)}s and was stopped`
26043
+ );
26044
+ }
26045
+ if (outcome.spawnError !== null) {
26046
+ return fail(
26047
+ "installer_unavailable",
26048
+ `${installerCommand} failed to run (${outcome.spawnError})`
26049
+ );
26050
+ }
26051
+ return fail(
26052
+ "installer_failed",
26053
+ `${installerCommand} install ${PACKAGE_NAME}@${version2} ${describeInstallerExit(outcome.code, outcome.signal)}`
26054
+ );
26055
+ }
26056
+ if (!await validReleaseAtPrefix(staging, version2)) {
26057
+ return fail(
26058
+ "incomplete_release",
26059
+ `${installerCommand} reported success but left no runnable ${PACKAGE_NAME}@${version2} in ${staging}`
26060
+ );
26009
26061
  }
26010
26062
  if (await validReleaseAtPrefix(prefix, version2)) return entry;
26011
26063
  const existing = await lstat5(prefix).catch((error52) => {
@@ -26015,11 +26067,18 @@ async function installRelease(version2, options = {}) {
26015
26067
  if (existing) await rename3(prefix, quarantine);
26016
26068
  try {
26017
26069
  await rename3(staging, prefix);
26018
- } catch {
26019
- return await validReleaseAtPrefix(prefix, version2) ? entry : null;
26070
+ } catch (error52) {
26071
+ if (await validReleaseAtPrefix(prefix, version2)) return entry;
26072
+ return fail(
26073
+ "commit_failed",
26074
+ `the validated tree could not be moved into ${prefix} (${error52 instanceof Error ? error52.message : "unknown error"})`
26075
+ );
26020
26076
  }
26021
26077
  await syncDirectory3(root);
26022
- return await validReleaseAtPrefix(prefix, version2) ? entry : null;
26078
+ return await validReleaseAtPrefix(prefix, version2) ? entry : fail(
26079
+ "commit_failed",
26080
+ `${prefix} is not a runnable ${PACKAGE_NAME}@${version2} after installing`
26081
+ );
26023
26082
  } finally {
26024
26083
  await rm5(staging, { recursive: true, force: true }).catch(() => void 0);
26025
26084
  await rm5(quarantine, { recursive: true, force: true }).catch(() => void 0);
@@ -26601,7 +26660,10 @@ async function superviseHost(options = {}) {
26601
26660
  platform,
26602
26661
  workerDiagnosticsRoot
26603
26662
  ));
26604
- const install = options.installVersion ?? ((version2, signal) => installRelease(version2, signal ? { signal } : {}));
26663
+ const install = options.installVersion ?? ((version2, signal, onFailure) => installRelease(version2, {
26664
+ ...signal ? { signal } : {},
26665
+ ...onFailure ? { onFailure } : {}
26666
+ }));
26605
26667
  const cleanupWorker = options.cleanupWorker ?? (options.spawnWorker ? async () => {
26606
26668
  } : null);
26607
26669
  const createWorkerContainment = options.createWorkerContainment ?? (platform === "win32" && !options.spawnWorker ? async (target, identityNonce, signal) => {
@@ -27023,6 +27085,9 @@ async function superviseHost(options = {}) {
27023
27085
  if (!await waitAfterCrash(runtimeMs)) return 0;
27024
27086
  continue;
27025
27087
  }
27088
+ log2(
27089
+ `Zixt Host: worker on ${command.version ?? "the launched copy"} asked to update (exit ${effectiveCode}${watchdogTriggered ? `, announced ${announcedExitCode} before its teardown was contained` : ""}); checking the published release`
27090
+ );
27026
27091
  if (watchdogTriggered) {
27027
27092
  await reportWorkerExit(workerExit, "installing the update it asked for anyway");
27028
27093
  }
@@ -27030,6 +27095,7 @@ async function superviseHost(options = {}) {
27030
27095
  if (orderlyValidatedBoundary) rollbackCandidate = null;
27031
27096
  const target = await published();
27032
27097
  let updateLanded = false;
27098
+ let rejectedUpdate = null;
27033
27099
  if (target === null) {
27034
27100
  log2(
27035
27101
  "Zixt Host: a newer release was reported but the registry is unreachable; staying on the current version"
@@ -27042,13 +27108,22 @@ async function superviseHost(options = {}) {
27042
27108
  log2(`Zixt Host: already running ${target}; ignoring a repeated update request`);
27043
27109
  } else {
27044
27110
  let entry;
27111
+ const attempt = { failure: null };
27112
+ log2(`Zixt Host: installing ${target} over ${command.version ?? "the launched copy"}`);
27045
27113
  try {
27046
- entry = await install(target, shutdownController.signal);
27114
+ entry = await install(target, shutdownController.signal, (failure2) => {
27115
+ attempt.failure = failure2;
27116
+ });
27047
27117
  } catch (error52) {
27048
27118
  if (error52 instanceof InstallerContainmentError) {
27049
27119
  log2(`Zixt Host: ${error52.message}; handing recovery to the stable launcher`);
27050
27120
  return 1;
27051
27121
  }
27122
+ attempt.failure = {
27123
+ version: target,
27124
+ reason: "commit_failed",
27125
+ detail: error52 instanceof Error ? error52.message : "unknown error"
27126
+ };
27052
27127
  entry = null;
27053
27128
  }
27054
27129
  if (shuttingDown2) return 0;
@@ -27136,9 +27211,14 @@ async function superviseHost(options = {}) {
27136
27211
  }
27137
27212
  }
27138
27213
  } else {
27139
- log2(`Zixt Host: could not install ${target}; staying on the current version`);
27214
+ const failure2 = attempt.failure;
27215
+ log2(
27216
+ `Zixt Host: could not install ${target} (${failure2 ? `${failure2.reason}: ${failure2.detail}` : "no reason reported"}); staying on ${command.version ?? "the launched copy"}`
27217
+ );
27218
+ if (failure2?.reason !== "cancelled") rejectedUpdate = target;
27140
27219
  }
27141
27220
  }
27221
+ if (rejectedUpdate) command = { ...command, rejectedVersion: rejectedUpdate };
27142
27222
  unsatisfiableUpdates = updateLanded ? 0 : unsatisfiableUpdates + 1;
27143
27223
  if (unsatisfiableUpdates > 0) {
27144
27224
  if (!await waitOrShutdown(streakBackoffMs(unsatisfiableUpdates))) return 0;
@@ -40899,7 +40979,12 @@ function shutdown(exitCode = 0) {
40899
40979
  if (shuttingDown) process.exit(exitCode);
40900
40980
  shuttingDown = true;
40901
40981
  retainRunAssignments();
40902
- log.info("Stopping Zixt Host", { machine, activeTasks: activeSessions });
40982
+ log.info("Stopping Zixt Host", {
40983
+ machine,
40984
+ activeTasks: activeSessions,
40985
+ exit: exitCode,
40986
+ reason: exitCode === UPDATE_EXIT_CODE ? "installing a Zixt Host update" : exitCode === DO_NOT_RESTART_EXIT_CODE ? "this Machine needs attention before it restarts" : "stop requested"
40987
+ });
40903
40988
  beginWorkerShutdown({
40904
40989
  activeTasks: activeSessions,
40905
40990
  exitCode,
@@ -40912,6 +40997,9 @@ function shutdown(exitCode = 0) {
40912
40997
  machine,
40913
40998
  deadline: formatDuration(deadlineMs),
40914
40999
  exit: code,
41000
+ // A stop that had to unwind live runs exits as a crash instead, so
41001
+ // the honoured code can differ from the verdict this stop was for.
41002
+ ...code === exitCode ? {} : { requested: exitCode },
40915
41003
  activeTasks: activeSessions,
40916
41004
  next: "The Host restarts automatically; report this if it repeats"
40917
41005
  }
@@ -40919,6 +41007,15 @@ function shutdown(exitCode = 0) {
40919
41007
  }
40920
41008
  });
40921
41009
  }
41010
+ var skippedRelease = process.env.ZIXT_HOST_REJECT_VERSION;
41011
+ if (packagedBuild && skippedRelease) {
41012
+ log.warn("Skipping a Zixt Host release this Machine could not install", {
41013
+ machine,
41014
+ version: skippedRelease,
41015
+ running: HOST_VERSION,
41016
+ next: "This Machine keeps working and takes the next release; report it if it stays behind"
41017
+ });
41018
+ }
40922
41019
  stopUpdateWatch = !packagedBuild ? () => {
40923
41020
  } : watchForUpdates({
40924
41021
  onUpdateAvailable: (version2) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zixt/host",
3
- "version": "0.0.85",
3
+ "version": "0.0.86",
4
4
  "type": "module",
5
5
  "exports": {
6
6
  ".": "./src/client.ts",