@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,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. |
@@ -0,0 +1,322 @@
1
+ # @tstdl/base/utils
2
+
3
+ A comprehensive, modular, and tree-shakeable utility library for TypeScript, providing a rich set of tools for common programming tasks. It features extensive support for asynchronous iterables, object manipulation, cryptography, streams, and robust type safety.
4
+
5
+ ## Table of Contents
6
+
7
+ - [✨ Features](#-features)
8
+ - [Core Concepts](#core-concepts)
9
+ - [🚀 Basic Usage](#-basic-usage)
10
+ - [🔧 Advanced Topics](#-advanced-topics)
11
+ - [Async Iterable Pipelines](#async-iterable-pipelines)
12
+ - [Parallel Processing](#parallel-processing)
13
+ - [Deep Object Merging & Decycling](#deep-object-merging--decycling)
14
+ - [Resilient Operations (Backoff & Retry)](#resilient-operations-backoff--retry)
15
+ - [Cryptography Wrappers](#cryptography-wrappers)
16
+ - [Stream Utilities](#stream-utilities)
17
+ - [📚 API](#-api)
18
+
19
+ ## ✨ Features
20
+
21
+ - **Async Iterable Helpers**: A complete suite of functional operators (`map`, `filter`, `reduce`, `batch`, etc.) for `AsyncIterable`, enabling powerful streaming data pipelines.
22
+ - **Parallel Processing**: Utilities to process async iterables concurrently (`parallelMap`, `parallelForEach`).
23
+ - **Object Manipulation**: Advanced helpers for deep merging, circular reference handling (`decycle`/`recycle`), and type-safe property path access.
24
+ - **Cryptography**: Simplified, promise-based wrappers around the Web Crypto API for encryption, hashing, and signing.
25
+ - **Resilience Patterns**: Built-in `backoffLoop` and `retryAsync` for handling unstable operations with exponential backoff and jitter.
26
+ - **Stream Utilities**: Tools to convert between Streams, Iterables, and Buffers, including `readBinaryStream` and `toBytesStream`.
27
+ - **Type Safety**: Extensive collection of type guards (`isString`, `isDefined`) and assertion functions (`assertDefinedPass`) to narrow types at runtime.
28
+ - **Zero Dependencies**: Lightweight and self-contained.
29
+
30
+ ## Core Concepts
31
+
32
+ ### Iterable-First Design
33
+
34
+ The library prioritizes `Iterable` and `AsyncIterable` interfaces. This allows for memory-efficient, lazy evaluation of data sequences. Instead of loading large datasets into arrays, you can process them item-by-item as they flow through a pipeline.
35
+
36
+ ### Tree-Shakeability
37
+
38
+ Every utility is exported in a way that allows modern bundlers to strip out unused code. You can import everything from the root `@tstdl/base/utils`, and only what you use will end up in your production build.
39
+
40
+ ### Type Guards & Assertions
41
+
42
+ We provide pairs of functions for type checking:
43
+
44
+ - **Guards** (`isString`): Return a boolean and narrow the type in TypeScript.
45
+ - **Assertions** (`assertString`): Throw an `AssertionError` if the check fails, asserting the type.
46
+ - **Pass-through Assertions** (`assertStringPass`): Assert the type and return the value, allowing for inline checks.
47
+
48
+ ## 🚀 Basic Usage
49
+
50
+ Import the utilities you need directly from the package root.
51
+
52
+ ```typescript
53
+ import { isDefined, timeout, mapAsync, toArrayAsync, randomString } from '@tstdl/base/utils';
54
+
55
+ async function main() {
56
+ // 1. Simple Type Guard
57
+ const value: string | undefined = 'Hello';
58
+ if (isDefined(value)) {
59
+ console.log(value.toUpperCase()); // value is typed as string here
60
+ }
61
+
62
+ // 2. Async Iterable Helper
63
+ async function* numberGenerator() {
64
+ yield 1;
65
+ yield 2;
66
+ yield 3;
67
+ }
68
+
69
+ const doubled = await toArrayAsync(
70
+ mapAsync(numberGenerator(), async (num) => {
71
+ await timeout(100); // Wait 100ms
72
+ return num * 2;
73
+ }),
74
+ );
75
+ console.log(doubled); // [2, 4, 6]
76
+ }
77
+ ```
78
+
79
+ ## 🔧 Advanced Topics
80
+
81
+ ### Async Iterable Pipelines
82
+
83
+ Chain multiple operations to process data streams efficiently. This is similar to RxJS or LINQ but built on standard `AsyncIterable`.
84
+
85
+ ```typescript
86
+ import { range, filterAsync, mapAsync, batchAsync, toArrayAsync } from '@tstdl/base/utils';
87
+
88
+ // Create a pipeline
89
+ const pipeline = batchAsync(
90
+ mapAsync(
91
+ filterAsync(
92
+ // Source: Sync iterable converted to async automatically
93
+ range(1, 100),
94
+ (x) => x % 2 === 0, // Keep evens
95
+ ),
96
+ async (x) => x * 10, // Multiply by 10
97
+ ),
98
+ 5, // Batch into arrays of 5 items
99
+ );
100
+
101
+ // Execute the pipeline
102
+ const batches = await toArrayAsync(pipeline);
103
+ // Result: [[20, 40, 60, 80, 100], [120, ...], ...]
104
+ ```
105
+
106
+ ### Parallel Processing
107
+
108
+ When processing items involves IO (like network requests), processing them sequentially is slow. Use `parallelMap` or `parallelForEach` to control concurrency.
109
+
110
+ ```typescript
111
+ import { parallelMap, toArrayAsync } from '@tstdl/base/utils';
112
+
113
+ const userIds = [1, 2, 3, 4, 5];
114
+
115
+ const users = await toArrayAsync(
116
+ parallelMap(
117
+ userIds,
118
+ 3, // Concurrency: Process 3 items at a time
119
+ true, // Keep Order: Ensure output order matches input order
120
+ async (id) => {
121
+ const response = await fetch(`/users/${id}`);
122
+ return response.json();
123
+ },
124
+ ),
125
+ );
126
+ ```
127
+
128
+ ### Deep Object Merging & Decycling
129
+
130
+ Handle complex objects with circular references or deep structures.
131
+
132
+ ```typescript
133
+ import { mergeDeep, decycle, recycle } from '@tstdl/base/utils';
134
+
135
+ // Deep Merge
136
+ const defaultSettings = { theme: { color: 'blue', font: 'arial' } };
137
+ const userSettings = { theme: { color: 'red' } };
138
+
139
+ const settings = mergeDeep(defaultSettings, userSettings);
140
+ // { theme: { color: 'red', font: 'arial' } }
141
+
142
+ // Circular References
143
+ const a: any = { name: 'A' };
144
+ const b: any = { name: 'B', parent: a };
145
+ a.child = b;
146
+
147
+ // JSON.stringify(a) would throw. Use decycle:
148
+ const safe = decycle(a);
149
+ const json = JSON.stringify(safe);
150
+
151
+ // Restore later
152
+ const restored = recycle(JSON.parse(json));
153
+ ```
154
+
155
+ ### Resilient Operations (Backoff & Retry)
156
+
157
+ Handle transient failures and hanging requests using `backoffLoop` and `retryWithBackoff`.
158
+
159
+ #### backoffLoop
160
+
161
+ Manual control over a retry loop.
162
+
163
+ ```typescript
164
+ import { backoffLoop } from '@tstdl/base/utils';
165
+
166
+ await backoffLoop(
167
+ async (controller) => {
168
+ try {
169
+ await fetch('https://api.example.com/unstable');
170
+ controller.break(); // Success, exit loop
171
+ } catch (error) {
172
+ console.warn('Request failed, retrying...');
173
+ controller.backoff(); // Wait (exponentially increasing delay) then retry
174
+ }
175
+ },
176
+ {
177
+ strategy: 'exponential',
178
+ initialDelay: 500,
179
+ maximumDelay: 5000,
180
+ jitter: 0.1,
181
+ },
182
+ );
183
+ ```
184
+
185
+ #### retryWithBackoff
186
+
187
+ A higher-order utility that combines retries, exponential backoff, jitter, and timeouts. It also automatically respects `Retry-After` headers for HTTP errors.
188
+
189
+ ```typescript
190
+ import { retryWithBackoff } from '@tstdl/base/utils';
191
+
192
+ const result = await retryWithBackoff(
193
+ async (signal) => {
194
+ // signal is set if the attempt times out or is cancelled
195
+ return await fetch('https://api.example.com/data', { signal: signal.asAbortSignal() });
196
+ },
197
+ {
198
+ timeout: 5000, // Timeout for EACH attempt
199
+ retry: {
200
+ shouldRetry: (error, attempt) => attempt < 3 && isTransientError(error),
201
+ backoff: { strategy: 'exponential', initialDelay: 1000 },
202
+ },
203
+ },
204
+ );
205
+ ```
206
+
207
+ ### Cryptography Wrappers
208
+
209
+ Simplified, promise-based access to modern crypto standards.
210
+
211
+ ```typescript
212
+ import { digest, generatePbkdf2Key, encrypt, decrypt, encodeBase64 } from '@tstdl/base/utils';
213
+
214
+ // Hashing
215
+ const hash = await digest('SHA-256', 'Hello World');
216
+ console.log(await hash.toHex());
217
+
218
+ // Encryption
219
+ const key = await generatePbkdf2Key(true);
220
+ const encrypted = encrypt('AES-GCM', key, 'Secret Message');
221
+ console.log(await encrypted.toBase64());
222
+ ```
223
+
224
+ ### Stream Utilities
225
+
226
+ Bridge the gap between Node.js Streams, Web Streams, and Iterables.
227
+
228
+ ```typescript
229
+ import { readBinaryStream, toBytesStream } from '@tstdl/base/utils';
230
+
231
+ // Read a Web ReadableStream into a single Uint8Array
232
+ const response = await fetch('https://example.com/image.png');
233
+ const buffer = await readBinaryStream(response.body!);
234
+
235
+ // Convert a stream of arbitrary chunks to a byte stream
236
+ const byteStream = toBytesStream(someObjectStream);
237
+ ```
238
+
239
+ ## 📚 API
240
+
241
+ ### Async Iterable Helpers
242
+
243
+ | Function | Description |
244
+ | :---------------------------------- | :-------------------------------------------------------- |
245
+ | `mapAsync` | Transform items asynchronously. |
246
+ | `filterAsync` | Filter items asynchronously. |
247
+ | `reduceAsync` | Reduce items to a single value. |
248
+ | `batchAsync` | Group items into arrays of a specific size. |
249
+ | `bufferAsync` | Buffer items to handle backpressure or bursts. |
250
+ | `takeAsync` / `skipAsync` | Take or skip a specific number of items. |
251
+ | `takeWhileAsync` / `takeUntilAsync` | Take items based on a predicate or signal. |
252
+ | `distinctAsync` | Filter out duplicate items. |
253
+ | `groupAsync` | Group items by a key selector. |
254
+ | `toArrayAsync` | Consume the iterable and return an array. |
255
+ | `firstAsync` / `lastAsync` | Get the first or last item. |
256
+ | `drainAsync` | Consume the iterable completely without returning values. |
257
+
258
+ ### Parallel Processing
259
+
260
+ | Function | Description |
261
+ | :---------------- | :------------------------------------------------- |
262
+ | `parallelMap` | Map items with specified concurrency. |
263
+ | `parallelFilter` | Filter items with specified concurrency. |
264
+ | `parallelForEach` | Execute a function for each item with concurrency. |
265
+ | `parallelGroup` | Group items with concurrency. |
266
+
267
+ ### Object Utilities
268
+
269
+ | Function | Description |
270
+ | :------------------------------ | :--------------------------------------------------------------- |
271
+ | `mergeDeep` | Deeply merge objects with array handling options. |
272
+ | `decycle` / `recycle` | Handle circular references for serialization. |
273
+ | `pick` / `omit` | Create new objects with selected/omitted keys. |
274
+ | `mapObject` / `mapObjectValues` | Map keys or values of an object. |
275
+ | `filterObject` | Filter object properties by value or key. |
276
+ | `getPropertyNameProxy` | Type-safe way to get property paths (e.g., `user.profile.name`). |
277
+ | `lazyProperty` | Define a property that initializes on first access. |
278
+
279
+ ### Type Guards & Assertions
280
+
281
+ | Function | Description |
282
+ | :---------------------------- | :------------------------------------------------------ |
283
+ | `isDefined` / `assertDefined` | Check for `null` or `undefined`. |
284
+ | `isString` / `assertString` | Check for string type. |
285
+ | `isNumber` / `assertNumber` | Check for number type (excluding NaN). |
286
+ | `isArray` / `assertArray` | Check for array. |
287
+ | `isObject` / `assertObject` | Check for non-null object. |
288
+ | `assert` | Generic assertion function. |
289
+ | `assert*Pass` | Assert and return the value (e.g., `assertStringPass`). |
290
+
291
+ ### Timing & Async
292
+
293
+ | Function | Description |
294
+ | :------------------ | :---------------------------------------- |
295
+ | `timeout` | Promise-based delay. |
296
+ | `cancelableTimeout` | Delay that can be cancelled via a signal. |
297
+ | `withTimeout` | Race a promise against a timeout. |
298
+ | `backoffLoop` | Run a loop with backoff logic. |
299
+ | `retryWithBackoff` | Higher-order retry utility with backoff. |
300
+ | `asyncHook` | Create an async event hook registry. |
301
+ | `Timer` | High-resolution timer for benchmarking. |
302
+
303
+ ### Cryptography & Encoding
304
+
305
+ | Function | Description |
306
+ | :------------------------------ | :-------------------------------------- |
307
+ | `encrypt` / `decrypt` | AES encryption wrappers. |
308
+ | `digest` | SHA hashing wrapper. |
309
+ | `sign` / `verify` | Digital signatures (HMAC, ECDSA, etc.). |
310
+ | `encodeBase64` / `decodeBase64` | Base64 encoding utilities. |
311
+ | `encodeHex` / `decodeHex` | Hex encoding utilities. |
312
+ | `encodeUtf8` / `decodeText` | String/Buffer encoding utilities. |
313
+
314
+ ### Miscellaneous
315
+
316
+ | Function | Description |
317
+ | :------------------------------- | :---------------------------------------- |
318
+ | `randomString` / `randomInt` | Random value generation. |
319
+ | `formatDuration` / `formatBytes` | Formatting utilities. |
320
+ | `tryIgnore` | Try a function, return fallback on error. |
321
+ | `buildUrl` | Construct URLs with query parameters. |
322
+ | `memoize` | Function memoization. |
@@ -1,2 +1,2 @@
1
- import type { Observable } from 'rxjs';
1
+ import { type Observable } from 'rxjs';
2
2
  export declare function observableAsyncIterable<T>(observable: Observable<T>): AsyncIterableIterator<T>;
@@ -1,30 +1,26 @@
1
+ import { firstValueFrom, merge } from 'rxjs';
1
2
  import { CancellationToken } from '../../cancellation/token.js';
2
- import { merge, take } from 'rxjs';
3
3
  import { ObservableArray } from '../../collections/observable/observable-array.js';
4
4
  export async function* observableAsyncIterable(observable) {
5
5
  const buffer = new ObservableArray();
6
6
  const completeToken = new CancellationToken();
7
7
  const errorToken = new CancellationToken();
8
- let error;
9
8
  const subscription = observable.subscribe({
10
9
  next: (value) => buffer.add(value),
11
10
  complete: () => completeToken.set(),
12
- error: (_error) => {
13
- error = _error;
14
- errorToken.set();
15
- }
11
+ error: (error) => errorToken.set(error),
16
12
  });
17
13
  try {
18
14
  while (buffer.length > 0 || !completeToken.isSet) {
19
15
  if (buffer.length == 0) {
20
- await merge(buffer.add$, completeToken.set$, errorToken.set$).pipe(take(1)).toPromise();
16
+ await firstValueFrom(merge(buffer.add$, completeToken, errorToken));
21
17
  }
22
18
  while (buffer.length > 0) {
23
19
  const item = buffer.removeFirst();
24
20
  yield item;
25
21
  }
26
22
  if (errorToken.isSet) {
27
- throw error;
23
+ throw errorToken.reason;
28
24
  }
29
25
  }
30
26
  }