@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/wire.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
// The protobuf codec of the REQUEST, HEADERS, ANSWER and STATUS payloads, written against the wire
|
|
2
|
+
// format directly, as the Go and Kotlin runtimes do (see "Protocol and Wire Format" in the wiki).
|
|
3
|
+
// Encoding is canonical proto3: fields in number order, zero values left out, and both fields of a
|
|
4
|
+
// map entry always written. Decoding accepts only what a conforming sender produces: a known field
|
|
5
|
+
// with another wire type, a uint32 above 2^32 - 1, a varint above 64 bits, invalid UTF-8 and
|
|
6
|
+
// truncated data are all errors, while unknown fields of every wire type are skipped.
|
|
7
|
+
import { BinaryReader, BinaryWriter, WireType } from "@bufbuild/protobuf/wire";
|
|
7
8
|
|
|
8
9
|
export const RpcKind = Object.freeze({
|
|
9
10
|
Unary: 0,
|
|
@@ -19,373 +20,460 @@ export const StreamCompression = Object.freeze({
|
|
|
19
20
|
Optimistic: 2,
|
|
20
21
|
});
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
23
|
+
/** How deeply unknown groups may nest. */
|
|
24
|
+
const MaxGroupDepth = 64;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The REQUEST payload: `{ method, metadata, kind, timeoutNanos, datagramFlow, acceptDictionaries,
|
|
28
|
+
* dictionaryQuery, streamCompression, connectionMetadata }`. 64-bit fields encode from a bigint, a
|
|
29
|
+
* number or a decimal string and decode as bigints; `connectionMetadata` is `{ id, metadata }`, or
|
|
30
|
+
* undefined when absent.
|
|
31
|
+
*/
|
|
32
|
+
export const RpcRequest = Object.freeze({
|
|
33
|
+
name: "RpcRequest",
|
|
34
|
+
encode(request) {
|
|
35
|
+
const writer = new BinaryWriter();
|
|
36
|
+
writeString(writer, 1, request.method);
|
|
37
|
+
writeMetadata(writer, 2, request.metadata);
|
|
38
|
+
writeInt32(writer, 3, request.kind);
|
|
39
|
+
writeUint64(writer, 4, request.timeoutNanos);
|
|
40
|
+
writeUint64(writer, 5, request.datagramFlow);
|
|
41
|
+
const accept = request.acceptDictionaries;
|
|
42
|
+
if (accept != null && accept.length > 0) {
|
|
43
|
+
writer.tag(6, WireType.LengthDelimited).fork();
|
|
44
|
+
for (const id of accept) {
|
|
45
|
+
writer.uint32(id);
|
|
46
|
+
}
|
|
47
|
+
writer.join();
|
|
48
|
+
}
|
|
49
|
+
writeDictionaries(writer, 7, request.dictionaryQuery);
|
|
50
|
+
writeInt32(writer, 8, request.streamCompression);
|
|
51
|
+
const connection = request.connectionMetadata;
|
|
52
|
+
if (connection != null) {
|
|
53
|
+
writer.tag(9, WireType.LengthDelimited).fork();
|
|
54
|
+
writeUint32(writer, 1, connection.id);
|
|
55
|
+
writeMetadata(writer, 2, connection.metadata);
|
|
56
|
+
writer.join();
|
|
57
|
+
}
|
|
58
|
+
return writer.finish();
|
|
59
|
+
},
|
|
60
|
+
decode(bytes) {
|
|
61
|
+
const request = {
|
|
62
|
+
method: "",
|
|
63
|
+
metadata: emptyMetadata(),
|
|
64
|
+
kind: 0,
|
|
65
|
+
timeoutNanos: 0n,
|
|
66
|
+
datagramFlow: 0n,
|
|
67
|
+
acceptDictionaries: [],
|
|
68
|
+
dictionaryQuery: [],
|
|
69
|
+
streamCompression: 0,
|
|
70
|
+
connectionMetadata: undefined,
|
|
71
|
+
};
|
|
72
|
+
const reader = new WireReader(bytes);
|
|
73
|
+
while (reader.more()) {
|
|
74
|
+
const [field, wireType] = reader.tag();
|
|
75
|
+
switch (field) {
|
|
76
|
+
case 1:
|
|
77
|
+
request.method = reader.string(wireType, "method");
|
|
78
|
+
break;
|
|
79
|
+
case 2:
|
|
80
|
+
reader.metadataEntry(wireType, request.metadata, "metadata");
|
|
81
|
+
break;
|
|
82
|
+
case 3:
|
|
83
|
+
request.kind = reader.int32(wireType, "kind");
|
|
84
|
+
break;
|
|
85
|
+
case 4:
|
|
86
|
+
request.timeoutNanos = reader.uint64(wireType, "timeout_nanos");
|
|
87
|
+
break;
|
|
88
|
+
case 5:
|
|
89
|
+
request.datagramFlow = reader.uint64(wireType, "datagram_flow");
|
|
90
|
+
break;
|
|
91
|
+
case 6:
|
|
92
|
+
reader.repeatedUint32(wireType, request.acceptDictionaries, "accept_dictionaries");
|
|
93
|
+
break;
|
|
94
|
+
case 7:
|
|
95
|
+
request.dictionaryQuery.push(reader.dictionaryInfo(wireType, "dictionary_query"));
|
|
96
|
+
break;
|
|
97
|
+
case 8:
|
|
98
|
+
request.streamCompression = reader.int32(wireType, "stream_compression");
|
|
99
|
+
break;
|
|
100
|
+
case 9:
|
|
101
|
+
request.connectionMetadata = reader.connectionMetadata(wireType, "connection_metadata");
|
|
102
|
+
break;
|
|
103
|
+
default:
|
|
104
|
+
reader.skip(field, wireType);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return request;
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
/** The HEADERS payload: `{ metadata }`. */
|
|
112
|
+
export const RpcHeaders = Object.freeze({
|
|
113
|
+
name: "RpcHeaders",
|
|
114
|
+
encode(headers) {
|
|
115
|
+
const writer = new BinaryWriter();
|
|
116
|
+
writeMetadata(writer, 1, headers.metadata);
|
|
117
|
+
return writer.finish();
|
|
118
|
+
},
|
|
119
|
+
decode(bytes) {
|
|
120
|
+
const headers = { metadata: emptyMetadata() };
|
|
121
|
+
const reader = new WireReader(bytes);
|
|
122
|
+
while (reader.more()) {
|
|
123
|
+
const [field, wireType] = reader.tag();
|
|
124
|
+
if (field === 1) {
|
|
125
|
+
reader.metadataEntry(wireType, headers.metadata, "metadata");
|
|
126
|
+
} else {
|
|
127
|
+
reader.skip(field, wireType);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return headers;
|
|
88
131
|
},
|
|
89
132
|
});
|
|
90
133
|
|
|
91
|
-
|
|
92
|
-
export const
|
|
93
|
-
|
|
94
|
-
|
|
134
|
+
/** The ANSWER payload: `{ dictionaries, streamCompression, connectionMetadata }`. */
|
|
135
|
+
export const RpcAnswer = Object.freeze({
|
|
136
|
+
name: "RpcAnswer",
|
|
137
|
+
encode(answer) {
|
|
138
|
+
const writer = new BinaryWriter();
|
|
139
|
+
writeDictionaries(writer, 1, answer.dictionaries);
|
|
140
|
+
writeBool(writer, 2, answer.streamCompression);
|
|
141
|
+
writeUint32(writer, 3, answer.connectionMetadata);
|
|
142
|
+
return writer.finish();
|
|
143
|
+
},
|
|
144
|
+
decode(bytes) {
|
|
145
|
+
const answer = { dictionaries: [], streamCompression: false, connectionMetadata: 0 };
|
|
146
|
+
const reader = new WireReader(bytes);
|
|
147
|
+
while (reader.more()) {
|
|
148
|
+
const [field, wireType] = reader.tag();
|
|
149
|
+
switch (field) {
|
|
150
|
+
case 1:
|
|
151
|
+
answer.dictionaries.push(reader.dictionaryInfo(wireType, "dictionaries"));
|
|
152
|
+
break;
|
|
153
|
+
case 2:
|
|
154
|
+
answer.streamCompression = reader.bool(wireType, "stream_compression");
|
|
155
|
+
break;
|
|
156
|
+
case 3:
|
|
157
|
+
answer.connectionMetadata = reader.uint32(wireType, "connection_metadata");
|
|
158
|
+
break;
|
|
159
|
+
default:
|
|
160
|
+
reader.skip(field, wireType);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return answer;
|
|
164
|
+
},
|
|
165
|
+
});
|
|
95
166
|
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
167
|
+
/** The STATUS payload: `{ code, message, metadata, refusedStreamCompression }`. */
|
|
168
|
+
export const RpcStatus = Object.freeze({
|
|
169
|
+
name: "RpcStatus",
|
|
170
|
+
encode(status) {
|
|
171
|
+
const writer = new BinaryWriter();
|
|
172
|
+
writeUint32(writer, 1, status.code);
|
|
173
|
+
writeString(writer, 2, status.message);
|
|
174
|
+
writeMetadata(writer, 3, status.metadata);
|
|
175
|
+
writeBool(writer, 4, status.refusedStreamCompression);
|
|
176
|
+
return writer.finish();
|
|
177
|
+
},
|
|
178
|
+
decode(bytes) {
|
|
179
|
+
const status = {
|
|
180
|
+
code: 0,
|
|
181
|
+
message: "",
|
|
182
|
+
metadata: emptyMetadata(),
|
|
183
|
+
refusedStreamCompression: false,
|
|
184
|
+
};
|
|
185
|
+
const reader = new WireReader(bytes);
|
|
186
|
+
while (reader.more()) {
|
|
187
|
+
const [field, wireType] = reader.tag();
|
|
188
|
+
switch (field) {
|
|
189
|
+
case 1:
|
|
190
|
+
status.code = reader.uint32(wireType, "code");
|
|
191
|
+
break;
|
|
192
|
+
case 2:
|
|
193
|
+
status.message = reader.string(wireType, "message");
|
|
194
|
+
break;
|
|
195
|
+
case 3:
|
|
196
|
+
reader.metadataEntry(wireType, status.metadata, "metadata");
|
|
197
|
+
break;
|
|
198
|
+
case 4:
|
|
199
|
+
status.refusedStreamCompression = reader.bool(wireType, "refused_stream_compression");
|
|
200
|
+
break;
|
|
201
|
+
default:
|
|
202
|
+
reader.skip(field, wireType);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return status;
|
|
206
|
+
},
|
|
207
|
+
});
|
|
100
208
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
scanMessage(messageType, byteView(body), 0);
|
|
209
|
+
function emptyMetadata() {
|
|
210
|
+
return {};
|
|
104
211
|
}
|
|
105
212
|
|
|
106
213
|
/**
|
|
107
|
-
*
|
|
108
|
-
*
|
|
214
|
+
* Sets a decoded metadata entry as an own property, so that a key such as `__proto__` is an entry
|
|
215
|
+
* like any other and never replaces the object's prototype.
|
|
109
216
|
*/
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
217
|
+
function setEntry(metadata, key, value) {
|
|
218
|
+
Object.defineProperty(metadata, key, {
|
|
219
|
+
value,
|
|
220
|
+
enumerable: true,
|
|
221
|
+
writable: true,
|
|
222
|
+
configurable: true,
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function writeString(writer, field, value) {
|
|
227
|
+
if (value != null && value !== "") {
|
|
228
|
+
writer.tag(field, WireType.LengthDelimited).string(value);
|
|
114
229
|
}
|
|
115
|
-
return root;
|
|
116
230
|
}
|
|
117
231
|
|
|
118
|
-
function
|
|
119
|
-
if (
|
|
120
|
-
|
|
232
|
+
function writeInt32(writer, field, value) {
|
|
233
|
+
if (value != null && value !== 0) {
|
|
234
|
+
writer.tag(field, WireType.Varint).int32(value);
|
|
121
235
|
}
|
|
236
|
+
}
|
|
122
237
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (fieldNumber === 0 || fieldNumber > MaxFieldNumber) {
|
|
129
|
-
throw malformedWire("invalid protobuf field tag");
|
|
130
|
-
}
|
|
238
|
+
function writeUint32(writer, field, value) {
|
|
239
|
+
if (value != null && value !== 0) {
|
|
240
|
+
writer.tag(field, WireType.Varint).uint32(value);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
131
243
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
244
|
+
function writeUint64(writer, field, value) {
|
|
245
|
+
if (value != null && value !== 0 && value !== 0n && value !== "0") {
|
|
246
|
+
writer.tag(field, WireType.Varint).uint64(value);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
137
249
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
scanKnownField(field, bytes, cursor, wireType, depth);
|
|
250
|
+
function writeBool(writer, field, value) {
|
|
251
|
+
if (value) {
|
|
252
|
+
writer.tag(field, WireType.Varint).bool(true);
|
|
142
253
|
}
|
|
143
254
|
}
|
|
144
255
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (isUint32Field(field) && value > MaxUint32) {
|
|
149
|
-
throw malformedWire(`protobuf field ${field.name} exceeded uint32`);
|
|
150
|
-
}
|
|
256
|
+
/** Writes a `map<string, bytes>` field; both fields of every entry, even when empty. */
|
|
257
|
+
function writeMetadata(writer, field, metadata) {
|
|
258
|
+
if (metadata == null) {
|
|
151
259
|
return;
|
|
152
260
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
261
|
+
for (const key of Object.keys(metadata)) {
|
|
262
|
+
writer
|
|
263
|
+
.tag(field, WireType.LengthDelimited)
|
|
264
|
+
.fork()
|
|
265
|
+
.tag(1, WireType.LengthDelimited)
|
|
266
|
+
.string(key)
|
|
267
|
+
.tag(2, WireType.LengthDelimited)
|
|
268
|
+
.bytes(metadata[key])
|
|
269
|
+
.join();
|
|
156
270
|
}
|
|
157
|
-
|
|
158
|
-
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Writes a repeated DictionaryInfo field `{ id, fingerprint }`; an empty entry is still sent. */
|
|
274
|
+
function writeDictionaries(writer, field, infos) {
|
|
275
|
+
if (infos == null) {
|
|
159
276
|
return;
|
|
160
277
|
}
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
} else if (field.resolvedType?.fieldsById != null) {
|
|
169
|
-
scanMessage(field.resolvedType, value, depth + 1);
|
|
170
|
-
} else if (field.type === "string") {
|
|
171
|
-
validateUtf8(value, field.name);
|
|
172
|
-
} else if (field.repeated && isPackableField(field)) {
|
|
173
|
-
scanPackedField(field, value);
|
|
278
|
+
for (const info of infos) {
|
|
279
|
+
writer.tag(field, WireType.LengthDelimited).fork();
|
|
280
|
+
writeUint32(writer, 1, info.id);
|
|
281
|
+
if (info.fingerprint != null && info.fingerprint.byteLength > 0) {
|
|
282
|
+
writer.tag(2, WireType.LengthDelimited).bytes(info.fingerprint);
|
|
283
|
+
}
|
|
284
|
+
writer.join();
|
|
174
285
|
}
|
|
175
286
|
}
|
|
176
287
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
const tag = readVarint(bytes, cursor, "truncated protobuf map entry tag");
|
|
185
|
-
const fieldNumber = Number(tag >> 3n);
|
|
186
|
-
const wireType = Number(tag & 7n);
|
|
187
|
-
if (fieldNumber === 0 || fieldNumber > MaxFieldNumber) {
|
|
188
|
-
throw malformedWire("invalid protobuf map entry tag");
|
|
189
|
-
}
|
|
288
|
+
/**
|
|
289
|
+
* Reads the fields of one wire message, checking each known field's wire type and range. Every
|
|
290
|
+
* failure is an Error, which the frame layer reports as InvalidArgument.
|
|
291
|
+
*/
|
|
292
|
+
class WireReader {
|
|
293
|
+
#bytes;
|
|
294
|
+
#reader;
|
|
190
295
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const messageType = field.resolvedType?.fieldsById != null ? field.resolvedType : undefined;
|
|
195
|
-
scanSyntheticField(
|
|
196
|
-
field.type,
|
|
197
|
-
`${field.name}.value`,
|
|
198
|
-
bytes,
|
|
199
|
-
cursor,
|
|
200
|
-
wireType,
|
|
201
|
-
depth,
|
|
202
|
-
messageType,
|
|
203
|
-
);
|
|
204
|
-
} else {
|
|
205
|
-
skipUnknownField(bytes, cursor, fieldNumber, wireType, depth);
|
|
206
|
-
}
|
|
296
|
+
constructor(bytes) {
|
|
297
|
+
this.#bytes = bytes;
|
|
298
|
+
this.#reader = new BinaryReader(bytes);
|
|
207
299
|
}
|
|
208
|
-
}
|
|
209
300
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const expected = messageType === undefined ? scalarWireType(type) : 2;
|
|
213
|
-
if (wireType !== expected) {
|
|
214
|
-
throw malformedWire(`field ${name} used incompatible protobuf wire type ${wireType}`);
|
|
301
|
+
more() {
|
|
302
|
+
return this.#reader.pos < this.#reader.len;
|
|
215
303
|
}
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
221
|
-
} else if (wireType === 1) {
|
|
222
|
-
skipFixed(bytes, cursor, 8, name);
|
|
223
|
-
} else if (wireType === 5) {
|
|
224
|
-
skipFixed(bytes, cursor, 4, name);
|
|
225
|
-
} else if (wireType === 2) {
|
|
226
|
-
const value = readLengthDelimited(bytes, cursor, `truncated protobuf field ${name}`);
|
|
227
|
-
if (messageType !== undefined) {
|
|
228
|
-
scanMessage(messageType, value, depth + 1);
|
|
229
|
-
} else if (type === "string") {
|
|
230
|
-
validateUtf8(value, name);
|
|
231
|
-
}
|
|
232
|
-
} else {
|
|
233
|
-
skipUnknownField(bytes, cursor, 0, wireType, depth);
|
|
304
|
+
|
|
305
|
+
/** The next field's number, at least 1, and wire type. */
|
|
306
|
+
tag() {
|
|
307
|
+
return this.#reader.tag();
|
|
234
308
|
}
|
|
235
|
-
}
|
|
236
309
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
while (cursor.offset < bytes.byteLength) {
|
|
241
|
-
if (wireType === 0) {
|
|
242
|
-
const value = readVarint(bytes, cursor, `truncated packed protobuf field ${field.name}`);
|
|
243
|
-
if (isUint32Field(field) && value > MaxUint32) {
|
|
244
|
-
throw malformedWire(`protobuf field ${field.name} exceeded uint32`);
|
|
245
|
-
}
|
|
246
|
-
} else if (wireType === 1) {
|
|
247
|
-
skipFixed(bytes, cursor, 8, field.name);
|
|
248
|
-
} else if (wireType === 5) {
|
|
249
|
-
skipFixed(bytes, cursor, 4, field.name);
|
|
250
|
-
} else {
|
|
251
|
-
throw malformedWire(`protobuf field ${field.name} cannot be packed`);
|
|
252
|
-
}
|
|
310
|
+
string(wireType, name) {
|
|
311
|
+
expectWireType(wireType, WireType.LengthDelimited, name);
|
|
312
|
+
return this.#reader.string(true);
|
|
253
313
|
}
|
|
254
|
-
}
|
|
255
314
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
return [2];
|
|
315
|
+
bytes(wireType, name) {
|
|
316
|
+
expectWireType(wireType, WireType.LengthDelimited, name);
|
|
317
|
+
return this.#reader.bytes();
|
|
260
318
|
}
|
|
261
|
-
const expected = field.resolvedType?.fieldsById != null ? 2 : scalarWireType(field.type);
|
|
262
|
-
return field.repeated && isPackableField(field) ? [expected, 2] : [expected];
|
|
263
|
-
}
|
|
264
319
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
case "fixed64":
|
|
269
|
-
case "sfixed64":
|
|
270
|
-
return 1;
|
|
271
|
-
case "string":
|
|
272
|
-
case "bytes":
|
|
273
|
-
return 2;
|
|
274
|
-
case "float":
|
|
275
|
-
case "fixed32":
|
|
276
|
-
case "sfixed32":
|
|
277
|
-
return 5;
|
|
278
|
-
default:
|
|
279
|
-
return 0;
|
|
320
|
+
bool(wireType, name) {
|
|
321
|
+
expectWireType(wireType, WireType.Varint, name);
|
|
322
|
+
return this.#reader.bool();
|
|
280
323
|
}
|
|
281
|
-
}
|
|
282
324
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
}
|
|
325
|
+
int32(wireType, name) {
|
|
326
|
+
expectWireType(wireType, WireType.Varint, name);
|
|
327
|
+
return this.#reader.int32();
|
|
328
|
+
}
|
|
288
329
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
330
|
+
uint32(wireType, name) {
|
|
331
|
+
expectWireType(wireType, WireType.Varint, name);
|
|
332
|
+
return this.#uint32Value(name);
|
|
333
|
+
}
|
|
292
334
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
335
|
+
uint64(wireType, name) {
|
|
336
|
+
expectWireType(wireType, WireType.Varint, name);
|
|
337
|
+
return BigInt(this.#reader.uint64());
|
|
338
|
+
}
|
|
296
339
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
340
|
+
/** Appends one value, or a packed run of values, of a repeated uint32 field to `values`. */
|
|
341
|
+
repeatedUint32(wireType, values, name) {
|
|
342
|
+
if (wireType === WireType.Varint) {
|
|
343
|
+
values.push(this.#uint32Value(name));
|
|
344
|
+
return;
|
|
302
345
|
}
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
|
|
346
|
+
const packed = this.#nested(wireType, name);
|
|
347
|
+
while (packed.more()) {
|
|
348
|
+
values.push(packed.#uint32Value(name));
|
|
306
349
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** A DictionaryInfo message, `{ id, fingerprint }`. */
|
|
353
|
+
dictionaryInfo(wireType, name) {
|
|
354
|
+
const reader = this.#nested(wireType, name);
|
|
355
|
+
const info = { id: 0, fingerprint: new Uint8Array(0) };
|
|
356
|
+
while (reader.more()) {
|
|
357
|
+
const [field, fieldWireType] = reader.tag();
|
|
358
|
+
if (field === 1) {
|
|
359
|
+
info.id = reader.uint32(fieldWireType, `${name}.id`);
|
|
360
|
+
} else if (field === 2) {
|
|
361
|
+
info.fingerprint = reader.bytes(fieldWireType, `${name}.fingerprint`);
|
|
362
|
+
} else {
|
|
363
|
+
reader.skip(field, fieldWireType);
|
|
311
364
|
}
|
|
312
|
-
return value;
|
|
313
365
|
}
|
|
366
|
+
return info;
|
|
314
367
|
}
|
|
315
|
-
throw malformedWire("protobuf varint exceeded 64 bits");
|
|
316
|
-
}
|
|
317
368
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
369
|
+
/** A ConnectionMetadata message, `{ id, metadata }`. */
|
|
370
|
+
connectionMetadata(wireType, name) {
|
|
371
|
+
const reader = this.#nested(wireType, name);
|
|
372
|
+
const connection = { id: 0, metadata: emptyMetadata() };
|
|
373
|
+
while (reader.more()) {
|
|
374
|
+
const [field, fieldWireType] = reader.tag();
|
|
375
|
+
if (field === 1) {
|
|
376
|
+
connection.id = reader.uint32(fieldWireType, `${name}.id`);
|
|
377
|
+
} else if (field === 2) {
|
|
378
|
+
reader.metadataEntry(fieldWireType, connection.metadata, `${name}.metadata`);
|
|
379
|
+
} else {
|
|
380
|
+
reader.skip(field, fieldWireType);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
return connection;
|
|
322
384
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
385
|
+
|
|
386
|
+
/** Adds one `map<string, bytes>` entry to `metadata`; a later entry for a key replaces it. */
|
|
387
|
+
metadataEntry(wireType, metadata, name) {
|
|
388
|
+
const reader = this.#nested(wireType, name);
|
|
389
|
+
let key = "";
|
|
390
|
+
let value = new Uint8Array(0);
|
|
391
|
+
while (reader.more()) {
|
|
392
|
+
const [field, fieldWireType] = reader.tag();
|
|
393
|
+
if (field === 1) {
|
|
394
|
+
key = reader.string(fieldWireType, `${name}.key`);
|
|
395
|
+
} else if (field === 2) {
|
|
396
|
+
value = reader.bytes(fieldWireType, `${name}.value`);
|
|
397
|
+
} else {
|
|
398
|
+
reader.skip(field, fieldWireType);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
setEntry(metadata, key, value);
|
|
326
402
|
}
|
|
327
|
-
const value = bytes.subarray(cursor.offset, end);
|
|
328
|
-
cursor.offset = end;
|
|
329
|
-
return value;
|
|
330
|
-
}
|
|
331
403
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
case 5:
|
|
347
|
-
skipFixed(bytes, cursor, 4, "unknown");
|
|
348
|
-
return;
|
|
349
|
-
default:
|
|
350
|
-
throw malformedWire(`unsupported protobuf wire type ${wireType}`);
|
|
404
|
+
/** Skips an unknown field of any wire type. */
|
|
405
|
+
skip(field, wireType, depth = 0) {
|
|
406
|
+
switch (wireType) {
|
|
407
|
+
case WireType.Varint:
|
|
408
|
+
this.#skipVarint();
|
|
409
|
+
return;
|
|
410
|
+
case WireType.StartGroup:
|
|
411
|
+
this.#skipGroup(field, depth + 1);
|
|
412
|
+
return;
|
|
413
|
+
case WireType.EndGroup:
|
|
414
|
+
throw new Error("protobuf end group tag without a start group");
|
|
415
|
+
default:
|
|
416
|
+
this.#reader.skip(wireType, field);
|
|
417
|
+
}
|
|
351
418
|
}
|
|
352
|
-
}
|
|
353
419
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
420
|
+
#skipGroup(field, depth) {
|
|
421
|
+
if (depth > MaxGroupDepth) {
|
|
422
|
+
throw new Error("protobuf group nesting exceeded limit");
|
|
423
|
+
}
|
|
424
|
+
while (this.more()) {
|
|
425
|
+
const [nested, wireType] = this.tag();
|
|
426
|
+
if (wireType === WireType.EndGroup) {
|
|
427
|
+
if (nested !== field) {
|
|
428
|
+
throw new Error("protobuf group end tag did not match start tag");
|
|
429
|
+
}
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
this.skip(nested, wireType, depth);
|
|
433
|
+
}
|
|
434
|
+
throw new Error("unterminated protobuf group");
|
|
357
435
|
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
436
|
+
|
|
437
|
+
/** Skips a varint of at most 64 bits (10 bytes, the last at most 1). */
|
|
438
|
+
#skipVarint() {
|
|
439
|
+
const bytes = this.#bytes;
|
|
440
|
+
const reader = this.#reader;
|
|
441
|
+
for (let index = 0; index < 10; index += 1) {
|
|
442
|
+
if (reader.pos >= reader.len) {
|
|
443
|
+
throw new Error("truncated protobuf varint");
|
|
444
|
+
}
|
|
445
|
+
const byte = bytes[reader.pos++];
|
|
446
|
+
if (byte < 0x80) {
|
|
447
|
+
if (index === 9 && byte > 1) {
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
return;
|
|
365
451
|
}
|
|
366
|
-
return;
|
|
367
452
|
}
|
|
368
|
-
|
|
453
|
+
throw new Error("protobuf varint exceeded 64 bits");
|
|
369
454
|
}
|
|
370
|
-
throw malformedWire("unterminated protobuf group");
|
|
371
|
-
}
|
|
372
455
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
456
|
+
/** Reads a varint that must fit in 32 bits: at most 5 bytes, the last at most 0x0f. */
|
|
457
|
+
#uint32Value(name) {
|
|
458
|
+
const reader = this.#reader;
|
|
459
|
+
const start = reader.pos;
|
|
460
|
+
const value = reader.uint32();
|
|
461
|
+
const length = reader.pos - start;
|
|
462
|
+
if (length > 5 || (length === 5 && this.#bytes[reader.pos - 1] > 0x0f)) {
|
|
463
|
+
throw new Error(`protobuf field ${name} exceeded uint32`);
|
|
464
|
+
}
|
|
465
|
+
return value;
|
|
377
466
|
}
|
|
378
|
-
cursor.offset = end;
|
|
379
|
-
}
|
|
380
467
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
throw malformedWire(`protobuf field ${name} was not valid UTF-8`);
|
|
468
|
+
/** A reader over the length-delimited value of field `name`. */
|
|
469
|
+
#nested(wireType, name) {
|
|
470
|
+
expectWireType(wireType, WireType.LengthDelimited, name);
|
|
471
|
+
return new WireReader(this.#reader.bytes());
|
|
386
472
|
}
|
|
387
473
|
}
|
|
388
474
|
|
|
389
|
-
function
|
|
390
|
-
|
|
475
|
+
function expectWireType(wireType, expected, name) {
|
|
476
|
+
if (wireType !== expected) {
|
|
477
|
+
throw new Error(`field ${name} used incompatible protobuf wire type ${wireType}`);
|
|
478
|
+
}
|
|
391
479
|
}
|