@tstdl/base 0.93.138 → 0.93.140

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 (138) hide show
  1. package/README.md +166 -0
  2. package/ai/genkit/multi-region.plugin.js +5 -3
  3. package/ai/genkit/tests/multi-region.test.d.ts +1 -0
  4. package/ai/genkit/tests/multi-region.test.js +5 -2
  5. package/ai/parser/parser.js +2 -2
  6. package/ai/prompts/build.js +1 -0
  7. package/ai/prompts/instructions-formatter.d.ts +15 -2
  8. package/ai/prompts/instructions-formatter.js +36 -31
  9. package/ai/prompts/prompt-builder.js +5 -5
  10. package/ai/prompts/steering.d.ts +3 -2
  11. package/ai/prompts/steering.js +3 -1
  12. package/ai/tests/instructions-formatter.test.js +1 -0
  13. package/api/README.md +403 -0
  14. package/api/client/client.js +7 -13
  15. package/api/client/tests/api-client.test.js +10 -10
  16. package/api/default-error-handlers.js +1 -1
  17. package/api/response.d.ts +2 -2
  18. package/api/response.js +22 -33
  19. package/api/server/api-controller.d.ts +1 -1
  20. package/api/server/api-controller.js +3 -3
  21. package/api/server/api-request-token.provider.d.ts +1 -0
  22. package/api/server/api-request-token.provider.js +1 -0
  23. package/api/server/middlewares/allowed-methods.middleware.js +2 -1
  24. package/api/server/middlewares/content-type.middleware.js +2 -1
  25. package/api/types.d.ts +3 -2
  26. package/application/README.md +240 -0
  27. package/application/application.js +2 -2
  28. package/audit/README.md +267 -0
  29. package/authentication/README.md +288 -0
  30. package/authentication/client/authentication.service.d.ts +12 -11
  31. package/authentication/client/authentication.service.js +21 -21
  32. package/authentication/client/http-client.middleware.js +2 -2
  33. package/authentication/tests/authentication.client-error-handling.test.js +2 -1
  34. package/authentication/tests/authentication.client-service-refresh.test.js +5 -3
  35. package/browser/README.md +401 -0
  36. package/cancellation/README.md +156 -0
  37. package/cancellation/tests/coverage.test.d.ts +1 -0
  38. package/cancellation/tests/coverage.test.js +49 -0
  39. package/cancellation/tests/leak.test.d.ts +1 -0
  40. package/cancellation/tests/leak.test.js +35 -0
  41. package/cancellation/tests/token.test.d.ts +1 -0
  42. package/cancellation/tests/token.test.js +136 -0
  43. package/cancellation/token.d.ts +53 -177
  44. package/cancellation/token.js +132 -201
  45. package/context/README.md +174 -0
  46. package/cookie/README.md +161 -0
  47. package/css/README.md +157 -0
  48. package/data-structures/README.md +320 -0
  49. package/decorators/README.md +140 -0
  50. package/distributed-loop/README.md +231 -0
  51. package/distributed-loop/distributed-loop.js +1 -1
  52. package/document-management/README.md +403 -0
  53. package/document-management/server/services/document-management.service.js +9 -7
  54. package/document-management/tests/document-management-core.test.js +2 -7
  55. package/document-management/tests/document-management.api.test.js +6 -7
  56. package/document-management/tests/document-statistics.service.test.js +11 -12
  57. package/document-management/tests/document.service.test.js +3 -3
  58. package/document-management/tests/enum-helpers.test.js +2 -3
  59. package/dom/README.md +213 -0
  60. package/enumerable/README.md +259 -0
  61. package/enumeration/README.md +121 -0
  62. package/errors/README.md +267 -0
  63. package/file/README.md +191 -0
  64. package/formats/README.md +210 -0
  65. package/function/README.md +144 -0
  66. package/http/README.md +318 -0
  67. package/http/client/adapters/undici.adapter.js +1 -1
  68. package/http/client/http-client-request.d.ts +6 -5
  69. package/http/client/http-client-request.js +8 -9
  70. package/http/server/node/node-http-server.js +1 -2
  71. package/image-service/README.md +137 -0
  72. package/injector/README.md +491 -0
  73. package/injector/injector.d.ts +1 -0
  74. package/injector/injector.js +17 -5
  75. package/injector/tests/leak.test.d.ts +1 -0
  76. package/injector/tests/leak.test.js +45 -0
  77. package/intl/README.md +113 -0
  78. package/json-path/README.md +182 -0
  79. package/jsx/README.md +154 -0
  80. package/key-value-store/README.md +191 -0
  81. package/lock/README.md +249 -0
  82. package/lock/web/web-lock.js +119 -47
  83. package/logger/README.md +287 -0
  84. package/mail/README.md +256 -0
  85. package/memory/README.md +144 -0
  86. package/message-bus/README.md +244 -0
  87. package/message-bus/message-bus-base.js +1 -1
  88. package/module/README.md +182 -0
  89. package/module/module.d.ts +1 -1
  90. package/module/module.js +77 -17
  91. package/module/modules/web-server.module.js +1 -1
  92. package/notification/tests/notification-type.service.test.js +24 -15
  93. package/object-storage/README.md +300 -0
  94. package/openid-connect/README.md +274 -0
  95. package/orm/README.md +423 -0
  96. package/package.json +8 -6
  97. package/password/README.md +164 -0
  98. package/pdf/README.md +246 -0
  99. package/polyfills.js +1 -0
  100. package/pool/README.md +198 -0
  101. package/process/README.md +237 -0
  102. package/promise/README.md +252 -0
  103. package/promise/cancelable-promise.js +1 -1
  104. package/random/README.md +193 -0
  105. package/reflection/README.md +305 -0
  106. package/rpc/README.md +386 -0
  107. package/rxjs-utils/README.md +262 -0
  108. package/schema/README.md +342 -0
  109. package/serializer/README.md +342 -0
  110. package/signals/implementation/README.md +134 -0
  111. package/sse/README.md +278 -0
  112. package/task-queue/README.md +300 -0
  113. package/task-queue/postgres/task-queue.d.ts +2 -1
  114. package/task-queue/postgres/task-queue.js +32 -2
  115. package/task-queue/task-context.js +1 -1
  116. package/task-queue/task-queue.d.ts +17 -0
  117. package/task-queue/task-queue.js +103 -44
  118. package/task-queue/tests/complex.test.js +4 -4
  119. package/task-queue/tests/dependencies.test.js +4 -2
  120. package/task-queue/tests/queue.test.js +111 -0
  121. package/task-queue/tests/worker.test.js +21 -13
  122. package/templates/README.md +287 -0
  123. package/testing/README.md +157 -0
  124. package/text/README.md +346 -0
  125. package/threading/README.md +238 -0
  126. package/types/README.md +311 -0
  127. package/utils/README.md +322 -0
  128. package/utils/async-iterable-helpers/observable-iterable.d.ts +1 -1
  129. package/utils/async-iterable-helpers/observable-iterable.js +4 -8
  130. package/utils/async-iterable-helpers/take-until.js +4 -4
  131. package/utils/backoff.js +89 -30
  132. package/utils/retry-with-backoff.js +1 -1
  133. package/utils/timer.d.ts +1 -1
  134. package/utils/timer.js +5 -7
  135. package/utils/timing.d.ts +1 -1
  136. package/utils/timing.js +2 -4
  137. package/utils/z-base32.d.ts +1 -0
  138. package/utils/z-base32.js +1 -0
