socket-function 0.9.3 → 0.9.5
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/.eslintrc.js +50 -50
- package/SocketFunction.ts +280 -280
- package/SocketFunctionTypes.ts +90 -90
- package/hot/HotReloadController.ts +105 -105
- package/mobx/UrlParam.ts +39 -39
- package/mobx/observer.tsx +49 -49
- package/mobx/promiseToObservable.tsx +41 -41
- package/package.json +1 -1
- package/require/CSSShim.ts +19 -19
- package/require/RequireController.ts +252 -252
- package/require/buffer.js +2368 -2368
- package/require/compileFlags.ts +44 -44
- package/require/require.html +13 -13
- package/require/require.js +464 -462
- package/spec.txt +115 -115
- package/src/CallFactory.ts +389 -389
- package/src/JSONLACKS/JSONLACKS.generated.js +17 -17
- package/src/JSONLACKS/JSONLACKS.pegjs +247 -247
- package/src/JSONLACKS/JSONLACKS.ts +441 -429
- package/src/args.ts +21 -21
- package/src/batching.ts +177 -170
- package/src/caching.ts +359 -318
- package/src/callHTTPHandler.ts +203 -203
- package/src/callManager.ts +134 -134
- package/src/certStore.ts +29 -29
- package/src/fixLargeNetworkCalls.ts +8 -8
- package/src/formatting/colors.ts +78 -78
- package/src/formatting/format.ts +160 -160
- package/src/formatting/logColors.ts +17 -17
- package/src/misc.ts +315 -302
- package/src/nodeCache.ts +92 -92
- package/src/nodeProxy.ts +54 -54
- package/src/profiling/getOwnTime.ts +107 -142
- package/src/profiling/measure.ts +289 -273
- package/src/profiling/stats.ts +212 -212
- package/src/profiling/tcpLagProxy.ts +63 -63
- package/src/storagePath.ts +10 -10
- package/src/tlsParsing.ts +96 -96
- package/src/types.ts +8 -8
- package/src/webSocketServer.ts +254 -250
- package/test/client.css +2 -2
- package/test/client.ts +46 -46
- package/test/server.ts +43 -43
- package/test/shared.ts +52 -52
- package/tsconfig.json +26 -26
package/src/misc.ts
CHANGED
|
@@ -1,303 +1,316 @@
|
|
|
1
|
-
import * as crypto from "crypto";
|
|
2
|
-
import { canHaveChildren, MaybePromise } from "./types";
|
|
3
|
-
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export function
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
export function
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (obj instanceof
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
keyArray =
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
export function
|
|
161
|
-
let map = new Map<K, T
|
|
162
|
-
for (let item of arr) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
nextAllowedCall
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
pendingArgs
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
1
|
+
import * as crypto from "crypto";
|
|
2
|
+
import { canHaveChildren, MaybePromise } from "./types";
|
|
3
|
+
|
|
4
|
+
export const timeInSecond = 1000;
|
|
5
|
+
export const timeInMinute = timeInSecond * 60;
|
|
6
|
+
export const timeInHour = timeInMinute * 60;
|
|
7
|
+
export const timeInDay = timeInHour * 24;
|
|
8
|
+
export const timeInWeek = timeInDay * 7;
|
|
9
|
+
export const timeInYear = timeInDay * 365;
|
|
10
|
+
|
|
11
|
+
export type Watchable<T> = (callback: (value: T) => void) => MaybePromise<void>;
|
|
12
|
+
|
|
13
|
+
export function convertErrorStackToError(error: string): Error {
|
|
14
|
+
let errorObj = new Error();
|
|
15
|
+
errorObj.stack = String(error);
|
|
16
|
+
errorObj.message = String(error).split("\n")[0].slice("Error: ".length);
|
|
17
|
+
return errorObj;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function sha256Hash(buffer: Buffer | string): string {
|
|
21
|
+
return crypto.createHash("sha256").update(buffer).digest("hex");
|
|
22
|
+
}
|
|
23
|
+
export function sha256HashBuffer(buffer: Buffer | string): Buffer {
|
|
24
|
+
return crypto.createHash("sha256").update(buffer).digest();
|
|
25
|
+
}
|
|
26
|
+
/** Async, but works both clientside and serverside. */
|
|
27
|
+
export async function sha256HashPromise(buffer: Buffer) {
|
|
28
|
+
if (isNode()) {
|
|
29
|
+
return crypto.createHash("sha256").update(buffer).digest("hex");
|
|
30
|
+
} else {
|
|
31
|
+
let buf = await window.crypto.subtle.digest("SHA-256", buffer);
|
|
32
|
+
return Buffer.from(buf).toString("hex");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export async function sha256BufferPromise(buffer: Buffer): Promise<Buffer> {
|
|
36
|
+
if (isNode()) {
|
|
37
|
+
return crypto.createHash("sha256").update(buffer).digest();
|
|
38
|
+
} else {
|
|
39
|
+
let buf = await window.crypto.subtle.digest("SHA-256", buffer);
|
|
40
|
+
return Buffer.from(buf);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
export function arrayEqual(a: unknown[], b: unknown[]) {
|
|
46
|
+
if (a.length !== b.length) return false;
|
|
47
|
+
for (let i = 0; i < a.length; i++) {
|
|
48
|
+
if (a[i] !== b[i]) return false;
|
|
49
|
+
}
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
export function isNode() {
|
|
53
|
+
return typeof document === "undefined";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function isNodeTrue() {
|
|
57
|
+
return isNode() as true;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function formatNumberSuffixed(count: number): string {
|
|
61
|
+
if (typeof count !== "number") return "0";
|
|
62
|
+
if (count < 0) {
|
|
63
|
+
return "-" + formatNumberSuffixed(-count);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let absValue = Math.abs(count);
|
|
67
|
+
|
|
68
|
+
const extraFactor = 10;
|
|
69
|
+
let divisor = 1;
|
|
70
|
+
let suffix = "";
|
|
71
|
+
if (absValue < 1000 * extraFactor) {
|
|
72
|
+
|
|
73
|
+
} else if (absValue < 1000 * 1000 * extraFactor) {
|
|
74
|
+
suffix = "K";
|
|
75
|
+
divisor = 1000;
|
|
76
|
+
} else if (absValue < 1000 * 1000 * 1000 * extraFactor) {
|
|
77
|
+
suffix = "M";
|
|
78
|
+
divisor = 1000 * 1000;
|
|
79
|
+
} else {
|
|
80
|
+
suffix = "B";
|
|
81
|
+
divisor = 1000 * 1000 * 1000;
|
|
82
|
+
}
|
|
83
|
+
count /= divisor;
|
|
84
|
+
absValue /= divisor;
|
|
85
|
+
|
|
86
|
+
return Math.round(count).toString() + suffix;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function list(count: number) {
|
|
90
|
+
let arr: number[] = [];
|
|
91
|
+
for (let i = 0; i < count; i++) {
|
|
92
|
+
arr.push(i);
|
|
93
|
+
}
|
|
94
|
+
return arr;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function recursiveFreeze<T>(obj: T): T {
|
|
98
|
+
if (!canHaveChildren(obj)) return obj;
|
|
99
|
+
let visited = new Set<unknown>();
|
|
100
|
+
function iterate(obj: unknown) {
|
|
101
|
+
if (!canHaveChildren(obj)) return;
|
|
102
|
+
if (visited.has(obj)) return;
|
|
103
|
+
visited.add(obj);
|
|
104
|
+
Object.freeze(obj);
|
|
105
|
+
let keys = getKeys(obj);
|
|
106
|
+
for (let key of keys) {
|
|
107
|
+
iterate(obj[key]);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
iterate(obj);
|
|
111
|
+
return obj;
|
|
112
|
+
}
|
|
113
|
+
export type ArrayBufferViewTypes = Uint8Array | Int8Array | Uint16Array | Int16Array | Uint32Array | Int32Array | BigUint64Array | BigInt64Array | Float64Array | Float32Array | Uint8ClampedArray;
|
|
114
|
+
export type BufferType = ArrayBuffer | SharedArrayBuffer | ArrayBufferViewTypes;
|
|
115
|
+
export function isBufferType(obj: unknown): obj is BufferType {
|
|
116
|
+
if (typeof obj !== "object") return false;
|
|
117
|
+
if (!obj) return false;
|
|
118
|
+
if (ArrayBuffer.isView(obj)) return true;
|
|
119
|
+
if (obj instanceof ArrayBuffer) return true;
|
|
120
|
+
if (global.SharedArrayBuffer && obj instanceof global.SharedArrayBuffer) return true;
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
export function getKeys(obj: unknown) {
|
|
124
|
+
if (typeof obj !== "object" && typeof obj !== "function" || obj === null) {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
if (obj instanceof MessagePort) {
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
let keyArray: PropertyKey[];
|
|
131
|
+
if (isBufferType(obj)) {
|
|
132
|
+
keyArray = [];
|
|
133
|
+
} else if (Array.isArray(obj)) {
|
|
134
|
+
// NOTE: We convert the indexes to strings, because that is what javascript does,
|
|
135
|
+
// and differing from it causes regressions that we simply cannot rectify (it breaks hashing
|
|
136
|
+
// consistency).
|
|
137
|
+
keyArray = Array(obj.length).fill(0).map((x, i) => String(i));
|
|
138
|
+
} else {
|
|
139
|
+
keyArray = Object.keys(obj);
|
|
140
|
+
}
|
|
141
|
+
for (let symbol of Object.getOwnPropertySymbols(obj)) {
|
|
142
|
+
let key = Symbol.keyFor(symbol);
|
|
143
|
+
if (key) {
|
|
144
|
+
keyArray.push(symbol);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return keyArray;
|
|
148
|
+
}
|
|
149
|
+
export function getStringKeys<T extends {}>(obj: T): ((keyof T) & string)[] {
|
|
150
|
+
return Object.keys(obj) as any;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (isNode()) {
|
|
154
|
+
// TODO: Find a better place for this...
|
|
155
|
+
process.on("unhandledRejection", async (reason: any, promise) => {
|
|
156
|
+
console.error(`Uncaught promise rejection: ${String(reason.stack || reason)}`);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function keyBy<T, K>(arr: T[], getKey: (value: T) => K): Map<K, T> {
|
|
161
|
+
let map = new Map<K, T>();
|
|
162
|
+
for (let item of arr) {
|
|
163
|
+
map.set(getKey(item), item);
|
|
164
|
+
}
|
|
165
|
+
return map;
|
|
166
|
+
}
|
|
167
|
+
export function keyByArray<T, K>(arr: T[], getKey: (value: T) => K): Map<K, T[]> {
|
|
168
|
+
let map = new Map<K, T[]>();
|
|
169
|
+
for (let item of arr) {
|
|
170
|
+
let key = getKey(item);
|
|
171
|
+
let arr = map.get(key);
|
|
172
|
+
if (!arr) {
|
|
173
|
+
arr = [];
|
|
174
|
+
map.set(key, arr);
|
|
175
|
+
}
|
|
176
|
+
arr.push(item);
|
|
177
|
+
}
|
|
178
|
+
return map;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function deepCloneJSON<T>(obj: T): T {
|
|
182
|
+
if (obj === undefined) return obj;
|
|
183
|
+
return JSON.parse(JSON.stringify(obj));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
export interface PromiseObj<T = void> {
|
|
189
|
+
resolve: (value: T | Promise<T>) => void;
|
|
190
|
+
reject: (error: any) => void;
|
|
191
|
+
promise: Promise<T>;
|
|
192
|
+
value: { value?: T; error?: string } | undefined;
|
|
193
|
+
/** Resolve called does not mean the value is ready, as it may be resolved with a promise. */
|
|
194
|
+
resolveCalled?: boolean;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export function promiseObj<T = void>(): PromiseObj<T> {
|
|
198
|
+
let resolve!: (value: T | Promise<T>) => void;
|
|
199
|
+
let reject!: (error: any) => void;
|
|
200
|
+
let promise = new Promise<T>((_resolve, _reject) => {
|
|
201
|
+
resolve = _resolve;
|
|
202
|
+
reject = _reject;
|
|
203
|
+
});
|
|
204
|
+
let obj: PromiseObj<T> = {
|
|
205
|
+
resolve(value: T | Promise<T>) {
|
|
206
|
+
obj.resolveCalled = true;
|
|
207
|
+
if (typeof value === "object" && value !== null && value instanceof Promise) {
|
|
208
|
+
value.then(
|
|
209
|
+
value => obj.value = { value },
|
|
210
|
+
error => obj.value = { error },
|
|
211
|
+
);
|
|
212
|
+
} else {
|
|
213
|
+
obj.value = { value };
|
|
214
|
+
}
|
|
215
|
+
resolve(value);
|
|
216
|
+
},
|
|
217
|
+
reject,
|
|
218
|
+
promise,
|
|
219
|
+
value: undefined
|
|
220
|
+
};
|
|
221
|
+
promise.then(value => obj.value = { value }, error => obj.value = { error });
|
|
222
|
+
return obj;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
// Allows an immediate call, then delays the next call until the first call finishes + delay
|
|
227
|
+
// - Drops all but the latest call, but only resolves the promises return to all
|
|
228
|
+
// calls once the latest call finishes.
|
|
229
|
+
// - Esentially the same as saying "don't run this function too often, don't run it in parallel,
|
|
230
|
+
// and don't let functions runs be too close together".
|
|
231
|
+
export function throttleFunction<Args extends any[]>(
|
|
232
|
+
delay: number,
|
|
233
|
+
fnc: (...args: Args) => MaybePromise<void>
|
|
234
|
+
): (...args: Args) => Promise<void> {
|
|
235
|
+
let nextAllowedCall = 0;
|
|
236
|
+
let pendingArgs: { args: Args; promiseObj: PromiseObj<void> } | undefined = undefined;
|
|
237
|
+
function doCall(args: Args, promiseObj: PromiseObj<void>) {
|
|
238
|
+
nextAllowedCall = Number.POSITIVE_INFINITY;
|
|
239
|
+
try {
|
|
240
|
+
let result = fnc(...args);
|
|
241
|
+
promiseObj.resolve(result);
|
|
242
|
+
if (result instanceof Promise) {
|
|
243
|
+
result.finally(() => {
|
|
244
|
+
afterCall(Date.now() + delay);
|
|
245
|
+
});
|
|
246
|
+
} else {
|
|
247
|
+
afterCall(Date.now() + delay);
|
|
248
|
+
}
|
|
249
|
+
} catch (e: any) {
|
|
250
|
+
debugger;
|
|
251
|
+
promiseObj.reject(e);
|
|
252
|
+
afterCall(Date.now() + delay);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
function afterCall(setNextAllowedCall: number | undefined) {
|
|
256
|
+
|
|
257
|
+
// NOTE: Ignore error, we really shouldn't have any here
|
|
258
|
+
if (setNextAllowedCall) {
|
|
259
|
+
nextAllowedCall = setNextAllowedCall;
|
|
260
|
+
} else {
|
|
261
|
+
if (nextAllowedCall === Number.POSITIVE_INFINITY) return;
|
|
262
|
+
}
|
|
263
|
+
if (!pendingArgs) return;
|
|
264
|
+
if (Date.now() > nextAllowedCall) {
|
|
265
|
+
let args = pendingArgs;
|
|
266
|
+
pendingArgs = undefined;
|
|
267
|
+
// Delay, so we don't turn a series of sequential calls to a series of nested calls
|
|
268
|
+
// (which will cause a stack overflow)
|
|
269
|
+
nextAllowedCall = Number.POSITIVE_INFINITY;
|
|
270
|
+
setImmediate(() => doCall(args.args, args.promiseObj));
|
|
271
|
+
} else {
|
|
272
|
+
setTimeout(() => {
|
|
273
|
+
if (pendingArgs) {
|
|
274
|
+
let args = pendingArgs;
|
|
275
|
+
pendingArgs = undefined;
|
|
276
|
+
doCall(args.args, args.promiseObj);
|
|
277
|
+
}
|
|
278
|
+
}, nextAllowedCall - Date.now());
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return function (...args: Args): Promise<void> {
|
|
282
|
+
if (pendingArgs) {
|
|
283
|
+
pendingArgs.args = args;
|
|
284
|
+
return pendingArgs.promiseObj.promise;
|
|
285
|
+
}
|
|
286
|
+
let time = Date.now();
|
|
287
|
+
if (time > nextAllowedCall) {
|
|
288
|
+
let promise = promiseObj();
|
|
289
|
+
doCall(args, promise);
|
|
290
|
+
return promise.promise;
|
|
291
|
+
} else {
|
|
292
|
+
pendingArgs = { args, promiseObj: promiseObj() };
|
|
293
|
+
afterCall(undefined);
|
|
294
|
+
return pendingArgs.promiseObj.promise;
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
export function nextId() {
|
|
301
|
+
return Date.now() + "_" + Math.random();
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
export function arrayFromOrderObject<T>(obj: { [order: number]: T }): T[] {
|
|
305
|
+
if (Array.isArray(obj)) return obj.slice();
|
|
306
|
+
return Object.entries(obj).sort((a, b) => +a[0] - +b[0]).map(x => x[1]).filter(x => x !== undefined && x !== null);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export function last<T>(arr: T[]): T | undefined {
|
|
310
|
+
return arr[arr.length - 1];
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export type ObjectValues<T> = T[keyof T];
|
|
314
|
+
export function entries<Obj extends { [key: string]: unknown }>(obj: Obj): [keyof Obj, ObjectValues<Obj>][] {
|
|
315
|
+
return Object.entries(obj) as any;
|
|
303
316
|
}
|