@ariestools/threads 8.0.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.
Files changed (209) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +946 -0
  3. package/dist/browser/common.d.ts +22 -0
  4. package/dist/browser/common.d.ts.map +1 -0
  5. package/dist/browser/index-browser.d.ts +9 -0
  6. package/dist/browser/index-browser.d.ts.map +1 -0
  7. package/dist/browser/index-browser.mjs +844 -0
  8. package/dist/browser/index-browser.mjs.map +7 -0
  9. package/dist/browser/index-node.d.ts +9 -0
  10. package/dist/browser/index-node.d.ts.map +1 -0
  11. package/dist/browser/isObservable.d.ts +2 -0
  12. package/dist/browser/isObservable.d.ts.map +1 -0
  13. package/dist/browser/master/get-bundle-url.browser.d.ts +4 -0
  14. package/dist/browser/master/get-bundle-url.browser.d.ts.map +1 -0
  15. package/dist/browser/master/implementation.browser.d.ts +14 -0
  16. package/dist/browser/master/implementation.browser.d.ts.map +1 -0
  17. package/dist/browser/master/implementation.browser.mjs +90 -0
  18. package/dist/browser/master/implementation.browser.mjs.map +7 -0
  19. package/dist/browser/master/implementation.node.d.ts +14 -0
  20. package/dist/browser/master/implementation.node.d.ts.map +1 -0
  21. package/dist/browser/master/index-browser.d.ts +13 -0
  22. package/dist/browser/master/index-browser.d.ts.map +1 -0
  23. package/dist/browser/master/index-browser.mjs +813 -0
  24. package/dist/browser/master/index-browser.mjs.map +7 -0
  25. package/dist/browser/master/index-node.d.ts +13 -0
  26. package/dist/browser/master/index-node.d.ts.map +1 -0
  27. package/dist/browser/master/invocation-proxy.d.ts +16 -0
  28. package/dist/browser/master/invocation-proxy.d.ts.map +1 -0
  29. package/dist/browser/master/pool-browser.d.ts +93 -0
  30. package/dist/browser/master/pool-browser.d.ts.map +1 -0
  31. package/dist/browser/master/pool-browser.mjs +308 -0
  32. package/dist/browser/master/pool-browser.mjs.map +7 -0
  33. package/dist/browser/master/pool-node.d.ts +93 -0
  34. package/dist/browser/master/pool-node.d.ts.map +1 -0
  35. package/dist/browser/master/pool-types.d.ts +68 -0
  36. package/dist/browser/master/pool-types.d.ts.map +1 -0
  37. package/dist/browser/master/register.d.ts +2 -0
  38. package/dist/browser/master/register.d.ts.map +1 -0
  39. package/dist/browser/master/spawn.d.ts +22 -0
  40. package/dist/browser/master/spawn.d.ts.map +1 -0
  41. package/dist/browser/master/thread.d.ts +14 -0
  42. package/dist/browser/master/thread.d.ts.map +1 -0
  43. package/dist/browser/observable-promise.d.ts +41 -0
  44. package/dist/browser/observable-promise.d.ts.map +1 -0
  45. package/dist/browser/observable.d.ts +24 -0
  46. package/dist/browser/observable.d.ts.map +1 -0
  47. package/dist/browser/promise.d.ts +6 -0
  48. package/dist/browser/promise.d.ts.map +1 -0
  49. package/dist/browser/serializers.d.ts +27 -0
  50. package/dist/browser/serializers.d.ts.map +1 -0
  51. package/dist/browser/symbols.d.ts +11 -0
  52. package/dist/browser/symbols.d.ts.map +1 -0
  53. package/dist/browser/transferable.d.ts +49 -0
  54. package/dist/browser/transferable.d.ts.map +1 -0
  55. package/dist/browser/types/master.d.ts +111 -0
  56. package/dist/browser/types/master.d.ts.map +1 -0
  57. package/dist/browser/types/messages.d.ts +71 -0
  58. package/dist/browser/types/messages.d.ts.map +1 -0
  59. package/dist/browser/types/worker.d.ts +13 -0
  60. package/dist/browser/types/worker.d.ts.map +1 -0
  61. package/dist/browser/worker/WorkerGlobalScope.d.ts +7 -0
  62. package/dist/browser/worker/WorkerGlobalScope.d.ts.map +1 -0
  63. package/dist/browser/worker/expose.d.ts +10 -0
  64. package/dist/browser/worker/expose.d.ts.map +1 -0
  65. package/dist/browser/worker/worker.browser.d.ts +20 -0
  66. package/dist/browser/worker/worker.browser.d.ts.map +1 -0
  67. package/dist/browser/worker/worker.browser.mjs +300 -0
  68. package/dist/browser/worker/worker.browser.mjs.map +7 -0
  69. package/dist/browser/worker/worker.node.d.ts +34 -0
  70. package/dist/browser/worker/worker.node.d.ts.map +1 -0
  71. package/dist/neutral/common.d.ts +22 -0
  72. package/dist/neutral/common.d.ts.map +1 -0
  73. package/dist/neutral/index-browser.d.ts +9 -0
  74. package/dist/neutral/index-browser.d.ts.map +1 -0
  75. package/dist/neutral/index-node.d.ts +9 -0
  76. package/dist/neutral/index-node.d.ts.map +1 -0
  77. package/dist/neutral/isObservable.d.ts +2 -0
  78. package/dist/neutral/isObservable.d.ts.map +1 -0
  79. package/dist/neutral/master/get-bundle-url.browser.d.ts +4 -0
  80. package/dist/neutral/master/get-bundle-url.browser.d.ts.map +1 -0
  81. package/dist/neutral/master/implementation.browser.d.ts +14 -0
  82. package/dist/neutral/master/implementation.browser.d.ts.map +1 -0
  83. package/dist/neutral/master/implementation.node.d.ts +14 -0
  84. package/dist/neutral/master/implementation.node.d.ts.map +1 -0
  85. package/dist/neutral/master/index-browser.d.ts +13 -0
  86. package/dist/neutral/master/index-browser.d.ts.map +1 -0
  87. package/dist/neutral/master/index-node.d.ts +13 -0
  88. package/dist/neutral/master/index-node.d.ts.map +1 -0
  89. package/dist/neutral/master/invocation-proxy.d.ts +16 -0
  90. package/dist/neutral/master/invocation-proxy.d.ts.map +1 -0
  91. package/dist/neutral/master/pool-browser.d.ts +93 -0
  92. package/dist/neutral/master/pool-browser.d.ts.map +1 -0
  93. package/dist/neutral/master/pool-node.d.ts +93 -0
  94. package/dist/neutral/master/pool-node.d.ts.map +1 -0
  95. package/dist/neutral/master/pool-types.d.ts +68 -0
  96. package/dist/neutral/master/pool-types.d.ts.map +1 -0
  97. package/dist/neutral/master/register.d.ts +2 -0
  98. package/dist/neutral/master/register.d.ts.map +1 -0
  99. package/dist/neutral/master/spawn.d.ts +22 -0
  100. package/dist/neutral/master/spawn.d.ts.map +1 -0
  101. package/dist/neutral/master/spawn.mjs +424 -0
  102. package/dist/neutral/master/spawn.mjs.map +7 -0
  103. package/dist/neutral/master/thread.d.ts +14 -0
  104. package/dist/neutral/master/thread.d.ts.map +1 -0
  105. package/dist/neutral/master/thread.mjs +24 -0
  106. package/dist/neutral/master/thread.mjs.map +7 -0
  107. package/dist/neutral/observable-promise.d.ts +41 -0
  108. package/dist/neutral/observable-promise.d.ts.map +1 -0
  109. package/dist/neutral/observable-promise.mjs +142 -0
  110. package/dist/neutral/observable-promise.mjs.map +7 -0
  111. package/dist/neutral/observable.d.ts +24 -0
  112. package/dist/neutral/observable.d.ts.map +1 -0
  113. package/dist/neutral/observable.mjs +32 -0
  114. package/dist/neutral/observable.mjs.map +7 -0
  115. package/dist/neutral/promise.d.ts +6 -0
  116. package/dist/neutral/promise.d.ts.map +1 -0
  117. package/dist/neutral/serializers.d.ts +27 -0
  118. package/dist/neutral/serializers.d.ts.map +1 -0
  119. package/dist/neutral/symbols.d.ts +11 -0
  120. package/dist/neutral/symbols.d.ts.map +1 -0
  121. package/dist/neutral/transferable.d.ts +49 -0
  122. package/dist/neutral/transferable.d.ts.map +1 -0
  123. package/dist/neutral/types/master.d.ts +111 -0
  124. package/dist/neutral/types/master.d.ts.map +1 -0
  125. package/dist/neutral/types/messages.d.ts +71 -0
  126. package/dist/neutral/types/messages.d.ts.map +1 -0
  127. package/dist/neutral/types/messages.mjs +19 -0
  128. package/dist/neutral/types/messages.mjs.map +7 -0
  129. package/dist/neutral/types/worker.d.ts +13 -0
  130. package/dist/neutral/types/worker.d.ts.map +1 -0
  131. package/dist/neutral/worker/WorkerGlobalScope.d.ts +7 -0
  132. package/dist/neutral/worker/WorkerGlobalScope.d.ts.map +1 -0
  133. package/dist/neutral/worker/expose.d.ts +10 -0
  134. package/dist/neutral/worker/expose.d.ts.map +1 -0
  135. package/dist/neutral/worker/worker.browser.d.ts +20 -0
  136. package/dist/neutral/worker/worker.browser.d.ts.map +1 -0
  137. package/dist/neutral/worker/worker.node.d.ts +34 -0
  138. package/dist/neutral/worker/worker.node.d.ts.map +1 -0
  139. package/dist/node/common.d.ts +22 -0
  140. package/dist/node/common.d.ts.map +1 -0
  141. package/dist/node/index-browser.d.ts +9 -0
  142. package/dist/node/index-browser.d.ts.map +1 -0
  143. package/dist/node/index-node.d.ts +9 -0
  144. package/dist/node/index-node.d.ts.map +1 -0
  145. package/dist/node/index-node.mjs +839 -0
  146. package/dist/node/index-node.mjs.map +7 -0
  147. package/dist/node/isObservable.d.ts +2 -0
  148. package/dist/node/isObservable.d.ts.map +1 -0
  149. package/dist/node/master/get-bundle-url.browser.d.ts +4 -0
  150. package/dist/node/master/get-bundle-url.browser.d.ts.map +1 -0
  151. package/dist/node/master/implementation.browser.d.ts +14 -0
  152. package/dist/node/master/implementation.browser.d.ts.map +1 -0
  153. package/dist/node/master/implementation.node.d.ts +14 -0
  154. package/dist/node/master/implementation.node.d.ts.map +1 -0
  155. package/dist/node/master/implementation.node.mjs +82 -0
  156. package/dist/node/master/implementation.node.mjs.map +7 -0
  157. package/dist/node/master/index-browser.d.ts +13 -0
  158. package/dist/node/master/index-browser.d.ts.map +1 -0
  159. package/dist/node/master/index-node.d.ts +13 -0
  160. package/dist/node/master/index-node.d.ts.map +1 -0
  161. package/dist/node/master/index-node.mjs +808 -0
  162. package/dist/node/master/index-node.mjs.map +7 -0
  163. package/dist/node/master/invocation-proxy.d.ts +16 -0
  164. package/dist/node/master/invocation-proxy.d.ts.map +1 -0
  165. package/dist/node/master/pool-browser.d.ts +93 -0
  166. package/dist/node/master/pool-browser.d.ts.map +1 -0
  167. package/dist/node/master/pool-node.d.ts +93 -0
  168. package/dist/node/master/pool-node.d.ts.map +1 -0
  169. package/dist/node/master/pool-node.mjs +309 -0
  170. package/dist/node/master/pool-node.mjs.map +7 -0
  171. package/dist/node/master/pool-types.d.ts +68 -0
  172. package/dist/node/master/pool-types.d.ts.map +1 -0
  173. package/dist/node/master/register.d.ts +2 -0
  174. package/dist/node/master/register.d.ts.map +1 -0
  175. package/dist/node/master/register.mjs +87 -0
  176. package/dist/node/master/register.mjs.map +7 -0
  177. package/dist/node/master/spawn.d.ts +22 -0
  178. package/dist/node/master/spawn.d.ts.map +1 -0
  179. package/dist/node/master/thread.d.ts +14 -0
  180. package/dist/node/master/thread.d.ts.map +1 -0
  181. package/dist/node/observable-promise.d.ts +41 -0
  182. package/dist/node/observable-promise.d.ts.map +1 -0
  183. package/dist/node/observable.d.ts +24 -0
  184. package/dist/node/observable.d.ts.map +1 -0
  185. package/dist/node/promise.d.ts +6 -0
  186. package/dist/node/promise.d.ts.map +1 -0
  187. package/dist/node/serializers.d.ts +27 -0
  188. package/dist/node/serializers.d.ts.map +1 -0
  189. package/dist/node/symbols.d.ts +11 -0
  190. package/dist/node/symbols.d.ts.map +1 -0
  191. package/dist/node/transferable.d.ts +49 -0
  192. package/dist/node/transferable.d.ts.map +1 -0
  193. package/dist/node/types/master.d.ts +111 -0
  194. package/dist/node/types/master.d.ts.map +1 -0
  195. package/dist/node/types/messages.d.ts +71 -0
  196. package/dist/node/types/messages.d.ts.map +1 -0
  197. package/dist/node/types/worker.d.ts +13 -0
  198. package/dist/node/types/worker.d.ts.map +1 -0
  199. package/dist/node/worker/WorkerGlobalScope.d.ts +7 -0
  200. package/dist/node/worker/WorkerGlobalScope.d.ts.map +1 -0
  201. package/dist/node/worker/expose.d.ts +10 -0
  202. package/dist/node/worker/expose.d.ts.map +1 -0
  203. package/dist/node/worker/worker.browser.d.ts +20 -0
  204. package/dist/node/worker/worker.browser.d.ts.map +1 -0
  205. package/dist/node/worker/worker.node.d.ts +34 -0
  206. package/dist/node/worker/worker.node.d.ts.map +1 -0
  207. package/dist/node/worker/worker.node.mjs +313 -0
  208. package/dist/node/worker/worker.node.mjs.map +7 -0
  209. package/package.json +147 -0
