@simplysm/core-node 13.0.82 → 13.0.84

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 ADDED
@@ -0,0 +1,48 @@
1
+ # @simplysm/core-node
2
+
3
+ > Simplysm package - Core module (node)
4
+
5
+ Node.js utility library providing enhanced filesystem operations, path manipulation, file watching, and a type-safe worker thread wrapper. All filesystem functions include automatic error wrapping with `SdError` for better stack traces.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @simplysm/core-node
11
+ ```
12
+
13
+ ## Documentation
14
+
15
+ | Category | Description | File |
16
+ |---|---|---|
17
+ | Filesystem Utilities | File/directory CRUD, glob, JSON read/write | [docs/filesystem.md](docs/filesystem.md) |
18
+ | Path Utilities | Path normalization, POSIX conversion, child path checks | [docs/path.md](docs/path.md) |
19
+ | File Watcher | Chokidar-based watcher with event debouncing and merging | [docs/fs-watcher.md](docs/fs-watcher.md) |
20
+ | Worker | Type-safe worker thread wrapper with RPC and events | [docs/worker.md](docs/worker.md) |
21
+
22
+ ## Quick Example
23
+
24
+ ```typescript
25
+ import { fsx, pathx, FsWatcher, Worker } from "@simplysm/core-node";
26
+
27
+ // Filesystem
28
+ const content = await fsx.read("config.json");
29
+ await fsx.write("output.txt", "hello");
30
+ const files = await fsx.glob("src/**/*.ts");
31
+
32
+ // Path
33
+ const normalized = pathx.norm("/some/path");
34
+ const posixPath = pathx.posix("C:\\Users\\test"); // "C:/Users/test"
35
+
36
+ // File watcher
37
+ const watcher = await FsWatcher.watch(["src/**/*.ts"]);
38
+ watcher.onChange({ delay: 300 }, (changes) => {
39
+ for (const { path, event } of changes) {
40
+ console.log(`${event}: ${path}`);
41
+ }
42
+ });
43
+
44
+ // Worker
45
+ const worker = Worker.create<typeof import("./my-worker")>("./my-worker.ts");
46
+ const result = await worker.add(1, 2);
47
+ await worker.terminate();
48
+ ```
@@ -0,0 +1,254 @@
1
+ # Filesystem Utilities (`fsx`)
2
+
3
+ Imported as a namespace:
4
+
5
+ ```typescript
6
+ import { fsx } from "@simplysm/core-node";
7
+ ```
8
+
9
+ All functions wrap Node.js `fs` operations with automatic `SdError` wrapping for improved stack traces. Most functions come in sync and async pairs.
10
+
11
+ ---
12
+
13
+ ## API Reference
14
+
15
+ ### exists / existsSync
16
+
17
+ ```typescript
18
+ function exists(targetPath: string): Promise<boolean>;
19
+ function existsSync(targetPath: string): boolean;
20
+ ```
21
+
22
+ Checks if a file or directory exists.
23
+
24
+ ---
25
+
26
+ ### mkdir / mkdirSync
27
+
28
+ ```typescript
29
+ function mkdir(targetPath: string): Promise<void>;
30
+ function mkdirSync(targetPath: string): void;
31
+ ```
32
+
33
+ Creates a directory recursively (like `mkdir -p`).
34
+
35
+ ---
36
+
37
+ ### rm / rmSync
38
+
39
+ ```typescript
40
+ function rm(targetPath: string): Promise<void>;
41
+ function rmSync(targetPath: string): void;
42
+ ```
43
+
44
+ Deletes a file or directory recursively with `force: true`.
45
+
46
+ - **`rm`** (async): Retries up to 6 times with a 500ms interval for transient errors (e.g., file locks).
47
+ - **`rmSync`**: Fails immediately without retries.
48
+
49
+ ---
50
+
51
+ ### copy / copySync
52
+
53
+ ```typescript
54
+ function copy(
55
+ sourcePath: string,
56
+ targetPath: string,
57
+ filter?: (absolutePath: string) => boolean,
58
+ ): Promise<void>;
59
+
60
+ function copySync(
61
+ sourcePath: string,
62
+ targetPath: string,
63
+ filter?: (absolutePath: string) => boolean,
64
+ ): void;
65
+ ```
66
+
67
+ Copies a file or directory. If `sourcePath` does not exist, returns silently.
68
+
69
+ **Parameters:**
70
+ - `sourcePath` -- Source path to copy from.
71
+ - `targetPath` -- Destination path.
72
+ - `filter` -- Optional filter receiving the absolute path of each child. Return `true` to include, `false` to exclude. The top-level `sourcePath` itself is not filtered; only its children (recursively) are subject to the filter. Returning `false` for a directory skips it and all its contents.
73
+
74
+ ---
75
+
76
+ ### read / readSync
77
+
78
+ ```typescript
79
+ function read(targetPath: string): Promise<string>;
80
+ function readSync(targetPath: string): string;
81
+ ```
82
+
83
+ Reads a file as a UTF-8 string.
84
+
85
+ ---
86
+
87
+ ### readBuffer / readBufferSync
88
+
89
+ ```typescript
90
+ function readBuffer(targetPath: string): Promise<Buffer>;
91
+ function readBufferSync(targetPath: string): Buffer;
92
+ ```
93
+
94
+ Reads a file as a Buffer.
95
+
96
+ ---
97
+
98
+ ### readJson / readJsonSync
99
+
100
+ ```typescript
101
+ function readJson<TData = unknown>(targetPath: string): Promise<TData>;
102
+ function readJsonSync<TData = unknown>(targetPath: string): TData;
103
+ ```
104
+
105
+ Reads and parses a JSON file using `JsonConvert` from `@simplysm/core-common`. On parse failure, the error includes a truncated preview of the file contents (up to 500 characters).
106
+
107
+ ---
108
+
109
+ ### write / writeSync
110
+
111
+ ```typescript
112
+ function write(targetPath: string, data: string | Uint8Array): Promise<void>;
113
+ function writeSync(targetPath: string, data: string | Uint8Array): void;
114
+ ```
115
+
116
+ Writes data to a file. Automatically creates parent directories if they do not exist. Uses `flush: true` for immediate disk write.
117
+
118
+ ---
119
+
120
+ ### writeJson / writeJsonSync
121
+
122
+ ```typescript
123
+ function writeJson(
124
+ targetPath: string,
125
+ data: unknown,
126
+ options?: {
127
+ replacer?: (this: unknown, key: string | undefined, value: unknown) => unknown;
128
+ space?: string | number;
129
+ },
130
+ ): Promise<void>;
131
+
132
+ function writeJsonSync(
133
+ targetPath: string,
134
+ data: unknown,
135
+ options?: {
136
+ replacer?: (this: unknown, key: string | undefined, value: unknown) => unknown;
137
+ space?: string | number;
138
+ },
139
+ ): void;
140
+ ```
141
+
142
+ Writes data to a JSON file using `JsonConvert`.
143
+
144
+ **Parameters:**
145
+ - `data` -- Data to serialize.
146
+ - `options.replacer` -- Custom JSON replacer function.
147
+ - `options.space` -- Indentation (number of spaces or string).
148
+
149
+ ---
150
+
151
+ ### readdir / readdirSync
152
+
153
+ ```typescript
154
+ function readdir(targetPath: string): Promise<string[]>;
155
+ function readdirSync(targetPath: string): string[];
156
+ ```
157
+
158
+ Reads the contents of a directory (file and directory names only, not full paths).
159
+
160
+ ---
161
+
162
+ ### stat / statSync
163
+
164
+ ```typescript
165
+ function stat(targetPath: string): Promise<fs.Stats>;
166
+ function statSync(targetPath: string): fs.Stats;
167
+ ```
168
+
169
+ Gets file/directory information. Follows symbolic links.
170
+
171
+ ---
172
+
173
+ ### lstat / lstatSync
174
+
175
+ ```typescript
176
+ function lstat(targetPath: string): Promise<fs.Stats>;
177
+ function lstatSync(targetPath: string): fs.Stats;
178
+ ```
179
+
180
+ Gets file/directory information. Does **not** follow symbolic links.
181
+
182
+ ---
183
+
184
+ ### glob / globSync
185
+
186
+ ```typescript
187
+ function glob(pattern: string, options?: GlobOptions): Promise<string[]>;
188
+ function globSync(pattern: string, options?: GlobOptions): string[];
189
+ ```
190
+
191
+ Searches for files using a glob pattern. Backslashes in the pattern are automatically converted to forward slashes. Returns an array of **absolute paths**.
192
+
193
+ ---
194
+
195
+ ### clearEmptyDirectory
196
+
197
+ ```typescript
198
+ function clearEmptyDirectory(dirPath: string): Promise<void>;
199
+ ```
200
+
201
+ Recursively searches and deletes empty directories under the specified path. If all children of a directory are deleted and it becomes empty, it is also removed.
202
+
203
+ ---
204
+
205
+ ### findAllParentChildPaths / findAllParentChildPathsSync
206
+
207
+ ```typescript
208
+ function findAllParentChildPaths(
209
+ childGlob: string,
210
+ fromPath: string,
211
+ rootPath?: string,
212
+ ): Promise<string[]>;
213
+
214
+ function findAllParentChildPathsSync(
215
+ childGlob: string,
216
+ fromPath: string,
217
+ rootPath?: string,
218
+ ): string[];
219
+ ```
220
+
221
+ Traverses parent directories from `fromPath` toward the root, collecting all file paths matching `childGlob` in each directory.
222
+
223
+ **Parameters:**
224
+ - `childGlob` -- Glob pattern to match in each directory.
225
+ - `fromPath` -- Starting directory.
226
+ - `rootPath` -- Optional boundary; stops searching at this directory. Must be a parent of `fromPath`.
227
+
228
+ ---
229
+
230
+ ## Usage Examples
231
+
232
+ ```typescript
233
+ import { fsx } from "@simplysm/core-node";
234
+
235
+ // Read and write JSON
236
+ const config = await fsx.readJson<{ port: number }>("config.json");
237
+ await fsx.writeJson("output.json", { port: 3000 }, { space: 2 });
238
+
239
+ // Copy with filter (skip node_modules)
240
+ await fsx.copy("src", "dist", (absPath) => !absPath.includes("node_modules"));
241
+
242
+ // Find all package.json files from a subdirectory up to the project root
243
+ const packageFiles = fsx.findAllParentChildPathsSync(
244
+ "package.json",
245
+ "/project/packages/my-lib/src",
246
+ "/project",
247
+ );
248
+
249
+ // Clean up empty directories after a build
250
+ await fsx.clearEmptyDirectory("dist");
251
+
252
+ // Glob search
253
+ const tsFiles = await fsx.glob("src/**/*.ts");
254
+ ```
@@ -0,0 +1,145 @@
1
+ # File Watcher (`FsWatcher`)
2
+
3
+ ```typescript
4
+ import { FsWatcher } from "@simplysm/core-node";
5
+ ```
6
+
7
+ A chokidar-based file system watcher that debounces and merges rapid file change events, delivering a single consolidated callback.
8
+
9
+ ---
10
+
11
+ ## API Reference
12
+
13
+ ### FsWatcherEvent
14
+
15
+ ```typescript
16
+ type FsWatcherEvent = "add" | "addDir" | "change" | "unlink" | "unlinkDir";
17
+ ```
18
+
19
+ Supported file change event types.
20
+
21
+ ---
22
+
23
+ ### FsWatcherChangeInfo
24
+
25
+ ```typescript
26
+ interface FsWatcherChangeInfo {
27
+ event: FsWatcherEvent;
28
+ path: NormPath;
29
+ }
30
+ ```
31
+
32
+ Describes a single file change with its event type and normalized path.
33
+
34
+ ---
35
+
36
+ ### FsWatcher
37
+
38
+ #### FsWatcher.watch
39
+
40
+ ```typescript
41
+ static async watch(
42
+ paths: string[],
43
+ options?: chokidar.ChokidarOptions,
44
+ ): Promise<FsWatcher>;
45
+ ```
46
+
47
+ Starts watching files and resolves once the watcher is ready.
48
+
49
+ **Parameters:**
50
+ - `paths` -- Array of file paths, directory paths, or glob patterns to watch.
51
+ - `options` -- Chokidar options. Note: `ignoreInitial` is internally forced to `true`.
52
+
53
+ ---
54
+
55
+ #### FsWatcher#onChange
56
+
57
+ ```typescript
58
+ onChange(
59
+ opt: { delay?: number },
60
+ cb: (changeInfos: FsWatcherChangeInfo[]) => void | Promise<void>,
61
+ ): this;
62
+ ```
63
+
64
+ Registers a change event handler. Events occurring within the `delay` window are merged and delivered in a single callback.
65
+
66
+ **Parameters:**
67
+ - `opt.delay` -- Debounce delay in milliseconds.
68
+ - `cb` -- Callback receiving an array of merged change events.
69
+
70
+ **Event merging strategy:**
71
+
72
+ When multiple events occur for the same file within the debounce window:
73
+
74
+ | Previous Event | New Event | Result |
75
+ |---|---|---|
76
+ | `add` | `change` | `add` (modification right after creation) |
77
+ | `add` | `unlink` | removed (created then deleted = no change) |
78
+ | `unlink` | `add`/`change` | `add` (recreated after deletion) |
79
+ | `addDir` | `unlinkDir` | removed (no change) |
80
+ | `unlinkDir` | `addDir` | `addDir` (recreated) |
81
+ | any | any (other) | latest event wins |
82
+
83
+ ---
84
+
85
+ #### FsWatcher#close
86
+
87
+ ```typescript
88
+ async close(): Promise<void>;
89
+ ```
90
+
91
+ Closes the file watcher and disposes all debounce queues.
92
+
93
+ ---
94
+
95
+ ## Usage Examples
96
+
97
+ ```typescript
98
+ import { FsWatcher } from "@simplysm/core-node";
99
+
100
+ // Watch TypeScript files with 300ms debounce
101
+ const watcher = await FsWatcher.watch(["src/**/*.ts"]);
102
+
103
+ watcher.onChange({ delay: 300 }, (changes) => {
104
+ for (const { path, event } of changes) {
105
+ console.log(`${event}: ${path}`);
106
+ }
107
+ });
108
+
109
+ // Watch multiple patterns
110
+ const multiWatcher = await FsWatcher.watch([
111
+ "src/**/*.ts",
112
+ "config/**/*.json",
113
+ ]);
114
+
115
+ multiWatcher.onChange({ delay: 500 }, async (changes) => {
116
+ const tsChanges = changes.filter((c) => c.path.endsWith(".ts"));
117
+ const configChanges = changes.filter((c) => c.path.endsWith(".json"));
118
+
119
+ if (tsChanges.length > 0) {
120
+ // Rebuild TypeScript
121
+ }
122
+ if (configChanges.length > 0) {
123
+ // Reload configuration
124
+ }
125
+ });
126
+
127
+ // Clean up
128
+ await watcher.close();
129
+ await multiWatcher.close();
130
+ ```
131
+
132
+ ### ignoreInitial behavior
133
+
134
+ By default, `ignoreInitial` is `true` and the callback is not invoked until an actual change occurs. If set to `false` in options, the callback is called once immediately with an empty array (the actual initial file list is not included -- this is intentional to avoid conflicts with event merging).
135
+
136
+ ```typescript
137
+ const watcher = await FsWatcher.watch(["src/**/*.ts"], {
138
+ ignoreInitial: false,
139
+ });
140
+
141
+ watcher.onChange({ delay: 300 }, (changes) => {
142
+ // First call: changes = [] (initial trigger)
143
+ // Subsequent calls: actual file changes
144
+ });
145
+ ```
package/docs/path.md ADDED
@@ -0,0 +1,154 @@
1
+ # Path Utilities (`pathx`)
2
+
3
+ Imported as a namespace:
4
+
5
+ ```typescript
6
+ import { pathx } from "@simplysm/core-node";
7
+ ```
8
+
9
+ Provides path normalization, POSIX conversion, child path detection, and target-based filtering utilities.
10
+
11
+ ---
12
+
13
+ ## API Reference
14
+
15
+ ### NormPath
16
+
17
+ ```typescript
18
+ type NormPath = string & { [NORM]: never };
19
+ ```
20
+
21
+ A branded string type representing a normalized absolute path. Can only be created through `norm()`. Useful for ensuring path consistency throughout an application.
22
+
23
+ ---
24
+
25
+ ### posix
26
+
27
+ ```typescript
28
+ function posix(...args: string[]): string;
29
+ ```
30
+
31
+ Converts path segments to a POSIX-style path (backslashes replaced with forward slashes). Segments are joined using `path.join()` before conversion.
32
+
33
+ ```typescript
34
+ pathx.posix("C:\\Users\\test"); // "C:/Users/test"
35
+ pathx.posix("src", "index.ts"); // "src/index.ts"
36
+ ```
37
+
38
+ ---
39
+
40
+ ### changeFileDirectory
41
+
42
+ ```typescript
43
+ function changeFileDirectory(
44
+ filePath: string,
45
+ fromDirectory: string,
46
+ toDirectory: string,
47
+ ): string;
48
+ ```
49
+
50
+ Changes the base directory of a file path. Throws `ArgumentError` if `filePath` is not inside `fromDirectory`.
51
+
52
+ ```typescript
53
+ pathx.changeFileDirectory("/a/b/c.txt", "/a", "/x");
54
+ // "/x/b/c.txt"
55
+ ```
56
+
57
+ ---
58
+
59
+ ### basenameWithoutExt
60
+
61
+ ```typescript
62
+ function basenameWithoutExt(filePath: string): string;
63
+ ```
64
+
65
+ Returns the filename without extension.
66
+
67
+ ```typescript
68
+ pathx.basenameWithoutExt("file.txt"); // "file"
69
+ pathx.basenameWithoutExt("/path/to/file.spec.ts"); // "file.spec"
70
+ ```
71
+
72
+ ---
73
+
74
+ ### isChildPath
75
+
76
+ ```typescript
77
+ function isChildPath(childPath: string, parentPath: string): boolean;
78
+ ```
79
+
80
+ Checks if `childPath` is a child of `parentPath`. Returns `false` if the paths are identical. Paths are normalized internally.
81
+
82
+ ```typescript
83
+ pathx.isChildPath("/a/b/c", "/a/b"); // true
84
+ pathx.isChildPath("/a/b", "/a/b/c"); // false
85
+ pathx.isChildPath("/a/b", "/a/b"); // false (same path)
86
+ ```
87
+
88
+ ---
89
+
90
+ ### norm
91
+
92
+ ```typescript
93
+ function norm(...paths: string[]): NormPath;
94
+ ```
95
+
96
+ Normalizes and resolves path segments to an absolute `NormPath`. Uses platform-specific separators.
97
+
98
+ ```typescript
99
+ const p = pathx.norm("/some/path"); // NormPath
100
+ const q = pathx.norm("relative", "path"); // NormPath (resolved to absolute)
101
+ ```
102
+
103
+ ---
104
+
105
+ ### filterByTargets
106
+
107
+ ```typescript
108
+ function filterByTargets(
109
+ files: string[],
110
+ targets: string[],
111
+ cwd: string,
112
+ ): string[];
113
+ ```
114
+
115
+ Filters an array of absolute file paths to only include those that match or are children of the given target paths.
116
+
117
+ **Parameters:**
118
+ - `files` -- Absolute file paths to filter.
119
+ - `targets` -- Target paths relative to `cwd` (POSIX style recommended).
120
+ - `cwd` -- Current working directory (absolute path).
121
+
122
+ Returns `files` unmodified if `targets` is empty.
123
+
124
+ ```typescript
125
+ const files = ["/proj/src/a.ts", "/proj/src/b.ts", "/proj/tests/c.ts"];
126
+ pathx.filterByTargets(files, ["src"], "/proj");
127
+ // ["/proj/src/a.ts", "/proj/src/b.ts"]
128
+ ```
129
+
130
+ ---
131
+
132
+ ## Usage Examples
133
+
134
+ ```typescript
135
+ import { pathx } from "@simplysm/core-node";
136
+
137
+ // Normalize paths for consistent comparison
138
+ const a = pathx.norm("/project/src/../lib");
139
+ const b = pathx.norm("/project/lib");
140
+ console.log(a === b); // true
141
+
142
+ // Remap file paths from one directory to another
143
+ const newPath = pathx.changeFileDirectory(
144
+ "/build/src/utils/helper.ts",
145
+ "/build/src",
146
+ "/dist",
147
+ );
148
+ // "/dist/utils/helper.ts"
149
+
150
+ // Filter files by target directories
151
+ const allFiles = ["/proj/src/a.ts", "/proj/docs/b.md", "/proj/tests/c.ts"];
152
+ const srcOnly = pathx.filterByTargets(allFiles, ["src", "tests"], "/proj");
153
+ // ["/proj/src/a.ts", "/proj/tests/c.ts"]
154
+ ```
package/docs/worker.md ADDED
@@ -0,0 +1,209 @@
1
+ # Worker
2
+
3
+ ```typescript
4
+ import { createWorker, Worker } from "@simplysm/core-node";
5
+ ```
6
+
7
+ Type-safe wrapper around Node.js `worker_threads`. Define methods in a worker file with `createWorker`, then call them from the main thread via `Worker.create` with full type inference.
8
+
9
+ ---
10
+
11
+ ## API Reference
12
+
13
+ ### createWorker
14
+
15
+ ```typescript
16
+ function createWorker<
17
+ TMethods extends Record<string, (...args: any[]) => unknown>,
18
+ TEvents extends Record<string, unknown> = Record<string, never>,
19
+ >(
20
+ methods: TMethods,
21
+ ): {
22
+ send<TEventName extends keyof TEvents & string>(
23
+ event: TEventName,
24
+ data?: TEvents[TEventName],
25
+ ): void;
26
+ __methods: TMethods;
27
+ __events: TEvents;
28
+ };
29
+ ```
30
+
31
+ Factory function for defining a worker module. Must be the default export of the worker file.
32
+
33
+ **Parameters:**
34
+ - `methods` -- Object mapping method names to handler functions.
35
+
36
+ **Returns** an object with:
37
+ - `send(event, data?)` -- Sends a custom event from the worker to the main thread.
38
+ - `__methods` / `__events` -- Type-only markers used for inference (not accessed at runtime).
39
+
40
+ ---
41
+
42
+ ### Worker.create
43
+
44
+ ```typescript
45
+ const Worker: {
46
+ create<TModule extends WorkerModule>(
47
+ filePath: string,
48
+ opt?: Omit<WorkerOptions, "stdout" | "stderr">,
49
+ ): WorkerProxy<TModule>;
50
+ };
51
+ ```
52
+
53
+ Creates a type-safe worker proxy. In development (`.ts` files), the worker is executed via `tsx` automatically. In production (`.js` files), the Worker is created directly.
54
+
55
+ **Parameters:**
56
+ - `filePath` -- Worker file path (absolute path or `file://` URL).
57
+ - `opt` -- Standard `WorkerOptions` (except `stdout`/`stderr`, which are managed internally).
58
+
59
+ **Returns** a `WorkerProxy` with:
60
+ - All worker methods available as async functions.
61
+ - `on(event, listener)` -- Subscribe to worker events.
62
+ - `off(event, listener)` -- Unsubscribe from worker events.
63
+ - `terminate()` -- Terminates the worker thread.
64
+
65
+ ---
66
+
67
+ ### WorkerModule
68
+
69
+ ```typescript
70
+ interface WorkerModule {
71
+ default: {
72
+ __methods: Record<string, (...args: any[]) => unknown>;
73
+ __events: Record<string, unknown>;
74
+ };
75
+ }
76
+ ```
77
+
78
+ Type structure of a worker module. Used for type inference with `Worker.create<typeof import("./worker")>()`.
79
+
80
+ ---
81
+
82
+ ### WorkerProxy
83
+
84
+ ```typescript
85
+ type WorkerProxy<TModule extends WorkerModule> = PromisifyMethods<
86
+ TModule["default"]["__methods"]
87
+ > & {
88
+ on<K extends keyof TModule["default"]["__events"] & string>(
89
+ event: K,
90
+ listener: (data: TModule["default"]["__events"][K]) => void,
91
+ ): void;
92
+ off<K extends keyof TModule["default"]["__events"] & string>(
93
+ event: K,
94
+ listener: (data: TModule["default"]["__events"][K]) => void,
95
+ ): void;
96
+ terminate(): Promise<void>;
97
+ };
98
+ ```
99
+
100
+ The proxy type returned by `Worker.create()`. All worker methods are promisified (return `Promise<Awaited<R>>`).
101
+
102
+ ---
103
+
104
+ ### PromisifyMethods
105
+
106
+ ```typescript
107
+ type PromisifyMethods<TMethods> = {
108
+ [K in keyof TMethods]: TMethods[K] extends (...args: infer P) => infer R
109
+ ? (...args: P) => Promise<Awaited<R>>
110
+ : never;
111
+ };
112
+ ```
113
+
114
+ Utility type that wraps all method return values in `Promise`. Worker communication is always asynchronous via `postMessage`.
115
+
116
+ ---
117
+
118
+ ## Usage Examples
119
+
120
+ ### Basic worker
121
+
122
+ ```typescript
123
+ // math-worker.ts
124
+ import { createWorker } from "@simplysm/core-node";
125
+
126
+ export default createWorker({
127
+ add: (a: number, b: number) => a + b,
128
+ multiply: (a: number, b: number) => a * b,
129
+ });
130
+ ```
131
+
132
+ ```typescript
133
+ // main.ts
134
+ import { Worker } from "@simplysm/core-node";
135
+
136
+ const worker = Worker.create<typeof import("./math-worker")>(
137
+ new URL("./math-worker.ts", import.meta.url).href,
138
+ );
139
+
140
+ const sum = await worker.add(10, 20); // 30
141
+ const product = await worker.multiply(3, 4); // 12
142
+
143
+ await worker.terminate();
144
+ ```
145
+
146
+ ### Worker with events
147
+
148
+ ```typescript
149
+ // process-worker.ts
150
+ import { createWorker } from "@simplysm/core-node";
151
+
152
+ interface ProcessEvents {
153
+ progress: number;
154
+ status: string;
155
+ }
156
+
157
+ const methods = {
158
+ processData: async (items: string[]) => {
159
+ const results: string[] = [];
160
+ for (let i = 0; i < items.length; i++) {
161
+ sender.send("progress", ((i + 1) / items.length) * 100);
162
+ sender.send("status", `Processing ${items[i]}`);
163
+ results.push(items[i].toUpperCase());
164
+ }
165
+ return results;
166
+ },
167
+ };
168
+
169
+ const sender = createWorker<typeof methods, ProcessEvents>(methods);
170
+ export default sender;
171
+ ```
172
+
173
+ ```typescript
174
+ // main.ts
175
+ import { Worker } from "@simplysm/core-node";
176
+
177
+ const worker = Worker.create<typeof import("./process-worker")>(
178
+ new URL("./process-worker.ts", import.meta.url).href,
179
+ );
180
+
181
+ worker.on("progress", (pct) => {
182
+ console.log(`Progress: ${pct}%`);
183
+ });
184
+
185
+ worker.on("status", (msg) => {
186
+ console.log(`Status: ${msg}`);
187
+ });
188
+
189
+ const results = await worker.processData(["hello", "world"]);
190
+ // Progress: 50%
191
+ // Status: Processing hello
192
+ // Progress: 100%
193
+ // Status: Processing world
194
+ // results: ["HELLO", "WORLD"]
195
+
196
+ await worker.terminate();
197
+ ```
198
+
199
+ ### Worker with options
200
+
201
+ ```typescript
202
+ const worker = Worker.create<typeof import("./my-worker")>(
203
+ new URL("./my-worker.ts", import.meta.url).href,
204
+ {
205
+ env: { NODE_ENV: "production" },
206
+ argv: ["--verbose"],
207
+ },
208
+ );
209
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/core-node",
3
- "version": "13.0.82",
3
+ "version": "13.0.84",
4
4
  "description": "Simplysm package - Core module (node)",
5
5
  "author": "simplysm",
6
6
  "license": "Apache-2.0",
@@ -25,6 +25,6 @@
25
25
  "glob": "^13.0.6",
26
26
  "minimatch": "^10.2.4",
27
27
  "tsx": "^4.21.0",
28
- "@simplysm/core-common": "13.0.82"
28
+ "@simplysm/core-common": "13.0.84"
29
29
  }
30
30
  }