initial commit of actions

This commit is contained in:
Dominik Polakovics Polakovics 2026-01-31 18:56:04 +01:00
commit 949ece5785
44660 changed files with 12034344 additions and 0 deletions

View file

@ -0,0 +1,174 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

View file

@ -0,0 +1,21 @@
@protobuf-ts/runtime-rpc
========================
Runtime library for RPC clients generated by [protobuf-ts](https://github.com/timostamm/protobuf-ts/).
Install this plugin if you want to create your own RPC transport:
```shell script
# with npm:
npm install @protobuf-ts/runtime-rpc
# with yarn:
yarn add @protobuf-ts/runtime-rpc
```
Or use one of the transports built with this package, for example Twirp via
[@protobuf-ts/twirp-transport](https://www.npmjs.com/package/@protobuf-ts/twirp-transport)
or gRPC web via [@protobuf-ts/grpcweb-transport](https://www.npmjs.com/package/@protobuf-ts/grpcweb-transport).
To learn more about the types provided by this package, please read the
[MANUAL](https://github.com/timostamm/protobuf-ts/blob/master/MANUAL.md#rpc-support).

View file

@ -0,0 +1,50 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClientStreamingCall = void 0;
/**
* A client streaming RPC call. This means that the clients sends 0, 1, or
* more messages to the server, and the server replies with exactly one
* message.
*/
class ClientStreamingCall {
constructor(method, requestHeaders, request, headers, response, status, trailers) {
this.method = method;
this.requestHeaders = requestHeaders;
this.requests = request;
this.headers = headers;
this.response = response;
this.status = status;
this.trailers = trailers;
}
/**
* Instead of awaiting the response status and trailers, you can
* just as well await this call itself to receive the server outcome.
* Note that it may still be valid to send more request messages.
*/
then(onfulfilled, onrejected) {
return this.promiseFinished().then(value => onfulfilled ? Promise.resolve(onfulfilled(value)) : value, reason => onrejected ? Promise.resolve(onrejected(reason)) : Promise.reject(reason));
}
promiseFinished() {
return __awaiter(this, void 0, void 0, function* () {
let [headers, response, status, trailers] = yield Promise.all([this.headers, this.response, this.status, this.trailers]);
return {
method: this.method,
requestHeaders: this.requestHeaders,
headers,
response,
status,
trailers
};
});
}
}
exports.ClientStreamingCall = ClientStreamingCall;

View file

@ -0,0 +1,86 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Deferred = exports.DeferredState = void 0;
var DeferredState;
(function (DeferredState) {
DeferredState[DeferredState["PENDING"] = 0] = "PENDING";
DeferredState[DeferredState["REJECTED"] = 1] = "REJECTED";
DeferredState[DeferredState["RESOLVED"] = 2] = "RESOLVED";
})(DeferredState = exports.DeferredState || (exports.DeferredState = {}));
/**
* A deferred promise. This is a "controller" for a promise, which lets you
* pass a promise around and reject or resolve it from the outside.
*
* Warning: This class is to be used with care. Using it can make code very
* difficult to read. It is intended for use in library code that exposes
* promises, not for regular business logic.
*/
class Deferred {
/**
* @param preventUnhandledRejectionWarning - prevents the warning
* "Unhandled Promise rejection" by adding a noop rejection handler.
* Working with calls returned from the runtime-rpc package in an
* async function usually means awaiting one call property after
* the other. This means that the "status" is not being awaited when
* an earlier await for the "headers" is rejected. This causes the
* "unhandled promise reject" warning. A more correct behaviour for
* calls might be to become aware whether at least one of the
* promises is handled and swallow the rejection warning for the
* others.
*/
constructor(preventUnhandledRejectionWarning = true) {
this._state = DeferredState.PENDING;
this._promise = new Promise((resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
});
if (preventUnhandledRejectionWarning) {
this._promise.catch(_ => { });
}
}
/**
* Get the current state of the promise.
*/
get state() {
return this._state;
}
/**
* Get the deferred promise.
*/
get promise() {
return this._promise;
}
/**
* Resolve the promise. Throws if the promise is already resolved or rejected.
*/
resolve(value) {
if (this.state !== DeferredState.PENDING)
throw new Error(`cannot resolve ${DeferredState[this.state].toLowerCase()}`);
this._resolve(value);
this._state = DeferredState.RESOLVED;
}
/**
* Reject the promise. Throws if the promise is already resolved or rejected.
*/
reject(reason) {
if (this.state !== DeferredState.PENDING)
throw new Error(`cannot reject ${DeferredState[this.state].toLowerCase()}`);
this._reject(reason);
this._state = DeferredState.REJECTED;
}
/**
* Resolve the promise. Ignore if not pending.
*/
resolvePending(val) {
if (this._state === DeferredState.PENDING)
this.resolve(val);
}
/**
* Reject the promise. Ignore if not pending.
*/
rejectPending(reason) {
if (this._state === DeferredState.PENDING)
this.reject(reason);
}
}
exports.Deferred = Deferred;

View file

@ -0,0 +1,49 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DuplexStreamingCall = void 0;
/**
* A duplex streaming RPC call. This means that the clients sends an
* arbitrary amount of messages to the server, while at the same time,
* the server sends an arbitrary amount of messages to the client.
*/
class DuplexStreamingCall {
constructor(method, requestHeaders, request, headers, response, status, trailers) {
this.method = method;
this.requestHeaders = requestHeaders;
this.requests = request;
this.headers = headers;
this.responses = response;
this.status = status;
this.trailers = trailers;
}
/**
* Instead of awaiting the response status and trailers, you can
* just as well await this call itself to receive the server outcome.
* Note that it may still be valid to send more request messages.
*/
then(onfulfilled, onrejected) {
return this.promiseFinished().then(value => onfulfilled ? Promise.resolve(onfulfilled(value)) : value, reason => onrejected ? Promise.resolve(onrejected(reason)) : Promise.reject(reason));
}
promiseFinished() {
return __awaiter(this, void 0, void 0, function* () {
let [headers, status, trailers] = yield Promise.all([this.headers, this.status, this.trailers]);
return {
method: this.method,
requestHeaders: this.requestHeaders,
headers,
status,
trailers,
};
});
}
}
exports.DuplexStreamingCall = DuplexStreamingCall;

View file

@ -0,0 +1,38 @@
"use strict";
// Public API of the rpc runtime.
// Note: we do not use `export * from ...` to help tree shakers,
// webpack verbose output hints that this should be useful
Object.defineProperty(exports, "__esModule", { value: true });
var service_type_1 = require("./service-type");
Object.defineProperty(exports, "ServiceType", { enumerable: true, get: function () { return service_type_1.ServiceType; } });
var reflection_info_1 = require("./reflection-info");
Object.defineProperty(exports, "readMethodOptions", { enumerable: true, get: function () { return reflection_info_1.readMethodOptions; } });
Object.defineProperty(exports, "readMethodOption", { enumerable: true, get: function () { return reflection_info_1.readMethodOption; } });
Object.defineProperty(exports, "readServiceOption", { enumerable: true, get: function () { return reflection_info_1.readServiceOption; } });
var rpc_error_1 = require("./rpc-error");
Object.defineProperty(exports, "RpcError", { enumerable: true, get: function () { return rpc_error_1.RpcError; } });
var rpc_options_1 = require("./rpc-options");
Object.defineProperty(exports, "mergeRpcOptions", { enumerable: true, get: function () { return rpc_options_1.mergeRpcOptions; } });
var rpc_output_stream_1 = require("./rpc-output-stream");
Object.defineProperty(exports, "RpcOutputStreamController", { enumerable: true, get: function () { return rpc_output_stream_1.RpcOutputStreamController; } });
var test_transport_1 = require("./test-transport");
Object.defineProperty(exports, "TestTransport", { enumerable: true, get: function () { return test_transport_1.TestTransport; } });
var deferred_1 = require("./deferred");
Object.defineProperty(exports, "Deferred", { enumerable: true, get: function () { return deferred_1.Deferred; } });
Object.defineProperty(exports, "DeferredState", { enumerable: true, get: function () { return deferred_1.DeferredState; } });
var duplex_streaming_call_1 = require("./duplex-streaming-call");
Object.defineProperty(exports, "DuplexStreamingCall", { enumerable: true, get: function () { return duplex_streaming_call_1.DuplexStreamingCall; } });
var client_streaming_call_1 = require("./client-streaming-call");
Object.defineProperty(exports, "ClientStreamingCall", { enumerable: true, get: function () { return client_streaming_call_1.ClientStreamingCall; } });
var server_streaming_call_1 = require("./server-streaming-call");
Object.defineProperty(exports, "ServerStreamingCall", { enumerable: true, get: function () { return server_streaming_call_1.ServerStreamingCall; } });
var unary_call_1 = require("./unary-call");
Object.defineProperty(exports, "UnaryCall", { enumerable: true, get: function () { return unary_call_1.UnaryCall; } });
var rpc_interceptor_1 = require("./rpc-interceptor");
Object.defineProperty(exports, "stackIntercept", { enumerable: true, get: function () { return rpc_interceptor_1.stackIntercept; } });
Object.defineProperty(exports, "stackDuplexStreamingInterceptors", { enumerable: true, get: function () { return rpc_interceptor_1.stackDuplexStreamingInterceptors; } });
Object.defineProperty(exports, "stackClientStreamingInterceptors", { enumerable: true, get: function () { return rpc_interceptor_1.stackClientStreamingInterceptors; } });
Object.defineProperty(exports, "stackServerStreamingInterceptors", { enumerable: true, get: function () { return rpc_interceptor_1.stackServerStreamingInterceptors; } });
Object.defineProperty(exports, "stackUnaryInterceptors", { enumerable: true, get: function () { return rpc_interceptor_1.stackUnaryInterceptors; } });
var server_call_context_1 = require("./server-call-context");
Object.defineProperty(exports, "ServerCallContextController", { enumerable: true, get: function () { return server_call_context_1.ServerCallContextController; } });

View file

@ -0,0 +1,57 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.readServiceOption = exports.readMethodOption = exports.readMethodOptions = exports.normalizeMethodInfo = void 0;
const runtime_1 = require("@protobuf-ts/runtime");
/**
* Turns PartialMethodInfo into MethodInfo.
*/
function normalizeMethodInfo(method, service) {
var _a, _b, _c;
let m = method;
m.service = service;
m.localName = (_a = m.localName) !== null && _a !== void 0 ? _a : runtime_1.lowerCamelCase(m.name);
// noinspection PointlessBooleanExpressionJS
m.serverStreaming = !!m.serverStreaming;
// noinspection PointlessBooleanExpressionJS
m.clientStreaming = !!m.clientStreaming;
m.options = (_b = m.options) !== null && _b !== void 0 ? _b : {};
m.idempotency = (_c = m.idempotency) !== null && _c !== void 0 ? _c : undefined;
return m;
}
exports.normalizeMethodInfo = normalizeMethodInfo;
/**
* Read custom method options from a generated service client.
*
* @deprecated use readMethodOption()
*/
function readMethodOptions(service, methodName, extensionName, extensionType) {
var _a;
const options = (_a = service.methods.find((m, i) => m.localName === methodName || i === methodName)) === null || _a === void 0 ? void 0 : _a.options;
return options && options[extensionName] ? extensionType.fromJson(options[extensionName]) : undefined;
}
exports.readMethodOptions = readMethodOptions;
function readMethodOption(service, methodName, extensionName, extensionType) {
var _a;
const options = (_a = service.methods.find((m, i) => m.localName === methodName || i === methodName)) === null || _a === void 0 ? void 0 : _a.options;
if (!options) {
return undefined;
}
const optionVal = options[extensionName];
if (optionVal === undefined) {
return optionVal;
}
return extensionType ? extensionType.fromJson(optionVal) : optionVal;
}
exports.readMethodOption = readMethodOption;
function readServiceOption(service, extensionName, extensionType) {
const options = service.options;
if (!options) {
return undefined;
}
const optionVal = options[extensionName];
if (optionVal === undefined) {
return optionVal;
}
return extensionType ? extensionType.fromJson(optionVal) : optionVal;
}
exports.readServiceOption = readServiceOption;

View file

@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View file

@ -0,0 +1,36 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RpcError = void 0;
/**
* An error that occurred while calling a RPC method.
*/
class RpcError extends Error {
constructor(message, code = 'UNKNOWN', meta) {
super(message);
this.name = 'RpcError';
// see https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#example
Object.setPrototypeOf(this, new.target.prototype);
this.code = code;
this.meta = meta !== null && meta !== void 0 ? meta : {};
}
toString() {
const l = [this.name + ': ' + this.message];
if (this.code) {
l.push('');
l.push('Code: ' + this.code);
}
if (this.serviceName && this.methodName) {
l.push('Method: ' + this.serviceName + '/' + this.methodName);
}
let m = Object.entries(this.meta);
if (m.length) {
l.push('');
l.push('Meta:');
for (let [k, v] of m) {
l.push(` ${k}: ${v}`);
}
}
return l.join('\n');
}
}
exports.RpcError = RpcError;

View file

@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View file

@ -0,0 +1,74 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.stackDuplexStreamingInterceptors = exports.stackClientStreamingInterceptors = exports.stackServerStreamingInterceptors = exports.stackUnaryInterceptors = exports.stackIntercept = void 0;
const runtime_1 = require("@protobuf-ts/runtime");
/**
* Creates a "stack" of of all interceptors specified in the given `RpcOptions`.
* Used by generated client implementations.
* @internal
*/
function stackIntercept(kind, transport, method, options, input) {
var _a, _b, _c, _d;
if (kind == "unary") {
let tail = (mtd, inp, opt) => transport.unary(mtd, inp, opt);
for (const curr of ((_a = options.interceptors) !== null && _a !== void 0 ? _a : []).filter(i => i.interceptUnary).reverse()) {
const next = tail;
tail = (mtd, inp, opt) => curr.interceptUnary(next, mtd, inp, opt);
}
return tail(method, input, options);
}
if (kind == "serverStreaming") {
let tail = (mtd, inp, opt) => transport.serverStreaming(mtd, inp, opt);
for (const curr of ((_b = options.interceptors) !== null && _b !== void 0 ? _b : []).filter(i => i.interceptServerStreaming).reverse()) {
const next = tail;
tail = (mtd, inp, opt) => curr.interceptServerStreaming(next, mtd, inp, opt);
}
return tail(method, input, options);
}
if (kind == "clientStreaming") {
let tail = (mtd, opt) => transport.clientStreaming(mtd, opt);
for (const curr of ((_c = options.interceptors) !== null && _c !== void 0 ? _c : []).filter(i => i.interceptClientStreaming).reverse()) {
const next = tail;
tail = (mtd, opt) => curr.interceptClientStreaming(next, mtd, opt);
}
return tail(method, options);
}
if (kind == "duplex") {
let tail = (mtd, opt) => transport.duplex(mtd, opt);
for (const curr of ((_d = options.interceptors) !== null && _d !== void 0 ? _d : []).filter(i => i.interceptDuplex).reverse()) {
const next = tail;
tail = (mtd, opt) => curr.interceptDuplex(next, mtd, opt);
}
return tail(method, options);
}
runtime_1.assertNever(kind);
}
exports.stackIntercept = stackIntercept;
/**
* @deprecated replaced by `stackIntercept()`, still here to support older generated code
*/
function stackUnaryInterceptors(transport, method, input, options) {
return stackIntercept("unary", transport, method, options, input);
}
exports.stackUnaryInterceptors = stackUnaryInterceptors;
/**
* @deprecated replaced by `stackIntercept()`, still here to support older generated code
*/
function stackServerStreamingInterceptors(transport, method, input, options) {
return stackIntercept("serverStreaming", transport, method, options, input);
}
exports.stackServerStreamingInterceptors = stackServerStreamingInterceptors;
/**
* @deprecated replaced by `stackIntercept()`, still here to support older generated code
*/
function stackClientStreamingInterceptors(transport, method, options) {
return stackIntercept("clientStreaming", transport, method, options);
}
exports.stackClientStreamingInterceptors = stackClientStreamingInterceptors;
/**
* @deprecated replaced by `stackIntercept()`, still here to support older generated code
*/
function stackDuplexStreamingInterceptors(transport, method, options) {
return stackIntercept("duplex", transport, method, options);
}
exports.stackDuplexStreamingInterceptors = stackDuplexStreamingInterceptors;

View file

@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View file

@ -0,0 +1,66 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.mergeRpcOptions = void 0;
const runtime_1 = require("@protobuf-ts/runtime");
/**
* Merges custom RPC options with defaults. Returns a new instance and keeps
* the "defaults" and the "options" unmodified.
*
* Merges `RpcMetadata` "meta", overwriting values from "defaults" with
* values from "options". Does not append values to existing entries.
*
* Merges "jsonOptions", including "jsonOptions.typeRegistry", by creating
* a new array that contains types from "options.jsonOptions.typeRegistry"
* first, then types from "defaults.jsonOptions.typeRegistry".
*
* Merges "binaryOptions".
*
* Merges "interceptors" by creating a new array that contains interceptors
* from "defaults" first, then interceptors from "options".
*
* Works with objects that extend `RpcOptions`, but only if the added
* properties are of type Date, primitive like string, boolean, or Array
* of primitives. If you have other property types, you have to merge them
* yourself.
*/
function mergeRpcOptions(defaults, options) {
if (!options)
return defaults;
let o = {};
copy(defaults, o);
copy(options, o);
for (let key of Object.keys(options)) {
let val = options[key];
switch (key) {
case "jsonOptions":
o.jsonOptions = runtime_1.mergeJsonOptions(defaults.jsonOptions, o.jsonOptions);
break;
case "binaryOptions":
o.binaryOptions = runtime_1.mergeBinaryOptions(defaults.binaryOptions, o.binaryOptions);
break;
case "meta":
o.meta = {};
copy(defaults.meta, o.meta);
copy(options.meta, o.meta);
break;
case "interceptors":
o.interceptors = defaults.interceptors ? defaults.interceptors.concat(val) : val.concat();
break;
}
}
return o;
}
exports.mergeRpcOptions = mergeRpcOptions;
function copy(a, into) {
if (!a)
return;
let c = into;
for (let [k, v] of Object.entries(a)) {
if (v instanceof Date)
c[k] = new Date(v.getTime());
else if (Array.isArray(v))
c[k] = v.concat();
else
c[k] = v;
}
}

View file

@ -0,0 +1,172 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.RpcOutputStreamController = void 0;
const deferred_1 = require("./deferred");
const runtime_1 = require("@protobuf-ts/runtime");
/**
* A `RpcOutputStream` that you control.
*/
class RpcOutputStreamController {
constructor() {
this._lis = {
nxt: [],
msg: [],
err: [],
cmp: [],
};
this._closed = false;
}
// --- RpcOutputStream callback API
onNext(callback) {
return this.addLis(callback, this._lis.nxt);
}
onMessage(callback) {
return this.addLis(callback, this._lis.msg);
}
onError(callback) {
return this.addLis(callback, this._lis.err);
}
onComplete(callback) {
return this.addLis(callback, this._lis.cmp);
}
addLis(callback, list) {
list.push(callback);
return () => {
let i = list.indexOf(callback);
if (i >= 0)
list.splice(i, 1);
};
}
// remove all listeners
clearLis() {
for (let l of Object.values(this._lis))
l.splice(0, l.length);
}
// --- Controller API
/**
* Is this stream already closed by a completion or error?
*/
get closed() {
return this._closed !== false;
}
/**
* Emit message, close with error, or close successfully, but only one
* at a time.
* Can be used to wrap a stream by using the other stream's `onNext`.
*/
notifyNext(message, error, complete) {
runtime_1.assert((message ? 1 : 0) + (error ? 1 : 0) + (complete ? 1 : 0) <= 1, 'only one emission at a time');
if (message)
this.notifyMessage(message);
if (error)
this.notifyError(error);
if (complete)
this.notifyComplete();
}
/**
* Emits a new message. Throws if stream is closed.
*
* Triggers onNext and onMessage callbacks.
*/
notifyMessage(message) {
runtime_1.assert(!this.closed, 'stream is closed');
this.pushIt({ value: message, done: false });
this._lis.msg.forEach(l => l(message));
this._lis.nxt.forEach(l => l(message, undefined, false));
}
/**
* Closes the stream with an error. Throws if stream is closed.
*
* Triggers onNext and onError callbacks.
*/
notifyError(error) {
runtime_1.assert(!this.closed, 'stream is closed');
this._closed = error;
this.pushIt(error);
this._lis.err.forEach(l => l(error));
this._lis.nxt.forEach(l => l(undefined, error, false));
this.clearLis();
}
/**
* Closes the stream successfully. Throws if stream is closed.
*
* Triggers onNext and onComplete callbacks.
*/
notifyComplete() {
runtime_1.assert(!this.closed, 'stream is closed');
this._closed = true;
this.pushIt({ value: null, done: true });
this._lis.cmp.forEach(l => l());
this._lis.nxt.forEach(l => l(undefined, undefined, true));
this.clearLis();
}
/**
* Creates an async iterator (that can be used with `for await {...}`)
* to consume the stream.
*
* Some things to note:
* - If an error occurs, the `for await` will throw it.
* - If an error occurred before the `for await` was started, `for await`
* will re-throw it.
* - If the stream is already complete, the `for await` will be empty.
* - If your `for await` consumes slower than the stream produces,
* for example because you are relaying messages in a slow operation,
* messages are queued.
*/
[Symbol.asyncIterator]() {
// init the iterator state, enabling pushIt()
if (!this._itState) {
this._itState = { q: [] };
}
// if we are closed, we are definitely not receiving any more messages.
// but we can't let the iterator get stuck. we want to either:
// a) finish the new iterator immediately, because we are completed
// b) reject the new iterator, because we errored
if (this._closed === true)
this.pushIt({ value: null, done: true });
else if (this._closed !== false)
this.pushIt(this._closed);
// the async iterator
return {
next: () => {
let state = this._itState;
runtime_1.assert(state, "bad state"); // if we don't have a state here, code is broken
// there should be no pending result.
// did the consumer call next() before we resolved our previous result promise?
runtime_1.assert(!state.p, "iterator contract broken");
// did we produce faster than the iterator consumed?
// return the oldest result from the queue.
let first = state.q.shift();
if (first)
return ("value" in first) ? Promise.resolve(first) : Promise.reject(first);
// we have no result ATM, but we promise one.
// as soon as we have a result, we must resolve promise.
state.p = new deferred_1.Deferred();
return state.p.promise;
},
};
}
// "push" a new iterator result.
// this either resolves a pending promise, or enqueues the result.
pushIt(result) {
let state = this._itState;
if (!state)
return;
// is the consumer waiting for us?
if (state.p) {
// yes, consumer is waiting for this promise.
const p = state.p;
runtime_1.assert(p.state == deferred_1.DeferredState.PENDING, "iterator contract broken");
// resolve the promise
("value" in result) ? p.resolve(result) : p.reject(result);
// must cleanup, otherwise iterator.next() would pick it up again.
delete state.p;
}
else {
// we are producing faster than the iterator consumes.
// push result onto queue.
state.q.push(result);
}
}
}
exports.RpcOutputStreamController = RpcOutputStreamController;

View file

@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View file

@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });

View file

@ -0,0 +1,60 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ServerCallContextController = void 0;
class ServerCallContextController {
constructor(method, headers, deadline, sendResponseHeadersFn, defaultStatus = { code: 'OK', detail: '' }) {
this._cancelled = false;
this._listeners = [];
this.method = method;
this.headers = headers;
this.deadline = deadline;
this.trailers = {};
this._sendRH = sendResponseHeadersFn;
this.status = defaultStatus;
}
/**
* Set the call cancelled.
*
* Invokes all callbacks registered with onCancel() and
* sets `cancelled = true`.
*/
notifyCancelled() {
if (!this._cancelled) {
this._cancelled = true;
for (let l of this._listeners) {
l();
}
}
}
/**
* Send response headers.
*/
sendResponseHeaders(data) {
this._sendRH(data);
}
/**
* Is the call cancelled?
*
* When the client closes the connection before the server
* is done, the call is cancelled.
*
* If you want to cancel a request on the server, throw a
* RpcError with the CANCELLED status code.
*/
get cancelled() {
return this._cancelled;
}
/**
* Add a callback for cancellation.
*/
onCancel(callback) {
const l = this._listeners;
l.push(callback);
return () => {
let i = l.indexOf(callback);
if (i >= 0)
l.splice(i, 1);
};
}
}
exports.ServerCallContextController = ServerCallContextController;

View file

@ -0,0 +1,50 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ServerStreamingCall = void 0;
/**
* A server streaming RPC call. The client provides exactly one input message
* but the server may respond with 0, 1, or more messages.
*/
class ServerStreamingCall {
constructor(method, requestHeaders, request, headers, response, status, trailers) {
this.method = method;
this.requestHeaders = requestHeaders;
this.request = request;
this.headers = headers;
this.responses = response;
this.status = status;
this.trailers = trailers;
}
/**
* Instead of awaiting the response status and trailers, you can
* just as well await this call itself to receive the server outcome.
* You should first setup some listeners to the `request` to
* see the actual messages the server replied with.
*/
then(onfulfilled, onrejected) {
return this.promiseFinished().then(value => onfulfilled ? Promise.resolve(onfulfilled(value)) : value, reason => onrejected ? Promise.resolve(onrejected(reason)) : Promise.reject(reason));
}
promiseFinished() {
return __awaiter(this, void 0, void 0, function* () {
let [headers, status, trailers] = yield Promise.all([this.headers, this.status, this.trailers]);
return {
method: this.method,
requestHeaders: this.requestHeaders,
request: this.request,
headers,
status,
trailers,
};
});
}
}
exports.ServerStreamingCall = ServerStreamingCall;

View file

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ServiceType = void 0;
const reflection_info_1 = require("./reflection-info");
class ServiceType {
constructor(typeName, methods, options) {
this.typeName = typeName;
this.methods = methods.map(i => reflection_info_1.normalizeMethodInfo(i, this));
this.options = options !== null && options !== void 0 ? options : {};
}
}
exports.ServiceType = ServiceType;

View file

@ -0,0 +1,321 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TestTransport = void 0;
const rpc_error_1 = require("./rpc-error");
const runtime_1 = require("@protobuf-ts/runtime");
const rpc_output_stream_1 = require("./rpc-output-stream");
const rpc_options_1 = require("./rpc-options");
const unary_call_1 = require("./unary-call");
const server_streaming_call_1 = require("./server-streaming-call");
const client_streaming_call_1 = require("./client-streaming-call");
const duplex_streaming_call_1 = require("./duplex-streaming-call");
/**
* Transport for testing.
*/
class TestTransport {
/**
* Initialize with mock data. Omitted fields have default value.
*/
constructor(data) {
/**
* Suppress warning / error about uncaught rejections of
* "status" and "trailers".
*/
this.suppressUncaughtRejections = true;
this.headerDelay = 10;
this.responseDelay = 50;
this.betweenResponseDelay = 10;
this.afterResponseDelay = 10;
this.data = data !== null && data !== void 0 ? data : {};
}
/**
* Sent message(s) during the last operation.
*/
get sentMessages() {
if (this.lastInput instanceof TestInputStream) {
return this.lastInput.sent;
}
else if (typeof this.lastInput == "object") {
return [this.lastInput.single];
}
return [];
}
/**
* Sending message(s) completed?
*/
get sendComplete() {
if (this.lastInput instanceof TestInputStream) {
return this.lastInput.completed;
}
else if (typeof this.lastInput == "object") {
return true;
}
return false;
}
// Creates a promise for response headers from the mock data.
promiseHeaders() {
var _a;
const headers = (_a = this.data.headers) !== null && _a !== void 0 ? _a : TestTransport.defaultHeaders;
return headers instanceof rpc_error_1.RpcError
? Promise.reject(headers)
: Promise.resolve(headers);
}
// Creates a promise for a single, valid, message from the mock data.
promiseSingleResponse(method) {
if (this.data.response instanceof rpc_error_1.RpcError) {
return Promise.reject(this.data.response);
}
let r;
if (Array.isArray(this.data.response)) {
runtime_1.assert(this.data.response.length > 0);
r = this.data.response[0];
}
else if (this.data.response !== undefined) {
r = this.data.response;
}
else {
r = method.O.create();
}
runtime_1.assert(method.O.is(r));
return Promise.resolve(r);
}
/**
* Pushes response messages from the mock data to the output stream.
* If an error response, status or trailers are mocked, the stream is
* closed with the respective error.
* Otherwise, stream is completed successfully.
*
* The returned promise resolves when the stream is closed. It should
* not reject. If it does, code is broken.
*/
streamResponses(method, stream, abort) {
return __awaiter(this, void 0, void 0, function* () {
// normalize "data.response" into an array of valid output messages
const messages = [];
if (this.data.response === undefined) {
messages.push(method.O.create());
}
else if (Array.isArray(this.data.response)) {
for (let msg of this.data.response) {
runtime_1.assert(method.O.is(msg));
messages.push(msg);
}
}
else if (!(this.data.response instanceof rpc_error_1.RpcError)) {
runtime_1.assert(method.O.is(this.data.response));
messages.push(this.data.response);
}
// start the stream with an initial delay.
// if the request is cancelled, notify() error and exit.
try {
yield delay(this.responseDelay, abort)(undefined);
}
catch (error) {
stream.notifyError(error);
return;
}
// if error response was mocked, notify() error (stream is now closed with error) and exit.
if (this.data.response instanceof rpc_error_1.RpcError) {
stream.notifyError(this.data.response);
return;
}
// regular response messages were mocked. notify() them.
for (let msg of messages) {
stream.notifyMessage(msg);
// add a short delay between responses
// if the request is cancelled, notify() error and exit.
try {
yield delay(this.betweenResponseDelay, abort)(undefined);
}
catch (error) {
stream.notifyError(error);
return;
}
}
// error status was mocked, notify() error (stream is now closed with error) and exit.
if (this.data.status instanceof rpc_error_1.RpcError) {
stream.notifyError(this.data.status);
return;
}
// error trailers were mocked, notify() error (stream is now closed with error) and exit.
if (this.data.trailers instanceof rpc_error_1.RpcError) {
stream.notifyError(this.data.trailers);
return;
}
// stream completed successfully
stream.notifyComplete();
});
}
// Creates a promise for response status from the mock data.
promiseStatus() {
var _a;
const status = (_a = this.data.status) !== null && _a !== void 0 ? _a : TestTransport.defaultStatus;
return status instanceof rpc_error_1.RpcError
? Promise.reject(status)
: Promise.resolve(status);
}
// Creates a promise for response trailers from the mock data.
promiseTrailers() {
var _a;
const trailers = (_a = this.data.trailers) !== null && _a !== void 0 ? _a : TestTransport.defaultTrailers;
return trailers instanceof rpc_error_1.RpcError
? Promise.reject(trailers)
: Promise.resolve(trailers);
}
maybeSuppressUncaught(...promise) {
if (this.suppressUncaughtRejections) {
for (let p of promise) {
p.catch(() => {
});
}
}
}
mergeOptions(options) {
return rpc_options_1.mergeRpcOptions({}, options);
}
unary(method, input, options) {
var _a;
const requestHeaders = (_a = options.meta) !== null && _a !== void 0 ? _a : {}, headersPromise = this.promiseHeaders()
.then(delay(this.headerDelay, options.abort)), responsePromise = headersPromise
.catch(_ => {
})
.then(delay(this.responseDelay, options.abort))
.then(_ => this.promiseSingleResponse(method)), statusPromise = responsePromise
.catch(_ => {
})
.then(delay(this.afterResponseDelay, options.abort))
.then(_ => this.promiseStatus()), trailersPromise = responsePromise
.catch(_ => {
})
.then(delay(this.afterResponseDelay, options.abort))
.then(_ => this.promiseTrailers());
this.maybeSuppressUncaught(statusPromise, trailersPromise);
this.lastInput = { single: input };
return new unary_call_1.UnaryCall(method, requestHeaders, input, headersPromise, responsePromise, statusPromise, trailersPromise);
}
serverStreaming(method, input, options) {
var _a;
const requestHeaders = (_a = options.meta) !== null && _a !== void 0 ? _a : {}, headersPromise = this.promiseHeaders()
.then(delay(this.headerDelay, options.abort)), outputStream = new rpc_output_stream_1.RpcOutputStreamController(), responseStreamClosedPromise = headersPromise
.then(delay(this.responseDelay, options.abort))
.catch(() => {
})
.then(() => this.streamResponses(method, outputStream, options.abort))
.then(delay(this.afterResponseDelay, options.abort)), statusPromise = responseStreamClosedPromise
.then(() => this.promiseStatus()), trailersPromise = responseStreamClosedPromise
.then(() => this.promiseTrailers());
this.maybeSuppressUncaught(statusPromise, trailersPromise);
this.lastInput = { single: input };
return new server_streaming_call_1.ServerStreamingCall(method, requestHeaders, input, headersPromise, outputStream, statusPromise, trailersPromise);
}
clientStreaming(method, options) {
var _a;
const requestHeaders = (_a = options.meta) !== null && _a !== void 0 ? _a : {}, headersPromise = this.promiseHeaders()
.then(delay(this.headerDelay, options.abort)), responsePromise = headersPromise
.catch(_ => {
})
.then(delay(this.responseDelay, options.abort))
.then(_ => this.promiseSingleResponse(method)), statusPromise = responsePromise
.catch(_ => {
})
.then(delay(this.afterResponseDelay, options.abort))
.then(_ => this.promiseStatus()), trailersPromise = responsePromise
.catch(_ => {
})
.then(delay(this.afterResponseDelay, options.abort))
.then(_ => this.promiseTrailers());
this.maybeSuppressUncaught(statusPromise, trailersPromise);
this.lastInput = new TestInputStream(this.data, options.abort);
return new client_streaming_call_1.ClientStreamingCall(method, requestHeaders, this.lastInput, headersPromise, responsePromise, statusPromise, trailersPromise);
}
duplex(method, options) {
var _a;
const requestHeaders = (_a = options.meta) !== null && _a !== void 0 ? _a : {}, headersPromise = this.promiseHeaders()
.then(delay(this.headerDelay, options.abort)), outputStream = new rpc_output_stream_1.RpcOutputStreamController(), responseStreamClosedPromise = headersPromise
.then(delay(this.responseDelay, options.abort))
.catch(() => {
})
.then(() => this.streamResponses(method, outputStream, options.abort))
.then(delay(this.afterResponseDelay, options.abort)), statusPromise = responseStreamClosedPromise
.then(() => this.promiseStatus()), trailersPromise = responseStreamClosedPromise
.then(() => this.promiseTrailers());
this.maybeSuppressUncaught(statusPromise, trailersPromise);
this.lastInput = new TestInputStream(this.data, options.abort);
return new duplex_streaming_call_1.DuplexStreamingCall(method, requestHeaders, this.lastInput, headersPromise, outputStream, statusPromise, trailersPromise);
}
}
exports.TestTransport = TestTransport;
TestTransport.defaultHeaders = {
responseHeader: "test"
};
TestTransport.defaultStatus = {
code: "OK", detail: "all good"
};
TestTransport.defaultTrailers = {
responseTrailer: "test"
};
function delay(ms, abort) {
return (v) => new Promise((resolve, reject) => {
if (abort === null || abort === void 0 ? void 0 : abort.aborted) {
reject(new rpc_error_1.RpcError("user cancel", "CANCELLED"));
}
else {
const id = setTimeout(() => resolve(v), ms);
if (abort) {
abort.addEventListener("abort", ev => {
clearTimeout(id);
reject(new rpc_error_1.RpcError("user cancel", "CANCELLED"));
});
}
}
});
}
class TestInputStream {
constructor(data, abort) {
this._completed = false;
this._sent = [];
this.data = data;
this.abort = abort;
}
get sent() {
return this._sent;
}
get completed() {
return this._completed;
}
send(message) {
if (this.data.inputMessage instanceof rpc_error_1.RpcError) {
return Promise.reject(this.data.inputMessage);
}
const delayMs = this.data.inputMessage === undefined
? 10
: this.data.inputMessage;
return Promise.resolve(undefined)
.then(() => {
this._sent.push(message);
})
.then(delay(delayMs, this.abort));
}
complete() {
if (this.data.inputComplete instanceof rpc_error_1.RpcError) {
return Promise.reject(this.data.inputComplete);
}
const delayMs = this.data.inputComplete === undefined
? 10
: this.data.inputComplete;
return Promise.resolve(undefined)
.then(() => {
this._completed = true;
})
.then(delay(delayMs, this.abort));
}
}

View file

@ -0,0 +1,49 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UnaryCall = void 0;
/**
* A unary RPC call. Unary means there is exactly one input message and
* exactly one output message unless an error occurred.
*/
class UnaryCall {
constructor(method, requestHeaders, request, headers, response, status, trailers) {
this.method = method;
this.requestHeaders = requestHeaders;
this.request = request;
this.headers = headers;
this.response = response;
this.status = status;
this.trailers = trailers;
}
/**
* If you are only interested in the final outcome of this call,
* you can await it to receive a `FinishedUnaryCall`.
*/
then(onfulfilled, onrejected) {
return this.promiseFinished().then(value => onfulfilled ? Promise.resolve(onfulfilled(value)) : value, reason => onrejected ? Promise.resolve(onrejected(reason)) : Promise.reject(reason));
}
promiseFinished() {
return __awaiter(this, void 0, void 0, function* () {
let [headers, response, status, trailers] = yield Promise.all([this.headers, this.response, this.status, this.trailers]);
return {
method: this.method,
requestHeaders: this.requestHeaders,
request: this.request,
headers,
response,
status,
trailers
};
});
}
}
exports.UnaryCall = UnaryCall;

View file

@ -0,0 +1,46 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
/**
* A client streaming RPC call. This means that the clients sends 0, 1, or
* more messages to the server, and the server replies with exactly one
* message.
*/
export class ClientStreamingCall {
constructor(method, requestHeaders, request, headers, response, status, trailers) {
this.method = method;
this.requestHeaders = requestHeaders;
this.requests = request;
this.headers = headers;
this.response = response;
this.status = status;
this.trailers = trailers;
}
/**
* Instead of awaiting the response status and trailers, you can
* just as well await this call itself to receive the server outcome.
* Note that it may still be valid to send more request messages.
*/
then(onfulfilled, onrejected) {
return this.promiseFinished().then(value => onfulfilled ? Promise.resolve(onfulfilled(value)) : value, reason => onrejected ? Promise.resolve(onrejected(reason)) : Promise.reject(reason));
}
promiseFinished() {
return __awaiter(this, void 0, void 0, function* () {
let [headers, response, status, trailers] = yield Promise.all([this.headers, this.response, this.status, this.trailers]);
return {
method: this.method,
requestHeaders: this.requestHeaders,
headers,
response,
status,
trailers
};
});
}
}

View file

@ -0,0 +1,82 @@
export var DeferredState;
(function (DeferredState) {
DeferredState[DeferredState["PENDING"] = 0] = "PENDING";
DeferredState[DeferredState["REJECTED"] = 1] = "REJECTED";
DeferredState[DeferredState["RESOLVED"] = 2] = "RESOLVED";
})(DeferredState || (DeferredState = {}));
/**
* A deferred promise. This is a "controller" for a promise, which lets you
* pass a promise around and reject or resolve it from the outside.
*
* Warning: This class is to be used with care. Using it can make code very
* difficult to read. It is intended for use in library code that exposes
* promises, not for regular business logic.
*/
export class Deferred {
/**
* @param preventUnhandledRejectionWarning - prevents the warning
* "Unhandled Promise rejection" by adding a noop rejection handler.
* Working with calls returned from the runtime-rpc package in an
* async function usually means awaiting one call property after
* the other. This means that the "status" is not being awaited when
* an earlier await for the "headers" is rejected. This causes the
* "unhandled promise reject" warning. A more correct behaviour for
* calls might be to become aware whether at least one of the
* promises is handled and swallow the rejection warning for the
* others.
*/
constructor(preventUnhandledRejectionWarning = true) {
this._state = DeferredState.PENDING;
this._promise = new Promise((resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
});
if (preventUnhandledRejectionWarning) {
this._promise.catch(_ => { });
}
}
/**
* Get the current state of the promise.
*/
get state() {
return this._state;
}
/**
* Get the deferred promise.
*/
get promise() {
return this._promise;
}
/**
* Resolve the promise. Throws if the promise is already resolved or rejected.
*/
resolve(value) {
if (this.state !== DeferredState.PENDING)
throw new Error(`cannot resolve ${DeferredState[this.state].toLowerCase()}`);
this._resolve(value);
this._state = DeferredState.RESOLVED;
}
/**
* Reject the promise. Throws if the promise is already resolved or rejected.
*/
reject(reason) {
if (this.state !== DeferredState.PENDING)
throw new Error(`cannot reject ${DeferredState[this.state].toLowerCase()}`);
this._reject(reason);
this._state = DeferredState.REJECTED;
}
/**
* Resolve the promise. Ignore if not pending.
*/
resolvePending(val) {
if (this._state === DeferredState.PENDING)
this.resolve(val);
}
/**
* Reject the promise. Ignore if not pending.
*/
rejectPending(reason) {
if (this._state === DeferredState.PENDING)
this.reject(reason);
}
}

View file

@ -0,0 +1,45 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
/**
* A duplex streaming RPC call. This means that the clients sends an
* arbitrary amount of messages to the server, while at the same time,
* the server sends an arbitrary amount of messages to the client.
*/
export class DuplexStreamingCall {
constructor(method, requestHeaders, request, headers, response, status, trailers) {
this.method = method;
this.requestHeaders = requestHeaders;
this.requests = request;
this.headers = headers;
this.responses = response;
this.status = status;
this.trailers = trailers;
}
/**
* Instead of awaiting the response status and trailers, you can
* just as well await this call itself to receive the server outcome.
* Note that it may still be valid to send more request messages.
*/
then(onfulfilled, onrejected) {
return this.promiseFinished().then(value => onfulfilled ? Promise.resolve(onfulfilled(value)) : value, reason => onrejected ? Promise.resolve(onrejected(reason)) : Promise.reject(reason));
}
promiseFinished() {
return __awaiter(this, void 0, void 0, function* () {
let [headers, status, trailers] = yield Promise.all([this.headers, this.status, this.trailers]);
return {
method: this.method,
requestHeaders: this.requestHeaders,
headers,
status,
trailers,
};
});
}
}

View file

@ -0,0 +1,16 @@
// Public API of the rpc runtime.
// Note: we do not use `export * from ...` to help tree shakers,
// webpack verbose output hints that this should be useful
export { ServiceType } from './service-type';
export { readMethodOptions, readMethodOption, readServiceOption } from './reflection-info';
export { RpcError } from './rpc-error';
export { mergeRpcOptions } from './rpc-options';
export { RpcOutputStreamController } from './rpc-output-stream';
export { TestTransport } from './test-transport';
export { Deferred, DeferredState } from './deferred';
export { DuplexStreamingCall } from './duplex-streaming-call';
export { ClientStreamingCall } from './client-streaming-call';
export { ServerStreamingCall } from './server-streaming-call';
export { UnaryCall } from './unary-call';
export { stackIntercept, stackDuplexStreamingInterceptors, stackClientStreamingInterceptors, stackServerStreamingInterceptors, stackUnaryInterceptors } from './rpc-interceptor';
export { ServerCallContextController } from './server-call-context';

View file

@ -0,0 +1,50 @@
import { lowerCamelCase } from "@protobuf-ts/runtime";
/**
* Turns PartialMethodInfo into MethodInfo.
*/
export function normalizeMethodInfo(method, service) {
var _a, _b, _c;
let m = method;
m.service = service;
m.localName = (_a = m.localName) !== null && _a !== void 0 ? _a : lowerCamelCase(m.name);
// noinspection PointlessBooleanExpressionJS
m.serverStreaming = !!m.serverStreaming;
// noinspection PointlessBooleanExpressionJS
m.clientStreaming = !!m.clientStreaming;
m.options = (_b = m.options) !== null && _b !== void 0 ? _b : {};
m.idempotency = (_c = m.idempotency) !== null && _c !== void 0 ? _c : undefined;
return m;
}
/**
* Read custom method options from a generated service client.
*
* @deprecated use readMethodOption()
*/
export function readMethodOptions(service, methodName, extensionName, extensionType) {
var _a;
const options = (_a = service.methods.find((m, i) => m.localName === methodName || i === methodName)) === null || _a === void 0 ? void 0 : _a.options;
return options && options[extensionName] ? extensionType.fromJson(options[extensionName]) : undefined;
}
export function readMethodOption(service, methodName, extensionName, extensionType) {
var _a;
const options = (_a = service.methods.find((m, i) => m.localName === methodName || i === methodName)) === null || _a === void 0 ? void 0 : _a.options;
if (!options) {
return undefined;
}
const optionVal = options[extensionName];
if (optionVal === undefined) {
return optionVal;
}
return extensionType ? extensionType.fromJson(optionVal) : optionVal;
}
export function readServiceOption(service, extensionName, extensionType) {
const options = service.options;
if (!options) {
return undefined;
}
const optionVal = options[extensionName];
if (optionVal === undefined) {
return optionVal;
}
return extensionType ? extensionType.fromJson(optionVal) : optionVal;
}

View file

@ -0,0 +1,32 @@
/**
* An error that occurred while calling a RPC method.
*/
export class RpcError extends Error {
constructor(message, code = 'UNKNOWN', meta) {
super(message);
this.name = 'RpcError';
// see https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#example
Object.setPrototypeOf(this, new.target.prototype);
this.code = code;
this.meta = meta !== null && meta !== void 0 ? meta : {};
}
toString() {
const l = [this.name + ': ' + this.message];
if (this.code) {
l.push('');
l.push('Code: ' + this.code);
}
if (this.serviceName && this.methodName) {
l.push('Method: ' + this.serviceName + '/' + this.methodName);
}
let m = Object.entries(this.meta);
if (m.length) {
l.push('');
l.push('Meta:');
for (let [k, v] of m) {
l.push(` ${k}: ${v}`);
}
}
return l.join('\n');
}
}

View file

@ -0,0 +1,66 @@
import { assertNever } from "@protobuf-ts/runtime";
/**
* Creates a "stack" of of all interceptors specified in the given `RpcOptions`.
* Used by generated client implementations.
* @internal
*/
export function stackIntercept(kind, transport, method, options, input) {
var _a, _b, _c, _d;
if (kind == "unary") {
let tail = (mtd, inp, opt) => transport.unary(mtd, inp, opt);
for (const curr of ((_a = options.interceptors) !== null && _a !== void 0 ? _a : []).filter(i => i.interceptUnary).reverse()) {
const next = tail;
tail = (mtd, inp, opt) => curr.interceptUnary(next, mtd, inp, opt);
}
return tail(method, input, options);
}
if (kind == "serverStreaming") {
let tail = (mtd, inp, opt) => transport.serverStreaming(mtd, inp, opt);
for (const curr of ((_b = options.interceptors) !== null && _b !== void 0 ? _b : []).filter(i => i.interceptServerStreaming).reverse()) {
const next = tail;
tail = (mtd, inp, opt) => curr.interceptServerStreaming(next, mtd, inp, opt);
}
return tail(method, input, options);
}
if (kind == "clientStreaming") {
let tail = (mtd, opt) => transport.clientStreaming(mtd, opt);
for (const curr of ((_c = options.interceptors) !== null && _c !== void 0 ? _c : []).filter(i => i.interceptClientStreaming).reverse()) {
const next = tail;
tail = (mtd, opt) => curr.interceptClientStreaming(next, mtd, opt);
}
return tail(method, options);
}
if (kind == "duplex") {
let tail = (mtd, opt) => transport.duplex(mtd, opt);
for (const curr of ((_d = options.interceptors) !== null && _d !== void 0 ? _d : []).filter(i => i.interceptDuplex).reverse()) {
const next = tail;
tail = (mtd, opt) => curr.interceptDuplex(next, mtd, opt);
}
return tail(method, options);
}
assertNever(kind);
}
/**
* @deprecated replaced by `stackIntercept()`, still here to support older generated code
*/
export function stackUnaryInterceptors(transport, method, input, options) {
return stackIntercept("unary", transport, method, options, input);
}
/**
* @deprecated replaced by `stackIntercept()`, still here to support older generated code
*/
export function stackServerStreamingInterceptors(transport, method, input, options) {
return stackIntercept("serverStreaming", transport, method, options, input);
}
/**
* @deprecated replaced by `stackIntercept()`, still here to support older generated code
*/
export function stackClientStreamingInterceptors(transport, method, options) {
return stackIntercept("clientStreaming", transport, method, options);
}
/**
* @deprecated replaced by `stackIntercept()`, still here to support older generated code
*/
export function stackDuplexStreamingInterceptors(transport, method, options) {
return stackIntercept("duplex", transport, method, options);
}

View file

@ -0,0 +1,62 @@
import { mergeBinaryOptions, mergeJsonOptions } from "@protobuf-ts/runtime";
/**
* Merges custom RPC options with defaults. Returns a new instance and keeps
* the "defaults" and the "options" unmodified.
*
* Merges `RpcMetadata` "meta", overwriting values from "defaults" with
* values from "options". Does not append values to existing entries.
*
* Merges "jsonOptions", including "jsonOptions.typeRegistry", by creating
* a new array that contains types from "options.jsonOptions.typeRegistry"
* first, then types from "defaults.jsonOptions.typeRegistry".
*
* Merges "binaryOptions".
*
* Merges "interceptors" by creating a new array that contains interceptors
* from "defaults" first, then interceptors from "options".
*
* Works with objects that extend `RpcOptions`, but only if the added
* properties are of type Date, primitive like string, boolean, or Array
* of primitives. If you have other property types, you have to merge them
* yourself.
*/
export function mergeRpcOptions(defaults, options) {
if (!options)
return defaults;
let o = {};
copy(defaults, o);
copy(options, o);
for (let key of Object.keys(options)) {
let val = options[key];
switch (key) {
case "jsonOptions":
o.jsonOptions = mergeJsonOptions(defaults.jsonOptions, o.jsonOptions);
break;
case "binaryOptions":
o.binaryOptions = mergeBinaryOptions(defaults.binaryOptions, o.binaryOptions);
break;
case "meta":
o.meta = {};
copy(defaults.meta, o.meta);
copy(options.meta, o.meta);
break;
case "interceptors":
o.interceptors = defaults.interceptors ? defaults.interceptors.concat(val) : val.concat();
break;
}
}
return o;
}
function copy(a, into) {
if (!a)
return;
let c = into;
for (let [k, v] of Object.entries(a)) {
if (v instanceof Date)
c[k] = new Date(v.getTime());
else if (Array.isArray(v))
c[k] = v.concat();
else
c[k] = v;
}
}

View file

@ -0,0 +1,168 @@
import { Deferred, DeferredState } from "./deferred";
import { assert } from "@protobuf-ts/runtime";
/**
* A `RpcOutputStream` that you control.
*/
export class RpcOutputStreamController {
constructor() {
this._lis = {
nxt: [],
msg: [],
err: [],
cmp: [],
};
this._closed = false;
}
// --- RpcOutputStream callback API
onNext(callback) {
return this.addLis(callback, this._lis.nxt);
}
onMessage(callback) {
return this.addLis(callback, this._lis.msg);
}
onError(callback) {
return this.addLis(callback, this._lis.err);
}
onComplete(callback) {
return this.addLis(callback, this._lis.cmp);
}
addLis(callback, list) {
list.push(callback);
return () => {
let i = list.indexOf(callback);
if (i >= 0)
list.splice(i, 1);
};
}
// remove all listeners
clearLis() {
for (let l of Object.values(this._lis))
l.splice(0, l.length);
}
// --- Controller API
/**
* Is this stream already closed by a completion or error?
*/
get closed() {
return this._closed !== false;
}
/**
* Emit message, close with error, or close successfully, but only one
* at a time.
* Can be used to wrap a stream by using the other stream's `onNext`.
*/
notifyNext(message, error, complete) {
assert((message ? 1 : 0) + (error ? 1 : 0) + (complete ? 1 : 0) <= 1, 'only one emission at a time');
if (message)
this.notifyMessage(message);
if (error)
this.notifyError(error);
if (complete)
this.notifyComplete();
}
/**
* Emits a new message. Throws if stream is closed.
*
* Triggers onNext and onMessage callbacks.
*/
notifyMessage(message) {
assert(!this.closed, 'stream is closed');
this.pushIt({ value: message, done: false });
this._lis.msg.forEach(l => l(message));
this._lis.nxt.forEach(l => l(message, undefined, false));
}
/**
* Closes the stream with an error. Throws if stream is closed.
*
* Triggers onNext and onError callbacks.
*/
notifyError(error) {
assert(!this.closed, 'stream is closed');
this._closed = error;
this.pushIt(error);
this._lis.err.forEach(l => l(error));
this._lis.nxt.forEach(l => l(undefined, error, false));
this.clearLis();
}
/**
* Closes the stream successfully. Throws if stream is closed.
*
* Triggers onNext and onComplete callbacks.
*/
notifyComplete() {
assert(!this.closed, 'stream is closed');
this._closed = true;
this.pushIt({ value: null, done: true });
this._lis.cmp.forEach(l => l());
this._lis.nxt.forEach(l => l(undefined, undefined, true));
this.clearLis();
}
/**
* Creates an async iterator (that can be used with `for await {...}`)
* to consume the stream.
*
* Some things to note:
* - If an error occurs, the `for await` will throw it.
* - If an error occurred before the `for await` was started, `for await`
* will re-throw it.
* - If the stream is already complete, the `for await` will be empty.
* - If your `for await` consumes slower than the stream produces,
* for example because you are relaying messages in a slow operation,
* messages are queued.
*/
[Symbol.asyncIterator]() {
// init the iterator state, enabling pushIt()
if (!this._itState) {
this._itState = { q: [] };
}
// if we are closed, we are definitely not receiving any more messages.
// but we can't let the iterator get stuck. we want to either:
// a) finish the new iterator immediately, because we are completed
// b) reject the new iterator, because we errored
if (this._closed === true)
this.pushIt({ value: null, done: true });
else if (this._closed !== false)
this.pushIt(this._closed);
// the async iterator
return {
next: () => {
let state = this._itState;
assert(state, "bad state"); // if we don't have a state here, code is broken
// there should be no pending result.
// did the consumer call next() before we resolved our previous result promise?
assert(!state.p, "iterator contract broken");
// did we produce faster than the iterator consumed?
// return the oldest result from the queue.
let first = state.q.shift();
if (first)
return ("value" in first) ? Promise.resolve(first) : Promise.reject(first);
// we have no result ATM, but we promise one.
// as soon as we have a result, we must resolve promise.
state.p = new Deferred();
return state.p.promise;
},
};
}
// "push" a new iterator result.
// this either resolves a pending promise, or enqueues the result.
pushIt(result) {
let state = this._itState;
if (!state)
return;
// is the consumer waiting for us?
if (state.p) {
// yes, consumer is waiting for this promise.
const p = state.p;
assert(p.state == DeferredState.PENDING, "iterator contract broken");
// resolve the promise
("value" in result) ? p.resolve(result) : p.reject(result);
// must cleanup, otherwise iterator.next() would pick it up again.
delete state.p;
}
else {
// we are producing faster than the iterator consumes.
// push result onto queue.
state.q.push(result);
}
}
}

View file

@ -0,0 +1,56 @@
export class ServerCallContextController {
constructor(method, headers, deadline, sendResponseHeadersFn, defaultStatus = { code: 'OK', detail: '' }) {
this._cancelled = false;
this._listeners = [];
this.method = method;
this.headers = headers;
this.deadline = deadline;
this.trailers = {};
this._sendRH = sendResponseHeadersFn;
this.status = defaultStatus;
}
/**
* Set the call cancelled.
*
* Invokes all callbacks registered with onCancel() and
* sets `cancelled = true`.
*/
notifyCancelled() {
if (!this._cancelled) {
this._cancelled = true;
for (let l of this._listeners) {
l();
}
}
}
/**
* Send response headers.
*/
sendResponseHeaders(data) {
this._sendRH(data);
}
/**
* Is the call cancelled?
*
* When the client closes the connection before the server
* is done, the call is cancelled.
*
* If you want to cancel a request on the server, throw a
* RpcError with the CANCELLED status code.
*/
get cancelled() {
return this._cancelled;
}
/**
* Add a callback for cancellation.
*/
onCancel(callback) {
const l = this._listeners;
l.push(callback);
return () => {
let i = l.indexOf(callback);
if (i >= 0)
l.splice(i, 1);
};
}
}

View file

@ -0,0 +1,46 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
/**
* A server streaming RPC call. The client provides exactly one input message
* but the server may respond with 0, 1, or more messages.
*/
export class ServerStreamingCall {
constructor(method, requestHeaders, request, headers, response, status, trailers) {
this.method = method;
this.requestHeaders = requestHeaders;
this.request = request;
this.headers = headers;
this.responses = response;
this.status = status;
this.trailers = trailers;
}
/**
* Instead of awaiting the response status and trailers, you can
* just as well await this call itself to receive the server outcome.
* You should first setup some listeners to the `request` to
* see the actual messages the server replied with.
*/
then(onfulfilled, onrejected) {
return this.promiseFinished().then(value => onfulfilled ? Promise.resolve(onfulfilled(value)) : value, reason => onrejected ? Promise.resolve(onrejected(reason)) : Promise.reject(reason));
}
promiseFinished() {
return __awaiter(this, void 0, void 0, function* () {
let [headers, status, trailers] = yield Promise.all([this.headers, this.status, this.trailers]);
return {
method: this.method,
requestHeaders: this.requestHeaders,
request: this.request,
headers,
status,
trailers,
};
});
}
}

View file

@ -0,0 +1,8 @@
import { normalizeMethodInfo } from "./reflection-info";
export class ServiceType {
constructor(typeName, methods, options) {
this.typeName = typeName;
this.methods = methods.map(i => normalizeMethodInfo(i, this));
this.options = options !== null && options !== void 0 ? options : {};
}
}

View file

@ -0,0 +1,317 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { RpcError } from "./rpc-error";
import { assert } from "@protobuf-ts/runtime";
import { RpcOutputStreamController } from "./rpc-output-stream";
import { mergeRpcOptions } from "./rpc-options";
import { UnaryCall } from "./unary-call";
import { ServerStreamingCall } from "./server-streaming-call";
import { ClientStreamingCall } from "./client-streaming-call";
import { DuplexStreamingCall } from "./duplex-streaming-call";
/**
* Transport for testing.
*/
export class TestTransport {
/**
* Initialize with mock data. Omitted fields have default value.
*/
constructor(data) {
/**
* Suppress warning / error about uncaught rejections of
* "status" and "trailers".
*/
this.suppressUncaughtRejections = true;
this.headerDelay = 10;
this.responseDelay = 50;
this.betweenResponseDelay = 10;
this.afterResponseDelay = 10;
this.data = data !== null && data !== void 0 ? data : {};
}
/**
* Sent message(s) during the last operation.
*/
get sentMessages() {
if (this.lastInput instanceof TestInputStream) {
return this.lastInput.sent;
}
else if (typeof this.lastInput == "object") {
return [this.lastInput.single];
}
return [];
}
/**
* Sending message(s) completed?
*/
get sendComplete() {
if (this.lastInput instanceof TestInputStream) {
return this.lastInput.completed;
}
else if (typeof this.lastInput == "object") {
return true;
}
return false;
}
// Creates a promise for response headers from the mock data.
promiseHeaders() {
var _a;
const headers = (_a = this.data.headers) !== null && _a !== void 0 ? _a : TestTransport.defaultHeaders;
return headers instanceof RpcError
? Promise.reject(headers)
: Promise.resolve(headers);
}
// Creates a promise for a single, valid, message from the mock data.
promiseSingleResponse(method) {
if (this.data.response instanceof RpcError) {
return Promise.reject(this.data.response);
}
let r;
if (Array.isArray(this.data.response)) {
assert(this.data.response.length > 0);
r = this.data.response[0];
}
else if (this.data.response !== undefined) {
r = this.data.response;
}
else {
r = method.O.create();
}
assert(method.O.is(r));
return Promise.resolve(r);
}
/**
* Pushes response messages from the mock data to the output stream.
* If an error response, status or trailers are mocked, the stream is
* closed with the respective error.
* Otherwise, stream is completed successfully.
*
* The returned promise resolves when the stream is closed. It should
* not reject. If it does, code is broken.
*/
streamResponses(method, stream, abort) {
return __awaiter(this, void 0, void 0, function* () {
// normalize "data.response" into an array of valid output messages
const messages = [];
if (this.data.response === undefined) {
messages.push(method.O.create());
}
else if (Array.isArray(this.data.response)) {
for (let msg of this.data.response) {
assert(method.O.is(msg));
messages.push(msg);
}
}
else if (!(this.data.response instanceof RpcError)) {
assert(method.O.is(this.data.response));
messages.push(this.data.response);
}
// start the stream with an initial delay.
// if the request is cancelled, notify() error and exit.
try {
yield delay(this.responseDelay, abort)(undefined);
}
catch (error) {
stream.notifyError(error);
return;
}
// if error response was mocked, notify() error (stream is now closed with error) and exit.
if (this.data.response instanceof RpcError) {
stream.notifyError(this.data.response);
return;
}
// regular response messages were mocked. notify() them.
for (let msg of messages) {
stream.notifyMessage(msg);
// add a short delay between responses
// if the request is cancelled, notify() error and exit.
try {
yield delay(this.betweenResponseDelay, abort)(undefined);
}
catch (error) {
stream.notifyError(error);
return;
}
}
// error status was mocked, notify() error (stream is now closed with error) and exit.
if (this.data.status instanceof RpcError) {
stream.notifyError(this.data.status);
return;
}
// error trailers were mocked, notify() error (stream is now closed with error) and exit.
if (this.data.trailers instanceof RpcError) {
stream.notifyError(this.data.trailers);
return;
}
// stream completed successfully
stream.notifyComplete();
});
}
// Creates a promise for response status from the mock data.
promiseStatus() {
var _a;
const status = (_a = this.data.status) !== null && _a !== void 0 ? _a : TestTransport.defaultStatus;
return status instanceof RpcError
? Promise.reject(status)
: Promise.resolve(status);
}
// Creates a promise for response trailers from the mock data.
promiseTrailers() {
var _a;
const trailers = (_a = this.data.trailers) !== null && _a !== void 0 ? _a : TestTransport.defaultTrailers;
return trailers instanceof RpcError
? Promise.reject(trailers)
: Promise.resolve(trailers);
}
maybeSuppressUncaught(...promise) {
if (this.suppressUncaughtRejections) {
for (let p of promise) {
p.catch(() => {
});
}
}
}
mergeOptions(options) {
return mergeRpcOptions({}, options);
}
unary(method, input, options) {
var _a;
const requestHeaders = (_a = options.meta) !== null && _a !== void 0 ? _a : {}, headersPromise = this.promiseHeaders()
.then(delay(this.headerDelay, options.abort)), responsePromise = headersPromise
.catch(_ => {
})
.then(delay(this.responseDelay, options.abort))
.then(_ => this.promiseSingleResponse(method)), statusPromise = responsePromise
.catch(_ => {
})
.then(delay(this.afterResponseDelay, options.abort))
.then(_ => this.promiseStatus()), trailersPromise = responsePromise
.catch(_ => {
})
.then(delay(this.afterResponseDelay, options.abort))
.then(_ => this.promiseTrailers());
this.maybeSuppressUncaught(statusPromise, trailersPromise);
this.lastInput = { single: input };
return new UnaryCall(method, requestHeaders, input, headersPromise, responsePromise, statusPromise, trailersPromise);
}
serverStreaming(method, input, options) {
var _a;
const requestHeaders = (_a = options.meta) !== null && _a !== void 0 ? _a : {}, headersPromise = this.promiseHeaders()
.then(delay(this.headerDelay, options.abort)), outputStream = new RpcOutputStreamController(), responseStreamClosedPromise = headersPromise
.then(delay(this.responseDelay, options.abort))
.catch(() => {
})
.then(() => this.streamResponses(method, outputStream, options.abort))
.then(delay(this.afterResponseDelay, options.abort)), statusPromise = responseStreamClosedPromise
.then(() => this.promiseStatus()), trailersPromise = responseStreamClosedPromise
.then(() => this.promiseTrailers());
this.maybeSuppressUncaught(statusPromise, trailersPromise);
this.lastInput = { single: input };
return new ServerStreamingCall(method, requestHeaders, input, headersPromise, outputStream, statusPromise, trailersPromise);
}
clientStreaming(method, options) {
var _a;
const requestHeaders = (_a = options.meta) !== null && _a !== void 0 ? _a : {}, headersPromise = this.promiseHeaders()
.then(delay(this.headerDelay, options.abort)), responsePromise = headersPromise
.catch(_ => {
})
.then(delay(this.responseDelay, options.abort))
.then(_ => this.promiseSingleResponse(method)), statusPromise = responsePromise
.catch(_ => {
})
.then(delay(this.afterResponseDelay, options.abort))
.then(_ => this.promiseStatus()), trailersPromise = responsePromise
.catch(_ => {
})
.then(delay(this.afterResponseDelay, options.abort))
.then(_ => this.promiseTrailers());
this.maybeSuppressUncaught(statusPromise, trailersPromise);
this.lastInput = new TestInputStream(this.data, options.abort);
return new ClientStreamingCall(method, requestHeaders, this.lastInput, headersPromise, responsePromise, statusPromise, trailersPromise);
}
duplex(method, options) {
var _a;
const requestHeaders = (_a = options.meta) !== null && _a !== void 0 ? _a : {}, headersPromise = this.promiseHeaders()
.then(delay(this.headerDelay, options.abort)), outputStream = new RpcOutputStreamController(), responseStreamClosedPromise = headersPromise
.then(delay(this.responseDelay, options.abort))
.catch(() => {
})
.then(() => this.streamResponses(method, outputStream, options.abort))
.then(delay(this.afterResponseDelay, options.abort)), statusPromise = responseStreamClosedPromise
.then(() => this.promiseStatus()), trailersPromise = responseStreamClosedPromise
.then(() => this.promiseTrailers());
this.maybeSuppressUncaught(statusPromise, trailersPromise);
this.lastInput = new TestInputStream(this.data, options.abort);
return new DuplexStreamingCall(method, requestHeaders, this.lastInput, headersPromise, outputStream, statusPromise, trailersPromise);
}
}
TestTransport.defaultHeaders = {
responseHeader: "test"
};
TestTransport.defaultStatus = {
code: "OK", detail: "all good"
};
TestTransport.defaultTrailers = {
responseTrailer: "test"
};
function delay(ms, abort) {
return (v) => new Promise((resolve, reject) => {
if (abort === null || abort === void 0 ? void 0 : abort.aborted) {
reject(new RpcError("user cancel", "CANCELLED"));
}
else {
const id = setTimeout(() => resolve(v), ms);
if (abort) {
abort.addEventListener("abort", ev => {
clearTimeout(id);
reject(new RpcError("user cancel", "CANCELLED"));
});
}
}
});
}
class TestInputStream {
constructor(data, abort) {
this._completed = false;
this._sent = [];
this.data = data;
this.abort = abort;
}
get sent() {
return this._sent;
}
get completed() {
return this._completed;
}
send(message) {
if (this.data.inputMessage instanceof RpcError) {
return Promise.reject(this.data.inputMessage);
}
const delayMs = this.data.inputMessage === undefined
? 10
: this.data.inputMessage;
return Promise.resolve(undefined)
.then(() => {
this._sent.push(message);
})
.then(delay(delayMs, this.abort));
}
complete() {
if (this.data.inputComplete instanceof RpcError) {
return Promise.reject(this.data.inputComplete);
}
const delayMs = this.data.inputComplete === undefined
? 10
: this.data.inputComplete;
return Promise.resolve(undefined)
.then(() => {
this._completed = true;
})
.then(delay(delayMs, this.abort));
}
}

View file

@ -0,0 +1,45 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
/**
* A unary RPC call. Unary means there is exactly one input message and
* exactly one output message unless an error occurred.
*/
export class UnaryCall {
constructor(method, requestHeaders, request, headers, response, status, trailers) {
this.method = method;
this.requestHeaders = requestHeaders;
this.request = request;
this.headers = headers;
this.response = response;
this.status = status;
this.trailers = trailers;
}
/**
* If you are only interested in the final outcome of this call,
* you can await it to receive a `FinishedUnaryCall`.
*/
then(onfulfilled, onrejected) {
return this.promiseFinished().then(value => onfulfilled ? Promise.resolve(onfulfilled(value)) : value, reason => onrejected ? Promise.resolve(onrejected(reason)) : Promise.reject(reason));
}
promiseFinished() {
return __awaiter(this, void 0, void 0, function* () {
let [headers, response, status, trailers] = yield Promise.all([this.headers, this.response, this.status, this.trailers]);
return {
method: this.method,
requestHeaders: this.requestHeaders,
request: this.request,
headers,
response,
status,
trailers
};
});
}
}

View file

@ -0,0 +1,97 @@
import type { RpcCallShared } from "./rpc-call-shared";
import type { RpcInputStream } from "./rpc-input-stream";
import type { RpcStatus } from "./rpc-status";
import type { RpcMetadata } from "./rpc-metadata";
import type { MethodInfo } from "./reflection-info";
/**
* A client streaming RPC call. This means that the clients sends 0, 1, or
* more messages to the server, and the server replies with exactly one
* message.
*/
export declare class ClientStreamingCall<I extends object = object, O extends object = object> implements RpcCallShared<I, O> {
/**
* Reflection information about this call.
*/
readonly method: MethodInfo<I, O>;
/**
* Request headers being sent with the request.
*
* Request headers are provided in the `meta` property of the
* `RpcOptions` passed to a call.
*/
readonly requestHeaders: Readonly<RpcMetadata>;
/**
* Request messages from the client.
*/
readonly requests: RpcInputStream<I>;
/**
* The response headers that the server sent.
*
* This promise will reject with a `RpcError` when the server sends a
* error status code.
*/
readonly headers: Promise<RpcMetadata>;
/**
* The message the server replied with.
*/
readonly response: Promise<O>;
/**
* The response status the server replied with.
*
* This promise will resolve when the server has finished the request
* successfully.
*
* If the server replies with an error status, this promise will
* reject with a `RpcError`.
*/
readonly status: Promise<RpcStatus>;
/**
* The trailers the server attached to the response.
*
* This promise will resolve when the server has finished the request
* successfully.
*
* If the server replies with an error status, this promise will
* reject with a `RpcError`.
*/
readonly trailers: Promise<RpcMetadata>;
constructor(method: MethodInfo<I, O>, requestHeaders: Readonly<RpcMetadata>, request: RpcInputStream<I>, headers: Promise<RpcMetadata>, response: Promise<O>, status: Promise<RpcStatus>, trailers: Promise<RpcMetadata>);
/**
* Instead of awaiting the response status and trailers, you can
* just as well await this call itself to receive the server outcome.
* Note that it may still be valid to send more request messages.
*/
then<TResult1 = FinishedClientStreamingCall<I, O>, TResult2 = never>(onfulfilled?: ((value: FinishedClientStreamingCall<I, O>) => (PromiseLike<TResult1> | TResult1)) | undefined | null, onrejected?: ((reason: any) => (PromiseLike<TResult2> | TResult2)) | undefined | null): Promise<TResult1 | TResult2>;
private promiseFinished;
}
/**
* A completed client streaming RPC call. The server will not send any more
* messages, but it may still be valid to send request messages.
*/
export interface FinishedClientStreamingCall<I extends object, O extends object> {
/**
* Reflection information about this call.
*/
readonly method: MethodInfo<I, O>;
/**
* Request headers being sent with the request.
*/
readonly requestHeaders: Readonly<RpcMetadata>;
/**
* The response headers that the server sent.
*/
readonly headers: RpcMetadata;
/**
* The message the server replied with.
*/
readonly response: O;
/**
* The response status the server replied with.
* The status code will always be OK.
*/
readonly status: RpcStatus;
/**
* The trailers the server attached to the response.
*/
readonly trailers: RpcMetadata;
}

View file

@ -0,0 +1,56 @@
export declare enum DeferredState {
PENDING = 0,
REJECTED = 1,
RESOLVED = 2
}
/**
* A deferred promise. This is a "controller" for a promise, which lets you
* pass a promise around and reject or resolve it from the outside.
*
* Warning: This class is to be used with care. Using it can make code very
* difficult to read. It is intended for use in library code that exposes
* promises, not for regular business logic.
*/
export declare class Deferred<T> {
/**
* Get the current state of the promise.
*/
get state(): DeferredState;
/**
* Get the deferred promise.
*/
get promise(): Promise<T>;
private readonly _promise;
private _state;
private _resolve;
private _reject;
/**
* @param preventUnhandledRejectionWarning - prevents the warning
* "Unhandled Promise rejection" by adding a noop rejection handler.
* Working with calls returned from the runtime-rpc package in an
* async function usually means awaiting one call property after
* the other. This means that the "status" is not being awaited when
* an earlier await for the "headers" is rejected. This causes the
* "unhandled promise reject" warning. A more correct behaviour for
* calls might be to become aware whether at least one of the
* promises is handled and swallow the rejection warning for the
* others.
*/
constructor(preventUnhandledRejectionWarning?: boolean);
/**
* Resolve the promise. Throws if the promise is already resolved or rejected.
*/
resolve(value: T | PromiseLike<T>): void;
/**
* Reject the promise. Throws if the promise is already resolved or rejected.
*/
reject(reason: any): void;
/**
* Resolve the promise. Ignore if not pending.
*/
resolvePending(val: T | PromiseLike<T>): void;
/**
* Reject the promise. Ignore if not pending.
*/
rejectPending(reason: any): void;
}

View file

@ -0,0 +1,94 @@
import type { RpcCallShared } from "./rpc-call-shared";
import type { RpcInputStream } from "./rpc-input-stream";
import type { RpcOutputStream } from "./rpc-output-stream";
import type { RpcStatus } from "./rpc-status";
import type { MethodInfo } from "./reflection-info";
import type { RpcMetadata } from "./rpc-metadata";
/**
* A duplex streaming RPC call. This means that the clients sends an
* arbitrary amount of messages to the server, while at the same time,
* the server sends an arbitrary amount of messages to the client.
*/
export declare class DuplexStreamingCall<I extends object = object, O extends object = object> implements RpcCallShared<I, O> {
/**
* Reflection information about this call.
*/
readonly method: MethodInfo<I, O>;
/**
* Request headers being sent with the request.
*
* Request headers are provided in the `meta` property of the
* `RpcOptions` passed to a call.
*/
readonly requestHeaders: Readonly<RpcMetadata>;
/**
* Request messages from the client.
*/
readonly requests: RpcInputStream<I>;
/**
* The response headers that the server sent.
*
* This promise will reject with a `RpcError` when the server sends a
* error status code.
*/
readonly headers: Promise<RpcMetadata>;
/**
* Response messages from the server.
*/
readonly responses: RpcOutputStream<O>;
/**
* The response status the server replied with.
*
* This promise will resolve when the server has finished the request
* successfully.
*
* If the server replies with an error status, this promise will
* reject with a `RpcError`.
*/
readonly status: Promise<RpcStatus>;
/**
* The trailers the server attached to the response.
*
* This promise will resolve when the server has finished the request
* successfully.
*
* If the server replies with an error status, this promise will
* reject with a `RpcError`.
*/
readonly trailers: Promise<RpcMetadata>;
constructor(method: MethodInfo<I, O>, requestHeaders: Readonly<RpcMetadata>, request: RpcInputStream<I>, headers: Promise<RpcMetadata>, response: RpcOutputStream<O>, status: Promise<RpcStatus>, trailers: Promise<RpcMetadata>);
/**
* Instead of awaiting the response status and trailers, you can
* just as well await this call itself to receive the server outcome.
* Note that it may still be valid to send more request messages.
*/
then<TResult1 = FinishedDuplexStreamingCall<I, O>, TResult2 = never>(onfulfilled?: ((value: FinishedDuplexStreamingCall<I, O>) => (PromiseLike<TResult1> | TResult1)) | undefined | null, onrejected?: ((reason: any) => (PromiseLike<TResult2> | TResult2)) | undefined | null): Promise<TResult1 | TResult2>;
private promiseFinished;
}
/**
* A completed duplex streaming RPC call. The server will not send any more
* messages, but it may still be valid to send request messages.
*/
export interface FinishedDuplexStreamingCall<I extends object, O extends object> {
/**
* Reflection information about this call.
*/
readonly method: MethodInfo<I, O>;
/**
* Request headers being sent with the request.
*/
readonly requestHeaders: Readonly<RpcMetadata>;
/**
* The response headers that the server sent.
*/
readonly headers: RpcMetadata;
/**
* The response status the server replied with.
* The status code will always be OK.
*/
readonly status: RpcStatus;
/**
* The trailers the server attached to the response.
*/
readonly trailers: RpcMetadata;
}

View file

@ -0,0 +1,17 @@
export { ServiceType } from './service-type';
export { MethodInfo, PartialMethodInfo, ServiceInfo, readMethodOptions, readMethodOption, readServiceOption } from './reflection-info';
export { RpcError } from './rpc-error';
export { RpcMetadata } from './rpc-metadata';
export { RpcOptions, mergeRpcOptions } from './rpc-options';
export { RpcInputStream } from './rpc-input-stream';
export { RpcOutputStream, RpcOutputStreamController } from './rpc-output-stream';
export { RpcStatus } from './rpc-status';
export { RpcTransport } from './rpc-transport';
export { TestTransport } from './test-transport';
export { Deferred, DeferredState } from './deferred';
export { DuplexStreamingCall } from './duplex-streaming-call';
export { ClientStreamingCall } from './client-streaming-call';
export { ServerStreamingCall, FinishedServerStreamingCall } from './server-streaming-call';
export { UnaryCall, FinishedUnaryCall } from './unary-call';
export { NextUnaryFn, RpcInterceptor, NextClientStreamingFn, NextDuplexStreamingFn, NextServerStreamingFn, stackIntercept, stackDuplexStreamingInterceptors, stackClientStreamingInterceptors, stackServerStreamingInterceptors, stackUnaryInterceptors } from './rpc-interceptor';
export { ServerCallContext, ServerCallContextController } from './server-call-context';

View file

@ -0,0 +1,143 @@
import type { IMessageType, JsonValue } from "@protobuf-ts/runtime";
/**
* Describes a protobuf service for runtime reflection.
*/
export interface ServiceInfo {
/**
* The protobuf type name of the service, including package name if
* present.
*/
readonly typeName: string;
/**
* Information for each rpc method of the service, in the order of
* declaration in the source .proto.
*/
readonly methods: MethodInfo[];
/**
* Contains custom service options from the .proto source in JSON format.
*/
readonly options: {
[extensionName: string]: JsonValue;
};
}
/**
* Describes a protobuf service method for runtime reflection.
*/
export interface MethodInfo<I extends object = any, O extends object = any> {
/**
* The service this method belongs to.
*/
readonly service: ServiceInfo;
/**
* The name of the method as declared in .proto
*/
readonly name: string;
/**
* The name of the method in the runtime.
*/
readonly localName: string;
/**
* The idempotency level as specified in .proto.
*
* For example, the following method declaration will set
* `idempotency` to 'NO_SIDE_EFFECTS'.
*
* ```proto
* rpc Foo (FooRequest) returns (FooResponse) {
* option idempotency_level = NO_SIDE_EFFECTS
* }
* ```
*
* See `google/protobuf/descriptor.proto`, `MethodOptions`.
*/
readonly idempotency: undefined | 'NO_SIDE_EFFECTS' | 'IDEMPOTENT';
/**
* Was the rpc declared with server streaming?
*
* Example declaration:
*
* ```proto
* rpc Foo (FooRequest) returns (stream FooResponse);
* ```
*/
readonly serverStreaming: boolean;
/**
* Was the rpc declared with client streaming?
*
* Example declaration:
*
* ```proto
* rpc Foo (stream FooRequest) returns (FooResponse);
* ```
*/
readonly clientStreaming: boolean;
/**
* The generated type handler for the input message.
* Provides methods to encode / decode binary or JSON format.
*/
readonly I: IMessageType<I>;
/**
* The generated type handler for the output message.
* Provides methods to encode / decode binary or JSON format.
*/
readonly O: IMessageType<O>;
/**
* Contains custom method options from the .proto source in JSON format.
*/
readonly options: {
[extensionName: string]: JsonValue;
};
}
/**
* Version of `MethodInfo` that does not include "service", and also allows
* the following properties to be omitted:
* - "localName": can be omitted if equal to lowerCamelCase(name)
* - "serverStreaming": omitting means `false`
* - "clientStreaming": omitting means `false`
* - "options"
*/
export declare type PartialMethodInfo<I extends object = any, O extends object = any> = PartialPartial<Omit<MethodInfo<I, O>, "service">, "localName" | "idempotency" | "serverStreaming" | "clientStreaming" | "options">;
declare type PartialPartial<T, K extends keyof T> = Partial<Pick<T, K>> & Omit<T, K>;
/**
* Turns PartialMethodInfo into MethodInfo.
*/
export declare function normalizeMethodInfo<I extends object = any, O extends object = any>(method: PartialMethodInfo<I, O>, service: ServiceInfo): MethodInfo<I, O>;
/**
* Read custom method options from a generated service client.
*
* @deprecated use readMethodOption()
*/
export declare function readMethodOptions<T extends object>(service: ServiceInfo, methodName: string | number, extensionName: string, extensionType: IMessageType<T>): T | undefined;
/**
* Read a custom method option.
*
* ```proto
* service MyService {
* rpc Get (Req) returns (Res) {
* option (acme.rpc_opt) = true;
* };
* }
* ```
*
* ```typescript
* let val = readMethodOption(MyService, 'get', 'acme.rpc_opt')
* ```
*/
export declare function readMethodOption<T extends object>(service: ServiceInfo, methodName: string | number, extensionName: string): JsonValue | undefined;
export declare function readMethodOption<T extends object>(service: ServiceInfo, methodName: string | number, extensionName: string, extensionType: IMessageType<T>): T | undefined;
/**
* Read a custom service option.
*
* ```proto
* service MyService {
* option (acme.service_opt) = true;
* }
* ```
*
* ```typescript
* let val = readServiceOption(MyService, 'acme.service_opt')
* ```
*/
export declare function readServiceOption<T extends object>(service: ServiceInfo, extensionName: string): JsonValue | undefined;
export declare function readServiceOption<T extends object>(service: ServiceInfo, extensionName: string, extensionType: IMessageType<T>): T | undefined;
export {};

View file

@ -0,0 +1,43 @@
import type { MethodInfo } from "./reflection-info";
import type { RpcStatus } from "./rpc-status";
import type { RpcMetadata } from "./rpc-metadata";
export interface RpcCallShared<I extends object, O extends object> {
/**
* Reflection information about this call.
*/
readonly method: MethodInfo<I, O>;
/**
* Request headers being sent with the request.
*
* Request headers are provided in the `meta` property of the
* `RpcOptions` passed to a call.
*/
readonly requestHeaders: Readonly<RpcMetadata>;
/**
* The response headers that the server sent.
*
* This promise will reject with a `RpcError` when the server sends an
* error status code.
*/
readonly headers: Promise<RpcMetadata>;
/**
* The response status the server replied with.
*
* This promise will resolve when the server has finished the request
* successfully.
*
* If the server replies with an error status, this promise will
* reject with a `RpcError`.
*/
readonly status: Promise<RpcStatus>;
/**
* The trailers the server attached to the response.
*
* This promise will resolve when the server has finished the request
* successfully.
*
* If the server replies with an error status, this promise will
* reject with a `RpcError`.
*/
readonly trailers: Promise<RpcMetadata>;
}

View file

@ -0,0 +1,40 @@
import type { RpcMetadata } from "./rpc-metadata";
/**
* An error that occurred while calling a RPC method.
*/
export declare class RpcError extends Error {
/**
* A status code as string. The value depends on the `RpcTransport` being
* used.
*
* For gRPC, it will be the string value of a StatusCode enum value
* https://github.com/grpc/grpc/blob/a19d8dcfb50caa81cddc25bc1a6afdd7a2f497b7/include/grpcpp/impl/codegen/status_code_enum.h#L24
*
* For Twirp, it will be one of the Twirp error codes as string:
* https://twitchtv.github.io/twirp/docs/spec_v5.html#error-codes
*/
code: string;
/**
* Metadata related to the failed call.
*/
meta: RpcMetadata;
/**
* The name of the RPC method that was called as declared in .proto
*/
methodName?: string;
/**
* The name of the RPC service that was called as declared in .proto
*
* It will be in the form of:
* - package name
* - dot "."
* - service name
*
* If the service was declared without a package, the package name and dot
* are omitted.
*/
serviceName?: string;
name: string;
constructor(message: string, code?: string, meta?: RpcMetadata);
toString(): string;
}

View file

@ -0,0 +1,16 @@
/**
* A stream of input messages.
*/
export interface RpcInputStream<T> {
/**
* Send a message down the stream.
* Only one message can be send at a time.
*/
send(message: T): Promise<void>;
/**
* Complete / close the stream.
* Can only be called if there is no pending send().
* No send() should follow this call.
*/
complete(): Promise<void>;
}

View file

@ -0,0 +1,121 @@
import type { ServerStreamingCall } from "./server-streaming-call";
import type { ClientStreamingCall } from "./client-streaming-call";
import type { DuplexStreamingCall } from "./duplex-streaming-call";
import type { RpcTransport } from "./rpc-transport";
import type { MethodInfo } from "./reflection-info";
import type { RpcOptions } from "./rpc-options";
import type { UnaryCall } from "./unary-call";
/**
* Interceptors can be used to manipulate request and response data.
*
* They are commonly used to add authentication metadata, log requests
* or implement client side caching.
*
* Interceptors are stacked. Call next() to invoke the next interceptor
* on the stack. To manipulate the request, change the data passed to
* next(). To manipulate a response, change the data returned by next().
*
* The following example adds an 'Authorization' header to unary calls:
*
* ```typescript
* interceptUnary(next, method, input, options): UnaryCall {
* if (!options.meta) {
* options.meta = {};
* }
* options.meta['Authorization'] = 'xxx';
* return next(method, input, options);
* }
* ```
*
* The following example intercepts server streaming calls. Every
* message that the server sends is emitted twice to the client:
*
* ```typescript
* interceptServerStreaming(next, method, input, options) {
* let original = next(method, input, options);
* let response = new RpcOutputStreamController();
* original.response.onNext((message, error, done) => {
* if (message) {
* response.notifyMessage(message);
* response.notifyMessage(message);
* }
* if (error)
* response.notifyError(error);
* if (done)
* response.notifyComplete();
* });
* return new ServerStreamingCall(
* original.method,
* original.requestHeaders,
* original.request,
* original.headers,
* response,
* original.status,
* original.trailers
* );
* }
* ```
*
*/
export interface RpcInterceptor {
interceptUnary?(next: NextUnaryFn, method: MethodInfo, input: object, options: RpcOptions): UnaryCall;
interceptServerStreaming?(next: NextServerStreamingFn, method: MethodInfo, input: object, options: RpcOptions): ServerStreamingCall;
interceptClientStreaming?(next: NextClientStreamingFn, method: MethodInfo, options: RpcOptions): ClientStreamingCall;
interceptDuplex?(next: NextDuplexStreamingFn, method: MethodInfo, options: RpcOptions): DuplexStreamingCall;
}
/**
* Invokes the next interceptor on the stack and returns its result.
*/
export declare type NextUnaryFn = (method: MethodInfo, input: object, options: RpcOptions) => UnaryCall;
/**
* Invokes the next interceptor on the stack and returns its result.
*/
export declare type NextServerStreamingFn = (method: MethodInfo, input: object, options: RpcOptions) => ServerStreamingCall;
/**
* Invokes the next interceptor on the stack and returns its result.
*/
export declare type NextClientStreamingFn = (method: MethodInfo, options: RpcOptions) => ClientStreamingCall;
/**
* Invokes the next interceptor on the stack and returns its result.
*/
export declare type NextDuplexStreamingFn = (method: MethodInfo, options: RpcOptions) => DuplexStreamingCall;
/**
* Creates a "stack" of of all unary interceptors specified in the given `RpcOptions`.
* Used by generated client implementations.
* @internal
*/
export declare function stackIntercept<I extends object, O extends object>(kind: "unary", transport: RpcTransport, method: MethodInfo<I, O>, options: RpcOptions, input: I): UnaryCall<I, O>;
/**
* Creates a "stack" of of all server streaming interceptors specified in the given `RpcOptions`.
* Used by generated client implementations.
* @internal
*/
export declare function stackIntercept<I extends object, O extends object>(kind: "serverStreaming", transport: RpcTransport, method: MethodInfo<I, O>, options: RpcOptions, input: I): ServerStreamingCall<I, O>;
/**
* Creates a "stack" of of all client streaming interceptors specified in the given `RpcOptions`.
* Used by generated client implementations.
* @internal
*/
export declare function stackIntercept<I extends object, O extends object>(kind: "clientStreaming", transport: RpcTransport, method: MethodInfo<I, O>, options: RpcOptions): ClientStreamingCall<I, O>;
/**
* Creates a "stack" of of all duplex streaming interceptors specified in the given `RpcOptions`.
* Used by generated client implementations.
* @internal
*/
export declare function stackIntercept<I extends object, O extends object>(kind: "duplex", transport: RpcTransport, method: MethodInfo<I, O>, options: RpcOptions): DuplexStreamingCall<I, O>;
/**
* @deprecated replaced by `stackIntercept()`, still here to support older generated code
*/
export declare function stackUnaryInterceptors<I extends object, O extends object>(transport: RpcTransport, method: MethodInfo<I, O>, input: I, options: RpcOptions): UnaryCall<I, O>;
/**
* @deprecated replaced by `stackIntercept()`, still here to support older generated code
*/
export declare function stackServerStreamingInterceptors<I extends object, O extends object>(transport: RpcTransport, method: MethodInfo<I, O>, input: I, options: RpcOptions): ServerStreamingCall<I, O>;
/**
* @deprecated replaced by `stackIntercept()`, still here to support older generated code
*/
export declare function stackClientStreamingInterceptors<I extends object, O extends object>(transport: RpcTransport, method: MethodInfo<I, O>, options: RpcOptions): ClientStreamingCall<I, O>;
/**
* @deprecated replaced by `stackIntercept()`, still here to support older generated code
*/
export declare function stackDuplexStreamingInterceptors<I extends object, O extends object>(transport: RpcTransport, method: MethodInfo<I, O>, options: RpcOptions): DuplexStreamingCall<I, O>;

View file

@ -0,0 +1,20 @@
/**
* RPC metadata provide optional additional information about a request or
* response.
*
* They can be transmitted at:
* - the start of a request (a.k.a. request headers)
* - the start of a response (a.k.a. response headers)
* - the end of a response (a.k.a. response trailers)
*
* Keys should only contain the characters a-z 0-9 _ . -
*
* Values can be US ASCII or binary. If a key ends with `-bin`, it contains
* binary data in base64 encoding.
*
* You can encode protobuf messages as binary metadata values, including
* `google.protobuf.Any`.
*/
export interface RpcMetadata {
[key: string]: string | string[];
}

View file

@ -0,0 +1,75 @@
import type { RpcMetadata } from "./rpc-metadata";
import type { BinaryReadOptions, BinaryWriteOptions, JsonReadOptions, JsonWriteOptions } from "@protobuf-ts/runtime";
import type { RpcInterceptor } from "./rpc-interceptor";
/**
* User-provided options for Remote Procedure Calls.
*
* Every generated service method accepts these options.
* They are passed on to the `RpcTransport` and can be evaluated there.
*/
export interface RpcOptions {
/**
* Meta data for the call.
*
* RPC meta data are simple key-value pairs that usually translate
* directly to HTTP request headers.
*
* If a key ends with `-bin`, it should contain binary data in base64
* encoding, allowing you to send serialized messages.
*/
meta?: RpcMetadata;
/**
* Timeout for the call in milliseconds.
* If a Date object is given, it is used as a deadline.
*/
timeout?: number | Date;
/**
* Interceptors can be used to manipulate request and response data.
* The most common use case is adding a "Authorization" header.
*/
interceptors?: RpcInterceptor[];
/**
* Options for the JSON wire format.
*
* To send or receive `google.protobuf.Any` in JSON format, you must
* provide `jsonOptions.typeRegistry` so that the runtime can discriminate
* the packed type.
*/
jsonOptions?: Partial<JsonReadOptions & JsonWriteOptions>;
/**
* Options for the binary wire format.
*/
binaryOptions?: Partial<BinaryReadOptions & BinaryWriteOptions>;
/**
* A signal to cancel a call. Can be created with an [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController).
* The npm package `abort-controller` provides a polyfill for Node.js.
*/
abort?: AbortSignal;
/**
* A `RpcTransport` implementation may allow arbitrary
* other options.
*/
[extra: string]: unknown;
}
/**
* Merges custom RPC options with defaults. Returns a new instance and keeps
* the "defaults" and the "options" unmodified.
*
* Merges `RpcMetadata` "meta", overwriting values from "defaults" with
* values from "options". Does not append values to existing entries.
*
* Merges "jsonOptions", including "jsonOptions.typeRegistry", by creating
* a new array that contains types from "options.jsonOptions.typeRegistry"
* first, then types from "defaults.jsonOptions.typeRegistry".
*
* Merges "binaryOptions".
*
* Merges "interceptors" by creating a new array that contains interceptors
* from "defaults" first, then interceptors from "options".
*
* Works with objects that extend `RpcOptions`, but only if the added
* properties are of type Date, primitive like string, boolean, or Array
* of primitives. If you have other property types, you have to merge them
* yourself.
*/
export declare function mergeRpcOptions<T extends RpcOptions>(defaults: T, options?: Partial<T>): T;

View file

@ -0,0 +1,106 @@
/**
* A stream of response messages. Messages can be read from the stream via
* the AsyncIterable interface:
*
* ```typescript
* for await (let message of response) {...
* ```
*
* Some things to note:
* - If an error occurs, the `for await` will throw it.
* - If an error occurred before the `for await` was started, `for await`
* will re-throw it.
* - If the stream is already complete, the `for await` will be empty.
* - If your `for await` consumes slower than the stream produces,
* for example because you are relaying messages in a slow operation,
* messages are queued.
*/
export interface RpcOutputStream<T extends object = object> extends AsyncIterable<T> {
/**
* Add a callback for every new datum.
* If a new message arrived, the "message" argument is set.
* If an error occurred, the "error" argument is set.
* If the stream is complete, the "complete" argument is `true`.
* Only one of the arguments is used at a time.
*/
onNext(callback: NextCallback<T>): RemoveListenerFn;
/**
* Add a callback for every new message.
*/
onMessage(callback: MessageCallback<T>): RemoveListenerFn;
/**
* Add a callback for stream completion.
* Called only when all messages have been read without error.
* The stream is closed when this callback is called.
*/
onComplete(callback: CompleteCallback): RemoveListenerFn;
/**
* Add a callback for errors.
* The stream is closed when this callback is called.
*/
onError(callback: ErrorCallback): RemoveListenerFn;
}
declare type NextCallback<T extends object> = (message: T | undefined, error: Error | undefined, complete: boolean) => void;
declare type MessageCallback<T extends object> = (message: T) => void;
declare type CompleteCallback = () => void;
declare type ErrorCallback = (reason: Error) => void;
declare type RemoveListenerFn = () => void;
/**
* A `RpcOutputStream` that you control.
*/
export declare class RpcOutputStreamController<T extends object = object> {
constructor();
onNext(callback: NextCallback<T>): RemoveListenerFn;
onMessage(callback: MessageCallback<T>): RemoveListenerFn;
onError(callback: ErrorCallback): RemoveListenerFn;
onComplete(callback: CompleteCallback): RemoveListenerFn;
private addLis;
private clearLis;
private readonly _lis;
/**
* Is this stream already closed by a completion or error?
*/
get closed(): boolean;
/**
* Emit message, close with error, or close successfully, but only one
* at a time.
* Can be used to wrap a stream by using the other stream's `onNext`.
*/
notifyNext(message: T | undefined, error: Error | undefined, complete: boolean): void;
/**
* Emits a new message. Throws if stream is closed.
*
* Triggers onNext and onMessage callbacks.
*/
notifyMessage(message: T): void;
/**
* Closes the stream with an error. Throws if stream is closed.
*
* Triggers onNext and onError callbacks.
*/
notifyError(error: Error): void;
/**
* Closes the stream successfully. Throws if stream is closed.
*
* Triggers onNext and onComplete callbacks.
*/
notifyComplete(): void;
private _closed;
private _itState;
/**
* Creates an async iterator (that can be used with `for await {...}`)
* to consume the stream.
*
* Some things to note:
* - If an error occurs, the `for await` will throw it.
* - If an error occurred before the `for await` was started, `for await`
* will re-throw it.
* - If the stream is already complete, the `for await` will be empty.
* - If your `for await` consumes slower than the stream produces,
* for example because you are relaying messages in a slow operation,
* messages are queued.
*/
[Symbol.asyncIterator](): AsyncIterator<T>;
private pushIt;
}
export {};

View file

@ -0,0 +1,24 @@
/**
* A RPC status consists of a code and a text message.
*
* The status is usually returned from the server as a response trailer,
* but a `RpcTransport` may also read the status from response headers.
*/
export interface RpcStatus {
/**
* A status code as a string. The value depends on the `RpcTransport` being
* used.
*
* For gRPC, it will be the string value of a StatusCode enum value
* https://github.com/grpc/grpc/blob/a19d8dcfb50caa81cddc25bc1a6afdd7a2f497b7/include/grpcpp/impl/codegen/status_code_enum.h#L24
*
* For Twirp, it will be one of the Twirp error codes as string:
* https://twitchtv.github.io/twirp/docs/spec_v5.html#error-codes
*
*/
code: string;
/**
* A text message that may describe the condition.
*/
detail: string;
}

View file

@ -0,0 +1,57 @@
import type { UnaryCall } from "./unary-call";
import type { ServerStreamingCall } from "./server-streaming-call";
import type { ClientStreamingCall } from "./client-streaming-call";
import type { DuplexStreamingCall } from "./duplex-streaming-call";
import type { MethodInfo } from "./reflection-info";
import type { RpcOptions } from "./rpc-options";
/**
* A `RpcTransport` executes Remote Procedure Calls defined by a protobuf
* service.
*
* This interface is the contract between a generated service client and
* some wire protocol like grpc, grpc-web, Twirp or other.
*
* The transport receives reflection information about the service and
* method being called.
*
* Some rules:
*
* a) An implementation **should** accept default `RpcOptions` (or an
* interface that extends `RpcOptions`) in the constructor.
*
* b) An implementation **must** merge the options given to `mergeOptions()`
* with its default options. If no extra options are implemented, or only
* primitive option values are used, using `mergeRpcOptions()` will
* produce the required behaviour.
*
* c) An implementation **must** pass `RpcOptions.jsonOptions` and
* `RpcOptions.binaryOptions` to the `fromBinary`, `toBinary`, `fromJson`
* and `toJson` methods when preparing a request or parsing a response.
*
* d) An implementation may support arbitrary other options, but they **must
* not** interfere with options keys of the binary or JSON options.
*/
export interface RpcTransport {
/**
* Merge call options with default options.
* Generated service clients will call this method with the users'
* call options and pass the result to the execute-method below.
*/
mergeOptions(options?: Partial<RpcOptions>): RpcOptions;
/**
* Execute an unary RPC.
*/
unary<I extends object, O extends object>(method: MethodInfo<I, O>, input: I, options: RpcOptions): UnaryCall<I, O>;
/**
* Execute a server streaming RPC.
*/
serverStreaming<I extends object, O extends object>(method: MethodInfo<I, O>, input: I, options: RpcOptions): ServerStreamingCall<I, O>;
/**
* Execute a client streaming RPC.
*/
clientStreaming<I extends object, O extends object>(method: MethodInfo<I, O>, options: RpcOptions): ClientStreamingCall<I, O>;
/**
* Execute a duplex streaming RPC.
*/
duplex<I extends object, O extends object>(method: MethodInfo<I, O>, options: RpcOptions): DuplexStreamingCall<I, O>;
}

View file

@ -0,0 +1,101 @@
import type { MethodInfo } from "./reflection-info";
import type { RpcMetadata } from "./rpc-metadata";
import type { RpcStatus } from "./rpc-status";
declare type CancelCallback = () => void;
declare type RemoveListenerFn = () => void;
declare type SendResponseHeadersFn = (headers: RpcMetadata) => void;
export declare class ServerCallContextController implements ServerCallContext {
private _cancelled;
private readonly _sendRH;
private readonly _listeners;
constructor(method: MethodInfo, headers: Readonly<RpcMetadata>, deadline: Date, sendResponseHeadersFn: SendResponseHeadersFn, defaultStatus?: RpcStatus);
/**
* Set the call cancelled.
*
* Invokes all callbacks registered with onCancel() and
* sets `cancelled = true`.
*/
notifyCancelled(): void;
/**
* Reflection information about this call.
*/
readonly method: MethodInfo;
/**
* Request headers.
*/
readonly headers: Readonly<RpcMetadata>;
/**
* Deadline for this call.
*/
readonly deadline: Date;
/**
* Trailers to send when the response is finished.
*/
trailers: RpcMetadata;
/**
* Status to send when the response is finished.
*/
status: RpcStatus;
/**
* Send response headers.
*/
sendResponseHeaders(data: RpcMetadata): void;
/**
* Is the call cancelled?
*
* When the client closes the connection before the server
* is done, the call is cancelled.
*
* If you want to cancel a request on the server, throw a
* RpcError with the CANCELLED status code.
*/
get cancelled(): boolean;
/**
* Add a callback for cancellation.
*/
onCancel(callback: CancelCallback): RemoveListenerFn;
}
/**
* Context for a RPC call on the server side.
*/
export interface ServerCallContext {
/**
* Reflection information about this call.
*/
readonly method: MethodInfo;
/**
* Request headers.
*/
readonly headers: Readonly<RpcMetadata>;
/**
* Deadline for this call.
*/
readonly deadline: Date;
/**
* Trailers to send when the response is finished.
*/
trailers: RpcMetadata;
/**
* Status to send when the response is finished.
*/
status: RpcStatus;
/**
* Send response headers.
*/
sendResponseHeaders(data: RpcMetadata): void;
/**
* Is the call cancelled?
*
* When the client closes the connection before the server
* is done, the call is cancelled.
*
* If you want to cancel a request on the server, throw a
* RpcError with the CANCELLED status code.
*/
readonly cancelled: boolean;
/**
* Add a callback for cancellation.
*/
onCancel(cb: CancelCallback): RemoveListenerFn;
}
export {};

View file

@ -0,0 +1,98 @@
import type { RpcCallShared } from "./rpc-call-shared";
import type { RpcOutputStream } from "./rpc-output-stream";
import type { RpcStatus } from "./rpc-status";
import type { MethodInfo } from "./reflection-info";
import type { RpcMetadata } from "./rpc-metadata";
/**
* A server streaming RPC call. The client provides exactly one input message
* but the server may respond with 0, 1, or more messages.
*/
export declare class ServerStreamingCall<I extends object = object, O extends object = object> implements RpcCallShared<I, O>, PromiseLike<FinishedServerStreamingCall<I, O>> {
/**
* Reflection information about this call.
*/
readonly method: MethodInfo<I, O>;
/**
* Request headers being sent with the request.
*
* Request headers are provided in the `meta` property of the
* `RpcOptions` passed to a call.
*/
readonly requestHeaders: Readonly<RpcMetadata>;
/**
* The request message being sent.
*/
readonly request: Readonly<I>;
/**
* The response headers that the server sent.
*
* This promise will reject with a `RpcError` when the server sends a
* error status code.
*/
readonly headers: Promise<RpcMetadata>;
/**
* Response messages from the server.
* This is an AsyncIterable that can be iterated with `await for .. of`.
*/
readonly responses: RpcOutputStream<O>;
/**
* The response status the server replied with.
*
* This promise will resolve when the server has finished the request
* successfully.
*
* If the server replies with an error status, this promise will
* reject with a `RpcError`.
*/
readonly status: Promise<RpcStatus>;
/**
* The trailers the server attached to the response.
*
* This promise will resolve when the server has finished the request
* successfully.
*
* If the server replies with an error status, this promise will
* reject with a `RpcError`.
*/
readonly trailers: Promise<RpcMetadata>;
constructor(method: MethodInfo<I, O>, requestHeaders: Readonly<RpcMetadata>, request: Readonly<I>, headers: Promise<RpcMetadata>, response: RpcOutputStream<O>, status: Promise<RpcStatus>, trailers: Promise<RpcMetadata>);
/**
* Instead of awaiting the response status and trailers, you can
* just as well await this call itself to receive the server outcome.
* You should first setup some listeners to the `request` to
* see the actual messages the server replied with.
*/
then<TResult1 = FinishedServerStreamingCall<I, O>, TResult2 = never>(onfulfilled?: ((value: FinishedServerStreamingCall<I, O>) => (PromiseLike<TResult1> | TResult1)) | undefined | null, onrejected?: ((reason: any) => (PromiseLike<TResult2> | TResult2)) | undefined | null): Promise<TResult1 | TResult2>;
private promiseFinished;
}
/**
* A completed server streaming RPC call. The server will not send any more
* messages.
*/
export interface FinishedServerStreamingCall<I extends object, O extends object> {
/**
* Reflection information about this call.
*/
readonly method: MethodInfo<I, O>;
/**
* Request headers being sent with the request.
*/
readonly requestHeaders: Readonly<RpcMetadata>;
/**
* The request message being sent.
*/
readonly request: Readonly<I>;
/**
* The response headers that the server sent.
*/
readonly headers: RpcMetadata;
/**
* The response status the server replied with.
* The status code will always be OK.
*/
readonly status: RpcStatus;
/**
* The trailers the server attached to the response.
*/
readonly trailers: RpcMetadata;
}

View file

@ -0,0 +1,23 @@
import { MethodInfo, PartialMethodInfo, ServiceInfo } from "./reflection-info";
import type { JsonValue } from "@protobuf-ts/runtime";
export declare class ServiceType implements ServiceInfo {
/**
* The protobuf type name of the service, including package name if
* present.
*/
readonly typeName: string;
/**
* Information for each rpc method of the service, in the order of
* declaration in the source .proto.
*/
readonly methods: MethodInfo[];
/**
* Contains custom service options from the .proto source in JSON format.
*/
readonly options: JsonOptionsMap;
constructor(typeName: string, methods: PartialMethodInfo[], options?: JsonOptionsMap);
}
declare type JsonOptionsMap = {
[extensionName: string]: JsonValue;
};
export {};

View file

@ -0,0 +1,101 @@
import { RpcError } from "./rpc-error";
import type { RpcMetadata } from "./rpc-metadata";
import type { RpcStatus } from "./rpc-status";
import type { RpcTransport } from "./rpc-transport";
import type { MethodInfo } from "./reflection-info";
import { RpcOptions } from "./rpc-options";
import { UnaryCall } from "./unary-call";
import { ServerStreamingCall } from "./server-streaming-call";
import { ClientStreamingCall } from "./client-streaming-call";
import { DuplexStreamingCall } from "./duplex-streaming-call";
/**
* Mock data for the TestTransport.
*/
interface TestTransportMockData {
/**
* Input stream behaviour for client streaming and bidi calls.
* If RpcError, sending a message rejects with this error.
* If number, sending message is delayed for N milliseconds.
* If omitted, sending a message is delayed for 10 milliseconds.
*/
inputMessage?: RpcError | number;
/**
* Input stream behaviour for client streaming and bidi calls.
* If RpcError, completing the stream rejects with this error.
* If number, completing the stream is delayed for N milliseconds.
* If omitted, completing the stream is delayed for 10 milliseconds.
*/
inputComplete?: RpcError | number;
/**
* If not provided, defaults to `{ responseHeader: "test" }`
* If RpcError, the "headers" promise is rejected with this error.
*/
headers?: RpcMetadata | RpcError;
/**
* If not provided, transport creates default output message using method info
* If RpcError, the "response" promise / stream is rejected with this error.
*/
response?: object | readonly object[] | RpcError;
/**
* If not provided, defaults to `{ code: "OK", detail: "all good" }`
* If RpcError, the "status" promise is rejected with this error.
*/
status?: RpcStatus | RpcError;
/**
* If not provided, defaults to `{ responseTrailer: "test" }`
* If RpcError, the "trailers" promise is rejected with this error.
*/
trailers?: RpcMetadata | RpcError;
}
/**
* Transport for testing.
*/
export declare class TestTransport implements RpcTransport {
static readonly defaultHeaders: Readonly<RpcMetadata>;
static readonly defaultStatus: Readonly<RpcStatus>;
static readonly defaultTrailers: Readonly<RpcMetadata>;
/**
* Sent message(s) during the last operation.
*/
get sentMessages(): any[];
/**
* Sending message(s) completed?
*/
get sendComplete(): boolean;
/**
* Suppress warning / error about uncaught rejections of
* "status" and "trailers".
*/
suppressUncaughtRejections: boolean;
private readonly data;
private readonly headerDelay;
private readonly responseDelay;
private readonly betweenResponseDelay;
private readonly afterResponseDelay;
private lastInput;
/**
* Initialize with mock data. Omitted fields have default value.
*/
constructor(data?: TestTransportMockData);
private promiseHeaders;
private promiseSingleResponse;
/**
* Pushes response messages from the mock data to the output stream.
* If an error response, status or trailers are mocked, the stream is
* closed with the respective error.
* Otherwise, stream is completed successfully.
*
* The returned promise resolves when the stream is closed. It should
* not reject. If it does, code is broken.
*/
private streamResponses;
private promiseStatus;
private promiseTrailers;
private maybeSuppressUncaught;
mergeOptions(options?: Partial<RpcOptions>): RpcOptions;
unary<I extends object, O extends object>(method: MethodInfo<I, O>, input: I, options: RpcOptions): UnaryCall<I, O>;
serverStreaming<I extends object, O extends object>(method: MethodInfo<I, O>, input: I, options: RpcOptions): ServerStreamingCall<I, O>;
clientStreaming<I extends object, O extends object>(method: MethodInfo<I, O>, options: RpcOptions): ClientStreamingCall<I, O>;
duplex<I extends object, O extends object>(method: MethodInfo<I, O>, options: RpcOptions): DuplexStreamingCall<I, O>;
}
export {};

View file

@ -0,0 +1,101 @@
import type { RpcCallShared } from "./rpc-call-shared";
import type { RpcStatus } from "./rpc-status";
import type { MethodInfo } from "./reflection-info";
import type { RpcMetadata } from "./rpc-metadata";
/**
* A unary RPC call. Unary means there is exactly one input message and
* exactly one output message unless an error occurred.
*/
export declare class UnaryCall<I extends object = object, O extends object = object> implements RpcCallShared<I, O>, PromiseLike<FinishedUnaryCall<I, O>> {
/**
* Reflection information about this call.
*/
readonly method: MethodInfo<I, O>;
/**
* Request headers being sent with the request.
*
* Request headers are provided in the `meta` property of the
* `RpcOptions` passed to a call.
*/
readonly requestHeaders: Readonly<RpcMetadata>;
/**
* The request message being sent.
*/
readonly request: Readonly<I>;
/**
* The response headers that the server sent.
*
* This promise will reject with a `RpcError` when the server sends an
* error status code.
*/
readonly headers: Promise<RpcMetadata>;
/**
* The message the server replied with.
*
* If the server does not send a message, this promise will reject with a
* `RpcError`.
*/
readonly response: Promise<O>;
/**
* The response status the server replied with.
*
* This promise will resolve when the server has finished the request
* successfully.
*
* If the server replies with an error status, this promise will
* reject with a `RpcError`.
*/
readonly status: Promise<RpcStatus>;
/**
* The trailers the server attached to the response.
*
* This promise will resolve when the server has finished the request
* successfully.
*
* If the server replies with an error status, this promise will
* reject with a `RpcError`.
*/
readonly trailers: Promise<RpcMetadata>;
constructor(method: MethodInfo<I, O>, requestHeaders: RpcMetadata, request: I, headers: Promise<RpcMetadata>, response: Promise<O>, status: Promise<RpcStatus>, trailers: Promise<RpcMetadata>);
/**
* If you are only interested in the final outcome of this call,
* you can await it to receive a `FinishedUnaryCall`.
*/
then<TResult1 = FinishedUnaryCall<I, O>, TResult2 = never>(onfulfilled?: ((value: FinishedUnaryCall<I, O>) => (PromiseLike<TResult1> | TResult1)) | undefined | null, onrejected?: ((reason: any) => (PromiseLike<TResult2> | TResult2)) | undefined | null): Promise<TResult1 | TResult2>;
private promiseFinished;
}
/**
* A completed unary RPC call. This will only exists if the RPC was
* successful.
*/
export interface FinishedUnaryCall<I extends object, O extends object> {
/**
* Reflection information about this call.
*/
readonly method: MethodInfo<I, O>;
/**
* Request headers being sent with the request.
*/
readonly requestHeaders: Readonly<RpcMetadata>;
/**
* The request message that has been sent.
*/
readonly request: Readonly<I>;
/**
* The response headers that the server sent.
*/
readonly headers: RpcMetadata;
/**
* The message the server replied with.
*/
readonly response: O;
/**
* The response status the server replied with.
* The status code will always be OK.
*/
readonly status: RpcStatus;
/**
* The trailers the server attached to the response.
*/
readonly trailers: RpcMetadata;
}

View file

@ -0,0 +1,42 @@
{
"name": "@protobuf-ts/runtime-rpc",
"version": "2.9.4",
"description": "Runtime library for RPC clients generated by the protoc plugin \"protobuf-ts\"",
"license": "Apache-2.0",
"author": "Timo Stamm <ts@timostamm.com>",
"homepage": "https://github.com/timostamm/protobuf-ts",
"keywords": [
"Protocol Buffers",
"protobuf",
"TypeScript",
"RPC"
],
"repository": {
"type": "git",
"url": "https://github.com/timostamm/protobuf-ts.git",
"directory": "packages/runtime-rpc"
},
"publishConfig": {
"access": "public"
},
"main": "./build/commonjs/index.js",
"module": "./build/es2015/index.js",
"typings": "./build/types/index.d.ts",
"sideEffects": false,
"devDependencies": {
"@types/jasmine": "^3.5.10",
"jasmine": "^3.5.0",
"jasmine-spec-reporter": "^5.0.2",
"karma": "^6.3.16",
"karma-chrome-launcher": "^3.1.0",
"karma-jasmine": "^3.3.1",
"karma-typescript": "^5.0.3",
"ts-node": "^8.10.2",
"tslib": ">=1.6.1",
"typescript": ">=3.8.3 <4"
},
"dependencies": {
"@protobuf-ts/runtime": "^2.9.4"
},
"gitHead": "1798e0d43c31eafb4b5877ef72f05abb87456823"
}