@replit/river 0.203.1 → 0.204.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.
Files changed (49) hide show
  1. package/dist/{chunk-T4WWG42M.js → chunk-3V7VMJNA.js} +19 -16
  2. package/dist/chunk-3V7VMJNA.js.map +1 -0
  3. package/dist/{chunk-TMOCPK63.js → chunk-6YUDEFCS.js} +42 -8
  4. package/dist/chunk-6YUDEFCS.js.map +1 -0
  5. package/dist/chunk-LJCR3ADI.js +1955 -0
  6. package/dist/chunk-LJCR3ADI.js.map +1 -0
  7. package/dist/{chunk-2FHJVQBE.js → chunk-QSW7AWEP.js} +5 -11
  8. package/dist/chunk-QSW7AWEP.js.map +1 -0
  9. package/dist/{chunk-7MKTFUJO.js → chunk-YODW2ZMU.js} +4 -3
  10. package/dist/chunk-YODW2ZMU.js.map +1 -0
  11. package/dist/{client-5d2e41a3.d.ts → client-0c0a4a5e.d.ts} +1 -1
  12. package/dist/{connection-11a4af0f.d.ts → connection-7b62dfec.d.ts} +1 -1
  13. package/dist/{context-d6dd8a1a.d.ts → context-3cf1ed4e.d.ts} +8 -2
  14. package/dist/router/index.cjs +23 -12
  15. package/dist/router/index.cjs.map +1 -1
  16. package/dist/router/index.d.cts +7 -7
  17. package/dist/router/index.d.ts +7 -7
  18. package/dist/router/index.js +18 -1611
  19. package/dist/router/index.js.map +1 -1
  20. package/dist/{server-e46399f9.d.ts → server-a287de55.d.ts} +1 -1
  21. package/dist/{services-56cbea0d.d.ts → services-51980ecd.d.ts} +2 -2
  22. package/dist/testUtil/index.cjs +72 -32
  23. package/dist/testUtil/index.cjs.map +1 -1
  24. package/dist/testUtil/index.d.cts +4 -4
  25. package/dist/testUtil/index.d.ts +4 -4
  26. package/dist/testUtil/index.js +8 -6
  27. package/dist/testUtil/index.js.map +1 -1
  28. package/dist/transport/impls/ws/client.cjs +72 -40
  29. package/dist/transport/impls/ws/client.cjs.map +1 -1
  30. package/dist/transport/impls/ws/client.d.cts +3 -3
  31. package/dist/transport/impls/ws/client.d.ts +3 -3
  32. package/dist/transport/impls/ws/client.js +4 -4
  33. package/dist/transport/impls/ws/server.cjs +58 -28
  34. package/dist/transport/impls/ws/server.cjs.map +1 -1
  35. package/dist/transport/impls/ws/server.d.cts +3 -3
  36. package/dist/transport/impls/ws/server.d.ts +3 -3
  37. package/dist/transport/impls/ws/server.js +4 -4
  38. package/dist/transport/index.cjs +70 -31
  39. package/dist/transport/index.cjs.map +1 -1
  40. package/dist/transport/index.d.cts +3 -3
  41. package/dist/transport/index.d.ts +3 -3
  42. package/dist/transport/index.js +4 -4
  43. package/package.json +2 -2
  44. package/dist/chunk-2FHJVQBE.js.map +0 -1
  45. package/dist/chunk-7MKTFUJO.js.map +0 -1
  46. package/dist/chunk-AK7NTFAM.js +0 -331
  47. package/dist/chunk-AK7NTFAM.js.map +0 -1
  48. package/dist/chunk-T4WWG42M.js.map +0 -1
  49. package/dist/chunk-TMOCPK63.js.map +0 -1
