From e84ddec08c4583d5a119563da56864ea0f025b27 Mon Sep 17 00:00:00 2001 From: JinmingYang <2214962083@qq.com> Date: Mon, 12 Jun 2023 22:31:34 +0800 Subject: [PATCH] fix(gpt-runner-web): state not share different host --- packages/gpt-runner-shared/package.json | 6 +- .../src/common/helpers/common.ts | 11 ++ .../src/common/helpers/env-config.ts | 14 +- .../src/common/helpers/index.ts | 2 + .../src/common/helpers/request.ts | 17 ++ .../src/common/helpers/socket.ts | 178 ++++++++++++++++++ .../src/common/types/enum.ts | 8 + .../src/common/types/index.ts | 1 + .../src/common/types/server.ts | 21 ++- .../src/common/types/socket.ts | 67 +++++++ .../src/common/zod/server.zod.ts | 19 +- .../src/node/helpers/request.ts | 18 +- packages/gpt-runner-vscode/package.json | 19 +- packages/gpt-runner-vscode/res/logo.png | Bin 16335 -> 31053 bytes packages/gpt-runner-vscode/res/logo.svg | 13 ++ .../gpt-runner-vscode/res/sidebar-icon.png | Bin 16335 -> 31053 bytes packages/gpt-runner-vscode/src/constant.ts | 1 + .../gpt-runner-vscode/src/register/webview.ts | 56 ++++-- packages/gpt-runner-vscode/src/state.ts | 2 + packages/gpt-runner-web/client/index.html | 18 +- .../client/src/helpers/global-config.ts | 3 +- .../client/src/networks/server-storage.ts | 10 +- .../zustand/global/sidebar-tree.slice.ts | 2 + .../client/src/store/zustand/storage.ts | 9 +- .../client/src/store/zustand/utils.ts | 7 +- packages/gpt-runner-web/package.json | 4 +- packages/gpt-runner-web/server/index.ts | 7 +- .../src/controllers/chatgpt.controller.ts | 4 +- .../src/controllers/config.controller.ts | 13 +- .../server/src/controllers/index.ts | 33 ++++ .../src/controllers/storage.controller.ts | 64 +++++-- .../server/src/controllers/ws/index.ts | 4 + .../controllers/ws/storage.ws-controller.ts | 84 +++++++++ packages/gpt-runner-web/server/src/types.ts | 18 +- pnpm-lock.yaml | 124 +++++++++++- 35 files changed, 767 insertions(+), 90 deletions(-) create mode 100644 packages/gpt-runner-shared/src/common/helpers/request.ts create mode 100644 packages/gpt-runner-shared/src/common/helpers/socket.ts create mode 100644 packages/gpt-runner-shared/src/common/types/socket.ts create mode 100644 packages/gpt-runner-vscode/res/logo.svg create mode 100644 packages/gpt-runner-web/server/src/controllers/ws/index.ts create mode 100644 packages/gpt-runner-web/server/src/controllers/ws/storage.ws-controller.ts diff --git a/packages/gpt-runner-shared/package.json b/packages/gpt-runner-shared/package.json index 82ea66a..489a6e6 100644 --- a/packages/gpt-runner-shared/package.json +++ b/packages/gpt-runner-shared/package.json @@ -62,6 +62,8 @@ "find-free-ports": "*", "ip": "*", "minimatch": "*", + "socket.io": "*", + "socket.io-client": "*", "zod": "*" }, "dependencies": { @@ -72,6 +74,8 @@ "find-free-ports": "^3.1.1", "ip": "^1.1.8", "minimatch": "^9.0.1", + "socket.io": "^4.6.2", + "socket.io-client": "^4.6.2", "zod": "^3.21.4" }, "devDependencies": { @@ -79,4 +83,4 @@ "@types/ip": "^1.1.0", "express": "^4.18.2" } -} +} \ No newline at end of file diff --git a/packages/gpt-runner-shared/src/common/helpers/common.ts b/packages/gpt-runner-shared/src/common/helpers/common.ts index 980974b..9779a6a 100644 --- a/packages/gpt-runner-shared/src/common/helpers/common.ts +++ b/packages/gpt-runner-shared/src/common/helpers/common.ts @@ -86,10 +86,21 @@ export function tryParseJson(str: string) { return JSON.parse(str) } catch (e) { + console.error('tryParseJson error: ', e) return {} } } +export function tryStringifyJson(obj: any) { + try { + return JSON.stringify(obj) + } + catch (e) { + console.error('tryStringifyJson error: ', e) + return '' + } +} + export function debounce any>(callback: T, wait: number) { let timeout: ReturnType | undefined diff --git a/packages/gpt-runner-shared/src/common/helpers/env-config.ts b/packages/gpt-runner-shared/src/common/helpers/env-config.ts index be0c760..b8984f7 100644 --- a/packages/gpt-runner-shared/src/common/helpers/env-config.ts +++ b/packages/gpt-runner-shared/src/common/helpers/env-config.ts @@ -15,7 +15,7 @@ interface EnvVarConfig { /** * if true, this env var will only be available on server side - * window.__config__ will not have this env var + * window.__env__ will not have this env var * * @default false */ @@ -26,7 +26,9 @@ const config: Record = { NODE_ENV: { defaultValue: 'production', }, - OPENAI_KEY: {}, + OPENAI_KEY: { + serverSideOnly: true, + }, GPTR_BASE_SERVER_URL: { defaultValue: 'http://localhost:3003', }, @@ -42,7 +44,7 @@ export class EnvConfig { // client side if (typeof window !== 'undefined' && !serverSideOnly) - return window?.__config__?.[key] ?? defaultValue ?? '' + return window?.__env__?.[key] ?? defaultValue ?? '' // server side return process.env[key] ?? defaultValue ?? '' @@ -51,7 +53,7 @@ export class EnvConfig { /** * get all env vars on server or client side * @param type server or client, get all allowed env vars on that scope - * @param getWays all or process, get env vars both on process and window.__config__ or only process.env + * @param getWays all or process, get env vars both on process and window.__env__ or only process.env * @returns env vars key value map */ static getAllEnvVarsOnScopes( @@ -93,7 +95,7 @@ export class EnvConfig { /** * for /api/config - * @returns env vars key value map for window.__config__ + * @returns env vars key value map for window.__env__ */ static getClientEnvVarsInServerSide(): Partial> { return EnvConfig.getAllEnvVarsOnScopes('client', 'process') @@ -106,6 +108,6 @@ declare global { } interface Window { - __config__?: Partial + __env__?: Partial } } diff --git a/packages/gpt-runner-shared/src/common/helpers/index.ts b/packages/gpt-runner-shared/src/common/helpers/index.ts index 4e55f40..86a99fd 100644 --- a/packages/gpt-runner-shared/src/common/helpers/index.ts +++ b/packages/gpt-runner-shared/src/common/helpers/index.ts @@ -4,4 +4,6 @@ export * from './create-filter-pattern' export * from './debug' export * from './env-config' export * from './is' +export * from './request' +export * from './socket' export * from './verify-zod' diff --git a/packages/gpt-runner-shared/src/common/helpers/request.ts b/packages/gpt-runner-shared/src/common/helpers/request.ts new file mode 100644 index 0000000..3f66d9c --- /dev/null +++ b/packages/gpt-runner-shared/src/common/helpers/request.ts @@ -0,0 +1,17 @@ +import type { FailResponse, SuccessResponse } from '../types' + +export function buildSuccessResponse(options: Omit, 'type'>): SuccessResponse { + return { + type: 'Success', + status: options.status || 200, + ...options, + } +} + +export function buildFailResponse(options: Omit, 'type'>): FailResponse { + return { + type: 'Fail', + status: options.status || 400, + ...options, + } +} diff --git a/packages/gpt-runner-shared/src/common/helpers/socket.ts b/packages/gpt-runner-shared/src/common/helpers/socket.ts new file mode 100644 index 0000000..0a5f4df --- /dev/null +++ b/packages/gpt-runner-shared/src/common/helpers/socket.ts @@ -0,0 +1,178 @@ +import * as uuid from 'uuid' +import type { BrowserSocket, MaybePromise, NodeServerSocket, Socket, WssActionName, WssActionNameRequestMap } from '../types' +import { EnvConfig } from './env-config' + +type SocketQueueFn = (socket: Socket) => void +export class WssUtils { + static _instance: WssUtils | undefined + static defaultWssUrl = `http://${new URL(EnvConfig.get('GPTR_BASE_SERVER_URL')).host}` + #wssUrl: string + #socketQueue: SocketQueueFn[] = [] + #hasConnected = false + + static get instance() { + if (!this._instance) + this._instance = new WssUtils() + + return this._instance + } + + constructor(wssUrl?: string) { + this.#wssUrl = wssUrl ?? WssUtils.defaultWssUrl + } + + static get isBrowser() { + return typeof window !== 'undefined' + } + + static isNodeServerSocket(socket: Socket | undefined): socket is NodeServerSocket { + return typeof window === 'undefined' && Boolean(socket) + } + + static isBrowserSocket(socket: Socket | undefined): socket is BrowserSocket { + return WssUtils.isBrowser && Boolean(socket) + } + + get wsUrl() { + return this.#wssUrl + } + + #wss: Socket | undefined + + #setWss = (socket: Socket) => { + this.#wss = socket + this.#socketQueue.forEach(fn => fn(socket)) + this.#socketQueue = [] + } + + get wss() { + return this.#wss + } + + connect = async (params?: { + server: any // http.createServer(expressApp); + }) => { + if (this.wss || this.#hasConnected) + return this.wss + + console.log('Connecting to WS...') + const { server } = params || {} + + try { + if (WssUtils.isBrowser) + await this.#connectBrowserSocket() + else + server && await this.#connectNodeSocket(server) + + this.#hasConnected = true + + return this.wss + } + catch (error) { + console.error('Error connecting to WS', error) + throw error + } + } + + // for nodejs + #connectNodeSocket = async (server: any) => { + if (WssUtils.isBrowser || this.wss) + return + + const { Server } = await import('socket.io') + + const serverSocket = new Server(server, { + cors: { + origin: '*', + }, + }) + + serverSocket.on('connection', (socket) => { + this.#setWss(socket) + this.#handleConnection() + }) + } + + // for browser + #connectBrowserSocket = async () => { + if (!WssUtils.isBrowser || this.wss) + return + + const { io } = await import('socket.io-client') + const socket = io(this.wsUrl) + this.#setWss(socket) + + // if (!WssUtils.isBrowserSocket(this.wss)) + // return + + // socket.on('connect', () => { + // this.#handleConnection() + // }) + } + + #handleConnection = async () => { + console.log('Connected to Socket server') + } + + on = (eventName: T, callback: (message: WssActionNameRequestMap[T]) => MaybePromise) => { + if (!this.wss) { + this.#socketQueue.push((socket) => { + socket.on(eventName, callback as any) + }) + return + } + + (this.wss as NodeServerSocket).on(eventName, callback as any) + } + + emit = (eventName: T, message: WssActionNameRequestMap[T]) => { + if (!this.wss) { + this.#socketQueue.push((socket) => { + socket.emit(eventName, message) + }) + return + } + + this.wss.emit(eventName, message) + } + + off = (eventName: T, callback: (message: WssActionNameRequestMap[T]) => MaybePromise) => { + if (!this.wss) { + this.#socketQueue.push((socket) => { + socket.off(eventName, callback as any) + }) + return + } + + this.wss.off(eventName, callback as any) + } + + emitAndWaitForRes = async (eventName: T, message: WssActionNameRequestMap[T]) => { + return new Promise((resolve, reject) => { + let destroyFn: () => void + + const timeout = setTimeout(() => { + destroyFn?.() + reject(new Error(`WS timeout, actionName: ${eventName}`)) + }, 10000) + + const __id__ = uuid.v4() + this.emit(eventName, { ...message, __id__ }) + + const handler = (message: WssActionNameRequestMap[T]) => { + if (message.__id__ !== __id__) + return + + destroyFn?.() + resolve(message) + } + + this.on(eventName, handler) + + destroyFn = () => { + clearTimeout(timeout) + this.off(eventName, handler) + } + }) + } +} diff --git a/packages/gpt-runner-shared/src/common/types/enum.ts b/packages/gpt-runner-shared/src/common/types/enum.ts index 9ec5908..118cea3 100644 --- a/packages/gpt-runner-shared/src/common/types/enum.ts +++ b/packages/gpt-runner-shared/src/common/types/enum.ts @@ -26,3 +26,11 @@ export enum ServerStorageName { FrontendState = 'frontend-state', WebPreset = 'web-preset', } + +export enum WssActionName { + Error = 'error', + StorageGetItem = 'storageGetItem', + StorageSetItem = 'storageSetItem', + StorageRemoveItem = 'storageRemoveItem', + StorageClear = 'storageClear', +} diff --git a/packages/gpt-runner-shared/src/common/types/index.ts b/packages/gpt-runner-shared/src/common/types/index.ts index 2cbf5a2..d1f13e7 100644 --- a/packages/gpt-runner-shared/src/common/types/index.ts +++ b/packages/gpt-runner-shared/src/common/types/index.ts @@ -4,3 +4,4 @@ export * from './config' export * from './enum' export * from './eventemitter' export * from './server' +export * from './socket' diff --git a/packages/gpt-runner-shared/src/common/types/server.ts b/packages/gpt-runner-shared/src/common/types/server.ts index d12030a..8ec1f5a 100644 --- a/packages/gpt-runner-shared/src/common/types/server.ts +++ b/packages/gpt-runner-shared/src/common/types/server.ts @@ -36,22 +36,35 @@ export interface GetUserConfigResData { userConfig: UserConfig } -export interface GetStorageReqParams { +export interface StorageGetItemReqParams { storageName: ServerStorageName key: string } export type ServerStorageValue = Record | null | undefined -export interface GetStorageResData { +export interface StorageGetItemResData { value: ServerStorageValue cacheDir: string } -export interface SaveStorageReqParams { +export interface StorageSetItemReqParams { storageName: ServerStorageName key: string value?: ServerStorageValue } -export type SaveStorageResData = null +export type StorageSetItemResData = null + +export interface StorageRemoveItemReqParams { + storageName: ServerStorageName + key: string +} + +export type StorageRemoveItemResData = null + +export interface StorageClearReqParams { + storageName: ServerStorageName +} + +export type StorageClearResData = null diff --git a/packages/gpt-runner-shared/src/common/types/socket.ts b/packages/gpt-runner-shared/src/common/types/socket.ts new file mode 100644 index 0000000..e3d7021 --- /dev/null +++ b/packages/gpt-runner-shared/src/common/types/socket.ts @@ -0,0 +1,67 @@ +import type { Socket as BrowserSocket } from 'socket.io-client' +import type { Socket as NodeServerSocket } from 'socket.io' +import type { MaybePromise } from './common' +import type { WssActionName } from './enum' + +import type { + BaseResponse, + StorageClearReqParams, + StorageClearResData, + StorageGetItemReqParams, + StorageGetItemResData, + StorageRemoveItemReqParams, + StorageRemoveItemResData, + StorageSetItemReqParams, + StorageSetItemResData, +} from './server' + +export interface IWssActionNameRequestMap extends Record + resData?: any +}> { + [WssActionName.Error]: { + reqParams?: { + error: Error + } + resData?: Error + } + + [WssActionName.StorageGetItem]: { + reqParams?: StorageGetItemReqParams + resData?: StorageGetItemResData + } + + [WssActionName.StorageSetItem]: { + reqParams?: StorageSetItemReqParams + resData?: StorageSetItemResData + } + + [WssActionName.StorageRemoveItem]: { + reqParams?: StorageRemoveItemReqParams + resData?: StorageRemoveItemResData + } + + [WssActionName.StorageClear]: { + reqParams?: StorageClearReqParams + resData?: StorageClearResData + } +} + +export type WssActionNameRequestMap = { + [K in keyof IWssActionNameRequestMap]: { + __id__?: string + reqParams?: IWssActionNameRequestMap[K]['reqParams'] + res?: BaseResponse + } +} + +export type WssEventsMap = { + [K in keyof WssActionNameRequestMap]: (message: WssActionNameRequestMap[K]) => MaybePromise; +} + +// export type NodeServerSocket = InstanceType> +// export type BrowserSocket = InstanceType> +// export type Socket = NodeServerSocket | BrowserSocket + +export type { BrowserSocket, NodeServerSocket } +export type Socket = BrowserSocket | NodeServerSocket diff --git a/packages/gpt-runner-shared/src/common/zod/server.zod.ts b/packages/gpt-runner-shared/src/common/zod/server.zod.ts index ab70936..7e65822 100644 --- a/packages/gpt-runner-shared/src/common/zod/server.zod.ts +++ b/packages/gpt-runner-shared/src/common/zod/server.zod.ts @@ -1,5 +1,5 @@ import { z } from 'zod' -import type { ChatStreamReqParams, GetGptFilesReqParams, GetStorageReqParams, GetUserConfigReqParams, SaveStorageReqParams } from '../types' +import type { ChatStreamReqParams, GetGptFilesReqParams, GetUserConfigReqParams, StorageClearReqParams, StorageGetItemReqParams, StorageRemoveItemReqParams, StorageSetItemReqParams } from '../types' import { SingleChatMessageSchema, SingleFileConfigSchema } from './config.zod' import { ServerStorageNameSchema } from './enum.zod' @@ -19,13 +19,22 @@ export const GetUserConfigReqParamsSchema = z.object({ rootPath: z.string(), }) satisfies z.ZodType -export const GetStorageReqParamsSchema = z.object({ +export const StorageGetItemReqParamsSchema = z.object({ storageName: ServerStorageNameSchema, key: z.string(), -}) satisfies z.ZodType +}) satisfies z.ZodType -export const SaveStorageReqParamsSchema = z.object({ +export const StorageSetItemReqParamsSchema = z.object({ storageName: ServerStorageNameSchema, key: z.string(), value: z.record(z.any()).nullable().optional(), -}) satisfies z.ZodType +}) satisfies z.ZodType + +export const StorageRemoveItemReqParamsSchema = z.object({ + storageName: ServerStorageNameSchema, + key: z.string(), +}) satisfies z.ZodType + +export const StorageClearReqParamsSchema = z.object({ + storageName: ServerStorageNameSchema, +}) satisfies z.ZodType diff --git a/packages/gpt-runner-shared/src/node/helpers/request.ts b/packages/gpt-runner-shared/src/node/helpers/request.ts index 9c97403..b33298c 100644 --- a/packages/gpt-runner-shared/src/node/helpers/request.ts +++ b/packages/gpt-runner-shared/src/node/helpers/request.ts @@ -1,23 +1,7 @@ import type { Response } from 'express' import type { z } from 'zod' import type { FailResponse, SuccessResponse } from '../../common' -import { verifyZod } from '../../common' - -export function buildSuccessResponse(options: Omit, 'type'>): SuccessResponse { - return { - type: 'Success', - status: options.status || 200, - ...options, - } -} - -export function buildFailResponse(options: Omit, 'type'>): FailResponse { - return { - type: 'Fail', - status: options.status || 400, - ...options, - } -} +import { buildFailResponse, buildSuccessResponse, verifyZod } from '../../common' export function sendSuccessResponse(res: Response, options: Omit, 'type'>): Response { return res.status(options.status || 200).json(buildSuccessResponse(options)) diff --git a/packages/gpt-runner-vscode/package.json b/packages/gpt-runner-vscode/package.json index 2d3daa0..26f189b 100644 --- a/packages/gpt-runner-vscode/package.json +++ b/packages/gpt-runner-vscode/package.json @@ -50,7 +50,13 @@ }, { "command": "gpt-runner.restartServer", - "title": "GPT Runner Restart Server", + "title": "Restart GPT Runner Server", + "category": "GPT Runner" + }, + { + "command": "gpt-runner.openChat", + "title": "Open GPT Runner Chat", + "icon": "res/logo.svg", "category": "GPT Runner" } ], @@ -64,6 +70,15 @@ "description": "Disable the GPT Runner extension" } } + }, + "menus": { + "editor/title": [ + { + "command": "gpt-runner.openChat", + "group": "navigation", + "icon": "res/logo.svg" + } + ] } }, "scripts": { @@ -84,4 +99,4 @@ "execa": "^7.1.1", "fs-extra": "^11.1.1" } -} +} \ No newline at end of file diff --git a/packages/gpt-runner-vscode/res/logo.png b/packages/gpt-runner-vscode/res/logo.png index d8ff49bef2660ba360b38760db1bef60d0e6cc60..1b7817857a0a3fb35564b4e40ddd65cd5e829880 100644 GIT binary patch literal 31053 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 + + + + + \ No newline at end of file diff --git a/packages/gpt-runner-vscode/res/sidebar-icon.png b/packages/gpt-runner-vscode/res/sidebar-icon.png index d8ff49bef2660ba360b38760db1bef60d0e6cc60..1b7817857a0a3fb35564b4e40ddd65cd5e829880 100644 GIT binary patch literal 31053 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 { + ChatViewProvider.updateWebview(webviewView.webview, this.#extContext, this.#projectPath) + } + + static createWebviewPanel(extContext: ExtensionContext, projectPath: string): vscode.WebviewPanel { + const panel = vscode.window.createWebviewPanel( + uuid.v4(), + EXT_DISPLAY_NAME, + { + viewColumn: vscode.ViewColumn.Two, + }, + { retainContextWhenHidden: true }, + ) + + state.webviewPanel = panel + + ChatViewProvider.updateWebview(panel.webview, extContext, projectPath) + + return panel + } + + static updateWebview(webview: vscode.Webview, extContext: ExtensionContext, projectPath: string) { + const { extensionUri } = extContext + + webview.onDidReceiveMessage(({ eventName, eventData }) => { emitter.emit(eventName, eventData, EventType.ReceiveMessage) }) const baseUri = vscode.Uri.joinPath(extensionUri, './node_modules/@nicepkg/gpt-runner-web/dist/browser') - webviewView.webview.options = { + webview.options = { // Allow scripts in the webview enableScripts: true, localResourceRoots: [baseUri], } - webviewView.webview.html = this.#getHtmlForWebview(webviewView.webview) + webview.html = ChatViewProvider.getHtmlForWebview(webview, extContext, projectPath) } - #getHtmlForWebview(webview: vscode.Webview) { - const { extensionUri } = this.#extContext + static getHtmlForWebview(webview: vscode.Webview, extContext: ExtensionContext, projectPath: string) { + const { extensionUri } = extContext const baseUri = vscode.Uri.joinPath(extensionUri, './node_modules/@nicepkg/gpt-runner-web/dist/browser') @@ -69,7 +92,7 @@ class ChatViewProvider implements vscode.WebviewViewProvider { window.vscode = acquireVsCodeApi() window.__GLOBAL_CONFIG__ = { - rootPath: '${this.#projectPath}', + rootPath: '${projectPath}', serverBaseUrl: '${getServerBaseUrl()}', initialRoutePath: '/chat', showDiffCodesBtn: true, @@ -106,16 +129,25 @@ export async function registerWebview( ext: ExtensionContext, ) { const provider = new ChatViewProvider(ext, cwd) - let webviewDisposer: vscode.Disposable | undefined + let sidebarWebviewDisposer: vscode.Disposable | undefined + let webviewPanelDisposer: vscode.Disposable | undefined const dispose = () => { - webviewDisposer?.dispose?.() + sidebarWebviewDisposer?.dispose?.() + webviewPanelDisposer?.dispose?.() } const registerProvider = () => { dispose() - webviewDisposer = vscode.window.registerWebviewViewProvider(ChatViewProvider.viewType, provider) - return webviewDisposer + + sidebarWebviewDisposer = vscode.window.registerWebviewViewProvider(ChatViewProvider.viewType, provider) + webviewPanelDisposer = vscode.commands.registerCommand(Commands.OpenChat, () => { + ChatViewProvider.createWebviewPanel(ext, cwd) + }) + + return vscode.Disposable.from({ + dispose, + }) } ext.subscriptions.push(registerProvider()) diff --git a/packages/gpt-runner-vscode/src/state.ts b/packages/gpt-runner-vscode/src/state.ts index b47436c..03708b2 100644 --- a/packages/gpt-runner-vscode/src/state.ts +++ b/packages/gpt-runner-vscode/src/state.ts @@ -4,6 +4,7 @@ export interface State { serverPort: number | null statusBarItem: vscode.StatusBarItem | null sidebarWebviewView: vscode.WebviewView | null + webviewPanel: vscode.WebviewPanel | null insertCodes: string diffCodes: string } @@ -12,6 +13,7 @@ export const state: State = { serverPort: null, statusBarItem: null, sidebarWebviewView: null, + webviewPanel: null, insertCodes: '', diffCodes: 'aaa', } diff --git a/packages/gpt-runner-web/client/index.html b/packages/gpt-runner-web/client/index.html index b9ac780..d81e144 100644 --- a/packages/gpt-runner-web/client/index.html +++ b/packages/gpt-runner-web/client/index.html @@ -23,6 +23,22 @@ + + @@ -35,4 +51,4 @@ - + \ No newline at end of file diff --git a/packages/gpt-runner-web/client/src/helpers/global-config.ts b/packages/gpt-runner-web/client/src/helpers/global-config.ts index 408d2af..c28bd2f 100644 --- a/packages/gpt-runner-web/client/src/helpers/global-config.ts +++ b/packages/gpt-runner-web/client/src/helpers/global-config.ts @@ -1,4 +1,5 @@ import { getSearchParams } from '@nicepkg/gpt-runner-shared/browser' +import { EnvConfig } from '@nicepkg/gpt-runner-shared/common' export interface GlobalConfig { rootPath: string @@ -11,7 +12,7 @@ export interface GlobalConfig { window.__DEFAULT_GLOBAL_CONFIG__ = { rootPath: getSearchParams('rootPath') || '/Users/yangxiaoming/Documents/codes/gpt-runner', initialRoutePath: '/', - serverBaseUrl: '', + serverBaseUrl: EnvConfig.get('GPTR_BASE_SERVER_URL'), showDiffCodesBtn: false, showInsertCodesBtn: false, } diff --git a/packages/gpt-runner-web/client/src/networks/server-storage.ts b/packages/gpt-runner-web/client/src/networks/server-storage.ts index c1219c5..a71bf9c 100644 --- a/packages/gpt-runner-web/client/src/networks/server-storage.ts +++ b/packages/gpt-runner-web/client/src/networks/server-storage.ts @@ -1,10 +1,10 @@ -import type { BaseResponse, GetStorageReqParams, GetStorageResData, SaveStorageReqParams, SaveStorageResData } from '@nicepkg/gpt-runner-shared/common' +import type { BaseResponse, StorageGetItemReqParams, StorageGetItemResData, StorageSetItemReqParams, StorageSetItemResData } from '@nicepkg/gpt-runner-shared/common' import { getGlobalConfig } from '../helpers/global-config' -export interface GetServerStorageParams extends GetStorageReqParams { +export interface GetServerStorageParams extends StorageGetItemReqParams { } -export type GetServerStorageRes = BaseResponse +export type GetServerStorageRes = BaseResponse export async function getServerStorage(params: GetServerStorageParams): Promise { const { storageName, key } = params @@ -19,10 +19,10 @@ export async function getServerStorage(params: GetServerStorageParams): Promise< return data } -export interface SaveServerStorageParams extends SaveStorageReqParams { +export interface SaveServerStorageParams extends StorageSetItemReqParams { } -export type SaveServerStorageRes = BaseResponse +export type SaveServerStorageRes = BaseResponse export async function saveServerStorage(params: SaveServerStorageParams): Promise { const { storageName, key, value } = params diff --git a/packages/gpt-runner-web/client/src/store/zustand/global/sidebar-tree.slice.ts b/packages/gpt-runner-web/client/src/store/zustand/global/sidebar-tree.slice.ts index b09415a..bd98f74 100644 --- a/packages/gpt-runner-web/client/src/store/zustand/global/sidebar-tree.slice.ts +++ b/packages/gpt-runner-web/client/src/store/zustand/global/sidebar-tree.slice.ts @@ -141,7 +141,9 @@ export const createSidebarTreeSlice: StateCreator< if (item.type === GptFileTreeItemType.File) { gptFileIds.push(item.id) + const chatIds = currentGptFileIdChatIdsMap.get(item.id) || [] + result.children = chatIds.map((chatId) => { const chatInfo = state.getChatInfo(chatId) chatInfo.parentId = item.id diff --git a/packages/gpt-runner-web/client/src/store/zustand/storage.ts b/packages/gpt-runner-web/client/src/store/zustand/storage.ts index fed3c57..fb08f16 100644 --- a/packages/gpt-runner-web/client/src/store/zustand/storage.ts +++ b/packages/gpt-runner-web/client/src/store/zustand/storage.ts @@ -20,7 +20,7 @@ async function getStateFromServerOnce(key: string) { } // will save each action state to server -const debounceSaveStateToServer = debounce(async (key: string, value: ServerStorageValue) => { +const debounceSaveStateToServerFn = debounce(async (key: string, value: ServerStorageValue) => { if (hasUpdateStateFromRemote !== 'finish') return @@ -31,6 +31,13 @@ const debounceSaveStateToServer = debounce(async (key: string, value: ServerStor }) }, 1000) +function debounceSaveStateToServer(key: string, value: ServerStorageValue) { + if (hasUpdateStateFromRemote !== 'finish') + return + + debounceSaveStateToServerFn(key, value) +} + export class CustomStorage implements StateStorage { #storage: Storage diff --git a/packages/gpt-runner-web/client/src/store/zustand/utils.ts b/packages/gpt-runner-web/client/src/store/zustand/utils.ts index 2fd285c..35997f6 100644 --- a/packages/gpt-runner-web/client/src/store/zustand/utils.ts +++ b/packages/gpt-runner-web/client/src/store/zustand/utils.ts @@ -18,7 +18,6 @@ export function resetAllState() { export function createStore(devtoolsName: string) { const newCreate = (store: any) => { - const defaultState = create(store).getState() let result: any // https://github.com/pmndrs/zustand/issues/852#issuecomment-1059783350 @@ -30,11 +29,13 @@ export function createStore(devtoolsName: string) { }), ) } - - result = create(store) + else { + result = create(store) + } // reset state of this store result.resetState = () => { + const defaultState = create(store).getState() result.setState(cloneDeep(defaultState), true) } diff --git a/packages/gpt-runner-web/package.json b/packages/gpt-runner-web/package.json index efb4e0d..3d587af 100644 --- a/packages/gpt-runner-web/package.json +++ b/packages/gpt-runner-web/package.json @@ -57,7 +57,7 @@ "build:server": "unbuild", "dev": "pnpm dev:server & pnpm dev:client", "dev:client": "vite --config ./client/vite.config.ts", - "dev:server": "cross-env NODE_OPTIONS='--experimental-fetch' NODE_NO_WARNINGS='1' DEBUG='enabled' pnpm esno server/start-server.ts --auto-free-port", + "dev:server": "cross-env NODE_ENV=development NODE_OPTIONS='--experimental-fetch' NODE_NO_WARNINGS='1' DEBUG='enabled' pnpm esno server/start-server.ts --auto-free-port", "start": "cross-env NODE_OPTIONS='--experimental-fetch' NODE_NO_WARNINGS='1' DEBUG='enabled' node dist/start-server.cjs --auto-free-port", "stub": "unbuild --stub" }, @@ -104,4 +104,4 @@ "@vitejs/plugin-react": "^4.0.0", "vite": "^4.3.9" } -} +} \ No newline at end of file diff --git a/packages/gpt-runner-web/server/index.ts b/packages/gpt-runner-web/server/index.ts index 862faa6..4baa78c 100644 --- a/packages/gpt-runner-web/server/index.ts +++ b/packages/gpt-runner-web/server/index.ts @@ -1,5 +1,6 @@ import './src/proxy' import path from 'node:path' +import http from 'node:http' import type { Express } from 'express' import express from 'express' import cors from 'cors' @@ -49,7 +50,11 @@ export async function startServer(props: StartServerProps): Promise { app.use(errorHandlerMiddleware) - app.listen(finalPort, () => console.log(`Server is running on port ${finalPort}`)) + const server = http.createServer(app) + + // await processWsControllers(server) + + server.listen(finalPort, () => console.log(`Server is running on port ${finalPort}`)) return app } diff --git a/packages/gpt-runner-web/server/src/controllers/chatgpt.controller.ts b/packages/gpt-runner-web/server/src/controllers/chatgpt.controller.ts index 9da70d8..6a4c43f 100644 --- a/packages/gpt-runner-web/server/src/controllers/chatgpt.controller.ts +++ b/packages/gpt-runner-web/server/src/controllers/chatgpt.controller.ts @@ -1,7 +1,7 @@ import type { Request, Response } from 'express' import type { ChatStreamReqParams, FailResponse, SuccessResponse } from '@nicepkg/gpt-runner-shared/common' -import { ChatStreamReqParamsSchema, EnvConfig } from '@nicepkg/gpt-runner-shared/common' -import { PathUtils, buildFailResponse, buildSuccessResponse, sendFailResponse, sendSuccessResponse, verifyParamsByZod } from '@nicepkg/gpt-runner-shared/node' +import { ChatStreamReqParamsSchema, EnvConfig, buildFailResponse, buildSuccessResponse } from '@nicepkg/gpt-runner-shared/common' +import { PathUtils, sendFailResponse, sendSuccessResponse, verifyParamsByZod } from '@nicepkg/gpt-runner-shared/node' import { loadUserConfig } from '@nicepkg/gpt-runner-core' import { chatgptChain } from '../services' import type { ControllerConfig } from './../types' diff --git a/packages/gpt-runner-web/server/src/controllers/config.controller.ts b/packages/gpt-runner-web/server/src/controllers/config.controller.ts index 5103e9e..60bd6a6 100644 --- a/packages/gpt-runner-web/server/src/controllers/config.controller.ts +++ b/packages/gpt-runner-web/server/src/controllers/config.controller.ts @@ -1,6 +1,6 @@ import { PathUtils, sendFailResponse, sendSuccessResponse, verifyParamsByZod } from '@nicepkg/gpt-runner-shared/node' import type { GetUserConfigReqParams, GetUserConfigResData } from '@nicepkg/gpt-runner-shared/common' -import { GetUserConfigReqParamsSchema, resetUserConfigUnsafeKey } from '@nicepkg/gpt-runner-shared/common' +import { EnvConfig, GetUserConfigReqParamsSchema, resetUserConfigUnsafeKey } from '@nicepkg/gpt-runner-shared/common' import { loadUserConfig } from '@nicepkg/gpt-runner-core' import pkg from '../../../package.json' import type { ControllerConfig } from '../types' @@ -19,6 +19,17 @@ export const configControllers: ControllerConfig = { }) }, }, + { + url: '/env.js', + method: 'get', + handler: async (req, res) => { + const envMap = EnvConfig.getClientEnvVarsInServerSide() + + // response a javascript file + res.setHeader('Content-Type', 'application/javascript') + res.send(`window.__env__ = ${JSON.stringify(envMap)}`) + }, + }, { url: '/user-config', method: 'get', diff --git a/packages/gpt-runner-web/server/src/controllers/index.ts b/packages/gpt-runner-web/server/src/controllers/index.ts index 7e7ab4a..584c63f 100644 --- a/packages/gpt-runner-web/server/src/controllers/index.ts +++ b/packages/gpt-runner-web/server/src/controllers/index.ts @@ -1,9 +1,11 @@ import type { NextFunction, Router } from 'express' +import { WssActionName, WssUtils, buildFailResponse } from '@nicepkg/gpt-runner-shared/common' import type { Controller, ControllerConfig } from '../types' import { chatgptControllers } from './chatgpt.controller' import { configControllers } from './config.controller' import { gptFilesControllers } from './gpt-files.controller' import { storageControllers } from './storage.controller' +import { allWsControllersConfig } from './ws' export function processControllers(router: Router) { const allControllersConfig: ControllerConfig[] = [ @@ -33,3 +35,34 @@ export function processControllers(router: Router) { }) }) } + +export async function processWsControllers(server: any) { + await WssUtils.instance.connect({ server }) + + allWsControllersConfig.forEach((controllerConfig) => { + const { controllers } = controllerConfig + + controllers.forEach((controller) => { + const { actionName, handler } = controller + + WssUtils.instance.on(actionName, async (params: Record) => { + console.log(`[WS] ${actionName} params:`, params) + try { + return await handler(params as any) + } + catch (error: any) { + const errRes = buildFailResponse({ data: error, message: error?.message || String(error) }) + + WssUtils.instance.emit(actionName, { + reqParams: params as any, + res: errRes, + }) + + WssUtils.instance.emit(WssActionName.Error, { + res: errRes, + }) + } + }) + }) + }) +} diff --git a/packages/gpt-runner-web/server/src/controllers/storage.controller.ts b/packages/gpt-runner-web/server/src/controllers/storage.controller.ts index 0207541..62c9ee2 100644 --- a/packages/gpt-runner-web/server/src/controllers/storage.controller.ts +++ b/packages/gpt-runner-web/server/src/controllers/storage.controller.ts @@ -1,6 +1,6 @@ import { getStorage, sendSuccessResponse, verifyParamsByZod } from '@nicepkg/gpt-runner-shared/node' -import type { GetStorageReqParams, GetStorageResData, SaveStorageReqParams, SaveStorageResData } from '@nicepkg/gpt-runner-shared/common' -import { GetStorageReqParamsSchema, SaveStorageReqParamsSchema } from '@nicepkg/gpt-runner-shared/common' +import type { StorageClearReqParams, StorageClearResData, StorageGetItemReqParams, StorageGetItemResData, StorageRemoveItemReqParams, StorageRemoveItemResData, StorageSetItemReqParams, StorageSetItemResData } from '@nicepkg/gpt-runner-shared/common' +import { StorageClearReqParamsSchema, StorageGetItemReqParamsSchema, StorageRemoveItemReqParamsSchema, StorageSetItemReqParamsSchema } from '@nicepkg/gpt-runner-shared/common' import type { ControllerConfig } from '../types' export const storageControllers: ControllerConfig = { @@ -10,9 +10,9 @@ export const storageControllers: ControllerConfig = { url: '/', method: 'get', handler: async (req, res) => { - const query = req.query as GetStorageReqParams + const query = req.query as StorageGetItemReqParams - verifyParamsByZod(query, GetStorageReqParamsSchema) + verifyParamsByZod(query, StorageGetItemReqParamsSchema) const { key, storageName } = query @@ -23,7 +23,7 @@ export const storageControllers: ControllerConfig = { data: { value, cacheDir, - } satisfies GetStorageResData, + } satisfies StorageGetItemResData, }) }, }, @@ -31,27 +31,53 @@ export const storageControllers: ControllerConfig = { url: '/', method: 'post', handler: async (req, res) => { - const body = req.body as SaveStorageReqParams + const body = req.body as StorageSetItemReqParams - verifyParamsByZod(body, SaveStorageReqParamsSchema) + verifyParamsByZod(body, StorageSetItemReqParamsSchema) const { storageName, key, value } = body - const { storage } = await getStorage(storageName) - switch (value) { - case undefined: - // remove - await storage.delete(key) - break - default: - // set - await storage.set(key, value) - break - } + await storage.set(key, value) sendSuccessResponse(res, { - data: null satisfies SaveStorageResData, + data: null satisfies StorageSetItemResData, + }) + }, + }, + { + url: '/', + method: 'delete', + handler: async (req, res) => { + const body = req.body as StorageRemoveItemReqParams + + verifyParamsByZod(body, StorageRemoveItemReqParamsSchema) + + const { key, storageName } = body + const { storage } = await getStorage(storageName) + + await storage.delete(key) + + sendSuccessResponse(res, { + data: null satisfies StorageRemoveItemResData, + }) + }, + }, + { + url: '/clear', + method: 'post', + handler: async (req, res) => { + const body = req.body as StorageClearReqParams + + verifyParamsByZod(body, StorageClearReqParamsSchema) + + const { storageName } = body + const { storage } = await getStorage(storageName) + + await storage.clear() + + sendSuccessResponse(res, { + data: null satisfies StorageClearResData, }) }, }, diff --git a/packages/gpt-runner-web/server/src/controllers/ws/index.ts b/packages/gpt-runner-web/server/src/controllers/ws/index.ts new file mode 100644 index 0000000..a82c18f --- /dev/null +++ b/packages/gpt-runner-web/server/src/controllers/ws/index.ts @@ -0,0 +1,4 @@ +import type { WssControllerConfig } from '../../types' +import { storageControllers } from './storage.ws-controller' + +export const allWsControllersConfig: WssControllerConfig[] = [storageControllers] diff --git a/packages/gpt-runner-web/server/src/controllers/ws/storage.ws-controller.ts b/packages/gpt-runner-web/server/src/controllers/ws/storage.ws-controller.ts new file mode 100644 index 0000000..9f9c068 --- /dev/null +++ b/packages/gpt-runner-web/server/src/controllers/ws/storage.ws-controller.ts @@ -0,0 +1,84 @@ +import type { StorageClearResData, StorageGetItemReqParams, StorageGetItemResData, StorageRemoveItemReqParams, StorageRemoveItemResData, StorageSetItemReqParams, StorageSetItemResData } from '@nicepkg/gpt-runner-shared/common' +import { StorageClearReqParamsSchema, StorageGetItemReqParamsSchema, StorageRemoveItemReqParamsSchema, StorageSetItemReqParamsSchema, WssActionName, WssUtils, buildSuccessResponse } from '@nicepkg/gpt-runner-shared/common' +import { getStorage, verifyParamsByZod } from '@nicepkg/gpt-runner-shared/node' +import type { WssControllerConfig } from '../../types' + +export const storageControllers: WssControllerConfig = { + controllers: [ + { + actionName: WssActionName.StorageGetItem, + handler: async (params: StorageGetItemReqParams) => { + verifyParamsByZod(params, StorageGetItemReqParamsSchema) + + const { key, storageName } = params + + const { storage, cacheDir } = await getStorage(storageName) + const value = await storage.get(key) + + WssUtils.instance.emit(WssActionName.StorageGetItem, { + reqParams: params, + res: buildSuccessResponse({ + data: { + value, + cacheDir, + } satisfies StorageGetItemResData, + }), + }) + }, + }, + { + actionName: WssActionName.StorageSetItem, + handler: async (params: StorageSetItemReqParams) => { + verifyParamsByZod(params, StorageSetItemReqParamsSchema) + + const { storageName, key, value } = params + + const { storage } = await getStorage(storageName) + await storage.set(key, value) + + WssUtils.instance.emit(WssActionName.StorageSetItem, { + reqParams: params, + res: buildSuccessResponse({ + data: null satisfies StorageSetItemResData, + }), + }) + }, + }, + { + actionName: WssActionName.StorageRemoveItem, + handler: async (params: StorageRemoveItemReqParams) => { + verifyParamsByZod(params, StorageRemoveItemReqParamsSchema) + + const { key, storageName } = params + + const { storage } = await getStorage(storageName) + await storage.delete(key) + + WssUtils.instance.emit(WssActionName.StorageRemoveItem, { + reqParams: params, + res: buildSuccessResponse({ + data: null satisfies StorageRemoveItemResData, + }), + }) + }, + }, + { + actionName: WssActionName.StorageClear, + handler: async (params) => { + verifyParamsByZod(params, StorageClearReqParamsSchema) + + const { storageName } = params + + const { storage } = await getStorage(storageName) + await storage.clear() + + WssUtils.instance.emit(WssActionName.StorageClear, { + reqParams: params, + res: buildSuccessResponse({ + data: null satisfies StorageClearResData, + }), + }) + }, + }, + ], +} diff --git a/packages/gpt-runner-web/server/src/types.ts b/packages/gpt-runner-web/server/src/types.ts index 6dbe927..963776e 100644 --- a/packages/gpt-runner-web/server/src/types.ts +++ b/packages/gpt-runner-web/server/src/types.ts @@ -1,11 +1,21 @@ +import type { WssActionName } from '@nicepkg/gpt-runner-shared/common' import type { NextFunction, Request, Response } from 'express' -export interface ControllerConfig { - namespacePath: string - controllers: Controller[] -} export interface Controller { url: string method: 'all' | 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options' | 'head' handler: (req: Request, any, any, Record>, res: Response, next: NextFunction) => Promise } +export interface ControllerConfig { + namespacePath: string + controllers: Controller[] +} + +export interface WssController { + actionName: WssActionName + handler: (params: any) => Promise +} + +export interface WssControllerConfig { + controllers: WssController[] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 55eca34..d748efc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -335,6 +335,12 @@ importers: minimatch: specifier: ^9.0.1 version: 9.0.1 + socket.io: + specifier: ^4.6.2 + version: 4.6.2 + socket.io-client: + specifier: ^4.6.2 + version: 4.6.2 zod: specifier: ^3.21.4 version: 3.21.4 @@ -3968,6 +3974,10 @@ packages: webpack-sources: 3.2.3 dev: false + /@socket.io/component-emitter@3.1.0: + resolution: {integrity: sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==} + dev: false + /@surma/rollup-plugin-off-main-thread@2.2.3: resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} dependencies: @@ -4354,13 +4364,11 @@ packages: /@types/cookie@0.4.1: resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==} - dev: true /@types/cors@2.8.13: resolution: {integrity: sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==} dependencies: '@types/node': 18.16.9 - dev: true /@types/debug@4.1.7: resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} @@ -5524,6 +5532,11 @@ packages: /base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + /base64id@2.0.0: + resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} + engines: {node: ^4.5.0 || >= 5.9} + dev: false + /batch@0.6.1: resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} dev: false @@ -6295,7 +6308,6 @@ packages: /cookie@0.4.2: resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} engines: {node: '>= 0.6'} - dev: true /cookie@0.5.0: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} @@ -7368,6 +7380,45 @@ packages: once: 1.4.0 dev: false + /engine.io-client@6.4.0: + resolution: {integrity: sha512-GyKPDyoEha+XZ7iEqam49vz6auPnNJ9ZBfy89f+rMMas8AuiMWOZ9PVzu8xb9ZC6rafUqiGHSCfu22ih66E+1g==} + dependencies: + '@socket.io/component-emitter': 3.1.0 + debug: 4.3.4 + engine.io-parser: 5.0.7 + ws: 8.11.0 + xmlhttprequest-ssl: 2.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + + /engine.io-parser@5.0.7: + resolution: {integrity: sha512-P+jDFbvK6lE3n1OL+q9KuzdOFWkkZ/cMV9gol/SbVfpyqfvrfrFTOFJ6fQm2VC3PZHlU3QPhVwmbsCnauHF2MQ==} + engines: {node: '>=10.0.0'} + dev: false + + /engine.io@6.4.2: + resolution: {integrity: sha512-FKn/3oMiJjrOEOeUub2WCox6JhxBXq/Zn3fZOMCBxKnNYtsdKjxhl7yR3fZhM9PV+rdE75SU5SYMc+2PGzo+Tg==} + engines: {node: '>=10.0.0'} + dependencies: + '@types/cookie': 0.4.1 + '@types/cors': 2.8.13 + '@types/node': 18.16.9 + accepts: 1.3.8 + base64id: 2.0.0 + cookie: 0.4.2 + cors: 2.8.5 + debug: 4.3.4 + engine.io-parser: 5.0.7 + ws: 8.11.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /enhanced-resolve@5.14.1: resolution: {integrity: sha512-Vklwq2vDKtl0y/vtwjSesgJ5MYS7Etuk5txS8VdKL4AOS1aUlD96zqIfsOSLQsdv3xgMRbtkWM8eG9XDfKUPow==} engines: {node: '>=10.13.0'} @@ -14459,6 +14510,55 @@ packages: engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} dev: true + /socket.io-adapter@2.5.2: + resolution: {integrity: sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==} + dependencies: + ws: 8.11.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + dev: false + + /socket.io-client@4.6.2: + resolution: {integrity: sha512-OwWrMbbA8wSqhBAR0yoPK6EdQLERQAYjXb3A0zLpgxfM1ZGLKoxHx8gVmCHA6pcclRX5oA/zvQf7bghAS11jRA==} + engines: {node: '>=10.0.0'} + dependencies: + '@socket.io/component-emitter': 3.1.0 + debug: 4.3.4 + engine.io-client: 6.4.0 + socket.io-parser: 4.2.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + + /socket.io-parser@4.2.4: + resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} + engines: {node: '>=10.0.0'} + dependencies: + '@socket.io/component-emitter': 3.1.0 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /socket.io@4.6.2: + resolution: {integrity: sha512-Vp+lSks5k0dewYTfwgPT9UeGGd+ht7sCpB7p0e83VgO4X/AHYWhXITMrNk/pg8syY2bpx23ptClCQuHhqi2BgQ==} + engines: {node: '>=10.0.0'} + dependencies: + accepts: 1.3.8 + base64id: 2.0.0 + debug: 4.3.4 + engine.io: 6.4.2 + socket.io-adapter: 2.5.2 + socket.io-parser: 4.2.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /sockjs@0.3.24: resolution: {integrity: sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==} dependencies: @@ -16827,6 +16927,19 @@ packages: optional: true dev: false + /ws@8.11.0: + resolution: {integrity: sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + /ws@8.13.0: resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} engines: {node: '>=10.0.0'} @@ -16860,6 +16973,11 @@ packages: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} dev: true + /xmlhttprequest-ssl@2.0.0: + resolution: {integrity: sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==} + engines: {node: '>=0.4.0'} + dev: false + /xtend@4.0.2: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'}