@arpabet/vrpc 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -0
- package/dist/index.d.ts +561 -0
- package/dist/index.js +2262 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2262 @@
|
|
|
1
|
+
// src/value.ts
|
|
2
|
+
var INT64_MIN = -9223372036854775808n;
|
|
3
|
+
var INT64_MAX = 9223372036854775807n;
|
|
4
|
+
var VrpcDouble = class {
|
|
5
|
+
constructor(value) {
|
|
6
|
+
this.value = value;
|
|
7
|
+
}
|
|
8
|
+
value;
|
|
9
|
+
valueOf() {
|
|
10
|
+
return this.value;
|
|
11
|
+
}
|
|
12
|
+
toString() {
|
|
13
|
+
return String(this.value);
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
function double(value) {
|
|
17
|
+
return new VrpcDouble(value);
|
|
18
|
+
}
|
|
19
|
+
var VrpcDecimal = class _VrpcDecimal {
|
|
20
|
+
constructor(coefficient, exponent) {
|
|
21
|
+
this.coefficient = coefficient;
|
|
22
|
+
this.exponent = exponent;
|
|
23
|
+
if (!Number.isInteger(exponent) || exponent < -2147483648 || exponent > 2147483647) {
|
|
24
|
+
throw new RangeError(`vrpc: decimal exponent out of int32 range: ${exponent}`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
coefficient;
|
|
28
|
+
exponent;
|
|
29
|
+
/** Parses "123", "-1.045", "1.2e-5" style decimal strings. */
|
|
30
|
+
static fromString(s) {
|
|
31
|
+
const m = /^([+-]?)(\d+)(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/.exec(s.trim());
|
|
32
|
+
if (!m) throw new SyntaxError(`vrpc: invalid decimal string: ${JSON.stringify(s)}`);
|
|
33
|
+
const [, sign, int, frac = "", expStr] = m;
|
|
34
|
+
let exponent = (expStr ? parseInt(expStr, 10) : 0) - frac.length;
|
|
35
|
+
let digits = (int ?? "") + frac;
|
|
36
|
+
digits = digits.replace(/^0+(?=\d)/, "");
|
|
37
|
+
let coefficient = BigInt(digits);
|
|
38
|
+
if (sign === "-") coefficient = -coefficient;
|
|
39
|
+
return new _VrpcDecimal(coefficient, exponent);
|
|
40
|
+
}
|
|
41
|
+
toString() {
|
|
42
|
+
const neg = this.coefficient < 0n;
|
|
43
|
+
let digits = (neg ? -this.coefficient : this.coefficient).toString();
|
|
44
|
+
let out;
|
|
45
|
+
if (this.exponent >= 0) {
|
|
46
|
+
out = digits + "0".repeat(this.exponent);
|
|
47
|
+
} else {
|
|
48
|
+
const point = digits.length + this.exponent;
|
|
49
|
+
if (point > 0) {
|
|
50
|
+
out = digits.slice(0, point) + "." + digits.slice(point);
|
|
51
|
+
} else {
|
|
52
|
+
out = "0." + "0".repeat(-point) + digits;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return (neg ? "-" : "") + out;
|
|
56
|
+
}
|
|
57
|
+
toNumber() {
|
|
58
|
+
return Number(this.toString());
|
|
59
|
+
}
|
|
60
|
+
equals(other) {
|
|
61
|
+
return this.coefficient === other.coefficient && this.exponent === other.exponent;
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
function decimal(s) {
|
|
65
|
+
return VrpcDecimal.fromString(s);
|
|
66
|
+
}
|
|
67
|
+
var VrpcExt = class {
|
|
68
|
+
constructor(tag, data) {
|
|
69
|
+
this.tag = tag;
|
|
70
|
+
this.data = data;
|
|
71
|
+
if (!Number.isInteger(tag) || tag < 0 || tag > 255) {
|
|
72
|
+
throw new RangeError(`vrpc: ext tag out of byte range: ${tag}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
tag;
|
|
76
|
+
data;
|
|
77
|
+
equals(other) {
|
|
78
|
+
return this.tag === other.tag && bytesEqual(this.data, other.data);
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
function bytesEqual(a, b) {
|
|
82
|
+
if (a.length !== b.length) return false;
|
|
83
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
function isPlainObject(v) {
|
|
87
|
+
if (v === null || typeof v !== "object") return false;
|
|
88
|
+
const proto = Object.getPrototypeOf(v);
|
|
89
|
+
return proto === Object.prototype || proto === null;
|
|
90
|
+
}
|
|
91
|
+
var textEncoder = new TextEncoder();
|
|
92
|
+
var textDecoder = new TextDecoder("utf-8", { fatal: false });
|
|
93
|
+
function utf8Encode(s) {
|
|
94
|
+
return textEncoder.encode(s);
|
|
95
|
+
}
|
|
96
|
+
function utf8Decode(b) {
|
|
97
|
+
return textDecoder.decode(b);
|
|
98
|
+
}
|
|
99
|
+
function compareUtf8(a, b) {
|
|
100
|
+
if (a === b) return 0;
|
|
101
|
+
const ab = utf8Encode(a);
|
|
102
|
+
const bb = utf8Encode(b);
|
|
103
|
+
const n = Math.min(ab.length, bb.length);
|
|
104
|
+
for (let i = 0; i < n; i++) {
|
|
105
|
+
const d = ab[i] - bb[i];
|
|
106
|
+
if (d !== 0) return d;
|
|
107
|
+
}
|
|
108
|
+
return ab.length - bb.length;
|
|
109
|
+
}
|
|
110
|
+
var B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
111
|
+
var B64REV = new Int8Array(128).fill(-1);
|
|
112
|
+
for (let i = 0; i < B64.length; i++) B64REV[B64.charCodeAt(i)] = i;
|
|
113
|
+
function base64RawStdEncode(data) {
|
|
114
|
+
let out = "";
|
|
115
|
+
let i = 0;
|
|
116
|
+
for (; i + 2 < data.length; i += 3) {
|
|
117
|
+
const n = data[i] << 16 | data[i + 1] << 8 | data[i + 2];
|
|
118
|
+
out += B64[n >> 18 & 63] + B64[n >> 12 & 63] + B64[n >> 6 & 63] + B64[n & 63];
|
|
119
|
+
}
|
|
120
|
+
const rest = data.length - i;
|
|
121
|
+
if (rest === 1) {
|
|
122
|
+
const n = data[i] << 16;
|
|
123
|
+
out += B64[n >> 18 & 63] + B64[n >> 12 & 63];
|
|
124
|
+
} else if (rest === 2) {
|
|
125
|
+
const n = data[i] << 16 | data[i + 1] << 8;
|
|
126
|
+
out += B64[n >> 18 & 63] + B64[n >> 12 & 63] + B64[n >> 6 & 63];
|
|
127
|
+
}
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
130
|
+
function base64RawStdDecode(s) {
|
|
131
|
+
let end = s.length;
|
|
132
|
+
while (end > 0 && s[end - 1] === "=") end--;
|
|
133
|
+
const outLen = Math.floor(end * 3 / 4);
|
|
134
|
+
const out = new Uint8Array(outLen);
|
|
135
|
+
let acc = 0;
|
|
136
|
+
let bits = 0;
|
|
137
|
+
let o = 0;
|
|
138
|
+
for (let i = 0; i < end; i++) {
|
|
139
|
+
const c = s.charCodeAt(i);
|
|
140
|
+
const v = c < 128 ? B64REV[c] : -1;
|
|
141
|
+
if (v < 0) throw new SyntaxError(`vrpc: invalid base64 character at ${i}`);
|
|
142
|
+
acc = acc << 6 | v;
|
|
143
|
+
bits += 6;
|
|
144
|
+
if (bits >= 8) {
|
|
145
|
+
bits -= 8;
|
|
146
|
+
out[o++] = acc >> bits & 255;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (o !== outLen) throw new SyntaxError("vrpc: truncated base64 input");
|
|
150
|
+
return out;
|
|
151
|
+
}
|
|
152
|
+
function bytesToHex(data) {
|
|
153
|
+
let out = "";
|
|
154
|
+
for (const b of data) out += b.toString(16).padStart(2, "0");
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// src/msgpack.ts
|
|
159
|
+
var BIGINT_EXT_TAG = 1;
|
|
160
|
+
var DECIMAL_EXT_TAG = 2;
|
|
161
|
+
var DEFAULT_LIMITS = {
|
|
162
|
+
maxDepth: 1e3,
|
|
163
|
+
maxCollectionLen: 16777216,
|
|
164
|
+
maxByteLen: 1073741824
|
|
165
|
+
};
|
|
166
|
+
var Writer = class {
|
|
167
|
+
buf = new Uint8Array(256);
|
|
168
|
+
len = 0;
|
|
169
|
+
ensure(n) {
|
|
170
|
+
if (this.len + n <= this.buf.length) return;
|
|
171
|
+
let cap = this.buf.length * 2;
|
|
172
|
+
while (cap < this.len + n) cap *= 2;
|
|
173
|
+
const next = new Uint8Array(cap);
|
|
174
|
+
next.set(this.buf.subarray(0, this.len));
|
|
175
|
+
this.buf = next;
|
|
176
|
+
}
|
|
177
|
+
byte(b) {
|
|
178
|
+
this.ensure(1);
|
|
179
|
+
this.buf[this.len++] = b;
|
|
180
|
+
}
|
|
181
|
+
bytes(data) {
|
|
182
|
+
this.ensure(data.length);
|
|
183
|
+
this.buf.set(data, this.len);
|
|
184
|
+
this.len += data.length;
|
|
185
|
+
}
|
|
186
|
+
u16(v) {
|
|
187
|
+
this.ensure(2);
|
|
188
|
+
this.buf[this.len++] = v >> 8 & 255;
|
|
189
|
+
this.buf[this.len++] = v & 255;
|
|
190
|
+
}
|
|
191
|
+
u32(v) {
|
|
192
|
+
this.ensure(4);
|
|
193
|
+
this.buf[this.len++] = v >>> 24 & 255;
|
|
194
|
+
this.buf[this.len++] = v >>> 16 & 255;
|
|
195
|
+
this.buf[this.len++] = v >>> 8 & 255;
|
|
196
|
+
this.buf[this.len++] = v & 255;
|
|
197
|
+
}
|
|
198
|
+
u64(v) {
|
|
199
|
+
this.ensure(8);
|
|
200
|
+
const dv = new DataView(this.buf.buffer, this.buf.byteOffset + this.len, 8);
|
|
201
|
+
dv.setBigUint64(0, BigInt.asUintN(64, v));
|
|
202
|
+
this.len += 8;
|
|
203
|
+
}
|
|
204
|
+
f64(v) {
|
|
205
|
+
this.ensure(8);
|
|
206
|
+
const dv = new DataView(this.buf.buffer, this.buf.byteOffset + this.len, 8);
|
|
207
|
+
dv.setFloat64(0, v);
|
|
208
|
+
this.len += 8;
|
|
209
|
+
}
|
|
210
|
+
result() {
|
|
211
|
+
return this.buf.slice(0, this.len);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
function packLongNumber(w, v) {
|
|
215
|
+
if (v >= 0) {
|
|
216
|
+
if (v <= 127) w.byte(v);
|
|
217
|
+
else if (v <= 255) {
|
|
218
|
+
w.byte(204);
|
|
219
|
+
w.byte(v);
|
|
220
|
+
} else if (v <= 65535) {
|
|
221
|
+
w.byte(205);
|
|
222
|
+
w.u16(v);
|
|
223
|
+
} else if (v <= 4294967295) {
|
|
224
|
+
w.byte(206);
|
|
225
|
+
w.u32(v);
|
|
226
|
+
} else {
|
|
227
|
+
w.byte(207);
|
|
228
|
+
w.u64(BigInt(v));
|
|
229
|
+
}
|
|
230
|
+
} else {
|
|
231
|
+
if (v >= -32) w.byte(256 + v);
|
|
232
|
+
else if (v >= -128) {
|
|
233
|
+
w.byte(208);
|
|
234
|
+
w.byte(v & 255);
|
|
235
|
+
} else if (v >= -32768) {
|
|
236
|
+
w.byte(209);
|
|
237
|
+
w.u16(v & 65535);
|
|
238
|
+
} else if (v >= -2147483648) {
|
|
239
|
+
w.byte(210);
|
|
240
|
+
w.u32(v >>> 0);
|
|
241
|
+
} else {
|
|
242
|
+
w.byte(211);
|
|
243
|
+
w.u64(BigInt.asUintN(64, BigInt(v)));
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function packLongBig(w, v) {
|
|
248
|
+
if (v >= 0n) {
|
|
249
|
+
if (v <= 0xffffffffn) {
|
|
250
|
+
packLongNumber(w, Number(v));
|
|
251
|
+
} else {
|
|
252
|
+
w.byte(207);
|
|
253
|
+
w.u64(v);
|
|
254
|
+
}
|
|
255
|
+
} else if (v >= -2147483648n) {
|
|
256
|
+
packLongNumber(w, Number(v));
|
|
257
|
+
} else {
|
|
258
|
+
w.byte(211);
|
|
259
|
+
w.u64(BigInt.asUintN(64, v));
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function packDouble(w, v) {
|
|
263
|
+
w.byte(203);
|
|
264
|
+
w.f64(v);
|
|
265
|
+
}
|
|
266
|
+
function packStr(w, s) {
|
|
267
|
+
const b = utf8Encode(s);
|
|
268
|
+
if (b.length < 32) w.byte(160 | b.length);
|
|
269
|
+
else if (b.length <= 255) {
|
|
270
|
+
w.byte(217);
|
|
271
|
+
w.byte(b.length);
|
|
272
|
+
} else if (b.length <= 65535) {
|
|
273
|
+
w.byte(218);
|
|
274
|
+
w.u16(b.length);
|
|
275
|
+
} else {
|
|
276
|
+
w.byte(219);
|
|
277
|
+
w.u32(b.length);
|
|
278
|
+
}
|
|
279
|
+
w.bytes(b);
|
|
280
|
+
}
|
|
281
|
+
function packBin(w, b) {
|
|
282
|
+
if (b.length <= 255) {
|
|
283
|
+
w.byte(196);
|
|
284
|
+
w.byte(b.length);
|
|
285
|
+
} else if (b.length <= 65535) {
|
|
286
|
+
w.byte(197);
|
|
287
|
+
w.u16(b.length);
|
|
288
|
+
} else {
|
|
289
|
+
w.byte(198);
|
|
290
|
+
w.u32(b.length);
|
|
291
|
+
}
|
|
292
|
+
w.bytes(b);
|
|
293
|
+
}
|
|
294
|
+
function packExt(w, tag, data) {
|
|
295
|
+
const n = data.length;
|
|
296
|
+
if (n === 1) w.byte(212);
|
|
297
|
+
else if (n === 2) w.byte(213);
|
|
298
|
+
else if (n === 4) w.byte(214);
|
|
299
|
+
else if (n === 8) w.byte(215);
|
|
300
|
+
else if (n === 16) w.byte(216);
|
|
301
|
+
else if (n <= 255) {
|
|
302
|
+
w.byte(199);
|
|
303
|
+
w.byte(n);
|
|
304
|
+
} else if (n <= 65535) {
|
|
305
|
+
w.byte(200);
|
|
306
|
+
w.u16(n);
|
|
307
|
+
} else {
|
|
308
|
+
w.byte(201);
|
|
309
|
+
w.u32(n);
|
|
310
|
+
}
|
|
311
|
+
w.byte(tag);
|
|
312
|
+
w.bytes(data);
|
|
313
|
+
}
|
|
314
|
+
function bigIntGobEncode(v) {
|
|
315
|
+
const neg = v < 0n;
|
|
316
|
+
let abs = neg ? -v : v;
|
|
317
|
+
const mag = [];
|
|
318
|
+
while (abs > 0n) {
|
|
319
|
+
mag.unshift(Number(abs & 0xffn));
|
|
320
|
+
abs >>= 8n;
|
|
321
|
+
}
|
|
322
|
+
const out = new Uint8Array(1 + mag.length);
|
|
323
|
+
out[0] = 1 << 1 | (neg ? 1 : 0);
|
|
324
|
+
out.set(mag, 1);
|
|
325
|
+
return out;
|
|
326
|
+
}
|
|
327
|
+
function bigIntGobDecode(data) {
|
|
328
|
+
if (data.length === 0) throw new SyntaxError("vrpc: empty bigint payload");
|
|
329
|
+
const first = data[0];
|
|
330
|
+
if (first >> 1 !== 1) throw new SyntaxError(`vrpc: unsupported bigint gob version ${first >> 1}`);
|
|
331
|
+
const neg = (first & 1) === 1;
|
|
332
|
+
let v = 0n;
|
|
333
|
+
for (let i = 1; i < data.length; i++) v = v << 8n | BigInt(data[i]);
|
|
334
|
+
return neg ? -v : v;
|
|
335
|
+
}
|
|
336
|
+
function packBigInt(w, v) {
|
|
337
|
+
packExt(w, BIGINT_EXT_TAG, bigIntGobEncode(v));
|
|
338
|
+
}
|
|
339
|
+
function packDecimal(w, v) {
|
|
340
|
+
const coef = bigIntGobEncode(v.coefficient);
|
|
341
|
+
const payload = new Uint8Array(4 + coef.length);
|
|
342
|
+
const dv = new DataView(payload.buffer);
|
|
343
|
+
dv.setInt32(0, v.exponent);
|
|
344
|
+
payload.set(coef, 4);
|
|
345
|
+
packExt(w, DECIMAL_EXT_TAG, payload);
|
|
346
|
+
}
|
|
347
|
+
function packValue(w, v) {
|
|
348
|
+
if (v === null || v === void 0) {
|
|
349
|
+
w.byte(192);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
switch (typeof v) {
|
|
353
|
+
case "boolean":
|
|
354
|
+
w.byte(v ? 195 : 194);
|
|
355
|
+
return;
|
|
356
|
+
case "number":
|
|
357
|
+
if (Number.isSafeInteger(v)) packLongNumber(w, v === 0 ? 0 : v);
|
|
358
|
+
else if (Number.isInteger(v)) {
|
|
359
|
+
throw new RangeError(
|
|
360
|
+
`vrpc: integer ${v} exceeds \xB12^53; pass a bigint for exact int64 encoding`
|
|
361
|
+
);
|
|
362
|
+
} else packDouble(w, v);
|
|
363
|
+
return;
|
|
364
|
+
case "string":
|
|
365
|
+
packStr(w, v);
|
|
366
|
+
return;
|
|
367
|
+
case "bigint":
|
|
368
|
+
if (v >= INT64_MIN && v <= INT64_MAX) packLongBig(w, v);
|
|
369
|
+
else packBigInt(w, v);
|
|
370
|
+
return;
|
|
371
|
+
case "object":
|
|
372
|
+
break;
|
|
373
|
+
default:
|
|
374
|
+
throw new TypeError(`vrpc: cannot encode ${typeof v} as a value`);
|
|
375
|
+
}
|
|
376
|
+
if (v instanceof Uint8Array) {
|
|
377
|
+
packBin(w, v);
|
|
378
|
+
} else if (v instanceof VrpcDouble) {
|
|
379
|
+
packDouble(w, v.value);
|
|
380
|
+
} else if (v instanceof VrpcDecimal) {
|
|
381
|
+
packDecimal(w, v);
|
|
382
|
+
} else if (v instanceof VrpcExt) {
|
|
383
|
+
packExt(w, v.tag, v.data);
|
|
384
|
+
} else if (Array.isArray(v)) {
|
|
385
|
+
if (v.length < 16) w.byte(144 | v.length);
|
|
386
|
+
else if (v.length <= 65535) {
|
|
387
|
+
w.byte(220);
|
|
388
|
+
w.u16(v.length);
|
|
389
|
+
} else {
|
|
390
|
+
w.byte(221);
|
|
391
|
+
w.u32(v.length);
|
|
392
|
+
}
|
|
393
|
+
for (const item of v) packValue(w, item);
|
|
394
|
+
} else if (v instanceof Map) {
|
|
395
|
+
packMapEntries(
|
|
396
|
+
w,
|
|
397
|
+
[...v.keys()].map((k) => String(k)),
|
|
398
|
+
(k) => v.get(k)
|
|
399
|
+
);
|
|
400
|
+
} else if (isPlainObject(v)) {
|
|
401
|
+
packMapEntries(w, Object.keys(v), (k) => v[k]);
|
|
402
|
+
} else {
|
|
403
|
+
throw new TypeError(`vrpc: cannot encode ${v.constructor?.name ?? "object"} as a value`);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
function packMapEntries(w, keys, get) {
|
|
407
|
+
const live = keys.filter((k) => get(k) !== void 0).sort(compareUtf8);
|
|
408
|
+
if (live.length < 16) w.byte(128 | live.length);
|
|
409
|
+
else if (live.length <= 65535) {
|
|
410
|
+
w.byte(222);
|
|
411
|
+
w.u16(live.length);
|
|
412
|
+
} else {
|
|
413
|
+
w.byte(223);
|
|
414
|
+
w.u32(live.length);
|
|
415
|
+
}
|
|
416
|
+
for (const k of live) {
|
|
417
|
+
packStr(w, k);
|
|
418
|
+
packValue(w, get(k));
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
function msgpackEncode(v) {
|
|
422
|
+
const w = new Writer();
|
|
423
|
+
packValue(w, v);
|
|
424
|
+
return w.result();
|
|
425
|
+
}
|
|
426
|
+
var Reader = class {
|
|
427
|
+
constructor(buf, limits) {
|
|
428
|
+
this.buf = buf;
|
|
429
|
+
this.limits = limits;
|
|
430
|
+
this.dv = new DataView(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
431
|
+
}
|
|
432
|
+
buf;
|
|
433
|
+
limits;
|
|
434
|
+
pos = 0;
|
|
435
|
+
dv;
|
|
436
|
+
byte() {
|
|
437
|
+
if (this.pos >= this.buf.length) throw new SyntaxError("vrpc: truncated msgpack input");
|
|
438
|
+
return this.buf[this.pos++];
|
|
439
|
+
}
|
|
440
|
+
take(n) {
|
|
441
|
+
if (n > this.limits.maxByteLen) throw new RangeError(`vrpc: msgpack byte length ${n} exceeds limit`);
|
|
442
|
+
if (this.pos + n > this.buf.length) throw new SyntaxError("vrpc: truncated msgpack input");
|
|
443
|
+
const out = this.buf.slice(this.pos, this.pos + n);
|
|
444
|
+
this.pos += n;
|
|
445
|
+
return out;
|
|
446
|
+
}
|
|
447
|
+
u8() {
|
|
448
|
+
return this.byte();
|
|
449
|
+
}
|
|
450
|
+
u16() {
|
|
451
|
+
const v = this.dv.getUint16(this.need(2));
|
|
452
|
+
return v;
|
|
453
|
+
}
|
|
454
|
+
u32() {
|
|
455
|
+
return this.dv.getUint32(this.need(4));
|
|
456
|
+
}
|
|
457
|
+
i8() {
|
|
458
|
+
return this.dv.getInt8(this.need(1));
|
|
459
|
+
}
|
|
460
|
+
i16() {
|
|
461
|
+
return this.dv.getInt16(this.need(2));
|
|
462
|
+
}
|
|
463
|
+
i32() {
|
|
464
|
+
return this.dv.getInt32(this.need(4));
|
|
465
|
+
}
|
|
466
|
+
i64() {
|
|
467
|
+
return this.dv.getBigInt64(this.need(8));
|
|
468
|
+
}
|
|
469
|
+
u64() {
|
|
470
|
+
return this.dv.getBigUint64(this.need(8));
|
|
471
|
+
}
|
|
472
|
+
f32() {
|
|
473
|
+
return this.dv.getFloat32(this.need(4));
|
|
474
|
+
}
|
|
475
|
+
f64() {
|
|
476
|
+
return this.dv.getFloat64(this.need(8));
|
|
477
|
+
}
|
|
478
|
+
need(n) {
|
|
479
|
+
if (this.pos + n > this.buf.length) throw new SyntaxError("vrpc: truncated msgpack input");
|
|
480
|
+
const at = this.pos;
|
|
481
|
+
this.pos += n;
|
|
482
|
+
return at;
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
function normalizeInt(v) {
|
|
486
|
+
return v >= -9007199254740991n && v <= 9007199254740991n ? Number(v) : v;
|
|
487
|
+
}
|
|
488
|
+
function decodeExt(tag, data) {
|
|
489
|
+
if (tag === BIGINT_EXT_TAG) return bigIntGobDecode(data);
|
|
490
|
+
if (tag === DECIMAL_EXT_TAG) {
|
|
491
|
+
if (data.length < 5) throw new SyntaxError("vrpc: truncated decimal payload");
|
|
492
|
+
const dv = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
493
|
+
const exponent = dv.getInt32(0);
|
|
494
|
+
return new VrpcDecimal(bigIntGobDecode(data.subarray(4)), exponent);
|
|
495
|
+
}
|
|
496
|
+
return new VrpcExt(tag, data);
|
|
497
|
+
}
|
|
498
|
+
function readValue(r, depth) {
|
|
499
|
+
if (depth > r.limits.maxDepth) throw new RangeError("vrpc: msgpack nesting too deep");
|
|
500
|
+
const b = r.byte();
|
|
501
|
+
if (b <= 127) return b;
|
|
502
|
+
if (b >= 224) return b - 256;
|
|
503
|
+
if (b >= 160 && b <= 191) return utf8Decode(r.take(b & 31));
|
|
504
|
+
if (b >= 144 && b <= 159) return readList(r, b & 15, depth);
|
|
505
|
+
if (b >= 128 && b <= 143) return readMap(r, b & 15, depth);
|
|
506
|
+
switch (b) {
|
|
507
|
+
case 192:
|
|
508
|
+
return null;
|
|
509
|
+
case 194:
|
|
510
|
+
return false;
|
|
511
|
+
case 195:
|
|
512
|
+
return true;
|
|
513
|
+
case 196:
|
|
514
|
+
return r.take(r.u8());
|
|
515
|
+
case 197:
|
|
516
|
+
return r.take(r.u16());
|
|
517
|
+
case 198:
|
|
518
|
+
return r.take(r.u32());
|
|
519
|
+
case 199: {
|
|
520
|
+
const n = r.u8();
|
|
521
|
+
return decodeExt(r.byte(), r.take(n));
|
|
522
|
+
}
|
|
523
|
+
case 200: {
|
|
524
|
+
const n = r.u16();
|
|
525
|
+
return decodeExt(r.byte(), r.take(n));
|
|
526
|
+
}
|
|
527
|
+
case 201: {
|
|
528
|
+
const n = r.u32();
|
|
529
|
+
return decodeExt(r.byte(), r.take(n));
|
|
530
|
+
}
|
|
531
|
+
case 202:
|
|
532
|
+
return r.f32();
|
|
533
|
+
case 203:
|
|
534
|
+
return r.f64();
|
|
535
|
+
case 204:
|
|
536
|
+
return r.u8();
|
|
537
|
+
case 205:
|
|
538
|
+
return r.u16();
|
|
539
|
+
case 206:
|
|
540
|
+
return r.u32();
|
|
541
|
+
case 207:
|
|
542
|
+
return normalizeInt(r.u64());
|
|
543
|
+
case 208:
|
|
544
|
+
return r.i8();
|
|
545
|
+
case 209:
|
|
546
|
+
return r.i16();
|
|
547
|
+
case 210:
|
|
548
|
+
return r.i32();
|
|
549
|
+
case 211:
|
|
550
|
+
return normalizeInt(r.i64());
|
|
551
|
+
case 212:
|
|
552
|
+
return decodeExt(r.byte(), r.take(1));
|
|
553
|
+
case 213:
|
|
554
|
+
return decodeExt(r.byte(), r.take(2));
|
|
555
|
+
case 214:
|
|
556
|
+
return decodeExt(r.byte(), r.take(4));
|
|
557
|
+
case 215:
|
|
558
|
+
return decodeExt(r.byte(), r.take(8));
|
|
559
|
+
case 216:
|
|
560
|
+
return decodeExt(r.byte(), r.take(16));
|
|
561
|
+
case 217:
|
|
562
|
+
return utf8Decode(r.take(r.u8()));
|
|
563
|
+
case 218:
|
|
564
|
+
return utf8Decode(r.take(r.u16()));
|
|
565
|
+
case 219:
|
|
566
|
+
return utf8Decode(r.take(r.u32()));
|
|
567
|
+
case 220:
|
|
568
|
+
return readList(r, r.u16(), depth);
|
|
569
|
+
case 221:
|
|
570
|
+
return readList(r, r.u32(), depth);
|
|
571
|
+
case 222:
|
|
572
|
+
return readMap(r, r.u16(), depth);
|
|
573
|
+
case 223:
|
|
574
|
+
return readMap(r, r.u32(), depth);
|
|
575
|
+
default:
|
|
576
|
+
throw new SyntaxError(`vrpc: unsupported msgpack format 0x${b.toString(16)}`);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
function readList(r, n, depth) {
|
|
580
|
+
if (n > r.limits.maxCollectionLen) throw new RangeError(`vrpc: msgpack list length ${n} exceeds limit`);
|
|
581
|
+
const out = new Array(n);
|
|
582
|
+
for (let i = 0; i < n; i++) out[i] = readValue(r, depth + 1);
|
|
583
|
+
return out;
|
|
584
|
+
}
|
|
585
|
+
function readMap(r, n, depth) {
|
|
586
|
+
if (n > r.limits.maxCollectionLen) throw new RangeError(`vrpc: msgpack map length ${n} exceeds limit`);
|
|
587
|
+
const out = {};
|
|
588
|
+
for (let i = 0; i < n; i++) {
|
|
589
|
+
const key = readValue(r, depth + 1);
|
|
590
|
+
const val = readValue(r, depth + 1);
|
|
591
|
+
if (typeof key === "string") out[key] = val;
|
|
592
|
+
else if (typeof key === "number" || typeof key === "bigint") out[String(key)] = val;
|
|
593
|
+
else throw new SyntaxError("vrpc: unsupported msgpack map key type");
|
|
594
|
+
}
|
|
595
|
+
return out;
|
|
596
|
+
}
|
|
597
|
+
function msgpackDecode(data, limits = DEFAULT_LIMITS) {
|
|
598
|
+
const r = new Reader(data, limits);
|
|
599
|
+
const v = readValue(r, 0);
|
|
600
|
+
if (r.pos !== data.length) throw new SyntaxError("vrpc: trailing bytes after msgpack value");
|
|
601
|
+
return v;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// src/json.ts
|
|
605
|
+
var BASE64_PREFIX = "base64,";
|
|
606
|
+
var EXT_PREFIX = "data:application/x-msgpack-ext;";
|
|
607
|
+
var MAX_SAFE = 9007199254740991;
|
|
608
|
+
function writeValue(out, v, depth) {
|
|
609
|
+
if (depth > 512) throw new RangeError("vrpc: json nesting too deep");
|
|
610
|
+
if (v === null || v === void 0) {
|
|
611
|
+
out.push("null");
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
switch (typeof v) {
|
|
615
|
+
case "boolean":
|
|
616
|
+
out.push(v ? "true" : "false");
|
|
617
|
+
return;
|
|
618
|
+
case "number":
|
|
619
|
+
writeNumber(out, v);
|
|
620
|
+
return;
|
|
621
|
+
case "bigint":
|
|
622
|
+
if (v > BigInt(MAX_SAFE) || v < -BigInt(MAX_SAFE)) {
|
|
623
|
+
throw new RangeError(
|
|
624
|
+
`vrpc: bigint ${v} exceeds \xB12^53 and cannot travel exactly in JSON; use the msgpack codec or model it as a string`
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
out.push(v.toString());
|
|
628
|
+
return;
|
|
629
|
+
case "string":
|
|
630
|
+
out.push(JSON.stringify(v));
|
|
631
|
+
return;
|
|
632
|
+
case "object":
|
|
633
|
+
break;
|
|
634
|
+
default:
|
|
635
|
+
throw new TypeError(`vrpc: cannot encode ${typeof v} as a value`);
|
|
636
|
+
}
|
|
637
|
+
if (v instanceof Uint8Array) {
|
|
638
|
+
out.push(JSON.stringify(BASE64_PREFIX + base64RawStdEncode(v)));
|
|
639
|
+
} else if (v instanceof VrpcDouble) {
|
|
640
|
+
writeNumber(out, v.value, true);
|
|
641
|
+
} else if (v instanceof VrpcExt) {
|
|
642
|
+
const payload = new Uint8Array(1 + v.data.length);
|
|
643
|
+
payload[0] = v.tag;
|
|
644
|
+
payload.set(v.data, 1);
|
|
645
|
+
out.push(JSON.stringify(EXT_PREFIX + BASE64_PREFIX + base64RawStdEncode(payload)));
|
|
646
|
+
} else if (v instanceof VrpcDecimal) {
|
|
647
|
+
throw new TypeError(
|
|
648
|
+
"vrpc: VrpcDecimal does not round-trip through the JSON codec; use msgpack or model it as a string"
|
|
649
|
+
);
|
|
650
|
+
} else if (Array.isArray(v)) {
|
|
651
|
+
out.push("[");
|
|
652
|
+
for (let i = 0; i < v.length; i++) {
|
|
653
|
+
if (i > 0) out.push(",");
|
|
654
|
+
writeValue(out, v[i], depth + 1);
|
|
655
|
+
}
|
|
656
|
+
out.push("]");
|
|
657
|
+
} else if (v instanceof Map || isPlainObject(v)) {
|
|
658
|
+
const get = v instanceof Map ? (k) => v.get(k) : (k) => v[k];
|
|
659
|
+
const keys = (v instanceof Map ? [...v.keys()].map(String) : Object.keys(v)).filter((k) => get(k) !== void 0).sort(compareUtf8);
|
|
660
|
+
out.push("{");
|
|
661
|
+
for (let i = 0; i < keys.length; i++) {
|
|
662
|
+
if (i > 0) out.push(",");
|
|
663
|
+
out.push(JSON.stringify(keys[i]), ":");
|
|
664
|
+
writeValue(out, get(keys[i]), depth + 1);
|
|
665
|
+
}
|
|
666
|
+
out.push("}");
|
|
667
|
+
} else {
|
|
668
|
+
throw new TypeError(`vrpc: cannot encode ${v.constructor?.name ?? "object"} as a value`);
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
function writeNumber(out, v, forceDouble = false) {
|
|
672
|
+
if (!Number.isFinite(v)) {
|
|
673
|
+
out.push("null");
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
if (Number.isInteger(v) && !forceDouble && Math.abs(v) > MAX_SAFE) {
|
|
677
|
+
throw new RangeError(`vrpc: integer ${v} exceeds \xB12^53; use the msgpack codec with a bigint`);
|
|
678
|
+
}
|
|
679
|
+
out.push(Object.is(v, -0) ? "0" : String(v));
|
|
680
|
+
}
|
|
681
|
+
function jsonEncode(v) {
|
|
682
|
+
const out = [];
|
|
683
|
+
writeValue(out, v, 0);
|
|
684
|
+
return out.join("");
|
|
685
|
+
}
|
|
686
|
+
function reviveString(s) {
|
|
687
|
+
if (s.startsWith(EXT_PREFIX)) {
|
|
688
|
+
const rest = s.slice(EXT_PREFIX.length);
|
|
689
|
+
if (rest.startsWith(BASE64_PREFIX)) {
|
|
690
|
+
const payload = base64RawStdDecode(rest.slice(BASE64_PREFIX.length));
|
|
691
|
+
if (payload.length >= 1) {
|
|
692
|
+
return new VrpcExt(payload[0], payload.slice(1));
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
return s;
|
|
696
|
+
}
|
|
697
|
+
if (s.startsWith(BASE64_PREFIX)) {
|
|
698
|
+
try {
|
|
699
|
+
return base64RawStdDecode(s.slice(BASE64_PREFIX.length));
|
|
700
|
+
} catch {
|
|
701
|
+
return s;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
return s;
|
|
705
|
+
}
|
|
706
|
+
function reviveValue(v, depth, limits) {
|
|
707
|
+
if (depth > limits.maxDepth) throw new RangeError("vrpc: json nesting too deep");
|
|
708
|
+
if (v === null) return null;
|
|
709
|
+
switch (typeof v) {
|
|
710
|
+
case "boolean":
|
|
711
|
+
case "number":
|
|
712
|
+
return v;
|
|
713
|
+
case "string":
|
|
714
|
+
return reviveString(v);
|
|
715
|
+
case "object":
|
|
716
|
+
break;
|
|
717
|
+
default:
|
|
718
|
+
throw new SyntaxError(`vrpc: unsupported json value of type ${typeof v}`);
|
|
719
|
+
}
|
|
720
|
+
if (Array.isArray(v)) {
|
|
721
|
+
if (v.length > limits.maxCollectionLen) throw new RangeError("vrpc: json list too long");
|
|
722
|
+
return v.map((item) => reviveValue(item, depth + 1, limits));
|
|
723
|
+
}
|
|
724
|
+
const out = {};
|
|
725
|
+
const entries = Object.entries(v);
|
|
726
|
+
if (entries.length > limits.maxCollectionLen) throw new RangeError("vrpc: json map too large");
|
|
727
|
+
for (const [k, val] of entries) out[k] = reviveValue(val, depth + 1, limits);
|
|
728
|
+
return out;
|
|
729
|
+
}
|
|
730
|
+
function jsonDecode(text, limits = DEFAULT_LIMITS) {
|
|
731
|
+
return reviveValue(JSON.parse(text), 0, limits);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
// src/codec.ts
|
|
735
|
+
function assertMap(v, codec) {
|
|
736
|
+
if (v === null || typeof v !== "object" || Array.isArray(v) || v instanceof Uint8Array) {
|
|
737
|
+
throw new SyntaxError(`vrpc: expected a ${codec} map envelope`);
|
|
738
|
+
}
|
|
739
|
+
return v;
|
|
740
|
+
}
|
|
741
|
+
function msgpackCodec(limits = DEFAULT_LIMITS) {
|
|
742
|
+
return {
|
|
743
|
+
name: "msgpack",
|
|
744
|
+
subprotocols: [],
|
|
745
|
+
textFrames: false,
|
|
746
|
+
encode: (msg) => msgpackEncode(msg),
|
|
747
|
+
decode: (data) => {
|
|
748
|
+
if (typeof data === "string") {
|
|
749
|
+
throw new SyntaxError(
|
|
750
|
+
"vrpc: received a text frame on a msgpack connection; JSON was not negotiated (offer subprotocol vrpc.json)"
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
return assertMap(msgpackDecode(data, limits), "msgpack");
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
function jsonCodec(limits = DEFAULT_LIMITS) {
|
|
758
|
+
return {
|
|
759
|
+
name: "json",
|
|
760
|
+
subprotocols: ["vrpc.json"],
|
|
761
|
+
textFrames: true,
|
|
762
|
+
encode: (msg) => jsonEncode(msg),
|
|
763
|
+
decode: (data) => {
|
|
764
|
+
if (typeof data !== "string") {
|
|
765
|
+
throw new SyntaxError("vrpc: received a binary frame on a JSON connection");
|
|
766
|
+
}
|
|
767
|
+
return assertMap(jsonDecode(data, limits), "json");
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
function codecByName(name, limits) {
|
|
772
|
+
return name === "json" ? jsonCodec(limits) : msgpackCodec(limits);
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// src/errors.ts
|
|
776
|
+
var Code = /* @__PURE__ */ ((Code2) => {
|
|
777
|
+
Code2[Code2["OK"] = 0] = "OK";
|
|
778
|
+
Code2[Code2["Unknown"] = 1] = "Unknown";
|
|
779
|
+
Code2[Code2["Canceled"] = 2] = "Canceled";
|
|
780
|
+
Code2[Code2["InvalidArgument"] = 3] = "InvalidArgument";
|
|
781
|
+
Code2[Code2["DeadlineExceeded"] = 4] = "DeadlineExceeded";
|
|
782
|
+
Code2[Code2["NotFound"] = 5] = "NotFound";
|
|
783
|
+
Code2[Code2["ResourceExhausted"] = 6] = "ResourceExhausted";
|
|
784
|
+
Code2[Code2["Unavailable"] = 7] = "Unavailable";
|
|
785
|
+
Code2[Code2["Unauthenticated"] = 8] = "Unauthenticated";
|
|
786
|
+
Code2[Code2["Internal"] = 9] = "Internal";
|
|
787
|
+
return Code2;
|
|
788
|
+
})(Code || {});
|
|
789
|
+
var CODE_NAMES = {
|
|
790
|
+
[0 /* OK */]: "OK",
|
|
791
|
+
[1 /* Unknown */]: "Unknown",
|
|
792
|
+
[2 /* Canceled */]: "Canceled",
|
|
793
|
+
[3 /* InvalidArgument */]: "InvalidArgument",
|
|
794
|
+
[4 /* DeadlineExceeded */]: "DeadlineExceeded",
|
|
795
|
+
[5 /* NotFound */]: "NotFound",
|
|
796
|
+
[6 /* ResourceExhausted */]: "ResourceExhausted",
|
|
797
|
+
[7 /* Unavailable */]: "Unavailable",
|
|
798
|
+
[8 /* Unauthenticated */]: "Unauthenticated",
|
|
799
|
+
[9 /* Internal */]: "Internal"
|
|
800
|
+
};
|
|
801
|
+
function codeName(code) {
|
|
802
|
+
return CODE_NAMES[code] ?? "Unknown";
|
|
803
|
+
}
|
|
804
|
+
var VrpcError = class extends Error {
|
|
805
|
+
constructor(code, message, options) {
|
|
806
|
+
super(`vrpc ${codeName(code)}: ${message}`, options);
|
|
807
|
+
this.code = code;
|
|
808
|
+
}
|
|
809
|
+
code;
|
|
810
|
+
name = "VrpcError";
|
|
811
|
+
/** The message without the "vrpc <Code>: " prefix. */
|
|
812
|
+
get detail() {
|
|
813
|
+
return this.message.replace(/^vrpc [A-Za-z]+: /, "");
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
function codeOf(err) {
|
|
817
|
+
if (err == null) return 0 /* OK */;
|
|
818
|
+
if (err instanceof VrpcError) return err.code;
|
|
819
|
+
return 1 /* Unknown */;
|
|
820
|
+
}
|
|
821
|
+
function errConnectionLost() {
|
|
822
|
+
return new VrpcError(7 /* Unavailable */, "connection lost");
|
|
823
|
+
}
|
|
824
|
+
function errClientClosed() {
|
|
825
|
+
return new VrpcError(7 /* Unavailable */, "client closed");
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// src/hashchain.ts
|
|
829
|
+
var HashChain = class _HashChain {
|
|
830
|
+
constructor(links, next) {
|
|
831
|
+
this.links = links;
|
|
832
|
+
this.next = next;
|
|
833
|
+
}
|
|
834
|
+
links;
|
|
835
|
+
next;
|
|
836
|
+
static DEFAULT_LENGTH = 1024;
|
|
837
|
+
static async create(n = _HashChain.DEFAULT_LENGTH) {
|
|
838
|
+
if (n <= 0) n = _HashChain.DEFAULT_LENGTH;
|
|
839
|
+
const links = new Array(n + 1);
|
|
840
|
+
const seed = new Uint8Array(32);
|
|
841
|
+
crypto.getRandomValues(seed);
|
|
842
|
+
links[0] = seed;
|
|
843
|
+
for (let i = 1; i <= n; i++) {
|
|
844
|
+
const digest = await crypto.subtle.digest("SHA-256", links[i - 1]);
|
|
845
|
+
links[i] = new Uint8Array(digest);
|
|
846
|
+
}
|
|
847
|
+
return new _HashChain(links, n - 1);
|
|
848
|
+
}
|
|
849
|
+
/** The public commitment h[N], hex-encoded. Resending it consumes nothing. */
|
|
850
|
+
anchor() {
|
|
851
|
+
return bytesToHex(this.links[this.links.length - 1]);
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* Reveals the next one-time resumption token and advances. Returns "" when
|
|
855
|
+
* the chain is exhausted and a fresh session is required.
|
|
856
|
+
*/
|
|
857
|
+
nextToken() {
|
|
858
|
+
if (this.next < 0) return "";
|
|
859
|
+
const tok = bytesToHex(this.links[this.next]);
|
|
860
|
+
this.next--;
|
|
861
|
+
return tok;
|
|
862
|
+
}
|
|
863
|
+
remaining() {
|
|
864
|
+
return this.next + 1;
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
|
|
868
|
+
// src/protocol.ts
|
|
869
|
+
var MessageType = /* @__PURE__ */ ((MessageType2) => {
|
|
870
|
+
MessageType2[MessageType2["HandshakeRequest"] = 0] = "HandshakeRequest";
|
|
871
|
+
MessageType2[MessageType2["HandshakeResponse"] = 1] = "HandshakeResponse";
|
|
872
|
+
MessageType2[MessageType2["FunctionRequest"] = 2] = "FunctionRequest";
|
|
873
|
+
MessageType2[MessageType2["FunctionResponse"] = 3] = "FunctionResponse";
|
|
874
|
+
MessageType2[MessageType2["GetStreamRequest"] = 4] = "GetStreamRequest";
|
|
875
|
+
MessageType2[MessageType2["PutStreamRequest"] = 5] = "PutStreamRequest";
|
|
876
|
+
MessageType2[MessageType2["ChatRequest"] = 6] = "ChatRequest";
|
|
877
|
+
MessageType2[MessageType2["ErrorResponse"] = 7] = "ErrorResponse";
|
|
878
|
+
MessageType2[MessageType2["StreamReady"] = 8] = "StreamReady";
|
|
879
|
+
MessageType2[MessageType2["StreamValue"] = 9] = "StreamValue";
|
|
880
|
+
MessageType2[MessageType2["StreamEnd"] = 10] = "StreamEnd";
|
|
881
|
+
MessageType2[MessageType2["CancelRequest"] = 11] = "CancelRequest";
|
|
882
|
+
MessageType2[MessageType2["StreamCredit"] = 14] = "StreamCredit";
|
|
883
|
+
return MessageType2;
|
|
884
|
+
})(MessageType || {});
|
|
885
|
+
function newDialect() {
|
|
886
|
+
return {
|
|
887
|
+
magic: "vRPC",
|
|
888
|
+
version: 1,
|
|
889
|
+
handshakeRequestId: 0,
|
|
890
|
+
messageTypeField: "t",
|
|
891
|
+
magicField: "m",
|
|
892
|
+
versionField: "v",
|
|
893
|
+
requestIdField: "rid",
|
|
894
|
+
timeoutField: "sla",
|
|
895
|
+
clientIdField: "cid",
|
|
896
|
+
sessionTokenField: "tok",
|
|
897
|
+
authField: "auth",
|
|
898
|
+
functionNameField: "fn",
|
|
899
|
+
argumentsField: "args",
|
|
900
|
+
resultField: "res",
|
|
901
|
+
errorField: "err",
|
|
902
|
+
codeField: "code",
|
|
903
|
+
creditField: "cr",
|
|
904
|
+
metadataField: "md",
|
|
905
|
+
valueField: "val"
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
var Protocol = class {
|
|
909
|
+
constructor(d) {
|
|
910
|
+
this.d = d;
|
|
911
|
+
}
|
|
912
|
+
d;
|
|
913
|
+
handshakeRequest(clientId, token, auth) {
|
|
914
|
+
const req = {
|
|
915
|
+
[this.d.magicField]: this.d.magic,
|
|
916
|
+
// Sent as a DOUBLE like the Go client (value.Double(1.0)); the server
|
|
917
|
+
// accepts any NUMBER <= its version.
|
|
918
|
+
[this.d.versionField]: new VrpcDouble(this.d.version),
|
|
919
|
+
[this.d.messageTypeField]: 0 /* HandshakeRequest */,
|
|
920
|
+
[this.d.requestIdField]: this.d.handshakeRequestId,
|
|
921
|
+
[this.d.clientIdField]: clientId
|
|
922
|
+
};
|
|
923
|
+
if (token !== "") req[this.d.sessionTokenField] = token;
|
|
924
|
+
if (auth !== void 0 && auth !== null) req[this.d.authField] = auth;
|
|
925
|
+
return req;
|
|
926
|
+
}
|
|
927
|
+
request(mt, requestId, name, args, timeoutMs, metadata) {
|
|
928
|
+
const req = {
|
|
929
|
+
[this.d.messageTypeField]: mt,
|
|
930
|
+
[this.d.requestIdField]: requestId,
|
|
931
|
+
[this.d.functionNameField]: name
|
|
932
|
+
};
|
|
933
|
+
if (args !== void 0) req[this.d.argumentsField] = args;
|
|
934
|
+
if (timeoutMs > 0) req[this.d.timeoutField] = Math.floor(timeoutMs);
|
|
935
|
+
if (metadata && Object.keys(metadata).length > 0) {
|
|
936
|
+
req[this.d.metadataField] = { ...metadata };
|
|
937
|
+
}
|
|
938
|
+
return req;
|
|
939
|
+
}
|
|
940
|
+
functionResult(requestId, result) {
|
|
941
|
+
const resp = {
|
|
942
|
+
[this.d.messageTypeField]: 3 /* FunctionResponse */,
|
|
943
|
+
[this.d.requestIdField]: requestId
|
|
944
|
+
};
|
|
945
|
+
if (result !== null && result !== void 0) resp[this.d.resultField] = result;
|
|
946
|
+
return resp;
|
|
947
|
+
}
|
|
948
|
+
errorResponse(requestId, code, message) {
|
|
949
|
+
return {
|
|
950
|
+
[this.d.messageTypeField]: 7 /* ErrorResponse */,
|
|
951
|
+
[this.d.requestIdField]: requestId,
|
|
952
|
+
[this.d.codeField]: code,
|
|
953
|
+
[this.d.errorField]: message
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
streamReady(requestId) {
|
|
957
|
+
return {
|
|
958
|
+
[this.d.messageTypeField]: 8 /* StreamReady */,
|
|
959
|
+
[this.d.requestIdField]: requestId
|
|
960
|
+
};
|
|
961
|
+
}
|
|
962
|
+
streamValue(requestId, value) {
|
|
963
|
+
return {
|
|
964
|
+
[this.d.messageTypeField]: 9 /* StreamValue */,
|
|
965
|
+
[this.d.requestIdField]: requestId,
|
|
966
|
+
[this.d.valueField]: value
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
streamEnd(requestId, value) {
|
|
970
|
+
const resp = {
|
|
971
|
+
[this.d.messageTypeField]: 10 /* StreamEnd */,
|
|
972
|
+
[this.d.requestIdField]: requestId
|
|
973
|
+
};
|
|
974
|
+
if (value !== void 0 && value !== null) resp[this.d.valueField] = value;
|
|
975
|
+
return resp;
|
|
976
|
+
}
|
|
977
|
+
streamCredit(requestId, credit) {
|
|
978
|
+
return {
|
|
979
|
+
[this.d.messageTypeField]: 14 /* StreamCredit */,
|
|
980
|
+
[this.d.requestIdField]: requestId,
|
|
981
|
+
[this.d.creditField]: credit
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
cancelRequest(requestId) {
|
|
985
|
+
return {
|
|
986
|
+
[this.d.messageTypeField]: 11 /* CancelRequest */,
|
|
987
|
+
[this.d.requestIdField]: requestId
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
// --- field accessors (absent or wrong-typed fields return undefined) ---
|
|
991
|
+
messageType(msg) {
|
|
992
|
+
return asIntField(msg[this.d.messageTypeField]);
|
|
993
|
+
}
|
|
994
|
+
requestId(msg) {
|
|
995
|
+
return asIntField(msg[this.d.requestIdField]);
|
|
996
|
+
}
|
|
997
|
+
functionName(msg) {
|
|
998
|
+
const v = msg[this.d.functionNameField];
|
|
999
|
+
return typeof v === "string" ? v : void 0;
|
|
1000
|
+
}
|
|
1001
|
+
args(msg) {
|
|
1002
|
+
return msg[this.d.argumentsField] ?? null;
|
|
1003
|
+
}
|
|
1004
|
+
result(msg) {
|
|
1005
|
+
return msg[this.d.resultField] ?? null;
|
|
1006
|
+
}
|
|
1007
|
+
streamVal(msg) {
|
|
1008
|
+
return msg[this.d.valueField] ?? null;
|
|
1009
|
+
}
|
|
1010
|
+
credit(msg) {
|
|
1011
|
+
return asIntField(msg[this.d.creditField]);
|
|
1012
|
+
}
|
|
1013
|
+
errorOf(msg) {
|
|
1014
|
+
const code = asIntField(msg[this.d.codeField]) ?? 1 /* Unknown */;
|
|
1015
|
+
const err = msg[this.d.errorField];
|
|
1016
|
+
return { code, message: typeof err === "string" ? err : "" };
|
|
1017
|
+
}
|
|
1018
|
+
metadata(msg) {
|
|
1019
|
+
const v = msg[this.d.metadataField];
|
|
1020
|
+
if (v === null || v === void 0 || typeof v !== "object" || Array.isArray(v) || v instanceof Uint8Array) {
|
|
1021
|
+
return void 0;
|
|
1022
|
+
}
|
|
1023
|
+
const out = {};
|
|
1024
|
+
let any = false;
|
|
1025
|
+
for (const [k, val] of Object.entries(v)) {
|
|
1026
|
+
if (typeof val === "string") {
|
|
1027
|
+
out[k] = val;
|
|
1028
|
+
any = true;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
return any ? out : void 0;
|
|
1032
|
+
}
|
|
1033
|
+
};
|
|
1034
|
+
function asIntField(v) {
|
|
1035
|
+
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
1036
|
+
if (typeof v === "bigint") return Number(v);
|
|
1037
|
+
return void 0;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
// src/transport.ts
|
|
1041
|
+
var webSocketDialer = (opts) => {
|
|
1042
|
+
return new Promise((resolve, reject) => {
|
|
1043
|
+
const WS = opts.webSocket ?? globalThis.WebSocket;
|
|
1044
|
+
if (typeof WS !== "function") {
|
|
1045
|
+
reject(
|
|
1046
|
+
new VrpcError(
|
|
1047
|
+
9 /* Internal */,
|
|
1048
|
+
"no WebSocket implementation available; pass one via the webSocket option"
|
|
1049
|
+
)
|
|
1050
|
+
);
|
|
1051
|
+
return;
|
|
1052
|
+
}
|
|
1053
|
+
let ws;
|
|
1054
|
+
try {
|
|
1055
|
+
ws = opts.subprotocols.length > 0 ? new WS(opts.url, opts.subprotocols) : new WS(opts.url);
|
|
1056
|
+
} catch (err) {
|
|
1057
|
+
reject(new VrpcError(7 /* Unavailable */, `websocket dial failed: ${String(err)}`, { cause: err }));
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
ws.binaryType = "arraybuffer";
|
|
1061
|
+
let settled = false;
|
|
1062
|
+
const timer = setTimeout(() => {
|
|
1063
|
+
if (settled) return;
|
|
1064
|
+
settled = true;
|
|
1065
|
+
ws.close();
|
|
1066
|
+
reject(new VrpcError(4 /* DeadlineExceeded */, `websocket dial timed out after ${opts.timeoutMs}ms`));
|
|
1067
|
+
}, opts.timeoutMs);
|
|
1068
|
+
ws.onopen = () => {
|
|
1069
|
+
if (settled) return;
|
|
1070
|
+
settled = true;
|
|
1071
|
+
clearTimeout(timer);
|
|
1072
|
+
if (opts.subprotocols.length > 0 && !opts.subprotocols.includes(ws.protocol)) {
|
|
1073
|
+
ws.close();
|
|
1074
|
+
reject(
|
|
1075
|
+
new VrpcError(
|
|
1076
|
+
7 /* Unavailable */,
|
|
1077
|
+
`server did not accept subprotocol ${opts.subprotocols.join("/")} (got ${JSON.stringify(
|
|
1078
|
+
ws.protocol
|
|
1079
|
+
)}); it likely predates JSON codec support \u2014 use codec: "msgpack"`
|
|
1080
|
+
)
|
|
1081
|
+
);
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
resolve(wrap(ws));
|
|
1085
|
+
};
|
|
1086
|
+
ws.onerror = () => {
|
|
1087
|
+
if (settled) return;
|
|
1088
|
+
settled = true;
|
|
1089
|
+
clearTimeout(timer);
|
|
1090
|
+
reject(new VrpcError(7 /* Unavailable */, `websocket dial failed: ${opts.url}`));
|
|
1091
|
+
};
|
|
1092
|
+
ws.onclose = (ev) => {
|
|
1093
|
+
if (settled) return;
|
|
1094
|
+
settled = true;
|
|
1095
|
+
clearTimeout(timer);
|
|
1096
|
+
reject(
|
|
1097
|
+
new VrpcError(
|
|
1098
|
+
7 /* Unavailable */,
|
|
1099
|
+
`websocket closed during dial (code ${ev.code}${ev.reason ? `, ${ev.reason}` : ""})`
|
|
1100
|
+
)
|
|
1101
|
+
);
|
|
1102
|
+
};
|
|
1103
|
+
});
|
|
1104
|
+
};
|
|
1105
|
+
function wrap(ws) {
|
|
1106
|
+
let onMessageCb = null;
|
|
1107
|
+
const early = [];
|
|
1108
|
+
const deliver = (d) => {
|
|
1109
|
+
if (onMessageCb) onMessageCb(d);
|
|
1110
|
+
else early.push(d);
|
|
1111
|
+
};
|
|
1112
|
+
const t = {
|
|
1113
|
+
send(data) {
|
|
1114
|
+
ws.send(data);
|
|
1115
|
+
},
|
|
1116
|
+
close() {
|
|
1117
|
+
ws.onclose = null;
|
|
1118
|
+
ws.onerror = null;
|
|
1119
|
+
ws.onmessage = null;
|
|
1120
|
+
try {
|
|
1121
|
+
ws.close(1e3);
|
|
1122
|
+
} catch {
|
|
1123
|
+
}
|
|
1124
|
+
},
|
|
1125
|
+
get onMessage() {
|
|
1126
|
+
return onMessageCb;
|
|
1127
|
+
},
|
|
1128
|
+
set onMessage(cb) {
|
|
1129
|
+
onMessageCb = cb;
|
|
1130
|
+
if (cb && early.length > 0) {
|
|
1131
|
+
const queued = early.splice(0, early.length);
|
|
1132
|
+
for (const d of queued) cb(d);
|
|
1133
|
+
}
|
|
1134
|
+
},
|
|
1135
|
+
onClose: null
|
|
1136
|
+
};
|
|
1137
|
+
let closed = false;
|
|
1138
|
+
const fireClose = (err) => {
|
|
1139
|
+
if (closed) return;
|
|
1140
|
+
closed = true;
|
|
1141
|
+
t.onClose?.(err);
|
|
1142
|
+
};
|
|
1143
|
+
ws.onmessage = (ev) => {
|
|
1144
|
+
const data = ev.data;
|
|
1145
|
+
if (typeof data === "string") deliver(data);
|
|
1146
|
+
else if (data instanceof ArrayBuffer) deliver(new Uint8Array(data));
|
|
1147
|
+
else if (ArrayBuffer.isView(data)) {
|
|
1148
|
+
const view = data;
|
|
1149
|
+
deliver(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));
|
|
1150
|
+
}
|
|
1151
|
+
};
|
|
1152
|
+
ws.onclose = (ev) => {
|
|
1153
|
+
fireClose(
|
|
1154
|
+
ev.wasClean && ev.code === 1e3 ? void 0 : new VrpcError(7 /* Unavailable */, `websocket closed (code ${ev.code}${ev.reason ? `, ${ev.reason}` : ""})`)
|
|
1155
|
+
);
|
|
1156
|
+
};
|
|
1157
|
+
ws.onerror = () => {
|
|
1158
|
+
fireClose(new VrpcError(7 /* Unavailable */, "websocket error"));
|
|
1159
|
+
};
|
|
1160
|
+
return t;
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
// src/internal/async.ts
|
|
1164
|
+
function deferred() {
|
|
1165
|
+
let resolve;
|
|
1166
|
+
let reject;
|
|
1167
|
+
const promise = new Promise((res, rej) => {
|
|
1168
|
+
resolve = res;
|
|
1169
|
+
reject = rej;
|
|
1170
|
+
});
|
|
1171
|
+
return { promise, resolve, reject };
|
|
1172
|
+
}
|
|
1173
|
+
var CreditGate = class {
|
|
1174
|
+
credit = 0;
|
|
1175
|
+
closed = false;
|
|
1176
|
+
waiters = [];
|
|
1177
|
+
acquire() {
|
|
1178
|
+
if (this.closed) return Promise.resolve(false);
|
|
1179
|
+
if (this.credit > 0) {
|
|
1180
|
+
this.credit--;
|
|
1181
|
+
return Promise.resolve(true);
|
|
1182
|
+
}
|
|
1183
|
+
const d = deferred();
|
|
1184
|
+
this.waiters.push(d);
|
|
1185
|
+
return d.promise;
|
|
1186
|
+
}
|
|
1187
|
+
grant(n) {
|
|
1188
|
+
if (n <= 0 || this.closed) return;
|
|
1189
|
+
this.credit += n;
|
|
1190
|
+
while (this.credit > 0 && this.waiters.length > 0) {
|
|
1191
|
+
this.credit--;
|
|
1192
|
+
this.waiters.shift().resolve(true);
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
close() {
|
|
1196
|
+
if (this.closed) return;
|
|
1197
|
+
this.closed = true;
|
|
1198
|
+
for (const w of this.waiters) w.resolve(false);
|
|
1199
|
+
this.waiters = [];
|
|
1200
|
+
}
|
|
1201
|
+
};
|
|
1202
|
+
var AsyncValueQueue = class {
|
|
1203
|
+
constructor(maxPending, onConsume) {
|
|
1204
|
+
this.maxPending = maxPending;
|
|
1205
|
+
this.onConsume = onConsume;
|
|
1206
|
+
}
|
|
1207
|
+
maxPending;
|
|
1208
|
+
onConsume;
|
|
1209
|
+
buf = [];
|
|
1210
|
+
waiter = null;
|
|
1211
|
+
ended = false;
|
|
1212
|
+
failure = null;
|
|
1213
|
+
/** Queues a value; false means the queue is finished or overflowed. */
|
|
1214
|
+
push(v) {
|
|
1215
|
+
if (this.ended) return false;
|
|
1216
|
+
if (this.waiter) {
|
|
1217
|
+
const w = this.waiter;
|
|
1218
|
+
this.waiter = null;
|
|
1219
|
+
w.resolve({ value: v, done: false });
|
|
1220
|
+
this.onConsume?.();
|
|
1221
|
+
return true;
|
|
1222
|
+
}
|
|
1223
|
+
if (this.buf.length >= this.maxPending) return false;
|
|
1224
|
+
this.buf.push(v);
|
|
1225
|
+
return true;
|
|
1226
|
+
}
|
|
1227
|
+
/** Graceful end-of-stream: buffered values still drain to the consumer. */
|
|
1228
|
+
end() {
|
|
1229
|
+
if (this.ended) return;
|
|
1230
|
+
this.ended = true;
|
|
1231
|
+
if (this.waiter && this.buf.length === 0) {
|
|
1232
|
+
const w = this.waiter;
|
|
1233
|
+
this.waiter = null;
|
|
1234
|
+
if (this.failure != null) w.reject(this.failure);
|
|
1235
|
+
else w.resolve({ value: void 0, done: true });
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
/** Ends the stream with an error; buffered values still drain first. */
|
|
1239
|
+
fail(err) {
|
|
1240
|
+
if (this.ended) return;
|
|
1241
|
+
this.failure = err;
|
|
1242
|
+
this.end();
|
|
1243
|
+
}
|
|
1244
|
+
/** Hard stop: discards buffered values and ends immediately. */
|
|
1245
|
+
abort(err) {
|
|
1246
|
+
this.buf = [];
|
|
1247
|
+
if (this.ended && !this.waiter) return;
|
|
1248
|
+
this.ended = true;
|
|
1249
|
+
if (err !== void 0) this.failure = err;
|
|
1250
|
+
if (this.waiter) {
|
|
1251
|
+
const w = this.waiter;
|
|
1252
|
+
this.waiter = null;
|
|
1253
|
+
if (this.failure != null) w.reject(this.failure);
|
|
1254
|
+
else w.resolve({ value: void 0, done: true });
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
get isEnded() {
|
|
1258
|
+
return this.ended;
|
|
1259
|
+
}
|
|
1260
|
+
next() {
|
|
1261
|
+
if (this.buf.length > 0) {
|
|
1262
|
+
const v = this.buf.shift();
|
|
1263
|
+
this.onConsume?.();
|
|
1264
|
+
return Promise.resolve({ value: v, done: false });
|
|
1265
|
+
}
|
|
1266
|
+
if (this.ended) {
|
|
1267
|
+
return this.failure != null ? Promise.reject(this.failure) : Promise.resolve({ value: void 0, done: true });
|
|
1268
|
+
}
|
|
1269
|
+
if (this.waiter) {
|
|
1270
|
+
return Promise.reject(new Error("vrpc: concurrent reads from a single stream consumer"));
|
|
1271
|
+
}
|
|
1272
|
+
this.waiter = deferred();
|
|
1273
|
+
return this.waiter.promise;
|
|
1274
|
+
}
|
|
1275
|
+
};
|
|
1276
|
+
function backoffDelay(attempt, opts) {
|
|
1277
|
+
let delay = opts.initialDelayMs * 2 ** Math.max(0, attempt - 1);
|
|
1278
|
+
if (delay > opts.maxDelayMs) delay = opts.maxDelayMs;
|
|
1279
|
+
if (opts.jitter) delay = delay / 2 + Math.random() * (delay / 2);
|
|
1280
|
+
return Math.round(delay);
|
|
1281
|
+
}
|
|
1282
|
+
function sleep(ms, signal) {
|
|
1283
|
+
return new Promise((resolve) => {
|
|
1284
|
+
if (signal?.aborted) return resolve();
|
|
1285
|
+
const t = setTimeout(done, ms);
|
|
1286
|
+
function done() {
|
|
1287
|
+
clearTimeout(t);
|
|
1288
|
+
signal?.removeEventListener("abort", done);
|
|
1289
|
+
resolve();
|
|
1290
|
+
}
|
|
1291
|
+
signal?.addEventListener("abort", done, { once: true });
|
|
1292
|
+
});
|
|
1293
|
+
}
|
|
1294
|
+
function randomClientId() {
|
|
1295
|
+
const a = new Uint32Array(2);
|
|
1296
|
+
crypto.getRandomValues(a);
|
|
1297
|
+
const id = a[0] % 2097152 * 4294967296 + a[1];
|
|
1298
|
+
return id === 0 ? 1 : id;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
// src/client.ts
|
|
1302
|
+
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
1303
|
+
var DEFAULT_CONNECT_TIMEOUT_MS = 1e4;
|
|
1304
|
+
var DEFAULT_MAX_PENDING = 4096;
|
|
1305
|
+
var PendingRequest = class {
|
|
1306
|
+
constructor(requestId, kind, name, window2) {
|
|
1307
|
+
this.requestId = requestId;
|
|
1308
|
+
this.kind = kind;
|
|
1309
|
+
this.name = name;
|
|
1310
|
+
this.window = window2;
|
|
1311
|
+
if (kind === "unary") this.unary = deferred();
|
|
1312
|
+
if (kind === "get" || kind === "chat") this.queue = new AsyncValueQueue(window2, () => this.onConsume?.());
|
|
1313
|
+
if (kind === "put" || kind === "chat") this.sendCredit = new CreditGate();
|
|
1314
|
+
this.ready.promise.catch(() => {
|
|
1315
|
+
});
|
|
1316
|
+
this.unary?.promise.catch(() => {
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
requestId;
|
|
1320
|
+
kind;
|
|
1321
|
+
name;
|
|
1322
|
+
window;
|
|
1323
|
+
ready = deferred();
|
|
1324
|
+
queue = null;
|
|
1325
|
+
sendCredit = null;
|
|
1326
|
+
unary = null;
|
|
1327
|
+
timer = null;
|
|
1328
|
+
error = null;
|
|
1329
|
+
getClosed = false;
|
|
1330
|
+
putClosed = false;
|
|
1331
|
+
delivered = 0;
|
|
1332
|
+
onConsume = null;
|
|
1333
|
+
fail(err) {
|
|
1334
|
+
this.error = err;
|
|
1335
|
+
this.ready.reject(err);
|
|
1336
|
+
this.unary?.reject(err);
|
|
1337
|
+
this.queue?.fail(err);
|
|
1338
|
+
this.sendCredit?.close();
|
|
1339
|
+
this.getClosed = true;
|
|
1340
|
+
this.putClosed = true;
|
|
1341
|
+
if (this.timer) clearTimeout(this.timer);
|
|
1342
|
+
}
|
|
1343
|
+
/** Graceful teardown without an error (server cancel / normal close). */
|
|
1344
|
+
finish() {
|
|
1345
|
+
this.ready.reject(this.error ?? new VrpcError(2 /* Canceled */, `request ${this.requestId} closed`));
|
|
1346
|
+
this.unary?.reject(this.error ?? new VrpcError(2 /* Canceled */, `request ${this.requestId} closed`));
|
|
1347
|
+
this.queue?.end();
|
|
1348
|
+
this.sendCredit?.close();
|
|
1349
|
+
this.getClosed = true;
|
|
1350
|
+
this.putClosed = true;
|
|
1351
|
+
if (this.timer) clearTimeout(this.timer);
|
|
1352
|
+
}
|
|
1353
|
+
};
|
|
1354
|
+
var ServingRequest = class {
|
|
1355
|
+
constructor(requestId, kind, window2) {
|
|
1356
|
+
this.requestId = requestId;
|
|
1357
|
+
this.kind = kind;
|
|
1358
|
+
this.window = window2;
|
|
1359
|
+
if (kind === "in" || kind === "chat") {
|
|
1360
|
+
this.inQueue = new AsyncValueQueue(window2, () => this.onConsume?.());
|
|
1361
|
+
}
|
|
1362
|
+
if (kind === "out" || kind === "chat") this.sendCredit = new CreditGate();
|
|
1363
|
+
}
|
|
1364
|
+
requestId;
|
|
1365
|
+
kind;
|
|
1366
|
+
window;
|
|
1367
|
+
inQueue = null;
|
|
1368
|
+
sendCredit = null;
|
|
1369
|
+
abort = new AbortController();
|
|
1370
|
+
delivered = 0;
|
|
1371
|
+
closed = false;
|
|
1372
|
+
onConsume = null;
|
|
1373
|
+
close() {
|
|
1374
|
+
if (this.closed) return;
|
|
1375
|
+
this.closed = true;
|
|
1376
|
+
this.abort.abort();
|
|
1377
|
+
this.sendCredit?.close();
|
|
1378
|
+
this.inQueue?.abort();
|
|
1379
|
+
}
|
|
1380
|
+
};
|
|
1381
|
+
var VrpcClient = class {
|
|
1382
|
+
protocol;
|
|
1383
|
+
codec;
|
|
1384
|
+
opts;
|
|
1385
|
+
reconnect;
|
|
1386
|
+
timeoutMs;
|
|
1387
|
+
connectTimeoutMs;
|
|
1388
|
+
maxPending;
|
|
1389
|
+
dialer;
|
|
1390
|
+
_status = "idle";
|
|
1391
|
+
_clientId = randomClientId();
|
|
1392
|
+
transport = null;
|
|
1393
|
+
chain = null;
|
|
1394
|
+
established = false;
|
|
1395
|
+
nextRequestId = 0;
|
|
1396
|
+
reconnects = 0;
|
|
1397
|
+
pending = /* @__PURE__ */ new Map();
|
|
1398
|
+
serving = /* @__PURE__ */ new Map();
|
|
1399
|
+
handlers = /* @__PURE__ */ new Map();
|
|
1400
|
+
listeners = /* @__PURE__ */ new Map();
|
|
1401
|
+
connectPromise = null;
|
|
1402
|
+
resumeAbort = null;
|
|
1403
|
+
openWaiters = [];
|
|
1404
|
+
handshakeWaiter = null;
|
|
1405
|
+
handshakeTransport = null;
|
|
1406
|
+
hintsInstalled = false;
|
|
1407
|
+
constructor(options) {
|
|
1408
|
+
this.opts = options;
|
|
1409
|
+
this.codec = typeof options.codec === "object" ? options.codec : codecByName(options.codec ?? "msgpack");
|
|
1410
|
+
this.protocol = new Protocol({ ...newDialect(), ...options.dialect });
|
|
1411
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
1412
|
+
this.connectTimeoutMs = options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
|
|
1413
|
+
this.maxPending = options.maxPending ?? DEFAULT_MAX_PENDING;
|
|
1414
|
+
this.dialer = options.dialer ?? webSocketDialer;
|
|
1415
|
+
const rc = options.reconnect;
|
|
1416
|
+
this.reconnect = {
|
|
1417
|
+
enabled: rc === false ? false : (rc === true || rc === void 0 ? void 0 : rc.enabled) ?? true,
|
|
1418
|
+
initialDelayMs: typeof rc === "object" && rc.initialDelayMs || 300,
|
|
1419
|
+
maxDelayMs: typeof rc === "object" && rc.maxDelayMs || 1e4,
|
|
1420
|
+
maxAttempts: typeof rc === "object" && rc.maxAttempts || Infinity,
|
|
1421
|
+
jitter: typeof rc === "object" ? rc.jitter ?? true : true
|
|
1422
|
+
};
|
|
1423
|
+
}
|
|
1424
|
+
get status() {
|
|
1425
|
+
return this._status;
|
|
1426
|
+
}
|
|
1427
|
+
get connected() {
|
|
1428
|
+
return this._status === "open";
|
|
1429
|
+
}
|
|
1430
|
+
get clientId() {
|
|
1431
|
+
return this._clientId;
|
|
1432
|
+
}
|
|
1433
|
+
get codecName() {
|
|
1434
|
+
return this.codec.name;
|
|
1435
|
+
}
|
|
1436
|
+
stats() {
|
|
1437
|
+
return {
|
|
1438
|
+
requests: this.nextRequestId,
|
|
1439
|
+
reconnects: this.reconnects,
|
|
1440
|
+
pending: this.pending.size,
|
|
1441
|
+
serving: this.serving.size
|
|
1442
|
+
};
|
|
1443
|
+
}
|
|
1444
|
+
// ------------------------------------------------------------------ events
|
|
1445
|
+
on(event, fn) {
|
|
1446
|
+
let set = this.listeners.get(event);
|
|
1447
|
+
if (!set) {
|
|
1448
|
+
set = /* @__PURE__ */ new Set();
|
|
1449
|
+
this.listeners.set(event, set);
|
|
1450
|
+
}
|
|
1451
|
+
set.add(fn);
|
|
1452
|
+
return () => set.delete(fn);
|
|
1453
|
+
}
|
|
1454
|
+
emit(event, ...args) {
|
|
1455
|
+
const set = this.listeners.get(event);
|
|
1456
|
+
if (!set) return;
|
|
1457
|
+
for (const fn of [...set]) {
|
|
1458
|
+
try {
|
|
1459
|
+
fn(...args);
|
|
1460
|
+
} catch {
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
setStatus(s) {
|
|
1465
|
+
if (this._status === s) return;
|
|
1466
|
+
this._status = s;
|
|
1467
|
+
this.emit("status", s);
|
|
1468
|
+
if (s === "open") {
|
|
1469
|
+
const waiters = this.openWaiters;
|
|
1470
|
+
this.openWaiters = [];
|
|
1471
|
+
for (const w of waiters) w.resolve();
|
|
1472
|
+
}
|
|
1473
|
+
if (s === "closed") {
|
|
1474
|
+
const waiters = this.openWaiters;
|
|
1475
|
+
this.openWaiters = [];
|
|
1476
|
+
for (const w of waiters) w.reject(errClientClosed());
|
|
1477
|
+
this.emit("close");
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
// -------------------------------------------------------------- connection
|
|
1481
|
+
/** Connects (idempotent). Calls also auto-connect on first use. */
|
|
1482
|
+
async connect() {
|
|
1483
|
+
if (this._status === "open") return;
|
|
1484
|
+
if (this._status === "closed") throw errClientClosed();
|
|
1485
|
+
if (!this.connectPromise) {
|
|
1486
|
+
this.setStatus(this._status === "resuming" ? "resuming" : "connecting");
|
|
1487
|
+
this.connectPromise = this.doConnect().finally(() => {
|
|
1488
|
+
this.connectPromise = null;
|
|
1489
|
+
});
|
|
1490
|
+
}
|
|
1491
|
+
return this.connectPromise;
|
|
1492
|
+
}
|
|
1493
|
+
async handshakeToken() {
|
|
1494
|
+
if (this.opts.resume === false) {
|
|
1495
|
+
if (this.established) this._clientId = randomClientId();
|
|
1496
|
+
return "";
|
|
1497
|
+
}
|
|
1498
|
+
if (!this.chain) {
|
|
1499
|
+
this.chain = await HashChain.create(this.opts.chainLength ?? HashChain.DEFAULT_LENGTH);
|
|
1500
|
+
}
|
|
1501
|
+
if (!this.established) return this.chain.anchor();
|
|
1502
|
+
const tok = this.chain.nextToken();
|
|
1503
|
+
if (tok !== "") return tok;
|
|
1504
|
+
this._clientId = randomClientId();
|
|
1505
|
+
this.chain = await HashChain.create(this.opts.chainLength ?? HashChain.DEFAULT_LENGTH);
|
|
1506
|
+
this.established = false;
|
|
1507
|
+
return this.chain.anchor();
|
|
1508
|
+
}
|
|
1509
|
+
async doConnect() {
|
|
1510
|
+
const token = await this.handshakeToken();
|
|
1511
|
+
const authOpt = this.opts.auth;
|
|
1512
|
+
const auth = typeof authOpt === "function" ? await authOpt() : authOpt;
|
|
1513
|
+
const dialOpts = {
|
|
1514
|
+
url: this.opts.url,
|
|
1515
|
+
subprotocols: this.codec.subprotocols,
|
|
1516
|
+
timeoutMs: this.connectTimeoutMs
|
|
1517
|
+
};
|
|
1518
|
+
if (this.opts.webSocket) dialOpts.webSocket = this.opts.webSocket;
|
|
1519
|
+
const transport = await this.dialer(dialOpts);
|
|
1520
|
+
if (this._status === "closed") {
|
|
1521
|
+
transport.close();
|
|
1522
|
+
throw errClientClosed();
|
|
1523
|
+
}
|
|
1524
|
+
const hs = deferred();
|
|
1525
|
+
this.handshakeWaiter = hs;
|
|
1526
|
+
this.handshakeTransport = transport;
|
|
1527
|
+
transport.onMessage = (data) => this.onFrame(transport, data);
|
|
1528
|
+
transport.onClose = (err) => this.onTransportClose(transport, err);
|
|
1529
|
+
try {
|
|
1530
|
+
transport.send(this.codec.encode(this.protocol.handshakeRequest(this._clientId, token, auth ?? null)));
|
|
1531
|
+
const timer = setTimeout(
|
|
1532
|
+
() => hs.reject(new VrpcError(4 /* DeadlineExceeded */, `handshake timed out after ${this.connectTimeoutMs}ms`)),
|
|
1533
|
+
this.connectTimeoutMs
|
|
1534
|
+
);
|
|
1535
|
+
let resp;
|
|
1536
|
+
try {
|
|
1537
|
+
resp = await hs.promise;
|
|
1538
|
+
} finally {
|
|
1539
|
+
clearTimeout(timer);
|
|
1540
|
+
this.handshakeWaiter = null;
|
|
1541
|
+
this.handshakeTransport = null;
|
|
1542
|
+
}
|
|
1543
|
+
this.transport = transport;
|
|
1544
|
+
this.established = true;
|
|
1545
|
+
this.setStatus("open");
|
|
1546
|
+
this.installBrowserHints();
|
|
1547
|
+
this.emit("open", resp);
|
|
1548
|
+
} catch (err) {
|
|
1549
|
+
this.handshakeWaiter = null;
|
|
1550
|
+
this.handshakeTransport = null;
|
|
1551
|
+
transport.onClose = null;
|
|
1552
|
+
transport.close();
|
|
1553
|
+
throw err instanceof VrpcError ? err : new VrpcError(7 /* Unavailable */, `handshake failed: ${String(err)}`, { cause: err });
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
/** Waits until the client is open, connecting if idle. */
|
|
1557
|
+
async ensureOpen(signal) {
|
|
1558
|
+
if (this._status === "open") return;
|
|
1559
|
+
if (this._status === "closed") throw errClientClosed();
|
|
1560
|
+
if (this._status === "idle") {
|
|
1561
|
+
await this.connect();
|
|
1562
|
+
return;
|
|
1563
|
+
}
|
|
1564
|
+
const d = deferred();
|
|
1565
|
+
this.openWaiters.push(d);
|
|
1566
|
+
if (signal) {
|
|
1567
|
+
const onAbort = () => d.reject(new VrpcError(2 /* Canceled */, "aborted while waiting for connection"));
|
|
1568
|
+
if (signal.aborted) onAbort();
|
|
1569
|
+
else signal.addEventListener("abort", onAbort, { once: true });
|
|
1570
|
+
}
|
|
1571
|
+
await d.promise;
|
|
1572
|
+
}
|
|
1573
|
+
onTransportClose(transport, err) {
|
|
1574
|
+
if (transport !== this.transport) {
|
|
1575
|
+
if (transport === this.handshakeTransport) {
|
|
1576
|
+
this.handshakeWaiter?.reject(err ?? errConnectionLost());
|
|
1577
|
+
}
|
|
1578
|
+
return;
|
|
1579
|
+
}
|
|
1580
|
+
this.transport = null;
|
|
1581
|
+
this.failAllInFlight(errConnectionLost());
|
|
1582
|
+
if (this._status === "closed") return;
|
|
1583
|
+
if (!this.reconnect.enabled) {
|
|
1584
|
+
this.setStatus("closed");
|
|
1585
|
+
return;
|
|
1586
|
+
}
|
|
1587
|
+
void this.resumeLoop();
|
|
1588
|
+
}
|
|
1589
|
+
async resumeLoop() {
|
|
1590
|
+
if (this.resumeAbort) return;
|
|
1591
|
+
this.setStatus("resuming");
|
|
1592
|
+
try {
|
|
1593
|
+
for (let attempt = 1; attempt <= this.reconnect.maxAttempts; attempt++) {
|
|
1594
|
+
const abort = new AbortController();
|
|
1595
|
+
this.resumeAbort = abort;
|
|
1596
|
+
await sleep(backoffDelay(attempt, this.reconnect), abort.signal);
|
|
1597
|
+
this.resumeAbort = null;
|
|
1598
|
+
if (this._status === "closed") return;
|
|
1599
|
+
if (abort.signal.aborted) attempt = 0;
|
|
1600
|
+
this.reconnects++;
|
|
1601
|
+
try {
|
|
1602
|
+
await this.connect();
|
|
1603
|
+
return;
|
|
1604
|
+
} catch {
|
|
1605
|
+
}
|
|
1606
|
+
}
|
|
1607
|
+
this.setStatus("closed");
|
|
1608
|
+
} finally {
|
|
1609
|
+
this.resumeAbort = null;
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
/** Browser wake hints: retry immediately when connectivity likely returned. */
|
|
1613
|
+
installBrowserHints() {
|
|
1614
|
+
if (this.hintsInstalled || typeof window === "undefined" || typeof window.addEventListener !== "function") {
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1617
|
+
this.hintsInstalled = true;
|
|
1618
|
+
const hint = () => {
|
|
1619
|
+
if (this._status === "resuming") this.resumeAbort?.abort();
|
|
1620
|
+
};
|
|
1621
|
+
window.addEventListener("online", hint);
|
|
1622
|
+
if (typeof document !== "undefined") {
|
|
1623
|
+
document.addEventListener("visibilitychange", () => {
|
|
1624
|
+
if (document.visibilityState === "visible") hint();
|
|
1625
|
+
});
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
failAllInFlight(err) {
|
|
1629
|
+
const pending = [...this.pending.values()];
|
|
1630
|
+
this.pending.clear();
|
|
1631
|
+
for (const p of pending) p.fail(err);
|
|
1632
|
+
const serving = [...this.serving.values()];
|
|
1633
|
+
this.serving.clear();
|
|
1634
|
+
for (const s of serving) s.close();
|
|
1635
|
+
}
|
|
1636
|
+
/** Closes the client permanently. */
|
|
1637
|
+
close() {
|
|
1638
|
+
if (this._status === "closed") return;
|
|
1639
|
+
this.resumeAbort?.abort();
|
|
1640
|
+
this.handshakeWaiter?.reject(errClientClosed());
|
|
1641
|
+
const t = this.transport;
|
|
1642
|
+
this.transport = null;
|
|
1643
|
+
this.setStatus("closed");
|
|
1644
|
+
this.failAllInFlight(errClientClosed());
|
|
1645
|
+
t?.close();
|
|
1646
|
+
}
|
|
1647
|
+
// ---------------------------------------------------------------- sending
|
|
1648
|
+
sendFrame(env) {
|
|
1649
|
+
const t = this.transport;
|
|
1650
|
+
if (!t) throw errConnectionLost();
|
|
1651
|
+
t.send(this.codec.encode(env));
|
|
1652
|
+
}
|
|
1653
|
+
trySendFrame(env) {
|
|
1654
|
+
try {
|
|
1655
|
+
this.sendFrame(env);
|
|
1656
|
+
} catch {
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
cancelRequest(requestId) {
|
|
1660
|
+
this.trySendFrame(this.protocol.cancelRequest(requestId));
|
|
1661
|
+
}
|
|
1662
|
+
buildMetadata(name, callMd) {
|
|
1663
|
+
const base = typeof this.opts.metadata === "function" ? this.opts.metadata(name) : this.opts.metadata;
|
|
1664
|
+
if (!base && !callMd) return void 0;
|
|
1665
|
+
return { ...base, ...callMd };
|
|
1666
|
+
}
|
|
1667
|
+
// ------------------------------------------------------------------ unary
|
|
1668
|
+
/** Calls a unary function on the server. */
|
|
1669
|
+
async call(name, args, opts = {}) {
|
|
1670
|
+
await this.ensureOpen(opts.signal);
|
|
1671
|
+
const timeoutMs = opts.timeoutMs ?? this.timeoutMs;
|
|
1672
|
+
const rid = ++this.nextRequestId;
|
|
1673
|
+
const p = new PendingRequest(rid, "unary", name, 1);
|
|
1674
|
+
this.pending.set(rid, p);
|
|
1675
|
+
const settle = () => {
|
|
1676
|
+
if (p.timer) clearTimeout(p.timer);
|
|
1677
|
+
this.pending.delete(rid);
|
|
1678
|
+
};
|
|
1679
|
+
if (timeoutMs > 0) {
|
|
1680
|
+
p.timer = setTimeout(() => {
|
|
1681
|
+
this.cancelRequest(rid);
|
|
1682
|
+
p.fail(new VrpcError(4 /* DeadlineExceeded */, `call ${name} timed out after ${timeoutMs}ms`));
|
|
1683
|
+
settle();
|
|
1684
|
+
}, timeoutMs);
|
|
1685
|
+
}
|
|
1686
|
+
if (opts.signal) {
|
|
1687
|
+
const onAbort = () => {
|
|
1688
|
+
this.cancelRequest(rid);
|
|
1689
|
+
p.fail(new VrpcError(2 /* Canceled */, `call ${name} aborted`));
|
|
1690
|
+
settle();
|
|
1691
|
+
};
|
|
1692
|
+
if (opts.signal.aborted) onAbort();
|
|
1693
|
+
else opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
1694
|
+
}
|
|
1695
|
+
try {
|
|
1696
|
+
this.sendFrame(
|
|
1697
|
+
this.protocol.request(2 /* FunctionRequest */, rid, name, args, timeoutMs, this.buildMetadata(name, opts.metadata))
|
|
1698
|
+
);
|
|
1699
|
+
} catch (err) {
|
|
1700
|
+
p.fail(err instanceof VrpcError ? err : errConnectionLost());
|
|
1701
|
+
settle();
|
|
1702
|
+
}
|
|
1703
|
+
try {
|
|
1704
|
+
return await p.unary.promise;
|
|
1705
|
+
} finally {
|
|
1706
|
+
settle();
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
// ---------------------------------------------------------------- streams
|
|
1710
|
+
/**
|
|
1711
|
+
* Opens a server->client stream. Consume with `for await`; breaking out of
|
|
1712
|
+
* the loop cancels the stream. Credit is granted as values are consumed, so
|
|
1713
|
+
* a slow consumer applies real backpressure to the server.
|
|
1714
|
+
*/
|
|
1715
|
+
getStream(name, args, opts = {}) {
|
|
1716
|
+
const rid = ++this.nextRequestId;
|
|
1717
|
+
const p = new PendingRequest(rid, "get", name, this.maxPending);
|
|
1718
|
+
return this.openConsumingStream(p, 4 /* GetStreamRequest */, name, args, opts);
|
|
1719
|
+
}
|
|
1720
|
+
openConsumingStream(p, mt, name, args, opts) {
|
|
1721
|
+
const rid = p.requestId;
|
|
1722
|
+
this.pending.set(rid, p);
|
|
1723
|
+
p.onConsume = () => {
|
|
1724
|
+
p.delivered++;
|
|
1725
|
+
const batch = Math.max(1, Math.floor(p.window / 2));
|
|
1726
|
+
if (p.delivered >= batch) {
|
|
1727
|
+
const n = p.delivered;
|
|
1728
|
+
p.delivered = 0;
|
|
1729
|
+
this.trySendFrame(this.protocol.streamCredit(rid, n));
|
|
1730
|
+
}
|
|
1731
|
+
};
|
|
1732
|
+
const timeoutMs = opts.timeoutMs ?? this.timeoutMs;
|
|
1733
|
+
void this.establishStream(p, mt, name, args, timeoutMs, opts);
|
|
1734
|
+
const self = this;
|
|
1735
|
+
const iterator = {
|
|
1736
|
+
requestId: rid,
|
|
1737
|
+
ready: p.ready.promise,
|
|
1738
|
+
async next() {
|
|
1739
|
+
const q = p.queue;
|
|
1740
|
+
const res = await q.next();
|
|
1741
|
+
if (res.done) self.retireGetSide(p);
|
|
1742
|
+
return res;
|
|
1743
|
+
},
|
|
1744
|
+
async return(value) {
|
|
1745
|
+
iterator.cancel();
|
|
1746
|
+
return { value, done: true };
|
|
1747
|
+
},
|
|
1748
|
+
async throw(err) {
|
|
1749
|
+
iterator.cancel();
|
|
1750
|
+
throw err;
|
|
1751
|
+
},
|
|
1752
|
+
cancel() {
|
|
1753
|
+
if (p.getClosed && p.putClosed) return;
|
|
1754
|
+
self.cancelRequest(rid);
|
|
1755
|
+
p.finish();
|
|
1756
|
+
self.pending.delete(rid);
|
|
1757
|
+
},
|
|
1758
|
+
[Symbol.asyncIterator]() {
|
|
1759
|
+
return this;
|
|
1760
|
+
}
|
|
1761
|
+
};
|
|
1762
|
+
return iterator;
|
|
1763
|
+
}
|
|
1764
|
+
async establishStream(p, mt, name, args, timeoutMs, opts) {
|
|
1765
|
+
const rid = p.requestId;
|
|
1766
|
+
try {
|
|
1767
|
+
await this.ensureOpen(opts.signal);
|
|
1768
|
+
const establishTimer = setTimeout(() => {
|
|
1769
|
+
if (!p.getClosed) {
|
|
1770
|
+
this.cancelRequest(rid);
|
|
1771
|
+
p.fail(new VrpcError(4 /* DeadlineExceeded */, `stream ${name} was not acked within ${timeoutMs}ms`));
|
|
1772
|
+
this.pending.delete(rid);
|
|
1773
|
+
}
|
|
1774
|
+
}, timeoutMs);
|
|
1775
|
+
p.ready.promise.then(
|
|
1776
|
+
() => clearTimeout(establishTimer),
|
|
1777
|
+
() => clearTimeout(establishTimer)
|
|
1778
|
+
);
|
|
1779
|
+
if (opts.signal) {
|
|
1780
|
+
const onAbort = () => {
|
|
1781
|
+
this.cancelRequest(rid);
|
|
1782
|
+
p.fail(new VrpcError(2 /* Canceled */, `stream ${name} aborted`));
|
|
1783
|
+
this.pending.delete(rid);
|
|
1784
|
+
};
|
|
1785
|
+
if (opts.signal.aborted) onAbort();
|
|
1786
|
+
else opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
1787
|
+
}
|
|
1788
|
+
this.sendFrame(
|
|
1789
|
+
this.protocol.request(mt, rid, name, args, timeoutMs, this.buildMetadata(name, opts.metadata))
|
|
1790
|
+
);
|
|
1791
|
+
if (p.queue) {
|
|
1792
|
+
p.ready.promise.then(
|
|
1793
|
+
() => this.trySendFrame(this.protocol.streamCredit(rid, p.window)),
|
|
1794
|
+
() => {
|
|
1795
|
+
}
|
|
1796
|
+
);
|
|
1797
|
+
}
|
|
1798
|
+
} catch (err) {
|
|
1799
|
+
p.fail(err instanceof VrpcError ? err : new VrpcError(7 /* Unavailable */, String(err), { cause: err }));
|
|
1800
|
+
this.pending.delete(rid);
|
|
1801
|
+
}
|
|
1802
|
+
}
|
|
1803
|
+
retireGetSide(p) {
|
|
1804
|
+
p.getClosed = true;
|
|
1805
|
+
if (p.kind !== "chat" || p.putClosed) this.pending.delete(p.requestId);
|
|
1806
|
+
}
|
|
1807
|
+
/**
|
|
1808
|
+
* Opens a client->server stream and sends every value from source, honoring
|
|
1809
|
+
* the server's flow-control credit. Resolves once the stream ended cleanly.
|
|
1810
|
+
*/
|
|
1811
|
+
async putStream(name, args, source, opts = {}) {
|
|
1812
|
+
const timeoutMs = opts.timeoutMs ?? this.timeoutMs;
|
|
1813
|
+
await this.ensureOpen(opts.signal);
|
|
1814
|
+
const rid = ++this.nextRequestId;
|
|
1815
|
+
const p = new PendingRequest(rid, "put", name, 1);
|
|
1816
|
+
this.pending.set(rid, p);
|
|
1817
|
+
const abortErr = () => p.error ?? new VrpcError(2 /* Canceled */, `stream ${name} aborted`);
|
|
1818
|
+
if (opts.signal) {
|
|
1819
|
+
const onAbort = () => {
|
|
1820
|
+
this.cancelRequest(rid);
|
|
1821
|
+
p.fail(new VrpcError(2 /* Canceled */, `stream ${name} aborted`));
|
|
1822
|
+
this.pending.delete(rid);
|
|
1823
|
+
};
|
|
1824
|
+
if (opts.signal.aborted) onAbort();
|
|
1825
|
+
else opts.signal.addEventListener("abort", onAbort, { once: true });
|
|
1826
|
+
}
|
|
1827
|
+
try {
|
|
1828
|
+
const establishTimer = setTimeout(() => {
|
|
1829
|
+
if (!p.putClosed) {
|
|
1830
|
+
this.cancelRequest(rid);
|
|
1831
|
+
p.fail(new VrpcError(4 /* DeadlineExceeded */, `stream ${name} was not acked within ${timeoutMs}ms`));
|
|
1832
|
+
this.pending.delete(rid);
|
|
1833
|
+
}
|
|
1834
|
+
}, timeoutMs);
|
|
1835
|
+
p.ready.promise.then(
|
|
1836
|
+
() => clearTimeout(establishTimer),
|
|
1837
|
+
() => clearTimeout(establishTimer)
|
|
1838
|
+
);
|
|
1839
|
+
this.sendFrame(
|
|
1840
|
+
this.protocol.request(5 /* PutStreamRequest */, rid, name, args, timeoutMs, this.buildMetadata(name, opts.metadata))
|
|
1841
|
+
);
|
|
1842
|
+
await p.ready.promise;
|
|
1843
|
+
for await (const v of source) {
|
|
1844
|
+
const gate = p.sendCredit;
|
|
1845
|
+
const ok = await gate.acquire();
|
|
1846
|
+
if (!ok) throw abortErr();
|
|
1847
|
+
this.sendFrame(this.protocol.streamValue(rid, v));
|
|
1848
|
+
}
|
|
1849
|
+
this.sendFrame(this.protocol.streamEnd(rid));
|
|
1850
|
+
p.putClosed = true;
|
|
1851
|
+
} finally {
|
|
1852
|
+
p.finish();
|
|
1853
|
+
this.pending.delete(rid);
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
/** Opens a bidirectional stream (chat). */
|
|
1857
|
+
chat(name, args, opts = {}) {
|
|
1858
|
+
const rid = ++this.nextRequestId;
|
|
1859
|
+
const p = new PendingRequest(rid, "chat", name, this.maxPending);
|
|
1860
|
+
const stream = this.openConsumingStream(p, 6 /* ChatRequest */, name, args, opts);
|
|
1861
|
+
const self = this;
|
|
1862
|
+
let ended = false;
|
|
1863
|
+
return {
|
|
1864
|
+
requestId: rid,
|
|
1865
|
+
ready: p.ready.promise,
|
|
1866
|
+
incoming: stream,
|
|
1867
|
+
async send(v) {
|
|
1868
|
+
if (ended) throw new VrpcError(9 /* Internal */, `chat ${name}: send after end`);
|
|
1869
|
+
await p.ready.promise;
|
|
1870
|
+
const ok = await p.sendCredit.acquire();
|
|
1871
|
+
if (!ok) throw p.error ?? errConnectionLost();
|
|
1872
|
+
self.sendFrame(self.protocol.streamValue(rid, v));
|
|
1873
|
+
},
|
|
1874
|
+
end() {
|
|
1875
|
+
if (ended || p.putClosed) return;
|
|
1876
|
+
ended = true;
|
|
1877
|
+
p.ready.promise.then(
|
|
1878
|
+
() => {
|
|
1879
|
+
if (!p.putClosed) {
|
|
1880
|
+
p.putClosed = true;
|
|
1881
|
+
self.trySendFrame(self.protocol.streamEnd(rid));
|
|
1882
|
+
if (p.getClosed) self.pending.delete(rid);
|
|
1883
|
+
}
|
|
1884
|
+
},
|
|
1885
|
+
() => {
|
|
1886
|
+
}
|
|
1887
|
+
);
|
|
1888
|
+
},
|
|
1889
|
+
cancel() {
|
|
1890
|
+
ended = true;
|
|
1891
|
+
stream.cancel();
|
|
1892
|
+
},
|
|
1893
|
+
[Symbol.asyncIterator]() {
|
|
1894
|
+
return stream;
|
|
1895
|
+
}
|
|
1896
|
+
};
|
|
1897
|
+
}
|
|
1898
|
+
// ------------------------------------------------- reverse-call registrar
|
|
1899
|
+
/** Registers a unary function the server may call on this client. */
|
|
1900
|
+
addFunction(name, fn) {
|
|
1901
|
+
this.handlers.set(name, { kind: "unary", fn });
|
|
1902
|
+
}
|
|
1903
|
+
/** Registers a stream the server can consume from this client (GetStream). */
|
|
1904
|
+
addOutgoingStream(name, fn) {
|
|
1905
|
+
this.handlers.set(name, { kind: "out", fn });
|
|
1906
|
+
}
|
|
1907
|
+
/** Registers a stream the server can send to this client (PutStream). */
|
|
1908
|
+
addIncomingStream(name, fn) {
|
|
1909
|
+
this.handlers.set(name, { kind: "in", fn });
|
|
1910
|
+
}
|
|
1911
|
+
/** Registers a bidirectional stream the server can open (Chat). */
|
|
1912
|
+
addChat(name, fn) {
|
|
1913
|
+
this.handlers.set(name, { kind: "chat", fn });
|
|
1914
|
+
}
|
|
1915
|
+
removeHandler(name) {
|
|
1916
|
+
this.handlers.delete(name);
|
|
1917
|
+
}
|
|
1918
|
+
// ------------------------------------------------------------- dispatch
|
|
1919
|
+
onFrame(transport, data) {
|
|
1920
|
+
if (transport !== this.transport && transport !== this.handshakeTransport) return;
|
|
1921
|
+
let msg;
|
|
1922
|
+
try {
|
|
1923
|
+
msg = this.codec.decode(data);
|
|
1924
|
+
} catch (err) {
|
|
1925
|
+
this.emit("error", new VrpcError(9 /* Internal */, `malformed frame: ${String(err)}`, { cause: err }));
|
|
1926
|
+
this.handshakeWaiter?.reject(new VrpcError(9 /* Internal */, `malformed handshake frame: ${String(err)}`));
|
|
1927
|
+
transport.onClose = null;
|
|
1928
|
+
transport.close();
|
|
1929
|
+
this.onTransportClose(transport, errConnectionLost());
|
|
1930
|
+
return;
|
|
1931
|
+
}
|
|
1932
|
+
const mt = this.protocol.messageType(msg);
|
|
1933
|
+
if (mt === void 0) {
|
|
1934
|
+
this.emit("error", new VrpcError(9 /* Internal */, "message type not found"));
|
|
1935
|
+
return;
|
|
1936
|
+
}
|
|
1937
|
+
if (mt === 1 /* HandshakeResponse */) {
|
|
1938
|
+
this.handshakeWaiter?.resolve(msg);
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1941
|
+
if (mt === 2 /* FunctionRequest */) {
|
|
1942
|
+
this.serveInboundCall(msg);
|
|
1943
|
+
return;
|
|
1944
|
+
}
|
|
1945
|
+
if (mt === 4 /* GetStreamRequest */ || mt === 5 /* PutStreamRequest */ || mt === 6 /* ChatRequest */) {
|
|
1946
|
+
this.serveInboundStream(mt, msg);
|
|
1947
|
+
return;
|
|
1948
|
+
}
|
|
1949
|
+
const rid = this.protocol.requestId(msg);
|
|
1950
|
+
if (rid === void 0) {
|
|
1951
|
+
this.emit("error", new VrpcError(9 /* Internal */, "request id not found"));
|
|
1952
|
+
return;
|
|
1953
|
+
}
|
|
1954
|
+
const sr = this.serving.get(rid);
|
|
1955
|
+
if (sr) {
|
|
1956
|
+
this.serveRunning(sr, mt, msg);
|
|
1957
|
+
return;
|
|
1958
|
+
}
|
|
1959
|
+
const p = this.pending.get(rid);
|
|
1960
|
+
if (p) {
|
|
1961
|
+
this.processResponse(p, mt, msg);
|
|
1962
|
+
return;
|
|
1963
|
+
}
|
|
1964
|
+
if (mt !== 9 /* StreamValue */ && mt !== 10 /* StreamEnd */ && mt !== 11 /* CancelRequest */) {
|
|
1965
|
+
this.emit("error", new VrpcError(9 /* Internal */, `no request ${rid} for message type ${mt}`));
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
processResponse(p, mt, msg) {
|
|
1969
|
+
switch (mt) {
|
|
1970
|
+
case 3 /* FunctionResponse */: {
|
|
1971
|
+
p.unary?.resolve(this.protocol.result(msg));
|
|
1972
|
+
this.pending.delete(p.requestId);
|
|
1973
|
+
break;
|
|
1974
|
+
}
|
|
1975
|
+
case 7 /* ErrorResponse */: {
|
|
1976
|
+
const { code, message } = this.protocol.errorOf(msg);
|
|
1977
|
+
p.fail(new VrpcError(code, message || "server error"));
|
|
1978
|
+
this.pending.delete(p.requestId);
|
|
1979
|
+
break;
|
|
1980
|
+
}
|
|
1981
|
+
case 8 /* StreamReady */: {
|
|
1982
|
+
p.ready.resolve();
|
|
1983
|
+
break;
|
|
1984
|
+
}
|
|
1985
|
+
case 9 /* StreamValue */: {
|
|
1986
|
+
const v = this.protocol.streamVal(msg);
|
|
1987
|
+
if (v === null || !p.queue) break;
|
|
1988
|
+
if (!p.queue.push(v)) {
|
|
1989
|
+
if (!p.queue.isEnded) {
|
|
1990
|
+
const err = new VrpcError(
|
|
1991
|
+
6 /* ResourceExhausted */,
|
|
1992
|
+
`stream ${p.requestId} truncated: server exceeded flow-control credit`
|
|
1993
|
+
);
|
|
1994
|
+
this.cancelRequest(p.requestId);
|
|
1995
|
+
p.fail(err);
|
|
1996
|
+
this.pending.delete(p.requestId);
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1999
|
+
break;
|
|
2000
|
+
}
|
|
2001
|
+
case 10 /* StreamEnd */: {
|
|
2002
|
+
const v = this.protocol.streamVal(msg);
|
|
2003
|
+
if (v !== null && p.queue) p.queue.push(v);
|
|
2004
|
+
p.queue?.end();
|
|
2005
|
+
p.getClosed = true;
|
|
2006
|
+
p.ready.resolve();
|
|
2007
|
+
if (p.kind !== "chat" || p.putClosed) this.pending.delete(p.requestId);
|
|
2008
|
+
break;
|
|
2009
|
+
}
|
|
2010
|
+
case 11 /* CancelRequest */: {
|
|
2011
|
+
p.finish();
|
|
2012
|
+
this.pending.delete(p.requestId);
|
|
2013
|
+
break;
|
|
2014
|
+
}
|
|
2015
|
+
case 14 /* StreamCredit */: {
|
|
2016
|
+
const cr = this.protocol.credit(msg);
|
|
2017
|
+
if (cr !== void 0) p.sendCredit?.grant(cr);
|
|
2018
|
+
break;
|
|
2019
|
+
}
|
|
2020
|
+
default:
|
|
2021
|
+
this.emit("error", new VrpcError(9 /* Internal */, `unsupported message type ${mt}`));
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
// ------------------------------------------------------- reverse serving
|
|
2025
|
+
handlerCtx(sr, msg) {
|
|
2026
|
+
return {
|
|
2027
|
+
requestId: sr.requestId,
|
|
2028
|
+
metadata: this.protocol.metadata(msg),
|
|
2029
|
+
signal: sr.abort.signal
|
|
2030
|
+
};
|
|
2031
|
+
}
|
|
2032
|
+
serveInboundCall(msg) {
|
|
2033
|
+
const rid = this.protocol.requestId(msg);
|
|
2034
|
+
if (rid === void 0) {
|
|
2035
|
+
this.emit("error", new VrpcError(9 /* Internal */, "reverse call without request id"));
|
|
2036
|
+
return;
|
|
2037
|
+
}
|
|
2038
|
+
const name = this.protocol.functionName(msg);
|
|
2039
|
+
if (name === void 0) {
|
|
2040
|
+
this.trySendFrame(this.protocol.errorResponse(rid, 3 /* InvalidArgument */, "function name field not found"));
|
|
2041
|
+
return;
|
|
2042
|
+
}
|
|
2043
|
+
const h = this.handlers.get(name);
|
|
2044
|
+
if (!h) {
|
|
2045
|
+
this.trySendFrame(this.protocol.errorResponse(rid, 5 /* NotFound */, `function not found ${name}`));
|
|
2046
|
+
return;
|
|
2047
|
+
}
|
|
2048
|
+
if (h.kind !== "unary") {
|
|
2049
|
+
this.trySendFrame(this.protocol.errorResponse(rid, 3 /* InvalidArgument */, `function '${name}' is not unary`));
|
|
2050
|
+
return;
|
|
2051
|
+
}
|
|
2052
|
+
const sr = new ServingRequest(rid, "unary", 1);
|
|
2053
|
+
const args = this.protocol.args(msg);
|
|
2054
|
+
void (async () => {
|
|
2055
|
+
try {
|
|
2056
|
+
const res = await h.fn(args, this.handlerCtx(sr, msg));
|
|
2057
|
+
this.trySendFrame(this.protocol.functionResult(rid, res ?? null));
|
|
2058
|
+
} catch (err) {
|
|
2059
|
+
this.trySendFrame(
|
|
2060
|
+
this.protocol.errorResponse(rid, handlerCode(err), `function ${name}: ${errMessage(err)}`)
|
|
2061
|
+
);
|
|
2062
|
+
}
|
|
2063
|
+
})();
|
|
2064
|
+
}
|
|
2065
|
+
serveInboundStream(mt, msg) {
|
|
2066
|
+
const rid = this.protocol.requestId(msg);
|
|
2067
|
+
if (rid === void 0) {
|
|
2068
|
+
this.emit("error", new VrpcError(9 /* Internal */, "reverse stream without request id"));
|
|
2069
|
+
return;
|
|
2070
|
+
}
|
|
2071
|
+
const name = this.protocol.functionName(msg);
|
|
2072
|
+
if (name === void 0) {
|
|
2073
|
+
this.trySendFrame(this.protocol.errorResponse(rid, 3 /* InvalidArgument */, "function name field not found"));
|
|
2074
|
+
return;
|
|
2075
|
+
}
|
|
2076
|
+
const wanted = mt === 4 /* GetStreamRequest */ ? "out" : mt === 5 /* PutStreamRequest */ ? "in" : "chat";
|
|
2077
|
+
const h = this.handlers.get(name);
|
|
2078
|
+
if (!h) {
|
|
2079
|
+
this.trySendFrame(this.protocol.errorResponse(rid, 5 /* NotFound */, `function not found ${name}`));
|
|
2080
|
+
return;
|
|
2081
|
+
}
|
|
2082
|
+
if (h.kind !== wanted) {
|
|
2083
|
+
this.trySendFrame(this.protocol.errorResponse(rid, 3 /* InvalidArgument */, `function '${name}' wrong stream type`));
|
|
2084
|
+
return;
|
|
2085
|
+
}
|
|
2086
|
+
const sr = new ServingRequest(rid, wanted, this.maxPending);
|
|
2087
|
+
this.serving.set(rid, sr);
|
|
2088
|
+
const args = this.protocol.args(msg);
|
|
2089
|
+
const ctx = this.handlerCtx(sr, msg);
|
|
2090
|
+
if (sr.inQueue) {
|
|
2091
|
+
sr.onConsume = () => {
|
|
2092
|
+
sr.delivered++;
|
|
2093
|
+
const batch = Math.max(1, Math.floor(sr.window / 2));
|
|
2094
|
+
if (sr.delivered >= batch) {
|
|
2095
|
+
const n = sr.delivered;
|
|
2096
|
+
sr.delivered = 0;
|
|
2097
|
+
this.trySendFrame(this.protocol.streamCredit(rid, n));
|
|
2098
|
+
}
|
|
2099
|
+
};
|
|
2100
|
+
this.trySendFrame(this.protocol.streamCredit(rid, sr.window));
|
|
2101
|
+
}
|
|
2102
|
+
const incoming = sr.inQueue ? queueIterator(sr.inQueue) : emptyIterator();
|
|
2103
|
+
void (async () => {
|
|
2104
|
+
try {
|
|
2105
|
+
if (wanted === "in") {
|
|
2106
|
+
this.trySendFrame(this.protocol.streamReady(rid));
|
|
2107
|
+
await h.fn(args, incoming, ctx);
|
|
2108
|
+
return;
|
|
2109
|
+
}
|
|
2110
|
+
const iterable = await h.fn(args, incoming, ctx);
|
|
2111
|
+
this.trySendFrame(this.protocol.streamReady(rid));
|
|
2112
|
+
for await (const v of iterable) {
|
|
2113
|
+
const gate = sr.sendCredit;
|
|
2114
|
+
const ok = await gate.acquire();
|
|
2115
|
+
if (!ok || sr.closed) return;
|
|
2116
|
+
this.trySendFrame(this.protocol.streamValue(rid, v));
|
|
2117
|
+
}
|
|
2118
|
+
this.trySendFrame(this.protocol.streamEnd(rid));
|
|
2119
|
+
} catch (err) {
|
|
2120
|
+
if (!sr.closed) {
|
|
2121
|
+
this.trySendFrame(
|
|
2122
|
+
this.protocol.errorResponse(rid, handlerCode(err), `${kindLabel(wanted)} ${name}: ${errMessage(err)}`)
|
|
2123
|
+
);
|
|
2124
|
+
}
|
|
2125
|
+
} finally {
|
|
2126
|
+
if (wanted !== "in") {
|
|
2127
|
+
this.serving.delete(rid);
|
|
2128
|
+
sr.close();
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
})();
|
|
2132
|
+
}
|
|
2133
|
+
serveRunning(sr, mt, msg) {
|
|
2134
|
+
switch (mt) {
|
|
2135
|
+
case 11 /* CancelRequest */: {
|
|
2136
|
+
this.serving.delete(sr.requestId);
|
|
2137
|
+
sr.close();
|
|
2138
|
+
break;
|
|
2139
|
+
}
|
|
2140
|
+
case 9 /* StreamValue */: {
|
|
2141
|
+
const v = this.protocol.streamVal(msg);
|
|
2142
|
+
if (v === null || !sr.inQueue) break;
|
|
2143
|
+
if (!sr.inQueue.push(v) && !sr.inQueue.isEnded) {
|
|
2144
|
+
this.trySendFrame(
|
|
2145
|
+
this.protocol.errorResponse(
|
|
2146
|
+
sr.requestId,
|
|
2147
|
+
6 /* ResourceExhausted */,
|
|
2148
|
+
`inbound stream ${sr.requestId} truncated: peer exceeded flow-control credit`
|
|
2149
|
+
)
|
|
2150
|
+
);
|
|
2151
|
+
this.serving.delete(sr.requestId);
|
|
2152
|
+
sr.close();
|
|
2153
|
+
}
|
|
2154
|
+
break;
|
|
2155
|
+
}
|
|
2156
|
+
case 10 /* StreamEnd */: {
|
|
2157
|
+
const v = this.protocol.streamVal(msg);
|
|
2158
|
+
if (v !== null && sr.inQueue) sr.inQueue.push(v);
|
|
2159
|
+
sr.inQueue?.end();
|
|
2160
|
+
if (sr.kind !== "chat") this.serving.delete(sr.requestId);
|
|
2161
|
+
break;
|
|
2162
|
+
}
|
|
2163
|
+
case 14 /* StreamCredit */: {
|
|
2164
|
+
const cr = this.protocol.credit(msg);
|
|
2165
|
+
if (cr !== void 0) sr.sendCredit?.grant(cr);
|
|
2166
|
+
break;
|
|
2167
|
+
}
|
|
2168
|
+
case 7 /* ErrorResponse */: {
|
|
2169
|
+
const { code, message } = this.protocol.errorOf(msg);
|
|
2170
|
+
this.emit("error", new VrpcError(code, `reverse stream ${sr.requestId}: ${message}`));
|
|
2171
|
+
this.serving.delete(sr.requestId);
|
|
2172
|
+
sr.close();
|
|
2173
|
+
break;
|
|
2174
|
+
}
|
|
2175
|
+
default:
|
|
2176
|
+
this.emit("error", new VrpcError(9 /* Internal */, `unsupported message type ${mt} for serving request`));
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
};
|
|
2180
|
+
function handlerCode(err) {
|
|
2181
|
+
const c = codeOf(err);
|
|
2182
|
+
return c === 1 /* Unknown */ ? 9 /* Internal */ : c;
|
|
2183
|
+
}
|
|
2184
|
+
function errMessage(err) {
|
|
2185
|
+
if (err instanceof VrpcError) return err.detail;
|
|
2186
|
+
if (err instanceof Error) return err.message;
|
|
2187
|
+
return String(err);
|
|
2188
|
+
}
|
|
2189
|
+
function kindLabel(kind) {
|
|
2190
|
+
switch (kind) {
|
|
2191
|
+
case "out":
|
|
2192
|
+
return "out stream";
|
|
2193
|
+
case "in":
|
|
2194
|
+
return "in stream";
|
|
2195
|
+
case "chat":
|
|
2196
|
+
return "chat";
|
|
2197
|
+
default:
|
|
2198
|
+
return "function";
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
function queueIterator(q) {
|
|
2202
|
+
return {
|
|
2203
|
+
next: () => q.next(),
|
|
2204
|
+
async return(value) {
|
|
2205
|
+
q.abort();
|
|
2206
|
+
return { value, done: true };
|
|
2207
|
+
},
|
|
2208
|
+
[Symbol.asyncIterator]() {
|
|
2209
|
+
return this;
|
|
2210
|
+
}
|
|
2211
|
+
};
|
|
2212
|
+
}
|
|
2213
|
+
function emptyIterator() {
|
|
2214
|
+
return {
|
|
2215
|
+
next: () => Promise.resolve({ value: void 0, done: true }),
|
|
2216
|
+
[Symbol.asyncIterator]() {
|
|
2217
|
+
return this;
|
|
2218
|
+
}
|
|
2219
|
+
};
|
|
2220
|
+
}
|
|
2221
|
+
function createClient(options) {
|
|
2222
|
+
return new VrpcClient(options);
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
// src/typed.ts
|
|
2226
|
+
function typedClient(client) {
|
|
2227
|
+
return {
|
|
2228
|
+
client,
|
|
2229
|
+
call: (name, args, opts) => client.call(name, args, opts),
|
|
2230
|
+
getStream: (name, args, opts) => client.getStream(name, args, opts),
|
|
2231
|
+
putStream: (name, args, source, opts) => client.putStream(name, args, source, opts),
|
|
2232
|
+
chat: (name, args, opts) => client.chat(name, args, opts)
|
|
2233
|
+
};
|
|
2234
|
+
}
|
|
2235
|
+
export {
|
|
2236
|
+
Code,
|
|
2237
|
+
DEFAULT_LIMITS,
|
|
2238
|
+
HashChain,
|
|
2239
|
+
MessageType,
|
|
2240
|
+
Protocol,
|
|
2241
|
+
VrpcClient,
|
|
2242
|
+
VrpcDecimal,
|
|
2243
|
+
VrpcDouble,
|
|
2244
|
+
VrpcError,
|
|
2245
|
+
VrpcExt,
|
|
2246
|
+
codeName,
|
|
2247
|
+
codeOf,
|
|
2248
|
+
codecByName,
|
|
2249
|
+
createClient,
|
|
2250
|
+
decimal,
|
|
2251
|
+
double,
|
|
2252
|
+
jsonCodec,
|
|
2253
|
+
jsonDecode,
|
|
2254
|
+
jsonEncode,
|
|
2255
|
+
msgpackCodec,
|
|
2256
|
+
msgpackDecode,
|
|
2257
|
+
msgpackEncode,
|
|
2258
|
+
newDialect,
|
|
2259
|
+
typedClient,
|
|
2260
|
+
webSocketDialer
|
|
2261
|
+
};
|
|
2262
|
+
//# sourceMappingURL=index.js.map
|