@spencer-kit/coder-studio 0.4.3 → 0.4.4
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/CHANGELOG.md +8 -0
- package/dist/esm/bin.mjs +428 -89
- package/dist/esm/bin.mjs.map +4 -4
- package/dist/esm/server-runner.mjs +406 -67
- package/dist/esm/server-runner.mjs.map +4 -4
- package/dist/esm/update-worker.mjs +118 -3
- package/dist/esm/update-worker.mjs.map +2 -2
- package/dist/web/assets/components-C4SKshs2.js +110 -0
- package/dist/web/assets/components-C4SKshs2.js.map +1 -0
- package/dist/web/assets/{components-AKM1pxhf.css → components-CMahvybm.css} +1 -1
- package/dist/web/assets/{main-CEv6hML1.js → main-CZuF2VZA.js} +2 -2
- package/dist/web/assets/{main-CEv6hML1.js.map → main-CZuF2VZA.js.map} +1 -1
- package/dist/web/assets/{ui-preview-Cd3euuid.js → ui-preview-DCeC0YmD.js} +3 -3
- package/dist/web/assets/{ui-preview-Cd3euuid.js.map → ui-preview-DCeC0YmD.js.map} +1 -1
- package/dist/web/index.html +3 -3
- package/dist/web/ui-preview.html +3 -3
- package/package.json +1 -1
- package/src/update-worker.test.ts +53 -12
- package/src/update-worker.ts +158 -3
- package/dist/web/assets/components-BZf_jLGv.js +0 -110
- package/dist/web/assets/components-BZf_jLGv.js.map +0 -1
|
@@ -5,12 +5,26 @@ import { spawn } from "node:child_process";
|
|
|
5
5
|
import { createWriteStream } from "node:fs";
|
|
6
6
|
import { mkdir } from "node:fs/promises";
|
|
7
7
|
import { dirname } from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
var RESTART_HANDOFF_MODE = "restart-handoff";
|
|
10
|
+
var DEFAULT_MODE = "install";
|
|
11
|
+
var RESTART_HANDOFF_WAIT_MS = 5e3;
|
|
12
|
+
var WORKER_ENTRY_PATH = fileURLToPath(import.meta.url);
|
|
8
13
|
async function writeState(filePath, value) {
|
|
9
14
|
await mkdir(dirname(filePath), { recursive: true });
|
|
10
15
|
await import("node:fs/promises").then(
|
|
11
16
|
({ writeFile }) => writeFile(filePath, JSON.stringify(value, null, 2) + "\n", "utf-8")
|
|
12
17
|
);
|
|
13
18
|
}
|
|
19
|
+
function closeLogStream(stream) {
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
stream.once("error", reject);
|
|
22
|
+
stream.end(() => {
|
|
23
|
+
stream.off("error", reject);
|
|
24
|
+
resolve();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
14
28
|
function parseJsonArray(value, fallback) {
|
|
15
29
|
if (!value) {
|
|
16
30
|
return fallback;
|
|
@@ -55,6 +69,17 @@ function buildManualCommand(input) {
|
|
|
55
69
|
`${input.cliCommand} ${input.restartArgs.join(" ")}`
|
|
56
70
|
].join("\n");
|
|
57
71
|
}
|
|
72
|
+
function readWorkerMode(env = process.env) {
|
|
73
|
+
return env.CODER_STUDIO_UPDATE_WORKER_MODE === RESTART_HANDOFF_MODE ? RESTART_HANDOFF_MODE : DEFAULT_MODE;
|
|
74
|
+
}
|
|
75
|
+
function readRestartParentPid(env = process.env) {
|
|
76
|
+
const raw = env.CODER_STUDIO_UPDATE_PARENT_PID;
|
|
77
|
+
if (!raw) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const pid = Number.parseInt(raw, 10);
|
|
81
|
+
return Number.isInteger(pid) && pid > 0 ? pid : null;
|
|
82
|
+
}
|
|
58
83
|
var INTERNAL_ENV_KEYS = /* @__PURE__ */ new Set([
|
|
59
84
|
"CODER_STUDIO_RUNTIME_JSON_PATH",
|
|
60
85
|
"CODER_STUDIO_SESSION_ID",
|
|
@@ -78,6 +103,54 @@ function buildChildProcessEnv(env = process.env) {
|
|
|
78
103
|
}
|
|
79
104
|
return nextEnv;
|
|
80
105
|
}
|
|
106
|
+
function buildWorkerEnv(input) {
|
|
107
|
+
return {
|
|
108
|
+
CODER_STUDIO_UPDATE_STATE_PATH: input.stateFilePath,
|
|
109
|
+
CODER_STUDIO_UPDATE_LOG_PATH: input.logFilePath,
|
|
110
|
+
CODER_STUDIO_UPDATE_PACKAGE_NAME: input.packageName,
|
|
111
|
+
CODER_STUDIO_UPDATE_TARGET_VERSION: input.targetVersion,
|
|
112
|
+
CODER_STUDIO_UPDATE_CLI_COMMAND: input.cliCommand,
|
|
113
|
+
CODER_STUDIO_UPDATE_CURRENT_VERSION: input.currentVersion,
|
|
114
|
+
CODER_STUDIO_UPDATE_NPM_COMMAND: input.npmCommand,
|
|
115
|
+
CODER_STUDIO_UPDATE_RESTART_ARGS: JSON.stringify(input.restartArgs),
|
|
116
|
+
CODER_STUDIO_UPDATE_INSTALL_ARGS_PREFIX: JSON.stringify(input.installArgsPrefix)
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function spawnDetachedProcess(command, args, env) {
|
|
120
|
+
return new Promise((resolve, reject) => {
|
|
121
|
+
const child = spawn(command, args, {
|
|
122
|
+
detached: true,
|
|
123
|
+
stdio: "ignore",
|
|
124
|
+
env
|
|
125
|
+
});
|
|
126
|
+
child.on("error", reject);
|
|
127
|
+
child.unref();
|
|
128
|
+
resolve();
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
var isMissingProcessError = (error) => Boolean(
|
|
132
|
+
error && typeof error === "object" && "code" in error && error.code === "ESRCH"
|
|
133
|
+
);
|
|
134
|
+
async function waitForProcessExit(pid, waitMs = RESTART_HANDOFF_WAIT_MS) {
|
|
135
|
+
const deadline = Date.now() + waitMs;
|
|
136
|
+
while (Date.now() <= deadline) {
|
|
137
|
+
try {
|
|
138
|
+
process.kill(pid, 0);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
if (isMissingProcessError(error)) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
const remainingMs = deadline - Date.now();
|
|
146
|
+
if (remainingMs <= 0) {
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
await new Promise((resolve) => {
|
|
150
|
+
setTimeout(resolve, Math.min(100, remainingMs));
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
81
154
|
function runCommand(command, args, options) {
|
|
82
155
|
return new Promise((resolve, reject) => {
|
|
83
156
|
const child = spawn(command, args, {
|
|
@@ -106,6 +179,8 @@ async function runUpdateWorker(input = readEnv(), deps) {
|
|
|
106
179
|
const logStream = createWriteStream(input.logFilePath, { flags: "a" });
|
|
107
180
|
const execute = deps?.runCommand ?? runCommand;
|
|
108
181
|
const childEnv = buildChildProcessEnv(process.env);
|
|
182
|
+
const processId = deps?.processId ?? process.pid;
|
|
183
|
+
const spawnRestartHandoff = deps?.spawnDetachedProcess ?? spawnDetachedProcess;
|
|
109
184
|
try {
|
|
110
185
|
await execute(
|
|
111
186
|
input.npmCommand,
|
|
@@ -129,7 +204,7 @@ async function runUpdateWorker(input = readEnv(), deps) {
|
|
|
129
204
|
manualCommand: permissionRelated ? buildManualCommand(input) : null,
|
|
130
205
|
errorSummary: message
|
|
131
206
|
});
|
|
132
|
-
logStream
|
|
207
|
+
await closeLogStream(logStream);
|
|
133
208
|
return;
|
|
134
209
|
}
|
|
135
210
|
await writeState(input.stateFilePath, {
|
|
@@ -147,6 +222,44 @@ async function runUpdateWorker(input = readEnv(), deps) {
|
|
|
147
222
|
errorSummary: null
|
|
148
223
|
});
|
|
149
224
|
try {
|
|
225
|
+
await spawnRestartHandoff(process.execPath, [WORKER_ENTRY_PATH], {
|
|
226
|
+
...childEnv,
|
|
227
|
+
...buildWorkerEnv(input),
|
|
228
|
+
CODER_STUDIO_UPDATE_WORKER_MODE: RESTART_HANDOFF_MODE,
|
|
229
|
+
CODER_STUDIO_UPDATE_PARENT_PID: String(processId)
|
|
230
|
+
});
|
|
231
|
+
} catch (error) {
|
|
232
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
233
|
+
await writeState(input.stateFilePath, {
|
|
234
|
+
version: 1,
|
|
235
|
+
currentVersion: input.currentVersion,
|
|
236
|
+
latestVersion: input.targetVersion,
|
|
237
|
+
availability: "update_available",
|
|
238
|
+
updateStatus: "failed",
|
|
239
|
+
lastCheckedAt: now(),
|
|
240
|
+
targetVersion: input.targetVersion,
|
|
241
|
+
startedAt: now(),
|
|
242
|
+
finishedAt: now(),
|
|
243
|
+
requiresManualStep: true,
|
|
244
|
+
manualCommand: `${input.cliCommand} ${input.restartArgs.join(" ")}`,
|
|
245
|
+
errorSummary: `new version installed but service restart failed: ${message}`
|
|
246
|
+
});
|
|
247
|
+
} finally {
|
|
248
|
+
await closeLogStream(logStream);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
async function runRestartHandoff(input = readEnv(), deps) {
|
|
252
|
+
const now = deps?.now ?? Date.now;
|
|
253
|
+
await mkdir(dirname(input.logFilePath), { recursive: true });
|
|
254
|
+
const logStream = createWriteStream(input.logFilePath, { flags: "a" });
|
|
255
|
+
const execute = deps?.runCommand ?? runCommand;
|
|
256
|
+
const waitForParentExit = deps?.waitForProcessExit ?? waitForProcessExit;
|
|
257
|
+
const childEnv = buildChildProcessEnv(process.env);
|
|
258
|
+
const restartParentPid = deps?.restartParentPid ?? readRestartParentPid(process.env);
|
|
259
|
+
try {
|
|
260
|
+
if (restartParentPid !== null) {
|
|
261
|
+
await waitForParentExit(restartParentPid);
|
|
262
|
+
}
|
|
150
263
|
await execute(input.cliCommand, input.restartArgs, { logStream, env: childEnv });
|
|
151
264
|
} catch (error) {
|
|
152
265
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -165,16 +278,18 @@ async function runUpdateWorker(input = readEnv(), deps) {
|
|
|
165
278
|
errorSummary: `new version installed but service restart failed: ${message}`
|
|
166
279
|
});
|
|
167
280
|
} finally {
|
|
168
|
-
logStream
|
|
281
|
+
await closeLogStream(logStream);
|
|
169
282
|
}
|
|
170
283
|
}
|
|
171
284
|
if (process.env.CODER_STUDIO_UPDATE_STATE_PATH) {
|
|
172
|
-
|
|
285
|
+
const run = readWorkerMode(process.env) === RESTART_HANDOFF_MODE ? runRestartHandoff : runUpdateWorker;
|
|
286
|
+
void run().catch((error) => {
|
|
173
287
|
console.error("[update-worker]", error);
|
|
174
288
|
process.exitCode = 1;
|
|
175
289
|
});
|
|
176
290
|
}
|
|
177
291
|
export {
|
|
292
|
+
runRestartHandoff,
|
|
178
293
|
runUpdateWorker
|
|
179
294
|
};
|
|
180
295
|
//# sourceMappingURL=update-worker.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/update-worker.ts"],
|
|
4
|
-
"sourcesContent": ["import { spawn } from \"node:child_process\";\nimport { createWriteStream } from \"node:fs\";\nimport { mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\n\ninterface UpdateStateSnapshot {\n version: 1;\n currentVersion: string;\n latestVersion: string | null;\n availability: \"unknown\" | \"up_to_date\" | \"update_available\" | \"check_failed\";\n updateStatus:\n | \"idle\"\n | \"checking\"\n | \"installing\"\n | \"restarting\"\n | \"succeeded\"\n | \"failed\"\n | \"manual_required\";\n lastCheckedAt: number | null;\n targetVersion: string | null;\n startedAt: number | null;\n finishedAt: number | null;\n requiresManualStep: boolean;\n manualCommand: string | null;\n errorSummary: string | null;\n}\n\ninterface WorkerEnv {\n stateFilePath: string;\n logFilePath: string;\n packageName: string;\n targetVersion: string;\n cliCommand: string;\n currentVersion: string;\n npmCommand: string;\n restartArgs: string[];\n installArgsPrefix: string[];\n}\n\nasync function writeState(filePath: string, value: UpdateStateSnapshot): Promise<void> {\n await mkdir(dirname(filePath), { recursive: true });\n await import(\"node:fs/promises\").then(({ writeFile }) =>\n writeFile(filePath, JSON.stringify(value, null, 2) + \"\\n\", \"utf-8\")\n );\n}\n\nfunction parseJsonArray(value: string | undefined, fallback: string[]): string[] {\n if (!value) {\n return fallback;\n }\n try {\n const parsed = JSON.parse(value) as unknown;\n if (Array.isArray(parsed) && parsed.every((item) => typeof item === \"string\")) {\n return parsed;\n }\n } catch {}\n return fallback;\n}\n\nfunction readEnv(env = process.env): WorkerEnv {\n const stateFilePath = env.CODER_STUDIO_UPDATE_STATE_PATH;\n const logFilePath = env.CODER_STUDIO_UPDATE_LOG_PATH;\n const packageName = env.CODER_STUDIO_UPDATE_PACKAGE_NAME;\n const targetVersion = env.CODER_STUDIO_UPDATE_TARGET_VERSION;\n const cliCommand = env.CODER_STUDIO_UPDATE_CLI_COMMAND;\n const currentVersion = env.CODER_STUDIO_UPDATE_CURRENT_VERSION;\n if (\n !stateFilePath ||\n !logFilePath ||\n !packageName ||\n !targetVersion ||\n !cliCommand ||\n !currentVersion\n ) {\n throw new Error(\"Missing detached update worker environment\");\n }\n return {\n stateFilePath,\n logFilePath,\n packageName,\n targetVersion,\n cliCommand,\n currentVersion,\n npmCommand: env.CODER_STUDIO_UPDATE_NPM_COMMAND || \"npm\",\n restartArgs: parseJsonArray(env.CODER_STUDIO_UPDATE_RESTART_ARGS, [\"serve\", \"--restart\"]),\n installArgsPrefix: parseJsonArray(env.CODER_STUDIO_UPDATE_INSTALL_ARGS_PREFIX, [\n \"install\",\n \"-g\",\n ]),\n };\n}\n\nfunction buildManualCommand(input: WorkerEnv): string {\n return [\n `${input.npmCommand} ${[...input.installArgsPrefix, `${input.packageName}@${input.targetVersion}`].join(\" \")}`,\n `${input.cliCommand} ${input.restartArgs.join(\" \")}`,\n ].join(\"\\n\");\n}\n\nconst INTERNAL_ENV_KEYS = new Set([\n \"CODER_STUDIO_RUNTIME_JSON_PATH\",\n \"CODER_STUDIO_SESSION_ID\",\n \"NODE_APP_INSTANCE\",\n \"NODE_CHANNEL_FD\",\n \"NODE_CHANNEL_SERIALIZATION_MODE\",\n \"PM2_INTERACTOR_PROCESSING\",\n \"PM2_JSON_PROCESSING\",\n \"PM2_PROGRAMMATIC\",\n]);\n\nfunction buildChildProcessEnv(env = process.env): NodeJS.ProcessEnv {\n const nextEnv: NodeJS.ProcessEnv = { ...env };\n\n for (const key of Object.keys(nextEnv)) {\n if (INTERNAL_ENV_KEYS.has(key)) {\n delete nextEnv[key];\n continue;\n }\n\n if (key.startsWith(\"CODER_STUDIO_UPDATE_\") || key.startsWith(\"pm_\")) {\n delete nextEnv[key];\n }\n }\n\n return nextEnv;\n}\n\nfunction runCommand(\n command: string,\n args: string[],\n options?: {\n stdio?: \"ignore\" | \"pipe\";\n logStream?: NodeJS.WritableStream;\n env?: NodeJS.ProcessEnv;\n }\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n stdio: options?.stdio === \"ignore\" ? \"ignore\" : \"pipe\",\n env: options?.env ?? process.env,\n });\n\n if (options?.logStream && child.stdout) {\n child.stdout.pipe(options.logStream, { end: false });\n }\n if (options?.logStream && child.stderr) {\n child.stderr.pipe(options.logStream, { end: false });\n }\n\n child.on(\"error\", reject);\n child.on(\"exit\", (code) => {\n if (code === 0) {\n resolve();\n return;\n }\n reject(new Error(`${command} exited with code ${code ?? 1}`));\n });\n });\n}\n\nexport async function runUpdateWorker(\n input = readEnv(),\n deps?: {\n runCommand?: typeof runCommand;\n now?: () => number;\n }\n): Promise<void> {\n const now = deps?.now ?? Date.now;\n await mkdir(dirname(input.logFilePath), { recursive: true });\n const logStream = createWriteStream(input.logFilePath, { flags: \"a\" });\n const execute = deps?.runCommand ?? runCommand;\n const childEnv = buildChildProcessEnv(process.env);\n\n try {\n await execute(\n input.npmCommand,\n [...input.installArgsPrefix, `${input.packageName}@${input.targetVersion}`],\n { logStream, env: childEnv }\n );\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const permissionRelated =\n /EACCES|EPERM|permission|not permitted/i.test(message) ||\n /requires elevated privileges/i.test(message);\n await writeState(input.stateFilePath, {\n version: 1,\n currentVersion: input.currentVersion,\n latestVersion: input.targetVersion,\n availability: \"update_available\",\n updateStatus: permissionRelated ? \"manual_required\" : \"failed\",\n lastCheckedAt: now(),\n targetVersion: input.targetVersion,\n startedAt: now(),\n finishedAt: now(),\n requiresManualStep: permissionRelated,\n manualCommand: permissionRelated ? buildManualCommand(input) : null,\n errorSummary: message,\n });\n logStream.end();\n return;\n }\n\n await writeState(input.stateFilePath, {\n version: 1,\n currentVersion: input.currentVersion,\n latestVersion: input.targetVersion,\n availability: \"update_available\",\n updateStatus: \"restarting\",\n lastCheckedAt: now(),\n targetVersion: input.targetVersion,\n startedAt: now(),\n finishedAt: null,\n requiresManualStep: false,\n manualCommand: null,\n errorSummary: null,\n });\n\n try {\n await execute(input.cliCommand, input.restartArgs, { logStream, env: childEnv });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n await writeState(input.stateFilePath, {\n version: 1,\n currentVersion: input.currentVersion,\n latestVersion: input.targetVersion,\n availability: \"update_available\",\n updateStatus: \"failed\",\n lastCheckedAt: now(),\n targetVersion: input.targetVersion,\n startedAt: now(),\n finishedAt: now(),\n requiresManualStep: true,\n manualCommand: `${input.cliCommand} ${input.restartArgs.join(\" \")}`,\n errorSummary: `new version installed but service restart failed: ${message}`,\n });\n } finally {\n logStream.end();\n }\n}\n\nif (process.env.CODER_STUDIO_UPDATE_STATE_PATH) {\n void runUpdateWorker().catch((error) => {\n console.error(\"[update-worker]\", error);\n process.exitCode = 1;\n });\n}\n"],
|
|
5
|
-
"mappings": ";;;AAAA,SAAS,aAAa;AACtB,SAAS,yBAAyB;AAClC,SAAS,aAAa;AACtB,SAAS,eAAe;
|
|
4
|
+
"sourcesContent": ["import { spawn } from \"node:child_process\";\nimport { createWriteStream } from \"node:fs\";\nimport { mkdir } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\ninterface UpdateStateSnapshot {\n version: 1;\n currentVersion: string;\n latestVersion: string | null;\n availability: \"unknown\" | \"up_to_date\" | \"update_available\" | \"check_failed\";\n updateStatus:\n | \"idle\"\n | \"checking\"\n | \"installing\"\n | \"restarting\"\n | \"succeeded\"\n | \"failed\"\n | \"manual_required\";\n lastCheckedAt: number | null;\n targetVersion: string | null;\n startedAt: number | null;\n finishedAt: number | null;\n requiresManualStep: boolean;\n manualCommand: string | null;\n errorSummary: string | null;\n}\n\ninterface WorkerEnv {\n stateFilePath: string;\n logFilePath: string;\n packageName: string;\n targetVersion: string;\n cliCommand: string;\n currentVersion: string;\n npmCommand: string;\n restartArgs: string[];\n installArgsPrefix: string[];\n}\n\ntype WorkerMode = \"install\" | \"restart-handoff\";\n\nconst RESTART_HANDOFF_MODE: WorkerMode = \"restart-handoff\";\nconst DEFAULT_MODE: WorkerMode = \"install\";\nconst RESTART_HANDOFF_WAIT_MS = 5_000;\nconst WORKER_ENTRY_PATH = fileURLToPath(import.meta.url);\n\nasync function writeState(filePath: string, value: UpdateStateSnapshot): Promise<void> {\n await mkdir(dirname(filePath), { recursive: true });\n await import(\"node:fs/promises\").then(({ writeFile }) =>\n writeFile(filePath, JSON.stringify(value, null, 2) + \"\\n\", \"utf-8\")\n );\n}\n\nfunction closeLogStream(stream: NodeJS.WritableStream): Promise<void> {\n return new Promise((resolve, reject) => {\n stream.once(\"error\", reject);\n stream.end(() => {\n stream.off(\"error\", reject);\n resolve();\n });\n });\n}\n\nfunction parseJsonArray(value: string | undefined, fallback: string[]): string[] {\n if (!value) {\n return fallback;\n }\n try {\n const parsed = JSON.parse(value) as unknown;\n if (Array.isArray(parsed) && parsed.every((item) => typeof item === \"string\")) {\n return parsed;\n }\n } catch {}\n return fallback;\n}\n\nfunction readEnv(env = process.env): WorkerEnv {\n const stateFilePath = env.CODER_STUDIO_UPDATE_STATE_PATH;\n const logFilePath = env.CODER_STUDIO_UPDATE_LOG_PATH;\n const packageName = env.CODER_STUDIO_UPDATE_PACKAGE_NAME;\n const targetVersion = env.CODER_STUDIO_UPDATE_TARGET_VERSION;\n const cliCommand = env.CODER_STUDIO_UPDATE_CLI_COMMAND;\n const currentVersion = env.CODER_STUDIO_UPDATE_CURRENT_VERSION;\n if (\n !stateFilePath ||\n !logFilePath ||\n !packageName ||\n !targetVersion ||\n !cliCommand ||\n !currentVersion\n ) {\n throw new Error(\"Missing detached update worker environment\");\n }\n return {\n stateFilePath,\n logFilePath,\n packageName,\n targetVersion,\n cliCommand,\n currentVersion,\n npmCommand: env.CODER_STUDIO_UPDATE_NPM_COMMAND || \"npm\",\n restartArgs: parseJsonArray(env.CODER_STUDIO_UPDATE_RESTART_ARGS, [\"serve\", \"--restart\"]),\n installArgsPrefix: parseJsonArray(env.CODER_STUDIO_UPDATE_INSTALL_ARGS_PREFIX, [\n \"install\",\n \"-g\",\n ]),\n };\n}\n\nfunction buildManualCommand(input: WorkerEnv): string {\n return [\n `${input.npmCommand} ${[...input.installArgsPrefix, `${input.packageName}@${input.targetVersion}`].join(\" \")}`,\n `${input.cliCommand} ${input.restartArgs.join(\" \")}`,\n ].join(\"\\n\");\n}\n\nfunction readWorkerMode(env = process.env): WorkerMode {\n return env.CODER_STUDIO_UPDATE_WORKER_MODE === RESTART_HANDOFF_MODE\n ? RESTART_HANDOFF_MODE\n : DEFAULT_MODE;\n}\n\nfunction readRestartParentPid(env = process.env): number | null {\n const raw = env.CODER_STUDIO_UPDATE_PARENT_PID;\n if (!raw) {\n return null;\n }\n\n const pid = Number.parseInt(raw, 10);\n return Number.isInteger(pid) && pid > 0 ? pid : null;\n}\n\nconst INTERNAL_ENV_KEYS = new Set([\n \"CODER_STUDIO_RUNTIME_JSON_PATH\",\n \"CODER_STUDIO_SESSION_ID\",\n \"NODE_APP_INSTANCE\",\n \"NODE_CHANNEL_FD\",\n \"NODE_CHANNEL_SERIALIZATION_MODE\",\n \"PM2_INTERACTOR_PROCESSING\",\n \"PM2_JSON_PROCESSING\",\n \"PM2_PROGRAMMATIC\",\n]);\n\nfunction buildChildProcessEnv(env = process.env): NodeJS.ProcessEnv {\n const nextEnv: NodeJS.ProcessEnv = { ...env };\n\n for (const key of Object.keys(nextEnv)) {\n if (INTERNAL_ENV_KEYS.has(key)) {\n delete nextEnv[key];\n continue;\n }\n\n if (key.startsWith(\"CODER_STUDIO_UPDATE_\") || key.startsWith(\"pm_\")) {\n delete nextEnv[key];\n }\n }\n\n return nextEnv;\n}\n\nfunction buildWorkerEnv(input: WorkerEnv): NodeJS.ProcessEnv {\n return {\n CODER_STUDIO_UPDATE_STATE_PATH: input.stateFilePath,\n CODER_STUDIO_UPDATE_LOG_PATH: input.logFilePath,\n CODER_STUDIO_UPDATE_PACKAGE_NAME: input.packageName,\n CODER_STUDIO_UPDATE_TARGET_VERSION: input.targetVersion,\n CODER_STUDIO_UPDATE_CLI_COMMAND: input.cliCommand,\n CODER_STUDIO_UPDATE_CURRENT_VERSION: input.currentVersion,\n CODER_STUDIO_UPDATE_NPM_COMMAND: input.npmCommand,\n CODER_STUDIO_UPDATE_RESTART_ARGS: JSON.stringify(input.restartArgs),\n CODER_STUDIO_UPDATE_INSTALL_ARGS_PREFIX: JSON.stringify(input.installArgsPrefix),\n };\n}\n\nfunction spawnDetachedProcess(\n command: string,\n args: string[],\n env: NodeJS.ProcessEnv\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n detached: true,\n stdio: \"ignore\",\n env,\n });\n\n child.on(\"error\", reject);\n child.unref();\n resolve();\n });\n}\n\nconst isMissingProcessError = (error: unknown): boolean =>\n Boolean(\n error &&\n typeof error === \"object\" &&\n \"code\" in error &&\n (error as NodeJS.ErrnoException).code === \"ESRCH\"\n );\n\nasync function waitForProcessExit(pid: number, waitMs = RESTART_HANDOFF_WAIT_MS): Promise<void> {\n const deadline = Date.now() + waitMs;\n\n while (Date.now() <= deadline) {\n try {\n process.kill(pid, 0);\n } catch (error) {\n if (isMissingProcessError(error)) {\n return;\n }\n\n throw error;\n }\n\n const remainingMs = deadline - Date.now();\n if (remainingMs <= 0) {\n break;\n }\n\n await new Promise((resolve) => {\n setTimeout(resolve, Math.min(100, remainingMs));\n });\n }\n}\n\nfunction runCommand(\n command: string,\n args: string[],\n options?: {\n stdio?: \"ignore\" | \"pipe\";\n logStream?: NodeJS.WritableStream;\n env?: NodeJS.ProcessEnv;\n }\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n stdio: options?.stdio === \"ignore\" ? \"ignore\" : \"pipe\",\n env: options?.env ?? process.env,\n });\n\n if (options?.logStream && child.stdout) {\n child.stdout.pipe(options.logStream, { end: false });\n }\n if (options?.logStream && child.stderr) {\n child.stderr.pipe(options.logStream, { end: false });\n }\n\n child.on(\"error\", reject);\n child.on(\"exit\", (code) => {\n if (code === 0) {\n resolve();\n return;\n }\n reject(new Error(`${command} exited with code ${code ?? 1}`));\n });\n });\n}\n\nexport async function runUpdateWorker(\n input = readEnv(),\n deps?: {\n runCommand?: typeof runCommand;\n now?: () => number;\n processId?: number;\n spawnDetachedProcess?: typeof spawnDetachedProcess;\n }\n): Promise<void> {\n const now = deps?.now ?? Date.now;\n await mkdir(dirname(input.logFilePath), { recursive: true });\n const logStream = createWriteStream(input.logFilePath, { flags: \"a\" });\n const execute = deps?.runCommand ?? runCommand;\n const childEnv = buildChildProcessEnv(process.env);\n const processId = deps?.processId ?? process.pid;\n const spawnRestartHandoff = deps?.spawnDetachedProcess ?? spawnDetachedProcess;\n\n try {\n await execute(\n input.npmCommand,\n [...input.installArgsPrefix, `${input.packageName}@${input.targetVersion}`],\n { logStream, env: childEnv }\n );\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const permissionRelated =\n /EACCES|EPERM|permission|not permitted/i.test(message) ||\n /requires elevated privileges/i.test(message);\n await writeState(input.stateFilePath, {\n version: 1,\n currentVersion: input.currentVersion,\n latestVersion: input.targetVersion,\n availability: \"update_available\",\n updateStatus: permissionRelated ? \"manual_required\" : \"failed\",\n lastCheckedAt: now(),\n targetVersion: input.targetVersion,\n startedAt: now(),\n finishedAt: now(),\n requiresManualStep: permissionRelated,\n manualCommand: permissionRelated ? buildManualCommand(input) : null,\n errorSummary: message,\n });\n await closeLogStream(logStream);\n return;\n }\n\n await writeState(input.stateFilePath, {\n version: 1,\n currentVersion: input.currentVersion,\n latestVersion: input.targetVersion,\n availability: \"update_available\",\n updateStatus: \"restarting\",\n lastCheckedAt: now(),\n targetVersion: input.targetVersion,\n startedAt: now(),\n finishedAt: null,\n requiresManualStep: false,\n manualCommand: null,\n errorSummary: null,\n });\n\n try {\n await spawnRestartHandoff(process.execPath, [WORKER_ENTRY_PATH], {\n ...childEnv,\n ...buildWorkerEnv(input),\n CODER_STUDIO_UPDATE_WORKER_MODE: RESTART_HANDOFF_MODE,\n CODER_STUDIO_UPDATE_PARENT_PID: String(processId),\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n await writeState(input.stateFilePath, {\n version: 1,\n currentVersion: input.currentVersion,\n latestVersion: input.targetVersion,\n availability: \"update_available\",\n updateStatus: \"failed\",\n lastCheckedAt: now(),\n targetVersion: input.targetVersion,\n startedAt: now(),\n finishedAt: now(),\n requiresManualStep: true,\n manualCommand: `${input.cliCommand} ${input.restartArgs.join(\" \")}`,\n errorSummary: `new version installed but service restart failed: ${message}`,\n });\n } finally {\n await closeLogStream(logStream);\n }\n}\n\nexport async function runRestartHandoff(\n input = readEnv(),\n deps?: {\n runCommand?: typeof runCommand;\n now?: () => number;\n waitForProcessExit?: typeof waitForProcessExit;\n restartParentPid?: number | null;\n }\n): Promise<void> {\n const now = deps?.now ?? Date.now;\n await mkdir(dirname(input.logFilePath), { recursive: true });\n const logStream = createWriteStream(input.logFilePath, { flags: \"a\" });\n const execute = deps?.runCommand ?? runCommand;\n const waitForParentExit = deps?.waitForProcessExit ?? waitForProcessExit;\n const childEnv = buildChildProcessEnv(process.env);\n const restartParentPid = deps?.restartParentPid ?? readRestartParentPid(process.env);\n\n try {\n if (restartParentPid !== null) {\n await waitForParentExit(restartParentPid);\n }\n\n await execute(input.cliCommand, input.restartArgs, { logStream, env: childEnv });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n await writeState(input.stateFilePath, {\n version: 1,\n currentVersion: input.currentVersion,\n latestVersion: input.targetVersion,\n availability: \"update_available\",\n updateStatus: \"failed\",\n lastCheckedAt: now(),\n targetVersion: input.targetVersion,\n startedAt: now(),\n finishedAt: now(),\n requiresManualStep: true,\n manualCommand: `${input.cliCommand} ${input.restartArgs.join(\" \")}`,\n errorSummary: `new version installed but service restart failed: ${message}`,\n });\n } finally {\n await closeLogStream(logStream);\n }\n}\n\nif (process.env.CODER_STUDIO_UPDATE_STATE_PATH) {\n const run =\n readWorkerMode(process.env) === RESTART_HANDOFF_MODE ? runRestartHandoff : runUpdateWorker;\n\n void run().catch((error) => {\n console.error(\"[update-worker]\", error);\n process.exitCode = 1;\n });\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|