r19
Version:
Simple remote procedure calls in TypeScript
121 lines (120 loc) • 3.62 kB
JavaScript
import { Buffer } from "node:buffer";
import { decode, encode } from "@msgpack/msgpack";
import { isErrorLike } from "./lib/isErrorLike.js";
import { isR19ErrorLike } from "./lib/isR19ErrorLike.js";
import { replaceLeaves } from "./lib/replaceLeaves.js";
import { R19Error } from "./R19Error.js";
const findProcedure = (procedures, path) => {
path = [...path];
let proceduresPointer = procedures;
while (path.length > 0) {
const pathSegment = path.shift();
if (pathSegment) {
proceduresPointer = proceduresPointer[pathSegment];
if (typeof proceduresPointer === "function") {
return proceduresPointer;
} else if (proceduresPointer === void 0) {
return;
}
}
}
};
const handleRPCRequest = async (args) => {
var _a, _b, _c;
if (!args.body) {
throw new Error("Invalid request body. Only requests from an r19 client are accepted.");
}
const clientArgs = decode(Buffer.from(args.body));
const procedure = findProcedure(args.procedures, clientArgs.procedurePath);
const headers = {
"Content-Type": "application/msgpack"
};
if (!procedure) {
const error = new R19Error(`Invalid procedure name: ${clientArgs.procedurePath.join(".")}`, {
procedurePath: clientArgs.procedurePath,
procedureArgs: clientArgs.procedureArgs
});
const body = encode({
error
}, { ignoreUndefined: true });
(_a = args.onError) == null ? void 0 : _a.call(args, { error, ...clientArgs });
return {
body,
headers,
statusCode: 500
};
}
let res;
try {
const procedureArgs = await replaceLeaves(clientArgs.procedureArgs, async (value) => {
if (value instanceof ArrayBuffer) {
return Buffer.from(value);
}
return value;
});
res = await procedure(...procedureArgs);
res = await replaceLeaves(res, async (value) => {
if (isErrorLike(value)) {
return {
name: value.name,
message: value.message,
stack: process.env.NODE_ENV === "development" ? value.stack : void 0
};
}
if (typeof value === "function") {
throw new R19Error("r19 does not support function return values.", {
procedurePath: clientArgs.procedurePath,
procedureArgs: clientArgs.procedureArgs
});
}
return value;
});
} catch (error) {
if (isErrorLike(error)) {
const body = encode({
error: isR19ErrorLike(error) ? error : {
name: error.name,
message: error.message,
stack: process.env.NODE_ENV === "development" ? error.stack : void 0
}
}, { ignoreUndefined: true });
(_b = args.onError) == null ? void 0 : _b.call(args, { error, ...clientArgs });
return {
body,
headers,
statusCode: 500
};
}
throw error;
}
try {
const body = encode({
data: res
}, { ignoreUndefined: true });
return {
body,
headers
};
} catch (error) {
if (error instanceof Error) {
const rpcError = new R19Error("Unable to serialize server response. Check the server log for details.", {
procedurePath: clientArgs.procedurePath,
procedureArgs: clientArgs.procedureArgs,
cause: error
});
console.error(rpcError);
const body = encode(rpcError);
(_c = args.onError) == null ? void 0 : _c.call(args, { error, ...clientArgs });
return {
body,
headers,
statusCode: 500
};
}
throw error;
}
};
export {
handleRPCRequest
};
//# sourceMappingURL=handleRPCRequest.js.map