@trevrpc/trevrpc-js 0.2.3 → 1.0.0
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 +89 -47
- package/bin/protoc-gen-trevrpc-js.js +1 -1
- package/package.json +11 -41
- package/src/bytes.js +10 -0
- package/src/call.js +287 -0
- package/src/channel.js +131 -296
- package/src/client.js +203 -1292
- package/src/framing.js +125 -519
- package/src/generator.js +26 -103
- package/src/index.d.ts +79 -452
- package/src/index.js +4 -3
- package/src/status.js +24 -70
- package/src/wire.js +4 -59
- package/examples/greeter/README.md +0 -35
- package/examples/greeter/client.js +0 -172
- package/examples/greeter/greeter.node.trevrpc.d.ts +0 -53
- package/examples/greeter/greeter.node.trevrpc.js +0 -9
- package/examples/greeter/greeter.proto +0 -18
- package/examples/greeter/greeter.trevrpc.d.ts +0 -55
- package/examples/greeter/greeter.trevrpc.js +0 -103
- package/examples/greeter/index.html +0 -140
- package/examples/greeter/static-server.js +0 -168
- package/src/advanced.d.ts +0 -29
- package/src/advanced.js +0 -1
- package/src/browser-channel.js +0 -49
- package/src/connect.js +0 -6
- package/src/connect.node.js +0 -6
- package/src/index.node.d.ts +0 -10
- package/src/index.node.js +0 -3
- package/src/native-loader.js +0 -118
- package/src/node-advanced.d.ts +0 -27
- package/src/node-advanced.js +0 -1
- package/src/node-generated.d.ts +0 -24
- package/src/node-generated.js +0 -126
- package/src/node-index.d.ts +0 -1
- package/src/node-index.js +0 -7
- package/src/node.d.ts +0 -298
- package/src/node.js +0 -1456
- package/src/runtime.js +0 -66
- package/src/server-response.js +0 -49
- package/src/timer.js +0 -29
- package/src/webtransport.js +0 -639
package/src/client.js
CHANGED
|
@@ -1,467 +1,40 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
TrevRpcError,
|
|
7
|
-
cancelled,
|
|
8
|
-
deadlineExceeded,
|
|
9
|
-
internal,
|
|
10
|
-
invalidArgument,
|
|
11
|
-
isOkStatus,
|
|
12
|
-
resourceExhausted,
|
|
13
|
-
statusFromResponse,
|
|
14
|
-
unavailable,
|
|
15
|
-
} from "./status.js";
|
|
16
|
-
import { scheduleTimeout } from "./timer.js";
|
|
17
|
-
import { RpcKind, RpcStreamFrameKind, WireVersion } from "./wire.js";
|
|
18
|
-
|
|
19
|
-
const RequestStreamBatchSize = 16;
|
|
20
|
-
const PreparedCallOptions = Symbol("trevrpc.preparedCallOptions");
|
|
21
|
-
const EmptyMetadata = Object.freeze(Object.create(null));
|
|
22
|
-
const WriterTerminalNone = 0;
|
|
23
|
-
const WriterTerminalOk = 1;
|
|
24
|
-
const WriterTerminalNonOk = 2;
|
|
25
|
-
|
|
26
|
-
/** Internal stream-state failure with a stable diagnostic reason. */
|
|
27
|
-
class StreamStateError extends TrevRpcError {
|
|
28
|
-
constructor(reason, message) {
|
|
29
|
-
super(Code.Internal, message);
|
|
30
|
-
this.name = "StreamStateError";
|
|
31
|
-
this.reason = reason;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** Coordinates request writer completion with response stream cleanup. */
|
|
36
|
-
export class RequestWriterSettlement {
|
|
37
|
-
constructor(
|
|
38
|
-
normalizeError = (error) => error,
|
|
39
|
-
isCleanupError = () => false,
|
|
40
|
-
isTerminalError = () => false,
|
|
41
|
-
terminalErrorRequiresTerminalFirst = false,
|
|
42
|
-
) {
|
|
43
|
-
this._terminal = WriterTerminalNone;
|
|
44
|
-
this._cleanupStarted = false;
|
|
45
|
-
this._hasWriterError = false;
|
|
46
|
-
this._writerError = undefined;
|
|
47
|
-
this._errorAfterCleanup = false;
|
|
48
|
-
this._errorAfterTerminal = false;
|
|
49
|
-
this._errorReported = false;
|
|
50
|
-
this._normalizeError = normalizeError;
|
|
51
|
-
this._isCleanupError = isCleanupError;
|
|
52
|
-
this._isTerminalError = isTerminalError;
|
|
53
|
-
this._terminalErrorRequiresTerminalFirst = terminalErrorRequiresTerminalFirst;
|
|
54
|
-
this.done = Promise.resolve();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
track(writerTask) {
|
|
58
|
-
this.done = Promise.resolve(writerTask).then(
|
|
59
|
-
() => {},
|
|
60
|
-
(error) => this.recordError(error),
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
recordError(error) {
|
|
65
|
-
if (this._hasWriterError) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
this._hasWriterError = true;
|
|
69
|
-
this._writerError = this._normalizeError(error);
|
|
70
|
-
this._errorAfterCleanup = this._cleanupStarted;
|
|
71
|
-
this._errorAfterTerminal = this._terminal !== WriterTerminalNone;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
recordTerminal(statusCode) {
|
|
75
|
-
if (this._terminal === WriterTerminalNone) {
|
|
76
|
-
this._terminal = statusCode === Code.Ok ? WriterTerminalOk : WriterTerminalNonOk;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
beginCleanup() {
|
|
81
|
-
this._cleanupStarted = true;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async finish() {
|
|
85
|
-
await this.done;
|
|
86
|
-
if (
|
|
87
|
-
!this._hasWriterError ||
|
|
88
|
-
this._terminal === WriterTerminalNonOk ||
|
|
89
|
-
(this._terminal === WriterTerminalOk &&
|
|
90
|
-
(!this._terminalErrorRequiresTerminalFirst || this._errorAfterTerminal) &&
|
|
91
|
-
this._isTerminalError(this._writerError)) ||
|
|
92
|
-
(this._errorAfterCleanup && this._isCleanupError(this._writerError)) ||
|
|
93
|
-
this._errorReported
|
|
94
|
-
) {
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
this._errorReported = true;
|
|
99
|
-
throw this._writerError;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
/** Returns the default client call options. */
|
|
104
|
-
export function defaultCallOptions() {
|
|
105
|
-
return {
|
|
106
|
-
timeoutMs: undefined,
|
|
107
|
-
maxResponseBodySize: DefaultMaxFrameSize,
|
|
108
|
-
maxResponseMessages: 4096,
|
|
109
|
-
maxResponseStreamBodySize: 16 * 1024 * 1024,
|
|
110
|
-
streamIdleTimeoutMs: 30_000,
|
|
111
|
-
metadata: {},
|
|
112
|
-
signal: undefined,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** Merges call options and normalizes metadata. */
|
|
117
|
-
export function mergeCallOptions(base = {}, override = {}) {
|
|
118
|
-
if (isPreparedCallOptions(base) && !hasDefinedOptions(override)) {
|
|
119
|
-
return base;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const merged = { ...defaultCallOptions() };
|
|
123
|
-
copyDefined(merged, base);
|
|
124
|
-
copyDefined(merged, override);
|
|
125
|
-
merged.metadata = mergeMetadata(base, override);
|
|
126
|
-
return markPreparedCallOptions(merged);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function preparedCallOptions(options = {}) {
|
|
130
|
-
return isPreparedCallOptions(options) ? options : mergeCallOptions(options);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/** Calls a unary RPC and decodes the protobuf response. */
|
|
134
|
-
export async function unary(
|
|
135
|
-
transport,
|
|
136
|
-
service,
|
|
137
|
-
method,
|
|
138
|
-
requestType,
|
|
139
|
-
responseType,
|
|
140
|
-
request,
|
|
141
|
-
options = {},
|
|
142
|
-
) {
|
|
143
|
-
return (
|
|
144
|
-
await unaryWithResponse(transport, service, method, requestType, responseType, request, options)
|
|
145
|
-
).message;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/** Calls a unary RPC and returns the decoded response envelope. */
|
|
149
|
-
export async function unaryWithResponse(
|
|
150
|
-
transport,
|
|
151
|
-
service,
|
|
152
|
-
method,
|
|
153
|
-
requestType,
|
|
154
|
-
responseType,
|
|
155
|
-
request,
|
|
156
|
-
options = {},
|
|
157
|
-
) {
|
|
158
|
-
const callOptions = preparedCallOptions(options);
|
|
159
|
-
const abortScope = callAbortScope(callOptions);
|
|
160
|
-
|
|
161
|
-
try {
|
|
162
|
-
throwIfAborted(abortScope.signal);
|
|
163
|
-
const requestBody = marshalMessage(requestType, request);
|
|
164
|
-
const rpcRequest = prepareClientRequest(
|
|
165
|
-
service,
|
|
166
|
-
method,
|
|
167
|
-
RpcKind.Unary,
|
|
168
|
-
requestBody,
|
|
169
|
-
abortScope.options,
|
|
170
|
-
);
|
|
171
|
-
const response = await waitForOperation(
|
|
172
|
-
transport.call(rpcRequest, abortScope.options),
|
|
173
|
-
abortScope.signal,
|
|
174
|
-
);
|
|
175
|
-
const responseStatus = validateResponse(response, callOptions.maxResponseBodySize);
|
|
176
|
-
abortScope.terminal();
|
|
177
|
-
if (!isOkStatus(responseStatus)) {
|
|
178
|
-
throw responseStatus;
|
|
179
|
-
}
|
|
180
|
-
return {
|
|
181
|
-
message: unmarshalMessage(responseType, response.body ?? new Uint8Array(0)),
|
|
182
|
-
metadata: response.metadata ?? {},
|
|
183
|
-
};
|
|
184
|
-
} finally {
|
|
185
|
-
abortScope.cleanup();
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/** Calls a server-streaming RPC and returns a decoded response stream. */
|
|
190
|
-
export async function serverStreaming(
|
|
191
|
-
transport,
|
|
192
|
-
service,
|
|
193
|
-
method,
|
|
194
|
-
requestType,
|
|
195
|
-
responseType,
|
|
196
|
-
request,
|
|
197
|
-
options = {},
|
|
198
|
-
) {
|
|
199
|
-
const callOptions = preparedCallOptions(options);
|
|
200
|
-
const abortScope = callAbortScope(callOptions);
|
|
201
|
-
try {
|
|
202
|
-
throwIfAborted(abortScope.signal);
|
|
203
|
-
const requestBody = marshalMessage(requestType, request);
|
|
204
|
-
const rpcRequest = prepareClientRequest(
|
|
205
|
-
service,
|
|
206
|
-
method,
|
|
207
|
-
RpcKind.ServerStreaming,
|
|
208
|
-
requestBody,
|
|
209
|
-
abortScope.options,
|
|
210
|
-
);
|
|
211
|
-
const frames = await waitForOperation(
|
|
212
|
-
transport.streamingCall(rpcRequest, emptyAsyncIterable(), abortScope.options),
|
|
213
|
-
abortScope.signal,
|
|
214
|
-
);
|
|
215
|
-
return responseMessageStream(frames, responseType, abortScope.options, abortScope);
|
|
216
|
-
} catch (error) {
|
|
217
|
-
abortScope.cleanup();
|
|
218
|
-
throw error;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
/** Calls a client-streaming RPC and returns a sendable call object. */
|
|
223
|
-
export async function clientStreaming(
|
|
224
|
-
transport,
|
|
225
|
-
service,
|
|
226
|
-
method,
|
|
227
|
-
requestType,
|
|
228
|
-
responseType,
|
|
229
|
-
options = {},
|
|
230
|
-
) {
|
|
231
|
-
const callOptions = preparedCallOptions(options);
|
|
232
|
-
const abortScope = callAbortScope(callOptions, { requestCancellation: true });
|
|
233
|
-
const requests = new RequestQueue(abortScope.signal);
|
|
234
|
-
try {
|
|
235
|
-
const rpcRequest = prepareClientRequest(
|
|
236
|
-
service,
|
|
237
|
-
method,
|
|
238
|
-
RpcKind.ClientStreaming,
|
|
239
|
-
new Uint8Array(0),
|
|
240
|
-
abortScope.options,
|
|
241
|
-
);
|
|
242
|
-
const frames = await waitForOperation(
|
|
243
|
-
transport.streamingCall(
|
|
244
|
-
rpcRequest,
|
|
245
|
-
encodeRequestStream(requestType, requests, abortScope.signal),
|
|
246
|
-
abortScope.options,
|
|
247
|
-
),
|
|
248
|
-
abortScope.signal,
|
|
249
|
-
);
|
|
250
|
-
return new ClientStreamingCall(
|
|
251
|
-
requests,
|
|
252
|
-
responseMessageStream(frames, responseType, abortScope.options, abortScope, (error) =>
|
|
253
|
-
requests.close(error),
|
|
254
|
-
),
|
|
255
|
-
);
|
|
256
|
-
} catch (error) {
|
|
257
|
-
requests.close(error);
|
|
258
|
-
abortScope.cleanup();
|
|
259
|
-
throw error;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/** Calls a bidirectional-streaming RPC and returns a sendable call object. */
|
|
264
|
-
export async function bidirectionalStreaming(
|
|
265
|
-
transport,
|
|
266
|
-
service,
|
|
267
|
-
method,
|
|
268
|
-
requestType,
|
|
269
|
-
responseType,
|
|
270
|
-
options = {},
|
|
271
|
-
) {
|
|
272
|
-
const callOptions = preparedCallOptions(options);
|
|
273
|
-
const abortScope = callAbortScope(callOptions, { requestCancellation: true });
|
|
274
|
-
const requests = new RequestQueue(abortScope.signal);
|
|
275
|
-
try {
|
|
276
|
-
const rpcRequest = prepareClientRequest(
|
|
277
|
-
service,
|
|
278
|
-
method,
|
|
279
|
-
RpcKind.BidirectionalStreaming,
|
|
280
|
-
new Uint8Array(0),
|
|
281
|
-
abortScope.options,
|
|
282
|
-
);
|
|
283
|
-
const frames = await waitForOperation(
|
|
284
|
-
transport.streamingCall(
|
|
285
|
-
rpcRequest,
|
|
286
|
-
encodeRequestStream(requestType, requests, abortScope.signal),
|
|
287
|
-
abortScope.options,
|
|
288
|
-
),
|
|
289
|
-
abortScope.signal,
|
|
290
|
-
);
|
|
291
|
-
return new BidirectionalStreamingCall(
|
|
292
|
-
requests,
|
|
293
|
-
responseMessageStream(frames, responseType, abortScope.options, abortScope, (error) =>
|
|
294
|
-
requests.close(error),
|
|
295
|
-
),
|
|
296
|
-
);
|
|
297
|
-
} catch (error) {
|
|
298
|
-
requests.close(error);
|
|
299
|
-
abortScope.cleanup();
|
|
300
|
-
throw error;
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
/** A client-streaming RPC call. */
|
|
305
|
-
export class ClientStreamingCall {
|
|
306
|
-
constructor(requests, responses) {
|
|
307
|
-
this._requests = requests;
|
|
308
|
-
this._responses = responses;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/** Sends one request message. */
|
|
312
|
-
send(request) {
|
|
313
|
-
return this._requests.send(request);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/** Sends multiple request messages. */
|
|
317
|
-
sendMany(requests) {
|
|
318
|
-
return this._requests.sendMany(requests);
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/** Closes the request stream. */
|
|
322
|
-
closeSend() {
|
|
323
|
-
this._requests.close();
|
|
324
|
-
return Promise.resolve();
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/** Closes the request stream and returns the final response. */
|
|
328
|
-
async closeAndRecv() {
|
|
329
|
-
this._requests.close();
|
|
330
|
-
return await readUnaryResponseFromStream(this._responses);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/** Closes the request stream and returns the final response envelope. */
|
|
334
|
-
async closeAndRecvWithResponse() {
|
|
335
|
-
this._requests.close();
|
|
336
|
-
return await readUnaryResponseEnvelopeFromStream(this._responses);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
/** Releases call resources without waiting for the response. */
|
|
340
|
-
async close(reason) {
|
|
341
|
-
const error = cancellationReason(reason, "request stream cancelled");
|
|
342
|
-
this._requests.close(error);
|
|
343
|
-
await this._responses.close(error);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/** A bidirectional-streaming RPC call. */
|
|
348
|
-
export class BidirectionalStreamingCall {
|
|
349
|
-
constructor(requests, responses) {
|
|
350
|
-
this._requests = requests;
|
|
351
|
-
this._responses = responses;
|
|
352
|
-
this.status = responses.status;
|
|
353
|
-
this._iterator = responses[Symbol.asyncIterator]();
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/** Sends one request message. */
|
|
357
|
-
send(request) {
|
|
358
|
-
return this._requests.send(request);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
/** Sends multiple request messages. */
|
|
362
|
-
sendMany(requests) {
|
|
363
|
-
return this._requests.sendMany(requests);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/** Receives one response message, or undefined after the response stream completes. */
|
|
367
|
-
async recv() {
|
|
368
|
-
const result = await this._iterator.next();
|
|
369
|
-
return result.done ? undefined : result.value;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
/** Closes the request stream while keeping the response stream readable. */
|
|
373
|
-
closeSend() {
|
|
374
|
-
this._requests.close();
|
|
375
|
-
return Promise.resolve();
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
/** Releases call resources without waiting for more responses. */
|
|
379
|
-
async close(reason) {
|
|
380
|
-
const error = cancellationReason(reason, "request stream cancelled");
|
|
381
|
-
this._requests.close(error);
|
|
382
|
-
await this._responses.close(error);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
[Symbol.asyncIterator]() {
|
|
386
|
-
return {
|
|
387
|
-
next: async () => {
|
|
388
|
-
const value = await this.recv();
|
|
389
|
-
return value === undefined ? { done: true, value: undefined } : { done: false, value };
|
|
390
|
-
},
|
|
391
|
-
return: async () => {
|
|
392
|
-
await this.close();
|
|
393
|
-
return { done: true, value: undefined };
|
|
394
|
-
},
|
|
395
|
-
};
|
|
396
|
-
}
|
|
397
|
-
}
|
|
1
|
+
import { Call, defaultCallOptions, mergeCallOptions } from "./call.js";
|
|
2
|
+
import { marshalMessage, unmarshalMessage } from "./framing.js";
|
|
3
|
+
import { validateMetadata } from "./metadata.js";
|
|
4
|
+
import { Code, internal, statusError } from "./status.js";
|
|
5
|
+
import { RpcKind, RpcResponse, RpcStreamFrameKind } from "./wire.js";
|
|
398
6
|
|
|
399
7
|
/** Creates a service client from a generated service descriptor. */
|
|
400
8
|
export function createServiceClient(transport, service, root, options = {}) {
|
|
9
|
+
const defaults = mergeCallOptions(defaultCallOptions(), options);
|
|
401
10
|
const client = {};
|
|
402
|
-
const baseOptions = mergeCallOptions(options);
|
|
403
11
|
|
|
404
12
|
for (const [jsName, method] of Object.entries(service.methods)) {
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
|
|
13
|
+
const rpc = {
|
|
14
|
+
service: service.fullName,
|
|
15
|
+
method: method.name,
|
|
16
|
+
requestType: root.lookupType(method.inputType),
|
|
17
|
+
responseType: root.lookupType(method.outputType),
|
|
18
|
+
};
|
|
19
|
+
const resolve = (override) => mergeCallOptions(defaults, override);
|
|
408
20
|
|
|
409
21
|
switch (method.kind) {
|
|
410
22
|
case "unary":
|
|
411
|
-
client[jsName] = (request, override) =>
|
|
412
|
-
|
|
413
|
-
transport,
|
|
414
|
-
service.fullName,
|
|
415
|
-
method.name,
|
|
416
|
-
requestType,
|
|
417
|
-
responseType,
|
|
418
|
-
request,
|
|
419
|
-
callOptions(override),
|
|
420
|
-
);
|
|
23
|
+
client[jsName] = async (request, override) =>
|
|
24
|
+
(await unaryCall(transport, rpc, request, resolve(override))).message;
|
|
421
25
|
client[`${jsName}WithResponse`] = (request, override) =>
|
|
422
|
-
|
|
423
|
-
transport,
|
|
424
|
-
service.fullName,
|
|
425
|
-
method.name,
|
|
426
|
-
requestType,
|
|
427
|
-
responseType,
|
|
428
|
-
request,
|
|
429
|
-
callOptions(override),
|
|
430
|
-
);
|
|
26
|
+
unaryCall(transport, rpc, request, resolve(override));
|
|
431
27
|
break;
|
|
432
28
|
case "serverStreaming":
|
|
433
29
|
client[jsName] = (request, override) =>
|
|
434
|
-
|
|
435
|
-
transport,
|
|
436
|
-
service.fullName,
|
|
437
|
-
method.name,
|
|
438
|
-
requestType,
|
|
439
|
-
responseType,
|
|
440
|
-
request,
|
|
441
|
-
callOptions(override),
|
|
442
|
-
);
|
|
30
|
+
serverStreamingCall(transport, rpc, request, resolve(override));
|
|
443
31
|
break;
|
|
444
32
|
case "clientStreaming":
|
|
445
|
-
client[jsName] = (override) =>
|
|
446
|
-
clientStreaming(
|
|
447
|
-
transport,
|
|
448
|
-
service.fullName,
|
|
449
|
-
method.name,
|
|
450
|
-
requestType,
|
|
451
|
-
responseType,
|
|
452
|
-
callOptions(override),
|
|
453
|
-
);
|
|
33
|
+
client[jsName] = (override) => clientStreamingCall(transport, rpc, resolve(override));
|
|
454
34
|
break;
|
|
455
35
|
case "bidirectionalStreaming":
|
|
456
36
|
client[jsName] = (override) =>
|
|
457
|
-
|
|
458
|
-
transport,
|
|
459
|
-
service.fullName,
|
|
460
|
-
method.name,
|
|
461
|
-
requestType,
|
|
462
|
-
responseType,
|
|
463
|
-
callOptions(override),
|
|
464
|
-
);
|
|
37
|
+
bidirectionalStreamingCall(transport, rpc, resolve(override));
|
|
465
38
|
break;
|
|
466
39
|
default:
|
|
467
40
|
throw internal(`unsupported generated RPC kind ${JSON.stringify(method.kind)}`);
|
|
@@ -471,927 +44,265 @@ export function createServiceClient(transport, service, root, options = {}) {
|
|
|
471
44
|
return client;
|
|
472
45
|
}
|
|
473
46
|
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
const request = {
|
|
479
|
-
service,
|
|
480
|
-
method,
|
|
481
|
-
body,
|
|
482
|
-
metadata,
|
|
483
|
-
version: WireVersion,
|
|
484
|
-
};
|
|
485
|
-
const timeout = timeoutNanos(options.timeoutMs);
|
|
486
|
-
|
|
487
|
-
if (kind !== RpcKind.Unary) {
|
|
488
|
-
request.kind = kind;
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
if (timeout != null) {
|
|
492
|
-
request.timeoutNanos = timeout;
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
return request;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
function validateResponse(response, maxBodySize) {
|
|
499
|
-
if (response == null) {
|
|
500
|
-
throw internal("missing RPC response");
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
validateResponseMetadata(response.metadata ?? {});
|
|
504
|
-
|
|
505
|
-
const body = response.body ?? new Uint8Array(0);
|
|
506
|
-
if (body.byteLength > maxBodySize) {
|
|
507
|
-
throw new FrameTooLargeError(body.byteLength, maxBodySize);
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
return statusFromResponse(response);
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
function responseMessageStream(
|
|
514
|
-
frameStream,
|
|
515
|
-
responseType,
|
|
516
|
-
options,
|
|
517
|
-
abortScope,
|
|
518
|
-
onTerminal = () => {},
|
|
519
|
-
) {
|
|
520
|
-
return new ResponseStreamController(frameStream, responseType, options, abortScope, onTerminal);
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
class ResponseStreamController {
|
|
524
|
-
constructor(frameStream, responseType, options, abortScope, onTerminal) {
|
|
525
|
-
this._iterator = frameStream[Symbol.asyncIterator]();
|
|
526
|
-
this._responseType = responseType;
|
|
527
|
-
this._options = options;
|
|
528
|
-
this._abortScope = abortScope;
|
|
529
|
-
this._onTerminal = onTerminal;
|
|
530
|
-
this._useBodyBatches = typeof this._iterator.nextBodyBatch === "function";
|
|
531
|
-
this._counters = { messages: 0, streamBodySize: 0 };
|
|
532
|
-
this._messages = [];
|
|
533
|
-
this._pendingError = null;
|
|
534
|
-
this._pendingStatus = null;
|
|
535
|
-
this._complete = false;
|
|
536
|
-
this._failure = null;
|
|
537
|
-
this._cleanupPromise = null;
|
|
538
|
-
this._statusSettled = false;
|
|
539
|
-
this._operation = Promise.resolve();
|
|
540
|
-
this.status = new Promise((resolve, reject) => {
|
|
541
|
-
this._resolveStatus = resolve;
|
|
542
|
-
this._rejectStatus = reject;
|
|
543
|
-
});
|
|
544
|
-
this.status.catch(() => {});
|
|
545
|
-
this._onAbort = () => {
|
|
546
|
-
const error = signalAbortError(this._options.signal);
|
|
547
|
-
this._recordFailure(error);
|
|
548
|
-
void this._cleanup(error);
|
|
549
|
-
};
|
|
550
|
-
if (this._options.signal?.aborted) {
|
|
551
|
-
this._onAbort();
|
|
552
|
-
} else {
|
|
553
|
-
this._options.signal?.addEventListener?.("abort", this._onAbort, { once: true });
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
[Symbol.asyncIterator]() {
|
|
558
|
-
return this;
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
next() {
|
|
562
|
-
return this._serialize(() => this._next());
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
async return() {
|
|
566
|
-
await this.close();
|
|
567
|
-
return { done: true, value: undefined };
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
async close(reason) {
|
|
571
|
-
if (this._complete) {
|
|
572
|
-
await this._cleanupPromise;
|
|
573
|
-
return;
|
|
574
|
-
}
|
|
575
|
-
const error = cancellationReason(reason, "response stream cancelled");
|
|
576
|
-
this._abortScope?.abort(error);
|
|
577
|
-
this._recordFailure(error);
|
|
578
|
-
await this._cleanup(error);
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
_serialize(operation) {
|
|
582
|
-
const result = this._operation.then(operation, operation);
|
|
583
|
-
this._operation = result.catch(() => {});
|
|
584
|
-
return result;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
async _next() {
|
|
588
|
-
if (this._failure != null) {
|
|
589
|
-
throw this._failure;
|
|
590
|
-
}
|
|
591
|
-
if (this._complete) {
|
|
592
|
-
return { done: true, value: undefined };
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
try {
|
|
596
|
-
for (;;) {
|
|
597
|
-
if (this._messages.length > 0) {
|
|
598
|
-
return { done: false, value: this._messages.shift() };
|
|
599
|
-
}
|
|
600
|
-
if (this._pendingError != null) {
|
|
601
|
-
const error = this._pendingError;
|
|
602
|
-
this._pendingError = null;
|
|
603
|
-
throw error;
|
|
604
|
-
}
|
|
605
|
-
if (this._pendingStatus != null) {
|
|
606
|
-
const frame = this._pendingStatus;
|
|
607
|
-
this._pendingStatus = null;
|
|
608
|
-
await this._finishStatus(frame);
|
|
609
|
-
if (this._failure != null) {
|
|
610
|
-
throw this._failure;
|
|
611
|
-
}
|
|
612
|
-
return { done: true, value: undefined };
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
const result = await this._readNext();
|
|
616
|
-
if (result.done) {
|
|
617
|
-
throw new StreamStateError(
|
|
618
|
-
"missing_terminal_status",
|
|
619
|
-
"response stream ended before final status",
|
|
620
|
-
);
|
|
621
|
-
}
|
|
622
|
-
this._consumeBatch(result.value);
|
|
623
|
-
}
|
|
624
|
-
} catch (error) {
|
|
625
|
-
const primary = this._recordFailure(error);
|
|
626
|
-
await this._cleanup(primary);
|
|
627
|
-
throw primary;
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
_consumeBatch(value) {
|
|
632
|
-
if (this._useBodyBatches) {
|
|
633
|
-
for (const body of value.bodies) {
|
|
634
|
-
validateResponseMessageBody(body, this._options, this._counters);
|
|
635
|
-
this._messages.push(unmarshalMessage(this._responseType, body));
|
|
636
|
-
}
|
|
637
|
-
if (value.status != null) {
|
|
638
|
-
this._pendingStatus = this._claimStatus(value.status);
|
|
639
|
-
}
|
|
640
|
-
return;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
644
|
-
const frame = value[index];
|
|
645
|
-
if (frame == null) {
|
|
646
|
-
const error = new StreamStateError(
|
|
647
|
-
"missing_terminal_status",
|
|
648
|
-
"response stream ended before final status",
|
|
649
|
-
);
|
|
650
|
-
if (this._messages.length > 0) {
|
|
651
|
-
this._pendingError = error;
|
|
652
|
-
return;
|
|
653
|
-
}
|
|
654
|
-
throw error;
|
|
655
|
-
}
|
|
656
|
-
if (frame.kind === RpcStreamFrameKind.Message) {
|
|
657
|
-
const body = frame.body ?? new Uint8Array(0);
|
|
658
|
-
validateResponseMessageBody(body, this._options, this._counters);
|
|
659
|
-
this._messages.push(unmarshalMessage(this._responseType, body));
|
|
660
|
-
continue;
|
|
661
|
-
}
|
|
662
|
-
if (frame.kind === RpcStreamFrameKind.Status) {
|
|
663
|
-
if (index + 1 < value.length) {
|
|
664
|
-
throw new StreamStateError(
|
|
665
|
-
"trailing_frame",
|
|
666
|
-
"response stream contained a frame after final status",
|
|
667
|
-
);
|
|
668
|
-
}
|
|
669
|
-
this._pendingStatus = this._claimStatus(frame);
|
|
670
|
-
continue;
|
|
671
|
-
}
|
|
672
|
-
const error = invalidArgument("response stream contained an unknown frame kind");
|
|
673
|
-
error.reason = "unsupported_frame_kind";
|
|
674
|
-
throw error;
|
|
675
|
-
}
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
_claimStatus(frame) {
|
|
679
|
-
validateResponseMetadata(frame.metadata ?? {});
|
|
680
|
-
const status = {
|
|
681
|
-
code: frame.status ?? Code.Ok,
|
|
682
|
-
message: frame.message ?? "",
|
|
683
|
-
metadata: frame.metadata ?? {},
|
|
684
|
-
};
|
|
685
|
-
const terminalError =
|
|
686
|
-
status.code === Code.Ok
|
|
687
|
-
? null
|
|
688
|
-
: statusFromResponse({
|
|
689
|
-
status: status.code,
|
|
690
|
-
message: status.message,
|
|
691
|
-
metadata: status.metadata,
|
|
692
|
-
});
|
|
693
|
-
|
|
694
|
-
if (!this._abortScope?.terminal()) {
|
|
695
|
-
throw signalAbortError(this._options.signal);
|
|
696
|
-
}
|
|
697
|
-
this._onTerminal(terminalError);
|
|
698
|
-
return { status, terminalError };
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
async _finishStatus(terminal) {
|
|
702
|
-
const { status, terminalError } = terminal;
|
|
703
|
-
let end;
|
|
704
|
-
try {
|
|
705
|
-
end = await this._readNext();
|
|
706
|
-
} catch (error) {
|
|
707
|
-
if (!isMalformedTrailingRead(error)) {
|
|
708
|
-
throw error;
|
|
709
|
-
}
|
|
710
|
-
const trailing = new StreamStateError(
|
|
711
|
-
"trailing_frame",
|
|
712
|
-
"response stream did not end cleanly after final status",
|
|
713
|
-
);
|
|
714
|
-
trailing.cause = error;
|
|
715
|
-
throw trailing;
|
|
716
|
-
}
|
|
717
|
-
if (!end.done) {
|
|
718
|
-
throw new StreamStateError(
|
|
719
|
-
"trailing_frame",
|
|
720
|
-
"response stream contained a frame after final status",
|
|
721
|
-
);
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
await this._cleanup(terminalError);
|
|
725
|
-
if (terminalError != null) {
|
|
726
|
-
this._recordFailure(terminalError);
|
|
727
|
-
throw terminalError;
|
|
728
|
-
}
|
|
729
|
-
this._complete = true;
|
|
730
|
-
this._settleStatus(true, status);
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
_readNext() {
|
|
734
|
-
return this._useBodyBatches
|
|
735
|
-
? nextBodyBatchWithTimeout(
|
|
736
|
-
this._iterator,
|
|
737
|
-
this._options.streamIdleTimeoutMs,
|
|
738
|
-
this._options.signal,
|
|
739
|
-
this._abortScope?.abort,
|
|
740
|
-
)
|
|
741
|
-
: nextFrameBatchWithTimeout(
|
|
742
|
-
this._iterator,
|
|
743
|
-
this._options.streamIdleTimeoutMs,
|
|
744
|
-
this._options.signal,
|
|
745
|
-
this._abortScope?.abort,
|
|
746
|
-
);
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
_recordFailure(error) {
|
|
750
|
-
if (this._failure == null && !this._complete) {
|
|
751
|
-
this._failure = error;
|
|
752
|
-
this._settleStatus(false, error);
|
|
753
|
-
}
|
|
754
|
-
return this._failure ?? error;
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
_settleStatus(success, value) {
|
|
758
|
-
if (this._statusSettled) {
|
|
759
|
-
return;
|
|
760
|
-
}
|
|
761
|
-
this._statusSettled = true;
|
|
762
|
-
if (success) {
|
|
763
|
-
this._resolveStatus(value);
|
|
764
|
-
} else {
|
|
765
|
-
this._rejectStatus(value);
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
_cleanup(primaryError) {
|
|
770
|
-
if (this._cleanupPromise != null) {
|
|
771
|
-
return this._cleanupPromise;
|
|
772
|
-
}
|
|
773
|
-
this._cleanupPromise = (async () => {
|
|
774
|
-
this._options.signal?.removeEventListener?.("abort", this._onAbort);
|
|
775
|
-
try {
|
|
776
|
-
if (typeof this._iterator.return === "function") {
|
|
777
|
-
await this._iterator.return();
|
|
778
|
-
}
|
|
779
|
-
} catch (error) {
|
|
780
|
-
if (primaryError == null) {
|
|
781
|
-
throw error;
|
|
782
|
-
}
|
|
783
|
-
} finally {
|
|
784
|
-
this._abortScope?.cleanup();
|
|
785
|
-
}
|
|
786
|
-
})();
|
|
787
|
-
return this._cleanupPromise;
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
function validateResponseMessageBody(body, options, counters) {
|
|
792
|
-
if (options.maxResponseMessages >= 0 && counters.messages >= options.maxResponseMessages) {
|
|
793
|
-
throw resourceExhausted(
|
|
794
|
-
`response stream exceeded maximum of ${options.maxResponseMessages} messages`,
|
|
795
|
-
);
|
|
796
|
-
}
|
|
47
|
+
/** Calls a unary RPC and returns the decoded response with its metadata. */
|
|
48
|
+
export async function unaryCall(transport, rpc, request, options) {
|
|
49
|
+
const body = marshalMessage(rpc.requestType, request);
|
|
50
|
+
const call = await Call.open(transport, requestHeader(rpc, RpcKind.Unary, body), options);
|
|
797
51
|
|
|
798
|
-
|
|
799
|
-
|
|
52
|
+
let response;
|
|
53
|
+
try {
|
|
54
|
+
// The response decides the outcome, so the request side finishes in the background.
|
|
55
|
+
call.closeSend().catch(() => {});
|
|
56
|
+
response = await call.readFrame(RpcResponse);
|
|
57
|
+
validateResponseMetadata(response.metadata);
|
|
58
|
+
} catch (error) {
|
|
59
|
+
throw call.fail(error);
|
|
800
60
|
}
|
|
61
|
+
call.finish();
|
|
801
62
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
if (
|
|
805
|
-
options.maxResponseStreamBodySize >= 0 &&
|
|
806
|
-
counters.streamBodySize > options.maxResponseStreamBodySize
|
|
807
|
-
) {
|
|
808
|
-
throw resourceExhausted(
|
|
809
|
-
`response stream exceeded maximum body size of ${options.maxResponseStreamBodySize} bytes`,
|
|
810
|
-
);
|
|
63
|
+
if (response.status !== Code.Ok) {
|
|
64
|
+
throw statusError(response.status, response.message, response.metadata);
|
|
811
65
|
}
|
|
66
|
+
return {
|
|
67
|
+
message: unmarshalMessage(rpc.responseType, response.body),
|
|
68
|
+
metadata: response.metadata,
|
|
69
|
+
};
|
|
812
70
|
}
|
|
813
71
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
72
|
+
/** Calls a server-streaming RPC and returns its response stream. */
|
|
73
|
+
export async function serverStreamingCall(transport, rpc, request, options) {
|
|
74
|
+
const body = marshalMessage(rpc.requestType, request);
|
|
75
|
+
const call = await Call.open(
|
|
76
|
+
transport,
|
|
77
|
+
requestHeader(rpc, RpcKind.ServerStreaming, body),
|
|
78
|
+
options,
|
|
821
79
|
);
|
|
80
|
+
const stream = new BidirectionalStreamingCall(call, rpc);
|
|
81
|
+
stream.closeSend().catch(() => {});
|
|
82
|
+
return new ResponseStream(stream);
|
|
822
83
|
}
|
|
823
84
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
const
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
onTimeout,
|
|
831
|
-
signal,
|
|
85
|
+
/** Calls a client-streaming RPC and returns a call for sending requests. */
|
|
86
|
+
export async function clientStreamingCall(transport, rpc, options) {
|
|
87
|
+
const call = await Call.open(
|
|
88
|
+
transport,
|
|
89
|
+
requestHeader(rpc, RpcKind.ClientStreaming, new Uint8Array(0)),
|
|
90
|
+
options,
|
|
832
91
|
);
|
|
833
|
-
return
|
|
92
|
+
return new ClientStreamingCall(new BidirectionalStreamingCall(call, rpc));
|
|
834
93
|
}
|
|
835
94
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
95
|
+
/** Calls a bidirectional-streaming RPC. */
|
|
96
|
+
export async function bidirectionalStreamingCall(transport, rpc, options) {
|
|
97
|
+
const call = await Call.open(
|
|
98
|
+
transport,
|
|
99
|
+
requestHeader(rpc, RpcKind.BidirectionalStreaming, new Uint8Array(0)),
|
|
100
|
+
options,
|
|
841
101
|
);
|
|
102
|
+
return new BidirectionalStreamingCall(call, rpc);
|
|
842
103
|
}
|
|
843
104
|
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
105
|
+
/**
|
|
106
|
+
* A bidirectional-streaming RPC. Messages are received with recv() or async iteration. The call
|
|
107
|
+
* ends with the server's final status: a non-OK status makes recv() throw it, and `status`
|
|
108
|
+
* settles with the final status or the error that ended the call.
|
|
109
|
+
*/
|
|
110
|
+
export class BidirectionalStreamingCall {
|
|
111
|
+
#call;
|
|
112
|
+
#rpc;
|
|
113
|
+
/** Serializes recv() so concurrent callers never interleave frame reads. */
|
|
114
|
+
#reads = Promise.resolve();
|
|
115
|
+
#settled = false;
|
|
116
|
+
#error = null;
|
|
117
|
+
#uploadError = null;
|
|
118
|
+
#resolveStatus;
|
|
119
|
+
#rejectStatus;
|
|
120
|
+
|
|
121
|
+
/** The final status, or the error that ended the call. */
|
|
122
|
+
status = new Promise((resolve, reject) => {
|
|
123
|
+
this.#resolveStatus = resolve;
|
|
124
|
+
this.#rejectStatus = reject;
|
|
125
|
+
});
|
|
858
126
|
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
127
|
+
constructor(call, rpc) {
|
|
128
|
+
this.#call = call;
|
|
129
|
+
this.#rpc = rpc;
|
|
130
|
+
this.status.catch(() => {});
|
|
131
|
+
call.signal.addEventListener("abort", () => this.#settleFailure(call.signal.reason), {
|
|
132
|
+
once: true,
|
|
133
|
+
});
|
|
134
|
+
if (call.signal.aborted) {
|
|
135
|
+
this.#settleFailure(call.signal.reason);
|
|
865
136
|
}
|
|
866
|
-
messageCount += 1;
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
const status = stream.status == null ? { metadata: {} } : await stream.status;
|
|
870
|
-
if (messageCount === 0) {
|
|
871
|
-
throw new StreamStateError(
|
|
872
|
-
"response_cardinality",
|
|
873
|
-
"response stream ended without a response message",
|
|
874
|
-
);
|
|
875
|
-
}
|
|
876
|
-
if (messageCount !== 1) {
|
|
877
|
-
throw new StreamStateError(
|
|
878
|
-
"response_cardinality",
|
|
879
|
-
"client-streaming RPC returned more than one response message",
|
|
880
|
-
);
|
|
881
137
|
}
|
|
882
138
|
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
if (timeoutMs == null) {
|
|
888
|
-
return null;
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
if (!Number.isFinite(timeoutMs) || timeoutMs < 0) {
|
|
892
|
-
throw invalidArgument("RPC timeout must be a non-negative finite number of milliseconds");
|
|
139
|
+
/** Sends one request message. */
|
|
140
|
+
async send(message) {
|
|
141
|
+
const body = marshalMessage(this.#rpc.requestType, message);
|
|
142
|
+
await this.#recordUploadError(this.#call.sendMessage(body));
|
|
893
143
|
}
|
|
894
144
|
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
function withTimeout(promise, timeoutMs, makeError, onTimeout, signal) {
|
|
900
|
-
if (timeoutMs == null && signal == null) {
|
|
901
|
-
return promise;
|
|
145
|
+
/** Closes the request stream while keeping the response stream readable. */
|
|
146
|
+
async closeSend() {
|
|
147
|
+
await this.#recordUploadError(this.#call.closeSend());
|
|
902
148
|
}
|
|
903
149
|
|
|
904
|
-
|
|
905
|
-
|
|
150
|
+
/** Receives the next response message, or undefined after the final OK status. */
|
|
151
|
+
recv() {
|
|
152
|
+
const next = this.#reads.then(() => this.#recv());
|
|
153
|
+
this.#reads = next.catch(() => {});
|
|
154
|
+
return next;
|
|
906
155
|
}
|
|
907
156
|
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
cancelTimer();
|
|
913
|
-
signal?.removeEventListener?.("abort", onAbort);
|
|
914
|
-
};
|
|
915
|
-
const settle = (complete, value) => {
|
|
916
|
-
if (settled) {
|
|
917
|
-
return;
|
|
918
|
-
}
|
|
919
|
-
settled = true;
|
|
920
|
-
cleanup();
|
|
921
|
-
complete(value);
|
|
922
|
-
};
|
|
923
|
-
const onAbort = () => settle(reject, signalAbortError(signal));
|
|
924
|
-
|
|
925
|
-
if (timeoutMs != null && timeoutMs >= 0) {
|
|
926
|
-
cancelTimer = scheduleTimeout(() => {
|
|
927
|
-
const error = makeError();
|
|
928
|
-
onTimeout?.(error);
|
|
929
|
-
settle(reject, error);
|
|
930
|
-
}, timeoutMs);
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
if (signal != null) {
|
|
934
|
-
if (signal.aborted) {
|
|
935
|
-
onAbort();
|
|
936
|
-
return;
|
|
937
|
-
}
|
|
938
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
157
|
+
/** Cancels the call unless it already finished. */
|
|
158
|
+
async close(reason) {
|
|
159
|
+
if (!this.#settled) {
|
|
160
|
+
this.#call.cancel(reason);
|
|
939
161
|
}
|
|
940
|
-
|
|
941
|
-
promise.then(
|
|
942
|
-
(value) => {
|
|
943
|
-
settle(resolve, value);
|
|
944
|
-
},
|
|
945
|
-
(error) => {
|
|
946
|
-
settle(reject, error);
|
|
947
|
-
},
|
|
948
|
-
);
|
|
949
|
-
});
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
function signalAbortError(signal) {
|
|
953
|
-
const reason = signal?.reason;
|
|
954
|
-
return reason instanceof TrevRpcError ? reason : cancelled("RPC cancelled");
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
function cancellationReason(reason, fallback) {
|
|
958
|
-
if (reason instanceof TrevRpcError && reason.code === Code.Cancelled) {
|
|
959
|
-
return reason;
|
|
960
|
-
}
|
|
961
|
-
const error = cancelled(fallback);
|
|
962
|
-
if (reason !== undefined) {
|
|
963
|
-
Object.defineProperty(error, "cause", { configurable: true, value: reason });
|
|
964
162
|
}
|
|
965
|
-
return error;
|
|
966
|
-
}
|
|
967
163
|
|
|
968
|
-
|
|
969
|
-
return reason instanceof TrevRpcError ? reason : cancellationReason(reason, "RPC cancelled");
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
function throwIfAborted(signal) {
|
|
973
|
-
if (signal?.aborted) {
|
|
974
|
-
throw signalAbortError(signal);
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
|
|
978
|
-
function waitForOperation(promise, signal) {
|
|
979
|
-
return withTimeout(promise, null, null, null, signal);
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
function callAbortScope(options, { requestCancellation = false } = {}) {
|
|
983
|
-
const needsTransportSignal = options.signal != null || options.timeoutMs != null;
|
|
984
|
-
if (!needsTransportSignal && !requestCancellation) {
|
|
164
|
+
[Symbol.asyncIterator]() {
|
|
985
165
|
return {
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
return false;
|
|
166
|
+
next: async () => {
|
|
167
|
+
const value = await this.recv();
|
|
168
|
+
return value === undefined ? { done: true, value: undefined } : { done: false, value };
|
|
990
169
|
},
|
|
991
|
-
|
|
992
|
-
|
|
170
|
+
return: async () => {
|
|
171
|
+
await this.close();
|
|
172
|
+
return { done: true, value: undefined };
|
|
993
173
|
},
|
|
994
|
-
cleanup() {},
|
|
995
174
|
};
|
|
996
175
|
}
|
|
997
176
|
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
const controller = new AbortController();
|
|
1003
|
-
const parentSignal = options.signal;
|
|
1004
|
-
const deadlineError =
|
|
1005
|
-
options.timeoutMs == null ? null : deadlineExceeded("RPC deadline exceeded");
|
|
1006
|
-
let settlement = "active";
|
|
1007
|
-
let cleaned = false;
|
|
1008
|
-
let cancelDeadline = () => {};
|
|
1009
|
-
|
|
1010
|
-
const clearDeadline = () => {
|
|
1011
|
-
cancelDeadline();
|
|
1012
|
-
cancelDeadline = () => {};
|
|
1013
|
-
};
|
|
1014
|
-
const removeParent = () => parentSignal?.removeEventListener?.("abort", onParentAbort);
|
|
1015
|
-
const abort = (reason) => {
|
|
1016
|
-
if (settlement !== "active") {
|
|
1017
|
-
return false;
|
|
1018
|
-
}
|
|
1019
|
-
settlement = "aborted";
|
|
1020
|
-
clearDeadline();
|
|
1021
|
-
removeParent();
|
|
1022
|
-
controller.abort(normalizeAbortReason(reason));
|
|
1023
|
-
return true;
|
|
1024
|
-
};
|
|
1025
|
-
const terminal = () => {
|
|
1026
|
-
if (settlement !== "active") {
|
|
1027
|
-
return false;
|
|
177
|
+
async #recv() {
|
|
178
|
+
if (this.#error != null) {
|
|
179
|
+
throw this.#error;
|
|
1028
180
|
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
removeParent();
|
|
1032
|
-
return true;
|
|
1033
|
-
};
|
|
1034
|
-
const onParentAbort = () => abort(parentSignal.reason);
|
|
1035
|
-
|
|
1036
|
-
if (parentSignal != null) {
|
|
1037
|
-
if (parentSignal.aborted) {
|
|
1038
|
-
onParentAbort();
|
|
1039
|
-
} else {
|
|
1040
|
-
parentSignal.addEventListener("abort", onParentAbort, { once: true });
|
|
181
|
+
if (this.#settled) {
|
|
182
|
+
return undefined;
|
|
1041
183
|
}
|
|
1042
|
-
}
|
|
1043
|
-
if (deadlineError != null && settlement === "active") {
|
|
1044
|
-
cancelDeadline = scheduleTimeout(() => abort(deadlineError), options.timeoutMs);
|
|
1045
|
-
}
|
|
1046
184
|
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
cleanup() {
|
|
1053
|
-
if (cleaned) {
|
|
1054
|
-
return;
|
|
185
|
+
let frame;
|
|
186
|
+
try {
|
|
187
|
+
frame = await this.#call.readStreamFrame();
|
|
188
|
+
if (frame === null) {
|
|
189
|
+
throw this.#uploadError ?? internal("response stream ended before final status");
|
|
1055
190
|
}
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
removeParent();
|
|
1059
|
-
},
|
|
1060
|
-
};
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
class RequestQueue {
|
|
1064
|
-
constructor(signal) {
|
|
1065
|
-
this._pending = [];
|
|
1066
|
-
this._waiter = undefined;
|
|
1067
|
-
this._closed = false;
|
|
1068
|
-
this._error = undefined;
|
|
1069
|
-
this._signal = signal;
|
|
1070
|
-
this._onAbort = () => this.close(signalAbortError(signal));
|
|
1071
|
-
if (signal?.aborted) {
|
|
1072
|
-
this._onAbort();
|
|
1073
|
-
} else {
|
|
1074
|
-
signal?.addEventListener?.("abort", this._onAbort, { once: true });
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
send(value) {
|
|
1079
|
-
return this.sendMany([value]);
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
sendMany(values) {
|
|
1083
|
-
if (this._closed) {
|
|
1084
|
-
return Promise.reject(this._error ?? cancelled("request stream is closed"));
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
const batch = Array.from(values);
|
|
1088
|
-
if (batch.length === 0) {
|
|
1089
|
-
return Promise.resolve();
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
return new Promise((resolve, reject) => {
|
|
1093
|
-
let remaining = batch.length;
|
|
1094
|
-
const resolveOne = () => {
|
|
1095
|
-
remaining -= 1;
|
|
1096
|
-
if (remaining === 0) {
|
|
1097
|
-
resolve();
|
|
1098
|
-
}
|
|
1099
|
-
};
|
|
1100
|
-
for (const value of batch) {
|
|
1101
|
-
this._pending.push({ value, resolve: resolveOne, reject });
|
|
191
|
+
if (frame.kind === RpcStreamFrameKind.Message) {
|
|
192
|
+
return unmarshalMessage(this.#rpc.responseType, frame.body);
|
|
1102
193
|
}
|
|
1103
|
-
|
|
1104
|
-
})
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
close(error) {
|
|
1108
|
-
if (this._closed) {
|
|
1109
|
-
return;
|
|
194
|
+
validateResponseMetadata(frame.metadata);
|
|
195
|
+
} catch (error) {
|
|
196
|
+
throw this.#settleFailure(this.#call.fail(error));
|
|
1110
197
|
}
|
|
1111
198
|
|
|
1112
|
-
|
|
1113
|
-
this.
|
|
1114
|
-
this
|
|
1115
|
-
if (
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
}
|
|
1120
|
-
if (this._waiter != null) {
|
|
1121
|
-
const waiter = this._waiter;
|
|
1122
|
-
this._waiter = undefined;
|
|
1123
|
-
if (error == null) {
|
|
1124
|
-
waiter.resolve({ done: true, value: undefined });
|
|
1125
|
-
} else {
|
|
1126
|
-
waiter.reject(error);
|
|
1127
|
-
}
|
|
199
|
+
// A status frame is final: the request side stops and the stream drains in the background.
|
|
200
|
+
this.#call.finish();
|
|
201
|
+
this.#settled = true;
|
|
202
|
+
if (frame.status !== Code.Ok) {
|
|
203
|
+
this.#error = statusError(frame.status, frame.message, frame.metadata);
|
|
204
|
+
this.#rejectStatus(this.#error);
|
|
205
|
+
throw this.#error;
|
|
1128
206
|
}
|
|
207
|
+
this.#resolveStatus({ code: Code.Ok, message: frame.message, metadata: frame.metadata });
|
|
208
|
+
return undefined;
|
|
1129
209
|
}
|
|
1130
210
|
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
if (this._pending.length > 0) {
|
|
1137
|
-
const pending = this._pending.shift();
|
|
1138
|
-
pending.resolve();
|
|
1139
|
-
return Promise.resolve({ done: false, value: pending.value });
|
|
211
|
+
#settleFailure(error) {
|
|
212
|
+
if (!this.#settled) {
|
|
213
|
+
this.#settled = true;
|
|
214
|
+
this.#error = error;
|
|
215
|
+
this.#rejectStatus(error);
|
|
1140
216
|
}
|
|
1141
|
-
|
|
1142
|
-
return Promise.reject(this._error);
|
|
1143
|
-
}
|
|
1144
|
-
if (this._closed) {
|
|
1145
|
-
return Promise.resolve({ done: true, value: undefined });
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
return new Promise((resolve, reject) => {
|
|
1149
|
-
this._waiter = { resolve, reject };
|
|
1150
|
-
});
|
|
217
|
+
return this.#error;
|
|
1151
218
|
}
|
|
1152
219
|
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
}
|
|
1160
|
-
if (this._closed) {
|
|
1161
|
-
return Promise.resolve({ done: true, value: undefined });
|
|
220
|
+
async #recordUploadError(upload) {
|
|
221
|
+
try {
|
|
222
|
+
await upload;
|
|
223
|
+
} catch (error) {
|
|
224
|
+
this.#uploadError ??= error;
|
|
225
|
+
throw error;
|
|
1162
226
|
}
|
|
1163
|
-
|
|
1164
|
-
return new Promise((resolve, reject) => {
|
|
1165
|
-
this._waiter = { resolve, reject, batch: true, max };
|
|
1166
|
-
});
|
|
1167
227
|
}
|
|
228
|
+
}
|
|
1168
229
|
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
}
|
|
230
|
+
/** A client-streaming RPC: send requests, then close and receive the single response. */
|
|
231
|
+
export class ClientStreamingCall {
|
|
232
|
+
#call;
|
|
1173
233
|
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
const values = Array.from({ length: count });
|
|
1177
|
-
for (let i = 0; i < count; i++) {
|
|
1178
|
-
const pending = this._pending.shift();
|
|
1179
|
-
pending.resolve();
|
|
1180
|
-
values[i] = pending.value;
|
|
1181
|
-
}
|
|
1182
|
-
return values;
|
|
234
|
+
constructor(call) {
|
|
235
|
+
this.#call = call;
|
|
1183
236
|
}
|
|
1184
237
|
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
}
|
|
1189
|
-
|
|
1190
|
-
const waiter = this._waiter;
|
|
1191
|
-
this._waiter = undefined;
|
|
1192
|
-
if (waiter.batch) {
|
|
1193
|
-
queueMicrotask(() => this._resolveBatchWaiter(waiter));
|
|
1194
|
-
return;
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
const pending = this._pending.shift();
|
|
1198
|
-
pending.resolve();
|
|
1199
|
-
waiter.resolve({ done: false, value: pending.value });
|
|
238
|
+
/** Sends one request message. */
|
|
239
|
+
send(message) {
|
|
240
|
+
return this.#call.send(message);
|
|
1200
241
|
}
|
|
1201
242
|
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
} else if (this._error != null) {
|
|
1206
|
-
waiter.reject(this._error);
|
|
1207
|
-
} else if (this._closed) {
|
|
1208
|
-
waiter.resolve({ done: true, value: undefined });
|
|
1209
|
-
} else {
|
|
1210
|
-
this._waiter = waiter;
|
|
1211
|
-
}
|
|
243
|
+
/** Closes the request stream and returns the final response. */
|
|
244
|
+
async closeAndRecv() {
|
|
245
|
+
return (await this.closeAndRecvWithResponse()).message;
|
|
1212
246
|
}
|
|
1213
|
-
}
|
|
1214
247
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
return {
|
|
1219
|
-
[Symbol.asyncIterator]() {
|
|
1220
|
-
return this;
|
|
1221
|
-
},
|
|
1222
|
-
async next() {
|
|
1223
|
-
if (done) {
|
|
1224
|
-
return { done: true, value: undefined };
|
|
1225
|
-
}
|
|
1226
|
-
const result = await nextRequest(iterator, signal);
|
|
1227
|
-
if (result.done) {
|
|
1228
|
-
done = true;
|
|
1229
|
-
return { done: true, value: undefined };
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
return { done: false, value: marshalMessage(requestType, result.value) };
|
|
1233
|
-
},
|
|
1234
|
-
async nextBatch(max = RequestStreamBatchSize) {
|
|
1235
|
-
if (done) {
|
|
1236
|
-
return { done: true, value: undefined };
|
|
1237
|
-
}
|
|
1238
|
-
const result = await nextRequestBatch(iterator, signal, max);
|
|
1239
|
-
if (result.done) {
|
|
1240
|
-
done = true;
|
|
1241
|
-
return { done: true, value: undefined };
|
|
1242
|
-
}
|
|
248
|
+
/** Closes the request stream and returns the final response with its metadata. */
|
|
249
|
+
async closeAndRecvWithResponse() {
|
|
250
|
+
this.#call.closeSend().catch(() => {});
|
|
1243
251
|
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
done = true;
|
|
1251
|
-
if (signal?.aborted && typeof iterator.return === "function") {
|
|
1252
|
-
await iterator.return();
|
|
252
|
+
let message;
|
|
253
|
+
let count = 0;
|
|
254
|
+
for (;;) {
|
|
255
|
+
const next = await this.#call.recv();
|
|
256
|
+
if (next === undefined) {
|
|
257
|
+
break;
|
|
1253
258
|
}
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
return
|
|
1262
|
-
}
|
|
1263
|
-
|
|
1264
|
-
if (typeof requests?.[Symbol.iterator] === "function") {
|
|
1265
|
-
const iterator = requests[Symbol.iterator]();
|
|
1266
|
-
return {
|
|
1267
|
-
next() {
|
|
1268
|
-
return Promise.resolve(iterator.next());
|
|
1269
|
-
},
|
|
1270
|
-
return() {
|
|
1271
|
-
return Promise.resolve(
|
|
1272
|
-
typeof iterator.return === "function"
|
|
1273
|
-
? iterator.return()
|
|
1274
|
-
: { done: true, value: undefined },
|
|
1275
|
-
);
|
|
1276
|
-
},
|
|
1277
|
-
};
|
|
1278
|
-
}
|
|
1279
|
-
|
|
1280
|
-
throw invalidArgument("request stream must be an async iterable or iterable");
|
|
1281
|
-
}
|
|
1282
|
-
|
|
1283
|
-
function nextRequest(iterator, signal) {
|
|
1284
|
-
return nextRequestResult(() => iterator.next(), signal);
|
|
1285
|
-
}
|
|
1286
|
-
|
|
1287
|
-
async function nextRequestBatch(iterator, signal, max) {
|
|
1288
|
-
if (typeof iterator.nextBatch === "function") {
|
|
1289
|
-
return await nextRequestResult(() => iterator.nextBatch(max), signal);
|
|
259
|
+
message ??= next;
|
|
260
|
+
count += 1;
|
|
261
|
+
}
|
|
262
|
+
if (count !== 1) {
|
|
263
|
+
throw internal(`client-streaming RPC returned ${count} response messages instead of one`);
|
|
264
|
+
}
|
|
265
|
+
const status = await this.#call.status;
|
|
266
|
+
return { message, metadata: status.metadata };
|
|
1290
267
|
}
|
|
1291
268
|
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
function nextRequestResult(next, signal) {
|
|
1297
|
-
if (signal?.aborted) {
|
|
1298
|
-
return Promise.reject(signal.reason ?? cancelled("request stream cancelled"));
|
|
1299
|
-
}
|
|
1300
|
-
if (signal == null) {
|
|
1301
|
-
return next();
|
|
269
|
+
/** Cancels the call unless it already finished. */
|
|
270
|
+
close(reason) {
|
|
271
|
+
return this.#call.close(reason);
|
|
1302
272
|
}
|
|
1303
|
-
|
|
1304
|
-
return new Promise((resolve, reject) => {
|
|
1305
|
-
const onAbort = () => reject(signal.reason ?? cancelled("request stream cancelled"));
|
|
1306
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
1307
|
-
next().then(
|
|
1308
|
-
(value) => {
|
|
1309
|
-
signal.removeEventListener("abort", onAbort);
|
|
1310
|
-
resolve(value);
|
|
1311
|
-
},
|
|
1312
|
-
(error) => {
|
|
1313
|
-
signal.removeEventListener("abort", onAbort);
|
|
1314
|
-
reject(error);
|
|
1315
|
-
},
|
|
1316
|
-
);
|
|
1317
|
-
});
|
|
1318
273
|
}
|
|
1319
274
|
|
|
1320
|
-
|
|
275
|
+
/** The response stream of a server-streaming RPC. */
|
|
276
|
+
export class ResponseStream {
|
|
277
|
+
#call;
|
|
1321
278
|
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
if (value !== undefined && key !== "metadata") {
|
|
1325
|
-
target[key] = value;
|
|
1326
|
-
}
|
|
279
|
+
constructor(call) {
|
|
280
|
+
this.#call = call;
|
|
1327
281
|
}
|
|
1328
|
-
}
|
|
1329
|
-
|
|
1330
|
-
function mergeMetadata(base, override) {
|
|
1331
|
-
const baseHasMetadata = hasMetadataEntries(base?.metadata);
|
|
1332
|
-
const overrideHasMetadata = hasMetadataEntries(override?.metadata);
|
|
1333
282
|
|
|
1334
|
-
|
|
1335
|
-
|
|
283
|
+
/** The final status after the stream ends, or the error that ended it. */
|
|
284
|
+
get status() {
|
|
285
|
+
return this.#call.status;
|
|
1336
286
|
}
|
|
1337
287
|
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
: normalizeMetadata(base.metadata);
|
|
288
|
+
/** Cancels the call unless it already finished. */
|
|
289
|
+
close(reason) {
|
|
290
|
+
return this.#call.close(reason);
|
|
1342
291
|
}
|
|
1343
292
|
|
|
1344
|
-
|
|
1345
|
-
return
|
|
1346
|
-
? (override.metadata ?? EmptyMetadata)
|
|
1347
|
-
: normalizeMetadata(override.metadata);
|
|
293
|
+
[Symbol.asyncIterator]() {
|
|
294
|
+
return this.#call[Symbol.asyncIterator]();
|
|
1348
295
|
}
|
|
1349
|
-
|
|
1350
|
-
const metadata = Object.assign(
|
|
1351
|
-
Object.create(null),
|
|
1352
|
-
isPreparedCallOptions(base) ? base.metadata : normalizeMetadata(base.metadata),
|
|
1353
|
-
isPreparedCallOptions(override) ? override.metadata : normalizeMetadata(override.metadata),
|
|
1354
|
-
);
|
|
1355
|
-
validateMetadata(metadata);
|
|
1356
|
-
return metadata;
|
|
1357
296
|
}
|
|
1358
297
|
|
|
1359
|
-
function
|
|
1360
|
-
|
|
1361
|
-
return false;
|
|
1362
|
-
}
|
|
1363
|
-
if (metadata instanceof Map) {
|
|
1364
|
-
return metadata.size > 0;
|
|
1365
|
-
}
|
|
1366
|
-
for (const _key in metadata) {
|
|
1367
|
-
return true;
|
|
1368
|
-
}
|
|
1369
|
-
return false;
|
|
298
|
+
function requestHeader(rpc, kind, body) {
|
|
299
|
+
return { service: rpc.service, method: rpc.method, kind, body };
|
|
1370
300
|
}
|
|
1371
301
|
|
|
1372
|
-
function
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
}
|
|
1378
|
-
} else if (value !== undefined) {
|
|
1379
|
-
return true;
|
|
1380
|
-
}
|
|
302
|
+
function validateResponseMetadata(metadata) {
|
|
303
|
+
try {
|
|
304
|
+
validateMetadata(metadata);
|
|
305
|
+
} catch (error) {
|
|
306
|
+
throw internal(`invalid response metadata: ${error.statusMessage ?? error.message}`);
|
|
1381
307
|
}
|
|
1382
|
-
return false;
|
|
1383
|
-
}
|
|
1384
|
-
|
|
1385
|
-
function markPreparedCallOptions(options) {
|
|
1386
|
-
Object.defineProperty(options, PreparedCallOptions, { value: true });
|
|
1387
|
-
return options;
|
|
1388
|
-
}
|
|
1389
|
-
|
|
1390
|
-
function isPreparedCallOptions(options) {
|
|
1391
|
-
return options?.[PreparedCallOptions] === true;
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
function saturatingAdd(left, right) {
|
|
1395
|
-
const sum = left + right;
|
|
1396
|
-
return Number.isSafeInteger(sum) ? sum : Number.MAX_SAFE_INTEGER;
|
|
1397
308
|
}
|