@keeex/utils 7.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.
Files changed (183) hide show
  1. package/LICENSE +9 -0
  2. package/README.md +105 -0
  3. package/lib/array.d.ts +28 -0
  4. package/lib/array.js +36 -0
  5. package/lib/arraybuffer.d.ts +138 -0
  6. package/lib/arraybuffer.js +141 -0
  7. package/lib/async/asynctrigger.d.ts +50 -0
  8. package/lib/async/asynctrigger.js +108 -0
  9. package/lib/async/deferredpromise.d.ts +32 -0
  10. package/lib/async/deferredpromise.js +66 -0
  11. package/lib/async/keycache.d.ts +56 -0
  12. package/lib/async/keycache.js +103 -0
  13. package/lib/async/queues.d.ts +69 -0
  14. package/lib/async/queues.js +135 -0
  15. package/lib/async/timecache.d.ts +58 -0
  16. package/lib/async/timecache.js +118 -0
  17. package/lib/base58.d.ts +27 -0
  18. package/lib/base58.js +83 -0
  19. package/lib/base64.d.ts +51 -0
  20. package/lib/base64.js +126 -0
  21. package/lib/benchmark.d.ts +126 -0
  22. package/lib/benchmark.js +177 -0
  23. package/lib/bits/arraybuffer.d.ts +35 -0
  24. package/lib/bits/arraybuffer.js +64 -0
  25. package/lib/bits/base64.d.ts +35 -0
  26. package/lib/bits/base64.js +70 -0
  27. package/lib/bits/hex.d.ts +17 -0
  28. package/lib/bits/hex.js +30 -0
  29. package/lib/bits/uint8array.d.ts +28 -0
  30. package/lib/bits/uint8array.js +42 -0
  31. package/lib/bytebuffer.d.ts +27 -0
  32. package/lib/bytebuffer.js +29 -0
  33. package/lib/consts.d.ts +33 -0
  34. package/lib/consts.js +33 -0
  35. package/lib/cron/logger.d.ts +22 -0
  36. package/lib/cron/logger.js +31 -0
  37. package/lib/cron/scheduledtask.d.ts +71 -0
  38. package/lib/cron/scheduledtask.js +137 -0
  39. package/lib/cron/types.d.ts +53 -0
  40. package/lib/cron/types.js +31 -0
  41. package/lib/cron.d.ts +29 -0
  42. package/lib/cron.js +47 -0
  43. package/lib/dict.d.ts +56 -0
  44. package/lib/dict.js +74 -0
  45. package/lib/error.d.ts +25 -0
  46. package/lib/error.js +41 -0
  47. package/lib/global.d.ts +27 -0
  48. package/lib/global.js +53 -0
  49. package/lib/hex.d.ts +32 -0
  50. package/lib/hex.js +58 -0
  51. package/lib/idx.d.ts +51 -0
  52. package/lib/idx.js +81 -0
  53. package/lib/json.d.ts +57 -0
  54. package/lib/json.js +116 -0
  55. package/lib/marshalling/marshaller.d.ts +51 -0
  56. package/lib/marshalling/marshaller.js +155 -0
  57. package/lib/marshalling/unmarshaller.d.ts +53 -0
  58. package/lib/marshalling/unmarshaller.js +124 -0
  59. package/lib/marshalling/util.d.ts +25 -0
  60. package/lib/marshalling/util.js +25 -0
  61. package/lib/number.d.ts +17 -0
  62. package/lib/number.js +21 -0
  63. package/lib/path.d.ts +25 -0
  64. package/lib/path.js +29 -0
  65. package/lib/promise.d.ts +42 -0
  66. package/lib/promise.js +78 -0
  67. package/lib/starttime.d.ts +23 -0
  68. package/lib/starttime.js +29 -0
  69. package/lib/string.d.ts +65 -0
  70. package/lib/string.js +108 -0
  71. package/lib/types/array.d.ts +34 -0
  72. package/lib/types/array.js +64 -0
  73. package/lib/types/enum.d.ts +30 -0
  74. package/lib/types/enum.js +44 -0
  75. package/lib/types/predicateerror.d.ts +40 -0
  76. package/lib/types/predicateerror.js +107 -0
  77. package/lib/types/primitive.d.ts +23 -0
  78. package/lib/types/primitive.js +34 -0
  79. package/lib/types/record.d.ts +67 -0
  80. package/lib/types/record.js +235 -0
  81. package/lib/types/types.d.ts +64 -0
  82. package/lib/types/types.js +115 -0
  83. package/lib/types/utils.d.ts +18 -0
  84. package/lib/types/utils.js +67 -0
  85. package/lib/uint8array.d.ts +176 -0
  86. package/lib/uint8array.js +438 -0
  87. package/lib/units.d.ts +159 -0
  88. package/lib/units.js +290 -0
  89. package/lib/utils/buffer.d.ts +49 -0
  90. package/lib/utils/buffer.js +79 -0
  91. package/lib/utils/fourbytes.d.ts +29 -0
  92. package/lib/utils/fourbytes.js +45 -0
  93. package/package.json +1 -0
  94. package/web/array.d.ts +28 -0
  95. package/web/array.js +34 -0
  96. package/web/arraybuffer.d.ts +138 -0
  97. package/web/arraybuffer.js +141 -0
  98. package/web/async/asynctrigger.d.ts +50 -0
  99. package/web/async/asynctrigger.js +106 -0
  100. package/web/async/deferredpromise.d.ts +32 -0
  101. package/web/async/deferredpromise.js +65 -0
  102. package/web/async/keycache.d.ts +56 -0
  103. package/web/async/keycache.js +97 -0
  104. package/web/async/queues.d.ts +69 -0
  105. package/web/async/queues.js +131 -0
  106. package/web/async/timecache.d.ts +58 -0
  107. package/web/async/timecache.js +107 -0
  108. package/web/base58.d.ts +27 -0
  109. package/web/base58.js +78 -0
  110. package/web/base64.d.ts +51 -0
  111. package/web/base64.js +136 -0
  112. package/web/benchmark.d.ts +126 -0
  113. package/web/benchmark.js +183 -0
  114. package/web/bits/arraybuffer.d.ts +35 -0
  115. package/web/bits/arraybuffer.js +59 -0
  116. package/web/bits/base64.d.ts +35 -0
  117. package/web/bits/base64.js +67 -0
  118. package/web/bits/hex.d.ts +17 -0
  119. package/web/bits/hex.js +27 -0
  120. package/web/bits/uint8array.d.ts +28 -0
  121. package/web/bits/uint8array.js +41 -0
  122. package/web/bytebuffer.d.ts +27 -0
  123. package/web/bytebuffer.js +29 -0
  124. package/web/consts.d.ts +33 -0
  125. package/web/consts.js +33 -0
  126. package/web/cron/logger.d.ts +22 -0
  127. package/web/cron/logger.js +30 -0
  128. package/web/cron/scheduledtask.d.ts +71 -0
  129. package/web/cron/scheduledtask.js +136 -0
  130. package/web/cron/types.d.ts +53 -0
  131. package/web/cron/types.js +31 -0
  132. package/web/cron.d.ts +29 -0
  133. package/web/cron.js +47 -0
  134. package/web/dict.d.ts +56 -0
  135. package/web/dict.js +67 -0
  136. package/web/error.d.ts +25 -0
  137. package/web/error.js +39 -0
  138. package/web/global.d.ts +27 -0
  139. package/web/global.js +49 -0
  140. package/web/hex.d.ts +32 -0
  141. package/web/hex.js +52 -0
  142. package/web/idx.d.ts +51 -0
  143. package/web/idx.js +76 -0
  144. package/web/json.d.ts +57 -0
  145. package/web/json.js +98 -0
  146. package/web/marshalling/marshaller.d.ts +51 -0
  147. package/web/marshalling/marshaller.js +150 -0
  148. package/web/marshalling/unmarshaller.d.ts +53 -0
  149. package/web/marshalling/unmarshaller.js +115 -0
  150. package/web/marshalling/util.d.ts +25 -0
  151. package/web/marshalling/util.js +25 -0
  152. package/web/number.d.ts +17 -0
  153. package/web/number.js +21 -0
  154. package/web/path.d.ts +25 -0
  155. package/web/path.js +26 -0
  156. package/web/promise.d.ts +42 -0
  157. package/web/promise.js +74 -0
  158. package/web/starttime.d.ts +23 -0
  159. package/web/starttime.js +29 -0
  160. package/web/string.d.ts +65 -0
  161. package/web/string.js +101 -0
  162. package/web/types/array.d.ts +34 -0
  163. package/web/types/array.js +63 -0
  164. package/web/types/enum.d.ts +30 -0
  165. package/web/types/enum.js +40 -0
  166. package/web/types/predicateerror.d.ts +40 -0
  167. package/web/types/predicateerror.js +128 -0
  168. package/web/types/primitive.d.ts +23 -0
  169. package/web/types/primitive.js +33 -0
  170. package/web/types/record.d.ts +67 -0
  171. package/web/types/record.js +213 -0
  172. package/web/types/types.d.ts +64 -0
  173. package/web/types/types.js +123 -0
  174. package/web/types/utils.d.ts +18 -0
  175. package/web/types/utils.js +30 -0
  176. package/web/uint8array.d.ts +176 -0
  177. package/web/uint8array.js +412 -0
  178. package/web/units.d.ts +159 -0
  179. package/web/units.js +312 -0
  180. package/web/utils/buffer.d.ts +49 -0
  181. package/web/utils/buffer.js +76 -0
  182. package/web/utils/fourbytes.d.ts +29 -0
  183. package/web/utils/fourbytes.js +45 -0
