{"version":3,"file":"handleRPCRequest.cjs","sources":["../../src/handleRPCRequest.ts"],"sourcesContent":["import { Buffer } from \"node:buffer\";\nimport { decode, encode } from \"@msgpack/msgpack\";\n\nimport { isErrorLike } from \"./lib/isErrorLike\";\nimport { isR19ErrorLike } from \"./lib/isR19ErrorLike\";\nimport { replaceLeaves } from \"./lib/replaceLeaves\";\n\nimport {\n\tProcedure,\n\tProcedures,\n\tProcedureCallServerArgs,\n\tOnErrorEventHandler,\n} from \"./types\";\nimport { R19Error } from \"./R19Error\";\n\nconst findProcedure = (\n\tprocedures: Procedures,\n\tpath: string[],\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Procedure<any> | undefined => {\n\t// Use a clone to prevent unwanted mutations.\n\tpath = [...path];\n\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tlet proceduresPointer: Procedures | Procedure<any> = procedures;\n\n\twhile (path.length > 0) {\n\t\tconst pathSegment = path.shift();\n\n\t\tif (pathSegment) {\n\t\t\tproceduresPointer = proceduresPointer[pathSegment];\n\n\t\t\tif (typeof proceduresPointer === \"function\") {\n\t\t\t\treturn proceduresPointer;\n\t\t\t} else if (proceduresPointer === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n};\n\ntype HandleRPCRequestArgs<TProcedures extends Procedures> = {\n\tprocedures: TProcedures;\n\tbody: ArrayBuffer | Buffer | undefined;\n\tonError?: OnErrorEventHandler;\n};\n\ntype HandleRPCRequestReturnType = {\n\tbody: Uint8Array;\n\theaders: Record<string, string>;\n\tstatusCode?: number;\n};\n\nexport const handleRPCRequest = async <TProcedures extends Procedures>(\n\targs: HandleRPCRequestArgs<TProcedures>,\n): Promise<HandleRPCRequestReturnType> => {\n\tif (!args.body) {\n\t\tthrow new Error(\n\t\t\t\"Invalid request body. Only requests from an r19 client are accepted.\",\n\t\t);\n\t}\n\n\tconst clientArgs = decode(Buffer.from(args.body)) as ProcedureCallServerArgs;\n\n\tconst procedure = findProcedure(args.procedures, clientArgs.procedurePath);\n\tconst headers = {\n\t\t\"Content-Type\": \"application/msgpack\",\n\t};\n\n\tif (!procedure) {\n\t\tconst error = new R19Error(\n\t\t\t`Invalid procedure name: ${clientArgs.procedurePath.join(\".\")}`,\n\t\t\t{\n\t\t\t\tprocedurePath: clientArgs.procedurePath,\n\t\t\t\tprocedureArgs: clientArgs.procedureArgs,\n\t\t\t},\n\t\t);\n\n\t\tconst body = encode(\n\t\t\t{\n\t\t\t\terror,\n\t\t\t},\n\t\t\t{ ignoreUndefined: true },\n\t\t);\n\n\t\targs.onError?.({ error, ...clientArgs });\n\n\t\treturn {\n\t\t\tbody,\n\t\t\theaders,\n\t\t\tstatusCode: 500,\n\t\t};\n\t}\n\n\tlet res: unknown;\n\n\ttry {\n\t\tconst procedureArgs = await replaceLeaves(\n\t\t\tclientArgs.procedureArgs,\n\t\t\tasync (value) => {\n\t\t\t\tif (value instanceof ArrayBuffer) {\n\t\t\t\t\treturn Buffer.from(value);\n\t\t\t\t}\n\n\t\t\t\treturn value;\n\t\t\t},\n\t\t);\n\n\t\tres = await procedure(...procedureArgs);\n\n\t\tres = await replaceLeaves(res, async (value) => {\n\t\t\tif (isErrorLike(value)) {\n\t\t\t\treturn {\n\t\t\t\t\tname: value.name,\n\t\t\t\t\tmessage: value.message,\n\t\t\t\t\tstack:\n\t\t\t\t\t\tprocess.env.NODE_ENV === \"development\" ? value.stack : undefined,\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tif (typeof value === \"function\") {\n\t\t\t\tthrow new R19Error(\"r19 does not support function return values.\", {\n\t\t\t\t\tprocedurePath: clientArgs.procedurePath,\n\t\t\t\t\tprocedureArgs: clientArgs.procedureArgs,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn value;\n\t\t});\n\t} catch (error) {\n\t\tif (isErrorLike(error)) {\n\t\t\tconst body = encode(\n\t\t\t\t{\n\t\t\t\t\terror: isR19ErrorLike(error)\n\t\t\t\t\t\t? error\n\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\tname: error.name,\n\t\t\t\t\t\t\t\tmessage: error.message,\n\t\t\t\t\t\t\t\tstack:\n\t\t\t\t\t\t\t\t\tprocess.env.NODE_ENV === \"development\"\n\t\t\t\t\t\t\t\t\t\t? error.stack\n\t\t\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t{ ignoreUndefined: true },\n\t\t\t);\n\n\t\t\targs.onError?.({ error, ...clientArgs });\n\n\t\t\treturn {\n\t\t\t\tbody,\n\t\t\t\theaders,\n\t\t\t\tstatusCode: 500,\n\t\t\t};\n\t\t}\n\n\t\tthrow error;\n\t}\n\n\ttry {\n\t\tconst body = encode(\n\t\t\t{\n\t\t\t\tdata: res,\n\t\t\t},\n\t\t\t{ ignoreUndefined: true },\n\t\t);\n\n\t\treturn {\n\t\t\tbody,\n\t\t\theaders,\n\t\t};\n\t} catch (error) {\n\t\tif (error instanceof Error) {\n\t\t\tconst rpcError = new R19Error(\n\t\t\t\t\"Unable to serialize server response. Check the server log for details.\",\n\t\t\t\t{\n\t\t\t\t\tprocedurePath: clientArgs.procedurePath,\n\t\t\t\t\tprocedureArgs: clientArgs.procedureArgs,\n\t\t\t\t\tcause: error,\n\t\t\t\t},\n\t\t\t);\n\n\t\t\tconsole.error(rpcError);\n\n\t\t\tconst body = encode(rpcError);\n\n\t\t\targs.onError?.({ error, ...clientArgs });\n\n\t\t\treturn {\n\t\t\t\tbody,\n\t\t\t\theaders,\n\t\t\t\tstatusCode: 500,\n\t\t\t};\n\t\t}\n\n\t\tthrow error;\n\t}\n};\n"],"names":["decode","Buffer","R19Error","encode","replaceLeaves","isErrorLike","isR19ErrorLike"],"mappings":";;;;;;;;AAeA,MAAM,gBAAgB,CACrB,YACA,SAE+B;AAExB,SAAA,CAAC,GAAG,IAAI;AAGf,MAAI,oBAAiD;AAE9C,SAAA,KAAK,SAAS,GAAG;AACjB,UAAA,cAAc,KAAK;AAEzB,QAAI,aAAa;AAChB,0BAAoB,kBAAkB,WAAW;AAE7C,UAAA,OAAO,sBAAsB,YAAY;AACrC,eAAA;AAAA,MAAA,WACG,sBAAsB,QAAW;AAC3C;AAAA,MACA;AAAA,IACD;AAAA,EACD;AACF;AAca,MAAA,mBAAmB,OAC/B,SACwC;;AACpC,MAAA,CAAC,KAAK,MAAM;AACT,UAAA,IAAI,MACT,sEAAsE;AAAA,EAEvE;AAED,QAAM,aAAaA,QAAAA,OAAOC,YAAA,OAAO,KAAK,KAAK,IAAI,CAAC;AAEhD,QAAM,YAAY,cAAc,KAAK,YAAY,WAAW,aAAa;AACzE,QAAM,UAAU;AAAA,IACf,gBAAgB;AAAA,EAAA;AAGjB,MAAI,CAAC,WAAW;AACT,UAAA,QAAQ,IAAIC,SACjB,SAAA,2BAA2B,WAAW,cAAc,KAAK,GAAG,CAAC,IAC7D;AAAA,MACC,eAAe,WAAW;AAAA,MAC1B,eAAe,WAAW;AAAA,IAAA,CAC1B;AAGF,UAAM,OAAOC,QAAAA,OACZ;AAAA,MACC;AAAA,IAAA,GAED,EAAE,iBAAiB,KAAA,CAAM;AAG1B,eAAK,YAAL,8BAAe,EAAE,OAAO,GAAG,WAAY;AAEhC,WAAA;AAAA,MACN;AAAA,MACA;AAAA,MACA,YAAY;AAAA,IAAA;AAAA,EAEb;AAEG,MAAA;AAEA,MAAA;AACH,UAAM,gBAAgB,MAAMC,cAAA,cAC3B,WAAW,eACX,OAAO,UAAS;AACf,UAAI,iBAAiB,aAAa;AAC1B,eAAAH,YAAA,OAAO,KAAK,KAAK;AAAA,MACxB;AAEM,aAAA;AAAA,IAAA,CACP;AAGI,UAAA,MAAM,UAAU,GAAG,aAAa;AAEtC,UAAM,MAAMG,cAAAA,cAAc,KAAK,OAAO,UAAS;AAC1C,UAAAC,YAAAA,YAAY,KAAK,GAAG;AAChB,eAAA;AAAA,UACN,MAAM,MAAM;AAAA,UACZ,SAAS,MAAM;AAAA,UACf,OACC,QAAQ,IAAI,aAAa,gBAAgB,MAAM,QAAQ;AAAA,QAAA;AAAA,MAEzD;AAEG,UAAA,OAAO,UAAU,YAAY;AAC1B,cAAA,IAAIH,kBAAS,gDAAgD;AAAA,UAClE,eAAe,WAAW;AAAA,UAC1B,eAAe,WAAW;AAAA,QAAA,CAC1B;AAAA,MACD;AAEM,aAAA;AAAA,IAAA,CACP;AAAA,WACO,OAAO;AACX,QAAAG,YAAAA,YAAY,KAAK,GAAG;AACvB,YAAM,OAAOF,QAAAA,OACZ;AAAA,QACC,OAAOG,eAAA,eAAe,KAAK,IACxB,QACA;AAAA,UACA,MAAM,MAAM;AAAA,UACZ,SAAS,MAAM;AAAA,UACf,OACC,QAAQ,IAAI,aAAa,gBACtB,MAAM,QACN;AAAA,QACJ;AAAA,MAAA,GAEJ,EAAE,iBAAiB,KAAA,CAAM;AAG1B,iBAAK,YAAL,8BAAe,EAAE,OAAO,GAAG,WAAY;AAEhC,aAAA;AAAA,QACN;AAAA,QACA;AAAA,QACA,YAAY;AAAA,MAAA;AAAA,IAEb;AAEK,UAAA;AAAA,EACN;AAEG,MAAA;AACH,UAAM,OAAOH,QAAAA,OACZ;AAAA,MACC,MAAM;AAAA,IAAA,GAEP,EAAE,iBAAiB,KAAA,CAAM;AAGnB,WAAA;AAAA,MACN;AAAA,MACA;AAAA,IAAA;AAAA,WAEO,OAAO;AACf,QAAI,iBAAiB,OAAO;AACrB,YAAA,WAAW,IAAID,SAAA,SACpB,0EACA;AAAA,QACC,eAAe,WAAW;AAAA,QAC1B,eAAe,WAAW;AAAA,QAC1B,OAAO;AAAA,MAAA,CACP;AAGF,cAAQ,MAAM,QAAQ;AAEhB,YAAA,OAAOC,eAAO,QAAQ;AAE5B,iBAAK,YAAL,8BAAe,EAAE,OAAO,GAAG,WAAY;AAEhC,aAAA;AAAA,QACN;AAAA,QACA;AAAA,QACA,YAAY;AAAA,MAAA;AAAA,IAEb;AAEK,UAAA;AAAA,EACN;AACF;;"}