@xylabs/threads 4.6.4 → 4.7.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 (227) hide show
  1. package/dist/browser/master/implementation.browser.mjs +89 -0
  2. package/dist/browser/master/implementation.browser.mjs.map +1 -0
  3. package/dist/browser/worker/worker.browser.mjs +291 -0
  4. package/dist/browser/worker/worker.browser.mjs.map +1 -0
  5. package/dist/neutral/index.mjs +1022 -0
  6. package/dist/neutral/index.mjs.map +1 -0
  7. package/dist/neutral/master/implementation.mjs +264 -0
  8. package/dist/neutral/master/implementation.mjs.map +1 -0
  9. package/dist/neutral/master/index.mjs +988 -0
  10. package/dist/neutral/master/index.mjs.map +1 -0
  11. package/dist/neutral/master/pool.mjs +579 -0
  12. package/dist/neutral/master/pool.mjs.map +1 -0
  13. package/dist/neutral/master/register.mjs +272 -0
  14. package/dist/neutral/master/register.mjs.map +1 -0
  15. package/dist/neutral/master/spawn.mjs +412 -0
  16. package/dist/neutral/master/spawn.mjs.map +1 -0
  17. package/dist/neutral/master/thread.mjs +29 -0
  18. package/dist/neutral/master/thread.mjs.map +1 -0
  19. package/dist/neutral/observable-promise.mjs +132 -0
  20. package/dist/neutral/observable-promise.mjs.map +1 -0
  21. package/dist/neutral/observable.mjs +31 -0
  22. package/dist/neutral/observable.mjs.map +1 -0
  23. package/dist/node/master/implementation.node.mjs +154 -0
  24. package/dist/node/master/implementation.node.mjs.map +1 -0
  25. package/dist/node/worker/worker.node.mjs +304 -0
  26. package/dist/node/worker/worker.node.mjs.map +1 -0
  27. package/dist/{common.d.ts → types/common.d.ts} +5 -1
  28. package/dist/types/common.d.ts.map +1 -0
  29. package/dist/types/index.d.ts +9 -0
  30. package/dist/types/index.d.ts.map +1 -0
  31. package/dist/{master → types/master}/get-bundle-url.browser.d.ts +1 -0
  32. package/dist/types/master/get-bundle-url.browser.d.ts.map +1 -0
  33. package/dist/{master → types/master}/implementation.browser.d.ts +2 -1
  34. package/dist/types/master/implementation.browser.d.ts.map +1 -0
  35. package/dist/{master → types/master}/implementation.d.ts +4 -1
  36. package/dist/types/master/implementation.d.ts.map +1 -0
  37. package/dist/{master → types/master}/implementation.node.d.ts +2 -1
  38. package/dist/types/master/implementation.node.d.ts.map +1 -0
  39. package/dist/types/master/index.d.ts +13 -0
  40. package/dist/types/master/index.d.ts.map +1 -0
  41. package/dist/{master → types/master}/invocation-proxy.d.ts +2 -1
  42. package/dist/types/master/invocation-proxy.d.ts.map +1 -0
  43. package/dist/{master → types/master}/pool-types.d.ts +16 -1
  44. package/dist/types/master/pool-types.d.ts.map +1 -0
  45. package/dist/types/master/pool.d.ts +93 -0
  46. package/dist/types/master/pool.d.ts.map +1 -0
  47. package/dist/types/master/register.d.ts +2 -0
  48. package/dist/types/master/register.d.ts.map +1 -0
  49. package/dist/{master → types/master}/spawn.d.ts +12 -2
  50. package/dist/types/master/spawn.d.ts.map +1 -0
  51. package/dist/types/master/thread.d.ts +13 -0
  52. package/dist/types/master/thread.d.ts.map +1 -0
  53. package/dist/{observable-promise.d.ts → types/observable-promise.d.ts} +14 -0
  54. package/dist/types/observable-promise.d.ts.map +1 -0
  55. package/dist/types/observable.d.ts +21 -0
  56. package/dist/types/observable.d.ts.map +1 -0
  57. package/dist/{ponyfills.d.ts → types/ponyfills.d.ts} +1 -0
  58. package/dist/types/ponyfills.d.ts.map +1 -0
  59. package/dist/types/promise.d.ts +6 -0
  60. package/dist/types/promise.d.ts.map +1 -0
  61. package/dist/{serializers.d.ts → types/serializers.d.ts} +1 -0
  62. package/dist/types/serializers.d.ts.map +1 -0
  63. package/dist/{symbols.d.ts → types/symbols.d.ts} +1 -0
  64. package/dist/types/symbols.d.ts.map +1 -0
  65. package/dist/types/transferable.d.ts +43 -0
  66. package/dist/types/transferable.d.ts.map +1 -0
  67. package/dist/types/{master.d.ts → types/master.d.ts} +17 -3
  68. package/dist/types/types/master.d.ts.map +1 -0
  69. package/dist/types/{messages.d.ts → types/messages.d.ts} +1 -0
  70. package/dist/types/types/messages.d.ts.map +1 -0
  71. package/dist/types/{worker.d.ts → types/worker.d.ts} +1 -0
  72. package/dist/types/types/worker.d.ts.map +1 -0
  73. package/dist/types/worker/WorkerGlobalScope.d.ts +6 -0
  74. package/dist/types/worker/WorkerGlobalScope.d.ts.map +1 -0
  75. package/dist/types/worker/expose.d.ts +4 -0
  76. package/dist/types/worker/expose.d.ts.map +1 -0
  77. package/dist/types/worker/worker.browser.d.ts +14 -0
  78. package/dist/types/worker/worker.browser.d.ts.map +1 -0
  79. package/dist/types/worker/worker.node.d.ts +25 -0
  80. package/dist/types/worker/worker.node.d.ts.map +1 -0
  81. package/package.json +66 -77
  82. package/src/common.ts +10 -6
  83. package/src/index.ts +10 -9
  84. package/src/master/get-bundle-url.browser.ts +2 -1
  85. package/src/master/implementation.browser.ts +2 -2
  86. package/src/master/implementation.node.ts +19 -96
  87. package/src/master/implementation.ts +2 -2
  88. package/src/master/index.ts +7 -7
  89. package/src/master/invocation-proxy.ts +6 -6
  90. package/src/master/pool-types.ts +1 -1
  91. package/src/master/pool.ts +14 -13
  92. package/src/master/register.ts +2 -1
  93. package/src/master/spawn.ts +8 -8
  94. package/src/master/thread.ts +2 -2
  95. package/src/observable-promise.ts +3 -2
  96. package/src/serializers.ts +1 -1
  97. package/src/transferable.ts +2 -1
  98. package/src/types/master.ts +3 -3
  99. package/src/worker/WorkerGlobalScope.ts +5 -0
  100. package/src/worker/expose.ts +234 -0
  101. package/src/worker/is-observable.d.ts +7 -0
  102. package/src/worker/{implementation.browser.ts → worker.browser.ts} +26 -10
  103. package/src/worker/{implementation.worker_threads.ts → worker.node.ts} +30 -12
  104. package/types/is-observable.d.ts +1 -1
  105. package/xy.config.ts +24 -0
  106. package/dist/common.js +0 -16
  107. package/dist/esm/common.js +0 -16
  108. package/dist/esm/index.js +0 -26
  109. package/dist/esm/master/get-bundle-url.browser.js +0 -25
  110. package/dist/esm/master/implementation.browser.js +0 -65
  111. package/dist/esm/master/implementation.js +0 -43
  112. package/dist/esm/master/implementation.node.js +0 -205
  113. package/dist/esm/master/index.js +0 -14
  114. package/dist/esm/master/invocation-proxy.js +0 -121
  115. package/dist/esm/master/pool-types.js +0 -14
  116. package/dist/esm/master/pool.js +0 -262
  117. package/dist/esm/master/register.js +0 -11
  118. package/dist/esm/master/spawn.js +0 -114
  119. package/dist/esm/master/thread.js +0 -18
  120. package/dist/esm/observable-promise.js +0 -132
  121. package/dist/esm/observable.js +0 -33
  122. package/dist/esm/ponyfills.js +0 -20
  123. package/dist/esm/promise.js +0 -23
  124. package/dist/esm/serializers.js +0 -41
  125. package/dist/esm/symbols.js +0 -8
  126. package/dist/esm/transferable.js +0 -25
  127. package/dist/esm/types/master.js +0 -9
  128. package/dist/esm/types/messages.js +0 -16
  129. package/dist/esm/types/worker.js +0 -2
  130. package/dist/esm/worker/bundle-entry.js +0 -26
  131. package/dist/esm/worker/implementation.browser.js +0 -24
  132. package/dist/esm/worker/implementation.js +0 -19
  133. package/dist/esm/worker/implementation.tiny-worker.js +0 -37
  134. package/dist/esm/worker/implementation.worker_threads.js +0 -41
  135. package/dist/esm/worker/index.js +0 -174
  136. package/dist/esm/worker_threads.js +0 -13
  137. package/dist/index.d.ts +0 -7
  138. package/dist/index.js +0 -26
  139. package/dist/master/get-bundle-url.browser.js +0 -25
  140. package/dist/master/implementation.browser.js +0 -65
  141. package/dist/master/implementation.js +0 -43
  142. package/dist/master/implementation.node.js +0 -205
  143. package/dist/master/index.d.ts +0 -10
  144. package/dist/master/index.js +0 -14
  145. package/dist/master/invocation-proxy.js +0 -121
  146. package/dist/master/pool-types.js +0 -14
  147. package/dist/master/pool.d.ts +0 -50
  148. package/dist/master/pool.js +0 -262
  149. package/dist/master/register.d.ts +0 -1
  150. package/dist/master/register.js +0 -11
  151. package/dist/master/spawn.js +0 -114
  152. package/dist/master/thread.d.ts +0 -8
  153. package/dist/master/thread.js +0 -18
  154. package/dist/observable-promise.js +0 -132
  155. package/dist/observable.d.ts +0 -11
  156. package/dist/observable.js +0 -33
  157. package/dist/ponyfills.js +0 -20
  158. package/dist/promise.d.ts +0 -1
  159. package/dist/promise.js +0 -23
  160. package/dist/serializers.js +0 -41
  161. package/dist/symbols.js +0 -8
  162. package/dist/transferable.d.ts +0 -9
  163. package/dist/transferable.js +0 -25
  164. package/dist/types/master.js +0 -9
  165. package/dist/types/messages.js +0 -16
  166. package/dist/types/worker.js +0 -2
  167. package/dist/worker/bundle-entry.d.ts +0 -1
  168. package/dist/worker/bundle-entry.js +0 -26
  169. package/dist/worker/implementation.browser.d.ts +0 -6
  170. package/dist/worker/implementation.browser.js +0 -24
  171. package/dist/worker/implementation.d.ts +0 -3
  172. package/dist/worker/implementation.js +0 -19
  173. package/dist/worker/implementation.tiny-worker.d.ts +0 -6
  174. package/dist/worker/implementation.tiny-worker.js +0 -37
  175. package/dist/worker/implementation.worker_threads.d.ts +0 -8
  176. package/dist/worker/implementation.worker_threads.js +0 -41
  177. package/dist/worker/index.d.ts +0 -5
  178. package/dist/worker/index.js +0 -174
  179. package/dist/worker_threads.d.ts +0 -8
  180. package/dist/worker_threads.js +0 -13
  181. package/observable.d.ts +0 -2
  182. package/observable.js +0 -2
  183. package/observable.mjs +0 -4
  184. package/register.d.ts +0 -2
  185. package/register.js +0 -2
  186. package/register.mjs +0 -1
  187. package/rollup.config.js +0 -16
  188. package/src/worker/bundle-entry.ts +0 -10
  189. package/src/worker/implementation.tiny-worker.ts +0 -55
  190. package/src/worker/implementation.ts +0 -23
  191. package/src/worker/index.ts +0 -230
  192. package/src/worker_threads.ts +0 -27
  193. package/test/lib/index.ts +0 -1
  194. package/test/lib/serialization.ts +0 -38
  195. package/test/observable-promise.test.ts +0 -205
  196. package/test/observable.test.ts +0 -87
  197. package/test/pool.test.ts +0 -183
  198. package/test/serialization.test.ts +0 -23
  199. package/test/spawn.chromium.mocha.ts +0 -53
  200. package/test/spawn.test.ts +0 -87
  201. package/test/streaming.test.ts +0 -29
  202. package/test/transferables.test.ts +0 -71
  203. package/test/workers/arraybuffer-xor.ts +0 -10
  204. package/test/workers/count-to-five.ts +0 -12
  205. package/test/workers/counter.ts +0 -19
  206. package/test/workers/faulty-function.ts +0 -5
  207. package/test/workers/hello-world.ts +0 -5
  208. package/test/workers/increment.ts +0 -8
  209. package/test/workers/minmax.ts +0 -25
  210. package/test/workers/serialization.ts +0 -13
  211. package/test/workers/top-level-throw.ts +0 -1
  212. package/test-tooling/rollup/app.js +0 -21
  213. package/test-tooling/rollup/rollup.config.ts +0 -14
  214. package/test-tooling/rollup/worker.js +0 -7
  215. package/test-tooling/tsconfig/minimal.ts +0 -12
  216. package/test-tooling/webpack/addition-worker.ts +0 -9
  217. package/test-tooling/webpack/app-with-inlined-worker.ts +0 -28
  218. package/test-tooling/webpack/app.ts +0 -61
  219. package/test-tooling/webpack/pool-worker.ts +0 -5
  220. package/test-tooling/webpack/raw-loader.d.ts +0 -4
  221. package/test-tooling/webpack/webpack.chromium.mocha.ts +0 -21
  222. package/test-tooling/webpack/webpack.node.config.js +0 -29
  223. package/test-tooling/webpack/webpack.web.config.js +0 -28
  224. package/types/webworker.d.ts +0 -9
  225. package/worker.d.ts +0 -2
  226. package/worker.js +0 -2
  227. package/worker.mjs +0 -6
