@xylabs/threads 4.7.0 → 4.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{types/common.d.ts → common.d.ts} +1 -5
- package/dist/common.js +16 -0
- package/dist/esm/common.js +16 -0
- package/dist/esm/index.js +26 -0
- package/dist/esm/master/get-bundle-url.browser.js +25 -0
- package/dist/esm/master/implementation.browser.js +65 -0
- package/dist/esm/master/implementation.js +43 -0
- package/dist/esm/master/implementation.node.js +205 -0
- package/dist/esm/master/index.js +14 -0
- package/dist/esm/master/invocation-proxy.js +121 -0
- package/dist/esm/master/pool-types.js +14 -0
- package/dist/esm/master/pool.js +262 -0
- package/dist/esm/master/register.js +11 -0
- package/dist/esm/master/spawn.js +114 -0
- package/dist/esm/master/thread.js +18 -0
- package/dist/esm/observable-promise.js +132 -0
- package/dist/esm/observable.js +33 -0
- package/dist/esm/ponyfills.js +20 -0
- package/dist/esm/promise.js +23 -0
- package/dist/esm/serializers.js +41 -0
- package/dist/esm/symbols.js +8 -0
- package/dist/esm/transferable.js +25 -0
- package/dist/esm/types/master.js +9 -0
- package/dist/esm/types/messages.js +16 -0
- package/dist/esm/types/worker.js +2 -0
- package/dist/esm/worker/bundle-entry.js +26 -0
- package/dist/esm/worker/implementation.browser.js +24 -0
- package/dist/esm/worker/implementation.js +19 -0
- package/dist/esm/worker/implementation.tiny-worker.js +37 -0
- package/dist/esm/worker/implementation.worker_threads.js +41 -0
- package/dist/esm/worker/index.js +174 -0
- package/dist/esm/worker_threads.js +13 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +26 -0
- package/dist/{types/master → master}/get-bundle-url.browser.d.ts +0 -1
- package/dist/master/get-bundle-url.browser.js +25 -0
- package/dist/{types/master → master}/implementation.browser.d.ts +1 -2
- package/dist/master/implementation.browser.js +65 -0
- package/dist/{types/master → master}/implementation.d.ts +1 -4
- package/dist/master/implementation.js +43 -0
- package/dist/{types/master → master}/implementation.node.d.ts +1 -2
- package/dist/master/implementation.node.js +205 -0
- package/dist/master/index.d.ts +10 -0
- package/dist/master/index.js +14 -0
- package/dist/{types/master → master}/invocation-proxy.d.ts +1 -2
- package/dist/master/invocation-proxy.js +121 -0
- package/dist/{types/master → master}/pool-types.d.ts +1 -16
- package/dist/master/pool-types.js +14 -0
- package/dist/master/pool.d.ts +50 -0
- package/dist/master/pool.js +262 -0
- package/dist/master/register.d.ts +1 -0
- package/dist/master/register.js +11 -0
- package/dist/{types/master → master}/spawn.d.ts +2 -12
- package/dist/master/spawn.js +114 -0
- package/dist/master/thread.d.ts +8 -0
- package/dist/master/thread.js +18 -0
- package/dist/{types/observable-promise.d.ts → observable-promise.d.ts} +0 -14
- package/dist/observable-promise.js +132 -0
- package/dist/observable.d.ts +11 -0
- package/dist/observable.js +33 -0
- package/dist/{types/ponyfills.d.ts → ponyfills.d.ts} +0 -1
- package/dist/ponyfills.js +20 -0
- package/dist/promise.d.ts +1 -0
- package/dist/promise.js +23 -0
- package/dist/{types/serializers.d.ts → serializers.d.ts} +0 -1
- package/dist/serializers.js +41 -0
- package/dist/{types/symbols.d.ts → symbols.d.ts} +0 -1
- package/dist/symbols.js +8 -0
- package/dist/transferable.d.ts +9 -0
- package/dist/transferable.js +25 -0
- package/dist/types/{types/master.d.ts → master.d.ts} +3 -17
- package/dist/types/master.js +9 -0
- package/dist/types/{types/messages.d.ts → messages.d.ts} +0 -1
- package/dist/types/messages.js +16 -0
- package/dist/types/{types/worker.d.ts → worker.d.ts} +0 -1
- package/dist/types/worker.js +2 -0
- package/dist/worker/bundle-entry.d.ts +1 -0
- package/dist/worker/bundle-entry.js +26 -0
- package/dist/worker/implementation.browser.d.ts +6 -0
- package/dist/worker/implementation.browser.js +24 -0
- package/dist/worker/implementation.d.ts +3 -0
- package/dist/worker/implementation.js +19 -0
- package/dist/worker/implementation.tiny-worker.d.ts +6 -0
- package/dist/worker/implementation.tiny-worker.js +37 -0
- package/dist/worker/implementation.worker_threads.d.ts +8 -0
- package/dist/worker/implementation.worker_threads.js +41 -0
- package/dist/worker/index.d.ts +5 -0
- package/dist/worker/index.js +174 -0
- package/dist/worker_threads.d.ts +8 -0
- package/dist/worker_threads.js +13 -0
- package/observable.d.ts +2 -0
- package/observable.js +2 -0
- package/observable.mjs +4 -0
- package/package.json +77 -66
- package/register.d.ts +2 -0
- package/register.js +2 -0
- package/register.mjs +1 -0
- package/rollup.config.js +16 -0
- package/src/common.ts +6 -10
- package/src/index.ts +9 -10
- package/src/master/get-bundle-url.browser.ts +1 -2
- package/src/master/implementation.browser.ts +2 -2
- package/src/master/implementation.node.ts +96 -19
- 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 +13 -14
- package/src/master/register.ts +1 -2
- package/src/master/spawn.ts +8 -8
- package/src/master/thread.ts +2 -2
- package/src/observable-promise.ts +2 -3
- package/src/serializers.ts +1 -1
- package/src/transferable.ts +1 -2
- package/src/types/master.ts +3 -3
- package/src/worker/bundle-entry.ts +10 -0
- package/src/worker/{worker.browser.ts → implementation.browser.ts} +10 -26
- package/src/worker/implementation.tiny-worker.ts +55 -0
- package/src/worker/implementation.ts +23 -0
- package/src/worker/{worker.node.ts → implementation.worker_threads.ts} +12 -30
- package/src/worker/index.ts +230 -0
- package/src/worker_threads.ts +27 -0
- package/test/lib/index.ts +1 -0
- package/test/lib/serialization.ts +38 -0
- package/test/observable-promise.test.ts +205 -0
- package/test/observable.test.ts +87 -0
- package/test/pool.test.ts +183 -0
- package/test/serialization.test.ts +23 -0
- package/test/spawn.chromium.mocha.ts +53 -0
- package/test/spawn.test.ts +87 -0
- package/test/streaming.test.ts +29 -0
- package/test/transferables.test.ts +71 -0
- package/test/workers/arraybuffer-xor.ts +10 -0
- package/test/workers/count-to-five.ts +12 -0
- package/test/workers/counter.ts +19 -0
- package/test/workers/faulty-function.ts +5 -0
- package/test/workers/hello-world.ts +5 -0
- package/test/workers/increment.ts +8 -0
- package/test/workers/minmax.ts +25 -0
- package/test/workers/serialization.ts +13 -0
- package/test/workers/top-level-throw.ts +1 -0
- package/test-tooling/rollup/app.js +21 -0
- package/test-tooling/rollup/rollup.config.ts +14 -0
- package/test-tooling/rollup/worker.js +7 -0
- package/test-tooling/tsconfig/minimal.ts +12 -0
- package/test-tooling/webpack/addition-worker.ts +9 -0
- package/test-tooling/webpack/app-with-inlined-worker.ts +28 -0
- package/test-tooling/webpack/app.ts +61 -0
- package/test-tooling/webpack/pool-worker.ts +5 -0
- package/test-tooling/webpack/raw-loader.d.ts +4 -0
- package/test-tooling/webpack/webpack.chromium.mocha.ts +21 -0
- package/test-tooling/webpack/webpack.node.config.js +29 -0
- package/test-tooling/webpack/webpack.web.config.js +28 -0
- package/types/is-observable.d.ts +1 -1
- package/types/webworker.d.ts +9 -0
- package/worker.d.ts +2 -0
- package/worker.js +2 -0
- package/worker.mjs +6 -0
- package/dist/browser/master/implementation.browser.mjs +0 -89
- package/dist/browser/master/implementation.browser.mjs.map +0 -1
- package/dist/browser/worker/worker.browser.mjs +0 -291
- package/dist/browser/worker/worker.browser.mjs.map +0 -1
- package/dist/neutral/index.mjs +0 -1022
- package/dist/neutral/index.mjs.map +0 -1
- package/dist/neutral/master/implementation.mjs +0 -264
- package/dist/neutral/master/implementation.mjs.map +0 -1
- package/dist/neutral/master/index.mjs +0 -988
- package/dist/neutral/master/index.mjs.map +0 -1
- package/dist/neutral/master/pool.mjs +0 -579
- package/dist/neutral/master/pool.mjs.map +0 -1
- package/dist/neutral/master/register.mjs +0 -272
- package/dist/neutral/master/register.mjs.map +0 -1
- package/dist/neutral/master/spawn.mjs +0 -412
- package/dist/neutral/master/spawn.mjs.map +0 -1
- package/dist/neutral/master/thread.mjs +0 -29
- package/dist/neutral/master/thread.mjs.map +0 -1
- package/dist/neutral/observable-promise.mjs +0 -132
- package/dist/neutral/observable-promise.mjs.map +0 -1
- package/dist/neutral/observable.mjs +0 -31
- package/dist/neutral/observable.mjs.map +0 -1
- package/dist/node/master/implementation.node.mjs +0 -154
- package/dist/node/master/implementation.node.mjs.map +0 -1
- package/dist/node/worker/worker.node.mjs +0 -304
- package/dist/node/worker/worker.node.mjs.map +0 -1
- package/dist/types/common.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -9
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/master/get-bundle-url.browser.d.ts.map +0 -1
- package/dist/types/master/implementation.browser.d.ts.map +0 -1
- package/dist/types/master/implementation.d.ts.map +0 -1
- package/dist/types/master/implementation.node.d.ts.map +0 -1
- package/dist/types/master/index.d.ts +0 -13
- package/dist/types/master/index.d.ts.map +0 -1
- package/dist/types/master/invocation-proxy.d.ts.map +0 -1
- package/dist/types/master/pool-types.d.ts.map +0 -1
- package/dist/types/master/pool.d.ts +0 -93
- package/dist/types/master/pool.d.ts.map +0 -1
- package/dist/types/master/register.d.ts +0 -2
- package/dist/types/master/register.d.ts.map +0 -1
- package/dist/types/master/spawn.d.ts.map +0 -1
- package/dist/types/master/thread.d.ts +0 -13
- package/dist/types/master/thread.d.ts.map +0 -1
- package/dist/types/observable-promise.d.ts.map +0 -1
- package/dist/types/observable.d.ts +0 -21
- package/dist/types/observable.d.ts.map +0 -1
- package/dist/types/ponyfills.d.ts.map +0 -1
- package/dist/types/promise.d.ts +0 -6
- package/dist/types/promise.d.ts.map +0 -1
- package/dist/types/serializers.d.ts.map +0 -1
- package/dist/types/symbols.d.ts.map +0 -1
- package/dist/types/transferable.d.ts +0 -43
- package/dist/types/transferable.d.ts.map +0 -1
- package/dist/types/types/master.d.ts.map +0 -1
- package/dist/types/types/messages.d.ts.map +0 -1
- package/dist/types/types/worker.d.ts.map +0 -1
- package/dist/types/worker/WorkerGlobalScope.d.ts +0 -6
- package/dist/types/worker/WorkerGlobalScope.d.ts.map +0 -1
- package/dist/types/worker/expose.d.ts +0 -4
- package/dist/types/worker/expose.d.ts.map +0 -1
- package/dist/types/worker/worker.browser.d.ts +0 -14
- package/dist/types/worker/worker.browser.d.ts.map +0 -1
- package/dist/types/worker/worker.node.d.ts +0 -25
- package/dist/types/worker/worker.node.d.ts.map +0 -1
- package/src/worker/WorkerGlobalScope.ts +0 -5
- package/src/worker/expose.ts +0 -234
- package/src/worker/is-observable.d.ts +0 -7
- package/xy.config.ts +0 -24
package/src/master/spawn.ts
CHANGED
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
import DebugLogger from 'debug'
|
|
5
5
|
import { Observable } from 'observable-fns'
|
|
6
6
|
|
|
7
|
-
import { deserialize } from '../common
|
|
8
|
-
import { createPromiseWithResolver } from '../promise
|
|
7
|
+
import { deserialize } from '../common'
|
|
8
|
+
import { createPromiseWithResolver } from '../promise'
|
|
9
9
|
import {
|
|
10
10
|
$errors, $events, $terminate, $worker,
|
|
11
|
-
} from '../symbols
|
|
11
|
+
} from '../symbols'
|
|
12
12
|
import type {
|
|
13
13
|
FunctionThread,
|
|
14
14
|
ModuleThread,
|
|
@@ -19,11 +19,11 @@ import type {
|
|
|
19
19
|
WorkerInternalErrorEvent,
|
|
20
20
|
WorkerMessageEvent,
|
|
21
21
|
WorkerTerminationEvent,
|
|
22
|
-
} from '../types/master
|
|
23
|
-
import { WorkerEventType } from '../types/master
|
|
24
|
-
import type { WorkerInitMessage, WorkerUncaughtErrorMessage } from '../types/messages
|
|
25
|
-
import type { WorkerFunction, WorkerModule } from '../types/worker
|
|
26
|
-
import { createProxyFunction, createProxyModule } from './invocation-proxy
|
|
22
|
+
} from '../types/master'
|
|
23
|
+
import { WorkerEventType } from '../types/master'
|
|
24
|
+
import type { WorkerInitMessage, WorkerUncaughtErrorMessage } from '../types/messages'
|
|
25
|
+
import type { WorkerFunction, WorkerModule } from '../types/worker'
|
|
26
|
+
import { createProxyFunction, createProxyModule } from './invocation-proxy'
|
|
27
27
|
|
|
28
28
|
type ArbitraryWorkerInterface = WorkerFunction & WorkerModule<string> & { somekeythatisneverusedinproductioncode123: 'magicmarker123' }
|
|
29
29
|
type ArbitraryThreadType = FunctionThread<any, any> & ModuleThread<any>
|
package/src/master/thread.ts
CHANGED
|
@@ -3,8 +3,8 @@ import type { Observable } from 'observable-fns'
|
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
$errors, $events, $terminate,
|
|
6
|
-
} from '../symbols
|
|
7
|
-
import type { Thread as ThreadType, WorkerEvent } from '../types/master
|
|
6
|
+
} from '../symbols'
|
|
7
|
+
import type { Thread as ThreadType, WorkerEvent } from '../types/master'
|
|
8
8
|
|
|
9
9
|
function fail(message: string): never {
|
|
10
10
|
throw new Error(message)
|
|
@@ -132,8 +132,7 @@ export class ObservablePromise<T> extends Observable<T> implements Promise<T> {
|
|
|
132
132
|
const fulfillmentCallback = (value: T) => {
|
|
133
133
|
try {
|
|
134
134
|
resolve(onFulfilled(value))
|
|
135
|
-
} catch (
|
|
136
|
-
const error = ex as Error
|
|
135
|
+
} catch (error) {
|
|
137
136
|
rejectionCallback(error)
|
|
138
137
|
}
|
|
139
138
|
}
|
|
@@ -167,7 +166,7 @@ export class ObservablePromise<T> extends Observable<T> implements Promise<T> {
|
|
|
167
166
|
) as Promise<T>
|
|
168
167
|
}
|
|
169
168
|
|
|
170
|
-
static
|
|
169
|
+
static from<T>(thing: Observable<T> | ObservableLike<T> | ArrayLike<T> | Thenable<T>): ObservablePromise<T> {
|
|
171
170
|
return isThenable(thing)
|
|
172
171
|
? new ObservablePromise((observer) => {
|
|
173
172
|
const onFulfilled = (value: T) => {
|
package/src/serializers.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable import-x/no-internal-modules */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
-
import type { SerializedError } from './types/messages
|
|
3
|
+
import type { SerializedError } from './types/messages'
|
|
4
4
|
|
|
5
5
|
export interface Serializer<Msg = JsonSerializable, Input = any> {
|
|
6
6
|
deserialize(message: Msg): Input
|
package/src/transferable.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { $transferable } from './symbols
|
|
2
|
+
import { $transferable } from './symbols'
|
|
3
3
|
|
|
4
4
|
export interface TransferDescriptor<T = any> {
|
|
5
5
|
[$transferable]: true
|
|
@@ -55,7 +55,6 @@ export function Transfer(transferable: Transferable): TransferDescriptor
|
|
|
55
55
|
export function Transfer<T>(payload: T, transferables: Transferable[]): TransferDescriptor
|
|
56
56
|
|
|
57
57
|
export function Transfer<T>(payload: T, transferables?: Transferable[]): TransferDescriptor {
|
|
58
|
-
console.log('Transfer')
|
|
59
58
|
if (!transferables) {
|
|
60
59
|
if (!isTransferable(payload)) throw new Error('Not transferable')
|
|
61
60
|
transferables = [payload]
|
package/src/types/master.ts
CHANGED
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
// See <https://github.com/microsoft/TypeScript/issues/28009>
|
|
7
7
|
import type { Observable } from 'observable-fns'
|
|
8
8
|
|
|
9
|
-
import type { ObservablePromise } from '../observable-promise
|
|
9
|
+
import type { ObservablePromise } from '../observable-promise'
|
|
10
10
|
import type {
|
|
11
11
|
$errors, $events, $terminate, $worker,
|
|
12
|
-
} from '../symbols
|
|
13
|
-
import type { TransferDescriptor } from '../transferable
|
|
12
|
+
} from '../symbols'
|
|
13
|
+
import type { TransferDescriptor } from '../transferable'
|
|
14
14
|
|
|
15
15
|
interface ObservableLikeSubscription {
|
|
16
16
|
unsubscribe(): any
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
import { expose } from './index'
|
|
3
|
+
export * from './index'
|
|
4
|
+
|
|
5
|
+
if (typeof globalThis !== 'undefined') {
|
|
6
|
+
;(globalThis as any).expose = expose
|
|
7
|
+
}
|
|
8
|
+
if (typeof globalThis !== 'undefined') {
|
|
9
|
+
;(globalThis as any).expose = expose
|
|
10
|
+
}
|
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
/* eslint-disable import-x/no-internal-modules */
|
|
2
|
-
|
|
3
|
-
/// <reference lib="
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
/// <reference lib="dom" />
|
|
4
4
|
// tslint:disable no-shadowed-variable
|
|
5
5
|
|
|
6
|
-
import type { AbstractedWorkerAPI } from '../types/worker
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
import type { AbstractedWorkerAPI } from '../types/worker'
|
|
7
|
+
|
|
8
|
+
interface WorkerGlobalScope {
|
|
9
|
+
addEventListener(eventName: string, listener: (event: Event) => void): void
|
|
10
|
+
postMessage(message: any, transferables?: any[]): void
|
|
11
|
+
removeEventListener(eventName: string, listener: (event: Event) => void): void
|
|
12
|
+
}
|
|
9
13
|
|
|
10
14
|
declare const self: WorkerGlobalScope
|
|
11
15
|
|
|
@@ -29,28 +33,8 @@ const subscribeToMasterMessages: AbstractedWorkerAPI['subscribeToMasterMessages'
|
|
|
29
33
|
return unsubscribe
|
|
30
34
|
}
|
|
31
35
|
|
|
32
|
-
|
|
33
|
-
const postMessage = self.postMessage
|
|
34
|
-
const removeEventListener = self.removeEventListener
|
|
35
|
-
|
|
36
|
-
export {
|
|
37
|
-
addEventListener,
|
|
38
|
-
postMessage,
|
|
39
|
-
removeEventListener,
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const expose = createExpose({
|
|
43
|
-
isWorkerRuntime, postMessageToMaster, subscribeToMasterMessages,
|
|
44
|
-
}, {
|
|
45
|
-
addEventListener, postMessage, removeEventListener,
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
export {
|
|
36
|
+
export default {
|
|
49
37
|
isWorkerRuntime,
|
|
50
38
|
postMessageToMaster,
|
|
51
39
|
subscribeToMasterMessages,
|
|
52
40
|
}
|
|
53
|
-
|
|
54
|
-
export { registerSerializer } from '../common.ts'
|
|
55
|
-
export { Transfer } from '../transferable.ts'
|
|
56
|
-
export { expose }
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/* eslint-disable import-x/no-internal-modules */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
/// <reference lib="dom" />
|
|
4
|
+
// tslint:disable no-shadowed-variable
|
|
5
|
+
|
|
6
|
+
import type { AbstractedWorkerAPI } from '../types/worker'
|
|
7
|
+
|
|
8
|
+
interface WorkerGlobalScope {
|
|
9
|
+
addEventListener(eventName: string, listener: (event: Event) => void): void
|
|
10
|
+
postMessage(message: any, transferables?: any[]): void
|
|
11
|
+
removeEventListener(eventName: string, listener: (event: Event) => void): void
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
declare const self: WorkerGlobalScope
|
|
15
|
+
try {
|
|
16
|
+
if (self === undefined) {
|
|
17
|
+
;(globalThis as any).self = globalThis
|
|
18
|
+
}
|
|
19
|
+
} catch {
|
|
20
|
+
;(globalThis as any).self = globalThis
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const isWorkerRuntime: AbstractedWorkerAPI['isWorkerRuntime'] = function isWorkerRuntime() {
|
|
24
|
+
return self !== undefined && self['postMessage'] ? true : false
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const postMessageToMaster: AbstractedWorkerAPI['postMessageToMaster'] = function postMessageToMaster(data) {
|
|
28
|
+
// TODO: Warn that Transferables are not supported on first attempt to use feature
|
|
29
|
+
self.postMessage(data)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let muxingHandlerSetUp = false
|
|
33
|
+
const messageHandlers = new Set<(data: any) => void>()
|
|
34
|
+
|
|
35
|
+
const subscribeToMasterMessages: AbstractedWorkerAPI['subscribeToMasterMessages'] = function subscribeToMasterMessages(onMessage) {
|
|
36
|
+
if (!muxingHandlerSetUp) {
|
|
37
|
+
// We have one multiplexing message handler as tiny-worker's
|
|
38
|
+
// addEventListener() only allows you to set a single message handler
|
|
39
|
+
self.addEventListener('message', ((event: MessageEvent) => {
|
|
40
|
+
for (const handler of messageHandlers) handler(event.data)
|
|
41
|
+
}) as EventListener)
|
|
42
|
+
muxingHandlerSetUp = true
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
messageHandlers.add(onMessage)
|
|
46
|
+
|
|
47
|
+
const unsubscribe = () => messageHandlers.delete(onMessage)
|
|
48
|
+
return unsubscribe
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default {
|
|
52
|
+
isWorkerRuntime,
|
|
53
|
+
postMessageToMaster,
|
|
54
|
+
subscribeToMasterMessages,
|
|
55
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/* eslint-disable import-x/no-internal-modules */
|
|
2
|
+
// tslint:disable no-var-requires
|
|
3
|
+
/*
|
|
4
|
+
* This file is only a stub to make './implementation' resolve to the right module.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { AbstractedWorkerAPI } from '../types/worker'
|
|
8
|
+
import WebWorkerImplementation from './implementation.browser'
|
|
9
|
+
import TinyWorkerImplementation from './implementation.tiny-worker'
|
|
10
|
+
import WorkerThreadsImplementation from './implementation.worker_threads'
|
|
11
|
+
|
|
12
|
+
const runningInNode = typeof process !== 'undefined' && (process.arch as string) !== 'browser' && 'pid' in process
|
|
13
|
+
|
|
14
|
+
function selectNodeImplementation(): AbstractedWorkerAPI {
|
|
15
|
+
try {
|
|
16
|
+
WorkerThreadsImplementation.testImplementation()
|
|
17
|
+
return WorkerThreadsImplementation
|
|
18
|
+
} catch {
|
|
19
|
+
return TinyWorkerImplementation
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default runningInNode ? selectNodeImplementation() : WebWorkerImplementation
|
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
/* eslint-disable import-x/no-internal-modules */
|
|
2
2
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
3
|
// tslint:disable no-shadowed-variable
|
|
4
|
+
import type { MessagePort } from 'node:worker_threads'
|
|
4
5
|
|
|
5
|
-
import type {
|
|
6
|
-
import
|
|
7
|
-
|
|
8
|
-
import { assertEx } from '@xylabs/assert'
|
|
9
|
-
|
|
10
|
-
import type { AbstractedWorkerAPI } from '../types/worker.ts'
|
|
11
|
-
import { createExpose } from './expose.ts'
|
|
12
|
-
|
|
13
|
-
const parentPort = assertEx(optionalParentPort, () => 'Invariant violation: MessagePort to parent is not available.')
|
|
6
|
+
import type { AbstractedWorkerAPI } from '../types/worker'
|
|
7
|
+
import WorkerThreads from '../worker_threads'
|
|
14
8
|
|
|
15
9
|
function assertMessagePort(port: MessagePort | null | undefined): MessagePort {
|
|
16
10
|
if (!port) {
|
|
@@ -20,14 +14,16 @@ function assertMessagePort(port: MessagePort | null | undefined): MessagePort {
|
|
|
20
14
|
}
|
|
21
15
|
|
|
22
16
|
const isWorkerRuntime: AbstractedWorkerAPI['isWorkerRuntime'] = function isWorkerRuntime() {
|
|
23
|
-
return
|
|
17
|
+
return !WorkerThreads().isMainThread
|
|
24
18
|
}
|
|
25
19
|
|
|
26
20
|
const postMessageToMaster: AbstractedWorkerAPI['postMessageToMaster'] = function postMessageToMaster(data, transferList) {
|
|
27
|
-
assertMessagePort(parentPort).postMessage(data, transferList as
|
|
21
|
+
assertMessagePort(WorkerThreads().parentPort).postMessage(data, transferList as any)
|
|
28
22
|
}
|
|
29
23
|
|
|
30
24
|
const subscribeToMasterMessages: AbstractedWorkerAPI['subscribeToMasterMessages'] = function subscribeToMasterMessages(onMessage) {
|
|
25
|
+
const parentPort = WorkerThreads().parentPort
|
|
26
|
+
|
|
31
27
|
if (!parentPort) {
|
|
32
28
|
throw new Error('Invariant violation: MessagePort to parent is not available.')
|
|
33
29
|
}
|
|
@@ -41,28 +37,14 @@ const subscribeToMasterMessages: AbstractedWorkerAPI['subscribeToMasterMessages'
|
|
|
41
37
|
return unsubscribe
|
|
42
38
|
}
|
|
43
39
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
export {
|
|
49
|
-
addEventListener,
|
|
50
|
-
postMessage,
|
|
51
|
-
removeEventListener,
|
|
40
|
+
function testImplementation() {
|
|
41
|
+
// Will throw if `worker_threads` are not available
|
|
42
|
+
WorkerThreads()
|
|
52
43
|
}
|
|
53
44
|
|
|
54
|
-
|
|
55
|
-
isWorkerRuntime, postMessageToMaster, subscribeToMasterMessages,
|
|
56
|
-
}, {
|
|
57
|
-
addEventListener, postMessage, removeEventListener,
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
export {
|
|
45
|
+
export default {
|
|
61
46
|
isWorkerRuntime,
|
|
62
47
|
postMessageToMaster,
|
|
63
48
|
subscribeToMasterMessages,
|
|
49
|
+
testImplementation,
|
|
64
50
|
}
|
|
65
|
-
|
|
66
|
-
export { registerSerializer } from '../common.ts'
|
|
67
|
-
export { Transfer } from '../transferable.ts'
|
|
68
|
-
export { expose }
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/* eslint-disable import-x/no-internal-modules */
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-floating-promises */
|
|
4
|
+
import isSomeObservable from 'is-observable-2-1-0'
|
|
5
|
+
import type { Observable, Subscription } from 'observable-fns'
|
|
6
|
+
|
|
7
|
+
import { deserialize, serialize } from '../common'
|
|
8
|
+
import type { TransferDescriptor } from '../transferable'
|
|
9
|
+
import { isTransferDescriptor } from '../transferable'
|
|
10
|
+
import type {
|
|
11
|
+
MasterJobCancelMessage,
|
|
12
|
+
MasterJobRunMessage,
|
|
13
|
+
SerializedError,
|
|
14
|
+
WorkerInitMessage,
|
|
15
|
+
WorkerJobErrorMessage,
|
|
16
|
+
WorkerJobResultMessage,
|
|
17
|
+
WorkerJobStartMessage,
|
|
18
|
+
WorkerUncaughtErrorMessage,
|
|
19
|
+
} from '../types/messages'
|
|
20
|
+
import {
|
|
21
|
+
MasterMessageType,
|
|
22
|
+
WorkerMessageType,
|
|
23
|
+
} from '../types/messages'
|
|
24
|
+
import type { WorkerFunction, WorkerModule } from '../types/worker'
|
|
25
|
+
import Implementation from './implementation'
|
|
26
|
+
|
|
27
|
+
export { registerSerializer } from '../common'
|
|
28
|
+
export { Transfer } from '../transferable'
|
|
29
|
+
|
|
30
|
+
/** Returns `true` if this code is currently running in a worker. */
|
|
31
|
+
export const isWorkerRuntime = Implementation.isWorkerRuntime
|
|
32
|
+
|
|
33
|
+
let exposeCalled = false
|
|
34
|
+
|
|
35
|
+
const activeSubscriptions = new Map<number, Subscription<any>>()
|
|
36
|
+
|
|
37
|
+
const isMasterJobCancelMessage = (thing: any): thing is MasterJobCancelMessage => thing && thing.type === MasterMessageType.cancel
|
|
38
|
+
const isMasterJobRunMessage = (thing: any): thing is MasterJobRunMessage => thing && thing.type === MasterMessageType.run
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* There are issues with `is-observable` not recognizing zen-observable's instances.
|
|
42
|
+
* We are using `observable-fns`, but it's based on zen-observable, too.
|
|
43
|
+
*/
|
|
44
|
+
const isObservable = (thing: any): thing is Observable<any> => isSomeObservable(thing) || isZenObservable(thing)
|
|
45
|
+
|
|
46
|
+
function isZenObservable(thing: any): thing is Observable<any> {
|
|
47
|
+
return thing && typeof thing === 'object' && typeof thing.subscribe === 'function'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function deconstructTransfer(thing: any) {
|
|
51
|
+
return isTransferDescriptor(thing) ? { payload: thing.send, transferables: thing.transferables } : { payload: thing, transferables: undefined }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function postFunctionInitMessage() {
|
|
55
|
+
const initMessage: WorkerInitMessage = {
|
|
56
|
+
exposed: { type: 'function' },
|
|
57
|
+
type: WorkerMessageType.init,
|
|
58
|
+
}
|
|
59
|
+
Implementation.postMessageToMaster(initMessage)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function postModuleInitMessage(methodNames: string[]) {
|
|
63
|
+
const initMessage: WorkerInitMessage = {
|
|
64
|
+
exposed: {
|
|
65
|
+
methods: methodNames,
|
|
66
|
+
type: 'module',
|
|
67
|
+
},
|
|
68
|
+
type: WorkerMessageType.init,
|
|
69
|
+
}
|
|
70
|
+
Implementation.postMessageToMaster(initMessage)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function postJobErrorMessage(uid: number, rawError: Error | TransferDescriptor<Error>) {
|
|
74
|
+
const { payload: error, transferables } = deconstructTransfer(rawError)
|
|
75
|
+
const errorMessage: WorkerJobErrorMessage = {
|
|
76
|
+
error: serialize(error) as any as SerializedError,
|
|
77
|
+
type: WorkerMessageType.error,
|
|
78
|
+
uid,
|
|
79
|
+
}
|
|
80
|
+
Implementation.postMessageToMaster(errorMessage, transferables)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function postJobResultMessage(uid: number, completed: boolean, resultValue?: any) {
|
|
84
|
+
const { payload, transferables } = deconstructTransfer(resultValue)
|
|
85
|
+
const resultMessage: WorkerJobResultMessage = {
|
|
86
|
+
complete: completed ? true : undefined,
|
|
87
|
+
payload,
|
|
88
|
+
type: WorkerMessageType.result,
|
|
89
|
+
uid,
|
|
90
|
+
}
|
|
91
|
+
Implementation.postMessageToMaster(resultMessage, transferables)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function postJobStartMessage(uid: number, resultType: WorkerJobStartMessage['resultType']) {
|
|
95
|
+
const startMessage: WorkerJobStartMessage = {
|
|
96
|
+
resultType,
|
|
97
|
+
type: WorkerMessageType.running,
|
|
98
|
+
uid,
|
|
99
|
+
}
|
|
100
|
+
Implementation.postMessageToMaster(startMessage)
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function postUncaughtErrorMessage(error: Error) {
|
|
104
|
+
try {
|
|
105
|
+
const errorMessage: WorkerUncaughtErrorMessage = {
|
|
106
|
+
error: serialize(error) as any as SerializedError,
|
|
107
|
+
type: WorkerMessageType.uncaughtError,
|
|
108
|
+
}
|
|
109
|
+
Implementation.postMessageToMaster(errorMessage)
|
|
110
|
+
} catch (subError) {
|
|
111
|
+
// tslint:disable-next-line no-console
|
|
112
|
+
console.error(
|
|
113
|
+
'Not reporting uncaught error back to master thread as it ' + 'occured while reporting an uncaught error already.' + '\nLatest error:',
|
|
114
|
+
subError,
|
|
115
|
+
'\nOriginal error:',
|
|
116
|
+
error,
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function runFunction(jobUID: number, fn: WorkerFunction, args: any[]) {
|
|
122
|
+
let syncResult: any
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
syncResult = fn(...args)
|
|
126
|
+
} catch (error) {
|
|
127
|
+
return postJobErrorMessage(jobUID, error)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const resultType = isObservable(syncResult) ? 'observable' : 'promise'
|
|
131
|
+
postJobStartMessage(jobUID, resultType)
|
|
132
|
+
|
|
133
|
+
if (isObservable(syncResult)) {
|
|
134
|
+
const subscription = syncResult.subscribe(
|
|
135
|
+
value => postJobResultMessage(jobUID, false, serialize(value)),
|
|
136
|
+
(error) => {
|
|
137
|
+
postJobErrorMessage(jobUID, serialize(error) as any)
|
|
138
|
+
activeSubscriptions.delete(jobUID)
|
|
139
|
+
},
|
|
140
|
+
() => {
|
|
141
|
+
postJobResultMessage(jobUID, true)
|
|
142
|
+
activeSubscriptions.delete(jobUID)
|
|
143
|
+
},
|
|
144
|
+
)
|
|
145
|
+
activeSubscriptions.set(jobUID, subscription)
|
|
146
|
+
} else {
|
|
147
|
+
try {
|
|
148
|
+
const result = await syncResult
|
|
149
|
+
postJobResultMessage(jobUID, true, serialize(result))
|
|
150
|
+
} catch (error) {
|
|
151
|
+
postJobErrorMessage(jobUID, serialize(error) as any)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Expose a function or a module (an object whose values are functions)
|
|
158
|
+
* to the main thread. Must be called exactly once in every worker thread
|
|
159
|
+
* to signal its API to the main thread.
|
|
160
|
+
*
|
|
161
|
+
* @param exposed Function or object whose values are functions
|
|
162
|
+
*/
|
|
163
|
+
export function expose(exposed: WorkerFunction | WorkerModule<any>) {
|
|
164
|
+
if (!Implementation.isWorkerRuntime()) {
|
|
165
|
+
throw new Error('expose() called in the master thread.')
|
|
166
|
+
}
|
|
167
|
+
if (exposeCalled) {
|
|
168
|
+
throw new Error('expose() called more than once. This is not possible. Pass an object to expose() if you want to expose multiple functions.')
|
|
169
|
+
}
|
|
170
|
+
exposeCalled = true
|
|
171
|
+
|
|
172
|
+
if (typeof exposed === 'function') {
|
|
173
|
+
Implementation.subscribeToMasterMessages((messageData) => {
|
|
174
|
+
if (isMasterJobRunMessage(messageData) && !messageData.method) {
|
|
175
|
+
runFunction(messageData.uid, exposed, messageData.args.map(deserialize))
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
postFunctionInitMessage()
|
|
179
|
+
} else if (typeof exposed === 'object' && exposed) {
|
|
180
|
+
Implementation.subscribeToMasterMessages((messageData) => {
|
|
181
|
+
if (isMasterJobRunMessage(messageData) && messageData.method) {
|
|
182
|
+
runFunction(messageData.uid, exposed[messageData.method], messageData.args.map(deserialize))
|
|
183
|
+
}
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
const methodNames = Object.keys(exposed).filter(key => typeof exposed[key] === 'function')
|
|
187
|
+
postModuleInitMessage(methodNames)
|
|
188
|
+
} else {
|
|
189
|
+
throw new Error(`Invalid argument passed to expose(). Expected a function or an object, got: ${exposed}`)
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
Implementation.subscribeToMasterMessages((messageData) => {
|
|
193
|
+
if (isMasterJobCancelMessage(messageData)) {
|
|
194
|
+
const jobUID = messageData.uid
|
|
195
|
+
const subscription = activeSubscriptions.get(jobUID)
|
|
196
|
+
|
|
197
|
+
if (subscription) {
|
|
198
|
+
subscription.unsubscribe()
|
|
199
|
+
activeSubscriptions.delete(jobUID)
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (typeof globalThis !== 'undefined' && typeof self.addEventListener === 'function' && Implementation.isWorkerRuntime()) {
|
|
206
|
+
self.addEventListener('error', (event) => {
|
|
207
|
+
// Post with some delay, so the master had some time to subscribe to messages
|
|
208
|
+
setTimeout(() => postUncaughtErrorMessage(event.error || event), 250)
|
|
209
|
+
})
|
|
210
|
+
self.addEventListener('unhandledrejection', (event) => {
|
|
211
|
+
const error = (event as any).reason
|
|
212
|
+
if (error && typeof (error as any).message === 'string') {
|
|
213
|
+
// Post with some delay, so the master had some time to subscribe to messages
|
|
214
|
+
setTimeout(() => postUncaughtErrorMessage(error), 250)
|
|
215
|
+
}
|
|
216
|
+
})
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (typeof process !== 'undefined' && typeof process.on === 'function' && Implementation.isWorkerRuntime()) {
|
|
220
|
+
process.on('uncaughtException', (error) => {
|
|
221
|
+
// Post with some delay, so the master had some time to subscribe to messages
|
|
222
|
+
setTimeout(() => postUncaughtErrorMessage(error), 250)
|
|
223
|
+
})
|
|
224
|
+
process.on('unhandledRejection', (error) => {
|
|
225
|
+
if (error && typeof (error as any).message === 'string') {
|
|
226
|
+
// Post with some delay, so the master had some time to subscribe to messages
|
|
227
|
+
setTimeout(() => postUncaughtErrorMessage(error as any), 250)
|
|
228
|
+
}
|
|
229
|
+
})
|
|
230
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
// Webpack hack
|
|
3
|
+
// tslint:disable no-eval
|
|
4
|
+
|
|
5
|
+
declare function __non_webpack_require__(module: string): any
|
|
6
|
+
|
|
7
|
+
// FIXME
|
|
8
|
+
type MessagePort = any
|
|
9
|
+
|
|
10
|
+
interface WorkerThreadsModule {
|
|
11
|
+
MessagePort: typeof MessagePort
|
|
12
|
+
isMainThread: boolean
|
|
13
|
+
parentPort: MessagePort
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let implementation: WorkerThreadsModule | undefined
|
|
17
|
+
|
|
18
|
+
function selectImplementation(): WorkerThreadsModule {
|
|
19
|
+
return typeof __non_webpack_require__ === 'function' ? __non_webpack_require__('worker_threads') : eval('require')('worker_threads')
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default function getImplementation(): WorkerThreadsModule {
|
|
23
|
+
if (!implementation) {
|
|
24
|
+
implementation = selectImplementation()
|
|
25
|
+
}
|
|
26
|
+
return implementation
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './serialization.js'
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
|
|
3
|
+
import type { JsonSerializable, SerializerImplementation } from '../../src/index'
|
|
4
|
+
|
|
5
|
+
export class Foo<T> {
|
|
6
|
+
private readonly value: T
|
|
7
|
+
|
|
8
|
+
constructor(value: T) {
|
|
9
|
+
this.value = value
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
getValue() {
|
|
13
|
+
return this.value
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface SerializedFoo<T extends JsonSerializable> {
|
|
18
|
+
__type: '$$foo'
|
|
19
|
+
val: T
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const isSerializedFoo = (thing: any): thing is SerializedFoo<JsonSerializable> =>
|
|
23
|
+
thing && typeof thing === 'object' && '__type' in thing && thing.__type === '$$foo'
|
|
24
|
+
|
|
25
|
+
export const fooSerializer: SerializerImplementation = {
|
|
26
|
+
deserialize(serialized, fallback) {
|
|
27
|
+
return isSerializedFoo(serialized) ? new Foo(serialized.val) : fallback(serialized)
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
serialize(data, fallback) {
|
|
31
|
+
return data instanceof Foo
|
|
32
|
+
? {
|
|
33
|
+
__type: '$$foo',
|
|
34
|
+
val: data.getValue(),
|
|
35
|
+
}
|
|
36
|
+
: fallback(data)
|
|
37
|
+
},
|
|
38
|
+
}
|