@@ -0,0 +1,262 @@
1
+ # rxjs-utils
2
+
3
+ A collection of custom RxJS operators, Observable creators, and utilities designed to enhance reactive programming workflows. This module provides tools for type safety, advanced retry strategies, timing and scheduling, progressive data emission, and integration with reactive signals.
4
+
5
+ ## Table of Contents
6
+
7
+ - [✨ Features](#-features)
8
+ - [Core Concepts](#core-concepts)
9
+ - [🚀 Basic Usage](#-basic-usage)
10
+ - [Type Casting](#type-casting)
11
+ - [Retry with Backoff](#retry-with-backoff)
12
+ - [Timing Observables](#timing-observables)
13
+ - [🔧 Advanced Topics](#-advanced-topics)
14
+ - [Progressive Array Emission](#progressive-array-emission)
15
+ - [Lifecycle Teardown](#lifecycle-teardown)
16
+ - [Signal Integration](#signal-integration)
17
+ - [📚 API](#-api)
18
+
19
+ ## ✨ Features
20
+
21
+ - **Type Safety Operators**: Explicitly cast observable types for better TypeScript inference.
22
+ - **Retry Strategies**: Robust `retryBackoff` operators supporting exponential backoff and custom handling logic.
23
+ - **Timing Sources**: Observables wrapping `requestAnimationFrame`, `requestIdleCallback`, `setImmediate`, and `process.nextTick`.
24
+ - **Progressive Loading**: `slowArray` operators to emit array chunks over time (useful for rendering large lists).
25
+ - **Lifecycle Hooks**: `teardown` operator to access the last emitted value or error when a subscription ends.
26
+ - **Signal Integration**: `untrack` operator to prevent RxJS subscriptions from tracking dependencies within Signal effects.
27
+
28
+ ## Core Concepts
29
+
30
+ ### Robust Retries
31
+
32
+ Standard RxJS `retry` is often too aggressive (immediate retry). `retryBackoff` implements delays (constant, linear, or exponential) between retries to prevent overwhelming failing services.
33
+
34
+ ### Scheduling & Timing
35
+
36
+ Instead of using `interval` or `timer` for everything, this module provides specific observables for the browser's render loop (`animationFrame$`), idle periods (`idle$`), and Node.js event loop phases (`nextTick$`, `immediate$`).
37
+
38
+ ### Progressive Data
39
+
40
+ When dealing with large datasets in a UI, emitting the entire array at once can freeze the interface. `slowArray` allows you to emit an initial chunk and then progressively add more items, smoothing out the rendering process.
41
+
42
+ ## 🚀 Basic Usage
43
+
44
+ ### Type Casting
45
+
46
+ Use `cast` to assert a more specific type for an Observable, or `forceCast` to cast from `unknown`.
47
+
48
+ ```ts
49
+ import { cast, forceCast } from '@tstdl/base/rxjs-utils';
50
+ import { of } from 'rxjs';
51
+
52
+ interface User {
53
+ id: string;
54
+ name: string;
55
+ }
56
+ interface Admin extends User {
57
+ permissions: string[];
58
+ }
59
+
60
+ const user$ = of({ id: '1', name: 'Alice', permissions: ['root'] } as User);
61
+ const admin$ = of({ id: '1', name: 'Alice', permissions: ['root'] } as Admin);
62
+
63
+ // Safe upcast: Admin to User (Admin extends User)
64
+ const userFromAdmin$ = admin$.pipe(cast<Admin, User>());
65
+
66
+ // Force cast: unknown to User
67
+ const unknown$ = of<unknown>({ id: '2', name: 'Bob' });
68
+ const forcedUser$ = unknown$.pipe(forceCast<User>());
69
+ ```
70
+
71
+ ### Retry with Backoff
72
+
73
+ Handle temporary failures with exponential backoff.
74
+
75
+ ```ts
76
+ import { retryBackoff } from '@tstdl/base/rxjs-utils';
77
+ import { HttpClient } from '@tstdl/base/http/client'; // Example http client
78
+ import { inject } from '@tstdl/base/injector';
79
+
80
+ const http = inject(HttpClient);
81
+
82
+ http
83
+ .get('https://api.example.com/data')
84
+ .pipe(
85
+ // Retry up to 3 times
86
+ // Initial delay 500ms, increasing exponentially
87
+ retryBackoff(3, {
88
+ strategy: 'exponential',
89
+ initialDelay: 500,
90
+ maximumDelay: 5000,
91
+ }),
92
+ )
93
+ .subscribe({
94
+ next: (response) => console.log('Success:', response),
95
+ error: (err) => console.error('Failed after retries:', err),
96
+ });
97
+ ```
98
+
99
+ ### Timing Observables
100
+
101
+ Use specific schedulers for performance-critical tasks.
102
+
103
+ ```ts
104
+ import { animationFrame$, idle$ } from '@tstdl/base/rxjs-utils';
105
+
106
+ // Run logic on every animation frame (recursive)
107
+ const renderLoop$ = animationFrame$.subscribe(() => {
108
+ // Update canvas or DOM
109
+ });
110
+
111
+ // Run logic only when the browser is idle
112
+ const backgroundTask$ = idle$.subscribe((deadline) => {
113
+ console.log('Browser is idle, time remaining:', deadline.timeRemaining());
114
+ });
115
+ ```
116
+
117
+ ## 🔧 Advanced Topics
118
+
119
+ ### Progressive Array Emission
120
+
121
+ Use `slowArray` to emit a large array in chunks. This is useful for "infinite scroll" behavior or rendering large lists without blocking the main thread.
122
+
123
+ ```ts
124
+ import { slowArray } from '@tstdl/base/rxjs-utils';
125
+
126
+ const largeData = Array.from({ length: 1000 }, (_, i) => i);
127
+
128
+ slowArray(largeData, {
129
+ delay: 0, // Start immediately
130
+ initialSize: 20, // Emit first 20 items immediately
131
+ interval: 50, // Add more items every 50ms
132
+ size: 10, // Add 10 items per interval
133
+ }).subscribe((currentArray) => {
134
+ // currentArray grows: [0..19] -> [0..29] -> [0..39] ...
135
+ console.log(`Rendered ${currentArray.length} items`);
136
+ });
137
+ ```
138
+
139
+ To handle a stream of incoming arrays (e.g., from a search result that updates), use the `persistentSlowArray` operator. It maintains the current "chunk size" even when the underlying source array changes.
140
+
141
+ ```ts
142
+ import { persistentSlowArray } from '@tstdl/base/rxjs-utils';
143
+ import { fromEvent, map, debounceTime } from 'rxjs';
144
+
145
+ // Imagine a search input emitting new results
146
+ const searchResults$ = fromEvent(input, 'input').pipe(
147
+ debounceTime(300),
148
+ switchMap(q => fetchResults(q)), // returns Observable<Item[]>
149
+ persistentSlowArray({
150
+ interval: 100,
151
+ size: 5,
152
+ initialSize: 10
153
+ })
154
+ );
155
+ ```
156
+
157
+ ### Lazy Initial Values
158
+
159
+ Use `startWithProvider` when you need to emit an initial value that must be calculated at the exact moment of subscription (e.g., a timestamp or a value from another service).
160
+
161
+ ```ts
162
+ import { startWithProvider } from '@tstdl/base/rxjs-utils';
163
+ import { of } from 'rxjs';
164
+
165
+ const source$ = of('event 1', 'event 2').pipe(
166
+ startWithProvider(() => `Started at ${new Date().toISOString()}`)
167
+ );
168
+ ```
169
+
170
+ ### Lifecycle Teardown
171
+
172
+ The `teardown` operator allows you to execute logic when the stream ends (completes, errors, or unsubscribes), with access to the last emitted value and the error (if any).
173
+
174
+ ```ts
175
+ import { teardown } from '@tstdl/base/rxjs-utils';
176
+ import { interval } from 'rxjs';
177
+
178
+ const sub = interval(1000)
179
+ .pipe(
180
+ teardown((lastValue, error) => {
181
+ if (error) {
182
+ console.error('Stream crashed at:', lastValue, error);
183
+ } else {
184
+ console.log('Stream cleaned up. Last value was:', lastValue);
185
+ }
186
+ }),
187
+ )
188
+ .subscribe();
189
+
190
+ setTimeout(() => sub.unsubscribe(), 2500);
191
+ // Output after 2.5s: "Stream cleaned up. Last value was: 1"
192
+ ```
193
+
194
+ ### Signal Integration
195
+
196
+ When using RxJS inside a reactive context (like `@tstdl/base/signals` effects), subscriptions might accidentally become dependencies. `untrack` wraps the subscription callbacks to prevent this.
197
+
198
+ ```ts
199
+ import { untrack } from '@tstdl/base/rxjs-utils';
200
+ import { effect } from '@tstdl/base/signals';
201
+ import { interval } from 'rxjs';
202
+
203
+ effect(() => {
204
+ // This subscription will NOT cause the effect to re-run
205
+ // when the observable emits, because the subscriber logic is untracked.
206
+ const sub = interval(1000)
207
+ .pipe(untrack())
208
+ .subscribe((val) => {
209
+ console.log(val);
210
+ });
211
+
212
+ return () => sub.unsubscribe();
213
+ });
214
+ ```
215
+
216
+ ## 📚 API
217
+
218
+ ### Operators
219
+
220
+ | Function | Description |
221
+ | :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------- |
222
+ | `cast<Input, Output>()` | Casts an Observable from `Input` type to `Output` type (checked). |
223
+ | `forceCast<Output>()` | Casts an Observable from `unknown` to `Output` type. |
224
+ | `noopOperator<T>()` | An operator that does nothing and passes values through unchanged. |
225
+ | `rejectErrors<T>()` | Suppresses errors from the source observable (stops emission on error without notifying downstream). |
226
+ | `retryBackoff<T>(count, options)` | Retries the source observable on error with a specified backoff strategy. |
227
+ | `retryBackoffHandled<T>(count, options, handler)` | Similar to `retryBackoff`, but allows a custom handler function to determine behavior or side effects on retry. |
228
+ | `persistentSlowArray<T>(options)` | Operator version of `slowArray`. Emits growing arrays from a source array emission. |
229
+ | `startWithProvider<T, D>(provider)` | Like `startWith`, but accepts a function to lazily generate the initial value. |
230
+ | `teardown<T>(fn)` | Registers a callback to run on finalization, receiving the last value and error. |
231
+ | `untrack<T>()` | Wraps subscription handlers in `untracked()` to prevent signal dependency tracking. |
232
+
233
+ ### Observable Creators
234
+
235
+ | Function | Description |
236
+ | :----------------------------- | :------------------------------------------------------------------------------- |
237
+ | `noop<T>(source)` | Returns the source observable as is. |
238
+ | `slowArray<T>(array, options)` | Creates an observable that emits the provided array in growing chunks over time. |
239
+ | `singleIdle$` | Emits once when the browser is idle (via `requestIdleCallback`). |
240
+ | `idle$` | Emits repeatedly when the browser is idle. |
241
+ | `singleAnimationFrame$` | Emits once on the next animation frame. |
242
+ | `animationFrame$` | Emits repeatedly on every animation frame. |
243
+ | `singleImmediate$` | Emits once via `setImmediate` (Node.js/Polyfill). |
244
+ | `immediate$` | Emits repeatedly via `setImmediate`. |
245
+ | `microtask$` | Emits once via `queueMicrotask`. |
246
+ | `singleNextTick$` | Emits once via `process.nextTick`. |
247
+ | `nextTick$` | Emits repeatedly via `process.nextTick`. |
248
+
249
+ ### Types
250
+
251
+ | Type | Description |
252
+ | :----------------- | :------------------------------------------------------------------------------------------------------------ |
253
+ | `SlowArrayOptions` | Configuration for `slowArray` (`delay`, `initialSize`, `interval`, `size`). |
254
+ | `BackoffOptions` | Configuration for retry backoff (`strategy`, `initialDelay`, `maximumDelay`, `increase`, `jitter`). |
255
+ | `BackoffStrategy` | Either `'linear'` or `'exponential'`. |
256
+ | `IdleDeadline` | The object passed to `idle$` subscribers, containing `timeRemaining()` and `didTimeout`. (native JS type) |
257
+
258
+ ## 🏁 Platform Compatibility
259
+
260
+ - **Browser**: Full support for all operators and observables, including `animationFrame$` and `idle$`.
261
+ - **Node.js**: Full support, though `animationFrame$` and `idle$` require polyfills if used. `nextTick$` and `immediate$` are native to Node.js.
262
+ - **Workers**: Support varies depending on the availability of `requestAnimationFrame` and `requestIdleCallback`.
@@ -0,0 +1,342 @@
1
+ # @tstdl/base/schema
2
+
3
+ A powerful, TypeScript-first schema declaration and validation library. Define data structures once using builder functions or class decorators and get static types, runtime validation, and OpenAPI specifications for free.
4
+
5
+ ## Table of Contents
6
+
7
+ - [✨ Features](#-features)
8
+ - [Core Concepts](#core-concepts)
9
+ - [Builder Functions](#builder-functions)
10
+ - [Class Decorators](#class-decorators)
11
+ - [🚀 Basic Usage](#-basic-usage)
12
+ - [🔧 Advanced Topics](#-advanced-topics)
13
+ - [Class-based Schemas](#class-based-schemas)
14
+ - [Type Coercion](#type-coercion)
15
+ - [Object Utilities](#object-utilities)
16
+ - [Recursive Schemas](#recursive-schemas)
17
+ - [OpenAPI Generation](#openapi-generation)
18
+ - [Function & Method Schemas](#function--method-schemas)
19
+ - [📚 API](#-api)
20
+
21
+ ## ✨ Features
22
+
23
+ - **Type Safety**: Automatically infers TypeScript types directly from your schemas.
24
+ - **Dual API**: Define schemas using functional builders or class decorators.
25
+ - **Runtime Validation**: Robust validation for API payloads, configuration, and user input.
26
+ - **Type Coercion**: Automatically convert input data (e.g., strings to numbers) during parsing.
27
+ - **Detailed Error Reporting**: JSON-path based error reporting to pinpoint exactly where validation failed.
28
+ - **OpenAPI Support**: Generate OpenAPI v3 schema definitions from your code.
29
+ - **Reflection**: Leverages TypeScript metadata to infer schemas from class properties.
30
+ - **Extensible**: Supports custom transformations and complex types like `Uint8Array` and `ReadableStream`.
31
+
32
+ ## Core Concepts
33
+
34
+ The library provides two primary ways to define schemas. Both produce a `Schema` object that can be used for validation.
35
+
36
+ ### Builder Functions
37
+
38
+ Ideal for defining data shapes on the fly, for API contracts, or when you don't need a class instance.
39
+
40
+ ```typescript
41
+ import { object, string, number } from '@tstdl/base/schema';
42
+
43
+ const userSchema = object({
44
+ name: string(),
45
+ age: number(),
46
+ });
47
+ ```
48
+
49
+ ### Class Decorators
50
+
51
+ Ideal for domain models where you want the class to serve as both the type definition and the validation schema. This requires `experimentalDecorators` and `emitDecoratorMetadata` in your `tsconfig.json`.
52
+
53
+ ```typescript
54
+ import { Class, StringProperty, NumberProperty } from '@tstdl/base/schema';
55
+
56
+ @Class()
57
+ class User {
58
+ @StringProperty()
59
+ name: string;
60
+
61
+ @NumberProperty()
62
+ age: number;
63
+ }
64
+ ```
65
+
66
+ ## 🚀 Basic Usage
67
+
68
+ The `Schema` class provides static methods to validate and parse data.
69
+
70
+ ```typescript
71
+ import { Schema, object, string, number, array, optional, SchemaError } from '@tstdl/base/schema';
72
+
73
+ // 1. Define a schema
74
+ const productSchema = object({
75
+ id: string(),
76
+ name: string(),
77
+ price: number({ minimum: 0 }),
78
+ tags: array(string()),
79
+ description: optional(string()),
80
+ });
81
+
82
+ // 2. Infer the TypeScript type (optional, but useful)
83
+ type Product = Schema.Output<typeof productSchema>;
84
+
85
+ // 3. Validate data
86
+ const rawData = {
87
+ id: 'prod_123',
88
+ name: 'Super Widget',
89
+ price: 29.99,
90
+ tags: ['gadget', 'new'],
91
+ };
92
+
93
+ try {
94
+ // .parse() returns the typed value if valid, or throws SchemaError
95
+ const product = Schema.parse(productSchema, rawData);
96
+ console.log(`Validated product: ${product.name}`);
97
+ } catch (error) {
98
+ if (error instanceof SchemaError) {
99
+ console.error('Validation failed:', error.message);
100
+ }
101
+ }
102
+
103
+ // .validate() returns a boolean
104
+ const isValid = Schema.validate(productSchema, { id: 123 }); // false
105
+ ```
106
+
107
+ ## 🔧 Advanced Topics
108
+
109
+ ### Class-based Schemas
110
+
111
+ You can use decorators to define schemas directly on your classes. The class constructor itself becomes a valid schema object.
112
+
113
+ ```typescript
114
+ import { Schema, Class, StringProperty, NumberProperty, Array, Integer } from '@tstdl/base/schema';
115
+
116
+ @Class()
117
+ class User {
118
+ @StringProperty()
119
+ id: string;
120
+
121
+ @StringProperty()
122
+ username: string;
123
+
124
+ @Integer({ minimum: 18 })
125
+ age: number;
126
+
127
+ @Array(String)
128
+ roles: string[];
129
+ }
130
+
131
+ const input = {
132
+ id: 'u1',
133
+ username: 'admin',
134
+ age: 25,
135
+ roles: ['admin', 'editor'],
136
+ };
137
+
138
+ // Pass the Class constructor to Schema methods
139
+ const user = Schema.parse(User, input);
140
+
141
+ console.log(user instanceof User); // true
142
+ console.log(user.username); // 'admin'
143
+ ```
144
+
145
+ ### Type Coercion
146
+
147
+ When handling data from sources like query strings or form data, types are often strings. Enable `coerce` to automatically convert them.
148
+
149
+ ```typescript
150
+ import { Schema, object, number, boolean, date } from '@tstdl/base/schema';
151
+
152
+ const querySchema = object({
153
+ page: number({ integer: true }),
154
+ active: boolean(),
155
+ from: date(),
156
+ });
157
+
158
+ const rawQuery = {
159
+ page: '5',
160
+ active: 'true',
161
+ from: '2023-10-27',
162
+ };
163
+
164
+ // Enable coercion in the options
165
+ const parsed = Schema.parse(querySchema, rawQuery, { coerce: true });
166
+
167
+ console.log(typeof parsed.page); // 'number'
168
+ console.log(typeof parsed.active); // 'boolean'
169
+ console.log(parsed.from instanceof Date); // true
170
+ ```
171
+
172
+ ### Object Utilities
173
+
174
+ Compose new schemas from existing ones using utilities similar to TypeScript's utility types.
175
+
176
+ ```typescript
177
+ import { object, string, number, pick, omit, partial, assign } from '@tstdl/base/schema';
178
+
179
+ const baseUser = object({
180
+ id: string(),
181
+ name: string(),
182
+ email: string(),
183
+ age: number(),
184
+ });
185
+
186
+ // Pick specific fields
187
+ const userSummary = pick(baseUser, ['id', 'name']);
188
+
189
+ // Omit sensitive fields
190
+ const publicUser = omit(baseUser, ['email']);
191
+
192
+ // Make all fields optional (e.g., for patch updates)
193
+ const patchUser = partial(baseUser);
194
+
195
+ // Merge schemas
196
+ const timestampedUser = assign(
197
+ baseUser,
198
+ object({
199
+ createdAt: number(),
200
+ updatedAt: number(),
201
+ }),
202
+ );
203
+ ```
204
+
205
+ ### Recursive Schemas
206
+
207
+ Use `deferred` to define schemas that reference themselves, useful for tree structures.
208
+
209
+ ```typescript
210
+ import { Schema, object, string, array, optional, deferred } from '@tstdl/base/schema';
211
+
212
+ type Category = {
213
+ name: string;
214
+ children?: Category[];
215
+ };
216
+
217
+ const categorySchema = object({
218
+ name: string(),
219
+ children: optional(array(deferred(() => categorySchema))),
220
+ });
221
+
222
+ const tree = {
223
+ name: 'Root',
224
+ children: [{ name: 'Child A' }, { name: 'Child B', children: [{ name: 'Grandchild B.1' }] }],
225
+ };
226
+
227
+ const validTree = Schema.parse(categorySchema, tree);
228
+ ```
229
+
230
+ ### OpenAPI Generation
231
+
232
+ Convert your schemas into OpenAPI v3 compatible JSON schema objects. This is perfect for generating API documentation automatically.
233
+
234
+ ```typescript
235
+ import { object, string, integer, enumeration } from '@tstdl/base/schema';
236
+ import { convertToOpenApiSchema } from '@tstdl/base/schema/converters';
237
+
238
+ enum Status {
239
+ Active = 'active',
240
+ Inactive = 'inactive',
241
+ }
242
+
243
+ const apiResponseSchema = object({
244
+ id: string({ description: 'Unique identifier' }),
245
+ count: integer({ minimum: 0 }),
246
+ status: enumeration(Status),
247
+ });
248
+
249
+ const openApiSpec = convertToOpenApiSchema(apiResponseSchema);
250
+ console.log(JSON.stringify(openApiSpec, null, 2));
251
+ ```
252
+
253
+ ### Function & Method Schemas
254
+
255
+ You can define schemas for functions and class methods, validating both arguments and return values.
256
+
257
+ ```typescript
258
+ import { Method, StringProperty, Integer } from '@tstdl/base/schema';
259
+
260
+ class Calculator {
261
+ @Method([Integer(), Integer()], Integer())
262
+ add(a: number, b: number): number {
263
+ return a + b;
264
+ }
265
+ }
266
+ ```
267
+
268
+ ## 📚 API
269
+
270
+ ### Static Methods
271
+
272
+ | Method | Description |
273
+ | :----------------------------------------- | :---------------------------------------------------------------------------------- |
274
+ | `Schema.parse(schema, value, options?)` | Validates and returns the typed value. Throws `SchemaError` on failure. |
275
+ | `Schema.validate(schema, value, options?)` | Returns `true` if valid, `false` otherwise. |
276
+ | `Schema.assert(schema, value, options?)` | Asserts that `value` matches the schema (TypeScript type guard). Throws on failure. |
277
+ | `Schema.test(schema, value, options?)` | Returns a result object `{ valid: boolean, value?: T, error?: SchemaError }`. |
278
+
279
+ ### Schema Builders
280
+
281
+ | Function | Description |
282
+ | :------------------------ | :---------------------------------------------------------- |
283
+ | `string(options?)` | Schema for strings. Supports regex pattern, min/max length. |
284
+ | `number(options?)` | Schema for numbers. Supports min/max. |
285
+ | `integer(options?)` | Schema for integers. |
286
+ | `boolean(options?)` | Schema for booleans. |
287
+ | `date(options?)` | Schema for `Date` objects. |
288
+ | `bigint(options?)` | Schema for `bigint` values. |
289
+ | `symbol(options?)` | Schema for `symbol` values. |
290
+ | `regexp(options?)` | Schema for `RegExp` objects. |
291
+ | `object(props, options?)` | Schema for objects with defined properties. |
292
+ | `record(key, value)` | Schema for objects/dictionaries with arbitrary keys. |
293
+ | `array(item, options?)` | Schema for arrays. |
294
+ | `uint8Array(options?)` | Schema for `Uint8Array`. Supports base64/hex coercion. |
295
+ | `readableStream()` | Schema for `ReadableStream`. |
296
+ | `enumeration(enum)` | Schema for TypeScript enums or array of values. |
297
+ | `literal(value)` | Schema for exact primitive values. |
298
+ | `union(...schemas)` | Schema matching any one of the provided schemas. |
299
+ | `instance(Class)` | Schema checking `instanceof`. |
300
+ | `any()` | Allows any value (use carefully). |
301
+ | `unknown()` | Allows any value but types it as `unknown`. |
302
+ | `never()` | Allows no values. |
303
+ | `func(...)` | Schema for functions. |
304
+
305
+ ### Modifiers & Utilities
306
+
307
+ | Function | Description |
308
+ | :----------------------- | :--------------------------------------------------- |
309
+ | `optional(schema)` | Allows `undefined`. |
310
+ | `nullable(schema)` | Allows `null`. |
311
+ | `defaulted(schema, val)` | Provides a default value if input is null/undefined. |
312
+ | `oneOrMany(schema)` | Accepts a single item or an array of items. |
313
+ | `deferred(() => schema)` | Defers schema resolution (for recursion). |
314
+ | `transform(schema, fn)` | Transforms the value after validation. |
315
+ | `pick(schema, keys)` | Creates a new object schema with picked keys. |
316
+ | `omit(schema, keys)` | Creates a new object schema without specified keys. |
317
+ | `partial(schema)` | Makes all object properties optional. |
318
+ | `assign(...schemas)` | Merges multiple object schemas. |
319
+
320
+ ### Decorators
321
+
322
+ | Decorator | Description |
323
+ | :------------------- | :--------------------------------------------------- |
324
+ | `@Class(options?)` | Marks a class as a schema source. |
325
+ | `@Property(schema?)` | Defines a property schema. |
326
+ | `@StringProperty()` | Shortcut for `string()`. |
327
+ | `@NumberProperty()` | Shortcut for `number()`. |
328
+ | `@Integer()` | Shortcut for `integer()`. |
329
+ | `@BooleanProperty()` | Shortcut for `boolean()`. |
330
+ | `@DateProperty()` | Shortcut for `date()`. |
331
+ | `@Array(schema)` | Shortcut for `array()`. |
332
+ | `@Optional(schema?)` | Marks property as optional. |
333
+ | `@Nullable(schema?)` | Marks property as nullable. |
334
+ | `@Enumeration(enum)` | Shortcut for `enumeration()`. |
335
+ | `@Method(...)` | Defines schema for method arguments and return type. |
336
+ | `@Parameter(name)` | Defines schema/name for a parameter. |
337
+
338
+ ### Converters
339
+
340
+ | Function | Description |
341
+ | :------------------------------- | :------------------------------------------------ |
342
+ | `convertToOpenApiSchema(schema)` | Converts a schema to an OpenAPI v3 schema object. |