@@ -1,205 +0,0 @@
1
- /* eslint-disable import-x/no-internal-modules */
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
3
-
4
- import { Observable } from 'observable-fns'
5
- import { expect, test } from 'vitest'
6
-
7
- import { ObservablePromise } from '../src/observable-promise'
8
-
9
- const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
10
-
11
- test('can create an observable promise', async () => {
12
- expect.assertions(1)
13
-
14
- await new ObservablePromise((observer) => {
15
- expect(true).toBe(true)
16
- observer.complete()
17
- })
18
- })
19
-
20
- test('init function is only called once', async () => {
21
- let initCallCount = 0
22
-
23
- const async = new ObservablePromise((observer) => {
24
- initCallCount++
25
- setTimeout(() => observer.complete(), 10)
26
- })
27
-
28
- await Promise.all([
29
- async.then(() => expect(true).toBe(true)),
30
- async.then(() => expect(true).toBe(true)),
31
- async.then(() => expect(true).toBe(true)),
32
- ])
33
-
34
- expect(initCallCount).toBe(1)
35
- })
36
-
37
- test('can proxy a promise fulfillment', async () => {
38
- expect.assertions(2) // Ensure two assertions are made
39
-
40
- const async = new ObservablePromise((observer) => {
41
- setTimeout(() => {
42
- observer.next(123)
43
-
44
- // Ignore all values after the first one
45
- observer.next(456)
46
- observer.complete()
47
- }, 1)
48
- })
49
-
50
- const promise1 = async.then(
51
- value => expect(value).toBe(123),
52
- () => expect.fail('Promise was rejected unexpectedly'),
53
- )
54
-
55
- await delay(10)
56
-
57
- const promise2 = async.then(
58
- value => expect(value).toBe(123),
59
- () => expect.fail('Promise was rejected unexpectedly'),
60
- )
61
-
62
- await Promise.all([promise1, promise2])
63
- })
64
-
65
- test('can proxy a promise rejection', async () => {
66
- let handlerCallCount = 0
67
-
68
- const async = new ObservablePromise((observer) => {
69
- setTimeout(() => observer.error(new Error('I am supposed to be rejected.')), 1)
70
- })
71
-
72
- const promise1 = async.then(
73
- () => expect.fail('Promise should not become fulfilled'),
74
- () => handlerCallCount++,
75
- )
76
-
77
- await delay(10)
78
-
79
- const promise2 = async.then(
80
- () => expect.fail('Promise should not become fulfilled'),
81
- () => handlerCallCount++,
82
- )
83
-
84
- await Promise.all([promise1.catch(() => true), promise2.catch(() => true)])
85
- expect(handlerCallCount).toBe(2)
86
- })
87
-
88
- test('can proxy a promise rejection caused by a sync throw', async () => {
89
- let handlerCallCount = 0
90
-
91
- const async = new ObservablePromise(() => {
92
- throw new Error('I am supposed to be rejected.')
93
- })
94
-
95
- const promise1 = async.then(
96
- () => expect.fail('Promise should not become fulfilled'),
97
- () => handlerCallCount++,
98
- )
99
-
100
- await delay(10)
101
-
102
- const promise2 = async.then(
103
- () => expect.fail('Promise should not become fulfilled'),
104
- () => handlerCallCount++,
105
- )
106
-
107
- await Promise.all([promise1.catch(() => true), promise2.catch(() => true)])
108
- expect(handlerCallCount).toBe(2)
109
- })
110
-
111
- test('can subscribe to values and completion', async () => {
112
- const capturedValues: any[] = []
113
- let capturedCompletions = 0
114
-
115
- const async = new ObservablePromise((observer) => {
116
- setTimeout(() => observer.next(1), 10)
117
- setTimeout(() => observer.next(2), 20)
118
- setTimeout(() => observer.complete(), 30)
119
- })
120
-
121
- for (let index = 0; index < 2; index++) {
122
- async.subscribe(
123
- value => capturedValues.push(value),
124
- () => {},
125
- () => capturedCompletions++,
126
- )
127
- }
128
-
129
- await async.finally()
130
- await delay(1)
131
-
132
- expect(capturedValues).toEqual([1, 1, 2, 2])
133
- expect(capturedCompletions).toBe(2)
134
- })
135
-
136
- test('can subscribe to errors', async () => {
137
- const capturedErrorMessages: string[] = []
138
- const capturedValues: any[] = []
139
- let capturedCompletions = 0
140
-
141
- const async = new ObservablePromise((observer) => {
142
- setTimeout(() => observer.next(1), 10)
143
- setTimeout(() => observer.error(new Error('Fails as expected.')), 20)
144
- setTimeout(() => observer.next(2), 30) // This won't be called due to error
145
- setTimeout(() => observer.complete(), 40) // This also won't be called
146
- })
147
-
148
- for (let index = 0; index < 2; index++) {
149
- async.subscribe(
150
- value => capturedValues.push(value),
151
- error => capturedErrorMessages.push(error.message),
152
- () => capturedCompletions++,
153
- )
154
- }
155
-
156
- await async.finally()
157
- await delay(35) // Wait to ensure the error and all async events are captured
158
-
159
- expect(capturedValues).toEqual([1, 1])
160
- expect(capturedErrorMessages).toEqual(['Fails as expected.', 'Fails as expected.'])
161
- expect(capturedCompletions).toBe(0)
162
- })
163
-
164
- test('from(Observable) works', async () => {
165
- const capturedErrorMessages: string[] = []
166
- const capturedValues: any[] = []
167
- let capturedCompletions = 0
168
-
169
- const async = ObservablePromise.from(
170
- new Observable((observer) => {
171
- setTimeout(() => observer.next(1), 10)
172
- setTimeout(() => observer.error(new Error('Fails as expected.')), 20)
173
- setTimeout(() => observer.next(2), 30) // This won't be called due to error
174
- setTimeout(() => observer.complete(), 40) // This also won't be called
175
- }),
176
- )
177
-
178
- for (let index = 0; index < 2; index++) {
179
- async.subscribe(
180
- value => capturedValues.push(value),
181
- error => capturedErrorMessages.push(error.message),
182
- () => capturedCompletions++,
183
- )
184
- }
185
-
186
- await async.finally()
187
- await delay(35) // Allow time for error and async processing
188
-
189
- expect(capturedValues).toEqual([1, 1])
190
- expect(capturedErrorMessages).toEqual(['Fails as expected.', 'Fails as expected.'])
191
- expect(capturedCompletions).toBe(0)
192
- })
193
-
194
- test('from(Promise) works', async () => {
195
- const resolved = ObservablePromise.from(
196
- new Promise((resolve) => {
197
- setTimeout(() => resolve('Works'), 10)
198
- }),
199
- )
200
-
201
- await expect(resolved).resolves.toBe('Works')
202
-
203
- const rejected = ObservablePromise.from(Promise.reject(new Error('Fails')))
204
- await expect(rejected).rejects.toThrow('Fails')
205
- })
@@ -1,87 +0,0 @@
1
- /* eslint-disable import-x/no-internal-modules */
2
- /* eslint-disable require-await */
3
-
4
- import { expect, test } from 'vitest'
5
-
6
- import { Observable, Subject } from '../src/observable'
7
-
8
- test('Observable subject emits values and completion event', async () => {
9
- let completed1 = false
10
- const values1: number[] = []
11
- let completed2 = false
12
- const values2: number[] = []
13
- let completed3 = false
14
- const values3: number[] = []
15
-
16
- const subject = new Subject<number>()
17
- const observable = Observable.from(subject)
18
-
19
- const subscription1 = subject.subscribe(
20
- value => values1.push(value),
21
- undefined,
22
- () => (completed1 = false),
23
- )
24
- subject.subscribe(
25
- value => values2.push(value),
26
- undefined,
27
- () => (completed2 = true),
28
- )
29
- observable.subscribe(
30
- value => values3.push(value),
31
- undefined,
32
- () => (completed3 = true),
33
- )
34
-
35
- subject.next(1)
36
- subscription1.unsubscribe()
37
-
38
- subject.next(2)
39
- subject.complete()
40
-
41
- expect(values1).toEqual([1])
42
- expect(values2).toEqual([1, 2])
43
- expect(values3).toEqual([1, 2])
44
- expect(completed1).toBe(false)
45
- expect(completed2).toBe(true)
46
- expect(completed3).toBe(true)
47
- })
48
-
49
- test('Observable subject propagates errors', async () => {
50
- let completed1 = false
51
- let error1: Error | undefined
52
- let completed2 = false
53
- let error2: Error | undefined
54
- let completed3 = false
55
- let error3: Error | undefined
56
-
57
- const subject = new Subject<number>()
58
- const observable = Observable.from(subject)
59
-
60
- const subscription1 = subject.subscribe(
61
- () => {},
62
- error => (error1 = error),
63
- () => (completed1 = true),
64
- )
65
- subject.subscribe(
66
- () => {},
67
- error => (error2 = error),
68
- () => (completed2 = true),
69
- )
70
- observable.subscribe(
71
- () => {},
72
- error => (error3 = error),
73
- () => (completed3 = true),
74
- )
75
-
76
- const testingError = new Error('Test, test!')
77
-
78
- subscription1.unsubscribe()
79
- subject.error(testingError)
80
-
81
- expect(completed1).toBe(false)
82
- expect(error1).toBeUndefined()
83
- expect(completed2).toBe(false)
84
- expect(error2).toBe(testingError)
85
- expect(completed3).toBe(false)
86
- expect(error3).toBe(testingError)
87
- })
package/test/pool.test.ts DELETED
@@ -1,183 +0,0 @@
1
- /* eslint-disable import-x/no-internal-modules */
2
-
3
- /* eslint-disable require-await */
4
- /* eslint-disable @typescript-eslint/no-explicit-any */
5
-
6
- // eslint-disable import-x/no-internal-modules
7
- import { expect, test } from 'vitest'
8
-
9
- import type { FunctionThread } from '../src/index'
10
- import {
11
- Pool, spawn, Worker,
12
- } from '../src/index'
13
- import type { PoolEvent, QueuedTask } from '../src/master/pool'
14
- import { PoolEventType } from '../src/master/pool'
15
-
16
- const workerPath = './workers/hello-world.ts'
17
- const HELLO_WORLD = 'Hello World'
18
-
19
- test('thread pool basics work and events are emitted', async () => {
20
- const events: Pool.Event[] = []
21
- let spawnCalled = 0
22
- let taskFnCalled = 0
23
-
24
- const spawnHelloWorld = () => {
25
- spawnCalled++
26
- return spawn<() => string>(new Worker(workerPath))
27
- }
28
-
29
- const pool = Pool(spawnHelloWorld, 3)
30
- pool.events().subscribe(event => events.push(event))
31
-
32
- // Ensure all worker threads are initialized before starting to queue tasks
33
- await new Promise<PoolEvent<FunctionThread<[], string>>>((resolve, reject) => {
34
- pool
35
- .events()
36
- .filter(event => event.type === Pool.EventType.initialized)
37
- .subscribe(resolve, reject)
38
- })
39
-
40
- await pool.queue(async (helloWorld) => {
41
- taskFnCalled++
42
- const result = await helloWorld()
43
- expect(result).toBe(HELLO_WORLD)
44
- return result
45
- })
46
-
47
- await pool.terminate()
48
-
49
- expect(spawnCalled).toBe(3)
50
- expect(taskFnCalled).toBe(1)
51
-
52
- expect(events).toEqual([
53
- {
54
- size: 3,
55
- type: Pool.EventType.initialized,
56
- },
57
- {
58
- taskID: 1,
59
- type: Pool.EventType.taskQueued,
60
- },
61
- {
62
- taskID: 1,
63
- type: Pool.EventType.taskStart,
64
- workerID: 1,
65
- },
66
- {
67
- returnValue: HELLO_WORLD,
68
- taskID: 1,
69
- type: Pool.EventType.taskCompleted,
70
- workerID: 1,
71
- },
72
- { type: Pool.EventType.taskQueueDrained },
73
- {
74
- remainingQueue: [],
75
- type: Pool.EventType.terminated,
76
- },
77
- ])
78
- })
79
-
80
- test('pool.completed() works', async () => {
81
- const returned: any[] = []
82
-
83
- const spawnHelloWorld = () => spawn(new Worker(workerPath))
84
- const pool = Pool(spawnHelloWorld, 2)
85
-
86
- for (let i = 0; i < 3; i++) {
87
- pool.queue(async (helloWorld) => {
88
- returned.push(await helloWorld())
89
- })
90
- }
91
-
92
- await pool.completed()
93
-
94
- expect(returned).toEqual([HELLO_WORLD, HELLO_WORLD, HELLO_WORLD])
95
- })
96
-
97
- test('pool.completed() proxies errors', async () => {
98
- const spawnHelloWorld = () => spawn(new Worker(workerPath))
99
- const pool = Pool(spawnHelloWorld, 2)
100
-
101
- pool.queue(async () => {
102
- throw new Error('Ooopsie')
103
- })
104
-
105
- await expect(pool.completed()).rejects.toThrow('Ooopsie')
106
- })
107
-
108
- test('pool.completed(true) works', async () => {
109
- const spawnHelloWorld = () => spawn(new Worker(workerPath))
110
- const pool = Pool(spawnHelloWorld, 2)
111
-
112
- await pool.completed(true)
113
-
114
- expect(true).toBe(true) // Equivalent to t.pass() in Vitest
115
- })
116
-
117
- test('pool.settled() does not reject on task failure', async () => {
118
- const returned: any[] = []
119
-
120
- const spawnHelloWorld = () => spawn(new Worker(workerPath))
121
- const pool = Pool(spawnHelloWorld, 2)
122
-
123
- pool.queue(async (helloWorld) => {
124
- returned.push(await helloWorld())
125
- })
126
- pool.queue(async () => {
127
- throw new Error('Test error one')
128
- })
129
- pool.queue(async () => {
130
- throw new Error('Test error two')
131
- })
132
-
133
- const errors = await pool.settled()
134
-
135
- expect(errors.length).toBe(2)
136
- expect(errors.map(error => error.message).sort()).toEqual(['Test error one', 'Test error two'])
137
- })
138
-
139
- test('pool.settled(true) works', async () => {
140
- const spawnHelloWorld = () => spawn(new Worker(workerPath))
141
- const pool = Pool(spawnHelloWorld, 2)
142
-
143
- await pool.settled(true)
144
-
145
- expect(true).toBe(true) // Equivalent to t.pass() in Vitest
146
- })
147
-
148
- test('task.cancel() works', async () => {
149
- const events: Pool.Event[] = []
150
- const spawnHelloWorld = () => spawn(new Worker(workerPath))
151
- const pool = Pool(spawnHelloWorld, 1)
152
-
153
- pool.events().subscribe(event => events.push(event))
154
-
155
- let executionCount = 0
156
- const tasks: QueuedTask<any, any>[] = []
157
-
158
- for (let i = 0; i < 4; i++) {
159
- const task = pool.queue((helloWorld) => {
160
- executionCount++
161
- return helloWorld()
162
- })
163
- tasks.push(task)
164
- }
165
-
166
- tasks[2].cancel()
167
- tasks[3].cancel()
168
-
169
- await pool.completed()
170
- expect(executionCount).toBe(2)
171
-
172
- const cancellationEvents = events.filter(event => event.type === PoolEventType.taskCanceled)
173
- expect(cancellationEvents).toEqual([
174
- {
175
- taskID: 3,
176
- type: PoolEventType.taskCanceled,
177
- },
178
- {
179
- taskID: 4,
180
- type: PoolEventType.taskCanceled,
181
- },
182
- ])
183
- })
@@ -1,23 +0,0 @@
1
- /* eslint-disable import-x/no-internal-modules */
2
- import { expect, test } from 'vitest'
3
-
4
- import {
5
- registerSerializer, spawn, Thread, Worker,
6
- } from '../src/index'
7
- import { Foo, fooSerializer } from './lib/serialization'
8
-
9
- registerSerializer(fooSerializer)
10
-
11
- test('can use a custom serializer', async () => {
12
- const run = await spawn(new Worker('./workers/serialization.ts'))
13
-
14
- try {
15
- const input = new Foo('Test')
16
- const result: Foo<string> = await run(input)
17
-
18
- expect(result).toBeInstanceOf(Foo)
19
- expect(result.getValue()).toBe('TestTest')
20
- } finally {
21
- await Thread.terminate(run)
22
- }
23
- })
@@ -1,53 +0,0 @@
1
- /* eslint-disable import-x/no-internal-modules */
2
- /* eslint-disable no-restricted-imports */
3
- /*
4
- * This code here will be run in a headless Chromium browser using `puppet-run`.
5
- * Check the package.json scripts `test:puppeteer:*`.
6
- */
7
-
8
- // We need this as a work-around to make our threads Worker global, since
9
- // the bundler would otherwise not recognize `new Worker()` as a web worker
10
- import '../src/master/register'
11
-
12
- import {
13
- describe, expect, it,
14
- } from 'vitest'
15
-
16
- import {
17
- BlobWorker, spawn, Thread,
18
- } from '..'
19
-
20
- describe('threads in browser', function () {
21
- it('can spawn and terminate a thread', async function () {
22
- const helloWorld = await spawn<() => string>(new Worker('./workers/hello-world.ts'))
23
- expect(await helloWorld()).to.equal('Hello World')
24
- await Thread.terminate(helloWorld)
25
- })
26
-
27
- it('can call a function thread more than once', async function () {
28
- const increment = await spawn<() => number>(new Worker('./workers/increment.ts'))
29
- expect(await increment()).to.equal(1)
30
- expect(await increment()).to.equal(2)
31
- expect(await increment()).to.equal(3)
32
- await Thread.terminate(increment)
33
- })
34
-
35
- it('can spawn and use a blob worker', async function () {
36
- const baseUrl = new URL(globalThis.location.href).origin
37
- const workerSource = `
38
- // Makes expose() available on global scope
39
- importScripts(${JSON.stringify(baseUrl + '/worker.js')})
40
-
41
- let counter = 0
42
-
43
- expose(function() {
44
- return ++counter
45
- })
46
- `
47
- const increment = await spawn<() => number>(BlobWorker.fromText(workerSource))
48
- expect(await increment()).to.equal(1)
49
- expect(await increment()).to.equal(2)
50
- expect(await increment()).to.equal(3)
51
- await Thread.terminate(increment)
52
- })
53
- })
@@ -1,87 +0,0 @@
1
- /* eslint-disable import-x/no-internal-modules */
2
-
3
- /* eslint-disable @typescript-eslint/no-explicit-any */
4
-
5
- import { builtinModules } from 'node:module'
6
-
7
- import type { Observable } from 'observable-fns'
8
- import { expect, test } from 'vitest'
9
-
10
- import {
11
- spawn, Thread, Worker,
12
- } from '../src/index'
13
- import type { Counter } from './workers/counter.ts'
14
-
15
- test('can spawn and terminate a thread', async () => {
16
- // We also test here that running spawn() without type parameters works
17
- const helloWorld = await spawn(new Worker('./workers/hello-world.ts'))
18
-
19
- expect(await helloWorld()).toBe('Hello World')
20
- await Thread.terminate(helloWorld)
21
-
22
- expect(true).toBe(true) // Equivalent to t.pass() in Vitest
23
- })
24
-
25
- test('can call a function thread more than once', async () => {
26
- const increment = await spawn<() => number>(new Worker('./workers/increment.ts'))
27
-
28
- expect(await increment()).toBe(1)
29
- expect(await increment()).toBe(2)
30
- expect(await increment()).toBe(3)
31
-
32
- await Thread.terminate(increment)
33
- })
34
-
35
- test('can subscribe to an observable returned by a thread call', async () => {
36
- const countToFive = await spawn<() => Observable<number>>(new Worker('./workers/count-to-five.ts'))
37
- const encounteredValues: any[] = []
38
-
39
- const observable = countToFive()
40
- observable.subscribe(value => encounteredValues.push(value))
41
- await observable
42
-
43
- expect(encounteredValues).toEqual([1, 2, 3, 4, 5])
44
- await Thread.terminate(countToFive)
45
- })
46
-
47
- test('can spawn a module thread', async () => {
48
- const counter = await spawn<Counter>(new Worker('./workers/counter.ts'))
49
-
50
- expect(await counter.getCount()).toBe(0)
51
-
52
- await Promise.all([counter.increment(), counter.increment()])
53
- expect(await counter.getCount()).toBe(2)
54
-
55
- await counter.decrement()
56
- expect(await counter.getCount()).toBe(1)
57
-
58
- await Thread.terminate(counter)
59
- })
60
-
61
- test('thread job errors are handled', async () => {
62
- const fail = await spawn<() => Promise<never>>(new Worker('./workers/faulty-function.ts'))
63
-
64
- await expect(fail()).rejects.toThrow('I am supposed to fail.')
65
-
66
- await Thread.terminate(fail)
67
- })
68
-
69
- test('thread transfer errors are handled', async () => {
70
- if (builtinModules.includes('worker_threads')) {
71
- // Test is applicable only for native worker_threads
72
- const helloWorld = await spawn(new Worker('./workers/hello-world.ts'))
73
- const badTransferObj = { fn: () => {} }
74
-
75
- await expect(helloWorld(badTransferObj)).rejects.toThrow()
76
-
77
- await Thread.terminate(helloWorld)
78
- } else {
79
- expect(true).toBe(true) // Equivalent to t.pass() in Vitest
80
- }
81
- })
82
-
83
- /* test('catches top-level thread errors', async () => {
84
- await expect(spawn(new Worker('./workers/top-level-throw.ts'))).rejects.toThrow()
85
- }) */
86
-
87
- test.todo('can subscribe to thread events')
@@ -1,29 +0,0 @@
1
- import { expect, test } from 'vitest'
2
-
3
- import {
4
- spawn, Thread, Worker,
5
- } from '../src/index'
6
-
7
- test('can use worker returning an observable subject', async () => {
8
- const captured: Array<{ max: number; min: number }> = []
9
-
10
- const minmax = await spawn(new Worker('./workers/minmax.ts'))
11
- minmax.values().subscribe(values => captured.push(values))
12
-
13
- await minmax.push(2)
14
- await minmax.push(3)
15
- await minmax.push(4)
16
- await minmax.push(1)
17
- await minmax.push(5)
18
- await minmax.finish()
19
-
20
- await Thread.terminate(minmax)
21
-
22
- expect(captured).toEqual([
23
- { max: 2, min: 2 },
24
- { max: 3, min: 2 },
25
- { max: 4, min: 2 },
26
- { max: 4, min: 1 },
27
- { max: 5, min: 1 },
28
- ])
29
- })