@sigil0/looking-glass 0.1.0 → 0.2.0
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/README.md +143 -61
- package/dist/agents/coordinator.js +1 -1
- package/dist/agents/coordinator.js.map +1 -1
- package/dist/cli.js +14 -8
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +5 -3
- package/dist/config.js.map +1 -1
- package/dist/paths.d.ts +8 -4
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +39 -15
- package/dist/paths.js.map +1 -1
- package/dist/scheduler/index.d.ts +5 -1
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +3 -1
- package/dist/scheduler/index.js.map +1 -1
- package/dist/scheduler/runner.d.ts.map +1 -1
- package/dist/scheduler/runner.js +35 -3
- package/dist/scheduler/runner.js.map +1 -1
- package/dist/scheduler/service.d.ts +15 -0
- package/dist/scheduler/service.d.ts.map +1 -0
- package/dist/scheduler/service.js +20 -0
- package/dist/scheduler/service.js.map +1 -0
- package/dist/scheduler/windows.d.ts +87 -0
- package/dist/scheduler/windows.d.ts.map +1 -0
- package/dist/scheduler/windows.js +506 -0
- package/dist/scheduler/windows.js.map +1 -0
- package/dist/storage/artifact-store.d.ts +2 -1
- package/dist/storage/artifact-store.d.ts.map +1 -1
- package/dist/storage/artifact-store.js +8 -3
- package/dist/storage/artifact-store.js.map +1 -1
- package/dist/storage/database.d.ts +1 -1
- package/dist/storage/database.d.ts.map +1 -1
- package/dist/storage/database.js +10 -6
- package/dist/storage/database.js.map +1 -1
- package/dist/tools/apply-patch.d.ts +15 -0
- package/dist/tools/apply-patch.d.ts.map +1 -1
- package/dist/tools/apply-patch.js +81 -12
- package/dist/tools/apply-patch.js.map +1 -1
- package/dist/tools/bash.d.ts +2 -0
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +43 -22
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/executable.d.ts +13 -0
- package/dist/tools/executable.d.ts.map +1 -0
- package/dist/tools/executable.js +82 -0
- package/dist/tools/executable.js.map +1 -0
- package/dist/tools/process.d.ts +8 -0
- package/dist/tools/process.d.ts.map +1 -1
- package/dist/tools/process.js +105 -35
- package/dist/tools/process.js.map +1 -1
- package/dist/tools/safety.d.ts +5 -1
- package/dist/tools/safety.d.ts.map +1 -1
- package/dist/tools/safety.js +125 -7
- package/dist/tools/safety.js.map +1 -1
- package/dist/tools/schedule.d.ts.map +1 -1
- package/dist/tools/schedule.js +4 -3
- package/dist/tools/schedule.js.map +1 -1
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +9 -4
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/shell.d.ts +30 -0
- package/dist/tools/shell.d.ts.map +1 -0
- package/dist/tools/shell.js +51 -0
- package/dist/tools/shell.js.map +1 -0
- package/dist/ui/tui.d.ts +6 -0
- package/dist/ui/tui.d.ts.map +1 -1
- package/dist/ui/tui.js +44 -21
- package/dist/ui/tui.js.map +1 -1
- package/looking-glass-title.svg +69 -0
- package/package.json +7 -5
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { isAbsolute, join, resolve, win32 } from "node:path";
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
import { configDir } from "../paths.js";
|
|
7
|
+
import { powershellExecutable, windowsSystemExecutable } from "../tools/shell.js";
|
|
8
|
+
/** The per-user task used by the scheduler on Windows. */
|
|
9
|
+
export const TASK_NAME = "Looking Glass Scheduler";
|
|
10
|
+
/** Compatibility name shared with the systemd backend's public vocabulary. */
|
|
11
|
+
export const SERVICE_NAME = TASK_NAME;
|
|
12
|
+
export const LAUNCHER_FILE_NAME = "scheduler-launcher.ps1";
|
|
13
|
+
export const TASK_XML_FILE_NAME = "scheduler-task.xml";
|
|
14
|
+
function defaultCommand(command, args) {
|
|
15
|
+
const result = spawnSync(command, args, {
|
|
16
|
+
encoding: "utf8",
|
|
17
|
+
shell: false,
|
|
18
|
+
windowsHide: true,
|
|
19
|
+
});
|
|
20
|
+
const commandResult = {
|
|
21
|
+
status: result.status,
|
|
22
|
+
stdout: result.stdout ?? "",
|
|
23
|
+
stderr: result.stderr ?? "",
|
|
24
|
+
};
|
|
25
|
+
if (result.error) {
|
|
26
|
+
const errorCode = result.error.code;
|
|
27
|
+
if (errorCode !== undefined)
|
|
28
|
+
commandResult.errorCode = errorCode;
|
|
29
|
+
commandResult.errorMessage = result.error.message;
|
|
30
|
+
}
|
|
31
|
+
return commandResult;
|
|
32
|
+
}
|
|
33
|
+
function currentTaskUser() {
|
|
34
|
+
const domain = process.env.USERDOMAIN;
|
|
35
|
+
const user = process.env.USERNAME ?? process.env.USER;
|
|
36
|
+
if (domain && user)
|
|
37
|
+
return `${domain}\\${user}`;
|
|
38
|
+
return user ?? "";
|
|
39
|
+
}
|
|
40
|
+
function resolveOptions(options = {}) {
|
|
41
|
+
const directory = options.configDirectory ?? configDir();
|
|
42
|
+
const resolved = {
|
|
43
|
+
command: options.command ?? options.run ?? options.spawn ?? options.exec ?? defaultCommand,
|
|
44
|
+
configDirectory: directory,
|
|
45
|
+
taskName: options.taskName ?? TASK_NAME,
|
|
46
|
+
launcherPath: options.launcherPath ?? join(directory, LAUNCHER_FILE_NAME),
|
|
47
|
+
taskXmlPath: options.taskXmlPath ?? join(directory, TASK_XML_FILE_NAME),
|
|
48
|
+
nodePath: options.nodePath ?? process.execPath,
|
|
49
|
+
user: options.user ?? currentTaskUser(),
|
|
50
|
+
powershellPath: options.powershellPath ?? powershellExecutable(options.systemRoot),
|
|
51
|
+
schtasksPath: windowsSystemExecutable("schtasks.exe", options.systemRoot),
|
|
52
|
+
};
|
|
53
|
+
requiredText(resolved.configDirectory, "config directory");
|
|
54
|
+
requiredText(resolved.taskName, "task name");
|
|
55
|
+
requiredText(resolved.launcherPath, "launcher path");
|
|
56
|
+
requiredText(resolved.taskXmlPath, "task XML path");
|
|
57
|
+
requiredText(resolved.nodePath, "node path");
|
|
58
|
+
requiredText(resolved.user, "task user");
|
|
59
|
+
requiredText(resolved.powershellPath, "PowerShell path");
|
|
60
|
+
return resolved;
|
|
61
|
+
}
|
|
62
|
+
function validateXmlCharacters(value, label) {
|
|
63
|
+
for (let index = 0; index < value.length;) {
|
|
64
|
+
const codePoint = value.codePointAt(index);
|
|
65
|
+
if (codePoint === undefined)
|
|
66
|
+
break;
|
|
67
|
+
const valid = codePoint === 0x09 || codePoint === 0x0a || codePoint === 0x0d
|
|
68
|
+
|| (codePoint >= 0x20 && codePoint <= 0xd7ff)
|
|
69
|
+
|| (codePoint >= 0xe000 && codePoint <= 0xfffd)
|
|
70
|
+
|| (codePoint >= 0x10000 && codePoint <= 0x10ffff);
|
|
71
|
+
if (!valid)
|
|
72
|
+
throw new TypeError(`${label} contains an invalid XML control character`);
|
|
73
|
+
index += codePoint > 0xffff ? 2 : 1;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function requiredText(value, label) {
|
|
77
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
78
|
+
throw new TypeError(`${label} must not be empty`);
|
|
79
|
+
}
|
|
80
|
+
validateXmlCharacters(value, label);
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
/** Escape a value used as a single-quoted PowerShell string literal. */
|
|
84
|
+
export function powerShellLiteral(value) {
|
|
85
|
+
return `'${value.replaceAll("'", "''")}'`;
|
|
86
|
+
}
|
|
87
|
+
/** Escape XML text, rejecting characters that XML 1.0 cannot represent. */
|
|
88
|
+
export function xmlText(value) {
|
|
89
|
+
if (typeof value !== "string")
|
|
90
|
+
throw new TypeError("XML text must be a string");
|
|
91
|
+
validateXmlCharacters(value, "XML text");
|
|
92
|
+
return value
|
|
93
|
+
.replaceAll("&", "&")
|
|
94
|
+
.replaceAll("<", "<")
|
|
95
|
+
.replaceAll(">", ">")
|
|
96
|
+
.replaceAll('"', """)
|
|
97
|
+
.replaceAll("'", "'");
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Quote one argument for the command line passed to an Exec action. The
|
|
101
|
+
* launcher path is a Windows path (and thus cannot contain a double quote),
|
|
102
|
+
* but handling backslashes here also makes this safe for synthetic test
|
|
103
|
+
* paths and future callers.
|
|
104
|
+
*/
|
|
105
|
+
export function windowsArgument(value) {
|
|
106
|
+
if (value.length > 0 && !/[\s"]/.test(value))
|
|
107
|
+
return value;
|
|
108
|
+
let result = '"';
|
|
109
|
+
let slashes = 0;
|
|
110
|
+
for (const character of value) {
|
|
111
|
+
if (character === "\\") {
|
|
112
|
+
slashes += 1;
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (character === '"') {
|
|
116
|
+
result += "\\".repeat(slashes * 2 + 1) + '"';
|
|
117
|
+
slashes = 0;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
result += "\\".repeat(slashes) + character;
|
|
121
|
+
slashes = 0;
|
|
122
|
+
}
|
|
123
|
+
result += "\\".repeat(slashes * 2) + '"';
|
|
124
|
+
return result;
|
|
125
|
+
}
|
|
126
|
+
/** Render the PowerShell process launcher used by the scheduled task. */
|
|
127
|
+
export function renderLauncher(nodePath, cliPath, dbPath) {
|
|
128
|
+
requiredText(nodePath, "node path");
|
|
129
|
+
requiredText(cliPath, "CLI path");
|
|
130
|
+
requiredText(dbPath, "database path");
|
|
131
|
+
return [
|
|
132
|
+
"$ErrorActionPreference = 'Stop'",
|
|
133
|
+
`$node = ${powerShellLiteral(nodePath)}`,
|
|
134
|
+
`$cli = ${powerShellLiteral(cliPath)}`,
|
|
135
|
+
`$env:LOOKING_GLASS_DB = ${powerShellLiteral(dbPath)}`,
|
|
136
|
+
"& $node $cli 'cron' 'daemon'",
|
|
137
|
+
"exit $LASTEXITCODE",
|
|
138
|
+
"",
|
|
139
|
+
].join("\r\n");
|
|
140
|
+
}
|
|
141
|
+
/** Descriptive alias for callers that want to make the generated format explicit. */
|
|
142
|
+
export const renderPowerShellLauncher = renderLauncher;
|
|
143
|
+
function taskXmlOptions(userOrOptions, powershellPath, workingDirectory) {
|
|
144
|
+
if (typeof userOrOptions === "object" && userOrOptions !== null) {
|
|
145
|
+
const options = {
|
|
146
|
+
taskName: userOrOptions.taskName ?? TASK_NAME,
|
|
147
|
+
user: userOrOptions.user ?? currentTaskUser(),
|
|
148
|
+
powershellPath: userOrOptions.powershellPath ?? powershellExecutable(userOrOptions.systemRoot),
|
|
149
|
+
workingDirectory: userOrOptions.workingDirectory ?? homedir(),
|
|
150
|
+
};
|
|
151
|
+
requiredText(options.taskName, "task name");
|
|
152
|
+
requiredText(options.user, "task user");
|
|
153
|
+
requiredText(options.powershellPath, "PowerShell path");
|
|
154
|
+
requiredText(options.workingDirectory, "working directory");
|
|
155
|
+
return options;
|
|
156
|
+
}
|
|
157
|
+
const options = {
|
|
158
|
+
taskName: TASK_NAME,
|
|
159
|
+
user: userOrOptions ?? currentTaskUser(),
|
|
160
|
+
powershellPath: powershellPath ?? powershellExecutable(),
|
|
161
|
+
workingDirectory: workingDirectory ?? homedir(),
|
|
162
|
+
};
|
|
163
|
+
requiredText(options.taskName, "task name");
|
|
164
|
+
requiredText(options.user, "task user");
|
|
165
|
+
requiredText(options.powershellPath, "PowerShell path");
|
|
166
|
+
requiredText(options.workingDirectory, "working directory");
|
|
167
|
+
return options;
|
|
168
|
+
}
|
|
169
|
+
export function renderTaskXml(launcherPath, userOrOptions = undefined, powershellPath, workingDirectory) {
|
|
170
|
+
requiredText(launcherPath, "launcher path");
|
|
171
|
+
const options = taskXmlOptions(userOrOptions, powershellPath, workingDirectory);
|
|
172
|
+
const commandArguments = `-NoLogo -NoProfile -NonInteractive -WindowStyle Hidden -ExecutionPolicy Bypass -File ${windowsArgument(launcherPath)}`;
|
|
173
|
+
// The trigger and principal deliberately share UserId: InteractiveToken
|
|
174
|
+
// keeps execution tied to this user's interactive logon, while
|
|
175
|
+
// LeastPrivilege avoids elevating the scheduler daemon.
|
|
176
|
+
return `<?xml version="1.0" encoding="UTF-16"?>
|
|
177
|
+
<Task version="1.4" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
|
|
178
|
+
<RegistrationInfo>
|
|
179
|
+
<Description>${xmlText(options.taskName)} persistent scheduler</Description>
|
|
180
|
+
<URI>\\${xmlText(options.taskName)}</URI>
|
|
181
|
+
</RegistrationInfo>
|
|
182
|
+
<Triggers>
|
|
183
|
+
<LogonTrigger>
|
|
184
|
+
<UserId>${xmlText(options.user)}</UserId>
|
|
185
|
+
<Enabled>true</Enabled>
|
|
186
|
+
</LogonTrigger>
|
|
187
|
+
</Triggers>
|
|
188
|
+
<Principals>
|
|
189
|
+
<Principal id="Author">
|
|
190
|
+
<UserId>${xmlText(options.user)}</UserId>
|
|
191
|
+
<LogonType>InteractiveToken</LogonType>
|
|
192
|
+
<RunLevel>LeastPrivilege</RunLevel>
|
|
193
|
+
</Principal>
|
|
194
|
+
</Principals>
|
|
195
|
+
<Settings>
|
|
196
|
+
<MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>
|
|
197
|
+
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
|
|
198
|
+
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
|
|
199
|
+
<AllowHardTerminate>true</AllowHardTerminate>
|
|
200
|
+
<StartWhenAvailable>true</StartWhenAvailable>
|
|
201
|
+
<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
|
|
202
|
+
<RestartOnFailure>
|
|
203
|
+
<Interval>PT1M</Interval>
|
|
204
|
+
<Count>3</Count>
|
|
205
|
+
</RestartOnFailure>
|
|
206
|
+
<Priority>7</Priority>
|
|
207
|
+
</Settings>
|
|
208
|
+
<Actions Context="Author">
|
|
209
|
+
<Exec>
|
|
210
|
+
<Command>${xmlText(options.powershellPath)}</Command>
|
|
211
|
+
<Arguments>${xmlText(commandArguments)}</Arguments>
|
|
212
|
+
<WorkingDirectory>${xmlText(options.workingDirectory)}</WorkingDirectory>
|
|
213
|
+
</Exec>
|
|
214
|
+
</Actions>
|
|
215
|
+
</Task>
|
|
216
|
+
`;
|
|
217
|
+
}
|
|
218
|
+
/** Alias with a shorter name for callers that only need a pure renderer. */
|
|
219
|
+
export const renderTask = renderTaskXml;
|
|
220
|
+
function commandOutput(result) {
|
|
221
|
+
return [
|
|
222
|
+
result.stdout ?? "",
|
|
223
|
+
result.stderr ?? "",
|
|
224
|
+
result.errorMessage ?? result.message ?? "",
|
|
225
|
+
].filter(Boolean).join("\n").trim();
|
|
226
|
+
}
|
|
227
|
+
function commandFailure(command, args, result) {
|
|
228
|
+
const code = result.errorCode ?? result.code;
|
|
229
|
+
const suffix = code === undefined ? "" : ` (code ${String(code)})`;
|
|
230
|
+
return new Error(commandOutput(result) || `${command} ${args.join(" ")} exited with ${String(result.status)}${suffix}`);
|
|
231
|
+
}
|
|
232
|
+
function runSchtasks(options, args, tolerateFailure = false) {
|
|
233
|
+
const result = options.command(options.schtasksPath, args);
|
|
234
|
+
if (result.status !== 0 && !tolerateFailure) {
|
|
235
|
+
throw commandFailure(options.schtasksPath, args, result);
|
|
236
|
+
}
|
|
237
|
+
return result;
|
|
238
|
+
}
|
|
239
|
+
function resultCode(result) {
|
|
240
|
+
return String(result.errorCode ?? result.code ?? "").toLowerCase().replaceAll("_", "");
|
|
241
|
+
}
|
|
242
|
+
const TASK_NOT_FOUND_SENTINEL = "LOOKING_GLASS_TASK_NOT_FOUND";
|
|
243
|
+
// These are the documented Win32 / Task Scheduler values returned by the
|
|
244
|
+
// schtasks operation itself. Do not add message text (or a generic
|
|
245
|
+
// "*not-found" code) here: a localized or otherwise unrelated failure must
|
|
246
|
+
// never authorize removal of the generated scheduler files.
|
|
247
|
+
const DOCUMENTED_MISSING_TASK_CODES = new Set([
|
|
248
|
+
"2", // ERROR_FILE_NOT_FOUND
|
|
249
|
+
"2147942402", // HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
|
|
250
|
+
"0x80070002", // HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
|
|
251
|
+
"2147750671", // SCHED_E_TASK_NOT_FOUND
|
|
252
|
+
"0x8004130f", // SCHED_E_TASK_NOT_FOUND
|
|
253
|
+
"errorfilenotfound",
|
|
254
|
+
"schedetasknotfound",
|
|
255
|
+
]);
|
|
256
|
+
/** Only the internal sentinel or documented invariant codes count as missing. */
|
|
257
|
+
function isMissingTaskFailure(result) {
|
|
258
|
+
if (commandOutput(result).trim() === TASK_NOT_FOUND_SENTINEL)
|
|
259
|
+
return true;
|
|
260
|
+
return DOCUMENTED_MISSING_TASK_CODES.has(resultCode(result));
|
|
261
|
+
}
|
|
262
|
+
function isNotRunningFailure(result) {
|
|
263
|
+
const code = resultCode(result);
|
|
264
|
+
return code === "0x8004131f" || code === "2147750687"
|
|
265
|
+
|| /(?:not currently running|is not running|no running instance|cannot be stopped because)/i.test(commandOutput(result));
|
|
266
|
+
}
|
|
267
|
+
function taskStateScript(taskName) {
|
|
268
|
+
return [
|
|
269
|
+
"$ErrorActionPreference = 'Stop'",
|
|
270
|
+
"try {",
|
|
271
|
+
` $task = Get-ScheduledTask -TaskName ${powerShellLiteral(taskName)} -ErrorAction Stop`,
|
|
272
|
+
` if ($null -eq $task) { [Console]::Error.Write('${TASK_NOT_FOUND_SENTINEL}'); exit 3 }`,
|
|
273
|
+
" [Console]::Out.Write($task.State.ToString())",
|
|
274
|
+
"} catch {",
|
|
275
|
+
" $id = [string]$_.FullyQualifiedErrorId",
|
|
276
|
+
// Get-ScheduledTask uses this invariant FullyQualifiedErrorId for an
|
|
277
|
+
// empty task query. Match it exactly; ObjectNotFound/NotFound text also
|
|
278
|
+
// occurs for operational failures and is not safe to interpret broadly.
|
|
279
|
+
` if ($id -eq 'CmdletizationQuery_NotFound,Get-ScheduledTask') { [Console]::Error.Write('${TASK_NOT_FOUND_SENTINEL}'); exit 3 }`,
|
|
280
|
+
" [Console]::Error.Write('LOOKING_GLASS_TASK_ERROR')",
|
|
281
|
+
" exit 4",
|
|
282
|
+
"}",
|
|
283
|
+
].join("\r\n");
|
|
284
|
+
}
|
|
285
|
+
/** Query the enum-valued State property; never parse localized schtasks output. */
|
|
286
|
+
function lookupTask(options) {
|
|
287
|
+
const args = ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", taskStateScript(options.taskName)];
|
|
288
|
+
const result = options.command(options.powershellPath, args);
|
|
289
|
+
if (result.status === 0) {
|
|
290
|
+
const state = (result.stdout ?? "").trim();
|
|
291
|
+
if (state.length === 0)
|
|
292
|
+
throw commandFailure(options.powershellPath, args, result);
|
|
293
|
+
return { kind: "present", state };
|
|
294
|
+
}
|
|
295
|
+
if (isMissingTaskFailure(result))
|
|
296
|
+
return { kind: "missing" };
|
|
297
|
+
throw commandFailure(options.powershellPath, args, result);
|
|
298
|
+
}
|
|
299
|
+
function removeFile(path) {
|
|
300
|
+
try {
|
|
301
|
+
unlinkSync(path);
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
if (error.code !== "ENOENT")
|
|
305
|
+
throw error;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
function restoreFile(path, previous) {
|
|
309
|
+
if (previous === null)
|
|
310
|
+
removeFile(path);
|
|
311
|
+
else
|
|
312
|
+
writeFileSync(path, previous, { mode: 0o600 });
|
|
313
|
+
}
|
|
314
|
+
function isRenameCollision(error) {
|
|
315
|
+
const code = error.code;
|
|
316
|
+
return code === "EEXIST" || code === "EPERM" || code === "ENOTEMPTY";
|
|
317
|
+
}
|
|
318
|
+
/** Replace a completed file atomically where the host permits it. */
|
|
319
|
+
function replaceCompletedFile(temporaryPath, targetPath) {
|
|
320
|
+
try {
|
|
321
|
+
renameSync(temporaryPath, targetPath);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
catch (error) {
|
|
325
|
+
if (!isRenameCollision(error))
|
|
326
|
+
throw error;
|
|
327
|
+
}
|
|
328
|
+
// Windows rename does not replace an existing file. Move it aside first,
|
|
329
|
+
// then rename the complete temporary file into place; both operations are
|
|
330
|
+
// metadata changes and never expose a partially written generated file.
|
|
331
|
+
const backupPath = `${targetPath}.${randomUUID()}.bak`;
|
|
332
|
+
let backedUp = false;
|
|
333
|
+
try {
|
|
334
|
+
try {
|
|
335
|
+
renameSync(targetPath, backupPath);
|
|
336
|
+
backedUp = true;
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
if (error.code !== "ENOENT")
|
|
340
|
+
throw error;
|
|
341
|
+
}
|
|
342
|
+
renameSync(temporaryPath, targetPath);
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
if (backedUp) {
|
|
346
|
+
try {
|
|
347
|
+
renameSync(backupPath, targetPath);
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
// Preserve the original failure; the caller still rolls back both files.
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
throw error;
|
|
354
|
+
}
|
|
355
|
+
if (backedUp)
|
|
356
|
+
removeFile(backupPath);
|
|
357
|
+
}
|
|
358
|
+
/** End a task before replacement/deletion; stopped tasks report a benign error. */
|
|
359
|
+
function endTask(options) {
|
|
360
|
+
const args = ["/End", "/TN", options.taskName];
|
|
361
|
+
const result = runSchtasks(options, args, true);
|
|
362
|
+
if (result.status !== 0 && !isMissingTaskFailure(result) && !isNotRunningFailure(result)) {
|
|
363
|
+
throw commandFailure(options.schtasksPath, args, result);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
/** Best-effort recovery for a task stopped before a replacement/deletion failed. */
|
|
367
|
+
function restartTask(options) {
|
|
368
|
+
try {
|
|
369
|
+
runSchtasks(options, ["/Run", "/TN", options.taskName], true);
|
|
370
|
+
}
|
|
371
|
+
catch {
|
|
372
|
+
// Recovery must never replace the failure that triggered the rollback.
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
/** Install or replace the current user's logon task and start it once. */
|
|
376
|
+
export function installService(cliPath, dbPath, serviceOptions = {}) {
|
|
377
|
+
requiredText(cliPath, "CLI path");
|
|
378
|
+
requiredText(dbPath, "database path");
|
|
379
|
+
const options = resolveOptions(serviceOptions);
|
|
380
|
+
mkdirSync(options.configDirectory, { recursive: true, mode: 0o700 });
|
|
381
|
+
const previousLauncher = existsSync(options.launcherPath) ? readFileSync(options.launcherPath) : null;
|
|
382
|
+
const previousXml = existsSync(options.taskXmlPath) ? readFileSync(options.taskXmlPath) : null;
|
|
383
|
+
const existingTask = lookupTask(options);
|
|
384
|
+
const previousTaskWasRunning = existingTask.kind === "present" && /^running$/i.test(existingTask.state ?? "");
|
|
385
|
+
if (previousTaskWasRunning)
|
|
386
|
+
endTask(options);
|
|
387
|
+
// `process.argv[1]` is commonly relative when glass is launched as
|
|
388
|
+
// `node dist/cli.js`; Task Scheduler will not resolve it relative to the
|
|
389
|
+
// terminal that performed the install.
|
|
390
|
+
const resolvedCliPath = isAbsolute(cliPath) || win32.isAbsolute(cliPath) ? cliPath : resolve(cliPath);
|
|
391
|
+
const resolvedDbPath = isAbsolute(dbPath) || win32.isAbsolute(dbPath) ? dbPath : resolve(dbPath);
|
|
392
|
+
const launcher = renderLauncher(options.nodePath, resolvedCliPath, resolvedDbPath);
|
|
393
|
+
const xml = renderTaskXml(options.launcherPath, {
|
|
394
|
+
taskName: options.taskName,
|
|
395
|
+
user: options.user,
|
|
396
|
+
powershellPath: options.powershellPath,
|
|
397
|
+
workingDirectory: homedir(),
|
|
398
|
+
});
|
|
399
|
+
const tempSuffix = randomUUID();
|
|
400
|
+
const temporaryLauncher = `${options.launcherPath}.${tempSuffix}.tmp`;
|
|
401
|
+
const temporaryXml = `${options.taskXmlPath}.${tempSuffix}.tmp`;
|
|
402
|
+
let taskCreated = false;
|
|
403
|
+
try {
|
|
404
|
+
// Windows PowerShell 5.1 reads UTF-8 scripts reliably only when they have
|
|
405
|
+
// a BOM (important for non-ASCII usernames and installation paths).
|
|
406
|
+
writeFileSync(temporaryLauncher, Buffer.from(`\uFEFF${launcher}`, "utf8"), { mode: 0o600, flag: "wx" });
|
|
407
|
+
// Task Scheduler expects UTF-16 XML. Include the BOM as required by its
|
|
408
|
+
// XML importer rather than relying on the host's default encoding.
|
|
409
|
+
writeFileSync(temporaryXml, `\uFEFF${xml}`, { encoding: "utf16le", mode: 0o600, flag: "wx" });
|
|
410
|
+
// Both temporary files are complete before either target is replaced.
|
|
411
|
+
replaceCompletedFile(temporaryLauncher, options.launcherPath);
|
|
412
|
+
replaceCompletedFile(temporaryXml, options.taskXmlPath);
|
|
413
|
+
runSchtasks(options, ["/Create", "/TN", options.taskName, "/XML", options.taskXmlPath, "/F"]);
|
|
414
|
+
taskCreated = true;
|
|
415
|
+
runSchtasks(options, ["/Run", "/TN", options.taskName]);
|
|
416
|
+
}
|
|
417
|
+
catch (error) {
|
|
418
|
+
try {
|
|
419
|
+
removeFile(temporaryLauncher);
|
|
420
|
+
}
|
|
421
|
+
catch {
|
|
422
|
+
// Preserve the replacement failure below.
|
|
423
|
+
}
|
|
424
|
+
try {
|
|
425
|
+
removeFile(temporaryXml);
|
|
426
|
+
}
|
|
427
|
+
catch {
|
|
428
|
+
// Preserve the replacement failure below.
|
|
429
|
+
}
|
|
430
|
+
// Once Create succeeded, retain the matching generated files even if an
|
|
431
|
+
// immediate Run is unavailable. The logon trigger still has a valid
|
|
432
|
+
// task and will start it at the next interactive logon.
|
|
433
|
+
if (!taskCreated) {
|
|
434
|
+
try {
|
|
435
|
+
restoreFile(options.launcherPath, previousLauncher);
|
|
436
|
+
restoreFile(options.taskXmlPath, previousXml);
|
|
437
|
+
}
|
|
438
|
+
catch {
|
|
439
|
+
// Preserve the replacement failure below.
|
|
440
|
+
}
|
|
441
|
+
if (previousTaskWasRunning)
|
|
442
|
+
restartTask(options);
|
|
443
|
+
}
|
|
444
|
+
throw error;
|
|
445
|
+
}
|
|
446
|
+
return options.taskName;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Return a stable ActiveState line in addition to useful Task Scheduler
|
|
450
|
+
* details. A confirmed missing task is inactive; access/operational failures
|
|
451
|
+
* are surfaced instead of being misreported as an absent task.
|
|
452
|
+
*/
|
|
453
|
+
export function serviceStatus(serviceOptions = {}) {
|
|
454
|
+
const options = resolveOptions(serviceOptions);
|
|
455
|
+
const task = lookupTask(options);
|
|
456
|
+
if (task.kind === "missing") {
|
|
457
|
+
return `ActiveState=inactive\nTask=${options.taskName} is not installed`;
|
|
458
|
+
}
|
|
459
|
+
const status = task.state ?? "unknown";
|
|
460
|
+
const active = /^running$/i.test(status);
|
|
461
|
+
return [
|
|
462
|
+
`TaskName=${options.taskName}`,
|
|
463
|
+
`TaskStatus=${status.trim() || "unknown"}`,
|
|
464
|
+
`ActiveState=${active ? "active" : "inactive"}`,
|
|
465
|
+
].join("\n");
|
|
466
|
+
}
|
|
467
|
+
/** Remove the task and only the generated scheduler definition files. */
|
|
468
|
+
export function uninstallService(serviceOptions = {}) {
|
|
469
|
+
const options = resolveOptions(serviceOptions);
|
|
470
|
+
const task = lookupTask(options);
|
|
471
|
+
if (task.kind === "missing") {
|
|
472
|
+
// A confirmed not-found result is sufficient to clean up stale generated
|
|
473
|
+
// definitions; operational failures above intentionally leave them alone.
|
|
474
|
+
removeFile(options.launcherPath);
|
|
475
|
+
removeFile(options.taskXmlPath);
|
|
476
|
+
return false;
|
|
477
|
+
}
|
|
478
|
+
const deleteArgs = ["/Delete", "/TN", options.taskName, "/F"];
|
|
479
|
+
const previousTaskWasRunning = /^running$/i.test(task.state ?? "");
|
|
480
|
+
if (previousTaskWasRunning)
|
|
481
|
+
endTask(options);
|
|
482
|
+
try {
|
|
483
|
+
const deleted = runSchtasks(options, deleteArgs, true);
|
|
484
|
+
if (deleted.status !== 0 && !isMissingTaskFailure(deleted)) {
|
|
485
|
+
throw commandFailure(options.schtasksPath, deleteArgs, deleted);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
catch (error) {
|
|
489
|
+
if (previousTaskWasRunning)
|
|
490
|
+
restartTask(options);
|
|
491
|
+
throw error;
|
|
492
|
+
}
|
|
493
|
+
// Only a successful delete or a confirmed race-to-not-found permits file cleanup.
|
|
494
|
+
removeFile(options.launcherPath);
|
|
495
|
+
removeFile(options.taskXmlPath);
|
|
496
|
+
return true;
|
|
497
|
+
}
|
|
498
|
+
/** Bind injectable options once for the platform dispatcher and tests. */
|
|
499
|
+
export function createWindowsScheduler(options = {}) {
|
|
500
|
+
return {
|
|
501
|
+
installService: (cliPath, dbPath) => installService(cliPath, dbPath, options),
|
|
502
|
+
serviceStatus: () => serviceStatus(options),
|
|
503
|
+
uninstallService: () => uninstallService(options),
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
//# sourceMappingURL=windows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"windows.js","sourceRoot":"","sources":["../../src/scheduler/windows.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACrG,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAElF,0DAA0D;AAC1D,MAAM,CAAC,MAAM,SAAS,GAAG,yBAAyB,CAAC;AACnD,8EAA8E;AAC9E,MAAM,CAAC,MAAM,YAAY,GAAG,SAAS,CAAC;AAEtC,MAAM,CAAC,MAAM,kBAAkB,GAAG,wBAAwB,CAAC;AAC3D,MAAM,CAAC,MAAM,kBAAkB,GAAG,oBAAoB,CAAC;AA0DvD,SAAS,cAAc,CAAC,OAAe,EAAE,IAAc;IACrD,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE;QACtC,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,KAAK;QACZ,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC;IACH,MAAM,aAAa,GAAyB;QAC1C,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;QAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE;KAC5B,CAAC;IACF,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,SAAS,GAAI,MAAM,CAAC,KAA+B,CAAC,IAAI,CAAC;QAC/D,IAAI,SAAS,KAAK,SAAS;YAAE,aAAa,CAAC,SAAS,GAAG,SAAS,CAAC;QACjE,aAAa,CAAC,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC;IACpD,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC;AAED,SAAS,eAAe;IACtB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;IACtC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;IACtD,IAAI,MAAM,IAAI,IAAI;QAAE,OAAO,GAAG,MAAM,KAAK,IAAI,EAAE,CAAC;IAChD,OAAO,IAAI,IAAI,EAAE,CAAC;AACpB,CAAC;AAED,SAAS,cAAc,CAAC,UAAiC,EAAE;IACzD,MAAM,SAAS,GAAG,OAAO,CAAC,eAAe,IAAI,SAAS,EAAE,CAAC;IACzD,MAAM,QAAQ,GAAG;QACf,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,IAAI,IAAI,cAAc;QAC1F,eAAe,EAAE,SAAS;QAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,SAAS;QACvC,YAAY,EAAE,OAAO,CAAC,YAAY,IAAI,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC;QACzE,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC;QACvE,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ;QAC9C,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,eAAe,EAAE;QACvC,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,oBAAoB,CAAC,OAAO,CAAC,UAAU,CAAC;QAClF,YAAY,EAAE,uBAAuB,CAAC,cAAc,EAAE,OAAO,CAAC,UAAU,CAAC;KAC1E,CAAC;IACF,YAAY,CAAC,QAAQ,CAAC,eAAe,EAAE,kBAAkB,CAAC,CAAC;IAC3D,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC7C,YAAY,CAAC,QAAQ,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;IACrD,YAAY,CAAC,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;IACpD,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC7C,YAAY,CAAC,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACzC,YAAY,CAAC,QAAQ,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;IACzD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAa,EAAE,KAAa;IACzD,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC;QAC1C,MAAM,SAAS,GAAG,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,SAAS,KAAK,SAAS;YAAE,MAAM;QACnC,MAAM,KAAK,GAAG,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,IAAI;eACvE,CAAC,SAAS,IAAI,IAAI,IAAI,SAAS,IAAI,MAAM,CAAC;eAC1C,CAAC,SAAS,IAAI,MAAM,IAAI,SAAS,IAAI,MAAM,CAAC;eAC5C,CAAC,SAAS,IAAI,OAAO,IAAI,SAAS,IAAI,QAAQ,CAAC,CAAC;QACrD,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,SAAS,CAAC,GAAG,KAAK,4CAA4C,CAAC,CAAC;QACtF,KAAK,IAAI,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,KAAa,EAAE,KAAa;IAChD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,SAAS,CAAC,GAAG,KAAK,oBAAoB,CAAC,CAAC;IACpD,CAAC;IACD,qBAAqB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACpC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC7C,OAAO,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC;AAC5C,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,OAAO,CAAC,KAAa;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,MAAM,IAAI,SAAS,CAAC,2BAA2B,CAAC,CAAC;IAChF,qBAAqB,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;IACzC,OAAO,KAAK;SACT,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;SACxB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC;SACzB,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;AAC/B,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3D,IAAI,MAAM,GAAG,GAAG,CAAC;IACjB,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,SAAS,IAAI,KAAK,EAAE,CAAC;QAC9B,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC,CAAC;YACb,SAAS;QACX,CAAC;QACD,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;YACtB,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;YAC7C,OAAO,GAAG,CAAC,CAAC;YACZ,SAAS;QACX,CAAC;QACD,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC;QAC3C,OAAO,GAAG,CAAC,CAAC;IACd,CAAC;IACD,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;IACzC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,OAAe,EAAE,MAAc;IAC9E,YAAY,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IACpC,YAAY,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAClC,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACtC,OAAO;QACL,iCAAiC;QACjC,WAAW,iBAAiB,CAAC,QAAQ,CAAC,EAAE;QACxC,UAAU,iBAAiB,CAAC,OAAO,CAAC,EAAE;QACtC,2BAA2B,iBAAiB,CAAC,MAAM,CAAC,EAAE;QACtD,8BAA8B;QAC9B,oBAAoB;QACpB,EAAE;KACH,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACjB,CAAC;AAED,qFAAqF;AACrF,MAAM,CAAC,MAAM,wBAAwB,GAAG,cAAc,CAAC;AAEvD,SAAS,cAAc,CACrB,aAAkD,EAClD,cAAkC,EAClC,gBAAoC;IAEpC,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;QAChE,MAAM,OAAO,GAAG;YACd,QAAQ,EAAE,aAAa,CAAC,QAAQ,IAAI,SAAS;YAC7C,IAAI,EAAE,aAAa,CAAC,IAAI,IAAI,eAAe,EAAE;YAC7C,cAAc,EAAE,aAAa,CAAC,cAAc,IAAI,oBAAoB,CAAC,aAAa,CAAC,UAAU,CAAC;YAC9F,gBAAgB,EAAE,aAAa,CAAC,gBAAgB,IAAI,OAAO,EAAE;SAC9D,CAAC;QACF,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QAC5C,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QACxC,YAAY,CAAC,OAAO,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;QACxD,YAAY,CAAC,OAAO,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,CAAC;QAC5D,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,MAAM,OAAO,GAAG;QACd,QAAQ,EAAE,SAAS;QACnB,IAAI,EAAE,aAAa,IAAI,eAAe,EAAE;QACxC,cAAc,EAAE,cAAc,IAAI,oBAAoB,EAAE;QACxD,gBAAgB,EAAE,gBAAgB,IAAI,OAAO,EAAE;KAChD,CAAC;IACF,YAAY,CAAC,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;IAC5C,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IACxC,YAAY,CAAC,OAAO,CAAC,cAAc,EAAE,iBAAiB,CAAC,CAAC;IACxD,YAAY,CAAC,OAAO,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,CAAC;IAC5D,OAAO,OAAO,CAAC;AACjB,CAAC;AAQD,MAAM,UAAU,aAAa,CAC3B,YAAoB,EACpB,gBAAqD,SAAS,EAC9D,cAAuB,EACvB,gBAAyB;IAEzB,YAAY,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,cAAc,CAAC,aAAa,EAAE,cAAc,EAAE,gBAAgB,CAAC,CAAC;IAChF,MAAM,gBAAgB,GAAG,wFAAwF,eAAe,CAAC,YAAY,CAAC,EAAE,CAAC;IACjJ,wEAAwE;IACxE,+DAA+D;IAC/D,wDAAwD;IACxD,OAAO;;;mBAGU,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;aAC/B,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;;;;gBAItB,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;;;;;;gBAMrB,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;iBAoBpB,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC;mBAC7B,OAAO,CAAC,gBAAgB,CAAC;0BAClB,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC;;;;CAI1D,CAAC;AACF,CAAC;AAED,4EAA4E;AAC5E,MAAM,CAAC,MAAM,UAAU,GAAG,aAAa,CAAC;AAExC,SAAS,aAAa,CAAC,MAA4B;IACjD,OAAO;QACL,MAAM,CAAC,MAAM,IAAI,EAAE;QACnB,MAAM,CAAC,MAAM,IAAI,EAAE;QACnB,MAAM,CAAC,YAAY,IAAI,MAAM,CAAC,OAAO,IAAI,EAAE;KAC5C,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,SAAS,cAAc,CAAC,OAAe,EAAE,IAAc,EAAE,MAA4B;IACnF,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC;IAC7C,MAAM,MAAM,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;IACnE,OAAO,IAAI,KAAK,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,GAAG,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,gBAAgB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC,CAAC;AAC1H,CAAC;AAED,SAAS,WAAW,CAAC,OAAsC,EAAE,IAAc,EAAE,eAAe,GAAG,KAAK;IAClG,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IAC3D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC;QAC5C,MAAM,cAAc,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,UAAU,CAAC,MAA4B;IAC9C,OAAO,MAAM,CAAC,MAAM,CAAC,SAAS,IAAI,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,uBAAuB,GAAG,8BAA8B,CAAC;AAE/D,yEAAyE;AACzE,oEAAoE;AACpE,2EAA2E;AAC3E,4DAA4D;AAC5D,MAAM,6BAA6B,GAAG,IAAI,GAAG,CAAC;IAC5C,GAAG,EAAE,uBAAuB;IAC5B,YAAY,EAAE,2CAA2C;IACzD,YAAY,EAAE,2CAA2C;IACzD,YAAY,EAAE,yBAAyB;IACvC,YAAY,EAAE,yBAAyB;IACvC,mBAAmB;IACnB,oBAAoB;CACrB,CAAC,CAAC;AAEH,iFAAiF;AACjF,SAAS,oBAAoB,CAAC,MAA4B;IACxD,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,uBAAuB;QAAE,OAAO,IAAI,CAAC;IAC1E,OAAO,6BAA6B,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;AAC/D,CAAC;AAED,SAAS,mBAAmB,CAAC,MAA4B;IACvD,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAChC,OAAO,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,YAAY;WAChD,yFAAyF,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;AAC7H,CAAC;AAED,SAAS,eAAe,CAAC,QAAgB;IACvC,OAAO;QACL,iCAAiC;QACjC,OAAO;QACP,yCAAyC,iBAAiB,CAAC,QAAQ,CAAC,oBAAoB;QACxF,oDAAoD,uBAAuB,cAAc;QACzF,gDAAgD;QAChD,WAAW;QACX,0CAA0C;QAC1C,qEAAqE;QACrE,yEAAyE;QACzE,wEAAwE;QACxE,4FAA4F,uBAAuB,cAAc;QACjI,sDAAsD;QACtD,UAAU;QACV,GAAG;KACJ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACjB,CAAC;AAOD,mFAAmF;AACnF,SAAS,UAAU,CAAC,OAAsC;IACxD,MAAM,IAAI,GAAG,CAAC,SAAS,EAAE,YAAY,EAAE,iBAAiB,EAAE,UAAU,EAAE,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IACzG,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;IAC7D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,cAAc,CAAC,OAAO,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;QACnF,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IACpC,CAAC;IACD,IAAI,oBAAoB,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC7D,MAAM,cAAc,CAAC,OAAO,CAAC,cAAc,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,IAAI,CAAC;QACH,UAAU,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,KAAK,CAAC;IACtE,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,IAAY,EAAE,QAAuB;IACxD,IAAI,QAAQ,KAAK,IAAI;QAAE,UAAU,CAAC,IAAI,CAAC,CAAC;;QACnC,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc;IACvC,MAAM,IAAI,GAAI,KAA+B,CAAC,IAAI,CAAC;IACnD,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,WAAW,CAAC;AACvE,CAAC;AAED,qEAAqE;AACrE,SAAS,oBAAoB,CAAC,aAAqB,EAAE,UAAkB;IACrE,IAAI,CAAC;QACH,UAAU,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;QACtC,OAAO;IACT,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC;YAAE,MAAM,KAAK,CAAC;IAC7C,CAAC;IAED,yEAAyE;IACzE,0EAA0E;IAC1E,wEAAwE;IACxE,MAAM,UAAU,GAAG,GAAG,UAAU,IAAI,UAAU,EAAE,MAAM,CAAC;IACvD,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,CAAC;QACH,IAAI,CAAC;YACH,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YACnC,QAAQ,GAAG,IAAI,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,KAAK,CAAC;QACtE,CAAC;QACD,UAAU,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,QAAQ,EAAE,CAAC;YACb,IAAI,CAAC;gBACH,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YACrC,CAAC;YAAC,MAAM,CAAC;gBACP,yEAAyE;YAC3E,CAAC;QACH,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IACD,IAAI,QAAQ;QAAE,UAAU,CAAC,UAAU,CAAC,CAAC;AACvC,CAAC;AAED,mFAAmF;AACnF,SAAS,OAAO,CAAC,OAAsC;IACrD,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,WAAW,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAChD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC;QACzF,MAAM,cAAc,CAAC,OAAO,CAAC,YAAY,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC;AAED,oFAAoF;AACpF,SAAS,WAAW,CAAC,OAAsC;IACzD,IAAI,CAAC;QACH,WAAW,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC;QACP,uEAAuE;IACzE,CAAC;AACH,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAAC,OAAe,EAAE,MAAc,EAAE,iBAAwC,EAAE;IACxG,YAAY,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAClC,YAAY,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;IAC/C,SAAS,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACrE,MAAM,gBAAgB,GAAG,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACtG,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/F,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,sBAAsB,GAAG,YAAY,CAAC,IAAI,KAAK,SAAS,IAAI,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAC9G,IAAI,sBAAsB;QAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,mEAAmE;IACnE,yEAAyE;IACzE,uCAAuC;IACvC,MAAM,eAAe,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACtG,MAAM,cAAc,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACjG,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,QAAQ,EAAE,eAAe,EAAE,cAAc,CAAC,CAAC;IACnF,MAAM,GAAG,GAAG,aAAa,CAAC,OAAO,CAAC,YAAY,EAAE;QAC9C,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,gBAAgB,EAAE,OAAO,EAAE;KAC5B,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,UAAU,EAAE,CAAC;IAChC,MAAM,iBAAiB,GAAG,GAAG,OAAO,CAAC,YAAY,IAAI,UAAU,MAAM,CAAC;IACtE,MAAM,YAAY,GAAG,GAAG,OAAO,CAAC,WAAW,IAAI,UAAU,MAAM,CAAC;IAChE,IAAI,WAAW,GAAG,KAAK,CAAC;IACxB,IAAI,CAAC;QACH,0EAA0E;QAC1E,oEAAoE;QACpE,aAAa,CAAC,iBAAiB,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,QAAQ,EAAE,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACxG,yEAAyE;QACzE,mEAAmE;QACnE,aAAa,CAAC,YAAY,EAAE,SAAS,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9F,sEAAsE;QACtE,oBAAoB,CAAC,iBAAiB,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;QAC9D,oBAAoB,CAAC,YAAY,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC;QACxD,WAAW,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9F,WAAW,GAAG,IAAI,CAAC;QACnB,WAAW,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC;YACH,UAAU,CAAC,iBAAiB,CAAC,CAAC;QAChC,CAAC;QAAC,MAAM,CAAC;YACP,0CAA0C;QAC5C,CAAC;QACD,IAAI,CAAC;YACH,UAAU,CAAC,YAAY,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,0CAA0C;QAC5C,CAAC;QACD,wEAAwE;QACxE,qEAAqE;QACrE,wDAAwD;QACxD,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,IAAI,CAAC;gBACH,WAAW,CAAC,OAAO,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;gBACpD,WAAW,CAAC,OAAO,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;YAChD,CAAC;YAAC,MAAM,CAAC;gBACP,0CAA0C;YAC5C,CAAC;YACD,IAAI,sBAAsB;gBAAE,WAAW,CAAC,OAAO,CAAC,CAAC;QACnD,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IACD,OAAO,OAAO,CAAC,QAAQ,CAAC;AAC1B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,iBAAwC,EAAE;IACtE,MAAM,OAAO,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,8BAA8B,OAAO,CAAC,QAAQ,mBAAmB,CAAC;IAC3E,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,IAAI,SAAS,CAAC;IACvC,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACzC,OAAO;QACL,YAAY,OAAO,CAAC,QAAQ,EAAE;QAC9B,cAAc,MAAM,CAAC,IAAI,EAAE,IAAI,SAAS,EAAE;QAC1C,eAAe,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,EAAE;KAChD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,gBAAgB,CAAC,iBAAwC,EAAE;IACzE,MAAM,OAAO,GAAG,cAAc,CAAC,cAAc,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC5B,yEAAyE;QACzE,0EAA0E;QAC1E,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACjC,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QAChC,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,UAAU,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC9D,MAAM,sBAAsB,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACnE,IAAI,sBAAsB;QAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,CAAC,CAAC;QACvD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3D,MAAM,cAAc,CAAC,OAAO,CAAC,YAAY,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,sBAAsB;YAAE,WAAW,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,KAAK,CAAC;IACd,CAAC;IACD,kFAAkF;IAClF,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACjC,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAChC,OAAO,IAAI,CAAC;AACd,CAAC;AAQD,0EAA0E;AAC1E,MAAM,UAAU,sBAAsB,CAAC,UAAiC,EAAE;IACxE,OAAO;QACL,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC;QAC7E,aAAa,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC;QAC3C,gBAAgB,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,OAAO,CAAC;KAClD,CAAC;AACJ,CAAC"}
|
|
@@ -11,7 +11,8 @@ export interface ArtifactRecord {
|
|
|
11
11
|
export declare class ArtifactStore {
|
|
12
12
|
private readonly db;
|
|
13
13
|
private readonly directory;
|
|
14
|
-
|
|
14
|
+
private readonly platform;
|
|
15
|
+
constructor(db: GlassDatabase, directory: string, platform?: NodeJS.Platform);
|
|
15
16
|
save(sessionId: string | null, kind: string, content: string | Buffer, metadata?: Record<string, unknown>): ArtifactRecord;
|
|
16
17
|
get(idOrUri: string): ArtifactRecord | null;
|
|
17
18
|
read(idOrUri: string, offset?: number, limit?: number): Buffer;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-store.d.ts","sourceRoot":"","sources":["../../src/storage/artifact-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"artifact-store.d.ts","sourceRoot":"","sources":["../../src/storage/artifact-store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;CACnB;AAWD,qBAAa,aAAa;IAEtB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAFR,EAAE,EAAE,aAAa,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,GAAE,MAAM,CAAC,QAA2B;IAG/D,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,cAAc;IAe9H,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAe3C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAI,EAAE,KAAK,SAAY,GAAG,MAAM;CAM7D"}
|
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { chmodSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
+
import { shouldEnforcePosixPermissions } from "../paths.js";
|
|
4
5
|
export class ArtifactStore {
|
|
5
6
|
db;
|
|
6
7
|
directory;
|
|
7
|
-
|
|
8
|
+
platform;
|
|
9
|
+
constructor(db, directory, platform = process.platform) {
|
|
8
10
|
this.db = db;
|
|
9
11
|
this.directory = directory;
|
|
12
|
+
this.platform = platform;
|
|
10
13
|
}
|
|
11
14
|
save(sessionId, kind, content, metadata = {}) {
|
|
12
15
|
const id = randomUUID();
|
|
13
16
|
const path = join(this.directory, id);
|
|
14
17
|
const data = typeof content === "string" ? Buffer.from(content) : content;
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
const enforcePermissions = shouldEnforcePosixPermissions(this.platform);
|
|
19
|
+
writeFileSync(path, data, { flag: "wx", ...(enforcePermissions ? { mode: 0o600 } : {}) });
|
|
20
|
+
if (enforcePermissions)
|
|
21
|
+
chmodSync(path, 0o600);
|
|
17
22
|
const createdAt = Date.now();
|
|
18
23
|
this.db.prepare(`
|
|
19
24
|
INSERT INTO artifacts(id, session_id, kind, file_path, byte_count, metadata_json, created_at)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-store.js","sourceRoot":"","sources":["../../src/storage/artifact-store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"artifact-store.js","sourceRoot":"","sources":["../../src/storage/artifact-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Database from "better-sqlite3";
|
|
2
2
|
export type GlassDatabase = Database.Database;
|
|
3
|
-
export declare function openDatabase(path: string): GlassDatabase;
|
|
3
|
+
export declare function openDatabase(path: string, platform?: NodeJS.Platform): GlassDatabase;
|
|
4
4
|
export declare function checkpointDatabase(db: GlassDatabase): void;
|
|
5
5
|
//# sourceMappingURL=database.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/storage/database.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/storage/database.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAkTtC,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,QAAQ,CAAC;AAE9C,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,aAAa,CAgGtG;AAED,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,aAAa,GAAG,IAAI,CAE1D"}
|
package/dist/storage/database.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Database from "better-sqlite3";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
3
|
import { chmodSync, existsSync, mkdirSync } from "node:fs";
|
|
4
|
+
import { shouldEnforcePosixPermissions } from "../paths.js";
|
|
4
5
|
import { bashApprovalExecutable } from "../tools/safety.js";
|
|
5
6
|
const SESSION_SCHEMA = `
|
|
6
7
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
@@ -292,25 +293,28 @@ function migrateBashApprovalScopes(db) {
|
|
|
292
293
|
}
|
|
293
294
|
}
|
|
294
295
|
}
|
|
295
|
-
export function openDatabase(path) {
|
|
296
|
-
|
|
297
|
-
|
|
296
|
+
export function openDatabase(path, platform = process.platform) {
|
|
297
|
+
const enforcePermissions = shouldEnforcePosixPermissions(platform);
|
|
298
|
+
mkdirSync(dirname(path), { recursive: true, ...(enforcePermissions ? { mode: 0o700 } : {}) });
|
|
299
|
+
const previousUmask = enforcePermissions ? process.umask(0o077) : null;
|
|
298
300
|
let db;
|
|
299
301
|
try {
|
|
300
302
|
db = new Database(path, { timeout: 5_000 });
|
|
301
|
-
|
|
303
|
+
if (enforcePermissions)
|
|
304
|
+
chmodSync(path, 0o600);
|
|
302
305
|
db.pragma("journal_mode = WAL");
|
|
303
306
|
db.pragma("synchronous = FULL");
|
|
304
307
|
db.pragma("foreign_keys = ON");
|
|
305
308
|
db.pragma("busy_timeout = 5000");
|
|
306
309
|
db.pragma("wal_autocheckpoint = 1000");
|
|
307
310
|
for (const sidecar of [`${path}-wal`, `${path}-shm`]) {
|
|
308
|
-
if (existsSync(sidecar))
|
|
311
|
+
if (enforcePermissions && existsSync(sidecar))
|
|
309
312
|
chmodSync(sidecar, 0o600);
|
|
310
313
|
}
|
|
311
314
|
}
|
|
312
315
|
finally {
|
|
313
|
-
|
|
316
|
+
if (previousUmask !== null)
|
|
317
|
+
process.umask(previousUmask);
|
|
314
318
|
}
|
|
315
319
|
const migrate = db.transaction(() => {
|
|
316
320
|
db.exec(SESSION_SCHEMA);
|