@simplysm/core-node 13.0.0-beta.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.
Files changed (111) hide show
  1. package/.cache/typecheck-node.tsbuildinfo +1 -0
  2. package/.cache/typecheck-tests-node.tsbuildinfo +1 -0
  3. package/README.md +375 -0
  4. package/dist/core-common/src/common.types.d.ts +74 -0
  5. package/dist/core-common/src/common.types.d.ts.map +1 -0
  6. package/dist/core-common/src/env.d.ts +6 -0
  7. package/dist/core-common/src/env.d.ts.map +1 -0
  8. package/dist/core-common/src/errors/argument-error.d.ts +25 -0
  9. package/dist/core-common/src/errors/argument-error.d.ts.map +1 -0
  10. package/dist/core-common/src/errors/not-implemented-error.d.ts +29 -0
  11. package/dist/core-common/src/errors/not-implemented-error.d.ts.map +1 -0
  12. package/dist/core-common/src/errors/sd-error.d.ts +27 -0
  13. package/dist/core-common/src/errors/sd-error.d.ts.map +1 -0
  14. package/dist/core-common/src/errors/timeout-error.d.ts +31 -0
  15. package/dist/core-common/src/errors/timeout-error.d.ts.map +1 -0
  16. package/dist/core-common/src/extensions/arr-ext.d.ts +15 -0
  17. package/dist/core-common/src/extensions/arr-ext.d.ts.map +1 -0
  18. package/dist/core-common/src/extensions/arr-ext.helpers.d.ts +19 -0
  19. package/dist/core-common/src/extensions/arr-ext.helpers.d.ts.map +1 -0
  20. package/dist/core-common/src/extensions/arr-ext.types.d.ts +215 -0
  21. package/dist/core-common/src/extensions/arr-ext.types.d.ts.map +1 -0
  22. package/dist/core-common/src/extensions/map-ext.d.ts +57 -0
  23. package/dist/core-common/src/extensions/map-ext.d.ts.map +1 -0
  24. package/dist/core-common/src/extensions/set-ext.d.ts +36 -0
  25. package/dist/core-common/src/extensions/set-ext.d.ts.map +1 -0
  26. package/dist/core-common/src/features/debounce-queue.d.ts +53 -0
  27. package/dist/core-common/src/features/debounce-queue.d.ts.map +1 -0
  28. package/dist/core-common/src/features/event-emitter.d.ts +66 -0
  29. package/dist/core-common/src/features/event-emitter.d.ts.map +1 -0
  30. package/dist/core-common/src/features/serial-queue.d.ts +47 -0
  31. package/dist/core-common/src/features/serial-queue.d.ts.map +1 -0
  32. package/dist/core-common/src/index.d.ts +32 -0
  33. package/dist/core-common/src/index.d.ts.map +1 -0
  34. package/dist/core-common/src/types/date-only.d.ts +152 -0
  35. package/dist/core-common/src/types/date-only.d.ts.map +1 -0
  36. package/dist/core-common/src/types/date-time.d.ts +96 -0
  37. package/dist/core-common/src/types/date-time.d.ts.map +1 -0
  38. package/dist/core-common/src/types/lazy-gc-map.d.ts +80 -0
  39. package/dist/core-common/src/types/lazy-gc-map.d.ts.map +1 -0
  40. package/dist/core-common/src/types/time.d.ts +68 -0
  41. package/dist/core-common/src/types/time.d.ts.map +1 -0
  42. package/dist/core-common/src/types/uuid.d.ts +35 -0
  43. package/dist/core-common/src/types/uuid.d.ts.map +1 -0
  44. package/dist/core-common/src/utils/bytes.d.ts +51 -0
  45. package/dist/core-common/src/utils/bytes.d.ts.map +1 -0
  46. package/dist/core-common/src/utils/date-format.d.ts +90 -0
  47. package/dist/core-common/src/utils/date-format.d.ts.map +1 -0
  48. package/dist/core-common/src/utils/json.d.ts +34 -0
  49. package/dist/core-common/src/utils/json.d.ts.map +1 -0
  50. package/dist/core-common/src/utils/num.d.ts +60 -0
  51. package/dist/core-common/src/utils/num.d.ts.map +1 -0
  52. package/dist/core-common/src/utils/obj.d.ts +258 -0
  53. package/dist/core-common/src/utils/obj.d.ts.map +1 -0
  54. package/dist/core-common/src/utils/path.d.ts +23 -0
  55. package/dist/core-common/src/utils/path.d.ts.map +1 -0
  56. package/dist/core-common/src/utils/primitive.d.ts +18 -0
  57. package/dist/core-common/src/utils/primitive.d.ts.map +1 -0
  58. package/dist/core-common/src/utils/str.d.ts +103 -0
  59. package/dist/core-common/src/utils/str.d.ts.map +1 -0
  60. package/dist/core-common/src/utils/template-strings.d.ts +84 -0
  61. package/dist/core-common/src/utils/template-strings.d.ts.map +1 -0
  62. package/dist/core-common/src/utils/transferable.d.ts +47 -0
  63. package/dist/core-common/src/utils/transferable.d.ts.map +1 -0
  64. package/dist/core-common/src/utils/wait.d.ts +19 -0
  65. package/dist/core-common/src/utils/wait.d.ts.map +1 -0
  66. package/dist/core-common/src/utils/xml.d.ts +36 -0
  67. package/dist/core-common/src/utils/xml.d.ts.map +1 -0
  68. package/dist/core-common/src/zip/sd-zip.d.ts +80 -0
  69. package/dist/core-common/src/zip/sd-zip.d.ts.map +1 -0
  70. package/dist/core-node/src/features/fs-watcher.d.ts +70 -0
  71. package/dist/core-node/src/features/fs-watcher.d.ts.map +1 -0
  72. package/dist/core-node/src/index.d.ts +7 -0
  73. package/dist/core-node/src/index.d.ts.map +1 -0
  74. package/dist/core-node/src/utils/fs.d.ts +197 -0
  75. package/dist/core-node/src/utils/fs.d.ts.map +1 -0
  76. package/dist/core-node/src/utils/path.d.ts +75 -0
  77. package/dist/core-node/src/utils/path.d.ts.map +1 -0
  78. package/dist/core-node/src/worker/create-worker.d.ts +23 -0
  79. package/dist/core-node/src/worker/create-worker.d.ts.map +1 -0
  80. package/dist/core-node/src/worker/types.d.ts +67 -0
  81. package/dist/core-node/src/worker/types.d.ts.map +1 -0
  82. package/dist/core-node/src/worker/worker.d.ts +27 -0
  83. package/dist/core-node/src/worker/worker.d.ts.map +1 -0
  84. package/dist/features/fs-watcher.js +100 -0
  85. package/dist/features/fs-watcher.js.map +7 -0
  86. package/dist/index.js +7 -0
  87. package/dist/index.js.map +7 -0
  88. package/dist/utils/fs.js +305 -0
  89. package/dist/utils/fs.js.map +7 -0
  90. package/dist/utils/path.js +48 -0
  91. package/dist/utils/path.js.map +7 -0
  92. package/dist/worker/create-worker.js +85 -0
  93. package/dist/worker/create-worker.js.map +7 -0
  94. package/dist/worker/types.js +1 -0
  95. package/dist/worker/types.js.map +7 -0
  96. package/dist/worker/worker.js +142 -0
  97. package/dist/worker/worker.js.map +7 -0
  98. package/lib/worker-dev-proxy.js +12 -0
  99. package/package.json +23 -0
  100. package/src/features/fs-watcher.ts +176 -0
  101. package/src/index.ts +11 -0
  102. package/src/utils/fs.ts +550 -0
  103. package/src/utils/path.ts +128 -0
  104. package/src/worker/create-worker.ts +141 -0
  105. package/src/worker/types.ts +86 -0
  106. package/src/worker/worker.ts +207 -0
  107. package/tests/utils/fs-watcher.spec.ts +295 -0
  108. package/tests/utils/fs.spec.ts +754 -0
  109. package/tests/utils/path.spec.ts +192 -0
  110. package/tests/worker/fixtures/test-worker.ts +35 -0
  111. package/tests/worker/sd-worker.spec.ts +183 -0
