@php-skir/skir-client 1.0.19

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