Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@bufbuild/connect-web

Package Overview
Dependencies
Maintainers
5
Versions
38
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bufbuild/connect-web - npm Package Compare versions

Comparing version 0.0.9 to 0.0.10

dist/cjs/call-options.js

16

dist/cjs/callback-client.js

@@ -50,3 +50,3 @@ "use strict";

}, (reason) => {
const err = (0, connect_error_js_1.connectErrorFromReason)(reason);
const err = (0, connect_error_js_1.connectErrorFromReason)(reason, code_js_1.Code.Internal);
if (err.code === code_js_1.Code.Canceled && abort.signal.aborted) {

@@ -78,8 +78,11 @@ // As documented, discard Canceled errors if canceled by the user.

run().catch((reason) => {
const err = (0, connect_error_js_1.connectErrorFromReason)(reason);
const err = (0, connect_error_js_1.connectErrorFromReason)(reason, code_js_1.Code.Internal);
if (err.code === code_js_1.Code.Canceled && abort.signal.aborted) {
// As documented, discard Canceled errors if canceled by the user.
return;
// As documented, discard Canceled errors if canceled by the user,
// but do invoke the close-callback.
onClose(undefined);
}
onClose(err);
else {
onClose(err);
}
});

@@ -92,4 +95,7 @@ return () => abort.abort();

options.signal.addEventListener("abort", () => abort.abort());
if (options.signal.aborted) {
abort.abort();
}
}
return Object.assign(Object.assign({}, options), { signal: abort.signal });
}

@@ -16,3 +16,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.newParseError = exports.connectErrorFromReason = exports.connectErrorFromJson = exports.ConnectError = void 0;
exports.newParseError = exports.connectErrorFromReason = exports.connectErrorFromJson = exports.connectErrorDetails = exports.ConnectError = void 0;
const code_js_1 = require("./code.js");

@@ -27,11 +27,12 @@ const protobuf_1 = require("@bufbuild/protobuf");

