@vampgg/utils 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +467 -0
- package/dist/async-queue.d.mts +68 -0
- package/dist/async-queue.mjs +156 -0
- package/dist/bebop.d.mts +37 -0
- package/dist/bebop.mjs +434 -0
- package/dist/context-logger.d.mts +11 -0
- package/dist/context-logger.mjs +31 -0
- package/dist/create-duplex-iterator.d.mts +16 -0
- package/dist/create-duplex-iterator.mjs +36 -0
- package/dist/create-event-iterator.d.mts +39 -0
- package/dist/create-event-iterator.mjs +67 -0
- package/dist/debug-logger.d.mts +43 -0
- package/dist/debug-logger.mjs +122 -0
- package/dist/error.d.mts +27 -0
- package/dist/error.mjs +49 -0
- package/dist/extension-channel.d.mts +96 -0
- package/dist/extension-channel.mjs +377 -0
- package/dist/extension-router.d.mts +154 -0
- package/dist/extension-router.mjs +375 -0
- package/dist/memory-storage.d.mts +12 -0
- package/dist/memory-storage.mjs +18 -0
- package/dist/pino-logger.d.mts +44 -0
- package/dist/pino-logger.mjs +127 -0
- package/dist/sync-storage.d.mts +11 -0
- package/dist/sync-storage.mjs +18 -0
- package/dist/worker-channel.d.mts +99 -0
- package/dist/worker-channel.mjs +419 -0
- package/dist/worker-router.d.mts +26 -0
- package/dist/worker-router.mjs +254 -0
- package/dist/ws-channel.d.mts +108 -0
- package/dist/ws-channel.mjs +520 -0
- package/dist/ws-router.d.mts +52 -0
- package/dist/ws-router.mjs +278 -0
- package/package.json +73 -0
- package/schema/error.bop +7 -0
- package/schema/index.bop +2 -0
- package/schema/message.bop +12 -0
- package/schema/pool.bop +16 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { Message } from "./bebop.mjs";
|
|
2
|
+
import { createEventIterator } from "./create-event-iterator.mjs";
|
|
3
|
+
import { Deadline, Metadata, MethodType, TempoError, TempoStatusCode, TempoUtil, stringifyCredential } from "@tempojs/common";
|
|
4
|
+
import { EventEmitter } from "tseep";
|
|
5
|
+
import { BaseRouter, ServerContext, TempoRouterConfiguration } from "@tempojs/server";
|
|
6
|
+
//#region src/worker-router.ts
|
|
7
|
+
var TempoWorkerRouter = class extends BaseRouter {
|
|
8
|
+
events = new EventEmitter();
|
|
9
|
+
clientStreams = /* @__PURE__ */ new Map();
|
|
10
|
+
serverStreams = /* @__PURE__ */ new Map();
|
|
11
|
+
constructor(logger, registry, configuration = new TempoRouterConfiguration(), authInterceptor) {
|
|
12
|
+
super(logger, registry, configuration, authInterceptor);
|
|
13
|
+
}
|
|
14
|
+
async setAuthContext(request, context) {
|
|
15
|
+
const authHeader = request.authorization;
|
|
16
|
+
if (authHeader !== void 0 && this.authInterceptor !== void 0) {
|
|
17
|
+
const authContext = await this.authInterceptor.intercept(context, authHeader);
|
|
18
|
+
if (authContext !== void 0) context.authContext = authContext;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async invokeUnaryMethod(request, context, method, contentType) {
|
|
22
|
+
await this.setAuthContext(request, context);
|
|
23
|
+
if (this.hooks !== void 0) await this.hooks.executeRequestHooks(context);
|
|
24
|
+
const requestData = request.data;
|
|
25
|
+
const record = this.deserializeRequest(requestData, method, contentType);
|
|
26
|
+
if (this.hooks !== void 0) await this.hooks.executeDecodeHooks(context, record);
|
|
27
|
+
return await method.invoke(record, context);
|
|
28
|
+
}
|
|
29
|
+
async invokeClientStreamMethod(request, context, method, contentType) {
|
|
30
|
+
await this.setAuthContext(request, context);
|
|
31
|
+
if (this.hooks !== void 0) await this.hooks.executeRequestHooks(context);
|
|
32
|
+
const messageId = request.messageId;
|
|
33
|
+
if (this.clientStreams.has(messageId)) {
|
|
34
|
+
const invocation = this.clientStreams.get(messageId);
|
|
35
|
+
this.events.emit(messageId, request);
|
|
36
|
+
return await invocation;
|
|
37
|
+
}
|
|
38
|
+
const generator = () => {
|
|
39
|
+
return createEventIterator(({ emit, cancel }) => {
|
|
40
|
+
const eventHandler = async (message) => {
|
|
41
|
+
if (this.hooks !== void 0) await this.hooks.executeRequestHooks(context);
|
|
42
|
+
if (message.status === TempoStatusCode.CANCELLED) {
|
|
43
|
+
cancel();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const requestData = message.data;
|
|
47
|
+
const record = this.deserializeRequest(requestData, method, contentType);
|
|
48
|
+
if (this.hooks !== void 0) await this.hooks.executeDecodeHooks(context, record);
|
|
49
|
+
emit(record);
|
|
50
|
+
};
|
|
51
|
+
this.events.on(messageId, eventHandler);
|
|
52
|
+
return () => {
|
|
53
|
+
this.events.off(messageId, eventHandler);
|
|
54
|
+
this.clientStreams.delete(messageId);
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
const invocation = method.invoke(generator, context);
|
|
59
|
+
this.clientStreams.set(messageId, invocation);
|
|
60
|
+
this.events.emit(messageId, request);
|
|
61
|
+
return await invocation.finally(() => {
|
|
62
|
+
this.clientStreams.delete(messageId);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
async invokeServerStreamMethod(request, context, method, contentType) {
|
|
66
|
+
await this.setAuthContext(request, context);
|
|
67
|
+
if (this.hooks !== void 0) await this.hooks.executeRequestHooks(context);
|
|
68
|
+
const requestData = request.data;
|
|
69
|
+
const record = this.deserializeRequest(requestData, method, contentType);
|
|
70
|
+
if (!TempoUtil.isAsyncGeneratorFunction(method.invoke.bind(method))) throw new TempoError(TempoStatusCode.INTERNAL, "service method incorrect: method must be async generator");
|
|
71
|
+
if (this.hooks !== void 0) await this.hooks.executeDecodeHooks(context, record);
|
|
72
|
+
return method.invoke(record, context);
|
|
73
|
+
}
|
|
74
|
+
async invokeDuplexStreamMethod(request, context, method, contentType) {
|
|
75
|
+
await this.setAuthContext(request, context);
|
|
76
|
+
if (this.hooks !== void 0) await this.hooks.executeRequestHooks(context);
|
|
77
|
+
const messageId = request.messageId;
|
|
78
|
+
if (this.clientStreams.has(messageId)) {
|
|
79
|
+
const invocation = this.clientStreams.get(messageId);
|
|
80
|
+
this.events.emit(messageId, request);
|
|
81
|
+
return invocation;
|
|
82
|
+
}
|
|
83
|
+
if (!TempoUtil.isAsyncGeneratorFunction(method.invoke.bind(method))) throw new TempoError(TempoStatusCode.INTERNAL, "service method incorrect: method must be async generator");
|
|
84
|
+
const generator = () => {
|
|
85
|
+
return createEventIterator(({ emit, cancel }) => {
|
|
86
|
+
const eventHandler = async (message) => {
|
|
87
|
+
if (this.hooks !== void 0) await this.hooks.executeRequestHooks(context);
|
|
88
|
+
if (message.status === TempoStatusCode.CANCELLED) {
|
|
89
|
+
cancel();
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const requestData = message.data;
|
|
93
|
+
const record = this.deserializeRequest(requestData, method, contentType);
|
|
94
|
+
if (this.hooks !== void 0) await this.hooks.executeDecodeHooks(context, record);
|
|
95
|
+
emit(record);
|
|
96
|
+
};
|
|
97
|
+
this.events.on(messageId, eventHandler);
|
|
98
|
+
this.events.emit(messageId, request);
|
|
99
|
+
return () => {
|
|
100
|
+
this.events.off(messageId, eventHandler);
|
|
101
|
+
this.clientStreams.delete(messageId);
|
|
102
|
+
};
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
const invocation = method.invoke(generator, context);
|
|
106
|
+
this.clientStreams.set(messageId, invocation);
|
|
107
|
+
return invocation;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Tear down all open streams for this connection (driven by the host
|
|
111
|
+
* close/error lifecycle). Returns each server-stream generator and emits a
|
|
112
|
+
* synthetic CANCELLED to each client/duplex stream, then clears listeners.
|
|
113
|
+
*/
|
|
114
|
+
async closeConnection() {
|
|
115
|
+
for (const [id, info] of [...this.serverStreams]) {
|
|
116
|
+
info.cancelled = true;
|
|
117
|
+
await info.generator.return(void 0).catch(() => {});
|
|
118
|
+
this.serverStreams.delete(id);
|
|
119
|
+
}
|
|
120
|
+
for (const id of [...this.clientStreams.keys()]) {
|
|
121
|
+
this.events.emit(id, Message({
|
|
122
|
+
messageId: id,
|
|
123
|
+
status: TempoStatusCode.CANCELLED,
|
|
124
|
+
data: new Uint8Array()
|
|
125
|
+
}));
|
|
126
|
+
this.clientStreams.delete(id);
|
|
127
|
+
}
|
|
128
|
+
this.events.removeAllListeners();
|
|
129
|
+
}
|
|
130
|
+
async process(req, response, env) {
|
|
131
|
+
let request = Message.decode(req);
|
|
132
|
+
let context;
|
|
133
|
+
const contentType = "bebop";
|
|
134
|
+
if (request.status === TempoStatusCode.CANCELLED && request.messageId) {
|
|
135
|
+
const streamInfo = this.serverStreams.get(request.messageId);
|
|
136
|
+
if (streamInfo) {
|
|
137
|
+
streamInfo.cancelled = true;
|
|
138
|
+
await streamInfo.generator.return(void 0);
|
|
139
|
+
this.serverStreams.delete(request.messageId);
|
|
140
|
+
}
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
const methodId = request.methodId;
|
|
145
|
+
const method = this.registry.getMethod(methodId);
|
|
146
|
+
if (!method) throw new TempoError(TempoStatusCode.NOT_FOUND, `no service is registered which contains a method of '${methodId}'`);
|
|
147
|
+
const metadataHeader = request.customMetadata;
|
|
148
|
+
const metadata = metadataHeader ? Metadata.fromHttpHeader(metadataHeader) : new Metadata();
|
|
149
|
+
const previousAttempts = request.previousAttempts;
|
|
150
|
+
if (previousAttempts !== void 0 && previousAttempts > this.maxRetryAttempts) throw new TempoError(TempoStatusCode.RESOURCE_EXHAUSTED, "max retry attempts exceeded");
|
|
151
|
+
let deadline;
|
|
152
|
+
const deadlineHeader = request.deadline;
|
|
153
|
+
if (deadlineHeader !== void 0) deadline = Deadline.fromUnixTimestamp(deadlineHeader.valueOf());
|
|
154
|
+
if (deadline !== void 0 && deadline.isExpired()) throw new TempoError(TempoStatusCode.DEADLINE_EXCEEDED, "incoming request has already exceeded its deadline");
|
|
155
|
+
const outgoingMetadata = new Metadata();
|
|
156
|
+
const incomingContext = {
|
|
157
|
+
headers: new Headers(),
|
|
158
|
+
metadata
|
|
159
|
+
};
|
|
160
|
+
if (deadline !== void 0) incomingContext.deadline = deadline;
|
|
161
|
+
context = new ServerContext(incomingContext, { metadata: outgoingMetadata }, env);
|
|
162
|
+
const handleRequest = async () => {
|
|
163
|
+
let recordGenerator = void 0;
|
|
164
|
+
let record;
|
|
165
|
+
switch (method.type) {
|
|
166
|
+
case MethodType.Unary:
|
|
167
|
+
record = await this.invokeUnaryMethod(request, context, method, contentType);
|
|
168
|
+
break;
|
|
169
|
+
case MethodType.ClientStream:
|
|
170
|
+
record = await this.invokeClientStreamMethod(request, context, method, contentType);
|
|
171
|
+
break;
|
|
172
|
+
case MethodType.ServerStream:
|
|
173
|
+
recordGenerator = await this.invokeServerStreamMethod(request, context, method, contentType);
|
|
174
|
+
break;
|
|
175
|
+
case MethodType.DuplexStream:
|
|
176
|
+
recordGenerator = await this.invokeDuplexStreamMethod(request, context, method, contentType);
|
|
177
|
+
break;
|
|
178
|
+
default: throw new TempoError(TempoStatusCode.INTERNAL, "service method incorrect: unknown method type");
|
|
179
|
+
}
|
|
180
|
+
const outgoingCredential = context.outgoingCredential;
|
|
181
|
+
if (outgoingCredential) response.credential = stringifyCredential(outgoingCredential);
|
|
182
|
+
response.methodId = request.methodId;
|
|
183
|
+
response.messageId = request.messageId;
|
|
184
|
+
response.status = TempoStatusCode.OK;
|
|
185
|
+
response.timestamp = /* @__PURE__ */ new Date();
|
|
186
|
+
if (this.hooks !== void 0) await this.hooks.executeResponseHooks(context);
|
|
187
|
+
outgoingMetadata.freeze();
|
|
188
|
+
if (outgoingMetadata.size() > 0) response.customMetadata = outgoingMetadata.data;
|
|
189
|
+
if (recordGenerator !== void 0) {
|
|
190
|
+
const messageId = request.messageId;
|
|
191
|
+
const streamInfo = {
|
|
192
|
+
generator: recordGenerator,
|
|
193
|
+
cancelled: false
|
|
194
|
+
};
|
|
195
|
+
this.serverStreams.set(messageId, streamInfo);
|
|
196
|
+
const writeFrames = async () => {
|
|
197
|
+
try {
|
|
198
|
+
for await (const value of recordGenerator) {
|
|
199
|
+
if (streamInfo.cancelled) break;
|
|
200
|
+
const responseData = this.serializeResponse(value, method, "bebop");
|
|
201
|
+
response.data = new Uint8Array(responseData);
|
|
202
|
+
const encoded = Message.encode(response).slice();
|
|
203
|
+
postMessage(encoded, [encoded.buffer]);
|
|
204
|
+
}
|
|
205
|
+
} finally {
|
|
206
|
+
this.serverStreams.delete(messageId);
|
|
207
|
+
response.data = new Uint8Array();
|
|
208
|
+
response.status = TempoStatusCode.CANCELLED;
|
|
209
|
+
const encoded = Message.encode(response).slice();
|
|
210
|
+
postMessage(encoded, [encoded.buffer]);
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
if (deadline) await deadline.executeWithinDeadline(writeFrames);
|
|
214
|
+
else await writeFrames();
|
|
215
|
+
} else {
|
|
216
|
+
if (record === void 0) throw new TempoError(TempoStatusCode.INTERNAL, "service method did not return a record");
|
|
217
|
+
const responseData = this.serializeResponse(record, method, contentType);
|
|
218
|
+
response.data = new Uint8Array(responseData);
|
|
219
|
+
const encoded = Message.encode(response).slice();
|
|
220
|
+
postMessage(encoded, [encoded.buffer]);
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
if (deadline !== void 0) await deadline.executeWithinDeadline(handleRequest);
|
|
224
|
+
else await handleRequest();
|
|
225
|
+
} catch (e) {
|
|
226
|
+
let status = TempoStatusCode.UNKNOWN;
|
|
227
|
+
let message = "unknown error";
|
|
228
|
+
if (e instanceof TempoError) {
|
|
229
|
+
status = e.status;
|
|
230
|
+
message = e.message;
|
|
231
|
+
if (e.status === TempoStatusCode.INTERNAL && this.transmitInternalErrors !== true) message = "internal error";
|
|
232
|
+
if (e.status === TempoStatusCode.INTERNAL) this.logger.critical(e.message, void 0, e);
|
|
233
|
+
else this.logger.error(message, void 0, e);
|
|
234
|
+
} else if (e instanceof Error) {
|
|
235
|
+
message = e.message;
|
|
236
|
+
this.logger.error(message, void 0, e);
|
|
237
|
+
}
|
|
238
|
+
if (e instanceof Error && this.hooks !== void 0) await this.hooks.executeErrorHooks(context, e);
|
|
239
|
+
this.clientStreams.delete(request.messageId);
|
|
240
|
+
response.status = status;
|
|
241
|
+
response.msg = message;
|
|
242
|
+
response.messageId = request.messageId;
|
|
243
|
+
response.timestamp = request.timestamp;
|
|
244
|
+
response.methodId = request.methodId;
|
|
245
|
+
const encoded = Message.encode(response).slice();
|
|
246
|
+
postMessage(encoded, [encoded.buffer]);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
handle(_request, _env) {
|
|
250
|
+
throw new TempoError(TempoStatusCode.UNIMPLEMENTED, "Method not implemented.");
|
|
251
|
+
}
|
|
252
|
+
};
|
|
253
|
+
//#endregion
|
|
254
|
+
export { TempoWorkerRouter };
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { Message } from "./bebop.mjs";
|
|
2
|
+
import { BebopRecord } from "bebop";
|
|
3
|
+
import * as _tempojs_common0 from "@tempojs/common";
|
|
4
|
+
import { BebopContentType, Credential, Deadline, TempoError } from "@tempojs/common";
|
|
5
|
+
import { BaseChannel, CallCredential, CallOptions, ClientContext, MethodInfo, RetryPolicy, TempoChannelOptions } from "@tempojs/client";
|
|
6
|
+
import { EventEmitter } from "tseep";
|
|
7
|
+
import { Websocket, WebsocketOptions } from "websocket-ts";
|
|
8
|
+
|
|
9
|
+
//#region src/ws-channel.d.ts
|
|
10
|
+
type TempoWSChannelOptions = TempoChannelOptions & {
|
|
11
|
+
binaryType?: BinaryType;
|
|
12
|
+
} & WebsocketOptions;
|
|
13
|
+
/**
|
|
14
|
+
* Represents a Tempo channel for communication with a remote server.
|
|
15
|
+
*/
|
|
16
|
+
declare class TempoWSChannel extends BaseChannel {
|
|
17
|
+
static readonly defaultMaxRetryAttempts: number;
|
|
18
|
+
static readonly defaultMaxReceiveMessageSize: number;
|
|
19
|
+
static readonly defaultMaxSendMessageSize: number;
|
|
20
|
+
static readonly defaultCredential: CallCredential;
|
|
21
|
+
static readonly defaultContentType: BebopContentType;
|
|
22
|
+
ws: Websocket;
|
|
23
|
+
readonly events: EventEmitter<Record<string, (message: Message) => void>>;
|
|
24
|
+
readonly pending: Map<string, (e: unknown) => void>;
|
|
25
|
+
private closed;
|
|
26
|
+
private readonly isSecure;
|
|
27
|
+
private readonly credential;
|
|
28
|
+
private readonly userAgent;
|
|
29
|
+
private readonly maxReceiveMessageSize;
|
|
30
|
+
private readonly maxSendMessageSize;
|
|
31
|
+
private readonly _url;
|
|
32
|
+
private readonly _wsOptions;
|
|
33
|
+
get log(): _tempojs_common0.TempoLogger;
|
|
34
|
+
/**
|
|
35
|
+
* Constructs a new TempoChannel instance.
|
|
36
|
+
*
|
|
37
|
+
* @param {URL} target - The target URL for the channel.
|
|
38
|
+
* @param {TempoWSChannelOptions} options - The configuration options for the channel.
|
|
39
|
+
* @protected
|
|
40
|
+
*/
|
|
41
|
+
protected constructor(target: URL | WebSocket, options: TempoWSChannelOptions);
|
|
42
|
+
/**
|
|
43
|
+
* Creates a new TempoChannel instance for the specified address.
|
|
44
|
+
*
|
|
45
|
+
* @param {string | URL} address - The target address as a string or URL object.
|
|
46
|
+
* @param {TempoChannelOptions} [options] - Optional configuration options for the channel.
|
|
47
|
+
* @returns {TempoChannel} - A new TempoChannel instance.
|
|
48
|
+
*/
|
|
49
|
+
static forWebSocket(target: WebSocket, options?: TempoWSChannelOptions): TempoWSChannel;
|
|
50
|
+
/**
|
|
51
|
+
* Creates a new TempoChannel instance for the specified address.
|
|
52
|
+
*
|
|
53
|
+
* @param {string | URL} address - The target address as a string or URL object.
|
|
54
|
+
* @param {TempoChannelOptions} [options] - Optional configuration options for the channel.
|
|
55
|
+
* @returns {TempoChannel} - A new TempoChannel instance.
|
|
56
|
+
*/
|
|
57
|
+
static forAddress(address: string | URL, options?: TempoWSChannelOptions): TempoWSChannel;
|
|
58
|
+
private _setupWebSocket;
|
|
59
|
+
private _reconnect;
|
|
60
|
+
removeCredential(): Promise<void>;
|
|
61
|
+
getCredential(): Promise<Credential | undefined>;
|
|
62
|
+
/**
|
|
63
|
+
* Executes a function with retries according to the provided retry policy.
|
|
64
|
+
* The function will be retried if it fails with a TempoError and its status code is included in the retryableStatusCodes of the retry policy.
|
|
65
|
+
* If a deadline is provided, the deadline for each attempt will be managed by the provided deadline, but the deadline will not be reset upon each retry.
|
|
66
|
+
*
|
|
67
|
+
* @template T - The type of the result returned by the function.
|
|
68
|
+
* @param {((retryAttempt: number) => Promise<T>)} func - A function that returns a Promise with a result. The function will receive a number indicating the current retry attempt.
|
|
69
|
+
* @param {RetryPolicy} retryPolicy - An object defining the retry policy, including maxAttempts, initialBackoff, maxBackoff, backoffMultiplier, and retryableStatusCodes.
|
|
70
|
+
* @param {Deadline} [deadline] - An optional deadline object that manages the timeout for each attempt.
|
|
71
|
+
* @param {AbortController} [abortController] - An optional AbortController instance to cancel the function execution.
|
|
72
|
+
* @returns {Promise<T>} - A Promise that resolves with the result of the function if it completes within the deadline and retry policy constraints.
|
|
73
|
+
* @throws {Error} - If the function execution fails and the error does not match the retry policy, or if the maximum number of attempts is reached without a successful result.
|
|
74
|
+
*/
|
|
75
|
+
executeWithRetry<T>(func: (retryAttempt: number) => Promise<T>, retryPolicy: RetryPolicy, deadline?: Deadline, abortController?: AbortController): Promise<T>;
|
|
76
|
+
private fetchUnary;
|
|
77
|
+
private fetchClientStream;
|
|
78
|
+
private fetchServerStream;
|
|
79
|
+
private fetchDuplexStream;
|
|
80
|
+
private createRequest;
|
|
81
|
+
private processResponseHeaders;
|
|
82
|
+
waitForOpen(): Promise<void>;
|
|
83
|
+
send(message: Message): void;
|
|
84
|
+
/**
|
|
85
|
+
* Tear down the channel: reject every in-flight unary/client-stream call,
|
|
86
|
+
* remove all event listeners, and close the socket. Idempotent and safe to
|
|
87
|
+
* invoke from the socket `close`/`error` events or by an explicit caller.
|
|
88
|
+
*/
|
|
89
|
+
close(reason?: TempoError): void;
|
|
90
|
+
/**
|
|
91
|
+
* {@inheritDoc BaseChannel.startUnary}
|
|
92
|
+
*/
|
|
93
|
+
startUnary<TRequest extends BebopRecord, TResponse extends BebopRecord>(request: TRequest, context: ClientContext, method: MethodInfo<TRequest, TResponse>, options?: CallOptions): Promise<TResponse>;
|
|
94
|
+
/**
|
|
95
|
+
* {@inheritDoc BaseChannel.startClientStream}
|
|
96
|
+
*/
|
|
97
|
+
startClientStream<TRequest extends BebopRecord, TResponse extends BebopRecord>(generator: () => AsyncGenerator<TRequest, void, undefined>, context: ClientContext, method: MethodInfo<TRequest, TResponse>, options?: CallOptions): Promise<TResponse>;
|
|
98
|
+
/**
|
|
99
|
+
* {@inheritDoc BaseChannel.startServerStream}
|
|
100
|
+
*/
|
|
101
|
+
startServerStream<TRequest extends BebopRecord, TResponse extends BebopRecord>(request: TRequest, context: ClientContext, method: MethodInfo<TRequest, TResponse>, options?: CallOptions): Promise<AsyncGenerator<TResponse, void, undefined>>;
|
|
102
|
+
/**
|
|
103
|
+
* {@inheritDoc BaseChannel.startDuplexStream}
|
|
104
|
+
*/
|
|
105
|
+
startDuplexStream<TRequest extends BebopRecord, TResponse extends BebopRecord>(generator: () => AsyncGenerator<TRequest, void, undefined>, context: ClientContext, method: MethodInfo<TRequest, TResponse>, options?: CallOptions): Promise<AsyncGenerator<TResponse, void, undefined>>;
|
|
106
|
+
}
|
|
107
|
+
//#endregion
|
|
108
|
+
export { TempoWSChannel, TempoWSChannelOptions };
|