@replit/river 0.200.0-rc.9 → 0.200.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/README.md +8 -8
- package/dist/{chunk-42Z2FQIU.js → chunk-6VA5DW7N.js} +21 -13
- package/dist/chunk-6VA5DW7N.js.map +1 -0
- package/dist/{chunk-4PVU7J25.js → chunk-AJGIY2UB.js} +1 -1
- package/dist/chunk-AJGIY2UB.js.map +1 -0
- package/dist/chunk-MADS7AI5.js +298 -0
- package/dist/chunk-MADS7AI5.js.map +1 -0
- package/dist/{chunk-4HT6P2ZG.js → chunk-SONGYR7A.js} +22 -30
- package/dist/chunk-SONGYR7A.js.map +1 -0
- package/dist/{chunk-EETL2L77.js → chunk-UQHYJZTP.js} +14 -32
- package/dist/chunk-UQHYJZTP.js.map +1 -0
- package/dist/{chunk-ZXZE253M.js → chunk-YQPJ3HZK.js} +24 -37
- package/dist/chunk-YQPJ3HZK.js.map +1 -0
- package/dist/{chunk-VXYHC666.js → chunk-YTMS7OP6.js} +1 -1
- package/dist/chunk-YTMS7OP6.js.map +1 -0
- package/dist/{chunk-I75XYO5W.js → chunk-ZDYZ2FCN.js} +82 -20
- package/dist/chunk-ZDYZ2FCN.js.map +1 -0
- package/dist/{chunk-GR3AQKHL.js → chunk-ZNJM2HIE.js} +14 -4
- package/dist/chunk-ZNJM2HIE.js.map +1 -0
- package/dist/{client-22a47343.d.ts → client-095a929e.d.ts} +3 -4
- package/dist/codec/index.cjs.map +1 -1
- package/dist/codec/index.js +1 -1
- package/dist/connection-623d75e9.d.ts +32 -0
- package/dist/{context-b4aff18f.d.ts → context-85b8690e.d.ts} +43 -43
- package/dist/logging/index.cjs.map +1 -1
- package/dist/logging/index.d.cts +1 -1
- package/dist/logging/index.d.ts +1 -1
- package/dist/logging/index.js +1 -1
- package/dist/{message-7d135e38.d.ts → message-57bb8187.d.ts} +5 -3
- package/dist/router/index.cjs +600 -681
- package/dist/router/index.cjs.map +1 -1
- package/dist/router/index.d.cts +22 -12
- package/dist/router/index.d.ts +22 -12
- package/dist/router/index.js +477 -389
- package/dist/router/index.js.map +1 -1
- package/dist/{server-dd6a9853.d.ts → server-456bf6cb.d.ts} +5 -5
- package/dist/{services-1b5ac5bc.d.ts → services-e4f28470.d.ts} +182 -194
- package/dist/transport/impls/ws/client.cjs +129 -62
- package/dist/transport/impls/ws/client.cjs.map +1 -1
- package/dist/transport/impls/ws/client.d.cts +4 -4
- package/dist/transport/impls/ws/client.d.ts +4 -4
- package/dist/transport/impls/ws/client.js +7 -7
- package/dist/transport/impls/ws/client.js.map +1 -1
- package/dist/transport/impls/ws/server.cjs +146 -70
- package/dist/transport/impls/ws/server.cjs.map +1 -1
- package/dist/transport/impls/ws/server.d.cts +6 -5
- package/dist/transport/impls/ws/server.d.ts +6 -5
- package/dist/transport/impls/ws/server.js +21 -9
- package/dist/transport/impls/ws/server.js.map +1 -1
- package/dist/transport/index.cjs +138 -92
- package/dist/transport/index.cjs.map +1 -1
- package/dist/transport/index.d.cts +4 -4
- package/dist/transport/index.d.ts +4 -4
- package/dist/transport/index.js +7 -7
- package/dist/util/testHelpers.cjs +256 -327
- package/dist/util/testHelpers.cjs.map +1 -1
- package/dist/util/testHelpers.d.cts +36 -31
- package/dist/util/testHelpers.d.ts +36 -31
- package/dist/util/testHelpers.js +82 -52
- package/dist/util/testHelpers.js.map +1 -1
- package/package.json +4 -3
- package/dist/chunk-42Z2FQIU.js.map +0 -1
- package/dist/chunk-4HT6P2ZG.js.map +0 -1
- package/dist/chunk-4PVU7J25.js.map +0 -1
- package/dist/chunk-EETL2L77.js.map +0 -1
- package/dist/chunk-GR3AQKHL.js.map +0 -1
- package/dist/chunk-I75XYO5W.js.map +0 -1
- package/dist/chunk-MQ6ANR3H.js +0 -451
- package/dist/chunk-MQ6ANR3H.js.map +0 -1
- package/dist/chunk-VXYHC666.js.map +0 -1
- package/dist/chunk-ZXZE253M.js.map +0 -1
- package/dist/connection-260e45a8.d.ts +0 -11
package/dist/router/index.js
CHANGED
|
@@ -1,39 +1,49 @@
|
|
|
1
1
|
import {
|
|
2
|
-
ABORT_CODE,
|
|
3
2
|
AnyResultSchema,
|
|
3
|
+
CANCEL_CODE,
|
|
4
4
|
Err,
|
|
5
5
|
ErrResultSchema,
|
|
6
|
-
INTERNAL_RIVER_ERROR_CODE,
|
|
7
6
|
INVALID_REQUEST_CODE,
|
|
8
7
|
Ok,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
RequestReaderErrorSchema,
|
|
12
|
-
ResponseReaderErrorSchema,
|
|
8
|
+
ReadableImpl,
|
|
9
|
+
ReaderErrorSchema,
|
|
13
10
|
UNCAUGHT_ERROR_CODE,
|
|
14
11
|
UNEXPECTED_DISCONNECT_CODE,
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
WritableImpl,
|
|
13
|
+
flattenErrorType,
|
|
14
|
+
unwrapOrThrow
|
|
15
|
+
} from "../chunk-MADS7AI5.js";
|
|
17
16
|
import {
|
|
18
17
|
ControlMessageCloseSchema,
|
|
19
18
|
ControlMessagePayloadSchema,
|
|
20
|
-
|
|
19
|
+
cancelMessage,
|
|
21
20
|
closeStreamMessage,
|
|
22
21
|
coerceErrorString,
|
|
23
22
|
createHandlerSpan,
|
|
24
23
|
createProcTelemetryInfo,
|
|
25
24
|
generateId,
|
|
26
25
|
getPropagationContext,
|
|
27
|
-
|
|
26
|
+
isStreamCancel,
|
|
28
27
|
isStreamClose,
|
|
29
|
-
isStreamCloseRequest,
|
|
30
28
|
isStreamOpen,
|
|
31
|
-
requestCloseStreamMessage,
|
|
32
29
|
version
|
|
33
|
-
} from "../chunk-
|
|
30
|
+
} from "../chunk-UQHYJZTP.js";
|
|
34
31
|
|
|
35
32
|
// router/services.ts
|
|
36
33
|
import { Type } from "@sinclair/typebox";
|
|
34
|
+
function serializeSchemaV1Compat(services, handshakeSchema) {
|
|
35
|
+
const serializedServiceObject = Object.entries(services).reduce((acc, [name, value]) => {
|
|
36
|
+
acc[name] = value.serializeV1Compat();
|
|
37
|
+
return acc;
|
|
38
|
+
}, {});
|
|
39
|
+
const schema = {
|
|
40
|
+
services: serializedServiceObject
|
|
41
|
+
};
|
|
42
|
+
if (handshakeSchema) {
|
|
43
|
+
schema.handshakeSchema = Type.Strict(handshakeSchema);
|
|
44
|
+
}
|
|
45
|
+
return schema;
|
|
46
|
+
}
|
|
37
47
|
function serializeSchema(services, handshakeSchema) {
|
|
38
48
|
const serializedServiceObject = Object.entries(services).reduce((acc, [name, value]) => {
|
|
39
49
|
acc[name] = value.serialize();
|
|
@@ -170,7 +180,7 @@ var ServiceSchema = class _ServiceSchema {
|
|
|
170
180
|
* protocol v1. This is useful to be able to continue to generate schemas for older
|
|
171
181
|
* clients as they are still supported.
|
|
172
182
|
*/
|
|
173
|
-
|
|
183
|
+
serializeV1Compat() {
|
|
174
184
|
return {
|
|
175
185
|
procedures: Object.fromEntries(
|
|
176
186
|
Object.entries(this.procedures).map(
|
|
@@ -283,9 +293,86 @@ var ServiceScaffold = class {
|
|
|
283
293
|
}
|
|
284
294
|
};
|
|
285
295
|
|
|
296
|
+
// router/procedures.ts
|
|
297
|
+
import { Type as Type2 } from "@sinclair/typebox";
|
|
298
|
+
function rpc({
|
|
299
|
+
requestInit,
|
|
300
|
+
responseData,
|
|
301
|
+
responseError = Type2.Never(),
|
|
302
|
+
description,
|
|
303
|
+
handler
|
|
304
|
+
}) {
|
|
305
|
+
return {
|
|
306
|
+
...description ? { description } : {},
|
|
307
|
+
type: "rpc",
|
|
308
|
+
requestInit,
|
|
309
|
+
responseData,
|
|
310
|
+
responseError,
|
|
311
|
+
handler
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
function upload({
|
|
315
|
+
requestInit,
|
|
316
|
+
requestData,
|
|
317
|
+
responseData,
|
|
318
|
+
responseError = Type2.Never(),
|
|
319
|
+
description,
|
|
320
|
+
handler
|
|
321
|
+
}) {
|
|
322
|
+
return {
|
|
323
|
+
type: "upload",
|
|
324
|
+
...description ? { description } : {},
|
|
325
|
+
requestInit,
|
|
326
|
+
requestData,
|
|
327
|
+
responseData,
|
|
328
|
+
responseError,
|
|
329
|
+
handler
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
function subscription({
|
|
333
|
+
requestInit,
|
|
334
|
+
responseData,
|
|
335
|
+
responseError = Type2.Never(),
|
|
336
|
+
description,
|
|
337
|
+
handler
|
|
338
|
+
}) {
|
|
339
|
+
return {
|
|
340
|
+
type: "subscription",
|
|
341
|
+
...description ? { description } : {},
|
|
342
|
+
requestInit,
|
|
343
|
+
responseData,
|
|
344
|
+
responseError,
|
|
345
|
+
handler
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
function stream({
|
|
349
|
+
requestInit,
|
|
350
|
+
requestData,
|
|
351
|
+
responseData,
|
|
352
|
+
responseError = Type2.Never(),
|
|
353
|
+
description,
|
|
354
|
+
handler
|
|
355
|
+
}) {
|
|
356
|
+
return {
|
|
357
|
+
type: "stream",
|
|
358
|
+
...description ? { description } : {},
|
|
359
|
+
requestInit,
|
|
360
|
+
requestData,
|
|
361
|
+
responseData,
|
|
362
|
+
responseError,
|
|
363
|
+
handler
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
var Procedure = {
|
|
367
|
+
rpc,
|
|
368
|
+
upload,
|
|
369
|
+
subscription,
|
|
370
|
+
stream
|
|
371
|
+
};
|
|
372
|
+
|
|
286
373
|
// router/client.ts
|
|
287
374
|
import { Value } from "@sinclair/typebox/value";
|
|
288
|
-
var
|
|
375
|
+
var ReaderErrResultSchema = ErrResultSchema(ReaderErrorSchema);
|
|
289
376
|
var noop = () => {
|
|
290
377
|
};
|
|
291
378
|
function _createRecursiveProxy(callback, path) {
|
|
@@ -346,6 +433,11 @@ function createClient(transport, serverId, providedClientOptions = {}) {
|
|
|
346
433
|
}, []);
|
|
347
434
|
}
|
|
348
435
|
function handleProc(procType, transport, serverId, init, serviceName, procedureName, abortSignal) {
|
|
436
|
+
const session = transport.sessions.get(serverId) ?? transport.createUnconnectedSession(serverId);
|
|
437
|
+
const sessionScopedSend = transport.getSessionBoundSendFn(
|
|
438
|
+
serverId,
|
|
439
|
+
session.id
|
|
440
|
+
);
|
|
349
441
|
const procClosesWithInit = procType === "rpc" || procType === "subscription";
|
|
350
442
|
const streamId = generateId();
|
|
351
443
|
const { span, ctx } = createProcTelemetryInfo(
|
|
@@ -356,61 +448,61 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
|
|
|
356
448
|
streamId
|
|
357
449
|
);
|
|
358
450
|
let cleanClose = true;
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
451
|
+
const reqWritable = new WritableImpl({
|
|
452
|
+
writeCb: (rawIn) => {
|
|
453
|
+
sessionScopedSend({
|
|
454
|
+
streamId,
|
|
455
|
+
payload: rawIn,
|
|
456
|
+
controlFlags: 0
|
|
457
|
+
});
|
|
458
|
+
},
|
|
459
|
+
// close callback
|
|
460
|
+
closeCb: () => {
|
|
461
|
+
span.addEvent("reqWritable closed");
|
|
462
|
+
if (!procClosesWithInit && cleanClose) {
|
|
463
|
+
sessionScopedSend(closeStreamMessage(streamId));
|
|
464
|
+
}
|
|
465
|
+
if (resReadable.isClosed()) {
|
|
466
|
+
cleanup();
|
|
467
|
+
}
|
|
374
468
|
}
|
|
375
469
|
});
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
if (reqWriter.isClosed()) {
|
|
470
|
+
const resReadable = new ReadableImpl();
|
|
471
|
+
const closeReadable = () => {
|
|
472
|
+
resReadable._triggerClose();
|
|
473
|
+
span.addEvent("resReadable closed");
|
|
474
|
+
if (reqWritable.isClosed()) {
|
|
382
475
|
cleanup();
|
|
383
476
|
}
|
|
384
|
-
}
|
|
477
|
+
};
|
|
385
478
|
function cleanup() {
|
|
386
479
|
transport.removeEventListener("message", onMessage);
|
|
387
480
|
transport.removeEventListener("sessionStatus", onSessionStatus);
|
|
388
|
-
abortSignal?.removeEventListener("abort",
|
|
481
|
+
abortSignal?.removeEventListener("abort", onClientCancel);
|
|
389
482
|
span.end();
|
|
390
483
|
}
|
|
391
|
-
function
|
|
392
|
-
if (
|
|
484
|
+
function onClientCancel() {
|
|
485
|
+
if (resReadable.isClosed() && reqWritable.isClosed()) {
|
|
393
486
|
return;
|
|
394
487
|
}
|
|
395
|
-
span.addEvent("sending
|
|
488
|
+
span.addEvent("sending cancel");
|
|
396
489
|
cleanClose = false;
|
|
397
|
-
if (!
|
|
398
|
-
|
|
490
|
+
if (!resReadable.isClosed()) {
|
|
491
|
+
resReadable._pushValue(
|
|
399
492
|
Err({
|
|
400
|
-
code:
|
|
401
|
-
message: "
|
|
493
|
+
code: CANCEL_CODE,
|
|
494
|
+
message: "cancelled by client"
|
|
402
495
|
})
|
|
403
496
|
);
|
|
404
|
-
|
|
497
|
+
closeReadable();
|
|
405
498
|
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
abortMessage(
|
|
499
|
+
reqWritable.close();
|
|
500
|
+
sessionScopedSend(
|
|
501
|
+
cancelMessage(
|
|
410
502
|
streamId,
|
|
411
503
|
Err({
|
|
412
|
-
code:
|
|
413
|
-
message: "
|
|
504
|
+
code: CANCEL_CODE,
|
|
505
|
+
message: "cancelled by client"
|
|
414
506
|
})
|
|
415
507
|
)
|
|
416
508
|
);
|
|
@@ -419,47 +511,44 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
|
|
|
419
511
|
if (msg.streamId !== streamId)
|
|
420
512
|
return;
|
|
421
513
|
if (msg.to !== transport.clientId) {
|
|
422
|
-
transport.log?.error("
|
|
514
|
+
transport.log?.error("got stream message from unexpected client", {
|
|
423
515
|
clientId: transport.clientId,
|
|
424
516
|
transportMessage: msg
|
|
425
517
|
});
|
|
426
518
|
return;
|
|
427
519
|
}
|
|
428
|
-
if (
|
|
429
|
-
reqWriter.triggerCloseRequest();
|
|
430
|
-
}
|
|
431
|
-
if (isStreamAbort(msg.controlFlags)) {
|
|
520
|
+
if (isStreamCancel(msg.controlFlags)) {
|
|
432
521
|
cleanClose = false;
|
|
433
|
-
span.addEvent("received
|
|
434
|
-
let
|
|
435
|
-
if (Value.Check(
|
|
436
|
-
|
|
522
|
+
span.addEvent("received cancel");
|
|
523
|
+
let cancelResult;
|
|
524
|
+
if (Value.Check(ReaderErrResultSchema, msg.payload)) {
|
|
525
|
+
cancelResult = msg.payload;
|
|
437
526
|
} else {
|
|
438
|
-
|
|
439
|
-
code:
|
|
440
|
-
message: "
|
|
527
|
+
cancelResult = Err({
|
|
528
|
+
code: CANCEL_CODE,
|
|
529
|
+
message: "stream cancelled with invalid payload"
|
|
441
530
|
});
|
|
442
531
|
transport.log?.error(
|
|
443
|
-
"
|
|
532
|
+
"got stream cancel without a valid protocol error",
|
|
444
533
|
{
|
|
445
534
|
clientId: transport.clientId,
|
|
446
535
|
transportMessage: msg,
|
|
447
536
|
validationErrors: [
|
|
448
|
-
...Value.Errors(
|
|
537
|
+
...Value.Errors(ReaderErrResultSchema, msg.payload)
|
|
449
538
|
]
|
|
450
539
|
}
|
|
451
540
|
);
|
|
452
541
|
}
|
|
453
|
-
if (!
|
|
454
|
-
|
|
455
|
-
|
|
542
|
+
if (!resReadable.isClosed()) {
|
|
543
|
+
resReadable._pushValue(cancelResult);
|
|
544
|
+
closeReadable();
|
|
456
545
|
}
|
|
457
|
-
|
|
546
|
+
reqWritable.close();
|
|
458
547
|
return;
|
|
459
548
|
}
|
|
460
|
-
if (
|
|
461
|
-
span.recordException("
|
|
462
|
-
transport.log?.error("
|
|
549
|
+
if (resReadable.isClosed()) {
|
|
550
|
+
span.recordException("received message after response stream is closed");
|
|
551
|
+
transport.log?.error("received message after response stream is closed", {
|
|
463
552
|
clientId: transport.clientId,
|
|
464
553
|
transportMessage: msg
|
|
465
554
|
});
|
|
@@ -467,7 +556,7 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
|
|
|
467
556
|
}
|
|
468
557
|
if (!Value.Check(ControlMessageCloseSchema, msg.payload)) {
|
|
469
558
|
if (Value.Check(AnyResultSchema, msg.payload)) {
|
|
470
|
-
|
|
559
|
+
resReadable._pushValue(msg.payload);
|
|
471
560
|
} else {
|
|
472
561
|
transport.log?.error(
|
|
473
562
|
"Got non-control payload, but was not a valid result",
|
|
@@ -480,33 +569,36 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
|
|
|
480
569
|
}
|
|
481
570
|
}
|
|
482
571
|
if (isStreamClose(msg.controlFlags)) {
|
|
483
|
-
span.addEvent("received
|
|
484
|
-
|
|
572
|
+
span.addEvent("received response close");
|
|
573
|
+
if (resReadable.isClosed()) {
|
|
574
|
+
transport.log?.error(
|
|
575
|
+
"received stream close but readable was already closed"
|
|
576
|
+
);
|
|
577
|
+
} else {
|
|
578
|
+
closeReadable();
|
|
579
|
+
}
|
|
485
580
|
}
|
|
486
581
|
}
|
|
487
582
|
function onSessionStatus(evt) {
|
|
488
|
-
if (evt.status !== "disconnect") {
|
|
489
|
-
return;
|
|
490
|
-
}
|
|
491
|
-
if (evt.session.to !== serverId) {
|
|
583
|
+
if (evt.status !== "disconnect" || evt.session.to !== serverId || session.id !== evt.session.id) {
|
|
492
584
|
return;
|
|
493
585
|
}
|
|
494
586
|
cleanClose = false;
|
|
495
|
-
if (!
|
|
496
|
-
|
|
587
|
+
if (!resReadable.isClosed()) {
|
|
588
|
+
resReadable._pushValue(
|
|
497
589
|
Err({
|
|
498
590
|
code: UNEXPECTED_DISCONNECT_CODE,
|
|
499
591
|
message: `${serverId} unexpectedly disconnected`
|
|
500
592
|
})
|
|
501
593
|
);
|
|
594
|
+
closeReadable();
|
|
502
595
|
}
|
|
503
|
-
|
|
504
|
-
resReader.triggerClose();
|
|
596
|
+
reqWritable.close();
|
|
505
597
|
}
|
|
506
|
-
abortSignal?.addEventListener("abort",
|
|
598
|
+
abortSignal?.addEventListener("abort", onClientCancel);
|
|
507
599
|
transport.addEventListener("message", onMessage);
|
|
508
600
|
transport.addEventListener("sessionStatus", onSessionStatus);
|
|
509
|
-
|
|
601
|
+
sessionScopedSend({
|
|
510
602
|
streamId,
|
|
511
603
|
serviceName,
|
|
512
604
|
procedureName,
|
|
@@ -515,34 +607,39 @@ function handleProc(procType, transport, serverId, init, serviceName, procedureN
|
|
|
515
607
|
controlFlags: procClosesWithInit ? 2 /* StreamOpenBit */ | 8 /* StreamClosedBit */ : 2 /* StreamOpenBit */
|
|
516
608
|
});
|
|
517
609
|
if (procClosesWithInit) {
|
|
518
|
-
|
|
610
|
+
reqWritable.close();
|
|
519
611
|
}
|
|
520
612
|
if (procType === "subscription") {
|
|
521
|
-
return {
|
|
613
|
+
return {
|
|
614
|
+
resReadable
|
|
615
|
+
};
|
|
522
616
|
}
|
|
523
617
|
if (procType === "rpc") {
|
|
524
|
-
return getSingleMessage(
|
|
618
|
+
return getSingleMessage(resReadable, transport.log);
|
|
525
619
|
}
|
|
526
620
|
if (procType === "upload") {
|
|
527
621
|
let didFinalize = false;
|
|
528
622
|
return {
|
|
529
|
-
|
|
530
|
-
|
|
623
|
+
reqWritable,
|
|
624
|
+
finalize: () => {
|
|
531
625
|
if (didFinalize) {
|
|
532
626
|
throw new Error("upload stream already finalized");
|
|
533
627
|
}
|
|
534
628
|
didFinalize = true;
|
|
535
|
-
if (!
|
|
536
|
-
|
|
629
|
+
if (!reqWritable.isClosed()) {
|
|
630
|
+
reqWritable.close();
|
|
537
631
|
}
|
|
538
|
-
return getSingleMessage(
|
|
632
|
+
return getSingleMessage(resReadable, transport.log);
|
|
539
633
|
}
|
|
540
634
|
};
|
|
541
635
|
}
|
|
542
|
-
return {
|
|
636
|
+
return {
|
|
637
|
+
resReadable,
|
|
638
|
+
reqWritable
|
|
639
|
+
};
|
|
543
640
|
}
|
|
544
|
-
async function getSingleMessage(
|
|
545
|
-
const ret = await
|
|
641
|
+
async function getSingleMessage(resReadable, log) {
|
|
642
|
+
const ret = await resReadable.collect();
|
|
546
643
|
if (ret.length > 1) {
|
|
547
644
|
log?.error("Expected single message from server, got multiple");
|
|
548
645
|
}
|
|
@@ -550,25 +647,31 @@ async function getSingleMessage(resReader, log) {
|
|
|
550
647
|
}
|
|
551
648
|
|
|
552
649
|
// router/server.ts
|
|
650
|
+
import { Type as Type3 } from "@sinclair/typebox";
|
|
553
651
|
import { Value as Value2 } from "@sinclair/typebox/value";
|
|
554
652
|
import { SpanStatusCode } from "@opentelemetry/api";
|
|
555
|
-
var
|
|
653
|
+
var CancelResultSchema = ErrResultSchema(
|
|
654
|
+
Type3.Object({
|
|
655
|
+
code: Type3.Literal(CANCEL_CODE),
|
|
656
|
+
message: Type3.String()
|
|
657
|
+
})
|
|
658
|
+
);
|
|
556
659
|
var RiverServer = class {
|
|
557
660
|
transport;
|
|
558
661
|
contextMap;
|
|
559
662
|
log;
|
|
560
663
|
/**
|
|
561
|
-
* We create a tombstones for streams
|
|
664
|
+
* We create a tombstones for streams cancelled by the server
|
|
562
665
|
* so that we don't hit errors when the client has inflight
|
|
563
|
-
* requests it sent before it saw the
|
|
564
|
-
* We track
|
|
666
|
+
* requests it sent before it saw the cancel.
|
|
667
|
+
* We track cancelled streams for every client separately, so
|
|
565
668
|
* that bad clients don't affect good clients.
|
|
566
669
|
*/
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
670
|
+
serverCancelledStreams;
|
|
671
|
+
maxCancelledStreamTombstonesPerSession;
|
|
672
|
+
streams;
|
|
570
673
|
services;
|
|
571
|
-
constructor(transport, services, handshakeOptions, extendedContext,
|
|
674
|
+
constructor(transport, services, handshakeOptions, extendedContext, maxCancelledStreamTombstonesPerSession = 200) {
|
|
572
675
|
const instances = {};
|
|
573
676
|
this.services = instances;
|
|
574
677
|
this.contextMap = /* @__PURE__ */ new Map();
|
|
@@ -584,34 +687,40 @@ var RiverServer = class {
|
|
|
584
687
|
transport.extendHandshake(handshakeOptions);
|
|
585
688
|
}
|
|
586
689
|
this.transport = transport;
|
|
587
|
-
this.
|
|
588
|
-
this.
|
|
589
|
-
this.
|
|
690
|
+
this.streams = /* @__PURE__ */ new Map();
|
|
691
|
+
this.serverCancelledStreams = /* @__PURE__ */ new Map();
|
|
692
|
+
this.maxCancelledStreamTombstonesPerSession = maxCancelledStreamTombstonesPerSession;
|
|
590
693
|
this.log = transport.log;
|
|
591
|
-
const
|
|
592
|
-
if (
|
|
694
|
+
const handleCreatingNewStreams = (message) => {
|
|
695
|
+
if (message.to !== this.transport.clientId) {
|
|
593
696
|
this.log?.info(
|
|
594
697
|
`got msg with destination that isn't this server, ignoring`,
|
|
595
698
|
{
|
|
596
699
|
clientId: this.transport.clientId,
|
|
597
|
-
transportMessage:
|
|
700
|
+
transportMessage: message
|
|
598
701
|
}
|
|
599
702
|
);
|
|
600
703
|
return;
|
|
601
704
|
}
|
|
602
|
-
|
|
705
|
+
const streamId = message.streamId;
|
|
706
|
+
const stream2 = this.streams.get(streamId);
|
|
707
|
+
if (stream2) {
|
|
708
|
+
stream2.handleMsg(message);
|
|
603
709
|
return;
|
|
604
710
|
}
|
|
605
|
-
if (this.
|
|
711
|
+
if (this.serverCancelledStreams.get(message.from)?.has(streamId)) {
|
|
606
712
|
return;
|
|
607
713
|
}
|
|
608
|
-
const
|
|
609
|
-
if (!
|
|
714
|
+
const newStreamProps = this.validateNewProcStream(message);
|
|
715
|
+
if (!newStreamProps) {
|
|
610
716
|
return;
|
|
611
717
|
}
|
|
612
|
-
this.createNewProcStream(
|
|
718
|
+
const newStream = this.createNewProcStream({
|
|
719
|
+
...newStreamProps,
|
|
720
|
+
...message
|
|
721
|
+
});
|
|
722
|
+
this.streams.set(streamId, newStream);
|
|
613
723
|
};
|
|
614
|
-
this.transport.addEventListener("message", handleMessage);
|
|
615
724
|
const handleSessionStatus = (evt) => {
|
|
616
725
|
if (evt.status !== "disconnect")
|
|
617
726
|
return;
|
|
@@ -620,256 +729,248 @@ var RiverServer = class {
|
|
|
620
729
|
`got session disconnect from ${disconnectedClientId}, cleaning up streams`,
|
|
621
730
|
evt.session.loggingMetadata
|
|
622
731
|
);
|
|
623
|
-
this.
|
|
732
|
+
for (const stream2 of this.streams.values()) {
|
|
733
|
+
if (stream2.from === disconnectedClientId) {
|
|
734
|
+
stream2.handleSessionDisconnect();
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
this.serverCancelledStreams.delete(disconnectedClientId);
|
|
624
738
|
};
|
|
625
|
-
|
|
626
|
-
this.transport.addEventListener("transportStatus", (evt) => {
|
|
739
|
+
const handleTransportStatus = (evt) => {
|
|
627
740
|
if (evt.status !== "closed")
|
|
628
741
|
return;
|
|
629
|
-
this.transport.removeEventListener("message",
|
|
742
|
+
this.transport.removeEventListener("message", handleCreatingNewStreams);
|
|
630
743
|
this.transport.removeEventListener("sessionStatus", handleSessionStatus);
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
procedure,
|
|
635
|
-
procedureName,
|
|
636
|
-
service,
|
|
637
|
-
serviceName,
|
|
638
|
-
sessionMetadata,
|
|
639
|
-
loggingMetadata,
|
|
640
|
-
streamId,
|
|
641
|
-
controlFlags,
|
|
642
|
-
initPayload,
|
|
643
|
-
from,
|
|
644
|
-
sessionId,
|
|
645
|
-
tracingCtx,
|
|
646
|
-
protocolVersion,
|
|
647
|
-
passInitAsDataForBackwardsCompat
|
|
648
|
-
}) {
|
|
649
|
-
this.openStreams.add(streamId);
|
|
650
|
-
let cleanClose = true;
|
|
651
|
-
const onServerAbort = (errResult) => {
|
|
652
|
-
if (reqReader.isClosed() && resWriter.isClosed()) {
|
|
653
|
-
return;
|
|
654
|
-
}
|
|
655
|
-
cleanClose = false;
|
|
656
|
-
if (!reqReader.isClosed()) {
|
|
657
|
-
reqReader.pushValue(errResult);
|
|
658
|
-
reqReader.triggerClose();
|
|
659
|
-
}
|
|
660
|
-
resWriter.close();
|
|
661
|
-
this.abortStream(from, streamId, errResult);
|
|
662
|
-
};
|
|
663
|
-
const onHandlerAbort = () => {
|
|
664
|
-
onServerAbort(
|
|
665
|
-
Err({
|
|
666
|
-
code: ABORT_CODE,
|
|
667
|
-
message: "Aborted by server procedure handler"
|
|
668
|
-
})
|
|
744
|
+
this.transport.removeEventListener(
|
|
745
|
+
"transportStatus",
|
|
746
|
+
handleTransportStatus
|
|
669
747
|
);
|
|
670
748
|
};
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
749
|
+
this.transport.addEventListener("message", handleCreatingNewStreams);
|
|
750
|
+
this.transport.addEventListener("sessionStatus", handleSessionStatus);
|
|
751
|
+
this.transport.addEventListener("transportStatus", handleTransportStatus);
|
|
752
|
+
}
|
|
753
|
+
createNewProcStream(props) {
|
|
754
|
+
const {
|
|
755
|
+
streamId,
|
|
756
|
+
initialSession,
|
|
757
|
+
procedureName,
|
|
758
|
+
serviceName,
|
|
759
|
+
procedure,
|
|
760
|
+
sessionMetadata,
|
|
761
|
+
serviceContext,
|
|
762
|
+
initPayload,
|
|
763
|
+
tracingCtx,
|
|
764
|
+
procClosesWithInit,
|
|
765
|
+
passInitAsDataForBackwardsCompat
|
|
766
|
+
} = props;
|
|
767
|
+
const {
|
|
768
|
+
to: from,
|
|
769
|
+
loggingMetadata,
|
|
770
|
+
protocolVersion,
|
|
771
|
+
id: sessionId
|
|
772
|
+
} = initialSession;
|
|
773
|
+
let cleanClose = true;
|
|
694
774
|
const onMessage = (msg) => {
|
|
695
|
-
if (streamId !== msg.streamId) {
|
|
696
|
-
return;
|
|
697
|
-
}
|
|
698
775
|
if (msg.from !== from) {
|
|
699
|
-
this.log?.error("
|
|
776
|
+
this.log?.error("got stream message from unexpected client", {
|
|
700
777
|
...loggingMetadata,
|
|
701
|
-
clientId: this.transport.clientId,
|
|
702
778
|
transportMessage: msg,
|
|
703
779
|
tags: ["invariant-violation"]
|
|
704
780
|
});
|
|
705
781
|
return;
|
|
706
782
|
}
|
|
707
|
-
if (
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
let abortResult;
|
|
712
|
-
if (Value2.Check(InputErrResultSchema, msg.payload)) {
|
|
713
|
-
abortResult = msg.payload;
|
|
783
|
+
if (isStreamCancelBackwardsCompat(msg.controlFlags, protocolVersion)) {
|
|
784
|
+
let cancelResult;
|
|
785
|
+
if (Value2.Check(CancelResultSchema, msg.payload)) {
|
|
786
|
+
cancelResult = msg.payload;
|
|
714
787
|
} else {
|
|
715
|
-
|
|
716
|
-
code:
|
|
717
|
-
message: "
|
|
788
|
+
cancelResult = Err({
|
|
789
|
+
code: CANCEL_CODE,
|
|
790
|
+
message: "stream cancelled, client sent invalid payload"
|
|
718
791
|
});
|
|
719
|
-
this.log?.warn("
|
|
792
|
+
this.log?.warn("got stream cancel without a valid protocol error", {
|
|
720
793
|
...loggingMetadata,
|
|
721
|
-
clientId: this.transport.clientId,
|
|
722
794
|
transportMessage: msg,
|
|
723
795
|
validationErrors: [
|
|
724
|
-
...Value2.Errors(
|
|
796
|
+
...Value2.Errors(CancelResultSchema, msg.payload)
|
|
725
797
|
],
|
|
726
798
|
tags: ["invalid-request"]
|
|
727
799
|
});
|
|
728
800
|
}
|
|
729
|
-
if (!
|
|
730
|
-
|
|
731
|
-
|
|
801
|
+
if (!reqReadable.isClosed()) {
|
|
802
|
+
reqReadable._pushValue(cancelResult);
|
|
803
|
+
closeReadable();
|
|
732
804
|
}
|
|
733
|
-
|
|
734
|
-
clientAbortController.abort(abortResult.payload);
|
|
805
|
+
resWritable.close();
|
|
735
806
|
return;
|
|
736
807
|
}
|
|
737
|
-
if (
|
|
738
|
-
this.log?.warn("
|
|
808
|
+
if (reqReadable.isClosed()) {
|
|
809
|
+
this.log?.warn("received message after request stream is closed", {
|
|
739
810
|
...loggingMetadata,
|
|
740
|
-
clientId: this.transport.clientId,
|
|
741
811
|
transportMessage: msg,
|
|
742
812
|
tags: ["invalid-request"]
|
|
743
813
|
});
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
})
|
|
749
|
-
);
|
|
814
|
+
onServerCancel({
|
|
815
|
+
code: INVALID_REQUEST_CODE,
|
|
816
|
+
message: "received message after request stream is closed"
|
|
817
|
+
});
|
|
750
818
|
return;
|
|
751
819
|
}
|
|
752
820
|
if ("requestData" in procedure && Value2.Check(procedure.requestData, msg.payload)) {
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
821
|
+
reqReadable._pushValue(Ok(msg.payload));
|
|
822
|
+
if (isStreamCloseBackwardsCompat(msg.controlFlags, protocolVersion)) {
|
|
823
|
+
closeReadable();
|
|
824
|
+
}
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
if (Value2.Check(ControlMessagePayloadSchema, msg.payload) && isStreamCloseBackwardsCompat(msg.controlFlags, protocolVersion)) {
|
|
828
|
+
closeReadable();
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
let validationErrors;
|
|
832
|
+
let errMessage;
|
|
833
|
+
if ("requestData" in procedure) {
|
|
834
|
+
errMessage = "expected requestData or control payload";
|
|
835
|
+
validationErrors = [
|
|
836
|
+
...Value2.Errors(procedure.responseData, msg.payload)
|
|
837
|
+
];
|
|
838
|
+
} else {
|
|
839
|
+
validationErrors = [
|
|
756
840
|
...Value2.Errors(ControlMessagePayloadSchema, msg.payload)
|
|
757
841
|
];
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
842
|
+
errMessage = "expected control payload";
|
|
843
|
+
}
|
|
844
|
+
this.log?.warn(errMessage, {
|
|
845
|
+
...loggingMetadata,
|
|
846
|
+
transportMessage: msg,
|
|
847
|
+
validationErrors,
|
|
848
|
+
tags: ["invalid-request"]
|
|
849
|
+
});
|
|
850
|
+
onServerCancel({
|
|
851
|
+
code: INVALID_REQUEST_CODE,
|
|
852
|
+
message: errMessage
|
|
853
|
+
});
|
|
854
|
+
};
|
|
855
|
+
const procStream = {
|
|
856
|
+
from,
|
|
857
|
+
streamId,
|
|
858
|
+
procedureName,
|
|
859
|
+
serviceName,
|
|
860
|
+
sessionMetadata,
|
|
861
|
+
procedure,
|
|
862
|
+
handleMsg: onMessage,
|
|
863
|
+
handleSessionDisconnect: () => {
|
|
864
|
+
cleanClose = false;
|
|
865
|
+
const errPayload = {
|
|
866
|
+
code: UNEXPECTED_DISCONNECT_CODE,
|
|
867
|
+
message: "client unexpectedly disconnected"
|
|
868
|
+
};
|
|
869
|
+
if (!reqReadable.isClosed()) {
|
|
870
|
+
reqReadable._pushValue(Err(errPayload));
|
|
871
|
+
closeReadable();
|
|
764
872
|
}
|
|
765
|
-
|
|
766
|
-
...loggingMetadata,
|
|
767
|
-
clientId: this.transport.clientId,
|
|
768
|
-
transportMessage: msg,
|
|
769
|
-
validationErrors,
|
|
770
|
-
tags: ["invalid-request"]
|
|
771
|
-
});
|
|
772
|
-
onServerAbort(
|
|
773
|
-
Err({
|
|
774
|
-
code: INVALID_REQUEST_CODE,
|
|
775
|
-
message: errMessage
|
|
776
|
-
})
|
|
777
|
-
);
|
|
873
|
+
resWritable.close();
|
|
778
874
|
}
|
|
779
|
-
|
|
780
|
-
|
|
875
|
+
};
|
|
876
|
+
const sessionScopedSend = this.transport.getSessionBoundSendFn(
|
|
877
|
+
from,
|
|
878
|
+
sessionId
|
|
879
|
+
);
|
|
880
|
+
const cancelStream = (streamId2, payload) => {
|
|
881
|
+
this.cancelStream(from, sessionScopedSend, streamId2, payload);
|
|
882
|
+
};
|
|
883
|
+
const onServerCancel = (e) => {
|
|
884
|
+
if (reqReadable.isClosed() && resWritable.isClosed()) {
|
|
885
|
+
return;
|
|
781
886
|
}
|
|
887
|
+
cleanClose = false;
|
|
888
|
+
const result = Err(e);
|
|
889
|
+
if (!reqReadable.isClosed()) {
|
|
890
|
+
reqReadable._pushValue(result);
|
|
891
|
+
closeReadable();
|
|
892
|
+
}
|
|
893
|
+
resWritable.close();
|
|
894
|
+
cancelStream(streamId, result);
|
|
782
895
|
};
|
|
783
|
-
|
|
784
|
-
const onFinishedCallbacks = [];
|
|
896
|
+
const finishedController = new AbortController();
|
|
785
897
|
const cleanup = () => {
|
|
786
|
-
|
|
787
|
-
this.
|
|
788
|
-
handlerAbortController.signal.addEventListener("abort", onHandlerAbort);
|
|
789
|
-
this.openStreams.delete(streamId);
|
|
790
|
-
onFinishedCallbacks.forEach((cb) => {
|
|
791
|
-
try {
|
|
792
|
-
cb();
|
|
793
|
-
} catch {
|
|
794
|
-
}
|
|
795
|
-
});
|
|
796
|
-
onFinishedCallbacks.length = 0;
|
|
898
|
+
finishedController.abort();
|
|
899
|
+
this.streams.delete(streamId);
|
|
797
900
|
};
|
|
798
901
|
const procClosesWithResponse = procedure.type === "rpc" || procedure.type === "upload";
|
|
799
|
-
const
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
reqReader.onClose(() => {
|
|
902
|
+
const reqReadable = new ReadableImpl();
|
|
903
|
+
const closeReadable = () => {
|
|
904
|
+
reqReadable._triggerClose();
|
|
803
905
|
if (protocolVersion === "v1.1") {
|
|
804
|
-
if (!procClosesWithResponse && !
|
|
805
|
-
|
|
906
|
+
if (!procClosesWithResponse && !resWritable.isClosed()) {
|
|
907
|
+
resWritable.close();
|
|
806
908
|
}
|
|
807
909
|
}
|
|
808
|
-
if (
|
|
910
|
+
if (resWritable.isClosed()) {
|
|
809
911
|
cleanup();
|
|
810
912
|
}
|
|
811
|
-
}
|
|
913
|
+
};
|
|
812
914
|
if (passInitAsDataForBackwardsCompat) {
|
|
813
|
-
|
|
915
|
+
reqReadable._pushValue(Ok(initPayload));
|
|
814
916
|
}
|
|
815
|
-
const
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
917
|
+
const resWritable = new WritableImpl({
|
|
918
|
+
writeCb: (response) => {
|
|
919
|
+
sessionScopedSend({
|
|
920
|
+
streamId,
|
|
921
|
+
controlFlags: procClosesWithResponse ? getStreamCloseBackwardsCompat(protocolVersion) : 0,
|
|
922
|
+
payload: response
|
|
923
|
+
});
|
|
924
|
+
if (procClosesWithResponse) {
|
|
925
|
+
resWritable.close();
|
|
926
|
+
}
|
|
927
|
+
},
|
|
928
|
+
// close callback
|
|
929
|
+
closeCb: () => {
|
|
930
|
+
if (!procClosesWithResponse && cleanClose) {
|
|
931
|
+
const message = closeStreamMessage(streamId);
|
|
932
|
+
message.controlFlags = getStreamCloseBackwardsCompat(protocolVersion);
|
|
933
|
+
sessionScopedSend(message);
|
|
934
|
+
}
|
|
935
|
+
if (protocolVersion === "v1.1") {
|
|
936
|
+
if (!reqReadable.isClosed()) {
|
|
937
|
+
closeReadable();
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
if (reqReadable.isClosed()) {
|
|
941
|
+
cleanup();
|
|
831
942
|
}
|
|
832
|
-
}
|
|
833
|
-
if (reqReader.isClosed()) {
|
|
834
|
-
cleanup();
|
|
835
943
|
}
|
|
836
944
|
});
|
|
837
945
|
const onHandlerError = (err, span) => {
|
|
838
946
|
const errorMsg = coerceErrorString(err);
|
|
839
947
|
span.recordException(err instanceof Error ? err : new Error(errorMsg));
|
|
840
948
|
span.setStatus({ code: SpanStatusCode.ERROR });
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
})
|
|
846
|
-
);
|
|
949
|
+
onServerCancel({
|
|
950
|
+
code: UNCAUGHT_ERROR_CODE,
|
|
951
|
+
message: errorMsg
|
|
952
|
+
});
|
|
847
953
|
};
|
|
848
|
-
if (
|
|
849
|
-
|
|
954
|
+
if (procClosesWithInit) {
|
|
955
|
+
closeReadable();
|
|
850
956
|
} else if (procedure.type === "rpc" || procedure.type === "subscription") {
|
|
851
|
-
this.log?.warn(
|
|
957
|
+
this.log?.warn("sent an init without a stream close", {
|
|
852
958
|
...loggingMetadata,
|
|
853
959
|
clientId: this.transport.clientId
|
|
854
960
|
});
|
|
855
961
|
}
|
|
856
|
-
const
|
|
857
|
-
...
|
|
962
|
+
const handlerContext = {
|
|
963
|
+
...serviceContext,
|
|
858
964
|
from,
|
|
859
965
|
sessionId,
|
|
860
966
|
metadata: sessionMetadata,
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
}
|
|
869
|
-
return;
|
|
870
|
-
}
|
|
871
|
-
onFinishedCallbacks.push(cb);
|
|
872
|
-
}
|
|
967
|
+
cancel: () => {
|
|
968
|
+
onServerCancel({
|
|
969
|
+
code: CANCEL_CODE,
|
|
970
|
+
message: "cancelled by server procedure handler"
|
|
971
|
+
});
|
|
972
|
+
},
|
|
973
|
+
signal: finishedController.signal
|
|
873
974
|
};
|
|
874
975
|
switch (procedure.type) {
|
|
875
976
|
case "rpc":
|
|
@@ -881,15 +982,14 @@ var RiverServer = class {
|
|
|
881
982
|
tracingCtx,
|
|
882
983
|
async (span) => {
|
|
883
984
|
try {
|
|
884
|
-
const
|
|
885
|
-
ctx:
|
|
985
|
+
const responsePayload = await procedure.handler({
|
|
986
|
+
ctx: handlerContext,
|
|
886
987
|
reqInit: initPayload
|
|
887
988
|
});
|
|
888
|
-
if (
|
|
989
|
+
if (resWritable.isClosed()) {
|
|
889
990
|
return;
|
|
890
991
|
}
|
|
891
|
-
|
|
892
|
-
resWriter.close();
|
|
992
|
+
resWritable.write(responsePayload);
|
|
893
993
|
} catch (err) {
|
|
894
994
|
onHandlerError(err, span);
|
|
895
995
|
} finally {
|
|
@@ -908,10 +1008,10 @@ var RiverServer = class {
|
|
|
908
1008
|
async (span) => {
|
|
909
1009
|
try {
|
|
910
1010
|
await procedure.handler({
|
|
911
|
-
ctx:
|
|
1011
|
+
ctx: handlerContext,
|
|
912
1012
|
reqInit: initPayload,
|
|
913
|
-
|
|
914
|
-
|
|
1013
|
+
reqReadable,
|
|
1014
|
+
resWritable
|
|
915
1015
|
});
|
|
916
1016
|
} catch (err) {
|
|
917
1017
|
onHandlerError(err, span);
|
|
@@ -931,9 +1031,9 @@ var RiverServer = class {
|
|
|
931
1031
|
async (span) => {
|
|
932
1032
|
try {
|
|
933
1033
|
await procedure.handler({
|
|
934
|
-
ctx:
|
|
935
|
-
reqInit:
|
|
936
|
-
|
|
1034
|
+
ctx: handlerContext,
|
|
1035
|
+
reqInit: initPayload,
|
|
1036
|
+
resWritable
|
|
937
1037
|
});
|
|
938
1038
|
} catch (err) {
|
|
939
1039
|
onHandlerError(err, span);
|
|
@@ -952,16 +1052,15 @@ var RiverServer = class {
|
|
|
952
1052
|
tracingCtx,
|
|
953
1053
|
async (span) => {
|
|
954
1054
|
try {
|
|
955
|
-
const
|
|
956
|
-
ctx:
|
|
957
|
-
reqInit:
|
|
958
|
-
|
|
1055
|
+
const responsePayload = await procedure.handler({
|
|
1056
|
+
ctx: handlerContext,
|
|
1057
|
+
reqInit: initPayload,
|
|
1058
|
+
reqReadable
|
|
959
1059
|
});
|
|
960
|
-
if (
|
|
1060
|
+
if (resWritable.isClosed()) {
|
|
961
1061
|
return;
|
|
962
1062
|
}
|
|
963
|
-
|
|
964
|
-
resWriter.close();
|
|
1063
|
+
resWritable.write(responsePayload);
|
|
965
1064
|
} catch (err) {
|
|
966
1065
|
onHandlerError(err, span);
|
|
967
1066
|
} finally {
|
|
@@ -970,16 +1069,8 @@ var RiverServer = class {
|
|
|
970
1069
|
}
|
|
971
1070
|
);
|
|
972
1071
|
break;
|
|
973
|
-
default:
|
|
974
|
-
this.log?.error(
|
|
975
|
-
`got request for invalid procedure type ${procedure.type} at ${serviceName}.${procedureName}`,
|
|
976
|
-
{
|
|
977
|
-
...loggingMetadata,
|
|
978
|
-
tags: ["invariant-violation"]
|
|
979
|
-
}
|
|
980
|
-
);
|
|
981
|
-
return;
|
|
982
1072
|
}
|
|
1073
|
+
return procStream;
|
|
983
1074
|
}
|
|
984
1075
|
getContext(service, serviceName) {
|
|
985
1076
|
const context = this.contextMap.get(service);
|
|
@@ -996,22 +1087,20 @@ var RiverServer = class {
|
|
|
996
1087
|
validateNewProcStream(initMessage) {
|
|
997
1088
|
const session = this.transport.sessions.get(initMessage.from);
|
|
998
1089
|
if (!session) {
|
|
999
|
-
const errMessage = `couldn't find a session for ${initMessage.from}`;
|
|
1000
1090
|
this.log?.error(`couldn't find session for ${initMessage.from}`, {
|
|
1001
1091
|
clientId: this.transport.clientId,
|
|
1002
1092
|
transportMessage: initMessage,
|
|
1003
1093
|
tags: ["invariant-violation"]
|
|
1004
1094
|
});
|
|
1005
|
-
this.abortStream(
|
|
1006
|
-
initMessage.from,
|
|
1007
|
-
initMessage.streamId,
|
|
1008
|
-
Err({
|
|
1009
|
-
code: INTERNAL_RIVER_ERROR_CODE,
|
|
1010
|
-
message: errMessage
|
|
1011
|
-
})
|
|
1012
|
-
);
|
|
1013
1095
|
return null;
|
|
1014
1096
|
}
|
|
1097
|
+
const sessionScopedSend = this.transport.getSessionBoundSendFn(
|
|
1098
|
+
initMessage.from,
|
|
1099
|
+
session.id
|
|
1100
|
+
);
|
|
1101
|
+
const cancelStream = (streamId, payload) => {
|
|
1102
|
+
this.cancelStream(initMessage.from, sessionScopedSend, streamId, payload);
|
|
1103
|
+
};
|
|
1015
1104
|
const sessionMetadata = this.transport.sessionHandshakeMetadata.get(
|
|
1016
1105
|
session.to
|
|
1017
1106
|
);
|
|
@@ -1021,11 +1110,10 @@ var RiverServer = class {
|
|
|
1021
1110
|
...session.loggingMetadata,
|
|
1022
1111
|
tags: ["invariant-violation"]
|
|
1023
1112
|
});
|
|
1024
|
-
|
|
1025
|
-
initMessage.from,
|
|
1113
|
+
cancelStream(
|
|
1026
1114
|
initMessage.streamId,
|
|
1027
1115
|
Err({
|
|
1028
|
-
code:
|
|
1116
|
+
code: UNCAUGHT_ERROR_CODE,
|
|
1029
1117
|
message: errMessage
|
|
1030
1118
|
})
|
|
1031
1119
|
);
|
|
@@ -1039,8 +1127,7 @@ var RiverServer = class {
|
|
|
1039
1127
|
transportMessage: initMessage,
|
|
1040
1128
|
tags: ["invalid-request"]
|
|
1041
1129
|
});
|
|
1042
|
-
|
|
1043
|
-
initMessage.from,
|
|
1130
|
+
cancelStream(
|
|
1044
1131
|
initMessage.streamId,
|
|
1045
1132
|
Err({
|
|
1046
1133
|
code: INVALID_REQUEST_CODE,
|
|
@@ -1053,12 +1140,10 @@ var RiverServer = class {
|
|
|
1053
1140
|
const errMessage = `missing service name in stream open message`;
|
|
1054
1141
|
this.log?.warn(errMessage, {
|
|
1055
1142
|
...session.loggingMetadata,
|
|
1056
|
-
clientId: this.transport.clientId,
|
|
1057
1143
|
transportMessage: initMessage,
|
|
1058
1144
|
tags: ["invalid-request"]
|
|
1059
1145
|
});
|
|
1060
|
-
|
|
1061
|
-
initMessage.from,
|
|
1146
|
+
cancelStream(
|
|
1062
1147
|
initMessage.streamId,
|
|
1063
1148
|
Err({
|
|
1064
1149
|
code: INVALID_REQUEST_CODE,
|
|
@@ -1071,12 +1156,10 @@ var RiverServer = class {
|
|
|
1071
1156
|
const errMessage = `missing procedure name in stream open message`;
|
|
1072
1157
|
this.log?.warn(errMessage, {
|
|
1073
1158
|
...session.loggingMetadata,
|
|
1074
|
-
clientId: this.transport.clientId,
|
|
1075
1159
|
transportMessage: initMessage,
|
|
1076
1160
|
tags: ["invalid-request"]
|
|
1077
1161
|
});
|
|
1078
|
-
|
|
1079
|
-
initMessage.from,
|
|
1162
|
+
cancelStream(
|
|
1080
1163
|
initMessage.streamId,
|
|
1081
1164
|
Err({
|
|
1082
1165
|
code: INVALID_REQUEST_CODE,
|
|
@@ -1093,8 +1176,7 @@ var RiverServer = class {
|
|
|
1093
1176
|
transportMessage: initMessage,
|
|
1094
1177
|
tags: ["invalid-request"]
|
|
1095
1178
|
});
|
|
1096
|
-
|
|
1097
|
-
initMessage.from,
|
|
1179
|
+
cancelStream(
|
|
1098
1180
|
initMessage.streamId,
|
|
1099
1181
|
Err({
|
|
1100
1182
|
code: INVALID_REQUEST_CODE,
|
|
@@ -1108,12 +1190,10 @@ var RiverServer = class {
|
|
|
1108
1190
|
const errMessage = `couldn't find a matching procedure for ${initMessage.serviceName}.${initMessage.procedureName}`;
|
|
1109
1191
|
this.log?.warn(errMessage, {
|
|
1110
1192
|
...session.loggingMetadata,
|
|
1111
|
-
clientId: this.transport.clientId,
|
|
1112
1193
|
transportMessage: initMessage,
|
|
1113
1194
|
tags: ["invalid-request"]
|
|
1114
1195
|
});
|
|
1115
|
-
|
|
1116
|
-
initMessage.from,
|
|
1196
|
+
cancelStream(
|
|
1117
1197
|
initMessage.streamId,
|
|
1118
1198
|
Err({
|
|
1119
1199
|
code: INVALID_REQUEST_CODE,
|
|
@@ -1122,7 +1202,19 @@ var RiverServer = class {
|
|
|
1122
1202
|
);
|
|
1123
1203
|
return null;
|
|
1124
1204
|
}
|
|
1205
|
+
const serviceContext = this.getContext(service, initMessage.serviceName);
|
|
1125
1206
|
const procedure = service.procedures[initMessage.procedureName];
|
|
1207
|
+
if (!["rpc", "upload", "stream", "subscription"].includes(procedure.type)) {
|
|
1208
|
+
this.log?.error(
|
|
1209
|
+
`got request for invalid procedure type ${procedure.type} at ${initMessage.serviceName}.${initMessage.procedureName}`,
|
|
1210
|
+
{
|
|
1211
|
+
...session.loggingMetadata,
|
|
1212
|
+
transportMessage: initMessage,
|
|
1213
|
+
tags: ["invariant-violation"]
|
|
1214
|
+
}
|
|
1215
|
+
);
|
|
1216
|
+
return null;
|
|
1217
|
+
}
|
|
1126
1218
|
let passInitAsDataForBackwardsCompat = false;
|
|
1127
1219
|
if (session.protocolVersion === "v1.1" && (procedure.type === "upload" || procedure.type === "stream") && Value2.Check(procedure.requestData, initMessage.payload) && Value2.Check(procedure.requestInit, {})) {
|
|
1128
1220
|
passInitAsDataForBackwardsCompat = true;
|
|
@@ -1134,8 +1226,7 @@ var RiverServer = class {
|
|
|
1134
1226
|
transportMessage: initMessage,
|
|
1135
1227
|
tags: ["invalid-request"]
|
|
1136
1228
|
});
|
|
1137
|
-
|
|
1138
|
-
initMessage.from,
|
|
1229
|
+
cancelStream(
|
|
1139
1230
|
initMessage.streamId,
|
|
1140
1231
|
Err({
|
|
1141
1232
|
code: INVALID_REQUEST_CODE,
|
|
@@ -1145,37 +1236,33 @@ var RiverServer = class {
|
|
|
1145
1236
|
return null;
|
|
1146
1237
|
}
|
|
1147
1238
|
return {
|
|
1148
|
-
|
|
1149
|
-
|
|
1239
|
+
initialSession: session,
|
|
1240
|
+
streamId: initMessage.streamId,
|
|
1150
1241
|
procedureName: initMessage.procedureName,
|
|
1151
|
-
service,
|
|
1152
1242
|
serviceName: initMessage.serviceName,
|
|
1153
|
-
loggingMetadata: {
|
|
1154
|
-
...session.loggingMetadata,
|
|
1155
|
-
transportMessage: initMessage
|
|
1156
|
-
},
|
|
1157
|
-
streamId: initMessage.streamId,
|
|
1158
|
-
controlFlags: initMessage.controlFlags,
|
|
1159
1243
|
tracingCtx: initMessage.tracing,
|
|
1160
1244
|
initPayload: initMessage.payload,
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1245
|
+
sessionMetadata,
|
|
1246
|
+
procedure,
|
|
1247
|
+
serviceContext,
|
|
1248
|
+
procClosesWithInit: isStreamCloseBackwardsCompat(
|
|
1249
|
+
initMessage.controlFlags,
|
|
1250
|
+
session.protocolVersion
|
|
1251
|
+
),
|
|
1164
1252
|
passInitAsDataForBackwardsCompat
|
|
1165
1253
|
};
|
|
1166
1254
|
}
|
|
1167
|
-
|
|
1168
|
-
let
|
|
1169
|
-
if (!
|
|
1170
|
-
|
|
1171
|
-
|
|
1255
|
+
cancelStream(to, sessionScopedSend, streamId, payload) {
|
|
1256
|
+
let cancelledStreamsInSession = this.serverCancelledStreams.get(to);
|
|
1257
|
+
if (!cancelledStreamsInSession) {
|
|
1258
|
+
cancelledStreamsInSession = new LRUSet(
|
|
1259
|
+
this.maxCancelledStreamTombstonesPerSession
|
|
1260
|
+
);
|
|
1261
|
+
this.serverCancelledStreams.set(to, cancelledStreamsInSession);
|
|
1172
1262
|
}
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
// TODO remove once clients migrate to v2
|
|
1177
|
-
this.transport.sessions.get(to)?.protocolVersion === "v1.1" ? closeStreamMessage(streamId) : abortMessage(streamId, payload)
|
|
1178
|
-
);
|
|
1263
|
+
cancelledStreamsInSession.add(streamId);
|
|
1264
|
+
const msg = cancelMessage(streamId, payload);
|
|
1265
|
+
sessionScopedSend(msg);
|
|
1179
1266
|
}
|
|
1180
1267
|
};
|
|
1181
1268
|
var LRUSet = class {
|
|
@@ -1200,21 +1287,21 @@ var LRUSet = class {
|
|
|
1200
1287
|
return this.items.has(item);
|
|
1201
1288
|
}
|
|
1202
1289
|
};
|
|
1203
|
-
function
|
|
1290
|
+
function isStreamCancelBackwardsCompat(controlFlags, protocolVersion) {
|
|
1204
1291
|
if (protocolVersion === "v1.1") {
|
|
1205
1292
|
return false;
|
|
1206
1293
|
}
|
|
1207
|
-
return
|
|
1294
|
+
return isStreamCancel(controlFlags);
|
|
1208
1295
|
}
|
|
1209
1296
|
function isStreamCloseBackwardsCompat(controlFlags, protocolVersion) {
|
|
1210
1297
|
if (protocolVersion === "v1.1") {
|
|
1211
|
-
return
|
|
1298
|
+
return isStreamCancel(controlFlags);
|
|
1212
1299
|
}
|
|
1213
1300
|
return isStreamClose(controlFlags);
|
|
1214
1301
|
}
|
|
1215
1302
|
function getStreamCloseBackwardsCompat(protocolVersion) {
|
|
1216
1303
|
if (protocolVersion === "v1.1") {
|
|
1217
|
-
return 4 /*
|
|
1304
|
+
return 4 /* StreamCancelBit */;
|
|
1218
1305
|
}
|
|
1219
1306
|
return 8 /* StreamClosedBit */;
|
|
1220
1307
|
}
|
|
@@ -1224,7 +1311,7 @@ function createServer(transport, services, providedServerOptions) {
|
|
|
1224
1311
|
services,
|
|
1225
1312
|
providedServerOptions?.handshakeOptions,
|
|
1226
1313
|
providedServerOptions?.extendedContext,
|
|
1227
|
-
providedServerOptions?.
|
|
1314
|
+
providedServerOptions?.maxCancelledStreamTombstonesPerSession
|
|
1228
1315
|
);
|
|
1229
1316
|
}
|
|
1230
1317
|
|
|
@@ -1236,15 +1323,13 @@ function createServerHandshakeOptions(schema, validate) {
|
|
|
1236
1323
|
return { schema, validate };
|
|
1237
1324
|
}
|
|
1238
1325
|
export {
|
|
1239
|
-
|
|
1326
|
+
CANCEL_CODE,
|
|
1240
1327
|
Err,
|
|
1241
|
-
INTERNAL_RIVER_ERROR_CODE,
|
|
1242
1328
|
INVALID_REQUEST_CODE,
|
|
1243
1329
|
Ok,
|
|
1244
1330
|
Procedure,
|
|
1245
1331
|
version as RIVER_VERSION,
|
|
1246
|
-
|
|
1247
|
-
ResponseReaderErrorSchema,
|
|
1332
|
+
ReaderErrorSchema,
|
|
1248
1333
|
ServiceSchema,
|
|
1249
1334
|
UNCAUGHT_ERROR_CODE,
|
|
1250
1335
|
UNEXPECTED_DISCONNECT_CODE,
|
|
@@ -1252,6 +1337,9 @@ export {
|
|
|
1252
1337
|
createClientHandshakeOptions,
|
|
1253
1338
|
createServer,
|
|
1254
1339
|
createServerHandshakeOptions,
|
|
1255
|
-
|
|
1340
|
+
flattenErrorType,
|
|
1341
|
+
serializeSchema,
|
|
1342
|
+
serializeSchemaV1Compat,
|
|
1343
|
+
unwrapOrThrow
|
|
1256
1344
|
};
|
|
1257
1345
|
//# sourceMappingURL=index.js.map
|