@youtyan/code-viewer 0.2.6 → 0.2.7
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/dist/code-viewer.js +814 -250
- package/package.json +1 -1
- package/web/app.js +460 -225
package/dist/code-viewer.js
CHANGED
|
@@ -17,14 +17,97 @@ var __export = (target, all) => {
|
|
|
17
17
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
18
18
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
19
19
|
|
|
20
|
+
// web-src/server/json-store.ts
|
|
21
|
+
import { randomBytes } from "node:crypto";
|
|
22
|
+
import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
|
|
23
|
+
import { dirname } from "node:path";
|
|
24
|
+
function isEnoent(err) {
|
|
25
|
+
return err?.code === "ENOENT";
|
|
26
|
+
}
|
|
27
|
+
function tmpPath(file) {
|
|
28
|
+
return `${file}.tmp-${process.pid}-${Date.now()}-${randomBytes(4).toString("hex")}`;
|
|
29
|
+
}
|
|
30
|
+
async function backupInvalidFile(file, suffix) {
|
|
31
|
+
try {
|
|
32
|
+
await rename(file, `${file}.${suffix}-${Date.now()}`);
|
|
33
|
+
} catch {}
|
|
34
|
+
}
|
|
35
|
+
function createJsonFileStore(options) {
|
|
36
|
+
const queues = new Map;
|
|
37
|
+
const backupSuffix = options.backupSuffix ?? "corrupt";
|
|
38
|
+
const serialize = options.serialize ?? ((state) => `${JSON.stringify(state, null, 2)}
|
|
39
|
+
`);
|
|
40
|
+
async function loadUnqueued(root) {
|
|
41
|
+
const file = options.filePath(root);
|
|
42
|
+
let raw;
|
|
43
|
+
try {
|
|
44
|
+
raw = await readFile(file, "utf8");
|
|
45
|
+
} catch (err) {
|
|
46
|
+
if (isEnoent(err))
|
|
47
|
+
return options.empty();
|
|
48
|
+
throw err;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
return options.sanitize(JSON.parse(raw));
|
|
52
|
+
} catch {
|
|
53
|
+
await backupInvalidFile(file, backupSuffix);
|
|
54
|
+
return options.empty();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async function saveUnqueued(root, state) {
|
|
58
|
+
const file = options.filePath(root);
|
|
59
|
+
const normalized = options.sanitize(state);
|
|
60
|
+
const content = serialize(normalized);
|
|
61
|
+
if (options.maxBytes !== undefined && Buffer.byteLength(content, "utf8") > options.maxBytes) {
|
|
62
|
+
throw new Error(options.sizeErrorMessage ?? "JSON state too large");
|
|
63
|
+
}
|
|
64
|
+
await mkdir(dirname(file), { recursive: true });
|
|
65
|
+
const tmp = tmpPath(file);
|
|
66
|
+
await writeFile(tmp, content, "utf8");
|
|
67
|
+
await rename(tmp, file);
|
|
68
|
+
}
|
|
69
|
+
async function load(root) {
|
|
70
|
+
const pendingWrite = queues.get(options.filePath(root));
|
|
71
|
+
if (pendingWrite)
|
|
72
|
+
await pendingWrite.catch(() => {});
|
|
73
|
+
return loadUnqueued(root);
|
|
74
|
+
}
|
|
75
|
+
async function save(root, state) {
|
|
76
|
+
const file = options.filePath(root);
|
|
77
|
+
const previous = queues.get(file) ?? Promise.resolve();
|
|
78
|
+
const run = previous.catch(() => {}).then(() => saveUnqueued(root, state));
|
|
79
|
+
const queued = run.then(() => {}, () => {});
|
|
80
|
+
queues.set(file, queued);
|
|
81
|
+
try {
|
|
82
|
+
await run;
|
|
83
|
+
} finally {
|
|
84
|
+
if (queues.get(file) === queued)
|
|
85
|
+
queues.delete(file);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
async function update(root, updater) {
|
|
89
|
+
const file = options.filePath(root);
|
|
90
|
+
const previous = queues.get(file) ?? Promise.resolve();
|
|
91
|
+
const run = previous.catch(() => {}).then(async () => {
|
|
92
|
+
const current = await loadUnqueued(root);
|
|
93
|
+
const updated = await updater(current);
|
|
94
|
+
await saveUnqueued(root, updated.state);
|
|
95
|
+
return updated.result;
|
|
96
|
+
});
|
|
97
|
+
const queued = run.then(() => {}, () => {});
|
|
98
|
+
queues.set(file, queued);
|
|
99
|
+
try {
|
|
100
|
+
return await run;
|
|
101
|
+
} finally {
|
|
102
|
+
if (queues.get(file) === queued)
|
|
103
|
+
queues.delete(file);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return { load, save, update };
|
|
107
|
+
}
|
|
108
|
+
var init_json_store = () => {};
|
|
109
|
+
|
|
20
110
|
// web-src/server/annotations.ts
|
|
21
|
-
import {
|
|
22
|
-
existsSync,
|
|
23
|
-
mkdirSync,
|
|
24
|
-
readFileSync,
|
|
25
|
-
renameSync,
|
|
26
|
-
writeFileSync
|
|
27
|
-
} from "node:fs";
|
|
28
111
|
import { join } from "node:path";
|
|
29
112
|
function annotationsFilePath(root) {
|
|
30
113
|
return join(root, CODE_VIEWER_DIR, ANNOTATIONS_FILE_NAME);
|
|
@@ -242,24 +325,11 @@ function normalizeAnnotationsState(raw) {
|
|
|
242
325
|
sessions: sessions.map(normalizeSession).filter((session) => session !== null)
|
|
243
326
|
};
|
|
244
327
|
}
|
|
245
|
-
function loadAnnotationsState(root) {
|
|
246
|
-
|
|
247
|
-
if (!existsSync(file))
|
|
248
|
-
return emptyAnnotationsState();
|
|
249
|
-
try {
|
|
250
|
-
return normalizeAnnotationsState(JSON.parse(readFileSync(file, "utf8")));
|
|
251
|
-
} catch {
|
|
252
|
-
return emptyAnnotationsState();
|
|
253
|
-
}
|
|
328
|
+
async function loadAnnotationsState(root) {
|
|
329
|
+
return annotationsStore.load(root);
|
|
254
330
|
}
|
|
255
|
-
function saveAnnotationsState(root, state) {
|
|
256
|
-
|
|
257
|
-
mkdirSync(dir, { recursive: true });
|
|
258
|
-
const file = annotationsFilePath(root);
|
|
259
|
-
const tmp = `${file}.tmp-${process.pid}`;
|
|
260
|
-
writeFileSync(tmp, `${JSON.stringify(state, null, 2)}
|
|
261
|
-
`, "utf8");
|
|
262
|
-
renameSync(tmp, file);
|
|
331
|
+
async function saveAnnotationsState(root, state) {
|
|
332
|
+
return annotationsStore.save(root, state);
|
|
263
333
|
}
|
|
264
334
|
function startAnnotationSession(state, title, now, id = makeAnnotationId("s")) {
|
|
265
335
|
const session = {
|
|
@@ -484,9 +554,18 @@ function deleteAnnotationById(state, id) {
|
|
|
484
554
|
}
|
|
485
555
|
return { state, removed: null };
|
|
486
556
|
}
|
|
487
|
-
var CODE_VIEWER_DIR = ".code-viewer", ANNOTATIONS_FILE_NAME = "annotations.json", ANNOTATION_BODY_MAX_BYTES, ANNOTATION_TITLE_MAX_CHARS = 300;
|
|
557
|
+
var CODE_VIEWER_DIR = ".code-viewer", ANNOTATIONS_FILE_NAME = "annotations.json", ANNOTATION_BODY_MAX_BYTES, ANNOTATION_TITLE_MAX_CHARS = 300, MAX_ANNOTATIONS_JSON_BYTES = 5000000, annotationsStore;
|
|
488
558
|
var init_annotations = __esm(() => {
|
|
559
|
+
init_json_store();
|
|
489
560
|
ANNOTATION_BODY_MAX_BYTES = 64 * 1024;
|
|
561
|
+
annotationsStore = createJsonFileStore({
|
|
562
|
+
filePath: annotationsFilePath,
|
|
563
|
+
empty: emptyAnnotationsState,
|
|
564
|
+
sanitize: normalizeAnnotationsState,
|
|
565
|
+
maxBytes: MAX_ANNOTATIONS_JSON_BYTES,
|
|
566
|
+
backupSuffix: "corrupt",
|
|
567
|
+
sizeErrorMessage: "annotations state too large"
|
|
568
|
+
});
|
|
490
569
|
});
|
|
491
570
|
|
|
492
571
|
// web-src/server/runtime.ts
|
|
@@ -673,10 +752,10 @@ var init_runtime = () => {};
|
|
|
673
752
|
|
|
674
753
|
// web-src/server/git.ts
|
|
675
754
|
import {
|
|
676
|
-
existsSync
|
|
755
|
+
existsSync,
|
|
677
756
|
lstatSync,
|
|
678
757
|
readdirSync,
|
|
679
|
-
readFileSync
|
|
758
|
+
readFileSync,
|
|
680
759
|
statSync
|
|
681
760
|
} from "node:fs";
|
|
682
761
|
import { join as join2 } from "node:path";
|
|
@@ -1120,7 +1199,7 @@ function omittedWorktreeDirectoryReason(name, omitDirNames) {
|
|
|
1120
1199
|
return omitDirNames.has(name) ? "heavy" : undefined;
|
|
1121
1200
|
}
|
|
1122
1201
|
function worktreeEntryFromDirent(base, dir, name, isDirectory, omitDirNames, excludeNames) {
|
|
1123
|
-
if (excludeNames.has(name.toLowerCase())
|
|
1202
|
+
if (excludeNames.has(name.toLowerCase()))
|
|
1124
1203
|
return {
|
|
1125
1204
|
name,
|
|
1126
1205
|
path: "",
|
|
@@ -1182,7 +1261,7 @@ function worktreeFilesystemEntries(cwd, path, recursive, omitDirNames = DEFAULT_
|
|
|
1182
1261
|
return;
|
|
1183
1262
|
}
|
|
1184
1263
|
for (const entry of entries) {
|
|
1185
|
-
if (excludeNameSet.has(entry.name.toLowerCase())
|
|
1264
|
+
if (excludeNameSet.has(entry.name.toLowerCase()))
|
|
1186
1265
|
continue;
|
|
1187
1266
|
const entryPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
1188
1267
|
const full = join2(dir, entry.name);
|
|
@@ -1287,12 +1366,12 @@ function untrackedMeta(cwd) {
|
|
|
1287
1366
|
let lines = 0;
|
|
1288
1367
|
let fileExists = false;
|
|
1289
1368
|
try {
|
|
1290
|
-
fileExists =
|
|
1369
|
+
fileExists = existsSync(full) && statSync(full).isFile();
|
|
1291
1370
|
} catch {
|
|
1292
1371
|
fileExists = false;
|
|
1293
1372
|
}
|
|
1294
1373
|
if (fileExists) {
|
|
1295
|
-
const data =
|
|
1374
|
+
const data = readFileSync(full);
|
|
1296
1375
|
const probe = data.subarray(0, 8192);
|
|
1297
1376
|
binary = probe.includes(0);
|
|
1298
1377
|
if (!binary)
|
|
@@ -1471,11 +1550,11 @@ var init_git = __esm(() => {
|
|
|
1471
1550
|
// web-src/server/server-registry.ts
|
|
1472
1551
|
import { createHash } from "node:crypto";
|
|
1473
1552
|
import {
|
|
1474
|
-
existsSync as
|
|
1475
|
-
mkdirSync
|
|
1476
|
-
readFileSync as
|
|
1553
|
+
existsSync as existsSync2,
|
|
1554
|
+
mkdirSync,
|
|
1555
|
+
readFileSync as readFileSync2,
|
|
1477
1556
|
unlinkSync,
|
|
1478
|
-
writeFileSync
|
|
1557
|
+
writeFileSync
|
|
1479
1558
|
} from "node:fs";
|
|
1480
1559
|
import { homedir } from "node:os";
|
|
1481
1560
|
import { join as join3 } from "node:path";
|
|
@@ -1488,17 +1567,17 @@ function serverRegistryFilePath(root) {
|
|
|
1488
1567
|
}
|
|
1489
1568
|
function writeServerRegistry(entry) {
|
|
1490
1569
|
try {
|
|
1491
|
-
|
|
1492
|
-
|
|
1570
|
+
mkdirSync(registryDir(), { recursive: true });
|
|
1571
|
+
writeFileSync(serverRegistryFilePath(entry.root), `${JSON.stringify(entry, null, 2)}
|
|
1493
1572
|
`, "utf8");
|
|
1494
1573
|
} catch {}
|
|
1495
1574
|
}
|
|
1496
1575
|
function readServerRegistry(root) {
|
|
1497
1576
|
const file = serverRegistryFilePath(root);
|
|
1498
|
-
if (!
|
|
1577
|
+
if (!existsSync2(file))
|
|
1499
1578
|
return null;
|
|
1500
1579
|
try {
|
|
1501
|
-
const raw = JSON.parse(
|
|
1580
|
+
const raw = JSON.parse(readFileSync2(file, "utf8"));
|
|
1502
1581
|
if (!raw || typeof raw !== "object")
|
|
1503
1582
|
return null;
|
|
1504
1583
|
const entry = raw;
|
|
@@ -1532,7 +1611,7 @@ __export(exports_annotate_cli, {
|
|
|
1532
1611
|
ANNOTATE_HELP: () => ANNOTATE_HELP,
|
|
1533
1612
|
ANNOTATE_AGENT_HELP: () => ANNOTATE_AGENT_HELP
|
|
1534
1613
|
});
|
|
1535
|
-
import { readFileSync as
|
|
1614
|
+
import { readFileSync as readFileSync3, realpathSync } from "node:fs";
|
|
1536
1615
|
function takeValue(argv, index, flag) {
|
|
1537
1616
|
const value = argv[index + 1];
|
|
1538
1617
|
if (value === undefined)
|
|
@@ -1961,7 +2040,7 @@ async function annotationBodyFromCommand(command) {
|
|
|
1961
2040
|
let body = command.body;
|
|
1962
2041
|
if (body === undefined && command.bodyFile !== undefined) {
|
|
1963
2042
|
try {
|
|
1964
|
-
body =
|
|
2043
|
+
body = readFileSync3(command.bodyFile, "utf8");
|
|
1965
2044
|
} catch {
|
|
1966
2045
|
console.error(`could not read --body-file: ${command.bodyFile}`);
|
|
1967
2046
|
process.exit(1);
|
|
@@ -2029,7 +2108,7 @@ async function runAnnotateCli(argv) {
|
|
|
2029
2108
|
let sql = command.sql;
|
|
2030
2109
|
if (sql === undefined && command.sqlFile !== undefined) {
|
|
2031
2110
|
try {
|
|
2032
|
-
sql =
|
|
2111
|
+
sql = readFileSync3(command.sqlFile, "utf8");
|
|
2033
2112
|
} catch {
|
|
2034
2113
|
console.error(`could not read --sql-file: ${command.sqlFile}`);
|
|
2035
2114
|
process.exit(1);
|
|
@@ -2098,7 +2177,7 @@ async function runAnnotateCli(argv) {
|
|
|
2098
2177
|
if (command.kind === "edit") {
|
|
2099
2178
|
let bodyText = command.body;
|
|
2100
2179
|
if (command.bodyFile !== undefined)
|
|
2101
|
-
bodyText =
|
|
2180
|
+
bodyText = readFileSync3(command.bodyFile, "utf8");
|
|
2102
2181
|
if (bodyText === undefined) {
|
|
2103
2182
|
const stdin = await readStdin();
|
|
2104
2183
|
if (stdin.trim())
|
|
@@ -2656,16 +2735,16 @@ var init_query_cli = __esm(() => {
|
|
|
2656
2735
|
});
|
|
2657
2736
|
|
|
2658
2737
|
// web-src/server/root.ts
|
|
2659
|
-
import { existsSync as
|
|
2660
|
-
import { dirname, join as join4, normalize } from "node:path";
|
|
2738
|
+
import { existsSync as existsSync3 } from "node:fs";
|
|
2739
|
+
import { dirname as dirname2, join as join4, normalize } from "node:path";
|
|
2661
2740
|
import { fileURLToPath } from "node:url";
|
|
2662
2741
|
function findRoot(start) {
|
|
2663
2742
|
let current = start;
|
|
2664
2743
|
for (let i = 0;i < 5; i++) {
|
|
2665
|
-
if (
|
|
2744
|
+
if (existsSync3(join4(current, "package.json")) && existsSync3(join4(current, "web"))) {
|
|
2666
2745
|
return normalize(current);
|
|
2667
2746
|
}
|
|
2668
|
-
const parent =
|
|
2747
|
+
const parent = dirname2(current);
|
|
2669
2748
|
if (parent === current)
|
|
2670
2749
|
break;
|
|
2671
2750
|
current = parent;
|
|
@@ -2674,7 +2753,7 @@ function findRoot(start) {
|
|
|
2674
2753
|
}
|
|
2675
2754
|
var ROOT;
|
|
2676
2755
|
var init_root = __esm(() => {
|
|
2677
|
-
ROOT = findRoot(
|
|
2756
|
+
ROOT = findRoot(dirname2(fileURLToPath(import.meta.url)));
|
|
2678
2757
|
});
|
|
2679
2758
|
|
|
2680
2759
|
// web-src/server/skill-cli.ts
|
|
@@ -2686,7 +2765,7 @@ __export(exports_skill_cli, {
|
|
|
2686
2765
|
SKILL_HELP: () => SKILL_HELP,
|
|
2687
2766
|
AGENT_SKILL_DIRS: () => AGENT_SKILL_DIRS
|
|
2688
2767
|
});
|
|
2689
|
-
import { cpSync, existsSync as
|
|
2768
|
+
import { cpSync, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "node:fs";
|
|
2690
2769
|
import { homedir as homedir2 } from "node:os";
|
|
2691
2770
|
import { join as join5, resolve } from "node:path";
|
|
2692
2771
|
function parseAgentList(value) {
|
|
@@ -2743,7 +2822,7 @@ function parseSkillArgs(argv) {
|
|
|
2743
2822
|
return { ok: true, args: { kind: "install", agents, global, cwd } };
|
|
2744
2823
|
}
|
|
2745
2824
|
function installSkill(args, deps) {
|
|
2746
|
-
if (!
|
|
2825
|
+
if (!existsSync4(join5(deps.sourceDir, "SKILL.md"))) {
|
|
2747
2826
|
return {
|
|
2748
2827
|
ok: false,
|
|
2749
2828
|
error: `bundled skill not found at ${deps.sourceDir}`
|
|
@@ -2753,9 +2832,9 @@ function installSkill(args, deps) {
|
|
|
2753
2832
|
const results = [];
|
|
2754
2833
|
for (const agent of args.agents) {
|
|
2755
2834
|
const target = join5(base, AGENT_SKILL_DIRS[agent], "skills", SKILL_NAME);
|
|
2756
|
-
const action =
|
|
2835
|
+
const action = existsSync4(target) ? "updated" : "installed";
|
|
2757
2836
|
try {
|
|
2758
|
-
|
|
2837
|
+
mkdirSync2(target, { recursive: true });
|
|
2759
2838
|
cpSync(deps.sourceDir, target, { recursive: true });
|
|
2760
2839
|
} catch (error) {
|
|
2761
2840
|
return { ok: false, error: String(error) };
|
|
@@ -3923,6 +4002,366 @@ function makeId(prefix) {
|
|
|
3923
4002
|
return `${prefix}-${Date.now().toString(36)}${Math.random().toString(36).slice(2, 10)}`;
|
|
3924
4003
|
}
|
|
3925
4004
|
|
|
4005
|
+
// web-src/server/state-store.ts
|
|
4006
|
+
import { join as join8 } from "node:path";
|
|
4007
|
+
function codeViewerPath(root, fileName) {
|
|
4008
|
+
return join8(root, CODE_VIEWER_DIR2, fileName);
|
|
4009
|
+
}
|
|
4010
|
+
function isRecord(value) {
|
|
4011
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
4012
|
+
}
|
|
4013
|
+
function optionalString(value, maxLen) {
|
|
4014
|
+
if (typeof value !== "string")
|
|
4015
|
+
return;
|
|
4016
|
+
if (value.length === 0 || value.length > maxLen)
|
|
4017
|
+
return;
|
|
4018
|
+
if (value.includes("\x00"))
|
|
4019
|
+
return;
|
|
4020
|
+
return value;
|
|
4021
|
+
}
|
|
4022
|
+
function optionalBoolean(value) {
|
|
4023
|
+
return typeof value === "boolean" ? value : undefined;
|
|
4024
|
+
}
|
|
4025
|
+
function optionalNumber(value, min, max) {
|
|
4026
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
4027
|
+
return;
|
|
4028
|
+
return Math.max(min, Math.min(max, Math.round(value)));
|
|
4029
|
+
}
|
|
4030
|
+
function optionalFloat(value, min, max) {
|
|
4031
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
4032
|
+
return;
|
|
4033
|
+
return Math.max(min, Math.min(max, value));
|
|
4034
|
+
}
|
|
4035
|
+
function optionalFontSize(value) {
|
|
4036
|
+
return value === "compact" || value === "regular" || value === "large" || value === "xlarge" ? value : undefined;
|
|
4037
|
+
}
|
|
4038
|
+
function normalizeStringList(value, options) {
|
|
4039
|
+
if (!Array.isArray(value))
|
|
4040
|
+
return;
|
|
4041
|
+
const out = [];
|
|
4042
|
+
const seen = new Set;
|
|
4043
|
+
const items = options.keepLast ? [...value].reverse() : value;
|
|
4044
|
+
for (const item of items) {
|
|
4045
|
+
if (out.length >= options.maxItems)
|
|
4046
|
+
break;
|
|
4047
|
+
if (typeof item !== "string")
|
|
4048
|
+
continue;
|
|
4049
|
+
const name = item.trim();
|
|
4050
|
+
if (!name || name.length > options.maxLen || name.includes("\x00"))
|
|
4051
|
+
continue;
|
|
4052
|
+
if (options.pathSafe && (name.includes("/") || name.includes("\\") || name === "." || name === ".." || name === ".git")) {
|
|
4053
|
+
continue;
|
|
4054
|
+
}
|
|
4055
|
+
if (seen.has(name))
|
|
4056
|
+
continue;
|
|
4057
|
+
seen.add(name);
|
|
4058
|
+
out.push(name);
|
|
4059
|
+
}
|
|
4060
|
+
if (options.keepLast)
|
|
4061
|
+
out.reverse();
|
|
4062
|
+
return options.sort === false ? out : out.sort((a, b) => a.localeCompare(b));
|
|
4063
|
+
}
|
|
4064
|
+
function emptySettings() {
|
|
4065
|
+
return { version: 1 };
|
|
4066
|
+
}
|
|
4067
|
+
function emptyViewState() {
|
|
4068
|
+
return { version: 1, collapsedDirs: [], viewedFiles: [] };
|
|
4069
|
+
}
|
|
4070
|
+
function emptyDbUiState() {
|
|
4071
|
+
return { version: 1, columnWidths: {} };
|
|
4072
|
+
}
|
|
4073
|
+
function sanitizeSettings(raw) {
|
|
4074
|
+
if (!isRecord(raw))
|
|
4075
|
+
return emptySettings();
|
|
4076
|
+
const out = { version: 1 };
|
|
4077
|
+
if (raw.layout === "side-by-side" || raw.layout === "line-by-line")
|
|
4078
|
+
out.layout = raw.layout;
|
|
4079
|
+
if (raw.theme === "light" || raw.theme === "dark")
|
|
4080
|
+
out.theme = raw.theme;
|
|
4081
|
+
if (raw.language === "en" || raw.language === "ja")
|
|
4082
|
+
out.language = raw.language;
|
|
4083
|
+
if (raw.sidebarView === "tree" || raw.sidebarView === "flat")
|
|
4084
|
+
out.sidebarView = raw.sidebarView;
|
|
4085
|
+
const sidebarWidth = optionalNumber(raw.sidebarWidth, 180, 900);
|
|
4086
|
+
if (sidebarWidth !== undefined)
|
|
4087
|
+
out.sidebarWidth = sidebarWidth;
|
|
4088
|
+
const historyWidth = optionalNumber(raw.historyWidth, 220, 640);
|
|
4089
|
+
if (historyWidth !== undefined)
|
|
4090
|
+
out.historyWidth = historyWidth;
|
|
4091
|
+
const sidebarHidden = optionalBoolean(raw.sidebarHidden);
|
|
4092
|
+
if (sidebarHidden !== undefined)
|
|
4093
|
+
out.sidebarHidden = sidebarHidden;
|
|
4094
|
+
const sidebarFontSize = optionalFontSize(raw.sidebarFontSize);
|
|
4095
|
+
if (sidebarFontSize)
|
|
4096
|
+
out.sidebarFontSize = sidebarFontSize;
|
|
4097
|
+
const codeFontSize = optionalFontSize(raw.codeFontSize);
|
|
4098
|
+
if (codeFontSize)
|
|
4099
|
+
out.codeFontSize = codeFontSize;
|
|
4100
|
+
const syntaxHighlight = optionalBoolean(raw.syntaxHighlight);
|
|
4101
|
+
if (syntaxHighlight !== undefined)
|
|
4102
|
+
out.syntaxHighlight = syntaxHighlight;
|
|
4103
|
+
const autoUpdate = optionalBoolean(raw.autoUpdate);
|
|
4104
|
+
if (autoUpdate !== undefined)
|
|
4105
|
+
out.autoUpdate = autoUpdate;
|
|
4106
|
+
const queryHistoryPanelWidth = optionalNumber(raw.queryHistoryPanelWidth, 280, 800);
|
|
4107
|
+
if (queryHistoryPanelWidth !== undefined)
|
|
4108
|
+
out.queryHistoryPanelWidth = queryHistoryPanelWidth;
|
|
4109
|
+
const annotationPanelOpen = optionalBoolean(raw.annotationPanelOpen);
|
|
4110
|
+
if (annotationPanelOpen !== undefined)
|
|
4111
|
+
out.annotationPanelOpen = annotationPanelOpen;
|
|
4112
|
+
const annotationFollow = optionalBoolean(raw.annotationFollow);
|
|
4113
|
+
if (annotationFollow !== undefined)
|
|
4114
|
+
out.annotationFollow = annotationFollow;
|
|
4115
|
+
const annotationMuted = optionalBoolean(raw.annotationMuted);
|
|
4116
|
+
if (annotationMuted !== undefined)
|
|
4117
|
+
out.annotationMuted = annotationMuted;
|
|
4118
|
+
const annotationRate = optionalFloat(raw.annotationRate, 0.5, 2);
|
|
4119
|
+
if (annotationRate !== undefined)
|
|
4120
|
+
out.annotationRate = annotationRate;
|
|
4121
|
+
const ignoreWhitespace = optionalBoolean(raw.ignoreWhitespace);
|
|
4122
|
+
if (ignoreWhitespace !== undefined)
|
|
4123
|
+
out.ignoreWhitespace = ignoreWhitespace;
|
|
4124
|
+
const hideTests = optionalBoolean(raw.hideTests);
|
|
4125
|
+
if (hideTests !== undefined)
|
|
4126
|
+
out.hideTests = hideTests;
|
|
4127
|
+
const scopeOmitDirs = normalizeStringList(raw.scopeOmitDirs, {
|
|
4128
|
+
maxItems: 100,
|
|
4129
|
+
maxLen: 64,
|
|
4130
|
+
pathSafe: true
|
|
4131
|
+
});
|
|
4132
|
+
if (scopeOmitDirs)
|
|
4133
|
+
out.scopeOmitDirs = scopeOmitDirs;
|
|
4134
|
+
const scopeExcludeNames = normalizeStringList(raw.scopeExcludeNames, {
|
|
4135
|
+
maxItems: 200,
|
|
4136
|
+
maxLen: 128,
|
|
4137
|
+
pathSafe: true
|
|
4138
|
+
});
|
|
4139
|
+
if (scopeExcludeNames)
|
|
4140
|
+
out.scopeExcludeNames = scopeExcludeNames;
|
|
4141
|
+
if (isRecord(raw.range)) {
|
|
4142
|
+
const from = optionalString(raw.range.from, MAX_REF_LEN);
|
|
4143
|
+
const to = optionalString(raw.range.to, MAX_REF_LEN);
|
|
4144
|
+
if (from && to)
|
|
4145
|
+
out.range = { from, to };
|
|
4146
|
+
}
|
|
4147
|
+
return out;
|
|
4148
|
+
}
|
|
4149
|
+
function mergeSettings(current, patch) {
|
|
4150
|
+
if (!isRecord(patch))
|
|
4151
|
+
return current;
|
|
4152
|
+
const raw = { ...current };
|
|
4153
|
+
for (const [key, value] of Object.entries(patch)) {
|
|
4154
|
+
if (key === "version")
|
|
4155
|
+
continue;
|
|
4156
|
+
if (value === null)
|
|
4157
|
+
delete raw[key];
|
|
4158
|
+
else
|
|
4159
|
+
raw[key] = value;
|
|
4160
|
+
}
|
|
4161
|
+
return sanitizeSettings({ ...raw, version: 1 });
|
|
4162
|
+
}
|
|
4163
|
+
function sanitizeViewState(raw) {
|
|
4164
|
+
if (!isRecord(raw))
|
|
4165
|
+
return emptyViewState();
|
|
4166
|
+
return {
|
|
4167
|
+
version: 1,
|
|
4168
|
+
collapsedDirs: normalizeStringList(raw.collapsedDirs, {
|
|
4169
|
+
maxItems: MAX_VIEW_ITEMS,
|
|
4170
|
+
maxLen: MAX_KEY_LEN,
|
|
4171
|
+
keepLast: true,
|
|
4172
|
+
sort: false
|
|
4173
|
+
}) ?? [],
|
|
4174
|
+
viewedFiles: normalizeStringList(raw.viewedFiles, {
|
|
4175
|
+
maxItems: MAX_VIEW_ITEMS,
|
|
4176
|
+
maxLen: MAX_KEY_LEN,
|
|
4177
|
+
keepLast: true,
|
|
4178
|
+
sort: false
|
|
4179
|
+
}) ?? []
|
|
4180
|
+
};
|
|
4181
|
+
}
|
|
4182
|
+
function mergeViewState(current, patch) {
|
|
4183
|
+
if (!isRecord(patch))
|
|
4184
|
+
return current;
|
|
4185
|
+
const base = sanitizeViewState({ ...current, version: 1 });
|
|
4186
|
+
const collapsedDirs = new Set(base.collapsedDirs);
|
|
4187
|
+
const viewedFiles = new Set(base.viewedFiles);
|
|
4188
|
+
const addedCollapsedDirs = normalizeStringList(patch.addedCollapsedDirs, {
|
|
4189
|
+
maxItems: MAX_VIEW_ITEMS,
|
|
4190
|
+
maxLen: MAX_KEY_LEN,
|
|
4191
|
+
keepLast: true,
|
|
4192
|
+
sort: false
|
|
4193
|
+
});
|
|
4194
|
+
for (const path of addedCollapsedDirs || [])
|
|
4195
|
+
collapsedDirs.add(path);
|
|
4196
|
+
const removedCollapsedDirs = normalizeStringList(patch.removedCollapsedDirs, {
|
|
4197
|
+
maxItems: MAX_VIEW_ITEMS,
|
|
4198
|
+
maxLen: MAX_KEY_LEN,
|
|
4199
|
+
sort: false
|
|
4200
|
+
});
|
|
4201
|
+
for (const path of removedCollapsedDirs || [])
|
|
4202
|
+
collapsedDirs.delete(path);
|
|
4203
|
+
const addedViewedFiles = normalizeStringList(patch.addedViewedFiles, {
|
|
4204
|
+
maxItems: MAX_VIEW_ITEMS,
|
|
4205
|
+
maxLen: MAX_KEY_LEN,
|
|
4206
|
+
keepLast: true,
|
|
4207
|
+
sort: false
|
|
4208
|
+
});
|
|
4209
|
+
for (const path of addedViewedFiles || [])
|
|
4210
|
+
viewedFiles.add(path);
|
|
4211
|
+
const removedViewedFiles = normalizeStringList(patch.removedViewedFiles, {
|
|
4212
|
+
maxItems: MAX_VIEW_ITEMS,
|
|
4213
|
+
maxLen: MAX_KEY_LEN,
|
|
4214
|
+
sort: false
|
|
4215
|
+
});
|
|
4216
|
+
for (const path of removedViewedFiles || [])
|
|
4217
|
+
viewedFiles.delete(path);
|
|
4218
|
+
return sanitizeViewState({
|
|
4219
|
+
version: 1,
|
|
4220
|
+
collapsedDirs: [...collapsedDirs],
|
|
4221
|
+
viewedFiles: [...viewedFiles]
|
|
4222
|
+
});
|
|
4223
|
+
}
|
|
4224
|
+
function safeObjectKey(value) {
|
|
4225
|
+
if (!value || value.length > MAX_KEY_LEN || value.includes("\x00"))
|
|
4226
|
+
return null;
|
|
4227
|
+
return value;
|
|
4228
|
+
}
|
|
4229
|
+
function sanitizeDbUiState(raw) {
|
|
4230
|
+
if (!isRecord(raw) || !isRecord(raw.columnWidths))
|
|
4231
|
+
return emptyDbUiState();
|
|
4232
|
+
const columnWidths = {};
|
|
4233
|
+
let dbCount = 0;
|
|
4234
|
+
for (const [dbIdRaw, tablesRaw] of Object.entries(raw.columnWidths)) {
|
|
4235
|
+
if (dbCount >= MAX_DB_UI_DBS)
|
|
4236
|
+
break;
|
|
4237
|
+
const dbId = safeObjectKey(dbIdRaw);
|
|
4238
|
+
if (!dbId || !isRecord(tablesRaw))
|
|
4239
|
+
continue;
|
|
4240
|
+
const tables = {};
|
|
4241
|
+
let tableCount = 0;
|
|
4242
|
+
for (const [tableRaw, columnsRaw] of Object.entries(tablesRaw)) {
|
|
4243
|
+
if (tableCount >= MAX_DB_UI_TABLES)
|
|
4244
|
+
break;
|
|
4245
|
+
const table = safeObjectKey(tableRaw);
|
|
4246
|
+
if (!table || !isRecord(columnsRaw))
|
|
4247
|
+
continue;
|
|
4248
|
+
const columns = {};
|
|
4249
|
+
let columnCount = 0;
|
|
4250
|
+
for (const [columnRaw, widthRaw] of Object.entries(columnsRaw)) {
|
|
4251
|
+
if (columnCount >= MAX_DB_UI_COLUMNS)
|
|
4252
|
+
break;
|
|
4253
|
+
const column = safeObjectKey(columnRaw);
|
|
4254
|
+
const width = optionalNumber(widthRaw, 60, 1200);
|
|
4255
|
+
if (!column || width === undefined)
|
|
4256
|
+
continue;
|
|
4257
|
+
columns[column] = width;
|
|
4258
|
+
columnCount++;
|
|
4259
|
+
}
|
|
4260
|
+
if (Object.keys(columns).length === 0)
|
|
4261
|
+
continue;
|
|
4262
|
+
tables[table] = columns;
|
|
4263
|
+
tableCount++;
|
|
4264
|
+
}
|
|
4265
|
+
if (Object.keys(tables).length === 0)
|
|
4266
|
+
continue;
|
|
4267
|
+
columnWidths[dbId] = tables;
|
|
4268
|
+
dbCount++;
|
|
4269
|
+
}
|
|
4270
|
+
return { version: 1, columnWidths };
|
|
4271
|
+
}
|
|
4272
|
+
function mergeDbUiState(current, patch) {
|
|
4273
|
+
if (!isRecord(patch))
|
|
4274
|
+
return current;
|
|
4275
|
+
if (!isRecord(patch.columnWidths)) {
|
|
4276
|
+
return sanitizeDbUiState({ ...current, ...patch, version: 1 });
|
|
4277
|
+
}
|
|
4278
|
+
const columnWidths = {
|
|
4279
|
+
...current.columnWidths
|
|
4280
|
+
};
|
|
4281
|
+
for (const [dbId, tablesRaw] of Object.entries(patch.columnWidths)) {
|
|
4282
|
+
if (tablesRaw === null) {
|
|
4283
|
+
delete columnWidths[dbId];
|
|
4284
|
+
continue;
|
|
4285
|
+
}
|
|
4286
|
+
if (!isRecord(tablesRaw))
|
|
4287
|
+
continue;
|
|
4288
|
+
const tables = { ...columnWidths[dbId] || {} };
|
|
4289
|
+
for (const [table, columnsRaw] of Object.entries(tablesRaw)) {
|
|
4290
|
+
if (columnsRaw === null) {
|
|
4291
|
+
delete tables[table];
|
|
4292
|
+
continue;
|
|
4293
|
+
}
|
|
4294
|
+
if (!isRecord(columnsRaw))
|
|
4295
|
+
continue;
|
|
4296
|
+
const columns = { ...tables[table] || {} };
|
|
4297
|
+
for (const [column, widthRaw] of Object.entries(columnsRaw)) {
|
|
4298
|
+
if (widthRaw === null)
|
|
4299
|
+
delete columns[column];
|
|
4300
|
+
else
|
|
4301
|
+
columns[column] = widthRaw;
|
|
4302
|
+
}
|
|
4303
|
+
tables[table] = columns;
|
|
4304
|
+
}
|
|
4305
|
+
columnWidths[dbId] = tables;
|
|
4306
|
+
}
|
|
4307
|
+
return sanitizeDbUiState({ ...current, ...patch, columnWidths, version: 1 });
|
|
4308
|
+
}
|
|
4309
|
+
async function loadAppSettingsState(root) {
|
|
4310
|
+
return settingsStore.load(root);
|
|
4311
|
+
}
|
|
4312
|
+
async function patchAppSettingsState(root, patch) {
|
|
4313
|
+
return settingsStore.update(root, (state) => {
|
|
4314
|
+
const next = mergeSettings(state, patch);
|
|
4315
|
+
return { state: next, result: next };
|
|
4316
|
+
});
|
|
4317
|
+
}
|
|
4318
|
+
async function loadViewState(root) {
|
|
4319
|
+
return viewStateStore.load(root);
|
|
4320
|
+
}
|
|
4321
|
+
async function patchViewState(root, patch) {
|
|
4322
|
+
return viewStateStore.update(root, (state) => {
|
|
4323
|
+
const next = mergeViewState(state, patch);
|
|
4324
|
+
return { state: next, result: next };
|
|
4325
|
+
});
|
|
4326
|
+
}
|
|
4327
|
+
async function loadDbUiState(root) {
|
|
4328
|
+
return dbUiStore.load(root);
|
|
4329
|
+
}
|
|
4330
|
+
async function patchDbUiState(root, patch) {
|
|
4331
|
+
return dbUiStore.update(root, (state) => {
|
|
4332
|
+
const next = mergeDbUiState(state, patch);
|
|
4333
|
+
return { state: next, result: next };
|
|
4334
|
+
});
|
|
4335
|
+
}
|
|
4336
|
+
var CODE_VIEWER_DIR2 = ".code-viewer", SETTINGS_FILE_NAME = "settings.json", VIEW_STATE_FILE_NAME = "view-state.json", DB_UI_FILE_NAME = "db-ui.json", MAX_SETTINGS_BYTES = 200000, MAX_VIEW_STATE_BYTES = 1e6, MAX_DB_UI_BYTES = 1e6, MAX_REF_LEN = 1024, MAX_KEY_LEN = 2048, MAX_VIEW_ITEMS = 20000, MAX_DB_UI_DBS = 200, MAX_DB_UI_TABLES = 500, MAX_DB_UI_COLUMNS = 1000, settingsStore, viewStateStore, dbUiStore;
|
|
4337
|
+
var init_state_store = __esm(() => {
|
|
4338
|
+
init_json_store();
|
|
4339
|
+
settingsStore = createJsonFileStore({
|
|
4340
|
+
filePath: (root) => codeViewerPath(root, SETTINGS_FILE_NAME),
|
|
4341
|
+
empty: emptySettings,
|
|
4342
|
+
sanitize: sanitizeSettings,
|
|
4343
|
+
maxBytes: MAX_SETTINGS_BYTES,
|
|
4344
|
+
backupSuffix: "corrupt",
|
|
4345
|
+
sizeErrorMessage: "settings state too large"
|
|
4346
|
+
});
|
|
4347
|
+
viewStateStore = createJsonFileStore({
|
|
4348
|
+
filePath: (root) => codeViewerPath(root, VIEW_STATE_FILE_NAME),
|
|
4349
|
+
empty: emptyViewState,
|
|
4350
|
+
sanitize: sanitizeViewState,
|
|
4351
|
+
maxBytes: MAX_VIEW_STATE_BYTES,
|
|
4352
|
+
backupSuffix: "corrupt",
|
|
4353
|
+
sizeErrorMessage: "view state too large"
|
|
4354
|
+
});
|
|
4355
|
+
dbUiStore = createJsonFileStore({
|
|
4356
|
+
filePath: (root) => codeViewerPath(root, DB_UI_FILE_NAME),
|
|
4357
|
+
empty: emptyDbUiState,
|
|
4358
|
+
sanitize: sanitizeDbUiState,
|
|
4359
|
+
maxBytes: MAX_DB_UI_BYTES,
|
|
4360
|
+
backupSuffix: "corrupt",
|
|
4361
|
+
sizeErrorMessage: "db UI state too large"
|
|
4362
|
+
});
|
|
4363
|
+
});
|
|
4364
|
+
|
|
3926
4365
|
// web-src/server/database/adapters/abort.ts
|
|
3927
4366
|
function abortError(message = "operation aborted") {
|
|
3928
4367
|
const err = new Error(message);
|
|
@@ -5626,14 +6065,14 @@ var init_connection_pool = __esm(() => {
|
|
|
5626
6065
|
// web-src/server/database/discovery.ts
|
|
5627
6066
|
import {
|
|
5628
6067
|
closeSync,
|
|
5629
|
-
existsSync as
|
|
6068
|
+
existsSync as existsSync5,
|
|
5630
6069
|
openSync,
|
|
5631
6070
|
readSync,
|
|
5632
6071
|
realpathSync as realpathSync3,
|
|
5633
6072
|
statSync as statSync2
|
|
5634
6073
|
} from "node:fs";
|
|
5635
|
-
import { lstat, open, readdir, readFile, stat } from "node:fs/promises";
|
|
5636
|
-
import { basename as basename2, join as
|
|
6074
|
+
import { lstat, open, readdir, readFile as readFile2, stat } from "node:fs/promises";
|
|
6075
|
+
import { basename as basename2, join as join9, relative as relative2 } from "node:path";
|
|
5637
6076
|
function isSqliteFile(fullPath) {
|
|
5638
6077
|
try {
|
|
5639
6078
|
const stat2 = statSync2(fullPath);
|
|
@@ -5704,7 +6143,7 @@ async function discoverSqliteFilesAsync(cwd, omitDirNames, signal) {
|
|
|
5704
6143
|
return;
|
|
5705
6144
|
if (omitSet.has(entry.toLowerCase()))
|
|
5706
6145
|
continue;
|
|
5707
|
-
const full =
|
|
6146
|
+
const full = join9(dir, entry);
|
|
5708
6147
|
let entryStat;
|
|
5709
6148
|
try {
|
|
5710
6149
|
entryStat = await lstat(full);
|
|
@@ -5748,8 +6187,8 @@ function validateDbPath(cwd, dbPath) {
|
|
|
5748
6187
|
const parts = dbPath.split(/[\\/]+/);
|
|
5749
6188
|
if (parts.some((p) => p === ".." || p.toLowerCase() === ".git" || p.toLowerCase() === ".code-viewer"))
|
|
5750
6189
|
return null;
|
|
5751
|
-
const full =
|
|
5752
|
-
if (!
|
|
6190
|
+
const full = join9(cwd, dbPath);
|
|
6191
|
+
if (!existsSync5(full))
|
|
5753
6192
|
return null;
|
|
5754
6193
|
let realCwd;
|
|
5755
6194
|
let realFull;
|
|
@@ -5885,7 +6324,7 @@ function resolveEnvValue(raw, composeDirEnv = {}) {
|
|
|
5885
6324
|
}
|
|
5886
6325
|
async function readDotenvAsync(composeDir) {
|
|
5887
6326
|
try {
|
|
5888
|
-
const content = await
|
|
6327
|
+
const content = await readFile2(join9(composeDir, ".env"), "utf-8");
|
|
5889
6328
|
return parseDotenvContent(content);
|
|
5890
6329
|
} catch {
|
|
5891
6330
|
return {};
|
|
@@ -6059,7 +6498,7 @@ function parseComposeContent(content, filepath, composeDir, cwd, composeDirEnv,
|
|
|
6059
6498
|
async function parseComposeFileAsync(filepath, composeDir, cwd, results) {
|
|
6060
6499
|
let content;
|
|
6061
6500
|
try {
|
|
6062
|
-
content = await
|
|
6501
|
+
content = await readFile2(filepath, "utf-8");
|
|
6063
6502
|
} catch {
|
|
6064
6503
|
return;
|
|
6065
6504
|
}
|
|
@@ -6105,7 +6544,7 @@ async function discoverDockerDatabasesAsync(cwd, omitDirNames = [], signal) {
|
|
|
6105
6544
|
if (depth > MAX_SCAN_DEPTH)
|
|
6106
6545
|
return;
|
|
6107
6546
|
for (const filename of COMPOSE_FILENAMES) {
|
|
6108
|
-
const filepath =
|
|
6547
|
+
const filepath = join9(dir, filename);
|
|
6109
6548
|
if (await pathExistsAsync(filepath)) {
|
|
6110
6549
|
await parseComposeFileAsync(filepath, dir, cwd, results);
|
|
6111
6550
|
break;
|
|
@@ -6128,7 +6567,7 @@ async function discoverDockerDatabasesAsync(cwd, omitDirNames = [], signal) {
|
|
|
6128
6567
|
return;
|
|
6129
6568
|
if (omitSet.has(entry.toLowerCase()))
|
|
6130
6569
|
continue;
|
|
6131
|
-
const full =
|
|
6570
|
+
const full = join9(dir, entry);
|
|
6132
6571
|
let entryStat;
|
|
6133
6572
|
try {
|
|
6134
6573
|
entryStat = await lstat(full);
|
|
@@ -6763,6 +7202,32 @@ function textError(message, status) {
|
|
|
6763
7202
|
}
|
|
6764
7203
|
});
|
|
6765
7204
|
}
|
|
7205
|
+
async function jsonLoadResponse(load, logPrefix, errorMessage) {
|
|
7206
|
+
try {
|
|
7207
|
+
return json(await load());
|
|
7208
|
+
} catch (err) {
|
|
7209
|
+
console.error(`[code-viewer] ${logPrefix} error:`, err);
|
|
7210
|
+
return textError(errorMessage, 500);
|
|
7211
|
+
}
|
|
7212
|
+
}
|
|
7213
|
+
async function parseBoundedJsonBody(req, maxBytes, tooLargeMessage) {
|
|
7214
|
+
const contentType = req.headers.get("content-type") || "";
|
|
7215
|
+
if (!contentType.toLowerCase().startsWith("application/json")) {
|
|
7216
|
+
return textError("unsupported media type", 415);
|
|
7217
|
+
}
|
|
7218
|
+
const contentLength = Number(req.headers.get("content-length") || "0");
|
|
7219
|
+
if (contentLength > maxBytes)
|
|
7220
|
+
return textError(tooLargeMessage, 413);
|
|
7221
|
+
try {
|
|
7222
|
+
const raw = await req.text();
|
|
7223
|
+
if (Buffer.byteLength(raw, "utf8") > maxBytes) {
|
|
7224
|
+
return textError(tooLargeMessage, 413);
|
|
7225
|
+
}
|
|
7226
|
+
return JSON.parse(raw);
|
|
7227
|
+
} catch {
|
|
7228
|
+
return textError("invalid JSON body", 400);
|
|
7229
|
+
}
|
|
7230
|
+
}
|
|
6766
7231
|
function waitForCallerAbort(promise, signal, message) {
|
|
6767
7232
|
if (!signal)
|
|
6768
7233
|
return promise;
|
|
@@ -6794,6 +7259,10 @@ function waitForCallerAbort(promise, signal, message) {
|
|
|
6794
7259
|
});
|
|
6795
7260
|
});
|
|
6796
7261
|
}
|
|
7262
|
+
function isFilesystemAccessError(err) {
|
|
7263
|
+
const code = err?.code;
|
|
7264
|
+
return code === "EACCES" || code === "EBUSY" || code === "EIO" || code === "EISDIR" || code === "ENOSPC" || code === "ENOTDIR" || code === "EPERM" || code === "EROFS";
|
|
7265
|
+
}
|
|
6797
7266
|
async function resolveDockerExplorerAsync(cwd, dbParam, kind, cache, openFn, omitDirNames, signal) {
|
|
6798
7267
|
if (!dbParam)
|
|
6799
7268
|
return textError("missing db parameter", 400);
|
|
@@ -6860,6 +7329,9 @@ function handleError(prefix, action, err) {
|
|
|
6860
7329
|
if (isDockerComposeServiceUnavailableError(err)) {
|
|
6861
7330
|
return textError(message, err.status);
|
|
6862
7331
|
}
|
|
7332
|
+
if (isFilesystemAccessError(err)) {
|
|
7333
|
+
return textError(`failed to ${action}`, 500);
|
|
7334
|
+
}
|
|
6863
7335
|
return textError(`failed to ${action}: ${message}`, 500);
|
|
6864
7336
|
}
|
|
6865
7337
|
var DEFAULT_MAX_DOCKER_ADAPTER_CACHE = 8, DEFAULT_DOCKER_ADAPTER_IDLE_MS;
|
|
@@ -8657,13 +9129,9 @@ var init_handle_s3 = __esm(() => {
|
|
|
8657
9129
|
});
|
|
8658
9130
|
|
|
8659
9131
|
// web-src/server/database/query-history.ts
|
|
8660
|
-
import {
|
|
8661
|
-
import { join as join9 } from "node:path";
|
|
9132
|
+
import { join as join10 } from "node:path";
|
|
8662
9133
|
function historyFilePath(root) {
|
|
8663
|
-
return
|
|
8664
|
-
}
|
|
8665
|
-
function isEnoent(err) {
|
|
8666
|
-
return err?.code === "ENOENT";
|
|
9134
|
+
return join10(root, CODE_VIEWER_DIR3, HISTORY_FILE_NAME);
|
|
8667
9135
|
}
|
|
8668
9136
|
function emptyState() {
|
|
8669
9137
|
return { version: 1, entries: [] };
|
|
@@ -8682,69 +9150,86 @@ function serializeHistoryState(state) {
|
|
|
8682
9150
|
}
|
|
8683
9151
|
return content;
|
|
8684
9152
|
}
|
|
8685
|
-
|
|
8686
|
-
|
|
8687
|
-
|
|
8688
|
-
|
|
9153
|
+
function optionalString2(value, maxLen) {
|
|
9154
|
+
if (typeof value !== "string")
|
|
9155
|
+
return;
|
|
9156
|
+
if (!value || value.length > maxLen || value.includes("\x00"))
|
|
9157
|
+
return;
|
|
9158
|
+
return value;
|
|
8689
9159
|
}
|
|
8690
|
-
|
|
8691
|
-
|
|
8692
|
-
|
|
8693
|
-
|
|
9160
|
+
function finiteNumber(value, min = 0) {
|
|
9161
|
+
if (typeof value !== "number" || !Number.isFinite(value))
|
|
9162
|
+
return;
|
|
9163
|
+
return Math.max(min, Math.round(value));
|
|
9164
|
+
}
|
|
9165
|
+
function sanitizeDbValue(value) {
|
|
9166
|
+
if (value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
9167
|
+
return value;
|
|
8694
9168
|
}
|
|
8695
|
-
return
|
|
9169
|
+
return null;
|
|
8696
9170
|
}
|
|
8697
|
-
|
|
8698
|
-
|
|
8699
|
-
|
|
8700
|
-
|
|
8701
|
-
|
|
8702
|
-
|
|
8703
|
-
|
|
8704
|
-
|
|
8705
|
-
|
|
9171
|
+
function sanitizeRows(raw) {
|
|
9172
|
+
if (!Array.isArray(raw))
|
|
9173
|
+
return [];
|
|
9174
|
+
return raw.slice(0, MAX_PREVIEW_ROWS).map((row) => {
|
|
9175
|
+
if (!Array.isArray(row))
|
|
9176
|
+
return [];
|
|
9177
|
+
return row.map(sanitizeDbValue);
|
|
9178
|
+
});
|
|
9179
|
+
}
|
|
9180
|
+
function sanitizeEntry(raw) {
|
|
9181
|
+
if (!raw || typeof raw !== "object")
|
|
9182
|
+
return null;
|
|
9183
|
+
const entry = raw;
|
|
9184
|
+
const id = optionalString2(entry.id, MAX_ID_LEN);
|
|
9185
|
+
const dbId = optionalString2(entry.dbId, MAX_DB_ID_LEN);
|
|
9186
|
+
const sql = optionalString2(entry.sql, MAX_SQL_LEN);
|
|
9187
|
+
if (!id || !dbId || !sql)
|
|
9188
|
+
return null;
|
|
9189
|
+
const columns = Array.isArray(entry.columns) ? entry.columns.filter((col) => typeof col === "string" && !!col).map((col) => col.slice(0, MAX_COLUMN_LEN)).slice(0, MAX_COLUMNS) : [];
|
|
9190
|
+
const rowsPreview = sanitizeRows(entry.rowsPreview);
|
|
9191
|
+
const schema = optionalString2(entry.schema, MAX_SCHEMA_LEN);
|
|
9192
|
+
const title = optionalString2(entry.title, MAX_TEXT_LEN);
|
|
9193
|
+
const body = optionalString2(entry.body, MAX_TEXT_LEN);
|
|
9194
|
+
return {
|
|
9195
|
+
id,
|
|
9196
|
+
dbId,
|
|
9197
|
+
...schema ? { schema } : {},
|
|
9198
|
+
sql,
|
|
9199
|
+
...title ? { title } : {},
|
|
9200
|
+
...body ? { body } : {},
|
|
9201
|
+
columns,
|
|
9202
|
+
rowsPreview,
|
|
9203
|
+
rowCount: finiteNumber(entry.rowCount) ?? rowsPreview.length,
|
|
9204
|
+
savedRows: finiteNumber(entry.savedRows) ?? rowsPreview.length,
|
|
9205
|
+
truncated: typeof entry.truncated === "boolean" ? entry.truncated : false,
|
|
9206
|
+
elapsedMs: finiteNumber(entry.elapsedMs) ?? 0,
|
|
9207
|
+
executedAt: optionalString2(entry.executedAt, 64) ?? new Date(0).toISOString(),
|
|
9208
|
+
executedBy: entry.executedBy === "ai" ? "ai" : "user",
|
|
9209
|
+
source: entry.source === "cli" ? "cli" : "browser"
|
|
9210
|
+
};
|
|
9211
|
+
}
|
|
9212
|
+
function sanitizeHistoryState(raw) {
|
|
9213
|
+
if (!raw || typeof raw !== "object")
|
|
8706
9214
|
return emptyState();
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
const parsed = JSON.parse(raw);
|
|
8710
|
-
if (!parsed || typeof parsed !== "object" || parsed.version !== 1 || !Array.isArray(parsed.entries)) {
|
|
8711
|
-
await backupCorruptHistoryFileAsync(file);
|
|
8712
|
-
return emptyState();
|
|
8713
|
-
}
|
|
8714
|
-
return parsed;
|
|
8715
|
-
} catch (err) {
|
|
8716
|
-
if (isEnoent(err))
|
|
8717
|
-
return emptyState();
|
|
8718
|
-
await backupCorruptHistoryFileAsync(file);
|
|
9215
|
+
const entriesRaw = raw.entries;
|
|
9216
|
+
if (!Array.isArray(entriesRaw))
|
|
8719
9217
|
return emptyState();
|
|
9218
|
+
const entries = [];
|
|
9219
|
+
for (const entry of entriesRaw) {
|
|
9220
|
+
if (entries.length >= MAX_ENTRIES2)
|
|
9221
|
+
break;
|
|
9222
|
+
const normalized = sanitizeEntry(entry);
|
|
9223
|
+
if (normalized)
|
|
9224
|
+
entries.push(normalized);
|
|
8720
9225
|
}
|
|
9226
|
+
return { version: 1, entries };
|
|
8721
9227
|
}
|
|
8722
|
-
async function
|
|
8723
|
-
|
|
8724
|
-
await mkdir(dir, { recursive: true });
|
|
8725
|
-
const file = historyFilePath(cwd);
|
|
8726
|
-
const tmp = `${file}.tmp-${process.pid}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
8727
|
-
const content = serializeHistoryState(state);
|
|
8728
|
-
await writeFile(tmp, content, "utf8");
|
|
8729
|
-
await rename(tmp, file);
|
|
9228
|
+
async function loadQueryHistoryAsync(cwd) {
|
|
9229
|
+
return historyStore.load(cwd);
|
|
8730
9230
|
}
|
|
8731
9231
|
async function updateQueryHistoryAsync(cwd, updater) {
|
|
8732
|
-
|
|
8733
|
-
const run2 = previous.catch(() => {}).then(async () => {
|
|
8734
|
-
const current = await loadQueryHistoryAsyncUnqueued(cwd);
|
|
8735
|
-
const updated = await updater(current);
|
|
8736
|
-
await saveQueryHistoryAsync(cwd, updated.state);
|
|
8737
|
-
return updated.result;
|
|
8738
|
-
});
|
|
8739
|
-
const queued = run2.then(() => {}, () => {});
|
|
8740
|
-
historyWriteQueues.set(cwd, queued);
|
|
8741
|
-
try {
|
|
8742
|
-
return await run2;
|
|
8743
|
-
} finally {
|
|
8744
|
-
if (historyWriteQueues.get(cwd) === queued) {
|
|
8745
|
-
historyWriteQueues.delete(cwd);
|
|
8746
|
-
}
|
|
8747
|
-
}
|
|
9232
|
+
return historyStore.update(cwd, updater);
|
|
8748
9233
|
}
|
|
8749
9234
|
function clampPreviewRows(rows) {
|
|
8750
9235
|
return rows.slice(0, MAX_PREVIEW_ROWS);
|
|
@@ -8780,15 +9265,23 @@ function clearQueryHistory(state, dbId, schema) {
|
|
|
8780
9265
|
})
|
|
8781
9266
|
};
|
|
8782
9267
|
}
|
|
8783
|
-
var
|
|
9268
|
+
var CODE_VIEWER_DIR3 = ".code-viewer", HISTORY_FILE_NAME = "query-history.json", MAX_ENTRIES2 = 200, MAX_PREVIEW_ROWS = 100, MAX_JSON_BYTES = 1e6, MAX_ID_LEN = 128, MAX_DB_ID_LEN = 2048, MAX_SCHEMA_LEN = 512, MAX_SQL_LEN = 64000, MAX_TEXT_LEN = 64000, MAX_COLUMN_LEN = 512, MAX_COLUMNS = 500, historyStore;
|
|
8784
9269
|
var init_query_history = __esm(() => {
|
|
8785
|
-
|
|
9270
|
+
init_json_store();
|
|
9271
|
+
historyStore = createJsonFileStore({
|
|
9272
|
+
filePath: historyFilePath,
|
|
9273
|
+
empty: emptyState,
|
|
9274
|
+
sanitize: sanitizeHistoryState,
|
|
9275
|
+
maxBytes: MAX_JSON_BYTES,
|
|
9276
|
+
backupSuffix: "corrupt",
|
|
9277
|
+
serialize: serializeHistoryState
|
|
9278
|
+
});
|
|
8786
9279
|
});
|
|
8787
9280
|
|
|
8788
9281
|
// web-src/server/database/snapshot-store.ts
|
|
8789
|
-
import { createHash as createHash5, randomBytes } from "node:crypto";
|
|
8790
|
-
import { mkdirSync as
|
|
8791
|
-
import { join as
|
|
9282
|
+
import { createHash as createHash5, randomBytes as randomBytes2 } from "node:crypto";
|
|
9283
|
+
import { mkdirSync as mkdirSync3 } from "node:fs";
|
|
9284
|
+
import { join as join11 } from "node:path";
|
|
8792
9285
|
async function getSqliteClass2() {
|
|
8793
9286
|
if (cachedDbClass2)
|
|
8794
9287
|
return cachedDbClass2;
|
|
@@ -8805,7 +9298,7 @@ async function getSqliteClass2() {
|
|
|
8805
9298
|
throw new Error("No SQLite driver available. Install better-sqlite3 or use the bun runtime.");
|
|
8806
9299
|
}
|
|
8807
9300
|
async function getStoreDb(cwd) {
|
|
8808
|
-
const dbPath =
|
|
9301
|
+
const dbPath = join11(cwd, CODE_VIEWER_DIR4, SNAPSHOT_DB_NAME);
|
|
8809
9302
|
if (storeDb && storeDbPath === dbPath)
|
|
8810
9303
|
return storeDb;
|
|
8811
9304
|
if (storeDb) {
|
|
@@ -8813,7 +9306,7 @@ async function getStoreDb(cwd) {
|
|
|
8813
9306
|
storeDb.close();
|
|
8814
9307
|
} catch {}
|
|
8815
9308
|
}
|
|
8816
|
-
|
|
9309
|
+
mkdirSync3(join11(cwd, CODE_VIEWER_DIR4), { recursive: true });
|
|
8817
9310
|
const DbClass = await getSqliteClass2();
|
|
8818
9311
|
storeDb = new DbClass(dbPath);
|
|
8819
9312
|
storeDbPath = dbPath;
|
|
@@ -8826,7 +9319,7 @@ async function getStoreDb(cwd) {
|
|
|
8826
9319
|
return storeDb;
|
|
8827
9320
|
}
|
|
8828
9321
|
function makeId2(prefix) {
|
|
8829
|
-
return `${prefix}-${
|
|
9322
|
+
return `${prefix}-${randomBytes2(8).toString("hex")}`;
|
|
8830
9323
|
}
|
|
8831
9324
|
function hashPayload(payloadJson) {
|
|
8832
9325
|
return createHash5("sha256").update(payloadJson).digest("hex");
|
|
@@ -9073,7 +9566,7 @@ async function computeDiffRows(cwd, beforeId, afterId, table, offset = 0, limit
|
|
|
9073
9566
|
});
|
|
9074
9567
|
return { rows, total };
|
|
9075
9568
|
}
|
|
9076
|
-
var
|
|
9569
|
+
var CODE_VIEWER_DIR4 = ".code-viewer", SNAPSHOT_DB_NAME = "db-snapshots.sqlite", cachedDbClass2 = null, SCHEMA_SQL = `
|
|
9077
9570
|
CREATE TABLE IF NOT EXISTS snapshots (
|
|
9078
9571
|
id TEXT PRIMARY KEY,
|
|
9079
9572
|
db_id TEXT NOT NULL,
|
|
@@ -9170,13 +9663,9 @@ var init_snapshot_runner = __esm(() => {
|
|
|
9170
9663
|
});
|
|
9171
9664
|
|
|
9172
9665
|
// web-src/server/database/tabs-store.ts
|
|
9173
|
-
import {
|
|
9174
|
-
import { join as join11 } from "node:path";
|
|
9666
|
+
import { join as join12 } from "node:path";
|
|
9175
9667
|
function tabsFilePath(root) {
|
|
9176
|
-
return
|
|
9177
|
-
}
|
|
9178
|
-
function isEnoent2(err) {
|
|
9179
|
-
return err?.code === "ENOENT";
|
|
9668
|
+
return join12(root, CODE_VIEWER_DIR5, TABS_FILE_NAME);
|
|
9180
9669
|
}
|
|
9181
9670
|
function emptyState2() {
|
|
9182
9671
|
return { version: 1, tabs: [], activeTabId: null };
|
|
@@ -9244,6 +9733,31 @@ function sanitizeEs(v) {
|
|
|
9244
9733
|
return;
|
|
9245
9734
|
return out;
|
|
9246
9735
|
}
|
|
9736
|
+
function sanitizeS3(v) {
|
|
9737
|
+
if (!v || typeof v !== "object")
|
|
9738
|
+
return;
|
|
9739
|
+
const r = v;
|
|
9740
|
+
const out = {};
|
|
9741
|
+
const bucket = sanitizeOptionalString(r.bucket, MAX_S3_BUCKET_LEN);
|
|
9742
|
+
if (bucket !== undefined)
|
|
9743
|
+
out.bucket = bucket;
|
|
9744
|
+
const prefix = sanitizeOptionalString(r.prefix, MAX_S3_KEY_LEN);
|
|
9745
|
+
if (prefix !== undefined)
|
|
9746
|
+
out.prefix = prefix;
|
|
9747
|
+
const query = sanitizeOptionalString(r.query, MAX_S3_QUERY_LEN);
|
|
9748
|
+
if (query !== undefined)
|
|
9749
|
+
out.query = query;
|
|
9750
|
+
if (r.mode === "prefix" || r.mode === "contains")
|
|
9751
|
+
out.mode = r.mode;
|
|
9752
|
+
if (r.sort === "key-asc" || r.sort === "updated-desc")
|
|
9753
|
+
out.sort = r.sort;
|
|
9754
|
+
const key = sanitizeOptionalString(r.key, MAX_S3_KEY_LEN);
|
|
9755
|
+
if (key !== undefined)
|
|
9756
|
+
out.key = key;
|
|
9757
|
+
if (out.bucket === undefined && out.prefix === undefined && out.query === undefined && out.mode === undefined && out.sort === undefined && out.key === undefined)
|
|
9758
|
+
return;
|
|
9759
|
+
return out;
|
|
9760
|
+
}
|
|
9247
9761
|
function sanitize(input) {
|
|
9248
9762
|
if (!input || typeof input !== "object")
|
|
9249
9763
|
return emptyState2();
|
|
@@ -9265,12 +9779,15 @@ function sanitize(input) {
|
|
|
9265
9779
|
if (seenIds.has(id))
|
|
9266
9780
|
continue;
|
|
9267
9781
|
seenIds.add(id);
|
|
9268
|
-
const dbId = sanitizeOptionalString(tab.dbId,
|
|
9782
|
+
const dbId = sanitizeOptionalString(tab.dbId, MAX_DB_ID_LEN2) ?? null;
|
|
9269
9783
|
if (isToolInternalDbId(dbId))
|
|
9270
9784
|
continue;
|
|
9785
|
+
const schema = sanitizeOptionalString(tab.schema, MAX_SCHEMA_NAME_LEN);
|
|
9271
9786
|
const table = sanitizeOptionalString(tab.table, MAX_TABLE_NAME_LEN) ?? null;
|
|
9272
9787
|
const view = typeof tab.view === "string" && VALID_VIEWS.has(tab.view) ? tab.view : "data";
|
|
9273
9788
|
const out = { id, dbId, table, view };
|
|
9789
|
+
if (schema !== undefined)
|
|
9790
|
+
out.schema = schema;
|
|
9274
9791
|
const sqlDraft = sanitizeOptionalString(tab.sqlDraft, MAX_SQL_DRAFT_LEN);
|
|
9275
9792
|
if (sqlDraft !== undefined)
|
|
9276
9793
|
out.sqlDraft = sqlDraft;
|
|
@@ -9288,6 +9805,9 @@ function sanitize(input) {
|
|
|
9288
9805
|
const es = sanitizeEs(tab.es);
|
|
9289
9806
|
if (es !== undefined)
|
|
9290
9807
|
out.es = es;
|
|
9808
|
+
const s3 = sanitizeS3(tab.s3);
|
|
9809
|
+
if (s3 !== undefined)
|
|
9810
|
+
out.s3 = s3;
|
|
9291
9811
|
tabs.push(out);
|
|
9292
9812
|
}
|
|
9293
9813
|
let activeTabId = sanitizeOptionalString(obj.activeTabId, MAX_TAB_ID_LEN) ?? null;
|
|
@@ -9297,69 +9817,14 @@ function sanitize(input) {
|
|
|
9297
9817
|
return { version: 1, tabs, activeTabId };
|
|
9298
9818
|
}
|
|
9299
9819
|
async function loadTabsAsync(cwd) {
|
|
9300
|
-
|
|
9301
|
-
if (pendingWrite) {
|
|
9302
|
-
await pendingWrite.catch(() => {});
|
|
9303
|
-
}
|
|
9304
|
-
const file = tabsFilePath(cwd);
|
|
9305
|
-
let raw;
|
|
9306
|
-
try {
|
|
9307
|
-
raw = await readFile3(file, "utf8");
|
|
9308
|
-
} catch (err) {
|
|
9309
|
-
if (isEnoent2(err))
|
|
9310
|
-
return emptyState2();
|
|
9311
|
-
await backupInvalidTabsFileAsync(file);
|
|
9312
|
-
return emptyState2();
|
|
9313
|
-
}
|
|
9314
|
-
try {
|
|
9315
|
-
const parsed = JSON.parse(raw);
|
|
9316
|
-
if (!parsed || typeof parsed !== "object" || parsed.version !== 1) {
|
|
9317
|
-
await backupInvalidTabsFileAsync(file);
|
|
9318
|
-
return emptyState2();
|
|
9319
|
-
}
|
|
9320
|
-
return sanitize(parsed);
|
|
9321
|
-
} catch (err) {
|
|
9322
|
-
if (isEnoent2(err))
|
|
9323
|
-
return emptyState2();
|
|
9324
|
-
await backupInvalidTabsFileAsync(file);
|
|
9325
|
-
return emptyState2();
|
|
9326
|
-
}
|
|
9327
|
-
}
|
|
9328
|
-
async function backupInvalidTabsFileAsync(file) {
|
|
9329
|
-
try {
|
|
9330
|
-
await rename2(file, `${file}.bak-${Date.now()}`);
|
|
9331
|
-
} catch {}
|
|
9332
|
-
}
|
|
9333
|
-
async function saveTabsAsyncUnqueued(cwd, state) {
|
|
9334
|
-
const normalized = sanitize(state);
|
|
9335
|
-
const dir = join11(cwd, CODE_VIEWER_DIR4);
|
|
9336
|
-
await mkdir2(dir, { recursive: true });
|
|
9337
|
-
const file = tabsFilePath(cwd);
|
|
9338
|
-
const tmp = `${file}.${makeId(`tmp-${process.pid}`)}`;
|
|
9339
|
-
const content = `${JSON.stringify(normalized, null, 2)}
|
|
9340
|
-
`;
|
|
9341
|
-
if (Buffer.byteLength(content, "utf8") > MAX_JSON_BYTES2) {
|
|
9342
|
-
throw new Error("tabs state too large");
|
|
9343
|
-
}
|
|
9344
|
-
await writeFile2(tmp, content, "utf8");
|
|
9345
|
-
await rename2(tmp, file);
|
|
9820
|
+
return tabsStore.load(cwd);
|
|
9346
9821
|
}
|
|
9347
9822
|
async function saveTabsAsync(cwd, state) {
|
|
9348
|
-
|
|
9349
|
-
const run2 = previous.catch(() => {}).then(() => saveTabsAsyncUnqueued(cwd, state));
|
|
9350
|
-
const queued = run2.then(() => {}, () => {});
|
|
9351
|
-
tabsWriteQueues.set(cwd, queued);
|
|
9352
|
-
try {
|
|
9353
|
-
await run2;
|
|
9354
|
-
} finally {
|
|
9355
|
-
if (tabsWriteQueues.get(cwd) === queued) {
|
|
9356
|
-
tabsWriteQueues.delete(cwd);
|
|
9357
|
-
}
|
|
9358
|
-
}
|
|
9823
|
+
return tabsStore.save(cwd, state);
|
|
9359
9824
|
}
|
|
9360
|
-
var
|
|
9825
|
+
var CODE_VIEWER_DIR5 = ".code-viewer", TABS_FILE_NAME = "tabs.json", MAX_TABS = 64, MAX_JSON_BYTES2 = 1e6, MAX_SQL_DRAFT_LEN = 16000, MAX_ES_QUERY_LEN = 16000, MAX_TAB_ID_LEN = 128, MAX_DB_ID_LEN2 = 2048, MAX_SCHEMA_NAME_LEN = 512, MAX_TABLE_NAME_LEN = 512, MAX_REDIS_KEY_LEN = 1024, MAX_REDIS_KEY_FILTER_LEN = 512, MAX_INDEX_NAME_LEN = 256, MAX_S3_BUCKET_LEN = 256, MAX_S3_KEY_LEN = 2048, MAX_S3_QUERY_LEN = 2048, MAX_CSS_SIZE_LEN = 16, VALID_VIEWS, tabsStore;
|
|
9361
9826
|
var init_tabs_store = __esm(() => {
|
|
9362
|
-
|
|
9827
|
+
init_json_store();
|
|
9363
9828
|
VALID_VIEWS = new Set([
|
|
9364
9829
|
"data",
|
|
9365
9830
|
"query",
|
|
@@ -9368,6 +9833,14 @@ var init_tabs_store = __esm(() => {
|
|
|
9368
9833
|
"search",
|
|
9369
9834
|
"snapshot"
|
|
9370
9835
|
]);
|
|
9836
|
+
tabsStore = createJsonFileStore({
|
|
9837
|
+
filePath: tabsFilePath,
|
|
9838
|
+
empty: emptyState2,
|
|
9839
|
+
sanitize,
|
|
9840
|
+
maxBytes: MAX_JSON_BYTES2,
|
|
9841
|
+
backupSuffix: "bak",
|
|
9842
|
+
sizeErrorMessage: "tabs state too large"
|
|
9843
|
+
});
|
|
9371
9844
|
});
|
|
9372
9845
|
|
|
9373
9846
|
// web-src/server/database/handle.ts
|
|
@@ -9396,7 +9869,7 @@ function sanitizeFilename(name) {
|
|
|
9396
9869
|
function normalizeSchemaParam(value) {
|
|
9397
9870
|
if (value === undefined || value === null || value === "")
|
|
9398
9871
|
return;
|
|
9399
|
-
if (value.length >
|
|
9872
|
+
if (value.length > MAX_SCHEMA_NAME_LEN2) {
|
|
9400
9873
|
return textError("invalid schema parameter", 400);
|
|
9401
9874
|
}
|
|
9402
9875
|
if (hasControlCharacter(value)) {
|
|
@@ -10355,6 +10828,23 @@ async function handleTabsPut(cwd, req) {
|
|
|
10355
10828
|
return textError(`failed to save tabs: ${message}`, 500);
|
|
10356
10829
|
}
|
|
10357
10830
|
}
|
|
10831
|
+
async function handleDbUiGet(cwd) {
|
|
10832
|
+
return jsonLoadResponse(() => loadDbUiState(cwd), "db UI", "failed to load db UI state");
|
|
10833
|
+
}
|
|
10834
|
+
async function handleDbUiPatch(cwd, req) {
|
|
10835
|
+
const body = await parseBoundedJsonBody(req, MAX_DB_UI_BODY_BYTES, "db UI body too large");
|
|
10836
|
+
if (body instanceof Response)
|
|
10837
|
+
return body;
|
|
10838
|
+
try {
|
|
10839
|
+
return json(await patchDbUiState(cwd, body));
|
|
10840
|
+
} catch (err) {
|
|
10841
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
10842
|
+
if (message === "db UI state too large")
|
|
10843
|
+
return textError(message, 413);
|
|
10844
|
+
console.error("[code-viewer] db UI error:", err);
|
|
10845
|
+
return textError("failed to save db UI state", 500);
|
|
10846
|
+
}
|
|
10847
|
+
}
|
|
10358
10848
|
async function handleClose(cwd, req, omitDirNames) {
|
|
10359
10849
|
const body = await parsePostJsonBody(req);
|
|
10360
10850
|
if (body instanceof Response)
|
|
@@ -10517,11 +11007,17 @@ async function handleDatabaseRoute(req, url, cwd, omitDirNames, sideEffectAllowe
|
|
|
10517
11007
|
methods: ["GET", "PUT", "POST"],
|
|
10518
11008
|
sideEffect: (m) => m !== "GET",
|
|
10519
11009
|
handler: () => method === "GET" ? handleTabsGet(cwd) : handleTabsPut(cwd, req)
|
|
11010
|
+
},
|
|
11011
|
+
"/_db/ui": {
|
|
11012
|
+
methods: ["GET", "PATCH"],
|
|
11013
|
+
sideEffect: (m) => m !== "GET",
|
|
11014
|
+
handler: () => method === "GET" ? handleDbUiGet(cwd) : handleDbUiPatch(cwd, req)
|
|
10520
11015
|
}
|
|
10521
11016
|
}, sideEffectAllowed, wrapResponse, (err) => handleError("database", "handle database request", err));
|
|
10522
11017
|
}
|
|
10523
|
-
var initialized = false, dockerAdapterCache,
|
|
11018
|
+
var initialized = false, dockerAdapterCache, MAX_SCHEMA_NAME_LEN2 = 1024, EXPORT_MAX_ROWS = 1e5, MAX_TABS_BODY_BYTES = 1e6, MAX_DB_UI_BODY_BYTES = 1e6, MAX_SNAPSHOT_TABLES = 512, MAX_SNAPSHOT_TABLE_NAME_LEN = 1024, searchJobs, snapshotJobs, DOCKER_CLOSE_REGISTRY, SNAPSHOT_DOCKER_SOURCE_REGISTRY;
|
|
10524
11019
|
var init_handle = __esm(() => {
|
|
11020
|
+
init_state_store();
|
|
10525
11021
|
init_docker();
|
|
10526
11022
|
init_docker_utils();
|
|
10527
11023
|
init_sqlite();
|
|
@@ -10575,25 +11071,87 @@ var init_handle = __esm(() => {
|
|
|
10575
11071
|
};
|
|
10576
11072
|
});
|
|
10577
11073
|
|
|
11074
|
+
// web-src/server/state-route.ts
|
|
11075
|
+
var exports_state_route = {};
|
|
11076
|
+
__export(exports_state_route, {
|
|
11077
|
+
handleStateRoute: () => handleStateRoute
|
|
11078
|
+
});
|
|
11079
|
+
async function parseJsonBody(req) {
|
|
11080
|
+
return parseBoundedJsonBody(req, MAX_STATE_PATCH_BODY_BYTES, "state body too large");
|
|
11081
|
+
}
|
|
11082
|
+
async function handleSettingsGet(cwd) {
|
|
11083
|
+
return jsonLoadResponse(() => loadAppSettingsState(cwd), "state", "failed to load settings state");
|
|
11084
|
+
}
|
|
11085
|
+
async function handleSettingsPatch(cwd, req) {
|
|
11086
|
+
const body = await parseJsonBody(req);
|
|
11087
|
+
if (body instanceof Response)
|
|
11088
|
+
return body;
|
|
11089
|
+
try {
|
|
11090
|
+
return json(await patchAppSettingsState(cwd, body));
|
|
11091
|
+
} catch (err) {
|
|
11092
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11093
|
+
if (message === "settings state too large")
|
|
11094
|
+
return textError(message, 413);
|
|
11095
|
+
console.error("[code-viewer] state error:", err);
|
|
11096
|
+
return textError("failed to save settings state", 500);
|
|
11097
|
+
}
|
|
11098
|
+
}
|
|
11099
|
+
async function handleViewGet(cwd) {
|
|
11100
|
+
return jsonLoadResponse(() => loadViewState(cwd), "state", "failed to load view state");
|
|
11101
|
+
}
|
|
11102
|
+
async function handleViewPatch(cwd, req) {
|
|
11103
|
+
const body = await parseJsonBody(req);
|
|
11104
|
+
if (body instanceof Response)
|
|
11105
|
+
return body;
|
|
11106
|
+
try {
|
|
11107
|
+
return json(await patchViewState(cwd, body));
|
|
11108
|
+
} catch (err) {
|
|
11109
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11110
|
+
if (message === "view state too large")
|
|
11111
|
+
return textError(message, 413);
|
|
11112
|
+
console.error("[code-viewer] state error:", err);
|
|
11113
|
+
return textError("failed to save view state", 500);
|
|
11114
|
+
}
|
|
11115
|
+
}
|
|
11116
|
+
async function handleStateRoute(req, url, cwd, sideEffectAllowed) {
|
|
11117
|
+
return dispatchRoutes(req, url, {
|
|
11118
|
+
"/_state/settings": {
|
|
11119
|
+
methods: ["GET", "PATCH"],
|
|
11120
|
+
sideEffect: (method) => method !== "GET",
|
|
11121
|
+
handler: () => req.method === "GET" ? handleSettingsGet(cwd) : handleSettingsPatch(cwd, req)
|
|
11122
|
+
},
|
|
11123
|
+
"/_state/view": {
|
|
11124
|
+
methods: ["GET", "PATCH"],
|
|
11125
|
+
sideEffect: (method) => method !== "GET",
|
|
11126
|
+
handler: () => req.method === "GET" ? handleViewGet(cwd) : handleViewPatch(cwd, req)
|
|
11127
|
+
}
|
|
11128
|
+
}, sideEffectAllowed, (res) => res, (err) => handleError("state", "handle state request", err));
|
|
11129
|
+
}
|
|
11130
|
+
var MAX_STATE_PATCH_BODY_BYTES = 1e6;
|
|
11131
|
+
var init_state_route = __esm(() => {
|
|
11132
|
+
init_handle_shared();
|
|
11133
|
+
init_state_store();
|
|
11134
|
+
});
|
|
11135
|
+
|
|
10578
11136
|
// web-src/server/preview.ts
|
|
10579
11137
|
var exports_preview = {};
|
|
10580
11138
|
import {
|
|
10581
11139
|
closeSync as closeSync2,
|
|
10582
11140
|
constants,
|
|
10583
|
-
existsSync as
|
|
11141
|
+
existsSync as existsSync6,
|
|
10584
11142
|
lstatSync as lstatSync4,
|
|
10585
|
-
mkdirSync as
|
|
11143
|
+
mkdirSync as mkdirSync4,
|
|
10586
11144
|
openSync as openSync2,
|
|
10587
|
-
readFileSync as
|
|
11145
|
+
readFileSync as readFileSync4,
|
|
10588
11146
|
realpathSync as realpathSync4,
|
|
10589
|
-
renameSync
|
|
11147
|
+
renameSync,
|
|
10590
11148
|
statSync as statSync3,
|
|
10591
11149
|
unlinkSync as unlinkSync2,
|
|
10592
11150
|
watch,
|
|
10593
|
-
writeFileSync as
|
|
11151
|
+
writeFileSync as writeFileSync2
|
|
10594
11152
|
} from "node:fs";
|
|
10595
11153
|
import { homedir as homedir3 } from "node:os";
|
|
10596
|
-
import { basename as basename3, dirname as
|
|
11154
|
+
import { basename as basename3, dirname as dirname3, extname as extname2, join as join13, relative as relative3 } from "node:path";
|
|
10597
11155
|
function parseCli() {
|
|
10598
11156
|
const rest = [];
|
|
10599
11157
|
for (let i = 2;i < process.argv.length; i++) {
|
|
@@ -10734,10 +11292,10 @@ function staticFile(pathname) {
|
|
|
10734
11292
|
const spec = map[pathname];
|
|
10735
11293
|
if (!spec)
|
|
10736
11294
|
return null;
|
|
10737
|
-
const full =
|
|
10738
|
-
if (!
|
|
11295
|
+
const full = join13(WEB_ROOT, spec[0]);
|
|
11296
|
+
if (!existsSync6(full))
|
|
10739
11297
|
return text("not found", 404);
|
|
10740
|
-
return new Response(
|
|
11298
|
+
return new Response(readFileSync4(full), {
|
|
10741
11299
|
headers: { "Content-Type": spec[1], "Cache-Control": "no-store" }
|
|
10742
11300
|
});
|
|
10743
11301
|
}
|
|
@@ -10968,8 +11526,8 @@ function parseScopeExcludeNamesQuery(value) {
|
|
|
10968
11526
|
return normalizeScopeExcludeNames(names);
|
|
10969
11527
|
}
|
|
10970
11528
|
function loadProjectConfig() {
|
|
10971
|
-
const full =
|
|
10972
|
-
if (!
|
|
11529
|
+
const full = join13(cwd, ".code-viewer.json");
|
|
11530
|
+
if (!existsSync6(full))
|
|
10973
11531
|
return null;
|
|
10974
11532
|
let realCwd;
|
|
10975
11533
|
let realConfig;
|
|
@@ -10979,10 +11537,10 @@ function loadProjectConfig() {
|
|
|
10979
11537
|
} catch {
|
|
10980
11538
|
return null;
|
|
10981
11539
|
}
|
|
10982
|
-
if (
|
|
11540
|
+
if (dirname3(realConfig) !== realCwd || basename3(realConfig) !== ".code-viewer.json")
|
|
10983
11541
|
return null;
|
|
10984
11542
|
try {
|
|
10985
|
-
const parsed = JSON.parse(
|
|
11543
|
+
const parsed = JSON.parse(readFileSync4(realConfig, "utf8"));
|
|
10986
11544
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed) && "version" in parsed && parsed.version !== 1)
|
|
10987
11545
|
return null;
|
|
10988
11546
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
@@ -11033,8 +11591,8 @@ function safeWorktreePath(path) {
|
|
|
11033
11591
|
return null;
|
|
11034
11592
|
if (isGitInternalPath(path))
|
|
11035
11593
|
return null;
|
|
11036
|
-
const full =
|
|
11037
|
-
if (!
|
|
11594
|
+
const full = join13(cwd, path);
|
|
11595
|
+
if (!existsSync6(full))
|
|
11038
11596
|
return null;
|
|
11039
11597
|
let realCwd;
|
|
11040
11598
|
let realFull;
|
|
@@ -11052,7 +11610,7 @@ function safeWorktreePath(path) {
|
|
|
11052
11610
|
return realFull;
|
|
11053
11611
|
}
|
|
11054
11612
|
function worktreePath(path) {
|
|
11055
|
-
return
|
|
11613
|
+
return join13(cwd, path);
|
|
11056
11614
|
}
|
|
11057
11615
|
function safeOpenWorktreePath(path) {
|
|
11058
11616
|
if (path === "") {
|
|
@@ -11068,7 +11626,7 @@ function safeOpenWorktreePath(path) {
|
|
|
11068
11626
|
return safeWorktreePath(path);
|
|
11069
11627
|
}
|
|
11070
11628
|
function parentRepoPath(path) {
|
|
11071
|
-
const parent =
|
|
11629
|
+
const parent = dirname3(path);
|
|
11072
11630
|
return parent === "." ? "" : parent;
|
|
11073
11631
|
}
|
|
11074
11632
|
function isoDate(ms) {
|
|
@@ -11135,7 +11693,7 @@ function readReadme(target, dirPath) {
|
|
|
11135
11693
|
if (!full)
|
|
11136
11694
|
continue;
|
|
11137
11695
|
try {
|
|
11138
|
-
return { path, text:
|
|
11696
|
+
return { path, text: readFileSync4(full, "utf8") };
|
|
11139
11697
|
} catch {
|
|
11140
11698
|
continue;
|
|
11141
11699
|
}
|
|
@@ -11256,7 +11814,7 @@ function grepWorktreeFallback(query, max, paths, omitDirNames, excludeNames) {
|
|
|
11256
11814
|
continue;
|
|
11257
11815
|
let data;
|
|
11258
11816
|
try {
|
|
11259
|
-
data =
|
|
11817
|
+
data = readFileSync4(full);
|
|
11260
11818
|
} catch {
|
|
11261
11819
|
continue;
|
|
11262
11820
|
}
|
|
@@ -11792,10 +12350,10 @@ async function handleUploadFiles(req) {
|
|
|
11792
12350
|
total += file.size;
|
|
11793
12351
|
if (total > MAX_UPLOAD_TOTAL_BYTES)
|
|
11794
12352
|
return text("upload too large", 413);
|
|
11795
|
-
const target =
|
|
11796
|
-
if (relative3(realDir,
|
|
12353
|
+
const target = join13(realDir, safeName);
|
|
12354
|
+
if (relative3(realDir, dirname3(target)) !== "")
|
|
11797
12355
|
return text("invalid filename", 400);
|
|
11798
|
-
if (
|
|
12356
|
+
if (existsSync6(target))
|
|
11799
12357
|
return text("file exists", 409);
|
|
11800
12358
|
uploads.push({ file, name: safeName, target });
|
|
11801
12359
|
}
|
|
@@ -11804,7 +12362,7 @@ async function handleUploadFiles(req) {
|
|
|
11804
12362
|
for (const upload of uploads) {
|
|
11805
12363
|
const fd = openSync2(upload.target, uploadOpenFlags(), 420);
|
|
11806
12364
|
try {
|
|
11807
|
-
|
|
12365
|
+
writeFileSync2(fd, new Uint8Array(await upload.file.arrayBuffer()));
|
|
11808
12366
|
} finally {
|
|
11809
12367
|
closeSync2(fd);
|
|
11810
12368
|
}
|
|
@@ -11914,12 +12472,12 @@ function triggerUpdate(changedPaths) {
|
|
|
11914
12472
|
sendSse("update", data);
|
|
11915
12473
|
}
|
|
11916
12474
|
function moveMacPathIntoTrash(path) {
|
|
11917
|
-
const trashDir =
|
|
12475
|
+
const trashDir = join13(homedir3(), ".Trash");
|
|
11918
12476
|
const base = basename3(path) || "code-viewer-trash-item";
|
|
11919
|
-
const target =
|
|
12477
|
+
const target = join13(trashDir, `${base}-${Date.now()}-${process.pid}-${Math.random().toString(36).slice(2, 8)}`);
|
|
11920
12478
|
try {
|
|
11921
|
-
|
|
11922
|
-
|
|
12479
|
+
mkdirSync4(trashDir, { recursive: true });
|
|
12480
|
+
renameSync(path, target);
|
|
11923
12481
|
return { ok: true, trashPath: target };
|
|
11924
12482
|
} catch (error) {
|
|
11925
12483
|
return { ok: false, error: String(error) };
|
|
@@ -11950,20 +12508,20 @@ function restoreTrashPath(originalPath, trashPath) {
|
|
|
11950
12508
|
if (!parentFullPath)
|
|
11951
12509
|
return { ok: false, error: "invalid restore target" };
|
|
11952
12510
|
const original = worktreePath(originalPath);
|
|
11953
|
-
if (
|
|
12511
|
+
if (existsSync6(original))
|
|
11954
12512
|
return { ok: false, error: "restore target exists" };
|
|
11955
12513
|
if (trashPath) {
|
|
11956
12514
|
if (process.platform !== "darwin")
|
|
11957
12515
|
return { ok: false, error: "invalid trash handle" };
|
|
11958
|
-
if (!
|
|
12516
|
+
if (!existsSync6(trashPath))
|
|
11959
12517
|
return { ok: false, error: "trash item not found" };
|
|
11960
12518
|
try {
|
|
11961
|
-
const trashRoot =
|
|
12519
|
+
const trashRoot = join13(homedir3(), ".Trash");
|
|
11962
12520
|
const trashRelative = relative3(trashRoot, trashPath);
|
|
11963
12521
|
if (trashRelative === "" || trashRelative.startsWith("..") || trashRelative.startsWith("/") || trashRelative.startsWith("\\"))
|
|
11964
12522
|
return { ok: false, error: "invalid trash handle" };
|
|
11965
|
-
|
|
11966
|
-
|
|
12523
|
+
mkdirSync4(dirname3(original), { recursive: true });
|
|
12524
|
+
renameSync(trashPath, original);
|
|
11967
12525
|
return { ok: true };
|
|
11968
12526
|
} catch (error) {
|
|
11969
12527
|
return { ok: false, error: String(error) };
|
|
@@ -12108,11 +12666,11 @@ async function handleCreateDirectory(req) {
|
|
|
12108
12666
|
const targetPath = dir ? `${dir}/${name}` : name;
|
|
12109
12667
|
if (!safeRepoPath(targetPath) || isGitInternalPath(targetPath))
|
|
12110
12668
|
return text("invalid target", 400);
|
|
12111
|
-
const target =
|
|
12112
|
-
if (
|
|
12669
|
+
const target = join13(parent, name);
|
|
12670
|
+
if (existsSync6(target))
|
|
12113
12671
|
return text("already exists", 409);
|
|
12114
12672
|
try {
|
|
12115
|
-
|
|
12673
|
+
mkdirSync4(target, { recursive: false });
|
|
12116
12674
|
} catch (error) {
|
|
12117
12675
|
if (error.code === "EEXIST")
|
|
12118
12676
|
return text("already exists", 409);
|
|
@@ -12158,7 +12716,7 @@ function annotationSse(kind, sessionId, entryId) {
|
|
|
12158
12716
|
}
|
|
12159
12717
|
async function handleAnnotations(req) {
|
|
12160
12718
|
if (req.method === "GET")
|
|
12161
|
-
return json2(loadAnnotationsState(cwd));
|
|
12719
|
+
return json2(await loadAnnotationsState(cwd));
|
|
12162
12720
|
if (req.method !== "POST")
|
|
12163
12721
|
return text("method not allowed", 405);
|
|
12164
12722
|
if (!sideEffectRequestAllowed(req))
|
|
@@ -12182,8 +12740,8 @@ async function handleAnnotations(req) {
|
|
|
12182
12740
|
const action = body.action;
|
|
12183
12741
|
if (action === "start") {
|
|
12184
12742
|
const title = typeof body.title === "string" ? body.title : "";
|
|
12185
|
-
const started = startAnnotationSession(loadAnnotationsState(cwd), title, new Date().toISOString());
|
|
12186
|
-
saveAnnotationsState(cwd, started.state);
|
|
12743
|
+
const started = startAnnotationSession(await loadAnnotationsState(cwd), title, new Date().toISOString());
|
|
12744
|
+
await saveAnnotationsState(cwd, started.state);
|
|
12187
12745
|
annotationSse("start", started.session.id);
|
|
12188
12746
|
return json2({ ok: true, session: started.session });
|
|
12189
12747
|
}
|
|
@@ -12201,7 +12759,7 @@ async function handleAnnotations(req) {
|
|
|
12201
12759
|
if (isGitInternalPath(path) || isCodeViewerInternalPath(path))
|
|
12202
12760
|
return text("forbidden", 403);
|
|
12203
12761
|
}
|
|
12204
|
-
const result = addAnnotationEntry(loadAnnotationsState(cwd), {
|
|
12762
|
+
const result = addAnnotationEntry(await loadAnnotationsState(cwd), {
|
|
12205
12763
|
session_id: typeof body.session_id === "string" ? body.session_id : undefined,
|
|
12206
12764
|
session_title: typeof body.session_title === "string" ? body.session_title : undefined,
|
|
12207
12765
|
path,
|
|
@@ -12216,7 +12774,7 @@ async function handleAnnotations(req) {
|
|
|
12216
12774
|
}, new Date().toISOString());
|
|
12217
12775
|
if (result.ok === false)
|
|
12218
12776
|
return text(result.error, 400);
|
|
12219
|
-
saveAnnotationsState(cwd, result.state);
|
|
12777
|
+
await saveAnnotationsState(cwd, result.state);
|
|
12220
12778
|
annotationSse("add", result.session.id, result.entry.id);
|
|
12221
12779
|
return json2({
|
|
12222
12780
|
ok: true,
|
|
@@ -12230,14 +12788,14 @@ async function handleAnnotations(req) {
|
|
|
12230
12788
|
const id = typeof body.id === "string" ? body.id : "";
|
|
12231
12789
|
if (!id)
|
|
12232
12790
|
return text("invalid id", 400);
|
|
12233
|
-
const result = moveAnnotationEntry(loadAnnotationsState(cwd), id, {
|
|
12791
|
+
const result = moveAnnotationEntry(await loadAnnotationsState(cwd), id, {
|
|
12234
12792
|
before_id: typeof body.before_id === "string" ? body.before_id : undefined,
|
|
12235
12793
|
after_id: typeof body.after_id === "string" ? body.after_id : undefined,
|
|
12236
12794
|
position: typeof body.position === "number" ? body.position : undefined
|
|
12237
12795
|
});
|
|
12238
12796
|
if (result.ok === false)
|
|
12239
12797
|
return text(result.error, 400);
|
|
12240
|
-
saveAnnotationsState(cwd, result.state);
|
|
12798
|
+
await saveAnnotationsState(cwd, result.state);
|
|
12241
12799
|
annotationSse("update", result.session.id, result.entry.id);
|
|
12242
12800
|
return json2({
|
|
12243
12801
|
ok: true,
|
|
@@ -12249,9 +12807,9 @@ async function handleAnnotations(req) {
|
|
|
12249
12807
|
const id = typeof body.id === "string" ? body.id : "";
|
|
12250
12808
|
if (!id)
|
|
12251
12809
|
return text("invalid id", 400);
|
|
12252
|
-
const result = deleteAnnotationById(loadAnnotationsState(cwd), id);
|
|
12810
|
+
const result = deleteAnnotationById(await loadAnnotationsState(cwd), id);
|
|
12253
12811
|
if (result.removed) {
|
|
12254
|
-
saveAnnotationsState(cwd, result.state);
|
|
12812
|
+
await saveAnnotationsState(cwd, result.state);
|
|
12255
12813
|
annotationSse("delete");
|
|
12256
12814
|
}
|
|
12257
12815
|
return json2({ ok: true, removed: result.removed });
|
|
@@ -12261,10 +12819,10 @@ async function handleAnnotations(req) {
|
|
|
12261
12819
|
const title = typeof body.title === "string" ? body.title : "";
|
|
12262
12820
|
if (!id)
|
|
12263
12821
|
return text("invalid id", 400);
|
|
12264
|
-
const result = renameAnnotationSession(loadAnnotationsState(cwd), id, title);
|
|
12822
|
+
const result = renameAnnotationSession(await loadAnnotationsState(cwd), id, title);
|
|
12265
12823
|
if (!result.renamed)
|
|
12266
12824
|
return text("session not found", 404);
|
|
12267
|
-
saveAnnotationsState(cwd, result.state);
|
|
12825
|
+
await saveAnnotationsState(cwd, result.state);
|
|
12268
12826
|
annotationSse("update", id);
|
|
12269
12827
|
return json2({ ok: true });
|
|
12270
12828
|
}
|
|
@@ -12272,18 +12830,18 @@ async function handleAnnotations(req) {
|
|
|
12272
12830
|
const id = typeof body.id === "string" ? body.id : "";
|
|
12273
12831
|
if (!id)
|
|
12274
12832
|
return text("invalid id", 400);
|
|
12275
|
-
const result = updateAnnotationEntry(loadAnnotationsState(cwd), id, {
|
|
12833
|
+
const result = updateAnnotationEntry(await loadAnnotationsState(cwd), id, {
|
|
12276
12834
|
title: typeof body.title === "string" ? body.title : undefined,
|
|
12277
12835
|
body: typeof body.body === "string" ? body.body : undefined
|
|
12278
12836
|
});
|
|
12279
12837
|
if (result.ok === false)
|
|
12280
12838
|
return text(result.error, 400);
|
|
12281
|
-
saveAnnotationsState(cwd, result.state);
|
|
12839
|
+
await saveAnnotationsState(cwd, result.state);
|
|
12282
12840
|
annotationSse("update", undefined, id);
|
|
12283
12841
|
return json2({ ok: true, entry: result.entry });
|
|
12284
12842
|
}
|
|
12285
12843
|
if (action === "clear") {
|
|
12286
|
-
saveAnnotationsState(cwd, emptyAnnotationsState());
|
|
12844
|
+
await saveAnnotationsState(cwd, emptyAnnotationsState());
|
|
12287
12845
|
annotationSse("clear");
|
|
12288
12846
|
return json2({ ok: true });
|
|
12289
12847
|
}
|
|
@@ -12352,8 +12910,8 @@ var init_preview = __esm(async () => {
|
|
|
12352
12910
|
init_search();
|
|
12353
12911
|
init_server_registry();
|
|
12354
12912
|
init_worktree_watcher();
|
|
12355
|
-
WEB_ROOT =
|
|
12356
|
-
VERSION = JSON.parse(
|
|
12913
|
+
WEB_ROOT = join13(ROOT, "web");
|
|
12914
|
+
VERSION = JSON.parse(readFileSync4(join13(ROOT, "package.json"), "utf8")).version;
|
|
12357
12915
|
DEFAULT_ARGS = ["HEAD"];
|
|
12358
12916
|
WATCHED_ASSET_FILES = ["index.html", "style.css", "app.js"];
|
|
12359
12917
|
LINE_INDEX_MAX_FILE_BYTES = 256 * 1024 * 1024;
|
|
@@ -12457,6 +13015,12 @@ var init_preview = __esm(async () => {
|
|
|
12457
13015
|
if (dbResponse)
|
|
12458
13016
|
return dbResponse;
|
|
12459
13017
|
}
|
|
13018
|
+
if (url.pathname.startsWith("/_state/")) {
|
|
13019
|
+
const { handleStateRoute: handleStateRoute2 } = await Promise.resolve().then(() => (init_state_route(), exports_state_route));
|
|
13020
|
+
const stateResponse = await handleStateRoute2(req, url, cwd, sideEffectRequestAllowed);
|
|
13021
|
+
if (stateResponse)
|
|
13022
|
+
return stateResponse;
|
|
13023
|
+
}
|
|
12460
13024
|
if (url.pathname === "/_annotations")
|
|
12461
13025
|
return handleAnnotations(req);
|
|
12462
13026
|
if (url.pathname === "/_refs")
|