@@ -0,0 +1,309 @@
1
+ // src/master/pool-node.ts
2
+ import DebugLogger from "debug";
3
+ import {
4
+ multicast,
5
+ Observable,
6
+ Subject
7
+ } from "observable-fns";
8
+
9
+ // src/master/implementation.node.ts
10
+ import { cpus } from "node:os";
11
+ var defaultPoolSize = cpus().length;
12
+
13
+ // src/master/pool-types.ts
14
+ var PoolEventType = /* @__PURE__ */ ((PoolEventType2) => {
15
+ PoolEventType2["initialized"] = "initialized";
16
+ PoolEventType2["taskCanceled"] = "taskCanceled";
17
+ PoolEventType2["taskCompleted"] = "taskCompleted";
18
+ PoolEventType2["taskFailed"] = "taskFailed";
19
+ PoolEventType2["taskQueued"] = "taskQueued";
20
+ PoolEventType2["taskQueueDrained"] = "taskQueueDrained";
21
+ PoolEventType2["taskStart"] = "taskStart";
22
+ PoolEventType2["terminated"] = "terminated";
23
+ return PoolEventType2;
24
+ })(PoolEventType || {});
25
+
26
+ // src/symbols.ts
27
+ var $errors = /* @__PURE__ */ Symbol("thread.errors");
28
+ var $events = /* @__PURE__ */ Symbol("thread.events");
29
+ var $terminate = /* @__PURE__ */ Symbol("thread.terminate");
30
+
31
+ // src/master/thread.ts
32
+ function fail(message) {
33
+ throw new Error(message);
34
+ }
35
+ function readPrivateThreadProp(thread, key) {
36
+ return Reflect.get(thread, key);
37
+ }
38
+ var Thread = {
39
+ /** Return an observable that can be used to subscribe to all errors happening in the thread. */
40
+ errors: (thread) => readPrivateThreadProp(thread, $errors) ?? fail("Error observable not found. Make sure to pass a thread instance as returned by the spawn() promise."),
41
+ /** Return an observable that can be used to subscribe to internal events happening in the thread. Useful for debugging. */
42
+ events: (thread) => readPrivateThreadProp(thread, $events) ?? fail("Events observable not found. Make sure to pass a thread instance as returned by the spawn() promise."),
43
+ /** Terminate a thread. Remember to terminate every thread when you are done using it. */
44
+ terminate: (thread) => readPrivateThreadProp(thread, $terminate)?.() ?? fail("Terminate function not found. Make sure to pass a thread instance as returned by the spawn() promise.")
45
+ };
46
+
47
+ // src/master/pool-node.ts
48
+ var nextPoolID = 1;
49
+ function createArray(size) {
50
+ const array = [];
51
+ for (let index = 0; index < size; index++) {
52
+ array.push(index);
53
+ }
54
+ return array;
55
+ }
56
+ function delay(ms) {
57
+ return new Promise((resolve) => setTimeout(resolve, ms));
58
+ }
59
+ function flatMap(array, mapper) {
60
+ return array.reduce((flattened, element) => [...flattened, ...mapper(element)], []);
61
+ }
62
+ function slugify(text) {
63
+ return text.replaceAll(/\W/g, " ").trim().replaceAll(/\s+/g, "-");
64
+ }
65
+ function spawnWorkers(spawnWorker, count) {
66
+ return createArray(count).map(
67
+ () => ({
68
+ init: spawnWorker(),
69
+ runningTasks: []
70
+ })
71
+ );
72
+ }
73
+ var WorkerPool = class {
74
+ static EventType = PoolEventType;
75
+ debug;
76
+ eventObservable;
77
+ options;
78
+ workers;
79
+ eventSubject = new Subject();
80
+ initErrors = [];
81
+ isClosing = false;
82
+ nextTaskID = 1;
83
+ taskQueue = [];
84
+ constructor(spawnWorker, optionsOrSize) {
85
+ const options = typeof optionsOrSize === "number" ? { size: optionsOrSize } : optionsOrSize || {};
86
+ const { size = defaultPoolSize } = options;
87
+ this.debug = DebugLogger(`threads:pool:${slugify(options.name ?? String(nextPoolID++))}`);
88
+ this.options = options;
89
+ this.workers = spawnWorkers(spawnWorker, size);
90
+ this.eventObservable = multicast(Observable.from(this.eventSubject));
91
+ const debug = this.debug;
92
+ const workers = this.workers;
93
+ void (async () => {
94
+ try {
95
+ await Promise.all(workers.map((worker) => worker.init));
96
+ this.eventSubject.next({
97
+ size: workers.length,
98
+ type: "initialized" /* initialized */
99
+ });
100
+ } catch (error) {
101
+ const initError = error instanceof Error ? error : new Error(String(error));
102
+ debug("Error while initializing pool worker:", initError);
103
+ this.eventSubject.error(initError);
104
+ this.initErrors.push(initError);
105
+ }
106
+ })();
107
+ }
108
+ findIdlingWorker() {
109
+ const { concurrency = 1 } = this.options;
110
+ return this.workers.find((worker) => worker.runningTasks.length < concurrency);
111
+ }
112
+ async runPoolTask(worker, task) {
113
+ const workerID = this.workers.indexOf(worker) + 1;
114
+ this.debug(`Running task #${task.id} on worker #${workerID}...`);
115
+ this.eventSubject.next({
116
+ taskID: task.id,
117
+ type: "taskStart" /* taskStart */,
118
+ workerID
119
+ });
120
+ try {
121
+ const returnValue = await task.run(await worker.init);
122
+ this.debug(`Task #${task.id} completed successfully`);
123
+ this.eventSubject.next({
124
+ returnValue,
125
+ taskID: task.id,
126
+ type: "taskCompleted" /* taskCompleted */,
127
+ workerID
128
+ });
129
+ } catch (ex) {
130
+ const error = ex;
131
+ this.debug(`Task #${task.id} failed`);
132
+ this.eventSubject.next({
133
+ error,
134
+ taskID: task.id,
135
+ type: "taskFailed" /* taskFailed */,
136
+ workerID
137
+ });
138
+ }
139
+ }
140
+ run(worker, task) {
141
+ const runPromise = (async () => {
142
+ const removeTaskFromWorkersRunningTasks = () => {
143
+ worker.runningTasks = worker.runningTasks.filter((someRunPromise) => someRunPromise !== runPromise);
144
+ };
145
+ await delay(0);
146
+ try {
147
+ await this.runPoolTask(worker, task);
148
+ } finally {
149
+ removeTaskFromWorkersRunningTasks();
150
+ if (!this.isClosing) {
151
+ this.scheduleWork();
152
+ }
153
+ }
154
+ })();
155
+ worker.runningTasks.push(runPromise);
156
+ }
157
+ scheduleWork() {
158
+ this.debug("Attempt de-queueing a task in order to run it...");
159
+ const availableWorker = this.findIdlingWorker();
160
+ if (!availableWorker) return;
161
+ const nextTask = this.taskQueue.shift();
162
+ if (!nextTask) {
163
+ this.debug("Task queue is empty");
164
+ this.eventSubject.next({ type: "taskQueueDrained" /* taskQueueDrained */ });
165
+ return;
166
+ }
167
+ this.run(availableWorker, nextTask);
168
+ }
169
+ taskCompletion(taskID) {
170
+ return new Promise((resolve, reject) => {
171
+ const eventSubscription = this.events().subscribe((event) => {
172
+ if (event.type === "taskCompleted" /* taskCompleted */ && event.taskID === taskID) {
173
+ eventSubscription.unsubscribe();
174
+ resolve(event.returnValue);
175
+ } else if (event.type === "taskFailed" /* taskFailed */ && event.taskID === taskID) {
176
+ eventSubscription.unsubscribe();
177
+ reject(event.error);
178
+ } else if (event.type === "terminated" /* terminated */) {
179
+ eventSubscription.unsubscribe();
180
+ reject(new Error("Pool has been terminated before task was run."));
181
+ }
182
+ });
183
+ });
184
+ }
185
+ async settled(allowResolvingImmediately = false) {
186
+ if (this.initErrors.length > 0) {
187
+ throw this.initErrors[0];
188
+ }
189
+ if (allowResolvingImmediately && this.taskQueue.length === 0) {
190
+ await Promise.allSettled(flatMap(this.workers, (worker) => worker.runningTasks));
191
+ return [];
192
+ }
193
+ const getCurrentlyRunningTasks = () => flatMap(this.workers, (worker) => worker.runningTasks);
194
+ const taskFailures = [];
195
+ const failureSubscription = this.eventObservable.subscribe((event) => {
196
+ if (event.type === "taskFailed" /* taskFailed */) {
197
+ taskFailures.push(event.error);
198
+ }
199
+ });
200
+ await new Promise((resolve, reject) => {
201
+ const subscription = this.eventObservable.subscribe({
202
+ error: reject,
203
+ next(event) {
204
+ if (event.type !== "taskQueueDrained" /* taskQueueDrained */) {
205
+ return;
206
+ }
207
+ subscription.unsubscribe();
208
+ resolve(void 0);
209
+ }
210
+ // make a pool-wide error reject the completed() result promise
211
+ });
212
+ });
213
+ await Promise.allSettled(getCurrentlyRunningTasks());
214
+ failureSubscription.unsubscribe();
215
+ return taskFailures;
216
+ }
217
+ async completed(allowResolvingImmediately = false) {
218
+ const settlementPromise = this.settled(allowResolvingImmediately);
219
+ const earlyExitPromise = new Promise((resolve, reject) => {
220
+ const subscription = this.eventObservable.subscribe({
221
+ error: reject,
222
+ next(event) {
223
+ if (event.type === "taskQueueDrained" /* taskQueueDrained */) {
224
+ subscription.unsubscribe();
225
+ resolve(settlementPromise);
226
+ } else if (event.type === "taskFailed" /* taskFailed */) {
227
+ subscription.unsubscribe();
228
+ reject(event.error);
229
+ }
230
+ }
231
+ // make a pool-wide error reject the completed() result promise
232
+ });
233
+ });
234
+ const errors = await Promise.race([settlementPromise, earlyExitPromise]);
235
+ if (errors.length > 0) {
236
+ throw errors[0];
237
+ }
238
+ }
239
+ events() {
240
+ return this.eventObservable;
241
+ }
242
+ queue(taskFunction) {
243
+ const { maxQueuedJobs = Infinity } = this.options;
244
+ if (this.isClosing) {
245
+ throw new Error("Cannot schedule pool tasks after terminate() has been called.");
246
+ }
247
+ if (this.initErrors.length > 0) {
248
+ throw this.initErrors[0];
249
+ }
250
+ const taskID = this.nextTaskID++;
251
+ const taskCompletion = this.taskCompletion(taskID);
252
+ void (async () => {
253
+ try {
254
+ await taskCompletion;
255
+ } catch (error) {
256
+ this.debug(`Task #${taskID} errored:`, error);
257
+ }
258
+ })();
259
+ const task = {
260
+ cancel: () => {
261
+ if (!this.taskQueue.includes(task)) return;
262
+ this.taskQueue = this.taskQueue.filter((someTask) => someTask !== task);
263
+ this.eventSubject.next({
264
+ taskID: task.id,
265
+ type: "taskCanceled" /* taskCanceled */
266
+ });
267
+ },
268
+ id: taskID,
269
+ run: taskFunction,
270
+ then: taskCompletion.then.bind(taskCompletion)
271
+ };
272
+ if (this.taskQueue.length >= maxQueuedJobs) {
273
+ throw new Error(
274
+ "Maximum number of pool tasks queued. Refusing to queue another one.\nThis usually happens for one of two reasons: We are either at peak workload right now or some tasks just won't finish, thus blocking the pool."
275
+ );
276
+ }
277
+ this.debug(`Queueing task #${task.id}...`);
278
+ this.taskQueue.push(task);
279
+ this.eventSubject.next({
280
+ taskID: task.id,
281
+ type: "taskQueued" /* taskQueued */
282
+ });
283
+ this.scheduleWork();
284
+ return task;
285
+ }
286
+ async terminate(force) {
287
+ this.isClosing = true;
288
+ if (force !== true) {
289
+ await this.completed(true);
290
+ }
291
+ this.eventSubject.next({
292
+ remainingQueue: [...this.taskQueue],
293
+ type: "terminated" /* terminated */
294
+ });
295
+ this.eventSubject.complete();
296
+ await Promise.all(this.workers.map(async (worker) => Thread.terminate(await worker.init)));
297
+ }
298
+ };
299
+ function PoolConstructor(spawnWorker, optionsOrSize) {
300
+ return new WorkerPool(spawnWorker, optionsOrSize);
301
+ }
302
+ PoolConstructor.EventType = PoolEventType;
303
+ var Pool = PoolConstructor;
304
+ export {
305
+ Pool,
306
+ PoolEventType,
307
+ Thread
308
+ };
309
+ //# sourceMappingURL=pool-node.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/master/pool-node.ts", "../../../src/master/implementation.node.ts", "../../../src/master/pool-types.ts", "../../../src/symbols.ts", "../../../src/master/thread.ts"],
4
+ "sourcesContent": ["/* eslint-disable import-x/export */\n/* eslint-disable unicorn/no-thenable */\n\n/* eslint-disable @typescript-eslint/member-ordering */\n/* eslint-disable unicorn/no-array-reduce */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-namespace */\n\n/// <reference lib=\"esnext\" />\n\nimport DebugLogger from 'debug'\nimport {\n multicast, Observable, Subject,\n} from 'observable-fns'\n\nimport { defaultPoolSize } from './implementation.node.ts'\nimport type {\n PoolEvent, QueuedTask, TaskRunFunction, WorkerDescriptor,\n} from './pool-types.ts'\nimport { PoolEventType } from './pool-types.ts'\nimport { Thread } from './thread.ts'\n\nexport declare namespace Pool {\n type Event<ThreadType extends Thread = any> = PoolEvent<ThreadType>\n type EventType = PoolEventType\n}\n\nlet nextPoolID = 1\n\nfunction createArray(size: number): number[] {\n const array: number[] = []\n for (let index = 0; index < size; index++) {\n array.push(index)\n }\n return array\n}\n\nfunction delay(ms: number) {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\nfunction flatMap<In, Out>(array: In[], mapper: (element: In) => Out[]): Out[] {\n return array.reduce<Out[]>((flattened, element) => [...flattened, ...mapper(element)], [])\n}\n\nfunction slugify(text: string) {\n return text.replaceAll(/\\W/g, ' ').trim().replaceAll(/\\s+/g, '-')\n}\n\nfunction spawnWorkers<ThreadType extends Thread>(spawnWorker: () => Promise<ThreadType>, count: number): WorkerDescriptor<ThreadType>[] {\n return createArray(count).map(\n (): WorkerDescriptor<ThreadType> => ({\n init: spawnWorker(),\n runningTasks: [],\n }),\n )\n}\n\n/**\n * Thread pool managing a set of worker threads.\n * Use it to queue tasks that are run on those threads with limited\n * concurrency.\n */\nexport interface Pool<ThreadType extends Thread> {\n /**\n * Returns a promise that resolves once the task queue is emptied.\n * Promise will be rejected if any task fails.\n *\n * @param allowResolvingImmediately Set to `true` to resolve immediately if task queue is currently empty.\n */\n completed(allowResolvingImmediately?: boolean): Promise<any>\n\n /**\n * Returns a promise that resolves once the task queue is emptied.\n * Failing tasks will not cause the promise to be rejected.\n *\n * @param allowResolvingImmediately Set to `true` to resolve immediately if task queue is currently empty.\n */\n settled(allowResolvingImmediately?: boolean): Promise<Error[]>\n\n /**\n * Returns an observable that yields pool events.\n */\n events(): Observable<PoolEvent<ThreadType>>\n\n /**\n * Queue a task and return a promise that resolves once the task has been dequeued,\n * started and finished.\n *\n * @param task An async function that takes a thread instance and invokes it.\n */\n queue<Return>(task: TaskRunFunction<ThreadType, Return>): QueuedTask<ThreadType, Return>\n\n /**\n * Terminate all pool threads.\n *\n * @param force Set to `true` to kill the thread even if it cannot be stopped gracefully.\n */\n terminate(force?: boolean): Promise<void>\n}\n\ninterface PoolOptions {\n /** Maximum no. of tasks to run on one worker thread at a time. Defaults to one. */\n concurrency?: number\n\n /** Maximum no. of jobs to be queued for execution before throwing an error. */\n maxQueuedJobs?: number\n\n /** Gives that pool a name to be used for debug logging, letting you distinguish between log output of different pools. */\n name?: string\n\n /** No. of worker threads to spawn and to be managed by the pool. */\n size?: number\n}\n\nclass WorkerPool<ThreadType extends Thread> implements Pool<ThreadType> {\n static EventType = PoolEventType\n\n private readonly debug: DebugLogger.Debugger\n private readonly eventObservable: Observable<PoolEvent<ThreadType>>\n private readonly options: PoolOptions\n private readonly workers: WorkerDescriptor<ThreadType>[]\n\n private readonly eventSubject = new Subject<PoolEvent<ThreadType>>()\n private initErrors: Error[] = []\n private isClosing = false\n private nextTaskID = 1\n private taskQueue: QueuedTask<ThreadType, any>[] = []\n\n constructor(spawnWorker: () => Promise<ThreadType>, optionsOrSize?: number | PoolOptions) {\n const options: PoolOptions = typeof optionsOrSize === 'number' ? { size: optionsOrSize } : optionsOrSize || {}\n\n const { size = defaultPoolSize } = options\n\n this.debug = DebugLogger(`threads:pool:${slugify(options.name ?? String(nextPoolID++))}`)\n this.options = options\n this.workers = spawnWorkers(spawnWorker, size)\n\n this.eventObservable = multicast(Observable.from(this.eventSubject))\n\n const debug = this.debug\n const workers = this.workers\n void (async () => {\n try {\n await Promise.all(workers.map(worker => worker.init))\n this.eventSubject.next({\n size: workers.length,\n type: PoolEventType.initialized,\n })\n } catch (error) {\n const initError = error instanceof Error ? error : new Error(String(error))\n debug('Error while initializing pool worker:', initError)\n this.eventSubject.error(initError)\n this.initErrors.push(initError)\n }\n })()\n }\n\n private findIdlingWorker(): WorkerDescriptor<ThreadType> | undefined {\n const { concurrency = 1 } = this.options\n return this.workers.find(worker => worker.runningTasks.length < concurrency)\n }\n\n private async runPoolTask(worker: WorkerDescriptor<ThreadType>, task: QueuedTask<ThreadType, any>) {\n const workerID = this.workers.indexOf(worker) + 1\n\n this.debug(`Running task #${task.id} on worker #${workerID}...`)\n this.eventSubject.next({\n taskID: task.id,\n type: PoolEventType.taskStart,\n workerID,\n })\n\n try {\n const returnValue = await task.run(await worker.init)\n\n this.debug(`Task #${task.id} completed successfully`)\n this.eventSubject.next({\n returnValue,\n taskID: task.id,\n type: PoolEventType.taskCompleted,\n workerID,\n })\n } catch (ex) {\n const error = ex as Error\n this.debug(`Task #${task.id} failed`)\n this.eventSubject.next({\n error,\n taskID: task.id,\n type: PoolEventType.taskFailed,\n workerID,\n })\n }\n }\n\n private run(worker: WorkerDescriptor<ThreadType>, task: QueuedTask<ThreadType, any>) {\n const runPromise = (async () => {\n const removeTaskFromWorkersRunningTasks = () => {\n worker.runningTasks = worker.runningTasks.filter(someRunPromise => someRunPromise !== runPromise)\n }\n\n // Defer task execution by one tick to give handlers time to subscribe\n await delay(0)\n\n try {\n await this.runPoolTask(worker, task)\n } finally {\n removeTaskFromWorkersRunningTasks()\n\n if (!this.isClosing) {\n this.scheduleWork()\n }\n }\n })()\n\n worker.runningTasks.push(runPromise)\n }\n\n private scheduleWork() {\n this.debug('Attempt de-queueing a task in order to run it...')\n\n const availableWorker = this.findIdlingWorker()\n if (!availableWorker) return\n\n const nextTask = this.taskQueue.shift()\n if (!nextTask) {\n this.debug('Task queue is empty')\n this.eventSubject.next({ type: PoolEventType.taskQueueDrained })\n return\n }\n\n this.run(availableWorker, nextTask)\n }\n\n private taskCompletion(taskID: number) {\n return new Promise<any>((resolve, reject) => {\n const eventSubscription = this.events().subscribe((event) => {\n if (event.type === PoolEventType.taskCompleted && event.taskID === taskID) {\n eventSubscription.unsubscribe()\n resolve(event.returnValue)\n } else if (event.type === PoolEventType.taskFailed && event.taskID === taskID) {\n eventSubscription.unsubscribe()\n reject(event.error)\n } else if (event.type === PoolEventType.terminated) {\n eventSubscription.unsubscribe()\n reject(new Error('Pool has been terminated before task was run.'))\n }\n })\n })\n }\n\n async settled(allowResolvingImmediately = false): Promise<Error[]> {\n if (this.initErrors.length > 0) {\n throw this.initErrors[0]\n }\n if (allowResolvingImmediately && this.taskQueue.length === 0) {\n await Promise.allSettled(flatMap(this.workers, worker => worker.runningTasks))\n return []\n }\n\n const getCurrentlyRunningTasks = () => flatMap(this.workers, worker => worker.runningTasks)\n const taskFailures: Error[] = []\n\n const failureSubscription = this.eventObservable.subscribe((event) => {\n if (event.type === PoolEventType.taskFailed) {\n taskFailures.push(event.error)\n }\n })\n\n await new Promise<void>((resolve, reject) => {\n const subscription = this.eventObservable.subscribe({\n error: reject,\n next(event) {\n if (event.type !== PoolEventType.taskQueueDrained) {\n return\n }\n\n subscription.unsubscribe()\n resolve(void 0)\n }, // make a pool-wide error reject the completed() result promise\n })\n })\n\n await Promise.allSettled(getCurrentlyRunningTasks())\n failureSubscription.unsubscribe()\n\n return taskFailures\n }\n\n async completed(allowResolvingImmediately = false) {\n const settlementPromise = this.settled(allowResolvingImmediately)\n\n const earlyExitPromise = new Promise<Error[]>((resolve, reject) => {\n const subscription = this.eventObservable.subscribe({\n error: reject,\n next(event) {\n if (event.type === PoolEventType.taskQueueDrained) {\n subscription.unsubscribe()\n resolve(settlementPromise)\n } else if (event.type === PoolEventType.taskFailed) {\n subscription.unsubscribe()\n reject(event.error)\n }\n }, // make a pool-wide error reject the completed() result promise\n })\n })\n\n const errors = await Promise.race([settlementPromise, earlyExitPromise])\n\n if (errors.length > 0) {\n throw errors[0]\n }\n }\n\n events() {\n return this.eventObservable\n }\n\n queue(taskFunction: TaskRunFunction<ThreadType, any>) {\n const { maxQueuedJobs = Infinity } = this.options\n\n if (this.isClosing) {\n throw new Error('Cannot schedule pool tasks after terminate() has been called.')\n }\n if (this.initErrors.length > 0) {\n throw this.initErrors[0]\n }\n\n const taskID = this.nextTaskID++\n const taskCompletion = this.taskCompletion(taskID)\n\n void (async () => {\n try {\n await taskCompletion\n } catch (error) {\n // Prevent unhandled rejections here as we assume the user will use\n // `pool.completed()`, `pool.settled()` or `task.catch()` to handle errors\n this.debug(`Task #${taskID} errored:`, error)\n }\n })()\n\n const task: QueuedTask<ThreadType, any> = {\n cancel: () => {\n if (!this.taskQueue.includes(task)) return\n this.taskQueue = this.taskQueue.filter(someTask => someTask !== task)\n this.eventSubject.next({\n taskID: task.id,\n type: PoolEventType.taskCanceled,\n })\n },\n id: taskID,\n run: taskFunction,\n then: taskCompletion.then.bind(taskCompletion),\n }\n\n if (this.taskQueue.length >= maxQueuedJobs) {\n throw new Error(\n 'Maximum number of pool tasks queued. Refusing to queue another one.\\n'\n + 'This usually happens for one of two reasons: We are either at peak '\n + \"workload right now or some tasks just won't finish, thus blocking the pool.\",\n )\n }\n\n this.debug(`Queueing task #${task.id}...`)\n this.taskQueue.push(task)\n\n this.eventSubject.next({\n taskID: task.id,\n type: PoolEventType.taskQueued,\n })\n\n this.scheduleWork()\n return task\n }\n\n async terminate(force?: boolean) {\n this.isClosing = true\n if (force !== true) {\n await this.completed(true)\n }\n this.eventSubject.next({\n remainingQueue: [...this.taskQueue],\n type: PoolEventType.terminated,\n })\n this.eventSubject.complete()\n await Promise.all(this.workers.map(async worker => Thread.terminate(await worker.init)))\n }\n}\n\n/**\n * Thread pool constructor. Creates a new pool and spawns its worker threads.\n */\nfunction PoolConstructor<ThreadType extends Thread>(spawnWorker: () => Promise<ThreadType>, optionsOrSize?: number | PoolOptions) {\n // The function exists only so we don't need to use `new` to create a pool (we still can, though).\n // If the Pool is a class or not is an implementation detail that should not concern the user.\n return new WorkerPool(spawnWorker, optionsOrSize)\n}\n\n;(PoolConstructor as any).EventType = PoolEventType\n\n/**\n * Thread pool constructor. Creates a new pool and spawns its worker threads.\n */\nexport const Pool = PoolConstructor as typeof PoolConstructor & { EventType: typeof PoolEventType }\n\nexport type { PoolEvent, QueuedTask } from './pool-types.ts'\nexport { PoolEventType } from './pool-types.ts'\nexport { Thread } from './thread.ts'\n", "/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable unicorn/text-encoding-identifier-case */\n/// <reference types=\"node\" />\n\nimport { cpus } from 'node:os'\nimport path from 'node:path'\nimport { cwd } from 'node:process'\nimport { isMainThread, Worker as NativeWorker } from 'node:worker_threads'\n\nimport type {\n ImplementationExport, ThreadsWorkerOptions, WorkerImplementation,\n} from '../types/master.ts'\n\n/** Default thread pool size based on the number of CPU cores. */\nexport const defaultPoolSize = cpus().length\n\nfunction resolveScriptPath(scriptPath: string, baseURL?: string) {\n const makeAbsolute = (filePath: string) => {\n return path.isAbsolute(filePath) ? filePath : path.join(baseURL ?? cwd(), filePath)\n }\n\n const absolutePath = makeAbsolute(scriptPath)\n return absolutePath\n}\n\nfunction initWorkerThreadsWorker(): ImplementationExport {\n let allWorkers: NativeWorker[] = []\n\n class Worker extends NativeWorker {\n private mappedEventListeners: WeakMap<EventListener, EventListener>\n\n constructor(scriptPath: string, options?: ThreadsWorkerOptions & { fromSource: boolean }) {\n const resolvedScriptPath = options?.fromSource === true ? null : resolveScriptPath(scriptPath, options?._baseURL)\n if (resolvedScriptPath === null) {\n // `options.fromSource` is true\n const sourceCode = scriptPath\n super(sourceCode, { ...options, eval: true })\n } else {\n super(resolvedScriptPath, options)\n }\n\n this.mappedEventListeners = new WeakMap()\n allWorkers.push(this)\n }\n\n addEventListener(eventName: string, rawListener: EventListener) {\n const listener = (message: any) => {\n rawListener({ data: message } as any)\n }\n this.mappedEventListeners.set(rawListener, listener)\n this.on(eventName, listener)\n }\n\n removeEventListener(eventName: string, rawListener: EventListener) {\n const listener = this.mappedEventListeners.get(rawListener) || rawListener\n this.off(eventName, listener)\n }\n }\n\n const terminateWorkersAndMaster = () => {\n // we should terminate all workers and then gracefully shutdown self process\n void (async () => {\n try {\n await Promise.all(allWorkers.map(worker => worker.terminate()))\n process.exit(0)\n } catch {\n process.exit(1)\n }\n })()\n allWorkers = []\n }\n\n // Take care to not leave orphaned processes behind. See #147.\n process.on('SIGINT', () => terminateWorkersAndMaster())\n process.on('SIGTERM', () => terminateWorkersAndMaster())\n\n class BlobWorker extends Worker {\n constructor(blob: Uint8Array, options?: ThreadsWorkerOptions) {\n super(Buffer.from(blob).toString('utf-8'), { ...options, fromSource: true })\n }\n\n static fromText(source: string, options?: ThreadsWorkerOptions): WorkerImplementation {\n return new Worker(source, { ...options, fromSource: true }) as any\n }\n }\n\n return {\n blob: BlobWorker as any,\n default: Worker as any,\n }\n}\n\nlet implementation: ImplementationExport\n\n/**\n * Get the Node.js-specific worker implementation using `worker_threads`, lazily initializing it on first call.\n * @returns The platform-specific worker implementation export.\n */\nexport function getWorkerImplementation(): ImplementationExport {\n if (implementation === undefined) {\n implementation = initWorkerThreadsWorker()\n }\n return implementation\n}\n\n/**\n * Check whether the current code is running inside a Node.js worker thread.\n * @returns True if running in a worker thread (not the main thread), false otherwise.\n */\nexport function isWorkerRuntime() {\n return !isMainThread\n}\n", "/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/member-ordering */\nimport type { Thread } from './thread.ts'\n\n/** Pool event type. Specifies the type of each `PoolEvent`. */\nexport enum PoolEventType {\n initialized = 'initialized',\n taskCanceled = 'taskCanceled',\n taskCompleted = 'taskCompleted',\n taskFailed = 'taskFailed',\n taskQueued = 'taskQueued',\n taskQueueDrained = 'taskQueueDrained',\n taskStart = 'taskStart',\n terminated = 'terminated',\n}\n\n/** A function that runs a task on a worker thread and returns a promise of the result. */\nexport type TaskRunFunction<ThreadType extends Thread, Return> = (worker: ThreadType) => Promise<Return>\n\n/** Pool event. Subscribe to those events using `pool.events()`. Useful for debugging. */\nexport type PoolEvent<ThreadType extends Thread>\n = | {\n type: PoolEventType.initialized\n size: number\n }\n | {\n type: PoolEventType.taskQueued\n taskID: number\n }\n | {\n type: PoolEventType.taskQueueDrained\n }\n | {\n type: PoolEventType.taskStart\n taskID: number\n workerID: number\n }\n | {\n type: PoolEventType.taskCompleted\n returnValue: any\n taskID: number\n workerID: number\n }\n | {\n type: PoolEventType.taskFailed\n error: Error\n taskID: number\n workerID: number\n }\n | {\n type: PoolEventType.taskCanceled\n taskID: number\n }\n | {\n type: PoolEventType.terminated\n remainingQueue: QueuedTask<ThreadType, any>[]\n }\n\n/** Descriptor for a worker in a pool, tracking its initialization and running tasks. */\nexport interface WorkerDescriptor<ThreadType extends Thread> {\n init: Promise<ThreadType>\n runningTasks: Promise<any>[]\n}\n\n/**\n * Task that has been `pool.queued()`-ed.\n */\nexport interface QueuedTask<ThreadType extends Thread, Return> {\n /** @private */\n id: number\n\n /** @private */\n run: TaskRunFunction<ThreadType, Return>\n\n /**\n * Queued tasks can be cancelled until the pool starts running them on a worker thread.\n */\n cancel(): void\n\n /**\n * `QueuedTask` is thenable, so you can `await` it.\n * Resolves when the task has successfully been executed. Rejects if the task fails.\n */\n then: Promise<Return>['then']\n}\n", "/** Symbol key for accessing a thread's error observable. */\nexport const $errors = Symbol('thread.errors')\n/** Symbol key for accessing a thread's event observable. */\nexport const $events = Symbol('thread.events')\n/** Symbol key for accessing a thread's terminate function. */\nexport const $terminate = Symbol('thread.terminate')\n/** Symbol key for marking an object as a transferable descriptor. */\nexport const $transferable = Symbol('thread.transferable')\n/** Symbol key for accessing the underlying worker instance of a thread. */\nexport const $worker = Symbol('thread.worker')\n", "import type { Observable } from 'observable-fns'\n\nimport {\n $errors, $events, $terminate,\n} from '../symbols.ts'\nimport type {\n PrivateThreadProps, Thread as ThreadType, WorkerEvent,\n} from '../types/master.ts'\n\nfunction fail(message: string): never {\n throw new Error(message)\n}\n\nfunction readPrivateThreadProp<K extends keyof PrivateThreadProps>(\n thread: ThreadType,\n key: K,\n): PrivateThreadProps[K] | undefined {\n return Reflect.get(thread, key)\n}\n\n/** Re-exported Thread type from the master types module. */\nexport type Thread = ThreadType\n\n/** Thread utility functions. Use them to manage or inspect a `spawn()`-ed thread. */\nexport const Thread = {\n /** Return an observable that can be used to subscribe to all errors happening in the thread. */\n errors: <ThreadT extends ThreadType>(thread: ThreadT): Observable<Error> =>\n readPrivateThreadProp(thread, $errors) ?? fail('Error observable not found. Make sure to pass a thread instance as returned by the spawn() promise.'),\n /** Return an observable that can be used to subscribe to internal events happening in the thread. Useful for debugging. */\n events: <ThreadT extends ThreadType>(thread: ThreadT): Observable<WorkerEvent> =>\n readPrivateThreadProp(thread, $events) ?? fail('Events observable not found. Make sure to pass a thread instance as returned by the spawn() promise.'),\n /** Terminate a thread. Remember to terminate every thread when you are done using it. */\n terminate: <ThreadT extends ThreadType>(thread: ThreadT) =>\n readPrivateThreadProp(thread, $terminate)?.() ?? fail('Terminate function not found. Make sure to pass a thread instance as returned by the spawn() promise.'),\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["PoolEventType"]
7
+ }
@@ -0,0 +1,68 @@
1
+ import type { Thread } from './thread.ts';
2
+ /** Pool event type. Specifies the type of each `PoolEvent`. */
3
+ export declare enum PoolEventType {
4
+ initialized = "initialized",
5
+ taskCanceled = "taskCanceled",
6
+ taskCompleted = "taskCompleted",
7
+ taskFailed = "taskFailed",
8
+ taskQueued = "taskQueued",
9
+ taskQueueDrained = "taskQueueDrained",
10
+ taskStart = "taskStart",
11
+ terminated = "terminated"
12
+ }
13
+ /** A function that runs a task on a worker thread and returns a promise of the result. */
14
+ export type TaskRunFunction<ThreadType extends Thread, Return> = (worker: ThreadType) => Promise<Return>;
15
+ /** Pool event. Subscribe to those events using `pool.events()`. Useful for debugging. */
16
+ export type PoolEvent<ThreadType extends Thread> = {
17
+ type: PoolEventType.initialized;
18
+ size: number;
19
+ } | {
20
+ type: PoolEventType.taskQueued;
21
+ taskID: number;
22
+ } | {
23
+ type: PoolEventType.taskQueueDrained;
24
+ } | {
25
+ type: PoolEventType.taskStart;
26
+ taskID: number;
27
+ workerID: number;
28
+ } | {
29
+ type: PoolEventType.taskCompleted;
30
+ returnValue: any;
31
+ taskID: number;
32
+ workerID: number;
33
+ } | {
34
+ type: PoolEventType.taskFailed;
35
+ error: Error;
36
+ taskID: number;
37
+ workerID: number;
38
+ } | {
39
+ type: PoolEventType.taskCanceled;
40
+ taskID: number;
41
+ } | {
42
+ type: PoolEventType.terminated;
43
+ remainingQueue: QueuedTask<ThreadType, any>[];
44
+ };
45
+ /** Descriptor for a worker in a pool, tracking its initialization and running tasks. */
46
+ export interface WorkerDescriptor<ThreadType extends Thread> {
47
+ init: Promise<ThreadType>;
48
+ runningTasks: Promise<any>[];
49
+ }
50
+ /**
51
+ * Task that has been `pool.queued()`-ed.
52
+ */
53
+ export interface QueuedTask<ThreadType extends Thread, Return> {
54
+ /** @private */
55
+ id: number;
56
+ /** @private */
57
+ run: TaskRunFunction<ThreadType, Return>;
58
+ /**
59
+ * Queued tasks can be cancelled until the pool starts running them on a worker thread.
60
+ */
61
+ cancel(): void;
62
+ /**
63
+ * `QueuedTask` is thenable, so you can `await` it.
64
+ * Resolves when the task has successfully been executed. Rejects if the task fails.
65
+ */
66
+ then: Promise<Return>['then'];
67
+ }
68
+ //# sourceMappingURL=pool-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pool-types.d.ts","sourceRoot":"","sources":["../../../src/master/pool-types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEzC,+DAA+D;AAC/D,oBAAY,aAAa;IACvB,WAAW,gBAAgB;IAC3B,YAAY,iBAAiB;IAC7B,aAAa,kBAAkB;IAC/B,UAAU,eAAe;IACzB,UAAU,eAAe;IACzB,gBAAgB,qBAAqB;IACrC,SAAS,cAAc;IACvB,UAAU,eAAe;CAC1B;AAED,0FAA0F;AAC1F,MAAM,MAAM,eAAe,CAAC,UAAU,SAAS,MAAM,EAAE,MAAM,IAAI,CAAC,MAAM,EAAE,UAAU,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;AAExG,yFAAyF;AACzF,MAAM,MAAM,SAAS,CAAC,UAAU,SAAS,MAAM,IACzC;IACF,IAAI,EAAE,aAAa,CAAC,WAAW,CAAA;IAC/B,IAAI,EAAE,MAAM,CAAA;CACb,GACC;IACA,IAAI,EAAE,aAAa,CAAC,UAAU,CAAA;IAC9B,MAAM,EAAE,MAAM,CAAA;CACf,GACC;IACA,IAAI,EAAE,aAAa,CAAC,gBAAgB,CAAA;CACrC,GACC;IACA,IAAI,EAAE,aAAa,CAAC,SAAS,CAAA;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;CACjB,GACC;IACA,IAAI,EAAE,aAAa,CAAC,aAAa,CAAA;IACjC,WAAW,EAAE,GAAG,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;CACjB,GACC;IACA,IAAI,EAAE,aAAa,CAAC,UAAU,CAAA;IAC9B,KAAK,EAAE,KAAK,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;CACjB,GACC;IACA,IAAI,EAAE,aAAa,CAAC,YAAY,CAAA;IAChC,MAAM,EAAE,MAAM,CAAA;CACf,GACC;IACA,IAAI,EAAE,aAAa,CAAC,UAAU,CAAA;IAC9B,cAAc,EAAE,UAAU,CAAC,UAAU,EAAE,GAAG,CAAC,EAAE,CAAA;CAC9C,CAAA;AAEH,wFAAwF;AACxF,MAAM,WAAW,gBAAgB,CAAC,UAAU,SAAS,MAAM;IACzD,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAA;IACzB,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAA;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,UAAU,CAAC,UAAU,SAAS,MAAM,EAAE,MAAM;IAC3D,eAAe;IACf,EAAE,EAAE,MAAM,CAAA;IAEV,eAAe;IACf,GAAG,EAAE,eAAe,CAAC,UAAU,EAAE,MAAM,CAAC,CAAA;IAExC;;OAEG;IACH,MAAM,IAAI,IAAI,CAAA;IAEd;;;OAGG;IACH,IAAI,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAA;CAC9B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/master/register.ts"],"names":[],"mappings":""}
@@ -0,0 +1,87 @@
1
+ // src/master/implementation.node.ts
2
+ import { cpus } from "node:os";
3
+ import path from "node:path";
4
+ import { cwd } from "node:process";
5
+ import { isMainThread, Worker as NativeWorker } from "node:worker_threads";
6
+ var defaultPoolSize = cpus().length;
7
+ function resolveScriptPath(scriptPath, baseURL) {
8
+ const makeAbsolute = (filePath) => {
9
+ return path.isAbsolute(filePath) ? filePath : path.join(baseURL ?? cwd(), filePath);
10
+ };
11
+ const absolutePath = makeAbsolute(scriptPath);
12
+ return absolutePath;
13
+ }
14
+ function initWorkerThreadsWorker() {
15
+ let allWorkers = [];
16
+ class Worker2 extends NativeWorker {
17
+ mappedEventListeners;
18
+ constructor(scriptPath, options) {
19
+ const resolvedScriptPath = options?.fromSource === true ? null : resolveScriptPath(scriptPath, options?._baseURL);
20
+ if (resolvedScriptPath === null) {
21
+ const sourceCode = scriptPath;
22
+ super(sourceCode, { ...options, eval: true });
23
+ } else {
24
+ super(resolvedScriptPath, options);
25
+ }
26
+ this.mappedEventListeners = /* @__PURE__ */ new WeakMap();
27
+ allWorkers.push(this);
28
+ }
29
+ addEventListener(eventName, rawListener) {
30
+ const listener = (message) => {
31
+ rawListener({ data: message });
32
+ };
33
+ this.mappedEventListeners.set(rawListener, listener);
34
+ this.on(eventName, listener);
35
+ }
36
+ removeEventListener(eventName, rawListener) {
37
+ const listener = this.mappedEventListeners.get(rawListener) || rawListener;
38
+ this.off(eventName, listener);
39
+ }
40
+ }
41
+ const terminateWorkersAndMaster = () => {
42
+ void (async () => {
43
+ try {
44
+ await Promise.all(allWorkers.map((worker) => worker.terminate()));
45
+ process.exit(0);
46
+ } catch {
47
+ process.exit(1);
48
+ }
49
+ })();
50
+ allWorkers = [];
51
+ };
52
+ process.on("SIGINT", () => terminateWorkersAndMaster());
53
+ process.on("SIGTERM", () => terminateWorkersAndMaster());
54
+ class BlobWorker2 extends Worker2 {
55
+ constructor(blob, options) {
56
+ super(Buffer.from(blob).toString("utf-8"), { ...options, fromSource: true });
57
+ }
58
+ static fromText(source, options) {
59
+ return new Worker2(source, { ...options, fromSource: true });
60
+ }
61
+ }
62
+ return {
63
+ blob: BlobWorker2,
64
+ default: Worker2
65
+ };
66
+ }
67
+ var implementation;
68
+ function getWorkerImplementation() {
69
+ if (implementation === void 0) {
70
+ implementation = initWorkerThreadsWorker();
71
+ }
72
+ return implementation;
73
+ }
74
+
75
+ // src/master/index-node.ts
76
+ var BlobWorker = getWorkerImplementation().blob;
77
+ var Worker = getWorkerImplementation().default;
78
+
79
+ // src/master/register.ts
80
+ if (typeof globalThis !== "undefined") {
81
+ ;
82
+ globalThis.Worker = Worker;
83
+ } else if (window !== void 0) {
84
+ ;
85
+ window.Worker = Worker;
86
+ }
87
+ //# sourceMappingURL=register.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/master/implementation.node.ts", "../../../src/master/index-node.ts", "../../../src/master/register.ts"],
4
+ "sourcesContent": ["/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable unicorn/text-encoding-identifier-case */\n/// <reference types=\"node\" />\n\nimport { cpus } from 'node:os'\nimport path from 'node:path'\nimport { cwd } from 'node:process'\nimport { isMainThread, Worker as NativeWorker } from 'node:worker_threads'\n\nimport type {\n ImplementationExport, ThreadsWorkerOptions, WorkerImplementation,\n} from '../types/master.ts'\n\n/** Default thread pool size based on the number of CPU cores. */\nexport const defaultPoolSize = cpus().length\n\nfunction resolveScriptPath(scriptPath: string, baseURL?: string) {\n const makeAbsolute = (filePath: string) => {\n return path.isAbsolute(filePath) ? filePath : path.join(baseURL ?? cwd(), filePath)\n }\n\n const absolutePath = makeAbsolute(scriptPath)\n return absolutePath\n}\n\nfunction initWorkerThreadsWorker(): ImplementationExport {\n let allWorkers: NativeWorker[] = []\n\n class Worker extends NativeWorker {\n private mappedEventListeners: WeakMap<EventListener, EventListener>\n\n constructor(scriptPath: string, options?: ThreadsWorkerOptions & { fromSource: boolean }) {\n const resolvedScriptPath = options?.fromSource === true ? null : resolveScriptPath(scriptPath, options?._baseURL)\n if (resolvedScriptPath === null) {\n // `options.fromSource` is true\n const sourceCode = scriptPath\n super(sourceCode, { ...options, eval: true })\n } else {\n super(resolvedScriptPath, options)\n }\n\n this.mappedEventListeners = new WeakMap()\n allWorkers.push(this)\n }\n\n addEventListener(eventName: string, rawListener: EventListener) {\n const listener = (message: any) => {\n rawListener({ data: message } as any)\n }\n this.mappedEventListeners.set(rawListener, listener)\n this.on(eventName, listener)\n }\n\n removeEventListener(eventName: string, rawListener: EventListener) {\n const listener = this.mappedEventListeners.get(rawListener) || rawListener\n this.off(eventName, listener)\n }\n }\n\n const terminateWorkersAndMaster = () => {\n // we should terminate all workers and then gracefully shutdown self process\n void (async () => {\n try {\n await Promise.all(allWorkers.map(worker => worker.terminate()))\n process.exit(0)\n } catch {\n process.exit(1)\n }\n })()\n allWorkers = []\n }\n\n // Take care to not leave orphaned processes behind. See #147.\n process.on('SIGINT', () => terminateWorkersAndMaster())\n process.on('SIGTERM', () => terminateWorkersAndMaster())\n\n class BlobWorker extends Worker {\n constructor(blob: Uint8Array, options?: ThreadsWorkerOptions) {\n super(Buffer.from(blob).toString('utf-8'), { ...options, fromSource: true })\n }\n\n static fromText(source: string, options?: ThreadsWorkerOptions): WorkerImplementation {\n return new Worker(source, { ...options, fromSource: true }) as any\n }\n }\n\n return {\n blob: BlobWorker as any,\n default: Worker as any,\n }\n}\n\nlet implementation: ImplementationExport\n\n/**\n * Get the Node.js-specific worker implementation using `worker_threads`, lazily initializing it on first call.\n * @returns The platform-specific worker implementation export.\n */\nexport function getWorkerImplementation(): ImplementationExport {\n if (implementation === undefined) {\n implementation = initWorkerThreadsWorker()\n }\n return implementation\n}\n\n/**\n * Check whether the current code is running inside a Node.js worker thread.\n * @returns True if running in a worker thread (not the main thread), false otherwise.\n */\nexport function isWorkerRuntime() {\n return !isMainThread\n}\n", "import type { BlobWorker as BlobWorkerClass, Worker as WorkerType } from '../types/master.ts'\nimport * as NodeImplementation from './implementation.node.ts'\n\nexport type { FunctionThread, ModuleThread } from '../types/master.ts'\nexport { Pool } from './pool-browser.ts'\nexport { spawn } from './spawn.ts'\nexport { Thread } from './thread.ts'\n\nexport type BlobWorker = typeof BlobWorkerClass\nexport type Worker = WorkerType\n\n/** Separate class to spawn workers from source code blobs or strings. */\nexport const BlobWorker = NodeImplementation.getWorkerImplementation().blob\n\n/** Worker implementation. Either web worker or a Node.js Worker class. */\nexport const Worker = NodeImplementation.getWorkerImplementation().default\n\nexport { isWorkerRuntime } from './implementation.node.ts'\n", "/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { Worker as WorkerImplementation } from './index-node.ts'\n\ndeclare const window: any\n\nif (typeof globalThis !== 'undefined') {\n ;(globalThis as any).Worker = WorkerImplementation\n} else if (window !== undefined) {\n ;(window).Worker = WorkerImplementation\n}\n"],
5
+ "mappings": ";AAIA,SAAS,YAAY;AACrB,OAAO,UAAU;AACjB,SAAS,WAAW;AACpB,SAAS,cAAc,UAAU,oBAAoB;AAO9C,IAAM,kBAAkB,KAAK,EAAE;AAEtC,SAAS,kBAAkB,YAAoB,SAAkB;AAC/D,QAAM,eAAe,CAAC,aAAqB;AACzC,WAAO,KAAK,WAAW,QAAQ,IAAI,WAAW,KAAK,KAAK,WAAW,IAAI,GAAG,QAAQ;AAAA,EACpF;AAEA,QAAM,eAAe,aAAa,UAAU;AAC5C,SAAO;AACT;AAEA,SAAS,0BAAgD;AACvD,MAAI,aAA6B,CAAC;AAAA,EAElC,MAAMA,gBAAe,aAAa;AAAA,IACxB;AAAA,IAER,YAAY,YAAoB,SAA0D;AACxF,YAAM,qBAAqB,SAAS,eAAe,OAAO,OAAO,kBAAkB,YAAY,SAAS,QAAQ;AAChH,UAAI,uBAAuB,MAAM;AAE/B,cAAM,aAAa;AACnB,cAAM,YAAY,EAAE,GAAG,SAAS,MAAM,KAAK,CAAC;AAAA,MAC9C,OAAO;AACL,cAAM,oBAAoB,OAAO;AAAA,MACnC;AAEA,WAAK,uBAAuB,oBAAI,QAAQ;AACxC,iBAAW,KAAK,IAAI;AAAA,IACtB;AAAA,IAEA,iBAAiB,WAAmB,aAA4B;AAC9D,YAAM,WAAW,CAAC,YAAiB;AACjC,oBAAY,EAAE,MAAM,QAAQ,CAAQ;AAAA,MACtC;AACA,WAAK,qBAAqB,IAAI,aAAa,QAAQ;AACnD,WAAK,GAAG,WAAW,QAAQ;AAAA,IAC7B;AAAA,IAEA,oBAAoB,WAAmB,aAA4B;AACjE,YAAM,WAAW,KAAK,qBAAqB,IAAI,WAAW,KAAK;AAC/D,WAAK,IAAI,WAAW,QAAQ;AAAA,IAC9B;AAAA,EACF;AAEA,QAAM,4BAA4B,MAAM;AAEtC,UAAM,YAAY;AAChB,UAAI;AACF,cAAM,QAAQ,IAAI,WAAW,IAAI,YAAU,OAAO,UAAU,CAAC,CAAC;AAC9D,gBAAQ,KAAK,CAAC;AAAA,MAChB,QAAQ;AACN,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF,GAAG;AACH,iBAAa,CAAC;AAAA,EAChB;AAGA,UAAQ,GAAG,UAAU,MAAM,0BAA0B,CAAC;AACtD,UAAQ,GAAG,WAAW,MAAM,0BAA0B,CAAC;AAAA,EAEvD,MAAMC,oBAAmBD,QAAO;AAAA,IAC9B,YAAY,MAAkB,SAAgC;AAC5D,YAAM,OAAO,KAAK,IAAI,EAAE,SAAS,OAAO,GAAG,EAAE,GAAG,SAAS,YAAY,KAAK,CAAC;AAAA,IAC7E;AAAA,IAEA,OAAO,SAAS,QAAgB,SAAsD;AACpF,aAAO,IAAIA,QAAO,QAAQ,EAAE,GAAG,SAAS,YAAY,KAAK,CAAC;AAAA,IAC5D;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAMC;AAAA,IACN,SAASD;AAAA,EACX;AACF;AAEA,IAAI;AAMG,SAAS,0BAAgD;AAC9D,MAAI,mBAAmB,QAAW;AAChC,qBAAiB,wBAAwB;AAAA,EAC3C;AACA,SAAO;AACT;;;AC3FO,IAAM,aAAgC,wBAAwB,EAAE;AAGhE,IAAM,SAA4B,wBAAwB,EAAE;;;ACTnE,IAAI,OAAO,eAAe,aAAa;AACrC;AAAC,EAAC,WAAmB,SAAS;AAChC,WAAW,WAAW,QAAW;AAC/B;AAAC,EAAC,OAAQ,SAAS;AACrB;",
6
+ "names": ["Worker", "BlobWorker"]
7
+ }
@@ -0,0 +1,22 @@
1
+ import type { FunctionThread, ModuleThread, StripAsync, Worker as WorkerType } from '../types/master.ts';
2
+ import type { WorkerFunction, WorkerModule } from '../types/worker.ts';
3
+ type ArbitraryWorkerInterface = WorkerFunction & WorkerModule<string> & {
4
+ somekeythatisneverusedinproductioncode123: 'magicmarker123';
5
+ };
6
+ type ArbitraryThreadType = FunctionThread<any, any> & ModuleThread<any>;
7
+ /** Maps a worker's exposed API type to its corresponding thread type (`FunctionThread` or `ModuleThread`). */
8
+ export type ExposedToThreadType<Exposed extends WorkerFunction | WorkerModule<any>> = Exposed extends ArbitraryWorkerInterface ? ArbitraryThreadType : Exposed extends WorkerFunction ? FunctionThread<Parameters<Exposed>, StripAsync<ReturnType<Exposed>>> : Exposed extends WorkerModule<any> ? ModuleThread<Exposed> : never;
9
+ /**
10
+ * Spawn a new thread. Takes a fresh worker instance, wraps it in a thin
11
+ * abstraction layer to provide the transparent API and verifies that
12
+ * the worker has initialized successfully.
13
+ *
14
+ * @param worker Instance of `Worker`. Either a web worker or `worker_threads` worker.
15
+ * @param [options]
16
+ * @param [options.timeout] Init message timeout. Default: 10000 or set by environment variable.
17
+ */
18
+ export declare function spawn<Exposed extends WorkerFunction | WorkerModule<any> = ArbitraryWorkerInterface>(worker: WorkerType, options?: {
19
+ timeout?: number;
20
+ }): Promise<ExposedToThreadType<Exposed>>;
21
+ export {};
22
+ //# sourceMappingURL=spawn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawn.d.ts","sourceRoot":"","sources":["../../../src/master/spawn.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EAEZ,UAAU,EACV,MAAM,IAAI,UAAU,EAKrB,MAAM,oBAAoB,CAAA;AAG3B,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAGtE,KAAK,wBAAwB,GAAG,cAAc,GAAG,YAAY,CAAC,MAAM,CAAC,GAAG;IAAE,yCAAyC,EAAE,gBAAgB,CAAA;CAAE,CAAA;AACvI,KAAK,mBAAmB,GAAG,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,CAAA;AAUvE,8GAA8G;AAC9G,MAAM,MAAM,mBAAmB,CAAC,OAAO,SAAS,cAAc,GAAG,YAAY,CAAC,GAAG,CAAC,IAC9E,OAAO,SAAS,wBAAwB,GAAG,mBAAmB,GAC5D,OAAO,SAAS,cAAc,GAAG,cAAc,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GACnG,OAAO,SAAS,YAAY,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC,OAAO,CAAC,GACvD,KAAK,CAAA;AA4Gf;;;;;;;;GAQG;AACH,wBAAsB,KAAK,CAAC,OAAO,SAAS,cAAc,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,wBAAwB,EACvG,MAAM,EAAE,UAAU,EAClB,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7B,OAAO,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAwBvC"}
@@ -0,0 +1,14 @@
1
+ import type { Observable } from 'observable-fns';
2
+ import type { Thread as ThreadType, WorkerEvent } from '../types/master.ts';
3
+ /** Re-exported Thread type from the master types module. */
4
+ export type Thread = ThreadType;
5
+ /** Thread utility functions. Use them to manage or inspect a `spawn()`-ed thread. */
6
+ export declare const Thread: {
7
+ /** Return an observable that can be used to subscribe to all errors happening in the thread. */
8
+ errors: <ThreadT extends ThreadType>(thread: ThreadT) => Observable<Error>;
9
+ /** Return an observable that can be used to subscribe to internal events happening in the thread. Useful for debugging. */
10
+ events: <ThreadT extends ThreadType>(thread: ThreadT) => Observable<WorkerEvent>;
11
+ /** Terminate a thread. Remember to terminate every thread when you are done using it. */
12
+ terminate: <ThreadT extends ThreadType>(thread: ThreadT) => Promise<void>;
13
+ };
14
+ //# sourceMappingURL=thread.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread.d.ts","sourceRoot":"","sources":["../../../src/master/thread.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAKhD,OAAO,KAAK,EACU,MAAM,IAAI,UAAU,EAAE,WAAW,EACtD,MAAM,oBAAoB,CAAA;AAa3B,4DAA4D;AAC5D,MAAM,MAAM,MAAM,GAAG,UAAU,CAAA;AAE/B,qFAAqF;AACrF,eAAO,MAAM,MAAM;IACjB,gGAAgG;aACvF,OAAO,SAAS,UAAU,UAAU,OAAO,KAAG,UAAU,CAAC,KAAK,CAAC;IAExE,2HAA2H;aAClH,OAAO,SAAS,UAAU,UAAU,OAAO,KAAG,UAAU,CAAC,WAAW,CAAC;IAE9E,yFAAyF;gBAC7E,OAAO,SAAS,UAAU,UAAU,OAAO;CAExD,CAAA"}
@@ -0,0 +1,41 @@
1
+ import type { ObservableLike, SubscriptionObserver } from 'observable-fns';
2
+ import { Observable } from 'observable-fns';
3
+ type Initializer<T> = (observer: SubscriptionObserver<T>) => UnsubscribeFn | void;
4
+ type Thenable<T> = {
5
+ then: (onFulfilled?: (value: T) => any, onRejected?: (error: any) => any) => any;
6
+ };
7
+ type UnsubscribeFn = () => void;
8
+ /**
9
+ * Creates a hybrid, combining the APIs of an Observable and a Promise.
10
+ *
11
+ * It is used to proxy async process states when we are initially not sure
12
+ * if that async process will yield values once (-> Promise) or multiple
13
+ * times (-> Observable).
14
+ *
15
+ * Note that the observable promise inherits some of the observable's characteristics:
16
+ * The `init` function will be called *once for every time anyone subscribes to it*.
17
+ *
18
+ * If this is undesired, derive a hot observable from it using `makeHot()` and
19
+ * subscribe to that.
20
+ */
21
+ export declare class ObservablePromise<T> extends Observable<T> implements Promise<T> {
22
+ readonly [Symbol.toStringTag] = "[object ObservablePromise]";
23
+ private initHasRun;
24
+ private fulfillmentCallbacks;
25
+ private rejectionCallbacks;
26
+ private firstValue;
27
+ private firstValueSet;
28
+ private rejection;
29
+ private state;
30
+ constructor(init: Initializer<T>);
31
+ private onNext;
32
+ private onError;
33
+ private onCompletion;
34
+ private createPromise;
35
+ then<TResult1 = T, TResult2 = never>(onFulfilledRaw?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null, onRejectedRaw?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
36
+ catch<Result = never>(onRejected: ((error: Error) => Promise<Result> | Result) | null | undefined): Promise<T | Result>;
37
+ finally(onCompleted?: (() => void) | null): Promise<T>;
38
+ static from<T>(thing: Observable<T> | ObservableLike<T> | ArrayLike<T> | Thenable<T>): ObservablePromise<T>;
39
+ }
40
+ export {};
41
+ //# sourceMappingURL=observable-promise.d.ts.map