@very_aq/codex-cli-web 0.0.1
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/LICENSE +21 -0
- package/README.md +228 -0
- package/README.zh-CN.md +228 -0
- package/package.json +38 -0
- package/server/dist/admin/userAdminRoutes.d.ts +7 -0
- package/server/dist/admin/userAdminRoutes.js +91 -0
- package/server/dist/admin/userAdminRoutes.js.map +1 -0
- package/server/dist/app.d.ts +22 -0
- package/server/dist/app.js +993 -0
- package/server/dist/app.js.map +1 -0
- package/server/dist/auth/adminInit.d.ts +41 -0
- package/server/dist/auth/adminInit.js +126 -0
- package/server/dist/auth/adminInit.js.map +1 -0
- package/server/dist/auth/bootstrapAdmin.d.ts +6 -0
- package/server/dist/auth/bootstrapAdmin.js +11 -0
- package/server/dist/auth/bootstrapAdmin.js.map +1 -0
- package/server/dist/auth/httpAuth.d.ts +16 -0
- package/server/dist/auth/httpAuth.js +31 -0
- package/server/dist/auth/httpAuth.js.map +1 -0
- package/server/dist/auth/password.d.ts +2 -0
- package/server/dist/auth/password.js +68 -0
- package/server/dist/auth/password.js.map +1 -0
- package/server/dist/auth/requireAdmin.d.ts +2 -0
- package/server/dist/auth/requireAdmin.js +14 -0
- package/server/dist/auth/requireAdmin.js.map +1 -0
- package/server/dist/auth/roles.d.ts +3 -0
- package/server/dist/auth/roles.js +13 -0
- package/server/dist/auth/roles.js.map +1 -0
- package/server/dist/auth/session.d.ts +24 -0
- package/server/dist/auth/session.js +127 -0
- package/server/dist/auth/session.js.map +1 -0
- package/server/dist/auth/sqlite/authDb.d.ts +18 -0
- package/server/dist/auth/sqlite/authDb.js +26 -0
- package/server/dist/auth/sqlite/authDb.js.map +1 -0
- package/server/dist/auth/sqlite/legacyImport.d.ts +22 -0
- package/server/dist/auth/sqlite/legacyImport.js +208 -0
- package/server/dist/auth/sqlite/legacyImport.js.map +1 -0
- package/server/dist/auth/sqlite/schema.d.ts +11 -0
- package/server/dist/auth/sqlite/schema.js +47 -0
- package/server/dist/auth/sqlite/schema.js.map +1 -0
- package/server/dist/auth/sqlite/sqliteUserStore.d.ts +12 -0
- package/server/dist/auth/sqlite/sqliteUserStore.js +194 -0
- package/server/dist/auth/sqlite/sqliteUserStore.js.map +1 -0
- package/server/dist/auth/userStore.d.ts +19 -0
- package/server/dist/auth/userStore.js +26 -0
- package/server/dist/auth/userStore.js.map +1 -0
- package/server/dist/auth/userTypes.d.ts +13 -0
- package/server/dist/auth/userTypes.js +3 -0
- package/server/dist/auth/userTypes.js.map +1 -0
- package/server/dist/chat/attachmentPathRedaction.d.ts +5 -0
- package/server/dist/chat/attachmentPathRedaction.js +67 -0
- package/server/dist/chat/attachmentPathRedaction.js.map +1 -0
- package/server/dist/chat/chatItemEnricher.d.ts +5 -0
- package/server/dist/chat/chatItemEnricher.js +40 -0
- package/server/dist/chat/chatItemEnricher.js.map +1 -0
- package/server/dist/chat/codexEventProjector.d.ts +33 -0
- package/server/dist/chat/codexEventProjector.js +482 -0
- package/server/dist/chat/codexEventProjector.js.map +1 -0
- package/server/dist/chat/contextUsageProjector.d.ts +10 -0
- package/server/dist/chat/contextUsageProjector.js +472 -0
- package/server/dist/chat/contextUsageProjector.js.map +1 -0
- package/server/dist/chat/fileChangeExtractor.d.ts +5 -0
- package/server/dist/chat/fileChangeExtractor.js +121 -0
- package/server/dist/chat/fileChangeExtractor.js.map +1 -0
- package/server/dist/chat/markdown/markdownAst.d.ts +5 -0
- package/server/dist/chat/markdown/markdownAst.js +154 -0
- package/server/dist/chat/markdown/markdownAst.js.map +1 -0
- package/server/dist/chat/systemToolCallSummary.d.ts +10 -0
- package/server/dist/chat/systemToolCallSummary.js +112 -0
- package/server/dist/chat/systemToolCallSummary.js.map +1 -0
- package/server/dist/chat/terminal/terminalPlainText.d.ts +14 -0
- package/server/dist/chat/terminal/terminalPlainText.js +139 -0
- package/server/dist/chat/terminal/terminalPlainText.js.map +1 -0
- package/server/dist/chat/textMetrics.d.ts +9 -0
- package/server/dist/chat/textMetrics.js +24 -0
- package/server/dist/chat/textMetrics.js.map +1 -0
- package/server/dist/chat/threadTurnsProjector.d.ts +12 -0
- package/server/dist/chat/threadTurnsProjector.js +292 -0
- package/server/dist/chat/threadTurnsProjector.js.map +1 -0
- package/server/dist/chat/todoPlanProjector.d.ts +8 -0
- package/server/dist/chat/todoPlanProjector.js +94 -0
- package/server/dist/chat/todoPlanProjector.js.map +1 -0
- package/server/dist/chat/todoPlanTypes.d.ts +21 -0
- package/server/dist/chat/todoPlanTypes.js +3 -0
- package/server/dist/chat/todoPlanTypes.js.map +1 -0
- package/server/dist/chat/types.d.ts +138 -0
- package/server/dist/chat/types.js +3 -0
- package/server/dist/chat/types.js.map +1 -0
- package/server/dist/cli/configArg.d.ts +21 -0
- package/server/dist/cli/configArg.js +70 -0
- package/server/dist/cli/configArg.js.map +1 -0
- package/server/dist/codex/appServerProcess.d.ts +24 -0
- package/server/dist/codex/appServerProcess.js +56 -0
- package/server/dist/codex/appServerProcess.js.map +1 -0
- package/server/dist/codex/cliArgs.d.ts +17 -0
- package/server/dist/codex/cliArgs.js +34 -0
- package/server/dist/codex/cliArgs.js.map +1 -0
- package/server/dist/codex/codexAppServer.d.ts +103 -0
- package/server/dist/codex/codexAppServer.js +206 -0
- package/server/dist/codex/codexAppServer.js.map +1 -0
- package/server/dist/codex/jsonl.d.ts +4 -0
- package/server/dist/codex/jsonl.js +23 -0
- package/server/dist/codex/jsonl.js.map +1 -0
- package/server/dist/codex/jsonrpc.d.ts +43 -0
- package/server/dist/codex/jsonrpc.js +96 -0
- package/server/dist/codex/jsonrpc.js.map +1 -0
- package/server/dist/config/serverConfig.d.ts +150 -0
- package/server/dist/config/serverConfig.js +64 -0
- package/server/dist/config/serverConfig.js.map +1 -0
- package/server/dist/env.d.ts +101 -0
- package/server/dist/env.js +523 -0
- package/server/dist/env.js.map +1 -0
- package/server/dist/history/http/historyRoutes.d.ts +18 -0
- package/server/dist/history/http/historyRoutes.js +67 -0
- package/server/dist/history/http/historyRoutes.js.map +1 -0
- package/server/dist/history/index.d.ts +24 -0
- package/server/dist/history/index.js +30 -0
- package/server/dist/history/index.js.map +1 -0
- package/server/dist/history/ingest/historyIngestService.d.ts +15 -0
- package/server/dist/history/ingest/historyIngestService.js +42 -0
- package/server/dist/history/ingest/historyIngestService.js.map +1 -0
- package/server/dist/history/projector/extractIds.d.ts +36 -0
- package/server/dist/history/projector/extractIds.js +111 -0
- package/server/dist/history/projector/extractIds.js.map +1 -0
- package/server/dist/history/projector/projectCodexEvent.d.ts +27 -0
- package/server/dist/history/projector/projectCodexEvent.js +845 -0
- package/server/dist/history/projector/projectCodexEvent.js.map +1 -0
- package/server/dist/history/query/historyQueryService.d.ts +34 -0
- package/server/dist/history/query/historyQueryService.js +170 -0
- package/server/dist/history/query/historyQueryService.js.map +1 -0
- package/server/dist/history/sqlite/schema.d.ts +11 -0
- package/server/dist/history/sqlite/schema.js +34 -0
- package/server/dist/history/sqlite/schema.js.map +1 -0
- package/server/dist/history/sqlite/sqliteHistoryStore.d.ts +69 -0
- package/server/dist/history/sqlite/sqliteHistoryStore.js +206 -0
- package/server/dist/history/sqlite/sqliteHistoryStore.js.map +1 -0
- package/server/dist/history/types.d.ts +29 -0
- package/server/dist/history/types.js +3 -0
- package/server/dist/history/types.js.map +1 -0
- package/server/dist/index.d.ts +1 -0
- package/server/dist/index.js +166 -0
- package/server/dist/index.js.map +1 -0
- package/server/dist/security/executionPolicy.d.ts +33 -0
- package/server/dist/security/executionPolicy.js +72 -0
- package/server/dist/security/executionPolicy.js.map +1 -0
- package/server/dist/security/origin.d.ts +11 -0
- package/server/dist/security/origin.js +40 -0
- package/server/dist/security/origin.js.map +1 -0
- package/server/dist/settings/sqliteUserSettingsStore.d.ts +12 -0
- package/server/dist/settings/sqliteUserSettingsStore.js +62 -0
- package/server/dist/settings/sqliteUserSettingsStore.js.map +1 -0
- package/server/dist/settings/userSettingsRoutes.d.ts +8 -0
- package/server/dist/settings/userSettingsRoutes.js +55 -0
- package/server/dist/settings/userSettingsRoutes.js.map +1 -0
- package/server/dist/settings/userSettingsStore.d.ts +19 -0
- package/server/dist/settings/userSettingsStore.js +26 -0
- package/server/dist/settings/userSettingsStore.js.map +1 -0
- package/server/dist/settings/userSettingsTypes.d.ts +70 -0
- package/server/dist/settings/userSettingsTypes.js +196 -0
- package/server/dist/settings/userSettingsTypes.js.map +1 -0
- package/server/dist/status/codexTaskTracker.d.ts +21 -0
- package/server/dist/status/codexTaskTracker.js +123 -0
- package/server/dist/status/codexTaskTracker.js.map +1 -0
- package/server/dist/status/threadContextUsage.d.ts +19 -0
- package/server/dist/status/threadContextUsage.js +229 -0
- package/server/dist/status/threadContextUsage.js.map +1 -0
- package/server/dist/threadList/threadListServerCache.d.ts +10 -0
- package/server/dist/threadList/threadListServerCache.js +42 -0
- package/server/dist/threadList/threadListServerCache.js.map +1 -0
- package/server/dist/tools/cwdSuggest.d.ts +11 -0
- package/server/dist/tools/cwdSuggest.js +128 -0
- package/server/dist/tools/cwdSuggest.js.map +1 -0
- package/server/dist/workspace/accessControl.d.ts +16 -0
- package/server/dist/workspace/accessControl.js +82 -0
- package/server/dist/workspace/accessControl.js.map +1 -0
- package/server/dist/workspace/sqliteUserWorkspaceStore.d.ts +12 -0
- package/server/dist/workspace/sqliteUserWorkspaceStore.js +82 -0
- package/server/dist/workspace/sqliteUserWorkspaceStore.js.map +1 -0
- package/server/dist/workspace/threadAccess.d.ts +19 -0
- package/server/dist/workspace/threadAccess.js +22 -0
- package/server/dist/workspace/threadAccess.js.map +1 -0
- package/server/dist/workspace/threadListVisibility.d.ts +25 -0
- package/server/dist/workspace/threadListVisibility.js +104 -0
- package/server/dist/workspace/threadListVisibility.js.map +1 -0
- package/server/dist/workspace/userWorkspaceRoutes.d.ts +7 -0
- package/server/dist/workspace/userWorkspaceRoutes.js +124 -0
- package/server/dist/workspace/userWorkspaceRoutes.js.map +1 -0
- package/server/dist/workspace/userWorkspaceStore.d.ts +12 -0
- package/server/dist/workspace/userWorkspaceStore.js +23 -0
- package/server/dist/workspace/userWorkspaceStore.js.map +1 -0
- package/server/dist/ws/socketIoBridge.d.ts +32 -0
- package/server/dist/ws/socketIoBridge.js +194 -0
- package/server/dist/ws/socketIoBridge.js.map +1 -0
- package/server/dist/ws/types.d.ts +113 -0
- package/server/dist/ws/types.js +3 -0
- package/server/dist/ws/types.js.map +1 -0
- package/server/dist/ws/wsHub.d.ts +119 -0
- package/server/dist/ws/wsHub.js +1259 -0
- package/server/dist/ws/wsHub.js.map +1 -0
- package/web/dist/assets/index-CY6cnwQz.js +174 -0
- package/web/dist/assets/index-DI7kJHr2.css +32 -0
- package/web/dist/favicon-mask.svg +9 -0
- package/web/dist/favicon.svg +26 -0
- package/web/dist/index.html +75 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createUserWorkspaceRoutes = createUserWorkspaceRoutes;
|
|
7
|
+
const express_1 = __importDefault(require("express"));
|
|
8
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const env_1 = require("../env");
|
|
11
|
+
const accessControl_1 = require("./accessControl");
|
|
12
|
+
function normalizeWorkspaceDirInputs(rawWorkspaceDirs) {
|
|
13
|
+
const input = Array.isArray(rawWorkspaceDirs) ? rawWorkspaceDirs : [];
|
|
14
|
+
return input.map((dir) => String(dir ?? "").trim()).filter(Boolean);
|
|
15
|
+
}
|
|
16
|
+
function mapWorkspaceValidationError(error) {
|
|
17
|
+
const details = String(error?.message ?? error ?? "invalid workspace dir");
|
|
18
|
+
if (details.includes("cwd not allowed")) {
|
|
19
|
+
return { status: 403, code: "path_not_allowed", details };
|
|
20
|
+
}
|
|
21
|
+
if (details.includes("cwd not found") || details.includes("cwd is not a directory") || details.includes("invalid cwd")) {
|
|
22
|
+
return { status: 400, code: "invalid_workspace_dir", details };
|
|
23
|
+
}
|
|
24
|
+
return { status: 400, code: "invalid_input", details };
|
|
25
|
+
}
|
|
26
|
+
async function resolveRealpathOrFallback(candidatePath) {
|
|
27
|
+
return promises_1.default.realpath(candidatePath).catch(() => node_path_1.default.resolve(candidatePath));
|
|
28
|
+
}
|
|
29
|
+
function resolveRequestedWorkspaceDir(workspaceDir) {
|
|
30
|
+
// 与 accessControl 的 cwd 解析口径保持一致:相对路径基于 CODEX_CWD。
|
|
31
|
+
const baseCwd = node_path_1.default.resolve((0, env_1.getCodexCwd)());
|
|
32
|
+
const rawWorkspaceDir = String(workspaceDir ?? "").trim();
|
|
33
|
+
if (rawWorkspaceDir.includes("\0"))
|
|
34
|
+
throw new Error("invalid cwd");
|
|
35
|
+
if (!rawWorkspaceDir)
|
|
36
|
+
throw new Error("invalid cwd");
|
|
37
|
+
return node_path_1.default.isAbsolute(rawWorkspaceDir) ? node_path_1.default.resolve(rawWorkspaceDir) : node_path_1.default.resolve(baseCwd, rawWorkspaceDir);
|
|
38
|
+
}
|
|
39
|
+
async function resolveTargetRealpathByExistingAncestor(targetPath) {
|
|
40
|
+
// 为了避免“通过 symlink 越权创建目录”,基于最近存在父目录的 realpath 计算目标真实路径。
|
|
41
|
+
let existingAncestorPath = node_path_1.default.resolve(targetPath);
|
|
42
|
+
while (true) {
|
|
43
|
+
try {
|
|
44
|
+
await promises_1.default.stat(existingAncestorPath);
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
const parentPath = node_path_1.default.dirname(existingAncestorPath);
|
|
49
|
+
if (parentPath === existingAncestorPath)
|
|
50
|
+
break;
|
|
51
|
+
existingAncestorPath = parentPath;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const existingAncestorRealpath = await resolveRealpathOrFallback(existingAncestorPath);
|
|
55
|
+
const relativeToAncestor = node_path_1.default.relative(existingAncestorPath, node_path_1.default.resolve(targetPath));
|
|
56
|
+
return relativeToAncestor ? node_path_1.default.resolve(existingAncestorRealpath, relativeToAncestor) : existingAncestorRealpath;
|
|
57
|
+
}
|
|
58
|
+
async function assertWorkspaceCreateTargetAllowed(workspaceDir, user) {
|
|
59
|
+
const resolvedWorkspaceDir = resolveRequestedWorkspaceDir(workspaceDir);
|
|
60
|
+
const access = (0, accessControl_1.resolveAllowedRootsForUser)(user);
|
|
61
|
+
if (access.allowAnyRoot)
|
|
62
|
+
return resolvedWorkspaceDir;
|
|
63
|
+
if (!access.roots.length)
|
|
64
|
+
throw new Error(`cwd not allowed: ${resolvedWorkspaceDir}`);
|
|
65
|
+
const candidateRealpathBeforeCreate = await resolveTargetRealpathByExistingAncestor(resolvedWorkspaceDir);
|
|
66
|
+
const allowedRootRealpaths = await Promise.all(access.roots.map((rootPath) => resolveRealpathOrFallback(rootPath)));
|
|
67
|
+
const withinAllowedRoots = allowedRootRealpaths.some((rootRealpath) => (0, accessControl_1.isPathWithinRoot)(rootRealpath, candidateRealpathBeforeCreate));
|
|
68
|
+
if (!withinAllowedRoots)
|
|
69
|
+
throw new Error(`cwd not allowed: ${candidateRealpathBeforeCreate}`);
|
|
70
|
+
return resolvedWorkspaceDir;
|
|
71
|
+
}
|
|
72
|
+
async function ensureWorkspaceDirectoryExists(workspaceDir, user) {
|
|
73
|
+
const allowedTargetWorkspaceDir = await assertWorkspaceCreateTargetAllowed(workspaceDir, user);
|
|
74
|
+
// 路径不存在时自动创建;存在时保持幂等。
|
|
75
|
+
await promises_1.default.mkdir(allowedTargetWorkspaceDir, { recursive: true });
|
|
76
|
+
}
|
|
77
|
+
function createUserWorkspaceRoutes(opts) {
|
|
78
|
+
const router = express_1.default.Router();
|
|
79
|
+
router.get("/user-created", async (req, res) => {
|
|
80
|
+
const username = String(req.user?.username ?? "").trim();
|
|
81
|
+
if (!username) {
|
|
82
|
+
res.status(401).json({ ok: false, error: "unauthorized" });
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const workspaceDirs = await opts.userWorkspaceStore.listUserWorkspaceDirs(username);
|
|
86
|
+
res.json({ ok: true, workspaceDirs });
|
|
87
|
+
});
|
|
88
|
+
router.put("/user-created", async (req, res) => {
|
|
89
|
+
const username = String(req.user?.username ?? "").trim();
|
|
90
|
+
const user = req.user;
|
|
91
|
+
if (!username || !user) {
|
|
92
|
+
res.status(401).json({ ok: false, error: "unauthorized" });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const body = (req.body ?? {});
|
|
96
|
+
if (!Array.isArray(body.workspaceDirs)) {
|
|
97
|
+
res.status(400).json({ ok: false, error: "invalid_input", details: "workspaceDirs must be an array" });
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
const inputWorkspaceDirs = normalizeWorkspaceDirInputs(body.workspaceDirs);
|
|
102
|
+
const seen = new Set();
|
|
103
|
+
const validatedWorkspaceDirs = [];
|
|
104
|
+
for (const workspaceDir of inputWorkspaceDirs) {
|
|
105
|
+
// 用户保存目录时路径不存在则自动创建;创建前先做权限边界校验。
|
|
106
|
+
await ensureWorkspaceDirectoryExists(workspaceDir, user);
|
|
107
|
+
// 复用现有访问控制:同时校验目录存在性与用户权限边界,返回 canonical 绝对路径。
|
|
108
|
+
const canonicalWorkspaceDir = await (0, accessControl_1.assertCwdAllowedForUser)({ cwd: workspaceDir, user });
|
|
109
|
+
if (seen.has(canonicalWorkspaceDir))
|
|
110
|
+
continue;
|
|
111
|
+
seen.add(canonicalWorkspaceDir);
|
|
112
|
+
validatedWorkspaceDirs.push(canonicalWorkspaceDir);
|
|
113
|
+
}
|
|
114
|
+
const workspaceDirs = await opts.userWorkspaceStore.replaceUserWorkspaceDirs(username, validatedWorkspaceDirs);
|
|
115
|
+
res.json({ ok: true, workspaceDirs });
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
const mapped = mapWorkspaceValidationError(error);
|
|
119
|
+
res.status(mapped.status).json({ ok: false, error: mapped.code, details: mapped.details });
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
return router;
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=userWorkspaceRoutes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"userWorkspaceRoutes.js","sourceRoot":"","sources":["../../src/workspace/userWorkspaceRoutes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type AuthDb } from "../auth/sqlite/authDb";
|
|
2
|
+
export type UserWorkspaceStore = {
|
|
3
|
+
listUserWorkspaceDirs(username: string): Promise<string[]>;
|
|
4
|
+
replaceUserWorkspaceDirs(username: string, workspaceDirs: string[]): Promise<string[]>;
|
|
5
|
+
};
|
|
6
|
+
type CreateUserWorkspaceStoreOptions = {
|
|
7
|
+
filePath?: string;
|
|
8
|
+
dbPath?: string;
|
|
9
|
+
authDb?: AuthDb;
|
|
10
|
+
};
|
|
11
|
+
export declare function createUserWorkspaceStore(opts: CreateUserWorkspaceStoreOptions): Promise<UserWorkspaceStore>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createUserWorkspaceStore = createUserWorkspaceStore;
|
|
7
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
8
|
+
const authDb_1 = require("../auth/sqlite/authDb");
|
|
9
|
+
const sqliteUserWorkspaceStore_1 = require("./sqliteUserWorkspaceStore");
|
|
10
|
+
/**
|
|
11
|
+
* 解析用户工作目录仓库 SQLite 路径。
|
|
12
|
+
*/
|
|
13
|
+
function resolveUserWorkspaceStoreDbPath(opts) {
|
|
14
|
+
const rawDbPath = String(opts.dbPath ?? opts.filePath ?? "").trim();
|
|
15
|
+
if (!rawDbPath)
|
|
16
|
+
throw new Error("user workspace store dbPath is required");
|
|
17
|
+
return node_path_1.default.resolve(rawDbPath);
|
|
18
|
+
}
|
|
19
|
+
async function createUserWorkspaceStore(opts) {
|
|
20
|
+
const authDb = opts.authDb ?? (0, authDb_1.createAuthDb)({ dbPath: resolveUserWorkspaceStoreDbPath(opts) });
|
|
21
|
+
return (0, sqliteUserWorkspaceStore_1.createSqliteUserWorkspaceStore)({ authDb });
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=userWorkspaceStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"userWorkspaceStore.js","sourceRoot":"","sources":["../../src/workspace/userWorkspaceStore.ts"],"names":[],"mappings":";;;;;AA6BA,4DAGC;AAhCD,0DAA6B;AAC7B,kDAAkE;AAClE,yEAA4E;AAkB5E;;GAEG;AACH,SAAS,+BAA+B,CAAC,IAAqC;IAC5E,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACpE,IAAI,CAAC,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,yCAAyC,CAAC,CAAC;IAC3E,OAAO,mBAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AACjC,CAAC;AAEM,KAAK,UAAU,wBAAwB,CAAC,IAAqC;IAClF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAA,qBAAY,EAAC,EAAE,MAAM,EAAE,+BAA+B,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9F,OAAO,IAAA,yDAA8B,EAAC,EAAE,MAAM,EAAE,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Server as SocketIoServer, Socket } from "socket.io";
|
|
2
|
+
/**
|
|
3
|
+
* Socket.IO bridge 的生命周期句柄。
|
|
4
|
+
*/
|
|
5
|
+
export type SocketIoBridge = {
|
|
6
|
+
/**
|
|
7
|
+
* 清理 bridge 绑定的事件监听。
|
|
8
|
+
*/
|
|
9
|
+
dispose: () => void;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* 生成上游 ws URL 的参数。
|
|
13
|
+
*/
|
|
14
|
+
type UpstreamWsUrlFactoryInput = {
|
|
15
|
+
socket: Socket;
|
|
16
|
+
rawWsPath: string;
|
|
17
|
+
host: string;
|
|
18
|
+
port: number;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* 创建 Socket.IO bridge 的入参。
|
|
22
|
+
*/
|
|
23
|
+
type CreateSocketIoBridgeInput = {
|
|
24
|
+
ioServer: SocketIoServer;
|
|
25
|
+
rawWsPath?: string;
|
|
26
|
+
upstreamWsUrlFactory?: (input: UpstreamWsUrlFactoryInput) => string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* 创建 Socket.IO -> 原 ws Hub 的桥接层。
|
|
30
|
+
*/
|
|
31
|
+
export declare function createSocketIoBridge(input: CreateSocketIoBridgeInput): SocketIoBridge;
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createSocketIoBridge = createSocketIoBridge;
|
|
7
|
+
const ws_1 = __importDefault(require("ws"));
|
|
8
|
+
/**
|
|
9
|
+
* 连接桥中的消息事件名,统一复用单一事件承载现有 ws 协议对象。
|
|
10
|
+
*/
|
|
11
|
+
const SOCKET_IO_MESSAGE_EVENT = "message";
|
|
12
|
+
/**
|
|
13
|
+
* 创建 Socket.IO -> 原 ws Hub 的桥接层。
|
|
14
|
+
*/
|
|
15
|
+
function createSocketIoBridge(input) {
|
|
16
|
+
/**
|
|
17
|
+
* 目标 ws path,默认沿用现有 ws hub 路径。
|
|
18
|
+
*/
|
|
19
|
+
const rawWsPath = input.rawWsPath ?? "/ws";
|
|
20
|
+
/**
|
|
21
|
+
* 统一处理 Socket.IO 客户端连接,并桥接到内部 ws。
|
|
22
|
+
*/
|
|
23
|
+
const onConnection = (socket) => {
|
|
24
|
+
/**
|
|
25
|
+
* 上游 ws 地址,默认指向当前进程监听端口。
|
|
26
|
+
*/
|
|
27
|
+
const upstreamWsUrl = buildUpstreamWsUrl({
|
|
28
|
+
socket,
|
|
29
|
+
rawWsPath,
|
|
30
|
+
upstreamWsUrlFactory: input.upstreamWsUrlFactory,
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* 透传 cookie 到上游 ws,以复用现有鉴权逻辑。
|
|
34
|
+
*/
|
|
35
|
+
const cookieHeader = typeof socket.handshake.headers.cookie === "string" ? socket.handshake.headers.cookie : "";
|
|
36
|
+
/**
|
|
37
|
+
* 上游 ws 客户端实例。
|
|
38
|
+
*/
|
|
39
|
+
const upstreamWs = new ws_1.default(upstreamWsUrl, cookieHeader ? { headers: { Cookie: cookieHeader } } : undefined);
|
|
40
|
+
/**
|
|
41
|
+
* 在 socket.io 侧发送标准化错误消息。
|
|
42
|
+
*/
|
|
43
|
+
const emitBridgeError = (message, details) => {
|
|
44
|
+
socket.emit(SOCKET_IO_MESSAGE_EVENT, {
|
|
45
|
+
type: "error",
|
|
46
|
+
message,
|
|
47
|
+
details,
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* socket.io -> ws:转发前端消息。
|
|
52
|
+
*/
|
|
53
|
+
const onSocketMessage = (payload) => {
|
|
54
|
+
if (upstreamWs.readyState !== ws_1.default.OPEN)
|
|
55
|
+
return;
|
|
56
|
+
try {
|
|
57
|
+
upstreamWs.send(JSON.stringify(payload));
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
emitBridgeError("socket.io bridge send failed", String(err));
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* ws -> socket.io:转发服务端消息。
|
|
65
|
+
*/
|
|
66
|
+
const onUpstreamMessage = (buffer) => {
|
|
67
|
+
const raw = Buffer.isBuffer(buffer) ? buffer.toString("utf8") : String(buffer);
|
|
68
|
+
try {
|
|
69
|
+
const parsed = JSON.parse(raw);
|
|
70
|
+
socket.emit(SOCKET_IO_MESSAGE_EVENT, parsed);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// 仅透传 JSON 协议消息,非 JSON 直接忽略。
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* 上游 ws 关闭后,主动断开 socket.io 客户端,触发其重连策略。
|
|
78
|
+
*/
|
|
79
|
+
const onUpstreamClose = (code, reasonBuffer) => {
|
|
80
|
+
if (code === 1008) {
|
|
81
|
+
emitBridgeError("unauthorized", reasonBuffer.toString("utf8"));
|
|
82
|
+
}
|
|
83
|
+
if (socket.connected)
|
|
84
|
+
socket.disconnect(true);
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* 上游 ws 错误处理,便于前端可观测。
|
|
88
|
+
*/
|
|
89
|
+
const onUpstreamError = (err) => {
|
|
90
|
+
emitBridgeError("socket.io bridge upstream error", String(err));
|
|
91
|
+
if (socket.connected)
|
|
92
|
+
socket.disconnect(true);
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* socket.io 断开时,清理上游 ws。
|
|
96
|
+
*/
|
|
97
|
+
const onSocketDisconnect = () => {
|
|
98
|
+
if (upstreamWs.readyState === ws_1.default.OPEN || upstreamWs.readyState === ws_1.default.CONNECTING) {
|
|
99
|
+
upstreamWs.close();
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
socket.on(SOCKET_IO_MESSAGE_EVENT, onSocketMessage);
|
|
103
|
+
socket.on("disconnect", onSocketDisconnect);
|
|
104
|
+
upstreamWs.on("message", onUpstreamMessage);
|
|
105
|
+
upstreamWs.on("close", onUpstreamClose);
|
|
106
|
+
upstreamWs.on("error", onUpstreamError);
|
|
107
|
+
};
|
|
108
|
+
input.ioServer.on("connection", onConnection);
|
|
109
|
+
return {
|
|
110
|
+
dispose: () => {
|
|
111
|
+
input.ioServer.off("connection", onConnection);
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* 构建上游 ws 地址。
|
|
117
|
+
*/
|
|
118
|
+
function buildUpstreamWsUrl(input) {
|
|
119
|
+
/**
|
|
120
|
+
* 基于本地监听地址推导可回环访问的 host。
|
|
121
|
+
*/
|
|
122
|
+
const host = normalizeLoopbackHost(resolveLocalAddress(input.socket));
|
|
123
|
+
/**
|
|
124
|
+
* 当前连接可解析出的本地端口。
|
|
125
|
+
*/
|
|
126
|
+
const port = resolveLocalPort(input.socket);
|
|
127
|
+
if (input.upstreamWsUrlFactory) {
|
|
128
|
+
return input.upstreamWsUrlFactory({
|
|
129
|
+
socket: input.socket,
|
|
130
|
+
rawWsPath: input.rawWsPath,
|
|
131
|
+
host,
|
|
132
|
+
port,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
if (!port || !Number.isFinite(port))
|
|
136
|
+
throw new Error("socket.io bridge failed to resolve local port");
|
|
137
|
+
return `ws://${host}:${port}${input.rawWsPath}`;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* 将监听地址标准化为可用于回环连接的 host。
|
|
141
|
+
*/
|
|
142
|
+
function normalizeLoopbackHost(host) {
|
|
143
|
+
const normalizedHost = String(host || "").trim().toLowerCase();
|
|
144
|
+
if (!normalizedHost)
|
|
145
|
+
return "127.0.0.1";
|
|
146
|
+
if (normalizedHost === "::" || normalizedHost === "0.0.0.0")
|
|
147
|
+
return "127.0.0.1";
|
|
148
|
+
if (normalizedHost === "::1")
|
|
149
|
+
return "127.0.0.1";
|
|
150
|
+
if (normalizedHost.startsWith("::ffff:"))
|
|
151
|
+
return normalizedHost.slice("::ffff:".length);
|
|
152
|
+
return normalizedHost;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 解析 Socket.IO 连接的本地地址(用于构建回环 ws URL)。
|
|
156
|
+
*/
|
|
157
|
+
function resolveLocalAddress(socket) {
|
|
158
|
+
const fromRequest = socket.request?.socket?.localAddress;
|
|
159
|
+
const fromConnRequest = socket.conn?.request?.socket?.localAddress;
|
|
160
|
+
const fromConnTransport = socket.conn?.transport?.socket?.localAddress;
|
|
161
|
+
const fromServer = resolveServerAddress(socket)?.address;
|
|
162
|
+
return String(fromRequest || fromConnRequest || fromConnTransport || fromServer || "127.0.0.1");
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* 解析 Socket.IO 连接对应的本地端口。
|
|
166
|
+
*/
|
|
167
|
+
function resolveLocalPort(socket) {
|
|
168
|
+
const fromRequest = Number(socket.request?.socket?.localPort || 0);
|
|
169
|
+
if (Number.isFinite(fromRequest) && fromRequest > 0)
|
|
170
|
+
return fromRequest;
|
|
171
|
+
const fromConnRequest = Number(socket.conn?.request?.socket?.localPort || 0);
|
|
172
|
+
if (Number.isFinite(fromConnRequest) && fromConnRequest > 0)
|
|
173
|
+
return fromConnRequest;
|
|
174
|
+
const fromConnTransport = Number(socket.conn?.transport?.socket?.localPort || 0);
|
|
175
|
+
if (Number.isFinite(fromConnTransport) && fromConnTransport > 0)
|
|
176
|
+
return fromConnTransport;
|
|
177
|
+
const fromServer = Number(resolveServerAddress(socket)?.port || 0);
|
|
178
|
+
if (Number.isFinite(fromServer) && fromServer > 0)
|
|
179
|
+
return fromServer;
|
|
180
|
+
return 0;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* 从 Socket.IO server 提取监听地址对象。
|
|
184
|
+
*/
|
|
185
|
+
function resolveServerAddress(socket) {
|
|
186
|
+
const httpServer = socket.nsp?.server?.httpServer;
|
|
187
|
+
if (!httpServer)
|
|
188
|
+
return null;
|
|
189
|
+
const serverAddress = httpServer.address();
|
|
190
|
+
if (!serverAddress || typeof serverAddress === "string")
|
|
191
|
+
return null;
|
|
192
|
+
return serverAddress;
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=socketIoBridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socketIoBridge.js","sourceRoot":"","sources":["../../src/ws/socketIoBridge.ts"],"names":[],"mappings":";;;;;AAwCA,oDAwGC;AA/ID,4CAA2B;AA+B3B;;GAEG;AACH,MAAM,uBAAuB,GAAG,SAAS,CAAC;AAE1C;;GAEG;AACH,SAAgB,oBAAoB,CAAC,KAAgC;IACnE;;OAEG;IACH,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC;IAE3C;;OAEG;IACH,MAAM,YAAY,GAAG,CAAC,MAAc,EAAE,EAAE;QACtC;;WAEG;QACH,MAAM,aAAa,GAAG,kBAAkB,CAAC;YACvC,MAAM;YACN,SAAS;YACT,oBAAoB,EAAE,KAAK,CAAC,oBAAoB;SACjD,CAAC,CAAC;QACH;;WAEG;QACH,MAAM,YAAY,GAAG,OAAO,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QAChH;;WAEG;QACH,MAAM,UAAU,GAAG,IAAI,YAAS,CAAC,aAAa,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QAElH;;WAEG;QACH,MAAM,eAAe,GAAG,CAAC,OAAe,EAAE,OAAiB,EAAE,EAAE;YAC7D,MAAM,CAAC,IAAI,CAAC,uBAAuB,EAAE;gBACnC,IAAI,EAAE,OAAO;gBACb,OAAO;gBACP,OAAO;aACR,CAAC,CAAC;QACL,CAAC,CAAC;QAEF;;WAEG;QACH,MAAM,eAAe,GAAG,CAAC,OAAgB,EAAE,EAAE;YAC3C,IAAI,UAAU,CAAC,UAAU,KAAK,YAAS,CAAC,IAAI;gBAAE,OAAO;YACrD,IAAI,CAAC;gBACH,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;YAC3C,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,eAAe,CAAC,8BAA8B,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAC/D,CAAC;QACH,CAAC,CAAC;QAEF;;WAEG;QACH,MAAM,iBAAiB,GAAG,CAAC,MAAyB,EAAE,EAAE;YACtD,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC/E,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC/B,MAAM,CAAC,IAAI,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAC;YAC/C,CAAC;YAAC,MAAM,CAAC;gBACP,6BAA6B;YAC/B,CAAC;QACH,CAAC,CAAC;QAEF;;WAEG;QACH,MAAM,eAAe,GAAG,CAAC,IAAY,EAAE,YAAoB,EAAE,EAAE;YAC7D,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAClB,eAAe,CAAC,cAAc,EAAE,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;YACjE,CAAC;YACD,IAAI,MAAM,CAAC,SAAS;gBAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAChD,CAAC,CAAC;QAEF;;WAEG;QACH,MAAM,eAAe,GAAG,CAAC,GAAY,EAAE,EAAE;YACvC,eAAe,CAAC,iCAAiC,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YAChE,IAAI,MAAM,CAAC,SAAS;gBAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAChD,CAAC,CAAC;QAEF;;WAEG;QACH,MAAM,kBAAkB,GAAG,GAAG,EAAE;YAC9B,IAAI,UAAU,CAAC,UAAU,KAAK,YAAS,CAAC,IAAI,IAAI,UAAU,CAAC,UAAU,KAAK,YAAS,CAAC,UAAU,EAAE,CAAC;gBAC/F,UAAU,CAAC,KAAK,EAAE,CAAC;YACrB,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,CAAC,EAAE,CAAC,uBAAuB,EAAE,eAAe,CAAC,CAAC;QACpD,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,kBAAkB,CAAC,CAAC;QAC5C,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;QAC5C,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QACxC,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IAC1C,CAAC,CAAC;IAEF,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IAE9C,OAAO;QACL,OAAO,EAAE,GAAG,EAAE;YACZ,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;QACjD,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAS,kBAAkB,CAAC,KAI3B;IACC;;OAEG;IACH,MAAM,IAAI,GAAG,qBAAqB,CAAC,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IACtE;;OAEG;IACH,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAE5C,IAAI,KAAK,CAAC,oBAAoB,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC,oBAAoB,CAAC;YAChC,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,IAAI;YACJ,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IAED,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACtG,OAAO,QAAQ,IAAI,IAAI,IAAI,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAAC,IAAY;IACzC,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC/D,IAAI,CAAC,cAAc;QAAE,OAAO,WAAW,CAAC;IACxC,IAAI,cAAc,KAAK,IAAI,IAAI,cAAc,KAAK,SAAS;QAAE,OAAO,WAAW,CAAC;IAChF,IAAI,cAAc,KAAK,KAAK;QAAE,OAAO,WAAW,CAAC;IACjD,IAAI,cAAc,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,cAAc,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACxF,OAAO,cAAc,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,SAAS,mBAAmB,CAAC,MAAc;IACzC,MAAM,WAAW,GAAI,MAAM,CAAC,OAAe,EAAE,MAAM,EAAE,YAAY,CAAC;IAClE,MAAM,eAAe,GAAI,MAAM,CAAC,IAAY,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC;IAC5E,MAAM,iBAAiB,GAAI,MAAM,CAAC,IAAY,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,CAAC;IAChF,MAAM,UAAU,GAAG,oBAAoB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;IACzD,OAAO,MAAM,CAAC,WAAW,IAAI,eAAe,IAAI,iBAAiB,IAAI,UAAU,IAAI,WAAW,CAAC,CAAC;AAClG,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,MAAc;IACtC,MAAM,WAAW,GAAG,MAAM,CAAE,MAAM,CAAC,OAAe,EAAE,MAAM,EAAE,SAAS,IAAI,CAAC,CAAC,CAAC;IAC5E,IAAI,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,WAAW,GAAG,CAAC;QAAE,OAAO,WAAW,CAAC;IAExE,MAAM,eAAe,GAAG,MAAM,CAAE,MAAM,CAAC,IAAY,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,IAAI,CAAC,CAAC,CAAC;IACtF,IAAI,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,eAAe,GAAG,CAAC;QAAE,OAAO,eAAe,CAAC;IAEpF,MAAM,iBAAiB,GAAG,MAAM,CAAE,MAAM,CAAC,IAAY,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,IAAI,CAAC,CAAC,CAAC;IAC1F,IAAI,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAAC,IAAI,iBAAiB,GAAG,CAAC;QAAE,OAAO,iBAAiB,CAAC;IAE1F,MAAM,UAAU,GAAG,MAAM,CAAC,oBAAoB,CAAC,MAAM,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC;IACnE,IAAI,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC;QAAE,OAAO,UAAU,CAAC;IAErE,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;GAEG;AACH,SAAS,oBAAoB,CAAC,MAAc;IAC1C,MAAM,UAAU,GAAI,MAAM,CAAC,GAAG,EAAE,MAAc,EAAE,UAA8G,CAAC;IAC/J,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAC7B,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC;IAC3C,IAAI,CAAC,aAAa,IAAI,OAAO,aAAa,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACrE,OAAO,aAAa,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { ChatItem, ChatOp, FileChange } from "../chat/types";
|
|
2
|
+
import type { TodoPlanUpdate } from "../chat/todoPlanTypes";
|
|
3
|
+
export type WsClientMessage = {
|
|
4
|
+
type: "hello";
|
|
5
|
+
token: string;
|
|
6
|
+
clientVersion?: string;
|
|
7
|
+
} | {
|
|
8
|
+
type: "get_status";
|
|
9
|
+
} | {
|
|
10
|
+
type: "list_threads";
|
|
11
|
+
cwd?: string;
|
|
12
|
+
requestId?: string;
|
|
13
|
+
} | {
|
|
14
|
+
type: "open_thread";
|
|
15
|
+
threadId?: string;
|
|
16
|
+
clientMessageId?: string;
|
|
17
|
+
cwd?: string;
|
|
18
|
+
approvalPolicy?: "untrusted" | "on-failure" | "on-request" | "never";
|
|
19
|
+
sandbox?: "read-only" | "workspace-write" | "danger-full-access";
|
|
20
|
+
model?: string;
|
|
21
|
+
} | {
|
|
22
|
+
type: "load_thread_turns";
|
|
23
|
+
threadId: string;
|
|
24
|
+
before: number;
|
|
25
|
+
limit?: number;
|
|
26
|
+
clientMessageId?: string;
|
|
27
|
+
} | {
|
|
28
|
+
type: "submit";
|
|
29
|
+
threadId: string;
|
|
30
|
+
text: string;
|
|
31
|
+
model?: string;
|
|
32
|
+
effort?: string;
|
|
33
|
+
reasoningEffort?: string;
|
|
34
|
+
approvalPolicy?: "untrusted" | "on-failure" | "on-request" | "never";
|
|
35
|
+
sandbox?: "read-only" | "workspace-write" | "danger-full-access";
|
|
36
|
+
collaborationMode?: unknown;
|
|
37
|
+
clientMessageId?: string;
|
|
38
|
+
} | {
|
|
39
|
+
type: "interrupt";
|
|
40
|
+
threadId: string;
|
|
41
|
+
clientMessageId?: string;
|
|
42
|
+
} | {
|
|
43
|
+
type: "respond_user_input";
|
|
44
|
+
requestId: string | number;
|
|
45
|
+
response: unknown;
|
|
46
|
+
clientMessageId?: string;
|
|
47
|
+
};
|
|
48
|
+
export type WsServerMessage = {
|
|
49
|
+
type: "ack";
|
|
50
|
+
ackType: "submit" | "open_thread" | "load_thread_turns" | "interrupt" | "respond_user_input";
|
|
51
|
+
clientMessageId: string;
|
|
52
|
+
threadId?: string;
|
|
53
|
+
requestId?: string | number;
|
|
54
|
+
} | {
|
|
55
|
+
type: "ready";
|
|
56
|
+
serverVersion: string;
|
|
57
|
+
threads: unknown[];
|
|
58
|
+
} | {
|
|
59
|
+
type: "status";
|
|
60
|
+
snapshot: {
|
|
61
|
+
codex?: unknown;
|
|
62
|
+
codexTask?: unknown;
|
|
63
|
+
ws?: unknown;
|
|
64
|
+
};
|
|
65
|
+
} | {
|
|
66
|
+
type: "threads";
|
|
67
|
+
threads: unknown[];
|
|
68
|
+
requestId?: string;
|
|
69
|
+
cwd?: string | null;
|
|
70
|
+
} | {
|
|
71
|
+
type: "thread_opened";
|
|
72
|
+
thread: unknown;
|
|
73
|
+
chatItems?: ChatItem[];
|
|
74
|
+
} | {
|
|
75
|
+
type: "thread_turns";
|
|
76
|
+
threadId: string;
|
|
77
|
+
turns: unknown[];
|
|
78
|
+
turnsStart: number;
|
|
79
|
+
turnsTotal: number;
|
|
80
|
+
chatItems?: ChatItem[];
|
|
81
|
+
} | {
|
|
82
|
+
type: "chat_ops";
|
|
83
|
+
threadId: string;
|
|
84
|
+
ops: ChatOp[];
|
|
85
|
+
} | {
|
|
86
|
+
type: "todo_plan_update";
|
|
87
|
+
update: TodoPlanUpdate;
|
|
88
|
+
} | {
|
|
89
|
+
type: "thread_context_usage";
|
|
90
|
+
threadId: string;
|
|
91
|
+
usagePercent: number;
|
|
92
|
+
} | {
|
|
93
|
+
type: "user_input_required";
|
|
94
|
+
requestId: string | number;
|
|
95
|
+
threadId: string | null;
|
|
96
|
+
method: string;
|
|
97
|
+
params: unknown;
|
|
98
|
+
fileChanges?: FileChange[];
|
|
99
|
+
} | {
|
|
100
|
+
type: "user_input_resolved";
|
|
101
|
+
requestId: string | number;
|
|
102
|
+
threadId: string | null;
|
|
103
|
+
method?: string;
|
|
104
|
+
response?: unknown;
|
|
105
|
+
mappedResponse?: unknown;
|
|
106
|
+
requestParams?: unknown;
|
|
107
|
+
} | {
|
|
108
|
+
type: "error";
|
|
109
|
+
message: string;
|
|
110
|
+
details?: unknown;
|
|
111
|
+
clientMessageId?: string;
|
|
112
|
+
requestId?: string;
|
|
113
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/ws/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { WebSocketServer } from "ws";
|
|
2
|
+
import type { CodexAppServer } from "../codex/codexAppServer";
|
|
3
|
+
import type { UserStore } from "../auth/userStore";
|
|
4
|
+
import type { HistoryIngestService } from "../history/types";
|
|
5
|
+
type StatusSnapshot = {
|
|
6
|
+
codex?: unknown;
|
|
7
|
+
codexTask?: unknown;
|
|
8
|
+
ws?: unknown;
|
|
9
|
+
};
|
|
10
|
+
type WsHubOpts = {
|
|
11
|
+
getActiveTurnIds?: (threadId: string) => string[];
|
|
12
|
+
pendingTimeoutMs?: number;
|
|
13
|
+
heartbeatIntervalMs?: number;
|
|
14
|
+
userStore?: UserStore;
|
|
15
|
+
historyIngest?: HistoryIngestService | null;
|
|
16
|
+
};
|
|
17
|
+
export declare class WsHub {
|
|
18
|
+
private readonly wss;
|
|
19
|
+
private readonly codex;
|
|
20
|
+
private readonly sessionSecret;
|
|
21
|
+
private readonly getStatusSnapshot;
|
|
22
|
+
private readonly clients;
|
|
23
|
+
private readonly readyClients;
|
|
24
|
+
private readonly threadOwners;
|
|
25
|
+
private readonly threadOwnerUsername;
|
|
26
|
+
private readonly threadOwnerUsernameMax;
|
|
27
|
+
private readonly threadCwdById;
|
|
28
|
+
private readonly pending;
|
|
29
|
+
private readonly seenSubmitIdsByThread;
|
|
30
|
+
private readonly submitDedupTtlMs;
|
|
31
|
+
private readonly submitDedupMaxPerThread;
|
|
32
|
+
private readonly wsUser;
|
|
33
|
+
private readonly wsByUser;
|
|
34
|
+
private readonly openThreadResultsByUser;
|
|
35
|
+
private readonly openThreadDedupTtlMs;
|
|
36
|
+
private readonly openThreadDedupMaxPerUser;
|
|
37
|
+
private readonly threadTurnsByUser;
|
|
38
|
+
private readonly threadTurnsCacheTtlMs;
|
|
39
|
+
private readonly threadTurnsCacheMaxPerUser;
|
|
40
|
+
private readonly threadContextUsageReader;
|
|
41
|
+
private readonly chatProjector;
|
|
42
|
+
private readonly threadCreatedAtMsById;
|
|
43
|
+
private readonly initialThreadTurnLimit;
|
|
44
|
+
private readonly loadThreadTurnsDefaultLimit;
|
|
45
|
+
private readonly loadThreadTurnsMaxLimit;
|
|
46
|
+
private readonly seenInterruptIdsByThread;
|
|
47
|
+
private readonly interruptDedupTtlMs;
|
|
48
|
+
private readonly interruptDedupMaxPerThread;
|
|
49
|
+
private statusTimer;
|
|
50
|
+
private lastStatusJson;
|
|
51
|
+
private readonly getActiveTurnIds;
|
|
52
|
+
private readonly pendingTimeoutMs;
|
|
53
|
+
private heartbeatTimer;
|
|
54
|
+
private readonly userStore;
|
|
55
|
+
private readonly historyIngest;
|
|
56
|
+
private workspaceRoutingSnapshot;
|
|
57
|
+
private workspaceRoutingSnapshotPromise;
|
|
58
|
+
private readonly workspaceRoutingSnapshotTtlMs;
|
|
59
|
+
constructor(wss: WebSocketServer, codex: CodexAppServer, sessionSecret: string, getStatusSnapshot: () => StatusSnapshot, opts?: WsHubOpts);
|
|
60
|
+
dispose(): void;
|
|
61
|
+
private onConnection;
|
|
62
|
+
private resolveWsUserInfo;
|
|
63
|
+
private getWsUserInfo;
|
|
64
|
+
private assertThreadAllowedForUser;
|
|
65
|
+
private startHeartbeat;
|
|
66
|
+
private handleAuthedMessage;
|
|
67
|
+
private listThreadsForClient;
|
|
68
|
+
private getWorkspaceRoutingSnapshot;
|
|
69
|
+
private isCwdVisibleToUser;
|
|
70
|
+
private getOrFetchThreadCwd;
|
|
71
|
+
/**
|
|
72
|
+
* 将消息广播给“对该 thread cwd 有权限”的在线用户,避免跨工作区泄露。
|
|
73
|
+
* 说明:同一通知可能对应多条下发消息(chat_ops + todo + usage),因此这里支持批量发送。
|
|
74
|
+
*/
|
|
75
|
+
private broadcastMessagesToAuthorizedUsers;
|
|
76
|
+
private sendReady;
|
|
77
|
+
private rememberSubmitId;
|
|
78
|
+
private forgetSubmitId;
|
|
79
|
+
private getCachedOpenThreadResult;
|
|
80
|
+
private cacheOpenThreadResult;
|
|
81
|
+
private trimThreadTurnsForClient;
|
|
82
|
+
/**
|
|
83
|
+
* 从线程 session 文件中读取最新 token_count,并写入 `contextUsagePercent` 字段。
|
|
84
|
+
* 说明:前端会从 thread_opened payload 中读取该值,以解决“刚进来没有上下文使用率”的问题。
|
|
85
|
+
*/
|
|
86
|
+
private attachThreadContextUsagePercent;
|
|
87
|
+
private cacheThreadTurns;
|
|
88
|
+
private getCachedThreadTurns;
|
|
89
|
+
private getOrFetchThreadTurns;
|
|
90
|
+
/**
|
|
91
|
+
* 解析本次 interrupt 应该尝试中断的 turnId 列表。
|
|
92
|
+
* 优先使用任务跟踪器提供的 active turnId;若为空,则回退为线程中最新的 turnId(尽力而为)。
|
|
93
|
+
*/
|
|
94
|
+
private resolveInterruptTurnIds;
|
|
95
|
+
/**
|
|
96
|
+
* 从线程 turns 中提取“最新一个可用的 turnId”,用于 active turnId 缺失时的保底中断。
|
|
97
|
+
* 注意:这是 best-effort,任何读取/解析异常都应返回 null,避免影响 ack 流程。
|
|
98
|
+
*/
|
|
99
|
+
private getLatestThreadTurnId;
|
|
100
|
+
private isThreadNotFoundError;
|
|
101
|
+
private recoverThreadForSubmit;
|
|
102
|
+
private rememberInterruptId;
|
|
103
|
+
private startStatusPump;
|
|
104
|
+
private sendStatus;
|
|
105
|
+
private broadcastStatus;
|
|
106
|
+
private broadcast;
|
|
107
|
+
private safeSend;
|
|
108
|
+
private handleCodexServerRequest;
|
|
109
|
+
private resolvePendingTargetUsername;
|
|
110
|
+
private setThreadOwner;
|
|
111
|
+
private pruneThreadOwnerUsernames;
|
|
112
|
+
private addUserClient;
|
|
113
|
+
private removeUserClient;
|
|
114
|
+
private isUserAuthorizedForPending;
|
|
115
|
+
private flushPendingForWs;
|
|
116
|
+
private dispatchPendingToReadyClients;
|
|
117
|
+
private broadcastUserInputResolved;
|
|
118
|
+
}
|
|
119
|
+
export {};
|