@simplysm/core-node 13.0.100 → 14.0.4
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/README.md +93 -79
- package/dist/features/fs-watcher.d.ts +21 -21
- package/dist/features/fs-watcher.d.ts.map +1 -1
- package/dist/features/fs-watcher.js +176 -114
- package/dist/features/fs-watcher.js.map +1 -6
- package/dist/index.js +6 -7
- package/dist/index.js.map +1 -6
- package/dist/utils/fs.d.ts +96 -96
- package/dist/utils/fs.d.ts.map +1 -1
- package/dist/utils/fs.js +437 -272
- package/dist/utils/fs.js.map +1 -6
- package/dist/utils/path.d.ts +22 -22
- package/dist/utils/path.js +103 -45
- package/dist/utils/path.js.map +1 -6
- package/dist/worker/create-worker.d.ts +3 -3
- package/dist/worker/create-worker.js +106 -81
- package/dist/worker/create-worker.js.map +1 -6
- package/dist/worker/types.d.ts +14 -14
- package/dist/worker/types.js +4 -1
- package/dist/worker/types.js.map +1 -6
- package/dist/worker/worker.d.ts +5 -5
- package/dist/worker/worker.js +168 -132
- package/dist/worker/worker.js.map +1 -6
- package/docs/fs-watcher.md +107 -0
- package/docs/fsx.md +287 -0
- package/docs/pathx.md +115 -0
- package/docs/worker.md +117 -62
- package/lib/worker-dev-proxy.js +15 -0
- package/package.json +9 -6
- package/src/features/fs-watcher.ts +53 -42
- package/src/index.ts +3 -3
- package/src/utils/fs.ts +111 -120
- package/src/utils/path.ts +26 -26
- package/src/worker/create-worker.ts +10 -10
- package/src/worker/types.ts +14 -14
- package/src/worker/worker.ts +29 -29
- package/docs/features.md +0 -91
- package/docs/fs.md +0 -309
- package/docs/path.md +0 -120
- package/tests/utils/fs-watcher.spec.ts +0 -286
- package/tests/utils/fs.spec.ts +0 -705
- package/tests/utils/path.spec.ts +0 -179
- package/tests/worker/fixtures/test-worker.ts +0 -35
- package/tests/worker/sd-worker.spec.ts +0 -174
package/docs/fsx.md
ADDED
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# fsx -- File System Utilities
|
|
2
|
+
|
|
3
|
+
Namespace providing sync and async file system operations with automatic error wrapping, recursive directory creation, and glob support.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { fsx } from "@simplysm/core-node";
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Functions
|
|
10
|
+
|
|
11
|
+
### existsSync
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
function existsSync(targetPath: string): boolean
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Check if a file or directory exists (synchronous).
|
|
18
|
+
|
|
19
|
+
### exists
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
async function exists(targetPath: string): Promise<boolean>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Check if a file or directory exists (asynchronous).
|
|
26
|
+
|
|
27
|
+
### mkdirSync
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
function mkdirSync(targetPath: string): void
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Create a directory recursively (synchronous). Equivalent to `mkdir -p`.
|
|
34
|
+
|
|
35
|
+
### mkdir
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
async function mkdir(targetPath: string): Promise<void>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Create a directory recursively (asynchronous). Equivalent to `mkdir -p`.
|
|
42
|
+
|
|
43
|
+
### rmSync
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
function rmSync(targetPath: string): void
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Remove a file or directory recursively (synchronous). Does not retry on failure -- use `rm` if transient errors (e.g., file locks) are expected.
|
|
50
|
+
|
|
51
|
+
### rm
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
async function rm(targetPath: string): Promise<void>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Remove a file or directory recursively (asynchronous). Retries up to 6 times with 500ms delay on transient errors.
|
|
58
|
+
|
|
59
|
+
### copySync
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
function copySync(
|
|
63
|
+
sourcePath: string,
|
|
64
|
+
targetPath: string,
|
|
65
|
+
filter?: (absolutePath: string) => boolean,
|
|
66
|
+
): void
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Copy a file or directory recursively (synchronous).
|
|
70
|
+
|
|
71
|
+
- If `sourcePath` does not exist, returns silently.
|
|
72
|
+
- `filter` receives the absolute path of each child entry. Return `true` to include, `false` to exclude.
|
|
73
|
+
- The top-level `sourcePath` is not subject to filtering -- only its descendants are.
|
|
74
|
+
- Returning `false` for a directory skips it and all its contents.
|
|
75
|
+
|
|
76
|
+
### copy
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
async function copy(
|
|
80
|
+
sourcePath: string,
|
|
81
|
+
targetPath: string,
|
|
82
|
+
filter?: (absolutePath: string) => boolean,
|
|
83
|
+
): Promise<void>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Copy a file or directory recursively (asynchronous). Same semantics as `copySync`.
|
|
87
|
+
|
|
88
|
+
### readSync
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
function readSync(targetPath: string): string
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Read a file as a UTF-8 string (synchronous).
|
|
95
|
+
|
|
96
|
+
### read
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
async function read(targetPath: string): Promise<string>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Read a file as a UTF-8 string (asynchronous).
|
|
103
|
+
|
|
104
|
+
### readBufferSync
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
function readBufferSync(targetPath: string): Buffer
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Read a file as a `Buffer` (synchronous).
|
|
111
|
+
|
|
112
|
+
### readBuffer
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
async function readBuffer(targetPath: string): Promise<Buffer>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Read a file as a `Buffer` (asynchronous).
|
|
119
|
+
|
|
120
|
+
### readJsonSync
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
function readJsonSync<TData = unknown>(targetPath: string): TData
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Read and parse a JSON file using `json.parse` from `@simplysm/core-common` (synchronous). On parse failure, the error message includes a preview of the file contents.
|
|
127
|
+
|
|
128
|
+
### readJson
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
async function readJson<TData = unknown>(targetPath: string): Promise<TData>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Read and parse a JSON file using `json.parse` from `@simplysm/core-common` (asynchronous). On parse failure, the error message includes a preview of the file contents.
|
|
135
|
+
|
|
136
|
+
### writeSync
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
function writeSync(targetPath: string, data: string | Uint8Array): void
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Write data to a file (synchronous). Parent directories are created automatically. The file is flushed to disk.
|
|
143
|
+
|
|
144
|
+
### write
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
async function write(targetPath: string, data: string | Uint8Array): Promise<void>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Write data to a file (asynchronous). Parent directories are created automatically. The file is flushed to disk.
|
|
151
|
+
|
|
152
|
+
### writeJsonSync
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
function writeJsonSync(
|
|
156
|
+
targetPath: string,
|
|
157
|
+
data: unknown,
|
|
158
|
+
options?: {
|
|
159
|
+
replacer?: (this: unknown, key: string | undefined, value: unknown) => unknown;
|
|
160
|
+
space?: string | number;
|
|
161
|
+
},
|
|
162
|
+
): void
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Serialize data to JSON and write to a file (synchronous). Uses `json.stringify` from `@simplysm/core-common`.
|
|
166
|
+
|
|
167
|
+
| Option | Type | Description |
|
|
168
|
+
|--------|------|-------------|
|
|
169
|
+
| `replacer` | `(this: unknown, key: string \| undefined, value: unknown) => unknown` | Custom replacer function |
|
|
170
|
+
| `space` | `string \| number` | Indentation (spaces or string) |
|
|
171
|
+
|
|
172
|
+
### writeJson
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
async function writeJson(
|
|
176
|
+
targetPath: string,
|
|
177
|
+
data: unknown,
|
|
178
|
+
options?: {
|
|
179
|
+
replacer?: (this: unknown, key: string | undefined, value: unknown) => unknown;
|
|
180
|
+
space?: string | number;
|
|
181
|
+
},
|
|
182
|
+
): Promise<void>
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Serialize data to JSON and write to a file (asynchronous). Uses `json.stringify` from `@simplysm/core-common`. Same options as `writeJsonSync`.
|
|
186
|
+
|
|
187
|
+
### readdirSync
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
function readdirSync(targetPath: string): string[]
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Read directory contents (synchronous). Returns an array of entry names.
|
|
194
|
+
|
|
195
|
+
### readdir
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
async function readdir(targetPath: string): Promise<string[]>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Read directory contents (asynchronous). Returns an array of entry names.
|
|
202
|
+
|
|
203
|
+
### statSync
|
|
204
|
+
|
|
205
|
+
```ts
|
|
206
|
+
function statSync(targetPath: string): fs.Stats
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Get file/directory info (synchronous). Follows symbolic links.
|
|
210
|
+
|
|
211
|
+
### stat
|
|
212
|
+
|
|
213
|
+
```ts
|
|
214
|
+
async function stat(targetPath: string): Promise<fs.Stats>
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Get file/directory info (asynchronous). Follows symbolic links.
|
|
218
|
+
|
|
219
|
+
### lstatSync
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
function lstatSync(targetPath: string): fs.Stats
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Get file/directory info (synchronous). Does **not** follow symbolic links.
|
|
226
|
+
|
|
227
|
+
### lstat
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
async function lstat(targetPath: string): Promise<fs.Stats>
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Get file/directory info (asynchronous). Does **not** follow symbolic links.
|
|
234
|
+
|
|
235
|
+
### globSync
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
function globSync(pattern: string, options?: GlobOptions): string[]
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Search for files matching a glob pattern (synchronous). Returns absolute paths. Backslashes in the pattern are converted to forward slashes.
|
|
242
|
+
|
|
243
|
+
### glob
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
async function glob(pattern: string, options?: GlobOptions): Promise<string[]>
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Search for files matching a glob pattern (asynchronous). Returns absolute paths. Backslashes in the pattern are converted to forward slashes.
|
|
250
|
+
|
|
251
|
+
### clearEmptyDirectory
|
|
252
|
+
|
|
253
|
+
```ts
|
|
254
|
+
async function clearEmptyDirectory(dirPath: string): Promise<void>
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Recursively find and remove empty directories under `dirPath`. If removing children causes a parent directory to become empty, it is also removed.
|
|
258
|
+
|
|
259
|
+
### findAllParentChildPathsSync
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
function findAllParentChildPathsSync(
|
|
263
|
+
childGlob: string,
|
|
264
|
+
fromPath: string,
|
|
265
|
+
rootPath?: string,
|
|
266
|
+
): string[]
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Walk from `fromPath` toward the filesystem root, collecting all files matching `childGlob` in each directory (synchronous).
|
|
270
|
+
|
|
271
|
+
| Parameter | Type | Description |
|
|
272
|
+
|-----------|------|-------------|
|
|
273
|
+
| `childGlob` | `string` | Glob pattern to match in each directory |
|
|
274
|
+
| `fromPath` | `string` | Starting path for the upward walk |
|
|
275
|
+
| `rootPath` | `string?` | Stop path (defaults to filesystem root). `fromPath` must be a descendant of `rootPath`. |
|
|
276
|
+
|
|
277
|
+
### findAllParentChildPaths
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
async function findAllParentChildPaths(
|
|
281
|
+
childGlob: string,
|
|
282
|
+
fromPath: string,
|
|
283
|
+
rootPath?: string,
|
|
284
|
+
): Promise<string[]>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Walk from `fromPath` toward the filesystem root, collecting all files matching `childGlob` in each directory (asynchronous). Same parameters as `findAllParentChildPathsSync`.
|
package/docs/pathx.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# pathx -- Path Utilities
|
|
2
|
+
|
|
3
|
+
Namespace providing path manipulation utilities with normalization, POSIX conversion, and filtering.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { pathx } from "@simplysm/core-node";
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Types
|
|
10
|
+
|
|
11
|
+
### NormPath
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
type NormPath = string & { [NORM]: never }
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Branded type representing a normalized absolute path. Can only be created via `norm()`. The brand prevents accidental use of raw strings where a normalized path is expected.
|
|
18
|
+
|
|
19
|
+
## Functions
|
|
20
|
+
|
|
21
|
+
### posix
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
function posix(...args: string[]): string
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Convert a path to POSIX style by joining the arguments and replacing backslashes with forward slashes.
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
pathx.posix("C:\\Users\\test"); // "C:/Users/test"
|
|
31
|
+
pathx.posix("src", "index.ts"); // "src/index.ts"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### changeFileDirectory
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
function changeFileDirectory(
|
|
38
|
+
filePath: string,
|
|
39
|
+
fromDirectory: string,
|
|
40
|
+
toDirectory: string,
|
|
41
|
+
): string
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Change the directory portion of a file path. The file must be inside `fromDirectory`; throws `ArgumentError` otherwise.
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
pathx.changeFileDirectory("/a/b/c.txt", "/a", "/x");
|
|
48
|
+
// "/x/b/c.txt"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### basenameWithoutExt
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
function basenameWithoutExt(filePath: string): string
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Return the filename without its extension.
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
pathx.basenameWithoutExt("file.txt"); // "file"
|
|
61
|
+
pathx.basenameWithoutExt("/path/to/file.spec.ts"); // "file.spec"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### isChildPath
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
function isChildPath(childPath: string, parentPath: string): boolean
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Check if `childPath` is a descendant of `parentPath`. Returns `false` for identical paths. Paths are normalized internally via `norm()`.
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
pathx.isChildPath("/a/b/c", "/a/b"); // true
|
|
74
|
+
pathx.isChildPath("/a/b", "/a/b/c"); // false
|
|
75
|
+
pathx.isChildPath("/a/b", "/a/b"); // false (same path)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### norm
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
function norm(...paths: string[]): NormPath
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Normalize and resolve path segments into an absolute `NormPath`. Uses the platform-specific path separator.
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
pathx.norm("/some/path"); // NormPath
|
|
88
|
+
pathx.norm("relative", "path"); // NormPath (resolved to absolute)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### filterByTargets
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
function filterByTargets(
|
|
95
|
+
files: string[],
|
|
96
|
+
targets: string[],
|
|
97
|
+
cwd: string,
|
|
98
|
+
): string[]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Filter file paths by target directory prefixes.
|
|
102
|
+
|
|
103
|
+
| Parameter | Type | Description |
|
|
104
|
+
|-----------|------|-------------|
|
|
105
|
+
| `files` | `string[]` | Absolute file paths to filter (must be under `cwd`) |
|
|
106
|
+
| `targets` | `string[]` | Target directory prefixes (relative to `cwd`, POSIX style recommended) |
|
|
107
|
+
| `cwd` | `string` | Current working directory (absolute path) |
|
|
108
|
+
|
|
109
|
+
Returns `files` unchanged if `targets` is empty. Otherwise returns only files whose relative path matches or is a child of a target.
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
const files = ["/proj/src/a.ts", "/proj/src/b.ts", "/proj/tests/c.ts"];
|
|
113
|
+
pathx.filterByTargets(files, ["src"], "/proj");
|
|
114
|
+
// ["/proj/src/a.ts", "/proj/src/b.ts"]
|
|
115
|
+
```
|
package/docs/worker.md
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
# Worker
|
|
1
|
+
# Worker -- Typed Worker Threads
|
|
2
2
|
|
|
3
|
-
Type-safe
|
|
3
|
+
Type-safe worker thread wrapper providing Proxy-based RPC and event communication between the main thread and worker threads.
|
|
4
4
|
|
|
5
|
-
```
|
|
5
|
+
```ts
|
|
6
6
|
import { Worker, createWorker } from "@simplysm/core-node";
|
|
7
|
+
import type {
|
|
8
|
+
WorkerModule,
|
|
9
|
+
PromisifyMethods,
|
|
10
|
+
WorkerProxy,
|
|
11
|
+
WorkerRequest,
|
|
12
|
+
WorkerResponse,
|
|
13
|
+
} from "@simplysm/core-node";
|
|
7
14
|
```
|
|
8
15
|
|
|
9
16
|
## Types
|
|
10
17
|
|
|
11
|
-
###
|
|
18
|
+
### WorkerModule (interface)
|
|
12
19
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
20
|
+
```ts
|
|
16
21
|
interface WorkerModule {
|
|
17
22
|
default: {
|
|
18
23
|
__methods: Record<string, (...args: any[]) => unknown>;
|
|
@@ -21,48 +26,56 @@ interface WorkerModule {
|
|
|
21
26
|
}
|
|
22
27
|
```
|
|
23
28
|
|
|
24
|
-
|
|
29
|
+
Type structure representing a worker module. Used with `Worker.create<typeof import("./worker")>()` for type inference.
|
|
30
|
+
|
|
31
|
+
| Field | Type | Description |
|
|
32
|
+
|-------|------|-------------|
|
|
33
|
+
| `default.__methods` | `Record<string, (...args: any[]) => unknown>` | Map of callable worker methods |
|
|
34
|
+
| `default.__events` | `Record<string, unknown>` | Map of event names to event data types |
|
|
25
35
|
|
|
26
|
-
|
|
36
|
+
### PromisifyMethods
|
|
27
37
|
|
|
28
|
-
```
|
|
38
|
+
```ts
|
|
29
39
|
type PromisifyMethods<TMethods> = {
|
|
30
40
|
[K in keyof TMethods]: TMethods[K] extends (...args: infer P) => infer R
|
|
31
41
|
? (...args: P) => Promise<Awaited<R>>
|
|
32
42
|
: never;
|
|
33
|
-
}
|
|
43
|
+
}
|
|
34
44
|
```
|
|
35
45
|
|
|
36
|
-
|
|
46
|
+
Utility type that wraps all method return types in `Promise`. Worker methods communicate via `postMessage` and are inherently asynchronous, so even synchronous method signatures are converted to `Promise<Awaited<R>>`.
|
|
37
47
|
|
|
38
|
-
|
|
48
|
+
### WorkerProxy
|
|
39
49
|
|
|
40
|
-
```
|
|
50
|
+
```ts
|
|
41
51
|
type WorkerProxy<TModule extends WorkerModule> = PromisifyMethods<
|
|
42
52
|
TModule["default"]["__methods"]
|
|
43
53
|
> & {
|
|
44
|
-
/** Registers a worker event listener. */
|
|
45
54
|
on<TEventName extends keyof TModule["default"]["__events"] & string>(
|
|
46
55
|
event: TEventName,
|
|
47
56
|
listener: (data: TModule["default"]["__events"][TEventName]) => void,
|
|
48
57
|
): void;
|
|
49
58
|
|
|
50
|
-
/** Unregisters a worker event listener. */
|
|
51
59
|
off<TEventName extends keyof TModule["default"]["__events"] & string>(
|
|
52
60
|
event: TEventName,
|
|
53
61
|
listener: (data: TModule["default"]["__events"][TEventName]) => void,
|
|
54
62
|
): void;
|
|
55
63
|
|
|
56
|
-
/** Terminates the worker. */
|
|
57
64
|
terminate(): Promise<void>;
|
|
58
|
-
}
|
|
65
|
+
}
|
|
59
66
|
```
|
|
60
67
|
|
|
61
|
-
|
|
68
|
+
The proxy type returned by `Worker.create()`. Combines promisified worker methods with event handling and termination.
|
|
69
|
+
|
|
70
|
+
| Method | Description |
|
|
71
|
+
|--------|-------------|
|
|
72
|
+
| `on(event, listener)` | Register an event listener |
|
|
73
|
+
| `off(event, listener)` | Remove an event listener |
|
|
74
|
+
| `terminate()` | Terminate the worker thread |
|
|
62
75
|
|
|
63
|
-
|
|
76
|
+
### WorkerRequest (interface)
|
|
64
77
|
|
|
65
|
-
```
|
|
78
|
+
```ts
|
|
66
79
|
interface WorkerRequest {
|
|
67
80
|
id: string;
|
|
68
81
|
method: string;
|
|
@@ -70,99 +83,141 @@ interface WorkerRequest {
|
|
|
70
83
|
}
|
|
71
84
|
```
|
|
72
85
|
|
|
73
|
-
|
|
86
|
+
Internal message format sent from the main thread to the worker.
|
|
74
87
|
|
|
75
|
-
|
|
88
|
+
| Field | Type | Description |
|
|
89
|
+
|-------|------|-------------|
|
|
90
|
+
| `id` | `string` | Unique request identifier (UUID) |
|
|
91
|
+
| `method` | `string` | Name of the method to invoke |
|
|
92
|
+
| `params` | `unknown[]` | Method arguments |
|
|
76
93
|
|
|
77
|
-
|
|
94
|
+
### WorkerResponse (type)
|
|
95
|
+
|
|
96
|
+
```ts
|
|
78
97
|
type WorkerResponse =
|
|
79
98
|
| { request: WorkerRequest; type: "return"; body?: unknown }
|
|
80
99
|
| { request: WorkerRequest; type: "error"; body: Error }
|
|
81
100
|
| { type: "event"; event: string; body?: unknown }
|
|
82
|
-
| { type: "log"; body: string }
|
|
101
|
+
| { type: "log"; body: string }
|
|
83
102
|
```
|
|
84
103
|
|
|
85
|
-
|
|
104
|
+
Internal message format sent from the worker to the main thread. A discriminated union with four variants:
|
|
86
105
|
|
|
87
|
-
|
|
106
|
+
| Variant | Fields | Description |
|
|
107
|
+
|---------|--------|-------------|
|
|
108
|
+
| `return` | `request`, `body?` | Successful method return value |
|
|
109
|
+
| `error` | `request`, `body` | Method threw an error |
|
|
110
|
+
| `event` | `event`, `body?` | Worker-emitted event |
|
|
111
|
+
| `log` | `body` | Redirected stdout output |
|
|
88
112
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
113
|
+
## Worker (const)
|
|
114
|
+
|
|
115
|
+
Factory object for creating type-safe worker proxies.
|
|
116
|
+
|
|
117
|
+
### Worker.create
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
Worker.create<TModule extends WorkerModule>(
|
|
121
|
+
filePath: string,
|
|
122
|
+
opt?: Omit<WorkerRawOptions, "stdout" | "stderr">,
|
|
123
|
+
): WorkerProxy<TModule>
|
|
96
124
|
```
|
|
97
125
|
|
|
98
|
-
|
|
99
|
-
- `filePath` -- Worker file path (file:// URL or absolute path)
|
|
100
|
-
- `opt` -- Worker options
|
|
126
|
+
Create a type-safe worker proxy.
|
|
101
127
|
|
|
102
|
-
|
|
128
|
+
| Parameter | Type | Description |
|
|
129
|
+
|-----------|------|-------------|
|
|
130
|
+
| `filePath` | `string` | Worker file path (`file://` URL or absolute path) |
|
|
131
|
+
| `opt` | `Omit<WorkerRawOptions, "stdout" \| "stderr">?` | Node.js `WorkerOptions` (excluding stdout/stderr which are managed internally) |
|
|
103
132
|
|
|
104
|
-
In development (`.ts` files),
|
|
133
|
+
In development (`.ts` files), the worker is loaded via `tsx`. In production (`.js` files), the worker is loaded directly.
|
|
105
134
|
|
|
106
|
-
|
|
135
|
+
Worker stdout/stderr is piped to the main process. On abnormal exit, all pending requests are rejected.
|
|
107
136
|
|
|
108
|
-
|
|
137
|
+
## createWorker (function)
|
|
109
138
|
|
|
110
|
-
```
|
|
139
|
+
```ts
|
|
111
140
|
function createWorker<
|
|
112
141
|
TMethods extends Record<string, (...args: any[]) => unknown>,
|
|
113
142
|
TEvents extends Record<string, unknown> = Record<string, never>,
|
|
114
143
|
>(
|
|
115
144
|
methods: TMethods,
|
|
116
145
|
): {
|
|
117
|
-
send<TEventName extends keyof TEvents & string>(
|
|
146
|
+
send<TEventName extends keyof TEvents & string>(
|
|
147
|
+
event: TEventName,
|
|
148
|
+
data?: TEvents[TEventName],
|
|
149
|
+
): void;
|
|
118
150
|
__methods: TMethods;
|
|
119
151
|
__events: TEvents;
|
|
120
|
-
}
|
|
152
|
+
}
|
|
121
153
|
```
|
|
122
154
|
|
|
123
|
-
|
|
155
|
+
Define a worker module inside a worker thread file. Returns a sender object that can emit events to the main thread.
|
|
156
|
+
|
|
157
|
+
| Parameter | Type | Description |
|
|
158
|
+
|-----------|------|-------------|
|
|
159
|
+
| `methods` | `TMethods` | Object mapping method names to handler functions |
|
|
160
|
+
|
|
161
|
+
The returned object exposes:
|
|
162
|
+
|
|
163
|
+
| Property/Method | Description |
|
|
164
|
+
|-----------------|-------------|
|
|
165
|
+
| `send(event, data?)` | Emit a typed event to the main thread |
|
|
166
|
+
| `__methods` | Type-level reference to the methods map (used for type inference) |
|
|
167
|
+
| `__events` | Type-level reference to the events map (used for type inference) |
|
|
124
168
|
|
|
125
|
-
|
|
126
|
-
|
|
169
|
+
Throws if not running in a worker thread (`parentPort` is null).
|
|
170
|
+
|
|
171
|
+
## Usage
|
|
172
|
+
|
|
173
|
+
### Basic worker (no events)
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
// math-worker.ts
|
|
127
177
|
import { createWorker } from "@simplysm/core-node";
|
|
128
178
|
|
|
129
179
|
export default createWorker({
|
|
130
180
|
add: (a: number, b: number) => a + b,
|
|
181
|
+
multiply: (a: number, b: number) => a * b,
|
|
131
182
|
});
|
|
132
183
|
|
|
133
184
|
// main.ts
|
|
134
185
|
import { Worker } from "@simplysm/core-node";
|
|
135
186
|
|
|
136
|
-
const worker = Worker.create<typeof import("./worker")>("./worker.ts");
|
|
137
|
-
const
|
|
187
|
+
const worker = Worker.create<typeof import("./math-worker")>("./math-worker.ts");
|
|
188
|
+
const sum = await worker.add(10, 20); // 30
|
|
189
|
+
const product = await worker.multiply(3, 7); // 21
|
|
138
190
|
await worker.terminate();
|
|
139
191
|
```
|
|
140
192
|
|
|
141
|
-
### Worker with
|
|
193
|
+
### Worker with events
|
|
142
194
|
|
|
143
|
-
```
|
|
144
|
-
// worker.ts
|
|
195
|
+
```ts
|
|
196
|
+
// process-worker.ts
|
|
145
197
|
import { createWorker } from "@simplysm/core-node";
|
|
146
198
|
|
|
147
|
-
interface
|
|
199
|
+
interface Events {
|
|
148
200
|
progress: number;
|
|
149
201
|
}
|
|
150
202
|
|
|
151
203
|
const methods = {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
204
|
+
processData: (items: string[]) => {
|
|
205
|
+
for (let i = 0; i < items.length; i++) {
|
|
206
|
+
// ... process item ...
|
|
207
|
+
sender.send("progress", ((i + 1) / items.length) * 100);
|
|
208
|
+
}
|
|
209
|
+
return items.length;
|
|
155
210
|
},
|
|
156
211
|
};
|
|
157
212
|
|
|
158
|
-
const sender = createWorker<typeof methods,
|
|
213
|
+
const sender = createWorker<typeof methods, Events>(methods);
|
|
159
214
|
export default sender;
|
|
160
215
|
|
|
161
216
|
// main.ts
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
});
|
|
166
|
-
const
|
|
217
|
+
import { Worker } from "@simplysm/core-node";
|
|
218
|
+
|
|
219
|
+
const worker = Worker.create<typeof import("./process-worker")>("./process-worker.ts");
|
|
220
|
+
worker.on("progress", (pct) => console.log(`${pct}% done`));
|
|
221
|
+
const count = await worker.processData(["a", "b", "c"]);
|
|
167
222
|
await worker.terminate();
|
|
168
223
|
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { tsImport } from "tsx/esm/api";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
|
|
5
|
+
// Assume argv[2] contains the actual worker file path
|
|
6
|
+
const workerFile = process.argv[2];
|
|
7
|
+
if (!workerFile) {
|
|
8
|
+
throw new Error("Worker file path is required as argument!");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// If file:// URL is already passed, use it as-is; otherwise convert
|
|
12
|
+
const workerFileUrl = workerFile.startsWith("file://")
|
|
13
|
+
? workerFile
|
|
14
|
+
: pathToFileURL(workerFile).href;
|
|
15
|
+
await tsImport(workerFileUrl, import.meta.url);
|