@dr.pogodin/js-utils 0.0.17 → 0.1.0
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 +11 -0
- package/build/common/Barrier.js +34 -12
- package/build/common/Barrier.js.map +1 -1
- package/build/common/Cached.js +81 -0
- package/build/common/Cached.js.map +1 -0
- package/build/common/Emitter.js +14 -12
- package/build/common/Emitter.js.map +1 -1
- package/build/common/Semaphore.js +31 -28
- package/build/common/Semaphore.js.map +1 -1
- package/build/common/index.js +12 -0
- package/build/common/index.js.map +1 -1
- package/build/common/time.js +24 -9
- package/build/common/time.js.map +1 -1
- package/build/common/withRetries.js +1 -5
- package/build/common/withRetries.js.map +1 -1
- package/build/module/Barrier.js +34 -12
- package/build/module/Barrier.js.map +1 -1
- package/build/module/Cached.js +74 -0
- package/build/module/Cached.js.map +1 -0
- package/build/module/Emitter.js +14 -12
- package/build/module/Emitter.js.map +1 -1
- package/build/module/Semaphore.js +31 -28
- package/build/module/Semaphore.js.map +1 -1
- package/build/module/index.js +1 -0
- package/build/module/index.js.map +1 -1
- package/build/module/time.js +24 -9
- package/build/module/time.js.map +1 -1
- package/build/module/withRetries.js +1 -5
- package/build/module/withRetries.js.map +1 -1
- package/build/types/Barrier.d.ts +5 -5
- package/build/types/Cached.d.ts +26 -0
- package/build/types/Emitter.d.ts +1 -1
- package/build/types/Semaphore.d.ts +5 -6
- package/build/types/index.d.ts +1 -0
- package/build/types/time.d.ts +4 -4
- package/config/babel/preset.js +1 -1
- package/docs/common-sense-versioning.md +39 -0
- package/eslint.config.mjs +14 -0
- package/package.json +22 -23
- package/tstyche.config.json +4 -2
package/README.md
CHANGED
|
@@ -52,6 +52,10 @@ and used in the same way):
|
|
|
52
52
|
### Classes
|
|
53
53
|
- [Barrier] — A [Promise] with **resolve()** and **reject()** exposed as
|
|
54
54
|
instance methods.
|
|
55
|
+
|
|
56
|
+
- `Cached` — Implements a cache of (a)synchronously retrieved items with
|
|
57
|
+
timestamp-based expiration. _To be documented_.
|
|
58
|
+
|
|
55
59
|
- [Emitter](https://dr.pogodin.studio/docs/react-utils/docs/api/classes/Emitter)
|
|
56
60
|
— Simple listeneable data emitter.
|
|
57
61
|
- [Semaphore](https://dr.pogodin.studio/docs/react-utils/docs/api/classes/Semaphore)
|
|
@@ -59,6 +63,13 @@ and used in the same way):
|
|
|
59
63
|
- `Timer` — The core implementation of [timer()] functionality, allowing
|
|
60
64
|
to create further customized timer objects. _To be documented_.
|
|
61
65
|
|
|
66
|
+
---
|
|
67
|
+
Repository of this library also hosts some documents, to be referenced from
|
|
68
|
+
other projects, as needed:
|
|
69
|
+
- [The Common Sense Versioning](./docs/common-sense-versioning.md) —
|
|
70
|
+
a lax description of a lax approach to product versioning that makes more
|
|
71
|
+
sense than [SemVer](https://semver.org).
|
|
72
|
+
|
|
62
73
|
<!-- References -->
|
|
63
74
|
|
|
64
75
|
[Barrier]: https://dr.pogodin.studio/docs/react-utils/docs/api/classes/Barrier
|
package/build/common/Barrier.js
CHANGED
|
@@ -34,7 +34,7 @@ var STATE = /*#__PURE__*/function (STATE) {
|
|
|
34
34
|
* Docs: https://dr.pogodin.studio/docs/react-utils/docs/api/classes/Barrier
|
|
35
35
|
*/
|
|
36
36
|
class Barrier extends Promise {
|
|
37
|
-
|
|
37
|
+
pState = STATE.PENDING;
|
|
38
38
|
constructor(executor) {
|
|
39
39
|
let resolveRef;
|
|
40
40
|
let rejectRef;
|
|
@@ -42,7 +42,7 @@ class Barrier extends Promise {
|
|
|
42
42
|
// Note: Enforcing `void` return type because of the BEWARE note below.
|
|
43
43
|
resolveRef = value => {
|
|
44
44
|
resolve(value);
|
|
45
|
-
this.
|
|
45
|
+
this.pState = STATE.RESOLVED;
|
|
46
46
|
|
|
47
47
|
// BEWARE: Don't try to return `this` here, it will easily cause
|
|
48
48
|
// infinite loops in React Native, which are extremely difficult
|
|
@@ -54,7 +54,7 @@ class Barrier extends Promise {
|
|
|
54
54
|
// Note: Enforcing `void` return type because of the BEWARE note below.
|
|
55
55
|
rejectRef = reason => {
|
|
56
56
|
reject(reason);
|
|
57
|
-
this.
|
|
57
|
+
this.pState = STATE.REJECTED;
|
|
58
58
|
};
|
|
59
59
|
if (executor) executor(resolveRef, rejectRef);
|
|
60
60
|
});
|
|
@@ -63,40 +63,62 @@ class Barrier extends Promise {
|
|
|
63
63
|
// the Barrier is constructed by a .then() call on a "parent" barrier,
|
|
64
64
|
// and in that scenario .then() itself will replace .p_resolve by another
|
|
65
65
|
// resolver immediately after this constructor returns.
|
|
66
|
-
this.
|
|
67
|
-
this.
|
|
66
|
+
this.pResolve = resolveRef;
|
|
67
|
+
this.pReject = rejectRef;
|
|
68
68
|
}
|
|
69
69
|
get resolve() {
|
|
70
70
|
return arg => {
|
|
71
|
-
this.
|
|
71
|
+
this.pResolve(arg);
|
|
72
72
|
return this;
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
75
|
get reject() {
|
|
76
76
|
return arg => {
|
|
77
|
-
this.
|
|
77
|
+
this.pReject(arg);
|
|
78
78
|
return this;
|
|
79
79
|
};
|
|
80
80
|
}
|
|
81
81
|
get resolved() {
|
|
82
|
-
return this.
|
|
82
|
+
return this.pState === STATE.RESOLVED;
|
|
83
83
|
}
|
|
84
84
|
get rejected() {
|
|
85
|
-
return this.
|
|
85
|
+
return this.pState === STATE.REJECTED;
|
|
86
86
|
}
|
|
87
87
|
get settled() {
|
|
88
|
-
return this.
|
|
88
|
+
return this.pState !== STATE.PENDING;
|
|
89
89
|
}
|
|
90
|
+
|
|
91
|
+
// TODO: For async functions TS requires the return type to be the global
|
|
92
|
+
// Promise, thus not allowing to return our Barrier type extending it.
|
|
93
|
+
// Thus, we don't mark this method async for now, disabling the rule,
|
|
94
|
+
// and we should think more about it in future.
|
|
95
|
+
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
90
96
|
catch(onRejected) {
|
|
91
97
|
return super.catch(onRejected);
|
|
92
98
|
}
|
|
99
|
+
|
|
100
|
+
// TODO: For async functions TS requires the return type to be the global
|
|
101
|
+
// Promise, thus not allowing to return our Barrier type extending it.
|
|
102
|
+
// Thus, we don't mark this method async for now, disabling the rule,
|
|
103
|
+
// and we should think more about it in future.
|
|
104
|
+
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
93
105
|
finally(onFinally) {
|
|
94
106
|
return super.finally(onFinally);
|
|
95
107
|
}
|
|
108
|
+
|
|
109
|
+
// TODO: For async functions TS requires the return type to be the global
|
|
110
|
+
// Promise, thus not allowing to return our Barrier type extending it.
|
|
111
|
+
// Thus, we don't mark this method async for now, disabling the rule,
|
|
112
|
+
// and we should think more about it in future.
|
|
113
|
+
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
96
114
|
then(onFulfilled, onRejected) {
|
|
97
115
|
const res = super.then(onFulfilled, onRejected);
|
|
98
|
-
|
|
99
|
-
|
|
116
|
+
// TODO: Revise later.
|
|
117
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
118
|
+
res.pResolve = this.resolve;
|
|
119
|
+
// TODO: Revise later.
|
|
120
|
+
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
121
|
+
res.pReject = this.reject;
|
|
100
122
|
return res;
|
|
101
123
|
}
|
|
102
124
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Barrier.js","names":["STATE","Barrier","Promise","
|
|
1
|
+
{"version":3,"file":"Barrier.js","names":["STATE","Barrier","Promise","pState","PENDING","constructor","executor","resolveRef","rejectRef","resolve","reject","value","RESOLVED","reason","REJECTED","pResolve","pReject","arg","resolved","rejected","settled","catch","onRejected","finally","onFinally","then","onFulfilled","res","exports","default"],"sources":["../../src/Barrier.ts"],"sourcesContent":["export type Executor<T> = ConstructorParameters<typeof Promise<T>>[0];\n\ntype Resolver<T> = Parameters<Executor<T>>[0];\ntype Rejecter = Parameters<Executor<unknown>>[1];\n\nenum STATE {\n PENDING = 'PENDING',\n REJECTED = 'REJECTED',\n RESOLVED = 'RESOLVED',\n}\n\n/**\n * Barrier is just a Promise which has resolve and reject exposed as instance\n * methods.\n *\n * It has two generic arguments T and TR which correspond to the argument of\n * the .resolve() method, and to the value resolved by the promise (barrier).\n * For a simple barrier TR equals to T, however for barriers created via .then()\n * chain, T corresponds to the argument of the original barrier, and TR to\n * the value resolved by the latest promise in the chain. Consider this:\n *\n * const b = new Barrier<string>();\n * b.resolve('result');\n * const s = await b; // `s` has `string` type, and equals \"result\".\n *\n * const b = (new Barrier<string>()).then((s) => s.length);\n * b.resolve('result'); // Chained barrier exposes .resolve() method of\n * // the first barrier in the chain, which expects\n * // `string` arugment (T), but the chained barrier\n * // resolves to `number` (TR).\n * const n = await b; // `n` has `number` type, and equals 6.\n *\n * Docs: https://dr.pogodin.studio/docs/react-utils/docs/api/classes/Barrier\n */\nexport default class Barrier<T = unknown, TR = T> extends Promise<TR> {\n private pResolve: Resolver<T>;\n\n private pReject: Rejecter;\n\n private pState = STATE.PENDING;\n\n constructor(executor?: Executor<TR>) {\n let resolveRef: Resolver<TR>;\n let rejectRef: Rejecter;\n\n super((resolve, reject) => {\n // Note: Enforcing `void` return type because of the BEWARE note below.\n resolveRef = (value: TR | PromiseLike<TR>): void => {\n resolve(value);\n this.pState = STATE.RESOLVED;\n\n // BEWARE: Don't try to return `this` here, it will easily cause\n // infinite loops in React Native, which are extremely difficult\n // to troubleshoot (I wasn't able to figure out, are they due to\n // internal Promise implementation in RN, or because of some bad\n // patterns in the host code).\n };\n\n // Note: Enforcing `void` return type because of the BEWARE note below.\n rejectRef = (reason?: unknown): void => {\n reject(reason);\n this.pState = STATE.REJECTED;\n };\n\n if (executor) executor(resolveRef, rejectRef);\n });\n\n // NOTE: We assume, the only scenario where TR is not equal T is when\n // the Barrier is constructed by a .then() call on a \"parent\" barrier,\n // and in that scenario .then() itself will replace .p_resolve by another\n // resolver immediately after this constructor returns.\n this.pResolve = resolveRef! as Resolver<T>;\n\n this.pReject = rejectRef!;\n }\n\n get resolve() {\n return (arg: Parameters<Resolver<T>>[0]): this => {\n this.pResolve(arg);\n return this;\n };\n }\n\n get reject() {\n return (arg: Parameters<Rejecter>[0]): this => {\n this.pReject(arg);\n return this;\n };\n }\n\n get resolved(): boolean {\n return this.pState === STATE.RESOLVED;\n }\n\n get rejected(): boolean {\n return this.pState === STATE.REJECTED;\n }\n\n get settled(): boolean {\n return this.pState !== STATE.PENDING;\n }\n\n // TODO: For async functions TS requires the return type to be the global\n // Promise, thus not allowing to return our Barrier type extending it.\n // Thus, we don't mark this method async for now, disabling the rule,\n // and we should think more about it in future.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n catch<TR1>(\n onRejected?: ((reason: unknown) => TR1 | PromiseLike<TR1>) | null,\n ): Barrier<T, TR1> {\n return super.catch(onRejected) as Barrier<T, TR1>;\n }\n\n // TODO: For async functions TS requires the return type to be the global\n // Promise, thus not allowing to return our Barrier type extending it.\n // Thus, we don't mark this method async for now, disabling the rule,\n // and we should think more about it in future.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n finally(onFinally?: (() => void) | null): Barrier<TR> {\n return super.finally(onFinally) as Barrier<TR>;\n }\n\n // TODO: For async functions TS requires the return type to be the global\n // Promise, thus not allowing to return our Barrier type extending it.\n // Thus, we don't mark this method async for now, disabling the rule,\n // and we should think more about it in future.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n then<TR1, TR2>(\n onFulfilled?: ((value: TR) => TR1 | PromiseLike<TR1>) | null,\n onRejected?: ((reason: unknown) => TR2 | PromiseLike<TR2>) | null,\n ): Barrier<T, TR1 | TR2> {\n const res = super.then(onFulfilled, onRejected) as Barrier<T, TR1 | TR2>;\n // TODO: Revise later.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n res.pResolve = this.resolve;\n // TODO: Revise later.\n // eslint-disable-next-line @typescript-eslint/no-misused-promises\n res.pReject = this.reject;\n return res;\n }\n}\n"],"mappings":";;;;;;IAKKA,KAAK,0BAALA,KAAK;EAALA,KAAK;EAALA,KAAK;EAALA,KAAK;EAAA,OAALA,KAAK;AAAA,EAALA,KAAK;AAMV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe,MAAMC,OAAO,SAA8BC,OAAO,CAAK;EAK5DC,MAAM,GAAGH,KAAK,CAACI,OAAO;EAE9BC,WAAWA,CAACC,QAAuB,EAAE;IACnC,IAAIC,UAAwB;IAC5B,IAAIC,SAAmB;IAEvB,KAAK,CAAC,CAACC,OAAO,EAAEC,MAAM,KAAK;MACzB;MACAH,UAAU,GAAII,KAA2B,IAAW;QAClDF,OAAO,CAACE,KAAK,CAAC;QACd,IAAI,CAACR,MAAM,GAAGH,KAAK,CAACY,QAAQ;;QAE5B;QACA;QACA;QACA;QACA;MACF,CAAC;;MAED;MACAJ,SAAS,GAAIK,MAAgB,IAAW;QACtCH,MAAM,CAACG,MAAM,CAAC;QACd,IAAI,CAACV,MAAM,GAAGH,KAAK,CAACc,QAAQ;MAC9B,CAAC;MAED,IAAIR,QAAQ,EAAEA,QAAQ,CAACC,UAAU,EAAEC,SAAS,CAAC;IAC/C,CAAC,CAAC;;IAEF;IACA;IACA;IACA;IACA,IAAI,CAACO,QAAQ,GAAGR,UAA0B;IAE1C,IAAI,CAACS,OAAO,GAAGR,SAAU;EAC3B;EAEA,IAAIC,OAAOA,CAAA,EAAG;IACZ,OAAQQ,GAA+B,IAAW;MAChD,IAAI,CAACF,QAAQ,CAACE,GAAG,CAAC;MAClB,OAAO,IAAI;IACb,CAAC;EACH;EAEA,IAAIP,MAAMA,CAAA,EAAG;IACX,OAAQO,GAA4B,IAAW;MAC7C,IAAI,CAACD,OAAO,CAACC,GAAG,CAAC;MACjB,OAAO,IAAI;IACb,CAAC;EACH;EAEA,IAAIC,QAAQA,CAAA,EAAY;IACtB,OAAO,IAAI,CAACf,MAAM,KAAKH,KAAK,CAACY,QAAQ;EACvC;EAEA,IAAIO,QAAQA,CAAA,EAAY;IACtB,OAAO,IAAI,CAAChB,MAAM,KAAKH,KAAK,CAACc,QAAQ;EACvC;EAEA,IAAIM,OAAOA,CAAA,EAAY;IACrB,OAAO,IAAI,CAACjB,MAAM,KAAKH,KAAK,CAACI,OAAO;EACtC;;EAEA;EACA;EACA;EACA;EACA;EACAiB,KAAKA,CACHC,UAAiE,EAChD;IACjB,OAAO,KAAK,CAACD,KAAK,CAACC,UAAU,CAAC;EAChC;;EAEA;EACA;EACA;EACA;EACA;EACAC,OAAOA,CAACC,SAA+B,EAAe;IACpD,OAAO,KAAK,CAACD,OAAO,CAACC,SAAS,CAAC;EACjC;;EAEA;EACA;EACA;EACA;EACA;EACAC,IAAIA,CACFC,WAA4D,EAC5DJ,UAAiE,EAC1C;IACvB,MAAMK,GAAG,GAAG,KAAK,CAACF,IAAI,CAACC,WAAW,EAAEJ,UAAU,CAA0B;IACxE;IACA;IACAK,GAAG,CAACZ,QAAQ,GAAG,IAAI,CAACN,OAAO;IAC3B;IACA;IACAkB,GAAG,CAACX,OAAO,GAAG,IAAI,CAACN,MAAM;IACzB,OAAOiB,GAAG;EACZ;AACF;AAACC,OAAA,CAAAC,OAAA,GAAA5B,OAAA","ignoreList":[]}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.Cached = void 0;
|
|
7
|
+
/** Adds timestamp to the promise. */
|
|
8
|
+
function addTimestamp(promise, timestamp) {
|
|
9
|
+
const res = promise;
|
|
10
|
+
res.timestamp = timestamp;
|
|
11
|
+
return res;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/** Gets entry timestamp. */
|
|
15
|
+
function getTimestamp(e) {
|
|
16
|
+
return Array.isArray(e) ? e[1] : e.timestamp;
|
|
17
|
+
}
|
|
18
|
+
class Cached {
|
|
19
|
+
data = {};
|
|
20
|
+
oldestTimestamp = Number.MAX_SAFE_INTEGER;
|
|
21
|
+
|
|
22
|
+
/** For test use only. */
|
|
23
|
+
get _data() {
|
|
24
|
+
return this.data;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** For test use only. */
|
|
28
|
+
get _oldestTimestamp() {
|
|
29
|
+
return this.oldestTimestamp;
|
|
30
|
+
}
|
|
31
|
+
constructor(maxage, getter) {
|
|
32
|
+
this.maxage = maxage;
|
|
33
|
+
this.getter = getter;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Removes stale items from the cache, and updates .oldestTimestamp. */
|
|
37
|
+
cleanCache() {
|
|
38
|
+
const deadline = Date.now() - this.maxage;
|
|
39
|
+
this.oldestTimestamp = Number.MAX_SAFE_INTEGER;
|
|
40
|
+
for (const [key, entry] of Object.entries(this.data)) {
|
|
41
|
+
const timestamp = getTimestamp(entry);
|
|
42
|
+
if (timestamp < deadline) delete this.data[key];else if (timestamp < this.oldestTimestamp) {
|
|
43
|
+
this.oldestTimestamp = timestamp;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Adds `datum` to the cache, and removes stale items from the cache. */
|
|
49
|
+
set(id, datum) {
|
|
50
|
+
const now = Date.now();
|
|
51
|
+
if (this.oldestTimestamp < now - this.maxage) this.cleanCache();
|
|
52
|
+
if (now < this.oldestTimestamp) this.oldestTimestamp = now;
|
|
53
|
+
const res = [datum, now];
|
|
54
|
+
this.data[id] = res;
|
|
55
|
+
return res;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Retrieves envelope of the specified datum, either read from the cache,
|
|
59
|
+
* or retrieved using the getter provided at construction time. */
|
|
60
|
+
getEntry(id) {
|
|
61
|
+
const now = Date.now();
|
|
62
|
+
let cached = this.data[id];
|
|
63
|
+
if (cached && getTimestamp(cached) >= now - this.maxage) return cached;
|
|
64
|
+
const itemOrPromise = this.getter(id);
|
|
65
|
+
if (!(itemOrPromise instanceof Promise)) {
|
|
66
|
+
return this.set(id, itemOrPromise);
|
|
67
|
+
}
|
|
68
|
+
cached = addTimestamp(itemOrPromise.then(item => this.set(id, item)), now);
|
|
69
|
+
if (now < this.oldestTimestamp) this.oldestTimestamp = now;
|
|
70
|
+
this.data[id] = cached;
|
|
71
|
+
return cached;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Gets item. */
|
|
75
|
+
get(id) {
|
|
76
|
+
const entry = this.getEntry(id);
|
|
77
|
+
return Array.isArray(entry) ? entry[0] : entry.then(e => e[0]);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
exports.Cached = Cached;
|
|
81
|
+
//# sourceMappingURL=Cached.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Cached.js","names":["addTimestamp","promise","timestamp","res","getTimestamp","e","Array","isArray","Cached","data","oldestTimestamp","Number","MAX_SAFE_INTEGER","_data","_oldestTimestamp","constructor","maxage","getter","cleanCache","deadline","Date","now","key","entry","Object","entries","set","id","datum","getEntry","cached","itemOrPromise","Promise","then","item","get","exports"],"sources":["../../src/Cached.ts"],"sourcesContent":["type CachedT<T> = [T, number];\ntype TimestampedPromise<T> = Promise<T> & { timestamp: number };\ntype EntryT<T> = CachedT<T> | TimestampedPromise<CachedT<T>>;\n\n/** Adds timestamp to the promise. */\nfunction addTimestamp<T>(\n promise: Promise<T>,\n timestamp: number,\n): TimestampedPromise<T> {\n const res = promise as TimestampedPromise<T>;\n res.timestamp = timestamp;\n return res;\n}\n\n/** Gets entry timestamp. */\nfunction getTimestamp<T>(e: EntryT<T>): number {\n return Array.isArray(e) ? e[1] : e.timestamp;\n}\n\nexport class Cached<T> {\n private data: Record<string, EntryT<T>> = {};\n private oldestTimestamp = Number.MAX_SAFE_INTEGER;\n\n /** For test use only. */\n get _data(): Readonly<Record<string, EntryT<T>>> {\n return this.data;\n }\n\n /** For test use only. */\n get _oldestTimestamp(): number {\n return this.oldestTimestamp;\n }\n\n constructor(\n public readonly maxage: number,\n private getter: (id: string) => T | Promise<T>,\n ) {}\n\n /** Removes stale items from the cache, and updates .oldestTimestamp. */\n private cleanCache() {\n const deadline = Date.now() - this.maxage;\n this.oldestTimestamp = Number.MAX_SAFE_INTEGER;\n for (const [key, entry] of Object.entries(this.data)) {\n const timestamp = getTimestamp(entry);\n if (timestamp < deadline) delete this.data[key];\n else if (timestamp < this.oldestTimestamp) {\n this.oldestTimestamp = timestamp;\n }\n }\n }\n\n /** Adds `datum` to the cache, and removes stale items from the cache. */\n private set(id: string, datum: T): CachedT<T> {\n const now = Date.now();\n if (this.oldestTimestamp < now - this.maxage) this.cleanCache();\n if (now < this.oldestTimestamp) this.oldestTimestamp = now;\n const res: CachedT<T> = [datum, now];\n this.data[id] = res;\n return res;\n }\n\n /** Retrieves envelope of the specified datum, either read from the cache,\n * or retrieved using the getter provided at construction time. */\n private getEntry(id: string): EntryT<T> {\n const now = Date.now();\n\n let cached = this.data[id];\n if (cached && getTimestamp(cached) >= now - this.maxage) return cached;\n\n const itemOrPromise = this.getter(id);\n if (!(itemOrPromise instanceof Promise)) {\n return this.set(id, itemOrPromise);\n }\n\n cached = addTimestamp(\n itemOrPromise.then((item) => this.set(id, item)),\n now,\n );\n if (now < this.oldestTimestamp) this.oldestTimestamp = now;\n this.data[id] = cached;\n return cached;\n }\n\n /** Gets item. */\n get(id: string): T | Promise<T> {\n const entry = this.getEntry(id);\n return Array.isArray(entry) ? entry[0] : entry.then((e) => e[0]);\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
package/build/common/Emitter.js
CHANGED
|
@@ -8,17 +8,17 @@ exports.Emitter = void 0;
|
|
|
8
8
|
* Simple listeneable data Emitter.
|
|
9
9
|
*/
|
|
10
10
|
class Emitter {
|
|
11
|
-
|
|
11
|
+
pListeners = [];
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Returns "true" if any listener is connected; "false" otherwise.
|
|
15
15
|
* @return {boolean}
|
|
16
16
|
*/
|
|
17
17
|
get hasListeners() {
|
|
18
|
-
return !!this.
|
|
18
|
+
return !!this.pListeners.length;
|
|
19
19
|
}
|
|
20
20
|
get listeners() {
|
|
21
|
-
return this.
|
|
21
|
+
return this.pListeners;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
@@ -27,26 +27,28 @@ class Emitter {
|
|
|
27
27
|
* @return {function} Unsubscribe function.
|
|
28
28
|
*/
|
|
29
29
|
addListener(listener) {
|
|
30
|
-
if (!this.
|
|
31
|
-
this.
|
|
30
|
+
if (!this.pListeners.includes(listener)) {
|
|
31
|
+
this.pListeners.push(listener);
|
|
32
32
|
}
|
|
33
|
-
return () =>
|
|
33
|
+
return () => {
|
|
34
|
+
this.removeListener(listener);
|
|
35
|
+
};
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
/**
|
|
37
39
|
* Calls every connected listener with the given arguments.
|
|
38
40
|
* @param args
|
|
39
41
|
*/
|
|
40
|
-
emit() {
|
|
41
|
-
const listeners = this.
|
|
42
|
-
for (const listener of listeners) listener(...
|
|
42
|
+
emit(...args) {
|
|
43
|
+
const listeners = this.pListeners.slice();
|
|
44
|
+
for (const listener of listeners) listener(...args);
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
/**
|
|
46
48
|
* Removes all connected listeners.
|
|
47
49
|
*/
|
|
48
50
|
removeAllListeners() {
|
|
49
|
-
this.
|
|
51
|
+
this.pListeners = [];
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
/**
|
|
@@ -54,8 +56,8 @@ class Emitter {
|
|
|
54
56
|
* @param listener
|
|
55
57
|
*/
|
|
56
58
|
removeListener(listener) {
|
|
57
|
-
const idx = this.
|
|
58
|
-
if (idx >= 0) this.
|
|
59
|
+
const idx = this.pListeners.indexOf(listener);
|
|
60
|
+
if (idx >= 0) this.pListeners.splice(idx, 1);
|
|
59
61
|
}
|
|
60
62
|
}
|
|
61
63
|
exports.Emitter = Emitter;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Emitter.js","names":["Emitter","
|
|
1
|
+
{"version":3,"file":"Emitter.js","names":["Emitter","pListeners","hasListeners","length","listeners","addListener","listener","includes","push","removeListener","emit","args","slice","removeAllListeners","idx","indexOf","splice","exports"],"sources":["../../src/Emitter.ts"],"sourcesContent":["export type Listener<T extends unknown[] = unknown[]> = (...args: T) => void;\n\n/**\n * Simple listeneable data Emitter.\n */\nexport class Emitter<T extends unknown[] = unknown[]> {\n private pListeners: Array<Listener<T>> = [];\n\n /**\n * Returns \"true\" if any listener is connected; \"false\" otherwise.\n * @return {boolean}\n */\n get hasListeners(): boolean {\n return !!this.pListeners.length;\n }\n\n get listeners(): ReadonlyArray<Listener<T>> {\n return this.pListeners;\n }\n\n /**\n * Adds `listener` if it is not already connected.\n * @param {function} listener\n * @return {function} Unsubscribe function.\n */\n addListener(listener: Listener<T>): () => void {\n if (!this.pListeners.includes(listener)) {\n this.pListeners.push(listener);\n }\n return () => {\n this.removeListener(listener);\n };\n }\n\n /**\n * Calls every connected listener with the given arguments.\n * @param args\n */\n emit(...args: T): void {\n const listeners = this.pListeners.slice();\n for (const listener of listeners) listener(...args);\n }\n\n /**\n * Removes all connected listeners.\n */\n removeAllListeners(): void {\n this.pListeners = [];\n }\n\n /**\n * Removes specified `listener`, if connected.\n * @param listener\n */\n removeListener(listener: Listener<T>): void {\n const idx = this.pListeners.indexOf(listener);\n if (idx >= 0) this.pListeners.splice(idx, 1);\n }\n}\n"],"mappings":";;;;;;AAEA;AACA;AACA;AACO,MAAMA,OAAO,CAAkC;EAC5CC,UAAU,GAAuB,EAAE;;EAE3C;AACF;AACA;AACA;EACE,IAAIC,YAAYA,CAAA,EAAY;IAC1B,OAAO,CAAC,CAAC,IAAI,CAACD,UAAU,CAACE,MAAM;EACjC;EAEA,IAAIC,SAASA,CAAA,EAA+B;IAC1C,OAAO,IAAI,CAACH,UAAU;EACxB;;EAEA;AACF;AACA;AACA;AACA;EACEI,WAAWA,CAACC,QAAqB,EAAc;IAC7C,IAAI,CAAC,IAAI,CAACL,UAAU,CAACM,QAAQ,CAACD,QAAQ,CAAC,EAAE;MACvC,IAAI,CAACL,UAAU,CAACO,IAAI,CAACF,QAAQ,CAAC;IAChC;IACA,OAAO,MAAM;MACX,IAAI,CAACG,cAAc,CAACH,QAAQ,CAAC;IAC/B,CAAC;EACH;;EAEA;AACF;AACA;AACA;EACEI,IAAIA,CAAC,GAAGC,IAAO,EAAQ;IACrB,MAAMP,SAAS,GAAG,IAAI,CAACH,UAAU,CAACW,KAAK,CAAC,CAAC;IACzC,KAAK,MAAMN,QAAQ,IAAIF,SAAS,EAAEE,QAAQ,CAAC,GAAGK,IAAI,CAAC;EACrD;;EAEA;AACF;AACA;EACEE,kBAAkBA,CAAA,EAAS;IACzB,IAAI,CAACZ,UAAU,GAAG,EAAE;EACtB;;EAEA;AACF;AACA;AACA;EACEQ,cAAcA,CAACH,QAAqB,EAAQ;IAC1C,MAAMQ,GAAG,GAAG,IAAI,CAACb,UAAU,CAACc,OAAO,CAACT,QAAQ,CAAC;IAC7C,IAAIQ,GAAG,IAAI,CAAC,EAAE,IAAI,CAACb,UAAU,CAACe,MAAM,CAACF,GAAG,EAAE,CAAC,CAAC;EAC9C;AACF;AAACG,OAAA,CAAAjB,OAAA,GAAAA,OAAA","ignoreList":[]}
|
|
@@ -10,39 +10,42 @@ var _Barrier = _interopRequireDefault(require("./Barrier"));
|
|
|
10
10
|
* Implements a simple semaphore for async code logic.
|
|
11
11
|
*/
|
|
12
12
|
class Semaphore {
|
|
13
|
-
constructor() {
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
constructor(ready = false) {
|
|
14
|
+
// TODO: Boolean conversion is performed for backward compatibility with
|
|
15
|
+
// plain JS projects. Drop it in future.
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion
|
|
17
|
+
this.pReady = !!ready;
|
|
16
18
|
}
|
|
17
19
|
get ready() {
|
|
18
|
-
return this.
|
|
20
|
+
return this.pReady;
|
|
19
21
|
}
|
|
20
22
|
setReady(ready) {
|
|
23
|
+
// TODO: Boolean conversion is performed for backward compatibility with
|
|
24
|
+
// plain JS projects. Drop it in future.
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion
|
|
21
26
|
const bool = !!ready;
|
|
22
|
-
if (this.
|
|
23
|
-
this.
|
|
24
|
-
if (bool && !this.
|
|
25
|
-
this.
|
|
27
|
+
if (this.pReady !== bool) {
|
|
28
|
+
this.pReady = bool;
|
|
29
|
+
if (bool && !this.pDraining && this.pQueue.length) {
|
|
30
|
+
void this.pDrainQueue();
|
|
26
31
|
}
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
/**
|
|
31
36
|
* Waits until the semaphore is ready, and marks it as non-ready (seizes it).
|
|
32
|
-
* @return {Promise}
|
|
33
37
|
*/
|
|
34
38
|
async seize() {
|
|
35
39
|
return this.waitReady(true);
|
|
36
40
|
}
|
|
37
|
-
async waitReady() {
|
|
38
|
-
|
|
39
|
-
if (!this.p_ready || this.p_queue.length) {
|
|
41
|
+
async waitReady(seize = false) {
|
|
42
|
+
if (!this.pReady || this.pQueue.length) {
|
|
40
43
|
const barrier = new _Barrier.default();
|
|
41
|
-
this.
|
|
44
|
+
this.pQueue.push(barrier);
|
|
42
45
|
await barrier;
|
|
43
|
-
if (seize) this.
|
|
44
|
-
this.
|
|
45
|
-
} else if (seize) this.
|
|
46
|
+
if (seize) this.pReady = false;
|
|
47
|
+
void this.pDrainLock.resolve();
|
|
48
|
+
} else if (seize) this.pReady = false;
|
|
46
49
|
}
|
|
47
50
|
|
|
48
51
|
// Private members below this point.
|
|
@@ -53,21 +56,21 @@ class Semaphore {
|
|
|
53
56
|
* Otherwise, it breaks the queue draining loop, which will be restarted
|
|
54
57
|
* the next time the semaphore is set ready.
|
|
55
58
|
*/
|
|
56
|
-
async
|
|
57
|
-
this.
|
|
58
|
-
while (this.
|
|
59
|
-
this.
|
|
60
|
-
this.
|
|
61
|
-
await this.
|
|
62
|
-
this.
|
|
59
|
+
async pDrainQueue() {
|
|
60
|
+
this.pDraining = true;
|
|
61
|
+
while (this.pReady && this.pQueue.length) {
|
|
62
|
+
this.pDrainLock = new _Barrier.default();
|
|
63
|
+
void this.pQueue[0].resolve();
|
|
64
|
+
await this.pDrainLock;
|
|
65
|
+
void this.pQueue.shift();
|
|
63
66
|
}
|
|
64
|
-
this.
|
|
65
|
-
this.
|
|
67
|
+
this.pDraining = false;
|
|
68
|
+
this.pDrainLock = null;
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
// "true" when the drain queue process is running (and thus no need to start
|
|
69
72
|
// a new one).
|
|
70
|
-
|
|
73
|
+
pDraining = false;
|
|
71
74
|
|
|
72
75
|
// Each time a Promise from drain queue is resolved this drainLock is set
|
|
73
76
|
// to block further queue draining until the promise resolution handler
|
|
@@ -75,11 +78,11 @@ class Semaphore {
|
|
|
75
78
|
// to continue the draining. This is specifically important for .seize(),
|
|
76
79
|
// which should have a chance to switch semaphore state to non-ready prior
|
|
77
80
|
// to next Promise in the queue being unlocked.
|
|
78
|
-
|
|
81
|
+
pDrainLock = null;
|
|
79
82
|
|
|
80
83
|
// The array of barriers set for each async code flow awaiting for
|
|
81
84
|
// the Semaphore to become ready.
|
|
82
|
-
|
|
85
|
+
pQueue = [];
|
|
83
86
|
}
|
|
84
87
|
exports.default = Semaphore;
|
|
85
88
|
//# sourceMappingURL=Semaphore.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Semaphore.js","names":["_Barrier","_interopRequireDefault","require","Semaphore","constructor","ready","
|
|
1
|
+
{"version":3,"file":"Semaphore.js","names":["_Barrier","_interopRequireDefault","require","Semaphore","constructor","ready","pReady","setReady","bool","pDraining","pQueue","length","pDrainQueue","seize","waitReady","barrier","Barrier","push","pDrainLock","resolve","shift","exports","default"],"sources":["../../src/Semaphore.ts"],"sourcesContent":["import Barrier from './Barrier';\n\n/**\n * Implements a simple semaphore for async code logic.\n */\nexport default class Semaphore {\n constructor(ready = false) {\n // TODO: Boolean conversion is performed for backward compatibility with\n // plain JS projects. Drop it in future.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion\n this.pReady = !!ready;\n }\n\n get ready(): boolean {\n return this.pReady;\n }\n\n setReady(ready: boolean): void {\n // TODO: Boolean conversion is performed for backward compatibility with\n // plain JS projects. Drop it in future.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-conversion\n const bool = !!ready;\n if (this.pReady !== bool) {\n this.pReady = bool;\n if (bool && !this.pDraining && this.pQueue.length) {\n void this.pDrainQueue();\n }\n }\n }\n\n /**\n * Waits until the semaphore is ready, and marks it as non-ready (seizes it).\n */\n async seize(): Promise<void> {\n return this.waitReady(true);\n }\n\n async waitReady(seize = false): Promise<void> {\n if (!this.pReady || this.pQueue.length) {\n const barrier = new Barrier<void>();\n this.pQueue.push(barrier);\n await barrier;\n if (seize) this.pReady = false;\n void this.pDrainLock!.resolve();\n } else if (seize) this.pReady = false;\n }\n\n // Private members below this point.\n\n /**\n * If semaphore is ready, it releases the next barrier in the queue, if any,\n * and reschedules itself for a call in the next event loop iteration.\n * Otherwise, it breaks the queue draining loop, which will be restarted\n * the next time the semaphore is set ready.\n */\n async pDrainQueue(): Promise<void> {\n this.pDraining = true;\n while (this.pReady && this.pQueue.length) {\n this.pDrainLock = new Barrier();\n void this.pQueue[0]!.resolve();\n await this.pDrainLock;\n void this.pQueue.shift();\n }\n this.pDraining = false;\n this.pDrainLock = null;\n }\n\n // \"true\" when the drain queue process is running (and thus no need to start\n // a new one).\n private pDraining = false;\n\n // Each time a Promise from drain queue is resolved this drainLock is set\n // to block further queue draining until the promise resolution handler\n // (.seize() or .waitReady()) unlocks it, thus confirming it is fine\n // to continue the draining. This is specifically important for .seize(),\n // which should have a chance to switch semaphore state to non-ready prior\n // to next Promise in the queue being unlocked.\n private pDrainLock: Barrier<void> | null = null;\n\n // The array of barriers set for each async code flow awaiting for\n // the Semaphore to become ready.\n private pQueue: Array<Barrier<void>> = [];\n\n private pReady: boolean;\n}\n"],"mappings":";;;;;;;AAAA,IAAAA,QAAA,GAAAC,sBAAA,CAAAC,OAAA;AAEA;AACA;AACA;AACe,MAAMC,SAAS,CAAC;EAC7BC,WAAWA,CAACC,KAAK,GAAG,KAAK,EAAE;IACzB;IACA;IACA;IACA,IAAI,CAACC,MAAM,GAAG,CAAC,CAACD,KAAK;EACvB;EAEA,IAAIA,KAAKA,CAAA,EAAY;IACnB,OAAO,IAAI,CAACC,MAAM;EACpB;EAEAC,QAAQA,CAACF,KAAc,EAAQ;IAC7B;IACA;IACA;IACA,MAAMG,IAAI,GAAG,CAAC,CAACH,KAAK;IACpB,IAAI,IAAI,CAACC,MAAM,KAAKE,IAAI,EAAE;MACxB,IAAI,CAACF,MAAM,GAAGE,IAAI;MAClB,IAAIA,IAAI,IAAI,CAAC,IAAI,CAACC,SAAS,IAAI,IAAI,CAACC,MAAM,CAACC,MAAM,EAAE;QACjD,KAAK,IAAI,CAACC,WAAW,CAAC,CAAC;MACzB;IACF;EACF;;EAEA;AACF;AACA;EACE,MAAMC,KAAKA,CAAA,EAAkB;IAC3B,OAAO,IAAI,CAACC,SAAS,CAAC,IAAI,CAAC;EAC7B;EAEA,MAAMA,SAASA,CAACD,KAAK,GAAG,KAAK,EAAiB;IAC5C,IAAI,CAAC,IAAI,CAACP,MAAM,IAAI,IAAI,CAACI,MAAM,CAACC,MAAM,EAAE;MACtC,MAAMI,OAAO,GAAG,IAAIC,gBAAO,CAAO,CAAC;MACnC,IAAI,CAACN,MAAM,CAACO,IAAI,CAACF,OAAO,CAAC;MACzB,MAAMA,OAAO;MACb,IAAIF,KAAK,EAAE,IAAI,CAACP,MAAM,GAAG,KAAK;MAC9B,KAAK,IAAI,CAACY,UAAU,CAAEC,OAAO,CAAC,CAAC;IACjC,CAAC,MAAM,IAAIN,KAAK,EAAE,IAAI,CAACP,MAAM,GAAG,KAAK;EACvC;;EAEA;;EAEA;AACF;AACA;AACA;AACA;AACA;EACE,MAAMM,WAAWA,CAAA,EAAkB;IACjC,IAAI,CAACH,SAAS,GAAG,IAAI;IACrB,OAAO,IAAI,CAACH,MAAM,IAAI,IAAI,CAACI,MAAM,CAACC,MAAM,EAAE;MACxC,IAAI,CAACO,UAAU,GAAG,IAAIF,gBAAO,CAAC,CAAC;MAC/B,KAAK,IAAI,CAACN,MAAM,CAAC,CAAC,CAAC,CAAES,OAAO,CAAC,CAAC;MAC9B,MAAM,IAAI,CAACD,UAAU;MACrB,KAAK,IAAI,CAACR,MAAM,CAACU,KAAK,CAAC,CAAC;IAC1B;IACA,IAAI,CAACX,SAAS,GAAG,KAAK;IACtB,IAAI,CAACS,UAAU,GAAG,IAAI;EACxB;;EAEA;EACA;EACQT,SAAS,GAAG,KAAK;;EAEzB;EACA;EACA;EACA;EACA;EACA;EACQS,UAAU,GAAyB,IAAI;;EAE/C;EACA;EACQR,MAAM,GAAyB,EAAE;AAG3C;AAACW,OAAA,CAAAC,OAAA,GAAAnB,SAAA","ignoreList":[]}
|
package/build/common/index.js
CHANGED
|
@@ -28,6 +28,18 @@ Object.defineProperty(exports, "withRetries", {
|
|
|
28
28
|
}
|
|
29
29
|
});
|
|
30
30
|
var _Barrier = _interopRequireDefault(require("./Barrier"));
|
|
31
|
+
var _Cached = require("./Cached");
|
|
32
|
+
Object.keys(_Cached).forEach(function (key) {
|
|
33
|
+
if (key === "default" || key === "__esModule") return;
|
|
34
|
+
if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return;
|
|
35
|
+
if (key in exports && exports[key] === _Cached[key]) return;
|
|
36
|
+
Object.defineProperty(exports, key, {
|
|
37
|
+
enumerable: true,
|
|
38
|
+
get: function () {
|
|
39
|
+
return _Cached[key];
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
});
|
|
31
43
|
var _Emitter = require("./Emitter");
|
|
32
44
|
Object.keys(_Emitter).forEach(function (key) {
|
|
33
45
|
if (key === "default" || key === "__esModule") return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["_Barrier","_interopRequireDefault","require","
|
|
1
|
+
{"version":3,"file":"index.js","names":["_Barrier","_interopRequireDefault","require","_Cached","Object","keys","forEach","key","prototype","hasOwnProperty","call","_exportNames","exports","defineProperty","enumerable","get","_Emitter","_Semaphore","_time","_withRetries"],"sources":["../../src/index.ts"],"sourcesContent":["export { default as Barrier } from './Barrier';\nexport * from './Cached';\nexport * from './Emitter';\nexport { default as Semaphore } from './Semaphore';\nexport * from './time';\nexport { default as withRetries } from './withRetries';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,IAAAA,QAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,OAAA,GAAAD,OAAA;AAAAE,MAAA,CAAAC,IAAA,CAAAF,OAAA,EAAAG,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAJ,OAAA,CAAAI,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAZ,OAAA,CAAAI,GAAA;IAAA;EAAA;AAAA;AACA,IAAAS,QAAA,GAAAd,OAAA;AAAAE,MAAA,CAAAC,IAAA,CAAAW,QAAA,EAAAV,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAS,QAAA,CAAAT,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAC,QAAA,CAAAT,GAAA;IAAA;EAAA;AAAA;AACA,IAAAU,UAAA,GAAAhB,sBAAA,CAAAC,OAAA;AACA,IAAAgB,KAAA,GAAAhB,OAAA;AAAAE,MAAA,CAAAC,IAAA,CAAAa,KAAA,EAAAZ,OAAA,WAAAC,GAAA;EAAA,IAAAA,GAAA,kBAAAA,GAAA;EAAA,IAAAH,MAAA,CAAAI,SAAA,CAAAC,cAAA,CAAAC,IAAA,CAAAC,YAAA,EAAAJ,GAAA;EAAA,IAAAA,GAAA,IAAAK,OAAA,IAAAA,OAAA,CAAAL,GAAA,MAAAW,KAAA,CAAAX,GAAA;EAAAH,MAAA,CAAAS,cAAA,CAAAD,OAAA,EAAAL,GAAA;IAAAO,UAAA;IAAAC,GAAA,WAAAA,CAAA;MAAA,OAAAG,KAAA,CAAAX,GAAA;IAAA;EAAA;AAAA;AACA,IAAAY,YAAA,GAAAlB,sBAAA,CAAAC,OAAA","ignoreList":[]}
|
package/build/common/time.js
CHANGED
|
@@ -22,10 +22,10 @@ const YEAR_MS = exports.YEAR_MS = 31536000000; // 365 * DAY_MS
|
|
|
22
22
|
// from the library as well, and it should be documented later.
|
|
23
23
|
class Timer extends _Barrier.default {
|
|
24
24
|
get abort() {
|
|
25
|
-
return this.
|
|
25
|
+
return this.pAbort;
|
|
26
26
|
}
|
|
27
27
|
get timeout() {
|
|
28
|
-
return this.
|
|
28
|
+
return this.pTimeout;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/**
|
|
@@ -43,24 +43,34 @@ class Timer extends _Barrier.default {
|
|
|
43
43
|
*/
|
|
44
44
|
constructor(executor) {
|
|
45
45
|
super(executor);
|
|
46
|
-
this.
|
|
46
|
+
this.pAbort = () => undefined;
|
|
47
47
|
}
|
|
48
48
|
init(timeout) {
|
|
49
|
-
if (this.
|
|
49
|
+
if (this.pTimeout !== undefined) {
|
|
50
50
|
throw Error('This Timer is initialized already');
|
|
51
51
|
}
|
|
52
|
-
this.
|
|
52
|
+
this.pTimeout = timeout;
|
|
53
53
|
if (timeout > 0) {
|
|
54
|
-
const id = setTimeout(
|
|
55
|
-
|
|
54
|
+
const id = setTimeout(() => {
|
|
55
|
+
void super.resolve();
|
|
56
|
+
}, timeout);
|
|
57
|
+
this.pAbort = () => {
|
|
58
|
+
clearTimeout(id);
|
|
59
|
+
};
|
|
56
60
|
} else {
|
|
57
|
-
super.resolve();
|
|
61
|
+
void super.resolve();
|
|
58
62
|
}
|
|
59
63
|
return this;
|
|
60
64
|
}
|
|
65
|
+
|
|
66
|
+
// TODO: For async functions TS requires the return type to be the global
|
|
67
|
+
// Promise, thus not allowing to return our Timer type extending that via
|
|
68
|
+
// Barrier. Thus, we don't mark this method async for now, disabling the rule,
|
|
69
|
+
// and we should think more about it in future.
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
61
71
|
then(onFulfilled, onRejected) {
|
|
62
72
|
const res = super.then(onFulfilled, onRejected);
|
|
63
|
-
if (this.timeout !== undefined) res.init(this.timeout);
|
|
73
|
+
if (this.timeout !== undefined) void res.init(this.timeout);
|
|
64
74
|
return res;
|
|
65
75
|
}
|
|
66
76
|
}
|
|
@@ -72,6 +82,11 @@ class Timer extends _Barrier.default {
|
|
|
72
82
|
* .abort() method attached, which cancels the pending timer resolution
|
|
73
83
|
* (without resolving or rejecting the barrier).
|
|
74
84
|
*/
|
|
85
|
+
// TODO: For async functions TS requires the return type to be the global
|
|
86
|
+
// Promise, thus not allowing to return our Timer type extending that via
|
|
87
|
+
// Barrier. Thus, we don't mark this method async for now, disabling the rule,
|
|
88
|
+
// and we should think more about it in future.
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
75
90
|
exports.Timer = Timer;
|
|
76
91
|
function timer(timeout) {
|
|
77
92
|
const t = new Timer();
|
package/build/common/time.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"time.js","names":["_Barrier","_interopRequireDefault","require","SEC_MS","exports","MIN_MS","HOUR_MS","DAY_MS","YEAR_MS","Timer","Barrier","abort","
|
|
1
|
+
{"version":3,"file":"time.js","names":["_Barrier","_interopRequireDefault","require","SEC_MS","exports","MIN_MS","HOUR_MS","DAY_MS","YEAR_MS","Timer","Barrier","abort","pAbort","timeout","pTimeout","constructor","executor","undefined","init","Error","id","setTimeout","resolve","clearTimeout","then","onFulfilled","onRejected","res","timer","t"],"sources":["../../src/time.ts"],"sourcesContent":["import Barrier, { type Executor } from './Barrier';\n\n// This is not very elegant, but as of now TypeScript does not support type\n// arithmetic, thus we can't have constants assigned like `MIN_MS = 60 * SEC_MS`\n// and have the result type to be 60000 (number literal), it would be just\n// the generic number type.\nexport const SEC_MS = 1000;\nexport const MIN_MS = 60000; // 60 * SEC_MS\nexport const HOUR_MS = 3600000; // 60 * MIN_MS\nexport const DAY_MS = 86400000; // 24 * HOUR_MS\nexport const YEAR_MS = 31536000000; // 365 * DAY_MS\n\n// TODO: Ok, as we have ended up with a Timer class, mostly to achieve a good\n// TypeScript typing for timer() function, it makes sense to expose the class\n// from the library as well, and it should be documented later.\nexport class Timer<T> extends Barrier<void, T> {\n private pAbort: () => void;\n\n private pTimeout?: number;\n\n get abort(): () => void {\n return this.pAbort;\n }\n\n get timeout(): number | undefined {\n return this.pTimeout;\n }\n\n /**\n * Creates a new, non-initialized instance of Timer. Call .init() method\n * to actually initialize and launch the timer.\n *\n * NOTE: Although it might be tempting to accept `timeout` value as\n * a constructor's argument, it won't work well, because Timer is an\n * extension of Promise (via Barrier), and the way Promises works (in\n * particular their .then() method, which internally calls constructor()\n * with special executor) does not play along with initalization depending\n * on custom parameters done in constructor().\n *\n * @param executor\n */\n constructor(executor?: Executor<T>) {\n super(executor);\n this.pAbort = () => undefined;\n }\n\n init(timeout: number): this {\n if (this.pTimeout !== undefined) {\n throw Error('This Timer is initialized already');\n }\n this.pTimeout = timeout;\n if (timeout > 0) {\n const id = setTimeout(() => {\n void super.resolve();\n }, timeout);\n this.pAbort = () => {\n clearTimeout(id);\n };\n } else {\n void super.resolve();\n }\n return this;\n }\n\n // TODO: For async functions TS requires the return type to be the global\n // Promise, thus not allowing to return our Timer type extending that via\n // Barrier. Thus, we don't mark this method async for now, disabling the rule,\n // and we should think more about it in future.\n // eslint-disable-next-line @typescript-eslint/promise-function-async\n then<TR1, TR2>(\n onFulfilled?: ((value: T) => TR1 | PromiseLike<TR1>) | null,\n onRejected?: ((reason: unknown) => TR2 | PromiseLike<TR2>) | null,\n ): Timer<TR1 | TR2> {\n const res = super.then(onFulfilled, onRejected) as Timer<TR1 | TR2>;\n if (this.timeout !== undefined) void res.init(this.timeout);\n return res;\n }\n}\n\n/**\n * Creates a Promise, which resolves after the given timeout.\n * @param {number} timeout Timeout [ms].\n * @return {Barrier} Resolves after the timeout. It has additional\n * .abort() method attached, which cancels the pending timer resolution\n * (without resolving or rejecting the barrier).\n */\n// TODO: For async functions TS requires the return type to be the global\n// Promise, thus not allowing to return our Timer type extending that via\n// Barrier. Thus, we don't mark this method async for now, disabling the rule,\n// and we should think more about it in future.\n// eslint-disable-next-line @typescript-eslint/promise-function-async\nexport function timer(timeout: number): Timer<void> {\n const t = new Timer<void>();\n return t.init(timeout);\n}\n"],"mappings":";;;;;;;;AAAA,IAAAA,QAAA,GAAAC,sBAAA,CAAAC,OAAA;AAEA;AACA;AACA;AACA;AACO,MAAMC,MAAM,GAAAC,OAAA,CAAAD,MAAA,GAAG,IAAI;AACnB,MAAME,MAAM,GAAAD,OAAA,CAAAC,MAAA,GAAG,KAAK,CAAC,CAAC;AACtB,MAAMC,OAAO,GAAAF,OAAA,CAAAE,OAAA,GAAG,OAAO,CAAC,CAAC;AACzB,MAAMC,MAAM,GAAAH,OAAA,CAAAG,MAAA,GAAG,QAAQ,CAAC,CAAC;AACzB,MAAMC,OAAO,GAAAJ,OAAA,CAAAI,OAAA,GAAG,WAAW,CAAC,CAAC;;AAEpC;AACA;AACA;AACO,MAAMC,KAAK,SAAYC,gBAAO,CAAU;EAK7C,IAAIC,KAAKA,CAAA,EAAe;IACtB,OAAO,IAAI,CAACC,MAAM;EACpB;EAEA,IAAIC,OAAOA,CAAA,EAAuB;IAChC,OAAO,IAAI,CAACC,QAAQ;EACtB;;EAEA;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACEC,WAAWA,CAACC,QAAsB,EAAE;IAClC,KAAK,CAACA,QAAQ,CAAC;IACf,IAAI,CAACJ,MAAM,GAAG,MAAMK,SAAS;EAC/B;EAEAC,IAAIA,CAACL,OAAe,EAAQ;IAC1B,IAAI,IAAI,CAACC,QAAQ,KAAKG,SAAS,EAAE;MAC/B,MAAME,KAAK,CAAC,mCAAmC,CAAC;IAClD;IACA,IAAI,CAACL,QAAQ,GAAGD,OAAO;IACvB,IAAIA,OAAO,GAAG,CAAC,EAAE;MACf,MAAMO,EAAE,GAAGC,UAAU,CAAC,MAAM;QAC1B,KAAK,KAAK,CAACC,OAAO,CAAC,CAAC;MACtB,CAAC,EAAET,OAAO,CAAC;MACX,IAAI,CAACD,MAAM,GAAG,MAAM;QAClBW,YAAY,CAACH,EAAE,CAAC;MAClB,CAAC;IACH,CAAC,MAAM;MACL,KAAK,KAAK,CAACE,OAAO,CAAC,CAAC;IACtB;IACA,OAAO,IAAI;EACb;;EAEA;EACA;EACA;EACA;EACA;EACAE,IAAIA,CACFC,WAA2D,EAC3DC,UAAiE,EAC/C;IAClB,MAAMC,GAAG,GAAG,KAAK,CAACH,IAAI,CAACC,WAAW,EAAEC,UAAU,CAAqB;IACnE,IAAI,IAAI,CAACb,OAAO,KAAKI,SAAS,EAAE,KAAKU,GAAG,CAACT,IAAI,CAAC,IAAI,CAACL,OAAO,CAAC;IAC3D,OAAOc,GAAG;EACZ;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAAvB,OAAA,CAAAK,KAAA,GAAAA,KAAA;AACO,SAASmB,KAAKA,CAACf,OAAe,EAAe;EAClD,MAAMgB,CAAC,GAAG,IAAIpB,KAAK,CAAO,CAAC;EAC3B,OAAOoB,CAAC,CAACX,IAAI,CAACL,OAAO,CAAC;AACxB","ignoreList":[]}
|
|
@@ -16,10 +16,7 @@ var _time = require("./time");
|
|
|
16
16
|
* @returns Resolves to the result of the successful `action` execution;
|
|
17
17
|
* or rejects with the error from the last faileda attempt.
|
|
18
18
|
*/
|
|
19
|
-
async function withRetries(action) {
|
|
20
|
-
let maxRetries = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 3;
|
|
21
|
-
let interval = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 300;
|
|
22
|
-
/* eslint-disable no-await-in-loop */
|
|
19
|
+
async function withRetries(action, maxRetries = 3, interval = 300) {
|
|
23
20
|
for (let n = 1;; ++n) {
|
|
24
21
|
try {
|
|
25
22
|
const res = action();
|
|
@@ -28,6 +25,5 @@ async function withRetries(action) {
|
|
|
28
25
|
if (n < maxRetries) await (0, _time.timer)(interval);else throw error;
|
|
29
26
|
}
|
|
30
27
|
}
|
|
31
|
-
/* eslint-enable no-await-in-loop */
|
|
32
28
|
}
|
|
33
29
|
//# sourceMappingURL=withRetries.js.map
|