@vampgg/utils 1.0.0-beta.2 → 1.0.0-beta.4
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/README.md +20 -1
- package/dist/channel-core.d.mts +139 -0
- package/dist/channel-core.mjs +411 -0
- package/dist/extension-channel.d.mts +14 -70
- package/dist/extension-channel.mjs +17 -327
- package/dist/extension-router.d.mts +18 -8
- package/dist/extension-router.mjs +62 -209
- package/dist/router-core.d.mts +121 -0
- package/dist/router-core.mjs +282 -0
- package/dist/worker-channel.d.mts +14 -70
- package/dist/worker-channel.mjs +18 -335
- package/dist/worker-router.d.mts +1 -7
- package/dist/worker-router.mjs +40 -216
- package/dist/ws-channel.d.mts +17 -48
- package/dist/ws-channel.mjs +24 -335
- package/dist/ws-router.d.mts +1 -6
- package/dist/ws-router.mjs +46 -204
- package/package.json +3 -9
- package/dist/debug-logger.d.mts +0 -43
- package/dist/debug-logger.mjs +0 -122
- package/dist/error.d.mts +0 -27
- package/dist/error.mjs +0 -49
- package/dist/memory-storage.d.mts +0 -12
- package/dist/memory-storage.mjs +0 -18
- package/dist/sync-storage.d.mts +0 -11
- package/dist/sync-storage.mjs +0 -18
|
@@ -0,0 +1,282 @@
|
|
|
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 { ServerContext } from "@tempojs/server";
|
|
6
|
+
//#region src/router-core.ts
|
|
7
|
+
/**
|
|
8
|
+
* Parse the request's custom-metadata header into a {@link Metadata} (the
|
|
9
|
+
* default incoming metadata for the worker/extension routers).
|
|
10
|
+
*/
|
|
11
|
+
function customMetadataOf(request) {
|
|
12
|
+
const metadataHeader = request.customMetadata;
|
|
13
|
+
return metadataHeader ? Metadata.fromHttpHeader(metadataHeader) : new Metadata();
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Shared server-side routing core for the worker, WebSocket, and
|
|
17
|
+
* browser-extension routers.
|
|
18
|
+
*
|
|
19
|
+
* Owns the per-connection stream state (response demultiplexing events and
|
|
20
|
+
* in-flight client/duplex streams) plus every transport-agnostic step of
|
|
21
|
+
* dispatching one framed request: auth interception, hook execution, the four
|
|
22
|
+
* RPC invocation shapes, response population, deadline enforcement, and error
|
|
23
|
+
* mapping. Each concrete router composes an instance and passes the genuinely
|
|
24
|
+
* transport-specific bits per request via {@link ProcessTransport}.
|
|
25
|
+
*
|
|
26
|
+
* Internal to `@vampgg/utils`; the public routers are `TempoWorkerRouter`,
|
|
27
|
+
* `TempoWsRouter`, and `TempoExtensionRouter`.
|
|
28
|
+
*/
|
|
29
|
+
var RouterCore = class {
|
|
30
|
+
host;
|
|
31
|
+
/** Per-stream frame listeners keyed by messageId. */
|
|
32
|
+
events = new EventEmitter();
|
|
33
|
+
/** In-flight client/duplex stream invocations keyed by messageId. */
|
|
34
|
+
clientStreams = /* @__PURE__ */ new Map();
|
|
35
|
+
constructor(host) {
|
|
36
|
+
this.host = host;
|
|
37
|
+
}
|
|
38
|
+
async setAuthContext(request, context) {
|
|
39
|
+
const authHeader = request.authorization;
|
|
40
|
+
if (authHeader !== void 0 && this.host.authInterceptor !== void 0) {
|
|
41
|
+
const authContext = await this.host.authInterceptor.intercept(context, authHeader);
|
|
42
|
+
if (authContext !== void 0) context.authContext = authContext;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async invokeUnaryMethod(request, context, method, contentType) {
|
|
46
|
+
await this.setAuthContext(request, context);
|
|
47
|
+
const hooks = this.host.getHooks();
|
|
48
|
+
if (hooks !== void 0) await hooks.executeRequestHooks(context);
|
|
49
|
+
const requestData = request.data;
|
|
50
|
+
const record = this.host.deserializeRequest(requestData, method, contentType);
|
|
51
|
+
if (hooks !== void 0) await hooks.executeDecodeHooks(context, record);
|
|
52
|
+
return await method.invoke(record, context);
|
|
53
|
+
}
|
|
54
|
+
async invokeClientStreamMethod(request, context, method, contentType) {
|
|
55
|
+
await this.setAuthContext(request, context);
|
|
56
|
+
if (this.host.getHooks() !== void 0) await this.host.getHooks().executeRequestHooks(context);
|
|
57
|
+
const messageId = request.messageId;
|
|
58
|
+
const stream = this.clientStreams.get(messageId);
|
|
59
|
+
if (stream) {
|
|
60
|
+
this.events.emit(messageId, request);
|
|
61
|
+
return await stream;
|
|
62
|
+
}
|
|
63
|
+
const generator = () => {
|
|
64
|
+
return createEventIterator(({ emit, cancel }) => {
|
|
65
|
+
const eventHandler = async (message) => {
|
|
66
|
+
const hooks = this.host.getHooks();
|
|
67
|
+
if (hooks !== void 0) await hooks.executeRequestHooks(context);
|
|
68
|
+
if (message.status === TempoStatusCode.CANCELLED) {
|
|
69
|
+
cancel();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const requestData = message.data;
|
|
73
|
+
const record = this.host.deserializeRequest(requestData, method, contentType);
|
|
74
|
+
if (hooks !== void 0) await hooks.executeDecodeHooks(context, record);
|
|
75
|
+
emit(record);
|
|
76
|
+
};
|
|
77
|
+
this.events.on(messageId, eventHandler);
|
|
78
|
+
return () => {
|
|
79
|
+
this.events.off(messageId, eventHandler);
|
|
80
|
+
this.clientStreams.delete(messageId);
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
const invocation = method.invoke(generator, context);
|
|
85
|
+
this.clientStreams.set(messageId, invocation);
|
|
86
|
+
this.events.emit(messageId, request);
|
|
87
|
+
return await invocation.finally(() => {
|
|
88
|
+
this.clientStreams.delete(messageId);
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
async invokeServerStreamMethod(request, context, method, contentType) {
|
|
92
|
+
await this.setAuthContext(request, context);
|
|
93
|
+
const hooks = this.host.getHooks();
|
|
94
|
+
if (hooks !== void 0) await hooks.executeRequestHooks(context);
|
|
95
|
+
const requestData = request.data;
|
|
96
|
+
const record = this.host.deserializeRequest(requestData, method, contentType);
|
|
97
|
+
if (!TempoUtil.isAsyncGeneratorFunction(method.invoke.bind(method))) throw new TempoError(TempoStatusCode.INTERNAL, "service method incorrect: method must be async generator");
|
|
98
|
+
if (hooks !== void 0) await hooks.executeDecodeHooks(context, record);
|
|
99
|
+
return method.invoke(record, context);
|
|
100
|
+
}
|
|
101
|
+
async invokeDuplexStreamMethod(request, context, method, contentType) {
|
|
102
|
+
await this.setAuthContext(request, context);
|
|
103
|
+
if (this.host.getHooks() !== void 0) await this.host.getHooks().executeRequestHooks(context);
|
|
104
|
+
const messageId = request.messageId;
|
|
105
|
+
const stream = this.clientStreams.get(messageId);
|
|
106
|
+
if (stream) {
|
|
107
|
+
this.events.emit(messageId, request);
|
|
108
|
+
return stream;
|
|
109
|
+
}
|
|
110
|
+
if (!TempoUtil.isAsyncGeneratorFunction(method.invoke.bind(method))) throw new TempoError(TempoStatusCode.INTERNAL, "service method incorrect: method must be async generator");
|
|
111
|
+
const generator = () => {
|
|
112
|
+
return createEventIterator(({ emit, cancel }) => {
|
|
113
|
+
const eventHandler = async (message) => {
|
|
114
|
+
const hooks = this.host.getHooks();
|
|
115
|
+
if (hooks !== void 0) await hooks.executeRequestHooks(context);
|
|
116
|
+
if (message.status === TempoStatusCode.CANCELLED) {
|
|
117
|
+
cancel();
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
const requestData = message.data;
|
|
121
|
+
const record = this.host.deserializeRequest(requestData, method, contentType);
|
|
122
|
+
if (hooks !== void 0) await hooks.executeDecodeHooks(context, record);
|
|
123
|
+
emit(record);
|
|
124
|
+
};
|
|
125
|
+
this.events.on(messageId, eventHandler);
|
|
126
|
+
this.events.emit(messageId, request);
|
|
127
|
+
return () => {
|
|
128
|
+
this.events.off(messageId, eventHandler);
|
|
129
|
+
this.clientStreams.delete(messageId);
|
|
130
|
+
};
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
const invocation = method.invoke(generator, context);
|
|
134
|
+
this.clientStreams.set(messageId, invocation);
|
|
135
|
+
return invocation;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Emit a synthetic CANCELLED to every in-flight client/duplex stream so its
|
|
139
|
+
* generator ends, and drop the tracking entries (connection teardown).
|
|
140
|
+
*/
|
|
141
|
+
cancelClientStreams() {
|
|
142
|
+
for (const id of [...this.clientStreams.keys()]) {
|
|
143
|
+
this.events.emit(id, Message({
|
|
144
|
+
messageId: id,
|
|
145
|
+
status: TempoStatusCode.CANCELLED,
|
|
146
|
+
data: new Uint8Array()
|
|
147
|
+
}));
|
|
148
|
+
this.clientStreams.delete(id);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/** Drop every per-stream frame listener (connection teardown). */
|
|
152
|
+
removeAllListeners() {
|
|
153
|
+
this.events.removeAllListeners();
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Pump a server-stream / duplex generator into response frames and emit the
|
|
157
|
+
* terminal CANCELLED frame that tells the client the stream is complete.
|
|
158
|
+
*/
|
|
159
|
+
async writeStreamFrames(opts) {
|
|
160
|
+
const contentType = opts.contentType ?? "bebop";
|
|
161
|
+
const serializePayload = opts.serializePayload ?? ((value) => new Uint8Array(this.host.serializeResponse(value, opts.method, contentType)));
|
|
162
|
+
const terminate = async () => {
|
|
163
|
+
opts.onEnd?.();
|
|
164
|
+
opts.response.data = new Uint8Array();
|
|
165
|
+
opts.response.status = TempoStatusCode.CANCELLED;
|
|
166
|
+
await opts.send(opts.response);
|
|
167
|
+
};
|
|
168
|
+
const pump = async () => {
|
|
169
|
+
for await (const value of opts.generator) {
|
|
170
|
+
if (opts.shouldStop?.()) break;
|
|
171
|
+
opts.response.data = serializePayload(value);
|
|
172
|
+
await opts.send(opts.response);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
if (opts.alwaysTerminate) try {
|
|
176
|
+
await pump();
|
|
177
|
+
} finally {
|
|
178
|
+
await terminate();
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
await pump();
|
|
182
|
+
await terminate();
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Dispatch one decoded request envelope: resolve the method, enforce retry
|
|
187
|
+
* and deadline limits, build the {@link ServerContext}, invoke the method by
|
|
188
|
+
* type, populate and deliver the response, and map any failure onto an error
|
|
189
|
+
* frame. Transport-specific behavior is injected via `transport`.
|
|
190
|
+
*/
|
|
191
|
+
async processRequest(request, response, env, transport, contentType = "bebop") {
|
|
192
|
+
let context;
|
|
193
|
+
try {
|
|
194
|
+
const methodId = request.methodId;
|
|
195
|
+
const method = this.host.getMethod(methodId);
|
|
196
|
+
if (!method) throw new TempoError(TempoStatusCode.NOT_FOUND, `no service is registered which contains a method of '${methodId}'`);
|
|
197
|
+
const previousAttempts = request.previousAttempts;
|
|
198
|
+
if (previousAttempts !== void 0 && previousAttempts > this.host.maxRetryAttempts) throw new TempoError(TempoStatusCode.RESOURCE_EXHAUSTED, "max retry attempts exceeded");
|
|
199
|
+
let deadline;
|
|
200
|
+
const deadlineHeader = request.deadline;
|
|
201
|
+
if (deadlineHeader !== void 0) deadline = Deadline.fromUnixTimestamp(deadlineHeader.valueOf());
|
|
202
|
+
if (deadline !== void 0 && deadline.isExpired()) throw new TempoError(TempoStatusCode.DEADLINE_EXCEEDED, "incoming request has already exceeded its deadline");
|
|
203
|
+
const outgoingMetadata = new Metadata();
|
|
204
|
+
const incomingContext = {
|
|
205
|
+
headers: new Headers(),
|
|
206
|
+
metadata: transport.buildIncomingMetadata ? transport.buildIncomingMetadata(request) : customMetadataOf(request)
|
|
207
|
+
};
|
|
208
|
+
if (deadline !== void 0) incomingContext.deadline = deadline;
|
|
209
|
+
const serverContext = new ServerContext(incomingContext, { metadata: outgoingMetadata }, env);
|
|
210
|
+
context = serverContext;
|
|
211
|
+
const handleRequest = async () => {
|
|
212
|
+
let recordGenerator = void 0;
|
|
213
|
+
let record;
|
|
214
|
+
switch (method.type) {
|
|
215
|
+
case MethodType.Unary:
|
|
216
|
+
record = await this.invokeUnaryMethod(request, serverContext, method, contentType);
|
|
217
|
+
break;
|
|
218
|
+
case MethodType.ClientStream:
|
|
219
|
+
record = await this.invokeClientStreamMethod(request, serverContext, method, contentType);
|
|
220
|
+
break;
|
|
221
|
+
case MethodType.ServerStream:
|
|
222
|
+
recordGenerator = transport.invokeServerStream ? await transport.invokeServerStream(request, serverContext, method) : await this.invokeServerStreamMethod(request, serverContext, method, contentType);
|
|
223
|
+
break;
|
|
224
|
+
case MethodType.DuplexStream:
|
|
225
|
+
recordGenerator = await this.invokeDuplexStreamMethod(request, serverContext, method, contentType);
|
|
226
|
+
break;
|
|
227
|
+
default: throw new TempoError(TempoStatusCode.INTERNAL, "service method incorrect: unknown method type");
|
|
228
|
+
}
|
|
229
|
+
const outgoingCredential = serverContext.outgoingCredential;
|
|
230
|
+
if (outgoingCredential) response.credential = stringifyCredential(outgoingCredential);
|
|
231
|
+
response.methodId = request.methodId;
|
|
232
|
+
response.messageId = request.messageId;
|
|
233
|
+
response.status = TempoStatusCode.OK;
|
|
234
|
+
response.timestamp = /* @__PURE__ */ new Date();
|
|
235
|
+
transport.decorateResponse?.(response);
|
|
236
|
+
const hooks = this.host.getHooks();
|
|
237
|
+
if (hooks !== void 0) await hooks.executeResponseHooks(serverContext);
|
|
238
|
+
outgoingMetadata.freeze();
|
|
239
|
+
if (outgoingMetadata.size() > 0) response.customMetadata = outgoingMetadata.data;
|
|
240
|
+
if (recordGenerator !== void 0) {
|
|
241
|
+
const generator = recordGenerator;
|
|
242
|
+
const writeFrames = () => transport.writeStreamFrames(generator, response, method);
|
|
243
|
+
if (deadline) await deadline.executeWithinDeadline(writeFrames);
|
|
244
|
+
else await writeFrames();
|
|
245
|
+
} else {
|
|
246
|
+
if (record === void 0) throw new TempoError(TempoStatusCode.INTERNAL, "service method did not return a record");
|
|
247
|
+
const responseData = this.host.serializeResponse(record, method, contentType);
|
|
248
|
+
response.data = new Uint8Array(responseData);
|
|
249
|
+
await transport.send(response);
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
if (deadline !== void 0) await deadline.executeWithinDeadline(handleRequest);
|
|
253
|
+
else await handleRequest();
|
|
254
|
+
} catch (e) {
|
|
255
|
+
let status = TempoStatusCode.UNKNOWN;
|
|
256
|
+
let message = "unknown error";
|
|
257
|
+
if (e instanceof TempoError) {
|
|
258
|
+
status = e.status;
|
|
259
|
+
message = e.message;
|
|
260
|
+
if (e.status === TempoStatusCode.INTERNAL && this.host.transmitInternalErrors !== true) message = "internal error";
|
|
261
|
+
if (e.status === TempoStatusCode.INTERNAL) this.host.logger.critical(e.message, void 0, e);
|
|
262
|
+
else this.host.logger.error(message, void 0, e);
|
|
263
|
+
} else if (e instanceof Error) {
|
|
264
|
+
message = e.message;
|
|
265
|
+
this.host.logger.error(message, void 0, e);
|
|
266
|
+
}
|
|
267
|
+
const hooks = this.host.getHooks();
|
|
268
|
+
if (e instanceof Error && hooks !== void 0) await hooks.executeErrorHooks(context, e);
|
|
269
|
+
this.clientStreams.delete(request.messageId);
|
|
270
|
+
response.status = status;
|
|
271
|
+
response.msg = message;
|
|
272
|
+
if (transport.stampErrorResponse) {
|
|
273
|
+
response.messageId = request.messageId;
|
|
274
|
+
response.timestamp = request.timestamp;
|
|
275
|
+
response.methodId = request.methodId;
|
|
276
|
+
}
|
|
277
|
+
await transport.send(response);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
//#endregion
|
|
282
|
+
export { RouterCore };
|
|
@@ -1,24 +1,21 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { Message } from "./bebop.mjs";
|
|
2
|
+
import { CoreChannel } from "./channel-core.mjs";
|
|
3
|
+
import { CallCredential, TempoChannelOptions } from "@tempojs/client";
|
|
4
|
+
import { BebopContentType, TempoError } from "@tempojs/common";
|
|
4
5
|
|
|
5
6
|
//#region src/worker-channel.d.ts
|
|
6
7
|
/**
|
|
7
8
|
* Represents a Tempo channel for communication with a worker thread.
|
|
8
9
|
*/
|
|
9
|
-
declare class TempoWorkerChannel extends
|
|
10
|
+
declare class TempoWorkerChannel extends CoreChannel {
|
|
10
11
|
static readonly defaultMaxRetryAttempts: number;
|
|
11
12
|
static readonly defaultCredential: CallCredential;
|
|
12
13
|
static readonly defaultContentType: BebopContentType;
|
|
13
14
|
private readonly _worker;
|
|
14
|
-
private readonly events;
|
|
15
|
-
private readonly userAgent;
|
|
16
15
|
private _open;
|
|
17
16
|
private _ready;
|
|
18
17
|
private _resolveReady?;
|
|
19
18
|
private _rejectReady?;
|
|
20
|
-
readonly pending: Map<string, (e: unknown) => void>;
|
|
21
|
-
private closed;
|
|
22
19
|
get worker(): Bun.Worker;
|
|
23
20
|
get ready(): Promise<void>;
|
|
24
21
|
/**
|
|
@@ -29,71 +26,18 @@ declare class TempoWorkerChannel extends BaseChannel {
|
|
|
29
26
|
* @protected
|
|
30
27
|
*/
|
|
31
28
|
constructor(url: string, options?: TempoChannelOptions);
|
|
29
|
+
/** Reject a pending `ready` before in-flight calls are settled. */
|
|
30
|
+
protected onClosing(reason: TempoError): void;
|
|
31
|
+
/** Terminate the owned worker on {@link CoreChannel.close}. */
|
|
32
|
+
protected closeTransport(): void;
|
|
33
|
+
protected generateMessageId(): string;
|
|
32
34
|
/**
|
|
33
|
-
*
|
|
34
|
-
* remove all listeners, and terminate the owned worker. Idempotent.
|
|
35
|
-
*/
|
|
36
|
-
close(reason?: TempoError): void;
|
|
37
|
-
removeCredential(): Promise<void>;
|
|
38
|
-
getCredential(): Promise<Credential | undefined>;
|
|
39
|
-
/**
|
|
40
|
-
* Executes a function with retries according to the provided retry policy.
|
|
41
|
-
* The function will be retried if it fails with a TempoError and its status code is included in the retryableStatusCodes of the retry policy.
|
|
42
|
-
* 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.
|
|
43
|
-
*
|
|
44
|
-
* @template T - The type of the result returned by the function.
|
|
45
|
-
* @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.
|
|
46
|
-
* @param {RetryPolicy} retryPolicy - An object defining the retry policy, including maxAttempts, initialBackoff, maxBackoff, backoffMultiplier, and retryableStatusCodes.
|
|
47
|
-
* @param {Deadline} [deadline] - An optional deadline object that manages the timeout for each attempt.
|
|
48
|
-
* @param {AbortController} [abortController] - An optional AbortController instance to cancel the function execution.
|
|
49
|
-
* @returns {Promise<T>} - A Promise that resolves with the result of the function if it completes within the deadline and retry policy constraints.
|
|
50
|
-
* @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.
|
|
51
|
-
*/
|
|
52
|
-
executeWithRetry<T>(func: (retryAttempt: number) => Promise<T>, retryPolicy: RetryPolicy, deadline?: Deadline, abortController?: AbortController): Promise<T>;
|
|
53
|
-
private fetchUnary;
|
|
54
|
-
private fetchClientStream;
|
|
55
|
-
private fetchServerStream;
|
|
56
|
-
private fetchDuplexStream;
|
|
57
|
-
/**
|
|
58
|
-
* Creates a `RequestInit` object for a given payload, context, method and optional call options.
|
|
59
|
-
* This object can be used to make an HTTP request using the Fetch API.
|
|
60
|
-
*
|
|
61
|
-
* @private
|
|
62
|
-
* @param {Uint8Array} payload - The payload to be sent in the request.
|
|
63
|
-
* @param {ClientContext} context - The context of the client making the request.
|
|
64
|
-
* @param {MethodInfo<BebopRecord, BebopRecord>} method - Information about the method being called.
|
|
65
|
-
* @param {CallOptions | undefined} options - Optional configuration for the call.
|
|
66
|
-
* @returns {Promise<RequestInit>} A Promise resolving to the created `RequestInit` object.
|
|
67
|
-
* @throws {TempoError} Throws an error if there's a problem while getting the credential header.
|
|
68
|
-
*/
|
|
69
|
-
private createRequest;
|
|
70
|
-
/**
|
|
71
|
-
* Processes the headers of the response from the server, validating their integrity and correctness.
|
|
72
|
-
* Also sets the incoming metadata from the response headers to the provided context.
|
|
35
|
+
* {@inheritDoc CoreChannel.sendFrame}
|
|
73
36
|
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
* @param {ClientContext} context - The context of the client making the request.
|
|
77
|
-
* @param {MethodType} methodType - The type of method being called.
|
|
78
|
-
* @throws {TempoError} Throws an error if any validation checks fail or if there's a problem parsing or storing credentials.
|
|
79
|
-
*/
|
|
80
|
-
private processResponseHeaders;
|
|
81
|
-
/**
|
|
82
|
-
* {@inheritDoc BaseChannel.startUnary}
|
|
83
|
-
*/
|
|
84
|
-
startUnary<TRequest extends BebopRecord, TResponse extends BebopRecord>(request: TRequest, context: ClientContext, method: MethodInfo<TRequest, TResponse>, options?: CallOptions): Promise<TResponse>;
|
|
85
|
-
/**
|
|
86
|
-
* {@inheritDoc BaseChannel.startClientStream}
|
|
87
|
-
*/
|
|
88
|
-
startClientStream<TRequest extends BebopRecord, TResponse extends BebopRecord>(generator: () => AsyncGenerator<TRequest, void, undefined>, context: ClientContext, method: MethodInfo<TRequest, TResponse>, options?: CallOptions): Promise<TResponse>;
|
|
89
|
-
/**
|
|
90
|
-
* {@inheritDoc BaseChannel.startServerStream}
|
|
91
|
-
*/
|
|
92
|
-
startServerStream<TRequest extends BebopRecord, TResponse extends BebopRecord>(request: TRequest, context: ClientContext, method: MethodInfo<TRequest, TResponse>, options?: CallOptions): Promise<AsyncGenerator<TResponse, void, undefined>>;
|
|
93
|
-
/**
|
|
94
|
-
* {@inheritDoc BaseChannel.startDuplexStream}
|
|
37
|
+
* `.slice()` owns a fresh ArrayBuffer; transferring it cannot detach bebop's
|
|
38
|
+
* process-wide singleton write buffer.
|
|
95
39
|
*/
|
|
96
|
-
|
|
40
|
+
protected sendFrame(message: Message): void;
|
|
97
41
|
}
|
|
98
42
|
//#endregion
|
|
99
43
|
export { TempoWorkerChannel };
|