@hybrid-compute/worker 0.0.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/.release-it.json +70 -0
- package/CHANGELOG.md +20 -0
- package/README.md +83 -0
- package/eslint.config.mjs +3 -0
- package/package.json +53 -0
- package/src/__tests__/worker.spec.ts +139 -0
- package/src/index.ts +118 -0
- package/src/types.ts +53 -0
- package/tsconfig.json +12 -0
package/.release-it.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"git": false,
|
|
3
|
+
"github": {
|
|
4
|
+
"release": true,
|
|
5
|
+
"tokenRef": "GH_TOKEN"
|
|
6
|
+
},
|
|
7
|
+
"npm": {
|
|
8
|
+
"publish": true,
|
|
9
|
+
"skipChecks": true
|
|
10
|
+
},
|
|
11
|
+
"hooks": {
|
|
12
|
+
"after:release": "echo Successfully released ${name} v${version} to ${repo.repository}."
|
|
13
|
+
},
|
|
14
|
+
"plugins": {
|
|
15
|
+
"@release-it/bumper": {
|
|
16
|
+
"out": {
|
|
17
|
+
"file": "package.json",
|
|
18
|
+
"path": ["dependencies.@hybrid-compute/core"]
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"@release-it/conventional-changelog": {
|
|
22
|
+
"header": "# Changelog",
|
|
23
|
+
"preset": {
|
|
24
|
+
"name": "conventionalcommits",
|
|
25
|
+
"types": [
|
|
26
|
+
{
|
|
27
|
+
"type": "chore",
|
|
28
|
+
"section": "Tasks"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"type": "docs",
|
|
32
|
+
"section": "Documentation"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"type": "feat",
|
|
36
|
+
"section": "Feature"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"type": "fix",
|
|
40
|
+
"section": "Bug"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"type": "perf",
|
|
44
|
+
"section": "Performance change"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"type": "refactor",
|
|
48
|
+
"section": "Refactoring"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"type": "release",
|
|
52
|
+
"section": "Create a release commit",
|
|
53
|
+
"hidden": true
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"type": "style",
|
|
57
|
+
"section": "Markup, white-space, formatting, missing semi-colons...",
|
|
58
|
+
"hidden": true
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"type": "test",
|
|
62
|
+
"section": "Adding missing tests",
|
|
63
|
+
"hidden": true
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
"infile": "CHANGELOG.md"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.0.1 (2025-06-01)
|
|
4
|
+
|
|
5
|
+
### Tasks
|
|
6
|
+
|
|
7
|
+
* 🤖 Add deps ([0a08767](https://github.com/phun-ky/hybrid-compute/commit/0a08767abed76c91ea902363890bb8f99e44a1da))
|
|
8
|
+
* 🤖 Adjustments before release ([ee23ac6](https://github.com/phun-ky/hybrid-compute/commit/ee23ac627f7d04c3c2b4fdf9b2dc1f826fa21593))
|
|
9
|
+
* 🤖 More adjustments ([f9dfee8](https://github.com/phun-ky/hybrid-compute/commit/f9dfee8fb9eb2e1cb104fca9ea24903a69d16f26))
|
|
10
|
+
* 🤖 Preparing for first release, with setup ([13f8f03](https://github.com/phun-ky/hybrid-compute/commit/13f8f03def7941c79b3695d0ba2409c6f9ba0896))
|
|
11
|
+
* 🤖 Remove lerna ([f4ba79e](https://github.com/phun-ky/hybrid-compute/commit/f4ba79ed10bb66271859cdfb905b8e4a8979784e))
|
|
12
|
+
* 🤖 Update references, keywords and description + badges ([bc0b1ac](https://github.com/phun-ky/hybrid-compute/commit/bc0b1ac537bc9610ade89fc001132776d096fd55))
|
|
13
|
+
* 🤖 Update workflows ([7f9d6b5](https://github.com/phun-ky/hybrid-compute/commit/7f9d6b55f7180bb0179fc9159d7453395e2ca1af))
|
|
14
|
+
* preparing for release ([d07d107](https://github.com/phun-ky/hybrid-compute/commit/d07d10777a200a755965cef115106430805fe70b))
|
|
15
|
+
|
|
16
|
+
### Documentation
|
|
17
|
+
|
|
18
|
+
* ✏️ Add documentation ([81e6fa1](https://github.com/phun-ky/hybrid-compute/commit/81e6fa189a3fb974e89c03a846d030118fdedbe4))
|
|
19
|
+
* ✏️ Regenerate documentation ([487d54f](https://github.com/phun-ky/hybrid-compute/commit/487d54ffb40abc03315e04fd2e5c1434fc3e9b27))
|
|
20
|
+
* ✏️ Update documentation ([1039082](https://github.com/phun-ky/hybrid-compute/commit/10390822d4a087a7a26b7a25ce25cb9099dbce94))
|
package/README.md
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# @hybrid-compute/worker
|
|
2
|
+
|
|
3
|
+
[](http://commitizen.github.io/cz-cli/)
|
|
4
|
+
[](http://makeapullrequest.com)
|
|
5
|
+
[](http://semver.org/spec/v2.0.0.html)
|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+
[](https://codecov.io/gh/phun-ky/hybrid-compute)
|
|
13
|
+
[](https://github.com/phun-ky/hybrid-compute/actions/workflows/check.yml)
|
|
14
|
+
|
|
15
|
+
Part of the [`@hybrid-compute`](https://github.com/phun-ky/hybrid-compute)
|
|
16
|
+
monorepo.
|
|
17
|
+
|
|
18
|
+
> See the [main README](https://github.com/phun-ky/hybrid-compute#readme) for
|
|
19
|
+
> full project overview, usage examples, architecture, and contribution
|
|
20
|
+
> guidelines.
|
|
21
|
+
|
|
22
|
+
## API Docs
|
|
23
|
+
|
|
24
|
+
[ThreadedCompute API Documentation](https://github.com/phun-ky/hybrid-compute/blob/main/docs/api/worker/src/classes/ThreadedCompute.md)
|
|
25
|
+
|
|
26
|
+
## 📦 Package Info
|
|
27
|
+
|
|
28
|
+
This package provides:
|
|
29
|
+
|
|
30
|
+
- A compute backend that runs tasks in a dedicated Web Worker
|
|
31
|
+
- Asynchronous task messaging via `postMessage`
|
|
32
|
+
- Useful for offloading CPU-intensive work from the main thread
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npm install @hybrid-compute/worker
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { createThreadedCompute } from '@hybrid-compute/worker';
|
|
42
|
+
|
|
43
|
+
const threaded = createThreadedCompute(
|
|
44
|
+
new URL('./worker.js', import.meta.url),
|
|
45
|
+
['add']
|
|
46
|
+
);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Contributing
|
|
52
|
+
|
|
53
|
+
Want to contribute? Please read the
|
|
54
|
+
[CONTRIBUTING.md](https://github.com/phun-ky/hybrid-compute/blob/main/CONTRIBUTING.md)
|
|
55
|
+
and
|
|
56
|
+
[CODE_OF_CONDUCT.md](https://github.com/phun-ky/hybrid-compute/blob/main/CODE_OF_CONDUCT.md)
|
|
57
|
+
|
|
58
|
+
## License
|
|
59
|
+
|
|
60
|
+
This project is licensed under the MIT License - see the
|
|
61
|
+
[LICENSE](https://github.com/phun-ky/hybrid-compute/blob/main/LICENSE) file for
|
|
62
|
+
details.
|
|
63
|
+
|
|
64
|
+
## Sponsor me
|
|
65
|
+
|
|
66
|
+
I'm an Open Source evangelist, creating stuff that does not exist yet to help
|
|
67
|
+
get rid of secondary activities and to enhance systems already in place, be it
|
|
68
|
+
documentation, tools or web sites.
|
|
69
|
+
|
|
70
|
+
The sponsorship is an unique opportunity to alleviate more hours for me to
|
|
71
|
+
maintain my projects, create new ones and contribute to the large community
|
|
72
|
+
we're all part of :)
|
|
73
|
+
|
|
74
|
+
[Support me on GitHub Sponsors](https://github.com/sponsors/phun-ky).
|
|
75
|
+
|
|
76
|
+
p.s. **Ukraine is still under brutal Russian invasion. A lot of Ukrainian people
|
|
77
|
+
are hurt, without shelter and need help**. You can help in various ways, for
|
|
78
|
+
instance, directly helping refugees, spreading awareness, putting pressure on
|
|
79
|
+
your local government or companies. You can also support Ukraine by donating
|
|
80
|
+
e.g. to [Red Cross](https://www.icrc.org/en/donate/ukraine),
|
|
81
|
+
[Ukraine humanitarian organisation](https://savelife.in.ua/en/donate-en/#donate-army-card-weekly)
|
|
82
|
+
or
|
|
83
|
+
[donate Ambulances for Ukraine](https://www.gofundme.com/f/help-to-save-the-lives-of-civilians-in-a-war-zone).
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hybrid-compute/worker",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Threaded compute backend for executing tasks in Web Workers.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"web-worker",
|
|
7
|
+
"worker",
|
|
8
|
+
"thread",
|
|
9
|
+
"multithreaded",
|
|
10
|
+
"compute",
|
|
11
|
+
"offload",
|
|
12
|
+
"async",
|
|
13
|
+
"frontend",
|
|
14
|
+
"task"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://phun-ky.net/projects/hybrid-compute",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/phun-ky/hybrid-compute/issues"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/phun-ky/hybrid-compute.git"
|
|
23
|
+
},
|
|
24
|
+
"funding": "https://github.com/phun-ky/hybrid-compute?sponsor=1",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"author": "Alexander Vassbotn Røyne-Helgesen <alexander@phun-ky.net>",
|
|
27
|
+
"type": "module",
|
|
28
|
+
"exports": "./dist/index.js",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"scripts": {
|
|
31
|
+
"release": "release-it",
|
|
32
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
33
|
+
"test": "tsx --test **/__tests__/**/*.spec.ts",
|
|
34
|
+
"pretest:ci": "rm -rf coverage && mkdir -p coverage",
|
|
35
|
+
"test:ci": "glob -c \"node --import tsx --test --no-warnings --experimental-test-coverage --test-reporter=cobertura --test-reporter-destination=coverage/cobertura-coverage.xml --test-reporter=spec --test-reporter-destination=stdout\" \"**/__tests__/**/*.spec.ts\""
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@hybrid-compute/core": "0.0.1"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"eslint": "^9.27.0",
|
|
42
|
+
"eslint-config-phun-ky": "^1.0.3",
|
|
43
|
+
"prettier": "^3.5.3",
|
|
44
|
+
"typescript": "^5.8.3"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=22.0.0",
|
|
48
|
+
"npm": ">=10.8.2"
|
|
49
|
+
},
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import test, { describe } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import {
|
|
4
|
+
createThreadedCompute,
|
|
5
|
+
ThreadedCompute,
|
|
6
|
+
WorkerResultMessageInterface,
|
|
7
|
+
WorkerTaskMessageInterface
|
|
8
|
+
} from '..';
|
|
9
|
+
|
|
10
|
+
describe('ThreadedCompute', () => {
|
|
11
|
+
test('canRun returns true for registered task', () => {
|
|
12
|
+
const OriginalWorker = globalThis.Worker;
|
|
13
|
+
|
|
14
|
+
class MockWorker {
|
|
15
|
+
public onmessage: ((event: any) => void) | null = null;
|
|
16
|
+
constructor(
|
|
17
|
+
public path: string,
|
|
18
|
+
public options: object
|
|
19
|
+
) {}
|
|
20
|
+
postMessage() {}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// @ts-expect-error allow override
|
|
24
|
+
globalThis.Worker = MockWorker;
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const threaded = new ThreadedCompute('mock-worker.js', ['foo', 'bar']);
|
|
28
|
+
assert.equal(threaded.canRun('foo'), true);
|
|
29
|
+
assert.equal(threaded.canRun('baz'), false);
|
|
30
|
+
} finally {
|
|
31
|
+
globalThis.Worker = OriginalWorker;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('runTask resolves with worker result', async () => {
|
|
36
|
+
const OriginalWorker = globalThis.Worker;
|
|
37
|
+
|
|
38
|
+
class MockWorker {
|
|
39
|
+
public onmessage:
|
|
40
|
+
| ((event: MessageEvent<WorkerResultMessageInterface>) => void)
|
|
41
|
+
| null = null;
|
|
42
|
+
public received: WorkerTaskMessageInterface | null = null;
|
|
43
|
+
|
|
44
|
+
constructor(
|
|
45
|
+
public path: string,
|
|
46
|
+
public options: object
|
|
47
|
+
) {}
|
|
48
|
+
|
|
49
|
+
postMessage(msg: WorkerTaskMessageInterface) {
|
|
50
|
+
this.received = msg;
|
|
51
|
+
|
|
52
|
+
setTimeout(() => {
|
|
53
|
+
this.onmessage?.({
|
|
54
|
+
data: {
|
|
55
|
+
id: msg.id,
|
|
56
|
+
result: `result-${msg.input}`
|
|
57
|
+
}
|
|
58
|
+
} as MessageEvent<WorkerResultMessageInterface>);
|
|
59
|
+
}, 10);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// @ts-expect-error override
|
|
64
|
+
globalThis.Worker = MockWorker;
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const compute = new ThreadedCompute('mock-worker.js', ['echo']);
|
|
68
|
+
const result = await compute.runTask<string, string>('echo', 'ping');
|
|
69
|
+
assert.equal(result, 'result-ping');
|
|
70
|
+
} finally {
|
|
71
|
+
globalThis.Worker = OriginalWorker;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test('runTask rejects with worker error', async () => {
|
|
76
|
+
const OriginalWorker = globalThis.Worker;
|
|
77
|
+
|
|
78
|
+
class MockWorker {
|
|
79
|
+
public onmessage:
|
|
80
|
+
| ((event: MessageEvent<WorkerResultMessageInterface>) => void)
|
|
81
|
+
| null = null;
|
|
82
|
+
|
|
83
|
+
constructor(
|
|
84
|
+
public path: string,
|
|
85
|
+
public options: object
|
|
86
|
+
) {}
|
|
87
|
+
|
|
88
|
+
postMessage(msg: WorkerTaskMessageInterface) {
|
|
89
|
+
setTimeout(() => {
|
|
90
|
+
this.onmessage?.({
|
|
91
|
+
data: {
|
|
92
|
+
id: msg.id,
|
|
93
|
+
error: 'Something went wrong'
|
|
94
|
+
}
|
|
95
|
+
} as MessageEvent<WorkerResultMessageInterface>);
|
|
96
|
+
}, 10);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// @ts-expect-error override
|
|
101
|
+
globalThis.Worker = MockWorker;
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
const compute = new ThreadedCompute('mock-worker.js', ['fail']);
|
|
105
|
+
await assert.rejects(
|
|
106
|
+
() => compute.runTask('fail', 42),
|
|
107
|
+
/Something went wrong/
|
|
108
|
+
);
|
|
109
|
+
} finally {
|
|
110
|
+
globalThis.Worker = OriginalWorker;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
describe('createThreadedCompute', () => {
|
|
115
|
+
test('returns instance of ThreadedCompute', () => {
|
|
116
|
+
const OriginalWorker = globalThis.Worker;
|
|
117
|
+
|
|
118
|
+
class MockWorker {
|
|
119
|
+
public onmessage:
|
|
120
|
+
| ((event: MessageEvent<WorkerResultMessageInterface>) => void)
|
|
121
|
+
| null = null;
|
|
122
|
+
constructor(
|
|
123
|
+
public path: string,
|
|
124
|
+
public options: object
|
|
125
|
+
) {}
|
|
126
|
+
postMessage() {}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// @ts-expect-error override
|
|
130
|
+
globalThis.Worker = MockWorker;
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const instance = createThreadedCompute('mock-worker.js', ['foo']);
|
|
134
|
+
assert.ok(instance instanceof ThreadedCompute);
|
|
135
|
+
} finally {
|
|
136
|
+
globalThis.Worker = OriginalWorker;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
});
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { ComputeBackendInterface } from '@hybrid-compute/core';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
WorkerResultMessageInterface,
|
|
5
|
+
WorkerTaskMessageInterface
|
|
6
|
+
} from './types.js';
|
|
7
|
+
|
|
8
|
+
export * from './types.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* `ThreadedCompute` is a compute backend that runs tasks in a dedicated Web Worker.
|
|
12
|
+
*
|
|
13
|
+
* It manages communication with the worker via `postMessage`, assigns unique task
|
|
14
|
+
* request IDs, and resolves results asynchronously. Tasks are registered by name
|
|
15
|
+
* during construction and mapped internally for availability checks.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const threaded = new ThreadedCompute(new URL('./worker.js', import.meta.url), ['add']);
|
|
20
|
+
*
|
|
21
|
+
* const result = await threaded.runTask<number, number>('add', 5);
|
|
22
|
+
* console.log(result); // Output from worker
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Worker
|
|
26
|
+
*/
|
|
27
|
+
export class ThreadedCompute implements ComputeBackendInterface {
|
|
28
|
+
private worker: Worker;
|
|
29
|
+
private taskMap = new Set<string>();
|
|
30
|
+
|
|
31
|
+
// Map of task response IDs to success callbacks
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
33
|
+
private callbacks = new Map<number, (value: any) => void>();
|
|
34
|
+
|
|
35
|
+
// Map of task response IDs to error callbacks
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
37
|
+
private errors = new Map<number, (err: any) => void>();
|
|
38
|
+
|
|
39
|
+
private nextId = 1;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Constructs a new `ThreadedCompute` backend with a specified worker and list of available task names.
|
|
43
|
+
*
|
|
44
|
+
* @param workerPath - Path to the worker script (typically a URL via `import.meta.url`).
|
|
45
|
+
* @param taskNames - A list of task identifiers this worker is capable of executing.
|
|
46
|
+
*/
|
|
47
|
+
constructor(workerPath: string, taskNames: string[]) {
|
|
48
|
+
this.worker = new Worker(workerPath, { type: 'module' });
|
|
49
|
+
this.taskMap = new Set(taskNames);
|
|
50
|
+
|
|
51
|
+
this.worker.onmessage = (e: MessageEvent<WorkerResultMessageInterface>) => {
|
|
52
|
+
const { id, result, error } = e.data;
|
|
53
|
+
|
|
54
|
+
if (error) this.errors.get(id)?.(error);
|
|
55
|
+
else this.callbacks.get(id)?.(result);
|
|
56
|
+
|
|
57
|
+
this.callbacks.delete(id);
|
|
58
|
+
this.errors.delete(id);
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Checks whether the current worker is registered to handle a given task.
|
|
64
|
+
*
|
|
65
|
+
* @param taskName - The name of the task to check.
|
|
66
|
+
* @returns `true` if the task is supported, otherwise `false`.
|
|
67
|
+
*/
|
|
68
|
+
canRun(taskName: string): boolean {
|
|
69
|
+
return this.taskMap.has(taskName);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Runs a task inside the Web Worker.
|
|
74
|
+
*
|
|
75
|
+
* The task is assigned a unique ID and sent via `postMessage`. The result or error
|
|
76
|
+
* is resolved asynchronously when the worker responds.
|
|
77
|
+
*
|
|
78
|
+
* @typeParam Input - The input type for the task.
|
|
79
|
+
* @typeParam Output - The output type returned by the task.
|
|
80
|
+
*
|
|
81
|
+
* @param taskName - The name of the task to execute.
|
|
82
|
+
* @param input - The input payload for the task.
|
|
83
|
+
* @returns A Promise resolving to the task output.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* const result = await threaded.runTask('square', 9); // 81
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
runTask<Input, Output>(taskName: string, input: Input): Promise<Output> {
|
|
91
|
+
return new Promise<Output>((resolve, reject) => {
|
|
92
|
+
const id = this.nextId++;
|
|
93
|
+
|
|
94
|
+
this.callbacks.set(id, resolve);
|
|
95
|
+
this.errors.set(id, reject);
|
|
96
|
+
|
|
97
|
+
const message: WorkerTaskMessageInterface = { task: taskName, input, id };
|
|
98
|
+
|
|
99
|
+
this.worker.postMessage(message);
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Factory function to create a new `ThreadedCompute` backend.
|
|
106
|
+
*
|
|
107
|
+
* @param workerPath - The module worker file path (e.g. `new URL('./worker.js', import.meta.url)`).
|
|
108
|
+
* @param tasks - A list of supported task names this worker can execute.
|
|
109
|
+
* @returns A new `ThreadedCompute` instance.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* ```ts
|
|
113
|
+
* const backend = createThreadedCompute(new URL('./worker.js', import.meta.url), ['resizeImage']);
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export function createThreadedCompute(workerPath: string, tasks: string[]) {
|
|
117
|
+
return new ThreadedCompute(workerPath, tasks);
|
|
118
|
+
}
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The message format sent from the main thread to a Web Worker when executing a task.
|
|
3
|
+
*
|
|
4
|
+
* This message includes a task name, its input payload, and a unique ID used to match
|
|
5
|
+
* the response from the worker.
|
|
6
|
+
*
|
|
7
|
+
* @property task - The name of the task to be executed in the worker.
|
|
8
|
+
* @property input - The input data for the task. This can be any JSON-serializable value.
|
|
9
|
+
* @property id - A unique identifier for correlating the response message.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const message: WorkerTaskMessageInterface = {
|
|
14
|
+
* task: 'double',
|
|
15
|
+
* input: 21,
|
|
16
|
+
* id: 1
|
|
17
|
+
* };
|
|
18
|
+
* worker.postMessage(message);
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export interface WorkerTaskMessageInterface {
|
|
22
|
+
task: string;
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
24
|
+
input: any;
|
|
25
|
+
id: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* The message format sent from a Web Worker back to the main thread upon task completion.
|
|
30
|
+
*
|
|
31
|
+
* This message includes the result of the task execution or an error message if the task failed.
|
|
32
|
+
*
|
|
33
|
+
* @property id - The unique identifier that matches a previously sent task message.
|
|
34
|
+
* @property result - The result of the task execution (if successful).
|
|
35
|
+
* @property error - An optional error message if the task failed.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* const response: WorkerResultMessageInterface = {
|
|
40
|
+
* id: 1,
|
|
41
|
+
* result: 42
|
|
42
|
+
* };
|
|
43
|
+
* postMessage(response);
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers
|
|
47
|
+
*/
|
|
48
|
+
export interface WorkerResultMessageInterface {
|
|
49
|
+
id: number;
|
|
50
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
51
|
+
result: any;
|
|
52
|
+
error?: string;
|
|
53
|
+
}
|
package/tsconfig.json
ADDED