@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.
- package/dist/browser/master/implementation.browser.mjs +89 -0
- package/dist/browser/master/implementation.browser.mjs.map +1 -0
- package/dist/browser/worker/worker.browser.mjs +291 -0
- package/dist/browser/worker/worker.browser.mjs.map +1 -0
- package/dist/neutral/index.mjs +1022 -0
- package/dist/neutral/index.mjs.map +1 -0
- package/dist/neutral/master/implementation.mjs +264 -0
- package/dist/neutral/master/implementation.mjs.map +1 -0
- package/dist/neutral/master/index.mjs +988 -0
- package/dist/neutral/master/index.mjs.map +1 -0
- package/dist/neutral/master/pool.mjs +579 -0
- package/dist/neutral/master/pool.mjs.map +1 -0
- package/dist/neutral/master/register.mjs +272 -0
- package/dist/neutral/master/register.mjs.map +1 -0
- package/dist/neutral/master/spawn.mjs +412 -0
- package/dist/neutral/master/spawn.mjs.map +1 -0
- package/dist/neutral/master/thread.mjs +29 -0
- package/dist/neutral/master/thread.mjs.map +1 -0
- package/dist/neutral/observable-promise.mjs +132 -0
- package/dist/neutral/observable-promise.mjs.map +1 -0
- package/dist/neutral/observable.mjs +31 -0
- package/dist/neutral/observable.mjs.map +1 -0
- package/dist/node/master/implementation.node.mjs +154 -0
- package/dist/node/master/implementation.node.mjs.map +1 -0
- package/dist/node/worker/worker.node.mjs +304 -0
- package/dist/node/worker/worker.node.mjs.map +1 -0
- package/dist/{common.d.ts → types/common.d.ts} +5 -1
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/{master → types/master}/get-bundle-url.browser.d.ts +1 -0
- package/dist/types/master/get-bundle-url.browser.d.ts.map +1 -0
- package/dist/{master → types/master}/implementation.browser.d.ts +2 -1
- package/dist/types/master/implementation.browser.d.ts.map +1 -0
- package/dist/{master → types/master}/implementation.d.ts +4 -1
- package/dist/types/master/implementation.d.ts.map +1 -0
- package/dist/{master → types/master}/implementation.node.d.ts +2 -1
- package/dist/types/master/implementation.node.d.ts.map +1 -0
- package/dist/types/master/index.d.ts +13 -0
- package/dist/types/master/index.d.ts.map +1 -0
- package/dist/{master → types/master}/invocation-proxy.d.ts +2 -1
- package/dist/types/master/invocation-proxy.d.ts.map +1 -0
- package/dist/{master → types/master}/pool-types.d.ts +16 -1
- package/dist/types/master/pool-types.d.ts.map +1 -0
- package/dist/types/master/pool.d.ts +93 -0
- package/dist/types/master/pool.d.ts.map +1 -0
- package/dist/types/master/register.d.ts +2 -0
- package/dist/types/master/register.d.ts.map +1 -0
- package/dist/{master → types/master}/spawn.d.ts +12 -2
- package/dist/types/master/spawn.d.ts.map +1 -0
- package/dist/types/master/thread.d.ts +13 -0
- package/dist/types/master/thread.d.ts.map +1 -0
- package/dist/{observable-promise.d.ts → types/observable-promise.d.ts} +14 -0
- package/dist/types/observable-promise.d.ts.map +1 -0
- package/dist/types/observable.d.ts +21 -0
- package/dist/types/observable.d.ts.map +1 -0
- package/dist/{ponyfills.d.ts → types/ponyfills.d.ts} +1 -0
- package/dist/types/ponyfills.d.ts.map +1 -0
- package/dist/types/promise.d.ts +6 -0
- package/dist/types/promise.d.ts.map +1 -0
- package/dist/{serializers.d.ts → types/serializers.d.ts} +1 -0
- package/dist/types/serializers.d.ts.map +1 -0
- package/dist/{symbols.d.ts → types/symbols.d.ts} +1 -0
- package/dist/types/symbols.d.ts.map +1 -0
- package/dist/types/transferable.d.ts +43 -0
- package/dist/types/transferable.d.ts.map +1 -0
- package/dist/types/{master.d.ts → types/master.d.ts} +17 -3
- package/dist/types/types/master.d.ts.map +1 -0
- package/dist/types/{messages.d.ts → types/messages.d.ts} +1 -0
- package/dist/types/types/messages.d.ts.map +1 -0
- package/dist/types/{worker.d.ts → types/worker.d.ts} +1 -0
- package/dist/types/types/worker.d.ts.map +1 -0
- package/dist/types/worker/WorkerGlobalScope.d.ts +6 -0
- package/dist/types/worker/WorkerGlobalScope.d.ts.map +1 -0
- package/dist/types/worker/expose.d.ts +4 -0
- package/dist/types/worker/expose.d.ts.map +1 -0
- package/dist/types/worker/worker.browser.d.ts +14 -0
- package/dist/types/worker/worker.browser.d.ts.map +1 -0
- package/dist/types/worker/worker.node.d.ts +25 -0
- package/dist/types/worker/worker.node.d.ts.map +1 -0
- package/package.json +66 -77
- package/src/common.ts +10 -6
- package/src/index.ts +10 -9
- package/src/master/get-bundle-url.browser.ts +2 -1
- package/src/master/implementation.browser.ts +2 -2
- package/src/master/implementation.node.ts +19 -96
- package/src/master/implementation.ts +2 -2
- package/src/master/index.ts +7 -7
- package/src/master/invocation-proxy.ts +6 -6
- package/src/master/pool-types.ts +1 -1
- package/src/master/pool.ts +14 -13
- package/src/master/register.ts +2 -1
- package/src/master/spawn.ts +8 -8
- package/src/master/thread.ts +2 -2
- package/src/observable-promise.ts +3 -2
- package/src/serializers.ts +1 -1
- package/src/transferable.ts +2 -1
- package/src/types/master.ts +3 -3
- package/src/worker/WorkerGlobalScope.ts +5 -0
- package/src/worker/expose.ts +234 -0
- package/src/worker/is-observable.d.ts +7 -0
- package/src/worker/{implementation.browser.ts → worker.browser.ts} +26 -10
- package/src/worker/{implementation.worker_threads.ts → worker.node.ts} +30 -12
- package/types/is-observable.d.ts +1 -1
- package/xy.config.ts +24 -0
- package/dist/common.js +0 -16
- package/dist/esm/common.js +0 -16
- package/dist/esm/index.js +0 -26
- package/dist/esm/master/get-bundle-url.browser.js +0 -25
- package/dist/esm/master/implementation.browser.js +0 -65
- package/dist/esm/master/implementation.js +0 -43
- package/dist/esm/master/implementation.node.js +0 -205
- package/dist/esm/master/index.js +0 -14
- package/dist/esm/master/invocation-proxy.js +0 -121
- package/dist/esm/master/pool-types.js +0 -14
- package/dist/esm/master/pool.js +0 -262
- package/dist/esm/master/register.js +0 -11
- package/dist/esm/master/spawn.js +0 -114
- package/dist/esm/master/thread.js +0 -18
- package/dist/esm/observable-promise.js +0 -132
- package/dist/esm/observable.js +0 -33
- package/dist/esm/ponyfills.js +0 -20
- package/dist/esm/promise.js +0 -23
- package/dist/esm/serializers.js +0 -41
- package/dist/esm/symbols.js +0 -8
- package/dist/esm/transferable.js +0 -25
- package/dist/esm/types/master.js +0 -9
- package/dist/esm/types/messages.js +0 -16
- package/dist/esm/types/worker.js +0 -2
- package/dist/esm/worker/bundle-entry.js +0 -26
- package/dist/esm/worker/implementation.browser.js +0 -24
- package/dist/esm/worker/implementation.js +0 -19
- package/dist/esm/worker/implementation.tiny-worker.js +0 -37
- package/dist/esm/worker/implementation.worker_threads.js +0 -41
- package/dist/esm/worker/index.js +0 -174
- package/dist/esm/worker_threads.js +0 -13
- package/dist/index.d.ts +0 -7
- package/dist/index.js +0 -26
- package/dist/master/get-bundle-url.browser.js +0 -25
- package/dist/master/implementation.browser.js +0 -65
- package/dist/master/implementation.js +0 -43
- package/dist/master/implementation.node.js +0 -205
- package/dist/master/index.d.ts +0 -10
- package/dist/master/index.js +0 -14
- package/dist/master/invocation-proxy.js +0 -121
- package/dist/master/pool-types.js +0 -14
- package/dist/master/pool.d.ts +0 -50
- package/dist/master/pool.js +0 -262
- package/dist/master/register.d.ts +0 -1
- package/dist/master/register.js +0 -11
- package/dist/master/spawn.js +0 -114
- package/dist/master/thread.d.ts +0 -8
- package/dist/master/thread.js +0 -18
- package/dist/observable-promise.js +0 -132
- package/dist/observable.d.ts +0 -11
- package/dist/observable.js +0 -33
- package/dist/ponyfills.js +0 -20
- package/dist/promise.d.ts +0 -1
- package/dist/promise.js +0 -23
- package/dist/serializers.js +0 -41
- package/dist/symbols.js +0 -8
- package/dist/transferable.d.ts +0 -9
- package/dist/transferable.js +0 -25
- package/dist/types/master.js +0 -9
- package/dist/types/messages.js +0 -16
- package/dist/types/worker.js +0 -2
- package/dist/worker/bundle-entry.d.ts +0 -1
- package/dist/worker/bundle-entry.js +0 -26
- package/dist/worker/implementation.browser.d.ts +0 -6
- package/dist/worker/implementation.browser.js +0 -24
- package/dist/worker/implementation.d.ts +0 -3
- package/dist/worker/implementation.js +0 -19
- package/dist/worker/implementation.tiny-worker.d.ts +0 -6
- package/dist/worker/implementation.tiny-worker.js +0 -37
- package/dist/worker/implementation.worker_threads.d.ts +0 -8
- package/dist/worker/implementation.worker_threads.js +0 -41
- package/dist/worker/index.d.ts +0 -5
- package/dist/worker/index.js +0 -174
- package/dist/worker_threads.d.ts +0 -8
- package/dist/worker_threads.js +0 -13
- package/observable.d.ts +0 -2
- package/observable.js +0 -2
- package/observable.mjs +0 -4
- package/register.d.ts +0 -2
- package/register.js +0 -2
- package/register.mjs +0 -1
- package/rollup.config.js +0 -16
- package/src/worker/bundle-entry.ts +0 -10
- package/src/worker/implementation.tiny-worker.ts +0 -55
- package/src/worker/implementation.ts +0 -23
- package/src/worker/index.ts +0 -230
- package/src/worker_threads.ts +0 -27
- package/test/lib/index.ts +0 -1
- package/test/lib/serialization.ts +0 -38
- package/test/observable-promise.test.ts +0 -205
- package/test/observable.test.ts +0 -87
- package/test/pool.test.ts +0 -183
- package/test/serialization.test.ts +0 -23
- package/test/spawn.chromium.mocha.ts +0 -53
- package/test/spawn.test.ts +0 -87
- package/test/streaming.test.ts +0 -29
- package/test/transferables.test.ts +0 -71
- package/test/workers/arraybuffer-xor.ts +0 -10
- package/test/workers/count-to-five.ts +0 -12
- package/test/workers/counter.ts +0 -19
- package/test/workers/faulty-function.ts +0 -5
- package/test/workers/hello-world.ts +0 -5
- package/test/workers/increment.ts +0 -8
- package/test/workers/minmax.ts +0 -25
- package/test/workers/serialization.ts +0 -13
- package/test/workers/top-level-throw.ts +0 -1
- package/test-tooling/rollup/app.js +0 -21
- package/test-tooling/rollup/rollup.config.ts +0 -14
- package/test-tooling/rollup/worker.js +0 -7
- package/test-tooling/tsconfig/minimal.ts +0 -12
- package/test-tooling/webpack/addition-worker.ts +0 -9
- package/test-tooling/webpack/app-with-inlined-worker.ts +0 -28
- package/test-tooling/webpack/app.ts +0 -61
- package/test-tooling/webpack/pool-worker.ts +0 -5
- package/test-tooling/webpack/raw-loader.d.ts +0 -4
- package/test-tooling/webpack/webpack.chromium.mocha.ts +0 -21
- package/test-tooling/webpack/webpack.node.config.js +0 -29
- package/test-tooling/webpack/webpack.web.config.js +0 -28
- package/types/webworker.d.ts +0 -9
- package/worker.d.ts +0 -2
- package/worker.js +0 -2
- 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
|
-
})
|
package/test/observable.test.ts
DELETED
|
@@ -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
|
-
})
|
package/test/spawn.test.ts
DELETED
|
@@ -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')
|
package/test/streaming.test.ts
DELETED
|
@@ -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
|
-
})
|