@superblocksteam/vite-plugin-file-sync 2.0.167-next.0 → 2.0.169-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ai-service/agent/middleware.d.ts.map +1 -1
- package/dist/ai-service/agent/middleware.js +23 -0
- package/dist/ai-service/agent/middleware.js.map +1 -1
- package/dist/ai-service/agent/prompts/build-base-system-prompt.js +4 -4
- package/dist/ai-service/agent/tool-message-utils.d.ts +1 -1
- package/dist/ai-service/agent/tool-message-utils.d.ts.map +1 -1
- package/dist/ai-service/agent/tool-message-utils.js.map +1 -1
- package/dist/ai-service/agent/tool-permission-delivery.d.ts +5 -4
- package/dist/ai-service/agent/tool-permission-delivery.d.ts.map +1 -1
- package/dist/ai-service/agent/tool-permission-delivery.js +22 -28
- package/dist/ai-service/agent/tool-permission-delivery.js.map +1 -1
- package/dist/ai-service/agent/tool-permission-outcome-metrics.d.ts +9 -0
- package/dist/ai-service/agent/tool-permission-outcome-metrics.d.ts.map +1 -0
- package/dist/ai-service/agent/tool-permission-outcome-metrics.js +23 -0
- package/dist/ai-service/agent/tool-permission-outcome-metrics.js.map +1 -0
- package/dist/ai-service/agent/tools/build-capture-screenshot.d.ts +44 -0
- package/dist/ai-service/agent/tools/build-capture-screenshot.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/build-capture-screenshot.js +198 -18
- package/dist/ai-service/agent/tools/build-capture-screenshot.js.map +1 -1
- package/dist/ai-service/agent/tools/build-manage-checklist.d.ts +2 -0
- package/dist/ai-service/agent/tools/build-manage-checklist.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/build-manage-checklist.js.map +1 -1
- package/dist/ai-service/agent/tools/build-reload-file.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/build-reload-file.js +32 -19
- package/dist/ai-service/agent/tools/build-reload-file.js.map +1 -1
- package/dist/ai-service/agent/tools/get-security-findings.d.ts +45 -0
- package/dist/ai-service/agent/tools/get-security-findings.d.ts.map +1 -0
- package/dist/ai-service/agent/tools/get-security-findings.js +74 -0
- package/dist/ai-service/agent/tools/get-security-findings.js.map +1 -0
- package/dist/ai-service/agent/tools/integrations/integration-setup.d.ts +2 -2
- package/dist/ai-service/agent/tools/integrations/integration-setup.d.ts.map +1 -1
- package/dist/ai-service/agent/tools/integrations/integration-setup.js +24 -2
- package/dist/ai-service/agent/tools/integrations/integration-setup.js.map +1 -1
- package/dist/ai-service/agent/tools/report-security-findings.d.ts +20 -20
- package/dist/ai-service/agent/tools.d.ts.map +1 -1
- package/dist/ai-service/agent/tools.js +13 -2
- package/dist/ai-service/agent/tools.js.map +1 -1
- package/dist/ai-service/agent/tools2/tools/exit-plan-mode.d.ts.map +1 -1
- package/dist/ai-service/agent/tools2/tools/exit-plan-mode.js +14 -0
- package/dist/ai-service/agent/tools2/tools/exit-plan-mode.js.map +1 -1
- package/dist/ai-service/agent/tools2/tools/git.d.ts +2 -1
- package/dist/ai-service/agent/tools2/tools/git.d.ts.map +1 -1
- package/dist/ai-service/agent/tools2/tools/git.js +1 -1
- package/dist/ai-service/agent/tools2/tools/git.js.map +1 -1
- package/dist/ai-service/agent/utils.d.ts.map +1 -1
- package/dist/ai-service/agent/utils.js +5 -0
- package/dist/ai-service/agent/utils.js.map +1 -1
- package/dist/ai-service/app-interface/app-package-manager.d.ts +43 -0
- package/dist/ai-service/app-interface/app-package-manager.d.ts.map +1 -0
- package/dist/ai-service/app-interface/app-package-manager.js +82 -0
- package/dist/ai-service/app-interface/app-package-manager.js.map +1 -0
- package/dist/ai-service/app-interface/constants.d.ts +2 -2
- package/dist/ai-service/app-interface/constants.d.ts.map +1 -1
- package/dist/ai-service/app-interface/constants.js +5 -0
- package/dist/ai-service/app-interface/constants.js.map +1 -1
- package/dist/ai-service/app-interface/file-system-interface.d.ts.map +1 -1
- package/dist/ai-service/app-interface/file-system-interface.js +0 -3
- package/dist/ai-service/app-interface/file-system-interface.js.map +1 -1
- package/dist/ai-service/app-interface/npm-error-parser.d.ts +1 -1
- package/dist/ai-service/app-interface/npm-error-parser.d.ts.map +1 -1
- package/dist/ai-service/app-interface/npm-error-parser.js +42 -8
- package/dist/ai-service/app-interface/npm-error-parser.js.map +1 -1
- package/dist/ai-service/app-interface/npm-registry.d.ts +30 -0
- package/dist/ai-service/app-interface/npm-registry.d.ts.map +1 -1
- package/dist/ai-service/app-interface/npm-registry.js +108 -1
- package/dist/ai-service/app-interface/npm-registry.js.map +1 -1
- package/dist/ai-service/app-interface/pnpm-lockfile.d.ts +28 -0
- package/dist/ai-service/app-interface/pnpm-lockfile.d.ts.map +1 -0
- package/dist/ai-service/app-interface/pnpm-lockfile.js +89 -0
- package/dist/ai-service/app-interface/pnpm-lockfile.js.map +1 -0
- package/dist/ai-service/app-interface/shell.d.ts +43 -7
- package/dist/ai-service/app-interface/shell.d.ts.map +1 -1
- package/dist/ai-service/app-interface/shell.js +252 -119
- package/dist/ai-service/app-interface/shell.js.map +1 -1
- package/dist/ai-service/app-interface/vulnerability-gate.d.ts +5 -0
- package/dist/ai-service/app-interface/vulnerability-gate.d.ts.map +1 -1
- package/dist/ai-service/app-interface/vulnerability-gate.js +3 -0
- package/dist/ai-service/app-interface/vulnerability-gate.js.map +1 -1
- package/dist/ai-service/app-skills/helpers.d.ts.map +1 -1
- package/dist/ai-service/app-skills/helpers.js +9 -9
- package/dist/ai-service/app-skills/helpers.js.map +1 -1
- package/dist/ai-service/chat/chat-session-store.d.ts +4 -1
- package/dist/ai-service/chat/chat-session-store.d.ts.map +1 -1
- package/dist/ai-service/chat/chat-session-store.js +4 -0
- package/dist/ai-service/chat/chat-session-store.js.map +1 -1
- package/dist/ai-service/checklist/persisted-checklist-store.d.ts +66 -1
- package/dist/ai-service/checklist/persisted-checklist-store.d.ts.map +1 -1
- package/dist/ai-service/checklist/persisted-checklist-store.js +274 -4
- package/dist/ai-service/checklist/persisted-checklist-store.js.map +1 -1
- package/dist/ai-service/checklist/policy-remediation.d.ts +8 -0
- package/dist/ai-service/checklist/policy-remediation.d.ts.map +1 -0
- package/dist/ai-service/checklist/policy-remediation.js +46 -0
- package/dist/ai-service/checklist/policy-remediation.js.map +1 -0
- package/dist/ai-service/checklist/remediation-findings-client.d.ts +31 -0
- package/dist/ai-service/checklist/remediation-findings-client.d.ts.map +1 -0
- package/dist/ai-service/checklist/remediation-findings-client.js +117 -0
- package/dist/ai-service/checklist/remediation-findings-client.js.map +1 -0
- package/dist/ai-service/context-download.d.ts.map +1 -1
- package/dist/ai-service/context-download.js +76 -37
- package/dist/ai-service/context-download.js.map +1 -1
- package/dist/ai-service/dev-database-file-sync.d.ts +2 -1
- package/dist/ai-service/dev-database-file-sync.d.ts.map +1 -1
- package/dist/ai-service/dev-database-file-sync.js.map +1 -1
- package/dist/ai-service/index.d.ts +59 -9
- package/dist/ai-service/index.d.ts.map +1 -1
- package/dist/ai-service/index.js +1191 -479
- package/dist/ai-service/index.js.map +1 -1
- package/dist/ai-service/integrations/store.d.ts.map +1 -1
- package/dist/ai-service/integrations/store.js +11 -2
- package/dist/ai-service/integrations/store.js.map +1 -1
- package/dist/ai-service/llm/context-v2/adapter.d.ts +3 -0
- package/dist/ai-service/llm/context-v2/adapter.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/adapter.js +6 -0
- package/dist/ai-service/llm/context-v2/adapter.js.map +1 -1
- package/dist/ai-service/llm/context-v2/context.d.ts +22 -1
- package/dist/ai-service/llm/context-v2/context.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/context.js +185 -30
- package/dist/ai-service/llm/context-v2/context.js.map +1 -1
- package/dist/ai-service/llm/context-v2/conversation-context.d.ts +7 -0
- package/dist/ai-service/llm/context-v2/conversation-context.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/manager.d.ts +11 -10
- package/dist/ai-service/llm/context-v2/manager.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/manager.js +128 -85
- package/dist/ai-service/llm/context-v2/manager.js.map +1 -1
- package/dist/ai-service/llm/context-v2/storage/event-store.d.ts +73 -1
- package/dist/ai-service/llm/context-v2/storage/event-store.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/storage/event-types.d.ts +152 -24
- package/dist/ai-service/llm/context-v2/storage/event-types.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/storage/event-types.js +141 -0
- package/dist/ai-service/llm/context-v2/storage/event-types.js.map +1 -1
- package/dist/ai-service/llm/context-v2/storage/jsonl-event-store.d.ts +20 -2
- package/dist/ai-service/llm/context-v2/storage/jsonl-event-store.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/storage/jsonl-event-store.js +111 -49
- package/dist/ai-service/llm/context-v2/storage/jsonl-event-store.js.map +1 -1
- package/dist/ai-service/llm/context-v2/storage/migration.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/storage/migration.js +31 -4
- package/dist/ai-service/llm/context-v2/storage/migration.js.map +1 -1
- package/dist/ai-service/llm/context-v2/token-tracker.d.ts +34 -0
- package/dist/ai-service/llm/context-v2/token-tracker.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/token-tracker.js +164 -0
- package/dist/ai-service/llm/context-v2/token-tracker.js.map +1 -1
- package/dist/ai-service/llm/context-v2/types.d.ts +5 -2
- package/dist/ai-service/llm/context-v2/types.d.ts.map +1 -1
- package/dist/ai-service/llm/context-v2/types.js +1 -1
- package/dist/ai-service/llm/context-v2/types.js.map +1 -1
- package/dist/ai-service/llm/stream/config.d.ts +7 -0
- package/dist/ai-service/llm/stream/config.d.ts.map +1 -1
- package/dist/ai-service/llm/stream/config.js +20 -2
- package/dist/ai-service/llm/stream/config.js.map +1 -1
- package/dist/ai-service/llm/stream/orchestrator.d.ts.map +1 -1
- package/dist/ai-service/llm/stream/orchestrator.js +30 -14
- package/dist/ai-service/llm/stream/orchestrator.js.map +1 -1
- package/dist/ai-service/llm/stream/session.d.ts +1 -1
- package/dist/ai-service/llm/stream/session.d.ts.map +1 -1
- package/dist/ai-service/llm/stream/session.js +1 -1
- package/dist/ai-service/llm/stream/session.js.map +1 -1
- package/dist/ai-service/migration-llm-config.d.ts.map +1 -1
- package/dist/ai-service/migration-llm-config.js +13 -71
- package/dist/ai-service/migration-llm-config.js.map +1 -1
- package/dist/ai-service/security/secret-scanner-service.d.ts.map +1 -1
- package/dist/ai-service/security/secret-scanner-service.js +12 -2
- package/dist/ai-service/security/secret-scanner-service.js.map +1 -1
- package/dist/ai-service/security/secret-scanner.d.ts +1 -1
- package/dist/ai-service/security/secret-scanner.d.ts.map +1 -1
- package/dist/ai-service/security/secret-scanner.js +4 -1
- package/dist/ai-service/security/secret-scanner.js.map +1 -1
- package/dist/ai-service/security/vulnerability-triage.d.ts +2 -2
- package/dist/ai-service/state-machine/clark-fsm.d.ts +17 -1
- package/dist/ai-service/state-machine/clark-fsm.d.ts.map +1 -1
- package/dist/ai-service/state-machine/clark-fsm.js +85 -8
- package/dist/ai-service/state-machine/clark-fsm.js.map +1 -1
- package/dist/ai-service/state-machine/handlers/agent-planning.d.ts.map +1 -1
- package/dist/ai-service/state-machine/handlers/agent-planning.js +97 -47
- package/dist/ai-service/state-machine/handlers/agent-planning.js.map +1 -1
- package/dist/ai-service/state-machine/handlers/awaiting-user.d.ts.map +1 -1
- package/dist/ai-service/state-machine/handlers/awaiting-user.js +68 -50
- package/dist/ai-service/state-machine/handlers/awaiting-user.js.map +1 -1
- package/dist/ai-service/state-machine/handlers/llm-generating.d.ts.map +1 -1
- package/dist/ai-service/state-machine/handlers/llm-generating.js +91 -73
- package/dist/ai-service/state-machine/handlers/llm-generating.js.map +1 -1
- package/dist/ai-service/state-machine/helpers/prompt-failure.d.ts +1 -1
- package/dist/ai-service/state-machine/helpers/prompt-failure.d.ts.map +1 -1
- package/dist/ai-service/state-machine/helpers/prompt-failure.js +1 -0
- package/dist/ai-service/state-machine/helpers/prompt-failure.js.map +1 -1
- package/dist/ai-service/state-machine/helpers/prompt-request-metrics.d.ts +2 -1
- package/dist/ai-service/state-machine/helpers/prompt-request-metrics.d.ts.map +1 -1
- package/dist/ai-service/state-machine/helpers/prompt-request-metrics.js +1 -0
- package/dist/ai-service/state-machine/helpers/prompt-request-metrics.js.map +1 -1
- package/dist/ai-service/state-machine/helpers/user-response-message.d.ts +4 -0
- package/dist/ai-service/state-machine/helpers/user-response-message.d.ts.map +1 -0
- package/dist/ai-service/state-machine/helpers/user-response-message.js +37 -0
- package/dist/ai-service/state-machine/helpers/user-response-message.js.map +1 -0
- package/dist/ai-service/template-renderer.d.ts.map +1 -1
- package/dist/ai-service/template-renderer.js +22 -9
- package/dist/ai-service/template-renderer.js.map +1 -1
- package/dist/ai-service/types.d.ts +2 -1
- package/dist/ai-service/types.d.ts.map +1 -1
- package/dist/ai-service/types.js.map +1 -1
- package/dist/components-manager.d.ts +9 -2
- package/dist/components-manager.d.ts.map +1 -1
- package/dist/components-manager.js +0 -4
- package/dist/components-manager.js.map +1 -1
- package/dist/file-sync-vite-plugin.d.ts.map +1 -1
- package/dist/file-sync-vite-plugin.js +4 -8
- package/dist/file-sync-vite-plugin.js.map +1 -1
- package/dist/file-system-helpers.d.ts +14 -0
- package/dist/file-system-helpers.d.ts.map +1 -1
- package/dist/file-system-helpers.js +22 -1
- package/dist/file-system-helpers.js.map +1 -1
- package/dist/file-system-manager.d.ts +12 -1
- package/dist/file-system-manager.d.ts.map +1 -1
- package/dist/file-system-manager.js +42 -22
- package/dist/file-system-manager.js.map +1 -1
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/lock-service/index.d.ts +20 -0
- package/dist/lock-service/index.d.ts.map +1 -1
- package/dist/lock-service/index.js +53 -5
- package/dist/lock-service/index.js.map +1 -1
- package/dist/migration/get-fullstack-template-dir.js +2 -2
- package/dist/migration/get-fullstack-template-dir.js.map +1 -1
- package/dist/migration/migration-routes.d.ts.map +1 -1
- package/dist/migration/migration-routes.js +8 -2
- package/dist/migration/migration-routes.js.map +1 -1
- package/dist/plugin-options.d.ts +1 -0
- package/dist/plugin-options.d.ts.map +1 -1
- package/dist/plugin-options.js.map +1 -1
- package/dist/router-parser.d.ts.map +1 -1
- package/dist/router-parser.js +336 -65
- package/dist/router-parser.js.map +1 -1
- package/dist/socket-manager.d.ts +25 -2
- package/dist/socket-manager.d.ts.map +1 -1
- package/dist/socket-manager.js +270 -55
- package/dist/socket-manager.js.map +1 -1
- package/dist/split-edit-after-clark.d.ts +14 -0
- package/dist/split-edit-after-clark.d.ts.map +1 -0
- package/dist/split-edit-after-clark.js +40 -0
- package/dist/split-edit-after-clark.js.map +1 -0
- package/dist/sync-service/index.d.ts +2 -1
- package/dist/sync-service/index.d.ts.map +1 -1
- package/dist/sync-service/index.js +5 -0
- package/dist/sync-service/index.js.map +1 -1
- package/dist/sync-service/list-dir.d.ts.map +1 -1
- package/dist/sync-service/list-dir.js +9 -4
- package/dist/sync-service/list-dir.js.map +1 -1
- package/dist/util/log-sanitizer.d.ts.map +1 -1
- package/dist/util/log-sanitizer.js +4 -0
- package/dist/util/log-sanitizer.js.map +1 -1
- package/dist/vite-module-reload.d.ts +34 -0
- package/dist/vite-module-reload.d.ts.map +1 -0
- package/dist/vite-module-reload.js +121 -0
- package/dist/vite-module-reload.js.map +1 -0
- package/package.json +10 -9
package/dist/socket-manager.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
1
|
+
import { randomUUID, timingSafeEqual } from "node:crypto";
|
|
2
2
|
import { cp, mkdir, mkdtemp, rm } from "node:fs/promises";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { metrics } from "@opentelemetry/api";
|
|
6
|
-
import { WebSocketServer } from "ws";
|
|
6
|
+
import { WebSocket, WebSocketServer } from "ws";
|
|
7
7
|
import { createISocketClient, DEFAULT_NON_GIT_BRANCH, MAX_SOCKET_PAYLOAD_BYTES, SocketErrorException, SUPERBLOCKS_LIVE_GIT_BRANCH, TracedEventEmitter, TracedSocket, } from "@superblocksteam/shared";
|
|
8
8
|
import { uploadCheckpointScreenshot } from "./ai-service/checkpoint-screenshot.js";
|
|
9
9
|
import { uploadContextToBucketeer } from "./ai-service/context-upload.js";
|
|
@@ -18,6 +18,7 @@ import { GitConflictError, isMissingGitRevisionError, } from "./git-service/inde
|
|
|
18
18
|
import { doesRemoteLiveBranchExist, ensureLiveBranchCheckedOut, pushLiveBranchWithAutoRecreate, rollbackLastCommit, } from "./git-service/live-branch.js";
|
|
19
19
|
import { ensureProviderWorkflowFiles } from "./git-service/provider-workflow-files.js";
|
|
20
20
|
import { getSyncCountsAgainstDefaultBranch } from "./git-service/status-sync.js";
|
|
21
|
+
import { SplitEditAfterClark } from "./split-edit-after-clark.js";
|
|
21
22
|
import { getErrorMeta, getLogger } from "./util/logger.js";
|
|
22
23
|
import { OperationQueue } from "./util/operation-queue.js";
|
|
23
24
|
const SB_WORKTREE_SNAPSHOTS_DIR = join(tmpdir(), "sb-worktree-snapshots");
|
|
@@ -42,6 +43,55 @@ function extractCallerUserId(peerAuthorization) {
|
|
|
42
43
|
}
|
|
43
44
|
const EDITOR_PROTOCOL = "editor";
|
|
44
45
|
const GATEWAY_PROTOCOL = "gateway";
|
|
46
|
+
const AI_SERVICE_PROTOCOL = "ai-service";
|
|
47
|
+
const INTERNAL_METHODS = new Set([
|
|
48
|
+
"editor.internalApplyDraftChanges",
|
|
49
|
+
"editor.internalCreateDraftMarkerOnly",
|
|
50
|
+
"editor.internalHasDraftChanges",
|
|
51
|
+
"editor.internalGetBranchName",
|
|
52
|
+
"editor.internalUploadDirectory",
|
|
53
|
+
"editor.internalSyncCurrentDirectoryWithDraftsNow",
|
|
54
|
+
"editor.internalGetDraftDiff",
|
|
55
|
+
"editor.internalGetDraftChanges",
|
|
56
|
+
"editor.internalAcquireTurnLock",
|
|
57
|
+
"editor.internalReleaseTurnLock",
|
|
58
|
+
]);
|
|
59
|
+
const AI_SERVICE_METHODS = new Set([
|
|
60
|
+
...INTERNAL_METHODS,
|
|
61
|
+
"editor.aiAcceptDraft",
|
|
62
|
+
"editor.aiRejectDraft",
|
|
63
|
+
"editor.aiCancel",
|
|
64
|
+
"editor.aiClearDraftState",
|
|
65
|
+
]);
|
|
66
|
+
function decodeDraftBinary(value) {
|
|
67
|
+
const content = Buffer.from(value, "base64");
|
|
68
|
+
if (content.toString("base64") !== value) {
|
|
69
|
+
throw new SocketErrorException(400, "Invalid draft binary content");
|
|
70
|
+
}
|
|
71
|
+
return content;
|
|
72
|
+
}
|
|
73
|
+
function uploadAcceptedDraftContext(aiService, applicationId, commitId, branchName, peerAuthorization) {
|
|
74
|
+
void (async () => {
|
|
75
|
+
const contextId = aiService.getContextId();
|
|
76
|
+
if (!contextId)
|
|
77
|
+
return;
|
|
78
|
+
const jwt = aiService.getClarkJwt() || peerAuthorization?.replace("Bearer ", "");
|
|
79
|
+
if (!jwt)
|
|
80
|
+
return;
|
|
81
|
+
await uploadContextToBucketeer({
|
|
82
|
+
applicationId,
|
|
83
|
+
commitId,
|
|
84
|
+
branchName,
|
|
85
|
+
appRootDirPath: aiService.appRootDirPath,
|
|
86
|
+
useServerUpload: aiService.isAiFileUploadEnabled,
|
|
87
|
+
superblocksBaseUrl: aiService.superblocksBaseUrl,
|
|
88
|
+
logger: getLogger(),
|
|
89
|
+
jwt,
|
|
90
|
+
});
|
|
91
|
+
})().catch((error) => {
|
|
92
|
+
getLogger().warn("[aiAcceptDraft] Failed to upload context to bucketeer (non-blocking)", getErrorMeta(error));
|
|
93
|
+
});
|
|
94
|
+
}
|
|
45
95
|
/**
|
|
46
96
|
* Subprotocols the dev server answers with. The library runtime offers none at
|
|
47
97
|
* all and connects on that basis; there is no `library` protocol to negotiate.
|
|
@@ -52,6 +102,7 @@ const GATEWAY_PROTOCOL = "gateway";
|
|
|
52
102
|
const NEGOTIABLE_PROTOCOLS = [
|
|
53
103
|
EDITOR_PROTOCOL,
|
|
54
104
|
GATEWAY_PROTOCOL,
|
|
105
|
+
AI_SERVICE_PROTOCOL,
|
|
55
106
|
];
|
|
56
107
|
function selectProtocol(offered) {
|
|
57
108
|
for (const protocol of offered) {
|
|
@@ -81,6 +132,9 @@ export function classifyConnectionKind(offeredProtocols) {
|
|
|
81
132
|
if (selected === EDITOR_PROTOCOL) {
|
|
82
133
|
return "editor";
|
|
83
134
|
}
|
|
135
|
+
if (selected === AI_SERVICE_PROTOCOL) {
|
|
136
|
+
return "ai-service";
|
|
137
|
+
}
|
|
84
138
|
return "unsupported";
|
|
85
139
|
}
|
|
86
140
|
/**
|
|
@@ -132,6 +186,9 @@ export function disposeSocketManager() {
|
|
|
132
186
|
_socketManager?.dispose();
|
|
133
187
|
_socketManager = undefined;
|
|
134
188
|
}
|
|
189
|
+
export async function closeAllSocketClients() {
|
|
190
|
+
await _socketManager?.closeAllClientsGracefully();
|
|
191
|
+
}
|
|
135
192
|
class SocketManager extends TracedEventEmitter {
|
|
136
193
|
peerLiveness = new PeerLiveness();
|
|
137
194
|
socketLiveness = new WeakMap();
|
|
@@ -174,10 +231,13 @@ class SocketManager extends TracedEventEmitter {
|
|
|
174
231
|
super(tracer);
|
|
175
232
|
}
|
|
176
233
|
socketServer;
|
|
177
|
-
startSocketServer({ server, fileSyncManager, syncService, lockService, aiService, gitService, gitBootstrapAuthFailed, gitBootstrapFailed, activateGitService, refreshGitCredentials, checkAuthorization, path, tracer, gitOperationLock, superblocksBaseUrl, maxPayloadBytes = MAX_SOCKET_PAYLOAD_BYTES, }) {
|
|
234
|
+
startSocketServer({ server, applicationId, internalToken, fileSyncManager, syncService, draftClient, lockService, aiService, gitService, gitBootstrapAuthFailed, gitBootstrapFailed, activateGitService, refreshGitCredentials, checkAuthorization, onAuthenticated, path, tracer, gitOperationLock, superblocksBaseUrl, maxPayloadBytes = MAX_SOCKET_PAYLOAD_BYTES, }) {
|
|
178
235
|
if (this.socketServer) {
|
|
179
236
|
throw new Error("Socket server already started");
|
|
180
237
|
}
|
|
238
|
+
const splitEditAfterClark = syncService && !aiService
|
|
239
|
+
? new SplitEditAfterClark(syncService)
|
|
240
|
+
: undefined;
|
|
181
241
|
const wss = new WebSocketServer({
|
|
182
242
|
path,
|
|
183
243
|
noServer: true,
|
|
@@ -224,8 +284,9 @@ class SocketManager extends TracedEventEmitter {
|
|
|
224
284
|
return;
|
|
225
285
|
}
|
|
226
286
|
try {
|
|
227
|
-
|
|
228
|
-
(!ownedTurns.includes(owner) || owner.peerId !== peerId))
|
|
287
|
+
const stillNeeded = () => headlessLockOwners.some((owner) => !owner.handbackFailed &&
|
|
288
|
+
(!ownedTurns.includes(owner) || owner.peerId !== peerId));
|
|
289
|
+
await lockService?.relinquishLockForTurn(stillNeeded);
|
|
229
290
|
}
|
|
230
291
|
catch (error) {
|
|
231
292
|
await headlessLockOperationQueue.enqueue(async () => {
|
|
@@ -281,8 +342,9 @@ class SocketManager extends TracedEventEmitter {
|
|
|
281
342
|
return true;
|
|
282
343
|
}
|
|
283
344
|
try {
|
|
284
|
-
|
|
285
|
-
(owner !== ownedTurn || owner.peerId !== peerId))
|
|
345
|
+
const stillNeeded = () => headlessLockOwners.some((owner) => !owner.handbackFailed &&
|
|
346
|
+
(owner !== ownedTurn || owner.peerId !== peerId));
|
|
347
|
+
await lockService?.relinquishLockForTurn(stillNeeded);
|
|
286
348
|
}
|
|
287
349
|
catch (error) {
|
|
288
350
|
await headlessLockOperationQueue.enqueue(async () => {
|
|
@@ -411,7 +473,7 @@ class SocketManager extends TracedEventEmitter {
|
|
|
411
473
|
// because the dev server's own auto-commit pushes to the same remote with
|
|
412
474
|
// the same credential and has to be able to report a rejection too.
|
|
413
475
|
clearGitAuthFailed();
|
|
414
|
-
const getActiveGitService = async () => {
|
|
476
|
+
const getActiveGitService = async (options) => {
|
|
415
477
|
if (disconnectInProgress) {
|
|
416
478
|
return undefined;
|
|
417
479
|
}
|
|
@@ -448,6 +510,11 @@ class SocketManager extends TracedEventEmitter {
|
|
|
448
510
|
aiService?.setRuntimeGitServices(activeGitService, syncService, gitOperationLock);
|
|
449
511
|
return activeGitService;
|
|
450
512
|
}
|
|
513
|
+
// No remote. A failed startup bootstrap resolves `undefined` too;
|
|
514
|
+
// `gitBootstrapFailed` is what keeps those apps on the retry loop.
|
|
515
|
+
if (!options?.retryWhenUnconfigured && !gitBootstrapFailed) {
|
|
516
|
+
return undefined;
|
|
517
|
+
}
|
|
451
518
|
}
|
|
452
519
|
catch (error) {
|
|
453
520
|
getLogger().warn("[git] activation attempt failed", {
|
|
@@ -525,17 +592,24 @@ class SocketManager extends TracedEventEmitter {
|
|
|
525
592
|
ws.close(1002, "Unsupported subprotocol");
|
|
526
593
|
return;
|
|
527
594
|
}
|
|
595
|
+
if (kind === "ai-service" &&
|
|
596
|
+
(req.headers.origin !== undefined ||
|
|
597
|
+
!["127.0.0.1", "::1", "::ffff:127.0.0.1"].includes(req.socket.remoteAddress ?? ""))) {
|
|
598
|
+
ws.close(1008, "Internal access denied");
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
528
601
|
const peerId = url.searchParams.get("peerId");
|
|
529
602
|
if (!peerId) {
|
|
530
603
|
getLogger().error("No peerId in upgrade request");
|
|
531
604
|
ws.close(1008, "No peerId found");
|
|
532
605
|
return;
|
|
533
606
|
}
|
|
534
|
-
|
|
607
|
+
const expectedApplicationId = applicationId ?? syncService?.applicationId;
|
|
608
|
+
if (url.searchParams.get("applicationId") !== expectedApplicationId) {
|
|
535
609
|
getLogger().error("Application ID mismatch", {
|
|
536
610
|
error: {
|
|
537
611
|
kind: "ValidationError",
|
|
538
|
-
message: `Expected application ID ${
|
|
612
|
+
message: `Expected application ID ${expectedApplicationId}, received ${url.searchParams.get("applicationId")}`,
|
|
539
613
|
},
|
|
540
614
|
});
|
|
541
615
|
ws.close(1008, "Application ID mismatch");
|
|
@@ -560,6 +634,19 @@ class SocketManager extends TracedEventEmitter {
|
|
|
560
634
|
if (connectionLiveness) {
|
|
561
635
|
ws.on("message", () => connectionLiveness.markInbound());
|
|
562
636
|
}
|
|
637
|
+
const gatewayLivenessTimer = kind === "gateway" &&
|
|
638
|
+
!lockService &&
|
|
639
|
+
draftClient &&
|
|
640
|
+
connectionLiveness
|
|
641
|
+
? setInterval(() => {
|
|
642
|
+
if (!connectionLiveness.observe().available &&
|
|
643
|
+
headlessLockOwners.some((owner) => owner.peerId === peerId)) {
|
|
644
|
+
dropHeadlessLockOwnersInBackground(peerId, "gateway liveness lapsed");
|
|
645
|
+
aiService?.endHeadlessTurn(peerId, connectionLiveness);
|
|
646
|
+
}
|
|
647
|
+
}, 30_000)
|
|
648
|
+
: undefined;
|
|
649
|
+
gatewayLivenessTimer?.unref();
|
|
563
650
|
/**
|
|
564
651
|
* When an editor authenticates after git was enabled, the lock may
|
|
565
652
|
* still be on 'main'. This calls
|
|
@@ -578,10 +665,33 @@ class SocketManager extends TracedEventEmitter {
|
|
|
578
665
|
? ++nextEditorConnectionSequence
|
|
579
666
|
: 0;
|
|
580
667
|
const authMiddleware = async (params, ctx, _peer, next) => {
|
|
668
|
+
if (kind === "ai-service") {
|
|
669
|
+
const expected = internalToken?.();
|
|
670
|
+
const provided = ctx.peerAuthorization?.startsWith("Bearer ")
|
|
671
|
+
? ctx.peerAuthorization.slice(7)
|
|
672
|
+
: undefined;
|
|
673
|
+
const expectedBytes = Buffer.from(expected ?? "");
|
|
674
|
+
const providedBytes = Buffer.from(provided ?? "");
|
|
675
|
+
const hasInternalToken = !!expected &&
|
|
676
|
+
!!provided &&
|
|
677
|
+
expectedBytes.length === providedBytes.length &&
|
|
678
|
+
timingSafeEqual(expectedBytes, providedBytes);
|
|
679
|
+
if (!AI_SERVICE_METHODS.has(ctx.method) ||
|
|
680
|
+
(!hasInternalToken &&
|
|
681
|
+
!(await checkAuthorization(ctx.peerAuthorization)).success)) {
|
|
682
|
+
throw new SocketErrorException(403, "Internal access denied");
|
|
683
|
+
}
|
|
684
|
+
return await next();
|
|
685
|
+
}
|
|
686
|
+
if (INTERNAL_METHODS.has(ctx.method)) {
|
|
687
|
+
throw new SocketErrorException(403, "Internal access denied");
|
|
688
|
+
}
|
|
581
689
|
const result = await checkAuthorization(ctx.peerAuthorization);
|
|
582
690
|
if (!result.success) {
|
|
583
691
|
throw new SocketErrorException(result.status, result.error);
|
|
584
692
|
}
|
|
693
|
+
if (ctx.peerAuthorization)
|
|
694
|
+
onAuthenticated?.(ctx.peerAuthorization);
|
|
585
695
|
if (isEditor && this.editorSockets.has(socket)) {
|
|
586
696
|
this.authenticatedEditorSockets.add(socket);
|
|
587
697
|
}
|
|
@@ -722,6 +832,94 @@ class SocketManager extends TracedEventEmitter {
|
|
|
722
832
|
const middlewares = [recordingMiddleware, authMiddleware].filter((m) => m != null);
|
|
723
833
|
const socket = createISocketClient(new TracedSocket(ws, {
|
|
724
834
|
editor: {
|
|
835
|
+
internalApplyDraftChanges: [
|
|
836
|
+
async ({ changes }) => {
|
|
837
|
+
if (!syncService) {
|
|
838
|
+
throw new Error("Sync service not available");
|
|
839
|
+
}
|
|
840
|
+
await syncService.applyDraftChanges(changes.map(({ filePath, content }) => ({
|
|
841
|
+
filePath,
|
|
842
|
+
...(content && {
|
|
843
|
+
content: content.kind === "binary"
|
|
844
|
+
? decodeDraftBinary(content.value)
|
|
845
|
+
: content.value,
|
|
846
|
+
}),
|
|
847
|
+
})));
|
|
848
|
+
},
|
|
849
|
+
],
|
|
850
|
+
internalCreateDraftMarkerOnly: [
|
|
851
|
+
async ({ filePath }) => {
|
|
852
|
+
if (!syncService)
|
|
853
|
+
throw new Error("Sync service not available");
|
|
854
|
+
await syncService.createDraftMarkerOnly(filePath);
|
|
855
|
+
},
|
|
856
|
+
],
|
|
857
|
+
internalHasDraftChanges: [
|
|
858
|
+
async () => {
|
|
859
|
+
if (!syncService)
|
|
860
|
+
throw new Error("Sync service not available");
|
|
861
|
+
return await syncService.hasLocalDraftChanges();
|
|
862
|
+
},
|
|
863
|
+
],
|
|
864
|
+
internalGetBranchName: [
|
|
865
|
+
async () => {
|
|
866
|
+
if (!syncService)
|
|
867
|
+
throw new Error("Sync service not available");
|
|
868
|
+
return syncService.branchName;
|
|
869
|
+
},
|
|
870
|
+
],
|
|
871
|
+
internalUploadDirectory: [
|
|
872
|
+
async ({ source }) => {
|
|
873
|
+
if (!syncService)
|
|
874
|
+
throw new Error("Sync service not available");
|
|
875
|
+
await syncService.uploadDirectory(source);
|
|
876
|
+
},
|
|
877
|
+
],
|
|
878
|
+
internalSyncCurrentDirectoryWithDraftsNow: [
|
|
879
|
+
async ({ source }) => {
|
|
880
|
+
if (!syncService)
|
|
881
|
+
throw new Error("Sync service not available");
|
|
882
|
+
return await syncService.syncCurrentDirectoryWithDraftsNow(source);
|
|
883
|
+
},
|
|
884
|
+
],
|
|
885
|
+
internalGetDraftDiff: [
|
|
886
|
+
async ({ paths }) => {
|
|
887
|
+
if (!syncService)
|
|
888
|
+
throw new Error("Sync service not available");
|
|
889
|
+
return await syncService.getDraftDiff(paths);
|
|
890
|
+
},
|
|
891
|
+
],
|
|
892
|
+
internalGetDraftChanges: [
|
|
893
|
+
async () => {
|
|
894
|
+
if (!syncService)
|
|
895
|
+
throw new Error("Sync service not available");
|
|
896
|
+
return await syncService.getDraftChanges();
|
|
897
|
+
},
|
|
898
|
+
],
|
|
899
|
+
internalAcquireTurnLock: [
|
|
900
|
+
async (request) => {
|
|
901
|
+
if (!lockService)
|
|
902
|
+
throw new Error("Lock service not available");
|
|
903
|
+
await lockService.acquireLockForTurn();
|
|
904
|
+
lockService.markGatewayAttached("ai-service");
|
|
905
|
+
if (request?.promptId) {
|
|
906
|
+
await splitEditAfterClark?.startTurn(request.promptId, request.chatSessionId);
|
|
907
|
+
}
|
|
908
|
+
},
|
|
909
|
+
],
|
|
910
|
+
internalReleaseTurnLock: [
|
|
911
|
+
async (request) => {
|
|
912
|
+
if (!lockService)
|
|
913
|
+
throw new Error("Lock service not available");
|
|
914
|
+
if (request?.promptId) {
|
|
915
|
+
void splitEditAfterClark
|
|
916
|
+
?.endTurn(request.promptId)
|
|
917
|
+
.catch((error) => getLogger().warn("Could not finish edit-after-Clark measurement", getErrorMeta(error)));
|
|
918
|
+
}
|
|
919
|
+
await lockService.relinquishLockForTurn();
|
|
920
|
+
lockService.markGatewayDetached("ai-service");
|
|
921
|
+
},
|
|
922
|
+
],
|
|
725
923
|
// Renames
|
|
726
924
|
renameElement: [fileSyncManager.handleRenameElement],
|
|
727
925
|
renameApi: [fileSyncManager.handleRenameApi],
|
|
@@ -740,12 +938,18 @@ class SocketManager extends TracedEventEmitter {
|
|
|
740
938
|
// AI + draft handling
|
|
741
939
|
aiGenerate: [
|
|
742
940
|
async (request) => {
|
|
941
|
+
if (kind === "ai-service") {
|
|
942
|
+
throw new Error("Internal client cannot start AI generation");
|
|
943
|
+
}
|
|
743
944
|
const inputSource = { kind, peerId };
|
|
744
945
|
await aiService?.handleAiGenerate(request, inputSource);
|
|
745
946
|
},
|
|
746
947
|
],
|
|
747
948
|
aiGenerateWithQueue: [
|
|
748
949
|
async (request) => {
|
|
950
|
+
if (kind === "ai-service") {
|
|
951
|
+
throw new Error("Internal client cannot start AI generation");
|
|
952
|
+
}
|
|
749
953
|
if (!aiService) {
|
|
750
954
|
throw new Error("AI service not available");
|
|
751
955
|
}
|
|
@@ -835,12 +1039,30 @@ class SocketManager extends TracedEventEmitter {
|
|
|
835
1039
|
],
|
|
836
1040
|
aiRejectDraft: [
|
|
837
1041
|
async (request) => {
|
|
1042
|
+
if (draftClient) {
|
|
1043
|
+
await draftClient.rejectDraft(request);
|
|
1044
|
+
await aiService?.handleUserRejectedDraft(request.silently);
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
838
1047
|
await syncService?.discardLocalDraftChanges("ai:reject");
|
|
1048
|
+
splitEditAfterClark?.discardLastTurn();
|
|
839
1049
|
await aiService?.handleUserRejectedDraft(request.silently);
|
|
840
1050
|
},
|
|
841
1051
|
],
|
|
842
1052
|
aiAcceptDraft: [
|
|
843
1053
|
async (request, _context) => {
|
|
1054
|
+
if (draftClient) {
|
|
1055
|
+
const result = await draftClient.acceptDraft(request);
|
|
1056
|
+
await aiService?.handleUserAcceptedDraft(request.silently);
|
|
1057
|
+
const appId = applicationId ?? syncService?.applicationId;
|
|
1058
|
+
if (result.commitId && aiService && appId) {
|
|
1059
|
+
uploadAcceptedDraftContext(aiService, appId, result.commitId, result.branchName, _context.peerAuthorization);
|
|
1060
|
+
}
|
|
1061
|
+
return {
|
|
1062
|
+
commitId: result.commitId,
|
|
1063
|
+
...(result.warning && { warning: result.warning }),
|
|
1064
|
+
};
|
|
1065
|
+
}
|
|
844
1066
|
if (!syncService) {
|
|
845
1067
|
throw new Error("Sync service not available");
|
|
846
1068
|
}
|
|
@@ -887,47 +1109,8 @@ class SocketManager extends TracedEventEmitter {
|
|
|
887
1109
|
});
|
|
888
1110
|
}
|
|
889
1111
|
if (result?.commitId) {
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
void (async () => {
|
|
893
|
-
try {
|
|
894
|
-
// Get contextId using the same pattern as other context operations
|
|
895
|
-
// This gets userId from clark.context.jwt
|
|
896
|
-
const contextId = aiService.getContextId();
|
|
897
|
-
if (!contextId) {
|
|
898
|
-
getLogger().warn("[aiAcceptDraft] No contextId available (JWT missing or no userId), skipping context upload");
|
|
899
|
-
return;
|
|
900
|
-
}
|
|
901
|
-
// Get JWT from clark context (same source as userId)
|
|
902
|
-
// We need to access it via a method or use peer authorization as fallback
|
|
903
|
-
const jwt = aiService.getClarkJwt() ||
|
|
904
|
-
_context.peerAuthorization?.replace("Bearer ", "");
|
|
905
|
-
if (!jwt) {
|
|
906
|
-
getLogger().warn("[aiAcceptDraft] No JWT found, skipping context upload");
|
|
907
|
-
return;
|
|
908
|
-
}
|
|
909
|
-
await uploadContextToBucketeer({
|
|
910
|
-
applicationId: syncService.applicationId,
|
|
911
|
-
commitId: result.commitId,
|
|
912
|
-
branchName: syncService.branchName,
|
|
913
|
-
appRootDirPath: aiService.appRootDirPath,
|
|
914
|
-
useServerUpload: aiService.isAiFileUploadEnabled,
|
|
915
|
-
superblocksBaseUrl: aiService.superblocksBaseUrl,
|
|
916
|
-
logger: getLogger(),
|
|
917
|
-
jwt,
|
|
918
|
-
});
|
|
919
|
-
getLogger().info("[aiAcceptDraft] context upload completed", {
|
|
920
|
-
applicationId: syncService.applicationId,
|
|
921
|
-
branchName: syncService.branchName,
|
|
922
|
-
commitId: result.commitId,
|
|
923
|
-
contextUserId: contextId.userId,
|
|
924
|
-
});
|
|
925
|
-
}
|
|
926
|
-
catch (error) {
|
|
927
|
-
getLogger().warn("[aiAcceptDraft] Failed to upload context to bucketeer (non-blocking)", getErrorMeta(error));
|
|
928
|
-
// Don't throw - this is fire-and-forget
|
|
929
|
-
}
|
|
930
|
-
})();
|
|
1112
|
+
if (aiService) {
|
|
1113
|
+
uploadAcceptedDraftContext(aiService, syncService.applicationId, result.commitId, syncService.branchName, _context.peerAuthorization);
|
|
931
1114
|
}
|
|
932
1115
|
return draftStateCleared === true
|
|
933
1116
|
? { commitId: result.commitId }
|
|
@@ -966,13 +1149,23 @@ class SocketManager extends TracedEventEmitter {
|
|
|
966
1149
|
],
|
|
967
1150
|
aiClearDraftState: [
|
|
968
1151
|
async () => {
|
|
969
|
-
|
|
1152
|
+
if (draftClient) {
|
|
1153
|
+
await draftClient.clearDraftState();
|
|
1154
|
+
}
|
|
1155
|
+
else {
|
|
1156
|
+
await syncService?.clearDraftsDirectory();
|
|
1157
|
+
}
|
|
970
1158
|
},
|
|
971
1159
|
],
|
|
972
1160
|
aiCancel: [
|
|
973
1161
|
async (request) => {
|
|
974
1162
|
await aiService?.handleUserCanceled(request?.reason);
|
|
975
|
-
|
|
1163
|
+
if (draftClient) {
|
|
1164
|
+
await draftClient.reportDraftStateCleared();
|
|
1165
|
+
}
|
|
1166
|
+
else {
|
|
1167
|
+
await syncService?.reportDraftStateToServer(false);
|
|
1168
|
+
}
|
|
976
1169
|
},
|
|
977
1170
|
],
|
|
978
1171
|
aiNotifyIntegrationSetupClosed: [
|
|
@@ -1039,8 +1232,10 @@ class SocketManager extends TracedEventEmitter {
|
|
|
1039
1232
|
const messages = await aiService?.chatSessionStore.getMessages({
|
|
1040
1233
|
force: request?.force,
|
|
1041
1234
|
});
|
|
1235
|
+
aiService?.applyEditorContextOptions?.(request?.contextOptionsV2);
|
|
1042
1236
|
return {
|
|
1043
1237
|
messages: messages ?? [],
|
|
1238
|
+
...aiService?.getChatStateSnapshot(),
|
|
1044
1239
|
};
|
|
1045
1240
|
},
|
|
1046
1241
|
],
|
|
@@ -1463,7 +1658,9 @@ class SocketManager extends TracedEventEmitter {
|
|
|
1463
1658
|
// would be stuck with git permanently disabled.
|
|
1464
1659
|
disconnectInProgress = false;
|
|
1465
1660
|
clearGitAuthFailed();
|
|
1466
|
-
const service = await getActiveGitService(
|
|
1661
|
+
const service = await getActiveGitService({
|
|
1662
|
+
retryWhenUnconfigured: true,
|
|
1663
|
+
});
|
|
1467
1664
|
return { activated: !!service };
|
|
1468
1665
|
}),
|
|
1469
1666
|
],
|
|
@@ -1802,12 +1999,13 @@ class SocketManager extends TracedEventEmitter {
|
|
|
1802
1999
|
// Git activation is deliberately NOT started here — it runs from the
|
|
1803
2000
|
// auth middleware, after presence. See `activateGitForAuthedEditor`.
|
|
1804
2001
|
}
|
|
1805
|
-
else {
|
|
2002
|
+
else if (kind === "library") {
|
|
1806
2003
|
this.librarySockets.add(socket);
|
|
1807
2004
|
this.emit("connect:library", socket);
|
|
1808
2005
|
}
|
|
1809
2006
|
existingSockets.add(socket);
|
|
1810
2007
|
ws.on("close", (code, reason) => {
|
|
2008
|
+
clearInterval(gatewayLivenessTimer);
|
|
1811
2009
|
connectionLiveness?.close();
|
|
1812
2010
|
const peerSockets = this.peerIds.get(peerId);
|
|
1813
2011
|
peerSockets?.delete(socket);
|
|
@@ -2133,6 +2331,23 @@ class SocketManager extends TracedEventEmitter {
|
|
|
2133
2331
|
socket.close();
|
|
2134
2332
|
}
|
|
2135
2333
|
}
|
|
2334
|
+
async closeAllClientsGracefully() {
|
|
2335
|
+
await Promise.all(Array.from(this.socketServer?.clients ?? []).map((socket) => new Promise((resolve) => {
|
|
2336
|
+
if (socket.readyState === WebSocket.CLOSED) {
|
|
2337
|
+
resolve();
|
|
2338
|
+
return;
|
|
2339
|
+
}
|
|
2340
|
+
const timeout = setTimeout(() => {
|
|
2341
|
+
socket.terminate();
|
|
2342
|
+
resolve();
|
|
2343
|
+
}, 1_000);
|
|
2344
|
+
socket.once("close", () => {
|
|
2345
|
+
clearTimeout(timeout);
|
|
2346
|
+
resolve();
|
|
2347
|
+
});
|
|
2348
|
+
socket.close(1001, "Server shutting down");
|
|
2349
|
+
})));
|
|
2350
|
+
}
|
|
2136
2351
|
dispose() {
|
|
2137
2352
|
this._disposer();
|
|
2138
2353
|
}
|