localdeck 1.2.2 → 1.2.3

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.
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>LocalDeck</title>
7
7
  <link rel="icon" type="image/png" href="/localdeck-icon.png" />
8
- <script type="module" crossorigin src="/assets/index-BDrE-iT3.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-nFZAC5Mt.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-DbQzubLF.css">
10
10
  </head>
11
11
  <body>
@@ -2993,7 +2993,7 @@ var DAEMON_LOG = path.join(HOME_DIR, "daemon.log");
2993
2993
  var DEFAULT_API_PORT = Number(process.env.LOCALDECK_PORT ?? 7777);
2994
2994
  function assertUserRuntime(uid = process.getuid?.(), env = process.env) {
2995
2995
  if (uid === 0 && env.SUDO_UID && env.SUDO_UID !== "0") {
2996
- throw new Error("Do not launch or update the LocalDeck runtime with sudo. Run localdeck daemon start as your normal user. If installation requires administrator access, run sudo npm install -g localdeck@latest separately, then start LocalDeck without sudo.");
2996
+ throw new Error("Do not run the LocalDeck runtime with sudo. Run localdeck --update or localdeck daemon start without sudo. The updater requests administrator access only for npm when needed.");
2997
2997
  }
2998
2998
  }
2999
2999
  function ensureDirs() {
@@ -8148,7 +8148,7 @@ async function waitForProcessGroupExit(groupId, timeoutMs) {
8148
8148
  return true;
8149
8149
  }
8150
8150
  // ../daemon/package.json
8151
- var version = "1.2.2";
8151
+ var version = "1.2.3";
8152
8152
 
8153
8153
  // ../daemon/src/index.ts
8154
8154
  var VERSION = version;
package/dist/index.js CHANGED
@@ -30,7 +30,7 @@ import {
30
30
  stripAnsi,
31
31
  waitForReadiness,
32
32
  wrapper_default
33
- } from "./index-q0ecp96f.js";
33
+ } from "./index-6r7h3h6p.js";
34
34
 
35
35
  // src/index.ts
36
36
  import { spawn as spawn2 } from "node:child_process";
@@ -907,13 +907,13 @@ async function main(argv, overrides = {}) {
907
907
  case "--update":
908
908
  if (rest.length)
909
909
  throw new Error("Usage: localdeck --update");
910
- return (await import("./update-5pz3der1.js")).updateLocalDeck();
910
+ return (await import("./update-7rehj1x3.js")).updateLocalDeck();
911
911
  case "up":
912
912
  return cmdUp(rest, dependencies);
913
913
  case "init":
914
914
  return cmdInit(rest, dependencies);
915
915
  case "mcp":
916
- return (await import("./mcp-pwywe3ff.js")).runMcp(rest);
916
+ return (await import("./mcp-67ae2y6m.js")).runMcp(rest);
917
917
  case "doctor":
918
918
  return cmdDoctor(rest);
919
919
  case "forward":
@@ -9,7 +9,7 @@ import {
9
9
  listProjectSecrets,
10
10
  redactDiagnostic,
11
11
  resolveProjectSecrets
12
- } from "./index-q0ecp96f.js";
12
+ } from "./index-6r7h3h6p.js";
13
13
 
14
14
  // ../../node_modules/.bun/ajv@8.20.0/node_modules/ajv/dist/compile/codegen/code.js
15
15
  var require_code = __commonJS((exports) => {
@@ -3,7 +3,7 @@ import {
3
3
  STATE_FILE,
4
4
  assertUserRuntime,
5
5
  findDaemon
6
- } from "./index-q0ecp96f.js";
6
+ } from "./index-6r7h3h6p.js";
7
7
 
8
8
  // src/update.ts
9
9
  import { spawn } from "node:child_process";
@@ -56,6 +56,46 @@ async function execute(command, capture = false) {
56
56
  child.once("close", (code, signal) => code === 0 ? resolve(output.trim()) : reject(new Error(`Command failed (${signal ?? `exit ${code}`}).`)));
57
57
  });
58
58
  }
