{"version":3,"file":"sse-_ImhG6NM.cjs","names":["_endpoint: string","res: ServerResponse","authInfo: AuthInfo | undefined","TLSSocket","body: string | unknown","contentType","parsedMessage: JSONRPCMessage","JSONRPCMessageSchema"],"sources":["../src/sse/sse.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { TLSSocket } from 'node:tls';\n\nimport type { AuthInfo, JSONRPCMessage, MessageExtraInfo, Transport, TransportSendOptions } from '@modelcontextprotocol/core-internal';\nimport { JSONRPCMessageSchema } from '@modelcontextprotocol/core-internal';\nimport contentType from 'content-type';\nimport getRawBody from 'raw-body';\n\nconst MAXIMUM_MESSAGE_SIZE = '4mb';\n\n/**\n * Configuration options for SSEServerTransport.\n * @deprecated Use StreamableHTTPServerTransport instead.\n */\nexport interface SSEServerTransportOptions {\n    /**\n     * @deprecated Use the host-header-validation middleware from @modelcontextprotocol/express instead.\n     */\n    allowedHosts?: string[];\n\n    /**\n     * @deprecated Use the host-header-validation middleware from @modelcontextprotocol/express instead.\n     */\n    allowedOrigins?: string[];\n\n    /**\n     * @deprecated Use the host-header-validation middleware from @modelcontextprotocol/express instead.\n     */\n    enableDnsRebindingProtection?: boolean;\n}\n\n/**\n * Server transport for SSE: this will send messages over an SSE connection and receive messages from HTTP POST requests.\n *\n * This transport is only available in Node.js environments.\n * @deprecated Use StreamableHTTPServerTransport from @modelcontextprotocol/server instead.\n */\nexport class SSEServerTransport implements Transport {\n    private _sseResponse?: ServerResponse;\n    private _sessionId: string;\n    private _options: SSEServerTransportOptions;\n    onclose?: () => void;\n    onerror?: ((error: Error) => void) | undefined;\n    onmessage?: (<T extends JSONRPCMessage>(message: T, extra?: MessageExtraInfo) => void) | undefined;\n\n    constructor(\n        private _endpoint: string,\n        private res: ServerResponse,\n        options?: SSEServerTransportOptions\n    ) {\n        this._sessionId = randomUUID();\n        this._options = options || { enableDnsRebindingProtection: false };\n    }\n\n    private validateRequestHeaders(req: IncomingMessage): string | undefined {\n        if (!this._options.enableDnsRebindingProtection) {\n            return undefined;\n        }\n\n        if (this._options.allowedHosts && this._options.allowedHosts.length > 0) {\n            const hostHeader = req.headers.host;\n            if (!hostHeader || !this._options.allowedHosts.includes(hostHeader)) {\n                return `Invalid Host header: ${hostHeader}`;\n            }\n        }\n\n        if (this._options.allowedOrigins && this._options.allowedOrigins.length > 0) {\n            const originHeader = req.headers.origin;\n            if (originHeader && !this._options.allowedOrigins.includes(originHeader)) {\n                return `Invalid Origin header: ${originHeader}`;\n            }\n        }\n\n        return undefined;\n    }\n\n    async start(): Promise<void> {\n        if (this._sseResponse) {\n            throw new Error('SSEServerTransport already started! If using Server class, note that connect() calls start() automatically.');\n        }\n\n        this.res.writeHead(200, {\n            'Content-Type': 'text/event-stream',\n            'Cache-Control': 'no-cache, no-transform',\n            Connection: 'keep-alive'\n        });\n\n        const dummyBase = 'http://localhost';\n        const endpointUrl = new URL(this._endpoint, dummyBase);\n        endpointUrl.searchParams.set('sessionId', this._sessionId);\n\n        const relativeUrlWithSession = endpointUrl.pathname + endpointUrl.search + endpointUrl.hash;\n\n        this.res.write(`event: endpoint\\ndata: ${relativeUrlWithSession}\\n\\n`);\n\n        this._sseResponse = this.res;\n        this.res.on('close', () => {\n            this._sseResponse = undefined;\n            this.onclose?.();\n        });\n    }\n\n    async handlePostMessage(req: IncomingMessage & { auth?: AuthInfo }, res: ServerResponse, parsedBody?: unknown): Promise<void> {\n        if (!this._sseResponse) {\n            const message = 'SSE connection not established';\n            res.writeHead(500).end(message);\n            throw new Error(message);\n        }\n\n        const validationError = this.validateRequestHeaders(req);\n        if (validationError) {\n            res.writeHead(403).end(validationError);\n            this.onerror?.(new Error(validationError));\n            return;\n        }\n\n        const authInfo: AuthInfo | undefined = req.auth;\n\n        const host = req.headers.host;\n        const protocol = req.socket instanceof TLSSocket ? 'https' : 'http';\n        const fullUrl = host && req.url ? new URL(req.url, `${protocol}://${host}`) : undefined;\n\n        const headers = new Headers();\n        for (const [key, value] of Object.entries(req.headers)) {\n            if (typeof value === 'string') {\n                headers.set(key, value);\n            } else if (Array.isArray(value)) {\n                for (const v of value) {\n                    headers.append(key, v);\n                }\n            }\n        }\n\n        const request = fullUrl ? new Request(fullUrl.toString(), { method: req.method ?? 'POST', headers }) : undefined;\n\n        let body: string | unknown;\n        try {\n            const ct = contentType.parse(req.headers['content-type'] ?? '');\n            if (ct.type !== 'application/json') {\n                throw new Error(`Unsupported content-type: ${ct.type}`);\n            }\n\n            body =\n                parsedBody ??\n                (await getRawBody(req, {\n                    limit: MAXIMUM_MESSAGE_SIZE,\n                    encoding: ct.parameters.charset ?? 'utf8'\n                }));\n        } catch (error) {\n            res.writeHead(400).end(String(error));\n            this.onerror?.(error as Error);\n            return;\n        }\n\n        try {\n            await this.handleMessage(typeof body === 'string' ? JSON.parse(body) : body, { request, authInfo });\n        } catch {\n            res.writeHead(400).end(`Invalid message: ${body}`);\n            return;\n        }\n\n        res.writeHead(202).end('Accepted');\n    }\n\n    async handleMessage(message: unknown, extra?: MessageExtraInfo): Promise<void> {\n        let parsedMessage: JSONRPCMessage;\n        try {\n            parsedMessage = JSONRPCMessageSchema.parse(message);\n        } catch (error) {\n            this.onerror?.(error as Error);\n            throw error;\n        }\n\n        this.onmessage?.(parsedMessage, extra);\n    }\n\n    async close(): Promise<void> {\n        this._sseResponse?.end();\n        this._sseResponse = undefined;\n        this.onclose?.();\n    }\n\n    async send(message: JSONRPCMessage, _options?: TransportSendOptions): Promise<void> {\n        if (!this._sseResponse) {\n            throw new Error('Not connected');\n        }\n\n        this._sseResponse.write(`event: message\\ndata: ${JSON.stringify(message)}\\n\\n`);\n    }\n\n    get sessionId(): string {\n        return this._sessionId;\n    }\n}\n"],"mappings":"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"}