@spencer-kit/coder-studio 0.4.2 → 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 +16 -0
- package/dist/esm/bin.mjs +460 -91
- 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 +145 -6
- 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-D3dXqSaA.js → main-CZuF2VZA.js} +2 -2
- package/dist/web/assets/{main-D3dXqSaA.js.map → main-CZuF2VZA.js.map} +1 -1
- package/dist/web/assets/{ui-preview-BGZz053-.js → ui-preview-DCeC0YmD.js} +3 -3
- package/dist/web/assets/{ui-preview-BGZz053-.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/pm2-control.test.ts +48 -6
- package/src/pm2-control.ts +43 -2
- package/src/update-worker.test.ts +113 -12
- package/src/update-worker.ts +195 -7
- package/dist/web/assets/components-omWbMLvf.js +0 -110
- package/dist/web/assets/components-omWbMLvf.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,11 +69,93 @@ 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
|
+
}
|
|
83
|
+
var INTERNAL_ENV_KEYS = /* @__PURE__ */ new Set([
|
|
84
|
+
"CODER_STUDIO_RUNTIME_JSON_PATH",
|
|
85
|
+
"CODER_STUDIO_SESSION_ID",
|
|
86
|
+
"NODE_APP_INSTANCE",
|
|
87
|
+
"NODE_CHANNEL_FD",
|
|
88
|
+
"NODE_CHANNEL_SERIALIZATION_MODE",
|
|
89
|
+
"PM2_INTERACTOR_PROCESSING",
|
|
90
|
+
"PM2_JSON_PROCESSING",
|
|
91
|
+
"PM2_PROGRAMMATIC"
|
|
92
|
+
]);
|
|
93
|
+
function buildChildProcessEnv(env = process.env) {
|
|
94
|
+
const nextEnv = { ...env };
|
|
95
|
+
for (const key of Object.keys(nextEnv)) {
|
|
96
|
+
if (INTERNAL_ENV_KEYS.has(key)) {
|
|
97
|
+
delete nextEnv[key];
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (key.startsWith("CODER_STUDIO_UPDATE_") || key.startsWith("pm_")) {
|
|
101
|
+
delete nextEnv[key];
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return nextEnv;
|
|
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
|
+
}
|
|
58
154
|
function runCommand(command, args, options) {
|
|
59
155
|
return new Promise((resolve, reject) => {
|
|
60
156
|
const child = spawn(command, args, {
|
|
61
157
|
stdio: options?.stdio === "ignore" ? "ignore" : "pipe",
|
|
62
|
-
env: process.env
|
|
158
|
+
env: options?.env ?? process.env
|
|
63
159
|
});
|
|
64
160
|
if (options?.logStream && child.stdout) {
|
|
65
161
|
child.stdout.pipe(options.logStream, { end: false });
|
|
@@ -82,11 +178,14 @@ async function runUpdateWorker(input = readEnv(), deps) {
|
|
|
82
178
|
await mkdir(dirname(input.logFilePath), { recursive: true });
|
|
83
179
|
const logStream = createWriteStream(input.logFilePath, { flags: "a" });
|
|
84
180
|
const execute = deps?.runCommand ?? runCommand;
|
|
181
|
+
const childEnv = buildChildProcessEnv(process.env);
|
|
182
|
+
const processId = deps?.processId ?? process.pid;
|
|
183
|
+
const spawnRestartHandoff = deps?.spawnDetachedProcess ?? spawnDetachedProcess;
|
|
85
184
|
try {
|
|
86
185
|
await execute(
|
|
87
186
|
input.npmCommand,
|
|
88
187
|
[...input.installArgsPrefix, `${input.packageName}@${input.targetVersion}`],
|
|
89
|
-
{ logStream }
|
|
188
|
+
{ logStream, env: childEnv }
|
|
90
189
|
);
|
|
91
190
|
} catch (error) {
|
|
92
191
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -105,7 +204,7 @@ async function runUpdateWorker(input = readEnv(), deps) {
|
|
|
105
204
|
manualCommand: permissionRelated ? buildManualCommand(input) : null,
|
|
106
205
|
errorSummary: message
|
|
107
206
|
});
|
|
108
|
-
logStream
|
|
207
|
+
await closeLogStream(logStream);
|
|
109
208
|
return;
|
|
110
209
|
}
|
|
111
210
|
await writeState(input.stateFilePath, {
|
|
@@ -123,7 +222,45 @@ async function runUpdateWorker(input = readEnv(), deps) {
|
|
|
123
222
|
errorSummary: null
|
|
124
223
|
});
|
|
125
224
|
try {
|
|
126
|
-
await
|
|
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
|
+
}
|
|
263
|
+
await execute(input.cliCommand, input.restartArgs, { logStream, env: childEnv });
|
|
127
264
|
} catch (error) {
|
|
128
265
|
const message = error instanceof Error ? error.message : String(error);
|
|
129
266
|
await writeState(input.stateFilePath, {
|
|
@@ -141,16 +278,18 @@ async function runUpdateWorker(input = readEnv(), deps) {
|
|
|
141
278
|
errorSummary: `new version installed but service restart failed: ${message}`
|
|
142
279
|
});
|
|
143
280
|
} finally {
|
|
144
|
-
logStream
|
|
281
|
+
await closeLogStream(logStream);
|
|
145
282
|
}
|
|
146
283
|
}
|
|
147
284
|
if (process.env.CODER_STUDIO_UPDATE_STATE_PATH) {
|
|
148
|
-
|
|
285
|
+
const run = readWorkerMode(process.env) === RESTART_HANDOFF_MODE ? runRestartHandoff : runUpdateWorker;
|
|
286
|
+
void run().catch((error) => {
|
|
149
287
|
console.error("[update-worker]", error);
|
|
150
288
|
process.exitCode = 1;
|
|
151
289
|
});
|
|
152
290
|
}
|
|
153
291
|
export {
|
|
292
|
+
runRestartHandoff,
|
|
154
293
|
runUpdateWorker
|
|
155
294
|
};
|
|
156
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\nfunction runCommand(\n command: string,\n args: string[],\n options?: { stdio?: \"ignore\" | \"pipe\"; logStream?: NodeJS.WritableStream }\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n stdio: options?.stdio === \"ignore\" ? \"ignore\" : \"pipe\",\n 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\n try {\n await execute(\n input.npmCommand,\n [...input.installArgsPrefix, `${input.packageName}@${input.targetVersion}`],\n { logStream }\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 });\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": ";;;AAAA,SAAS,aAAa;AACtB,SAAS,yBAAyB;AAClC,SAAS,aAAa;AACtB,SAAS,eAAe;AACxB,SAAS,qBAAqB;AAsC9B,IAAM,uBAAmC;AACzC,IAAM,eAA2B;AACjC,IAAM,0BAA0B;AAChC,IAAM,oBAAoB,cAAc,YAAY,GAAG;AAEvD,eAAe,WAAW,UAAkB,OAA2C;AACrF,QAAM,MAAM,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;AAClD,QAAM,OAAO,kBAAkB,EAAE;AAAA,IAAK,CAAC,EAAE,UAAU,MACjD,UAAU,UAAU,KAAK,UAAU,OAAO,MAAM,CAAC,IAAI,MAAM,OAAO;AAAA,EACpE;AACF;AAEA,SAAS,eAAe,QAA8C;AACpE,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,WAAO,KAAK,SAAS,MAAM;AAC3B,WAAO,IAAI,MAAM;AACf,aAAO,IAAI,SAAS,MAAM;AAC1B,cAAQ;AAAA,IACV,CAAC;AAAA,EACH,CAAC;AACH;AAEA,SAAS,eAAe,OAA2B,UAA8B;AAC/E,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,QAAI,MAAM,QAAQ,MAAM,KAAK,OAAO,MAAM,CAAC,SAAS,OAAO,SAAS,QAAQ,GAAG;AAC7E,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAAC;AACT,SAAO;AACT;AAEA,SAAS,QAAQ,MAAM,QAAQ,KAAgB;AAC7C,QAAM,gBAAgB,IAAI;AAC1B,QAAM,cAAc,IAAI;AACxB,QAAM,cAAc,IAAI;AACxB,QAAM,gBAAgB,IAAI;AAC1B,QAAM,aAAa,IAAI;AACvB,QAAM,iBAAiB,IAAI;AAC3B,MACE,CAAC,iBACD,CAAC,eACD,CAAC,eACD,CAAC,iBACD,CAAC,cACD,CAAC,gBACD;AACA,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY,IAAI,mCAAmC;AAAA,IACnD,aAAa,eAAe,IAAI,kCAAkC,CAAC,SAAS,WAAW,CAAC;AAAA,IACxF,mBAAmB,eAAe,IAAI,yCAAyC;AAAA,MAC7E;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,SAAS,mBAAmB,OAA0B;AACpD,SAAO;AAAA,IACL,GAAG,MAAM,UAAU,IAAI,CAAC,GAAG,MAAM,mBAAmB,GAAG,MAAM,WAAW,IAAI,MAAM,aAAa,EAAE,EAAE,KAAK,GAAG,CAAC;AAAA,IAC5G,GAAG,MAAM,UAAU,IAAI,MAAM,YAAY,KAAK,GAAG,CAAC;AAAA,EACpD,EAAE,KAAK,IAAI;AACb;AAEA,SAAS,eAAe,MAAM,QAAQ,KAAiB;AACrD,SAAO,IAAI,oCAAoC,uBAC3C,uBACA;AACN;AAEA,SAAS,qBAAqB,MAAM,QAAQ,KAAoB;AAC9D,QAAM,MAAM,IAAI;AAChB,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,OAAO,SAAS,KAAK,EAAE;AACnC,SAAO,OAAO,UAAU,GAAG,KAAK,MAAM,IAAI,MAAM;AAClD;AAEA,IAAM,oBAAoB,oBAAI,IAAI;AAAA,EAChC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,qBAAqB,MAAM,QAAQ,KAAwB;AAClE,QAAM,UAA6B,EAAE,GAAG,IAAI;AAE5C,aAAW,OAAO,OAAO,KAAK,OAAO,GAAG;AACtC,QAAI,kBAAkB,IAAI,GAAG,GAAG;AAC9B,aAAO,QAAQ,GAAG;AAClB;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,sBAAsB,KAAK,IAAI,WAAW,KAAK,GAAG;AACnE,aAAO,QAAQ,GAAG;AAAA,IACpB;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,eAAe,OAAqC;AAC3D,SAAO;AAAA,IACL,gCAAgC,MAAM;AAAA,IACtC,8BAA8B,MAAM;AAAA,IACpC,kCAAkC,MAAM;AAAA,IACxC,oCAAoC,MAAM;AAAA,IAC1C,iCAAiC,MAAM;AAAA,IACvC,qCAAqC,MAAM;AAAA,IAC3C,iCAAiC,MAAM;AAAA,IACvC,kCAAkC,KAAK,UAAU,MAAM,WAAW;AAAA,IAClE,yCAAyC,KAAK,UAAU,MAAM,iBAAiB;AAAA,EACjF;AACF;AAEA,SAAS,qBACP,SACA,MACA,KACe;AACf,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,QAAQ,MAAM,SAAS,MAAM;AAAA,MACjC,UAAU;AAAA,MACV,OAAO;AAAA,MACP;AAAA,IACF,CAAC;AAED,UAAM,GAAG,SAAS,MAAM;AACxB,UAAM,MAAM;AACZ,YAAQ;AAAA,EACV,CAAC;AACH;AAEA,IAAM,wBAAwB,CAAC,UAC7B;AAAA,EACE,SACE,OAAO,UAAU,YACjB,UAAU,SACT,MAAgC,SAAS;AAC9C;AAEF,eAAe,mBAAmB,KAAa,SAAS,yBAAwC;AAC9F,QAAM,WAAW,KAAK,IAAI,IAAI;AAE9B,SAAO,KAAK,IAAI,KAAK,UAAU;AAC7B,QAAI;AACF,cAAQ,KAAK,KAAK,CAAC;AAAA,IACrB,SAAS,OAAO;AACd,UAAI,sBAAsB,KAAK,GAAG;AAChC;AAAA,MACF;AAEA,YAAM;AAAA,IACR;AAEA,UAAM,cAAc,WAAW,KAAK,IAAI;AACxC,QAAI,eAAe,GAAG;AACpB;AAAA,IACF;AAEA,UAAM,IAAI,QAAQ,CAAC,YAAY;AAC7B,iBAAW,SAAS,KAAK,IAAI,KAAK,WAAW,CAAC;AAAA,IAChD,CAAC;AAAA,EACH;AACF;AAEA,SAAS,WACP,SACA,MACA,SAKe;AACf,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,QAAQ,MAAM,SAAS,MAAM;AAAA,MACjC,OAAO,SAAS,UAAU,WAAW,WAAW;AAAA,MAChD,KAAK,SAAS,OAAO,QAAQ;AAAA,IAC/B,CAAC;AAED,QAAI,SAAS,aAAa,MAAM,QAAQ;AACtC,YAAM,OAAO,KAAK,QAAQ,WAAW,EAAE,KAAK,MAAM,CAAC;AAAA,IACrD;AACA,QAAI,SAAS,aAAa,MAAM,QAAQ;AACtC,YAAM,OAAO,KAAK,QAAQ,WAAW,EAAE,KAAK,MAAM,CAAC;AAAA,IACrD;AAEA,UAAM,GAAG,SAAS,MAAM;AACxB,UAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,UAAI,SAAS,GAAG;AACd,gBAAQ;AACR;AAAA,MACF;AACA,aAAO,IAAI,MAAM,GAAG,OAAO,qBAAqB,QAAQ,CAAC,EAAE,CAAC;AAAA,IAC9D,CAAC;AAAA,EACH,CAAC;AACH;AAEA,eAAsB,gBACpB,QAAQ,QAAQ,GAChB,MAMe;AACf,QAAM,MAAM,MAAM,OAAO,KAAK;AAC9B,QAAM,MAAM,QAAQ,MAAM,WAAW,GAAG,EAAE,WAAW,KAAK,CAAC;AAC3D,QAAM,YAAY,kBAAkB,MAAM,aAAa,EAAE,OAAO,IAAI,CAAC;AACrE,QAAM,UAAU,MAAM,cAAc;AACpC,QAAM,WAAW,qBAAqB,QAAQ,GAAG;AACjD,QAAM,YAAY,MAAM,aAAa,QAAQ;AAC7C,QAAM,sBAAsB,MAAM,wBAAwB;AAE1D,MAAI;AACF,UAAM;AAAA,MACJ,MAAM;AAAA,MACN,CAAC,GAAG,MAAM,mBAAmB,GAAG,MAAM,WAAW,IAAI,MAAM,aAAa,EAAE;AAAA,MAC1E,EAAE,WAAW,KAAK,SAAS;AAAA,IAC7B;AAAA,EACF,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,UAAM,oBACJ,yCAAyC,KAAK,OAAO,KACrD,gCAAgC,KAAK,OAAO;AAC9C,UAAM,WAAW,MAAM,eAAe;AAAA,MACpC,SAAS;AAAA,MACT,gBAAgB,MAAM;AAAA,MACtB,eAAe,MAAM;AAAA,MACrB,cAAc;AAAA,MACd,cAAc,oBAAoB,oBAAoB;AAAA,MACtD,eAAe,IAAI;AAAA,MACnB,eAAe,MAAM;AAAA,MACrB,WAAW,IAAI;AAAA,MACf,YAAY,IAAI;AAAA,MAChB,oBAAoB;AAAA,MACpB,eAAe,oBAAoB,mBAAmB,KAAK,IAAI;AAAA,MAC/D,cAAc;AAAA,IAChB,CAAC;AACD,UAAM,eAAe,SAAS;AAC9B;AAAA,EACF;AAEA,QAAM,WAAW,MAAM,eAAe;AAAA,IACpC,SAAS;AAAA,IACT,gBAAgB,MAAM;AAAA,IACtB,eAAe,MAAM;AAAA,IACrB,cAAc;AAAA,IACd,cAAc;AAAA,IACd,eAAe,IAAI;AAAA,IACnB,eAAe,MAAM;AAAA,IACrB,WAAW,IAAI;AAAA,IACf,YAAY;AAAA,IACZ,oBAAoB;AAAA,IACpB,eAAe;AAAA,IACf,cAAc;AAAA,EAChB,CAAC;AAED,MAAI;AACF,UAAM,oBAAoB,QAAQ,UAAU,CAAC,iBAAiB,GAAG;AAAA,MAC/D,GAAG;AAAA,MACH,GAAG,eAAe,KAAK;AAAA,MACvB,iCAAiC;AAAA,MACjC,gCAAgC,OAAO,SAAS;AAAA,IAClD,CAAC;AAAA,EACH,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,UAAM,WAAW,MAAM,eAAe;AAAA,MACpC,SAAS;AAAA,MACT,gBAAgB,MAAM;AAAA,MACtB,eAAe,MAAM;AAAA,MACrB,cAAc;AAAA,MACd,cAAc;AAAA,MACd,eAAe,IAAI;AAAA,MACnB,eAAe,MAAM;AAAA,MACrB,WAAW,IAAI;AAAA,MACf,YAAY,IAAI;AAAA,MAChB,oBAAoB;AAAA,MACpB,eAAe,GAAG,MAAM,UAAU,IAAI,MAAM,YAAY,KAAK,GAAG,CAAC;AAAA,MACjE,cAAc,qDAAqD,OAAO;AAAA,IAC5E,CAAC;AAAA,EACH,UAAE;AACA,UAAM,eAAe,SAAS;AAAA,EAChC;AACF;AAEA,eAAsB,kBACpB,QAAQ,QAAQ,GAChB,MAMe;AACf,QAAM,MAAM,MAAM,OAAO,KAAK;AAC9B,QAAM,MAAM,QAAQ,MAAM,WAAW,GAAG,EAAE,WAAW,KAAK,CAAC;AAC3D,QAAM,YAAY,kBAAkB,MAAM,aAAa,EAAE,OAAO,IAAI,CAAC;AACrE,QAAM,UAAU,MAAM,cAAc;AACpC,QAAM,oBAAoB,MAAM,sBAAsB;AACtD,QAAM,WAAW,qBAAqB,QAAQ,GAAG;AACjD,QAAM,mBAAmB,MAAM,oBAAoB,qBAAqB,QAAQ,GAAG;AAEnF,MAAI;AACF,QAAI,qBAAqB,MAAM;AAC7B,YAAM,kBAAkB,gBAAgB;AAAA,IAC1C;AAEA,UAAM,QAAQ,MAAM,YAAY,MAAM,aAAa,EAAE,WAAW,KAAK,SAAS,CAAC;AAAA,EACjF,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,UAAM,WAAW,MAAM,eAAe;AAAA,MACpC,SAAS;AAAA,MACT,gBAAgB,MAAM;AAAA,MACtB,eAAe,MAAM;AAAA,MACrB,cAAc;AAAA,MACd,cAAc;AAAA,MACd,eAAe,IAAI;AAAA,MACnB,eAAe,MAAM;AAAA,MACrB,WAAW,IAAI;AAAA,MACf,YAAY,IAAI;AAAA,MAChB,oBAAoB;AAAA,MACpB,eAAe,GAAG,MAAM,UAAU,IAAI,MAAM,YAAY,KAAK,GAAG,CAAC;AAAA,MACjE,cAAc,qDAAqD,OAAO;AAAA,IAC5E,CAAC;AAAA,EACH,UAAE;AACA,UAAM,eAAe,SAAS;AAAA,EAChC;AACF;AAEA,IAAI,QAAQ,IAAI,gCAAgC;AAC9C,QAAM,MACJ,eAAe,QAAQ,GAAG,MAAM,uBAAuB,oBAAoB;AAE7E,OAAK,IAAI,EAAE,MAAM,CAAC,UAAU;AAC1B,YAAQ,MAAM,mBAAmB,KAAK;AACtC,YAAQ,WAAW;AAAA,EACrB,CAAC;AACH;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|