59
+ function installationWritable(packageRoot, prefix, platform = process.platform) {
60
+ const paths = platform === "win32" ? path.win32 : path.posix;
61
+ for (const directory of [packageRoot, paths.dirname(packageRoot), platform === "win32" ? prefix : paths.join(prefix, "bin")]) {
62
+ try {
63
+ fs.accessSync(directory, fs.constants.W_OK | fs.constants.X_OK);
64
+ } catch (error) {
65
+ const code = error.code;
66
+ if (code === "EACCES" || code === "EPERM")
67
+ return false;
68
+ throw error;
69
+ }
70
+ }
71
+ return true;
72
+ }
73
+ async function installUpdate(options) {
74
+ const platform = options.platform ?? process.platform;
75
+ const run = options.execute ?? execute;
76
+ const command = [
77
+ ...options.npm,
78
+ "install",
79
+ "--global",
80
+ "--prefix",
81
+ options.prefix,
82
+ "localdeck@latest",
83
+ "--registry=https://registry.npmjs.org/",
84
+ "--ignore-scripts"
85
+ ];
86
+ if ((options.writable ?? installationWritable)(options.packageRoot, options.prefix, platform)) {
87
+ await run(command);
88
+ return;
89
+ }
90
+ if (platform !== "darwin" && platform !== "linux") {
91
+ throw new Error("The installation requires administrator access. Install localdeck@latest with npm in an administrator terminal, then restart LocalDeck as your normal user.");
92
+ }
93
+ if (!(options.interactive ?? Boolean(process.stdin.isTTY && process.stdout.isTTY))) {
94
+ throw new Error("The installation requires administrator access. Run localdeck --update in an interactive terminal so npm can request permission. Do not run LocalDeck with sudo.");
95
+ }
96
+ (options.log ?? console.log)(`Administrator access is required to update ${options.prefix}. Only npm will run with sudo; LocalDeck will continue as your normal user.`);
97
+ await run(["/usr/bin/sudo", "-H", "--", ...command]);
98
+ }
59
99
  async function applyUpdate(steps) {
60
100
  await steps.install();
61
101
  const version = await steps.validate();
@@ -76,9 +116,9 @@ async function updateLocalDeck() {
76
116
  const version = await applyUpdate({
77
117
  install: async () => {
78
118
  try {
79
- await execute([...npm, "install", "--global", "--prefix", prefix, "localdeck@latest", "--registry=https://registry.npmjs.org/"]);
119
+ await installUpdate({ npm, packageRoot: root, prefix });
80
120
  } catch (error) {
81
- throw new Error(`npm update failed. The daemon was not restarted. Check the npm error above; the installation prefix must be writable. ${error instanceof Error ? error.message : error}`);
121
+ throw new Error(`npm update failed. The daemon was not restarted. ${error instanceof Error ? error.message : error}`);
82
122
  }
83
123
  },
84
124
  validate: async () => {
@@ -124,6 +164,8 @@ async function updateLocalDeck() {
124
164
  }
125
165
  export {
126
166
  updateLocalDeck,
167
+ installationWritable,
127
168
  installationPrefix,
169
+ installUpdate,
128
170
  applyUpdate
129
171
  };
package/docs/commands.md CHANGED
@@ -101,6 +101,10 @@ localdeck --update
101
101
 
102
102
  Available starting with 1.0.3. Installs the latest public npm release into the current global npm prefix, verifies the updated CLI, and restarts the daemon. Restarting stops daemon-managed services and public shares. Start services again afterward; terminal sessions may need to be rerun to reconnect.
103
103
 
104
- A failed installation leaves the daemon running. The npm prefix must be writable; LocalDeck never invokes sudo. Source checkouts, linked builds, local installs, npx caches, and unsupported package-manager layouts must be updated manually. Custom Unix prefixes are preserved. On Windows the installation must match npm's active global root.
104
+ A failed installation leaves the daemon running. Starting with 1.2.3, LocalDeck checks installation permissions before updating. On macOS and Linux, a protected prefix such as `/usr/local` requests administrator access through sudo for the npm installation only. Run `localdeck --update` as your normal user in an interactive terminal; verification and daemon restart retain your user account. Cancelling authentication leaves the daemon running. Writable prefixes update without elevation. npm lifecycle scripts are disabled because the published package is prebuilt.
105
+
106
+ Non-interactive sessions cannot request administrator access. On Windows, a protected installation must be updated with npm from an administrator terminal, then LocalDeck restarted as the normal user. Source checkouts, linked builds, local installs, npx caches, and unsupported package-manager layouts must be updated manually. Custom Unix prefixes are preserved. On Windows the installation must match npm's active global root.
107
+
108
+ To get this fix when an older updater fails on a protected macOS/Linux installation, run `sudo npm install -g --prefix /usr/local localdeck@latest` (use your actual installation prefix), then `localdeck daemon stop` and `localdeck daemon start` without sudo. Future updates use `localdeck --update`.
105
109
 
106
110
  Older versions without this command can upgrade with `npm install -g localdeck@latest` using their existing npm prefix.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "localdeck",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "type": "module",
5
5
  "description": "Stable ports, shareable HTTPS links and request logs for your local dev servers",
6
6
  "bin": {