@mastra/hono 1.7.10-alpha.0 → 1.7.10-alpha.6
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/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +14 -14
package/dist/index.cjs
CHANGED
|
@@ -268,7 +268,7 @@ var MastraServer = class extends _mastra_server_server_adapter.MastraServer {
|
|
|
268
268
|
if (body.requestContext) bodyRequestContext = body.requestContext;
|
|
269
269
|
} catch {}
|
|
270
270
|
}
|
|
271
|
-
if (c.req.method === "GET") try {
|
|
271
|
+
if (c.req.method === "GET" || c.req.method === "POST") try {
|
|
272
272
|
const encodedRequestContext = c.req.query("requestContext");
|
|
273
273
|
if (encodedRequestContext) try {
|
|
274
274
|
paramsRequestContext = JSON.parse(encodedRequestContext);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["RequestContext","ViewerRegistry","MASTRA_FRAMEWORK_PUBLIC_KEY","MastraServerBase","fetchResponse"],"sources":["../src/mcp-disconnect.ts","../src/auth-middleware.ts","../src/browser-stream/index.ts","../src/index.ts"],"sourcesContent":["/**\n * Propagates a client disconnect to the simulated Node response produced by `toReqRes`.\n *\n * `fetch-to-node` builds the outgoing body from `res` events but never observes cancellation\n * of the stream it hands back. When an MCP Streamable HTTP client drops its session, nothing\n * tells `res` that the socket is gone, so the MCP transport keeps its SSE keep-alive timer\n * armed. The next keep-alive tick writes into an already-closed stream controller, and because\n * that write originates in a timer callback the resulting `ERR_INVALID_STATE` is unhandled and\n * takes down the process.\n *\n * Emitting `close` on `res` is the signal the MCP Node transport listens for: it aborts the\n * request's AbortController, which breaks the write loop and tears down the SSE stream,\n * clearing the keep-alive timer. No post-disconnect write is ever attempted.\n */\nexport function propagateClientDisconnect(\n fetchResponse: Response,\n res: { emit: (event: string) => void; destroy?: () => void },\n): Response {\n const upstream = fetchResponse.body;\n if (!upstream) return fetchResponse;\n\n let disconnected = false;\n const disconnect = () => {\n if (disconnected) return;\n disconnected = true;\n try {\n res.emit('close');\n } catch {\n // Already torn down - the transport has nothing left to clean up.\n }\n // Deliberately *not* cancelling or destroying the bridge stream here. `fetch-to-node`\n // buffers writes and flushes them from a cork timer; tearing its controller down leaves\n // that pending flush to enqueue into a closed controller, which throws an unhandled\n // ERR_INVALID_STATE from a timer callback - the very crash this guards against.\n // Emitting `close` aborts the transport, which ends the response, so the bridge closes\n // its own controller in the right order once buffered data has drained.\n void reader.read().then(\n function drain({ done }): unknown {\n return done ? undefined : reader.read().then(drain);\n },\n () => {},\n );\n };\n\n const reader = upstream.getReader();\n const body = new ReadableStream<Uint8Array>({\n async pull(controller) {\n const { done, value } = await reader.read();\n if (done) {\n controller.close();\n return;\n }\n controller.enqueue(value);\n },\n cancel() {\n disconnect();\n },\n });\n\n return new Response(body, {\n status: fetchResponse.status,\n statusText: fetchResponse.statusText,\n headers: fetchResponse.headers,\n });\n}\n","import type { Mastra } from '@mastra/core/mastra';\nimport { RequestContext } from '@mastra/core/request-context';\nimport { coreAuthMiddleware } from '@mastra/server/auth';\nimport type { Context, MiddlewareHandler } from 'hono';\n\nexport interface HonoAuthMiddlewareOptions {\n mastra: Mastra;\n requiresAuth?: boolean;\n}\n\nexport function createAuthMiddleware({ mastra, requiresAuth = true }: HonoAuthMiddlewareOptions): MiddlewareHandler {\n return async (c: Context, next) => {\n if (!requiresAuth) {\n return next();\n }\n\n const authConfig = mastra.getServer()?.auth;\n if (!authConfig) {\n return next();\n }\n\n const requestContext = c.get('requestContext') ?? new RequestContext();\n c.set('requestContext', requestContext);\n c.set('mastra', c.get('mastra') ?? mastra);\n\n const path = c.req.path;\n const method = c.req.method;\n const customRouteAuthConfig = new Map<string, boolean>(c.get('customRouteAuthConfig') ?? []);\n customRouteAuthConfig.set(`${method}:${path}`, true);\n\n const authHeader = c.req.header('Authorization');\n let token: string | null = authHeader ? authHeader.replace('Bearer ', '') : null;\n if (!token) {\n token = c.req.query('apiKey') || null;\n }\n\n const result = await coreAuthMiddleware({\n path,\n method,\n getHeader: name => c.req.header(name),\n mastra,\n authConfig,\n customRouteAuthConfig,\n requestContext,\n rawRequest: c.req.raw,\n token,\n buildAuthorizeContext: () => c,\n });\n\n if (result.action === 'next') {\n return next();\n }\n\n return c.json(result.body as any, result.status as any);\n };\n}\n","import type { createNodeWebSocket as CreateNodeWebSocket } from '@hono/node-ws';\nimport { handleInputMessage, ViewerRegistry } from '@mastra/server/browser-stream';\nimport type { BrowserStreamConfig, BrowserStreamResult } from '@mastra/server/browser-stream';\nimport type { Env, Hono, Schema } from 'hono';\n\n/**\n * Set up WebSocket-based browser stream endpoint for real-time screencast viewing.\n *\n * Creates a WebSocket route at `/browser/:agentId/stream` that:\n * - Accepts viewer connections\n * - Starts screencast when first viewer connects\n * - Broadcasts frames to all connected viewers\n * - Stops screencast when last viewer disconnects\n *\n * **Note**: Requires `ws` package to be installed. If not available, returns null\n * and logs a warning. Browser streaming will be disabled but everything else works.\n *\n * @param app - The Hono application instance\n * @param config - Configuration for browser stream\n * @returns Object containing injectWebSocket function and registry instance, or null if ws is not available\n *\n * @example\n * ```typescript\n * import { Hono } from 'hono';\n * import { serve } from '@hono/node-server';\n * import { setupBrowserStream } from '@mastra/hono';\n *\n * const app = new Hono();\n * const browserStream = await setupBrowserStream(app, {\n * getToolset: (agentId) => browserToolsets.get(agentId),\n * });\n *\n * const server = serve({ fetch: app.fetch, port: 4111 });\n * browserStream?.injectWebSocket(server);\n * ```\n */\nexport async function setupBrowserStream<E extends Env, S extends Schema, B extends string>(\n app: Hono<E, S, B>,\n config: BrowserStreamConfig,\n): Promise<BrowserStreamResult | null> {\n // Dynamic import to avoid bundling ws into non-Node environments (e.g. Cloudflare Workers).\n // The variable-based specifier prevents bundlers from resolving the module at build time.\n let createNodeWebSocket: typeof CreateNodeWebSocket;\n try {\n const mod = '@hono/node-ws';\n const honoNodeWs = await import(/* @vite-ignore */ /* webpackIgnore: true */ mod);\n createNodeWebSocket = honoNodeWs.createNodeWebSocket;\n } catch {\n // @hono/node-ws is not available (e.g. no ws package installed).\n // This is expected in non-Node environments — silently disable browser streaming.\n return null;\n }\n\n const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app });\n const registry = new ViewerRegistry();\n\n // Normalize the API prefix so we can build paths like `${apiPrefix}/agents/...`\n // without producing `//agents/...` when the prefix is missing or has a single\n // trailing slash. Anything weirder than that (e.g. `'/api//'`) is a config\n // bug we don't try to silently fix.\n const rawPrefix = config.apiPrefix ?? '/api';\n const trimmed = rawPrefix.endsWith('/') ? rawPrefix.slice(0, -1) : rawPrefix;\n const apiPrefix = trimmed || '/api';\n\n app.get(\n '/browser/:agentId/stream',\n upgradeWebSocket(c => {\n const agentId = c.req.param('agentId')!;\n const threadId = c.req.query('threadId');\n // Use composite key for thread-scoped screencasts\n const viewerKey = threadId ? `${agentId}:${threadId}` : agentId;\n\n return {\n onOpen(_event, ws) {\n // Send connected status immediately\n ws.send(JSON.stringify({ status: 'connected' }));\n\n // Add to registry (starts screencast if first viewer)\n // Fire-and-forget: screencast starts asynchronously\n // Pass agentId for toolset lookup, but viewerKey for registry scoping\n void registry.addViewer(viewerKey, ws, config.getToolset, agentId, threadId);\n },\n\n onMessage(event, _ws) {\n const data = typeof event.data === 'string' ? event.data : null;\n if (data) {\n void handleInputMessage(data, config.getToolset, agentId, threadId);\n }\n },\n\n onClose(_event, ws) {\n // Remove from registry (stops screencast if last viewer)\n // Fire-and-forget: cleanup is best-effort\n void registry.removeViewer(viewerKey, ws);\n },\n\n onError(event, ws) {\n console.error('[BrowserStream] WebSocket error:', event);\n // Fire-and-forget: cleanup is best-effort\n void registry.removeViewer(viewerKey, ws);\n },\n };\n }),\n );\n\n // Browser session probe endpoint - tells the client whether to open a WS.\n // Returns:\n // - screencastAvailable: true (this route only exists if setupBrowserStream succeeded)\n // - hasSession: whether the agent has an active browser session for the given thread\n app.get(`${apiPrefix}/agents/:agentId/browser/session`, async c => {\n const agentId = c.req.param('agentId');\n if (!agentId) {\n return c.json({ error: 'Agent ID is required' }, 400);\n }\n\n const threadId = c.req.query('threadId');\n const toolset = await config.getToolset(agentId);\n\n if (!toolset) {\n return c.json({ hasSession: false, screencastAvailable: true });\n }\n\n const hasSession = threadId ? toolset.hasThreadSession(threadId) : false;\n return c.json({ hasSession, screencastAvailable: true });\n });\n\n // Close browser session endpoint\n app.post(`${apiPrefix}/agents/:agentId/browser/close`, async c => {\n const agentId = c.req.param('agentId');\n if (!agentId) {\n return c.json({ error: 'Agent ID is required' }, 400);\n }\n\n const toolset = await config.getToolset(agentId);\n if (!toolset) {\n return c.json({ error: 'No browser session for this agent' }, 404);\n }\n\n try {\n // Parse threadId from request body\n let threadId: string | undefined;\n try {\n const body = await c.req.json();\n threadId = body?.threadId;\n } catch {\n // No body or invalid JSON - proceed without threadId\n }\n\n const scope = toolset.getScope();\n const viewerKey = threadId ? `${agentId}:${threadId}` : agentId;\n\n // For thread scope with a threadId, close only that thread's session\n if (scope === 'thread' && threadId) {\n // Close the session in the registry (stops screencast for this thread)\n await registry.closeBrowserSession(viewerKey);\n\n // Close just this thread's browser session\n if ('closeThreadSession' in toolset && typeof toolset.closeThreadSession === 'function') {\n await toolset.closeThreadSession(threadId);\n }\n } else {\n // For shared scope or no threadId, close the entire browser\n await registry.closeBrowserSession(viewerKey);\n await toolset.close();\n }\n\n return c.json({ success: true });\n } catch (error) {\n console.error(`[BrowserStream] Error closing browser for ${agentId}:`, error);\n return c.json({ error: 'Failed to close browser' }, 500);\n }\n });\n\n return { injectWebSocket: injectWebSocket as (server: unknown) => void, registry };\n}\n","import type { ToolsInput } from '@mastra/core/agent';\nimport type { Mastra } from '@mastra/core/mastra';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { InMemoryTaskStore } from '@mastra/server/a2a/store';\n\nimport type { MCPHttpTransportResult, MCPSseTransportResult } from '@mastra/server/handlers/mcp';\nimport type { ParsedRequestParams, ServerRoute } from '@mastra/server/server-adapter';\nimport {\n MASTRA_FRAMEWORK_PUBLIC_KEY,\n MastraServer as MastraServerBase,\n applyMcpRequestAuth,\n checkRouteFGA,\n getCustomHTTPExceptionResponse,\n isZodError,\n normalizeQueryParams,\n redactStreamChunk,\n serializeStreamChunk,\n} from '@mastra/server/server-adapter';\nimport { toReqRes, toFetchResponse } from 'fetch-to-node';\nimport type { Context, ExecutionContext, HonoRequest, MiddlewareHandler } from 'hono';\nimport { bodyLimit } from 'hono/body-limit';\nimport { stream } from 'hono/streaming';\nimport { propagateClientDisconnect } from './mcp-disconnect';\nexport { createAuthMiddleware } from './auth-middleware';\nexport type { HonoAuthMiddlewareOptions } from './auth-middleware';\n// Browser stream setup (Hono-specific WebSocket implementation)\nexport { setupBrowserStream } from './browser-stream';\n\ntype HasPermissionFn = (userPerms: string[], required: string) => boolean;\nlet _hasPermissionPromise: Promise<HasPermissionFn | undefined> | undefined;\nfunction loadHasPermission(): Promise<HasPermissionFn | undefined> {\n if (!_hasPermissionPromise) {\n _hasPermissionPromise = import('@mastra/core/auth/ee')\n .then(m => m.hasPermission)\n .catch(() => {\n console.error(\n '[@mastra/hono] Auth features require @mastra/core >= 1.6.0. Please upgrade: npm install @mastra/core@latest',\n );\n return undefined;\n });\n }\n return _hasPermissionPromise;\n}\n\n// Export type definitions for Hono app configuration\nexport type HonoVariables = {\n mastra: Mastra;\n requestContext: RequestContext;\n registeredTools: ToolsInput;\n abortSignal: AbortSignal;\n taskStore: InMemoryTaskStore;\n customRouteAuthConfig?: Map<string, boolean>;\n cachedBody?: unknown;\n /**\n * True when the current request targets a route the framework has declared\n * public (`requiresAuth: false`). Adapter authors MUST wrap user-registered\n * middleware with {@link skipIfFrameworkPublic} so that user middleware\n * cannot 401 these routes.\n */\n [MASTRA_FRAMEWORK_PUBLIC_KEY]?: boolean;\n};\n\n// Re-export the framework-public context key so users configuring Hono apps\n// can reference it directly without importing from @mastra/server.\nexport { MASTRA_FRAMEWORK_PUBLIC_KEY } from '@mastra/server/server-adapter';\n\n/**\n * Wrap a Hono middleware handler so it becomes a no-op for framework-public\n * routes (routes registered with `requiresAuth: false`).\n *\n * Adapters that expose user-provided middleware — for example `serverMiddleware`\n * on the Mastra instance or `server.middleware` in Mastra config — MUST wrap\n * those handlers with this before registering them. This is the framework's\n * guarantee that user middleware cannot accidentally (or intentionally) 401\n * routes the framework needs to keep reachable (e.g. Studio sign-in endpoints).\n *\n * The framework-public flag is computed once per request by\n * {@link MastraServer.registerContextMiddleware} and stashed on the Hono\n * context under `MASTRA_FRAMEWORK_PUBLIC_KEY`.\n */\nexport const skipIfFrameworkPublic = (handler: MiddlewareHandler): MiddlewareHandler => {\n return async (c, next) => {\n if (c.get(MASTRA_FRAMEWORK_PUBLIC_KEY)) {\n return next();\n }\n return handler(c, next);\n };\n};\n\n/**\n * Context key holding a pristine clone of the incoming request, captured by\n * the context middleware before user middleware runs. The custom-route bridge\n * reads the body from this clone so user middleware that consumes the request\n * body (e.g. `await c.req.json()`) does not break custom API routes.\n */\nconst MASTRA_PRISTINE_REQUEST_KEY = '__mastraPristineRequest';\n\nconst BODY_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);\n\nexport type HonoBindings = {};\n\n/**\n * Generic handler function type compatible across Hono versions.\n * Uses a minimal signature that all Hono middleware handlers satisfy.\n */\ntype HonoRouteHandler = (...args: any[]) => any;\n\n/**\n * Minimal interface representing what MastraServer needs from a Hono app.\n * This allows any Hono app instance to be passed without strict generic matching,\n * avoiding the version mismatch issues that occur with Hono's strict generic types.\n */\nexport interface HonoApp {\n use(path: string, ...handlers: HonoRouteHandler[]): unknown;\n get(path: string, ...handlers: HonoRouteHandler[]): unknown;\n post(path: string, ...handlers: HonoRouteHandler[]): unknown;\n put(path: string, ...handlers: HonoRouteHandler[]): unknown;\n delete(path: string, ...handlers: HonoRouteHandler[]): unknown;\n patch(path: string, ...handlers: HonoRouteHandler[]): unknown;\n all(path: string, ...handlers: HonoRouteHandler[]): unknown;\n}\n\nexport class MastraServer extends MastraServerBase<HonoApp, HonoRequest, Context> {\n createContextMiddleware(): MiddlewareHandler {\n return async (c, next) => {\n // Preserve a pristine clone of the request before user middleware runs.\n // `Request.clone()` tees the body stream, so the clone stays readable\n // even after middleware consumes the original (json/text/formData/raw).\n // Only taken when custom routes exist — the bridge is the sole consumer.\n if (this.hasCustomRouteHandler && BODY_METHODS.has(c.req.method) && c.req.raw.body) {\n c.set(MASTRA_PRISTINE_REQUEST_KEY, c.req.raw.clone());\n }\n\n // Patch req.json() to prevent \"Body is unusable\" errors when the body is read multiple times\n // e.g. by middleware and then by an agent.\n const originalJson = c.req.json.bind(c.req);\n let jsonPromise: Promise<any> | undefined;\n\n c.req.json = () => {\n if (!jsonPromise) {\n jsonPromise = originalJson().then(body => {\n // Cache in context if needed explicitly, though the promise memoization handles the reuse\n c.set('cachedBody', body);\n return body;\n });\n }\n return jsonPromise;\n };\n\n // Parse request context from request body and add to context\n\n let bodyRequestContext: Record<string, any> | undefined;\n let paramsRequestContext: Record<string, any> | undefined;\n\n // Parse request context from request body (POST/PUT)\n if (c.req.method === 'POST' || c.req.method === 'PUT') {\n const contentType = c.req.header('content-type');\n const contentLength = c.req.header('content-length');\n // Only parse if content-type is JSON and body is not empty\n if (contentType?.includes('application/json') && contentLength !== '0') {\n try {\n const body = (await c.req.raw.clone().json()) as { requestContext?: Record<string, any> };\n if (body.requestContext) {\n bodyRequestContext = body.requestContext;\n }\n } catch {\n // Body parsing failed, continue without body\n }\n }\n }\n\n // Parse request context from query params (GET)\n if (c.req.method === 'GET') {\n try {\n const encodedRequestContext = c.req.query('requestContext');\n if (encodedRequestContext) {\n // Try JSON first\n try {\n paramsRequestContext = JSON.parse(encodedRequestContext);\n } catch {\n // Fallback to base64(JSON)\n try {\n const json = Buffer.from(encodedRequestContext, 'base64').toString('utf-8');\n paramsRequestContext = JSON.parse(json);\n } catch {\n // ignore if still invalid\n }\n }\n }\n } catch {\n // ignore query parsing errors\n }\n }\n\n const requestContext = this.mergeRequestContext({ paramsRequestContext, bodyRequestContext });\n this.applyRequestMetadataToContext({\n requestContext,\n getHeader: name => c.req.header(name),\n });\n\n // Add relevant contexts to hono context\n c.set('requestContext', requestContext);\n c.set('mastra', this.mastra);\n c.set('registeredTools', this.tools || {});\n c.set('taskStore', this.taskStore);\n c.set('abortSignal', c.req.raw.signal);\n c.set('customRouteAuthConfig', this.customRouteAuthConfig);\n\n return next();\n };\n }\n async stream(route: ServerRoute, res: Context, result: { fullStream: ReadableStream }): Promise<any> {\n const streamFormat = route.streamFormat || 'stream';\n\n if (streamFormat === 'sse') {\n res.header('Content-Type', 'text/event-stream');\n res.header('Cache-Control', 'no-cache');\n res.header('Connection', 'keep-alive');\n res.header('X-Accel-Buffering', 'no');\n } else {\n res.header('Content-Type', 'text/plain');\n }\n res.header('Transfer-Encoding', 'chunked');\n\n return stream(\n res,\n async stream => {\n if (streamFormat === 'sse' && route.sseFlushOnConnect) {\n await stream.write(': connected\\n\\n');\n }\n\n const readableStream = result instanceof ReadableStream ? result : result.fullStream;\n const reader = readableStream.getReader();\n\n stream.onAbort(() => {\n void reader.cancel('request aborted').catch(() => {});\n });\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n if (value) {\n if (streamFormat === 'sse' && typeof value === 'string' && value.startsWith(':')) {\n await stream.write(value);\n continue;\n }\n\n // Optionally redact sensitive data (system prompts, tool definitions, API keys) before sending to the client\n const shouldRedact = this.streamOptions?.redact ?? true;\n const outputValue = shouldRedact ? redactStreamChunk(value) : value;\n // A chunk that can't be serialized must not kill the stream — skip it and keep streaming\n const serialized = serializeStreamChunk(outputValue);\n if (!serialized.ok) {\n this.mastra.getLogger()?.error('Failed to serialize stream chunk, skipping', {\n path: route.path,\n chunkType: (outputValue as { type?: string })?.type,\n error: serialized.error.message,\n });\n continue;\n }\n if (streamFormat === 'sse') {\n await stream.write(`data: ${serialized.json}\\n\\n`);\n } else {\n await stream.write(serialized.json + '\\x1E');\n }\n }\n }\n\n if (streamFormat === 'sse') {\n await stream.write('data: [DONE]\\n\\n');\n }\n } catch (error) {\n this.mastra.getLogger()?.error('Error in stream processing', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n } finally {\n await stream.close();\n }\n },\n async err => {\n this.mastra.getLogger()?.error('Stream error callback', {\n error: err instanceof Error ? { message: err.message, stack: err.stack } : err,\n });\n },\n );\n }\n\n async getParams(route: ServerRoute, request: HonoRequest): Promise<ParsedRequestParams> {\n const urlParams = request.param();\n // Use queries() to get all values for repeated params (e.g., ?tags=a&tags=b -> { tags: ['a', 'b'] })\n const queryParams = normalizeQueryParams(request.queries());\n let body: unknown;\n let bodyParseError: { message: string } | undefined;\n\n if (route.method === 'POST' || route.method === 'PUT' || route.method === 'PATCH' || route.method === 'DELETE') {\n const contentType = request.header('content-type') || '';\n\n if (contentType.includes('multipart/form-data')) {\n try {\n const formData = await request.formData();\n body = await this.parseFormData(formData);\n } catch (error) {\n this.mastra.getLogger()?.error('Failed to parse multipart form data', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n // Re-throw size limit errors, let others fall through to validation\n if (error instanceof Error && error.message.toLowerCase().includes('size')) {\n throw error;\n }\n bodyParseError = {\n message: error instanceof Error ? error.message : 'Failed to parse multipart form data',\n };\n }\n } else if (contentType.includes('application/json')) {\n // Clone the request to read the body text first\n // This allows us to check if there's actual content before parsing\n const clonedReq = request.raw.clone();\n const bodyText = await clonedReq.text();\n\n if (bodyText && bodyText.trim().length > 0) {\n // There's actual content - try to parse it as JSON\n try {\n body = JSON.parse(bodyText);\n } catch (error) {\n this.mastra.getLogger()?.error('Failed to parse JSON body', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n // Track JSON parse error to return 400 Bad Request\n bodyParseError = {\n message: error instanceof Error ? error.message : 'Invalid JSON in request body',\n };\n }\n }\n // Empty body is ok - body remains undefined\n }\n }\n return { urlParams, queryParams, body, bodyParseError };\n }\n\n /**\n * Parse FormData into a plain object, converting File objects to Buffers.\n */\n private async parseFormData(formData: FormData): Promise<Record<string, unknown>> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of formData.entries()) {\n if (value instanceof File) {\n const arrayBuffer = await value.arrayBuffer();\n result[key] = Buffer.from(arrayBuffer);\n } else if (typeof value === 'string') {\n // Try to parse JSON strings (like 'options')\n try {\n result[key] = JSON.parse(value);\n } catch {\n result[key] = value;\n }\n } else {\n result[key] = value;\n }\n }\n\n return result;\n }\n\n async sendResponse(route: ServerRoute, response: Context, result: unknown, prefix?: string): Promise<any> {\n const resolvedPrefix = prefix ?? this.prefix ?? '';\n\n // Apply refresh headers from transparent session refresh (e.g. Set-Cookie after token refresh)\n if (result && typeof result === 'object' && '__refreshHeaders' in result) {\n const refreshHeaders = (result as any).__refreshHeaders as Record<string, string>;\n for (const [key, value] of Object.entries(refreshHeaders)) {\n response.header(key, value);\n }\n delete (result as any).__refreshHeaders;\n }\n\n if (route.responseType === 'json') {\n return response.json(result as any, 200);\n } else if (route.responseType === 'stream') {\n return this.stream(route, response, result as { fullStream: ReadableStream });\n } else if (route.responseType === 'datastream-response') {\n const fetchResponse = result as globalThis.Response;\n return fetchResponse;\n } else if (route.responseType === 'mcp-http') {\n // MCP Streamable HTTP transport\n const { server, httpPath, mcpOptions: routeMcpOptions } = result as MCPHttpTransportResult;\n const { req, res } = toReqRes(response.req.raw);\n\n // Merge class-level mcpOptions with route-specific options (route takes precedence)\n const { setRequestAuth, ...options } = { ...this.mcpOptions, ...routeMcpOptions };\n\n // `toReqRes` builds a fresh IncomingMessage, so the principal resolved by\n // auth middleware never reaches the MCP transport unless we bridge it here.\n // This runs before startHTTP so every branch (stateless, existing session,\n // new session) sees the same `req.auth`.\n await applyMcpRequestAuth({ req, requestContext: response.get('requestContext'), setRequestAuth });\n\n // Do NOT await startHTTP — let it run in the background so SSE\n // notifications stream to the client as they are written.\n // toFetchResponse resolves when headers are sent, not when the body finishes.\n server\n .startHTTP({\n url: new URL(response.req.url),\n httpPath: `${resolvedPrefix}${httpPath}`,\n req,\n res,\n options: Object.keys(options).length > 0 ? options : undefined,\n })\n .catch((e: unknown) => {\n this.mastra.getLogger()?.error('[MCP HTTP] Error in background startHTTP:', {\n error: e instanceof Error ? { message: e.message, stack: e.stack } : e,\n });\n try {\n if (!res.headersSent) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n jsonrpc: '2.0',\n error: { code: -32603, message: 'Internal server error' },\n id: null,\n }),\n );\n }\n } catch {\n // Response stream already closed or destroyed - nothing more to do\n }\n });\n\n return propagateClientDisconnect(await toFetchResponse(res), res);\n } else if (route.responseType === 'mcp-sse') {\n // MCP SSE transport\n const { server, ssePath, messagePath } = result as MCPSseTransportResult;\n\n try {\n // SSE has no Node request to hang `req.auth` on, so resolve the auth info\n // here and pass it explicitly. Reuse the same bridge as streamable HTTP so\n // a `setRequestAuth` hook sees a real request object.\n const { req } = toReqRes(response.req.raw);\n await applyMcpRequestAuth({\n req,\n requestContext: response.get('requestContext'),\n setRequestAuth: this.mcpOptions?.setRequestAuth,\n });\n\n return await server.startHonoSSE({\n url: new URL(response.req.url),\n ssePath: `${resolvedPrefix}${ssePath}`,\n messagePath: `${resolvedPrefix}${messagePath}`,\n context: response,\n authInfo: (req as typeof req & { auth?: unknown }).auth,\n });\n } catch {\n return response.json({ error: 'Error handling MCP SSE request' }, 500);\n }\n } else {\n return response.status(500);\n }\n }\n\n async registerRoute(\n app: HonoApp,\n route: ServerRoute,\n { prefix: prefixParam }: { prefix?: string } = {},\n ): Promise<void> {\n // Default prefix to this.prefix if not provided, or empty string\n const prefix = prefixParam ?? this.prefix ?? '';\n\n const maxSize = route.maxBodySize ?? this.bodyLimitOptions?.maxSize;\n const isBodyMethod = ['POST', 'PUT', 'PATCH', 'DELETE'].includes(route.method.toUpperCase());\n\n // Build middleware array\n const middlewares: MiddlewareHandler[] = [];\n\n if (isBodyMethod && maxSize !== undefined) {\n middlewares.push(\n bodyLimit({\n maxSize,\n onError: (c: Context) => {\n let errorResponse: unknown = { error: 'Request body too large' };\n if (route.maxBodySize === undefined && this.bodyLimitOptions) {\n try {\n errorResponse = this.bodyLimitOptions.onError(errorResponse);\n } catch {\n // Fall back to the default response.\n }\n }\n return c.json(errorResponse, 413);\n },\n }),\n );\n }\n\n app[route.method.toLowerCase() as 'get' | 'post' | 'put' | 'delete' | 'patch' | 'all'](\n `${prefix}${route.path}`,\n ...middlewares,\n async (c: Context) => {\n // Check route-level authentication/authorization\n const authResult = await this.checkRouteAuth(route, {\n path: c.req.path,\n method: c.req.method,\n getHeader: name => c.req.header(name),\n getQuery: name => c.req.query(name),\n requestContext: c.get('requestContext'),\n request: c.req.raw,\n buildAuthorizeContext: () => c,\n });\n\n if (authResult) {\n // Apply any refresh headers (e.g. Set-Cookie from transparent session refresh)\n if (authResult.headers) {\n for (const [key, value] of Object.entries(authResult.headers)) {\n c.header(key, value as string);\n }\n }\n\n // If this is an auth error (not just a success-with-headers), return error response\n if (authResult.error) {\n return c.json({ error: authResult.error }, authResult.status as any);\n }\n }\n\n const params = await this.getParams(route, c.req);\n\n // Return 400 Bad Request if body parsing failed (e.g., malformed JSON)\n if (params.bodyParseError) {\n return c.json(\n {\n error: 'Invalid request body',\n issues: [{ field: 'body', message: params.bodyParseError.message }],\n },\n 400,\n );\n }\n\n if (params.queryParams) {\n try {\n params.queryParams = await this.parseQueryParams(route, params.queryParams);\n } catch (error) {\n this.mastra.getLogger()?.error('Error parsing query params', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n if (isZodError(error)) {\n const { status, body } = this.resolveValidationError(route, error, 'query');\n return c.json(body as any, status as any);\n }\n return c.json(\n {\n error: 'Invalid query parameters',\n issues: [{ field: 'unknown', message: error instanceof Error ? error.message : 'Unknown error' }],\n },\n 400,\n );\n }\n }\n\n if (params.body !== undefined || route.bodySchema) {\n try {\n params.body = await this.parseBody(route, params.body);\n } catch (error) {\n this.mastra.getLogger()?.error('Error parsing body', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n if (isZodError(error)) {\n const { status, body } = this.resolveValidationError(route, error, 'body');\n return c.json(body as any, status as any);\n }\n return c.json(\n {\n error: 'Invalid request body',\n issues: [{ field: 'unknown', message: error instanceof Error ? error.message : 'Unknown error' }],\n },\n 400,\n );\n }\n }\n\n // Parse path params through pathParamSchema for type coercion (e.g., z.coerce.number())\n if (params.urlParams) {\n try {\n params.urlParams = await this.parsePathParams(route, params.urlParams);\n } catch (error) {\n this.mastra.getLogger()?.error('Error parsing path params', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n if (isZodError(error)) {\n const { status, body } = this.resolveValidationError(route, error, 'path');\n return c.json(body as any, status as any);\n }\n return c.json(\n {\n error: 'Invalid path parameters',\n issues: [{ field: 'unknown', message: error instanceof Error ? error.message : 'Unknown error' }],\n },\n 400,\n );\n }\n }\n\n const handlerParams = {\n ...params.urlParams,\n ...params.queryParams,\n ...(typeof params.body === 'object' ? params.body : {}),\n requestContext: c.get('requestContext'),\n mastra: this.mastra,\n registeredTools: c.get('registeredTools'),\n taskStore: c.get('taskStore'),\n abortSignal: c.get('abortSignal'),\n routePrefix: prefix,\n request: c.req.raw, // Standard Request object with headers/cookies\n };\n\n // Check route permission requirement (EE feature)\n // Uses convention-based permission derivation: permissions are auto-derived\n // from route path/method unless explicitly set or route is public\n const requestContext = c.get('requestContext');\n // Check if any auth is configured (studio or server) for RBAC\n const hasAuth = this.mastra.getStudio?.()?.auth || this.mastra.getServer()?.auth;\n if (hasAuth) {\n const hasPermission = await loadHasPermission();\n if (hasPermission) {\n const userPermissions = requestContext.get('mastra__userPermissions') as string[] | undefined;\n const permissionError = this.checkRoutePermission(route, userPermissions, hasPermission, requestContext);\n\n if (permissionError) {\n return c.json(\n {\n error: permissionError.error,\n message: permissionError.message,\n },\n permissionError.status as any,\n );\n }\n }\n }\n\n // Check FGA authorization (EE feature)\n const fgaError = await checkRouteFGA(this.mastra, route, c.get('requestContext'), {\n ...params.urlParams,\n ...params.queryParams,\n ...(typeof params.body === 'object' ? params.body : {}),\n });\n if (fgaError) {\n return c.json({ error: fgaError.error, message: fgaError.message }, fgaError.status as any);\n }\n\n try {\n const result = await route.handler(handlerParams);\n return this.sendResponse(route, c, result, prefix);\n } catch (error) {\n // 4xx errors are client conditions (e.g. no session, expired token) and are\n // already returned as structured HTTP responses below. Logging them as errors\n // produces noise for callers — skip the logger call for those cases.\n const httpStatus =\n error && typeof error === 'object' && 'status' in error ? (error as any).status : undefined;\n const isClientError = typeof httpStatus === 'number' && httpStatus >= 400 && httpStatus < 500;\n if (!isClientError) {\n this.mastra.getLogger()?.error('Error calling handler', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n path: route.path,\n method: route.method,\n });\n }\n const customResponse = getCustomHTTPExceptionResponse(error);\n if (customResponse) {\n return customResponse;\n }\n\n // Check if it's an HTTPException or MastraError with a status code\n if (error && typeof error === 'object') {\n // Check for direct status property (HTTPException)\n if ('status' in error) {\n const status = (error as any).status;\n let safeCause: { failingItems: unknown[] } | undefined;\n try {\n const raw = error instanceof Error ? error.cause : undefined;\n if (\n raw &&\n typeof raw === 'object' &&\n !Array.isArray(raw) &&\n 'failingItems' in raw &&\n Array.isArray((raw as any).failingItems)\n ) {\n safeCause = { failingItems: (raw as any).failingItems };\n }\n } catch {\n // serialization or access error — omit cause\n }\n return c.json(\n {\n error: error instanceof Error ? error.message : 'Unknown error',\n ...(safeCause ? { cause: safeCause } : {}),\n },\n status,\n );\n }\n // Check for MastraError with status in details\n if ('details' in error && error.details && typeof error.details === 'object' && 'status' in error.details) {\n const status = (error.details as any).status;\n return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, status);\n }\n }\n return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500);\n }\n },\n );\n }\n\n async registerCustomApiRoutes(): Promise<void> {\n const routes = await this.registerSchemaApiRoutes();\n if (!(await this.buildCustomRouteHandler(routes))) return;\n\n for (const route of routes) {\n const serverRoute: ServerRoute = {\n method: route.method as any,\n path: route.path,\n responseType: 'json',\n handler: async () => {},\n requiresAuth: route.requiresAuth,\n requiresPermission: route.requiresPermission,\n fga: route.fga,\n };\n\n const routeHandler: MiddlewareHandler = async (c: Context) => {\n // Per-route auth check (same pattern as registerRoute)\n const authError = await this.checkRouteAuth(serverRoute, {\n path: c.req.path,\n method: c.req.method,\n getHeader: name => c.req.header(name),\n getQuery: name => c.req.query(name),\n requestContext: c.get('requestContext'),\n request: c.req.raw,\n buildAuthorizeContext: () => c,\n });\n\n if (authError) {\n if (authError.headers) {\n for (const [key, value] of Object.entries(authError.headers)) {\n c.header(key, value as string);\n }\n }\n if (authError.error) {\n return c.json({ error: authError.error }, authError.status as any);\n }\n }\n\n const requestContext = c.get('requestContext');\n // Check if any auth is configured (studio or server) for RBAC\n const hasAuth = this.mastra.getStudio?.()?.auth || this.mastra.getServer()?.auth;\n if (hasAuth) {\n const hasPermission = await loadHasPermission();\n if (hasPermission) {\n const userPermissions = requestContext.get('mastra__userPermissions') as string[] | undefined;\n const permissionError = this.checkRoutePermission(\n serverRoute,\n userPermissions,\n hasPermission,\n requestContext,\n );\n if (permissionError) {\n return c.json(\n { error: permissionError.error, message: permissionError.message },\n permissionError.status as any,\n );\n }\n }\n }\n\n // Use the pristine clone captured by the context middleware (before\n // user middleware ran) so body reads survive middleware that already\n // consumed `c.req.raw`.\n const pristineRequest = (c.get(MASTRA_PRISTINE_REQUEST_KEY) as Request | undefined) ?? c.req.raw;\n\n // Check FGA authorization (EE feature)\n let bodyParams: Record<string, unknown> = {};\n const contentType = c.req.header('content-type');\n if (contentType?.includes('application/json')) {\n try {\n const body = (await pristineRequest.clone().json()) as unknown;\n if (body && typeof body === 'object' && !Array.isArray(body)) {\n bodyParams = body as Record<string, unknown>;\n }\n } catch {\n bodyParams = {};\n }\n } else if (\n contentType?.includes('application/x-www-form-urlencoded') ||\n contentType?.includes('multipart/form-data')\n ) {\n try {\n bodyParams = Object.fromEntries(await pristineRequest.clone().formData());\n } catch {\n bodyParams = {};\n }\n }\n const fgaError = await checkRouteFGA(this.mastra, serverRoute, c.get('requestContext'), {\n ...c.req.param(),\n ...Object.fromEntries(new URL(c.req.url).searchParams.entries()),\n ...bodyParams,\n });\n if (fgaError) {\n return c.json({ error: fgaError.error, message: fgaError.message }, fgaError.status as any);\n }\n\n const reqHeaders: Record<string, string | string[] | undefined> = {};\n c.req.raw.headers.forEach((v, k) => {\n reqHeaders[k] = v;\n });\n // Forward the platform execution context (e.g. Cloudflare Workers'\n // `waitUntil`) so custom route handlers can keep background work alive\n // after the response. Hono's `executionCtx` getter throws when no\n // ExecutionContext exists (e.g. Node), so guard the access.\n let executionCtx: ExecutionContext | undefined;\n try {\n executionCtx = c.executionCtx;\n } catch {\n executionCtx = undefined;\n }\n const response = await this.handleCustomRouteRequest(\n c.req.url,\n c.req.method,\n reqHeaders,\n pristineRequest.body,\n c.get('requestContext'),\n c.req.raw.signal,\n executionCtx,\n );\n if (!response) {\n return c.json({ error: 'Not Found' }, 404);\n }\n return response;\n };\n\n const method = route.method.toLowerCase() as 'get' | 'post' | 'put' | 'delete' | 'patch' | 'all';\n this.app[method](route.path, routeHandler);\n }\n }\n\n registerContextMiddleware(): void {\n // Precompute the framework-public matcher once at registration time.\n // Called per-request below; used by adapters (see `skipIfFrameworkPublic`)\n // to short-circuit user-registered middleware for framework-public routes\n // so users cannot 401 routes declared public via `requiresAuth: false`.\n const isFrameworkPublic = this.getFrameworkPublicMatcher();\n\n this.app.use('*', this.createContextMiddleware());\n this.app.use('*', async (c, next) => {\n c.set(MASTRA_FRAMEWORK_PUBLIC_KEY, isFrameworkPublic(c.req.path, c.req.method));\n return next();\n });\n this.app.use('*', async (c, next) => {\n await next();\n this.warnIfUnregisteredChannelWebhook(c.req.path, c.req.method, c.res.status);\n });\n }\n\n registerAuthMiddleware(): void {\n // Auth is handled per-route in registerRoute() and registerCustomApiRoutes()\n // No global middleware needed\n }\n\n registerUserMiddleware(): void {\n // Middleware added at runtime via `mastra.setServerMiddleware()` — already\n // normalized to `{ path, handler }` entries by core.\n for (const m of this.mastra.getServerMiddleware?.() ?? []) {\n this.app.use(m.path, skipIfFrameworkPublic(m.handler));\n }\n\n const configMiddleware = this.mastra.getServer()?.middleware;\n if (!configMiddleware) {\n return;\n }\n\n const normalizedMiddlewares = Array.isArray(configMiddleware) ? configMiddleware : [configMiddleware];\n for (const middleware of normalizedMiddlewares) {\n const { path, handler } = typeof middleware === 'function' ? { path: '*', handler: middleware } : middleware;\n // Wrap with skipIfFrameworkPublic so user middleware cannot 401 routes\n // the framework declared public via `requiresAuth: false`\n // (e.g. Studio sign-in endpoints like /api/auth/capabilities).\n this.app.use(path, skipIfFrameworkPublic(handler as unknown as MiddlewareHandler));\n }\n }\n\n registerHttpLoggingMiddleware(): void {\n if (!this.httpLoggingConfig?.enabled) {\n return;\n }\n\n this.app.use('*', async (c, next) => {\n if (!this.shouldLogRequest(c.req.path)) {\n return next();\n }\n\n const start = Date.now();\n const method = c.req.method;\n const path = c.req.path;\n\n await next();\n\n const duration = Date.now() - start;\n const status = c.res.status;\n const level = this.httpLoggingConfig?.level || 'info';\n\n const logData: Record<string, any> = {\n method,\n path,\n status,\n duration: `${duration}ms`,\n };\n\n if (this.httpLoggingConfig?.includeQueryParams) {\n logData.query = c.req.query();\n }\n\n if (this.httpLoggingConfig?.includeHeaders) {\n const headers = Object.fromEntries(c.req.raw.headers.entries());\n const redactHeaders = this.httpLoggingConfig.redactHeaders || [];\n redactHeaders.forEach(h => {\n const key = h.toLowerCase();\n if (headers[key] !== undefined) {\n headers[key] = '[REDACTED]';\n }\n });\n logData.headers = headers;\n }\n\n this.logger[level](`${method} ${path} ${status} ${duration}ms`, logData);\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["RequestContext","ViewerRegistry","MASTRA_FRAMEWORK_PUBLIC_KEY","MastraServerBase","fetchResponse"],"sources":["../src/mcp-disconnect.ts","../src/auth-middleware.ts","../src/browser-stream/index.ts","../src/index.ts"],"sourcesContent":["/**\n * Propagates a client disconnect to the simulated Node response produced by `toReqRes`.\n *\n * `fetch-to-node` builds the outgoing body from `res` events but never observes cancellation\n * of the stream it hands back. When an MCP Streamable HTTP client drops its session, nothing\n * tells `res` that the socket is gone, so the MCP transport keeps its SSE keep-alive timer\n * armed. The next keep-alive tick writes into an already-closed stream controller, and because\n * that write originates in a timer callback the resulting `ERR_INVALID_STATE` is unhandled and\n * takes down the process.\n *\n * Emitting `close` on `res` is the signal the MCP Node transport listens for: it aborts the\n * request's AbortController, which breaks the write loop and tears down the SSE stream,\n * clearing the keep-alive timer. No post-disconnect write is ever attempted.\n */\nexport function propagateClientDisconnect(\n fetchResponse: Response,\n res: { emit: (event: string) => void; destroy?: () => void },\n): Response {\n const upstream = fetchResponse.body;\n if (!upstream) return fetchResponse;\n\n let disconnected = false;\n const disconnect = () => {\n if (disconnected) return;\n disconnected = true;\n try {\n res.emit('close');\n } catch {\n // Already torn down - the transport has nothing left to clean up.\n }\n // Deliberately *not* cancelling or destroying the bridge stream here. `fetch-to-node`\n // buffers writes and flushes them from a cork timer; tearing its controller down leaves\n // that pending flush to enqueue into a closed controller, which throws an unhandled\n // ERR_INVALID_STATE from a timer callback - the very crash this guards against.\n // Emitting `close` aborts the transport, which ends the response, so the bridge closes\n // its own controller in the right order once buffered data has drained.\n void reader.read().then(\n function drain({ done }): unknown {\n return done ? undefined : reader.read().then(drain);\n },\n () => {},\n );\n };\n\n const reader = upstream.getReader();\n const body = new ReadableStream<Uint8Array>({\n async pull(controller) {\n const { done, value } = await reader.read();\n if (done) {\n controller.close();\n return;\n }\n controller.enqueue(value);\n },\n cancel() {\n disconnect();\n },\n });\n\n return new Response(body, {\n status: fetchResponse.status,\n statusText: fetchResponse.statusText,\n headers: fetchResponse.headers,\n });\n}\n","import type { Mastra } from '@mastra/core/mastra';\nimport { RequestContext } from '@mastra/core/request-context';\nimport { coreAuthMiddleware } from '@mastra/server/auth';\nimport type { Context, MiddlewareHandler } from 'hono';\n\nexport interface HonoAuthMiddlewareOptions {\n mastra: Mastra;\n requiresAuth?: boolean;\n}\n\nexport function createAuthMiddleware({ mastra, requiresAuth = true }: HonoAuthMiddlewareOptions): MiddlewareHandler {\n return async (c: Context, next) => {\n if (!requiresAuth) {\n return next();\n }\n\n const authConfig = mastra.getServer()?.auth;\n if (!authConfig) {\n return next();\n }\n\n const requestContext = c.get('requestContext') ?? new RequestContext();\n c.set('requestContext', requestContext);\n c.set('mastra', c.get('mastra') ?? mastra);\n\n const path = c.req.path;\n const method = c.req.method;\n const customRouteAuthConfig = new Map<string, boolean>(c.get('customRouteAuthConfig') ?? []);\n customRouteAuthConfig.set(`${method}:${path}`, true);\n\n const authHeader = c.req.header('Authorization');\n let token: string | null = authHeader ? authHeader.replace('Bearer ', '') : null;\n if (!token) {\n token = c.req.query('apiKey') || null;\n }\n\n const result = await coreAuthMiddleware({\n path,\n method,\n getHeader: name => c.req.header(name),\n mastra,\n authConfig,\n customRouteAuthConfig,\n requestContext,\n rawRequest: c.req.raw,\n token,\n buildAuthorizeContext: () => c,\n });\n\n if (result.action === 'next') {\n return next();\n }\n\n return c.json(result.body as any, result.status as any);\n };\n}\n","import type { createNodeWebSocket as CreateNodeWebSocket } from '@hono/node-ws';\nimport { handleInputMessage, ViewerRegistry } from '@mastra/server/browser-stream';\nimport type { BrowserStreamConfig, BrowserStreamResult } from '@mastra/server/browser-stream';\nimport type { Env, Hono, Schema } from 'hono';\n\n/**\n * Set up WebSocket-based browser stream endpoint for real-time screencast viewing.\n *\n * Creates a WebSocket route at `/browser/:agentId/stream` that:\n * - Accepts viewer connections\n * - Starts screencast when first viewer connects\n * - Broadcasts frames to all connected viewers\n * - Stops screencast when last viewer disconnects\n *\n * **Note**: Requires `ws` package to be installed. If not available, returns null\n * and logs a warning. Browser streaming will be disabled but everything else works.\n *\n * @param app - The Hono application instance\n * @param config - Configuration for browser stream\n * @returns Object containing injectWebSocket function and registry instance, or null if ws is not available\n *\n * @example\n * ```typescript\n * import { Hono } from 'hono';\n * import { serve } from '@hono/node-server';\n * import { setupBrowserStream } from '@mastra/hono';\n *\n * const app = new Hono();\n * const browserStream = await setupBrowserStream(app, {\n * getToolset: (agentId) => browserToolsets.get(agentId),\n * });\n *\n * const server = serve({ fetch: app.fetch, port: 4111 });\n * browserStream?.injectWebSocket(server);\n * ```\n */\nexport async function setupBrowserStream<E extends Env, S extends Schema, B extends string>(\n app: Hono<E, S, B>,\n config: BrowserStreamConfig,\n): Promise<BrowserStreamResult | null> {\n // Dynamic import to avoid bundling ws into non-Node environments (e.g. Cloudflare Workers).\n // The variable-based specifier prevents bundlers from resolving the module at build time.\n let createNodeWebSocket: typeof CreateNodeWebSocket;\n try {\n const mod = '@hono/node-ws';\n const honoNodeWs = await import(/* @vite-ignore */ /* webpackIgnore: true */ mod);\n createNodeWebSocket = honoNodeWs.createNodeWebSocket;\n } catch {\n // @hono/node-ws is not available (e.g. no ws package installed).\n // This is expected in non-Node environments — silently disable browser streaming.\n return null;\n }\n\n const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app });\n const registry = new ViewerRegistry();\n\n // Normalize the API prefix so we can build paths like `${apiPrefix}/agents/...`\n // without producing `//agents/...` when the prefix is missing or has a single\n // trailing slash. Anything weirder than that (e.g. `'/api//'`) is a config\n // bug we don't try to silently fix.\n const rawPrefix = config.apiPrefix ?? '/api';\n const trimmed = rawPrefix.endsWith('/') ? rawPrefix.slice(0, -1) : rawPrefix;\n const apiPrefix = trimmed || '/api';\n\n app.get(\n '/browser/:agentId/stream',\n upgradeWebSocket(c => {\n const agentId = c.req.param('agentId')!;\n const threadId = c.req.query('threadId');\n // Use composite key for thread-scoped screencasts\n const viewerKey = threadId ? `${agentId}:${threadId}` : agentId;\n\n return {\n onOpen(_event, ws) {\n // Send connected status immediately\n ws.send(JSON.stringify({ status: 'connected' }));\n\n // Add to registry (starts screencast if first viewer)\n // Fire-and-forget: screencast starts asynchronously\n // Pass agentId for toolset lookup, but viewerKey for registry scoping\n void registry.addViewer(viewerKey, ws, config.getToolset, agentId, threadId);\n },\n\n onMessage(event, _ws) {\n const data = typeof event.data === 'string' ? event.data : null;\n if (data) {\n void handleInputMessage(data, config.getToolset, agentId, threadId);\n }\n },\n\n onClose(_event, ws) {\n // Remove from registry (stops screencast if last viewer)\n // Fire-and-forget: cleanup is best-effort\n void registry.removeViewer(viewerKey, ws);\n },\n\n onError(event, ws) {\n console.error('[BrowserStream] WebSocket error:', event);\n // Fire-and-forget: cleanup is best-effort\n void registry.removeViewer(viewerKey, ws);\n },\n };\n }),\n );\n\n // Browser session probe endpoint - tells the client whether to open a WS.\n // Returns:\n // - screencastAvailable: true (this route only exists if setupBrowserStream succeeded)\n // - hasSession: whether the agent has an active browser session for the given thread\n app.get(`${apiPrefix}/agents/:agentId/browser/session`, async c => {\n const agentId = c.req.param('agentId');\n if (!agentId) {\n return c.json({ error: 'Agent ID is required' }, 400);\n }\n\n const threadId = c.req.query('threadId');\n const toolset = await config.getToolset(agentId);\n\n if (!toolset) {\n return c.json({ hasSession: false, screencastAvailable: true });\n }\n\n const hasSession = threadId ? toolset.hasThreadSession(threadId) : false;\n return c.json({ hasSession, screencastAvailable: true });\n });\n\n // Close browser session endpoint\n app.post(`${apiPrefix}/agents/:agentId/browser/close`, async c => {\n const agentId = c.req.param('agentId');\n if (!agentId) {\n return c.json({ error: 'Agent ID is required' }, 400);\n }\n\n const toolset = await config.getToolset(agentId);\n if (!toolset) {\n return c.json({ error: 'No browser session for this agent' }, 404);\n }\n\n try {\n // Parse threadId from request body\n let threadId: string | undefined;\n try {\n const body = await c.req.json();\n threadId = body?.threadId;\n } catch {\n // No body or invalid JSON - proceed without threadId\n }\n\n const scope = toolset.getScope();\n const viewerKey = threadId ? `${agentId}:${threadId}` : agentId;\n\n // For thread scope with a threadId, close only that thread's session\n if (scope === 'thread' && threadId) {\n // Close the session in the registry (stops screencast for this thread)\n await registry.closeBrowserSession(viewerKey);\n\n // Close just this thread's browser session\n if ('closeThreadSession' in toolset && typeof toolset.closeThreadSession === 'function') {\n await toolset.closeThreadSession(threadId);\n }\n } else {\n // For shared scope or no threadId, close the entire browser\n await registry.closeBrowserSession(viewerKey);\n await toolset.close();\n }\n\n return c.json({ success: true });\n } catch (error) {\n console.error(`[BrowserStream] Error closing browser for ${agentId}:`, error);\n return c.json({ error: 'Failed to close browser' }, 500);\n }\n });\n\n return { injectWebSocket: injectWebSocket as (server: unknown) => void, registry };\n}\n","import type { ToolsInput } from '@mastra/core/agent';\nimport type { Mastra } from '@mastra/core/mastra';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { InMemoryTaskStore } from '@mastra/server/a2a/store';\n\nimport type { MCPHttpTransportResult, MCPSseTransportResult } from '@mastra/server/handlers/mcp';\nimport type { ParsedRequestParams, ServerRoute } from '@mastra/server/server-adapter';\nimport {\n MASTRA_FRAMEWORK_PUBLIC_KEY,\n MastraServer as MastraServerBase,\n applyMcpRequestAuth,\n checkRouteFGA,\n getCustomHTTPExceptionResponse,\n isZodError,\n normalizeQueryParams,\n redactStreamChunk,\n serializeStreamChunk,\n} from '@mastra/server/server-adapter';\nimport { toReqRes, toFetchResponse } from 'fetch-to-node';\nimport type { Context, ExecutionContext, HonoRequest, MiddlewareHandler } from 'hono';\nimport { bodyLimit } from 'hono/body-limit';\nimport { stream } from 'hono/streaming';\nimport { propagateClientDisconnect } from './mcp-disconnect';\nexport { createAuthMiddleware } from './auth-middleware';\nexport type { HonoAuthMiddlewareOptions } from './auth-middleware';\n// Browser stream setup (Hono-specific WebSocket implementation)\nexport { setupBrowserStream } from './browser-stream';\n\ntype HasPermissionFn = (userPerms: string[], required: string) => boolean;\nlet _hasPermissionPromise: Promise<HasPermissionFn | undefined> | undefined;\nfunction loadHasPermission(): Promise<HasPermissionFn | undefined> {\n if (!_hasPermissionPromise) {\n _hasPermissionPromise = import('@mastra/core/auth/ee')\n .then(m => m.hasPermission)\n .catch(() => {\n console.error(\n '[@mastra/hono] Auth features require @mastra/core >= 1.6.0. Please upgrade: npm install @mastra/core@latest',\n );\n return undefined;\n });\n }\n return _hasPermissionPromise;\n}\n\n// Export type definitions for Hono app configuration\nexport type HonoVariables = {\n mastra: Mastra;\n requestContext: RequestContext;\n registeredTools: ToolsInput;\n abortSignal: AbortSignal;\n taskStore: InMemoryTaskStore;\n customRouteAuthConfig?: Map<string, boolean>;\n cachedBody?: unknown;\n /**\n * True when the current request targets a route the framework has declared\n * public (`requiresAuth: false`). Adapter authors MUST wrap user-registered\n * middleware with {@link skipIfFrameworkPublic} so that user middleware\n * cannot 401 these routes.\n */\n [MASTRA_FRAMEWORK_PUBLIC_KEY]?: boolean;\n};\n\n// Re-export the framework-public context key so users configuring Hono apps\n// can reference it directly without importing from @mastra/server.\nexport { MASTRA_FRAMEWORK_PUBLIC_KEY } from '@mastra/server/server-adapter';\n\n/**\n * Wrap a Hono middleware handler so it becomes a no-op for framework-public\n * routes (routes registered with `requiresAuth: false`).\n *\n * Adapters that expose user-provided middleware — for example `serverMiddleware`\n * on the Mastra instance or `server.middleware` in Mastra config — MUST wrap\n * those handlers with this before registering them. This is the framework's\n * guarantee that user middleware cannot accidentally (or intentionally) 401\n * routes the framework needs to keep reachable (e.g. Studio sign-in endpoints).\n *\n * The framework-public flag is computed once per request by\n * {@link MastraServer.registerContextMiddleware} and stashed on the Hono\n * context under `MASTRA_FRAMEWORK_PUBLIC_KEY`.\n */\nexport const skipIfFrameworkPublic = (handler: MiddlewareHandler): MiddlewareHandler => {\n return async (c, next) => {\n if (c.get(MASTRA_FRAMEWORK_PUBLIC_KEY)) {\n return next();\n }\n return handler(c, next);\n };\n};\n\n/**\n * Context key holding a pristine clone of the incoming request, captured by\n * the context middleware before user middleware runs. The custom-route bridge\n * reads the body from this clone so user middleware that consumes the request\n * body (e.g. `await c.req.json()`) does not break custom API routes.\n */\nconst MASTRA_PRISTINE_REQUEST_KEY = '__mastraPristineRequest';\n\nconst BODY_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);\n\nexport type HonoBindings = {};\n\n/**\n * Generic handler function type compatible across Hono versions.\n * Uses a minimal signature that all Hono middleware handlers satisfy.\n */\ntype HonoRouteHandler = (...args: any[]) => any;\n\n/**\n * Minimal interface representing what MastraServer needs from a Hono app.\n * This allows any Hono app instance to be passed without strict generic matching,\n * avoiding the version mismatch issues that occur with Hono's strict generic types.\n */\nexport interface HonoApp {\n use(path: string, ...handlers: HonoRouteHandler[]): unknown;\n get(path: string, ...handlers: HonoRouteHandler[]): unknown;\n post(path: string, ...handlers: HonoRouteHandler[]): unknown;\n put(path: string, ...handlers: HonoRouteHandler[]): unknown;\n delete(path: string, ...handlers: HonoRouteHandler[]): unknown;\n patch(path: string, ...handlers: HonoRouteHandler[]): unknown;\n all(path: string, ...handlers: HonoRouteHandler[]): unknown;\n}\n\nexport class MastraServer extends MastraServerBase<HonoApp, HonoRequest, Context> {\n createContextMiddleware(): MiddlewareHandler {\n return async (c, next) => {\n // Preserve a pristine clone of the request before user middleware runs.\n // `Request.clone()` tees the body stream, so the clone stays readable\n // even after middleware consumes the original (json/text/formData/raw).\n // Only taken when custom routes exist — the bridge is the sole consumer.\n if (this.hasCustomRouteHandler && BODY_METHODS.has(c.req.method) && c.req.raw.body) {\n c.set(MASTRA_PRISTINE_REQUEST_KEY, c.req.raw.clone());\n }\n\n // Patch req.json() to prevent \"Body is unusable\" errors when the body is read multiple times\n // e.g. by middleware and then by an agent.\n const originalJson = c.req.json.bind(c.req);\n let jsonPromise: Promise<any> | undefined;\n\n c.req.json = () => {\n if (!jsonPromise) {\n jsonPromise = originalJson().then(body => {\n // Cache in context if needed explicitly, though the promise memoization handles the reuse\n c.set('cachedBody', body);\n return body;\n });\n }\n return jsonPromise;\n };\n\n // Parse request context from request body and add to context\n\n let bodyRequestContext: Record<string, any> | undefined;\n let paramsRequestContext: Record<string, any> | undefined;\n\n // Parse request context from request body (POST/PUT)\n if (c.req.method === 'POST' || c.req.method === 'PUT') {\n const contentType = c.req.header('content-type');\n const contentLength = c.req.header('content-length');\n // Only parse if content-type is JSON and body is not empty\n if (contentType?.includes('application/json') && contentLength !== '0') {\n try {\n const body = (await c.req.raw.clone().json()) as { requestContext?: Record<string, any> };\n if (body.requestContext) {\n bodyRequestContext = body.requestContext;\n }\n } catch {\n // Body parsing failed, continue without body\n }\n }\n }\n\n // Parse request context from query params.\n if (c.req.method === 'GET' || c.req.method === 'POST') {\n try {\n const encodedRequestContext = c.req.query('requestContext');\n if (encodedRequestContext) {\n // Try JSON first\n try {\n paramsRequestContext = JSON.parse(encodedRequestContext);\n } catch {\n // Fallback to base64(JSON)\n try {\n const json = Buffer.from(encodedRequestContext, 'base64').toString('utf-8');\n paramsRequestContext = JSON.parse(json);\n } catch {\n // ignore if still invalid\n }\n }\n }\n } catch {\n // ignore query parsing errors\n }\n }\n\n const requestContext = this.mergeRequestContext({ paramsRequestContext, bodyRequestContext });\n this.applyRequestMetadataToContext({\n requestContext,\n getHeader: name => c.req.header(name),\n });\n\n // Add relevant contexts to hono context\n c.set('requestContext', requestContext);\n c.set('mastra', this.mastra);\n c.set('registeredTools', this.tools || {});\n c.set('taskStore', this.taskStore);\n c.set('abortSignal', c.req.raw.signal);\n c.set('customRouteAuthConfig', this.customRouteAuthConfig);\n\n return next();\n };\n }\n async stream(route: ServerRoute, res: Context, result: { fullStream: ReadableStream }): Promise<any> {\n const streamFormat = route.streamFormat || 'stream';\n\n if (streamFormat === 'sse') {\n res.header('Content-Type', 'text/event-stream');\n res.header('Cache-Control', 'no-cache');\n res.header('Connection', 'keep-alive');\n res.header('X-Accel-Buffering', 'no');\n } else {\n res.header('Content-Type', 'text/plain');\n }\n res.header('Transfer-Encoding', 'chunked');\n\n return stream(\n res,\n async stream => {\n if (streamFormat === 'sse' && route.sseFlushOnConnect) {\n await stream.write(': connected\\n\\n');\n }\n\n const readableStream = result instanceof ReadableStream ? result : result.fullStream;\n const reader = readableStream.getReader();\n\n stream.onAbort(() => {\n void reader.cancel('request aborted').catch(() => {});\n });\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n if (value) {\n if (streamFormat === 'sse' && typeof value === 'string' && value.startsWith(':')) {\n await stream.write(value);\n continue;\n }\n\n // Optionally redact sensitive data (system prompts, tool definitions, API keys) before sending to the client\n const shouldRedact = this.streamOptions?.redact ?? true;\n const outputValue = shouldRedact ? redactStreamChunk(value) : value;\n // A chunk that can't be serialized must not kill the stream — skip it and keep streaming\n const serialized = serializeStreamChunk(outputValue);\n if (!serialized.ok) {\n this.mastra.getLogger()?.error('Failed to serialize stream chunk, skipping', {\n path: route.path,\n chunkType: (outputValue as { type?: string })?.type,\n error: serialized.error.message,\n });\n continue;\n }\n if (streamFormat === 'sse') {\n await stream.write(`data: ${serialized.json}\\n\\n`);\n } else {\n await stream.write(serialized.json + '\\x1E');\n }\n }\n }\n\n if (streamFormat === 'sse') {\n await stream.write('data: [DONE]\\n\\n');\n }\n } catch (error) {\n this.mastra.getLogger()?.error('Error in stream processing', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n } finally {\n await stream.close();\n }\n },\n async err => {\n this.mastra.getLogger()?.error('Stream error callback', {\n error: err instanceof Error ? { message: err.message, stack: err.stack } : err,\n });\n },\n );\n }\n\n async getParams(route: ServerRoute, request: HonoRequest): Promise<ParsedRequestParams> {\n const urlParams = request.param();\n // Use queries() to get all values for repeated params (e.g., ?tags=a&tags=b -> { tags: ['a', 'b'] })\n const queryParams = normalizeQueryParams(request.queries());\n let body: unknown;\n let bodyParseError: { message: string } | undefined;\n\n if (route.method === 'POST' || route.method === 'PUT' || route.method === 'PATCH' || route.method === 'DELETE') {\n const contentType = request.header('content-type') || '';\n\n if (contentType.includes('multipart/form-data')) {\n try {\n const formData = await request.formData();\n body = await this.parseFormData(formData);\n } catch (error) {\n this.mastra.getLogger()?.error('Failed to parse multipart form data', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n // Re-throw size limit errors, let others fall through to validation\n if (error instanceof Error && error.message.toLowerCase().includes('size')) {\n throw error;\n }\n bodyParseError = {\n message: error instanceof Error ? error.message : 'Failed to parse multipart form data',\n };\n }\n } else if (contentType.includes('application/json')) {\n // Clone the request to read the body text first\n // This allows us to check if there's actual content before parsing\n const clonedReq = request.raw.clone();\n const bodyText = await clonedReq.text();\n\n if (bodyText && bodyText.trim().length > 0) {\n // There's actual content - try to parse it as JSON\n try {\n body = JSON.parse(bodyText);\n } catch (error) {\n this.mastra.getLogger()?.error('Failed to parse JSON body', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n // Track JSON parse error to return 400 Bad Request\n bodyParseError = {\n message: error instanceof Error ? error.message : 'Invalid JSON in request body',\n };\n }\n }\n // Empty body is ok - body remains undefined\n }\n }\n return { urlParams, queryParams, body, bodyParseError };\n }\n\n /**\n * Parse FormData into a plain object, converting File objects to Buffers.\n */\n private async parseFormData(formData: FormData): Promise<Record<string, unknown>> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of formData.entries()) {\n if (value instanceof File) {\n const arrayBuffer = await value.arrayBuffer();\n result[key] = Buffer.from(arrayBuffer);\n } else if (typeof value === 'string') {\n // Try to parse JSON strings (like 'options')\n try {\n result[key] = JSON.parse(value);\n } catch {\n result[key] = value;\n }\n } else {\n result[key] = value;\n }\n }\n\n return result;\n }\n\n async sendResponse(route: ServerRoute, response: Context, result: unknown, prefix?: string): Promise<any> {\n const resolvedPrefix = prefix ?? this.prefix ?? '';\n\n // Apply refresh headers from transparent session refresh (e.g. Set-Cookie after token refresh)\n if (result && typeof result === 'object' && '__refreshHeaders' in result) {\n const refreshHeaders = (result as any).__refreshHeaders as Record<string, string>;\n for (const [key, value] of Object.entries(refreshHeaders)) {\n response.header(key, value);\n }\n delete (result as any).__refreshHeaders;\n }\n\n if (route.responseType === 'json') {\n return response.json(result as any, 200);\n } else if (route.responseType === 'stream') {\n return this.stream(route, response, result as { fullStream: ReadableStream });\n } else if (route.responseType === 'datastream-response') {\n const fetchResponse = result as globalThis.Response;\n return fetchResponse;\n } else if (route.responseType === 'mcp-http') {\n // MCP Streamable HTTP transport\n const { server, httpPath, mcpOptions: routeMcpOptions } = result as MCPHttpTransportResult;\n const { req, res } = toReqRes(response.req.raw);\n\n // Merge class-level mcpOptions with route-specific options (route takes precedence)\n const { setRequestAuth, ...options } = { ...this.mcpOptions, ...routeMcpOptions };\n\n // `toReqRes` builds a fresh IncomingMessage, so the principal resolved by\n // auth middleware never reaches the MCP transport unless we bridge it here.\n // This runs before startHTTP so every branch (stateless, existing session,\n // new session) sees the same `req.auth`.\n await applyMcpRequestAuth({ req, requestContext: response.get('requestContext'), setRequestAuth });\n\n // Do NOT await startHTTP — let it run in the background so SSE\n // notifications stream to the client as they are written.\n // toFetchResponse resolves when headers are sent, not when the body finishes.\n server\n .startHTTP({\n url: new URL(response.req.url),\n httpPath: `${resolvedPrefix}${httpPath}`,\n req,\n res,\n options: Object.keys(options).length > 0 ? options : undefined,\n })\n .catch((e: unknown) => {\n this.mastra.getLogger()?.error('[MCP HTTP] Error in background startHTTP:', {\n error: e instanceof Error ? { message: e.message, stack: e.stack } : e,\n });\n try {\n if (!res.headersSent) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n jsonrpc: '2.0',\n error: { code: -32603, message: 'Internal server error' },\n id: null,\n }),\n );\n }\n } catch {\n // Response stream already closed or destroyed - nothing more to do\n }\n });\n\n return propagateClientDisconnect(await toFetchResponse(res), res);\n } else if (route.responseType === 'mcp-sse') {\n // MCP SSE transport\n const { server, ssePath, messagePath } = result as MCPSseTransportResult;\n\n try {\n // SSE has no Node request to hang `req.auth` on, so resolve the auth info\n // here and pass it explicitly. Reuse the same bridge as streamable HTTP so\n // a `setRequestAuth` hook sees a real request object.\n const { req } = toReqRes(response.req.raw);\n await applyMcpRequestAuth({\n req,\n requestContext: response.get('requestContext'),\n setRequestAuth: this.mcpOptions?.setRequestAuth,\n });\n\n return await server.startHonoSSE({\n url: new URL(response.req.url),\n ssePath: `${resolvedPrefix}${ssePath}`,\n messagePath: `${resolvedPrefix}${messagePath}`,\n context: response,\n authInfo: (req as typeof req & { auth?: unknown }).auth,\n });\n } catch {\n return response.json({ error: 'Error handling MCP SSE request' }, 500);\n }\n } else {\n return response.status(500);\n }\n }\n\n async registerRoute(\n app: HonoApp,\n route: ServerRoute,\n { prefix: prefixParam }: { prefix?: string } = {},\n ): Promise<void> {\n // Default prefix to this.prefix if not provided, or empty string\n const prefix = prefixParam ?? this.prefix ?? '';\n\n const maxSize = route.maxBodySize ?? this.bodyLimitOptions?.maxSize;\n const isBodyMethod = ['POST', 'PUT', 'PATCH', 'DELETE'].includes(route.method.toUpperCase());\n\n // Build middleware array\n const middlewares: MiddlewareHandler[] = [];\n\n if (isBodyMethod && maxSize !== undefined) {\n middlewares.push(\n bodyLimit({\n maxSize,\n onError: (c: Context) => {\n let errorResponse: unknown = { error: 'Request body too large' };\n if (route.maxBodySize === undefined && this.bodyLimitOptions) {\n try {\n errorResponse = this.bodyLimitOptions.onError(errorResponse);\n } catch {\n // Fall back to the default response.\n }\n }\n return c.json(errorResponse, 413);\n },\n }),\n );\n }\n\n app[route.method.toLowerCase() as 'get' | 'post' | 'put' | 'delete' | 'patch' | 'all'](\n `${prefix}${route.path}`,\n ...middlewares,\n async (c: Context) => {\n // Check route-level authentication/authorization\n const authResult = await this.checkRouteAuth(route, {\n path: c.req.path,\n method: c.req.method,\n getHeader: name => c.req.header(name),\n getQuery: name => c.req.query(name),\n requestContext: c.get('requestContext'),\n request: c.req.raw,\n buildAuthorizeContext: () => c,\n });\n\n if (authResult) {\n // Apply any refresh headers (e.g. Set-Cookie from transparent session refresh)\n if (authResult.headers) {\n for (const [key, value] of Object.entries(authResult.headers)) {\n c.header(key, value as string);\n }\n }\n\n // If this is an auth error (not just a success-with-headers), return error response\n if (authResult.error) {\n return c.json({ error: authResult.error }, authResult.status as any);\n }\n }\n\n const params = await this.getParams(route, c.req);\n\n // Return 400 Bad Request if body parsing failed (e.g., malformed JSON)\n if (params.bodyParseError) {\n return c.json(\n {\n error: 'Invalid request body',\n issues: [{ field: 'body', message: params.bodyParseError.message }],\n },\n 400,\n );\n }\n\n if (params.queryParams) {\n try {\n params.queryParams = await this.parseQueryParams(route, params.queryParams);\n } catch (error) {\n this.mastra.getLogger()?.error('Error parsing query params', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n if (isZodError(error)) {\n const { status, body } = this.resolveValidationError(route, error, 'query');\n return c.json(body as any, status as any);\n }\n return c.json(\n {\n error: 'Invalid query parameters',\n issues: [{ field: 'unknown', message: error instanceof Error ? error.message : 'Unknown error' }],\n },\n 400,\n );\n }\n }\n\n if (params.body !== undefined || route.bodySchema) {\n try {\n params.body = await this.parseBody(route, params.body);\n } catch (error) {\n this.mastra.getLogger()?.error('Error parsing body', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n if (isZodError(error)) {\n const { status, body } = this.resolveValidationError(route, error, 'body');\n return c.json(body as any, status as any);\n }\n return c.json(\n {\n error: 'Invalid request body',\n issues: [{ field: 'unknown', message: error instanceof Error ? error.message : 'Unknown error' }],\n },\n 400,\n );\n }\n }\n\n // Parse path params through pathParamSchema for type coercion (e.g., z.coerce.number())\n if (params.urlParams) {\n try {\n params.urlParams = await this.parsePathParams(route, params.urlParams);\n } catch (error) {\n this.mastra.getLogger()?.error('Error parsing path params', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n if (isZodError(error)) {\n const { status, body } = this.resolveValidationError(route, error, 'path');\n return c.json(body as any, status as any);\n }\n return c.json(\n {\n error: 'Invalid path parameters',\n issues: [{ field: 'unknown', message: error instanceof Error ? error.message : 'Unknown error' }],\n },\n 400,\n );\n }\n }\n\n const handlerParams = {\n ...params.urlParams,\n ...params.queryParams,\n ...(typeof params.body === 'object' ? params.body : {}),\n requestContext: c.get('requestContext'),\n mastra: this.mastra,\n registeredTools: c.get('registeredTools'),\n taskStore: c.get('taskStore'),\n abortSignal: c.get('abortSignal'),\n routePrefix: prefix,\n request: c.req.raw, // Standard Request object with headers/cookies\n };\n\n // Check route permission requirement (EE feature)\n // Uses convention-based permission derivation: permissions are auto-derived\n // from route path/method unless explicitly set or route is public\n const requestContext = c.get('requestContext');\n // Check if any auth is configured (studio or server) for RBAC\n const hasAuth = this.mastra.getStudio?.()?.auth || this.mastra.getServer()?.auth;\n if (hasAuth) {\n const hasPermission = await loadHasPermission();\n if (hasPermission) {\n const userPermissions = requestContext.get('mastra__userPermissions') as string[] | undefined;\n const permissionError = this.checkRoutePermission(route, userPermissions, hasPermission, requestContext);\n\n if (permissionError) {\n return c.json(\n {\n error: permissionError.error,\n message: permissionError.message,\n },\n permissionError.status as any,\n );\n }\n }\n }\n\n // Check FGA authorization (EE feature)\n const fgaError = await checkRouteFGA(this.mastra, route, c.get('requestContext'), {\n ...params.urlParams,\n ...params.queryParams,\n ...(typeof params.body === 'object' ? params.body : {}),\n });\n if (fgaError) {\n return c.json({ error: fgaError.error, message: fgaError.message }, fgaError.status as any);\n }\n\n try {\n const result = await route.handler(handlerParams);\n return this.sendResponse(route, c, result, prefix);\n } catch (error) {\n // 4xx errors are client conditions (e.g. no session, expired token) and are\n // already returned as structured HTTP responses below. Logging them as errors\n // produces noise for callers — skip the logger call for those cases.\n const httpStatus =\n error && typeof error === 'object' && 'status' in error ? (error as any).status : undefined;\n const isClientError = typeof httpStatus === 'number' && httpStatus >= 400 && httpStatus < 500;\n if (!isClientError) {\n this.mastra.getLogger()?.error('Error calling handler', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n path: route.path,\n method: route.method,\n });\n }\n const customResponse = getCustomHTTPExceptionResponse(error);\n if (customResponse) {\n return customResponse;\n }\n\n // Check if it's an HTTPException or MastraError with a status code\n if (error && typeof error === 'object') {\n // Check for direct status property (HTTPException)\n if ('status' in error) {\n const status = (error as any).status;\n let safeCause: { failingItems: unknown[] } | undefined;\n try {\n const raw = error instanceof Error ? error.cause : undefined;\n if (\n raw &&\n typeof raw === 'object' &&\n !Array.isArray(raw) &&\n 'failingItems' in raw &&\n Array.isArray((raw as any).failingItems)\n ) {\n safeCause = { failingItems: (raw as any).failingItems };\n }\n } catch {\n // serialization or access error — omit cause\n }\n return c.json(\n {\n error: error instanceof Error ? error.message : 'Unknown error',\n ...(safeCause ? { cause: safeCause } : {}),\n },\n status,\n );\n }\n // Check for MastraError with status in details\n if ('details' in error && error.details && typeof error.details === 'object' && 'status' in error.details) {\n const status = (error.details as any).status;\n return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, status);\n }\n }\n return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500);\n }\n },\n );\n }\n\n async registerCustomApiRoutes(): Promise<void> {\n const routes = await this.registerSchemaApiRoutes();\n if (!(await this.buildCustomRouteHandler(routes))) return;\n\n for (const route of routes) {\n const serverRoute: ServerRoute = {\n method: route.method as any,\n path: route.path,\n responseType: 'json',\n handler: async () => {},\n requiresAuth: route.requiresAuth,\n requiresPermission: route.requiresPermission,\n fga: route.fga,\n };\n\n const routeHandler: MiddlewareHandler = async (c: Context) => {\n // Per-route auth check (same pattern as registerRoute)\n const authError = await this.checkRouteAuth(serverRoute, {\n path: c.req.path,\n method: c.req.method,\n getHeader: name => c.req.header(name),\n getQuery: name => c.req.query(name),\n requestContext: c.get('requestContext'),\n request: c.req.raw,\n buildAuthorizeContext: () => c,\n });\n\n if (authError) {\n if (authError.headers) {\n for (const [key, value] of Object.entries(authError.headers)) {\n c.header(key, value as string);\n }\n }\n if (authError.error) {\n return c.json({ error: authError.error }, authError.status as any);\n }\n }\n\n const requestContext = c.get('requestContext');\n // Check if any auth is configured (studio or server) for RBAC\n const hasAuth = this.mastra.getStudio?.()?.auth || this.mastra.getServer()?.auth;\n if (hasAuth) {\n const hasPermission = await loadHasPermission();\n if (hasPermission) {\n const userPermissions = requestContext.get('mastra__userPermissions') as string[] | undefined;\n const permissionError = this.checkRoutePermission(\n serverRoute,\n userPermissions,\n hasPermission,\n requestContext,\n );\n if (permissionError) {\n return c.json(\n { error: permissionError.error, message: permissionError.message },\n permissionError.status as any,\n );\n }\n }\n }\n\n // Use the pristine clone captured by the context middleware (before\n // user middleware ran) so body reads survive middleware that already\n // consumed `c.req.raw`.\n const pristineRequest = (c.get(MASTRA_PRISTINE_REQUEST_KEY) as Request | undefined) ?? c.req.raw;\n\n // Check FGA authorization (EE feature)\n let bodyParams: Record<string, unknown> = {};\n const contentType = c.req.header('content-type');\n if (contentType?.includes('application/json')) {\n try {\n const body = (await pristineRequest.clone().json()) as unknown;\n if (body && typeof body === 'object' && !Array.isArray(body)) {\n bodyParams = body as Record<string, unknown>;\n }\n } catch {\n bodyParams = {};\n }\n } else if (\n contentType?.includes('application/x-www-form-urlencoded') ||\n contentType?.includes('multipart/form-data')\n ) {\n try {\n bodyParams = Object.fromEntries(await pristineRequest.clone().formData());\n } catch {\n bodyParams = {};\n }\n }\n const fgaError = await checkRouteFGA(this.mastra, serverRoute, c.get('requestContext'), {\n ...c.req.param(),\n ...Object.fromEntries(new URL(c.req.url).searchParams.entries()),\n ...bodyParams,\n });\n if (fgaError) {\n return c.json({ error: fgaError.error, message: fgaError.message }, fgaError.status as any);\n }\n\n const reqHeaders: Record<string, string | string[] | undefined> = {};\n c.req.raw.headers.forEach((v, k) => {\n reqHeaders[k] = v;\n });\n // Forward the platform execution context (e.g. Cloudflare Workers'\n // `waitUntil`) so custom route handlers can keep background work alive\n // after the response. Hono's `executionCtx` getter throws when no\n // ExecutionContext exists (e.g. Node), so guard the access.\n let executionCtx: ExecutionContext | undefined;\n try {\n executionCtx = c.executionCtx;\n } catch {\n executionCtx = undefined;\n }\n const response = await this.handleCustomRouteRequest(\n c.req.url,\n c.req.method,\n reqHeaders,\n pristineRequest.body,\n c.get('requestContext'),\n c.req.raw.signal,\n executionCtx,\n );\n if (!response) {\n return c.json({ error: 'Not Found' }, 404);\n }\n return response;\n };\n\n const method = route.method.toLowerCase() as 'get' | 'post' | 'put' | 'delete' | 'patch' | 'all';\n this.app[method](route.path, routeHandler);\n }\n }\n\n registerContextMiddleware(): void {\n // Precompute the framework-public matcher once at registration time.\n // Called per-request below; used by adapters (see `skipIfFrameworkPublic`)\n // to short-circuit user-registered middleware for framework-public routes\n // so users cannot 401 routes declared public via `requiresAuth: false`.\n const isFrameworkPublic = this.getFrameworkPublicMatcher();\n\n this.app.use('*', this.createContextMiddleware());\n this.app.use('*', async (c, next) => {\n c.set(MASTRA_FRAMEWORK_PUBLIC_KEY, isFrameworkPublic(c.req.path, c.req.method));\n return next();\n });\n this.app.use('*', async (c, next) => {\n await next();\n this.warnIfUnregisteredChannelWebhook(c.req.path, c.req.method, c.res.status);\n });\n }\n\n registerAuthMiddleware(): void {\n // Auth is handled per-route in registerRoute() and registerCustomApiRoutes()\n // No global middleware needed\n }\n\n registerUserMiddleware(): void {\n // Middleware added at runtime via `mastra.setServerMiddleware()` — already\n // normalized to `{ path, handler }` entries by core.\n for (const m of this.mastra.getServerMiddleware?.() ?? []) {\n this.app.use(m.path, skipIfFrameworkPublic(m.handler));\n }\n\n const configMiddleware = this.mastra.getServer()?.middleware;\n if (!configMiddleware) {\n return;\n }\n\n const normalizedMiddlewares = Array.isArray(configMiddleware) ? configMiddleware : [configMiddleware];\n for (const middleware of normalizedMiddlewares) {\n const { path, handler } = typeof middleware === 'function' ? { path: '*', handler: middleware } : middleware;\n // Wrap with skipIfFrameworkPublic so user middleware cannot 401 routes\n // the framework declared public via `requiresAuth: false`\n // (e.g. Studio sign-in endpoints like /api/auth/capabilities).\n this.app.use(path, skipIfFrameworkPublic(handler as unknown as MiddlewareHandler));\n }\n }\n\n registerHttpLoggingMiddleware(): void {\n if (!this.httpLoggingConfig?.enabled) {\n return;\n }\n\n this.app.use('*', async (c, next) => {\n if (!this.shouldLogRequest(c.req.path)) {\n return next();\n }\n\n const start = Date.now();\n const method = c.req.method;\n const path = c.req.path;\n\n await next();\n\n const duration = Date.now() - start;\n const status = c.res.status;\n const level = this.httpLoggingConfig?.level || 'info';\n\n const logData: Record<string, any> = {\n method,\n path,\n status,\n duration: `${duration}ms`,\n };\n\n if (this.httpLoggingConfig?.includeQueryParams) {\n logData.query = c.req.query();\n }\n\n if (this.httpLoggingConfig?.includeHeaders) {\n const headers = Object.fromEntries(c.req.raw.headers.entries());\n const redactHeaders = this.httpLoggingConfig.redactHeaders || [];\n redactHeaders.forEach(h => {\n const key = h.toLowerCase();\n if (headers[key] !== undefined) {\n headers[key] = '[REDACTED]';\n }\n });\n logData.headers = headers;\n }\n\n this.logger[level](`${method} ${path} ${status} ${duration}ms`, logData);\n });\n }\n}\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -267,7 +267,7 @@ var MastraServer = class extends MastraServer$1 {
|
|
|
267
267
|
if (body.requestContext) bodyRequestContext = body.requestContext;
|
|
268
268
|
} catch {}
|
|
269
269
|
}
|
|
270
|
-
if (c.req.method === "GET") try {
|
|
270
|
+
if (c.req.method === "GET" || c.req.method === "POST") try {
|
|
271
271
|
const encodedRequestContext = c.req.query("requestContext");
|
|
272
272
|
if (encodedRequestContext) try {
|
|
273
273
|
paramsRequestContext = JSON.parse(encodedRequestContext);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["MASTRA_FRAMEWORK_PUBLIC_KEY","MastraServerBase","fetchResponse"],"sources":["../src/mcp-disconnect.ts","../src/auth-middleware.ts","../src/browser-stream/index.ts","../src/index.ts"],"sourcesContent":["/**\n * Propagates a client disconnect to the simulated Node response produced by `toReqRes`.\n *\n * `fetch-to-node` builds the outgoing body from `res` events but never observes cancellation\n * of the stream it hands back. When an MCP Streamable HTTP client drops its session, nothing\n * tells `res` that the socket is gone, so the MCP transport keeps its SSE keep-alive timer\n * armed. The next keep-alive tick writes into an already-closed stream controller, and because\n * that write originates in a timer callback the resulting `ERR_INVALID_STATE` is unhandled and\n * takes down the process.\n *\n * Emitting `close` on `res` is the signal the MCP Node transport listens for: it aborts the\n * request's AbortController, which breaks the write loop and tears down the SSE stream,\n * clearing the keep-alive timer. No post-disconnect write is ever attempted.\n */\nexport function propagateClientDisconnect(\n fetchResponse: Response,\n res: { emit: (event: string) => void; destroy?: () => void },\n): Response {\n const upstream = fetchResponse.body;\n if (!upstream) return fetchResponse;\n\n let disconnected = false;\n const disconnect = () => {\n if (disconnected) return;\n disconnected = true;\n try {\n res.emit('close');\n } catch {\n // Already torn down - the transport has nothing left to clean up.\n }\n // Deliberately *not* cancelling or destroying the bridge stream here. `fetch-to-node`\n // buffers writes and flushes them from a cork timer; tearing its controller down leaves\n // that pending flush to enqueue into a closed controller, which throws an unhandled\n // ERR_INVALID_STATE from a timer callback - the very crash this guards against.\n // Emitting `close` aborts the transport, which ends the response, so the bridge closes\n // its own controller in the right order once buffered data has drained.\n void reader.read().then(\n function drain({ done }): unknown {\n return done ? undefined : reader.read().then(drain);\n },\n () => {},\n );\n };\n\n const reader = upstream.getReader();\n const body = new ReadableStream<Uint8Array>({\n async pull(controller) {\n const { done, value } = await reader.read();\n if (done) {\n controller.close();\n return;\n }\n controller.enqueue(value);\n },\n cancel() {\n disconnect();\n },\n });\n\n return new Response(body, {\n status: fetchResponse.status,\n statusText: fetchResponse.statusText,\n headers: fetchResponse.headers,\n });\n}\n","import type { Mastra } from '@mastra/core/mastra';\nimport { RequestContext } from '@mastra/core/request-context';\nimport { coreAuthMiddleware } from '@mastra/server/auth';\nimport type { Context, MiddlewareHandler } from 'hono';\n\nexport interface HonoAuthMiddlewareOptions {\n mastra: Mastra;\n requiresAuth?: boolean;\n}\n\nexport function createAuthMiddleware({ mastra, requiresAuth = true }: HonoAuthMiddlewareOptions): MiddlewareHandler {\n return async (c: Context, next) => {\n if (!requiresAuth) {\n return next();\n }\n\n const authConfig = mastra.getServer()?.auth;\n if (!authConfig) {\n return next();\n }\n\n const requestContext = c.get('requestContext') ?? new RequestContext();\n c.set('requestContext', requestContext);\n c.set('mastra', c.get('mastra') ?? mastra);\n\n const path = c.req.path;\n const method = c.req.method;\n const customRouteAuthConfig = new Map<string, boolean>(c.get('customRouteAuthConfig') ?? []);\n customRouteAuthConfig.set(`${method}:${path}`, true);\n\n const authHeader = c.req.header('Authorization');\n let token: string | null = authHeader ? authHeader.replace('Bearer ', '') : null;\n if (!token) {\n token = c.req.query('apiKey') || null;\n }\n\n const result = await coreAuthMiddleware({\n path,\n method,\n getHeader: name => c.req.header(name),\n mastra,\n authConfig,\n customRouteAuthConfig,\n requestContext,\n rawRequest: c.req.raw,\n token,\n buildAuthorizeContext: () => c,\n });\n\n if (result.action === 'next') {\n return next();\n }\n\n return c.json(result.body as any, result.status as any);\n };\n}\n","import type { createNodeWebSocket as CreateNodeWebSocket } from '@hono/node-ws';\nimport { handleInputMessage, ViewerRegistry } from '@mastra/server/browser-stream';\nimport type { BrowserStreamConfig, BrowserStreamResult } from '@mastra/server/browser-stream';\nimport type { Env, Hono, Schema } from 'hono';\n\n/**\n * Set up WebSocket-based browser stream endpoint for real-time screencast viewing.\n *\n * Creates a WebSocket route at `/browser/:agentId/stream` that:\n * - Accepts viewer connections\n * - Starts screencast when first viewer connects\n * - Broadcasts frames to all connected viewers\n * - Stops screencast when last viewer disconnects\n *\n * **Note**: Requires `ws` package to be installed. If not available, returns null\n * and logs a warning. Browser streaming will be disabled but everything else works.\n *\n * @param app - The Hono application instance\n * @param config - Configuration for browser stream\n * @returns Object containing injectWebSocket function and registry instance, or null if ws is not available\n *\n * @example\n * ```typescript\n * import { Hono } from 'hono';\n * import { serve } from '@hono/node-server';\n * import { setupBrowserStream } from '@mastra/hono';\n *\n * const app = new Hono();\n * const browserStream = await setupBrowserStream(app, {\n * getToolset: (agentId) => browserToolsets.get(agentId),\n * });\n *\n * const server = serve({ fetch: app.fetch, port: 4111 });\n * browserStream?.injectWebSocket(server);\n * ```\n */\nexport async function setupBrowserStream<E extends Env, S extends Schema, B extends string>(\n app: Hono<E, S, B>,\n config: BrowserStreamConfig,\n): Promise<BrowserStreamResult | null> {\n // Dynamic import to avoid bundling ws into non-Node environments (e.g. Cloudflare Workers).\n // The variable-based specifier prevents bundlers from resolving the module at build time.\n let createNodeWebSocket: typeof CreateNodeWebSocket;\n try {\n const mod = '@hono/node-ws';\n const honoNodeWs = await import(/* @vite-ignore */ /* webpackIgnore: true */ mod);\n createNodeWebSocket = honoNodeWs.createNodeWebSocket;\n } catch {\n // @hono/node-ws is not available (e.g. no ws package installed).\n // This is expected in non-Node environments — silently disable browser streaming.\n return null;\n }\n\n const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app });\n const registry = new ViewerRegistry();\n\n // Normalize the API prefix so we can build paths like `${apiPrefix}/agents/...`\n // without producing `//agents/...` when the prefix is missing or has a single\n // trailing slash. Anything weirder than that (e.g. `'/api//'`) is a config\n // bug we don't try to silently fix.\n const rawPrefix = config.apiPrefix ?? '/api';\n const trimmed = rawPrefix.endsWith('/') ? rawPrefix.slice(0, -1) : rawPrefix;\n const apiPrefix = trimmed || '/api';\n\n app.get(\n '/browser/:agentId/stream',\n upgradeWebSocket(c => {\n const agentId = c.req.param('agentId')!;\n const threadId = c.req.query('threadId');\n // Use composite key for thread-scoped screencasts\n const viewerKey = threadId ? `${agentId}:${threadId}` : agentId;\n\n return {\n onOpen(_event, ws) {\n // Send connected status immediately\n ws.send(JSON.stringify({ status: 'connected' }));\n\n // Add to registry (starts screencast if first viewer)\n // Fire-and-forget: screencast starts asynchronously\n // Pass agentId for toolset lookup, but viewerKey for registry scoping\n void registry.addViewer(viewerKey, ws, config.getToolset, agentId, threadId);\n },\n\n onMessage(event, _ws) {\n const data = typeof event.data === 'string' ? event.data : null;\n if (data) {\n void handleInputMessage(data, config.getToolset, agentId, threadId);\n }\n },\n\n onClose(_event, ws) {\n // Remove from registry (stops screencast if last viewer)\n // Fire-and-forget: cleanup is best-effort\n void registry.removeViewer(viewerKey, ws);\n },\n\n onError(event, ws) {\n console.error('[BrowserStream] WebSocket error:', event);\n // Fire-and-forget: cleanup is best-effort\n void registry.removeViewer(viewerKey, ws);\n },\n };\n }),\n );\n\n // Browser session probe endpoint - tells the client whether to open a WS.\n // Returns:\n // - screencastAvailable: true (this route only exists if setupBrowserStream succeeded)\n // - hasSession: whether the agent has an active browser session for the given thread\n app.get(`${apiPrefix}/agents/:agentId/browser/session`, async c => {\n const agentId = c.req.param('agentId');\n if (!agentId) {\n return c.json({ error: 'Agent ID is required' }, 400);\n }\n\n const threadId = c.req.query('threadId');\n const toolset = await config.getToolset(agentId);\n\n if (!toolset) {\n return c.json({ hasSession: false, screencastAvailable: true });\n }\n\n const hasSession = threadId ? toolset.hasThreadSession(threadId) : false;\n return c.json({ hasSession, screencastAvailable: true });\n });\n\n // Close browser session endpoint\n app.post(`${apiPrefix}/agents/:agentId/browser/close`, async c => {\n const agentId = c.req.param('agentId');\n if (!agentId) {\n return c.json({ error: 'Agent ID is required' }, 400);\n }\n\n const toolset = await config.getToolset(agentId);\n if (!toolset) {\n return c.json({ error: 'No browser session for this agent' }, 404);\n }\n\n try {\n // Parse threadId from request body\n let threadId: string | undefined;\n try {\n const body = await c.req.json();\n threadId = body?.threadId;\n } catch {\n // No body or invalid JSON - proceed without threadId\n }\n\n const scope = toolset.getScope();\n const viewerKey = threadId ? `${agentId}:${threadId}` : agentId;\n\n // For thread scope with a threadId, close only that thread's session\n if (scope === 'thread' && threadId) {\n // Close the session in the registry (stops screencast for this thread)\n await registry.closeBrowserSession(viewerKey);\n\n // Close just this thread's browser session\n if ('closeThreadSession' in toolset && typeof toolset.closeThreadSession === 'function') {\n await toolset.closeThreadSession(threadId);\n }\n } else {\n // For shared scope or no threadId, close the entire browser\n await registry.closeBrowserSession(viewerKey);\n await toolset.close();\n }\n\n return c.json({ success: true });\n } catch (error) {\n console.error(`[BrowserStream] Error closing browser for ${agentId}:`, error);\n return c.json({ error: 'Failed to close browser' }, 500);\n }\n });\n\n return { injectWebSocket: injectWebSocket as (server: unknown) => void, registry };\n}\n","import type { ToolsInput } from '@mastra/core/agent';\nimport type { Mastra } from '@mastra/core/mastra';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { InMemoryTaskStore } from '@mastra/server/a2a/store';\n\nimport type { MCPHttpTransportResult, MCPSseTransportResult } from '@mastra/server/handlers/mcp';\nimport type { ParsedRequestParams, ServerRoute } from '@mastra/server/server-adapter';\nimport {\n MASTRA_FRAMEWORK_PUBLIC_KEY,\n MastraServer as MastraServerBase,\n applyMcpRequestAuth,\n checkRouteFGA,\n getCustomHTTPExceptionResponse,\n isZodError,\n normalizeQueryParams,\n redactStreamChunk,\n serializeStreamChunk,\n} from '@mastra/server/server-adapter';\nimport { toReqRes, toFetchResponse } from 'fetch-to-node';\nimport type { Context, ExecutionContext, HonoRequest, MiddlewareHandler } from 'hono';\nimport { bodyLimit } from 'hono/body-limit';\nimport { stream } from 'hono/streaming';\nimport { propagateClientDisconnect } from './mcp-disconnect';\nexport { createAuthMiddleware } from './auth-middleware';\nexport type { HonoAuthMiddlewareOptions } from './auth-middleware';\n// Browser stream setup (Hono-specific WebSocket implementation)\nexport { setupBrowserStream } from './browser-stream';\n\ntype HasPermissionFn = (userPerms: string[], required: string) => boolean;\nlet _hasPermissionPromise: Promise<HasPermissionFn | undefined> | undefined;\nfunction loadHasPermission(): Promise<HasPermissionFn | undefined> {\n if (!_hasPermissionPromise) {\n _hasPermissionPromise = import('@mastra/core/auth/ee')\n .then(m => m.hasPermission)\n .catch(() => {\n console.error(\n '[@mastra/hono] Auth features require @mastra/core >= 1.6.0. Please upgrade: npm install @mastra/core@latest',\n );\n return undefined;\n });\n }\n return _hasPermissionPromise;\n}\n\n// Export type definitions for Hono app configuration\nexport type HonoVariables = {\n mastra: Mastra;\n requestContext: RequestContext;\n registeredTools: ToolsInput;\n abortSignal: AbortSignal;\n taskStore: InMemoryTaskStore;\n customRouteAuthConfig?: Map<string, boolean>;\n cachedBody?: unknown;\n /**\n * True when the current request targets a route the framework has declared\n * public (`requiresAuth: false`). Adapter authors MUST wrap user-registered\n * middleware with {@link skipIfFrameworkPublic} so that user middleware\n * cannot 401 these routes.\n */\n [MASTRA_FRAMEWORK_PUBLIC_KEY]?: boolean;\n};\n\n// Re-export the framework-public context key so users configuring Hono apps\n// can reference it directly without importing from @mastra/server.\nexport { MASTRA_FRAMEWORK_PUBLIC_KEY } from '@mastra/server/server-adapter';\n\n/**\n * Wrap a Hono middleware handler so it becomes a no-op for framework-public\n * routes (routes registered with `requiresAuth: false`).\n *\n * Adapters that expose user-provided middleware — for example `serverMiddleware`\n * on the Mastra instance or `server.middleware` in Mastra config — MUST wrap\n * those handlers with this before registering them. This is the framework's\n * guarantee that user middleware cannot accidentally (or intentionally) 401\n * routes the framework needs to keep reachable (e.g. Studio sign-in endpoints).\n *\n * The framework-public flag is computed once per request by\n * {@link MastraServer.registerContextMiddleware} and stashed on the Hono\n * context under `MASTRA_FRAMEWORK_PUBLIC_KEY`.\n */\nexport const skipIfFrameworkPublic = (handler: MiddlewareHandler): MiddlewareHandler => {\n return async (c, next) => {\n if (c.get(MASTRA_FRAMEWORK_PUBLIC_KEY)) {\n return next();\n }\n return handler(c, next);\n };\n};\n\n/**\n * Context key holding a pristine clone of the incoming request, captured by\n * the context middleware before user middleware runs. The custom-route bridge\n * reads the body from this clone so user middleware that consumes the request\n * body (e.g. `await c.req.json()`) does not break custom API routes.\n */\nconst MASTRA_PRISTINE_REQUEST_KEY = '__mastraPristineRequest';\n\nconst BODY_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);\n\nexport type HonoBindings = {};\n\n/**\n * Generic handler function type compatible across Hono versions.\n * Uses a minimal signature that all Hono middleware handlers satisfy.\n */\ntype HonoRouteHandler = (...args: any[]) => any;\n\n/**\n * Minimal interface representing what MastraServer needs from a Hono app.\n * This allows any Hono app instance to be passed without strict generic matching,\n * avoiding the version mismatch issues that occur with Hono's strict generic types.\n */\nexport interface HonoApp {\n use(path: string, ...handlers: HonoRouteHandler[]): unknown;\n get(path: string, ...handlers: HonoRouteHandler[]): unknown;\n post(path: string, ...handlers: HonoRouteHandler[]): unknown;\n put(path: string, ...handlers: HonoRouteHandler[]): unknown;\n delete(path: string, ...handlers: HonoRouteHandler[]): unknown;\n patch(path: string, ...handlers: HonoRouteHandler[]): unknown;\n all(path: string, ...handlers: HonoRouteHandler[]): unknown;\n}\n\nexport class MastraServer extends MastraServerBase<HonoApp, HonoRequest, Context> {\n createContextMiddleware(): MiddlewareHandler {\n return async (c, next) => {\n // Preserve a pristine clone of the request before user middleware runs.\n // `Request.clone()` tees the body stream, so the clone stays readable\n // even after middleware consumes the original (json/text/formData/raw).\n // Only taken when custom routes exist — the bridge is the sole consumer.\n if (this.hasCustomRouteHandler && BODY_METHODS.has(c.req.method) && c.req.raw.body) {\n c.set(MASTRA_PRISTINE_REQUEST_KEY, c.req.raw.clone());\n }\n\n // Patch req.json() to prevent \"Body is unusable\" errors when the body is read multiple times\n // e.g. by middleware and then by an agent.\n const originalJson = c.req.json.bind(c.req);\n let jsonPromise: Promise<any> | undefined;\n\n c.req.json = () => {\n if (!jsonPromise) {\n jsonPromise = originalJson().then(body => {\n // Cache in context if needed explicitly, though the promise memoization handles the reuse\n c.set('cachedBody', body);\n return body;\n });\n }\n return jsonPromise;\n };\n\n // Parse request context from request body and add to context\n\n let bodyRequestContext: Record<string, any> | undefined;\n let paramsRequestContext: Record<string, any> | undefined;\n\n // Parse request context from request body (POST/PUT)\n if (c.req.method === 'POST' || c.req.method === 'PUT') {\n const contentType = c.req.header('content-type');\n const contentLength = c.req.header('content-length');\n // Only parse if content-type is JSON and body is not empty\n if (contentType?.includes('application/json') && contentLength !== '0') {\n try {\n const body = (await c.req.raw.clone().json()) as { requestContext?: Record<string, any> };\n if (body.requestContext) {\n bodyRequestContext = body.requestContext;\n }\n } catch {\n // Body parsing failed, continue without body\n }\n }\n }\n\n // Parse request context from query params (GET)\n if (c.req.method === 'GET') {\n try {\n const encodedRequestContext = c.req.query('requestContext');\n if (encodedRequestContext) {\n // Try JSON first\n try {\n paramsRequestContext = JSON.parse(encodedRequestContext);\n } catch {\n // Fallback to base64(JSON)\n try {\n const json = Buffer.from(encodedRequestContext, 'base64').toString('utf-8');\n paramsRequestContext = JSON.parse(json);\n } catch {\n // ignore if still invalid\n }\n }\n }\n } catch {\n // ignore query parsing errors\n }\n }\n\n const requestContext = this.mergeRequestContext({ paramsRequestContext, bodyRequestContext });\n this.applyRequestMetadataToContext({\n requestContext,\n getHeader: name => c.req.header(name),\n });\n\n // Add relevant contexts to hono context\n c.set('requestContext', requestContext);\n c.set('mastra', this.mastra);\n c.set('registeredTools', this.tools || {});\n c.set('taskStore', this.taskStore);\n c.set('abortSignal', c.req.raw.signal);\n c.set('customRouteAuthConfig', this.customRouteAuthConfig);\n\n return next();\n };\n }\n async stream(route: ServerRoute, res: Context, result: { fullStream: ReadableStream }): Promise<any> {\n const streamFormat = route.streamFormat || 'stream';\n\n if (streamFormat === 'sse') {\n res.header('Content-Type', 'text/event-stream');\n res.header('Cache-Control', 'no-cache');\n res.header('Connection', 'keep-alive');\n res.header('X-Accel-Buffering', 'no');\n } else {\n res.header('Content-Type', 'text/plain');\n }\n res.header('Transfer-Encoding', 'chunked');\n\n return stream(\n res,\n async stream => {\n if (streamFormat === 'sse' && route.sseFlushOnConnect) {\n await stream.write(': connected\\n\\n');\n }\n\n const readableStream = result instanceof ReadableStream ? result : result.fullStream;\n const reader = readableStream.getReader();\n\n stream.onAbort(() => {\n void reader.cancel('request aborted').catch(() => {});\n });\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n if (value) {\n if (streamFormat === 'sse' && typeof value === 'string' && value.startsWith(':')) {\n await stream.write(value);\n continue;\n }\n\n // Optionally redact sensitive data (system prompts, tool definitions, API keys) before sending to the client\n const shouldRedact = this.streamOptions?.redact ?? true;\n const outputValue = shouldRedact ? redactStreamChunk(value) : value;\n // A chunk that can't be serialized must not kill the stream — skip it and keep streaming\n const serialized = serializeStreamChunk(outputValue);\n if (!serialized.ok) {\n this.mastra.getLogger()?.error('Failed to serialize stream chunk, skipping', {\n path: route.path,\n chunkType: (outputValue as { type?: string })?.type,\n error: serialized.error.message,\n });\n continue;\n }\n if (streamFormat === 'sse') {\n await stream.write(`data: ${serialized.json}\\n\\n`);\n } else {\n await stream.write(serialized.json + '\\x1E');\n }\n }\n }\n\n if (streamFormat === 'sse') {\n await stream.write('data: [DONE]\\n\\n');\n }\n } catch (error) {\n this.mastra.getLogger()?.error('Error in stream processing', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n } finally {\n await stream.close();\n }\n },\n async err => {\n this.mastra.getLogger()?.error('Stream error callback', {\n error: err instanceof Error ? { message: err.message, stack: err.stack } : err,\n });\n },\n );\n }\n\n async getParams(route: ServerRoute, request: HonoRequest): Promise<ParsedRequestParams> {\n const urlParams = request.param();\n // Use queries() to get all values for repeated params (e.g., ?tags=a&tags=b -> { tags: ['a', 'b'] })\n const queryParams = normalizeQueryParams(request.queries());\n let body: unknown;\n let bodyParseError: { message: string } | undefined;\n\n if (route.method === 'POST' || route.method === 'PUT' || route.method === 'PATCH' || route.method === 'DELETE') {\n const contentType = request.header('content-type') || '';\n\n if (contentType.includes('multipart/form-data')) {\n try {\n const formData = await request.formData();\n body = await this.parseFormData(formData);\n } catch (error) {\n this.mastra.getLogger()?.error('Failed to parse multipart form data', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n // Re-throw size limit errors, let others fall through to validation\n if (error instanceof Error && error.message.toLowerCase().includes('size')) {\n throw error;\n }\n bodyParseError = {\n message: error instanceof Error ? error.message : 'Failed to parse multipart form data',\n };\n }\n } else if (contentType.includes('application/json')) {\n // Clone the request to read the body text first\n // This allows us to check if there's actual content before parsing\n const clonedReq = request.raw.clone();\n const bodyText = await clonedReq.text();\n\n if (bodyText && bodyText.trim().length > 0) {\n // There's actual content - try to parse it as JSON\n try {\n body = JSON.parse(bodyText);\n } catch (error) {\n this.mastra.getLogger()?.error('Failed to parse JSON body', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n // Track JSON parse error to return 400 Bad Request\n bodyParseError = {\n message: error instanceof Error ? error.message : 'Invalid JSON in request body',\n };\n }\n }\n // Empty body is ok - body remains undefined\n }\n }\n return { urlParams, queryParams, body, bodyParseError };\n }\n\n /**\n * Parse FormData into a plain object, converting File objects to Buffers.\n */\n private async parseFormData(formData: FormData): Promise<Record<string, unknown>> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of formData.entries()) {\n if (value instanceof File) {\n const arrayBuffer = await value.arrayBuffer();\n result[key] = Buffer.from(arrayBuffer);\n } else if (typeof value === 'string') {\n // Try to parse JSON strings (like 'options')\n try {\n result[key] = JSON.parse(value);\n } catch {\n result[key] = value;\n }\n } else {\n result[key] = value;\n }\n }\n\n return result;\n }\n\n async sendResponse(route: ServerRoute, response: Context, result: unknown, prefix?: string): Promise<any> {\n const resolvedPrefix = prefix ?? this.prefix ?? '';\n\n // Apply refresh headers from transparent session refresh (e.g. Set-Cookie after token refresh)\n if (result && typeof result === 'object' && '__refreshHeaders' in result) {\n const refreshHeaders = (result as any).__refreshHeaders as Record<string, string>;\n for (const [key, value] of Object.entries(refreshHeaders)) {\n response.header(key, value);\n }\n delete (result as any).__refreshHeaders;\n }\n\n if (route.responseType === 'json') {\n return response.json(result as any, 200);\n } else if (route.responseType === 'stream') {\n return this.stream(route, response, result as { fullStream: ReadableStream });\n } else if (route.responseType === 'datastream-response') {\n const fetchResponse = result as globalThis.Response;\n return fetchResponse;\n } else if (route.responseType === 'mcp-http') {\n // MCP Streamable HTTP transport\n const { server, httpPath, mcpOptions: routeMcpOptions } = result as MCPHttpTransportResult;\n const { req, res } = toReqRes(response.req.raw);\n\n // Merge class-level mcpOptions with route-specific options (route takes precedence)\n const { setRequestAuth, ...options } = { ...this.mcpOptions, ...routeMcpOptions };\n\n // `toReqRes` builds a fresh IncomingMessage, so the principal resolved by\n // auth middleware never reaches the MCP transport unless we bridge it here.\n // This runs before startHTTP so every branch (stateless, existing session,\n // new session) sees the same `req.auth`.\n await applyMcpRequestAuth({ req, requestContext: response.get('requestContext'), setRequestAuth });\n\n // Do NOT await startHTTP — let it run in the background so SSE\n // notifications stream to the client as they are written.\n // toFetchResponse resolves when headers are sent, not when the body finishes.\n server\n .startHTTP({\n url: new URL(response.req.url),\n httpPath: `${resolvedPrefix}${httpPath}`,\n req,\n res,\n options: Object.keys(options).length > 0 ? options : undefined,\n })\n .catch((e: unknown) => {\n this.mastra.getLogger()?.error('[MCP HTTP] Error in background startHTTP:', {\n error: e instanceof Error ? { message: e.message, stack: e.stack } : e,\n });\n try {\n if (!res.headersSent) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n jsonrpc: '2.0',\n error: { code: -32603, message: 'Internal server error' },\n id: null,\n }),\n );\n }\n } catch {\n // Response stream already closed or destroyed - nothing more to do\n }\n });\n\n return propagateClientDisconnect(await toFetchResponse(res), res);\n } else if (route.responseType === 'mcp-sse') {\n // MCP SSE transport\n const { server, ssePath, messagePath } = result as MCPSseTransportResult;\n\n try {\n // SSE has no Node request to hang `req.auth` on, so resolve the auth info\n // here and pass it explicitly. Reuse the same bridge as streamable HTTP so\n // a `setRequestAuth` hook sees a real request object.\n const { req } = toReqRes(response.req.raw);\n await applyMcpRequestAuth({\n req,\n requestContext: response.get('requestContext'),\n setRequestAuth: this.mcpOptions?.setRequestAuth,\n });\n\n return await server.startHonoSSE({\n url: new URL(response.req.url),\n ssePath: `${resolvedPrefix}${ssePath}`,\n messagePath: `${resolvedPrefix}${messagePath}`,\n context: response,\n authInfo: (req as typeof req & { auth?: unknown }).auth,\n });\n } catch {\n return response.json({ error: 'Error handling MCP SSE request' }, 500);\n }\n } else {\n return response.status(500);\n }\n }\n\n async registerRoute(\n app: HonoApp,\n route: ServerRoute,\n { prefix: prefixParam }: { prefix?: string } = {},\n ): Promise<void> {\n // Default prefix to this.prefix if not provided, or empty string\n const prefix = prefixParam ?? this.prefix ?? '';\n\n const maxSize = route.maxBodySize ?? this.bodyLimitOptions?.maxSize;\n const isBodyMethod = ['POST', 'PUT', 'PATCH', 'DELETE'].includes(route.method.toUpperCase());\n\n // Build middleware array\n const middlewares: MiddlewareHandler[] = [];\n\n if (isBodyMethod && maxSize !== undefined) {\n middlewares.push(\n bodyLimit({\n maxSize,\n onError: (c: Context) => {\n let errorResponse: unknown = { error: 'Request body too large' };\n if (route.maxBodySize === undefined && this.bodyLimitOptions) {\n try {\n errorResponse = this.bodyLimitOptions.onError(errorResponse);\n } catch {\n // Fall back to the default response.\n }\n }\n return c.json(errorResponse, 413);\n },\n }),\n );\n }\n\n app[route.method.toLowerCase() as 'get' | 'post' | 'put' | 'delete' | 'patch' | 'all'](\n `${prefix}${route.path}`,\n ...middlewares,\n async (c: Context) => {\n // Check route-level authentication/authorization\n const authResult = await this.checkRouteAuth(route, {\n path: c.req.path,\n method: c.req.method,\n getHeader: name => c.req.header(name),\n getQuery: name => c.req.query(name),\n requestContext: c.get('requestContext'),\n request: c.req.raw,\n buildAuthorizeContext: () => c,\n });\n\n if (authResult) {\n // Apply any refresh headers (e.g. Set-Cookie from transparent session refresh)\n if (authResult.headers) {\n for (const [key, value] of Object.entries(authResult.headers)) {\n c.header(key, value as string);\n }\n }\n\n // If this is an auth error (not just a success-with-headers), return error response\n if (authResult.error) {\n return c.json({ error: authResult.error }, authResult.status as any);\n }\n }\n\n const params = await this.getParams(route, c.req);\n\n // Return 400 Bad Request if body parsing failed (e.g., malformed JSON)\n if (params.bodyParseError) {\n return c.json(\n {\n error: 'Invalid request body',\n issues: [{ field: 'body', message: params.bodyParseError.message }],\n },\n 400,\n );\n }\n\n if (params.queryParams) {\n try {\n params.queryParams = await this.parseQueryParams(route, params.queryParams);\n } catch (error) {\n this.mastra.getLogger()?.error('Error parsing query params', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n if (isZodError(error)) {\n const { status, body } = this.resolveValidationError(route, error, 'query');\n return c.json(body as any, status as any);\n }\n return c.json(\n {\n error: 'Invalid query parameters',\n issues: [{ field: 'unknown', message: error instanceof Error ? error.message : 'Unknown error' }],\n },\n 400,\n );\n }\n }\n\n if (params.body !== undefined || route.bodySchema) {\n try {\n params.body = await this.parseBody(route, params.body);\n } catch (error) {\n this.mastra.getLogger()?.error('Error parsing body', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n if (isZodError(error)) {\n const { status, body } = this.resolveValidationError(route, error, 'body');\n return c.json(body as any, status as any);\n }\n return c.json(\n {\n error: 'Invalid request body',\n issues: [{ field: 'unknown', message: error instanceof Error ? error.message : 'Unknown error' }],\n },\n 400,\n );\n }\n }\n\n // Parse path params through pathParamSchema for type coercion (e.g., z.coerce.number())\n if (params.urlParams) {\n try {\n params.urlParams = await this.parsePathParams(route, params.urlParams);\n } catch (error) {\n this.mastra.getLogger()?.error('Error parsing path params', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n if (isZodError(error)) {\n const { status, body } = this.resolveValidationError(route, error, 'path');\n return c.json(body as any, status as any);\n }\n return c.json(\n {\n error: 'Invalid path parameters',\n issues: [{ field: 'unknown', message: error instanceof Error ? error.message : 'Unknown error' }],\n },\n 400,\n );\n }\n }\n\n const handlerParams = {\n ...params.urlParams,\n ...params.queryParams,\n ...(typeof params.body === 'object' ? params.body : {}),\n requestContext: c.get('requestContext'),\n mastra: this.mastra,\n registeredTools: c.get('registeredTools'),\n taskStore: c.get('taskStore'),\n abortSignal: c.get('abortSignal'),\n routePrefix: prefix,\n request: c.req.raw, // Standard Request object with headers/cookies\n };\n\n // Check route permission requirement (EE feature)\n // Uses convention-based permission derivation: permissions are auto-derived\n // from route path/method unless explicitly set or route is public\n const requestContext = c.get('requestContext');\n // Check if any auth is configured (studio or server) for RBAC\n const hasAuth = this.mastra.getStudio?.()?.auth || this.mastra.getServer()?.auth;\n if (hasAuth) {\n const hasPermission = await loadHasPermission();\n if (hasPermission) {\n const userPermissions = requestContext.get('mastra__userPermissions') as string[] | undefined;\n const permissionError = this.checkRoutePermission(route, userPermissions, hasPermission, requestContext);\n\n if (permissionError) {\n return c.json(\n {\n error: permissionError.error,\n message: permissionError.message,\n },\n permissionError.status as any,\n );\n }\n }\n }\n\n // Check FGA authorization (EE feature)\n const fgaError = await checkRouteFGA(this.mastra, route, c.get('requestContext'), {\n ...params.urlParams,\n ...params.queryParams,\n ...(typeof params.body === 'object' ? params.body : {}),\n });\n if (fgaError) {\n return c.json({ error: fgaError.error, message: fgaError.message }, fgaError.status as any);\n }\n\n try {\n const result = await route.handler(handlerParams);\n return this.sendResponse(route, c, result, prefix);\n } catch (error) {\n // 4xx errors are client conditions (e.g. no session, expired token) and are\n // already returned as structured HTTP responses below. Logging them as errors\n // produces noise for callers — skip the logger call for those cases.\n const httpStatus =\n error && typeof error === 'object' && 'status' in error ? (error as any).status : undefined;\n const isClientError = typeof httpStatus === 'number' && httpStatus >= 400 && httpStatus < 500;\n if (!isClientError) {\n this.mastra.getLogger()?.error('Error calling handler', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n path: route.path,\n method: route.method,\n });\n }\n const customResponse = getCustomHTTPExceptionResponse(error);\n if (customResponse) {\n return customResponse;\n }\n\n // Check if it's an HTTPException or MastraError with a status code\n if (error && typeof error === 'object') {\n // Check for direct status property (HTTPException)\n if ('status' in error) {\n const status = (error as any).status;\n let safeCause: { failingItems: unknown[] } | undefined;\n try {\n const raw = error instanceof Error ? error.cause : undefined;\n if (\n raw &&\n typeof raw === 'object' &&\n !Array.isArray(raw) &&\n 'failingItems' in raw &&\n Array.isArray((raw as any).failingItems)\n ) {\n safeCause = { failingItems: (raw as any).failingItems };\n }\n } catch {\n // serialization or access error — omit cause\n }\n return c.json(\n {\n error: error instanceof Error ? error.message : 'Unknown error',\n ...(safeCause ? { cause: safeCause } : {}),\n },\n status,\n );\n }\n // Check for MastraError with status in details\n if ('details' in error && error.details && typeof error.details === 'object' && 'status' in error.details) {\n const status = (error.details as any).status;\n return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, status);\n }\n }\n return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500);\n }\n },\n );\n }\n\n async registerCustomApiRoutes(): Promise<void> {\n const routes = await this.registerSchemaApiRoutes();\n if (!(await this.buildCustomRouteHandler(routes))) return;\n\n for (const route of routes) {\n const serverRoute: ServerRoute = {\n method: route.method as any,\n path: route.path,\n responseType: 'json',\n handler: async () => {},\n requiresAuth: route.requiresAuth,\n requiresPermission: route.requiresPermission,\n fga: route.fga,\n };\n\n const routeHandler: MiddlewareHandler = async (c: Context) => {\n // Per-route auth check (same pattern as registerRoute)\n const authError = await this.checkRouteAuth(serverRoute, {\n path: c.req.path,\n method: c.req.method,\n getHeader: name => c.req.header(name),\n getQuery: name => c.req.query(name),\n requestContext: c.get('requestContext'),\n request: c.req.raw,\n buildAuthorizeContext: () => c,\n });\n\n if (authError) {\n if (authError.headers) {\n for (const [key, value] of Object.entries(authError.headers)) {\n c.header(key, value as string);\n }\n }\n if (authError.error) {\n return c.json({ error: authError.error }, authError.status as any);\n }\n }\n\n const requestContext = c.get('requestContext');\n // Check if any auth is configured (studio or server) for RBAC\n const hasAuth = this.mastra.getStudio?.()?.auth || this.mastra.getServer()?.auth;\n if (hasAuth) {\n const hasPermission = await loadHasPermission();\n if (hasPermission) {\n const userPermissions = requestContext.get('mastra__userPermissions') as string[] | undefined;\n const permissionError = this.checkRoutePermission(\n serverRoute,\n userPermissions,\n hasPermission,\n requestContext,\n );\n if (permissionError) {\n return c.json(\n { error: permissionError.error, message: permissionError.message },\n permissionError.status as any,\n );\n }\n }\n }\n\n // Use the pristine clone captured by the context middleware (before\n // user middleware ran) so body reads survive middleware that already\n // consumed `c.req.raw`.\n const pristineRequest = (c.get(MASTRA_PRISTINE_REQUEST_KEY) as Request | undefined) ?? c.req.raw;\n\n // Check FGA authorization (EE feature)\n let bodyParams: Record<string, unknown> = {};\n const contentType = c.req.header('content-type');\n if (contentType?.includes('application/json')) {\n try {\n const body = (await pristineRequest.clone().json()) as unknown;\n if (body && typeof body === 'object' && !Array.isArray(body)) {\n bodyParams = body as Record<string, unknown>;\n }\n } catch {\n bodyParams = {};\n }\n } else if (\n contentType?.includes('application/x-www-form-urlencoded') ||\n contentType?.includes('multipart/form-data')\n ) {\n try {\n bodyParams = Object.fromEntries(await pristineRequest.clone().formData());\n } catch {\n bodyParams = {};\n }\n }\n const fgaError = await checkRouteFGA(this.mastra, serverRoute, c.get('requestContext'), {\n ...c.req.param(),\n ...Object.fromEntries(new URL(c.req.url).searchParams.entries()),\n ...bodyParams,\n });\n if (fgaError) {\n return c.json({ error: fgaError.error, message: fgaError.message }, fgaError.status as any);\n }\n\n const reqHeaders: Record<string, string | string[] | undefined> = {};\n c.req.raw.headers.forEach((v, k) => {\n reqHeaders[k] = v;\n });\n // Forward the platform execution context (e.g. Cloudflare Workers'\n // `waitUntil`) so custom route handlers can keep background work alive\n // after the response. Hono's `executionCtx` getter throws when no\n // ExecutionContext exists (e.g. Node), so guard the access.\n let executionCtx: ExecutionContext | undefined;\n try {\n executionCtx = c.executionCtx;\n } catch {\n executionCtx = undefined;\n }\n const response = await this.handleCustomRouteRequest(\n c.req.url,\n c.req.method,\n reqHeaders,\n pristineRequest.body,\n c.get('requestContext'),\n c.req.raw.signal,\n executionCtx,\n );\n if (!response) {\n return c.json({ error: 'Not Found' }, 404);\n }\n return response;\n };\n\n const method = route.method.toLowerCase() as 'get' | 'post' | 'put' | 'delete' | 'patch' | 'all';\n this.app[method](route.path, routeHandler);\n }\n }\n\n registerContextMiddleware(): void {\n // Precompute the framework-public matcher once at registration time.\n // Called per-request below; used by adapters (see `skipIfFrameworkPublic`)\n // to short-circuit user-registered middleware for framework-public routes\n // so users cannot 401 routes declared public via `requiresAuth: false`.\n const isFrameworkPublic = this.getFrameworkPublicMatcher();\n\n this.app.use('*', this.createContextMiddleware());\n this.app.use('*', async (c, next) => {\n c.set(MASTRA_FRAMEWORK_PUBLIC_KEY, isFrameworkPublic(c.req.path, c.req.method));\n return next();\n });\n this.app.use('*', async (c, next) => {\n await next();\n this.warnIfUnregisteredChannelWebhook(c.req.path, c.req.method, c.res.status);\n });\n }\n\n registerAuthMiddleware(): void {\n // Auth is handled per-route in registerRoute() and registerCustomApiRoutes()\n // No global middleware needed\n }\n\n registerUserMiddleware(): void {\n // Middleware added at runtime via `mastra.setServerMiddleware()` — already\n // normalized to `{ path, handler }` entries by core.\n for (const m of this.mastra.getServerMiddleware?.() ?? []) {\n this.app.use(m.path, skipIfFrameworkPublic(m.handler));\n }\n\n const configMiddleware = this.mastra.getServer()?.middleware;\n if (!configMiddleware) {\n return;\n }\n\n const normalizedMiddlewares = Array.isArray(configMiddleware) ? configMiddleware : [configMiddleware];\n for (const middleware of normalizedMiddlewares) {\n const { path, handler } = typeof middleware === 'function' ? { path: '*', handler: middleware } : middleware;\n // Wrap with skipIfFrameworkPublic so user middleware cannot 401 routes\n // the framework declared public via `requiresAuth: false`\n // (e.g. Studio sign-in endpoints like /api/auth/capabilities).\n this.app.use(path, skipIfFrameworkPublic(handler as unknown as MiddlewareHandler));\n }\n }\n\n registerHttpLoggingMiddleware(): void {\n if (!this.httpLoggingConfig?.enabled) {\n return;\n }\n\n this.app.use('*', async (c, next) => {\n if (!this.shouldLogRequest(c.req.path)) {\n return next();\n }\n\n const start = Date.now();\n const method = c.req.method;\n const path = c.req.path;\n\n await next();\n\n const duration = Date.now() - start;\n const status = c.res.status;\n const level = this.httpLoggingConfig?.level || 'info';\n\n const logData: Record<string, any> = {\n method,\n path,\n status,\n duration: `${duration}ms`,\n };\n\n if (this.httpLoggingConfig?.includeQueryParams) {\n logData.query = c.req.query();\n }\n\n if (this.httpLoggingConfig?.includeHeaders) {\n const headers = Object.fromEntries(c.req.raw.headers.entries());\n const redactHeaders = this.httpLoggingConfig.redactHeaders || [];\n redactHeaders.forEach(h => {\n const key = h.toLowerCase();\n if (headers[key] !== undefined) {\n headers[key] = '[REDACTED]';\n }\n });\n logData.headers = headers;\n }\n\n this.logger[level](`${method} ${path} ${status} ${duration}ms`, logData);\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["MASTRA_FRAMEWORK_PUBLIC_KEY","MastraServerBase","fetchResponse"],"sources":["../src/mcp-disconnect.ts","../src/auth-middleware.ts","../src/browser-stream/index.ts","../src/index.ts"],"sourcesContent":["/**\n * Propagates a client disconnect to the simulated Node response produced by `toReqRes`.\n *\n * `fetch-to-node` builds the outgoing body from `res` events but never observes cancellation\n * of the stream it hands back. When an MCP Streamable HTTP client drops its session, nothing\n * tells `res` that the socket is gone, so the MCP transport keeps its SSE keep-alive timer\n * armed. The next keep-alive tick writes into an already-closed stream controller, and because\n * that write originates in a timer callback the resulting `ERR_INVALID_STATE` is unhandled and\n * takes down the process.\n *\n * Emitting `close` on `res` is the signal the MCP Node transport listens for: it aborts the\n * request's AbortController, which breaks the write loop and tears down the SSE stream,\n * clearing the keep-alive timer. No post-disconnect write is ever attempted.\n */\nexport function propagateClientDisconnect(\n fetchResponse: Response,\n res: { emit: (event: string) => void; destroy?: () => void },\n): Response {\n const upstream = fetchResponse.body;\n if (!upstream) return fetchResponse;\n\n let disconnected = false;\n const disconnect = () => {\n if (disconnected) return;\n disconnected = true;\n try {\n res.emit('close');\n } catch {\n // Already torn down - the transport has nothing left to clean up.\n }\n // Deliberately *not* cancelling or destroying the bridge stream here. `fetch-to-node`\n // buffers writes and flushes them from a cork timer; tearing its controller down leaves\n // that pending flush to enqueue into a closed controller, which throws an unhandled\n // ERR_INVALID_STATE from a timer callback - the very crash this guards against.\n // Emitting `close` aborts the transport, which ends the response, so the bridge closes\n // its own controller in the right order once buffered data has drained.\n void reader.read().then(\n function drain({ done }): unknown {\n return done ? undefined : reader.read().then(drain);\n },\n () => {},\n );\n };\n\n const reader = upstream.getReader();\n const body = new ReadableStream<Uint8Array>({\n async pull(controller) {\n const { done, value } = await reader.read();\n if (done) {\n controller.close();\n return;\n }\n controller.enqueue(value);\n },\n cancel() {\n disconnect();\n },\n });\n\n return new Response(body, {\n status: fetchResponse.status,\n statusText: fetchResponse.statusText,\n headers: fetchResponse.headers,\n });\n}\n","import type { Mastra } from '@mastra/core/mastra';\nimport { RequestContext } from '@mastra/core/request-context';\nimport { coreAuthMiddleware } from '@mastra/server/auth';\nimport type { Context, MiddlewareHandler } from 'hono';\n\nexport interface HonoAuthMiddlewareOptions {\n mastra: Mastra;\n requiresAuth?: boolean;\n}\n\nexport function createAuthMiddleware({ mastra, requiresAuth = true }: HonoAuthMiddlewareOptions): MiddlewareHandler {\n return async (c: Context, next) => {\n if (!requiresAuth) {\n return next();\n }\n\n const authConfig = mastra.getServer()?.auth;\n if (!authConfig) {\n return next();\n }\n\n const requestContext = c.get('requestContext') ?? new RequestContext();\n c.set('requestContext', requestContext);\n c.set('mastra', c.get('mastra') ?? mastra);\n\n const path = c.req.path;\n const method = c.req.method;\n const customRouteAuthConfig = new Map<string, boolean>(c.get('customRouteAuthConfig') ?? []);\n customRouteAuthConfig.set(`${method}:${path}`, true);\n\n const authHeader = c.req.header('Authorization');\n let token: string | null = authHeader ? authHeader.replace('Bearer ', '') : null;\n if (!token) {\n token = c.req.query('apiKey') || null;\n }\n\n const result = await coreAuthMiddleware({\n path,\n method,\n getHeader: name => c.req.header(name),\n mastra,\n authConfig,\n customRouteAuthConfig,\n requestContext,\n rawRequest: c.req.raw,\n token,\n buildAuthorizeContext: () => c,\n });\n\n if (result.action === 'next') {\n return next();\n }\n\n return c.json(result.body as any, result.status as any);\n };\n}\n","import type { createNodeWebSocket as CreateNodeWebSocket } from '@hono/node-ws';\nimport { handleInputMessage, ViewerRegistry } from '@mastra/server/browser-stream';\nimport type { BrowserStreamConfig, BrowserStreamResult } from '@mastra/server/browser-stream';\nimport type { Env, Hono, Schema } from 'hono';\n\n/**\n * Set up WebSocket-based browser stream endpoint for real-time screencast viewing.\n *\n * Creates a WebSocket route at `/browser/:agentId/stream` that:\n * - Accepts viewer connections\n * - Starts screencast when first viewer connects\n * - Broadcasts frames to all connected viewers\n * - Stops screencast when last viewer disconnects\n *\n * **Note**: Requires `ws` package to be installed. If not available, returns null\n * and logs a warning. Browser streaming will be disabled but everything else works.\n *\n * @param app - The Hono application instance\n * @param config - Configuration for browser stream\n * @returns Object containing injectWebSocket function and registry instance, or null if ws is not available\n *\n * @example\n * ```typescript\n * import { Hono } from 'hono';\n * import { serve } from '@hono/node-server';\n * import { setupBrowserStream } from '@mastra/hono';\n *\n * const app = new Hono();\n * const browserStream = await setupBrowserStream(app, {\n * getToolset: (agentId) => browserToolsets.get(agentId),\n * });\n *\n * const server = serve({ fetch: app.fetch, port: 4111 });\n * browserStream?.injectWebSocket(server);\n * ```\n */\nexport async function setupBrowserStream<E extends Env, S extends Schema, B extends string>(\n app: Hono<E, S, B>,\n config: BrowserStreamConfig,\n): Promise<BrowserStreamResult | null> {\n // Dynamic import to avoid bundling ws into non-Node environments (e.g. Cloudflare Workers).\n // The variable-based specifier prevents bundlers from resolving the module at build time.\n let createNodeWebSocket: typeof CreateNodeWebSocket;\n try {\n const mod = '@hono/node-ws';\n const honoNodeWs = await import(/* @vite-ignore */ /* webpackIgnore: true */ mod);\n createNodeWebSocket = honoNodeWs.createNodeWebSocket;\n } catch {\n // @hono/node-ws is not available (e.g. no ws package installed).\n // This is expected in non-Node environments — silently disable browser streaming.\n return null;\n }\n\n const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app });\n const registry = new ViewerRegistry();\n\n // Normalize the API prefix so we can build paths like `${apiPrefix}/agents/...`\n // without producing `//agents/...` when the prefix is missing or has a single\n // trailing slash. Anything weirder than that (e.g. `'/api//'`) is a config\n // bug we don't try to silently fix.\n const rawPrefix = config.apiPrefix ?? '/api';\n const trimmed = rawPrefix.endsWith('/') ? rawPrefix.slice(0, -1) : rawPrefix;\n const apiPrefix = trimmed || '/api';\n\n app.get(\n '/browser/:agentId/stream',\n upgradeWebSocket(c => {\n const agentId = c.req.param('agentId')!;\n const threadId = c.req.query('threadId');\n // Use composite key for thread-scoped screencasts\n const viewerKey = threadId ? `${agentId}:${threadId}` : agentId;\n\n return {\n onOpen(_event, ws) {\n // Send connected status immediately\n ws.send(JSON.stringify({ status: 'connected' }));\n\n // Add to registry (starts screencast if first viewer)\n // Fire-and-forget: screencast starts asynchronously\n // Pass agentId for toolset lookup, but viewerKey for registry scoping\n void registry.addViewer(viewerKey, ws, config.getToolset, agentId, threadId);\n },\n\n onMessage(event, _ws) {\n const data = typeof event.data === 'string' ? event.data : null;\n if (data) {\n void handleInputMessage(data, config.getToolset, agentId, threadId);\n }\n },\n\n onClose(_event, ws) {\n // Remove from registry (stops screencast if last viewer)\n // Fire-and-forget: cleanup is best-effort\n void registry.removeViewer(viewerKey, ws);\n },\n\n onError(event, ws) {\n console.error('[BrowserStream] WebSocket error:', event);\n // Fire-and-forget: cleanup is best-effort\n void registry.removeViewer(viewerKey, ws);\n },\n };\n }),\n );\n\n // Browser session probe endpoint - tells the client whether to open a WS.\n // Returns:\n // - screencastAvailable: true (this route only exists if setupBrowserStream succeeded)\n // - hasSession: whether the agent has an active browser session for the given thread\n app.get(`${apiPrefix}/agents/:agentId/browser/session`, async c => {\n const agentId = c.req.param('agentId');\n if (!agentId) {\n return c.json({ error: 'Agent ID is required' }, 400);\n }\n\n const threadId = c.req.query('threadId');\n const toolset = await config.getToolset(agentId);\n\n if (!toolset) {\n return c.json({ hasSession: false, screencastAvailable: true });\n }\n\n const hasSession = threadId ? toolset.hasThreadSession(threadId) : false;\n return c.json({ hasSession, screencastAvailable: true });\n });\n\n // Close browser session endpoint\n app.post(`${apiPrefix}/agents/:agentId/browser/close`, async c => {\n const agentId = c.req.param('agentId');\n if (!agentId) {\n return c.json({ error: 'Agent ID is required' }, 400);\n }\n\n const toolset = await config.getToolset(agentId);\n if (!toolset) {\n return c.json({ error: 'No browser session for this agent' }, 404);\n }\n\n try {\n // Parse threadId from request body\n let threadId: string | undefined;\n try {\n const body = await c.req.json();\n threadId = body?.threadId;\n } catch {\n // No body or invalid JSON - proceed without threadId\n }\n\n const scope = toolset.getScope();\n const viewerKey = threadId ? `${agentId}:${threadId}` : agentId;\n\n // For thread scope with a threadId, close only that thread's session\n if (scope === 'thread' && threadId) {\n // Close the session in the registry (stops screencast for this thread)\n await registry.closeBrowserSession(viewerKey);\n\n // Close just this thread's browser session\n if ('closeThreadSession' in toolset && typeof toolset.closeThreadSession === 'function') {\n await toolset.closeThreadSession(threadId);\n }\n } else {\n // For shared scope or no threadId, close the entire browser\n await registry.closeBrowserSession(viewerKey);\n await toolset.close();\n }\n\n return c.json({ success: true });\n } catch (error) {\n console.error(`[BrowserStream] Error closing browser for ${agentId}:`, error);\n return c.json({ error: 'Failed to close browser' }, 500);\n }\n });\n\n return { injectWebSocket: injectWebSocket as (server: unknown) => void, registry };\n}\n","import type { ToolsInput } from '@mastra/core/agent';\nimport type { Mastra } from '@mastra/core/mastra';\nimport type { RequestContext } from '@mastra/core/request-context';\nimport type { InMemoryTaskStore } from '@mastra/server/a2a/store';\n\nimport type { MCPHttpTransportResult, MCPSseTransportResult } from '@mastra/server/handlers/mcp';\nimport type { ParsedRequestParams, ServerRoute } from '@mastra/server/server-adapter';\nimport {\n MASTRA_FRAMEWORK_PUBLIC_KEY,\n MastraServer as MastraServerBase,\n applyMcpRequestAuth,\n checkRouteFGA,\n getCustomHTTPExceptionResponse,\n isZodError,\n normalizeQueryParams,\n redactStreamChunk,\n serializeStreamChunk,\n} from '@mastra/server/server-adapter';\nimport { toReqRes, toFetchResponse } from 'fetch-to-node';\nimport type { Context, ExecutionContext, HonoRequest, MiddlewareHandler } from 'hono';\nimport { bodyLimit } from 'hono/body-limit';\nimport { stream } from 'hono/streaming';\nimport { propagateClientDisconnect } from './mcp-disconnect';\nexport { createAuthMiddleware } from './auth-middleware';\nexport type { HonoAuthMiddlewareOptions } from './auth-middleware';\n// Browser stream setup (Hono-specific WebSocket implementation)\nexport { setupBrowserStream } from './browser-stream';\n\ntype HasPermissionFn = (userPerms: string[], required: string) => boolean;\nlet _hasPermissionPromise: Promise<HasPermissionFn | undefined> | undefined;\nfunction loadHasPermission(): Promise<HasPermissionFn | undefined> {\n if (!_hasPermissionPromise) {\n _hasPermissionPromise = import('@mastra/core/auth/ee')\n .then(m => m.hasPermission)\n .catch(() => {\n console.error(\n '[@mastra/hono] Auth features require @mastra/core >= 1.6.0. Please upgrade: npm install @mastra/core@latest',\n );\n return undefined;\n });\n }\n return _hasPermissionPromise;\n}\n\n// Export type definitions for Hono app configuration\nexport type HonoVariables = {\n mastra: Mastra;\n requestContext: RequestContext;\n registeredTools: ToolsInput;\n abortSignal: AbortSignal;\n taskStore: InMemoryTaskStore;\n customRouteAuthConfig?: Map<string, boolean>;\n cachedBody?: unknown;\n /**\n * True when the current request targets a route the framework has declared\n * public (`requiresAuth: false`). Adapter authors MUST wrap user-registered\n * middleware with {@link skipIfFrameworkPublic} so that user middleware\n * cannot 401 these routes.\n */\n [MASTRA_FRAMEWORK_PUBLIC_KEY]?: boolean;\n};\n\n// Re-export the framework-public context key so users configuring Hono apps\n// can reference it directly without importing from @mastra/server.\nexport { MASTRA_FRAMEWORK_PUBLIC_KEY } from '@mastra/server/server-adapter';\n\n/**\n * Wrap a Hono middleware handler so it becomes a no-op for framework-public\n * routes (routes registered with `requiresAuth: false`).\n *\n * Adapters that expose user-provided middleware — for example `serverMiddleware`\n * on the Mastra instance or `server.middleware` in Mastra config — MUST wrap\n * those handlers with this before registering them. This is the framework's\n * guarantee that user middleware cannot accidentally (or intentionally) 401\n * routes the framework needs to keep reachable (e.g. Studio sign-in endpoints).\n *\n * The framework-public flag is computed once per request by\n * {@link MastraServer.registerContextMiddleware} and stashed on the Hono\n * context under `MASTRA_FRAMEWORK_PUBLIC_KEY`.\n */\nexport const skipIfFrameworkPublic = (handler: MiddlewareHandler): MiddlewareHandler => {\n return async (c, next) => {\n if (c.get(MASTRA_FRAMEWORK_PUBLIC_KEY)) {\n return next();\n }\n return handler(c, next);\n };\n};\n\n/**\n * Context key holding a pristine clone of the incoming request, captured by\n * the context middleware before user middleware runs. The custom-route bridge\n * reads the body from this clone so user middleware that consumes the request\n * body (e.g. `await c.req.json()`) does not break custom API routes.\n */\nconst MASTRA_PRISTINE_REQUEST_KEY = '__mastraPristineRequest';\n\nconst BODY_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);\n\nexport type HonoBindings = {};\n\n/**\n * Generic handler function type compatible across Hono versions.\n * Uses a minimal signature that all Hono middleware handlers satisfy.\n */\ntype HonoRouteHandler = (...args: any[]) => any;\n\n/**\n * Minimal interface representing what MastraServer needs from a Hono app.\n * This allows any Hono app instance to be passed without strict generic matching,\n * avoiding the version mismatch issues that occur with Hono's strict generic types.\n */\nexport interface HonoApp {\n use(path: string, ...handlers: HonoRouteHandler[]): unknown;\n get(path: string, ...handlers: HonoRouteHandler[]): unknown;\n post(path: string, ...handlers: HonoRouteHandler[]): unknown;\n put(path: string, ...handlers: HonoRouteHandler[]): unknown;\n delete(path: string, ...handlers: HonoRouteHandler[]): unknown;\n patch(path: string, ...handlers: HonoRouteHandler[]): unknown;\n all(path: string, ...handlers: HonoRouteHandler[]): unknown;\n}\n\nexport class MastraServer extends MastraServerBase<HonoApp, HonoRequest, Context> {\n createContextMiddleware(): MiddlewareHandler {\n return async (c, next) => {\n // Preserve a pristine clone of the request before user middleware runs.\n // `Request.clone()` tees the body stream, so the clone stays readable\n // even after middleware consumes the original (json/text/formData/raw).\n // Only taken when custom routes exist — the bridge is the sole consumer.\n if (this.hasCustomRouteHandler && BODY_METHODS.has(c.req.method) && c.req.raw.body) {\n c.set(MASTRA_PRISTINE_REQUEST_KEY, c.req.raw.clone());\n }\n\n // Patch req.json() to prevent \"Body is unusable\" errors when the body is read multiple times\n // e.g. by middleware and then by an agent.\n const originalJson = c.req.json.bind(c.req);\n let jsonPromise: Promise<any> | undefined;\n\n c.req.json = () => {\n if (!jsonPromise) {\n jsonPromise = originalJson().then(body => {\n // Cache in context if needed explicitly, though the promise memoization handles the reuse\n c.set('cachedBody', body);\n return body;\n });\n }\n return jsonPromise;\n };\n\n // Parse request context from request body and add to context\n\n let bodyRequestContext: Record<string, any> | undefined;\n let paramsRequestContext: Record<string, any> | undefined;\n\n // Parse request context from request body (POST/PUT)\n if (c.req.method === 'POST' || c.req.method === 'PUT') {\n const contentType = c.req.header('content-type');\n const contentLength = c.req.header('content-length');\n // Only parse if content-type is JSON and body is not empty\n if (contentType?.includes('application/json') && contentLength !== '0') {\n try {\n const body = (await c.req.raw.clone().json()) as { requestContext?: Record<string, any> };\n if (body.requestContext) {\n bodyRequestContext = body.requestContext;\n }\n } catch {\n // Body parsing failed, continue without body\n }\n }\n }\n\n // Parse request context from query params.\n if (c.req.method === 'GET' || c.req.method === 'POST') {\n try {\n const encodedRequestContext = c.req.query('requestContext');\n if (encodedRequestContext) {\n // Try JSON first\n try {\n paramsRequestContext = JSON.parse(encodedRequestContext);\n } catch {\n // Fallback to base64(JSON)\n try {\n const json = Buffer.from(encodedRequestContext, 'base64').toString('utf-8');\n paramsRequestContext = JSON.parse(json);\n } catch {\n // ignore if still invalid\n }\n }\n }\n } catch {\n // ignore query parsing errors\n }\n }\n\n const requestContext = this.mergeRequestContext({ paramsRequestContext, bodyRequestContext });\n this.applyRequestMetadataToContext({\n requestContext,\n getHeader: name => c.req.header(name),\n });\n\n // Add relevant contexts to hono context\n c.set('requestContext', requestContext);\n c.set('mastra', this.mastra);\n c.set('registeredTools', this.tools || {});\n c.set('taskStore', this.taskStore);\n c.set('abortSignal', c.req.raw.signal);\n c.set('customRouteAuthConfig', this.customRouteAuthConfig);\n\n return next();\n };\n }\n async stream(route: ServerRoute, res: Context, result: { fullStream: ReadableStream }): Promise<any> {\n const streamFormat = route.streamFormat || 'stream';\n\n if (streamFormat === 'sse') {\n res.header('Content-Type', 'text/event-stream');\n res.header('Cache-Control', 'no-cache');\n res.header('Connection', 'keep-alive');\n res.header('X-Accel-Buffering', 'no');\n } else {\n res.header('Content-Type', 'text/plain');\n }\n res.header('Transfer-Encoding', 'chunked');\n\n return stream(\n res,\n async stream => {\n if (streamFormat === 'sse' && route.sseFlushOnConnect) {\n await stream.write(': connected\\n\\n');\n }\n\n const readableStream = result instanceof ReadableStream ? result : result.fullStream;\n const reader = readableStream.getReader();\n\n stream.onAbort(() => {\n void reader.cancel('request aborted').catch(() => {});\n });\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n if (value) {\n if (streamFormat === 'sse' && typeof value === 'string' && value.startsWith(':')) {\n await stream.write(value);\n continue;\n }\n\n // Optionally redact sensitive data (system prompts, tool definitions, API keys) before sending to the client\n const shouldRedact = this.streamOptions?.redact ?? true;\n const outputValue = shouldRedact ? redactStreamChunk(value) : value;\n // A chunk that can't be serialized must not kill the stream — skip it and keep streaming\n const serialized = serializeStreamChunk(outputValue);\n if (!serialized.ok) {\n this.mastra.getLogger()?.error('Failed to serialize stream chunk, skipping', {\n path: route.path,\n chunkType: (outputValue as { type?: string })?.type,\n error: serialized.error.message,\n });\n continue;\n }\n if (streamFormat === 'sse') {\n await stream.write(`data: ${serialized.json}\\n\\n`);\n } else {\n await stream.write(serialized.json + '\\x1E');\n }\n }\n }\n\n if (streamFormat === 'sse') {\n await stream.write('data: [DONE]\\n\\n');\n }\n } catch (error) {\n this.mastra.getLogger()?.error('Error in stream processing', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n } finally {\n await stream.close();\n }\n },\n async err => {\n this.mastra.getLogger()?.error('Stream error callback', {\n error: err instanceof Error ? { message: err.message, stack: err.stack } : err,\n });\n },\n );\n }\n\n async getParams(route: ServerRoute, request: HonoRequest): Promise<ParsedRequestParams> {\n const urlParams = request.param();\n // Use queries() to get all values for repeated params (e.g., ?tags=a&tags=b -> { tags: ['a', 'b'] })\n const queryParams = normalizeQueryParams(request.queries());\n let body: unknown;\n let bodyParseError: { message: string } | undefined;\n\n if (route.method === 'POST' || route.method === 'PUT' || route.method === 'PATCH' || route.method === 'DELETE') {\n const contentType = request.header('content-type') || '';\n\n if (contentType.includes('multipart/form-data')) {\n try {\n const formData = await request.formData();\n body = await this.parseFormData(formData);\n } catch (error) {\n this.mastra.getLogger()?.error('Failed to parse multipart form data', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n // Re-throw size limit errors, let others fall through to validation\n if (error instanceof Error && error.message.toLowerCase().includes('size')) {\n throw error;\n }\n bodyParseError = {\n message: error instanceof Error ? error.message : 'Failed to parse multipart form data',\n };\n }\n } else if (contentType.includes('application/json')) {\n // Clone the request to read the body text first\n // This allows us to check if there's actual content before parsing\n const clonedReq = request.raw.clone();\n const bodyText = await clonedReq.text();\n\n if (bodyText && bodyText.trim().length > 0) {\n // There's actual content - try to parse it as JSON\n try {\n body = JSON.parse(bodyText);\n } catch (error) {\n this.mastra.getLogger()?.error('Failed to parse JSON body', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n // Track JSON parse error to return 400 Bad Request\n bodyParseError = {\n message: error instanceof Error ? error.message : 'Invalid JSON in request body',\n };\n }\n }\n // Empty body is ok - body remains undefined\n }\n }\n return { urlParams, queryParams, body, bodyParseError };\n }\n\n /**\n * Parse FormData into a plain object, converting File objects to Buffers.\n */\n private async parseFormData(formData: FormData): Promise<Record<string, unknown>> {\n const result: Record<string, unknown> = {};\n\n for (const [key, value] of formData.entries()) {\n if (value instanceof File) {\n const arrayBuffer = await value.arrayBuffer();\n result[key] = Buffer.from(arrayBuffer);\n } else if (typeof value === 'string') {\n // Try to parse JSON strings (like 'options')\n try {\n result[key] = JSON.parse(value);\n } catch {\n result[key] = value;\n }\n } else {\n result[key] = value;\n }\n }\n\n return result;\n }\n\n async sendResponse(route: ServerRoute, response: Context, result: unknown, prefix?: string): Promise<any> {\n const resolvedPrefix = prefix ?? this.prefix ?? '';\n\n // Apply refresh headers from transparent session refresh (e.g. Set-Cookie after token refresh)\n if (result && typeof result === 'object' && '__refreshHeaders' in result) {\n const refreshHeaders = (result as any).__refreshHeaders as Record<string, string>;\n for (const [key, value] of Object.entries(refreshHeaders)) {\n response.header(key, value);\n }\n delete (result as any).__refreshHeaders;\n }\n\n if (route.responseType === 'json') {\n return response.json(result as any, 200);\n } else if (route.responseType === 'stream') {\n return this.stream(route, response, result as { fullStream: ReadableStream });\n } else if (route.responseType === 'datastream-response') {\n const fetchResponse = result as globalThis.Response;\n return fetchResponse;\n } else if (route.responseType === 'mcp-http') {\n // MCP Streamable HTTP transport\n const { server, httpPath, mcpOptions: routeMcpOptions } = result as MCPHttpTransportResult;\n const { req, res } = toReqRes(response.req.raw);\n\n // Merge class-level mcpOptions with route-specific options (route takes precedence)\n const { setRequestAuth, ...options } = { ...this.mcpOptions, ...routeMcpOptions };\n\n // `toReqRes` builds a fresh IncomingMessage, so the principal resolved by\n // auth middleware never reaches the MCP transport unless we bridge it here.\n // This runs before startHTTP so every branch (stateless, existing session,\n // new session) sees the same `req.auth`.\n await applyMcpRequestAuth({ req, requestContext: response.get('requestContext'), setRequestAuth });\n\n // Do NOT await startHTTP — let it run in the background so SSE\n // notifications stream to the client as they are written.\n // toFetchResponse resolves when headers are sent, not when the body finishes.\n server\n .startHTTP({\n url: new URL(response.req.url),\n httpPath: `${resolvedPrefix}${httpPath}`,\n req,\n res,\n options: Object.keys(options).length > 0 ? options : undefined,\n })\n .catch((e: unknown) => {\n this.mastra.getLogger()?.error('[MCP HTTP] Error in background startHTTP:', {\n error: e instanceof Error ? { message: e.message, stack: e.stack } : e,\n });\n try {\n if (!res.headersSent) {\n res.writeHead(500, { 'Content-Type': 'application/json' });\n res.end(\n JSON.stringify({\n jsonrpc: '2.0',\n error: { code: -32603, message: 'Internal server error' },\n id: null,\n }),\n );\n }\n } catch {\n // Response stream already closed or destroyed - nothing more to do\n }\n });\n\n return propagateClientDisconnect(await toFetchResponse(res), res);\n } else if (route.responseType === 'mcp-sse') {\n // MCP SSE transport\n const { server, ssePath, messagePath } = result as MCPSseTransportResult;\n\n try {\n // SSE has no Node request to hang `req.auth` on, so resolve the auth info\n // here and pass it explicitly. Reuse the same bridge as streamable HTTP so\n // a `setRequestAuth` hook sees a real request object.\n const { req } = toReqRes(response.req.raw);\n await applyMcpRequestAuth({\n req,\n requestContext: response.get('requestContext'),\n setRequestAuth: this.mcpOptions?.setRequestAuth,\n });\n\n return await server.startHonoSSE({\n url: new URL(response.req.url),\n ssePath: `${resolvedPrefix}${ssePath}`,\n messagePath: `${resolvedPrefix}${messagePath}`,\n context: response,\n authInfo: (req as typeof req & { auth?: unknown }).auth,\n });\n } catch {\n return response.json({ error: 'Error handling MCP SSE request' }, 500);\n }\n } else {\n return response.status(500);\n }\n }\n\n async registerRoute(\n app: HonoApp,\n route: ServerRoute,\n { prefix: prefixParam }: { prefix?: string } = {},\n ): Promise<void> {\n // Default prefix to this.prefix if not provided, or empty string\n const prefix = prefixParam ?? this.prefix ?? '';\n\n const maxSize = route.maxBodySize ?? this.bodyLimitOptions?.maxSize;\n const isBodyMethod = ['POST', 'PUT', 'PATCH', 'DELETE'].includes(route.method.toUpperCase());\n\n // Build middleware array\n const middlewares: MiddlewareHandler[] = [];\n\n if (isBodyMethod && maxSize !== undefined) {\n middlewares.push(\n bodyLimit({\n maxSize,\n onError: (c: Context) => {\n let errorResponse: unknown = { error: 'Request body too large' };\n if (route.maxBodySize === undefined && this.bodyLimitOptions) {\n try {\n errorResponse = this.bodyLimitOptions.onError(errorResponse);\n } catch {\n // Fall back to the default response.\n }\n }\n return c.json(errorResponse, 413);\n },\n }),\n );\n }\n\n app[route.method.toLowerCase() as 'get' | 'post' | 'put' | 'delete' | 'patch' | 'all'](\n `${prefix}${route.path}`,\n ...middlewares,\n async (c: Context) => {\n // Check route-level authentication/authorization\n const authResult = await this.checkRouteAuth(route, {\n path: c.req.path,\n method: c.req.method,\n getHeader: name => c.req.header(name),\n getQuery: name => c.req.query(name),\n requestContext: c.get('requestContext'),\n request: c.req.raw,\n buildAuthorizeContext: () => c,\n });\n\n if (authResult) {\n // Apply any refresh headers (e.g. Set-Cookie from transparent session refresh)\n if (authResult.headers) {\n for (const [key, value] of Object.entries(authResult.headers)) {\n c.header(key, value as string);\n }\n }\n\n // If this is an auth error (not just a success-with-headers), return error response\n if (authResult.error) {\n return c.json({ error: authResult.error }, authResult.status as any);\n }\n }\n\n const params = await this.getParams(route, c.req);\n\n // Return 400 Bad Request if body parsing failed (e.g., malformed JSON)\n if (params.bodyParseError) {\n return c.json(\n {\n error: 'Invalid request body',\n issues: [{ field: 'body', message: params.bodyParseError.message }],\n },\n 400,\n );\n }\n\n if (params.queryParams) {\n try {\n params.queryParams = await this.parseQueryParams(route, params.queryParams);\n } catch (error) {\n this.mastra.getLogger()?.error('Error parsing query params', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n if (isZodError(error)) {\n const { status, body } = this.resolveValidationError(route, error, 'query');\n return c.json(body as any, status as any);\n }\n return c.json(\n {\n error: 'Invalid query parameters',\n issues: [{ field: 'unknown', message: error instanceof Error ? error.message : 'Unknown error' }],\n },\n 400,\n );\n }\n }\n\n if (params.body !== undefined || route.bodySchema) {\n try {\n params.body = await this.parseBody(route, params.body);\n } catch (error) {\n this.mastra.getLogger()?.error('Error parsing body', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n if (isZodError(error)) {\n const { status, body } = this.resolveValidationError(route, error, 'body');\n return c.json(body as any, status as any);\n }\n return c.json(\n {\n error: 'Invalid request body',\n issues: [{ field: 'unknown', message: error instanceof Error ? error.message : 'Unknown error' }],\n },\n 400,\n );\n }\n }\n\n // Parse path params through pathParamSchema for type coercion (e.g., z.coerce.number())\n if (params.urlParams) {\n try {\n params.urlParams = await this.parsePathParams(route, params.urlParams);\n } catch (error) {\n this.mastra.getLogger()?.error('Error parsing path params', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n });\n if (isZodError(error)) {\n const { status, body } = this.resolveValidationError(route, error, 'path');\n return c.json(body as any, status as any);\n }\n return c.json(\n {\n error: 'Invalid path parameters',\n issues: [{ field: 'unknown', message: error instanceof Error ? error.message : 'Unknown error' }],\n },\n 400,\n );\n }\n }\n\n const handlerParams = {\n ...params.urlParams,\n ...params.queryParams,\n ...(typeof params.body === 'object' ? params.body : {}),\n requestContext: c.get('requestContext'),\n mastra: this.mastra,\n registeredTools: c.get('registeredTools'),\n taskStore: c.get('taskStore'),\n abortSignal: c.get('abortSignal'),\n routePrefix: prefix,\n request: c.req.raw, // Standard Request object with headers/cookies\n };\n\n // Check route permission requirement (EE feature)\n // Uses convention-based permission derivation: permissions are auto-derived\n // from route path/method unless explicitly set or route is public\n const requestContext = c.get('requestContext');\n // Check if any auth is configured (studio or server) for RBAC\n const hasAuth = this.mastra.getStudio?.()?.auth || this.mastra.getServer()?.auth;\n if (hasAuth) {\n const hasPermission = await loadHasPermission();\n if (hasPermission) {\n const userPermissions = requestContext.get('mastra__userPermissions') as string[] | undefined;\n const permissionError = this.checkRoutePermission(route, userPermissions, hasPermission, requestContext);\n\n if (permissionError) {\n return c.json(\n {\n error: permissionError.error,\n message: permissionError.message,\n },\n permissionError.status as any,\n );\n }\n }\n }\n\n // Check FGA authorization (EE feature)\n const fgaError = await checkRouteFGA(this.mastra, route, c.get('requestContext'), {\n ...params.urlParams,\n ...params.queryParams,\n ...(typeof params.body === 'object' ? params.body : {}),\n });\n if (fgaError) {\n return c.json({ error: fgaError.error, message: fgaError.message }, fgaError.status as any);\n }\n\n try {\n const result = await route.handler(handlerParams);\n return this.sendResponse(route, c, result, prefix);\n } catch (error) {\n // 4xx errors are client conditions (e.g. no session, expired token) and are\n // already returned as structured HTTP responses below. Logging them as errors\n // produces noise for callers — skip the logger call for those cases.\n const httpStatus =\n error && typeof error === 'object' && 'status' in error ? (error as any).status : undefined;\n const isClientError = typeof httpStatus === 'number' && httpStatus >= 400 && httpStatus < 500;\n if (!isClientError) {\n this.mastra.getLogger()?.error('Error calling handler', {\n error: error instanceof Error ? { message: error.message, stack: error.stack } : error,\n path: route.path,\n method: route.method,\n });\n }\n const customResponse = getCustomHTTPExceptionResponse(error);\n if (customResponse) {\n return customResponse;\n }\n\n // Check if it's an HTTPException or MastraError with a status code\n if (error && typeof error === 'object') {\n // Check for direct status property (HTTPException)\n if ('status' in error) {\n const status = (error as any).status;\n let safeCause: { failingItems: unknown[] } | undefined;\n try {\n const raw = error instanceof Error ? error.cause : undefined;\n if (\n raw &&\n typeof raw === 'object' &&\n !Array.isArray(raw) &&\n 'failingItems' in raw &&\n Array.isArray((raw as any).failingItems)\n ) {\n safeCause = { failingItems: (raw as any).failingItems };\n }\n } catch {\n // serialization or access error — omit cause\n }\n return c.json(\n {\n error: error instanceof Error ? error.message : 'Unknown error',\n ...(safeCause ? { cause: safeCause } : {}),\n },\n status,\n );\n }\n // Check for MastraError with status in details\n if ('details' in error && error.details && typeof error.details === 'object' && 'status' in error.details) {\n const status = (error.details as any).status;\n return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, status);\n }\n }\n return c.json({ error: error instanceof Error ? error.message : 'Unknown error' }, 500);\n }\n },\n );\n }\n\n async registerCustomApiRoutes(): Promise<void> {\n const routes = await this.registerSchemaApiRoutes();\n if (!(await this.buildCustomRouteHandler(routes))) return;\n\n for (const route of routes) {\n const serverRoute: ServerRoute = {\n method: route.method as any,\n path: route.path,\n responseType: 'json',\n handler: async () => {},\n requiresAuth: route.requiresAuth,\n requiresPermission: route.requiresPermission,\n fga: route.fga,\n };\n\n const routeHandler: MiddlewareHandler = async (c: Context) => {\n // Per-route auth check (same pattern as registerRoute)\n const authError = await this.checkRouteAuth(serverRoute, {\n path: c.req.path,\n method: c.req.method,\n getHeader: name => c.req.header(name),\n getQuery: name => c.req.query(name),\n requestContext: c.get('requestContext'),\n request: c.req.raw,\n buildAuthorizeContext: () => c,\n });\n\n if (authError) {\n if (authError.headers) {\n for (const [key, value] of Object.entries(authError.headers)) {\n c.header(key, value as string);\n }\n }\n if (authError.error) {\n return c.json({ error: authError.error }, authError.status as any);\n }\n }\n\n const requestContext = c.get('requestContext');\n // Check if any auth is configured (studio or server) for RBAC\n const hasAuth = this.mastra.getStudio?.()?.auth || this.mastra.getServer()?.auth;\n if (hasAuth) {\n const hasPermission = await loadHasPermission();\n if (hasPermission) {\n const userPermissions = requestContext.get('mastra__userPermissions') as string[] | undefined;\n const permissionError = this.checkRoutePermission(\n serverRoute,\n userPermissions,\n hasPermission,\n requestContext,\n );\n if (permissionError) {\n return c.json(\n { error: permissionError.error, message: permissionError.message },\n permissionError.status as any,\n );\n }\n }\n }\n\n // Use the pristine clone captured by the context middleware (before\n // user middleware ran) so body reads survive middleware that already\n // consumed `c.req.raw`.\n const pristineRequest = (c.get(MASTRA_PRISTINE_REQUEST_KEY) as Request | undefined) ?? c.req.raw;\n\n // Check FGA authorization (EE feature)\n let bodyParams: Record<string, unknown> = {};\n const contentType = c.req.header('content-type');\n if (contentType?.includes('application/json')) {\n try {\n const body = (await pristineRequest.clone().json()) as unknown;\n if (body && typeof body === 'object' && !Array.isArray(body)) {\n bodyParams = body as Record<string, unknown>;\n }\n } catch {\n bodyParams = {};\n }\n } else if (\n contentType?.includes('application/x-www-form-urlencoded') ||\n contentType?.includes('multipart/form-data')\n ) {\n try {\n bodyParams = Object.fromEntries(await pristineRequest.clone().formData());\n } catch {\n bodyParams = {};\n }\n }\n const fgaError = await checkRouteFGA(this.mastra, serverRoute, c.get('requestContext'), {\n ...c.req.param(),\n ...Object.fromEntries(new URL(c.req.url).searchParams.entries()),\n ...bodyParams,\n });\n if (fgaError) {\n return c.json({ error: fgaError.error, message: fgaError.message }, fgaError.status as any);\n }\n\n const reqHeaders: Record<string, string | string[] | undefined> = {};\n c.req.raw.headers.forEach((v, k) => {\n reqHeaders[k] = v;\n });\n // Forward the platform execution context (e.g. Cloudflare Workers'\n // `waitUntil`) so custom route handlers can keep background work alive\n // after the response. Hono's `executionCtx` getter throws when no\n // ExecutionContext exists (e.g. Node), so guard the access.\n let executionCtx: ExecutionContext | undefined;\n try {\n executionCtx = c.executionCtx;\n } catch {\n executionCtx = undefined;\n }\n const response = await this.handleCustomRouteRequest(\n c.req.url,\n c.req.method,\n reqHeaders,\n pristineRequest.body,\n c.get('requestContext'),\n c.req.raw.signal,\n executionCtx,\n );\n if (!response) {\n return c.json({ error: 'Not Found' }, 404);\n }\n return response;\n };\n\n const method = route.method.toLowerCase() as 'get' | 'post' | 'put' | 'delete' | 'patch' | 'all';\n this.app[method](route.path, routeHandler);\n }\n }\n\n registerContextMiddleware(): void {\n // Precompute the framework-public matcher once at registration time.\n // Called per-request below; used by adapters (see `skipIfFrameworkPublic`)\n // to short-circuit user-registered middleware for framework-public routes\n // so users cannot 401 routes declared public via `requiresAuth: false`.\n const isFrameworkPublic = this.getFrameworkPublicMatcher();\n\n this.app.use('*', this.createContextMiddleware());\n this.app.use('*', async (c, next) => {\n c.set(MASTRA_FRAMEWORK_PUBLIC_KEY, isFrameworkPublic(c.req.path, c.req.method));\n return next();\n });\n this.app.use('*', async (c, next) => {\n await next();\n this.warnIfUnregisteredChannelWebhook(c.req.path, c.req.method, c.res.status);\n });\n }\n\n registerAuthMiddleware(): void {\n // Auth is handled per-route in registerRoute() and registerCustomApiRoutes()\n // No global middleware needed\n }\n\n registerUserMiddleware(): void {\n // Middleware added at runtime via `mastra.setServerMiddleware()` — already\n // normalized to `{ path, handler }` entries by core.\n for (const m of this.mastra.getServerMiddleware?.() ?? []) {\n this.app.use(m.path, skipIfFrameworkPublic(m.handler));\n }\n\n const configMiddleware = this.mastra.getServer()?.middleware;\n if (!configMiddleware) {\n return;\n }\n\n const normalizedMiddlewares = Array.isArray(configMiddleware) ? configMiddleware : [configMiddleware];\n for (const middleware of normalizedMiddlewares) {\n const { path, handler } = typeof middleware === 'function' ? { path: '*', handler: middleware } : middleware;\n // Wrap with skipIfFrameworkPublic so user middleware cannot 401 routes\n // the framework declared public via `requiresAuth: false`\n // (e.g. Studio sign-in endpoints like /api/auth/capabilities).\n this.app.use(path, skipIfFrameworkPublic(handler as unknown as MiddlewareHandler));\n }\n }\n\n registerHttpLoggingMiddleware(): void {\n if (!this.httpLoggingConfig?.enabled) {\n return;\n }\n\n this.app.use('*', async (c, next) => {\n if (!this.shouldLogRequest(c.req.path)) {\n return next();\n }\n\n const start = Date.now();\n const method = c.req.method;\n const path = c.req.path;\n\n await next();\n\n const duration = Date.now() - start;\n const status = c.res.status;\n const level = this.httpLoggingConfig?.level || 'info';\n\n const logData: Record<string, any> = {\n method,\n path,\n status,\n duration: `${duration}ms`,\n };\n\n if (this.httpLoggingConfig?.includeQueryParams) {\n logData.query = c.req.query();\n }\n\n if (this.httpLoggingConfig?.includeHeaders) {\n const headers = Object.fromEntries(c.req.raw.headers.entries());\n const redactHeaders = this.httpLoggingConfig.redactHeaders || [];\n redactHeaders.forEach(h => {\n const key = h.toLowerCase();\n if (headers[key] !== undefined) {\n headers[key] = '[REDACTED]';\n }\n });\n logData.headers = headers;\n }\n\n this.logger[level](`${method} ${path} ${status} ${duration}ms`, logData);\n });\n }\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/hono",
|
|
3
|
-
"version": "1.7.10-alpha.
|
|
3
|
+
"version": "1.7.10-alpha.6",
|
|
4
4
|
"description": "Mastra Hono adapter for the server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@hono/node-ws": "^1.3.0",
|
|
24
24
|
"fetch-to-node": "^2.1.0",
|
|
25
|
-
"ws": "^8.21.
|
|
26
|
-
"@mastra/server": "1.68.0-alpha.
|
|
25
|
+
"ws": "^8.21.3",
|
|
26
|
+
"@mastra/server": "1.68.0-alpha.6"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
29
|
"@ai-sdk/openai": "^2.0.115",
|
|
@@ -32,23 +32,23 @@
|
|
|
32
32
|
"@types/node": "22.20.1",
|
|
33
33
|
"@types/ws": "^8.18.1",
|
|
34
34
|
"eslint": "^10.7.0",
|
|
35
|
-
"hono": "^4.
|
|
35
|
+
"hono": "^4.13.7",
|
|
36
36
|
"tsdown": "0.22.9",
|
|
37
37
|
"typescript": "^7.0.2",
|
|
38
|
-
"vitest": "4.1.
|
|
39
|
-
"zod": "^4.4
|
|
40
|
-
"@internal/server-adapter-test-utils": "0.0.29",
|
|
41
|
-
"@internal/storage-test-utils": "0.0.129",
|
|
42
|
-
"@internal/types-builder": "0.0.108",
|
|
43
|
-
"@mastra/libsql": "1.23.0",
|
|
38
|
+
"vitest": "4.1.11",
|
|
39
|
+
"zod": "^4.6.4",
|
|
44
40
|
"@internal/lint": "0.0.133",
|
|
45
|
-
"@
|
|
46
|
-
"@mastra/
|
|
47
|
-
"@
|
|
41
|
+
"@internal/types-builder": "0.0.108",
|
|
42
|
+
"@mastra/server-adapters-test-suite": "0.1.0-alpha.0",
|
|
43
|
+
"@internal/storage-test-utils": "0.0.129",
|
|
44
|
+
"@mastra/observability": "1.17.9-alpha.1",
|
|
45
|
+
"@mastra/libsql": "1.23.1-alpha.1",
|
|
46
|
+
"@mastra/core": "1.68.0-alpha.6",
|
|
47
|
+
"@mastra/memory": "1.31.0-alpha.3"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"@mastra/core": ">=1.50.0-0 <2.0.0-0",
|
|
51
|
-
"hono": "^4.
|
|
51
|
+
"hono": "^4.13.5"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=22.13.0"
|