@tstdl/base 0.93.139 → 0.93.141
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 +166 -0
- package/ai/genkit/multi-region.plugin.js +5 -3
- package/ai/genkit/tests/multi-region.test.d.ts +1 -0
- package/ai/genkit/tests/multi-region.test.js +5 -2
- package/ai/parser/parser.js +2 -2
- package/ai/prompts/build.js +1 -0
- package/ai/prompts/instructions-formatter.d.ts +15 -2
- package/ai/prompts/instructions-formatter.js +36 -31
- package/ai/prompts/prompt-builder.js +5 -5
- package/ai/prompts/steering.d.ts +3 -2
- package/ai/prompts/steering.js +3 -1
- package/ai/tests/instructions-formatter.test.js +1 -0
- package/api/README.md +403 -0
- package/api/client/client.js +7 -13
- package/api/client/tests/api-client.test.js +10 -10
- package/api/default-error-handlers.js +1 -1
- package/api/response.d.ts +2 -2
- package/api/response.js +22 -33
- package/api/server/api-controller.d.ts +1 -1
- package/api/server/api-controller.js +3 -3
- package/api/server/api-request-token.provider.d.ts +1 -0
- package/api/server/api-request-token.provider.js +1 -0
- package/api/server/middlewares/allowed-methods.middleware.js +2 -1
- package/api/server/middlewares/content-type.middleware.js +2 -1
- package/api/types.d.ts +3 -2
- package/application/README.md +240 -0
- package/application/application.d.ts +1 -1
- package/application/application.js +3 -3
- package/application/providers.d.ts +20 -2
- package/application/providers.js +34 -7
- package/audit/README.md +267 -0
- package/audit/module.d.ts +5 -0
- package/audit/module.js +9 -1
- package/authentication/README.md +288 -0
- package/authentication/client/authentication.service.d.ts +12 -11
- package/authentication/client/authentication.service.js +21 -21
- package/authentication/client/http-client.middleware.js +2 -2
- package/authentication/server/module.d.ts +5 -0
- package/authentication/server/module.js +9 -1
- package/authentication/tests/authentication.api-controller.test.js +1 -1
- package/authentication/tests/authentication.api-request-token.provider.test.js +1 -1
- package/authentication/tests/authentication.client-error-handling.test.js +2 -1
- package/authentication/tests/authentication.client-service-refresh.test.js +5 -3
- package/authentication/tests/authentication.client-service.test.js +1 -1
- package/browser/README.md +401 -0
- package/cancellation/README.md +156 -0
- package/cancellation/tests/coverage.test.d.ts +1 -0
- package/cancellation/tests/coverage.test.js +49 -0
- package/cancellation/tests/leak.test.js +24 -29
- package/cancellation/tests/token.test.d.ts +1 -0
- package/cancellation/tests/token.test.js +136 -0
- package/cancellation/token.d.ts +53 -177
- package/cancellation/token.js +132 -208
- package/circuit-breaker/postgres/module.d.ts +1 -0
- package/circuit-breaker/postgres/module.js +5 -1
- package/context/README.md +174 -0
- package/cookie/README.md +161 -0
- package/css/README.md +157 -0
- package/data-structures/README.md +320 -0
- package/decorators/README.md +140 -0
- package/distributed-loop/README.md +231 -0
- package/distributed-loop/distributed-loop.js +1 -1
- package/document-management/README.md +403 -0
- package/document-management/server/configure.js +5 -1
- package/document-management/server/module.d.ts +1 -1
- package/document-management/server/module.js +1 -1
- package/document-management/server/services/document-management-ancillary.service.js +1 -1
- package/document-management/server/services/document-management.service.js +9 -7
- package/document-management/tests/ai-config-hierarchy.test.js +0 -5
- package/document-management/tests/document-management-ai-overrides.test.js +0 -1
- package/document-management/tests/document-management-core.test.js +2 -7
- package/document-management/tests/document-management.api.test.js +6 -7
- package/document-management/tests/document-statistics.service.test.js +11 -12
- package/document-management/tests/document-validation-ai-overrides.test.js +0 -1
- package/document-management/tests/document.service.test.js +3 -3
- package/document-management/tests/enum-helpers.test.js +2 -3
- package/dom/README.md +213 -0
- package/enumerable/README.md +259 -0
- package/enumeration/README.md +121 -0
- package/errors/README.md +267 -0
- package/examples/document-management/main.d.ts +1 -0
- package/examples/document-management/main.js +14 -11
- package/file/README.md +191 -0
- package/formats/README.md +210 -0
- package/function/README.md +144 -0
- package/http/README.md +318 -0
- package/http/client/adapters/undici.adapter.js +1 -1
- package/http/client/http-client-request.d.ts +6 -5
- package/http/client/http-client-request.js +8 -9
- package/http/server/node/node-http-server.js +1 -2
- package/image-service/README.md +137 -0
- package/injector/README.md +491 -0
- package/intl/README.md +113 -0
- package/json-path/README.md +182 -0
- package/jsx/README.md +154 -0
- package/key-value-store/README.md +191 -0
- package/key-value-store/postgres/module.d.ts +1 -0
- package/key-value-store/postgres/module.js +5 -1
- package/lock/README.md +249 -0
- package/lock/postgres/module.d.ts +1 -0
- package/lock/postgres/module.js +5 -1
- package/lock/web/web-lock.js +119 -47
- package/logger/README.md +287 -0
- package/mail/README.md +256 -0
- package/mail/module.d.ts +5 -1
- package/mail/module.js +11 -6
- package/memory/README.md +144 -0
- package/message-bus/README.md +244 -0
- package/message-bus/message-bus-base.js +1 -1
- package/module/README.md +182 -0
- package/module/module.d.ts +1 -1
- package/module/module.js +77 -17
- package/module/modules/web-server.module.js +3 -4
- package/notification/server/module.d.ts +1 -0
- package/notification/server/module.js +5 -1
- package/notification/tests/notification-flow.test.js +2 -2
- package/notification/tests/notification-type.service.test.js +24 -15
- package/object-storage/README.md +300 -0
- package/openid-connect/README.md +274 -0
- package/orm/README.md +423 -0
- package/orm/decorators.d.ts +5 -1
- package/orm/decorators.js +1 -1
- package/orm/server/drizzle/schema-converter.js +17 -30
- package/orm/server/encryption.d.ts +0 -1
- package/orm/server/encryption.js +1 -4
- package/orm/server/index.d.ts +1 -6
- package/orm/server/index.js +1 -6
- package/orm/server/migration.d.ts +19 -0
- package/orm/server/migration.js +72 -0
- package/orm/server/repository.d.ts +1 -1
- package/orm/server/transaction.d.ts +5 -10
- package/orm/server/transaction.js +22 -26
- package/orm/server/transactional.js +3 -3
- package/orm/tests/database-migration.test.d.ts +1 -0
- package/orm/tests/database-migration.test.js +82 -0
- package/orm/tests/encryption.test.js +3 -4
- package/orm/utils.d.ts +17 -2
- package/orm/utils.js +49 -1
- package/package.json +9 -6
- package/password/README.md +164 -0
- package/pdf/README.md +246 -0
- package/polyfills.js +1 -0
- package/pool/README.md +198 -0
- package/process/README.md +237 -0
- package/promise/README.md +252 -0
- package/promise/cancelable-promise.js +1 -1
- package/random/README.md +193 -0
- package/rate-limit/postgres/module.d.ts +1 -0
- package/rate-limit/postgres/module.js +5 -1
- package/reflection/README.md +305 -0
- package/reflection/decorator-data.js +11 -12
- package/rpc/README.md +386 -0
- package/rxjs-utils/README.md +262 -0
- package/schema/README.md +342 -0
- package/serializer/README.md +342 -0
- package/signals/implementation/README.md +134 -0
- package/sse/README.md +278 -0
- package/task-queue/README.md +293 -0
- package/task-queue/postgres/drizzle/{0000_simple_invisible_woman.sql → 0000_wakeful_sunspot.sql} +22 -14
- package/task-queue/postgres/drizzle/meta/0000_snapshot.json +160 -82
- package/task-queue/postgres/drizzle/meta/_journal.json +2 -2
- package/task-queue/postgres/module.d.ts +1 -0
- package/task-queue/postgres/module.js +5 -1
- package/task-queue/postgres/schemas.d.ts +9 -6
- package/task-queue/postgres/schemas.js +4 -3
- package/task-queue/postgres/task-queue.d.ts +4 -13
- package/task-queue/postgres/task-queue.js +462 -355
- package/task-queue/postgres/task.model.d.ts +12 -5
- package/task-queue/postgres/task.model.js +51 -25
- package/task-queue/task-context.d.ts +2 -2
- package/task-queue/task-context.js +8 -8
- package/task-queue/task-queue.d.ts +53 -19
- package/task-queue/task-queue.js +121 -55
- package/task-queue/tests/cascading-cancellations.test.d.ts +1 -0
- package/task-queue/tests/cascading-cancellations.test.js +38 -0
- package/task-queue/tests/complex.test.js +45 -229
- package/task-queue/tests/coverage-branch.test.d.ts +1 -0
- package/task-queue/tests/coverage-branch.test.js +407 -0
- package/task-queue/tests/coverage-enhancement.test.d.ts +1 -0
- package/task-queue/tests/coverage-enhancement.test.js +144 -0
- package/task-queue/tests/dag-dependencies.test.d.ts +1 -0
- package/task-queue/tests/dag-dependencies.test.js +41 -0
- package/task-queue/tests/dependencies.test.js +28 -26
- package/task-queue/tests/extensive-dependencies.test.js +64 -139
- package/task-queue/tests/fan-out-spawning.test.d.ts +1 -0
- package/task-queue/tests/fan-out-spawning.test.js +53 -0
- package/task-queue/tests/idempotent-replacement.test.d.ts +1 -0
- package/task-queue/tests/idempotent-replacement.test.js +61 -0
- package/task-queue/tests/missing-idempotent-tasks.test.d.ts +1 -0
- package/task-queue/tests/missing-idempotent-tasks.test.js +38 -0
- package/task-queue/tests/queue.test.js +128 -8
- package/task-queue/tests/worker.test.js +39 -16
- package/task-queue/tests/zombie-parent.test.d.ts +1 -0
- package/task-queue/tests/zombie-parent.test.js +45 -0
- package/task-queue/tests/zombie-recovery.test.d.ts +1 -0
- package/task-queue/tests/zombie-recovery.test.js +51 -0
- package/templates/README.md +287 -0
- package/test5.js +5 -5
- package/testing/README.md +157 -0
- package/testing/integration-setup.d.ts +4 -4
- package/testing/integration-setup.js +54 -29
- package/text/README.md +346 -0
- package/text/localization.service.js +2 -2
- package/threading/README.md +238 -0
- package/types/README.md +311 -0
- package/utils/README.md +322 -0
- package/utils/async-iterable-helpers/observable-iterable.d.ts +1 -1
- package/utils/async-iterable-helpers/observable-iterable.js +4 -8
- package/utils/async-iterable-helpers/take-until.js +4 -4
- package/utils/backoff.js +89 -30
- package/utils/file-reader.js +1 -2
- package/utils/retry-with-backoff.js +1 -1
- package/utils/timer.d.ts +1 -1
- package/utils/timer.js +5 -7
- package/utils/timing.d.ts +1 -1
- package/utils/timing.js +2 -4
- package/utils/z-base32.d.ts +1 -0
- package/utils/z-base32.js +1 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# @tstdl/base/threading
|
|
2
|
+
|
|
3
|
+
The `threading` module provides a unified, type-safe abstraction for multi-threading in both Node.js and browser environments. It utilizes a managed thread pool and an RPC mechanism to easily offload CPU-intensive tasks to worker threads without manually managing message passing.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [✨ Features](#-features)
|
|
8
|
+
2. [Core Concepts](#core-concepts)
|
|
9
|
+
3. [🚀 Basic Usage](#-basic-usage)
|
|
10
|
+
4. [🔧 Advanced Topics](#-advanced-topics)
|
|
11
|
+
- [Named Workers (Multiple Functions)](#named-workers-multiple-functions)
|
|
12
|
+
- [Configuration](#configuration)
|
|
13
|
+
5. [📚 API](#-api)
|
|
14
|
+
|
|
15
|
+
## ✨ Features
|
|
16
|
+
|
|
17
|
+
- **Cross-Platform:** Works seamlessly in Node.js (using `worker_threads`) and Browsers (using `Web Workers`).
|
|
18
|
+
- **Thread Pooling:** Automatically manages a pool of workers to reuse resources and limit concurrency.
|
|
19
|
+
- **RPC Communication:** Call worker functions directly as if they were local asynchronous functions, handling argument and return value serialization automatically.
|
|
20
|
+
- **Type Safety:** leveraging TypeScript to ensure the main thread invokes worker functions with correct arguments and return types.
|
|
21
|
+
- **Resource Management:** Implements `AsyncDisposable` for clean teardown of thread pools.
|
|
22
|
+
|
|
23
|
+
## Core Concepts
|
|
24
|
+
|
|
25
|
+
### Thread Pool
|
|
26
|
+
|
|
27
|
+
The `ThreadPool` is the main orchestrator running on the main thread. It spawns a specified number of worker threads based on a provided script URL. It manages the lifecycle of these workers and distributes tasks to them.
|
|
28
|
+
|
|
29
|
+
### RPC (Remote Procedure Call)
|
|
30
|
+
|
|
31
|
+
Instead of manually posting messages (`postMessage`) and listening for events, this module uses an RPC layer. You "expose" a function inside the worker, and the `ThreadPool` creates a "remote" proxy for that function. When you call the proxy, arguments are sent to the worker, the function executes, and the result is sent back.
|
|
32
|
+
|
|
33
|
+
### Worker Script
|
|
34
|
+
|
|
35
|
+
This is the separate entry point file that runs inside the thread. It imports `exposeThreadWorker` to make specific functions available to the pool.
|
|
36
|
+
|
|
37
|
+
## 🚀 Basic Usage
|
|
38
|
+
|
|
39
|
+
To use the threading module, you need two parts: the worker script (the code running in the thread) and the main application code (which creates the pool).
|
|
40
|
+
|
|
41
|
+
### 1. Create the Worker (`worker.ts`)
|
|
42
|
+
|
|
43
|
+
Define your CPU-intensive function, export its type (for type safety in the main thread), and expose it.
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { exposeThreadWorker } from '@tstdl/base/threading';
|
|
47
|
+
|
|
48
|
+
// 1. Define the function to run in the thread
|
|
49
|
+
function heavyComputation(input: number): number {
|
|
50
|
+
// Simulate heavy work
|
|
51
|
+
const start = Date.now();
|
|
52
|
+
while (Date.now() - start < 500);
|
|
53
|
+
return input * 2;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 2. Export the type so the main thread knows the signature
|
|
57
|
+
export type HeavyComputation = typeof heavyComputation;
|
|
58
|
+
|
|
59
|
+
// 3. Expose the function as the default handler
|
|
60
|
+
exposeThreadWorker(heavyComputation);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 2. Use the Pool (`main.ts`)
|
|
64
|
+
|
|
65
|
+
Instantiate the `ThreadPool` pointing to the compiled worker script.
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
import { ThreadPool } from '@tstdl/base/threading';
|
|
69
|
+
import { Logger } from '@tstdl/base/logger';
|
|
70
|
+
import type { HeavyComputation } from './worker.js'; // Import type only
|
|
71
|
+
|
|
72
|
+
async function main() {
|
|
73
|
+
const logger = new Logger('App');
|
|
74
|
+
|
|
75
|
+
// Point to the compiled JS file of the worker
|
|
76
|
+
const workerUrl = new URL('./worker.js', import.meta.url);
|
|
77
|
+
|
|
78
|
+
// Create the pool
|
|
79
|
+
const pool = new ThreadPool(workerUrl, logger);
|
|
80
|
+
|
|
81
|
+
try {
|
|
82
|
+
// Get a type-safe processor function
|
|
83
|
+
// The generic argument <HeavyComputation> ensures type safety
|
|
84
|
+
const process = pool.getProcessor<HeavyComputation>();
|
|
85
|
+
|
|
86
|
+
// Run the task
|
|
87
|
+
const result = await process(21);
|
|
88
|
+
console.log(`Result: ${result}`); // Result: 42
|
|
89
|
+
} finally {
|
|
90
|
+
// Clean up threads
|
|
91
|
+
await pool.dispose();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
main();
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 🔧 Advanced Topics
|
|
99
|
+
|
|
100
|
+
### Named Workers (Multiple Functions)
|
|
101
|
+
|
|
102
|
+
You can expose multiple functions from a single worker script by giving them unique names.
|
|
103
|
+
|
|
104
|
+
**Worker (`multi-worker.ts`):**
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import { exposeThreadWorker } from '@tstdl/base/threading';
|
|
108
|
+
|
|
109
|
+
function add(a: number, b: number): number {
|
|
110
|
+
return a + b;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function subtract(a: number, b: number): number {
|
|
114
|
+
return a - b;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export type Add = typeof add;
|
|
118
|
+
export type Subtract = typeof subtract;
|
|
119
|
+
|
|
120
|
+
// Expose with specific names
|
|
121
|
+
exposeThreadWorker(add, 'add');
|
|
122
|
+
exposeThreadWorker(subtract, 'subtract');
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
**Main (`main.ts`):**
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { ThreadPool } from '@tstdl/base/threading';
|
|
129
|
+
import { Logger } from '@tstdl/base/logger';
|
|
130
|
+
import type { Add, Subtract } from './multi-worker.js';
|
|
131
|
+
|
|
132
|
+
async function main() {
|
|
133
|
+
const logger = new Logger('App');
|
|
134
|
+
const pool = new ThreadPool(new URL('./multi-worker.js', import.meta.url), logger);
|
|
135
|
+
|
|
136
|
+
// Get processors by name
|
|
137
|
+
const addRemote = pool.getProcessor<Add>('add');
|
|
138
|
+
const subtractRemote = pool.getProcessor<Subtract>('subtract');
|
|
139
|
+
|
|
140
|
+
const sum = await addRemote(5, 3);
|
|
141
|
+
const diff = await subtractRemote(10, 4);
|
|
142
|
+
|
|
143
|
+
console.log({ sum, diff }); // { sum: 8, diff: 6 }
|
|
144
|
+
|
|
145
|
+
await pool.dispose();
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Best Practices
|
|
150
|
+
|
|
151
|
+
- **Offload CPU-Intensive Work Only:** Threading has overhead due to serialization and communication. Use it for heavy computations (e.g., image processing, complex math, large data parsing) rather than simple asynchronous I/O.
|
|
152
|
+
- **Minimize Data Transfer:** Arguments and return values are serialized (using the Structured Clone algorithm). Large objects can slow down communication.
|
|
153
|
+
- **Clean Up Resources:** Always call `dispose()` or use `[Symbol.asyncDispose]` (e.g., via `await using`) to ensure worker threads are terminated when they are no longer needed.
|
|
154
|
+
- **Worker Script Paths:** In Node.js, ensure the worker URL points to the _compiled_ `.js` file, especially when using TypeScript.
|
|
155
|
+
|
|
156
|
+
### Configuration
|
|
157
|
+
|
|
158
|
+
You can configure the underlying worker options and the number of threads in the pool.
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
import { ThreadPool } from '@tstdl/base/threading';
|
|
162
|
+
import { Logger } from '@tstdl/base/logger';
|
|
163
|
+
|
|
164
|
+
const pool = new ThreadPool(new URL('./worker.js', import.meta.url), new Logger('Pool'), {
|
|
165
|
+
// Number of workers to spawn.
|
|
166
|
+
// Defaults to half of CPU cores (via hardwareConcurrency / 2) or 4.
|
|
167
|
+
threadCount: 4,
|
|
168
|
+
|
|
169
|
+
// Node.js specific options (passed to node:worker_threads Worker constructor)
|
|
170
|
+
workerData: { some: 'data' },
|
|
171
|
+
|
|
172
|
+
// Browser specific options (passed to Web Worker constructor)
|
|
173
|
+
type: 'module',
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## 📚 API
|
|
178
|
+
|
|
179
|
+
### Classes
|
|
180
|
+
|
|
181
|
+
| Class | Description |
|
|
182
|
+
| :----------- | :--------------------------------------------------------------------------------------------------------------------------------------- |
|
|
183
|
+
| `ThreadPool` | Manages a pool of worker threads. Implements `AsyncDisposable` for clean resource cleanup. Provides type-safe access to worker functions. |
|
|
184
|
+
|
|
185
|
+
#### `ThreadPool`
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
class ThreadPool implements AsyncDisposable {
|
|
189
|
+
/** The URL or path to the worker script. */
|
|
190
|
+
readonly url: string | URL;
|
|
191
|
+
|
|
192
|
+
/** Configuration options used for this pool. */
|
|
193
|
+
readonly options: ThreadOptions | undefined;
|
|
194
|
+
|
|
195
|
+
constructor(url: string | URL, logger: Logger, options?: ThreadOptions);
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Returns a type-safe function that, when called, executes the task on an available worker.
|
|
199
|
+
* This is the preferred way to interact with the pool.
|
|
200
|
+
* @param name The name of the exposed function in the worker (default: 'default').
|
|
201
|
+
*/
|
|
202
|
+
getProcessor<T extends ThreadWorker>(name?: string): (...args: Parameters<T>) => Promise<ReturnType<T>>;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Directly executes a task on an available worker.
|
|
206
|
+
* @param name The name of the exposed function in the worker.
|
|
207
|
+
* @param args Arguments to pass to the worker function.
|
|
208
|
+
*/
|
|
209
|
+
process<T extends ThreadWorker>(name: string, ...args: Parameters<T>): Promise<ReturnType<T>>;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Terminates all workers in the pool and releases resources.
|
|
213
|
+
*/
|
|
214
|
+
dispose(): Promise<void>;
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### Functions
|
|
219
|
+
|
|
220
|
+
| Function | Description |
|
|
221
|
+
| :------------------- | :--------------------------------------------------------------------------------- |
|
|
222
|
+
| `exposeThreadWorker` | Exposes a function inside a worker script so it can be called by the `ThreadPool`. |
|
|
223
|
+
|
|
224
|
+
#### `exposeThreadWorker`
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
function exposeThreadWorker<T extends ThreadWorker>(worker: T, name?: string): void;
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
- `worker`: The function (synchronous or asynchronous) to expose.
|
|
231
|
+
- `name`: An optional name for the function. Defaults to `'default'`.
|
|
232
|
+
|
|
233
|
+
### Types
|
|
234
|
+
|
|
235
|
+
| Type | Definition | Description |
|
|
236
|
+
| :-------------- | :--------------------------------------------------------------------------------- | :---------------------------------------------------------- |
|
|
237
|
+
| `ThreadWorker` | `(...args: any[]) => any \| Promise<any>` | Represents the signature of a function running in a thread. |
|
|
238
|
+
| `ThreadOptions` | `(WorkerOptions \| NodeWorkerThreads.WorkerOptions) & { threadCount?: number }` | Configuration options for the `ThreadPool`. |
|
package/types/README.md
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# @tstdl/base/types
|
|
2
|
+
|
|
3
|
+
A comprehensive collection of fundamental, advanced, and specialized TypeScript utility types designed to enhance type safety, improve developer experience, and provide standard definitions for common data structures.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Features](#-features)
|
|
8
|
+
- [Core Concepts](#core-concepts)
|
|
9
|
+
- [General Utility Types](#general-utility-types)
|
|
10
|
+
- [Tagged Types](#tagged-types)
|
|
11
|
+
- [Enumerations](#enumerations)
|
|
12
|
+
- [GeoJSON Types](#geojson-types)
|
|
13
|
+
- [Web Types](#web-types)
|
|
14
|
+
- [🚀 Basic Usage](#-basic-usage)
|
|
15
|
+
- [Common Utilities](#common-utilities)
|
|
16
|
+
- [Tagged Types](#tagged-types-usage)
|
|
17
|
+
- [Enumerations](#enumerations-usage)
|
|
18
|
+
- [GeoJSON](#geojson)
|
|
19
|
+
- [🔧 Advanced Topics](#-advanced-topics)
|
|
20
|
+
- [Deep Selection](#deep-selection)
|
|
21
|
+
- [Type Paths](#type-paths)
|
|
22
|
+
- [📚 API](#-api)
|
|
23
|
+
|
|
24
|
+
## ✨ Features
|
|
25
|
+
|
|
26
|
+
- **Extensive Utility Belt**: Over 50 utility types for advanced manipulation (`Simplify`, `DeepPartial`, `Writable`, `PickDeep`, `Optionalize`, etc.).
|
|
27
|
+
- **Nominal Typing**: A robust `Tagged` type system to create distinct types from primitives (branding), preventing accidental misuse of semantically different values.
|
|
28
|
+
- **GeoJSON Support**: Complete, RFC 7946 compliant type definitions for geospatial data structures.
|
|
29
|
+
- **Web Standards**: Ready-to-use types for HTML input attributes, modes, and autocomplete values.
|
|
30
|
+
- **JSON & Primitives**: Strict definitions for JSON structures and primitive type mapping.
|
|
31
|
+
|
|
32
|
+
## Core Concepts
|
|
33
|
+
|
|
34
|
+
### General Utility Types
|
|
35
|
+
|
|
36
|
+
TypeScript's built-in utility types (`Partial`, `Pick`, etc.) are excellent, but complex applications often require more granular control. This module provides utilities to:
|
|
37
|
+
|
|
38
|
+
- **Simplify** complex intersection types into readable object literals (great for IDE tooltips).
|
|
39
|
+
- **Deeply** modify types (make everything writable, optional, or readonly recursively).
|
|
40
|
+
- **Select** or **Omit** nested properties using a structural mask.
|
|
41
|
+
- **Transform** optional properties (`| undefined`) into truly optional keys (`?`).
|
|
42
|
+
|
|
43
|
+
### Tagged Types
|
|
44
|
+
|
|
45
|
+
Primitives like `string` are often used for IDs (`UserId`, `OrderId`). However, TypeScript treats all strings as compatible, allowing you to accidentally pass a `UserId` to a function expecting an `OrderId`.
|
|
46
|
+
**Tagged Types** (also known as Branded Types) solve this by attaching a "tag" to the type signature. This makes them structurally unique to the compiler without requiring runtime overhead.
|
|
47
|
+
|
|
48
|
+
### Enumerations
|
|
49
|
+
|
|
50
|
+
While TypeScript has native enums, they often suffer from type-safety issues and limited runtime introspection. The library provides a set of types to work with both array-based and object-based enumerations defined via the `#/enumeration` module.
|
|
51
|
+
|
|
52
|
+
### GeoJSON Types
|
|
53
|
+
|
|
54
|
+
When working with maps and geospatial data, adhering to the GeoJSON standard is crucial. These types ensure your data structures (`Feature`, `Point`, `Polygon`) match the official specification.
|
|
55
|
+
|
|
56
|
+
### Web Types
|
|
57
|
+
|
|
58
|
+
Provides strict typing for HTML `<input>` and `<textarea>` attributes, including comprehensive unions for `autocomplete`, `inputmode`, and `type`.
|
|
59
|
+
|
|
60
|
+
## 🚀 Basic Usage
|
|
61
|
+
|
|
62
|
+
### Common Utilities
|
|
63
|
+
|
|
64
|
+
Use these utilities to clean up and transform your interfaces.
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import type { Simplify, Writable, Optionalize, OneOrMany } from '@tstdl/base/types';
|
|
68
|
+
|
|
69
|
+
// 1. Simplify: Flattens intersections for better readability
|
|
70
|
+
type Complex = { a: string } & { b: number };
|
|
71
|
+
type Simple = Simplify<Complex>; // { a: string; b: number; }
|
|
72
|
+
|
|
73
|
+
// 2. Writable: Removes 'readonly' modifiers
|
|
74
|
+
const config = { endpoint: 'https://api.com', retries: 3 } as const;
|
|
75
|
+
type MutableConfig = Writable<typeof config>;
|
|
76
|
+
// { endpoint: "https://api.com"; retries: 3; } (mutable)
|
|
77
|
+
|
|
78
|
+
// 3. Optionalize: Converts properties with `undefined` to optional keys `?`
|
|
79
|
+
type RawData = {
|
|
80
|
+
id: string;
|
|
81
|
+
description: string | undefined; // Required key, but value can be undefined
|
|
82
|
+
};
|
|
83
|
+
type CleanData = Optionalize<RawData>;
|
|
84
|
+
// { id: string; description?: string; }
|
|
85
|
+
|
|
86
|
+
// 4. OneOrMany: Handles single items or arrays
|
|
87
|
+
function processItems(items: OneOrMany<string>) {
|
|
88
|
+
const list = Array.isArray(items) ? items : [items];
|
|
89
|
+
// ...
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Tagged Types Usage
|
|
94
|
+
|
|
95
|
+
Create distinct types for different IDs to prevent bugs.
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import type { Tagged } from '@tstdl/base/types';
|
|
99
|
+
|
|
100
|
+
// Define distinct types
|
|
101
|
+
type UserId = Tagged<string, 'UserId'>;
|
|
102
|
+
type OrderId = Tagged<string, 'OrderId'>;
|
|
103
|
+
|
|
104
|
+
function cancelOrder(orderId: OrderId, user: UserId) {
|
|
105
|
+
console.log(`User ${user} cancelled order ${orderId}`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Casting is required to "brand" the primitive
|
|
109
|
+
const myUser = 'user-123' as UserId;
|
|
110
|
+
const myOrder = 'order-abc' as OrderId;
|
|
111
|
+
|
|
112
|
+
cancelOrder(myOrder, myUser); // ✅ OK
|
|
113
|
+
|
|
114
|
+
// cancelOrder(myUser, myOrder);
|
|
115
|
+
// ❌ Error: Argument of type 'UserId' is not assignable to parameter of type 'OrderId'.
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Enumerations Usage
|
|
119
|
+
|
|
120
|
+
Extract types from your enumeration definitions.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import type { EnumerationValue, EnumerationKey } from '@tstdl/base/types';
|
|
124
|
+
|
|
125
|
+
const Colors = {
|
|
126
|
+
Red: 'red',
|
|
127
|
+
Green: 'green',
|
|
128
|
+
Blue: 'blue',
|
|
129
|
+
} as const;
|
|
130
|
+
|
|
131
|
+
type Color = EnumerationValue<typeof Colors>; // 'red' | 'green' | 'blue'
|
|
132
|
+
type ColorKey = EnumerationKey<typeof Colors>; // 'Red' | 'Green' | 'Blue'
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### GeoJSON
|
|
136
|
+
|
|
137
|
+
Type-safe geospatial data structures.
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
import type { Feature, Point } from '@tstdl/base/types';
|
|
141
|
+
|
|
142
|
+
type PlaceProperties = {
|
|
143
|
+
name: string;
|
|
144
|
+
rating: number;
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const cafe: Feature<Point, PlaceProperties> = {
|
|
148
|
+
type: 'Feature',
|
|
149
|
+
geometry: {
|
|
150
|
+
type: 'Point',
|
|
151
|
+
coordinates: [13.405, 52.52], // [lon, lat]
|
|
152
|
+
},
|
|
153
|
+
properties: {
|
|
154
|
+
name: 'Coffee Shop',
|
|
155
|
+
rating: 4.5,
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## 🔧 Advanced Topics
|
|
161
|
+
|
|
162
|
+
### Deep Selection
|
|
163
|
+
|
|
164
|
+
Use `PickDeep` to select a subset of a deeply nested type structure. This is incredibly useful for defining API responses or GraphQL-like selection sets.
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import type { PickDeep } from '@tstdl/base/types';
|
|
168
|
+
|
|
169
|
+
type UserProfile = {
|
|
170
|
+
id: string;
|
|
171
|
+
personal: {
|
|
172
|
+
name: { first: string; last: string };
|
|
173
|
+
age: number;
|
|
174
|
+
};
|
|
175
|
+
settings: {
|
|
176
|
+
theme: 'dark' | 'light';
|
|
177
|
+
notifications: boolean;
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
// Select only the first name and theme
|
|
182
|
+
type UserPreview = PickDeep<
|
|
183
|
+
UserProfile,
|
|
184
|
+
{
|
|
185
|
+
personal: {
|
|
186
|
+
name: { first: true };
|
|
187
|
+
};
|
|
188
|
+
settings: {
|
|
189
|
+
theme: true;
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
>;
|
|
193
|
+
|
|
194
|
+
// Resulting Type:
|
|
195
|
+
// {
|
|
196
|
+
// personal: {
|
|
197
|
+
// name: { first: string };
|
|
198
|
+
// };
|
|
199
|
+
// settings: {
|
|
200
|
+
// theme: 'dark' | 'light';
|
|
201
|
+
// };
|
|
202
|
+
// }
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Type Paths
|
|
206
|
+
|
|
207
|
+
Extract valid dot-notation paths from an object, useful for form libraries or property accessors.
|
|
208
|
+
|
|
209
|
+
```ts
|
|
210
|
+
import type { Path, TypeFromPath } from '@tstdl/base/types';
|
|
211
|
+
|
|
212
|
+
type Config = {
|
|
213
|
+
database: {
|
|
214
|
+
host: string;
|
|
215
|
+
port: number;
|
|
216
|
+
};
|
|
217
|
+
logging: {
|
|
218
|
+
level: string;
|
|
219
|
+
};
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Union of all valid paths
|
|
223
|
+
type ConfigPaths = Path<Config>;
|
|
224
|
+
// "database" | "database.host" | "database.port" | "logging" | "logging.level"
|
|
225
|
+
|
|
226
|
+
// Extract the type at a specific path
|
|
227
|
+
type PortType = TypeFromPath<Config, 'database.port'>; // number
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## 📚 API
|
|
231
|
+
|
|
232
|
+
### General Utility Types
|
|
233
|
+
|
|
234
|
+
| Type | Description |
|
|
235
|
+
| :---------------------- | :---------------------------------------------------------------------------- |
|
|
236
|
+
| `Simplify<T>` | Flattens intersection types into a single object type for better readability. |
|
|
237
|
+
| `SimplifyDeep<T>` | Recursively simplifies types. |
|
|
238
|
+
| `Writable<T>` | Removes `readonly` modifiers from properties. |
|
|
239
|
+
| `DeepWritable<T>` | Recursively removes `readonly` modifiers. |
|
|
240
|
+
| `DeepReadonly<T>` | Recursively adds `readonly` modifiers. |
|
|
241
|
+
| `DeepPartial<T>` | Recursively makes all properties optional. |
|
|
242
|
+
| `DeepNonNullable<T>` | Recursively removes `null` and `undefined`. |
|
|
243
|
+
| `Optionalize<T>` | Converts properties that allow `undefined` into optional keys (`?`). |
|
|
244
|
+
| `OptionalizeDeep<T>` | Recursively optionalizes properties that allow `undefined`. |
|
|
245
|
+
| `OptionalizeNullable<T>`| Converts properties that allow `null` or `undefined` into optional keys (`?`).|
|
|
246
|
+
| `Unoptionalize<T>` | Converts optional keys (`?`) into required keys that allow `undefined`. |
|
|
247
|
+
| `PickBy<T, V>` | Picks properties from `T` whose values are assignable to `V`. |
|
|
248
|
+
| `OmitBy<T, V>` | Omits properties from `T` whose values are assignable to `V`. |
|
|
249
|
+
| `PickDeep<T, S>` | Deeply picks properties based on a selection shape `S`. |
|
|
250
|
+
| `OmitDeep<T, S>` | Deeply omits properties based on a selection shape `S`. |
|
|
251
|
+
| `Merge<T1, T2>` | Merges two types, with `T2` properties overwriting `T1`. |
|
|
252
|
+
| `OneOrMany<T>` | `T | readonly T[]`. |
|
|
253
|
+
| `Path<T>` | Union of dot-notation paths for object `T`. |
|
|
254
|
+
| `TypeFromPath<T, P>` | The type of the property at path `P` within `T`. |
|
|
255
|
+
| `Json` | Represents any valid JSON value. |
|
|
256
|
+
| `Record<K, V>` | Shorthand for `Record<K, V>` with default `K=PropertyKey`. |
|
|
257
|
+
| `Type<T>` | Represents a class constructor. |
|
|
258
|
+
| `AbstractType<T>` | Represents an abstract class constructor. |
|
|
259
|
+
| `ReactiveValue<T>` | `T | Signal<T> | Observable<T>`. |
|
|
260
|
+
| `PascalCase<V>` | Converts a string literal to PascalCase. |
|
|
261
|
+
| `Flatten<T>` | Unwraps a single level of array nesting. |
|
|
262
|
+
| `DeepFlatten<T>` | Recursively unwraps array nesting. |
|
|
263
|
+
| `ArrayItem<T>` | Extracts the item type from an array. |
|
|
264
|
+
| `Entries<T>` | Returns array of `[key, value]` tuples. |
|
|
265
|
+
| `FromEntries<E>` | Reconstructs an object from entries. |
|
|
266
|
+
|
|
267
|
+
### Tagged Types
|
|
268
|
+
|
|
269
|
+
| Type | Description |
|
|
270
|
+
| :----------------------- | :--------------------------------------------------------- |
|
|
271
|
+
| `Tagged<Type, TagName>` | Creates a nominal type by branding `Type` with `TagName`. |
|
|
272
|
+
| `Untagged<T>` | Extracts the underlying primitive type from a tagged type. |
|
|
273
|
+
| `UntaggedDeep<T>` | Recursively extracts underlying primitive types. |
|
|
274
|
+
| `HasTag<T, Token>` | Checks if a type has a specific tag. |
|
|
275
|
+
| `GetTagMetadata<T, Tag>` | Retrieves metadata associated with a tag. |
|
|
276
|
+
|
|
277
|
+
### Enumerations
|
|
278
|
+
|
|
279
|
+
| Type | Description |
|
|
280
|
+
| :-------------------- | :----------------------------------------------------- |
|
|
281
|
+
| `Enumeration` | Union of `EnumerationArray` and `EnumerationObject`. |
|
|
282
|
+
| `EnumerationValue<T>` | The union of all values in an enumeration. |
|
|
283
|
+
| `EnumerationKey<T>` | The union of all keys (keys for objects, indices for arrays). |
|
|
284
|
+
| `EnumerationMap<T>` | Maps keys to their normalized values. |
|
|
285
|
+
| `EnumerationEntry<T>` | Union of `[key, value]` pairs. |
|
|
286
|
+
|
|
287
|
+
### GeoJSON Types
|
|
288
|
+
|
|
289
|
+
| Type | Description |
|
|
290
|
+
| :------------------- | :------------------------------------------------------ |
|
|
291
|
+
| `Position` | `[longitude, latitude, elevation?]` |
|
|
292
|
+
| `Point` | GeoJSON Point geometry. |
|
|
293
|
+
| `LineString` | GeoJSON LineString geometry. |
|
|
294
|
+
| `Polygon` | GeoJSON Polygon geometry. |
|
|
295
|
+
| `MultiPoint` | GeoJSON MultiPoint geometry. |
|
|
296
|
+
| `MultiLineString` | GeoJSON MultiLineString geometry. |
|
|
297
|
+
| `MultiPolygon` | GeoJSON MultiPolygon geometry. |
|
|
298
|
+
| `Geometry` | Union of all geometry types. |
|
|
299
|
+
| `GeometryCollection` | A collection of geometries. |
|
|
300
|
+
| `Feature<G, P>` | A GeoJSON Feature with geometry `G` and properties `P`. |
|
|
301
|
+
| `FeatureCollection` | A collection of Features. |
|
|
302
|
+
|
|
303
|
+
### Web Types
|
|
304
|
+
|
|
305
|
+
| Type | Description |
|
|
306
|
+
| :------------------- | :----------------------------------------- |
|
|
307
|
+
| `InputType` | Union of valid HTML `<input>` type values. |
|
|
308
|
+
| `InputMode` | Union of valid HTML `inputmode` values. |
|
|
309
|
+
| `InputAutocomplete` | Union of valid HTML `autocomplete` values. |
|
|
310
|
+
| `InputAttributes` | Interface for HTML input attributes. |
|
|
311
|
+
| `TextAreaAttributes` | Interface for HTML textarea attributes. |
|