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