* Because developer tools typically show just the error message, we prefix
* it with the status code.
* it with the status code, so that the most important information is always
* visible immediately.
*
* Error details are wrapped with google.protobuf.Any on the wire, so that
* a server or middleware can attach arbitrary data to an error. We
* automatically unwrap the details for you.
* a server or middleware can attach arbitrary data to an error. Use the
* function connectErrorDetails() to retrieve the details.
*/
class ConnectError extends Error {
constructor(message, code = code_js_1.Code.Unknown, details, metadata) {
super(syntheticMessage(code, message));
super(createMessage(message, code));
this.name = "ConnectError";

@@ -42,3 +43,2 @@ // see https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#example

this.code = code;
this.details = details !== null && details !== void 0 ? details : [];
this.metadata = new Headers(metadata);

@@ -49,3 +49,29 @@ this.rawDetails = [];

exports.ConnectError = ConnectError;
function syntheticMessage(code, message) {
function connectErrorDetails(error, typeOrRegistry, ...moreTypes) {
const typeRegistry = "typeName" in typeOrRegistry
? protobuf_2.TypeRegistry.from(typeOrRegistry, ...moreTypes)
: typeOrRegistry;
const details = [];
for (const raw of error.rawDetails) {
try {
const any = "@type" in raw ? protobuf_2.Any.fromJson(raw, { typeRegistry }) : raw;
const name = any.typeUrl.substring(any.typeUrl.lastIndexOf("/") + 1);
const type = typeRegistry.findMessage(name);
if (type) {
const message = new type();
any.unpackTo(message);
details.push(message);
}
}
catch (_) {
//
}
}
return details;
}
exports.connectErrorDetails = connectErrorDetails;
/**
* Create an error message, prefixing the given code.
*/
function createMessage(message, code) {
return message.length

@@ -56,6 +82,6 @@ ? `[${(0, code_js_1.codeToString)(code)}] ${message}`

/**
* Parse an error from a JSON value.
* Parse a Connect error from a JSON value.
* Will return a ConnectError, but throw one in case the JSON is malformed.
*/
function connectErrorFromJson(jsonValue, options) {
function connectErrorFromJson(jsonValue, metadata) {
if (typeof jsonValue !== "object" ||

@@ -76,30 +102,5 @@ jsonValue == null ||

}
const error = new ConnectError(message !== null && message !== void 0 ? message : "", code, undefined, options === null || options === void 0 ? void 0 : options.metadata);
const error = new ConnectError(message !== null && message !== void 0 ? message : "", code, undefined, metadata);
if ("details" in jsonValue && Array.isArray(jsonValue.details)) {
for (const raw of jsonValue.details) {
let any;
try {
any = protobuf_2.Any.fromJson(raw, options);
}
catch (e) {
// We consider error details to be supplementary information.
// Parsing error details must not hide elementary information
// like code and message, so we deliberately ignore parsing
// errors here.
error.rawDetails.push(raw);
continue;
}
const typeName = any.typeUrl.substring(any.typeUrl.lastIndexOf("/") + 1);
if (!(options === null || options === void 0 ? void 0 : options.typeRegistry)) {
error.rawDetails.push(raw);
continue;
}
const messageType = options.typeRegistry.findMessage(typeName);
if (messageType) {
const message = new messageType();
if (any.unpackTo(message)) {
error.details.push(message);
}
}
}
error.rawDetails.push(...jsonValue.details);
}

@@ -110,8 +111,12 @@ return error;

/**
* Convert any value - typically a caught error into a ConnectError.
* If the value is already a ConnectError, return it as is.
* If the value is an AbortError from the fetch API, return code Canceled.
* For other values, return code Internal.
* Convert any value - typically a caught error into a ConnectError,
* following these rules:
* - If the value is already a ConnectError, return it as is.
* - If the value is an AbortError from the fetch API, return the message
* of the AbortError with code Canceled.
* - For other Errors, return the Errors message with code Unknown by default.
* - For other values, return the values String representation as a message,
* with the code Unknown by default.
*/
function connectErrorFromReason(reason) {
function connectErrorFromReason(reason, code = code_js_1.Code.Unknown) {
if (reason instanceof ConnectError) {

@@ -129,3 +134,3 @@ return reason;

}
return new ConnectError(String(reason), code_js_1.Code.Internal);
return new ConnectError(String(reason), code);
}

@@ -132,0 +137,0 @@ exports.connectErrorFromReason = connectErrorFromReason;

@@ -23,2 +23,7 @@ "use strict";

const http_headers_js_1 = require("./http-headers.js");
/**
* Create a Transport for the Connect protocol, which makes unary and
* server-streaming methods available to web browsers. It uses the fetch
* API to make HTTP requests.
*/
function createConnectTransport(options) {

@@ -51,6 +56,3 @@ var _a;

if (responseType == "application/json") {
throw (0, connect_error_js_1.connectErrorFromJson)((await response.json()), {
typeRegistry: options.errorDetailRegistry,
metadata: (0, http_headers_js_1.mergeHeaders)(...demuxHeaderTrailers(response.headers)),
});
throw (0, connect_error_js_1.connectErrorFromJson)((await response.json()), (0, http_headers_js_1.mergeHeaders)(...demuxHeaderTrailers(response.headers)));
}

@@ -74,3 +76,3 @@ throw new connect_error_js_1.ConnectError(`HTTP ${response.status} ${response.statusText}`, (0, code_js_1.codeFromConnectHttpStatus)(response.status));

catch (e) {
throw (0, connect_error_js_1.connectErrorFromReason)(e);
throw (0, connect_error_js_1.connectErrorFromReason)(e, code_js_1.Code.Internal);
}

@@ -101,6 +103,3 @@ },

if (responseType == "application/json") {
throw (0, connect_error_js_1.connectErrorFromJson)((await response.json()), {
typeRegistry: options.errorDetailRegistry,
metadata: (0, http_headers_js_1.mergeHeaders)(...demuxHeaderTrailers(response.headers)),
});
throw (0, connect_error_js_1.connectErrorFromJson)((await response.json()), (0, http_headers_js_1.mergeHeaders)(...demuxHeaderTrailers(response.headers)));
}

@@ -135,5 +134,3 @@ throw new connect_error_js_1.ConnectError(`HTTP ${response.status} ${response.statusText}`, (0, code_js_1.codeFromConnectHttpStatus)(response.status));

endStreamReceived = true;
const endStream = EndStream.fromJsonString(new TextDecoder().decode(result.value.data), {
typeRegistry: options.errorDetailRegistry,
});
const endStream = endStreamFromJson(result.value.data);
endStream.metadata.forEach((value, key) => this.trailer.append(key, value));

@@ -159,3 +156,3 @@ if (endStream.error) {

catch (e) {
throw (0, connect_error_js_1.connectErrorFromReason)(e);
throw (0, connect_error_js_1.connectErrorFromReason)(e, code_js_1.Code.Internal);
}

@@ -166,2 +163,7 @@ },

exports.createConnectTransport = createConnectTransport;
/**
* Creates a body for a Connect request. Supports only requests with a single
* message because of browser API limitations, but applies the enveloping
* required for server-streaming requests.
*/
function createConnectRequestBody(message, methodKind, useBinaryFormat, jsonOptions) {

@@ -183,2 +185,5 @@ const encoded = useBinaryFormat

}
/**
* Creates headers for a Connect request.
*/
function createConnectRequestHeaders(headers, timeoutMs, methodKind, useBinaryFormat) {

@@ -197,2 +202,6 @@ const result = new Headers(headers);

}
/**
* Asserts a valid Connect Content-Type response header. Raises a ConnectError
* otherwise.
*/
function expectContentType(contentType, stream, binaryFormat) {

@@ -226,69 +235,52 @@ const match = contentType === null || contentType === void 0 ? void 0 : contentType.match(/^application\/(connect\+)?(json|proto)$/);

/**
* Represents the EndStreamResponse of the Connect protocol.
* Parse an EndStreamResponse of the Connect protocol.
*/
class EndStream {
constructor(metadata, error) {
this.metadata = metadata;
this.error = error;
function endStreamFromJson(data) {
let jsonValue;
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
jsonValue = JSON.parse(new TextDecoder().decode(data));
}
/**
* Parse an EndStreamResponse from a JSON string.
* Will throw a ConnectError in case the JSON is malformed.
*/
static fromJsonString(jsonString, options) {
let json;
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
json = JSON.parse(jsonString);
}
catch (e) {
throw (0, connect_error_js_1.newParseError)(e, "", false);
}
return this.fromJson(json, options);
catch (e) {
throw (0, connect_error_js_1.newParseError)(e, "", false);
}
/**
* Parse an EndStreamResponse from a JSON value.
* Will return a ConnectError, but throw one in case the JSON is malformed.
*/
static fromJson(jsonValue, options) {
if (typeof jsonValue != "object" ||
jsonValue == null ||
Array.isArray(jsonValue)) {
throw (0, connect_error_js_1.newParseError)(jsonValue);
if (typeof jsonValue != "object" ||
jsonValue == null ||
Array.isArray(jsonValue)) {
throw (0, connect_error_js_1.newParseError)(jsonValue);
}
const metadata = new Headers();
if ("metadata" in jsonValue) {
if (typeof jsonValue.metadata != "object" ||
jsonValue.metadata == null ||
Array.isArray(jsonValue.metadata)) {
throw (0, connect_error_js_1.newParseError)(jsonValue, ".metadata");
}
const metadata = new Headers();
if ("metadata" in jsonValue) {
if (typeof jsonValue.metadata != "object" ||
jsonValue.metadata == null ||
Array.isArray(jsonValue.metadata)) {
throw (0, connect_error_js_1.newParseError)(jsonValue, ".metadata");
for (const [key, values] of Object.entries(jsonValue.metadata)) {
if (!Array.isArray(values) ||
values.some((value) => typeof value != "string")) {
throw (0, connect_error_js_1.newParseError)(values, `.metadata["${key}"]`);
}
for (const [key, values] of Object.entries(jsonValue.metadata)) {
if (!Array.isArray(values) ||
values.some((value) => typeof value != "string")) {
throw (0, connect_error_js_1.newParseError)(values, `.metadata["${key}"]`);
}
for (const value of values) {
metadata.append(key, value);
}
for (const value of values) {
metadata.append(key, value);
}
}
let error;
if ("error" in jsonValue) {
if (typeof jsonValue.error != "object" ||
jsonValue.error == null ||
Array.isArray(jsonValue.error)) {
throw (0, connect_error_js_1.newParseError)(jsonValue, ".error");
}
let error;
if ("error" in jsonValue) {
if (typeof jsonValue.error != "object" ||
jsonValue.error == null ||
Array.isArray(jsonValue.error)) {
throw (0, connect_error_js_1.newParseError)(jsonValue, ".error");
}
if (Object.keys(jsonValue.error).length > 0) {
try {
error = (0, connect_error_js_1.connectErrorFromJson)(jsonValue.error, metadata);
}
if (Object.keys(jsonValue.error).length > 0) {
try {
error = (0, connect_error_js_1.connectErrorFromJson)(jsonValue.error, Object.assign(Object.assign({}, options), { metadata }));
}
catch (e) {
throw (0, connect_error_js_1.newParseError)(e, ".error", false);
}
catch (e) {
throw (0, connect_error_js_1.newParseError)(e, ".error", false);
}
}
return new EndStream(metadata, error);
}
return { metadata, error };
}

@@ -16,25 +16,5 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.createEnvelopeReadableStream = exports.encodeEnvelopes = void 0;
exports.encodeEnvelopes = exports.createEnvelopeReadableStream = void 0;
const connect_error_js_1 = require("./connect-error.js");
const code_js_1 = require("./code.js");
function encodeEnvelopes(...envelopes) {
const target = new ArrayBuffer(envelopes.reduce((previousValue, currentValue) => previousValue + currentValue.data.length + 5, 0));
let offset = 0;
for (const m of envelopes) {
offset += encodeEnvelope(m, target, offset);
}
return new Uint8Array(target);
}
exports.encodeEnvelopes = encodeEnvelopes;
function encodeEnvelope(envelope, target, byteOffset) {
const len = envelope.data.length + 5;
const bytes = new Uint8Array(target, byteOffset, len);
bytes[0] = envelope.flags; // first byte is flags
for (let l = envelope.data.length, i = 4; i > 0; i--) {
bytes[i] = l % 256; // 4 bytes message length
l >>>= 8;
}
bytes.set(envelope.data, 5);
return len;
}
/**

@@ -96,1 +76,21 @@ * Create a ReadableStream of enveloped messages from a ReadableStream of bytes.

exports.createEnvelopeReadableStream = createEnvelopeReadableStream;
function encodeEnvelopes(...envelopes) {
const target = new ArrayBuffer(envelopes.reduce((previousValue, currentValue) => previousValue + currentValue.data.length + 5, 0));
let offset = 0;
for (const m of envelopes) {
offset += encodeEnvelope(m, target, offset);
}
return new Uint8Array(target);
}
exports.encodeEnvelopes = encodeEnvelopes;
function encodeEnvelope(envelope, target, byteOffset) {
const len = envelope.data.length + 5;
const bytes = new Uint8Array(target, byteOffset, len);
bytes[0] = envelope.flags; // first byte is flags
for (let l = envelope.data.length, i = 4; i > 0; i--) {
bytes[i] = l % 256; // 4 bytes message length
l >>>= 8;
}
bytes.set(envelope.data, 5);
return len;
}

@@ -23,2 +23,12 @@ "use strict";

const envelope_js_1 = require("./envelope.js");
/**
* Create a Transport for the gRPC-web protocol. The protocol encodes
* trailers in the response body and makes unary and server-streaming
* methods available to web browsers. It uses the fetch API to make
* HTTP requests.
*
* Note that this transport does not implement the grpc-web-text format,
* which applies base64 encoding to the request and response bodies to
* support reading streaming responses from an XMLHttpRequest.
*/
function createGrpcWebTransport(options) {

@@ -47,3 +57,3 @@ const transportOptions = options;

const response = await fetch(unaryRequest.url, Object.assign(Object.assign({}, unaryRequest.init), { headers: unaryRequest.header, signal: unaryRequest.signal, body: createGrpcWebRequestBody(unaryRequest.message, options.binaryOptions) }));
const headError = (_c = (_b = (_a = extractHttpStatusError(response)) !== null && _a !== void 0 ? _a : extractContentTypeError(response.headers)) !== null && _b !== void 0 ? _b : extractDetailsError(response.headers, transportOptions.errorDetailRegistry)) !== null && _c !== void 0 ? _c : extractHeadersError(response.headers);
const headError = (_c = (_b = (_a = extractHttpStatusError(response)) !== null && _a !== void 0 ? _a : extractContentTypeError(response.headers)) !== null && _b !== void 0 ? _b : extractDetailsError(response.headers)) !== null && _c !== void 0 ? _c : extractHeadersError(response.headers);
if (headError) {

@@ -64,3 +74,3 @@ throw headError;

// that only contains error trailers.
parseGrpcWebTrailerAndExtractError(messageOrTrailerResult.value.data, transportOptions.errorDetailRegistry);
parseGrpcWebTrailerAndExtractError(messageOrTrailerResult.value.data);
// At this point, we received trailers only, but the trailers did

@@ -78,3 +88,3 @@ // not have an error status code.

}
const trailer = parseGrpcWebTrailerAndExtractError(trailerResult.value.data, transportOptions.errorDetailRegistry);
const trailer = parseGrpcWebTrailerAndExtractError(trailerResult.value.data);
const eofResult = await reader.read();

@@ -93,3 +103,3 @@ if (!eofResult.done) {

catch (e) {
throw (0, connect_error_js_1.connectErrorFromReason)(e);
throw (0, connect_error_js_1.connectErrorFromReason)(e, code_js_1.Code.Internal);
}

@@ -117,3 +127,3 @@ },

const response = await fetch(unaryRequest.url, Object.assign(Object.assign({}, unaryRequest.init), { headers: unaryRequest.header, signal: unaryRequest.signal, body: createGrpcWebRequestBody(unaryRequest.message, options.binaryOptions) }));
const err = (_c = (_b = (_a = extractHttpStatusError(response)) !== null && _a !== void 0 ? _a : extractContentTypeError(response.headers)) !== null && _b !== void 0 ? _b : extractDetailsError(response.headers, transportOptions.errorDetailRegistry)) !== null && _c !== void 0 ? _c : extractHeadersError(response.headers);
const err = (_c = (_b = (_a = extractHttpStatusError(response)) !== null && _a !== void 0 ? _a : extractContentTypeError(response.headers)) !== null && _b !== void 0 ? _b : extractDetailsError(response.headers)) !== null && _c !== void 0 ? _c : extractHeadersError(response.headers);
if (err) {

@@ -147,3 +157,3 @@ throw err;

endStreamReceived = true;
const trailer = parseGrpcWebTrailerAndExtractError(result.value.data, transportOptions.errorDetailRegistry);
const trailer = parseGrpcWebTrailerAndExtractError(result.value.data);
trailer.forEach((value, key) => this.trailer.append(key, value));

@@ -165,3 +175,3 @@ return {

catch (e) {
throw (0, connect_error_js_1.connectErrorFromReason)(e);
throw (0, connect_error_js_1.connectErrorFromReason)(e, code_js_1.Code.Internal);
}

@@ -237,3 +247,3 @@ },

}
function extractDetailsError(header, typeRegistry) {
function extractDetailsError(header) {
const grpcStatusDetailsBin = header.get("grpc-status-details-bin");

@@ -250,21 +260,7 @@ if (grpcStatusDetailsBin == null) {

const error = new connect_error_js_1.ConnectError(status.message, status.code, undefined, header);
// TODO deduplicate with similar logic in ConnectError
for (const any of status.details) {
const typeName = any.typeUrl.substring(any.typeUrl.lastIndexOf("/") + 1);
if (!typeRegistry) {
error.rawDetails.push(any);
continue;
}
const messageType = typeRegistry.findMessage(typeName);
if (messageType) {
const message = new messageType();
if (any.unpackTo(message)) {
error.details.push(message);
}
}
}
error.rawDetails.push(...status.details);
return error;
}
catch (e) {
const ce = (0, connect_error_js_1.connectErrorFromReason)(e);
const ce = (0, connect_error_js_1.connectErrorFromReason)(e, code_js_1.Code.Internal);
header.forEach((value, key) => ce.metadata.append(key, value));

@@ -274,6 +270,6 @@ return ce;

}
function parseGrpcWebTrailerAndExtractError(data, errorDetailRegistry) {
function parseGrpcWebTrailerAndExtractError(data) {
var _a;
const trailer = parseGrpcWebTrailer(data);
const err = (_a = extractDetailsError(trailer, errorDetailRegistry)) !== null && _a !== void 0 ? _a : extractHeadersError(trailer);
const err = (_a = extractDetailsError(trailer)) !== null && _a !== void 0 ? _a : extractHeadersError(trailer);
if (err) {

@@ -280,0 +276,0 @@ throw err;

@@ -21,7 +21,9 @@ "use strict";

/**
* Encode a single binary header value according to the gRPC
* specification.
* Encode a single binary header value according to the Connect
* and gRPC specifications.
*
* Binary headers names end with `-bin`, and can contain arbitrary
* base64-encoded binary data.
* This function accepts raw binary data from a buffer, a string
* with UTF-8 text, or a protobuf message. It encodes the input
* with base64 and returns a string that can be used for a header
* whose name ends with `-bin`.
*/

@@ -33,2 +35,5 @@ function encodeBinaryHeader(value) {

}
else if (typeof value == "string") {
bytes = new TextEncoder().encode(value);
}
else {

@@ -35,0 +40,0 @@ bytes = value instanceof Uint8Array ? value : new Uint8Array(value);

@@ -16,3 +16,3 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
exports.encodeEnvelopes = exports.createEnvelopeReadableStream = exports.mergeHeaders = exports.encodeBinaryHeader = exports.decodeBinaryHeader = exports.createGrpcWebTransport = exports.createConnectTransport = exports.codeToString = exports.codeFromString = exports.Code = exports.connectErrorFromJson = exports.ConnectError = exports.runServerStream = exports.runUnary = exports.makeAnyClient = exports.createPromiseClient = exports.createCallbackClient = void 0;
exports.createEnvelopeReadableStream = exports.mergeHeaders = exports.decodeBinaryHeader = exports.encodeBinaryHeader = exports.codeToString = exports.codeFromString = exports.Code = exports.connectErrorFromJson = exports.connectErrorFromReason = exports.connectErrorDetails = exports.ConnectError = exports.runServerStream = exports.runUnary = exports.createGrpcWebTransport = exports.createConnectTransport = exports.makeAnyClient = exports.createPromiseClient = exports.createCallbackClient = void 0;
var callback_client_js_1 = require("./callback-client.js");

@@ -24,8 +24,13 @@ Object.defineProperty(exports, "createCallbackClient", { enumerable: true, get: function () { return callback_client_js_1.createCallbackClient; } });

Object.defineProperty(exports, "makeAnyClient", { enumerable: true, get: function () { return any_client_js_1.makeAnyClient; } });
var connect_transport_js_1 = require("./connect-transport.js");
Object.defineProperty(exports, "createConnectTransport", { enumerable: true, get: function () { return connect_transport_js_1.createConnectTransport; } });
var grpc_web_transport_js_1 = require("./grpc-web-transport.js");
Object.defineProperty(exports, "createGrpcWebTransport", { enumerable: true, get: function () { return grpc_web_transport_js_1.createGrpcWebTransport; } });
var interceptor_js_1 = require("./interceptor.js");
Object.defineProperty(exports, "runUnary", { enumerable: true, get: function () { return interceptor_js_1.runUnary; } });
Object.defineProperty(exports, "runServerStream", { enumerable: true, get: function () { return interceptor_js_1.runServerStream; } });
var transport_js_1 = require("./transport.js");
var connect_error_js_1 = require("./connect-error.js");
Object.defineProperty(exports, "ConnectError", { enumerable: true, get: function () { return connect_error_js_1.ConnectError; } });
Object.defineProperty(exports, "connectErrorDetails", { enumerable: true, get: function () { return connect_error_js_1.connectErrorDetails; } });
Object.defineProperty(exports, "connectErrorFromReason", { enumerable: true, get: function () { return connect_error_js_1.connectErrorFromReason; } });
Object.defineProperty(exports, "connectErrorFromJson", { enumerable: true, get: function () { return connect_error_js_1.connectErrorFromJson; } });

@@ -36,12 +41,7 @@ var code_js_1 = require("./code.js");

Object.defineProperty(exports, "codeToString", { enumerable: true, get: function () { return code_js_1.codeToString; } });
var connect_transport_js_1 = require("./connect-transport.js");
Object.defineProperty(exports, "createConnectTransport", { enumerable: true, get: function () { return connect_transport_js_1.createConnectTransport; } });
var grpc_web_transport_js_1 = require("./grpc-web-transport.js");
Object.defineProperty(exports, "createGrpcWebTransport", { enumerable: true, get: function () { return grpc_web_transport_js_1.createGrpcWebTransport; } });
var http_headers_js_1 = require("./http-headers.js");
Object.defineProperty(exports, "encodeBinaryHeader", { enumerable: true, get: function () { return http_headers_js_1.encodeBinaryHeader; } });
Object.defineProperty(exports, "decodeBinaryHeader", { enumerable: true, get: function () { return http_headers_js_1.decodeBinaryHeader; } });
Object.defineProperty(exports, "encodeBinaryHeader", { enumerable: true, get: function () { return http_headers_js_1.encodeBinaryHeader; } });
Object.defineProperty(exports, "mergeHeaders", { enumerable: true, get: function () { return http_headers_js_1.mergeHeaders; } });
var envelope_js_1 = require("./envelope.js");
Object.defineProperty(exports, "createEnvelopeReadableStream", { enumerable: true, get: function () { return envelope_js_1.createEnvelopeReadableStream; } });
Object.defineProperty(exports, "encodeEnvelopes", { enumerable: true, get: function () { return envelope_js_1.encodeEnvelopes; } });

@@ -17,3 +17,17 @@ "use strict";

exports.runServerStream = exports.runUnary = void 0;
// TODO document
/**
* applyInterceptors takes the given UnaryFn or ServerStreamingFn, and wraps
* it with each of the given interceptors, returning a new UnaryFn or
* ServerStreamingFn.
*/
function applyInterceptors(next, interceptors) {
return interceptors
.concat()
.reverse()
.reduce((n, i) => i(n), next);
}
/**
* Runs a unary method with the given interceptors. Note that this function
* is only used when implementing a Transport.
*/
function runUnary(req, next, interceptors) {

@@ -26,3 +40,6 @@ if (interceptors) {

exports.runUnary = runUnary;
// TODO document
/**
* Runs a server-streaming method with the given interceptors. Note that this
* function is only used when implementing a Transport.
*/
function runServerStream(req, next, interceptors) {

@@ -35,7 +52,1 @@ if (interceptors) {

exports.runServerStream = runServerStream;
function applyInterceptors(next, interceptors) {
return interceptors
.concat()
.reverse()
.reduce((n, i) => i(n), next);
}

@@ -46,3 +46,3 @@ // Copyright 2021-2022 Buf Technologies, Inc.

}, (reason) => {
const err = connectErrorFromReason(reason);
const err = connectErrorFromReason(reason, Code.Internal);
if (err.code === Code.Canceled && abort.signal.aborted) {

@@ -74,8 +74,11 @@ // As documented, discard Canceled errors if canceled by the user.

run().catch((reason) => {
const err = connectErrorFromReason(reason);
const err = connectErrorFromReason(reason, Code.Internal);
if (err.code === Code.Canceled && abort.signal.aborted) {
// As documented, discard Canceled errors if canceled by the user.
return;
// As documented, discard Canceled errors if canceled by the user,
// but do invoke the close-callback.
onClose(undefined);
}
onClose(err);
else {
onClose(err);
}
});

@@ -88,4 +91,7 @@ return () => abort.abort();

options.signal.addEventListener("abort", () => abort.abort());
if (options.signal.aborted) {
abort.abort();
}
}
return Object.assign(Object.assign({}, options), { signal: abort.signal });
}

@@ -16,3 +16,3 @@ // Copyright 2021-2022 Buf Technologies, Inc.

import { proto3, } from "@bufbuild/protobuf";
import { Any } from "@bufbuild/protobuf";
import { Any, TypeRegistry } from "@bufbuild/protobuf";
/**

@@ -24,11 +24,12 @@ * ConnectError captures three pieces of information: a Code, an error

* Because developer tools typically show just the error message, we prefix
* it with the status code.
* it with the status code, so that the most important information is always
* visible immediately.
*
* Error details are wrapped with google.protobuf.Any on the wire, so that
* a server or middleware can attach arbitrary data to an error. We
* automatically unwrap the details for you.
* a server or middleware can attach arbitrary data to an error. Use the
* function connectErrorDetails() to retrieve the details.
*/
export class ConnectError extends Error {
constructor(message, code = Code.Unknown, details, metadata) {
super(syntheticMessage(code, message));
super(createMessage(message, code));
this.name = "ConnectError";

@@ -39,3 +40,2 @@ // see https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#example

this.code = code;
this.details = details !== null && details !== void 0 ? details : [];
this.metadata = new Headers(metadata);

@@ -45,3 +45,28 @@ this.rawDetails = [];

}
function syntheticMessage(code, message) {
export function connectErrorDetails(error, typeOrRegistry, ...moreTypes) {
const typeRegistry = "typeName" in typeOrRegistry
? TypeRegistry.from(typeOrRegistry, ...moreTypes)
: typeOrRegistry;
const details = [];
for (const raw of error.rawDetails) {
try {
const any = "@type" in raw ? Any.fromJson(raw, { typeRegistry }) : raw;
const name = any.typeUrl.substring(any.typeUrl.lastIndexOf("/") + 1);
const type = typeRegistry.findMessage(name);
if (type) {
const message = new type();
any.unpackTo(message);
details.push(message);
}
}
catch (_) {
//
}
}
return details;
}
/**
* Create an error message, prefixing the given code.
*/
function createMessage(message, code) {
return message.length

@@ -52,6 +77,6 @@ ? `[${codeToString(code)}] ${message}`

/**
* Parse an error from a JSON value.
* Parse a Connect error from a JSON value.
* Will return a ConnectError, but throw one in case the JSON is malformed.
*/
export function connectErrorFromJson(jsonValue, options) {
export function connectErrorFromJson(jsonValue, metadata) {
if (typeof jsonValue !== "object" ||

@@ -72,30 +97,5 @@ jsonValue == null ||

}
const error = new ConnectError(message !== null && message !== void 0 ? message : "", code, undefined, options === null || options === void 0 ? void 0 : options.metadata);
const error = new ConnectError(message !== null && message !== void 0 ? message : "", code, undefined, metadata);
if ("details" in jsonValue && Array.isArray(jsonValue.details)) {
for (const raw of jsonValue.details) {
let any;
try {
any = Any.fromJson(raw, options);
}
catch (e) {
// We consider error details to be supplementary information.
// Parsing error details must not hide elementary information
// like code and message, so we deliberately ignore parsing
// errors here.
error.rawDetails.push(raw);
continue;
}
const typeName = any.typeUrl.substring(any.typeUrl.lastIndexOf("/") + 1);
if (!(options === null || options === void 0 ? void 0 : options.typeRegistry)) {
error.rawDetails.push(raw);
continue;
}
const messageType = options.typeRegistry.findMessage(typeName);
if (messageType) {
const message = new messageType();
if (any.unpackTo(message)) {
error.details.push(message);
}
}
}
error.rawDetails.push(...jsonValue.details);
}

@@ -105,8 +105,12 @@ return error;

/**
* Convert any value - typically a caught error into a ConnectError.
* If the value is already a ConnectError, return it as is.
* If the value is an AbortError from the fetch API, return code Canceled.
* For other values, return code Internal.
* Convert any value - typically a caught error into a ConnectError,
* following these rules:
* - If the value is already a ConnectError, return it as is.
* - If the value is an AbortError from the fetch API, return the message
* of the AbortError with code Canceled.
* - For other Errors, return the Errors message with code Unknown by default.
* - For other values, return the values String representation as a message,
* with the code Unknown by default.
*/
export function connectErrorFromReason(reason) {
export function connectErrorFromReason(reason, code = Code.Unknown) {
if (reason instanceof ConnectError) {

@@ -124,3 +128,3 @@ return reason;

}
return new ConnectError(String(reason), Code.Internal);
return new ConnectError(String(reason), code);
}

@@ -127,0 +131,0 @@ export function newParseError(valueOrError, property, json) {

@@ -20,2 +20,7 @@ // Copyright 2021-2022 Buf Technologies, Inc.

import { mergeHeaders } from "./http-headers.js";
/**
* Create a Transport for the Connect protocol, which makes unary and
* server-streaming methods available to web browsers. It uses the fetch
* API to make HTTP requests.
*/
export function createConnectTransport(options) {

@@ -48,6 +53,3 @@ var _a;

if (responseType == "application/json") {
throw connectErrorFromJson((await response.json()), {
typeRegistry: options.errorDetailRegistry,
metadata: mergeHeaders(...demuxHeaderTrailers(response.headers)),
});
throw connectErrorFromJson((await response.json()), mergeHeaders(...demuxHeaderTrailers(response.headers)));
}

@@ -71,3 +73,3 @@ throw new ConnectError(`HTTP ${response.status} ${response.statusText}`, codeFromConnectHttpStatus(response.status));

catch (e) {
throw connectErrorFromReason(e);
throw connectErrorFromReason(e, Code.Internal);
}

@@ -98,6 +100,3 @@ },

if (responseType == "application/json") {
throw connectErrorFromJson((await response.json()), {
typeRegistry: options.errorDetailRegistry,
metadata: mergeHeaders(...demuxHeaderTrailers(response.headers)),
});
throw connectErrorFromJson((await response.json()), mergeHeaders(...demuxHeaderTrailers(response.headers)));
}

@@ -132,5 +131,3 @@ throw new ConnectError(`HTTP ${response.status} ${response.statusText}`, codeFromConnectHttpStatus(response.status));

endStreamReceived = true;
const endStream = EndStream.fromJsonString(new TextDecoder().decode(result.value.data), {
typeRegistry: options.errorDetailRegistry,
});
const endStream = endStreamFromJson(result.value.data);
endStream.metadata.forEach((value, key) => this.trailer.append(key, value));

@@ -156,3 +153,3 @@ if (endStream.error) {

catch (e) {
throw connectErrorFromReason(e);
throw connectErrorFromReason(e, Code.Internal);
}

@@ -162,2 +159,7 @@ },

}
/**
* Creates a body for a Connect request. Supports only requests with a single
* message because of browser API limitations, but applies the enveloping
* required for server-streaming requests.
*/
function createConnectRequestBody(message, methodKind, useBinaryFormat, jsonOptions) {

@@ -179,2 +181,5 @@ const encoded = useBinaryFormat

}
/**
* Creates headers for a Connect request.
*/
function createConnectRequestHeaders(headers, timeoutMs, methodKind, useBinaryFormat) {

@@ -193,2 +198,6 @@ const result = new Headers(headers);

}
/**
* Asserts a valid Connect Content-Type response header. Raises a ConnectError
* otherwise.
*/
function expectContentType(contentType, stream, binaryFormat) {

@@ -222,69 +231,52 @@ const match = contentType === null || contentType === void 0 ? void 0 : contentType.match(/^application\/(connect\+)?(json|proto)$/);

/**
* Represents the EndStreamResponse of the Connect protocol.
* Parse an EndStreamResponse of the Connect protocol.
*/
class EndStream {
constructor(metadata, error) {
this.metadata = metadata;
this.error = error;
function endStreamFromJson(data) {
let jsonValue;
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
jsonValue = JSON.parse(new TextDecoder().decode(data));
}
/**
* Parse an EndStreamResponse from a JSON string.
* Will throw a ConnectError in case the JSON is malformed.
*/
static fromJsonString(jsonString, options) {
let json;
try {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
json = JSON.parse(jsonString);
}
catch (e) {
throw newParseError(e, "", false);
}
return this.fromJson(json, options);
catch (e) {
throw newParseError(e, "", false);
}
/**
* Parse an EndStreamResponse from a JSON value.
* Will return a ConnectError, but throw one in case the JSON is malformed.
*/
static fromJson(jsonValue, options) {
if (typeof jsonValue != "object" ||
jsonValue == null ||
Array.isArray(jsonValue)) {
throw newParseError(jsonValue);
if (typeof jsonValue != "object" ||
jsonValue == null ||
Array.isArray(jsonValue)) {
throw newParseError(jsonValue);
}
const metadata = new Headers();
if ("metadata" in jsonValue) {
if (typeof jsonValue.metadata != "object" ||
jsonValue.metadata == null ||
Array.isArray(jsonValue.metadata)) {
throw newParseError(jsonValue, ".metadata");
}
const metadata = new Headers();
if ("metadata" in jsonValue) {
if (typeof jsonValue.metadata != "object" ||
jsonValue.metadata == null ||
Array.isArray(jsonValue.metadata)) {
throw newParseError(jsonValue, ".metadata");
for (const [key, values] of Object.entries(jsonValue.metadata)) {
if (!Array.isArray(values) ||
values.some((value) => typeof value != "string")) {
throw newParseError(values, `.metadata["${key}"]`);
}
for (const [key, values] of Object.entries(jsonValue.metadata)) {
if (!Array.isArray(values) ||
values.some((value) => typeof value != "string")) {
throw newParseError(values, `.metadata["${key}"]`);
}
for (const value of values) {
metadata.append(key, value);
}
for (const value of values) {
metadata.append(key, value);
}
}
let error;
if ("error" in jsonValue) {
if (typeof jsonValue.error != "object" ||
jsonValue.error == null ||
Array.isArray(jsonValue.error)) {
throw newParseError(jsonValue, ".error");
}
let error;
if ("error" in jsonValue) {
if (typeof jsonValue.error != "object" ||
jsonValue.error == null ||
Array.isArray(jsonValue.error)) {
throw newParseError(jsonValue, ".error");
}
if (Object.keys(jsonValue.error).length > 0) {
try {
error = connectErrorFromJson(jsonValue.error, metadata);
}
if (Object.keys(jsonValue.error).length > 0) {
try {
error = connectErrorFromJson(jsonValue.error, Object.assign(Object.assign({}, options), { metadata }));
}
catch (e) {
throw newParseError(e, ".error", false);
}
catch (e) {
throw newParseError(e, ".error", false);
}
}
return new EndStream(metadata, error);
}
return { metadata, error };
}

@@ -16,21 +16,2 @@ // Copyright 2021-2022 Buf Technologies, Inc.

import { Code } from "./code.js";
export function encodeEnvelopes(...envelopes) {
const target = new ArrayBuffer(envelopes.reduce((previousValue, currentValue) => previousValue + currentValue.data.length + 5, 0));
let offset = 0;
for (const m of envelopes) {
offset += encodeEnvelope(m, target, offset);
}
return new Uint8Array(target);
}
function encodeEnvelope(envelope, target, byteOffset) {
const len = envelope.data.length + 5;
const bytes = new Uint8Array(target, byteOffset, len);
bytes[0] = envelope.flags; // first byte is flags
for (let l = envelope.data.length, i = 4; i > 0; i--) {
bytes[i] = l % 256; // 4 bytes message length
l >>>= 8;
}
bytes.set(envelope.data, 5);
return len;
}
/**

@@ -91,1 +72,20 @@ * Create a ReadableStream of enveloped messages from a ReadableStream of bytes.

}
export function encodeEnvelopes(...envelopes) {
const target = new ArrayBuffer(envelopes.reduce((previousValue, currentValue) => previousValue + currentValue.data.length + 5, 0));
let offset = 0;
for (const m of envelopes) {
offset += encodeEnvelope(m, target, offset);
}
return new Uint8Array(target);
}
function encodeEnvelope(envelope, target, byteOffset) {
const len = envelope.data.length + 5;
const bytes = new Uint8Array(target, byteOffset, len);
bytes[0] = envelope.flags; // first byte is flags
for (let l = envelope.data.length, i = 4; i > 0; i--) {
bytes[i] = l % 256; // 4 bytes message length
l >>>= 8;
}
bytes.set(envelope.data, 5);
return len;
}

@@ -20,2 +20,12 @@ // Copyright 2021-2022 Buf Technologies, Inc.

import { createEnvelopeReadableStream, encodeEnvelopes } from "./envelope.js";
/**
* Create a Transport for the gRPC-web protocol. The protocol encodes
* trailers in the response body and makes unary and server-streaming
* methods available to web browsers. It uses the fetch API to make
* HTTP requests.
*
* Note that this transport does not implement the grpc-web-text format,
* which applies base64 encoding to the request and response bodies to
* support reading streaming responses from an XMLHttpRequest.
*/
export function createGrpcWebTransport(options) {

@@ -44,3 +54,3 @@ const transportOptions = options;

const response = await fetch(unaryRequest.url, Object.assign(Object.assign({}, unaryRequest.init), { headers: unaryRequest.header, signal: unaryRequest.signal, body: createGrpcWebRequestBody(unaryRequest.message, options.binaryOptions) }));
const headError = (_c = (_b = (_a = extractHttpStatusError(response)) !== null && _a !== void 0 ? _a : extractContentTypeError(response.headers)) !== null && _b !== void 0 ? _b : extractDetailsError(response.headers, transportOptions.errorDetailRegistry)) !== null && _c !== void 0 ? _c : extractHeadersError(response.headers);
const headError = (_c = (_b = (_a = extractHttpStatusError(response)) !== null && _a !== void 0 ? _a : extractContentTypeError(response.headers)) !== null && _b !== void 0 ? _b : extractDetailsError(response.headers)) !== null && _c !== void 0 ? _c : extractHeadersError(response.headers);
if (headError) {

@@ -61,3 +71,3 @@ throw headError;

// that only contains error trailers.
parseGrpcWebTrailerAndExtractError(messageOrTrailerResult.value.data, transportOptions.errorDetailRegistry);
parseGrpcWebTrailerAndExtractError(messageOrTrailerResult.value.data);
// At this point, we received trailers only, but the trailers did

@@ -75,3 +85,3 @@ // not have an error status code.

}
const trailer = parseGrpcWebTrailerAndExtractError(trailerResult.value.data, transportOptions.errorDetailRegistry);
const trailer = parseGrpcWebTrailerAndExtractError(trailerResult.value.data);
const eofResult = await reader.read();

@@ -90,3 +100,3 @@ if (!eofResult.done) {

catch (e) {
throw connectErrorFromReason(e);
throw connectErrorFromReason(e, Code.Internal);
}

@@ -114,3 +124,3 @@ },

const response = await fetch(unaryRequest.url, Object.assign(Object.assign({}, unaryRequest.init), { headers: unaryRequest.header, signal: unaryRequest.signal, body: createGrpcWebRequestBody(unaryRequest.message, options.binaryOptions) }));
const err = (_c = (_b = (_a = extractHttpStatusError(response)) !== null && _a !== void 0 ? _a : extractContentTypeError(response.headers)) !== null && _b !== void 0 ? _b : extractDetailsError(response.headers, transportOptions.errorDetailRegistry)) !== null && _c !== void 0 ? _c : extractHeadersError(response.headers);
const err = (_c = (_b = (_a = extractHttpStatusError(response)) !== null && _a !== void 0 ? _a : extractContentTypeError(response.headers)) !== null && _b !== void 0 ? _b : extractDetailsError(response.headers)) !== null && _c !== void 0 ? _c : extractHeadersError(response.headers);
if (err) {

@@ -144,3 +154,3 @@ throw err;

endStreamReceived = true;
const trailer = parseGrpcWebTrailerAndExtractError(result.value.data, transportOptions.errorDetailRegistry);
const trailer = parseGrpcWebTrailerAndExtractError(result.value.data);
trailer.forEach((value, key) => this.trailer.append(key, value));

@@ -162,3 +172,3 @@ return {

catch (e) {
throw connectErrorFromReason(e);
throw connectErrorFromReason(e, Code.Internal);
}

@@ -233,3 +243,3 @@ },

}
function extractDetailsError(header, typeRegistry) {
function extractDetailsError(header) {
const grpcStatusDetailsBin = header.get("grpc-status-details-bin");

@@ -246,21 +256,7 @@ if (grpcStatusDetailsBin == null) {

const error = new ConnectError(status.message, status.code, undefined, header);
// TODO deduplicate with similar logic in ConnectError
for (const any of status.details) {
const typeName = any.typeUrl.substring(any.typeUrl.lastIndexOf("/") + 1);
if (!typeRegistry) {
error.rawDetails.push(any);
continue;
}
const messageType = typeRegistry.findMessage(typeName);
if (messageType) {
const message = new messageType();
if (any.unpackTo(message)) {
error.details.push(message);
}
}
}
error.rawDetails.push(...status.details);
return error;
}
catch (e) {
const ce = connectErrorFromReason(e);
const ce = connectErrorFromReason(e, Code.Internal);
header.forEach((value, key) => ce.metadata.append(key, value));

@@ -270,6 +266,6 @@ return ce;

}
function parseGrpcWebTrailerAndExtractError(data, errorDetailRegistry) {
function parseGrpcWebTrailerAndExtractError(data) {
var _a;
const trailer = parseGrpcWebTrailer(data);
const err = (_a = extractDetailsError(trailer, errorDetailRegistry)) !== null && _a !== void 0 ? _a : extractHeadersError(trailer);
const err = (_a = extractDetailsError(trailer)) !== null && _a !== void 0 ? _a : extractHeadersError(trailer);
if (err) {

@@ -276,0 +272,0 @@ throw err;

@@ -18,7 +18,9 @@ // Copyright 2021-2022 Buf Technologies, Inc.

/**
* Encode a single binary header value according to the gRPC
* specification.
* Encode a single binary header value according to the Connect
* and gRPC specifications.
*
* Binary headers names end with `-bin`, and can contain arbitrary
* base64-encoded binary data.
* This function accepts raw binary data from a buffer, a string
* with UTF-8 text, or a protobuf message. It encodes the input
* with base64 and returns a string that can be used for a header
* whose name ends with `-bin`.
*/

@@ -30,2 +32,5 @@ export function encodeBinaryHeader(value) {

}
else if (typeof value == "string") {
bytes = new TextEncoder().encode(value);
}
else {

@@ -32,0 +37,0 @@ bytes = value instanceof Uint8Array ? value : new Uint8Array(value);

@@ -17,9 +17,8 @@ // Copyright 2021-2022 Buf Technologies, Inc.

export { makeAnyClient } from "./any-client.js";
export { createConnectTransport, } from "./connect-transport.js";
export { createGrpcWebTransport, } from "./grpc-web-transport.js";
export { runUnary, runServerStream, } from "./interceptor.js";
export {} from "./transport.js";
export { ConnectError, connectErrorFromJson } from "./connect-error.js";
export { ConnectError, connectErrorDetails, connectErrorFromReason, connectErrorFromJson, } from "./connect-error.js";
export { Code, codeFromString, codeToString } from "./code.js";
export { createConnectTransport } from "./connect-transport.js";
export { createGrpcWebTransport } from "./grpc-web-transport.js";
export { decodeBinaryHeader, encodeBinaryHeader, mergeHeaders, } from "./http-headers.js";
export { createEnvelopeReadableStream, encodeEnvelopes, } from "./envelope.js";
export { encodeBinaryHeader, decodeBinaryHeader, mergeHeaders, } from "./http-headers.js";
export { createEnvelopeReadableStream } from "./envelope.js";

@@ -14,3 +14,17 @@ // Copyright 2021-2022 Buf Technologies, Inc.

// limitations under the License.
// TODO document
/**
* applyInterceptors takes the given UnaryFn or ServerStreamingFn, and wraps
* it with each of the given interceptors, returning a new UnaryFn or
* ServerStreamingFn.
*/
function applyInterceptors(next, interceptors) {
return interceptors
.concat()
.reverse()
.reduce((n, i) => i(n), next);
}
/**
* Runs a unary method with the given interceptors. Note that this function
* is only used when implementing a Transport.
*/
export function runUnary(req, next, interceptors) {

@@ -22,3 +36,6 @@ if (interceptors) {

}
// TODO document
/**
* Runs a server-streaming method with the given interceptors. Note that this
* function is only used when implementing a Transport.
*/
export function runServerStream(req, next, interceptors) {

@@ -30,7 +47,1 @@ if (interceptors) {

}
function applyInterceptors(next, interceptors) {
return interceptors
.concat()
.reverse()
.reduce((n, i) => i(n), next);
}
import type { MethodInfoServerStreaming, MethodInfoUnary, PartialMessage, ServiceType } from "@bufbuild/protobuf";
import type { ConnectError } from "./connect-error.js";
import type { CallOptions, Transport } from "./transport.js";
import type { Transport } from "./transport.js";
import type { CallOptions } from "./call-options.js";
/**

@@ -5,0 +6,0 @@ * CallbackClient is a simple client that supports unary and server

import { Code } from "./code.js";
import { AnyMessage, IMessageTypeRegistry, JsonValue } from "@bufbuild/protobuf";
import { AnyMessage, IMessageTypeRegistry, JsonValue, Message, MessageType } from "@bufbuild/protobuf";
import { Any } from "@bufbuild/protobuf";

@@ -10,7 +10,8 @@ /**

* Because developer tools typically show just the error message, we prefix
* it with the status code.
* it with the status code, so that the most important information is always
* visible immediately.
*
* Error details are wrapped with google.protobuf.Any on the wire, so that
* a server or middleware can attach arbitrary data to an error. We
* automatically unwrap the details for you.
* a server or middleware can attach arbitrary data to an error. Use the
* function connectErrorDetails() to retrieve the details.
*/

@@ -23,6 +24,2 @@ export declare class ConnectError extends Error {

/**
* Optional collection of arbitrary Protobuf messages.
*/
readonly details: AnyMessage[];
/**
* A union of response headers and trailers associated with this error.

@@ -32,8 +29,6 @@ */

/**
* When an error is parsed from the wire, details are unwrapped
* automatically from google.protobuf.Any, but we can only do so if you
* provide the message types in a type registry. If a message type is not
* given in a type registry, the unwrapped details are available here.
* When an error is parsed from the wire, error details are stored in
* this property. They can be retrieved using connectErrorDetails().
*/
readonly rawDetails: RawDetail[];
readonly rawDetails: RawErrorDetail[];
/**

@@ -50,7 +45,18 @@ * The error message, but without a status code in front.

/**
* A raw detail is a google.protobuf.Any, or it's JSON representation.
* Retrieve error details from a ConnectError. On the wire, error details are
* wrapped with google.protobuf.Any, so that a server or middleware can attach
* arbitrary data to an error. This function decodes the array of error details
* from the ConnectError object, and returns an array with the decoded
* messages. Any decoding errors are ignored, and the detail will simply be
* omitted from the list.
*/
export declare function connectErrorDetails<T extends Message<T>>(error: ConnectError, type: MessageType<T>): T[];
export declare function connectErrorDetails(error: ConnectError, type: MessageType, ...moreTypes: MessageType[]): AnyMessage[];
export declare function connectErrorDetails(error: ConnectError, registry: IMessageTypeRegistry): AnyMessage[];
/**
* A raw error detail is a google.protobuf.Any, or it's JSON representation.
* This type is used for error details that we could not unwrap because
* we are missing type information.
*/
export declare type RawDetail = Any | {
export declare type RawErrorDetail = Any | {
"@type": string;

@@ -60,16 +66,17 @@ [key: string]: JsonValue;

/**
* Parse an error from a JSON value.
* Parse a Connect error from a JSON value.
* Will return a ConnectError, but throw one in case the JSON is malformed.
*/
export declare function connectErrorFromJson(jsonValue: JsonValue, options?: {
typeRegistry?: IMessageTypeRegistry;
metadata?: HeadersInit;
}): ConnectError;
export declare function connectErrorFromJson(jsonValue: JsonValue, metadata?: HeadersInit): ConnectError;
/**
* Convert any value - typically a caught error into a ConnectError.
* If the value is already a ConnectError, return it as is.
* If the value is an AbortError from the fetch API, return code Canceled.
* For other values, return code Internal.
* Convert any value - typically a caught error into a ConnectError,
* following these rules:
* - If the value is already a ConnectError, return it as is.
* - If the value is an AbortError from the fetch API, return the message
* of the AbortError with code Canceled.
* - For other Errors, return the Errors message with code Unknown by default.
* - For other values, return the values String representation as a message,
* with the code Unknown by default.
*/
export declare function connectErrorFromReason(reason: unknown): ConnectError;
export declare function connectErrorFromReason(reason: unknown, code?: Code): ConnectError;
/**

@@ -76,0 +83,0 @@ * newParseError() is an internal utility to create a ConnectError while

@@ -1,5 +0,10 @@

import { BinaryReadOptions, BinaryWriteOptions, IMessageTypeRegistry, JsonReadOptions, JsonWriteOptions } from "@bufbuild/protobuf";
import { BinaryReadOptions, BinaryWriteOptions, JsonReadOptions, JsonWriteOptions } from "@bufbuild/protobuf";
import type { Transport } from "./transport.js";
import type { Interceptor } from "./interceptor.js";
interface ConnectTransportOptions {
/**
* Options used to configure the Connect transport.
*
* See createConnectTransport().
*/
export interface ConnectTransportOptions {
/**

@@ -26,4 +31,8 @@ * Base URI for all HTTP requests.

credentials?: RequestCredentials;
errorDetailRegistry?: IMessageTypeRegistry;
/**
* Interceptors that should be applied to all calls running through
* this transport. See the Interceptor type for details.
*/
interceptors?: Interceptor[];
/**
* Options for the JSON format.

@@ -36,5 +45,8 @@ */

binaryOptions?: Partial<BinaryReadOptions & BinaryWriteOptions>;
interceptors?: Interceptor[];
}
/**
* Create a Transport for the Connect protocol, which makes unary and
* server-streaming methods available to web browsers. It uses the fetch
* API to make HTTP requests.
*/
export declare function createConnectTransport(options: ConnectTransportOptions): Transport;
export {};
/**
* Enveloped-Message
* Represents an Enveloped-Message of the Connect protocol.
* https://connect.build/docs/protocol#streaming-rpcs
*/

@@ -14,3 +15,2 @@ export interface EnvelopedMessage {

}
export declare function encodeEnvelopes(...envelopes: EnvelopedMessage[]): Uint8Array;
/**

@@ -23,1 +23,2 @@ * Create a ReadableStream of enveloped messages from a ReadableStream of bytes.

export declare function createEnvelopeReadableStream(stream: ReadableStream<Uint8Array>): ReadableStream<EnvelopedMessage>;
export declare function encodeEnvelopes(...envelopes: EnvelopedMessage[]): Uint8Array;

@@ -1,5 +0,10 @@

import type { BinaryReadOptions, BinaryWriteOptions, IMessageTypeRegistry } from "@bufbuild/protobuf";
import type { BinaryReadOptions, BinaryWriteOptions } from "@bufbuild/protobuf";
import type { Transport } from "./transport.js";
import { Interceptor } from "./interceptor.js";
interface GrpcWebTransportOptions {
/**
* Options used to configure the gRPC-web transport.
*
* See createGrpcWebTransport().
*/
export interface GrpcWebTransportOptions {
/**

@@ -17,2 +22,7 @@ * Base URI for all HTTP requests.

/**
* Interceptors that should be applied to all calls running through
* this transport. See the Interceptor type for details.
*/
interceptors?: Interceptor[];
/**
* Controls what the fetch client will do with credentials, such as

@@ -23,3 +33,2 @@ * Cookies. The default value is "same-origin". For reference, see

credentials?: RequestCredentials;
errorDetailRegistry?: IMessageTypeRegistry;
/**

@@ -29,5 +38,13 @@ * Options for the binary wire format.

binaryOptions?: Partial<BinaryReadOptions & BinaryWriteOptions>;
interceptors?: Interceptor[];
}
/**
* Create a Transport for the gRPC-web protocol. The protocol encodes
* trailers in the response body and makes unary and server-streaming
* methods available to web browsers. It uses the fetch API to make
* HTTP requests.
*
* Note that this transport does not implement the grpc-web-text format,
* which applies base64 encoding to the request and response bodies to
* support reading streaming responses from an XMLHttpRequest.
*/
export declare function createGrpcWebTransport(options: GrpcWebTransportOptions): Transport;
export {};
import type { BinaryReadOptions, MessageType } from "@bufbuild/protobuf";
import { Message } from "@bufbuild/protobuf";
/**
* Encode a single binary header value according to the gRPC
* specification.
* Encode a single binary header value according to the Connect
* and gRPC specifications.
*
* Binary headers names end with `-bin`, and can contain arbitrary
* base64-encoded binary data.
* This function accepts raw binary data from a buffer, a string
* with UTF-8 text, or a protobuf message. It encodes the input
* with base64 and returns a string that can be used for a header
* whose name ends with `-bin`.
*/
export declare function encodeBinaryHeader(value: Uint8Array | ArrayBufferLike | Message): string;
export declare function encodeBinaryHeader(value: Uint8Array | ArrayBufferLike | Message | string): string;
/**
* Decode a single binary header value according to the gRPC
* specification.
* Decode a single binary header value according to the Connect
* and gRPC specifications.
*
* Binary headers names end with `-bin`, and can contain arbitrary
* base64-encoded binary data.
* This function returns the raw binary data from a header whose
* name ends with `-bin`. If given a message type in the second
* argument, it deserializes a protobuf message. To decode a value
* that contains unicode text, pass the raw binary data returned
* from this function through TextDecoder.decode.
*

@@ -23,3 +28,3 @@ * Note that duplicate header names may have their values joined

* If this function detects invalid base-64 encoding, or invalid
* binary message data, it throws a ConnectError with status
* binary message data, it throws a ConnectError with code
* DataLoss.

@@ -26,0 +31,0 @@ */

export { createCallbackClient, CallbackClient } from "./callback-client.js";
export { createPromiseClient, PromiseClient } from "./promise-client.js";
export { makeAnyClient, AnyClient } from "./any-client.js";
export type { CallOptions } from "./call-options.js";
export { createConnectTransport, ConnectTransportOptions, } from "./connect-transport.js";
export { createGrpcWebTransport, GrpcWebTransportOptions, } from "./grpc-web-transport.js";
export type { Transport } from "./transport.js";
export { Interceptor, UnaryRequest, UnaryResponse, StreamResponse, runUnary, runServerStream, } from "./interceptor.js";
export { Transport, CallOptions } from "./transport.js";
export { ConnectError, connectErrorFromJson } from "./connect-error.js";
export { ConnectError, connectErrorDetails, connectErrorFromReason, connectErrorFromJson, } from "./connect-error.js";
export { Code, codeFromString, codeToString } from "./code.js";
export { createConnectTransport } from "./connect-transport.js";
export { createGrpcWebTransport } from "./grpc-web-transport.js";
export { decodeBinaryHeader, encodeBinaryHeader, mergeHeaders, } from "./http-headers.js";
export { createEnvelopeReadableStream, EnvelopedMessage, encodeEnvelopes, } from "./envelope.js";
export { encodeBinaryHeader, decodeBinaryHeader, mergeHeaders, } from "./http-headers.js";
export { createEnvelopeReadableStream } from "./envelope.js";
import type { AnyMessage, Message, MethodInfo, ServiceType } from "@bufbuild/protobuf";
/**
* An interceptor can add logic to clients, similar to the decorators
* or middleware you may have seen in other libraries. Interceptors may
* mutate the request and response, catch errors and retry/recover, emit
* logs, or do nearly everything else.
*
* For a simple example, the following interceptor logs all requests:
*
* ```ts
* const logger: Interceptor = (next) => async (req) => {
* console.log(`sending message to ${req.url}`);
* return await next(req);
* };
* ```
*
* You can think of interceptors like a layered onion. A request initiated
* by a client goes through the outermost layer first. In the center, the
* actual HTTP request is run by the transport. The response then comes back
* through all layers and is returned to the client.
*
* To implement that layering, Interceptors are functions that wrap a call
* invocation. In an array of interceptors, the interceptor at the end of
* the array is applied first.
*/
export declare type Interceptor = (next: AnyFn) => AnyFn;
/**
* Interceptors apply to both UnaryFn and ServerStreamFn. In order to handle
* both in a single interceptor, interceptors operate on a AnyFn. Note that
* you can inspect the `stream` property of request and response to identify
* whether you are working with a stream.
*/
declare type AnyFn = (req: UnaryRequest) => Promise<UnaryResponse | StreamResponse>;
/**
* UnaryFn represents the client-side invocation of a unary RPC - a method
* that takes a single input message, and responds with a single output
* message.
* A Transport implements such a function, and makes it available to
* interceptors.
*/
declare type UnaryFn<I extends Message<I> = AnyMessage, O extends Message<O> = AnyMessage> = (req: UnaryRequest<I>) => Promise<UnaryResponse<O>>;
/**
* ServerStreamFn represents the client-side invocation of a server-streaming
* RPC - a method that takes one input message, and responds with zero or
* more output messages.
* A Transport implements such a function, and makes it available to
* interceptors.
*/
declare type ServerStreamFn<I extends Message<I> = AnyMessage, O extends Message<O> = AnyMessage> = (req: UnaryRequest<I>) => Promise<StreamResponse<O>>;
/**
* UnaryRequest is used in interceptors to represent a request with a
* single input message.
*/
export interface UnaryRequest<I extends Message<I> = AnyMessage> {
/**
* The `stream` property discriminates between UnaryRequest and
* other request types that may be added to this API in the future.
*/
readonly stream: false;
/**
* Metadata related to the service that is being called.
*/
readonly service: ServiceType;
/**
* Metadata related to the service method that is being called.
*/
readonly method: MethodInfo<I, AnyMessage>;
/**
* The URL the request is going to hit.
*/
readonly url: string;
/**
* Optional parameters to the fetch API.
*/
readonly init: Exclude<RequestInit, "body" | "headers" | "signal">;
/**
* The AbortSignal for the current call.
*/
readonly signal: AbortSignal;
/**
* Headers that will be sent along with the request.
*/
readonly header: Headers;
/**
* The input message that will be transmitted.
*/
readonly message: I;
}
/**
* UnaryResponse is used in interceptors to represent a response with
* a single output message.
*/
export interface UnaryResponse<O extends Message<O> = AnyMessage> {
/**
* The `stream` property discriminates between UnaryResponse and
* StreamResponse.
*/
readonly stream: false;
/**
* Metadata related to the service that is being called.
*/
readonly service: ServiceType;
/**
* Metadata related to the service method that is being called.
*/
readonly method: MethodInfo<AnyMessage, O>;
/**
* Headers received from the response.
*/
readonly header: Headers;
/**
* The received output message.
*/
readonly message: O;
/**
* Trailers received from the response.
*/
readonly trailer: Headers;
}
/**
* StreamResponse is used in interceptors to represent a response with
* zero or more output messages.
*/
export interface StreamResponse<O extends Message<O> = AnyMessage> {
/**
* The `stream` property discriminates between UnaryResponse and
* StreamResponse.
*/
readonly stream: true;
/**
* Metadata related to the service that is being called.
*/
readonly service: ServiceType;
/**
* Metadata related to the service method that is being called.
*/
readonly method: MethodInfo<AnyMessage, O>;
/**
* Headers received from the response.
*/
readonly header: Headers;
/**
* Reads a single output message from the response. The return value is a
* promise, which fulfills/rejects with a result depending on the state of
* the stream.
*
* The behavior is as follows:
* 1. If a message was read successfully, the promise is fulfilled with an
* object of the form `{value: O, done: false}`.
* 2. If the end of the stream was reached, the promise is fulfilled with
* `{value: undefined, done: true}`.
* 3. If an error occurred, the response is rejected with this error.
*/
read(): Promise<ReadableStreamDefaultReadResult<O>>;
/**
* Trailers received from the response.
* Note that trailers are only populated if the entirety of the stream was
* read.
*/
readonly trailer: Headers;
}
/**
* Runs a unary method with the given interceptors. Note that this function
* is only used when implementing a Transport.
*/
export declare function runUnary<I extends Message<I>, O extends Message<O>>(req: UnaryRequest<I>, next: UnaryFn<I, O>, interceptors?: Interceptor[]): Promise<UnaryResponse<O>>;
/**
* Runs a server-streaming method with the given interceptors. Note that this
* function is only used when implementing a Transport.
*/
export declare function runServerStream<I extends Message<I>, O extends Message<O>>(req: UnaryRequest<I>, next: ServerStreamFn<I, O>, interceptors?: Interceptor[]): Promise<StreamResponse<O>>;
declare type UnaryFn<I extends Message<I> = AnyMessage, O extends Message<O> = AnyMessage> = (req: UnaryRequest<I>) => Promise<UnaryResponse<O>>;
declare type ServerStreamFn<I extends Message<I> = AnyMessage, O extends Message<O> = AnyMessage> = (req: UnaryRequest<I>) => Promise<StreamResponse<O>>;
export {};
import type { MethodInfoServerStreaming, MethodInfoUnary, PartialMessage, ServiceType } from "@bufbuild/protobuf";
import type { CallOptions, Transport } from "./transport.js";
import type { Transport } from "./transport.js";
import type { CallOptions } from "./call-options.js";
/**

@@ -4,0 +5,0 @@ * PromiseClient is a simple client that supports unary and server-streaming

@@ -9,31 +9,12 @@ import type { AnyMessage, Message, MethodInfo, PartialMessage, ServiceType } from "@bufbuild/protobuf";

export interface Transport {
unary<I extends Message<I> = AnyMessage, O extends Message<O> = AnyMessage>(service: ServiceType, method: MethodInfo<I, O>, signal: AbortSignal | undefined, timeoutMs: number | undefined, header: HeadersInit | undefined, message: PartialMessage<I>): Promise<UnaryResponse<O>>;
serverStream<I extends Message<I> = AnyMessage, O extends Message<O> = AnyMessage>(service: ServiceType, method: MethodInfo<I, O>, signal: AbortSignal | undefined, timeoutMs: number | undefined, header: HeadersInit | undefined, message: PartialMessage<I>): Promise<StreamResponse<O>>;
}
/**
* Options for a call. Every client should accept CallOptions as optional
* argument in its RPC methods.
*/
export interface CallOptions {
/**
* Timeout in milliseconds.
* Call a unary RPC - a method that takes a single input message, and
* responds with a single output message.
*/
timeoutMs?: number;
unary<I extends Message<I> = AnyMessage, O extends Message<O> = AnyMessage>(service: ServiceType, method: MethodInfo<I, O>, signal: AbortSignal | undefined, timeoutMs: number | undefined, header: HeadersInit | undefined, message: PartialMessage<I>): Promise<UnaryResponse<O>>;
/**
* Custom headers to send with the request.
* Call a server-streaming RPC - a method that takes a single input message,
* and responds with zero or more output messages.
*/
headers?: HeadersInit;
/**
* An optional AbortSignal to cancel the call.
* If cancelled, an error with Code.Canceled is raised.
*/
signal?: AbortSignal;
/**
* Called when response headers are received.
*/
onHeader?(headers: Headers): void;
/**
* Called when response trailers are received.
*/
onTrailer?(trailers: Headers): void;
serverStream<I extends Message<I> = AnyMessage, O extends Message<O> = AnyMessage>(service: ServiceType, method: MethodInfo<I, O>, signal: AbortSignal | undefined, timeoutMs: number | undefined, header: HeadersInit | undefined, message: PartialMessage<I>): Promise<StreamResponse<O>>;
}
{
"name": "@bufbuild/connect-web",
"version": "0.0.9",
"version": "0.0.10",
"license": "Apache-2.0",

@@ -24,4 +24,5 @@ "repository": {

},
"main": "./dist/esm/index.js",
"peerDependencies": {
"@bufbuild/protobuf": "^0.0.7"
"@bufbuild/protobuf": "^0.0.9"
},

@@ -28,0 +29,0 @@ "devDependencies": {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc