nice-grpc-web
Version:
A Browser gRPC library that is nice to you
114 lines • 4.67 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeCall = makeCall;
const abort_controller_x_1 = require("abort-controller-x");
const nice_grpc_common_1 = require("nice-grpc-common");
const decodeResponse_1 = require("./decodeResponse");
const encodeRequest_1 = require("./encodeRequest");
const makeInternalErrorMessage_1 = require("./makeInternalErrorMessage");
const parseTrailer_1 = require("./parseTrailer");
/** @internal */
async function* makeCall(definition, channel, request, options) {
const { metadata, signal = new AbortController().signal, onHeader, onTrailer, } = options;
let receivedTrailersOnly = false;
let status;
let message;
function handleTrailer(trailer) {
if (receivedTrailersOnly) {
if (new Map(trailer).size > 0) {
throw new nice_grpc_common_1.ClientError(definition.path, nice_grpc_common_1.Status.INTERNAL, 'Received non-empty trailer after trailers-only response');
}
else {
return;
}
}
const parsedTrailer = (0, parseTrailer_1.parseTrailer)(trailer);
({ status, message } = parsedTrailer);
onTrailer === null || onTrailer === void 0 ? void 0 : onTrailer(parsedTrailer.trailer);
}
const finalMetadata = (0, nice_grpc_common_1.Metadata)(metadata);
finalMetadata.set('content-type', 'application/grpc-web+proto');
finalMetadata.set('x-grpc-web', '1');
const innerAbortController = new AbortController();
const abortListener = () => {
innerAbortController.abort();
};
signal.addEventListener('abort', abortListener);
let finished = false;
let requestError;
async function* interceptRequestError() {
try {
for await (const item of request) {
if (finished) {
throw new Error('Request finished');
}
yield item;
}
}
catch (err) {
requestError = { err };
innerAbortController.abort();
throw err;
}
}
async function* handleTransportErrors() {
try {
return yield* channel.transport({
url: channel.address + definition.path,
metadata: finalMetadata,
body: (0, encodeRequest_1.encodeRequest)({
request: interceptRequestError(),
encode: definition.requestSerialize,
}),
signal: innerAbortController.signal,
method: definition,
});
}
catch (err) {
(0, abort_controller_x_1.rethrowAbortError)(err);
throw new nice_grpc_common_1.ClientError(definition.path, nice_grpc_common_1.Status.UNKNOWN, `Transport error: ${(0, makeInternalErrorMessage_1.makeInternalErrorMessage)(err)}`);
}
}
const response = (0, decodeResponse_1.decodeResponse)({
response: handleTransportErrors(),
decode: definition.responseDeserialize,
onHeader(header) {
const isTrailersOnly = header.has('grpc-status');
if (isTrailersOnly) {
handleTrailer(header);
receivedTrailersOnly = true;
}
else {
onHeader === null || onHeader === void 0 ? void 0 : onHeader(header);
}
},
onTrailer(trailer) {
handleTrailer(trailer);
},
});
try {
yield* response;
}
catch (err) {
if (requestError !== undefined) {
throw requestError.err;
}
else if (err instanceof nice_grpc_common_1.ClientError || (0, abort_controller_x_1.isAbortError)(err)) {
throw err;
}
else {
throw new nice_grpc_common_1.ClientError(definition.path, nice_grpc_common_1.Status.INTERNAL, (0, makeInternalErrorMessage_1.makeInternalErrorMessage)(err));
}
}
finally {
finished = true;
signal.removeEventListener('abort', abortListener);
if (status != null && status !== nice_grpc_common_1.Status.OK) {
throw new nice_grpc_common_1.ClientError(definition.path, status, message !== null && message !== void 0 ? message : '');
}
}
if (status == null) {
throw new nice_grpc_common_1.ClientError(definition.path, nice_grpc_common_1.Status.UNKNOWN, 'Response stream closed without gRPC status. This may indicate a misconfigured CORS policy on the server: Access-Control-Expose-Headers must include "grpc-status" and "grpc-message".');
}
}
//# sourceMappingURL=makeCall.js.map