skir-client 0.0.1

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.
@@ -0,0 +1,2392 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports._initModuleClasses = exports.installServiceOnExpressApp = exports.Service = exports.RawResponse = exports.ServiceClient = exports._EnumBase = exports._FrozenBase = exports._toFrozenArray = exports._EMPTY_ARRAY = exports.parseTypeDescriptorFromJsonCode = exports.parseTypeDescriptorFromJson = exports.optionalSerializer = exports.arraySerializer = exports.primitiveSerializer = exports.ByteString = exports.Timestamp = void 0;
13
+ /**
14
+ * A single moment in time represented in a platform-independent format, with a
15
+ * precision of one millisecond.
16
+ *
17
+ * A `Timestamp` object can represent a maximum of ±8,640,000,000,000,000
18
+ * milliseconds, or ±100,000,000 (one hundred million) days, relative to the
19
+ * Unix epoch. This is the range from April 20, 271821 BC to September 13,
20
+ * 275760 AD.
21
+ *
22
+ * Unlike the Javascript built-in `Date` type, a `Timestamp` is immutable.
23
+ * Like a `Date`, a `Timestamp` object does not contain a timezone.
24
+ */
25
+ class Timestamp {
26
+ /**
27
+ * Returns a `Timestamp` representing the same moment in time as the given
28
+ * Javascript `Date` object.
29
+ *
30
+ * @throws if the given `Date` object has a timestamp value of NaN
31
+ */
32
+ static from(date) {
33
+ return this.fromUnixMillis(date.getTime());
34
+ }
35
+ /**
36
+ * Creates a `Timestamp` object from a number of milliseconds from the Unix
37
+ * epoch.
38
+ *
39
+ * If the given number if outside the valid range (±8,640,000,000,000,000),
40
+ * this function will return `Timestamp.MAX` or `Timestamp.MIN` depending on
41
+ * the sign of the number.
42
+ *
43
+ * @throws if the given number is NaN
44
+ */
45
+ static fromUnixMillis(unixMillis) {
46
+ if (unixMillis <= this.MIN.unixMillis) {
47
+ return Timestamp.MIN;
48
+ }
49
+ else if (unixMillis < Timestamp.MAX.unixMillis) {
50
+ return new Timestamp(Math.round(unixMillis));
51
+ }
52
+ else if (Number.isNaN(unixMillis)) {
53
+ throw new Error("Cannot construct Timestamp from NaN");
54
+ }
55
+ else {
56
+ return Timestamp.MAX;
57
+ }
58
+ }
59
+ /**
60
+ * Creates a `Timestamp` object from a number of seconds from the Unix epoch.
61
+ *
62
+ * If the given number if outside the valid range (±8,640,000,000,000), this
63
+ * function will return `Timestamp.MAX` or `Timestamp.MIN` depending on the
64
+ * sign of the number.
65
+ *
66
+ * @throws if the given number is NaN
67
+ */
68
+ static fromUnixSeconds(unixSeconds) {
69
+ return this.fromUnixMillis(unixSeconds * 1000);
70
+ }
71
+ /**
72
+ * Parses a date in the date time string format.
73
+ *
74
+ * @throws if the given string is not a date in the date time string format
75
+ * @see https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-date-time-string-format
76
+ */
77
+ static parse(date) {
78
+ return this.fromUnixMillis(Date.parse(date));
79
+ }
80
+ /** Returns a `Timestamp` representing the current moment in time. */
81
+ static now() {
82
+ return this.fromUnixMillis(Date.now());
83
+ }
84
+ constructor(
85
+ /** Number of milliseconds ellapsed since the Unix epoch. */
86
+ unixMillis) {
87
+ this.unixMillis = unixMillis;
88
+ Object.freeze(this);
89
+ }
90
+ /** Number of seconds ellapsed since the Unix epoch. */
91
+ get unixSeconds() {
92
+ return this.unixMillis / 1000.0;
93
+ }
94
+ /**
95
+ * Returns a `Date` object representing the same moment in time as this
96
+ * `Timestamp`.
97
+ */
98
+ toDate() {
99
+ return new Date(this.unixMillis);
100
+ }
101
+ toString() {
102
+ return this.toDate().toISOString();
103
+ }
104
+ }
105
+ exports.Timestamp = Timestamp;
106
+ /** Thursday, 1 January 1970. */
107
+ Timestamp.UNIX_EPOCH = new Timestamp(0);
108
+ /**
109
+ * Earliest moment in time representable as a `Timestamp`, namely April 20,
110
+ * 271821 BC.
111
+ *
112
+ * @see https://262.ecma-international.org/5.1/#sec-15.9.1.1
113
+ */
114
+ Timestamp.MIN = new Timestamp(-8640000000000000);
115
+ /**
116
+ * Latest moment in time representable as a `Timestamp`, namely September 13,
117
+ * 275760 AD.
118
+ *
119
+ * @see https://262.ecma-international.org/5.1/#sec-15.9.1.1
120
+ */
121
+ Timestamp.MAX = new Timestamp(8640000000000000);
122
+ /** An immutable array of bytes. */
123
+ class ByteString {
124
+ /**
125
+ * Returns an immutable byte string containing all the bytes of `input` from
126
+ * `start`, inclusive, up to `end`, exclusive.
127
+ *
128
+ * If `input` is an `ArrayBuffer`, this function copies the bytes. Otherwise
129
+ * this function returns a sliced view of the input `ByteString`.
130
+ *
131
+ * @example <caption>Copy an array buffer into a byte string</caption>
132
+ * const byteString = ByteString.sliceOf(arrayBuffer);
133
+ */
134
+ static sliceOf(input, start = 0, end) {
135
+ const { byteLength } = input;
136
+ if (start < 0) {
137
+ start = 0;
138
+ }
139
+ if (end === undefined || end > byteLength) {
140
+ end = byteLength;
141
+ }
142
+ if (end <= start) {
143
+ return ByteString.EMPTY;
144
+ }
145
+ if (input instanceof ByteString) {
146
+ if (start <= 0 && byteLength <= end) {
147
+ // Don't copy the ByteString itself.
148
+ return input;
149
+ }
150
+ else {
151
+ // Don't copy the ArrayBuffer.
152
+ const newByteOffset = input.byteOffset + start;
153
+ const newByteLength = end - start;
154
+ return new ByteString(input.arrayBuffer, newByteOffset, newByteLength);
155
+ }
156
+ }
157
+ else if (input instanceof ArrayBuffer) {
158
+ return new ByteString(input.slice(start, end));
159
+ }
160
+ else if (input instanceof SharedArrayBuffer) {
161
+ const slice = input.slice(start, end);
162
+ const newBuffer = new ArrayBuffer(slice.byteLength);
163
+ new Uint8Array(newBuffer).set(new Uint8Array(slice));
164
+ return new ByteString(newBuffer);
165
+ }
166
+ else {
167
+ const _ = input;
168
+ throw new TypeError(_);
169
+ }
170
+ }
171
+ /**
172
+ * Decodes a Base64 string, which can be obtained by calling `toBase64()`.
173
+ *
174
+ * @throws if the given string is not a valid Base64 string.
175
+ * @see https://en.wikipedia.org/wiki/Base64
176
+ */
177
+ static fromBase64(base64) {
178
+ // See https://developer.mozilla.org/en-US/docs/Glossary/Base64
179
+ const binaryString = atob(base64);
180
+ const array = Uint8Array.from(binaryString, (m) => m.codePointAt(0));
181
+ return new this(array.buffer);
182
+ }
183
+ /**
184
+ * Decodes a hexadecimal string, which can be obtained by calling
185
+ * `toBase16()`.
186
+ *
187
+ * @throws if the given string is not a valid Base64 string.
188
+ */
189
+ static fromBase16(base16) {
190
+ const bytes = new Uint8Array(base16.length / 2);
191
+ for (let i = 0; i < bytes.length; ++i) {
192
+ const byte = parseInt(base16.substring(i * 2, i * 2 + 2), 16);
193
+ if (Number.isNaN(byte)) {
194
+ throw new Error("Not a valid Base64 string");
195
+ }
196
+ bytes[i] = byte;
197
+ }
198
+ return new ByteString(bytes.buffer);
199
+ }
200
+ /** Copies the contents of this byte string into the given array buffer. */
201
+ copyTo(target, targetOffset = 0) {
202
+ new Uint8Array(target).set(this.uint8Array, targetOffset);
203
+ }
204
+ /** Copies the contents of this byte string into a new array buffer. */
205
+ toBuffer() {
206
+ return this.arrayBuffer.slice(this.byteOffset, this.byteOffset + this.byteLength);
207
+ }
208
+ /**
209
+ * Encodes this byte string into a Base64 string.
210
+ *
211
+ * @see https://en.wikipedia.org/wiki/Base64
212
+ */
213
+ toBase64() {
214
+ // See https://developer.mozilla.org/en-US/docs/Glossary/Base64
215
+ const binaryString = Array.from(this.uint8Array, (x) => String.fromCodePoint(x)).join("");
216
+ return btoa(binaryString);
217
+ }
218
+ /** Encodes this byte string into a hexadecimal string. */
219
+ toBase16() {
220
+ return [...this.uint8Array]
221
+ .map((x) => x.toString(16).padStart(2, "0"))
222
+ .join("");
223
+ }
224
+ at(index) {
225
+ return this.uint8Array[index < 0 ? index + this.byteLength : index];
226
+ }
227
+ toString() {
228
+ return `ByteString(${this.byteLength})`;
229
+ }
230
+ constructor(arrayBuffer, byteOffset = 0,
231
+ /** The length of this byte string. */
232
+ byteLength = arrayBuffer.byteLength) {
233
+ this.arrayBuffer = arrayBuffer;
234
+ this.byteOffset = byteOffset;
235
+ this.byteLength = byteLength;
236
+ this.uint8Array = new Uint8Array(arrayBuffer, byteOffset, byteLength);
237
+ Object.freeze(this);
238
+ }
239
+ }
240
+ exports.ByteString = ByteString;
241
+ /** An empty byte string. */
242
+ ByteString.EMPTY = new ByteString(new ArrayBuffer(0));
243
+ /**
244
+ * Returns a serializer of instances of the given Skir primitive type.
245
+ *
246
+ * @example
247
+ * expect(
248
+ * primitiveSerializer("string").toJsonCode("foo")
249
+ * ).toBe(
250
+ * '"foo"'
251
+ * );
252
+ */
253
+ function primitiveSerializer(primitiveType) {
254
+ return primitiveSerializers[primitiveType];
255
+ }
256
+ exports.primitiveSerializer = primitiveSerializer;
257
+ /**
258
+ * Returns a serializer of arrays of `Item`s.
259
+ *
260
+ * @example
261
+ * expect(
262
+ * arraySerializer(User.serializer).toJsonCode([JANE, JOE])
263
+ * ).toBe(
264
+ * '[["jane"],["joe"]]'
265
+ * );
266
+ */
267
+ function arraySerializer(item, keyChain) {
268
+ if (keyChain !== undefined &&
269
+ !/^[a-z_][a-z0-9_]*(\.[a-z_][a-z0-9_]*)*$/.test(keyChain)) {
270
+ throw new Error(`Invalid keyChain "${keyChain}"`);
271
+ }
272
+ return new ArraySerializerImpl(item, keyChain);
273
+ }
274
+ exports.arraySerializer = arraySerializer;
275
+ /** Returns a serializer of nullable `T`s. */
276
+ function optionalSerializer(other) {
277
+ return other instanceof OptionalSerializerImpl
278
+ ? other
279
+ : new OptionalSerializerImpl(other);
280
+ }
281
+ exports.optionalSerializer = optionalSerializer;
282
+ /** Parameter of the {@link InternalSerializer.decode} method. */
283
+ class InputStream {
284
+ constructor(buffer, keep) {
285
+ this.buffer = buffer;
286
+ this.offset = 0;
287
+ this.dataView = new DataView(buffer);
288
+ this.keepUnrecognizedValues = !!keep;
289
+ }
290
+ readUint8() {
291
+ return this.dataView.getUint8(this.offset++);
292
+ }
293
+ }
294
+ // For wires [232, 241]
295
+ const DECODE_NUMBER_FNS = [
296
+ (s) => s.dataView.getUint16((s.offset += 2) - 2, true),
297
+ (s) => s.dataView.getUint32((s.offset += 4) - 4, true),
298
+ (s) => s.dataView.getBigUint64((s.offset += 8) - 8, true),
299
+ (stream) => stream.readUint8() - 256,
300
+ (s) => s.dataView.getUint16((s.offset += 2) - 2, true) - 65536,
301
+ (s) => s.dataView.getInt32((s.offset += 4) - 4, true),
302
+ (s) => s.dataView.getBigInt64((s.offset += 8) - 8, true),
303
+ (s) => s.dataView.getBigInt64((s.offset += 8) - 8, true),
304
+ (s) => s.dataView.getFloat32((s.offset += 4) - 4, true),
305
+ (s) => s.dataView.getFloat64((s.offset += 8) - 8, true),
306
+ ];
307
+ function decodeNumber(stream) {
308
+ const wire = stream.readUint8();
309
+ return wire < 232 ? wire : DECODE_NUMBER_FNS[wire - 232](stream);
310
+ }
311
+ function decodeBigInt(stream) {
312
+ const number = decodeNumber(stream);
313
+ return typeof number === "bigint" ? number : BigInt(Math.round(number));
314
+ }
315
+ /** Parameter of the {@link InternalSerializer.encode} method. */
316
+ class OutputStream {
317
+ constructor() {
318
+ this.buffer = new ArrayBuffer(128);
319
+ this.dataView = new DataView(this.buffer);
320
+ this.offset = 0;
321
+ // The final binary form is the result of concatenating these arrays.
322
+ // The length of each array is approximately twice the length of the previous
323
+ // array.
324
+ this.pieces = [];
325
+ // Updated each time `flush()` is called.
326
+ this.byteLength = 0;
327
+ }
328
+ writeUint8(value) {
329
+ const dataView = this.reserve(1);
330
+ dataView.setUint8(++this.offset - 1, value);
331
+ }
332
+ writeUint16(value) {
333
+ const dataView = this.reserve(2);
334
+ dataView.setUint16((this.offset += 2) - 2, value, true);
335
+ }
336
+ writeUint32(value) {
337
+ const dataView = this.reserve(4);
338
+ dataView.setUint32((this.offset += 4) - 4, value, true);
339
+ }
340
+ writeInt32(value) {
341
+ const dataView = this.reserve(4);
342
+ dataView.setInt32((this.offset += 4) - 4, value, true);
343
+ }
344
+ writeUint64(value) {
345
+ const dataView = this.reserve(8);
346
+ dataView.setBigUint64((this.offset += 8) - 8, value, true);
347
+ }
348
+ writeInt64(value) {
349
+ const dataView = this.reserve(8);
350
+ dataView.setBigInt64((this.offset += 8) - 8, value, true);
351
+ }
352
+ writeFloat32(value) {
353
+ const dataView = this.reserve(4);
354
+ dataView.setFloat32((this.offset += 4) - 4, value, true);
355
+ }
356
+ writeFloat64(value) {
357
+ const dataView = this.reserve(8);
358
+ dataView.setFloat64((this.offset += 8) - 8, value, true);
359
+ }
360
+ /**
361
+ * Encodes the given string to UTF-8 and writes the bytes to this stream.
362
+ * Returns the number of bytes written.
363
+ */
364
+ putUtf8String(string) {
365
+ // We do at most 3 writes:
366
+ // - First, fill the current buffer as much as possible
367
+ // - If there is not enough room, allocate a new buffer of N bytes, where
368
+ // N is twice the number of remaining UTF-16 characters in the string,
369
+ // and write to it. This new buffer is very likely to have enough
370
+ // room.
371
+ // - If there was not enough room, try again one last time.
372
+ //
373
+ // See https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder
374
+ let dataView = this.dataView;
375
+ let result = 0;
376
+ while (string) {
377
+ const encodeResult = textEncoder.encodeInto(string, new Uint8Array(dataView.buffer, this.offset));
378
+ this.offset += encodeResult.written;
379
+ result += encodeResult.written;
380
+ string = string.substring(encodeResult.read);
381
+ if (string) {
382
+ dataView = this.reserve(string.length * 2);
383
+ }
384
+ }
385
+ return result;
386
+ }
387
+ putBytes(bytes) {
388
+ // We do at most 2 writes:
389
+ // - First, fill the current buffer as much as possible
390
+ // - If there is not enough room, allocate a new buffer of N bytes, where
391
+ // N is at least the number of bytes left in the byte string.
392
+ const { buffer } = this;
393
+ const bytesLeftInCurrentBuffer = buffer.byteLength - this.offset;
394
+ const head = ByteString.sliceOf(bytes, 0, bytesLeftInCurrentBuffer);
395
+ head.copyTo(buffer, this.offset);
396
+ this.offset += head.byteLength;
397
+ const remainingBytes = bytes.byteLength - head.byteLength;
398
+ if (remainingBytes <= 0) {
399
+ // Everything was written.
400
+ return;
401
+ }
402
+ const tail = ByteString.sliceOf(bytes, remainingBytes);
403
+ this.reserve(remainingBytes);
404
+ tail.copyTo(buffer, this.offset);
405
+ this.offset += remainingBytes;
406
+ }
407
+ finalize() {
408
+ this.flush();
409
+ Object.freeze(this.pieces);
410
+ Object.freeze(this);
411
+ return this;
412
+ }
413
+ copyTo(target, offset = 0) {
414
+ const targetArea = new Uint8Array(target);
415
+ for (const piece of this.pieces) {
416
+ targetArea.set(piece, offset);
417
+ offset += piece.length;
418
+ }
419
+ }
420
+ toBuffer() {
421
+ const result = new ArrayBuffer(this.byteLength);
422
+ this.copyTo(result);
423
+ return result;
424
+ }
425
+ /** Returns a data view with enough capacity for `bytes` more bytes. */
426
+ reserve(bytes) {
427
+ if (this.offset < this.buffer.byteLength - bytes) {
428
+ // Enough room in the current data view.
429
+ return this.dataView;
430
+ }
431
+ this.flush();
432
+ const lengthInBytes = Math.max(this.byteLength, bytes);
433
+ this.offset = 0;
434
+ this.buffer = new ArrayBuffer(lengthInBytes);
435
+ return (this.dataView = new DataView(this.buffer));
436
+ }
437
+ /** Adds the current buffer to `pieces`. Updates `byteLength` accordingly. */
438
+ flush() {
439
+ const { offset } = this;
440
+ this.pieces.push(new Uint8Array(this.dataView.buffer, 0, offset));
441
+ this.byteLength += offset;
442
+ }
443
+ }
444
+ function encodeUint32(length, stream) {
445
+ if (length < 232) {
446
+ stream.writeUint8(length);
447
+ }
448
+ else if (length < 65536) {
449
+ stream.writeUint8(232);
450
+ stream.writeUint16(length);
451
+ }
452
+ else if (length < 4294967296) {
453
+ stream.writeUint8(233);
454
+ stream.writeUint32(length);
455
+ }
456
+ else {
457
+ throw new Error(`max length exceeded: ${length}`);
458
+ }
459
+ }
460
+ class AbstractSerializer {
461
+ fromJsonCode(code, keep) {
462
+ return this.fromJson(JSON.parse(code), keep);
463
+ }
464
+ fromBytes(bytes, keep) {
465
+ const inputStream = new InputStream(bytes, keep);
466
+ inputStream.offset = 4; // Skip the "skir" header.
467
+ return this.decode(inputStream);
468
+ }
469
+ toJsonCode(input, flavor) {
470
+ const indent = flavor === "readable" ? " " : undefined;
471
+ return JSON.stringify(this.toJson(input, flavor), undefined, indent);
472
+ }
473
+ toBytes(input) {
474
+ const stream = new OutputStream();
475
+ stream.putUtf8String("skir");
476
+ this.encode(input, stream);
477
+ return stream.finalize();
478
+ }
479
+ // Default implementation; this behavior is not correct for all subclasses.
480
+ isDefault(input) {
481
+ return !input;
482
+ }
483
+ get typeDescriptor() {
484
+ return this;
485
+ }
486
+ asJson() {
487
+ const recordDefinitions = {};
488
+ this.addRecordDefinitionsTo(recordDefinitions);
489
+ const result = {
490
+ type: this.typeSignature,
491
+ records: Object.values(recordDefinitions),
492
+ };
493
+ return result;
494
+ }
495
+ asJsonCode() {
496
+ return JSON.stringify(this.asJson(), undefined, " ");
497
+ }
498
+ transform(json_or_bytes, out) {
499
+ const decoded = json_or_bytes instanceof ArrayBuffer
500
+ ? this.fromBytes(json_or_bytes)
501
+ : this.fromJson(json_or_bytes);
502
+ return out === "bytes"
503
+ ? this.toBytes(decoded).toBuffer()
504
+ : this.toJson(decoded, out);
505
+ }
506
+ }
507
+ // The UNKNOWN variant is common to all enums.
508
+ const UNKNOWN_VARIANT_DEFINITION = {
509
+ name: "?",
510
+ number: 0,
511
+ };
512
+ /**
513
+ * Returns a `TypeDescriptor` from its JSON representation as returned by
514
+ * `asJson()`.
515
+ */
516
+ function parseTypeDescriptorFromJson(json) {
517
+ var _a;
518
+ const typeDefinition = json;
519
+ const recordBundles = {};
520
+ // First loop: create the serializer for each record.
521
+ // It's not yet initialized.
522
+ for (const record of typeDefinition.records) {
523
+ let serializer;
524
+ switch (record.kind) {
525
+ case "struct":
526
+ serializer = new StructSerializerImpl({}, (initializer) => Object.freeze(Object.assign({}, initializer)), (() => ({})));
527
+ break;
528
+ case "enum":
529
+ serializer = new EnumSerializerImpl((o) => o instanceof UnrecognizedEnum
530
+ ? Object.freeze({ kind: "?" })
531
+ : Object.freeze({
532
+ kind: o.kind,
533
+ value: o.value,
534
+ }));
535
+ break;
536
+ }
537
+ const recordBundle = {
538
+ definition: record,
539
+ serializer: serializer,
540
+ };
541
+ recordBundles[record.id] = recordBundle;
542
+ }
543
+ function parse(ts) {
544
+ switch (ts.kind) {
545
+ case "array": {
546
+ const { item, key_extractor } = ts.value;
547
+ return new ArraySerializerImpl(parse(item), key_extractor);
548
+ }
549
+ case "optional":
550
+ return new OptionalSerializerImpl(parse(ts.value));
551
+ case "primitive":
552
+ return primitiveSerializer(ts.value);
553
+ case "record": {
554
+ const recordId = ts.value;
555
+ return recordBundles[recordId].serializer;
556
+ }
557
+ }
558
+ }
559
+ // Second loop: initialize each serializer.
560
+ const initOps = [];
561
+ for (const recordBundle of Object.values(recordBundles)) {
562
+ const { definition, serializer } = recordBundle;
563
+ const { defaultValue } = serializer;
564
+ const { id, removed_numbers } = definition;
565
+ const idParts = id.split(":");
566
+ const module = idParts[0];
567
+ const qualifiedName = idParts[1];
568
+ const nameParts = qualifiedName.split(".");
569
+ const name = nameParts[nameParts.length - 1];
570
+ const parentId = module + ":" + nameParts.slice(0, -1).join(".");
571
+ const parentType = (_a = recordBundles[parentId]) === null || _a === void 0 ? void 0 : _a.serializer;
572
+ switch (definition.kind) {
573
+ case "struct": {
574
+ const fields = [];
575
+ for (const f of definition.fields) {
576
+ const fieldSerializer = parse(f.type);
577
+ fields.push(new StructFieldImpl(f.name, f.name, f.number, fieldSerializer));
578
+ defaultValue[f.name] = fieldSerializer.defaultValue;
579
+ }
580
+ const s = serializer;
581
+ initOps.push(() => s.init(name, module, parentType, fields, removed_numbers !== null && removed_numbers !== void 0 ? removed_numbers : []));
582
+ break;
583
+ }
584
+ case "enum": {
585
+ const s = serializer;
586
+ const variants = [UNKNOWN_VARIANT_DEFINITION]
587
+ .concat(definition.variants)
588
+ .map((f) => f.type
589
+ ? new EnumWrapperVariantImpl(f.name, f.number, parse(f.type), serializer.createFn)
590
+ : {
591
+ name: f.name,
592
+ number: f.number,
593
+ constant: Object.freeze({ kind: f.name }),
594
+ });
595
+ initOps.push(() => s.init(name, module, parentType, variants, removed_numbers !== null && removed_numbers !== void 0 ? removed_numbers : []));
596
+ break;
597
+ }
598
+ }
599
+ }
600
+ // We need to actually initialize the serializers *after* the default values
601
+ // were constructed, because `init` calls `freezeDeeply` and this might result
602
+ // in freezing the default of another serializer.
603
+ initOps.forEach((op) => op());
604
+ return parse(typeDefinition.type).typeDescriptor;
605
+ }
606
+ exports.parseTypeDescriptorFromJson = parseTypeDescriptorFromJson;
607
+ /**
608
+ * Returns a `TypeDescriptor` from its JSON code representation as returned by
609
+ * `asJsonCode()`.
610
+ */
611
+ function parseTypeDescriptorFromJsonCode(code) {
612
+ return parseTypeDescriptorFromJson(JSON.parse(code));
613
+ }
614
+ exports.parseTypeDescriptorFromJsonCode = parseTypeDescriptorFromJsonCode;
615
+ class AbstractPrimitiveSerializer extends AbstractSerializer {
616
+ constructor() {
617
+ super(...arguments);
618
+ this.kind = "primitive";
619
+ }
620
+ get typeSignature() {
621
+ return {
622
+ kind: "primitive",
623
+ value: this.primitive,
624
+ };
625
+ }
626
+ addRecordDefinitionsTo(_out) { }
627
+ }
628
+ class BoolSerializer extends AbstractPrimitiveSerializer {
629
+ constructor() {
630
+ super(...arguments);
631
+ this.primitive = "bool";
632
+ this.defaultValue = false;
633
+ }
634
+ toJson(input, flavor) {
635
+ return flavor === "readable" ? !!input : input ? 1 : 0;
636
+ }
637
+ fromJson(json) {
638
+ return !!json && json !== "0";
639
+ }
640
+ encode(input, stream) {
641
+ stream.writeUint8(input ? 1 : 0);
642
+ }
643
+ decode(stream) {
644
+ return !!decodeNumber(stream);
645
+ }
646
+ }
647
+ class Int32Serializer extends AbstractPrimitiveSerializer {
648
+ constructor() {
649
+ super(...arguments);
650
+ this.primitive = "int32";
651
+ this.defaultValue = 0;
652
+ }
653
+ toJson(input) {
654
+ return input | 0;
655
+ }
656
+ fromJson(json) {
657
+ // `+value` will work if the input JSON value is a string, which is
658
+ // what the int64 serializer produces.
659
+ return +json | 0;
660
+ }
661
+ encode(input, stream) {
662
+ if (input < 0) {
663
+ if (input >= -256) {
664
+ stream.writeUint8(235);
665
+ stream.writeUint8(input + 256);
666
+ }
667
+ else if (input >= -65536) {
668
+ stream.writeUint8(236);
669
+ stream.writeUint16(input + 65536);
670
+ }
671
+ else {
672
+ stream.writeUint8(237);
673
+ stream.writeInt32(input >= -2147483648 ? input : -2147483648);
674
+ }
675
+ }
676
+ else if (input < 232) {
677
+ stream.writeUint8(input);
678
+ }
679
+ else if (input < 65536) {
680
+ stream.writeUint8(232);
681
+ stream.writeUint16(input);
682
+ }
683
+ else {
684
+ stream.writeUint8(233);
685
+ stream.writeUint32(input <= 2147483647 ? input : 2147483647);
686
+ }
687
+ }
688
+ decode(stream) {
689
+ return Number(decodeNumber(stream)) | 0;
690
+ }
691
+ }
692
+ const int32_Serializer = new Int32Serializer();
693
+ class FloatSerializer extends AbstractPrimitiveSerializer {
694
+ constructor() {
695
+ super(...arguments);
696
+ this.defaultValue = 0;
697
+ }
698
+ toJson(input) {
699
+ if (Number.isFinite(input)) {
700
+ return input;
701
+ }
702
+ else if (typeof input === "number") {
703
+ // If the number is NaN or +/- Infinity, return a JSON string.
704
+ return input.toString();
705
+ }
706
+ throw new TypeError();
707
+ }
708
+ fromJson(json) {
709
+ return +json;
710
+ }
711
+ decode(stream) {
712
+ return Number(decodeNumber(stream));
713
+ }
714
+ isDefault(input) {
715
+ // Needs to work for NaN.
716
+ return input === 0;
717
+ }
718
+ }
719
+ class Float32Serializer extends FloatSerializer {
720
+ constructor() {
721
+ super(...arguments);
722
+ this.primitive = "float32";
723
+ }
724
+ encode(input, stream) {
725
+ if (input === 0) {
726
+ stream.writeUint8(0);
727
+ }
728
+ else {
729
+ stream.writeUint8(240);
730
+ stream.writeFloat32(input);
731
+ }
732
+ }
733
+ }
734
+ class Float64Serializer extends FloatSerializer {
735
+ constructor() {
736
+ super(...arguments);
737
+ this.primitive = "float64";
738
+ }
739
+ encode(input, stream) {
740
+ if (input === 0) {
741
+ stream.writeUint8(0);
742
+ }
743
+ else {
744
+ stream.writeUint8(241);
745
+ stream.writeFloat64(input);
746
+ }
747
+ }
748
+ }
749
+ class AbstractBigIntSerializer extends AbstractPrimitiveSerializer {
750
+ constructor() {
751
+ super(...arguments);
752
+ this.defaultValue = BigInt(0);
753
+ }
754
+ fromJson(json) {
755
+ try {
756
+ return BigInt(json);
757
+ }
758
+ catch (e) {
759
+ if (typeof json === "number") {
760
+ return BigInt(Math.round(json));
761
+ }
762
+ else {
763
+ throw e;
764
+ }
765
+ }
766
+ }
767
+ }
768
+ const MIN_INT64 = BigInt("-9223372036854775808");
769
+ const MAX_INT64 = BigInt("9223372036854775807");
770
+ class Int64Serializer extends AbstractBigIntSerializer {
771
+ constructor() {
772
+ super(...arguments);
773
+ this.primitive = "int64";
774
+ }
775
+ toJson(input) {
776
+ // 9007199254740991 == Number.MAX_SAFE_INTEGER
777
+ if (-9007199254740991 <= input && input <= 9007199254740991) {
778
+ return Number(input);
779
+ }
780
+ const s = BigInt(input).toString();
781
+ // Clamp the number if it's out of bounds.
782
+ return s.length <= 18
783
+ ? // Small optimization for "small" numbers. The max int64 has 19 digits.
784
+ s
785
+ : input < MIN_INT64
786
+ ? MIN_INT64.toString()
787
+ : input < MAX_INT64
788
+ ? s
789
+ : MAX_INT64.toString();
790
+ }
791
+ encode(input, stream) {
792
+ if (input) {
793
+ if (-2147483648 <= input && input <= 2147483647) {
794
+ int32_Serializer.encode(Number(input), stream);
795
+ }
796
+ else {
797
+ stream.writeUint8(238);
798
+ // Clamp the number if it's out of bounds.
799
+ stream.writeInt64(input < MIN_INT64 ? MIN_INT64 : input < MAX_INT64 ? input : MAX_INT64);
800
+ }
801
+ }
802
+ else {
803
+ stream.writeUint8(0);
804
+ }
805
+ }
806
+ decode(stream) {
807
+ return decodeBigInt(stream);
808
+ }
809
+ }
810
+ const MAX_UINT64 = BigInt("18446744073709551615");
811
+ class Uint64Serializer extends AbstractBigIntSerializer {
812
+ constructor() {
813
+ super(...arguments);
814
+ this.primitive = "uint64";
815
+ }
816
+ toJson(input) {
817
+ if (input <= 9007199254740991) {
818
+ return input <= 0 ? 0 : Number(input);
819
+ }
820
+ input = BigInt(input);
821
+ return MAX_UINT64 < input ? MAX_UINT64.toString() : input.toString();
822
+ }
823
+ encode(input, stream) {
824
+ if (input < 232) {
825
+ stream.writeUint8(input <= 0 ? 0 : Number(input));
826
+ }
827
+ else if (input < 4294967296) {
828
+ if (input < 65536) {
829
+ stream.writeUint8(232);
830
+ stream.writeUint16(Number(input));
831
+ }
832
+ else {
833
+ stream.writeUint8(233);
834
+ stream.writeUint32(Number(input));
835
+ }
836
+ }
837
+ else {
838
+ stream.writeUint8(234);
839
+ stream.writeUint64(input <= MAX_UINT64 ? input : MAX_UINT64);
840
+ }
841
+ }
842
+ decode(stream) {
843
+ return decodeBigInt(stream);
844
+ }
845
+ }
846
+ class TimestampSerializer extends AbstractPrimitiveSerializer {
847
+ constructor() {
848
+ super(...arguments);
849
+ this.primitive = "timestamp";
850
+ this.defaultValue = Timestamp.UNIX_EPOCH;
851
+ }
852
+ toJson(input, flavor) {
853
+ return flavor === "readable"
854
+ ? {
855
+ unix_millis: input.unixMillis,
856
+ formatted: input.toDate().toISOString(),
857
+ }
858
+ : input.unixMillis;
859
+ }
860
+ fromJson(json) {
861
+ return Timestamp.fromUnixMillis(typeof json === "number"
862
+ ? json
863
+ : typeof json === "string"
864
+ ? +json
865
+ : json["unix_millis"]);
866
+ }
867
+ encode(input, stream) {
868
+ const { unixMillis } = input;
869
+ if (unixMillis) {
870
+ stream.writeUint8(239);
871
+ stream.writeInt64(BigInt(unixMillis));
872
+ }
873
+ else {
874
+ stream.writeUint8(0);
875
+ }
876
+ }
877
+ decode(stream) {
878
+ const unixMillis = decodeNumber(stream);
879
+ return Timestamp.fromUnixMillis(Number(unixMillis));
880
+ }
881
+ isDefault(input) {
882
+ return !input.unixMillis;
883
+ }
884
+ }
885
+ class StringSerializer extends AbstractPrimitiveSerializer {
886
+ constructor() {
887
+ super(...arguments);
888
+ this.primitive = "string";
889
+ this.defaultValue = "";
890
+ }
891
+ toJson(input) {
892
+ if (typeof input === "string") {
893
+ return input;
894
+ }
895
+ throw this.newTypeError(input);
896
+ }
897
+ fromJson(json) {
898
+ if (typeof json === "string") {
899
+ return json;
900
+ }
901
+ if (json === 0) {
902
+ return "";
903
+ }
904
+ throw this.newTypeError(json);
905
+ }
906
+ encode(input, stream) {
907
+ if (!input) {
908
+ stream.writeUint8(242);
909
+ return;
910
+ }
911
+ stream.writeUint8(243);
912
+ // We don't know the length of the UTF-8 string until we actually encode the
913
+ // string. We just know that it's at most 3 times the length of the input
914
+ // string.
915
+ const maxEncodedLength = input.length * 3;
916
+ // Write zero in place of the UTF-8 sequence length. We will override this
917
+ // number later.
918
+ if (maxEncodedLength < 232) {
919
+ stream.writeUint8(0);
920
+ }
921
+ else if (maxEncodedLength < 65536) {
922
+ stream.writeUint8(232);
923
+ stream.writeUint16(0);
924
+ }
925
+ else {
926
+ stream.writeUint8(233);
927
+ stream.writeUint32(0);
928
+ }
929
+ const { dataView, offset } = stream;
930
+ // Write the UTF-8 string and record the number of bytes written.
931
+ const encodedLength = stream.putUtf8String(input);
932
+ // Write the length of the UTF-8 string where we wrote 0.
933
+ if (maxEncodedLength < 232) {
934
+ dataView.setUint8(offset - 1, encodedLength);
935
+ }
936
+ else if (maxEncodedLength < 65536) {
937
+ dataView.setUint16(offset - 2, encodedLength, true);
938
+ }
939
+ else {
940
+ dataView.setUint32(offset - 4, encodedLength, true);
941
+ }
942
+ }
943
+ decode(stream) {
944
+ const wire = stream.readUint8();
945
+ if (wire === 0 || wire === 242) {
946
+ return "";
947
+ }
948
+ const encodedLength = decodeNumber(stream);
949
+ return textDecoder.decode(new Uint8Array(stream.buffer, (stream.offset += encodedLength) - encodedLength, encodedLength));
950
+ }
951
+ newTypeError(actual) {
952
+ return new TypeError(`expected: string; actual: ${typeof actual}`);
953
+ }
954
+ }
955
+ class ByteStringSerializer extends AbstractPrimitiveSerializer {
956
+ constructor() {
957
+ super(...arguments);
958
+ this.primitive = "bytes";
959
+ this.defaultValue = ByteString.EMPTY;
960
+ }
961
+ toJson(input, flavor) {
962
+ return flavor === "readable" ? "hex:" + input.toBase16() : input.toBase64();
963
+ }
964
+ fromJson(json) {
965
+ if (json === 0) {
966
+ return ByteString.EMPTY;
967
+ }
968
+ const string = json;
969
+ return string.startsWith("hex:")
970
+ ? ByteString.fromBase16(string.substring(4))
971
+ : ByteString.fromBase64(string);
972
+ }
973
+ encode(input, stream) {
974
+ const { byteLength } = input;
975
+ if (byteLength) {
976
+ stream.writeUint8(245);
977
+ encodeUint32(byteLength, stream);
978
+ stream.putBytes(input);
979
+ }
980
+ else {
981
+ stream.writeUint8(244);
982
+ }
983
+ }
984
+ decode(stream) {
985
+ const wire = stream.readUint8();
986
+ if (wire === 0 || wire === 244) {
987
+ return ByteString.EMPTY;
988
+ }
989
+ const lengthInBytes = decodeNumber(stream);
990
+ return ByteString.sliceOf(stream.buffer, stream.offset, (stream.offset += lengthInBytes));
991
+ }
992
+ isDefault(input) {
993
+ return !input.byteLength;
994
+ }
995
+ }
996
+ class StructFieldImpl {
997
+ constructor(name, property, number, serializer) {
998
+ this.name = name;
999
+ this.property = property;
1000
+ this.number = number;
1001
+ this.serializer = serializer;
1002
+ }
1003
+ get type() {
1004
+ return this.serializer.typeDescriptor;
1005
+ }
1006
+ get(struct) {
1007
+ return Reflect.get(struct, this.property);
1008
+ }
1009
+ set(struct, value) {
1010
+ Reflect.set(struct, this.property, value);
1011
+ }
1012
+ }
1013
+ const textEncoder = new TextEncoder();
1014
+ const textDecoder = new TextDecoder();
1015
+ class ArraySerializerImpl extends AbstractSerializer {
1016
+ constructor(itemSerializer, keyExtractor) {
1017
+ super();
1018
+ this.itemSerializer = itemSerializer;
1019
+ this.keyExtractor = keyExtractor;
1020
+ this.kind = "array";
1021
+ this.defaultValue = exports._EMPTY_ARRAY;
1022
+ }
1023
+ toJson(input, flavor) {
1024
+ return input.map((e) => this.itemSerializer.toJson(e, flavor));
1025
+ }
1026
+ fromJson(json, keep) {
1027
+ if (json === 0) {
1028
+ return exports._EMPTY_ARRAY;
1029
+ }
1030
+ return freezeArray(json.map((e) => this.itemSerializer.fromJson(e, keep)));
1031
+ }
1032
+ encode(input, stream) {
1033
+ const { length } = input;
1034
+ if (length <= 3) {
1035
+ stream.writeUint8(246 + length);
1036
+ }
1037
+ else {
1038
+ stream.writeUint8(250);
1039
+ encodeUint32(length, stream);
1040
+ }
1041
+ const { itemSerializer } = this;
1042
+ for (let i = 0; i < input.length; ++i) {
1043
+ itemSerializer.encode(input[i], stream);
1044
+ }
1045
+ }
1046
+ decode(stream) {
1047
+ const wire = stream.readUint8();
1048
+ if (wire === 0 || wire === 246) {
1049
+ return exports._EMPTY_ARRAY;
1050
+ }
1051
+ const length = wire === 250 ? decodeNumber(stream) : wire - 246;
1052
+ const { itemSerializer } = this;
1053
+ const result = new Array(length);
1054
+ for (let i = 0; i < length; ++i) {
1055
+ result[i] = itemSerializer.decode(stream);
1056
+ }
1057
+ return freezeArray(result);
1058
+ }
1059
+ isDefault(input) {
1060
+ return !input.length;
1061
+ }
1062
+ get itemType() {
1063
+ return this.itemSerializer.typeDescriptor;
1064
+ }
1065
+ get typeSignature() {
1066
+ return {
1067
+ kind: "array",
1068
+ value: {
1069
+ item: this.itemSerializer.typeSignature,
1070
+ key_extractor: this.keyExtractor,
1071
+ },
1072
+ };
1073
+ }
1074
+ addRecordDefinitionsTo(out) {
1075
+ this.itemSerializer.addRecordDefinitionsTo(out);
1076
+ }
1077
+ }
1078
+ class OptionalSerializerImpl extends AbstractSerializer {
1079
+ constructor(otherSerializer) {
1080
+ super();
1081
+ this.otherSerializer = otherSerializer;
1082
+ this.kind = "optional";
1083
+ this.defaultValue = null;
1084
+ }
1085
+ toJson(input, flavor) {
1086
+ return input !== null ? this.otherSerializer.toJson(input, flavor) : null;
1087
+ }
1088
+ fromJson(json, keep) {
1089
+ return json !== null ? this.otherSerializer.fromJson(json, keep) : null;
1090
+ }
1091
+ encode(input, stream) {
1092
+ if (input === null) {
1093
+ stream.writeUint8(255);
1094
+ }
1095
+ else {
1096
+ this.otherSerializer.encode(input, stream);
1097
+ }
1098
+ }
1099
+ decode(stream) {
1100
+ const wire = stream.dataView.getUint8(stream.offset);
1101
+ if (wire === 255) {
1102
+ ++stream.offset;
1103
+ return null;
1104
+ }
1105
+ return this.otherSerializer.decode(stream);
1106
+ }
1107
+ isDefault(input) {
1108
+ return input === null;
1109
+ }
1110
+ get otherType() {
1111
+ return this.otherSerializer.typeDescriptor;
1112
+ }
1113
+ get typeSignature() {
1114
+ return {
1115
+ kind: "optional",
1116
+ value: this.otherSerializer.typeSignature,
1117
+ };
1118
+ }
1119
+ addRecordDefinitionsTo(out) {
1120
+ this.otherSerializer.addRecordDefinitionsTo(out);
1121
+ }
1122
+ }
1123
+ const primitiveSerializers = {
1124
+ bool: new BoolSerializer(),
1125
+ int32: int32_Serializer,
1126
+ int64: new Int64Serializer(),
1127
+ uint64: new Uint64Serializer(),
1128
+ float32: new Float32Serializer(),
1129
+ float64: new Float64Serializer(),
1130
+ timestamp: new TimestampSerializer(),
1131
+ string: new StringSerializer(),
1132
+ bytes: new ByteStringSerializer(),
1133
+ };
1134
+ function decodeUnused(stream) {
1135
+ const wire = stream.readUint8();
1136
+ if (wire < 232) {
1137
+ return;
1138
+ }
1139
+ switch (wire - 232) {
1140
+ case 0: // uint16
1141
+ case 4: // uint16 - 65536
1142
+ stream.offset += 2;
1143
+ break;
1144
+ case 1: // uint32
1145
+ case 5: // int32
1146
+ case 8: // float32
1147
+ stream.offset += 4;
1148
+ break;
1149
+ case 2: // uint64
1150
+ case 6: // int64
1151
+ case 7: // uint64 timestamp
1152
+ case 9: // float64
1153
+ stream.offset += 8;
1154
+ break;
1155
+ case 3: // uint8 - 256
1156
+ ++stream.offset;
1157
+ break;
1158
+ case 11: // string
1159
+ case 13: {
1160
+ // bytes
1161
+ const length = decodeNumber(stream);
1162
+ stream.offset += length;
1163
+ break;
1164
+ }
1165
+ case 15: // array length==1
1166
+ case 19: // enum value kind==1
1167
+ case 20: // enum value kind==2
1168
+ case 21: // enum value kind==3
1169
+ case 22: // enum value kind==4
1170
+ decodeUnused(stream);
1171
+ break;
1172
+ case 16: // array length==2
1173
+ decodeUnused(stream);
1174
+ decodeUnused(stream);
1175
+ break;
1176
+ case 17: // array length==3
1177
+ decodeUnused(stream);
1178
+ decodeUnused(stream);
1179
+ decodeUnused(stream);
1180
+ break;
1181
+ case 18: {
1182
+ // array length==N
1183
+ const length = decodeNumber(stream);
1184
+ for (let i = 0; i < length; ++i) {
1185
+ decodeUnused(stream);
1186
+ }
1187
+ break;
1188
+ }
1189
+ }
1190
+ }
1191
+ class AbstractRecordSerializer extends AbstractSerializer {
1192
+ constructor() {
1193
+ super(...arguments);
1194
+ /** Uniquely identifies this record serializer. */
1195
+ this.token = Symbol();
1196
+ this.name = "";
1197
+ this.modulePath = "";
1198
+ this.removedNumbers = new Set();
1199
+ }
1200
+ init(name, modulePath, parentType, fieldsOrVariants, removedNumbers) {
1201
+ this.name = name;
1202
+ this.modulePath = modulePath;
1203
+ this.parentType = parentType;
1204
+ this.removedNumbers = new Set(removedNumbers);
1205
+ this.registerFieldsOrVariants(fieldsOrVariants);
1206
+ this.initialized = true;
1207
+ freezeDeeply(this);
1208
+ }
1209
+ get qualifiedName() {
1210
+ const { name, parentType } = this;
1211
+ return parentType ? `${parentType.name}.${name}` : name;
1212
+ }
1213
+ addRecordDefinitionsTo(out) {
1214
+ const recordId = `${this.modulePath}:${this.qualifiedName}`;
1215
+ if (out[recordId]) {
1216
+ return;
1217
+ }
1218
+ const recordDefinition = this.makeRecordDefinition(recordId);
1219
+ if (this.removedNumbers.size) {
1220
+ recordDefinition.removed_numbers = [...this.removedNumbers];
1221
+ }
1222
+ out[recordId] = recordDefinition;
1223
+ for (const dependency of this.dependencies()) {
1224
+ dependency.addRecordDefinitionsTo(out);
1225
+ }
1226
+ }
1227
+ }
1228
+ /** Unrecognized fields found when deserializing a struct. */
1229
+ class UnrecognizedFields {
1230
+ constructor(
1231
+ /** Uniquely identifies the struct. */
1232
+ token,
1233
+ /** Total number of fields in the struct. */
1234
+ totalSlots, json, bytes) {
1235
+ this.token = token;
1236
+ this.totalSlots = totalSlots;
1237
+ this.json = json;
1238
+ this.bytes = bytes;
1239
+ Object.freeze(this);
1240
+ }
1241
+ }
1242
+ class StructSerializerImpl extends AbstractRecordSerializer {
1243
+ constructor(defaultValue, createFn, newMutableFn) {
1244
+ super();
1245
+ this.defaultValue = defaultValue;
1246
+ this.createFn = createFn;
1247
+ this.newMutableFn = newMutableFn;
1248
+ this.kind = "struct";
1249
+ // Fields in the order they appear in the `.skir` file.
1250
+ this.fields = [];
1251
+ this.fieldMapping = {};
1252
+ // Fields sorted by number in descending order.
1253
+ this.reversedFields = [];
1254
+ // This is *not* a dense array, missing slots correspond to removed fields.
1255
+ this.slots = [];
1256
+ this.recognizedSlots = 0;
1257
+ // Contains one zero for every field number.
1258
+ this.zeros = [];
1259
+ this.initializerTemplate = {};
1260
+ }
1261
+ toJson(input, flavor) {
1262
+ if (input === this.defaultValue) {
1263
+ return flavor === "readable" ? {} : [];
1264
+ }
1265
+ if (flavor === "readable") {
1266
+ const { fields } = this;
1267
+ const result = {};
1268
+ for (const field of fields) {
1269
+ const { serializer } = field;
1270
+ const value = input[field.property];
1271
+ if (field.serializer.isDefault(value)) {
1272
+ continue;
1273
+ }
1274
+ result[field.name] = serializer.toJson(value, flavor);
1275
+ }
1276
+ return result;
1277
+ }
1278
+ else {
1279
+ // Dense flavor.
1280
+ const { slots } = this;
1281
+ let result;
1282
+ const unrecognizedFields = //
1283
+ input["^"];
1284
+ if (unrecognizedFields &&
1285
+ unrecognizedFields.json &&
1286
+ unrecognizedFields.token === this.token) {
1287
+ // We'll need to copy the unrecognized fields to the JSON.
1288
+ result = this.zeros.concat(unrecognizedFields.json);
1289
+ for (const field of this.fields) {
1290
+ result[field.number] = field.serializer.toJson(input[field.property], flavor);
1291
+ }
1292
+ }
1293
+ else {
1294
+ result = [];
1295
+ const arrayLength = this.getArrayLength(input);
1296
+ for (let i = 0; i < arrayLength; ++i) {
1297
+ const field = slots[i];
1298
+ result[i] = field
1299
+ ? field.serializer.toJson(input[field.property], flavor)
1300
+ : 0;
1301
+ }
1302
+ }
1303
+ return result;
1304
+ }
1305
+ }
1306
+ fromJson(json, keep) {
1307
+ if (!json) {
1308
+ return this.defaultValue;
1309
+ }
1310
+ const initializer = Object.assign({}, this.initializerTemplate);
1311
+ if (json instanceof Array) {
1312
+ const { slots, recognizedSlots } = this;
1313
+ // Dense flavor.
1314
+ if (json.length > recognizedSlots) {
1315
+ // We have some unrecognized fields.
1316
+ if (keep) {
1317
+ const unrecognizedFields = new UnrecognizedFields(this.token, json.length, copyJson(json.slice(recognizedSlots)));
1318
+ initializer["^"] = unrecognizedFields;
1319
+ }
1320
+ // Now that we have stored the unrecognized fields in `initializer`, we
1321
+ // can remove them from `json`.
1322
+ json = json.slice(0, recognizedSlots);
1323
+ }
1324
+ for (let i = 0; i < json.length && i < slots.length; ++i) {
1325
+ const field = slots[i];
1326
+ if (field) {
1327
+ initializer[field.property] = field.serializer.fromJson(json[i], keep);
1328
+ }
1329
+ // Else the field was removed.
1330
+ }
1331
+ return this.createFn(initializer);
1332
+ }
1333
+ else if (json instanceof Object) {
1334
+ // Readable flavor.
1335
+ const { fieldMapping } = this;
1336
+ for (const name in json) {
1337
+ const field = fieldMapping[name];
1338
+ if (field) {
1339
+ initializer[field.property] = field.serializer.fromJson(json[name], keep);
1340
+ }
1341
+ }
1342
+ return this.createFn(initializer);
1343
+ }
1344
+ throw TypeError();
1345
+ }
1346
+ encode(input, stream) {
1347
+ // Total number of slots to write. Includes removed and unrecognized fields.
1348
+ let totalSlots;
1349
+ let recognizedSlots;
1350
+ let unrecognizedBytes;
1351
+ const unrecognizedFields = input["^"];
1352
+ if (unrecognizedFields &&
1353
+ unrecognizedFields.bytes &&
1354
+ unrecognizedFields.token === this.token) {
1355
+ totalSlots = unrecognizedFields.totalSlots;
1356
+ recognizedSlots = this.recognizedSlots;
1357
+ unrecognizedBytes = unrecognizedFields.bytes;
1358
+ }
1359
+ else {
1360
+ // No unrecognized fields.
1361
+ totalSlots = recognizedSlots = this.getArrayLength(input);
1362
+ }
1363
+ if (totalSlots <= 3) {
1364
+ stream.writeUint8(246 + totalSlots);
1365
+ }
1366
+ else {
1367
+ stream.writeUint8(250);
1368
+ encodeUint32(totalSlots, stream);
1369
+ }
1370
+ const { slots } = this;
1371
+ for (let i = 0; i < recognizedSlots; ++i) {
1372
+ const field = slots[i];
1373
+ if (field) {
1374
+ field.serializer.encode(input[field.property], stream);
1375
+ }
1376
+ else {
1377
+ // Append '0' if the field was removed.
1378
+ stream.writeUint8(0);
1379
+ }
1380
+ }
1381
+ if (unrecognizedBytes) {
1382
+ // Copy the unrecognized fields.
1383
+ stream.putBytes(unrecognizedBytes);
1384
+ }
1385
+ }
1386
+ decode(stream) {
1387
+ const wire = stream.readUint8();
1388
+ if (wire === 0 || wire === 246) {
1389
+ return this.defaultValue;
1390
+ }
1391
+ const initializer = Object.assign({}, this.initializerTemplate);
1392
+ const encodedSlots = wire === 250 ? decodeNumber(stream) : wire - 246;
1393
+ const { slots, recognizedSlots } = this;
1394
+ // Do not read more slots than the number of recognized slots.
1395
+ for (let i = 0; i < encodedSlots && i < recognizedSlots; ++i) {
1396
+ const field = slots[i];
1397
+ if (field) {
1398
+ initializer[field.property] = field.serializer.decode(stream);
1399
+ }
1400
+ else {
1401
+ // The field was removed.
1402
+ decodeUnused(stream);
1403
+ }
1404
+ }
1405
+ if (encodedSlots > recognizedSlots) {
1406
+ // We have some unrecognized fields.
1407
+ const start = stream.offset;
1408
+ for (let i = recognizedSlots; i < encodedSlots; ++i) {
1409
+ decodeUnused(stream);
1410
+ }
1411
+ if (stream.keepUnrecognizedValues) {
1412
+ const end = stream.offset;
1413
+ const unrecognizedBytes = ByteString.sliceOf(stream.buffer, start, end);
1414
+ const unrecognizedFields = new UnrecognizedFields(this.token, encodedSlots, undefined, unrecognizedBytes);
1415
+ initializer["^"] = unrecognizedFields;
1416
+ }
1417
+ }
1418
+ return this.createFn(initializer);
1419
+ }
1420
+ /**
1421
+ * Returns the length of the JSON array for the given input, which is also the
1422
+ * number of slots and includes removed fields.
1423
+ * Assumes that `input` does not contain unrecognized fields.
1424
+ */
1425
+ getArrayLength(input) {
1426
+ const { reversedFields } = this;
1427
+ for (let i = 0; i < reversedFields.length; ++i) {
1428
+ const field = reversedFields[i];
1429
+ const isDefault = //
1430
+ field.serializer.isDefault(input[field.property]);
1431
+ if (!isDefault) {
1432
+ return field.number + 1;
1433
+ }
1434
+ }
1435
+ return 0;
1436
+ }
1437
+ isDefault(input) {
1438
+ if (input === this.defaultValue) {
1439
+ return true;
1440
+ }
1441
+ // It's possible for a value of type T to be equal to T.DEFAULT but to not
1442
+ // be the reference to T.DEFAULT.
1443
+ if (input["^"]) {
1444
+ return false;
1445
+ }
1446
+ return this.fields.every((f) => f.serializer.isDefault(input[f.property]));
1447
+ }
1448
+ get typeSignature() {
1449
+ return {
1450
+ kind: "record",
1451
+ value: `${this.modulePath}:${this.qualifiedName}`,
1452
+ };
1453
+ }
1454
+ getField(key) {
1455
+ return this.fieldMapping[key];
1456
+ }
1457
+ newMutable(initializer) {
1458
+ return this.newMutableFn(initializer);
1459
+ }
1460
+ registerFieldsOrVariants(fields) {
1461
+ for (const field of fields) {
1462
+ const { name, number, property } = field;
1463
+ this.fields.push(field);
1464
+ this.slots[number] = field;
1465
+ this.fieldMapping[name] = field;
1466
+ this.fieldMapping[property] = field;
1467
+ this.fieldMapping[number] = field;
1468
+ this.initializerTemplate[property] = this.defaultValue[field.property];
1469
+ }
1470
+ // Removed numbers count as recognized slots.
1471
+ this.recognizedSlots =
1472
+ Math.max(this.slots.length - 1, ...this.removedNumbers) + 1;
1473
+ this.zeros.push(...Array(this.recognizedSlots).fill(0));
1474
+ this.reversedFields = [...this.fields].sort((a, b) => b.number - a.number);
1475
+ }
1476
+ makeRecordDefinition(recordId) {
1477
+ return {
1478
+ kind: "struct",
1479
+ id: recordId,
1480
+ fields: this.fields.map((f) => ({
1481
+ name: f.name,
1482
+ number: f.number,
1483
+ type: f.serializer.typeSignature,
1484
+ })),
1485
+ };
1486
+ }
1487
+ dependencies() {
1488
+ return this.fields.map((f) => f.serializer);
1489
+ }
1490
+ }
1491
+ class UnrecognizedEnum {
1492
+ constructor(token, json, bytes) {
1493
+ this.token = token;
1494
+ this.json = json;
1495
+ this.bytes = bytes;
1496
+ Object.freeze(this);
1497
+ }
1498
+ }
1499
+ class EnumWrapperVariantImpl {
1500
+ constructor(name, number, serializer, createFn) {
1501
+ this.name = name;
1502
+ this.number = number;
1503
+ this.serializer = serializer;
1504
+ this.createFn = createFn;
1505
+ }
1506
+ get type() {
1507
+ return this.serializer.typeDescriptor;
1508
+ }
1509
+ get(e) {
1510
+ return e.kind === this.name
1511
+ ? e.value
1512
+ : undefined;
1513
+ }
1514
+ wrap(value) {
1515
+ return this.createFn({ kind: this.name, value: value });
1516
+ }
1517
+ }
1518
+ class EnumSerializerImpl extends AbstractRecordSerializer {
1519
+ constructor(createFn) {
1520
+ super();
1521
+ this.createFn = createFn;
1522
+ this.kind = "enum";
1523
+ this.variants = [];
1524
+ this.variantMapping = {};
1525
+ this.defaultValue = createFn("?");
1526
+ }
1527
+ toJson(input, flavor) {
1528
+ const unrecognized = input["^"];
1529
+ if (unrecognized &&
1530
+ unrecognized.json &&
1531
+ unrecognized.token === this.token) {
1532
+ // Unrecognized variant.
1533
+ return unrecognized.json;
1534
+ }
1535
+ const kind = input.kind;
1536
+ if (kind === "?") {
1537
+ return flavor === "readable" ? "?" : 0;
1538
+ }
1539
+ const variant = this.variantMapping[kind];
1540
+ const { serializer } = variant;
1541
+ if (serializer) {
1542
+ const value = input.value;
1543
+ if (flavor === "readable") {
1544
+ return {
1545
+ kind: variant.name,
1546
+ value: serializer.toJson(value, flavor),
1547
+ };
1548
+ }
1549
+ else {
1550
+ // Dense flavor.
1551
+ return [variant.number, serializer.toJson(value, flavor)];
1552
+ }
1553
+ }
1554
+ else {
1555
+ // A constant variant.
1556
+ return flavor === "readable" ? variant.name : variant.number;
1557
+ }
1558
+ }
1559
+ fromJson(json, keep) {
1560
+ const isNumber = typeof json === "number";
1561
+ if (isNumber || typeof json === "string") {
1562
+ const variant = this.variantMapping[isNumber ? json : String(json)];
1563
+ if (!variant) {
1564
+ // Check if the variant was removed, in which case we want to return
1565
+ // UNKNOWN, or is unrecognized.
1566
+ return !keep || (isNumber && this.removedNumbers.has(json))
1567
+ ? this.defaultValue
1568
+ : this.createFn(new UnrecognizedEnum(this.token, copyJson(json)));
1569
+ }
1570
+ if (variant.serializer) {
1571
+ throw new Error(`refers to a wrapper variant: ${json}`);
1572
+ }
1573
+ return variant.constant;
1574
+ }
1575
+ let variantKey;
1576
+ let valueAsJson;
1577
+ if (json instanceof Array) {
1578
+ variantKey = json[0];
1579
+ valueAsJson = json[1];
1580
+ }
1581
+ else if (json instanceof Object) {
1582
+ variantKey = json["kind"];
1583
+ valueAsJson = json["value"];
1584
+ }
1585
+ else {
1586
+ throw TypeError();
1587
+ }
1588
+ const variant = this.variantMapping[variantKey];
1589
+ if (!variant) {
1590
+ // Check if the variant was removed, in which case we want to return
1591
+ // UNKNOWN, or is unrecognized.
1592
+ return !keep ||
1593
+ (typeof variantKey === "number" && this.removedNumbers.has(variantKey))
1594
+ ? this.defaultValue
1595
+ : this.createFn(new UnrecognizedEnum(this.token, copyJson(json), undefined));
1596
+ }
1597
+ const { serializer } = variant;
1598
+ if (!serializer) {
1599
+ throw new Error(`refers to a constant variant: ${json}`);
1600
+ }
1601
+ return variant.wrap(serializer.fromJson(valueAsJson, keep));
1602
+ }
1603
+ encode(input, stream) {
1604
+ const unrecognized = //
1605
+ input["^"];
1606
+ if (unrecognized &&
1607
+ unrecognized.bytes &&
1608
+ unrecognized.token === this.token) {
1609
+ // Unrecognized variant.
1610
+ stream.putBytes(unrecognized.bytes);
1611
+ return;
1612
+ }
1613
+ const kind = input.kind;
1614
+ if (kind === "?") {
1615
+ stream.writeUint8(0);
1616
+ return;
1617
+ }
1618
+ const variant = this.variantMapping[kind];
1619
+ const { number, serializer } = variant;
1620
+ if (serializer) {
1621
+ // A wrapper variant.
1622
+ const value = input.value;
1623
+ if (number < 5) {
1624
+ // The number can't be 0 or else kind == "?".
1625
+ stream.writeUint8(250 + number);
1626
+ }
1627
+ else {
1628
+ stream.writeUint8(248);
1629
+ encodeUint32(number, stream);
1630
+ }
1631
+ serializer.encode(value, stream);
1632
+ }
1633
+ else {
1634
+ // A constant field.
1635
+ encodeUint32(number, stream);
1636
+ }
1637
+ }
1638
+ decode(stream) {
1639
+ const startOffset = stream.offset;
1640
+ const wire = stream.dataView.getUint8(startOffset);
1641
+ if (wire < 242) {
1642
+ // A number
1643
+ const number = decodeNumber(stream);
1644
+ const variant = this.variantMapping[number];
1645
+ if (!variant) {
1646
+ // Check if the variant was removed, in which case we want to return
1647
+ // UNKNOWN, or is unrecognized.
1648
+ if (!stream.keepUnrecognizedValues || this.removedNumbers.has(number)) {
1649
+ return this.defaultValue;
1650
+ }
1651
+ else {
1652
+ const { offset } = stream;
1653
+ const bytes = ByteString.sliceOf(stream.buffer, startOffset, offset);
1654
+ return this.createFn(new UnrecognizedEnum(this.token, undefined, bytes));
1655
+ }
1656
+ }
1657
+ if (variant.serializer) {
1658
+ throw new Error(`refers to a wrapper variant: ${number}`);
1659
+ }
1660
+ return variant.constant;
1661
+ }
1662
+ else {
1663
+ ++stream.offset;
1664
+ const number = wire === 248 ? decodeNumber(stream) : wire - 250;
1665
+ const variant = this.variantMapping[number];
1666
+ if (!variant) {
1667
+ decodeUnused(stream);
1668
+ // Check if the variant was removed, in which case we want to return
1669
+ // UNKNOWN, or is unrecognized.
1670
+ if (!stream.keepUnrecognizedValues || this.removedNumbers.has(number)) {
1671
+ return this.defaultValue;
1672
+ }
1673
+ else {
1674
+ const { offset } = stream;
1675
+ const bytes = ByteString.sliceOf(stream.buffer, startOffset, offset);
1676
+ return this.createFn(new UnrecognizedEnum(this.token, undefined, bytes));
1677
+ }
1678
+ }
1679
+ const { serializer } = variant;
1680
+ if (!serializer) {
1681
+ throw new Error(`refers to a constant variant: ${number}`);
1682
+ }
1683
+ return variant.wrap(serializer.decode(stream));
1684
+ }
1685
+ }
1686
+ get typeSignature() {
1687
+ return {
1688
+ kind: "record",
1689
+ value: `${this.modulePath}:${this.qualifiedName}`,
1690
+ };
1691
+ }
1692
+ isDefault(input) {
1693
+ return input.kind === "?" && !input["^"];
1694
+ }
1695
+ getVariant(key) {
1696
+ return this.variantMapping[key];
1697
+ }
1698
+ registerFieldsOrVariants(fields) {
1699
+ for (const field of fields) {
1700
+ this.variants.push(field);
1701
+ this.variantMapping[field.name] = field;
1702
+ this.variantMapping[field.number] = field;
1703
+ }
1704
+ }
1705
+ makeRecordDefinition(recordId) {
1706
+ return {
1707
+ kind: "enum",
1708
+ id: recordId,
1709
+ variants: this.variants
1710
+ // Skip the UNKNOWN variant.
1711
+ .filter((f) => f.number)
1712
+ .map((f) => {
1713
+ var _a;
1714
+ const result = {
1715
+ name: f.name,
1716
+ number: f.number,
1717
+ };
1718
+ const type = (_a = f === null || f === void 0 ? void 0 : f.serializer) === null || _a === void 0 ? void 0 : _a.typeSignature;
1719
+ return type ? Object.assign(Object.assign({}, result), { type: type }) : result;
1720
+ }),
1721
+ };
1722
+ }
1723
+ dependencies() {
1724
+ const result = [];
1725
+ for (const f of this.variants) {
1726
+ if (f.serializer) {
1727
+ result.push(f.serializer);
1728
+ }
1729
+ }
1730
+ return result;
1731
+ }
1732
+ }
1733
+ function copyJson(input) {
1734
+ if (input instanceof Array) {
1735
+ return Object.freeze(input.map(copyJson));
1736
+ }
1737
+ else if (input instanceof Object) {
1738
+ return Object.freeze(Object.fromEntries(Object.entries(input).map((k, v) => [k, copyJson(v)])));
1739
+ }
1740
+ // A boolean, a number, a string or null.
1741
+ return input;
1742
+ }
1743
+ function freezeDeeply(o) {
1744
+ if (!(o instanceof Object)) {
1745
+ return;
1746
+ }
1747
+ if (o instanceof _FrozenBase || o instanceof _EnumBase) {
1748
+ return;
1749
+ }
1750
+ if (o instanceof AbstractRecordSerializer && !o.initialized) {
1751
+ return;
1752
+ }
1753
+ if (Object.isFrozen(o)) {
1754
+ return;
1755
+ }
1756
+ Object.freeze(o);
1757
+ for (const v of Object.values(o)) {
1758
+ freezeDeeply(v);
1759
+ }
1760
+ }
1761
+ const frozenArrayRegistry = new WeakMap();
1762
+ function freezeArray(array) {
1763
+ if (!frozenArrayRegistry.has(array)) {
1764
+ frozenArrayRegistry.set(Object.freeze(array), {});
1765
+ }
1766
+ return array;
1767
+ }
1768
+ exports._EMPTY_ARRAY = freezeArray([]);
1769
+ function _toFrozenArray(initializers, itemToFrozenFn) {
1770
+ if (!initializers.length) {
1771
+ return exports._EMPTY_ARRAY;
1772
+ }
1773
+ if (frozenArrayRegistry.has(initializers)) {
1774
+ // No need to make a copy: the given array is already deeply-frozen.
1775
+ return initializers;
1776
+ }
1777
+ const ret = Object.freeze(itemToFrozenFn
1778
+ ? initializers.map(itemToFrozenFn)
1779
+ : initializers.slice());
1780
+ frozenArrayRegistry.set(ret, {});
1781
+ return ret;
1782
+ }
1783
+ exports._toFrozenArray = _toFrozenArray;
1784
+ const PRIVATE_KEY = Symbol();
1785
+ function forPrivateUseError(t) {
1786
+ const clazz = Object.getPrototypeOf(t).constructor;
1787
+ const { qualifiedName } = clazz.serializer;
1788
+ return Error([
1789
+ "Do not call the constructor directly; ",
1790
+ `instead, call ${qualifiedName}.create(...)`,
1791
+ ].join(""));
1792
+ }
1793
+ class _FrozenBase {
1794
+ constructor(privateKey) {
1795
+ if (privateKey !== PRIVATE_KEY) {
1796
+ throw forPrivateUseError(this);
1797
+ }
1798
+ }
1799
+ toMutable() {
1800
+ return new (Object.getPrototypeOf(this).constructor.Mutable)(this);
1801
+ }
1802
+ toFrozen() {
1803
+ return this;
1804
+ }
1805
+ toString() {
1806
+ return toStringImpl(this);
1807
+ }
1808
+ }
1809
+ exports._FrozenBase = _FrozenBase;
1810
+ class _EnumBase {
1811
+ constructor(privateKey, kind, value, unrecognized) {
1812
+ this.kind = kind;
1813
+ this.value = value;
1814
+ if (privateKey !== PRIVATE_KEY) {
1815
+ throw forPrivateUseError(this);
1816
+ }
1817
+ if (unrecognized) {
1818
+ if (!(unrecognized instanceof UnrecognizedEnum)) {
1819
+ throw new TypeError();
1820
+ }
1821
+ this["^"] = unrecognized;
1822
+ }
1823
+ Object.freeze(this);
1824
+ }
1825
+ toString() {
1826
+ return toStringImpl(this);
1827
+ }
1828
+ }
1829
+ exports._EnumBase = _EnumBase;
1830
+ // The TypeScript compiler complains if we define the property within the class.
1831
+ Object.defineProperty(_EnumBase.prototype, "union", {
1832
+ get: function () {
1833
+ return this;
1834
+ },
1835
+ });
1836
+ function toStringImpl(value) {
1837
+ const serializer = Object.getPrototypeOf(value).constructor
1838
+ .serializer;
1839
+ return serializer.toJsonCode(value, "readable");
1840
+ }
1841
+ /** Sends RPCs to a skir service. */
1842
+ class ServiceClient {
1843
+ constructor(serviceUrl, getRequestMetadata = () => ({})) {
1844
+ this.serviceUrl = serviceUrl;
1845
+ this.getRequestMetadata = getRequestMetadata;
1846
+ const url = new URL(serviceUrl);
1847
+ if (url.search) {
1848
+ throw new Error("Service URL must not contain a query string");
1849
+ }
1850
+ }
1851
+ /** Invokes the given method on the remote server through an RPC. */
1852
+ invokeRemote(method, request, httpMethod = "POST") {
1853
+ return __awaiter(this, void 0, void 0, function* () {
1854
+ this.lastRespHeaders = undefined;
1855
+ const requestJson = method.requestSerializer.toJsonCode(request);
1856
+ const requestBody = [method.name, method.number, "", requestJson].join(":");
1857
+ const requestInit = Object.assign({}, (yield Promise.resolve(this.getRequestMetadata(method))));
1858
+ const url = new URL(this.serviceUrl);
1859
+ requestInit.method = httpMethod;
1860
+ if (httpMethod === "POST") {
1861
+ requestInit.body = requestBody;
1862
+ }
1863
+ else {
1864
+ url.search = requestBody.replace(/%/g, "%25");
1865
+ }
1866
+ const httpResponse = yield fetch(url, requestInit);
1867
+ this.lastRespHeaders = httpResponse.headers;
1868
+ const responseData = yield httpResponse.blob();
1869
+ if (httpResponse.ok) {
1870
+ const jsonCode = yield responseData.text();
1871
+ return method.responseSerializer.fromJsonCode(jsonCode, "keep-unrecognized-values");
1872
+ }
1873
+ else {
1874
+ let message = "";
1875
+ if (/text\/plain\b/.test(responseData.type)) {
1876
+ message = `: ${yield responseData.text()}`;
1877
+ }
1878
+ throw new Error(`HTTP status ${httpResponse.status}${message}`);
1879
+ }
1880
+ });
1881
+ }
1882
+ get lastResponseHeaders() {
1883
+ return this.lastRespHeaders;
1884
+ }
1885
+ }
1886
+ exports.ServiceClient = ServiceClient;
1887
+ /** Raw response returned by the server. */
1888
+ class RawResponse {
1889
+ constructor(data, type) {
1890
+ this.data = data;
1891
+ this.type = type;
1892
+ }
1893
+ get statusCode() {
1894
+ switch (this.type) {
1895
+ case "ok-json":
1896
+ case "ok-html":
1897
+ return 200;
1898
+ case "bad-request":
1899
+ return 400;
1900
+ case "server-error":
1901
+ return 500;
1902
+ default: {
1903
+ const _ = this.type;
1904
+ throw new Error(_);
1905
+ }
1906
+ }
1907
+ }
1908
+ get contentType() {
1909
+ switch (this.type) {
1910
+ case "ok-json":
1911
+ return "application/json";
1912
+ case "ok-html":
1913
+ return "text/html; charset=utf-8";
1914
+ case "bad-request":
1915
+ case "server-error":
1916
+ return "text/plain; charset=utf-8";
1917
+ default: {
1918
+ const _ = this.type;
1919
+ throw new Error(_);
1920
+ }
1921
+ }
1922
+ }
1923
+ }
1924
+ exports.RawResponse = RawResponse;
1925
+ // Copied from
1926
+ // https://github.com/gepheum/restudio/blob/main/index.jsdeliver.html
1927
+ const RESTUDIO_HTML = `<!DOCTYPE html>
1928
+
1929
+ <html>
1930
+ <head>
1931
+ <meta charset="utf-8" />
1932
+ <title>RESTudio</title>
1933
+ <script src="https://cdn.jsdelivr.net/npm/restudio/dist/restudio-standalone.js"></script>
1934
+ </head>
1935
+ <body style="margin: 0; padding: 0;">
1936
+ <restudio-app></restudio-app>
1937
+ </body>
1938
+ </html>
1939
+ `;
1940
+ /**
1941
+ * Implementation of a skir service.
1942
+ *
1943
+ * Usage: call `.addMethod()` to register methods, then install the service on
1944
+ * an HTTP server either by:
1945
+ * - calling the `installServiceOnExpressApp()` top-level function if you are
1946
+ * using ExpressJS
1947
+ * - writing your own implementation of `installServiceOn*()` which calls
1948
+ * `.handleRequest()` if you are using another web application framework
1949
+ */
1950
+ class Service {
1951
+ constructor() {
1952
+ this.methodImpls = {};
1953
+ }
1954
+ addMethod(method, impl) {
1955
+ const { number } = method;
1956
+ if (this.methodImpls[number]) {
1957
+ throw new Error(`Method with the same number already registered (${number})`);
1958
+ }
1959
+ this.methodImpls[number] = {
1960
+ method: method,
1961
+ impl: impl,
1962
+ };
1963
+ return this;
1964
+ }
1965
+ /**
1966
+ * Parses the content of a user request and invokes the appropriate method.
1967
+ * If you are using ExpressJS as your web application framework, you don't
1968
+ * need to call this method, you can simply call the
1969
+ * `installServiceOnExpressApp()` top-level function.
1970
+ *
1971
+ * If the request is a GET request, pass in the decoded query string as the
1972
+ * request's body. The query string is the part of the URL after '?', and it
1973
+ * can be decoded with DecodeURIComponent.
1974
+ *
1975
+ * Pass in "keep-unrecognized-values" if the request cannot come from a
1976
+ * malicious user.
1977
+ */
1978
+ handleRequest(reqBody, reqMeta, resMeta, keepUnrecognizedValues) {
1979
+ return __awaiter(this, void 0, void 0, function* () {
1980
+ if (reqBody === "" || reqBody === "list") {
1981
+ const json = {
1982
+ methods: Object.values(this.methodImpls).map((methodImpl) => ({
1983
+ method: methodImpl.method.name,
1984
+ number: methodImpl.method.name,
1985
+ request: methodImpl.method.requestSerializer.typeDescriptor.asJson(),
1986
+ response: methodImpl.method.responseSerializer.typeDescriptor.asJson(),
1987
+ doc: methodImpl.method.doc,
1988
+ })),
1989
+ };
1990
+ const jsonCode = JSON.stringify(json, undefined, " ");
1991
+ return new RawResponse(jsonCode, "ok-json");
1992
+ }
1993
+ else if (reqBody === "debug" || reqBody === "restudio") {
1994
+ return new RawResponse(RESTUDIO_HTML, "ok-html");
1995
+ }
1996
+ // Parse request
1997
+ let methodName;
1998
+ let methodNumber;
1999
+ let format;
2000
+ let requestData;
2001
+ const firstChar = reqBody.charAt(0);
2002
+ if (/\s/.test(firstChar) || firstChar === "{") {
2003
+ // A JSON object
2004
+ let reqBodyJson;
2005
+ try {
2006
+ reqBodyJson = JSON.parse(reqBody);
2007
+ }
2008
+ catch (e) {
2009
+ return new RawResponse("bad request: invalid JSON", "bad-request");
2010
+ }
2011
+ const methodField = reqBodyJson["method"];
2012
+ if (methodField === undefined) {
2013
+ return new RawResponse("bad request: missing 'method' field in JSON", "bad-request");
2014
+ }
2015
+ if (typeof methodField === "string") {
2016
+ methodName = methodField;
2017
+ methodNumber = undefined;
2018
+ }
2019
+ else if (typeof methodField === "number") {
2020
+ methodName = "?";
2021
+ methodNumber = methodField;
2022
+ }
2023
+ else {
2024
+ return new RawResponse("bad request: 'method' field must be a string or a number", "bad-request");
2025
+ }
2026
+ format = "readable";
2027
+ const requestField = reqBodyJson["request"];
2028
+ if (requestField === undefined) {
2029
+ return new RawResponse("bad request: missing 'request' field in JSON", "bad-request");
2030
+ }
2031
+ requestData = ["json", requestField];
2032
+ }
2033
+ else {
2034
+ // A colon-separated string
2035
+ const match = reqBody.match(/^([^:]*):([^:]*):([^:]*):([\S\s]*)$/);
2036
+ if (!match) {
2037
+ return new RawResponse("bad request: invalid request format", "bad-request");
2038
+ }
2039
+ methodName = match[1];
2040
+ const methodNumberStr = match[2];
2041
+ format = match[3];
2042
+ requestData = ["json-code", match[4]];
2043
+ if (methodNumberStr) {
2044
+ if (!/^-?[0-9]+$/.test(methodNumberStr)) {
2045
+ return new RawResponse("bad request: can't parse method number", "bad-request");
2046
+ }
2047
+ methodNumber = parseInt(methodNumberStr);
2048
+ }
2049
+ else {
2050
+ methodNumber = undefined;
2051
+ }
2052
+ }
2053
+ // Look up method by number or name
2054
+ if (methodNumber === undefined) {
2055
+ // Try to get the method number by name
2056
+ const allMethods = Object.values(this.methodImpls);
2057
+ const nameMatches = allMethods.filter((m) => m.method.name === methodName);
2058
+ if (nameMatches.length === 0) {
2059
+ return new RawResponse(`bad request: method not found: ${methodName}`, "bad-request");
2060
+ }
2061
+ else if (nameMatches.length > 1) {
2062
+ return new RawResponse(`bad request: method name '${methodName}' is ambiguous; use method number instead`, "bad-request");
2063
+ }
2064
+ methodNumber = nameMatches[0].method.number;
2065
+ }
2066
+ const methodImpl = this.methodImpls[methodNumber];
2067
+ if (!methodImpl) {
2068
+ return new RawResponse(`bad request: method not found: ${methodName}; number: ${methodNumber}`, "bad-request");
2069
+ }
2070
+ let req;
2071
+ try {
2072
+ if (requestData[0] == "json") {
2073
+ req = methodImpl.method.requestSerializer.fromJson(requestData[1], keepUnrecognizedValues);
2074
+ }
2075
+ else {
2076
+ req = methodImpl.method.requestSerializer.fromJsonCode(requestData[1], keepUnrecognizedValues);
2077
+ }
2078
+ }
2079
+ catch (e) {
2080
+ return new RawResponse(`bad request: can't parse JSON: ${e}`, "bad-request");
2081
+ }
2082
+ let res;
2083
+ try {
2084
+ res = yield methodImpl.impl(req, reqMeta, resMeta);
2085
+ }
2086
+ catch (e) {
2087
+ return new RawResponse(`server error: ${e}`, "server-error");
2088
+ }
2089
+ let resJson;
2090
+ try {
2091
+ const flavor = format === "readable" ? "readable" : "dense";
2092
+ resJson = methodImpl.method.responseSerializer.toJsonCode(res, flavor);
2093
+ }
2094
+ catch (e) {
2095
+ return new RawResponse(`server error: can't serialize response to JSON: ${e}`, "server-error");
2096
+ }
2097
+ return new RawResponse(resJson, "ok-json");
2098
+ });
2099
+ }
2100
+ }
2101
+ exports.Service = Service;
2102
+ function installServiceOnExpressApp(app, queryPath, service, text, json, keepUnrecognizedValues) {
2103
+ const callback = (req, res) => __awaiter(this, void 0, void 0, function* () {
2104
+ let body;
2105
+ const indexOfQuestionMark = req.originalUrl.indexOf("?");
2106
+ if (indexOfQuestionMark >= 0) {
2107
+ const queryString = req.originalUrl.substring(indexOfQuestionMark + 1);
2108
+ body = decodeURIComponent(queryString);
2109
+ }
2110
+ else {
2111
+ body =
2112
+ typeof req.body === "string"
2113
+ ? req.body
2114
+ : typeof req.body === "object"
2115
+ ? JSON.stringify(req.body)
2116
+ : "";
2117
+ }
2118
+ const rawResponse = yield service.handleRequest(body, req, res, keepUnrecognizedValues);
2119
+ res
2120
+ .status(rawResponse.statusCode)
2121
+ .contentType(rawResponse.contentType)
2122
+ .send(rawResponse.data);
2123
+ });
2124
+ app.get(queryPath, callback);
2125
+ app.post(queryPath, text(), json(), callback);
2126
+ }
2127
+ exports.installServiceOnExpressApp = installServiceOnExpressApp;
2128
+ // The UNKNOWN variant is common to all enums.
2129
+ const UNKNOWN_FIELD_SPEC = {
2130
+ name: "?",
2131
+ number: 0,
2132
+ };
2133
+ function _initModuleClasses(modulePath, records) {
2134
+ var _a, _b, _c;
2135
+ const privateKey = PRIVATE_KEY;
2136
+ // First loop: add a serializer property to every record class.
2137
+ for (const record of records) {
2138
+ const clazz = record.ctor;
2139
+ switch (record.kind) {
2140
+ case "struct": {
2141
+ const { ctor, initFn } = record;
2142
+ // Create the DEFAULT value. It will be initialized in a second loop.
2143
+ // To see why we can't initialize it in the first loop, consider this
2144
+ // example:
2145
+ // struct Foo { bar: Bar; }
2146
+ // struct Bar { foo: Foo; }
2147
+ // The default value for Foo must contain a reference to the default
2148
+ // value for Bar, and the default value for Bar also needs to contain
2149
+ // a reference to the default value for Foo.
2150
+ clazz.DEFAULT = new ctor(privateKey);
2151
+ // Expose the mutable class as a static property of the frozen class.
2152
+ const mutableCtor = makeMutableClassForRecord(record, clazz.DEFAULT);
2153
+ clazz.Mutable = mutableCtor;
2154
+ // Define the 'create' static factory function.
2155
+ const createFn = (initializer) => {
2156
+ if (initializer instanceof ctor) {
2157
+ return initializer;
2158
+ }
2159
+ const ret = new ctor(privateKey);
2160
+ initFn(ret, initializer);
2161
+ if (initializer["^"]) {
2162
+ ret["^"] = initializer["^"];
2163
+ }
2164
+ return Object.freeze(ret);
2165
+ };
2166
+ clazz.create = createFn;
2167
+ // Create the serializer. It will be initialized in a second loop.
2168
+ clazz.serializer = new StructSerializerImpl(clazz.DEFAULT, createFn, () => new mutableCtor());
2169
+ break;
2170
+ }
2171
+ case "enum": {
2172
+ // Create the constants.
2173
+ // Prepend the UNKNOWN variant to the array of fields specified from the
2174
+ // generated code.
2175
+ record.fields = [UNKNOWN_FIELD_SPEC].concat(record.fields);
2176
+ for (const field of record.fields) {
2177
+ if (field.type) {
2178
+ continue;
2179
+ }
2180
+ const property = enumConstantNameToProperty(field.name);
2181
+ clazz[property] = new record.ctor(PRIVATE_KEY, field.name);
2182
+ }
2183
+ // Define the 'create' static factory function.
2184
+ const createFn = makeCreateEnumFunction(record);
2185
+ clazz.create = createFn;
2186
+ // Create the serializer. It will be initialized in a second loop.
2187
+ clazz.serializer = new EnumSerializerImpl(createFn);
2188
+ break;
2189
+ }
2190
+ }
2191
+ // If the record is nested, expose the record class as a static property of
2192
+ // the parent class.
2193
+ if (record.parentCtor) {
2194
+ record.parentCtor[record.name] = record.ctor;
2195
+ }
2196
+ }
2197
+ // Second loop: initialize the serializer of every record, initialize the
2198
+ // default value of every struct, and freeze every class so new properties
2199
+ // can't be added to it.
2200
+ for (const record of records) {
2201
+ const clazz = record.ctor;
2202
+ const parentTypeDescriptor = (_a = record.parentCtor) === null || _a === void 0 ? void 0 : _a.serializer;
2203
+ switch (record.kind) {
2204
+ case "struct": {
2205
+ // Initializer serializer.
2206
+ const fields = record.fields.map((f) => new StructFieldImpl(f.name, f.property, f.number, getSerializerForType(f.type)));
2207
+ const serializer = clazz.serializer;
2208
+ serializer.init(record.name, modulePath, parentTypeDescriptor, fields, (_b = record.removedNumbers) !== null && _b !== void 0 ? _b : []);
2209
+ // Initialize DEFAULT.
2210
+ const { DEFAULT } = clazz;
2211
+ record.initFn(DEFAULT, {});
2212
+ Object.freeze(DEFAULT);
2213
+ // Define the mutable getters in the Mutable class.
2214
+ const mutableCtor = clazz.Mutable;
2215
+ for (const field of record.fields) {
2216
+ if (field.mutableGetter) {
2217
+ Object.defineProperty(mutableCtor.prototype, field.mutableGetter, {
2218
+ get: makeMutableGetterFn(field),
2219
+ });
2220
+ }
2221
+ }
2222
+ // Define the search methods in the frozen class.
2223
+ for (const field of record.fields) {
2224
+ if (field.indexable) {
2225
+ record.ctor.prototype[field.indexable.searchMethod] =
2226
+ makeSearchMethod(field);
2227
+ }
2228
+ }
2229
+ // Freeze the frozen class and the mutable class.
2230
+ Object.freeze(record.ctor);
2231
+ Object.freeze(record.ctor.prototype);
2232
+ Object.freeze(clazz.Mutable);
2233
+ Object.freeze(clazz.Mutable.prototype);
2234
+ break;
2235
+ }
2236
+ case "enum": {
2237
+ const serializer = clazz.serializer;
2238
+ const fields = record.fields.map((f) => f.type
2239
+ ? new EnumWrapperVariantImpl(f.name, f.number, getSerializerForType(f.type), serializer.createFn)
2240
+ : {
2241
+ name: f.name,
2242
+ number: f.number,
2243
+ constant: clazz[enumConstantNameToProperty(f.name)],
2244
+ });
2245
+ serializer.init(record.name, modulePath, parentTypeDescriptor, fields, (_c = record.removedNumbers) !== null && _c !== void 0 ? _c : []);
2246
+ // Freeze the enum class.
2247
+ Object.freeze(record.ctor);
2248
+ Object.freeze(record.ctor.prototype);
2249
+ break;
2250
+ }
2251
+ }
2252
+ }
2253
+ }
2254
+ exports._initModuleClasses = _initModuleClasses;
2255
+ function enumConstantNameToProperty(name) {
2256
+ return name === "?" ? "UNKNOWN" : name;
2257
+ }
2258
+ function makeCreateEnumFunction(enumSpec) {
2259
+ const { ctor, createValueFn } = enumSpec;
2260
+ const createValue = createValueFn || (() => undefined);
2261
+ const privateKey = PRIVATE_KEY;
2262
+ return (initializer) => {
2263
+ if (initializer instanceof ctor) {
2264
+ return initializer;
2265
+ }
2266
+ if (typeof initializer === "string") {
2267
+ const maybeResult = ctor[enumConstantNameToProperty(initializer)];
2268
+ if (maybeResult instanceof ctor) {
2269
+ return maybeResult;
2270
+ }
2271
+ throw new Error(`Constant not found: ${initializer}`);
2272
+ }
2273
+ if (initializer instanceof UnrecognizedEnum) {
2274
+ return new ctor(privateKey, "?", undefined, initializer);
2275
+ }
2276
+ const kind = initializer.kind;
2277
+ if (kind === undefined) {
2278
+ throw new Error("Missing entry: kind");
2279
+ }
2280
+ const value = createValue(initializer);
2281
+ if (value === undefined) {
2282
+ throw new Error(`Wrapper field not found: ${kind}`);
2283
+ }
2284
+ return new ctor(privateKey, kind, value);
2285
+ };
2286
+ }
2287
+ function makeMutableClassForRecord(structSpec, defaultFrozen) {
2288
+ const { ctor: frozenCtor, initFn } = structSpec;
2289
+ const frozenClass = frozenCtor;
2290
+ class Mutable {
2291
+ constructor(initializer = defaultFrozen) {
2292
+ initFn(this, initializer);
2293
+ if (initializer["^"]) {
2294
+ this["^"] = initializer["^"];
2295
+ }
2296
+ Object.seal(this);
2297
+ }
2298
+ toFrozen() {
2299
+ return frozenClass.create(this);
2300
+ }
2301
+ toString() {
2302
+ const serializer = frozenClass.serializer;
2303
+ return serializer.toJsonCode(this, "readable");
2304
+ }
2305
+ }
2306
+ return Mutable;
2307
+ }
2308
+ function getSerializerForType(type) {
2309
+ switch (type.kind) {
2310
+ case "array":
2311
+ return arraySerializer(getSerializerForType(type.item), type.keyChain);
2312
+ case "optional":
2313
+ return optionalSerializer(getSerializerForType(type.other));
2314
+ case "primitive":
2315
+ return primitiveSerializer(type.primitive);
2316
+ case "record":
2317
+ return type.ctor
2318
+ .serializer;
2319
+ }
2320
+ }
2321
+ // The `mutableArray()` getter of the Mutable class returns `this.array` if and
2322
+ // only if `mutableArray()` was never called before or if `this.array` is the
2323
+ // last value returned by `mutableArray()`.
2324
+ // Otherwise, it makes a mutable copy of `this.array`, assigns it to
2325
+ // `this.array` and returns it.
2326
+ const arraysReturnedByMutableGetters = new WeakMap();
2327
+ function makeMutableGetterFn(field) {
2328
+ const { property, type } = field;
2329
+ switch (type.kind) {
2330
+ case "array": {
2331
+ class Class {
2332
+ static ret() {
2333
+ const value = this[property];
2334
+ if (arraysReturnedByMutableGetters.get(value) === this) {
2335
+ return value;
2336
+ }
2337
+ const copy = [...value];
2338
+ arraysReturnedByMutableGetters.set(copy, this);
2339
+ return (this[property] = copy);
2340
+ }
2341
+ }
2342
+ return Class.ret;
2343
+ }
2344
+ case "record": {
2345
+ const mutableCtor = type.ctor.Mutable;
2346
+ class Class {
2347
+ static ret() {
2348
+ const value = this[property];
2349
+ if (value instanceof mutableCtor) {
2350
+ return value;
2351
+ }
2352
+ return (this[property] = new mutableCtor(value));
2353
+ }
2354
+ }
2355
+ return Class.ret;
2356
+ }
2357
+ default: {
2358
+ throw new Error();
2359
+ }
2360
+ }
2361
+ }
2362
+ function makeSearchMethod(field) {
2363
+ var _a;
2364
+ const { property } = field;
2365
+ const indexable = field.indexable;
2366
+ const { keyFn } = indexable;
2367
+ const keyToHashable = (_a = indexable.keyToHashable) !== null && _a !== void 0 ? _a : ((e) => e);
2368
+ class Class {
2369
+ ret(key) {
2370
+ const array = this[property];
2371
+ const frozenArrayInfo = frozenArrayRegistry.get(array);
2372
+ let { keyFnToIndexing } = frozenArrayInfo;
2373
+ if (!keyFnToIndexing) {
2374
+ frozenArrayInfo.keyFnToIndexing = keyFnToIndexing = //
2375
+ new Map();
2376
+ }
2377
+ let hashableToValue = keyFnToIndexing.get(keyFn);
2378
+ if (!hashableToValue) {
2379
+ // The array has not been indexed yet. Index it.
2380
+ hashableToValue = new Map();
2381
+ for (const v of array) {
2382
+ const hashable = keyToHashable(keyFn(v));
2383
+ hashableToValue.set(hashable, v);
2384
+ }
2385
+ keyFnToIndexing.set(keyFn, hashableToValue);
2386
+ }
2387
+ return hashableToValue.get(keyToHashable(key));
2388
+ }
2389
+ }
2390
+ return Class.prototype.ret;
2391
+ }
2392
+ //# sourceMappingURL=skir-client.js.map