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