skir-client 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/serializer_tester.d.ts +18 -0
- package/dist/cjs/serializer_tester.d.ts.map +1 -0
- package/dist/cjs/serializer_tester.js +124 -0
- package/dist/cjs/serializer_tester.js.map +1 -0
- package/dist/cjs/skir-client.d.ts +697 -0
- package/dist/cjs/skir-client.d.ts.map +1 -0
- package/dist/cjs/skir-client.js +2392 -0
- package/dist/cjs/skir-client.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/serializer_tester.d.ts +18 -0
- package/dist/esm/serializer_tester.d.ts.map +1 -0
- package/dist/esm/serializer_tester.js +119 -0
- package/dist/esm/serializer_tester.js.map +1 -0
- package/dist/esm/skir-client.d.ts +697 -0
- package/dist/esm/skir-client.d.ts.map +1 -0
- package/dist/esm/skir-client.js +2374 -0
- package/dist/esm/skir-client.js.map +1 -0
- package/package.json +58 -0
- package/src/serializer_tester.ts +185 -0
- package/src/skir-client.ts +3492 -0
|
@@ -0,0 +1,697 @@
|
|
|
1
|
+
/// <reference types="node" resolution-mode="require"/>
|
|
2
|
+
import type { Express as ExpressApp, json as ExpressJson, Request as ExpressRequest, Response as ExpressResponse, text as ExpressText } from "express";
|
|
3
|
+
/**
|
|
4
|
+
* A single moment in time represented in a platform-independent format, with a
|
|
5
|
+
* precision of one millisecond.
|
|
6
|
+
*
|
|
7
|
+
* A `Timestamp` object can represent a maximum of ±8,640,000,000,000,000
|
|
8
|
+
* milliseconds, or ±100,000,000 (one hundred million) days, relative to the
|
|
9
|
+
* Unix epoch. This is the range from April 20, 271821 BC to September 13,
|
|
10
|
+
* 275760 AD.
|
|
11
|
+
*
|
|
12
|
+
* Unlike the Javascript built-in `Date` type, a `Timestamp` is immutable.
|
|
13
|
+
* Like a `Date`, a `Timestamp` object does not contain a timezone.
|
|
14
|
+
*/
|
|
15
|
+
export declare class Timestamp {
|
|
16
|
+
/** Number of milliseconds ellapsed since the Unix epoch. */
|
|
17
|
+
readonly unixMillis: number;
|
|
18
|
+
/**
|
|
19
|
+
* Returns a `Timestamp` representing the same moment in time as the given
|
|
20
|
+
* Javascript `Date` object.
|
|
21
|
+
*
|
|
22
|
+
* @throws if the given `Date` object has a timestamp value of NaN
|
|
23
|
+
*/
|
|
24
|
+
static from(date: Date): Timestamp;
|
|
25
|
+
/**
|
|
26
|
+
* Creates a `Timestamp` object from a number of milliseconds from the Unix
|
|
27
|
+
* epoch.
|
|
28
|
+
*
|
|
29
|
+
* If the given number if outside the valid range (±8,640,000,000,000,000),
|
|
30
|
+
* this function will return `Timestamp.MAX` or `Timestamp.MIN` depending on
|
|
31
|
+
* the sign of the number.
|
|
32
|
+
*
|
|
33
|
+
* @throws if the given number is NaN
|
|
34
|
+
*/
|
|
35
|
+
static fromUnixMillis(unixMillis: number): Timestamp;
|
|
36
|
+
/**
|
|
37
|
+
* Creates a `Timestamp` object from a number of seconds from the Unix epoch.
|
|
38
|
+
*
|
|
39
|
+
* If the given number if outside the valid range (±8,640,000,000,000), this
|
|
40
|
+
* function will return `Timestamp.MAX` or `Timestamp.MIN` depending on the
|
|
41
|
+
* sign of the number.
|
|
42
|
+
*
|
|
43
|
+
* @throws if the given number is NaN
|
|
44
|
+
*/
|
|
45
|
+
static fromUnixSeconds(unixSeconds: number): Timestamp;
|
|
46
|
+
/**
|
|
47
|
+
* Parses a date in the date time string format.
|
|
48
|
+
*
|
|
49
|
+
* @throws if the given string is not a date in the date time string format
|
|
50
|
+
* @see https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-date-time-string-format
|
|
51
|
+
*/
|
|
52
|
+
static parse(date: string): Timestamp;
|
|
53
|
+
/** Returns a `Timestamp` representing the current moment in time. */
|
|
54
|
+
static now(): Timestamp;
|
|
55
|
+
/** Thursday, 1 January 1970. */
|
|
56
|
+
static readonly UNIX_EPOCH: Timestamp;
|
|
57
|
+
/**
|
|
58
|
+
* Earliest moment in time representable as a `Timestamp`, namely April 20,
|
|
59
|
+
* 271821 BC.
|
|
60
|
+
*
|
|
61
|
+
* @see https://262.ecma-international.org/5.1/#sec-15.9.1.1
|
|
62
|
+
*/
|
|
63
|
+
static readonly MIN: Timestamp;
|
|
64
|
+
/**
|
|
65
|
+
* Latest moment in time representable as a `Timestamp`, namely September 13,
|
|
66
|
+
* 275760 AD.
|
|
67
|
+
*
|
|
68
|
+
* @see https://262.ecma-international.org/5.1/#sec-15.9.1.1
|
|
69
|
+
*/
|
|
70
|
+
static readonly MAX: Timestamp;
|
|
71
|
+
private constructor();
|
|
72
|
+
/** Number of seconds ellapsed since the Unix epoch. */
|
|
73
|
+
get unixSeconds(): number;
|
|
74
|
+
/**
|
|
75
|
+
* Returns a `Date` object representing the same moment in time as this
|
|
76
|
+
* `Timestamp`.
|
|
77
|
+
*/
|
|
78
|
+
toDate(): Date;
|
|
79
|
+
toString(): string;
|
|
80
|
+
}
|
|
81
|
+
/** An immutable array of bytes. */
|
|
82
|
+
export declare class ByteString {
|
|
83
|
+
private readonly arrayBuffer;
|
|
84
|
+
private readonly byteOffset;
|
|
85
|
+
/** The length of this byte string. */
|
|
86
|
+
readonly byteLength: number;
|
|
87
|
+
/**
|
|
88
|
+
* Returns an immutable byte string containing all the bytes of `input` from
|
|
89
|
+
* `start`, inclusive, up to `end`, exclusive.
|
|
90
|
+
*
|
|
91
|
+
* If `input` is an `ArrayBuffer`, this function copies the bytes. Otherwise
|
|
92
|
+
* this function returns a sliced view of the input `ByteString`.
|
|
93
|
+
*
|
|
94
|
+
* @example <caption>Copy an array buffer into a byte string</caption>
|
|
95
|
+
* const byteString = ByteString.sliceOf(arrayBuffer);
|
|
96
|
+
*/
|
|
97
|
+
static sliceOf(input: ArrayBuffer | SharedArrayBuffer | ByteString, start?: number, end?: number): ByteString;
|
|
98
|
+
/**
|
|
99
|
+
* Decodes a Base64 string, which can be obtained by calling `toBase64()`.
|
|
100
|
+
*
|
|
101
|
+
* @throws if the given string is not a valid Base64 string.
|
|
102
|
+
* @see https://en.wikipedia.org/wiki/Base64
|
|
103
|
+
*/
|
|
104
|
+
static fromBase64(base64: string): ByteString;
|
|
105
|
+
/**
|
|
106
|
+
* Decodes a hexadecimal string, which can be obtained by calling
|
|
107
|
+
* `toBase16()`.
|
|
108
|
+
*
|
|
109
|
+
* @throws if the given string is not a valid Base64 string.
|
|
110
|
+
*/
|
|
111
|
+
static fromBase16(base16: string): ByteString;
|
|
112
|
+
/** An empty byte string. */
|
|
113
|
+
static readonly EMPTY: ByteString;
|
|
114
|
+
/** Copies the contents of this byte string into the given array buffer. */
|
|
115
|
+
copyTo(target: ArrayBuffer, targetOffset?: number): void;
|
|
116
|
+
/** Copies the contents of this byte string into a new array buffer. */
|
|
117
|
+
toBuffer(): ArrayBuffer;
|
|
118
|
+
/**
|
|
119
|
+
* Encodes this byte string into a Base64 string.
|
|
120
|
+
*
|
|
121
|
+
* @see https://en.wikipedia.org/wiki/Base64
|
|
122
|
+
*/
|
|
123
|
+
toBase64(): string;
|
|
124
|
+
/** Encodes this byte string into a hexadecimal string. */
|
|
125
|
+
toBase16(): string;
|
|
126
|
+
at(index: number): number | undefined;
|
|
127
|
+
toString(): string;
|
|
128
|
+
private constructor();
|
|
129
|
+
private readonly uint8Array;
|
|
130
|
+
}
|
|
131
|
+
/** A read-only JSON value. */
|
|
132
|
+
export type Json = null | boolean | number | string | readonly Json[] | Readonly<{
|
|
133
|
+
[name: string]: Json;
|
|
134
|
+
}>;
|
|
135
|
+
/**
|
|
136
|
+
* Resolves to the generated mutable class for a struct.
|
|
137
|
+
* The type parameter is the generated frozen class.
|
|
138
|
+
*/
|
|
139
|
+
export type MutableForm<Frozen> = Frozen extends _FrozenBase ? ReturnType<Frozen["toMutable"]> & Freezable<Frozen> : Freezable<Frozen>;
|
|
140
|
+
/** Result of encoding a struct using binary encoding format. */
|
|
141
|
+
export interface BinaryForm {
|
|
142
|
+
/** Length (in bytes) of the binary form. */
|
|
143
|
+
readonly byteLength: number;
|
|
144
|
+
/** Copies the contents of the binary form into the given array buffer. */
|
|
145
|
+
copyTo(target: ArrayBuffer, offset?: number): void;
|
|
146
|
+
/** Copies the contents of this byte string into a new array buffer. */
|
|
147
|
+
toBuffer(): ArrayBuffer;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* When using the JSON serialization format, you can chose between two flavors.
|
|
151
|
+
*
|
|
152
|
+
* The dense flavor is the default flavor and is preferred in most cases.
|
|
153
|
+
* Structs are converted to JSON arrays, where the number of each field
|
|
154
|
+
* corresponds to the index of the value in the array. This results in a more
|
|
155
|
+
* compact representation than when using JSON objects, and this makes
|
|
156
|
+
* serialization and deserialization a bit faster. Because field names are left
|
|
157
|
+
* out of the JSON, it is a representation which allows persistence: you can
|
|
158
|
+
* safely rename a field in a `.skir` file without breaking backwards
|
|
159
|
+
* compatibility.
|
|
160
|
+
* One con of this representation is that it is harder to tell, just by looking
|
|
161
|
+
* at the JSON, what field of the struct each value in the array corresponds to.
|
|
162
|
+
*
|
|
163
|
+
* When using the readable flavor, structs are converted to JSON objects. The
|
|
164
|
+
* name of each field in the `.skir` file is used as-is in the JSON. This
|
|
165
|
+
* results in a representation which is much more readable by humans, but also
|
|
166
|
+
* not suited for persistence: when you rename a field in a `.skir` file, you
|
|
167
|
+
* will no lonnger be able to deserialize old JSONs.
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* const jane = Person.create({firstName: "Jane", lastName: "Doe"});
|
|
171
|
+
*
|
|
172
|
+
* console.log(Person.serializer.toJson(jane, "dense"));
|
|
173
|
+
* // Output: ["Jane","Doe"]
|
|
174
|
+
*
|
|
175
|
+
* console.log(Person.serializer.toJson(jane));
|
|
176
|
+
* // Output: ["Jane","Doe"]
|
|
177
|
+
*
|
|
178
|
+
* console.log(Person.serializer.toJson(jane, "readable"));
|
|
179
|
+
* // Output: {
|
|
180
|
+
* // "firstName": "Jane",
|
|
181
|
+
* // "lastName": "Doe"
|
|
182
|
+
* // }
|
|
183
|
+
*/
|
|
184
|
+
export type JsonFlavor = "dense" | "readable";
|
|
185
|
+
/**
|
|
186
|
+
* Serializes and deserializes instances of `T`. Supports two serialization
|
|
187
|
+
* formats: JSON and binary.
|
|
188
|
+
*
|
|
189
|
+
* All deserialization methods return a deeply-immutable `T`. If `T` is the
|
|
190
|
+
* generated frozen class for a struct, all serialization methods accept either
|
|
191
|
+
* a `T` or a `T.Mutable`.
|
|
192
|
+
*
|
|
193
|
+
* Do NOT create your own `Serializer` implementation. Only use implementations
|
|
194
|
+
* provided by Skir.
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* let jane = Person.create({firstName: "Jane", lastName: "Doe"});
|
|
198
|
+
* const json = Person.serializer.toJson(jane);
|
|
199
|
+
* jane = Person.serializer.fromJson(json);
|
|
200
|
+
* expect(jane.firstName).toBe("Jane");
|
|
201
|
+
*/
|
|
202
|
+
export interface Serializer<T> {
|
|
203
|
+
/**
|
|
204
|
+
* Converts back the given stringified JSON to `T`.
|
|
205
|
+
* Works with both [flavors]{@link JsonFlavor} of JSON.
|
|
206
|
+
*
|
|
207
|
+
* Pass in "keep-unrecognized-values" if and only if the input JSON comes
|
|
208
|
+
* from a trusted program which might have been built from more recent
|
|
209
|
+
* source files.
|
|
210
|
+
*/
|
|
211
|
+
fromJsonCode(code: string, keep?: "keep-unrecognized-values"): T;
|
|
212
|
+
/**
|
|
213
|
+
* Converts back the given JSON to `T`.
|
|
214
|
+
* Works with both [flavors]{@link JsonFlavor} of JSON.
|
|
215
|
+
*
|
|
216
|
+
* Pass in "keep-unrecognized-values" if and only if the input JSON comes
|
|
217
|
+
* from a trusted program which might have been built from more recent
|
|
218
|
+
* source files.
|
|
219
|
+
*/
|
|
220
|
+
fromJson(json: Json, keep?: "keep-unrecognized-values"): T;
|
|
221
|
+
/**
|
|
222
|
+
* Converts back the given binary form to `T`.
|
|
223
|
+
*
|
|
224
|
+
* Pass in "keep-unrecognized-values" if and only if the input JSON comes
|
|
225
|
+
* from a trusted program which might have been built from more recent
|
|
226
|
+
* source files.
|
|
227
|
+
*/
|
|
228
|
+
fromBytes(bytes: ArrayBuffer, keep?: "keep-unrecognized-values"): T;
|
|
229
|
+
/**
|
|
230
|
+
* Converts the given `T` to JSON and returns the stringified JSON. Same as
|
|
231
|
+
* calling `JSON.stringify()` on the result of `toJson()`.
|
|
232
|
+
*
|
|
233
|
+
* @param flavor dense or readable, defaults to dense
|
|
234
|
+
* @see JsonFlavor
|
|
235
|
+
*/
|
|
236
|
+
toJsonCode(input: T | MutableForm<T>, flavor?: JsonFlavor): string;
|
|
237
|
+
/**
|
|
238
|
+
* Converts the given `T` to JSON. If you only need the stringified JSON, call
|
|
239
|
+
* `toJsonCode()` instead.
|
|
240
|
+
*
|
|
241
|
+
* @param flavor dense or readable, defaults to dense
|
|
242
|
+
* @see JsonFlavor
|
|
243
|
+
*/
|
|
244
|
+
toJson(input: T | MutableForm<T>, flavor?: JsonFlavor): Json;
|
|
245
|
+
/** Converts the given `T` to binary format. */
|
|
246
|
+
toBytes(input: T | MutableForm<T>): BinaryForm;
|
|
247
|
+
/** An object describing the type `T`. Enables reflective programming. */
|
|
248
|
+
typeDescriptor: TypeDescriptorSpecialization<T>;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Returns a serializer of instances of the given Skir primitive type.
|
|
252
|
+
*
|
|
253
|
+
* @example
|
|
254
|
+
* expect(
|
|
255
|
+
* primitiveSerializer("string").toJsonCode("foo")
|
|
256
|
+
* ).toBe(
|
|
257
|
+
* '"foo"'
|
|
258
|
+
* );
|
|
259
|
+
*/
|
|
260
|
+
export declare function primitiveSerializer<P extends keyof PrimitiveTypes>(primitiveType: P): Serializer<PrimitiveTypes[P]>;
|
|
261
|
+
/**
|
|
262
|
+
* Returns a serializer of arrays of `Item`s.
|
|
263
|
+
*
|
|
264
|
+
* @example
|
|
265
|
+
* expect(
|
|
266
|
+
* arraySerializer(User.serializer).toJsonCode([JANE, JOE])
|
|
267
|
+
* ).toBe(
|
|
268
|
+
* '[["jane"],["joe"]]'
|
|
269
|
+
* );
|
|
270
|
+
*/
|
|
271
|
+
export declare function arraySerializer<Item>(item: Serializer<Item>, keyChain?: string): Serializer<ReadonlyArray<Item>>;
|
|
272
|
+
/** Returns a serializer of nullable `T`s. */
|
|
273
|
+
export declare function optionalSerializer<T>(other: Serializer<T>): Serializer<T | null>;
|
|
274
|
+
/**
|
|
275
|
+
* Describes the type `T`, where `T` is the TypeScript equivalent of a Skir
|
|
276
|
+
* type. Enables reflective programming.
|
|
277
|
+
*
|
|
278
|
+
* Every `TypeDescriptor` instance has a `kind` field which can take one of
|
|
279
|
+
* these 5 values: `"primitive"`, `"optional"`, `"array"`, `"struct"`, `"enum"`.
|
|
280
|
+
*/
|
|
281
|
+
export type TypeDescriptor<T = unknown> = OptionalDescriptor<T> | ArrayDescriptor<T> | StructDescriptor<T> | EnumDescriptor<T> | PrimitiveDescriptor;
|
|
282
|
+
/** Specialization of `TypeDescriptor<T>` when `T` is known. */
|
|
283
|
+
export type TypeDescriptorSpecialization<T> = [
|
|
284
|
+
T
|
|
285
|
+
] extends [_FrozenBase] ? StructDescriptor<T> : [T] extends [_EnumBase] ? EnumDescriptor<T> : TypeDescriptor<T>;
|
|
286
|
+
interface TypeDescriptorBase {
|
|
287
|
+
/** Returns the JSON representation of this `TypeDescriptor`. */
|
|
288
|
+
asJson(): Json;
|
|
289
|
+
/**
|
|
290
|
+
* Returns the JSON code representation of this `TypeDescriptor`.
|
|
291
|
+
* Same as calling `JSON.stringify()` on the result of `asJson()`.
|
|
292
|
+
*/
|
|
293
|
+
asJsonCode(): string;
|
|
294
|
+
/**
|
|
295
|
+
* Converts from one serialized form to another.
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* const denseJson = User.serializer.toJson(user, "dense");
|
|
299
|
+
* expect(
|
|
300
|
+
* User.serializer.typeDescriptor.transform(denseJson, "readable")
|
|
301
|
+
* ).toMatch(
|
|
302
|
+
* User.serializer.toJson(user, "readable")
|
|
303
|
+
* );
|
|
304
|
+
*/
|
|
305
|
+
transform(json_or_bytes: Json | ArrayBuffer, out: JsonFlavor): Json;
|
|
306
|
+
transform(json: Json, out: "bytes"): ArrayBuffer;
|
|
307
|
+
transform(json_or_bytes: Json | ArrayBuffer, out: JsonFlavor | "bytes"): Json | ArrayBuffer;
|
|
308
|
+
}
|
|
309
|
+
/** Describes a primitive Skir type. */
|
|
310
|
+
export interface PrimitiveDescriptor extends TypeDescriptorBase {
|
|
311
|
+
kind: "primitive";
|
|
312
|
+
primitive: keyof PrimitiveTypes;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* An interface mapping a primitive Skir type to the corresponding TypeScript
|
|
316
|
+
* type.
|
|
317
|
+
*/
|
|
318
|
+
export interface PrimitiveTypes {
|
|
319
|
+
bool: boolean;
|
|
320
|
+
int32: number;
|
|
321
|
+
int64: bigint;
|
|
322
|
+
uint64: bigint;
|
|
323
|
+
float32: number;
|
|
324
|
+
float64: number;
|
|
325
|
+
timestamp: Timestamp;
|
|
326
|
+
string: string;
|
|
327
|
+
bytes: ByteString;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Describes an optional type. In a `.skir` file, an optional type is
|
|
331
|
+
* represented with a question mark at the end of another type.
|
|
332
|
+
*/
|
|
333
|
+
export interface OptionalDescriptor<T> extends TypeDescriptorBase {
|
|
334
|
+
readonly kind: "optional";
|
|
335
|
+
/** Describes the other (non-optional) type. */
|
|
336
|
+
readonly otherType: TypeDescriptor<NonNullable<T>>;
|
|
337
|
+
}
|
|
338
|
+
/** Describes an array type. */
|
|
339
|
+
export interface ArrayDescriptor<T> extends TypeDescriptorBase {
|
|
340
|
+
readonly kind: "array";
|
|
341
|
+
/** Describes the type of the array items. */
|
|
342
|
+
readonly itemType: TypeDescriptor<T extends ReadonlyArray<infer Item> ? Item : unknown>;
|
|
343
|
+
readonly keyChain?: string;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Describes a Skir struct.
|
|
347
|
+
* The type parameter `T` refers to the generated frozen class for the struct.
|
|
348
|
+
*/
|
|
349
|
+
export interface StructDescriptor<T = unknown> extends TypeDescriptorBase {
|
|
350
|
+
readonly kind: "struct";
|
|
351
|
+
/** Name of the struct as specified in the `.skir` file. */
|
|
352
|
+
readonly name: string;
|
|
353
|
+
/**
|
|
354
|
+
* A string containing all the names in the hierarchic sequence above and
|
|
355
|
+
* including the struct. For example: "Foo.Bar" if "Bar" is nested within a
|
|
356
|
+
* type called "Foo", or simply "Bar" if "Bar" is defined at the top-level of
|
|
357
|
+
* the module.
|
|
358
|
+
*/
|
|
359
|
+
readonly qualifiedName: string;
|
|
360
|
+
/**
|
|
361
|
+
* Path to the module where the struct is defined, relative to the root of the
|
|
362
|
+
* project.
|
|
363
|
+
*/
|
|
364
|
+
readonly modulePath: string;
|
|
365
|
+
/**
|
|
366
|
+
* If the struct is nested within another type, the descriptor for that type.
|
|
367
|
+
* Undefined if the struct is defined at the top-level of the module.
|
|
368
|
+
*/
|
|
369
|
+
readonly parentType: StructDescriptor | EnumDescriptor | undefined;
|
|
370
|
+
/** The fields of the struct in the order they appear in the `.skir` file. */
|
|
371
|
+
readonly fields: ReadonlyArray<StructField<T>>;
|
|
372
|
+
/** The field numbers marked as removed. */
|
|
373
|
+
readonly removedNumbers: ReadonlySet<number>;
|
|
374
|
+
/**
|
|
375
|
+
* Looks up a field. The key can be one of: the field name (e.g. "user_id");
|
|
376
|
+
* the name of the property in the generated class (e.g. "userId"), the field
|
|
377
|
+
* number.
|
|
378
|
+
*
|
|
379
|
+
* The return type is `StructField<T> | undefined` unless the key is known at
|
|
380
|
+
* compile-time to be the name of the property in the generated class, in
|
|
381
|
+
* which case it is `StructField<T>`.
|
|
382
|
+
*/
|
|
383
|
+
getField<K extends string | number>(key: K): StructFieldResult<T, K>;
|
|
384
|
+
/**
|
|
385
|
+
* Returns a new instance of the generated mutable class for a struct.
|
|
386
|
+
* Performs a shallow copy of `initializer` if `initializer` is specified.
|
|
387
|
+
*/
|
|
388
|
+
newMutable(initializer?: T | MutableForm<T>): MutableForm<T>;
|
|
389
|
+
}
|
|
390
|
+
/** Field of a Skir struct. */
|
|
391
|
+
export interface StructField<Struct = unknown, Value = unknown> {
|
|
392
|
+
/** Field name as specified in the `.skir` file, e.g. "user_id". */
|
|
393
|
+
readonly name: string;
|
|
394
|
+
/** Name of the property in the generated class, e.g. "userId". */
|
|
395
|
+
readonly property: string;
|
|
396
|
+
/** Field number. */
|
|
397
|
+
readonly number: number;
|
|
398
|
+
/** Describes the field type. */
|
|
399
|
+
readonly type: TypeDescriptor<Value>;
|
|
400
|
+
/** Extracts the value of the field from the given struct. */
|
|
401
|
+
get(struct: Struct | MutableForm<Struct>): Value;
|
|
402
|
+
/** Assigns the given value to the field of the given struct. */
|
|
403
|
+
set(struct: MutableForm<Struct>, value: Value): void;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Return type of the `StructDescriptor.getField` method. If the argument is
|
|
407
|
+
* known at compile-time to be the name of a property of the generated class,
|
|
408
|
+
* resolves to `StructField<Struct>`. Otherwise, resolves to
|
|
409
|
+
* `StructField<Struct> | undefined`.
|
|
410
|
+
*
|
|
411
|
+
* @example <caption>The field is kown at compile-time</caption>
|
|
412
|
+
* const fieldNumber: number =
|
|
413
|
+
* User.serializer.typeDescriptor.getField("userId").number;
|
|
414
|
+
*
|
|
415
|
+
* @example <caption>The field is not kown at compile-time</caption>
|
|
416
|
+
* const fieldNumber: number | undefined =
|
|
417
|
+
* User.serializer.typeDescriptor.getField(variable)?.number;
|
|
418
|
+
*/
|
|
419
|
+
export type StructFieldResult<Struct, Key extends string | number> = StructField<Struct> | (Struct extends _FrozenBase ? Key extends keyof NonNullable<Struct[typeof _INITIALIZER]> ? never : undefined : undefined);
|
|
420
|
+
/** Describes a Skir enum. */
|
|
421
|
+
export interface EnumDescriptor<T = unknown> extends TypeDescriptorBase {
|
|
422
|
+
readonly kind: "enum";
|
|
423
|
+
/** Name of the enum as specified in the `.skir` file. */
|
|
424
|
+
readonly name: string;
|
|
425
|
+
/**
|
|
426
|
+
* A string containing all the names in the hierarchic sequence above and
|
|
427
|
+
* including the enum. For example: "Foo.Bar" if "Bar" is nested within a type
|
|
428
|
+
* called "Foo", or simply "Bar" if "Bar" is defined at the top-level of the
|
|
429
|
+
* module.
|
|
430
|
+
*/
|
|
431
|
+
readonly qualifiedName: string;
|
|
432
|
+
/**
|
|
433
|
+
* Path to the module where the enum is defined, relative to the root of the
|
|
434
|
+
* project.
|
|
435
|
+
*/
|
|
436
|
+
readonly modulePath: string;
|
|
437
|
+
/**
|
|
438
|
+
* If the enum is nested within another type, the descriptor for that type.
|
|
439
|
+
* Undefined if the struct is defined at the top-level of the module.
|
|
440
|
+
*/
|
|
441
|
+
readonly parentType: StructDescriptor | EnumDescriptor | undefined;
|
|
442
|
+
/**
|
|
443
|
+
* Includes the UNKNOWN variant, followed by the other variants in the order
|
|
444
|
+
* they appear in the `.skir` file.
|
|
445
|
+
*/
|
|
446
|
+
readonly variants: ReadonlyArray<EnumVariant<T>>;
|
|
447
|
+
/** The variant numbers marked as removed. */
|
|
448
|
+
readonly removedNumbers: ReadonlySet<number>;
|
|
449
|
+
/**
|
|
450
|
+
* Looks up a variant. The key can be one of the variant name or the variant
|
|
451
|
+
* number.
|
|
452
|
+
*
|
|
453
|
+
* The return type is `EnumVariant<T> | undefined` unless the key is known at
|
|
454
|
+
* compile-time to be a variant name of the enum, in which case it is
|
|
455
|
+
* `EnumVariant<T>`.
|
|
456
|
+
*/
|
|
457
|
+
getVariant<K extends string | number>(key: K): EnumVariantResult<T, K>;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Variant of a Skir enum. Variants which don't hold any value are called
|
|
461
|
+
* constant variants. Their name is always in UPPER_CASE. Variants which hold
|
|
462
|
+
* value of a given type are called wrapper variants, and their name is always
|
|
463
|
+
* in lower_case.
|
|
464
|
+
*/
|
|
465
|
+
export type EnumVariant<Enum = unknown> = EnumConstantVariant<Enum> | EnumWrapperVariant<Enum, unknown>;
|
|
466
|
+
/** Field of a Skir enum which does not hold any value. */
|
|
467
|
+
export interface EnumConstantVariant<Enum = unknown> {
|
|
468
|
+
/**
|
|
469
|
+
* Variant name as specified in the `.skir` file, e.g. "MONDAY".
|
|
470
|
+
* Always in UPPER_CASE format.
|
|
471
|
+
*/
|
|
472
|
+
readonly name: string;
|
|
473
|
+
/** Variant number. */
|
|
474
|
+
readonly number: number;
|
|
475
|
+
/** The instance of the generated class which corresponds to this field. */
|
|
476
|
+
readonly constant: Enum;
|
|
477
|
+
/** Always undefined, unlike the `type` field of `EnumWrapperVariant`. */
|
|
478
|
+
readonly type?: undefined;
|
|
479
|
+
}
|
|
480
|
+
/** Variant of a Skir enum which holds a value of a given type. */
|
|
481
|
+
export interface EnumWrapperVariant<Enum = unknown, Value = unknown> {
|
|
482
|
+
/**
|
|
483
|
+
* Variant name as specified in the `.skir` file, e.g. "v4".
|
|
484
|
+
* Always in lower_case format.
|
|
485
|
+
*/
|
|
486
|
+
readonly name: string;
|
|
487
|
+
/** Variant number. */
|
|
488
|
+
readonly number: number;
|
|
489
|
+
/** Describes the type of the value held by the field. */
|
|
490
|
+
readonly type: TypeDescriptor<Value>;
|
|
491
|
+
/** Always undefined, unlike the `type` field of `EnumConstantVariant`. */
|
|
492
|
+
readonly constant?: undefined;
|
|
493
|
+
/**
|
|
494
|
+
* Extracts the value held by the given enum instance if it matches this
|
|
495
|
+
* enum variant. Returns undefined otherwise.
|
|
496
|
+
*/
|
|
497
|
+
get(e: Enum): Value | unknown;
|
|
498
|
+
/**
|
|
499
|
+
* Returns a new enum instance matching this enum variant and holding the
|
|
500
|
+
* given value.
|
|
501
|
+
*/
|
|
502
|
+
wrap(value: Value): Enum;
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Return type of the `EnumDescriptor.getVariant` method. If the argument is
|
|
506
|
+
* known at compile-time to be the name of variant, resolves to
|
|
507
|
+
* `EnumVariant<Enum>`. Otherwise, resolves to
|
|
508
|
+
* `EnumVariant<Struct> | undefined`.
|
|
509
|
+
*
|
|
510
|
+
* @example <caption>The variant is known at compile-time</caption>
|
|
511
|
+
* const variantNumber: number =
|
|
512
|
+
* Weekday.serializer.typeDescriptor.getVariant("MONDAY").number;
|
|
513
|
+
*
|
|
514
|
+
* @example <caption>The variant is not known at compile-time</caption>
|
|
515
|
+
* const variantNumber: number | undefined =
|
|
516
|
+
* Weekday.serializer.typeDescriptor.getVariant(variable)?.number;
|
|
517
|
+
*/
|
|
518
|
+
export type EnumVariantResult<Enum, Key extends string | number> = EnumVariant<Enum> | (Enum extends _EnumBase ? Key extends Enum["kind"] ? never : undefined : undefined);
|
|
519
|
+
/**
|
|
520
|
+
* Identifies a procedure (the "P" in "RPC") on both the client side and the
|
|
521
|
+
* server side.
|
|
522
|
+
*/
|
|
523
|
+
export interface Method<Request, Response> {
|
|
524
|
+
/** Name of the procedure as specified in the `.skir` file. */
|
|
525
|
+
name: string;
|
|
526
|
+
/**
|
|
527
|
+
* A number which uniquely identifies this procedure.
|
|
528
|
+
* When it is not specified in the `.skir` file, it is obtained by hashing the
|
|
529
|
+
* procedure name.
|
|
530
|
+
*/
|
|
531
|
+
number: number;
|
|
532
|
+
/** Serializer of request objects. */
|
|
533
|
+
requestSerializer: Serializer<Request>;
|
|
534
|
+
/** Serializer of response objects. */
|
|
535
|
+
responseSerializer: Serializer<Response>;
|
|
536
|
+
/**
|
|
537
|
+
* Documentation for this procedure specified as doc comments in the `.skir`
|
|
538
|
+
* file.
|
|
539
|
+
*/
|
|
540
|
+
doc: string;
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Interface implemented by both the frozen and mutable classes generated for a
|
|
544
|
+
* struct. `T` is always the generated frozen class.
|
|
545
|
+
*/
|
|
546
|
+
export interface Freezable<T> {
|
|
547
|
+
/**
|
|
548
|
+
* Returns a deeply-immutable object, either by making a copy of `this` if
|
|
549
|
+
* `this` is mutable, or by returning `this` as-is if `this` is already
|
|
550
|
+
* immutable.
|
|
551
|
+
*/
|
|
552
|
+
toFrozen(): T;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* Returns a `TypeDescriptor` from its JSON representation as returned by
|
|
556
|
+
* `asJson()`.
|
|
557
|
+
*/
|
|
558
|
+
export declare function parseTypeDescriptorFromJson(json: Json): TypeDescriptor;
|
|
559
|
+
/**
|
|
560
|
+
* Returns a `TypeDescriptor` from its JSON code representation as returned by
|
|
561
|
+
* `asJsonCode()`.
|
|
562
|
+
*/
|
|
563
|
+
export declare function parseTypeDescriptorFromJsonCode(code: string): TypeDescriptor;
|
|
564
|
+
declare class UnrecognizedEnum {
|
|
565
|
+
readonly token: symbol;
|
|
566
|
+
readonly json?: Json | undefined;
|
|
567
|
+
readonly bytes?: ByteString | undefined;
|
|
568
|
+
constructor(token: symbol, json?: Json | undefined, bytes?: ByteString | undefined);
|
|
569
|
+
}
|
|
570
|
+
export declare const _EMPTY_ARRAY: readonly never[];
|
|
571
|
+
export declare function _toFrozenArray<T, Initializer>(initializers: readonly Initializer[], itemToFrozenFn?: (item: Initializer) => T): readonly T[];
|
|
572
|
+
export declare const _INITIALIZER: unique symbol;
|
|
573
|
+
export declare abstract class _FrozenBase {
|
|
574
|
+
protected constructor(privateKey: symbol);
|
|
575
|
+
toMutable(): unknown;
|
|
576
|
+
toFrozen(): this;
|
|
577
|
+
toString(): string;
|
|
578
|
+
[_INITIALIZER]: unknown;
|
|
579
|
+
}
|
|
580
|
+
export declare abstract class _EnumBase {
|
|
581
|
+
readonly kind: string;
|
|
582
|
+
readonly value?: unknown;
|
|
583
|
+
protected constructor(privateKey: symbol, kind: string, value?: unknown, unrecognized?: UnrecognizedEnum);
|
|
584
|
+
toString(): string;
|
|
585
|
+
}
|
|
586
|
+
/** Metadata of an HTTP request sent by a service client. */
|
|
587
|
+
export type RequestMeta = Omit<RequestInit, "body" | "method">;
|
|
588
|
+
/** Sends RPCs to a skir service. */
|
|
589
|
+
export declare class ServiceClient {
|
|
590
|
+
private readonly serviceUrl;
|
|
591
|
+
private readonly getRequestMetadata;
|
|
592
|
+
constructor(serviceUrl: string, getRequestMetadata?: (m: Method<unknown, unknown>) => Promise<RequestMeta> | RequestMeta);
|
|
593
|
+
/** Invokes the given method on the remote server through an RPC. */
|
|
594
|
+
invokeRemote<Request, Response>(method: Method<Request, Response>, request: Request, httpMethod?: "GET" | "POST"): Promise<Response>;
|
|
595
|
+
get lastResponseHeaders(): Headers | undefined;
|
|
596
|
+
private lastRespHeaders;
|
|
597
|
+
}
|
|
598
|
+
/** Raw response returned by the server. */
|
|
599
|
+
export declare class RawResponse {
|
|
600
|
+
readonly data: string;
|
|
601
|
+
readonly type: "ok-json" | "ok-html" | "bad-request" | "server-error";
|
|
602
|
+
constructor(data: string, type: "ok-json" | "ok-html" | "bad-request" | "server-error");
|
|
603
|
+
get statusCode(): number;
|
|
604
|
+
get contentType(): string;
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Implementation of a skir service.
|
|
608
|
+
*
|
|
609
|
+
* Usage: call `.addMethod()` to register methods, then install the service on
|
|
610
|
+
* an HTTP server either by:
|
|
611
|
+
* - calling the `installServiceOnExpressApp()` top-level function if you are
|
|
612
|
+
* using ExpressJS
|
|
613
|
+
* - writing your own implementation of `installServiceOn*()` which calls
|
|
614
|
+
* `.handleRequest()` if you are using another web application framework
|
|
615
|
+
*/
|
|
616
|
+
export declare class Service<RequestMeta = ExpressRequest, ResponseMeta = ExpressResponse> {
|
|
617
|
+
addMethod<Request, Response>(method: Method<Request, Response>, impl: (req: Request, reqMeta: RequestMeta, resMeta: ResponseMeta) => Promise<Response>): Service<RequestMeta, ResponseMeta>;
|
|
618
|
+
/**
|
|
619
|
+
* Parses the content of a user request and invokes the appropriate method.
|
|
620
|
+
* If you are using ExpressJS as your web application framework, you don't
|
|
621
|
+
* need to call this method, you can simply call the
|
|
622
|
+
* `installServiceOnExpressApp()` top-level function.
|
|
623
|
+
*
|
|
624
|
+
* If the request is a GET request, pass in the decoded query string as the
|
|
625
|
+
* request's body. The query string is the part of the URL after '?', and it
|
|
626
|
+
* can be decoded with DecodeURIComponent.
|
|
627
|
+
*
|
|
628
|
+
* Pass in "keep-unrecognized-values" if the request cannot come from a
|
|
629
|
+
* malicious user.
|
|
630
|
+
*/
|
|
631
|
+
handleRequest(reqBody: string, reqMeta: RequestMeta, resMeta: ResponseMeta, keepUnrecognizedValues?: "keep-unrecognized-values"): Promise<RawResponse>;
|
|
632
|
+
private readonly methodImpls;
|
|
633
|
+
}
|
|
634
|
+
export declare function installServiceOnExpressApp(app: ExpressApp, queryPath: string, service: Service<ExpressRequest, ExpressResponse>, text: typeof ExpressText, json: typeof ExpressJson, keepUnrecognizedValues?: "keep-unrecognized-values"): void;
|
|
635
|
+
interface StructSpec {
|
|
636
|
+
kind: "struct";
|
|
637
|
+
ctor: {
|
|
638
|
+
new (privateKey: symbol): unknown;
|
|
639
|
+
};
|
|
640
|
+
initFn: (target: unknown, initializer: unknown) => void;
|
|
641
|
+
name: string;
|
|
642
|
+
parentCtor?: {
|
|
643
|
+
new (): unknown;
|
|
644
|
+
};
|
|
645
|
+
fields: readonly StructFieldSpec[];
|
|
646
|
+
removedNumbers?: readonly number[];
|
|
647
|
+
}
|
|
648
|
+
interface StructFieldSpec {
|
|
649
|
+
name: string;
|
|
650
|
+
property: string;
|
|
651
|
+
number: number;
|
|
652
|
+
type: TypeSpec;
|
|
653
|
+
mutableGetter?: string;
|
|
654
|
+
indexable?: IndexableSpec;
|
|
655
|
+
}
|
|
656
|
+
interface IndexableSpec {
|
|
657
|
+
searchMethod: string;
|
|
658
|
+
keyFn: (v: unknown) => unknown;
|
|
659
|
+
keyToHashable?: (v: unknown) => unknown;
|
|
660
|
+
}
|
|
661
|
+
interface EnumSpec<Enum = unknown> {
|
|
662
|
+
kind: "enum";
|
|
663
|
+
ctor: {
|
|
664
|
+
new (privateKey: symbol, kind: string, value?: unknown, unrecognized?: UnrecognizedEnum): Enum;
|
|
665
|
+
};
|
|
666
|
+
createValueFn?: (initializer: unknown) => unknown;
|
|
667
|
+
name: string;
|
|
668
|
+
parentCtor?: {
|
|
669
|
+
new (): unknown;
|
|
670
|
+
};
|
|
671
|
+
fields: EnumFieldSpec[];
|
|
672
|
+
removedNumbers?: readonly number[];
|
|
673
|
+
}
|
|
674
|
+
interface EnumFieldSpec {
|
|
675
|
+
name: string;
|
|
676
|
+
number: number;
|
|
677
|
+
type?: TypeSpec;
|
|
678
|
+
}
|
|
679
|
+
type TypeSpec = {
|
|
680
|
+
kind: "optional";
|
|
681
|
+
other: TypeSpec;
|
|
682
|
+
} | {
|
|
683
|
+
kind: "array";
|
|
684
|
+
item: TypeSpec;
|
|
685
|
+
keyChain?: string;
|
|
686
|
+
} | {
|
|
687
|
+
kind: "record";
|
|
688
|
+
ctor: {
|
|
689
|
+
new (): unknown;
|
|
690
|
+
};
|
|
691
|
+
} | {
|
|
692
|
+
kind: "primitive";
|
|
693
|
+
primitive: keyof PrimitiveTypes;
|
|
694
|
+
};
|
|
695
|
+
export declare function _initModuleClasses(modulePath: string, records: ReadonlyArray<StructSpec | EnumSpec>): void;
|
|
696
|
+
export {};
|
|
697
|
+
//# sourceMappingURL=skir-client.d.ts.map
|