@trevrpc/trevrpc-js 1.5.0 → 1.6.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 +33 -42
- package/package.json +9 -13
- package/src/call.js +1 -1
- package/src/channel.js +44 -6
- package/src/client.js +30 -38
- package/src/framing.js +40 -12
- package/src/index.d.ts +55 -198
- package/src/index.js +1 -15
- package/src/method-options.js +170 -0
- package/src/qmux/session.js +17 -0
- package/src/wire.js +400 -312
- package/bin/protoc-gen-trevrpc-js.js +0 -17
- package/src/generator.js +0 -1152
- package/src/int64.js +0 -288
- package/src/wkt.js +0 -137
package/src/int64.js
DELETED
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
import protobuf from "protobufjs";
|
|
2
|
-
|
|
3
|
-
import { invalidArgument } from "./status.js";
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* How decoded 64-bit integer fields are represented: `bigint`, `number` (exact up to 2^53),
|
|
7
|
-
* decimal `string`, or protobuf.js's `long` (a Long object, as protobuf.js decodes them).
|
|
8
|
-
*/
|
|
9
|
-
export const Int64Representations = Object.freeze(["bigint", "number", "string", "long"]);
|
|
10
|
-
|
|
11
|
-
/** The representation of each root's 64-bit fields, for roots made with createRoot(). */
|
|
12
|
-
const rootRepresentations = new WeakMap();
|
|
13
|
-
/** The conversion plan of each message type, or null when its messages need none. */
|
|
14
|
-
const plans = new WeakMap();
|
|
15
|
-
|
|
16
|
-
const Int64Types = new Set(["int64", "uint64", "sint64", "fixed64", "sfixed64"]);
|
|
17
|
-
const UnsignedTypes = new Set(["uint64", "fixed64"]);
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Sets how the decoded messages of `root`'s types represent 64-bit integers. Without it they keep
|
|
21
|
-
* protobuf.js's Long objects. A field's `jstype` option (`JS_STRING` or `JS_NUMBER`) overrides it.
|
|
22
|
-
*/
|
|
23
|
-
export function setInt64Representation(root, representation) {
|
|
24
|
-
if (!Int64Representations.includes(representation)) {
|
|
25
|
-
throw invalidArgument(
|
|
26
|
-
`int64 must be one of ${Int64Representations.join(", ")}, not ${JSON.stringify(representation)}`,
|
|
27
|
-
);
|
|
28
|
-
}
|
|
29
|
-
rootRepresentations.set(root, representation);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Returns a function that converts, in place, the 64-bit integers of a message of `type` that
|
|
34
|
-
* protobuf.js decoded, as its root's representation says, and returns the message; or undefined
|
|
35
|
-
* when its messages need no conversion. 64-bit map keys, which protobuf.js decodes as 8-byte hash
|
|
36
|
-
* strings, become decimal strings in every representation.
|
|
37
|
-
*/
|
|
38
|
-
export function int64Converter(type) {
|
|
39
|
-
const plan = planFor(type);
|
|
40
|
-
return plan === null ? undefined : (message) => applyPlan(plan, message);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Converts a 64-bit integer, as a bigint, a number, a decimal string, or a Long-like object with
|
|
45
|
-
* `low`, `high` and `unsigned`, to a bigint. Null and undefined are zero.
|
|
46
|
-
*/
|
|
47
|
-
export function int64ToBigInt(value, unsigned = value?.unsigned === true) {
|
|
48
|
-
switch (typeof value) {
|
|
49
|
-
case "bigint":
|
|
50
|
-
return value;
|
|
51
|
-
case "number":
|
|
52
|
-
return BigInt(Math.trunc(value));
|
|
53
|
-
case "string":
|
|
54
|
-
return BigInt(value);
|
|
55
|
-
default: {
|
|
56
|
-
if (value == null) {
|
|
57
|
-
return 0n;
|
|
58
|
-
}
|
|
59
|
-
const bits = (BigInt(value.high >>> 0) << 32n) | BigInt(value.low >>> 0);
|
|
60
|
-
return unsigned ? bits : BigInt.asIntN(64, bits);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function planFor(type) {
|
|
66
|
-
const cached = plans.get(type);
|
|
67
|
-
if (cached !== undefined) {
|
|
68
|
-
return cached;
|
|
69
|
-
}
|
|
70
|
-
const representation = rootRepresentations.get(type.root);
|
|
71
|
-
if (representation === undefined) {
|
|
72
|
-
plans.set(type, null);
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
buildPlans(type, representation);
|
|
76
|
-
return plans.get(type);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Builds the plans of `start` and every message type reachable from it. A type needs a plan when
|
|
81
|
-
* it has a 64-bit field to convert, or a message field whose type needs one; that is settled for
|
|
82
|
-
* every reachable type at once, so recursive types are handled.
|
|
83
|
-
*/
|
|
84
|
-
function buildPlans(start, representation) {
|
|
85
|
-
const steps = new Map();
|
|
86
|
-
const pending = [start];
|
|
87
|
-
steps.set(start, undefined);
|
|
88
|
-
while (pending.length > 0) {
|
|
89
|
-
const type = pending.pop();
|
|
90
|
-
const typeSteps = [];
|
|
91
|
-
for (const field of type.fieldsArray) {
|
|
92
|
-
field.resolve();
|
|
93
|
-
const step = fieldStep(type, field, representation);
|
|
94
|
-
if (step !== undefined) {
|
|
95
|
-
typeSteps.push(step);
|
|
96
|
-
}
|
|
97
|
-
if (field.resolvedType instanceof protobuf.Type && !steps.has(field.resolvedType)) {
|
|
98
|
-
steps.set(field.resolvedType, undefined);
|
|
99
|
-
pending.push(field.resolvedType);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
steps.set(type, typeSteps);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// A type needs a plan when it converts a value itself or holds a type that needs one.
|
|
106
|
-
const needed = new Set();
|
|
107
|
-
for (let changed = true; changed;) {
|
|
108
|
-
changed = false;
|
|
109
|
-
for (const [type, typeSteps] of steps) {
|
|
110
|
-
if (
|
|
111
|
-
!needed.has(type) &&
|
|
112
|
-
typeSteps.some((step) => convertsItself(step) || needed.has(step.type))
|
|
113
|
-
) {
|
|
114
|
-
needed.add(type);
|
|
115
|
-
changed = true;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const built = new Map();
|
|
121
|
-
for (const type of steps.keys()) {
|
|
122
|
-
if (!plans.has(type)) {
|
|
123
|
-
built.set(type, needed.has(type) ? [] : null);
|
|
124
|
-
restoreNullDefaults(type);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
for (const [type, plan] of built) {
|
|
128
|
-
plans.set(type, plan);
|
|
129
|
-
}
|
|
130
|
-
for (const [type, plan] of built) {
|
|
131
|
-
if (plan === null) {
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
for (const step of steps.get(type)) {
|
|
135
|
-
const nested = step.type === undefined ? undefined : plans.get(step.type);
|
|
136
|
-
if (!convertsItself(step) && nested == null) {
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
plan.push({ ...step, nested: nested ?? undefined });
|
|
140
|
-
}
|
|
141
|
-
patchDefaults(type, plan);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/** Reports whether a step converts values or keys of its own, not only nested messages. */
|
|
146
|
-
function convertsItself(step) {
|
|
147
|
-
return step.convert !== undefined || step.convertKey !== undefined;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* The conversion step of one field of `type`, or undefined when it holds neither a 64-bit integer
|
|
152
|
-
* nor a message. `convert` converts its 64-bit values, `convertKey` its 64-bit map keys, and
|
|
153
|
-
* `type` is the message type of its values.
|
|
154
|
-
*/
|
|
155
|
-
function fieldStep(type, field, representation) {
|
|
156
|
-
const messageType = field.resolvedType instanceof protobuf.Type ? field.resolvedType : undefined;
|
|
157
|
-
const convert = Int64Types.has(field.type)
|
|
158
|
-
? valueConverter(fieldRepresentation(field, representation), UnsignedTypes.has(field.type))
|
|
159
|
-
: undefined;
|
|
160
|
-
if (field.map) {
|
|
161
|
-
const convertKey = Int64Types.has(field.keyType)
|
|
162
|
-
? keyConverter(UnsignedTypes.has(field.keyType))
|
|
163
|
-
: undefined;
|
|
164
|
-
if (convert === undefined && convertKey === undefined && messageType === undefined) {
|
|
165
|
-
return undefined;
|
|
166
|
-
}
|
|
167
|
-
return { name: field.name, shape: "map", convert, convertKey, type: messageType };
|
|
168
|
-
}
|
|
169
|
-
if (convert === undefined && messageType === undefined) {
|
|
170
|
-
return undefined;
|
|
171
|
-
}
|
|
172
|
-
const shape = field.repeated ? "repeated" : "single";
|
|
173
|
-
return { name: field.name, shape, convert, type: messageType };
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/** The representation of a 64-bit field: its `jstype` option's, or the root's. */
|
|
177
|
-
function fieldRepresentation(field, representation) {
|
|
178
|
-
switch (field.options?.jstype) {
|
|
179
|
-
case "JS_STRING":
|
|
180
|
-
return "string";
|
|
181
|
-
case "JS_NUMBER":
|
|
182
|
-
return "number";
|
|
183
|
-
default:
|
|
184
|
-
return representation;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/** Returns a function converting a decoded 64-bit value, or undefined for Long objects. */
|
|
189
|
-
function valueConverter(representation, unsigned) {
|
|
190
|
-
switch (representation) {
|
|
191
|
-
case "bigint":
|
|
192
|
-
return (value) => int64ToBigInt(value, unsigned);
|
|
193
|
-
case "number":
|
|
194
|
-
return (value) => Number(int64ToBigInt(value, unsigned));
|
|
195
|
-
case "string":
|
|
196
|
-
return (value) => int64ToBigInt(value, unsigned).toString();
|
|
197
|
-
default:
|
|
198
|
-
return undefined;
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/** Returns a function converting a decoded 64-bit map key, an 8-byte hash, to decimal. */
|
|
203
|
-
function keyConverter(unsigned) {
|
|
204
|
-
return (key) => int64ToBigInt(protobuf.util.longFromHash(key, unsigned), unsigned).toString();
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
/**
|
|
208
|
-
* Makes unset proto3 `optional` 64-bit fields of `type`'s messages read null, as other fields with
|
|
209
|
-
* presence do: protobuf.js turns their null default into a Long zero.
|
|
210
|
-
*/
|
|
211
|
-
function restoreNullDefaults(type) {
|
|
212
|
-
for (const field of type.fieldsArray) {
|
|
213
|
-
if (Int64Types.has(field.type) && field.options?.proto3_optional && !field.repeated) {
|
|
214
|
-
type.ctor.prototype[field.name] = null;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Converts the defaults that `type`'s messages read from their prototype for unset singular 64-bit
|
|
221
|
-
* fields, so that an unset field reads like a set one.
|
|
222
|
-
*/
|
|
223
|
-
function patchDefaults(type, plan) {
|
|
224
|
-
const prototype = type.ctor.prototype;
|
|
225
|
-
for (const step of plan) {
|
|
226
|
-
// A field with presence, such as a proto3 optional one, reads null when unset.
|
|
227
|
-
if (step.shape === "single" && step.convert !== undefined && prototype[step.name] != null) {
|
|
228
|
-
prototype[step.name] = step.convert(prototype[step.name]);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function applyPlan(plan, message) {
|
|
234
|
-
for (const step of plan) {
|
|
235
|
-
if (!Object.hasOwn(message, step.name)) {
|
|
236
|
-
continue;
|
|
237
|
-
}
|
|
238
|
-
const value = message[step.name];
|
|
239
|
-
if (value == null) {
|
|
240
|
-
continue;
|
|
241
|
-
}
|
|
242
|
-
switch (step.shape) {
|
|
243
|
-
case "single":
|
|
244
|
-
message[step.name] =
|
|
245
|
-
step.convert === undefined ? applyPlan(step.nested, value) : step.convert(value);
|
|
246
|
-
break;
|
|
247
|
-
case "repeated":
|
|
248
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
249
|
-
value[index] =
|
|
250
|
-
step.convert === undefined
|
|
251
|
-
? applyPlan(step.nested, value[index])
|
|
252
|
-
: step.convert(value[index]);
|
|
253
|
-
}
|
|
254
|
-
break;
|
|
255
|
-
case "map":
|
|
256
|
-
if (step.convertKey === undefined) {
|
|
257
|
-
convertMapValues(step, value);
|
|
258
|
-
} else {
|
|
259
|
-
message[step.name] = convertMap(step, value);
|
|
260
|
-
}
|
|
261
|
-
break;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
return message;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/** Returns a copy of a decoded map with converted keys and values. */
|
|
268
|
-
function convertMap(step, map) {
|
|
269
|
-
const converted = {};
|
|
270
|
-
for (const [key, value] of Object.entries(map)) {
|
|
271
|
-
converted[step.convertKey(key)] = convertMapValue(step, value);
|
|
272
|
-
}
|
|
273
|
-
return converted;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/** Converts the values of a decoded map in place. */
|
|
277
|
-
function convertMapValues(step, map) {
|
|
278
|
-
for (const [key, value] of Object.entries(map)) {
|
|
279
|
-
map[key] = convertMapValue(step, value);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
function convertMapValue(step, value) {
|
|
284
|
-
if (step.convert !== undefined) {
|
|
285
|
-
return step.convert(value);
|
|
286
|
-
}
|
|
287
|
-
return step.nested !== undefined && value != null ? applyPlan(step.nested, value) : value;
|
|
288
|
-
}
|
package/src/wkt.js
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
// Helpers for the well-known types google.protobuf.Timestamp, Duration, Struct, Value and
|
|
2
|
-
// ListValue, whose declarations generated code imports from the runtime.
|
|
3
|
-
import { int64ToBigInt } from "./int64.js";
|
|
4
|
-
import { invalidArgument } from "./status.js";
|
|
5
|
-
|
|
6
|
-
/** google.protobuf.NullValue. */
|
|
7
|
-
export const NullValue = Object.freeze({ NULL_VALUE: 0 });
|
|
8
|
-
|
|
9
|
-
const MsPerSecond = 1000n;
|
|
10
|
-
const NanosPerMs = 1_000_000;
|
|
11
|
-
|
|
12
|
-
/** Returns the Timestamp of a Date. */
|
|
13
|
-
export function timestampFromDate(date) {
|
|
14
|
-
return timestampFromMs(date.getTime());
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** Returns the Timestamp of milliseconds since the Unix epoch. */
|
|
18
|
-
export function timestampFromMs(ms) {
|
|
19
|
-
checkFinite(ms, "timestamp");
|
|
20
|
-
const whole = Math.floor(ms);
|
|
21
|
-
const seconds = Math.floor(whole / 1000);
|
|
22
|
-
return { seconds: BigInt(seconds), nanos: (whole - seconds * 1000) * NanosPerMs };
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/** Returns the Date of a Timestamp. */
|
|
26
|
-
export function timestampDate(timestamp) {
|
|
27
|
-
return new Date(timestampMs(timestamp));
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/** Returns the milliseconds since the Unix epoch of a Timestamp, rounded down. */
|
|
31
|
-
export function timestampMs(timestamp) {
|
|
32
|
-
return toMs(timestamp, Math.floor);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** Returns the Duration of a number of milliseconds. */
|
|
36
|
-
export function durationFromMs(ms) {
|
|
37
|
-
checkFinite(ms, "duration");
|
|
38
|
-
const whole = Math.trunc(ms);
|
|
39
|
-
const seconds = Math.trunc(whole / 1000);
|
|
40
|
-
// Seconds and nanos share the duration's sign; `+ 0` turns -0 into 0.
|
|
41
|
-
return { seconds: BigInt(seconds), nanos: (whole - seconds * 1000) * NanosPerMs + 0 };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/** Returns the milliseconds of a Duration, rounded towards zero. */
|
|
45
|
-
export function durationMs(duration) {
|
|
46
|
-
return toMs(duration, Math.trunc);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** Returns the Struct of a JSON object. */
|
|
50
|
-
export function structFromJson(json) {
|
|
51
|
-
if (json === null || typeof json !== "object" || Array.isArray(json)) {
|
|
52
|
-
throw invalidArgument("a Struct is made from a JSON object");
|
|
53
|
-
}
|
|
54
|
-
const fields = {};
|
|
55
|
-
for (const [key, value] of Object.entries(json)) {
|
|
56
|
-
fields[key] = valueFromJson(value);
|
|
57
|
-
}
|
|
58
|
-
return { fields };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
/** Returns the JSON object of a Struct. */
|
|
62
|
-
export function structToJson(struct) {
|
|
63
|
-
const json = {};
|
|
64
|
-
for (const [key, value] of Object.entries(struct?.fields ?? {})) {
|
|
65
|
-
json[key] = valueToJson(value);
|
|
66
|
-
}
|
|
67
|
-
return json;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/** Returns the Value of a JSON value. */
|
|
71
|
-
export function valueFromJson(json) {
|
|
72
|
-
if (json === null) {
|
|
73
|
-
return { nullValue: NullValue.NULL_VALUE };
|
|
74
|
-
}
|
|
75
|
-
switch (typeof json) {
|
|
76
|
-
case "number":
|
|
77
|
-
return { numberValue: json };
|
|
78
|
-
case "string":
|
|
79
|
-
return { stringValue: json };
|
|
80
|
-
case "boolean":
|
|
81
|
-
return { boolValue: json };
|
|
82
|
-
case "object":
|
|
83
|
-
return Array.isArray(json)
|
|
84
|
-
? { listValue: { values: json.map(valueFromJson) } }
|
|
85
|
-
: { structValue: structFromJson(json) };
|
|
86
|
-
default:
|
|
87
|
-
throw invalidArgument(`a Value cannot hold a ${typeof json}`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/** Returns the JSON value of a Value; a Value with no kind set is null. */
|
|
92
|
-
export function valueToJson(value) {
|
|
93
|
-
switch (valueKind(value)) {
|
|
94
|
-
case "numberValue":
|
|
95
|
-
return value.numberValue;
|
|
96
|
-
case "stringValue":
|
|
97
|
-
return value.stringValue;
|
|
98
|
-
case "boolValue":
|
|
99
|
-
return value.boolValue;
|
|
100
|
-
case "structValue":
|
|
101
|
-
return structToJson(value.structValue);
|
|
102
|
-
case "listValue":
|
|
103
|
-
return (value.listValue.values ?? []).map(valueToJson);
|
|
104
|
-
default:
|
|
105
|
-
return null;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const ValueKinds = [
|
|
110
|
-
"nullValue",
|
|
111
|
-
"numberValue",
|
|
112
|
-
"stringValue",
|
|
113
|
-
"boolValue",
|
|
114
|
-
"structValue",
|
|
115
|
-
"listValue",
|
|
116
|
-
];
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* The member of a Value's `kind` oneof that is set. A decoded Value reads the defaults of the
|
|
120
|
-
* other members from its prototype, so only own properties count.
|
|
121
|
-
*/
|
|
122
|
-
function valueKind(value) {
|
|
123
|
-
return ValueKinds.find(
|
|
124
|
-
(kind) => value != null && Object.hasOwn(value, kind) && value[kind] != null,
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/** The milliseconds of a Timestamp or Duration, with sub-millisecond nanos rounded by `round`. */
|
|
129
|
-
function toMs({ seconds, nanos } = {}, round) {
|
|
130
|
-
return Number(int64ToBigInt(seconds) * MsPerSecond) + round((nanos ?? 0) / NanosPerMs);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function checkFinite(ms, what) {
|
|
134
|
-
if (!Number.isFinite(ms)) {
|
|
135
|
-
throw invalidArgument(`a ${what} needs a finite number of milliseconds, not ${ms}`);
|
|
136
|
-
}
|
|
137
|
-
}
|