package/README.md ADDED
@@ -0,0 +1,375 @@
1
+ # @simplysm/core-node
2
+
3
+ A Node.js-specific utility package for the Simplysm framework. It provides path handling, file system operations, file change detection, and type-safe Worker thread wrappers.
4
+
5
+ ## Requirements
6
+
7
+ - Node.js 20.11+ (requires `import.meta.filename`/`import.meta.dirname` support)
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @simplysm/core-node
13
+ # or
14
+ pnpm add @simplysm/core-node
15
+ ```
16
+
17
+ ## Main Modules
18
+
19
+ ### Path Utilities (`utils/path`)
20
+
21
+ Provides path conversion, normalization, comparison, and filtering functions.
22
+
23
+ | Function/Type | Description |
24
+ |---------------|-------------|
25
+ | `NormPath` | A branded type created by `pathNorm()`. Represents a normalized absolute path. |
26
+ | `pathPosix(...args)` | Converts to POSIX-style path (replaces backslashes with slashes). |
27
+ | `pathNorm(...paths)` | Normalizes paths and returns as `NormPath`. Converts to absolute path and normalizes with platform-specific separators. |
28
+ | `pathIsChildPath(childPath, parentPath)` | Checks if `childPath` is a child path of `parentPath`. Returns `false` for identical paths. |
29
+ | `pathChangeFileDirectory(filePath, fromDir, toDir)` | Changes the directory of a file path. Throws an error if the file is not within `fromDir`. |
30
+ | `pathGetBasenameWithoutExt(filePath)` | Returns the filename (basename) without extension. |
31
+ | `pathFilterByTargets(files, targets, cwd)` | Filters files based on target path list. Returns `files` as-is if `targets` is an empty array. |
32
+
33
+ ```typescript
34
+ import {
35
+ pathPosix,
36
+ pathNorm,
37
+ pathIsChildPath,
38
+ pathChangeFileDirectory,
39
+ pathGetBasenameWithoutExt,
40
+ pathFilterByTargets,
41
+ } from "@simplysm/core-node";
42
+
43
+ // Convert to POSIX-style path
44
+ pathPosix("C:\\Users\\test"); // "C:/Users/test"
45
+ pathPosix("src", "index.ts"); // "src/index.ts"
46
+
47
+ // Normalize path (convert to absolute path)
48
+ const normPath = pathNorm("src", "index.ts"); // Returns NormPath type
49
+
50
+ // Check child path relationship
51
+ pathIsChildPath("/a/b/c", "/a/b"); // true
52
+ pathIsChildPath("/a/b", "/a/b/c"); // false
53
+ pathIsChildPath("/a/b", "/a/b"); // false (same path)
54
+
55
+ // Change file directory
56
+ pathChangeFileDirectory("/a/b/c.txt", "/a", "/x"); // "/x/b/c.txt"
57
+
58
+ // Return filename without extension
59
+ pathGetBasenameWithoutExt("file.txt"); // "file"
60
+ pathGetBasenameWithoutExt("/path/to/file.spec.ts"); // "file.spec"
61
+
62
+ // Filter files by target paths
63
+ const files = ["/proj/src/a.ts", "/proj/src/b.ts", "/proj/tests/c.ts"];
64
+ pathFilterByTargets(files, ["src"], "/proj");
65
+ // ["/proj/src/a.ts", "/proj/src/b.ts"]
66
+ ```
67
+
68
+ ---
69
+
70
+ ### File System Utilities (`utils/fs`)
71
+
72
+ Provides functions for reading, writing, deleting, copying, and searching files and directories. Most functions come in both async and sync (`Sync` suffix) versions.
73
+
74
+ #### Existence Check
75
+
76
+ | Function | Description |
77
+ |----------|-------------|
78
+ | `fsExists(targetPath)` | Asynchronously checks if a file or directory exists. |
79
+ | `fsExistsSync(targetPath)` | Synchronously checks if a file or directory exists. |
80
+
81
+ #### Directory Creation
82
+
83
+ | Function | Description |
84
+ |----------|-------------|
85
+ | `fsMkdir(targetPath)` | Asynchronously creates a directory (recursive). |
86
+ | `fsMkdirSync(targetPath)` | Synchronously creates a directory (recursive). |
87
+
88
+ #### Deletion
89
+
90
+ | Function | Description |
91
+ |----------|-------------|
92
+ | `fsRm(targetPath)` | Asynchronously deletes a file or directory. Retries up to 6 times (500ms intervals) for transient errors like file locks. |
93
+ | `fsRmSync(targetPath)` | Synchronously deletes a file or directory. Fails immediately without retries. |
94
+
95
+ #### Copy
96
+
97
+ | Function | Description |
98
+ |----------|-------------|
99
+ | `fsCopy(sourcePath, targetPath, filter?)` | Asynchronously copies a file or directory. Can filter copy targets with a `filter` function. Does nothing if `sourcePath` doesn't exist. |
100
+ | `fsCopySync(sourcePath, targetPath, filter?)` | Synchronously copies a file or directory. |
101
+
102
+ #### File Reading
103
+
104
+ | Function | Description |
105
+ |----------|-------------|
106
+ | `fsRead(targetPath)` | Asynchronously reads a file as a UTF-8 string. |
107
+ | `fsReadSync(targetPath)` | Synchronously reads a file as a UTF-8 string. |
108
+ | `fsReadBuffer(targetPath)` | Asynchronously reads a file as a Buffer. |
109
+ | `fsReadBufferSync(targetPath)` | Synchronously reads a file as a Buffer. |
110
+ | `fsReadJson<T>(targetPath)` | Asynchronously reads a JSON file (uses `jsonParse`). |
111
+ | `fsReadJsonSync<T>(targetPath)` | Synchronously reads a JSON file (uses `jsonParse`). |
112
+
113
+ #### File Writing
114
+
115
+ | Function | Description |
116
+ |----------|-------------|
117
+ | `fsWrite(targetPath, data)` | Asynchronously writes a file. Automatically creates parent directories if they don't exist. `data` is `string` or `Uint8Array`. |
118
+ | `fsWriteSync(targetPath, data)` | Synchronously writes a file. Automatically creates parent directories. |
119
+ | `fsWriteJson(targetPath, data, options?)` | Asynchronously writes a JSON file (uses `jsonStringify`). Can specify `replacer` and `space` in `options`. |
120
+ | `fsWriteJsonSync(targetPath, data, options?)` | Synchronously writes a JSON file. |
121
+
122
+ #### Directory Reading
123
+
124
+ | Function | Description |
125
+ |----------|-------------|
126
+ | `fsReaddir(targetPath)` | Asynchronously reads directory contents. |
127
+ | `fsReaddirSync(targetPath)` | Synchronously reads directory contents. |
128
+
129
+ #### File Information
130
+
131
+ | Function | Description |
132
+ |----------|-------------|
133
+ | `fsStat(targetPath)` | Asynchronously retrieves file/directory information (follows symbolic links). |
134
+ | `fsStatSync(targetPath)` | Synchronously retrieves file/directory information (follows symbolic links). |
135
+ | `fsLstat(targetPath)` | Asynchronously retrieves file/directory information (symbolic link itself). |
136
+ | `fsLstatSync(targetPath)` | Synchronously retrieves file/directory information (symbolic link itself). |
137
+
138
+ #### Glob Search
139
+
140
+ | Function | Description |
141
+ |----------|-------------|
142
+ | `fsGlob(pattern, options?)` | Asynchronously searches for files with a glob pattern. Returns an array of absolute paths of matched files. |
143
+ | `fsGlobSync(pattern, options?)` | Synchronously searches for files with a glob pattern. |
144
+
145
+ #### Other Utilities
146
+
147
+ | Function | Description |
148
+ |----------|-------------|
149
+ | `fsClearEmptyDirectory(dirPath)` | Recursively deletes empty directories under the specified directory. |
150
+ | `fsFindAllParentChildPaths(childGlob, fromPath, rootPath?)` | Traverses parent directories from the start path toward the root, asynchronously searching with a glob pattern. |
151
+ | `fsFindAllParentChildPathsSync(childGlob, fromPath, rootPath?)` | Synchronous version of the above. |
152
+
153
+ ```typescript
154
+ import {
155
+ fsExists,
156
+ fsRead,
157
+ fsWrite,
158
+ fsReadJson,
159
+ fsWriteJson,
160
+ fsStat,
161
+ fsLstat,
162
+ fsReaddir,
163
+ fsGlob,
164
+ fsMkdir,
165
+ fsRm,
166
+ fsCopy,
167
+ fsClearEmptyDirectory,
168
+ fsFindAllParentChildPaths,
169
+ fsReadBuffer,
170
+ } from "@simplysm/core-node";
171
+
172
+ // Check existence
173
+ if (await fsExists("/path/to/file.txt")) {
174
+ // ...
175
+ }
176
+
177
+ // Read/write files
178
+ const content = await fsRead("/path/to/file.txt");
179
+ await fsWrite("/path/to/output.txt", "content"); // Automatically creates parent directories
180
+
181
+ // Read binary files
182
+ const buffer = await fsReadBuffer("/path/to/file.bin");
183
+
184
+ // Read/write JSON files (uses JsonConvert)
185
+ interface Config { port: number; host: string }
186
+ const config = await fsReadJson<Config>("/path/to/config.json");
187
+ await fsWriteJson("/path/to/output.json", data, { space: 2 });
188
+
189
+ // Retrieve file information
190
+ const stat = await fsStat("/path/to/file.txt"); // Follows symbolic links
191
+ const lstat = await fsLstat("/path/to/link"); // Symbolic link itself
192
+
193
+ // Read directory
194
+ const entries = await fsReaddir("/path/to/dir");
195
+
196
+ // Search files with glob pattern
197
+ const tsFiles = await fsGlob("**/*.ts");
198
+
199
+ // Create/delete directories
200
+ await fsMkdir("/path/to/dir"); // recursive
201
+ await fsRm("/path/to/target");
202
+
203
+ // Recursively delete empty directories
204
+ await fsClearEmptyDirectory("/path/to/dir");
205
+
206
+ // Copy files/directories (exclude node_modules with filter function)
207
+ await fsCopy("/src", "/dest", (path) => !path.includes("node_modules"));
208
+
209
+ // Traverse parent directories and glob search
210
+ const configs = await fsFindAllParentChildPaths(
211
+ "package.json",
212
+ "/proj/src/sub",
213
+ "/proj",
214
+ );
215
+ ```
216
+
217
+ > It's recommended to use async functions except when async cannot be used (e.g., in constructors). Sync functions block the event loop and can cause performance degradation.
218
+
219
+ ---
220
+
221
+ ### FsWatcher (`features/fs-watcher`)
222
+
223
+ A chokidar-based file system change detection wrapper. It merges events that occur within a short time and invokes callbacks.
224
+
225
+ | API | Description |
226
+ |-----|-------------|
227
+ | `FsWatcher.watch(paths, options?)` | Starts file watching (static, async). Waits until chokidar's `ready` event and returns an `FsWatcher` instance. |
228
+ | `watcher.onChange(opt, cb)` | Registers a file change event handler. Set event merge wait time (ms) with `opt.delay`. Supports chaining. |
229
+ | `watcher.close()` | Stops file watching. |
230
+ | `FsWatcherEvent` | Event type: `"add"` \| `"addDir"` \| `"change"` \| `"unlink"` \| `"unlinkDir"` |
231
+ | `FsWatcherChangeInfo` | Change information interface. Has `event: FsWatcherEvent` and `path: NormPath` fields. |
232
+
233
+ **Event Merge Strategy:**
234
+
235
+ When multiple events occur for the same file within a short time, only the final state is delivered.
236
+
237
+ | Previous Event | New Event | Result |
238
+ |----------------|-----------|--------|
239
+ | `add` | `change` | `add` (modification right after creation is treated as creation) |
240
+ | `add` | `unlink` | Deleted (immediate deletion after creation is treated as no change) |
241
+ | `unlink` | `add` / `change` | `add` (recreation after deletion) |
242
+ | `unlinkDir` | `addDir` | `addDir` (directory recreation) |
243
+ | Others | - | Overwritten with the latest event |
244
+
245
+ ```typescript
246
+ import { FsWatcher } from "@simplysm/core-node";
247
+
248
+ // Start file watching
249
+ const watcher = await FsWatcher.watch(["src/**/*.ts"]);
250
+
251
+ // Register change event handler (merge events within 300ms)
252
+ watcher.onChange({ delay: 300 }, (changes) => {
253
+ for (const { path, event } of changes) {
254
+ console.log(`${event}: ${path}`);
255
+ // event: "add" | "addDir" | "change" | "unlink" | "unlinkDir"
256
+ }
257
+ });
258
+
259
+ // Stop watching
260
+ await watcher.close();
261
+ ```
262
+
263
+ ---
264
+
265
+ ### Worker (`worker/`)
266
+
267
+ Provides a type-safe Worker wrapper based on Node.js `worker_threads`. Using Proxy, you can call worker methods as if calling them directly, and custom events are also supported.
268
+
269
+ | API | Description |
270
+ |-----|-------------|
271
+ | `Worker.create<TModule>(filePath, opt?)` | Creates a type-safe Worker Proxy. `filePath` is a `file://` URL or absolute path. |
272
+ | `createWorker<TMethods, TEvents>(methods)` | Worker factory used inside worker threads. Registers method objects and returns a sender that can send events. |
273
+ | `WorkerModule` | Module type interface used for type inference in `Worker.create<typeof import("./worker")>()`. |
274
+ | `WorkerProxy<TModule>` | Proxy type returned by `Worker.create()`. Provides promisified methods, `on()`, `off()`, `terminate()`. |
275
+ | `PromisifyMethods<T>` | Utility type that wraps method return values in `Promise`. |
276
+ | `WorkerRequest` | Worker internal request message interface. |
277
+ | `WorkerResponse` | Worker internal response message type (`"return"` \| `"error"` \| `"event"` \| `"log"`). |
278
+
279
+ **Basic Usage (without events):**
280
+
281
+ ```typescript
282
+ // worker.ts - worker file
283
+ import { createWorker } from "@simplysm/core-node";
284
+
285
+ export default createWorker({
286
+ add: (a: number, b: number) => a + b,
287
+ multiply: (a: number, b: number) => a * b,
288
+ });
289
+
290
+ // main.ts - main thread
291
+ import { Worker } from "@simplysm/core-node";
292
+ import type * as MyWorker from "./worker";
293
+ import path from "path";
294
+
295
+ const worker = Worker.create<typeof MyWorker>(
296
+ path.resolve(import.meta.dirname, "./worker.ts"),
297
+ );
298
+
299
+ const sum = await worker.add(10, 20); // 30
300
+ const product = await worker.multiply(3, 4); // 12
301
+
302
+ await worker.terminate();
303
+ ```
304
+
305
+ **Worker with Events:**
306
+
307
+ ```typescript
308
+ // worker.ts
309
+ import { createWorker } from "@simplysm/core-node";
310
+
311
+ interface MyEvents {
312
+ progress: number;
313
+ }
314
+
315
+ // sender is defined below, but is referenced at function execution time due to closure
316
+ const methods = {
317
+ calculate: (a: number, b: number) => {
318
+ sender.send("progress", 50);
319
+ const result = a + b;
320
+ sender.send("progress", 100);
321
+ return result;
322
+ },
323
+ };
324
+
325
+ const sender = createWorker<typeof methods, MyEvents>(methods);
326
+ export default sender;
327
+
328
+ // main.ts
329
+ import { Worker } from "@simplysm/core-node";
330
+ import type * as MyWorker from "./worker";
331
+ import path from "path";
332
+
333
+ const worker = Worker.create<typeof MyWorker>(
334
+ path.resolve(import.meta.dirname, "./worker.ts"),
335
+ );
336
+
337
+ // Register event listener
338
+ worker.on("progress", (percent) => {
339
+ console.log(`Progress: ${percent}%`);
340
+ });
341
+
342
+ const result = await worker.calculate(10, 20); // 30
343
+
344
+ // Remove event listener
345
+ const listener = (percent: number) => { /* ... */ };
346
+ worker.on("progress", listener);
347
+ worker.off("progress", listener);
348
+
349
+ await worker.terminate();
350
+ ```
351
+
352
+ ---
353
+
354
+ ## Important Notes
355
+
356
+ - All functions throw errors wrapped in `SdError` to include path information.
357
+ - `fsRm` (async) retries up to 6 times (500ms intervals) for transient errors like file locks, but `fsRmSync` (sync) fails immediately without retries.
358
+ - In `fsCopy`/`fsCopySync`, the `filter` function is not applied to the top-level `sourcePath`, and returning `false` for a directory skips that directory and all its children.
359
+ - `FsWatcher` internally enforces `ignoreInitial: true`. If you pass `ignoreInitial: false`, the callback will be called with an empty array on the first `onChange` call, but the actual initial file list will not be included.
360
+ - Worker automatically runs TypeScript worker files through `tsx` in development environment (`.ts` files). In production environment (`.js`), it creates Workers directly.
361
+ - This package depends on `@simplysm/core-common` and uses `jsonParse`/`jsonStringify` for JSON processing.
362
+
363
+ ## Dependencies
364
+
365
+ | Package | Purpose |
366
+ |---------|---------|
367
+ | `@simplysm/core-common` | Common utilities (`SdError`, `jsonParse`, `jsonStringify`, `EventEmitter`, `DebounceQueue`, etc.) |
368
+ | `chokidar` | File system change detection (`FsWatcher`) |
369
+ | `consola` | Logging |
370
+ | `glob` | Glob pattern file search (`fsGlob`, `fsGlobSync`) |
371
+ | `tsx` | Running TypeScript worker files in development environment |
372
+
373
+ ## License
374
+
375
+ Apache-2.0
@@ -0,0 +1,74 @@
1
+ import { DateTime } from "./types/date-time";
2
+ import { DateOnly } from "./types/date-only";
3
+ import { Time } from "./types/time";
4
+ import { Uuid } from "./types/uuid";
5
+ /**
6
+ * Buffer 대신 사용하는 바이너리 타입
7
+ */
8
+ export type Bytes = Uint8Array;
9
+ /**
10
+ * Primitive 타입 매핑
11
+ * orm-common과 공유
12
+ */
13
+ export type PrimitiveTypeMap = {
14
+ string: string;
15
+ number: number;
16
+ boolean: boolean;
17
+ DateTime: DateTime;
18
+ DateOnly: DateOnly;
19
+ Time: Time;
20
+ Uuid: Uuid;
21
+ Bytes: Bytes;
22
+ };
23
+ /**
24
+ * Primitive 타입 문자열 키
25
+ */
26
+ export type PrimitiveTypeStr = keyof PrimitiveTypeMap;
27
+ /**
28
+ * Primitive 타입 유니온
29
+ */
30
+ export type PrimitiveType = PrimitiveTypeMap[PrimitiveTypeStr] | undefined;
31
+ /**
32
+ * 깊은 Partial 타입
33
+ *
34
+ * 객체의 모든 속성을 재귀적으로 선택적(optional)으로 만듭니다.
35
+ * Primitive 타입(string, number, boolean 등)은 그대로 유지하고,
36
+ * 객체/배열 타입만 재귀적으로 Partial을 적용합니다.
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * interface User {
41
+ * name: string;
42
+ * profile: {
43
+ * age: number;
44
+ * address: { city: string };
45
+ * };
46
+ * }
47
+ *
48
+ * // 모든 깊이의 속성이 선택적이 됨
49
+ * const partial: DeepPartial<User> = {
50
+ * profile: { address: {} }
51
+ * };
52
+ * ```
53
+ */
54
+ export type DeepPartial<T> = Partial<{
55
+ [K in keyof T]: T[K] extends PrimitiveType ? T[K] : DeepPartial<T[K]>;
56
+ }>;
57
+ /**
58
+ * 생성자 타입
59
+ *
60
+ * 클래스 생성자를 타입으로 표현할 때 사용합니다.
61
+ * 주로 의존성 주입, 팩토리 패턴, instanceof 체크 등에서 활용됩니다.
62
+ *
63
+ * @example
64
+ * function create<T>(ctor: Type<T>): T {
65
+ * return new ctor();
66
+ * }
67
+ *
68
+ * class MyClass { name = "test"; }
69
+ * const instance = create(MyClass); // MyClass 인스턴스
70
+ */
71
+ export interface Type<T> extends Function {
72
+ new (...args: unknown[]): T;
73
+ }
74
+ //# sourceMappingURL=common.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.types.d.ts","sourceRoot":"","sources":["../../../../core-common/src/common.types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAIpC;;GAEG;AACH,MAAM,MAAM,KAAK,GAAG,UAAU,CAAC;AAM/B;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,IAAI,CAAC;IACX,IAAI,EAAE,IAAI,CAAC;IACX,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,MAAM,gBAAgB,CAAC;AAEtD;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,gBAAgB,CAAC,gBAAgB,CAAC,GAAG,SAAS,CAAC;AAM3E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI,OAAO,CAAC;KAClC,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CACtE,CAAC,CAAC;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,IAAI,CAAC,CAAC,CAAE,SAAQ,QAAQ;IACvC,KAAK,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;CAC7B"}
@@ -0,0 +1,6 @@
1
+ export declare const env: {
2
+ DEV: boolean;
3
+ VER?: string;
4
+ [key: string]: unknown;
5
+ };
6
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../../core-common/src/env.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,GAAG,EAAE;IAChB,GAAG,EAAE,OAAO,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAKxB,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { SdError } from "./sd-error";
2
+ /**
3
+ * 인수 오류
4
+ *
5
+ * 잘못된 인수를 받았을 때 발생시키는 에러이다.
6
+ * 인수 객체를 YAML 형식으로 메시지에 포함하여 디버깅을 용이하게 한다.
7
+ *
8
+ * @example
9
+ * // 인수 객체만 전달
10
+ * throw new ArgumentError({ userId: 123, name: null });
11
+ * // 결과 메시지: "인수가 잘못되었습니다.\n\nuserId: 123\nname: null"
12
+ *
13
+ * @example
14
+ * // 커스텀 메시지와 인수 객체 전달
15
+ * throw new ArgumentError("유효하지 않은 사용자", { userId: 123 });
16
+ * // 결과 메시지: "유효하지 않은 사용자\n\nuserId: 123"
17
+ */
18
+ export declare class ArgumentError extends SdError {
19
+ /** 기본 메시지("인수가 잘못되었습니다.")와 함께 인수 객체를 YAML 형식으로 출력 */
20
+ constructor(argObj: Record<string, unknown>);
21
+ /** 커스텀 메시지와 함께 인수 객체를 YAML 형식으로 출력 */
22
+ constructor(message: string, argObj: Record<string, unknown>);
23
+ constructor(arg1: Record<string, unknown> | string, arg2?: Record<string, unknown>);
24
+ }
25
+ //# sourceMappingURL=argument-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"argument-error.d.ts","sourceRoot":"","sources":["../../../../../core-common/src/errors/argument-error.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,aAAc,SAAQ,OAAO;IACxC,qDAAqD;gBACzC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC3C,sCAAsC;gBAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAChD,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAYnF"}
@@ -0,0 +1,29 @@
1
+ import { SdError } from "./sd-error";
2
+ /**
3
+ * 미구현 오류
4
+ *
5
+ * 아직 구현되지 않은 기능을 호출했을 때 발생시키는 에러이다.
6
+ * 추상 메서드 스텁, 향후 구현 예정인 분기 등에 사용한다.
7
+ *
8
+ * @example
9
+ * // 추상 메서드 구현 전
10
+ * class BaseService {
11
+ * process(): void {
12
+ * throw new NotImplementedError("서브클래스에서 구현 필요");
13
+ * }
14
+ * }
15
+ *
16
+ * @example
17
+ * // 향후 구현 예정 분기
18
+ * switch (type) {
19
+ * case "A": return handleA();
20
+ * case "B": throw new NotImplementedError(`타입 ${type} 처리`);
21
+ * }
22
+ */
23
+ export declare class NotImplementedError extends SdError {
24
+ /**
25
+ * @param message 추가 설명 메시지
26
+ */
27
+ constructor(message?: string);
28
+ }
29
+ //# sourceMappingURL=not-implemented-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"not-implemented-error.d.ts","sourceRoot":"","sources":["../../../../../core-common/src/errors/not-implemented-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,mBAAoB,SAAQ,OAAO;IAC9C;;OAEG;gBACS,OAAO,CAAC,EAAE,MAAM;CAI7B"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * 오류의 Tree 구조 구성이 가능한 오류 클래스
3
+ * ES2024 cause 속성 활용
4
+ *
5
+ * @example
6
+ * // 원인 에러를 감싸서 생성
7
+ * try {
8
+ * await fetch(url);
9
+ * } catch (err) {
10
+ * throw new SdError(err, "API 호출 실패", "사용자 로드 실패");
11
+ * }
12
+ * // 결과 메시지: "사용자 로드 실패 => API 호출 실패 => 원본 에러 메시지"
13
+ *
14
+ * @example
15
+ * // 메시지만으로 생성
16
+ * throw new SdError("잘못된 상태", "처리 불가");
17
+ * // 결과 메시지: "처리 불가 => 잘못된 상태"
18
+ */
19
+ export declare class SdError extends Error {
20
+ cause?: Error;
21
+ /** 원인 에러를 감싸서 생성. 메시지는 역순으로 연결됨 (상위 메시지 => 하위 메시지 => 원인 메시지) */
22
+ constructor(cause: Error, ...messages: string[]);
23
+ /** 메시지만으로 생성. 메시지는 역순으로 연결됨 (상위 메시지 => 하위 메시지) */
24
+ constructor(...messages: string[]);
25
+ constructor(arg1?: unknown, ...messages: string[]);
26
+ }
27
+ //# sourceMappingURL=sd-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sd-error.d.ts","sourceRoot":"","sources":["../../../../../core-common/src/errors/sd-error.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,OAAQ,SAAQ,KAAK;IACvB,KAAK,CAAC,EAAE,KAAK,CAAC;IAEvB,gEAAgE;gBACpD,KAAK,EAAE,KAAK,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE;IAC/C,kDAAkD;gBACtC,GAAG,QAAQ,EAAE,MAAM,EAAE;gBACrB,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE;CA2BlD"}
@@ -0,0 +1,31 @@
1
+ import { SdError } from "./sd-error";
2
+ /**
3
+ * 타임아웃 오류
4
+ *
5
+ * 대기 시간이 초과되었을 때 발생하는 에러이다.
6
+ * Wait.until() 등의 비동기 대기 함수에서 최대 시도 횟수를 초과하면 자동으로 발생한다.
7
+ *
8
+ * @example
9
+ * // Wait.until에서 자동 발생
10
+ * try {
11
+ * await Wait.until(() => isReady, 100, 50); // 100ms 간격, 최대 50회
12
+ * } catch (err) {
13
+ * if (err instanceof TimeoutError) {
14
+ * console.log("시간 초과");
15
+ * }
16
+ * }
17
+ *
18
+ * @example
19
+ * // 직접 발생
20
+ * if (elapsed > maxTime) {
21
+ * throw new TimeoutError(undefined, "API 응답 대기 초과");
22
+ * }
23
+ */
24
+ export declare class TimeoutError extends SdError {
25
+ /**
26
+ * @param count 시도 횟수
27
+ * @param message 추가 메시지
28
+ */
29
+ constructor(count?: number, message?: string);
30
+ }
31
+ //# sourceMappingURL=timeout-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timeout-error.d.ts","sourceRoot":"","sources":["../../../../../core-common/src/errors/timeout-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAErC;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,YAAa,SAAQ,OAAO;IACvC;;;OAGG;gBACS,KAAK,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAM7C"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Array 확장 메서드
3
+ *
4
+ * @remarks 각 메서드의 TSDoc은 타입 정의 파일(arr-ext.types.ts) 참조
5
+ */
6
+ import "./map-ext";
7
+ import type { ReadonlyArrayExt, MutableArrayExt } from "./arr-ext.types";
8
+ declare global {
9
+ interface ReadonlyArray<T> extends ReadonlyArrayExt<T> {
10
+ }
11
+ interface Array<T> extends ReadonlyArrayExt<T>, MutableArrayExt<T> {
12
+ }
13
+ }
14
+ export type { ArrayDiffsResult, ArrayDiffs2Result, TreeArray, ComparableType } from "./arr-ext.types";
15
+ //# sourceMappingURL=arr-ext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arr-ext.d.ts","sourceRoot":"","sources":["../../../../../core-common/src/extensions/arr-ext.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,WAAW,CAAC;AAUnB,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EAIhB,MAAM,iBAAiB,CAAC;AA2uBzB,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,aAAa,CAAC,CAAC,CAAE,SAAQ,gBAAgB,CAAC,CAAC,CAAC;KAAG;IACzD,UAAU,KAAK,CAAC,CAAC,CAAE,SAAQ,gBAAgB,CAAC,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC;KAAG;CACtE;AAID,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Array 확장 헬퍼 함수
3
+ */
4
+ import type { ComparableType } from "./arr-ext.types";
5
+ /**
6
+ * DateTime, DateOnly, Time을 비교 가능한 primitive 값으로 변환
7
+ */
8
+ export declare function toComparable(value: ComparableType): string | number | boolean | undefined;
9
+ /**
10
+ * 정렬을 위한 비교 함수
11
+ *
12
+ * @param pp 비교 대상 1
13
+ * @param pn 비교 대상 2
14
+ * @param desc true: 내림차순, false: 오름차순
15
+ * @returns 음수: pp가 앞, 0: 같음, 양수: pn이 앞
16
+ * @note null/undefined 값은 오름차순 시 앞으로, 내림차순 시 뒤로 정렬됨
17
+ */
18
+ export declare function compareForOrder(pp: ComparableType, pn: ComparableType, desc: boolean): number;
19
+ //# sourceMappingURL=arr-ext.helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"arr-ext.helpers.d.ts","sourceRoot":"","sources":["../../../../../core-common/src/extensions/arr-ext.helpers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAKzF;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAuB7F"}