@@ -0,0 +1,66 @@
1
+ /**
2
+ * @license
3
+ * @preserve
4
+ *
5
+ * MIT License
6
+ *
7
+ * Copyright (c) 2023 KeeeX SAS
8
+ *
9
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14
+ *
15
+ */
16
+ /* eslint-disable no-console */
17
+ // Heavily based on https://stackoverflow.com/a/34637436/2059163
18
+ /**
19
+ * Allows returning a promise and resolving it in another scope
20
+ *
21
+ * @public
22
+ */
23
+ export class DeferredPromise {
24
+ /** The actual promise that can be awaited */
25
+ promise;
26
+ #resolveFunc;
27
+ #rejectFunc;
28
+ #resolved = false;
29
+ constructor() {
30
+ // eslint-disable-next-line @typescript-eslint/init-declarations
31
+ let resolveFunc;
32
+ // eslint-disable-next-line @typescript-eslint/init-declarations
33
+ let rejectFunc;
34
+ // eslint-disable-next-line promise/avoid-new
35
+ this.promise = new Promise((resolve, reject) => {
36
+ resolveFunc = resolve;
37
+ rejectFunc = reject;
38
+ });
39
+ if (!resolveFunc || !rejectFunc)
40
+ throw new Error("Unexpected state");
41
+ this.#resolveFunc = resolveFunc;
42
+ this.#rejectFunc = rejectFunc;
43
+ }
44
+ /** Indicate if the promise already resolved or rejected. */
45
+ get resolved() {
46
+ return this.#resolved;
47
+ }
48
+ /** Can be called from anywhere; will resolve the promise. */
49
+ resolve = (value) => {
50
+ if (this.#resolved) {
51
+ console.warn("Promise resolved multiple time; ignoring");
52
+ return;
53
+ }
54
+ this.#resolved = true;
55
+ this.#resolveFunc(value);
56
+ };
57
+ /** Can be called from anywhere; will reject the promise. */
58
+ reject = (reason) => {
59
+ if (this.#resolved) {
60
+ console.warn("Promise resolved multiple time; ignoring");
61
+ return;
62
+ }
63
+ this.#resolved = true;
64
+ this.#rejectFunc(reason);
65
+ };
66
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * @license
3
+ * @preserve
4
+ *
5
+ * MIT License
6
+ *
7
+ * Copyright (c) 2023 KeeeX SAS
8
+ *
9
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14
+ *
15
+ */
16
+ import { Awaitable } from "../types/types.js";
17
+ /**
18
+ * Function used to fill a cache entry on a cache miss.
19
+ *
20
+ * @param key - The requested key
21
+ *
22
+ * @returns
23
+ * The requested entry, or undefined if the value does not exist.
24
+ */
25
+ export type CacheGetFunc<ValueType> = (key: string) => Awaitable<ValueType | undefined>;
26
+ /**
27
+ * Basic key-value cache mechanism.
28
+ *
29
+ * Discards old data based on last access.
30
+ * Cache entries can be fetched asynchronously; multiple fetch on the same value will share the same
31
+ * promise.
32
+ *
33
+ * @public
34
+ */
35
+ export default class KeyCache<ValueType = string> {
36
+ #private;
37
+ /**
38
+ * Constructor.
39
+ *
40
+ * @param maxEntries - Maximum number of entries kept. Once more entries are added, oldest entries
41
+ * are discarded based on last access time.
42
+ *
43
+ * @param getFunc - A function to fetch missing cache entries.
44
+ * If the function returns undefined, the value is not cached. If the function throws, the error
45
+ * is kept (and requesting this entry again will return the rejected promise.
46
+ */
47
+ constructor(maxEntries?: number, getFunc?: CacheGetFunc<ValueType>);
48
+ get cache(): Record<string, Promise<ValueType | undefined>>;
49
+ get keys(): Array<string>;
50
+ /** Return a cache entry if present. */
51
+ get: (key: string) => Promise<ValueType | undefined>;
52
+ /** Manually set a cache entry. */
53
+ set: (key: string, value: Awaitable<ValueType>) => this;
54
+ /** Remove a stale entry. */
55
+ remove: (key: string) => this;
56
+ }
@@ -0,0 +1,103 @@
1
+ /**
2
+ * @license
3
+ * @preserve
4
+ *
5
+ * MIT License
6
+ *
7
+ * Copyright (c) 2023 KeeeX SAS
8
+ *
9
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14
+ *
15
+ */
16
+ import { dropPromise } from "../promise.js";
17
+ /**
18
+ * Basic key-value cache mechanism.
19
+ *
20
+ * Discards old data based on last access.
21
+ * Cache entries can be fetched asynchronously; multiple fetch on the same value will share the same
22
+ * promise.
23
+ *
24
+ * @public
25
+ */
26
+ export default class KeyCache {
27
+ #cache = {};
28
+ #keys = [];
29
+ #maxEntries;
30
+ #getFunc;
31
+ /**
32
+ * Constructor.
33
+ *
34
+ * @param maxEntries - Maximum number of entries kept. Once more entries are added, oldest entries
35
+ * are discarded based on last access time.
36
+ *
37
+ * @param getFunc - A function to fetch missing cache entries.
38
+ * If the function returns undefined, the value is not cached. If the function throws, the error
39
+ * is kept (and requesting this entry again will return the rejected promise.
40
+ */
41
+ constructor(maxEntries = 1000, getFunc) {
42
+ this.#maxEntries = maxEntries;
43
+ this.#getFunc = getFunc;
44
+ }
45
+ get cache() {
46
+ return this.#cache;
47
+ }
48
+ get keys() {
49
+ return this.#keys;
50
+ }
51
+ /** Return a cache entry if present. */
52
+ get = async (key) => {
53
+ if (key in this.#cache)
54
+ return this.#cache[key];
55
+ if (this.#getFunc)
56
+ return this.#addKey(key, this.#getFunc(key));
57
+ };
58
+ /** Manually set a cache entry. */
59
+ set = (key, value) => {
60
+ dropPromise(this.#addKey(key, value));
61
+ return this;
62
+ };
63
+ /** Remove a stale entry. */
64
+ remove = (key) => {
65
+ this.#removeKey(key);
66
+ return this;
67
+ };
68
+ /** Add a cache entry, purging older ones if needed */
69
+ #addKey = (key, valuePromise) => {
70
+ const res = async () => {
71
+ const value = await valuePromise;
72
+ if (value === undefined) {
73
+ this.#removeKey(key);
74
+ return;
75
+ }
76
+ return value;
77
+ };
78
+ const promise = res();
79
+ if (!(key in this.#cache))
80
+ this.#keys.push(key);
81
+ this.#cache[key] = promise;
82
+ this.#trim();
83
+ return promise;
84
+ };
85
+ /** Remove a specific key from the cache */
86
+ #removeKey = (key) => {
87
+ if (!(key in this.#cache))
88
+ return;
89
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
90
+ delete this.#cache[key];
91
+ this.#keys.splice(this.#keys.indexOf(key), 1);
92
+ };
93
+ /** Remove excess entries */
94
+ #trim = () => {
95
+ const entriesToTrim = Math.max(0, this.#keys.length - this.#maxEntries);
96
+ if (entriesToTrim <= 0)
97
+ return;
98
+ const keysToTrim = this.#keys.splice(0, entriesToTrim);
99
+ // eslint-disable-next-line @typescript-eslint/no-dynamic-delete
100
+ for (const keyToTrim of keysToTrim)
101
+ delete this.#cache[keyToTrim];
102
+ };
103
+ }
@@ -0,0 +1,69 @@
1
+ /**
2
+ * @license
3
+ * @preserve
4
+ *
5
+ * MIT License
6
+ *
7
+ * Copyright (c) 2023 KeeeX SAS
8
+ *
9
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14
+ *
15
+ */
16
+ /**
17
+ * Task function definition.
18
+ *
19
+ * @param params - is the argument passed to the `runTask()` method
20
+ * @param queueId - The queue identifier, starting at 0
21
+ *
22
+ * @public
23
+ */
24
+ export type TaskFunc<TaskParams, TaskResult> = (params: TaskParams, queueId: number) => Promise<TaskResult>;
25
+ /**
26
+ * Customizing the handling of a task
27
+ *
28
+ * @public
29
+ */
30
+ export interface TaskOptions {
31
+ /** Put the task in front of a queue instead of in the back */
32
+ priority?: boolean;
33
+ /**
34
+ * Force using the specified queue.
35
+ * This bypass the "max queued items" check.
36
+ */
37
+ forceQueueId?: number;
38
+ }
39
+ /**
40
+ * Run asynchronous tasks in controlled queues.
41
+ *
42
+ * The task function is shared among all queues.
43
+ * Each queue runs one operation at a time.
44
+ * Queued tasks can be run in parallel, and each will be given it's queue ID to distinguish them.
45
+ *
46
+ * For example, if you setup 3 queues and schedule 10 tasks, they might run like this (each queue
47
+ * running only one task at a time)
48
+ *
49
+ * - Queue 1: T0, T2, T5, T3
50
+ * - Queue 2: T1, T3, T6, T7
51
+ * - Queue 3: T4, T8, T9
52
+ *
53
+ * @public
54
+ */
55
+ export declare class Queues<TaskParams, TaskResult> {
56
+ #private;
57
+ /**
58
+ * @param maxQueuedItems - Maximum number of tasks pending. This is rounded up so that all queues
59
+ * have the same maximum.
60
+ */
61
+ constructor(task: TaskFunc<TaskParams, TaskResult>, queuesCount: number, maxQueuedItems: number);
62
+ /**
63
+ * Run a task.
64
+ * As specified in the description, only one task per queue runs at a time.
65
+ *
66
+ * If the maximum queue length is reached, throws.
67
+ */
68
+ runTask: (taskParams: TaskParams, options?: TaskOptions) => Promise<TaskResult>;
69
+ }
@@ -0,0 +1,135 @@
1
+ /**
2
+ * @license
3
+ * @preserve
4
+ *
5
+ * MIT License
6
+ *
7
+ * Copyright (c) 2023 KeeeX SAS
8
+ *
9
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14
+ *
15
+ */
16
+ import { dropPromise } from "../promise.js";
17
+ import { DeferredPromise } from "./deferredpromise.js";
18
+ /**
19
+ * Run asynchronous tasks in controlled queues.
20
+ *
21
+ * The task function is shared among all queues.
22
+ * Each queue runs one operation at a time.
23
+ * Queued tasks can be run in parallel, and each will be given it's queue ID to distinguish them.
24
+ *
25
+ * For example, if you setup 3 queues and schedule 10 tasks, they might run like this (each queue
26
+ * running only one task at a time)
27
+ *
28
+ * - Queue 1: T0, T2, T5, T3
29
+ * - Queue 2: T1, T3, T6, T7
30
+ * - Queue 3: T4, T8, T9
31
+ *
32
+ * @public
33
+ */
34
+ export class Queues {
35
+ /** Function to run a single task */
36
+ #task;
37
+ /** Maximum length of each queue */
38
+ #maxQueueLength;
39
+ /** Pending tasks */
40
+ #queues;
41
+ /** Flag to control wether a queue needs to be started or not */
42
+ #queueRunning;
43
+ /**
44
+ * @param maxQueuedItems - Maximum number of tasks pending. This is rounded up so that all queues
45
+ * have the same maximum.
46
+ */
47
+ constructor(task, queuesCount, maxQueuedItems) {
48
+ this.#task = task;
49
+ this.#maxQueueLength = Math.ceil(maxQueuedItems / queuesCount);
50
+ this.#queues = [];
51
+ this.#queueRunning = [];
52
+ for (let i = 0; i < queuesCount; ++i) {
53
+ this.#queues.push([]);
54
+ this.#queueRunning[i] = false;
55
+ }
56
+ }
57
+ /**
58
+ * Run a task.
59
+ * As specified in the description, only one task per queue runs at a time.
60
+ *
61
+ * If the maximum queue length is reached, throws.
62
+ */
63
+ runTask = (taskParams, options = {}) => {
64
+ const taskDef = {
65
+ deferred: new DeferredPromise(),
66
+ taskOptions: options,
67
+ taskParams,
68
+ };
69
+ this.#addToQueue(taskDef);
70
+ return taskDef.deferred.promise;
71
+ };
72
+ /** Return the queue to use for this task */
73
+ #getTargetQueue = (taskDef) => {
74
+ if (taskDef.taskOptions.forceQueueId !== undefined) {
75
+ const target = taskDef.taskOptions.forceQueueId;
76
+ if (target < 0 || target >= this.#queues.length) {
77
+ throw new Error("Forced queue ID is invalid");
78
+ }
79
+ return target;
80
+ }
81
+ // Find shortest queue
82
+ let shortestId = null;
83
+ let shortestLength = this.#maxQueueLength;
84
+ for (let i = 0; i < this.#queues.length && shortestLength > 0; ++i) {
85
+ const queueLength = this.#queues[i].length + (this.#queueRunning[i] ? 1 : 0);
86
+ if (queueLength < shortestLength) {
87
+ shortestLength = queueLength;
88
+ shortestId = i;
89
+ }
90
+ }
91
+ if (shortestId === null) {
92
+ throw new Error("Max queue length exceeded");
93
+ }
94
+ return shortestId;
95
+ };
96
+ /** Add a task definition to the currently shortest queue */
97
+ #addToQueue = (taskDef) => {
98
+ const targetQueue = this.#getTargetQueue(taskDef);
99
+ if (taskDef.taskOptions.priority) {
100
+ this.#queues[targetQueue].splice(0, 0, taskDef);
101
+ }
102
+ else {
103
+ this.#queues[targetQueue].push(taskDef);
104
+ }
105
+ if (this.#queues[targetQueue].length === 1)
106
+ dropPromise(this.#runQueue(targetQueue));
107
+ };
108
+ /**
109
+ * Start running a single queue.
110
+ * The function will keep going until the queue is empty.
111
+ * It can safely be called multiple time with the same queueId.
112
+ */
113
+ #runQueue = async (queueId) => {
114
+ if (this.#queueRunning[queueId]) {
115
+ return;
116
+ }
117
+ try {
118
+ this.#queueRunning[queueId] = true;
119
+ while (this.#queues[queueId].length > 0) {
120
+ const taskDef = this.#queues[queueId].splice(0, 1)[0];
121
+ try {
122
+ // eslint-disable-next-line no-await-in-loop
123
+ const res = await this.#task(taskDef.taskParams, queueId);
124
+ taskDef.deferred.resolve(res);
125
+ }
126
+ catch (e) {
127
+ taskDef.deferred.reject(e);
128
+ }
129
+ }
130
+ }
131
+ finally {
132
+ this.#queueRunning[queueId] = false;
133
+ }
134
+ };
135
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * @license
3
+ * @preserve
4
+ *
5
+ * MIT License
6
+ *
7
+ * Copyright (c) 2023 KeeeX SAS
8
+ *
9
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14
+ *
15
+ */
16
+ import { Awaitable } from "../types/types.js";
17
+ /** Function used to refresh a timed cache */
18
+ export type ProbeFunc<T> = () => Awaitable<T>;
19
+ type HandlerFunc<T> = (error?: Error, value?: T) => void;
20
+ /** Constructor parameters for `TimeCache` */
21
+ interface TimeCacheCtor<T> {
22
+ /** Function used to refresh the cached value */
23
+ probeFunc: ProbeFunc<T>;
24
+ /** Duration of the cached result, in ms */
25
+ cacheDurationMs: number;
26
+ /**
27
+ * Set to true to refresh (call the probe function) automatically, even if the value isn't read.
28
+ *
29
+ * When false (the default), the probe function will only be called as a result of querying the
30
+ * cached value outside of its cache duration.
31
+ */
32
+ autoProbe: boolean;
33
+ }
34
+ /**
35
+ * Remember a value for the specified amount of time, and reprobe it when needed.
36
+ *
37
+ * This support automatic probing over time and update callbacks.
38
+ *
39
+ * @public
40
+ */
41
+ export default class TimeCache<T> {
42
+ #private;
43
+ constructor(params: TimeCacheCtor<T>);
44
+ get value(): Promise<T>;
45
+ get autoProbe(): boolean;
46
+ set autoProbe(value: boolean);
47
+ /**
48
+ * Setup a callback triggered when the value is updated.
49
+ *
50
+ * When auto-update is disabled, these handler still get called when the value is manually probed.
51
+ */
52
+ onUpdate: (handler: HandlerFunc<T>) => void;
53
+ /**
54
+ * Remove a callback previously registered with `onUpdate()`.
55
+ */
56
+ offUpdate: (handler: HandlerFunc<T>) => void;
57
+ }
58
+ export {};
@@ -0,0 +1,118 @@
1
+ /**
2
+ * @license
3
+ * @preserve
4
+ *
5
+ * MIT License
6
+ *
7
+ * Copyright (c) 2023 KeeeX SAS
8
+ *
9
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14
+ *
15
+ */
16
+ import { asError } from "../error.js";
17
+ /**
18
+ * Remember a value for the specified amount of time, and reprobe it when needed.
19
+ *
20
+ * This support automatic probing over time and update callbacks.
21
+ *
22
+ * @public
23
+ */
24
+ export default class TimeCache {
25
+ #probeFunction;
26
+ #cacheDurationMs;
27
+ #autoProbe;
28
+ #loadedPromise;
29
+ #lastRefreshTime;
30
+ #nextRefreshTimeout;
31
+ #updateHandlers = [];
32
+ constructor(params) {
33
+ this.#probeFunction = params.probeFunc;
34
+ this.#cacheDurationMs = params.cacheDurationMs;
35
+ this.#autoProbe = params.autoProbe;
36
+ if (this.#autoProbe)
37
+ this.#probeTime();
38
+ }
39
+ get value() {
40
+ if (!this.#autoProbe)
41
+ this.#manualRefresh();
42
+ if (!this.#loadedPromise)
43
+ throw new Error("Unexpected state");
44
+ return this.#loadedPromise;
45
+ }
46
+ get autoProbe() {
47
+ return this.#autoProbe;
48
+ }
49
+ set autoProbe(value) {
50
+ if (this.#autoProbe === value)
51
+ return;
52
+ this.#autoProbe = value;
53
+ if (this.#autoProbe) {
54
+ this.#armAutoProbe();
55
+ }
56
+ else if (this.#nextRefreshTimeout) {
57
+ clearTimeout(this.#nextRefreshTimeout);
58
+ this.#nextRefreshTimeout = undefined;
59
+ }
60
+ }
61
+ /**
62
+ * Setup a callback triggered when the value is updated.
63
+ *
64
+ * When auto-update is disabled, these handler still get called when the value is manually probed.
65
+ */
66
+ onUpdate = (handler) => {
67
+ this.#updateHandlers.push(handler);
68
+ };
69
+ /**
70
+ * Remove a callback previously registered with `onUpdate()`.
71
+ */
72
+ offUpdate = (handler) => {
73
+ const id = this.#updateHandlers.lastIndexOf(handler);
74
+ if (id !== -1)
75
+ this.#updateHandlers.splice(id, 1);
76
+ };
77
+ /** Helper to setup #loadedPromise */
78
+ #callProbeFunction = async () => {
79
+ try {
80
+ const res = await this.#probeFunction();
81
+ this.#callHandler(undefined, res);
82
+ return res;
83
+ }
84
+ catch (e) {
85
+ this.#callHandler(asError(e));
86
+ throw e;
87
+ }
88
+ };
89
+ #callHandler = (error, value) => {
90
+ for (const handler of this.#updateHandlers)
91
+ handler(error, value);
92
+ };
93
+ /** Refresh the value */
94
+ #probeTime = () => {
95
+ this.#nextRefreshTimeout = undefined;
96
+ this.#loadedPromise = this.#callProbeFunction();
97
+ this.#lastRefreshTime = Date.now();
98
+ if (this.#autoProbe)
99
+ this.#armAutoProbe();
100
+ };
101
+ /** Setup the auto probe */
102
+ #armAutoProbe = () => {
103
+ if (this.#nextRefreshTimeout)
104
+ clearTimeout(this.#nextRefreshTimeout);
105
+ const remainingTime = this.#getRemainingTime();
106
+ this.#nextRefreshTimeout = setTimeout(this.#probeTime, remainingTime);
107
+ };
108
+ /** Return the remaining time before the next refresh (minimum 0) */
109
+ #getRemainingTime = () => {
110
+ const now = Date.now();
111
+ const nextRefresh = (this.#lastRefreshTime ?? Date.now()) + this.#cacheDurationMs;
112
+ return Math.max(0, nextRefresh - now);
113
+ };
114
+ #manualRefresh = () => {
115
+ if (this.#getRemainingTime() === 0 || !this.#loadedPromise)
116
+ this.#probeTime();
117
+ };
118
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @license
3
+ * @preserve
4
+ *
5
+ * MIT License
6
+ *
7
+ * Copyright (c) 2023 KeeeX SAS
8
+ *
9
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12
+ *
13
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14
+ *
15
+ */
16
+ /** @public */
17
+ export declare const encode: (data: Uint8Array) => string;
18
+ /** @public */
19
+ export declare const decode: (b58: string) => Uint8Array;
20
+ /**
21
+ * Encode a buf8 with base58.
22
+ *
23
+ * The output is padded accordingly to always accomodate a buffer of the full length of the input.
24
+ *
25
+ * @public
26
+ */
27
+ export declare const encodePad: (data: Uint8Array) => string;