{"version":3,"file":"jsonrpc.cjs","names":[],"sources":["../src/jsonrpc.ts"],"sourcesContent":["import type * as http from \"node:http\";\n\nexport type JsonRpcResponse = {\n  jsonrpc: \"2.0\";\n  id: string | number | null;\n  result?: unknown;\n  error?: { code: number; message: string; data?: unknown };\n};\n\nexport type MethodHandler = (\n  params: unknown,\n  id: string | number,\n  req: http.IncomingMessage,\n) => Promise<JsonRpcResponse | null>;\n\nexport interface JsonRpcDispatcherOptions {\n  methods: Record<string, MethodHandler>;\n  onNotification?: (method: string, params: unknown) => void;\n}\n\nfunction errorResponse(\n  code: number,\n  message: string,\n  id: string | number | null = null,\n): JsonRpcResponse {\n  return { jsonrpc: \"2.0\", id, error: { code, message } };\n}\n\nfunction isObject(val: unknown): val is Record<string, unknown> {\n  return typeof val === \"object\" && val !== null && !Array.isArray(val);\n}\n\nasync function processOne(\n  entry: unknown,\n  methods: Record<string, MethodHandler>,\n  onNotification: ((method: string, params: unknown) => void) | undefined,\n  req: http.IncomingMessage,\n): Promise<JsonRpcResponse | null> {\n  if (!isObject(entry)) {\n    return errorResponse(-32600, \"Invalid request\");\n  }\n\n  const { jsonrpc, method, params, id } = entry;\n\n  if (jsonrpc !== \"2.0\" || typeof method !== \"string\") {\n    const reqId = typeof id === \"string\" || typeof id === \"number\" ? id : null;\n    return errorResponse(-32600, \"Invalid request\", reqId);\n  }\n\n  // Notification: id is absent/undefined\n  const isNotification = !(\"id\" in entry) || id === undefined;\n\n  if (isNotification) {\n    if (onNotification) {\n      onNotification(method, params);\n    }\n    // Invoke the method handler for side effects (e.g., MCP notifications/initialized),\n    // but discard the result — notifications MUST NOT produce responses per JSON-RPC 2.0.\n    const handler = methods[method];\n    if (handler) {\n      try {\n        await handler(params, null as unknown as string | number, req);\n      } catch (err: unknown) {\n        console.warn(\"Notification handler error:\", err);\n      }\n    }\n    return null;\n  }\n\n  const reqId = typeof id === \"string\" || typeof id === \"number\" ? id : null;\n\n  const handler = methods[method];\n  if (!handler) {\n    return errorResponse(-32601, \"Method not found\", reqId);\n  }\n\n  try {\n    const result = await handler(params, reqId as string | number, req);\n    if (result) return result;\n    return { jsonrpc: \"2.0\", id: reqId, result: null };\n  } catch (err: unknown) {\n    const msg = err instanceof Error ? err.message : String(err);\n    return errorResponse(-32603, `Internal error: ${msg}`, reqId);\n  }\n}\n\nexport function createJsonRpcDispatcher(\n  options: JsonRpcDispatcherOptions,\n): (req: http.IncomingMessage, res: http.ServerResponse, body: string) => Promise<void> {\n  const { methods, onNotification } = options;\n\n  return async (\n    req: http.IncomingMessage,\n    res: http.ServerResponse,\n    body: string,\n  ): Promise<void> => {\n    let parsed: unknown;\n    try {\n      parsed = JSON.parse(body);\n    } catch {\n      const resp = errorResponse(-32700, \"Parse error\");\n      res.writeHead(200, { \"Content-Type\": \"application/json\" });\n      res.end(JSON.stringify(resp));\n      return;\n    }\n\n    // Empty batch\n    if (Array.isArray(parsed) && parsed.length === 0) {\n      const resp = errorResponse(-32600, \"Invalid request\");\n      res.writeHead(200, { \"Content-Type\": \"application/json\" });\n      res.end(JSON.stringify(resp));\n      return;\n    }\n\n    // Batch mode\n    if (Array.isArray(parsed)) {\n      const responses: JsonRpcResponse[] = [];\n      for (const entry of parsed) {\n        const result = await processOne(entry, methods, onNotification, req);\n        if (result !== null) {\n          responses.push(result);\n        }\n      }\n      if (responses.length === 0) {\n        res.writeHead(202);\n        res.end(\"\");\n        return;\n      }\n      res.writeHead(200, { \"Content-Type\": \"application/json\" });\n      res.end(JSON.stringify(responses));\n      return;\n    }\n\n    // Single request\n    const result = await processOne(parsed, methods, onNotification, req);\n    if (result === null) {\n      res.writeHead(202);\n      res.end(\"\");\n      return;\n    }\n    res.writeHead(200, { \"Content-Type\": \"application/json\" });\n    res.end(JSON.stringify(result));\n  };\n}\n"],"mappings":";;AAoBA,SAAS,cACP,MACA,SACA,KAA6B,MACZ;AACjB,QAAO;EAAE,SAAS;EAAO;EAAI,OAAO;GAAE;GAAM;GAAS;EAAE;;AAGzD,SAAS,SAAS,KAA8C;AAC9D,QAAO,OAAO,QAAQ,YAAY,QAAQ,QAAQ,CAAC,MAAM,QAAQ,IAAI;;AAGvE,eAAe,WACb,OACA,SACA,gBACA,KACiC;AACjC,KAAI,CAAC,SAAS,MAAM,CAClB,QAAO,cAAc,QAAQ,kBAAkB;CAGjD,MAAM,EAAE,SAAS,QAAQ,QAAQ,OAAO;AAExC,KAAI,YAAY,SAAS,OAAO,WAAW,SAEzC,QAAO,cAAc,QAAQ,mBADf,OAAO,OAAO,YAAY,OAAO,OAAO,WAAW,KAAK,KAChB;AAMxD,KAFuB,EAAE,QAAQ,UAAU,OAAO,QAE9B;AAClB,MAAI,eACF,gBAAe,QAAQ,OAAO;EAIhC,MAAM,UAAU,QAAQ;AACxB,MAAI,QACF,KAAI;AACF,SAAM,QAAQ,QAAQ,MAAoC,IAAI;WACvD,KAAc;AACrB,WAAQ,KAAK,+BAA+B,IAAI;;AAGpD,SAAO;;CAGT,MAAM,QAAQ,OAAO,OAAO,YAAY,OAAO,OAAO,WAAW,KAAK;CAEtE,MAAM,UAAU,QAAQ;AACxB,KAAI,CAAC,QACH,QAAO,cAAc,QAAQ,oBAAoB,MAAM;AAGzD,KAAI;EACF,MAAM,SAAS,MAAM,QAAQ,QAAQ,OAA0B,IAAI;AACnE,MAAI,OAAQ,QAAO;AACnB,SAAO;GAAE,SAAS;GAAO,IAAI;GAAO,QAAQ;GAAM;UAC3C,KAAc;AAErB,SAAO,cAAc,QAAQ,mBADjB,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI,IACL,MAAM;;;AAIjE,SAAgB,wBACd,SACsF;CACtF,MAAM,EAAE,SAAS,mBAAmB;AAEpC,QAAO,OACL,KACA,KACA,SACkB;EAClB,IAAI;AACJ,MAAI;AACF,YAAS,KAAK,MAAM,KAAK;UACnB;GACN,MAAM,OAAO,cAAc,QAAQ,cAAc;AACjD,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,KAAK,CAAC;AAC7B;;AAIF,MAAI,MAAM,QAAQ,OAAO,IAAI,OAAO,WAAW,GAAG;GAChD,MAAM,OAAO,cAAc,QAAQ,kBAAkB;AACrD,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,KAAK,CAAC;AAC7B;;AAIF,MAAI,MAAM,QAAQ,OAAO,EAAE;GACzB,MAAM,YAA+B,EAAE;AACvC,QAAK,MAAM,SAAS,QAAQ;IAC1B,MAAM,SAAS,MAAM,WAAW,OAAO,SAAS,gBAAgB,IAAI;AACpE,QAAI,WAAW,KACb,WAAU,KAAK,OAAO;;AAG1B,OAAI,UAAU,WAAW,GAAG;AAC1B,QAAI,UAAU,IAAI;AAClB,QAAI,IAAI,GAAG;AACX;;AAEF,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,UAAU,CAAC;AAClC;;EAIF,MAAM,SAAS,MAAM,WAAW,QAAQ,SAAS,gBAAgB,IAAI;AACrE,MAAI,WAAW,MAAM;AACnB,OAAI,UAAU,IAAI;AAClB,OAAI,IAAI,GAAG;AACX;;AAEF,MAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,MAAI,IAAI,KAAK,UAAU,OAAO,CAAC"}