@replit/river 0.23.15 → 0.200.0-rc.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 (72) hide show
  1. package/dist/{chunk-5HK7ZQYH.js → chunk-3FALN7ZG.js} +14 -2
  2. package/dist/{chunk-5HK7ZQYH.js.map → chunk-3FALN7ZG.js.map} +1 -1
  3. package/dist/{chunk-RQQZUQGE.js → chunk-6GK2IIDP.js} +2 -2
  4. package/dist/{chunk-JMVKSGND.js → chunk-6RKO3DDG.js} +4 -4
  5. package/dist/chunk-E2ZXI663.js +1995 -0
  6. package/dist/chunk-E2ZXI663.js.map +1 -0
  7. package/dist/{chunk-OXVWMLID.js → chunk-LK74ZG7M.js} +25 -10
  8. package/dist/chunk-LK74ZG7M.js.map +1 -0
  9. package/dist/{chunk-XYEOXPZQ.js → chunk-NDLWNT7B.js} +2 -2
  10. package/dist/{chunk-6LCL2ZZF.js → chunk-QMM35C3H.js} +1 -1
  11. package/dist/chunk-QMM35C3H.js.map +1 -0
  12. package/dist/{chunk-IJTGEBLG.js → chunk-TK7QHUFP.js} +4 -4
  13. package/dist/{chunk-MD4S7GO2.js → chunk-YUY37VAK.js} +23 -7
  14. package/dist/chunk-YUY37VAK.js.map +1 -0
  15. package/dist/{connection-5d0978ce.d.ts → connection-0638316b.d.ts} +1 -1
  16. package/dist/{connection-e57e98ea.d.ts → connection-c6521735.d.ts} +1 -1
  17. package/dist/{index-ea74cdbb.d.ts → index-10ebd26a.d.ts} +33 -33
  18. package/dist/logging/index.cjs.map +1 -1
  19. package/dist/logging/index.d.cts +1 -1
  20. package/dist/logging/index.d.ts +1 -1
  21. package/dist/logging/index.js +1 -1
  22. package/dist/router/index.cjs +1053 -912
  23. package/dist/router/index.cjs.map +1 -1
  24. package/dist/router/index.d.cts +19 -23
  25. package/dist/router/index.d.ts +19 -23
  26. package/dist/router/index.js +12 -6
  27. package/dist/services-34d97070.d.ts +1366 -0
  28. package/dist/transport/impls/uds/client.cjs +33 -5
  29. package/dist/transport/impls/uds/client.cjs.map +1 -1
  30. package/dist/transport/impls/uds/client.d.cts +3 -4
  31. package/dist/transport/impls/uds/client.d.ts +3 -4
  32. package/dist/transport/impls/uds/client.js +6 -6
  33. package/dist/transport/impls/uds/server.cjs +33 -5
  34. package/dist/transport/impls/uds/server.cjs.map +1 -1
  35. package/dist/transport/impls/uds/server.d.cts +4 -4
  36. package/dist/transport/impls/uds/server.d.ts +4 -4
  37. package/dist/transport/impls/uds/server.js +6 -6
  38. package/dist/transport/impls/ws/client.cjs +33 -5
  39. package/dist/transport/impls/ws/client.cjs.map +1 -1
  40. package/dist/transport/impls/ws/client.d.cts +5 -6
  41. package/dist/transport/impls/ws/client.d.ts +5 -6
  42. package/dist/transport/impls/ws/client.js +6 -6
  43. package/dist/transport/impls/ws/server.cjs +33 -5
  44. package/dist/transport/impls/ws/server.cjs.map +1 -1
  45. package/dist/transport/impls/ws/server.d.cts +4 -4
  46. package/dist/transport/impls/ws/server.d.ts +4 -4
  47. package/dist/transport/impls/ws/server.js +6 -6
  48. package/dist/transport/index.cjs +33 -5
  49. package/dist/transport/index.cjs.map +1 -1
  50. package/dist/transport/index.d.cts +27 -5
  51. package/dist/transport/index.d.ts +27 -5
  52. package/dist/transport/index.js +6 -6
  53. package/dist/util/testHelpers.cjs +382 -326
  54. package/dist/util/testHelpers.cjs.map +1 -1
  55. package/dist/util/testHelpers.d.cts +32 -21
  56. package/dist/util/testHelpers.d.ts +32 -21
  57. package/dist/util/testHelpers.js +76 -42
  58. package/dist/util/testHelpers.js.map +1 -1
  59. package/package.json +15 -15
  60. package/dist/chunk-6LCL2ZZF.js.map +0 -1
  61. package/dist/chunk-AEY7BBOZ.js +0 -1865
  62. package/dist/chunk-AEY7BBOZ.js.map +0 -1
  63. package/dist/chunk-MD4S7GO2.js.map +0 -1
  64. package/dist/chunk-OXVWMLID.js.map +0 -1
  65. package/dist/client-e13979ac.d.ts +0 -52
  66. package/dist/handshake-5665ffd3.d.ts +0 -511
  67. package/dist/server-1cfc88d1.d.ts +0 -24
  68. package/dist/services-86c4d10d.d.ts +0 -709
  69. /package/dist/{chunk-RQQZUQGE.js.map → chunk-6GK2IIDP.js.map} +0 -0
  70. /package/dist/{chunk-JMVKSGND.js.map → chunk-6RKO3DDG.js.map} +0 -0
  71. /package/dist/{chunk-XYEOXPZQ.js.map → chunk-NDLWNT7B.js.map} +0 -0
  72. /package/dist/{chunk-IJTGEBLG.js.map → chunk-TK7QHUFP.js.map} +0 -0