@@ -1,1616 +1,23 @@
1
1
  import {
2
- ControlMessageCloseSchema,
3
- ControlMessagePayloadSchema,
4
- cancelMessage,
5
- closeStreamMessage,
6
- coerceErrorString,
7
- createHandlerSpan,
8
- createProcTelemetryInfo,
9
- generateId,
10
- getPropagationContext,
11
- isStreamCancel,
12
- isStreamClose,
13
- isStreamOpen,
2
+ CANCEL_CODE,
3
+ Err,
4
+ INVALID_REQUEST_CODE,
5
+ Ok,
6
+ Procedure,
7
+ ReaderErrorSchema,
8
+ ServiceSchema,
9
+ UNCAUGHT_ERROR_CODE,
10
+ UNEXPECTED_DISCONNECT_CODE,
11
+ createClient,
12
+ createClientHandshakeOptions,
13
+ createServer,
14
+ createServerHandshakeOptions,
15
+ flattenErrorType,
16
+ serializeSchema,
17
+ serializeSchemaV1Compat,
18
+ unwrapOrThrow,
14
19
  version
15
- } from "../chunk-AK7NTFAM.js";
16
-
17
- // router/services.ts
18
- import { Type as Type2, Kind as Kind2 } from "@sinclair/typebox";
19
-
20
- // router/errors.ts
21
- import {
22
- Kind,
23
- Type
24
- } from "@sinclair/typebox";
25
- var UNCAUGHT_ERROR_CODE = "UNCAUGHT_ERROR";
26
- var UNEXPECTED_DISCONNECT_CODE = "UNEXPECTED_DISCONNECT";
27
- var INVALID_REQUEST_CODE = "INVALID_REQUEST";
28
- var CANCEL_CODE = "CANCEL";
29
- var ErrResultSchema = (t) => Type.Object({
30
- ok: Type.Literal(false),
31
- payload: t
32
- });
33
- var ReaderErrorSchema = Type.Union([
34
- Type.Object({
35
- code: Type.Literal(UNCAUGHT_ERROR_CODE),
36
- message: Type.String()
37
- }),
38
- Type.Object({
39
- code: Type.Literal(UNEXPECTED_DISCONNECT_CODE),
40
- message: Type.String()
41
- }),
42
- Type.Object({
43
- code: Type.Literal(INVALID_REQUEST_CODE),
44
- message: Type.String()
45
- }),
46
- Type.Object({
47
- code: Type.Literal(CANCEL_CODE),
48
- message: Type.String()
49
- })
50
- ]);
51
- function isUnion(schema) {
52
- return schema[Kind] === "Union";
53
- }
54
- function flattenErrorType(errType) {
55
- if (!isUnion(errType)) {
56
- return errType;
57
- }
58
- const flattenedTypes = [];
59
- function flatten(type) {
60
- if (isUnion(type)) {
61
- for (const t of type.anyOf) {
62
- flatten(t);
63
- }
64
- } else {
65
- flattenedTypes.push(type);
66
- }
67
- }
68
- flatten(errType);
69
- return Type.Union(flattenedTypes);
70
- }
71
-
72
- // router/services.ts
73
- function serializeSchemaV1Compat(services, handshakeSchema) {
74
- const serializedServiceObject = Object.entries(services).reduce((acc, [name, value]) => {
75
- acc[name] = value.serializeV1Compat();
76
- return acc;
77
- }, {});
78
- const schema = {
79
- services: serializedServiceObject
80
- };
81
- if (handshakeSchema) {
82
- schema.handshakeSchema = Type2.Strict(handshakeSchema);
83
- }
84
- return schema;
85
- }
86
- function serializeSchema(services, handshakeSchema) {
87
- const serializedServiceObject = Object.entries(services).reduce((acc, [name, value]) => {
88
- acc[name] = value.serialize();
89
- return acc;
90
- }, {});
91
- const schema = {
92
- services: serializedServiceObject
93
- };
94
- if (handshakeSchema) {
95
- schema.handshakeSchema = Type2.Strict(handshakeSchema);
96
- }
97
- return schema;
98
- }
99
- var ServiceSchema = class _ServiceSchema {
100
- /**
101
- * Factory function for creating a fresh state.
102
- */
103
- initializeState;
104
- /**
105
- * The procedures for this service.
106
- */
107
- procedures;
108
- /**
109
- * @param config - The configuration for this service.
110
- * @param procedures - The procedures for this service.
111
- */
112
- constructor(config, procedures) {
113
- this.initializeState = config.initializeState;
114
- this.procedures = procedures;
115
- }
116
- /**
117
- * Creates a {@link ServiceScaffold}, which can be used to define procedures
118
- * that can then be merged into a {@link ServiceSchema}, via the scaffold's
119
- * `finalize` method.
120
- *
121
- * There are two patterns that work well with this method. The first is using
122
- * it to separate the definition of procedures from the definition of the
123
- * service's configuration:
124
- * ```ts
125
- * const MyServiceScaffold = ServiceSchema.scaffold({
126
- * initializeState: () => ({ count: 0 }),
127
- * });
128
- *
129
- * const incrementProcedures = MyServiceScaffold.procedures({
130
- * increment: Procedure.rpc({
131
- * requestInit: Type.Object({ amount: Type.Number() }),
132
- * responseData: Type.Object({ current: Type.Number() }),
133
- * async handler(ctx, init) {
134
- * ctx.state.count += init.amount;
135
- * return Ok({ current: ctx.state.count });
136
- * }
137
- * }),
138
- * })
139
- *
140
- * const MyService = MyServiceScaffold.finalize({
141
- * ...incrementProcedures,
142
- * // you can also directly define procedures here
143
- * });
144
- * ```
145
- * This might be really handy if you have a very large service and you're
146
- * wanting to split it over multiple files. You can define the scaffold
147
- * in one file, and then import that scaffold in other files where you
148
- * define procedures - and then finally import the scaffolds and your
149
- * procedure objects in a final file where you finalize the scaffold into
150
- * a service schema.
151
- *
152
- * The other way is to use it like in a builder pattern:
153
- * ```ts
154
- * const MyService = ServiceSchema
155
- * .scaffold({ initializeState: () => ({ count: 0 }) })
156
- * .finalize({
157
- * increment: Procedure.rpc({
158
- * requestInit: Type.Object({ amount: Type.Number() }),
159
- * responseData: Type.Object({ current: Type.Number() }),
160
- * async handler(ctx, init) {
161
- * ctx.state.count += init.amount;
162
- * return Ok({ current: ctx.state.count });
163
- * }
164
- * }),
165
- * })
166
- * ```
167
- * Depending on your preferences, this may be a more appealing way to define
168
- * a schema versus using the {@link ServiceSchema.define} method.
169
- */
170
- static scaffold(config) {
171
- return new ServiceScaffold(config);
172
- }
173
- // actual implementation
174
- static define(configOrProcedures, maybeProcedures) {
175
- let config;
176
- let procedures;
177
- if ("initializeState" in configOrProcedures && typeof configOrProcedures.initializeState === "function") {
178
- if (!maybeProcedures) {
179
- throw new Error("Expected procedures to be defined");
180
- }
181
- config = configOrProcedures;
182
- procedures = maybeProcedures;
183
- } else {
184
- config = { initializeState: () => ({}) };
185
- procedures = configOrProcedures;
186
- }
187
- return new _ServiceSchema(config, procedures);
188
- }
189
- /**
190
- * Serializes this schema's procedures into a plain object that is JSON compatible.
191
- */
192
- serialize() {
193
- return {
194
- procedures: Object.fromEntries(
195
- Object.entries(this.procedures).map(([procName, procDef]) => [
196
- procName,
197
- {
198
- init: Type2.Strict(procDef.requestInit),
199
- output: Type2.Strict(procDef.responseData),
200
- errors: getSerializedProcErrors(procDef),
201
- // Only add `description` field if the type declares it.
202
- ..."description" in procDef ? { description: procDef.description } : {},
203
- type: procDef.type,
204
- // Only add the `input` field if the type declares it.
205
- ..."requestData" in procDef ? {
206
- input: Type2.Strict(procDef.requestData)
207
- } : {}
208
- }
209
- ])
210
- )
211
- };
212
- }
213
- // TODO remove once clients migrate to v2
214
- /**
215
- * Same as {@link ServiceSchema.serialize}, but with a format that is compatible with
216
- * protocol v1. This is useful to be able to continue to generate schemas for older
217
- * clients as they are still supported.
218
- */
219
- serializeV1Compat() {
220
- return {
221
- procedures: Object.fromEntries(
222
- Object.entries(this.procedures).map(
223
- ([procName, procDef]) => {
224
- if (procDef.type === "rpc" || procDef.type === "subscription") {
225
- return [
226
- procName,
227
- {
228
- // BACKWARDS COMPAT: map init to input for protocolv1
229
- // this is the only change needed to make it compatible.
230
- input: Type2.Strict(procDef.requestInit),
231
- output: Type2.Strict(procDef.responseData),
232
- errors: getSerializedProcErrors(procDef),
233
- // Only add `description` field if the type declares it.
234
- ..."description" in procDef ? { description: procDef.description } : {},
235
- type: procDef.type
236
- }
237
- ];
238
- }
239
- return [
240
- procName,
241
- {
242
- init: Type2.Strict(procDef.requestInit),
243
- output: Type2.Strict(procDef.responseData),
244
- errors: getSerializedProcErrors(procDef),
245
- // Only add `description` field if the type declares it.
246
- ..."description" in procDef ? { description: procDef.description } : {},
247
- type: procDef.type,
248
- input: Type2.Strict(procDef.requestData)
249
- }
250
- ];
251
- }
252
- )
253
- )
254
- };
255
- }
256
- /**
257
- * Instantiates this schema into a {@link Service} object.
258
- *
259
- * You probably don't need this, usually the River server will handle this
260
- * for you.
261
- */
262
- instantiate(extendedContext) {
263
- const state = this.initializeState(extendedContext);
264
- const dispose = async () => {
265
- await state[Symbol.asyncDispose]?.();
266
- state[Symbol.dispose]?.();
267
- };
268
- return Object.freeze({
269
- state,
270
- procedures: this.procedures,
271
- [Symbol.asyncDispose]: dispose
272
- });
273
- }
274
- };
275
- function getSerializedProcErrors(procDef) {
276
- if (!("responseError" in procDef) || procDef.responseError[Kind2] === "Never") {
277
- return Type2.Strict(ReaderErrorSchema);
278
- }
279
- const withProtocolErrors = flattenErrorType(
280
- Type2.Union([procDef.responseError, ReaderErrorSchema])
281
- );
282
- return Type2.Strict(withProtocolErrors);
283
- }
284
- var ServiceScaffold = class {
285
- /**
286
- * The configuration for this service.
287
- */
288
- config;
289
- /**
290
- * @param config - The configuration for this service.
291
- */
292
- constructor(config) {
293
- this.config = config;
294
- }
295
- /**
296
- * Define procedures for this service. Use the {@link Procedure} constructors
297
- * to create them. This returns the procedures object, which can then be
298
- * passed to {@link ServiceSchema.finalize} to create a {@link ServiceSchema}.
299
- *
300
- * @example
301
- * ```
302
- * const myProcedures = MyServiceScaffold.procedures({
303
- * myRPC: Procedure.rpc({
304
- * // ...
305
- * }),
306
- * });
307
- *
308
- * const MyService = MyServiceScaffold.finalize({
309
- * ...myProcedures,
310
- * });
311
- * ```
312
- *
313
- * @param procedures - The procedures for this service.
314
- */
315
- procedures(procedures) {
316
- return procedures;
317
- }
318
- /**
319
- * Finalizes the scaffold into a {@link ServiceSchema}. This is where you
320
- * provide the service's procedures and get a {@link ServiceSchema} in return.
321
- *
322
- * You can directly define procedures here, or you can define them separately
323
- * with the {@link ServiceScaffold.procedures} method, and then pass them here.
324
- *
325
- * @example
326
- * ```
327
- * const MyService = MyServiceScaffold.finalize({
328
- * myRPC: Procedure.rpc({
329
- * // ...
330
- * }),
331
- * // e.g. from the procedures method
332
- * ...myOtherProcedures,
333
- * });
334
- * ```
335
- */
336
- finalize(procedures) {
337
- return ServiceSchema.define(this.config, procedures);
338
- }
339
- };
340
-
341
- // router/procedures.ts
342
- import { Type as Type3 } from "@sinclair/typebox";
343
- function rpc({
344
- requestInit,
345
- responseData,
346
- responseError = Type3.Never(),
347
- description,
348
- handler
349
- }) {
350
- return {
351
- ...description ? { description } : {},
352
- type: "rpc",
353
- requestInit,
354
- responseData,
355
- responseError,
356
- handler
357
- };
358
- }
359
- function upload({
360
- requestInit,
361
- requestData,
362
- responseData,
363
- responseError = Type3.Never(),
364
- description,
365
- handler
366
- }) {
367
- return {
368
- type: "upload",
369
- ...description ? { description } : {},
370
- requestInit,
371
- requestData,
372
- responseData,
373
- responseError,
374
- handler
375
- };
376
- }
377
- function subscription({
378
- requestInit,
379
- responseData,
380
- responseError = Type3.Never(),
381
- description,
382
- handler
383
- }) {
384
- return {
385
- type: "subscription",
386
- ...description ? { description } : {},
387
- requestInit,
388
- responseData,
389
- responseError,
390
- handler
391
- };
392
- }
393
- function stream({
394
- requestInit,
395
- requestData,
396
- responseData,
397
- responseError = Type3.Never(),
398
- description,
399
- handler
400
- }) {
401
- return {
402
- type: "stream",
403
- ...description ? { description } : {},
404
- requestInit,
405
- requestData,
406
- responseData,
407
- responseError,
408
- handler
409
- };
410
- }
411
- var Procedure = {
412
- rpc,
413
- upload,
414
- subscription,
415
- stream
416
- };
417
-
418
- // router/result.ts
419
- import { Type as Type4 } from "@sinclair/typebox";
420
- var AnyResultSchema = Type4.Union([
421
- Type4.Object({
422
- ok: Type4.Literal(false),
423
- payload: Type4.Object({
424
- code: Type4.String(),
425
- message: Type4.String(),
426
- extras: Type4.Optional(Type4.Unknown())
427
- })
428
- }),
429
- Type4.Object({
430
- ok: Type4.Literal(true),
431
- payload: Type4.Unknown()
432
- })
433
- ]);
434
- function Ok(payload) {
435
- return {
436
- ok: true,
437
- payload
438
- };
439
- }
440
- function Err(error) {
441
- return {
442
- ok: false,
443
- payload: error
444
- };
445
- }
446
- function unwrapOrThrow(result) {
447
- if (result.ok) {
448
- return result.payload;
449
- }
450
- throw new Error(
451
- `Cannot non-ok result, got: ${result.payload.code} - ${result.payload.message}`
452
- );
453
- }
454
-
455
- // router/streams.ts
456
- var ReadableBrokenError = {
457
- code: "READABLE_BROKEN",
458
- message: "Readable was broken before it is fully consumed"
459
- };
460
- function createPromiseWithResolvers() {
461
- let resolve;
462
- let reject;
463
- const promise = new Promise((res, rej) => {
464
- resolve = res;
465
- reject = rej;
466
- });
467
- return {
468
- promise,
469
- // @ts-expect-error promise callbacks are sync
470
- resolve,
471
- // @ts-expect-error promise callbacks are sync
472
- reject
473
- };
474
- }
475
- var ReadableImpl = class {
476
- /**
477
- * Whether the {@link Readable} is closed.
478
- *
479
- * Closed {@link Readable}s are done receiving values, but that doesn't affect
480
- * any other aspect of the {@link Readable} such as it's consumability.
481
- */
482
- closed = false;
483
- /**
484
- * Whether the {@link Readable} is locked.
485
- *
486
- * @see {@link Readable}'s typedoc to understand locking
487
- */
488
- locked = false;
489
- /**
490
- * Whether {@link break} was called.
491
- *
492
- * @see {@link break} for more information
493
- */
494
- broken = false;
495
- /**
496
- * This flag allows us to avoid emitting a {@link ReadableBrokenError} after {@link break} was called
497
- * in cases where the {@link queue} is fully consumed and {@link ReadableImpl} is {@link closed}. This is just an
498
- * ergonomic feature to avoid emitting an error in our iteration when we don't have to.
499
- */
500
- brokenWithValuesLeftToRead = false;
501
- /**
502
- * A list of values that have been pushed to the {@link ReadableImpl} but not yet emitted to the user.
503
- */
504
- queue = [];
505
- /**
506
- * Used by methods in the class to signal to the iterator that it
507
- * should check for the next value.
508
- */
509
- next = null;
510
- [Symbol.asyncIterator]() {
511
- if (this.locked) {
512
- throw new TypeError("Readable is already locked");
513
- }
514
- this.locked = true;
515
- let didSignalBreak = false;
516
- return {
517
- next: async () => {
518
- if (didSignalBreak) {
519
- return {
520
- done: true,
521
- value: void 0
522
- };
523
- }
524
- while (this.queue.length === 0) {
525
- if (this.closed && !this.brokenWithValuesLeftToRead) {
526
- return {
527
- done: true,
528
- value: void 0
529
- };
530
- }
531
- if (this.broken) {
532
- didSignalBreak = true;
533
- return {
534
- done: false,
535
- value: Err(ReadableBrokenError)
536
- };
537
- }
538
- if (!this.next) {
539
- this.next = createPromiseWithResolvers();
540
- }
541
- await this.next.promise;
542
- this.next = null;
543
- }
544
- const value = this.queue.shift();
545
- return { done: false, value };
546
- },
547
- return: () => {
548
- this.break();
549
- return { done: true, value: void 0 };
550
- }
551
- };
552
- }
553
- async collect() {
554
- const array = [];
555
- for await (const value of this) {
556
- array.push(value);
557
- }
558
- return array;
559
- }
560
- break() {
561
- if (this.broken) {
562
- return;
563
- }
564
- this.locked = true;
565
- this.broken = true;
566
- this.brokenWithValuesLeftToRead = this.queue.length > 0;
567
- this.queue.length = 0;
568
- this.next?.resolve();
569
- }
570
- isReadable() {
571
- return !this.locked && !this.broken;
572
- }
573
- /**
574
- * @internal meant for use within river, not exposed as a public API
575
- *
576
- * Pushes a value to be read.
577
- */
578
- _pushValue(value) {
579
- if (this.broken) {
580
- return;
581
- }
582
- if (this.closed) {
583
- throw new Error("Cannot push to closed Readable");
584
- }
585
- this.queue.push(value);
586
- this.next?.resolve();
587
- }
588
- /**
589
- * @internal meant for use within river, not exposed as a public API
590
- *
591
- * Triggers the close of the {@link Readable}. Make sure to push all remaining
592
- * values before calling this method.
593
- */
594
- _triggerClose() {
595
- if (this.closed) {
596
- throw new Error("Unexpected closing multiple times");
597
- }
598
- this.closed = true;
599
- this.next?.resolve();
600
- }
601
- /**
602
- * @internal meant for use within river, not exposed as a public API
603
- */
604
- _hasValuesInQueue() {
605
- return this.queue.length > 0;
606
- }
607
- /**
608
- * @internal meant for use within river, not exposed as a public API
609
- */
610
- isClosed() {
611
- return this.closed;
612
- }
613
- };
614
- var WritableImpl = class {
615
- /**
616
- * Passed via constructor to pass on calls to {@link write}
617
- */
618
- writeCb;
619
- /**
620
- * Passed via constructor to pass on calls to {@link close}
621
- */
622
- closeCb;
623
- /**
624
- * Whether {@link close} was called, and {@link Writable} is not writable anymore.
625
- */
626
- closed = false;
627
- constructor(callbacks) {
628
- this.writeCb = callbacks.writeCb;
629
- this.closeCb = callbacks.closeCb;
630
- }
631
- write(value) {
632
- if (this.closed) {
633
- throw new Error("Cannot write to closed Writable");
634
- }
635
- this.writeCb(value);
636
- }
637
- isWritable() {
638
- return !this.closed;
639
- }
640
- close() {
641
- if (this.closed) {
642
- return;
643
- }
644
- this.closed = true;
645
- this.writeCb = () => void 0;
646
- this.closeCb();
647
- this.closeCb = () => void 0;
648
- }
649
- /**
650
- * @internal meant for use within river, not exposed as a public API
651
- */
652
- isClosed() {
653
- return this.closed;
654
- }
655
- };
656
-
657
- // router/client.ts
658
- import { Value } from "@sinclair/typebox/value";
659
- var ReaderErrResultSchema = ErrResultSchema(ReaderErrorSchema);
660
- var noop = () => {
661
- };
662
- function _createRecursiveProxy(callback, path) {
663
- const proxy = new Proxy(noop, {
664
- // property access, recurse and add field to path
665
- get(_obj, key) {
666
- if (typeof key !== "string")
667
- return void 0;
668
- return _createRecursiveProxy(callback, [...path, key]);
669
- },
670
- // hit the end, let's invoke the handler
671
- apply(_target, _this, args) {
672
- return callback({
673
- path,
674
- args
675
- });
676
- }
677
- });
678
- return proxy;
679
- }
680
- var defaultClientOptions = {
681
- connectOnInvoke: true,
682
- eagerlyConnect: true
683
- };
684
- function createClient(transport, serverId, providedClientOptions = {}) {
685
- if (providedClientOptions.handshakeOptions) {
686
- transport.extendHandshake(providedClientOptions.handshakeOptions);
687
- }
688
- const clientOptions = { ...defaultClientOptions, ...providedClientOptions };
689
- if (clientOptions.eagerlyConnect) {
690
- transport.connect(serverId);
691
- }
692
- return _createRecursiveProxy((opts) => {
693
- const [serviceName, procName, procMethod] = [...opts.path];
694
- if (!(serviceName && procName && procMethod)) {
695
- throw new Error(
696
- "invalid river call, ensure the service and procedure you are calling exists"
697
- );
698
- }
699
- const [init, callOptions] = opts.args;
700
- if (clientOptions.connectOnInvoke && !transport.sessions.has(serverId)) {
701
- transport.connect(serverId);
702
- }
703
- if (procMethod !== "rpc" && procMethod !== "subscribe" && procMethod !== "stream" && procMethod !== "upload") {
704
- throw new Error(
705
- `invalid river call, unknown procedure type ${procMethod}`
706
- );
707
- }
708
- return handleProc(
709
- procMethod === "subscribe" ? "subscription" : procMethod,
710
- transport,
711
- serverId,
712
- init,
713
- serviceName,
714
- procName,
715
- callOptions ? callOptions.signal : void 0
716
- );
717
- }, []);
718
- }
719
- function handleProc(procType, transport, serverId, init, serviceName, procedureName, abortSignal) {
720
- const session = transport.sessions.get(serverId) ?? transport.createUnconnectedSession(serverId);
721
- const sessionScopedSend = transport.getSessionBoundSendFn(
722
- serverId,
723
- session.id
724
- );
725
- const procClosesWithInit = procType === "rpc" || procType === "subscription";
726
- const streamId = generateId();
727
- const { span, ctx } = createProcTelemetryInfo(
728
- session,
729
- procType,
730
- serviceName,
731
- procedureName,
732
- streamId
733
- );
734
- let cleanClose = true;
735
- const reqWritable = new WritableImpl({
736
- writeCb: (rawIn) => {
737
- sessionScopedSend({
738
- streamId,
739
- payload: rawIn,
740
- controlFlags: 0
741
- });
742
- },
743
- // close callback
744
- closeCb: () => {
745
- span.addEvent("reqWritable closed");
746
- if (!procClosesWithInit && cleanClose) {
747
- sessionScopedSend(closeStreamMessage(streamId));
748
- }
749
- if (resReadable.isClosed()) {
750
- cleanup();
751
- }
752
- }
753
- });
754
- const resReadable = new ReadableImpl();
755
- const closeReadable = () => {
756
- resReadable._triggerClose();
757
- span.addEvent("resReadable closed");
758
- if (reqWritable.isClosed()) {
759
- cleanup();
760
- }
761
- };
762
- function cleanup() {
763
- transport.removeEventListener("message", onMessage);
764
- transport.removeEventListener("sessionStatus", onSessionStatus);
765
- abortSignal?.removeEventListener("abort", onClientCancel);
766
- span.end();
767
- }
768
- function onClientCancel() {
769
- if (resReadable.isClosed() && reqWritable.isClosed()) {
770
- return;
771
- }
772
- span.addEvent("sending cancel");
773
- cleanClose = false;
774
- if (!resReadable.isClosed()) {
775
- resReadable._pushValue(
776
- Err({
777
- code: CANCEL_CODE,
778
- message: "cancelled by client"
779
- })
780
- );
781
- closeReadable();
782
- }
783
- reqWritable.close();
784
- sessionScopedSend(
785
- cancelMessage(
786
- streamId,
787
- Err({
788
- code: CANCEL_CODE,
789
- message: "cancelled by client"
790
- })
791
- )
792
- );
793
- }
794
- function onMessage(msg) {
795
- if (msg.streamId !== streamId)
796
- return;
797
- if (msg.to !== transport.clientId) {
798
- transport.log?.error("got stream message from unexpected client", {
799
- clientId: transport.clientId,
800
- transportMessage: msg
801
- });
802
- return;
803
- }
804
- if (isStreamCancel(msg.controlFlags)) {
805
- cleanClose = false;
806
- span.addEvent("received cancel");
807
- let cancelResult;
808
- if (Value.Check(ReaderErrResultSchema, msg.payload)) {
809
- cancelResult = msg.payload;
810
- } else {
811
- cancelResult = Err({
812
- code: CANCEL_CODE,
813
- message: "stream cancelled with invalid payload"
814
- });
815
- transport.log?.error(
816
- "got stream cancel without a valid protocol error",
817
- {
818
- clientId: transport.clientId,
819
- transportMessage: msg,
820
- validationErrors: [
821
- ...Value.Errors(ReaderErrResultSchema, msg.payload)
822
- ]
823
- }
824
- );
825
- }
826
- if (!resReadable.isClosed()) {
827
- resReadable._pushValue(cancelResult);
828
- closeReadable();
829
- }
830
- reqWritable.close();
831
- return;
832
- }
833
- if (resReadable.isClosed()) {
834
- span.recordException("received message after response stream is closed");
835
- transport.log?.error("received message after response stream is closed", {
836
- clientId: transport.clientId,
837
- transportMessage: msg
838
- });
839
- return;
840
- }
841
- if (!Value.Check(ControlMessageCloseSchema, msg.payload)) {
842
- if (Value.Check(AnyResultSchema, msg.payload)) {
843
- resReadable._pushValue(msg.payload);
844
- } else {
845
- transport.log?.error(
846
- "Got non-control payload, but was not a valid result",
847
- {
848
- clientId: transport.clientId,
849
- transportMessage: msg,
850
- validationErrors: [...Value.Errors(AnyResultSchema, msg.payload)]
851
- }
852
- );
853
- }
854
- }
855
- if (isStreamClose(msg.controlFlags)) {
856
- span.addEvent("received response close");
857
- if (resReadable.isClosed()) {
858
- transport.log?.error(
859
- "received stream close but readable was already closed"
860
- );
861
- } else {
862
- closeReadable();
863
- }
864
- }
865
- }
866
- function onSessionStatus(evt) {
867
- if (evt.status !== "disconnect" || evt.session.to !== serverId || session.id !== evt.session.id) {
868
- return;
869
- }
870
- cleanClose = false;
871
- if (!resReadable.isClosed()) {
872
- resReadable._pushValue(
873
- Err({
874
- code: UNEXPECTED_DISCONNECT_CODE,
875
- message: `${serverId} unexpectedly disconnected`
876
- })
877
- );
878
- closeReadable();
879
- }
880
- reqWritable.close();
881
- }
882
- abortSignal?.addEventListener("abort", onClientCancel);
883
- transport.addEventListener("message", onMessage);
884
- transport.addEventListener("sessionStatus", onSessionStatus);
885
- sessionScopedSend({
886
- streamId,
887
- serviceName,
888
- procedureName,
889
- tracing: getPropagationContext(ctx),
890
- payload: init,
891
- controlFlags: procClosesWithInit ? 2 /* StreamOpenBit */ | 8 /* StreamClosedBit */ : 2 /* StreamOpenBit */
892
- });
893
- if (procClosesWithInit) {
894
- reqWritable.close();
895
- }
896
- if (procType === "subscription") {
897
- return {
898
- resReadable
899
- };
900
- }
901
- if (procType === "rpc") {
902
- return getSingleMessage(resReadable, transport.log);
903
- }
904
- if (procType === "upload") {
905
- let didFinalize = false;
906
- return {
907
- reqWritable,
908
- finalize: () => {
909
- if (didFinalize) {
910
- throw new Error("upload stream already finalized");
911
- }
912
- didFinalize = true;
913
- if (!reqWritable.isClosed()) {
914
- reqWritable.close();
915
- }
916
- return getSingleMessage(resReadable, transport.log);
917
- }
918
- };
919
- }
920
- return {
921
- resReadable,
922
- reqWritable
923
- };
924
- }
925
- async function getSingleMessage(resReadable, log) {
926
- const ret = await resReadable.collect();
927
- if (ret.length > 1) {
928
- log?.error("Expected single message from server, got multiple");
929
- }
930
- return ret[0];
931
- }
932
-
933
- // router/server.ts
934
- import { Type as Type5 } from "@sinclair/typebox";
935
- import { Value as Value2 } from "@sinclair/typebox/value";
936
- import { SpanStatusCode } from "@opentelemetry/api";
937
- var CancelResultSchema = ErrResultSchema(
938
- Type5.Object({
939
- code: Type5.Literal(CANCEL_CODE),
940
- message: Type5.String()
941
- })
942
- );
943
- var RiverServer = class {
944
- transport;
945
- contextMap;
946
- log;
947
- /**
948
- * We create a tombstones for streams cancelled by the server
949
- * so that we don't hit errors when the client has inflight
950
- * requests it sent before it saw the cancel.
951
- * We track cancelled streams for every client separately, so
952
- * that bad clients don't affect good clients.
953
- */
954
- serverCancelledStreams;
955
- maxCancelledStreamTombstonesPerSession;
956
- streams;
957
- services;
958
- unregisterTransportListeners;
959
- constructor(transport, services, handshakeOptions, extendedContext, maxCancelledStreamTombstonesPerSession = 200) {
960
- const instances = {};
961
- this.services = instances;
962
- this.contextMap = /* @__PURE__ */ new Map();
963
- for (const [name, service] of Object.entries(services)) {
964
- const instance = service.instantiate(extendedContext ?? {});
965
- instances[name] = instance;
966
- this.contextMap.set(instance, {
967
- ...extendedContext,
968
- state: instance.state
969
- });
970
- }
971
- if (handshakeOptions) {
972
- transport.extendHandshake(handshakeOptions);
973
- }
974
- this.transport = transport;
975
- this.streams = /* @__PURE__ */ new Map();
976
- this.serverCancelledStreams = /* @__PURE__ */ new Map();
977
- this.maxCancelledStreamTombstonesPerSession = maxCancelledStreamTombstonesPerSession;
978
- this.log = transport.log;
979
- const handleCreatingNewStreams = (message) => {
980
- if (message.to !== this.transport.clientId) {
981
- this.log?.info(
982
- `got msg with destination that isn't this server, ignoring`,
983
- {
984
- clientId: this.transport.clientId,
985
- transportMessage: message
986
- }
987
- );
988
- return;
989
- }
990
- const streamId = message.streamId;
991
- const stream2 = this.streams.get(streamId);
992
- if (stream2) {
993
- stream2.handleMsg(message);
994
- return;
995
- }
996
- if (this.serverCancelledStreams.get(message.from)?.has(streamId)) {
997
- return;
998
- }
999
- const newStreamProps = this.validateNewProcStream(message);
1000
- if (!newStreamProps) {
1001
- return;
1002
- }
1003
- createHandlerSpan(
1004
- newStreamProps.initialSession,
1005
- newStreamProps.procedure.type,
1006
- newStreamProps.serviceName,
1007
- newStreamProps.procedureName,
1008
- newStreamProps.streamId,
1009
- newStreamProps.tracingCtx,
1010
- (span) => {
1011
- this.createNewProcStream(span, newStreamProps);
1012
- }
1013
- );
1014
- };
1015
- const handleSessionStatus = (evt) => {
1016
- if (evt.status !== "disconnect")
1017
- return;
1018
- const disconnectedClientId = evt.session.to;
1019
- this.log?.info(
1020
- `got session disconnect from ${disconnectedClientId}, cleaning up streams`,
1021
- evt.session.loggingMetadata
1022
- );
1023
- for (const stream2 of this.streams.values()) {
1024
- if (stream2.from === disconnectedClientId) {
1025
- stream2.handleSessionDisconnect();
1026
- }
1027
- }
1028
- this.serverCancelledStreams.delete(disconnectedClientId);
1029
- };
1030
- const handleTransportStatus = (evt) => {
1031
- if (evt.status !== "closed")
1032
- return;
1033
- this.unregisterTransportListeners();
1034
- };
1035
- this.unregisterTransportListeners = () => {
1036
- this.transport.removeEventListener("message", handleCreatingNewStreams);
1037
- this.transport.removeEventListener("sessionStatus", handleSessionStatus);
1038
- this.transport.removeEventListener(
1039
- "transportStatus",
1040
- handleTransportStatus
1041
- );
1042
- };
1043
- this.transport.addEventListener("message", handleCreatingNewStreams);
1044
- this.transport.addEventListener("sessionStatus", handleSessionStatus);
1045
- this.transport.addEventListener("transportStatus", handleTransportStatus);
1046
- }
1047
- createNewProcStream(span, props) {
1048
- const {
1049
- streamId,
1050
- initialSession,
1051
- procedureName,
1052
- serviceName,
1053
- procedure,
1054
- sessionMetadata,
1055
- serviceContext,
1056
- initPayload,
1057
- procClosesWithInit,
1058
- passInitAsDataForBackwardsCompat
1059
- } = props;
1060
- const {
1061
- to: from,
1062
- loggingMetadata,
1063
- protocolVersion,
1064
- id: sessionId
1065
- } = initialSession;
1066
- loggingMetadata.telemetry = {
1067
- traceId: span.spanContext().traceId,
1068
- spanId: span.spanContext().spanId
1069
- };
1070
- let cleanClose = true;
1071
- const onMessage = (msg) => {
1072
- if (msg.from !== from) {
1073
- this.log?.error("got stream message from unexpected client", {
1074
- ...loggingMetadata,
1075
- transportMessage: msg,
1076
- tags: ["invariant-violation"]
1077
- });
1078
- return;
1079
- }
1080
- if (isStreamCancelBackwardsCompat(msg.controlFlags, protocolVersion)) {
1081
- let cancelResult;
1082
- if (Value2.Check(CancelResultSchema, msg.payload)) {
1083
- cancelResult = msg.payload;
1084
- } else {
1085
- cancelResult = Err({
1086
- code: CANCEL_CODE,
1087
- message: "stream cancelled, client sent invalid payload"
1088
- });
1089
- this.log?.warn("got stream cancel without a valid protocol error", {
1090
- ...loggingMetadata,
1091
- transportMessage: msg,
1092
- validationErrors: [
1093
- ...Value2.Errors(CancelResultSchema, msg.payload)
1094
- ],
1095
- tags: ["invalid-request"]
1096
- });
1097
- }
1098
- if (!reqReadable.isClosed()) {
1099
- reqReadable._pushValue(cancelResult);
1100
- closeReadable();
1101
- }
1102
- resWritable.close();
1103
- return;
1104
- }
1105
- if (reqReadable.isClosed()) {
1106
- this.log?.warn("received message after request stream is closed", {
1107
- ...loggingMetadata,
1108
- transportMessage: msg,
1109
- tags: ["invalid-request"]
1110
- });
1111
- onServerCancel({
1112
- code: INVALID_REQUEST_CODE,
1113
- message: "received message after request stream is closed"
1114
- });
1115
- return;
1116
- }
1117
- if ("requestData" in procedure && Value2.Check(procedure.requestData, msg.payload)) {
1118
- reqReadable._pushValue(Ok(msg.payload));
1119
- if (isStreamCloseBackwardsCompat(msg.controlFlags, protocolVersion)) {
1120
- closeReadable();
1121
- }
1122
- return;
1123
- }
1124
- if (Value2.Check(ControlMessagePayloadSchema, msg.payload) && isStreamCloseBackwardsCompat(msg.controlFlags, protocolVersion)) {
1125
- closeReadable();
1126
- return;
1127
- }
1128
- let validationErrors;
1129
- let errMessage;
1130
- if ("requestData" in procedure) {
1131
- errMessage = "expected requestData or control payload";
1132
- validationErrors = [
1133
- ...Value2.Errors(procedure.responseData, msg.payload)
1134
- ];
1135
- } else {
1136
- validationErrors = [
1137
- ...Value2.Errors(ControlMessagePayloadSchema, msg.payload)
1138
- ];
1139
- errMessage = "expected control payload";
1140
- }
1141
- this.log?.warn(errMessage, {
1142
- ...loggingMetadata,
1143
- transportMessage: msg,
1144
- validationErrors,
1145
- tags: ["invalid-request"]
1146
- });
1147
- onServerCancel({
1148
- code: INVALID_REQUEST_CODE,
1149
- message: errMessage
1150
- });
1151
- };
1152
- const finishedController = new AbortController();
1153
- const procStream = {
1154
- from,
1155
- streamId,
1156
- procedureName,
1157
- serviceName,
1158
- sessionMetadata,
1159
- procedure,
1160
- handleMsg: onMessage,
1161
- handleSessionDisconnect: () => {
1162
- cleanClose = false;
1163
- const errPayload = {
1164
- code: UNEXPECTED_DISCONNECT_CODE,
1165
- message: "client unexpectedly disconnected"
1166
- };
1167
- if (!reqReadable.isClosed()) {
1168
- reqReadable._pushValue(Err(errPayload));
1169
- closeReadable();
1170
- }
1171
- resWritable.close();
1172
- }
1173
- };
1174
- const sessionScopedSend = this.transport.getSessionBoundSendFn(
1175
- from,
1176
- sessionId
1177
- );
1178
- const cancelStream = (streamId2, payload) => {
1179
- this.cancelStream(from, sessionScopedSend, streamId2, payload);
1180
- };
1181
- const onServerCancel = (e) => {
1182
- if (reqReadable.isClosed() && resWritable.isClosed()) {
1183
- return;
1184
- }
1185
- cleanClose = false;
1186
- const result = Err(e);
1187
- if (!reqReadable.isClosed()) {
1188
- reqReadable._pushValue(result);
1189
- closeReadable();
1190
- }
1191
- resWritable.close();
1192
- cancelStream(streamId, result);
1193
- };
1194
- const cleanup = () => {
1195
- finishedController.abort();
1196
- this.streams.delete(streamId);
1197
- };
1198
- const procClosesWithResponse = procedure.type === "rpc" || procedure.type === "upload";
1199
- const reqReadable = new ReadableImpl();
1200
- const closeReadable = () => {
1201
- reqReadable._triggerClose();
1202
- if (protocolVersion === "v1.1") {
1203
- if (!procClosesWithResponse && !resWritable.isClosed()) {
1204
- resWritable.close();
1205
- }
1206
- }
1207
- if (resWritable.isClosed()) {
1208
- cleanup();
1209
- }
1210
- };
1211
- if (passInitAsDataForBackwardsCompat) {
1212
- reqReadable._pushValue(Ok(initPayload));
1213
- }
1214
- const resWritable = new WritableImpl({
1215
- writeCb: (response) => {
1216
- sessionScopedSend({
1217
- streamId,
1218
- controlFlags: procClosesWithResponse ? getStreamCloseBackwardsCompat(protocolVersion) : 0,
1219
- payload: response
1220
- });
1221
- if (procClosesWithResponse) {
1222
- resWritable.close();
1223
- }
1224
- },
1225
- // close callback
1226
- closeCb: () => {
1227
- if (!procClosesWithResponse && cleanClose) {
1228
- const message = closeStreamMessage(streamId);
1229
- message.controlFlags = getStreamCloseBackwardsCompat(protocolVersion);
1230
- sessionScopedSend(message);
1231
- }
1232
- if (protocolVersion === "v1.1") {
1233
- if (!reqReadable.isClosed()) {
1234
- closeReadable();
1235
- }
1236
- }
1237
- if (reqReadable.isClosed()) {
1238
- cleanup();
1239
- }
1240
- }
1241
- });
1242
- const onHandlerError = (err, span2) => {
1243
- const errorMsg = coerceErrorString(err);
1244
- span2.recordException(err instanceof Error ? err : new Error(errorMsg));
1245
- span2.setStatus({ code: SpanStatusCode.ERROR });
1246
- this.log?.error(
1247
- `${serviceName}.${procedureName} handler threw an uncaught error`,
1248
- {
1249
- ...loggingMetadata,
1250
- transportMessage: {
1251
- procedureName,
1252
- serviceName
1253
- },
1254
- extras: {
1255
- error: errorMsg,
1256
- originalException: err
1257
- },
1258
- tags: ["uncaught-handler-error"]
1259
- }
1260
- );
1261
- onServerCancel({
1262
- code: UNCAUGHT_ERROR_CODE,
1263
- message: errorMsg
1264
- });
1265
- };
1266
- if (procClosesWithInit) {
1267
- closeReadable();
1268
- }
1269
- const handlerContextWithSpan = (span2) => ({
1270
- ...serviceContext,
1271
- from,
1272
- sessionId,
1273
- metadata: sessionMetadata,
1274
- span: span2,
1275
- cancel: () => {
1276
- onServerCancel({
1277
- code: CANCEL_CODE,
1278
- message: "cancelled by server procedure handler"
1279
- });
1280
- },
1281
- signal: finishedController.signal
1282
- });
1283
- switch (procedure.type) {
1284
- case "rpc":
1285
- void (async () => {
1286
- try {
1287
- const responsePayload = await procedure.handler({
1288
- ctx: handlerContextWithSpan(span),
1289
- reqInit: initPayload
1290
- });
1291
- if (resWritable.isClosed()) {
1292
- return;
1293
- }
1294
- resWritable.write(responsePayload);
1295
- } catch (err) {
1296
- onHandlerError(err, span);
1297
- } finally {
1298
- span.end();
1299
- }
1300
- })();
1301
- break;
1302
- case "stream":
1303
- void (async () => {
1304
- try {
1305
- await procedure.handler({
1306
- ctx: handlerContextWithSpan(span),
1307
- reqInit: initPayload,
1308
- reqReadable,
1309
- resWritable
1310
- });
1311
- } catch (err) {
1312
- onHandlerError(err, span);
1313
- } finally {
1314
- span.end();
1315
- }
1316
- })();
1317
- break;
1318
- case "subscription":
1319
- void (async () => {
1320
- try {
1321
- await procedure.handler({
1322
- ctx: handlerContextWithSpan(span),
1323
- reqInit: initPayload,
1324
- resWritable
1325
- });
1326
- } catch (err) {
1327
- onHandlerError(err, span);
1328
- } finally {
1329
- span.end();
1330
- }
1331
- })();
1332
- break;
1333
- case "upload":
1334
- void (async () => {
1335
- try {
1336
- const responsePayload = await procedure.handler({
1337
- ctx: handlerContextWithSpan(span),
1338
- reqInit: initPayload,
1339
- reqReadable
1340
- });
1341
- if (resWritable.isClosed()) {
1342
- return;
1343
- }
1344
- resWritable.write(responsePayload);
1345
- } catch (err) {
1346
- onHandlerError(err, span);
1347
- } finally {
1348
- span.end();
1349
- }
1350
- })();
1351
- break;
1352
- }
1353
- if (!finishedController.signal.aborted) {
1354
- this.streams.set(streamId, procStream);
1355
- }
1356
- }
1357
- getContext(service, serviceName) {
1358
- const context = this.contextMap.get(service);
1359
- if (!context) {
1360
- const err = `no context found for ${serviceName}`;
1361
- this.log?.error(err, {
1362
- clientId: this.transport.clientId,
1363
- tags: ["invariant-violation"]
1364
- });
1365
- throw new Error(err);
1366
- }
1367
- return context;
1368
- }
1369
- validateNewProcStream(initMessage) {
1370
- const session = this.transport.sessions.get(initMessage.from);
1371
- if (!session) {
1372
- this.log?.error(`couldn't find session for ${initMessage.from}`, {
1373
- clientId: this.transport.clientId,
1374
- transportMessage: initMessage,
1375
- tags: ["invariant-violation"]
1376
- });
1377
- return null;
1378
- }
1379
- const sessionScopedSend = this.transport.getSessionBoundSendFn(
1380
- initMessage.from,
1381
- session.id
1382
- );
1383
- const cancelStream = (streamId, payload) => {
1384
- this.cancelStream(initMessage.from, sessionScopedSend, streamId, payload);
1385
- };
1386
- const sessionMetadata = this.transport.sessionHandshakeMetadata.get(
1387
- session.to
1388
- );
1389
- if (!sessionMetadata) {
1390
- const errMessage = `session doesn't have handshake metadata`;
1391
- this.log?.error(errMessage, {
1392
- ...session.loggingMetadata,
1393
- tags: ["invariant-violation"]
1394
- });
1395
- cancelStream(
1396
- initMessage.streamId,
1397
- Err({
1398
- code: UNCAUGHT_ERROR_CODE,
1399
- message: errMessage
1400
- })
1401
- );
1402
- return null;
1403
- }
1404
- if (!isStreamOpen(initMessage.controlFlags)) {
1405
- const errMessage = `can't create a new procedure stream from a message that doesn't have the stream open bit set`;
1406
- this.log?.warn(errMessage, {
1407
- ...session.loggingMetadata,
1408
- clientId: this.transport.clientId,
1409
- transportMessage: initMessage,
1410
- tags: ["invalid-request"]
1411
- });
1412
- cancelStream(
1413
- initMessage.streamId,
1414
- Err({
1415
- code: INVALID_REQUEST_CODE,
1416
- message: errMessage
1417
- })
1418
- );
1419
- return null;
1420
- }
1421
- if (!initMessage.serviceName) {
1422
- const errMessage = `missing service name in stream open message`;
1423
- this.log?.warn(errMessage, {
1424
- ...session.loggingMetadata,
1425
- transportMessage: initMessage,
1426
- tags: ["invalid-request"]
1427
- });
1428
- cancelStream(
1429
- initMessage.streamId,
1430
- Err({
1431
- code: INVALID_REQUEST_CODE,
1432
- message: errMessage
1433
- })
1434
- );
1435
- return null;
1436
- }
1437
- if (!initMessage.procedureName) {
1438
- const errMessage = `missing procedure name in stream open message`;
1439
- this.log?.warn(errMessage, {
1440
- ...session.loggingMetadata,
1441
- transportMessage: initMessage,
1442
- tags: ["invalid-request"]
1443
- });
1444
- cancelStream(
1445
- initMessage.streamId,
1446
- Err({
1447
- code: INVALID_REQUEST_CODE,
1448
- message: errMessage
1449
- })
1450
- );
1451
- return null;
1452
- }
1453
- if (!(initMessage.serviceName in this.services)) {
1454
- const errMessage = `couldn't find service ${initMessage.serviceName}`;
1455
- this.log?.warn(errMessage, {
1456
- ...session.loggingMetadata,
1457
- clientId: this.transport.clientId,
1458
- transportMessage: initMessage,
1459
- tags: ["invalid-request"]
1460
- });
1461
- cancelStream(
1462
- initMessage.streamId,
1463
- Err({
1464
- code: INVALID_REQUEST_CODE,
1465
- message: errMessage
1466
- })
1467
- );
1468
- return null;
1469
- }
1470
- const service = this.services[initMessage.serviceName];
1471
- if (!(initMessage.procedureName in service.procedures)) {
1472
- const errMessage = `couldn't find a matching procedure for ${initMessage.serviceName}.${initMessage.procedureName}`;
1473
- this.log?.warn(errMessage, {
1474
- ...session.loggingMetadata,
1475
- transportMessage: initMessage,
1476
- tags: ["invalid-request"]
1477
- });
1478
- cancelStream(
1479
- initMessage.streamId,
1480
- Err({
1481
- code: INVALID_REQUEST_CODE,
1482
- message: errMessage
1483
- })
1484
- );
1485
- return null;
1486
- }
1487
- const serviceContext = this.getContext(service, initMessage.serviceName);
1488
- const procedure = service.procedures[initMessage.procedureName];
1489
- if (!["rpc", "upload", "stream", "subscription"].includes(procedure.type)) {
1490
- this.log?.error(
1491
- `got request for invalid procedure type ${procedure.type} at ${initMessage.serviceName}.${initMessage.procedureName}`,
1492
- {
1493
- ...session.loggingMetadata,
1494
- transportMessage: initMessage,
1495
- tags: ["invariant-violation"]
1496
- }
1497
- );
1498
- return null;
1499
- }
1500
- let passInitAsDataForBackwardsCompat = false;
1501
- if (session.protocolVersion === "v1.1" && (procedure.type === "upload" || procedure.type === "stream") && Value2.Check(procedure.requestData, initMessage.payload) && Value2.Check(procedure.requestInit, {})) {
1502
- passInitAsDataForBackwardsCompat = true;
1503
- } else if (!Value2.Check(procedure.requestInit, initMessage.payload)) {
1504
- const errMessage = `procedure init failed validation`;
1505
- this.log?.warn(errMessage, {
1506
- ...session.loggingMetadata,
1507
- clientId: this.transport.clientId,
1508
- transportMessage: initMessage,
1509
- tags: ["invalid-request"]
1510
- });
1511
- cancelStream(
1512
- initMessage.streamId,
1513
- Err({
1514
- code: INVALID_REQUEST_CODE,
1515
- message: errMessage
1516
- })
1517
- );
1518
- return null;
1519
- }
1520
- return {
1521
- initialSession: session,
1522
- streamId: initMessage.streamId,
1523
- procedureName: initMessage.procedureName,
1524
- serviceName: initMessage.serviceName,
1525
- tracingCtx: initMessage.tracing,
1526
- initPayload: initMessage.payload,
1527
- sessionMetadata,
1528
- procedure,
1529
- serviceContext,
1530
- procClosesWithInit: isStreamCloseBackwardsCompat(
1531
- initMessage.controlFlags,
1532
- session.protocolVersion
1533
- ),
1534
- passInitAsDataForBackwardsCompat
1535
- };
1536
- }
1537
- cancelStream(to, sessionScopedSend, streamId, payload) {
1538
- let cancelledStreamsInSession = this.serverCancelledStreams.get(to);
1539
- if (!cancelledStreamsInSession) {
1540
- cancelledStreamsInSession = new LRUSet(
1541
- this.maxCancelledStreamTombstonesPerSession
1542
- );
1543
- this.serverCancelledStreams.set(to, cancelledStreamsInSession);
1544
- }
1545
- cancelledStreamsInSession.add(streamId);
1546
- const msg = cancelMessage(streamId, payload);
1547
- sessionScopedSend(msg);
1548
- }
1549
- async close() {
1550
- this.unregisterTransportListeners();
1551
- for (const serviceName of Object.keys(this.services)) {
1552
- const service = this.services[serviceName];
1553
- await service[Symbol.asyncDispose]();
1554
- }
1555
- }
1556
- };
1557
- var LRUSet = class {
1558
- items;
1559
- maxItems;
1560
- constructor(maxItems) {
1561
- this.items = /* @__PURE__ */ new Set();
1562
- this.maxItems = maxItems;
1563
- }
1564
- add(item) {
1565
- if (this.items.has(item)) {
1566
- this.items.delete(item);
1567
- } else if (this.items.size >= this.maxItems) {
1568
- const first = this.items.values().next();
1569
- if (!first.done) {
1570
- this.items.delete(first.value);
1571
- }
1572
- }
1573
- this.items.add(item);
1574
- }
1575
- has(item) {
1576
- return this.items.has(item);
1577
- }
1578
- };
1579
- function isStreamCancelBackwardsCompat(controlFlags, protocolVersion) {
1580
- if (protocolVersion === "v1.1") {
1581
- return false;
1582
- }
1583
- return isStreamCancel(controlFlags);
1584
- }
1585
- function isStreamCloseBackwardsCompat(controlFlags, protocolVersion) {
1586
- if (protocolVersion === "v1.1") {
1587
- return isStreamCancel(controlFlags);
1588
- }
1589
- return isStreamClose(controlFlags);
1590
- }
1591
- function getStreamCloseBackwardsCompat(protocolVersion) {
1592
- if (protocolVersion === "v1.1") {
1593
- return 4 /* StreamCancelBit */;
1594
- }
1595
- return 8 /* StreamClosedBit */;
1596
- }
1597
- function createServer(transport, services, providedServerOptions) {
1598
- return new RiverServer(
1599
- transport,
1600
- services,
1601
- providedServerOptions?.handshakeOptions,
1602
- providedServerOptions?.extendedContext,
1603
- providedServerOptions?.maxCancelledStreamTombstonesPerSession
1604
- );
1605
- }
1606
-
1607
- // router/handshake.ts
1608
- function createClientHandshakeOptions(schema, construct) {
1609
- return { schema, construct };
1610
- }
1611
- function createServerHandshakeOptions(schema, validate) {
1612
- return { schema, validate };
1613
- }
20
+ } from "../chunk-LJCR3ADI.js";
1614
21
  export {
1615
22
  CANCEL_CODE,
1616
23
  Err,