@xylabs/threads 4.7.1 → 4.7.3

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 (235) 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/master/index-browser.mjs +988 -0
  4. package/dist/browser/master/index-browser.mjs.map +1 -0
  5. package/dist/browser/worker/worker.browser.mjs +291 -0
  6. package/dist/browser/worker/worker.browser.mjs.map +1 -0
  7. package/dist/neutral/index.mjs +1022 -0
  8. package/dist/neutral/index.mjs.map +1 -0
  9. package/dist/neutral/master/implementation.mjs +264 -0
  10. package/dist/neutral/master/implementation.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 +162 -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/master/index-node.mjs +988 -0
  26. package/dist/node/master/index-node.mjs.map +1 -0
  27. package/dist/node/worker/worker.node.mjs +304 -0
  28. package/dist/node/worker/worker.node.mjs.map +1 -0
  29. package/dist/{common.d.ts → types/common.d.ts} +5 -1
  30. package/dist/types/common.d.ts.map +1 -0
  31. package/dist/types/index.d.ts +9 -0
  32. package/dist/types/index.d.ts.map +1 -0
  33. package/dist/{master → types/master}/get-bundle-url.browser.d.ts +1 -0
  34. package/dist/types/master/get-bundle-url.browser.d.ts.map +1 -0
  35. package/dist/{master → types/master}/implementation.browser.d.ts +2 -1
  36. package/dist/types/master/implementation.browser.d.ts.map +1 -0
  37. package/dist/{master → types/master}/implementation.d.ts +4 -1
  38. package/dist/types/master/implementation.d.ts.map +1 -0
  39. package/dist/{master → types/master}/implementation.node.d.ts +2 -1
  40. package/dist/types/master/implementation.node.d.ts.map +1 -0
  41. package/dist/types/master/index-browser.d.ts +13 -0
  42. package/dist/types/master/index-browser.d.ts.map +1 -0
  43. package/dist/types/master/index-node.d.ts +13 -0
  44. package/dist/types/master/index-node.d.ts.map +1 -0
  45. package/dist/{master → types/master}/invocation-proxy.d.ts +2 -1
  46. package/dist/types/master/invocation-proxy.d.ts.map +1 -0
  47. package/dist/{master → types/master}/pool-types.d.ts +16 -1
  48. package/dist/types/master/pool-types.d.ts.map +1 -0
  49. package/dist/types/master/pool.d.ts +93 -0
  50. package/dist/types/master/pool.d.ts.map +1 -0
  51. package/dist/types/master/register.d.ts +2 -0
  52. package/dist/types/master/register.d.ts.map +1 -0
  53. package/dist/{master → types/master}/spawn.d.ts +12 -2
  54. package/dist/types/master/spawn.d.ts.map +1 -0
  55. package/dist/types/master/thread.d.ts +13 -0
  56. package/dist/types/master/thread.d.ts.map +1 -0
  57. package/dist/{observable-promise.d.ts → types/observable-promise.d.ts} +14 -0
  58. package/dist/types/observable-promise.d.ts.map +1 -0
  59. package/dist/types/observable.d.ts +21 -0
  60. package/dist/types/observable.d.ts.map +1 -0
  61. package/dist/{ponyfills.d.ts → types/ponyfills.d.ts} +1 -0
  62. package/dist/types/ponyfills.d.ts.map +1 -0
  63. package/dist/types/promise.d.ts +6 -0
  64. package/dist/types/promise.d.ts.map +1 -0
  65. package/dist/{serializers.d.ts → types/serializers.d.ts} +1 -0
  66. package/dist/types/serializers.d.ts.map +1 -0
  67. package/dist/{symbols.d.ts → types/symbols.d.ts} +1 -0
  68. package/dist/types/symbols.d.ts.map +1 -0
  69. package/{src/transferable.ts → dist/types/transferable.d.ts} +8 -33
  70. package/dist/types/transferable.d.ts.map +1 -0
  71. package/dist/types/{master.d.ts → types/master.d.ts} +17 -3
  72. package/dist/types/types/master.d.ts.map +1 -0
  73. package/dist/types/{messages.d.ts → types/messages.d.ts} +1 -0
  74. package/dist/types/types/messages.d.ts.map +1 -0
  75. package/dist/types/{worker.d.ts → types/worker.d.ts} +1 -0
  76. package/dist/types/types/worker.d.ts.map +1 -0
  77. package/dist/types/worker/WorkerGlobalScope.d.ts +6 -0
  78. package/dist/types/worker/WorkerGlobalScope.d.ts.map +1 -0
  79. package/dist/types/worker/expose.d.ts +4 -0
  80. package/dist/types/worker/expose.d.ts.map +1 -0
  81. package/dist/types/worker/worker.browser.d.ts +14 -0
  82. package/dist/types/worker/worker.browser.d.ts.map +1 -0
  83. package/dist/types/worker/worker.node.d.ts +25 -0
  84. package/dist/types/worker/worker.node.d.ts.map +1 -0
  85. package/package.json +55 -92
  86. package/dist/common.js +0 -16
  87. package/dist/esm/common.js +0 -16
  88. package/dist/esm/index.js +0 -26
  89. package/dist/esm/master/get-bundle-url.browser.js +0 -25
  90. package/dist/esm/master/implementation.browser.js +0 -65
  91. package/dist/esm/master/implementation.js +0 -43
  92. package/dist/esm/master/implementation.node.js +0 -205
  93. package/dist/esm/master/index.js +0 -14
  94. package/dist/esm/master/invocation-proxy.js +0 -121
  95. package/dist/esm/master/pool-types.js +0 -14
  96. package/dist/esm/master/pool.js +0 -262
  97. package/dist/esm/master/register.js +0 -11
  98. package/dist/esm/master/spawn.js +0 -114
  99. package/dist/esm/master/thread.js +0 -18
  100. package/dist/esm/observable-promise.js +0 -132
  101. package/dist/esm/observable.js +0 -33
  102. package/dist/esm/ponyfills.js +0 -20
  103. package/dist/esm/promise.js +0 -23
  104. package/dist/esm/serializers.js +0 -41
  105. package/dist/esm/symbols.js +0 -8
  106. package/dist/esm/transferable.js +0 -25
  107. package/dist/esm/types/master.js +0 -9
  108. package/dist/esm/types/messages.js +0 -16
  109. package/dist/esm/types/worker.js +0 -2
  110. package/dist/esm/worker/bundle-entry.js +0 -26
  111. package/dist/esm/worker/implementation.browser.js +0 -24
  112. package/dist/esm/worker/implementation.js +0 -19
  113. package/dist/esm/worker/implementation.tiny-worker.js +0 -37
  114. package/dist/esm/worker/implementation.worker_threads.js +0 -41
  115. package/dist/esm/worker/index.js +0 -174
  116. package/dist/esm/worker_threads.js +0 -13
  117. package/dist/index.d.ts +0 -7
  118. package/dist/index.js +0 -26
  119. package/dist/master/get-bundle-url.browser.js +0 -25
  120. package/dist/master/implementation.browser.js +0 -65
  121. package/dist/master/implementation.js +0 -43
  122. package/dist/master/implementation.node.js +0 -205
  123. package/dist/master/index.d.ts +0 -10
  124. package/dist/master/index.js +0 -14
  125. package/dist/master/invocation-proxy.js +0 -121
  126. package/dist/master/pool-types.js +0 -14
  127. package/dist/master/pool.d.ts +0 -50
  128. package/dist/master/pool.js +0 -262
  129. package/dist/master/register.d.ts +0 -1
  130. package/dist/master/register.js +0 -11
  131. package/dist/master/spawn.js +0 -114
  132. package/dist/master/thread.d.ts +0 -8
  133. package/dist/master/thread.js +0 -18
  134. package/dist/observable-promise.js +0 -132
  135. package/dist/observable.d.ts +0 -11
  136. package/dist/observable.js +0 -33
  137. package/dist/ponyfills.js +0 -20
  138. package/dist/promise.d.ts +0 -1
  139. package/dist/promise.js +0 -23
  140. package/dist/serializers.js +0 -41
  141. package/dist/symbols.js +0 -8
  142. package/dist/transferable.d.ts +0 -9
  143. package/dist/transferable.js +0 -25
  144. package/dist/types/master.js +0 -9
  145. package/dist/types/messages.js +0 -16
  146. package/dist/types/worker.js +0 -2
  147. package/dist/worker/bundle-entry.d.ts +0 -1
  148. package/dist/worker/bundle-entry.js +0 -26
  149. package/dist/worker/implementation.browser.d.ts +0 -6
  150. package/dist/worker/implementation.browser.js +0 -24
  151. package/dist/worker/implementation.d.ts +0 -3
  152. package/dist/worker/implementation.js +0 -19
  153. package/dist/worker/implementation.tiny-worker.d.ts +0 -6
  154. package/dist/worker/implementation.tiny-worker.js +0 -37
  155. package/dist/worker/implementation.worker_threads.d.ts +0 -8
  156. package/dist/worker/implementation.worker_threads.js +0 -41
  157. package/dist/worker/index.d.ts +0 -5
  158. package/dist/worker/index.js +0 -174
  159. package/dist/worker_threads.d.ts +0 -8
  160. package/dist/worker_threads.js +0 -13
  161. package/eslint.config.mjs +0 -35
  162. package/index.mjs +0 -10
  163. package/observable.d.ts +0 -2
  164. package/observable.js +0 -2
  165. package/observable.mjs +0 -4
  166. package/register.d.ts +0 -2
  167. package/register.js +0 -2
  168. package/register.mjs +0 -1
  169. package/rollup.config.js +0 -16
  170. package/src/common.ts +0 -19
  171. package/src/index.ts +0 -10
  172. package/src/master/get-bundle-url.browser.ts +0 -31
  173. package/src/master/implementation.browser.ts +0 -82
  174. package/src/master/implementation.node.ts +0 -285
  175. package/src/master/implementation.ts +0 -21
  176. package/src/master/index.ts +0 -19
  177. package/src/master/invocation-proxy.ts +0 -151
  178. package/src/master/pool-types.ts +0 -83
  179. package/src/master/pool.ts +0 -399
  180. package/src/master/register.ts +0 -10
  181. package/src/master/spawn.ts +0 -172
  182. package/src/master/thread.ts +0 -29
  183. package/src/observable-promise.ts +0 -183
  184. package/src/observable.ts +0 -44
  185. package/src/ponyfills.ts +0 -31
  186. package/src/promise.ts +0 -26
  187. package/src/serializers.ts +0 -68
  188. package/src/symbols.ts +0 -5
  189. package/src/types/master.ts +0 -132
  190. package/src/types/messages.ts +0 -72
  191. package/src/types/worker.ts +0 -14
  192. package/src/worker/bundle-entry.ts +0 -10
  193. package/src/worker/implementation.browser.ts +0 -40
  194. package/src/worker/implementation.tiny-worker.ts +0 -55
  195. package/src/worker/implementation.ts +0 -23
  196. package/src/worker/implementation.worker_threads.ts +0 -50
  197. package/src/worker/index.ts +0 -230
  198. package/src/worker_threads.ts +0 -27
  199. package/test/lib/index.ts +0 -1
  200. package/test/lib/serialization.ts +0 -38
  201. package/test/observable-promise.test.ts +0 -205
  202. package/test/observable.test.ts +0 -87
  203. package/test/pool.test.ts +0 -183
  204. package/test/serialization.test.ts +0 -23
  205. package/test/spawn.chromium.mocha.ts +0 -53
  206. package/test/spawn.test.ts +0 -87
  207. package/test/streaming.test.ts +0 -29
  208. package/test/transferables.test.ts +0 -71
  209. package/test/workers/arraybuffer-xor.ts +0 -10
  210. package/test/workers/count-to-five.ts +0 -12
  211. package/test/workers/counter.ts +0 -19
  212. package/test/workers/faulty-function.ts +0 -5
  213. package/test/workers/hello-world.ts +0 -5
  214. package/test/workers/increment.ts +0 -8
  215. package/test/workers/minmax.ts +0 -25
  216. package/test/workers/serialization.ts +0 -13
  217. package/test/workers/top-level-throw.ts +0 -1
  218. package/test-tooling/rollup/app.js +0 -21
  219. package/test-tooling/rollup/rollup.config.ts +0 -14
  220. package/test-tooling/rollup/worker.js +0 -7
  221. package/test-tooling/tsconfig/minimal.ts +0 -12
  222. package/test-tooling/webpack/addition-worker.ts +0 -9
  223. package/test-tooling/webpack/app-with-inlined-worker.ts +0 -28
  224. package/test-tooling/webpack/app.ts +0 -61
  225. package/test-tooling/webpack/pool-worker.ts +0 -5
  226. package/test-tooling/webpack/raw-loader.d.ts +0 -4
  227. package/test-tooling/webpack/webpack.chromium.mocha.ts +0 -21
  228. package/test-tooling/webpack/webpack.node.config.js +0 -29
  229. package/test-tooling/webpack/webpack.web.config.js +0 -28
  230. package/types/is-observable.d.ts +0 -7
  231. package/types/tiny-worker.d.ts +0 -4
  232. package/types/webworker.d.ts +0 -9
  233. package/worker.d.ts +0 -2
  234. package/worker.js +0 -2
  235. package/worker.mjs +0 -6
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
- })
@@ -1,71 +0,0 @@
1
- /* eslint-disable import-x/no-internal-modules */
2
- /* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */
3
- /* eslint-disable @typescript-eslint/no-explicit-any */
4
-
5
- import { expect, test } from 'vitest'
6
-
7
- import {
8
- spawn, Thread, Transfer, Worker,
9
- } from '../src/index'
10
- import type { XorBuffer } from './workers/arraybuffer-xor.ts'
11
-
12
- type SpyInit<Args extends any[], OriginalReturn, NewReturn> = (originalFn: (...args: Args) => OriginalReturn) => (...args: Args) => NewReturn
13
-
14
- const arrayBufferPlaceholder = Symbol('ArrayBufferPlaceholder')
15
-
16
- function spyOn<Args extends any[], OriginalReturn, NewReturn>(
17
- target: (...args: Args) => OriginalReturn,
18
- spy: SpyInit<Args, OriginalReturn, NewReturn>,
19
- ): (...args: Args) => NewReturn {
20
- return spy(target)
21
- }
22
-
23
- function replaceArrayBufferWithPlaceholder<In extends any>(
24
- obj: In,
25
- arrayBuffer: ArrayBufferLike,
26
- ): In extends ArrayBufferLike ? In | typeof arrayBufferPlaceholder : In {
27
- if ((obj as any) === arrayBuffer) {
28
- return arrayBufferPlaceholder as any
29
- } else if (Array.isArray(obj)) {
30
- return (obj as any[]).map(element => replaceArrayBufferWithPlaceholder(element, arrayBuffer)) as any
31
- } else if (obj && typeof obj === 'object') {
32
- const result: In = Object.create(Object.getPrototypeOf(obj))
33
-
34
- for (const key of Object.getOwnPropertyNames(obj)) {
35
- (result as any)[key] = replaceArrayBufferWithPlaceholder((obj as any)[key], arrayBuffer)
36
- }
37
- return result as any
38
- } else {
39
- return obj as any
40
- }
41
- }
42
-
43
- test('can pass transferable objects on thread call', async () => {
44
- const testData = new ArrayBuffer(64)
45
-
46
- const worker = new Worker('./workers/arraybuffer-xor.ts')
47
- const postMessageCalls: Array<any[]> = []
48
-
49
- worker.postMessage = spyOn(worker.postMessage.bind(worker), postMessage => (...args) => {
50
- postMessageCalls.push(replaceArrayBufferWithPlaceholder(args, testData))
51
- return postMessage(...args)
52
- })
53
-
54
- const xorBuffer = await spawn<XorBuffer>(worker)
55
- const returnedBuffer = await xorBuffer(Transfer(testData), 15)
56
-
57
- expect(returnedBuffer.byteLength).toBe(64)
58
- expect(postMessageCalls.length).toBe(1)
59
- expect(postMessageCalls[0].length).toBe(2)
60
- expect(postMessageCalls[0][0]).toEqual({
61
- args: [arrayBufferPlaceholder, 15],
62
- method: undefined,
63
- type: 'run',
64
- uid: postMessageCalls[0][0].uid,
65
- })
66
- expect(postMessageCalls[0][1]).toEqual([arrayBufferPlaceholder])
67
-
68
- await Thread.terminate(xorBuffer)
69
- })
70
-
71
- test.todo('can pass transferable objects as observable values')
@@ -1,10 +0,0 @@
1
- import { expose, Transfer } from '../../src/worker'
2
-
3
- function xor(buffer: ArrayBufferLike, value: number) {
4
- const view = new Uint8Array(buffer)
5
- for (const [offset, byte] of view.entries()) view.set([byte ^ value], offset)
6
- return Transfer(buffer)
7
- }
8
-
9
- expose(xor)
10
- export type XorBuffer = typeof xor
@@ -1,12 +0,0 @@
1
- import { Observable } from 'observable-fns'
2
-
3
- import { expose } from '../../src/worker'
4
-
5
- expose(function countToFive() {
6
- return new Observable((observer) => {
7
- for (let counter = 1; counter <= 5; counter++) {
8
- observer.next(counter)
9
- }
10
- observer.complete()
11
- })
12
- })
@@ -1,19 +0,0 @@
1
- import { expose } from '../../src/worker'
2
-
3
- let currentCount = 0
4
-
5
- const counter = {
6
- decrement() {
7
- return --currentCount
8
- },
9
- getCount() {
10
- return currentCount
11
- },
12
- increment() {
13
- return ++currentCount
14
- },
15
- }
16
-
17
- expose(counter)
18
-
19
- export type Counter = typeof counter
@@ -1,5 +0,0 @@
1
- import { expose } from '../../src/worker'
2
-
3
- expose(function fail() {
4
- throw new Error('I am supposed to fail.')
5
- })
@@ -1,5 +0,0 @@
1
- import { expose } from '../../src/worker'
2
-
3
- expose(function helloWorld() {
4
- return 'Hello World'
5
- })
@@ -1,8 +0,0 @@
1
- import { expose } from '../../src/worker'
2
-
3
- let counter = 0
4
-
5
- expose(function increment(by: number = 1) {
6
- counter += by
7
- return counter
8
- })
@@ -1,25 +0,0 @@
1
- // eslint-disable-next-line import-x/no-internal-modules
2
- import { Observable, Subject } from '../../src/observable'
3
- import { expose } from '../../src/worker'
4
-
5
- let max = Number.NEGATIVE_INFINITY
6
- let min = Number.POSITIVE_INFINITY
7
-
8
- let subject = new Subject()
9
-
10
- const minmax = {
11
- finish() {
12
- subject.complete()
13
- subject = new Subject()
14
- },
15
- push(value) {
16
- max = Math.max(max, value)
17
- min = Math.min(min, value)
18
- subject.next({ max, min })
19
- },
20
- values() {
21
- return Observable.from(subject)
22
- },
23
- }
24
-
25
- expose(minmax)
@@ -1,13 +0,0 @@
1
- /* eslint-disable import-x/no-internal-modules */
2
- /* eslint-disable require-await */
3
-
4
- import { expose, registerSerializer } from '../../src/worker'
5
- import { Foo, fooSerializer } from '../lib/serialization'
6
-
7
- registerSerializer(fooSerializer)
8
-
9
- async function run(foo: Foo<string>) {
10
- return new Foo(foo.getValue() + foo.getValue())
11
- }
12
-
13
- expose(run)
@@ -1 +0,0 @@
1
- throw new Error('Top-level worker error')
@@ -1,21 +0,0 @@
1
- /* eslint-disable no-restricted-imports */
2
- import {
3
- spawn, Thread, Worker,
4
- } from '../..'
5
-
6
- async function run() {
7
- const add = await spawn(new Worker('./worker.js'))
8
- const result = await add(2, 3)
9
- await Thread.terminate(add)
10
- return result
11
- }
12
-
13
- run()
14
- .then((result) => {
15
- console.log(`Result: ${result}`)
16
- puppet.exit(0)
17
- })
18
- .catch((error) => {
19
- console.error(error)
20
- puppet.exit(1)
21
- })
@@ -1,14 +0,0 @@
1
- import commonjs from '@rollup/plugin-commonjs'
2
- import { nodeResolve } from '@rollup/plugin-node-resolve'
3
-
4
- export default {
5
- plugins: [
6
- nodeResolve({
7
- browser: true,
8
- mainFields: ['module', 'main'],
9
- preferBuiltins: true,
10
- }),
11
-
12
- commonjs(),
13
- ],
14
- }
@@ -1,7 +0,0 @@
1
- /* eslint-disable require-await */
2
-
3
- import { expose } from '../../dist/esm/worker'
4
-
5
- expose(async function add(a, b) {
6
- return a + b
7
- })
@@ -1,12 +0,0 @@
1
- /* eslint-disable no-restricted-imports */
2
- /* eslint-disable @typescript-eslint/no-floating-promises */
3
- import {
4
- spawn, Thread, Worker,
5
- } from '../..'
6
-
7
- async function main() {
8
- const helloWorld = await spawn(new Worker('./workers/hello-world.ts'))
9
- await Thread.terminate(helloWorld)
10
- }
11
-
12
- main()
@@ -1,9 +0,0 @@
1
- import { expose, isWorkerRuntime } from '../../src/worker'
2
-
3
- if (!isWorkerRuntime()) {
4
- throw new Error('isWorkerRuntime() says we are not in a worker.')
5
- }
6
-
7
- expose(function add(a: number, b: number) {
8
- return a + b
9
- })
@@ -1,28 +0,0 @@
1
- /* eslint-disable import-x/no-unresolved */
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
3
-
4
- /// <reference types="./raw-loader" />
5
-
6
- import AdditionWorkerNodeBundle from 'raw-loader!./dist/addition-worker.node/worker.js'
7
- import AdditionWorkerWebBundle from 'raw-loader!./dist/addition-worker.web/worker.js'
8
-
9
- import { BlobWorker, spawn } from '../../src/index'
10
-
11
- const AdditionWorkerBundle = (process as any).browser ? AdditionWorkerWebBundle : AdditionWorkerNodeBundle
12
- type AdditionWorker = (a: number, b: number) => number
13
-
14
- async function test() {
15
- // We also want to test if referencing multiple different workers in a module
16
- // built using webpack works
17
-
18
- const add = await spawn<AdditionWorker>(BlobWorker.fromText(AdditionWorkerBundle))
19
- const result = await add(2, 3)
20
-
21
- if (result !== 5) {
22
- throw new Error('Unexpected result returned by addition worker: ' + result)
23
- }
24
-
25
- return 'test succeeded'
26
- }
27
-
28
- export default test