@@ -1,1865 +0,0 @@
1
- import {
2
- ControlMessagePayloadSchema,
3
- coerceErrorString,
4
- createHandlerSpan,
5
- createProcTelemetryInfo,
6
- getPropagationContext,
7
- isStreamClose,
8
- isStreamOpen
9
- } from "./chunk-OXVWMLID.js";
10
-
11
- // router/services.ts
12
- import { Type } from "@sinclair/typebox";
13
- function serializeSchema(services, handshakeSchema) {
14
- const serializedServiceObject = Object.entries(services).reduce((acc, [name, value]) => {
15
- acc[name] = value.serialize();
16
- return acc;
17
- }, {});
18
- const schema = {
19
- services: serializedServiceObject
20
- };
21
- if (handshakeSchema) {
22
- schema.handshakeSchema = Type.Strict(handshakeSchema);
23
- }
24
- return schema;
25
- }
26
- var ServiceSchema = class _ServiceSchema {
27
- /**
28
- * Factory function for creating a fresh state.
29
- */
30
- initializeState;
31
- /**
32
- * The procedures for this service.
33
- */
34
- procedures;
35
- /**
36
- * @param config - The configuration for this service.
37
- * @param procedures - The procedures for this service.
38
- */
39
- constructor(config, procedures) {
40
- this.initializeState = config.initializeState;
41
- this.procedures = procedures;
42
- }
43
- /**
44
- * Creates a {@link ServiceScaffold}, which can be used to define procedures
45
- * that can then be merged into a {@link ServiceSchema}, via the scaffold's
46
- * `finalize` method.
47
- *
48
- * There are two patterns that work well with this method. The first is using
49
- * it to separate the definition of procedures from the definition of the
50
- * service's configuration:
51
- * ```ts
52
- * const MyServiceScaffold = ServiceSchema.scaffold({
53
- * initializeState: () => ({ count: 0 }),
54
- * });
55
- *
56
- * const incrementProcedures = MyServiceScaffold.procedures({
57
- * increment: Procedure.rpc({
58
- * input: Type.Object({ amount: Type.Number() }),
59
- * output: Type.Object({ current: Type.Number() }),
60
- * async handler(ctx, input) {
61
- * ctx.state.count += input.amount;
62
- * return Ok({ current: ctx.state.count });
63
- * }
64
- * }),
65
- * })
66
- *
67
- * const MyService = MyServiceScaffold.finalize({
68
- * ...incrementProcedures,
69
- * // you can also directly define procedures here
70
- * });
71
- * ```
72
- * This might be really handy if you have a very large service and you're
73
- * wanting to split it over multiple files. You can define the scaffold
74
- * in one file, and then import that scaffold in other files where you
75
- * define procedures - and then finally import the scaffolds and your
76
- * procedure objects in a final file where you finalize the scaffold into
77
- * a service schema.
78
- *
79
- * The other way is to use it like in a builder pattern:
80
- * ```ts
81
- * const MyService = ServiceSchema
82
- * .scaffold({ initializeState: () => ({ count: 0 }) })
83
- * .finalize({
84
- * increment: Procedure.rpc({
85
- * input: Type.Object({ amount: Type.Number() }),
86
- * output: Type.Object({ current: Type.Number() }),
87
- * async handler(ctx, input) {
88
- * ctx.state.count += input.amount;
89
- * return Ok({ current: ctx.state.count });
90
- * }
91
- * }),
92
- * })
93
- * ```
94
- * Depending on your preferences, this may be a more appealing way to define
95
- * a schema versus using the {@link ServiceSchema.define} method.
96
- */
97
- static scaffold(config) {
98
- return new ServiceScaffold(config);
99
- }
100
- // actual implementation
101
- static define(configOrProcedures, maybeProcedures) {
102
- let config;
103
- let procedures;
104
- if ("initializeState" in configOrProcedures && typeof configOrProcedures.initializeState === "function") {
105
- if (!maybeProcedures) {
106
- throw new Error("Expected procedures to be defined");
107
- }
108
- config = configOrProcedures;
109
- procedures = maybeProcedures;
110
- } else {
111
- config = { initializeState: () => ({}) };
112
- procedures = configOrProcedures;
113
- }
114
- return new _ServiceSchema(config, procedures);
115
- }
116
- /**
117
- * Serializes this schema's procedures into a plain object that is JSON compatible.
118
- */
119
- serialize() {
120
- return {
121
- procedures: Object.fromEntries(
122
- Object.entries(this.procedures).map(([procName, procDef]) => [
123
- procName,
124
- {
125
- input: Type.Strict(procDef.input),
126
- output: Type.Strict(procDef.output),
127
- // Only add `description` field if the type declares it.
128
- ..."description" in procDef ? { description: procDef.description } : {},
129
- // Only add the `errors` field if the type declares it.
130
- ..."errors" in procDef ? {
131
- errors: Type.Strict(procDef.errors)
132
- } : {},
133
- type: procDef.type,
134
- // Only add the `init` field if the type declares it.
135
- ..."init" in procDef ? {
136
- init: Type.Strict(procDef.init)
137
- } : {}
138
- }
139
- ])
140
- )
141
- };
142
- }
143
- /**
144
- * Instantiates this schema into a {@link Service} object.
145
- *
146
- * You probably don't need this, usually the River server will handle this
147
- * for you.
148
- */
149
- instantiate() {
150
- return Object.freeze({
151
- state: this.initializeState(),
152
- procedures: this.procedures
153
- });
154
- }
155
- };
156
- var ServiceScaffold = class {
157
- /**
158
- * The configuration for this service.
159
- */
160
- config;
161
- /**
162
- * @param config - The configuration for this service.
163
- */
164
- constructor(config) {
165
- this.config = config;
166
- }
167
- /**
168
- * Define procedures for this service. Use the {@link Procedure} constructors
169
- * to create them. This returns the procedures object, which can then be
170
- * passed to {@link ServiceSchema.finalize} to create a {@link ServiceSchema}.
171
- *
172
- * @example
173
- * ```
174
- * const myProcedures = MyServiceScaffold.procedures({
175
- * myRPC: Procedure.rpc({
176
- * // ...
177
- * }),
178
- * });
179
- *
180
- * const MyService = MyServiceScaffold.finalize({
181
- * ...myProcedures,
182
- * });
183
- * ```
184
- *
185
- * @param procedures - The procedures for this service.
186
- */
187
- procedures(procedures) {
188
- return procedures;
189
- }
190
- /**
191
- * Finalizes the scaffold into a {@link ServiceSchema}. This is where you
192
- * provide the service's procedures and get a {@link ServiceSchema} in return.
193
- *
194
- * You can directly define procedures here, or you can define them separately
195
- * with the {@link ServiceScaffold.procedures} method, and then pass them here.
196
- *
197
- * @example
198
- * ```
199
- * const MyService = MyServiceScaffold.finalize({
200
- * myRPC: Procedure.rpc({
201
- * // ...
202
- * }),
203
- * // e.g. from the procedures method
204
- * ...myOtherProcedures,
205
- * });
206
- * ```
207
- */
208
- finalize(procedures) {
209
- return ServiceSchema.define(this.config, procedures);
210
- }
211
- };
212
-
213
- // router/diff.ts
214
- function diffServerSchema(oldServer, newServer, options) {
215
- const allServices = /* @__PURE__ */ new Set([
216
- ...Object.keys(oldServer.services),
217
- ...Object.keys(newServer.services)
218
- ]);
219
- const breakages = {};
220
- for (const serviceName of allServices) {
221
- const oldService = oldServer.services[serviceName];
222
- const newService = newServer.services[serviceName];
223
- const breakage = diffService(oldService, newService, options);
224
- if (breakage) {
225
- breakages[serviceName] = breakage;
226
- }
227
- }
228
- if (Object.keys(breakages).length) {
229
- return { serviceBreakages: breakages };
230
- }
231
- return null;
232
- }
233
- function diffService(oldService, newService, options) {
234
- if (!newService) {
235
- return options?.allowServiceRemoval ? null : { reason: "removed" };
236
- }
237
- if (!oldService) {
238
- return null;
239
- }
240
- const allProcedures = /* @__PURE__ */ new Set([
241
- ...Object.keys(oldService.procedures),
242
- ...Object.keys(newService.procedures)
243
- ]);
244
- const breakages = {};
245
- for (const procedureName of allProcedures) {
246
- const aProcedure = oldService.procedures[procedureName];
247
- const bProcedure = newService.procedures[procedureName];
248
- const breakage = diffProcedure(aProcedure, bProcedure, options);
249
- if (breakage) {
250
- breakages[procedureName] = breakage;
251
- }
252
- }
253
- if (Object.keys(breakages).length) {
254
- return { reason: "modified", procedureBreakages: breakages };
255
- }
256
- return null;
257
- }
258
- function diffProcedure(oldProcedure, newProcedure, options) {
259
- if (!newProcedure) {
260
- return options?.allowProcedureRemoval ? null : { reason: "removed" };
261
- }
262
- if (!oldProcedure) {
263
- return null;
264
- }
265
- if (oldProcedure.type !== newProcedure.type) {
266
- return {
267
- reason: "type-changed",
268
- oldType: oldProcedure.type,
269
- newType: newProcedure.type
270
- };
271
- }
272
- const inputBreakage = diffProcedureField(
273
- oldProcedure.input,
274
- newProcedure.input,
275
- "client"
276
- );
277
- const initBreakage = diffProcedureField(
278
- oldProcedure.init,
279
- newProcedure.init,
280
- "client"
281
- );
282
- const outputBreakage = diffProcedureField(
283
- oldProcedure.output,
284
- newProcedure.output,
285
- "server"
286
- );
287
- if (inputBreakage ?? initBreakage ?? outputBreakage) {
288
- const result = {
289
- reason: "modified"
290
- };
291
- if (inputBreakage) {
292
- result.input = inputBreakage;
293
- }
294
- if (initBreakage) {
295
- result.init = initBreakage;
296
- }
297
- if (outputBreakage) {
298
- result.output = outputBreakage;
299
- }
300
- return result;
301
- }
302
- return null;
303
- }
304
- function diffProcedureField(oldSchema, newSchema, origin) {
305
- if (!oldSchema && !newSchema) {
306
- return null;
307
- }
308
- const diffBreakage = diffRequired(oldSchema, newSchema, origin, false, false);
309
- if (diffBreakage) {
310
- return diffBreakage;
311
- }
312
- if (!oldSchema || !newSchema) {
313
- throw new Error("Appease typescript, this should never happen");
314
- }
315
- return diffJSONSchema(oldSchema, newSchema, origin);
316
- }
317
- function diffRequired(oldSchema, newSchema, origin, oldRequired, newRequired) {
318
- if (!newSchema && !oldSchema) {
319
- throw new Error("Both old and new schema are undefined");
320
- }
321
- if (!newSchema) {
322
- if (!oldRequired && origin == "server") {
323
- return null;
324
- }
325
- return { reason: "removed-required" };
326
- }
327
- if (!oldSchema) {
328
- if (newRequired && origin === "client") {
329
- return { reason: "new-required" };
330
- }
331
- return null;
332
- }
333
- if (origin === "client" && !oldRequired && newRequired) {
334
- return { reason: "new-required" };
335
- }
336
- if (origin === "server" && oldRequired && !newRequired) {
337
- return { reason: "removed-required" };
338
- }
339
- return null;
340
- }
341
- function diffJSONSchema(oldSchema, newSchema, origin) {
342
- if (oldSchema.type !== newSchema.type) {
343
- return {
344
- reason: "type-changed",
345
- oldType: getReportingType(oldSchema),
346
- newType: getReportingType(newSchema)
347
- };
348
- }
349
- if (getReportingType(oldSchema) !== getReportingType(newSchema)) {
350
- return {
351
- reason: "type-changed",
352
- oldType: getReportingType(oldSchema),
353
- newType: getReportingType(newSchema)
354
- };
355
- }
356
- if ("const" in oldSchema && "const" in newSchema && oldSchema.const !== newSchema.const) {
357
- return {
358
- reason: "type-changed",
359
- oldType: `${getReportingType(oldSchema)}-const-${oldSchema.const}`,
360
- newType: `${getReportingType(newSchema)}-const-${newSchema.const}`
361
- };
362
- }
363
- if ("const" in oldSchema && !("const" in newSchema) && origin === "server") {
364
- return {
365
- reason: "type-changed",
366
- oldType: `${getReportingType(oldSchema)}-const-${oldSchema.const}`,
367
- newType: getReportingType(newSchema)
368
- };
369
- }
370
- if ("const" in newSchema && !("const" in oldSchema) && origin === "client") {
371
- return {
372
- reason: "type-changed",
373
- oldType: getReportingType(oldSchema),
374
- newType: `${getReportingType(newSchema)}-const-${newSchema.const}`
375
- };
376
- }
377
- const breakages = {};
378
- if ("$ref" in newSchema) {
379
- if (newSchema.$ref !== oldSchema.$ref) {
380
- return {
381
- reason: "type-changed",
382
- oldType: getReportingType(oldSchema),
383
- newType: getReportingType(newSchema)
384
- };
385
- }
386
- } else if ("not" in newSchema) {
387
- const notBreakage = diffJSONSchema(
388
- oldSchema.not,
389
- newSchema.not,
390
- origin
391
- );
392
- if (notBreakage) {
393
- breakages.not = notBreakage;
394
- }
395
- } else if ("anyOf" in newSchema) {
396
- const oldAnyOfStringified = oldSchema.anyOf.map((el) => JSON.stringify(el)).sort();
397
- const newAnyOfStringified = newSchema.anyOf.map((el) => JSON.stringify(el)).sort();
398
- const anyOfBreakages = {};
399
- for (let i = 0; i < oldAnyOfStringified.length; i++) {
400
- if (newAnyOfStringified.includes(oldAnyOfStringified[i])) {
401
- continue;
402
- }
403
- if (!newAnyOfStringified[i]) {
404
- if (origin === "server") {
405
- continue;
406
- }
407
- anyOfBreakages[`old-${i}`] = { reason: "removed-required" };
408
- } else {
409
- const breakage = diffJSONSchema(
410
- JSON.parse(oldAnyOfStringified[i]),
411
- JSON.parse(newAnyOfStringified[i]),
412
- origin
413
- );
414
- if (breakage) {
415
- anyOfBreakages[`old-${i}`] = breakage;
416
- }
417
- }
418
- }
419
- for (let i = 0; i < newAnyOfStringified.length; i++) {
420
- if (oldAnyOfStringified.includes(newAnyOfStringified[i])) {
421
- continue;
422
- }
423
- if (!oldAnyOfStringified[i]) {
424
- if (origin === "client") {
425
- continue;
426
- }
427
- anyOfBreakages[`new-${i}`] = { reason: "new-required" };
428
- } else {
429
- const breakage = diffJSONSchema(
430
- JSON.parse(oldAnyOfStringified[i]),
431
- JSON.parse(newAnyOfStringified[i]),
432
- origin
433
- );
434
- if (breakage) {
435
- anyOfBreakages[`new-${i}`] = breakage;
436
- }
437
- }
438
- }
439
- if (Object.keys(anyOfBreakages).length > 0) {
440
- breakages.anyOf = {
441
- reason: "field-breakage",
442
- fieldBreakages: anyOfBreakages
443
- };
444
- }
445
- } else if ("oneOf" in newSchema) {
446
- throw new Error("oneOf is not supported, typebox does not emit it");
447
- } else if ("allOf" in newSchema) {
448
- if (newSchema.allOf.length !== oldSchema.allOf.length) {
449
- breakages.allOf = {
450
- reason: "type-changed",
451
- oldType: `${oldSchema.allOf}`,
452
- newType: `${newSchema.allOf}`
453
- };
454
- } else {
455
- for (let i = 0; i < newSchema.allOf.length; i++) {
456
- const breakage = diffJSONSchema(
457
- oldSchema.allOf[i],
458
- newSchema.allOf[i],
459
- origin
460
- );
461
- if (breakage) {
462
- breakages.allOf = breakage;
463
- break;
464
- }
465
- }
466
- }
467
- } else if (newSchema.type === "array") {
468
- const itemsBreakages = diffJSONSchema(
469
- oldSchema.items,
470
- newSchema.items,
471
- origin
472
- );
473
- if (itemsBreakages) {
474
- breakages.items = itemsBreakages;
475
- }
476
- if (oldSchema.minItems < newSchema.minItems) {
477
- if (origin === "client") {
478
- breakages.minItems = {
479
- reason: "type-changed",
480
- oldType: `${oldSchema.minItems}`,
481
- newType: `${newSchema.minItems}`
482
- };
483
- }
484
- } else if (oldSchema.minItems > newSchema.minItems) {
485
- if (origin === "server") {
486
- breakages.minItems = {
487
- reason: "type-changed",
488
- oldType: `${oldSchema.minItems}`,
489
- newType: `${newSchema.minItems}`
490
- };
491
- }
492
- }
493
- if (oldSchema.maxItems < newSchema.maxItems) {
494
- if (origin === "server") {
495
- breakages.maxItems = {
496
- reason: "type-changed",
497
- oldType: `${oldSchema.maxItems}`,
498
- newType: `${newSchema.maxItems}`
499
- };
500
- }
501
- } else if (oldSchema.maxItems > newSchema.maxItems) {
502
- if (origin === "client") {
503
- breakages.maxItems = {
504
- reason: "type-changed",
505
- oldType: `${oldSchema.maxItems}`,
506
- newType: `${newSchema.maxItems}`
507
- };
508
- }
509
- }
510
- if (!oldSchema.uniqueItems && newSchema.uniqueItems && origin === "client") {
511
- breakages.uniqueItems = {
512
- reason: "type-changed",
513
- oldType: `${!!oldSchema.uniqueItems}`,
514
- newType: `${!!newSchema.uniqueItems}`
515
- };
516
- }
517
- if ("contains" in newSchema !== "contains" in oldSchema) {
518
- if ("contains" in newSchema && !("contains" in oldSchema) && origin === "client") {
519
- breakages.contains = {
520
- reason: "type-changed",
521
- oldType: "no-contains",
522
- newType: "contains"
523
- };
524
- }
525
- } else if ("contains" in newSchema) {
526
- const containsBreakage = diffJSONSchema(
527
- oldSchema.contains,
528
- newSchema.contains,
529
- origin
530
- );
531
- if (containsBreakage) {
532
- breakages.contains = containsBreakage;
533
- }
534
- }
535
- if (oldSchema.minContains < newSchema.minContains) {
536
- if (origin === "client") {
537
- breakages.minContains = {
538
- reason: "type-changed",
539
- oldType: `${oldSchema.minContains}`,
540
- newType: `${newSchema.minContains}`
541
- };
542
- }
543
- } else if (oldSchema.minContains > newSchema.minContains) {
544
- if (origin === "server") {
545
- breakages.minContains = {
546
- reason: "type-changed",
547
- oldType: `${oldSchema.minContains}`,
548
- newType: `${newSchema.minContains}`
549
- };
550
- }
551
- }
552
- if (oldSchema.maxContains < newSchema.maxContains) {
553
- if (origin === "server") {
554
- breakages.maxContains = {
555
- reason: "type-changed",
556
- oldType: `${oldSchema.maxContains}`,
557
- newType: `${newSchema.maxContains}`
558
- };
559
- }
560
- } else if (oldSchema.maxContains > newSchema.maxContains) {
561
- if (origin === "client") {
562
- breakages.maxContains = {
563
- reason: "type-changed",
564
- oldType: `${oldSchema.maxContains}`,
565
- newType: `${newSchema.maxContains}`
566
- };
567
- }
568
- }
569
- } else if (newSchema.type === "object") {
570
- if ("properties" in newSchema !== "properties" in oldSchema) {
571
- return {
572
- reason: "type-changed",
573
- oldType: "properties" in oldSchema ? "probably-object" : "probably-record",
574
- newType: "properties" in newSchema ? "probably-object" : "probably-record"
575
- };
576
- }
577
- if ("properties" in newSchema) {
578
- const propertiesBreakages = diffObjectProperties(
579
- oldSchema.properties,
580
- newSchema.properties,
581
- origin,
582
- oldSchema.required,
583
- newSchema.required
584
- );
585
- if (Object.keys(propertiesBreakages).length) {
586
- breakages.properties = {
587
- reason: "field-breakage",
588
- fieldBreakages: propertiesBreakages
589
- };
590
- }
591
- }
592
- if ("patternProperties" in newSchema) {
593
- const patternPropertiesBreakages = diffObjectProperties(
594
- oldSchema.patternProperties,
595
- newSchema.patternProperties,
596
- origin,
597
- oldSchema.required,
598
- newSchema.required
599
- );
600
- if (Object.keys(patternPropertiesBreakages).length) {
601
- breakages.patternProperties = {
602
- reason: "field-breakage",
603
- fieldBreakages: patternPropertiesBreakages
604
- };
605
- }
606
- }
607
- if ("additionalProperties" in newSchema || "additionalProperties" in oldSchema) {
608
- throw new Error("additionalProperties is not supported");
609
- }
610
- if ("minProperties" in newSchema || "minProperties" in oldSchema) {
611
- throw new Error("minProperties is not supported");
612
- }
613
- if ("maxProperties" in newSchema || "maxProperties" in oldSchema) {
614
- throw new Error("maxProperties is not supported");
615
- }
616
- }
617
- if (Object.keys(breakages).length) {
618
- return {
619
- reason: "field-breakage",
620
- fieldBreakages: breakages
621
- };
622
- }
623
- return null;
624
- }
625
- function diffObjectProperties(oldProperties, newProperties, origin, oldRequiredProperties = [], newRequiredProperties = []) {
626
- const allProperties = /* @__PURE__ */ new Set([
627
- ...Object.keys(oldProperties),
628
- ...Object.keys(newProperties)
629
- ]);
630
- const breakages = {};
631
- for (const propertyName of allProperties) {
632
- const requiredBreakage = diffRequired(
633
- oldProperties[propertyName],
634
- newProperties[propertyName],
635
- origin,
636
- oldRequiredProperties.includes(propertyName),
637
- newRequiredProperties.includes(propertyName)
638
- );
639
- if (requiredBreakage) {
640
- breakages[propertyName] = requiredBreakage;
641
- } else if (oldProperties[propertyName] && newProperties[propertyName]) {
642
- const propertyBreakage = diffJSONSchema(
643
- oldProperties[propertyName],
644
- newProperties[propertyName],
645
- origin
646
- );
647
- if (propertyBreakage) {
648
- breakages[propertyName] = propertyBreakage;
649
- }
650
- }
651
- }
652
- return breakages;
653
- }
654
- function getReportingType(schema) {
655
- if ("not" in schema) {
656
- return "not";
657
- }
658
- if ("anyOf" in schema) {
659
- return "anyOf";
660
- }
661
- if ("allOf" in schema) {
662
- return "allOf";
663
- }
664
- if ("$ref" in schema) {
665
- return "$ref";
666
- }
667
- if (schema.type && typeof schema.type === "string") {
668
- return schema.type;
669
- }
670
- throw new Error(
671
- "Subschema not supported, probably a conditional subschema. Check logs."
672
- );
673
- }
674
-
675
- // router/procedures.ts
676
- import { Type as Type2 } from "@sinclair/typebox";
677
- function rpc({
678
- input,
679
- output,
680
- errors = Type2.Never(),
681
- description,
682
- handler
683
- }) {
684
- return {
685
- ...description ? { description } : {},
686
- type: "rpc",
687
- input,
688
- output,
689
- errors,
690
- handler
691
- };
692
- }
693
- function upload({
694
- init,
695
- input,
696
- output,
697
- errors = Type2.Never(),
698
- description,
699
- handler
700
- }) {
701
- return init !== void 0 && init !== null ? {
702
- type: "upload",
703
- ...description ? { description } : {},
704
- init,
705
- input,
706
- output,
707
- errors,
708
- handler
709
- } : {
710
- type: "upload",
711
- ...description ? { description } : {},
712
- input,
713
- output,
714
- errors,
715
- handler
716
- };
717
- }
718
- function subscription({
719
- input,
720
- output,
721
- errors = Type2.Never(),
722
- description,
723
- handler
724
- }) {
725
- return {
726
- type: "subscription",
727
- ...description ? { description } : {},
728
- input,
729
- output,
730
- errors,
731
- handler
732
- };
733
- }
734
- function stream({
735
- init,
736
- input,
737
- output,
738
- errors = Type2.Never(),
739
- description,
740
- handler
741
- }) {
742
- return init !== void 0 && init !== null ? {
743
- type: "stream",
744
- ...description ? { description } : {},
745
- init,
746
- input,
747
- output,
748
- errors,
749
- handler
750
- } : {
751
- type: "stream",
752
- ...description ? { description } : {},
753
- input,
754
- output,
755
- errors,
756
- handler
757
- };
758
- }
759
- var Procedure = {
760
- rpc,
761
- upload,
762
- subscription,
763
- stream
764
- };
765
-
766
- // node_modules/p-defer/index.js
767
- function pDefer() {
768
- const deferred = {};
769
- deferred.promise = new Promise((resolve, reject) => {
770
- deferred.resolve = resolve;
771
- deferred.reject = reject;
772
- });
773
- return deferred;
774
- }
775
-
776
- // node_modules/it-pushable/dist/src/fifo.js
777
- var FixedFIFO = class {
778
- buffer;
779
- mask;
780
- top;
781
- btm;
782
- next;
783
- constructor(hwm) {
784
- if (!(hwm > 0) || (hwm - 1 & hwm) !== 0) {
785
- throw new Error("Max size for a FixedFIFO should be a power of two");
786
- }
787
- this.buffer = new Array(hwm);
788
- this.mask = hwm - 1;
789
- this.top = 0;
790
- this.btm = 0;
791
- this.next = null;
792
- }
793
- push(data) {
794
- if (this.buffer[this.top] !== void 0) {
795
- return false;
796
- }
797
- this.buffer[this.top] = data;
798
- this.top = this.top + 1 & this.mask;
799
- return true;
800
- }
801
- shift() {
802
- const last = this.buffer[this.btm];
803
- if (last === void 0) {
804
- return void 0;
805
- }
806
- this.buffer[this.btm] = void 0;
807
- this.btm = this.btm + 1 & this.mask;
808
- return last;
809
- }
810
- isEmpty() {
811
- return this.buffer[this.btm] === void 0;
812
- }
813
- };
814
- var FIFO = class {
815
- size;
816
- hwm;
817
- head;
818
- tail;
819
- constructor(options = {}) {
820
- this.hwm = options.splitLimit ?? 16;
821
- this.head = new FixedFIFO(this.hwm);
822
- this.tail = this.head;
823
- this.size = 0;
824
- }
825
- calculateSize(obj) {
826
- if (obj?.byteLength != null) {
827
- return obj.byteLength;
828
- }
829
- return 1;
830
- }
831
- push(val) {
832
- if (val?.value != null) {
833
- this.size += this.calculateSize(val.value);
834
- }
835
- if (!this.head.push(val)) {
836
- const prev = this.head;
837
- this.head = prev.next = new FixedFIFO(2 * this.head.buffer.length);
838
- this.head.push(val);
839
- }
840
- }
841
- shift() {
842
- let val = this.tail.shift();
843
- if (val === void 0 && this.tail.next != null) {
844
- const next = this.tail.next;
845
- this.tail.next = null;
846
- this.tail = next;
847
- val = this.tail.shift();
848
- }
849
- if (val?.value != null) {
850
- this.size -= this.calculateSize(val.value);
851
- }
852
- return val;
853
- }
854
- isEmpty() {
855
- return this.head.isEmpty();
856
- }
857
- };
858
-
859
- // node_modules/it-pushable/dist/src/index.js
860
- var AbortError = class extends Error {
861
- type;
862
- code;
863
- constructor(message, code) {
864
- super(message ?? "The operation was aborted");
865
- this.type = "aborted";
866
- this.code = code ?? "ABORT_ERR";
867
- }
868
- };
869
- function pushable(options = {}) {
870
- const getNext = (buffer) => {
871
- const next = buffer.shift();
872
- if (next == null) {
873
- return { done: true };
874
- }
875
- if (next.error != null) {
876
- throw next.error;
877
- }
878
- return {
879
- done: next.done === true,
880
- // @ts-expect-error if done is false, value will be present
881
- value: next.value
882
- };
883
- };
884
- return _pushable(getNext, options);
885
- }
886
- function _pushable(getNext, options) {
887
- options = options ?? {};
888
- let onEnd = options.onEnd;
889
- let buffer = new FIFO();
890
- let pushable2;
891
- let onNext;
892
- let ended;
893
- let drain = pDefer();
894
- const waitNext = async () => {
895
- try {
896
- if (!buffer.isEmpty()) {
897
- return getNext(buffer);
898
- }
899
- if (ended) {
900
- return { done: true };
901
- }
902
- return await new Promise((resolve, reject) => {
903
- onNext = (next) => {
904
- onNext = null;
905
- buffer.push(next);
906
- try {
907
- resolve(getNext(buffer));
908
- } catch (err) {
909
- reject(err);
910
- }
911
- return pushable2;
912
- };
913
- });
914
- } finally {
915
- if (buffer.isEmpty()) {
916
- queueMicrotask(() => {
917
- drain.resolve();
918
- drain = pDefer();
919
- });
920
- }
921
- }
922
- };
923
- const bufferNext = (next) => {
924
- if (onNext != null) {
925
- return onNext(next);
926
- }
927
- buffer.push(next);
928
- return pushable2;
929
- };
930
- const bufferError = (err) => {
931
- buffer = new FIFO();
932
- if (onNext != null) {
933
- return onNext({ error: err });
934
- }
935
- buffer.push({ error: err });
936
- return pushable2;
937
- };
938
- const push = (value) => {
939
- if (ended) {
940
- return pushable2;
941
- }
942
- if (options?.objectMode !== true && value?.byteLength == null) {
943
- throw new Error("objectMode was not true but tried to push non-Uint8Array value");
944
- }
945
- return bufferNext({ done: false, value });
946
- };
947
- const end = (err) => {
948
- if (ended)
949
- return pushable2;
950
- ended = true;
951
- return err != null ? bufferError(err) : bufferNext({ done: true });
952
- };
953
- const _return = () => {
954
- buffer = new FIFO();
955
- end();
956
- return { done: true };
957
- };
958
- const _throw = (err) => {
959
- end(err);
960
- return { done: true };
961
- };
962
- pushable2 = {
963
- [Symbol.asyncIterator]() {
964
- return this;
965
- },
966
- next: waitNext,
967
- return: _return,
968
- throw: _throw,
969
- push,
970
- end,
971
- get readableLength() {
972
- return buffer.size;
973
- },
974
- onEmpty: async (options2) => {
975
- const signal = options2?.signal;
976
- signal?.throwIfAborted();
977
- if (buffer.isEmpty()) {
978
- return;
979
- }
980
- let cancel;
981
- let listener;
982
- if (signal != null) {
983
- cancel = new Promise((resolve, reject) => {
984
- listener = () => {
985
- reject(new AbortError());
986
- };
987
- signal.addEventListener("abort", listener);
988
- });
989
- }
990
- try {
991
- await Promise.race([
992
- drain.promise,
993
- cancel
994
- ]);
995
- } finally {
996
- if (listener != null && signal != null) {
997
- signal?.removeEventListener("abort", listener);
998
- }
999
- }
1000
- }
1001
- };
1002
- if (onEnd == null) {
1003
- return pushable2;
1004
- }
1005
- const _pushable2 = pushable2;
1006
- pushable2 = {
1007
- [Symbol.asyncIterator]() {
1008
- return this;
1009
- },
1010
- next() {
1011
- return _pushable2.next();
1012
- },
1013
- throw(err) {
1014
- _pushable2.throw(err);
1015
- if (onEnd != null) {
1016
- onEnd(err);
1017
- onEnd = void 0;
1018
- }
1019
- return { done: true };
1020
- },
1021
- return() {
1022
- _pushable2.return();
1023
- if (onEnd != null) {
1024
- onEnd();
1025
- onEnd = void 0;
1026
- }
1027
- return { done: true };
1028
- },
1029
- push,
1030
- end(err) {
1031
- _pushable2.end(err);
1032
- if (onEnd != null) {
1033
- onEnd(err);
1034
- onEnd = void 0;
1035
- }
1036
- return pushable2;
1037
- },
1038
- get readableLength() {
1039
- return _pushable2.readableLength;
1040
- },
1041
- onEmpty: (opts) => {
1042
- return _pushable2.onEmpty(opts);
1043
- }
1044
- };
1045
- return pushable2;
1046
- }
1047
-
1048
- // router/client.ts
1049
- import { nanoid } from "nanoid";
1050
-
1051
- // router/result.ts
1052
- import {
1053
- Type as Type3
1054
- } from "@sinclair/typebox";
1055
- var UNCAUGHT_ERROR = "UNCAUGHT_ERROR";
1056
- var UNEXPECTED_DISCONNECT = "UNEXPECTED_DISCONNECT";
1057
- var RiverUncaughtSchema = Type3.Object({
1058
- code: Type3.Union([
1059
- Type3.Literal(UNCAUGHT_ERROR),
1060
- Type3.Literal(UNEXPECTED_DISCONNECT)
1061
- ]),
1062
- message: Type3.String()
1063
- });
1064
- function Ok(payload) {
1065
- return {
1066
- ok: true,
1067
- payload
1068
- };
1069
- }
1070
- function Err(error) {
1071
- return {
1072
- ok: false,
1073
- payload: error
1074
- };
1075
- }
1076
-
1077
- // router/client.ts
1078
- var noop = () => {
1079
- };
1080
- function _createRecursiveProxy(callback, path) {
1081
- const proxy = new Proxy(noop, {
1082
- // property access, recurse and add field to path
1083
- get(_obj, key) {
1084
- if (typeof key !== "string")
1085
- return void 0;
1086
- return _createRecursiveProxy(callback, [...path, key]);
1087
- },
1088
- // hit the end, let's invoke the handler
1089
- apply(_target, _this, args) {
1090
- return callback({
1091
- path,
1092
- args
1093
- });
1094
- }
1095
- });
1096
- return proxy;
1097
- }
1098
- var defaultClientOptions = {
1099
- connectOnInvoke: true,
1100
- eagerlyConnect: true
1101
- };
1102
- function createClient(transport, serverId, providedClientOptions = {}) {
1103
- if (providedClientOptions.handshakeOptions) {
1104
- transport.extendHandshake(providedClientOptions.handshakeOptions);
1105
- }
1106
- const options = { ...defaultClientOptions, ...providedClientOptions };
1107
- if (options.eagerlyConnect) {
1108
- void transport.connect(serverId);
1109
- }
1110
- return _createRecursiveProxy(async (opts) => {
1111
- const [serviceName, procName, procType] = [...opts.path];
1112
- if (!(serviceName && procName && procType)) {
1113
- throw new Error(
1114
- "invalid river call, ensure the service and procedure you are calling exists"
1115
- );
1116
- }
1117
- const [input] = opts.args;
1118
- if (options.connectOnInvoke && !transport.connections.has(serverId)) {
1119
- void transport.connect(serverId);
1120
- }
1121
- if (procType === "rpc") {
1122
- return handleRpc(transport, serverId, input, serviceName, procName);
1123
- } else if (procType === "stream") {
1124
- return handleStream(transport, serverId, input, serviceName, procName);
1125
- } else if (procType === "subscribe") {
1126
- return handleSubscribe(transport, serverId, input, serviceName, procName);
1127
- } else if (procType === "upload") {
1128
- return handleUpload(transport, serverId, input, serviceName, procName);
1129
- } else {
1130
- throw new Error(`invalid river call, unknown procedure type ${procType}`);
1131
- }
1132
- }, []);
1133
- }
1134
- function createSessionDisconnectHandler(from, cb) {
1135
- return (evt) => {
1136
- if (evt.status === "disconnect" && evt.session.to === from) {
1137
- cb();
1138
- }
1139
- };
1140
- }
1141
- function handleRpc(transport, serverId, input, serviceName, procedureName) {
1142
- const streamId = nanoid();
1143
- const { span, ctx } = createProcTelemetryInfo(
1144
- transport,
1145
- "rpc",
1146
- serviceName,
1147
- procedureName,
1148
- streamId
1149
- );
1150
- transport.send(serverId, {
1151
- streamId,
1152
- serviceName,
1153
- procedureName,
1154
- payload: input,
1155
- tracing: getPropagationContext(ctx),
1156
- controlFlags: 2 /* StreamOpenBit */ | 4 /* StreamClosedBit */
1157
- });
1158
- const responsePromise = new Promise((resolve) => {
1159
- const onSessionStatus = createSessionDisconnectHandler(serverId, () => {
1160
- cleanup();
1161
- resolve(
1162
- Err({
1163
- code: UNEXPECTED_DISCONNECT,
1164
- message: `${serverId} unexpectedly disconnected`
1165
- })
1166
- );
1167
- });
1168
- function cleanup() {
1169
- transport.removeEventListener("message", onMessage);
1170
- transport.removeEventListener("sessionStatus", onSessionStatus);
1171
- span.end();
1172
- }
1173
- function onMessage(msg) {
1174
- if (msg.streamId !== streamId)
1175
- return;
1176
- if (msg.to !== transport.clientId)
1177
- return;
1178
- cleanup();
1179
- resolve(msg.payload);
1180
- }
1181
- transport.addEventListener("message", onMessage);
1182
- transport.addEventListener("sessionStatus", onSessionStatus);
1183
- });
1184
- return responsePromise;
1185
- }
1186
- function handleStream(transport, serverId, init, serviceName, procedureName) {
1187
- const streamId = nanoid();
1188
- const { span, ctx } = createProcTelemetryInfo(
1189
- transport,
1190
- "stream",
1191
- serviceName,
1192
- procedureName,
1193
- streamId
1194
- );
1195
- const inputStream = pushable({ objectMode: true });
1196
- const outputStream = pushable({ objectMode: true });
1197
- let firstMessage = true;
1198
- let healthyClose = true;
1199
- if (init) {
1200
- transport.send(serverId, {
1201
- streamId,
1202
- serviceName,
1203
- procedureName,
1204
- payload: init,
1205
- tracing: getPropagationContext(ctx),
1206
- controlFlags: 2 /* StreamOpenBit */
1207
- });
1208
- firstMessage = false;
1209
- }
1210
- const pipeInputToTransport = async () => {
1211
- for await (const rawIn of inputStream) {
1212
- const m = {
1213
- streamId,
1214
- payload: rawIn,
1215
- controlFlags: 0
1216
- };
1217
- if (firstMessage) {
1218
- m.serviceName = serviceName;
1219
- m.procedureName = procedureName;
1220
- m.tracing = getPropagationContext(ctx);
1221
- m.controlFlags |= 2 /* StreamOpenBit */;
1222
- firstMessage = false;
1223
- }
1224
- transport.send(serverId, m);
1225
- }
1226
- if (!healthyClose)
1227
- return;
1228
- transport.sendCloseStream(serverId, streamId);
1229
- };
1230
- void pipeInputToTransport();
1231
- function onMessage(msg) {
1232
- if (msg.streamId !== streamId)
1233
- return;
1234
- if (msg.to !== transport.clientId)
1235
- return;
1236
- if (isStreamClose(msg.controlFlags)) {
1237
- cleanup();
1238
- } else {
1239
- outputStream.push(msg.payload);
1240
- }
1241
- }
1242
- function cleanup() {
1243
- inputStream.end();
1244
- outputStream.end();
1245
- transport.removeEventListener("message", onMessage);
1246
- transport.removeEventListener("sessionStatus", onSessionStatus);
1247
- span.end();
1248
- }
1249
- const onSessionStatus = createSessionDisconnectHandler(serverId, () => {
1250
- outputStream.push(
1251
- Err({
1252
- code: UNEXPECTED_DISCONNECT,
1253
- message: `${serverId} unexpectedly disconnected`
1254
- })
1255
- );
1256
- healthyClose = false;
1257
- cleanup();
1258
- });
1259
- transport.addEventListener("message", onMessage);
1260
- transport.addEventListener("sessionStatus", onSessionStatus);
1261
- return [inputStream, outputStream, cleanup];
1262
- }
1263
- function handleSubscribe(transport, serverId, input, serviceName, procedureName) {
1264
- const streamId = nanoid();
1265
- const { span, ctx } = createProcTelemetryInfo(
1266
- transport,
1267
- "subscription",
1268
- serviceName,
1269
- procedureName,
1270
- streamId
1271
- );
1272
- transport.send(serverId, {
1273
- streamId,
1274
- serviceName,
1275
- procedureName,
1276
- payload: input,
1277
- tracing: getPropagationContext(ctx),
1278
- controlFlags: 2 /* StreamOpenBit */
1279
- });
1280
- let healthyClose = true;
1281
- const outputStream = pushable({ objectMode: true });
1282
- function onMessage(msg) {
1283
- if (msg.streamId !== streamId)
1284
- return;
1285
- if (msg.to !== transport.clientId)
1286
- return;
1287
- if (isStreamClose(msg.controlFlags)) {
1288
- cleanup();
1289
- } else {
1290
- outputStream.push(msg.payload);
1291
- }
1292
- }
1293
- function cleanup() {
1294
- outputStream.end();
1295
- transport.removeEventListener("message", onMessage);
1296
- transport.removeEventListener("sessionStatus", onSessionStatus);
1297
- span.end();
1298
- }
1299
- const closeHandler = () => {
1300
- cleanup();
1301
- if (!healthyClose)
1302
- return;
1303
- transport.sendCloseStream(serverId, streamId);
1304
- };
1305
- const onSessionStatus = createSessionDisconnectHandler(serverId, () => {
1306
- outputStream.push(
1307
- Err({
1308
- code: UNEXPECTED_DISCONNECT,
1309
- message: `${serverId} unexpectedly disconnected`
1310
- })
1311
- );
1312
- healthyClose = false;
1313
- cleanup();
1314
- });
1315
- transport.addEventListener("message", onMessage);
1316
- transport.addEventListener("sessionStatus", onSessionStatus);
1317
- return [outputStream, closeHandler];
1318
- }
1319
- function handleUpload(transport, serverId, init, serviceName, procedureName) {
1320
- const streamId = nanoid();
1321
- const { span, ctx } = createProcTelemetryInfo(
1322
- transport,
1323
- "upload",
1324
- serviceName,
1325
- procedureName,
1326
- streamId
1327
- );
1328
- const inputStream = pushable({ objectMode: true });
1329
- let firstMessage = true;
1330
- let healthyClose = true;
1331
- if (init) {
1332
- transport.send(serverId, {
1333
- streamId,
1334
- serviceName,
1335
- procedureName,
1336
- payload: init,
1337
- tracing: getPropagationContext(ctx),
1338
- controlFlags: 2 /* StreamOpenBit */
1339
- });
1340
- firstMessage = false;
1341
- }
1342
- const pipeInputToTransport = async () => {
1343
- for await (const rawIn of inputStream) {
1344
- const m = {
1345
- streamId,
1346
- payload: rawIn,
1347
- controlFlags: 0
1348
- };
1349
- if (firstMessage) {
1350
- m.serviceName = serviceName;
1351
- m.procedureName = procedureName;
1352
- m.tracing = getPropagationContext(ctx);
1353
- m.controlFlags |= 2 /* StreamOpenBit */;
1354
- firstMessage = false;
1355
- }
1356
- transport.send(serverId, m);
1357
- }
1358
- if (!healthyClose)
1359
- return;
1360
- transport.sendCloseStream(serverId, streamId);
1361
- };
1362
- void pipeInputToTransport();
1363
- const responsePromise = new Promise((resolve) => {
1364
- const onSessionStatus = createSessionDisconnectHandler(serverId, () => {
1365
- healthyClose = false;
1366
- cleanup();
1367
- resolve(
1368
- Err({
1369
- code: UNEXPECTED_DISCONNECT,
1370
- message: `${serverId} unexpectedly disconnected`
1371
- })
1372
- );
1373
- });
1374
- function cleanup() {
1375
- inputStream.end();
1376
- transport.removeEventListener("message", onMessage);
1377
- transport.removeEventListener("sessionStatus", onSessionStatus);
1378
- span.end();
1379
- }
1380
- function onMessage(msg) {
1381
- if (msg.streamId !== streamId)
1382
- return;
1383
- if (msg.to !== transport.clientId)
1384
- return;
1385
- cleanup();
1386
- resolve(msg.payload);
1387
- }
1388
- transport.addEventListener("message", onMessage);
1389
- transport.addEventListener("sessionStatus", onSessionStatus);
1390
- });
1391
- return [inputStream, responsePromise];
1392
- }
1393
-
1394
- // router/server.ts
1395
- import { Value } from "@sinclair/typebox/value";
1396
- import { SpanStatusCode } from "@opentelemetry/api";
1397
- var RiverServer = class {
1398
- transport;
1399
- services;
1400
- contextMap;
1401
- // map of streamId to ProcStream
1402
- streamMap;
1403
- // map of client to their open streams by streamId
1404
- clientStreams;
1405
- disconnectedSessions;
1406
- log;
1407
- constructor(transport, services, handshakeOptions, extendedContext) {
1408
- const instances = {};
1409
- this.services = instances;
1410
- this.contextMap = /* @__PURE__ */ new Map();
1411
- for (const [name, service] of Object.entries(services)) {
1412
- const instance = service.instantiate();
1413
- instances[name] = instance;
1414
- this.contextMap.set(instance, {
1415
- ...extendedContext,
1416
- state: instance.state
1417
- });
1418
- }
1419
- if (handshakeOptions) {
1420
- transport.extendHandshake(handshakeOptions);
1421
- }
1422
- this.transport = transport;
1423
- this.disconnectedSessions = /* @__PURE__ */ new Set();
1424
- this.streamMap = /* @__PURE__ */ new Map();
1425
- this.clientStreams = /* @__PURE__ */ new Map();
1426
- this.transport.addEventListener("message", this.onMessage);
1427
- this.transport.addEventListener("sessionStatus", this.onSessionStatus);
1428
- this.log = transport.log;
1429
- this.transport.addEventListener("transportStatus", async ({ status }) => {
1430
- if (status !== "closed") {
1431
- return;
1432
- }
1433
- this.transport.removeEventListener("message", this.onMessage);
1434
- this.transport.removeEventListener("sessionStatus", this.onSessionStatus);
1435
- await Promise.all([...this.streamMap.keys()].map(this.cleanupStream));
1436
- });
1437
- }
1438
- get streams() {
1439
- return this.streamMap;
1440
- }
1441
- onMessage = async (message) => {
1442
- if (message.to !== this.transport.clientId) {
1443
- this.log?.info(
1444
- `got msg with destination that isn't this server, ignoring`,
1445
- {
1446
- clientId: this.transport.clientId,
1447
- transportMessage: message
1448
- }
1449
- );
1450
- return;
1451
- }
1452
- let procStream = this.streamMap.get(message.streamId);
1453
- const isInitMessage = !procStream;
1454
- procStream ||= this.createNewProcStream(message);
1455
- if (!procStream) {
1456
- return;
1457
- }
1458
- await this.pushToStream(procStream, message, isInitMessage);
1459
- };
1460
- // cleanup streams on session close
1461
- onSessionStatus = async (evt) => {
1462
- if (evt.status !== "disconnect")
1463
- return;
1464
- const disconnectedClientId = evt.session.to;
1465
- this.log?.info(
1466
- `got session disconnect from ${disconnectedClientId}, cleaning up streams`,
1467
- evt.session.loggingMetadata
1468
- );
1469
- const streamsFromThisClient = this.clientStreams.get(disconnectedClientId);
1470
- if (!streamsFromThisClient)
1471
- return;
1472
- this.disconnectedSessions.add(disconnectedClientId);
1473
- await Promise.all(
1474
- Array.from(streamsFromThisClient).map(this.cleanupStream)
1475
- );
1476
- this.disconnectedSessions.delete(disconnectedClientId);
1477
- this.clientStreams.delete(disconnectedClientId);
1478
- };
1479
- createNewProcStream(message) {
1480
- if (!isStreamOpen(message.controlFlags)) {
1481
- this.log?.error(
1482
- `can't create a new procedure stream from a message that doesn't have the stream open bit set`,
1483
- {
1484
- clientId: this.transport.clientId,
1485
- transportMessage: message,
1486
- tags: ["invariant-violation"]
1487
- }
1488
- );
1489
- return;
1490
- }
1491
- if (!message.procedureName || !message.serviceName) {
1492
- this.log?.warn(
1493
- `missing procedure or service name in stream open message`,
1494
- {
1495
- clientId: this.transport.clientId,
1496
- transportMessage: message
1497
- }
1498
- );
1499
- return;
1500
- }
1501
- if (!(message.serviceName in this.services)) {
1502
- this.log?.warn(`couldn't find service ${message.serviceName}`, {
1503
- clientId: this.transport.clientId,
1504
- transportMessage: message
1505
- });
1506
- return;
1507
- }
1508
- const service = this.services[message.serviceName];
1509
- const serviceContext = this.getContext(service, message.serviceName);
1510
- if (!(message.procedureName in service.procedures)) {
1511
- this.log?.warn(
1512
- `couldn't find a matching procedure for ${message.serviceName}.${message.procedureName}`,
1513
- {
1514
- clientId: this.transport.clientId,
1515
- transportMessage: message
1516
- }
1517
- );
1518
- return;
1519
- }
1520
- const session = this.transport.sessions.get(message.from);
1521
- if (!session) {
1522
- this.log?.warn(`couldn't find session for ${message.from}`, {
1523
- clientId: this.transport.clientId,
1524
- transportMessage: message
1525
- });
1526
- return;
1527
- }
1528
- const procedure = service.procedures[message.procedureName];
1529
- const incoming = pushable({ objectMode: true });
1530
- const outgoing = pushable({ objectMode: true });
1531
- const needsClose = procedure.type === "subscription" || procedure.type === "stream";
1532
- const disposables = [];
1533
- const outputHandler = (
1534
- // sending outgoing messages back to client
1535
- needsClose ? (
1536
- // subscription and stream case, we need to send a close bit after the response stream
1537
- (async () => {
1538
- for await (const response of outgoing) {
1539
- this.transport.send(session.to, {
1540
- streamId: message.streamId,
1541
- controlFlags: 0,
1542
- payload: response
1543
- });
1544
- }
1545
- if (!this.disconnectedSessions.has(message.from)) {
1546
- this.transport.sendCloseStream(session.to, message.streamId);
1547
- }
1548
- disposables.forEach((d) => d());
1549
- })()
1550
- ) : (
1551
- // rpc and upload case, we just send the response back with close bit
1552
- (async () => {
1553
- const response = await outgoing.next().then((res) => res.value);
1554
- if (response) {
1555
- this.transport.send(session.to, {
1556
- streamId: message.streamId,
1557
- controlFlags: 4 /* StreamClosedBit */,
1558
- payload: response
1559
- });
1560
- disposables.forEach((d) => d());
1561
- }
1562
- })()
1563
- )
1564
- );
1565
- const errorHandler = (err, span) => {
1566
- const errorMsg = coerceErrorString(err);
1567
- this.log?.error(
1568
- `procedure ${message.serviceName}.${message.procedureName} threw an uncaught error: ${errorMsg}`,
1569
- session.loggingMetadata
1570
- );
1571
- span.recordException(err instanceof Error ? err : new Error(errorMsg));
1572
- span.setStatus({ code: SpanStatusCode.ERROR });
1573
- outgoing.push(
1574
- Err({
1575
- code: UNCAUGHT_ERROR,
1576
- message: errorMsg
1577
- })
1578
- );
1579
- };
1580
- const sessionMeta = this.transport.sessionHandshakeMetadata.get(session);
1581
- if (!sessionMeta) {
1582
- this.log?.error(`session doesn't have handshake metadata`, {
1583
- ...session.loggingMetadata,
1584
- tags: ["invariant-violation"]
1585
- });
1586
- return;
1587
- }
1588
- let inputHandler;
1589
- const procHasInitMessage = "init" in procedure;
1590
- const serviceContextWithTransportInfo = {
1591
- ...serviceContext,
1592
- to: message.to,
1593
- from: message.from,
1594
- streamId: message.streamId,
1595
- session,
1596
- metadata: sessionMeta
1597
- };
1598
- switch (procedure.type) {
1599
- case "rpc":
1600
- inputHandler = createHandlerSpan(
1601
- procedure.type,
1602
- message,
1603
- async (span) => {
1604
- const inputMessage = await incoming.next();
1605
- if (inputMessage.done) {
1606
- return;
1607
- }
1608
- try {
1609
- const outputMessage = await procedure.handler(
1610
- serviceContextWithTransportInfo,
1611
- inputMessage.value
1612
- );
1613
- outgoing.push(outputMessage);
1614
- } catch (err) {
1615
- errorHandler(err, span);
1616
- } finally {
1617
- span.end();
1618
- }
1619
- }
1620
- );
1621
- break;
1622
- case "stream":
1623
- if (procHasInitMessage) {
1624
- inputHandler = createHandlerSpan(
1625
- procedure.type,
1626
- message,
1627
- async (span) => {
1628
- const initMessage = await incoming.next();
1629
- if (initMessage.done) {
1630
- return;
1631
- }
1632
- try {
1633
- const dispose = await procedure.handler(
1634
- serviceContextWithTransportInfo,
1635
- initMessage.value,
1636
- incoming,
1637
- outgoing
1638
- );
1639
- if (dispose) {
1640
- disposables.push(dispose);
1641
- }
1642
- } catch (err) {
1643
- errorHandler(err, span);
1644
- } finally {
1645
- span.end();
1646
- }
1647
- }
1648
- );
1649
- } else {
1650
- inputHandler = createHandlerSpan(
1651
- procedure.type,
1652
- message,
1653
- async (span) => {
1654
- try {
1655
- const dispose = await procedure.handler(
1656
- serviceContextWithTransportInfo,
1657
- incoming,
1658
- outgoing
1659
- );
1660
- if (dispose) {
1661
- disposables.push(dispose);
1662
- }
1663
- } catch (err) {
1664
- errorHandler(err, span);
1665
- } finally {
1666
- span.end();
1667
- }
1668
- }
1669
- );
1670
- }
1671
- break;
1672
- case "subscription":
1673
- inputHandler = createHandlerSpan(
1674
- procedure.type,
1675
- message,
1676
- async (span) => {
1677
- const inputMessage = await incoming.next();
1678
- if (inputMessage.done) {
1679
- return;
1680
- }
1681
- try {
1682
- const dispose = await procedure.handler(
1683
- serviceContextWithTransportInfo,
1684
- inputMessage.value,
1685
- outgoing
1686
- );
1687
- if (dispose) {
1688
- disposables.push(dispose);
1689
- }
1690
- } catch (err) {
1691
- errorHandler(err, span);
1692
- } finally {
1693
- span.end();
1694
- }
1695
- }
1696
- );
1697
- break;
1698
- case "upload":
1699
- if (procHasInitMessage) {
1700
- inputHandler = createHandlerSpan(
1701
- procedure.type,
1702
- message,
1703
- async (span) => {
1704
- const initMessage = await incoming.next();
1705
- if (initMessage.done) {
1706
- return;
1707
- }
1708
- try {
1709
- const outputMessage = await procedure.handler(
1710
- serviceContextWithTransportInfo,
1711
- initMessage.value,
1712
- incoming
1713
- );
1714
- if (!this.disconnectedSessions.has(message.from)) {
1715
- outgoing.push(outputMessage);
1716
- }
1717
- } catch (err) {
1718
- errorHandler(err, span);
1719
- } finally {
1720
- span.end();
1721
- }
1722
- }
1723
- );
1724
- } else {
1725
- inputHandler = createHandlerSpan(
1726
- procedure.type,
1727
- message,
1728
- async (span) => {
1729
- try {
1730
- const outputMessage = await procedure.handler(
1731
- serviceContextWithTransportInfo,
1732
- incoming
1733
- );
1734
- if (!this.disconnectedSessions.has(message.from)) {
1735
- outgoing.push(outputMessage);
1736
- }
1737
- } catch (err) {
1738
- errorHandler(err, span);
1739
- } finally {
1740
- span.end();
1741
- }
1742
- }
1743
- );
1744
- }
1745
- break;
1746
- default:
1747
- this.log?.warn(
1748
- `got request for invalid procedure type ${procedure.type} at ${message.serviceName}.${message.procedureName}`,
1749
- { ...session.loggingMetadata, transportMessage: message }
1750
- );
1751
- return;
1752
- }
1753
- const procStream = {
1754
- id: message.streamId,
1755
- incoming,
1756
- outgoing,
1757
- serviceName: message.serviceName,
1758
- procedureName: message.procedureName,
1759
- promises: { inputHandler, outputHandler }
1760
- };
1761
- this.streamMap.set(message.streamId, procStream);
1762
- const streamsFromThisClient = this.clientStreams.get(message.from) ?? /* @__PURE__ */ new Set();
1763
- streamsFromThisClient.add(message.streamId);
1764
- this.clientStreams.set(message.from, streamsFromThisClient);
1765
- return procStream;
1766
- }
1767
- async pushToStream(procStream, message, isInit) {
1768
- const { serviceName, procedureName } = procStream;
1769
- const procedure = this.services[serviceName].procedures[procedureName];
1770
- const procHasInitMessage = "init" in procedure;
1771
- if (isInit && procHasInitMessage) {
1772
- if (Value.Check(procedure.init, message.payload)) {
1773
- procStream.incoming.push(message.payload);
1774
- } else {
1775
- this.log?.error(
1776
- `procedure ${serviceName}.${procedureName} received invalid init payload`,
1777
- {
1778
- clientId: this.transport.clientId,
1779
- transportMessage: message,
1780
- validationErrors: [
1781
- ...Value.Errors(procedure.init, message.payload)
1782
- ]
1783
- }
1784
- );
1785
- }
1786
- } else if (Value.Check(procedure.input, message.payload)) {
1787
- procStream.incoming.push(message.payload);
1788
- } else if (!Value.Check(ControlMessagePayloadSchema, message.payload)) {
1789
- this.log?.error(
1790
- `procedure ${serviceName}.${procedureName} received invalid payload`,
1791
- {
1792
- clientId: this.transport.clientId,
1793
- transportMessage: message,
1794
- validationErrors: [...Value.Errors(procedure.input, message.payload)]
1795
- }
1796
- );
1797
- }
1798
- if (isStreamClose(message.controlFlags)) {
1799
- await this.cleanupStream(message.streamId);
1800
- const streamsFromThisClient = this.clientStreams.get(message.from);
1801
- if (streamsFromThisClient) {
1802
- streamsFromThisClient.delete(message.streamId);
1803
- if (streamsFromThisClient.size === 0) {
1804
- this.clientStreams.delete(message.from);
1805
- }
1806
- }
1807
- }
1808
- }
1809
- getContext(service, serviceName) {
1810
- const context = this.contextMap.get(service);
1811
- if (!context) {
1812
- const err = `no context found for ${serviceName}`;
1813
- this.log?.error(err, {
1814
- clientId: this.transport.clientId,
1815
- tags: ["invariant-violation"]
1816
- });
1817
- throw new Error(err);
1818
- }
1819
- return context;
1820
- }
1821
- cleanupStream = async (id) => {
1822
- const stream2 = this.streamMap.get(id);
1823
- if (!stream2) {
1824
- return;
1825
- }
1826
- stream2.incoming.end();
1827
- await stream2.promises.inputHandler;
1828
- stream2.outgoing.end();
1829
- await stream2.promises.outputHandler;
1830
- this.streamMap.delete(id);
1831
- };
1832
- };
1833
- function createServer(transport, services, providedServerOptions) {
1834
- return new RiverServer(
1835
- transport,
1836
- services,
1837
- providedServerOptions?.handshakeOptions,
1838
- providedServerOptions?.extendedContext
1839
- );
1840
- }
1841
-
1842
- // router/handshake.ts
1843
- function createClientHandshakeOptions(schema, construct) {
1844
- return { schema, construct };
1845
- }
1846
- function createServerHandshakeOptions(schema, validate) {
1847
- return { schema, validate };
1848
- }
1849
-
1850
- export {
1851
- serializeSchema,
1852
- ServiceSchema,
1853
- diffServerSchema,
1854
- Procedure,
1855
- pushable,
1856
- UNCAUGHT_ERROR,
1857
- RiverUncaughtSchema,
1858
- Ok,
1859
- Err,
1860
- createClient,
1861
- createServer,
1862
- createClientHandshakeOptions,
1863
- createServerHandshakeOptions
1864
- };
1865
- //# sourceMappingURL=chunk-AEY7BBOZ.js.map