mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-18 21:22:28 +03:00
fix(types): type Copilot WebSocket construction (#9974)
This commit is contained in:
@@ -67,6 +67,11 @@ interface CopilotWsEvent {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
type NodeWebSocketConstructor = new (
|
||||
url: string | URL,
|
||||
options?: { headers?: Record<string, string> }
|
||||
) => WebSocket;
|
||||
|
||||
// ─── Helpers ────────────────────────────────────────────────────────────────
|
||||
|
||||
export function getCopilotMode(model?: string): string {
|
||||
@@ -106,6 +111,12 @@ export function extractAccessToken(credential: string): string | null {
|
||||
return credential;
|
||||
}
|
||||
|
||||
/* @testonly */ export function buildCopilotWebSocketHeaders(
|
||||
accessToken: string
|
||||
): Record<string, string> {
|
||||
return { Authorization: `Bearer ${accessToken}` };
|
||||
}
|
||||
|
||||
/**
|
||||
* Map a token (or absence of one) to an in-memory session-pool key.
|
||||
*
|
||||
@@ -292,19 +303,17 @@ export class CopilotWebExecutor extends BaseExecutor {
|
||||
// Use Node.js built-in WebSocket if available, else dynamic import.
|
||||
// Pass the access token via Authorization header (not URL) to avoid
|
||||
// credential exposure in server logs.
|
||||
let WS = globalThis.WebSocket;
|
||||
if (!WS) {
|
||||
const BrowserWebSocket = globalThis.WebSocket;
|
||||
if (BrowserWebSocket) {
|
||||
ws = new BrowserWebSocket(wsUrl);
|
||||
} else {
|
||||
// @ts-ignore — ws module has no type declarations in this project
|
||||
WS = (await import("ws")).default as unknown as typeof WebSocket;
|
||||
if (accessToken) {
|
||||
// @ts-ignore — ws module supports headers option in second arg
|
||||
ws = new WS(wsUrl, {
|
||||
headers: { Authorization: `Bearer ${accessToken}` },
|
||||
}) as WebSocket;
|
||||
}
|
||||
}
|
||||
if (!ws) {
|
||||
ws = new WS(wsUrl) as WebSocket;
|
||||
const NodeWebSocket = (await import("ws"))
|
||||
.default as unknown as NodeWebSocketConstructor;
|
||||
ws = new NodeWebSocket(
|
||||
wsUrl,
|
||||
accessToken ? { headers: buildCopilotWebSocketHeaders(accessToken) } : undefined
|
||||
);
|
||||
}
|
||||
|
||||
const timeout = setTimeout(() => abort("Copilot WebSocket timeout"), FETCH_TIMEOUT_MS);
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
const { getCopilotMode, extractAccessToken, sessionPoolKey, solveHashcash } =
|
||||
await import("../../open-sse/executors/copilot-web.ts");
|
||||
const {
|
||||
buildCopilotWebSocketHeaders,
|
||||
getCopilotMode,
|
||||
extractAccessToken,
|
||||
sessionPoolKey,
|
||||
solveHashcash,
|
||||
} = await import("../../open-sse/executors/copilot-web.ts");
|
||||
|
||||
test("getCopilotMode maps known models to their Copilot modes", () => {
|
||||
assert.equal(getCopilotMode("copilot"), "chat");
|
||||
@@ -43,6 +48,12 @@ test("extractAccessToken returns null for empty input", () => {
|
||||
assert.equal(extractAccessToken(""), null);
|
||||
});
|
||||
|
||||
test("Copilot WebSocket credentials use the Authorization header", () => {
|
||||
assert.deepEqual(buildCopilotWebSocketHeaders("access-token"), {
|
||||
Authorization: "Bearer access-token",
|
||||
});
|
||||
});
|
||||
|
||||
test("sessionPoolKey produces unique keys per token preventing session sharing", () => {
|
||||
const key1 = sessionPoolKey("token-user-alice");
|
||||
const key2 = sessionPoolKey("token-user-bob");
|
||||
|
||||
Reference in New Issue
Block a user