@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.
Files changed (218) 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.d.ts +1 -1
  28. package/application/application.js +3 -3
  29. package/application/providers.d.ts +20 -2
  30. package/application/providers.js +34 -7
  31. package/audit/README.md +267 -0
  32. package/audit/module.d.ts +5 -0
  33. package/audit/module.js +9 -1
  34. package/authentication/README.md +288 -0
  35. package/authentication/client/authentication.service.d.ts +12 -11
  36. package/authentication/client/authentication.service.js +21 -21
  37. package/authentication/client/http-client.middleware.js +2 -2
  38. package/authentication/server/module.d.ts +5 -0
  39. package/authentication/server/module.js +9 -1
  40. package/authentication/tests/authentication.api-controller.test.js +1 -1
  41. package/authentication/tests/authentication.api-request-token.provider.test.js +1 -1
  42. package/authentication/tests/authentication.client-error-handling.test.js +2 -1
  43. package/authentication/tests/authentication.client-service-refresh.test.js +5 -3
  44. package/authentication/tests/authentication.client-service.test.js +1 -1
  45. package/browser/README.md +401 -0
  46. package/cancellation/README.md +156 -0
  47. package/cancellation/tests/coverage.test.d.ts +1 -0
  48. package/cancellation/tests/coverage.test.js +49 -0
  49. package/cancellation/tests/leak.test.js +24 -29
  50. package/cancellation/tests/token.test.d.ts +1 -0
  51. package/cancellation/tests/token.test.js +136 -0
  52. package/cancellation/token.d.ts +53 -177
  53. package/cancellation/token.js +132 -208
  54. package/circuit-breaker/postgres/module.d.ts +1 -0
  55. package/circuit-breaker/postgres/module.js +5 -1
  56. package/context/README.md +174 -0
  57. package/cookie/README.md +161 -0
  58. package/css/README.md +157 -0
  59. package/data-structures/README.md +320 -0
  60. package/decorators/README.md +140 -0
  61. package/distributed-loop/README.md +231 -0
  62. package/distributed-loop/distributed-loop.js +1 -1
  63. package/document-management/README.md +403 -0
  64. package/document-management/server/configure.js +5 -1
  65. package/document-management/server/module.d.ts +1 -1
  66. package/document-management/server/module.js +1 -1
  67. package/document-management/server/services/document-management-ancillary.service.js +1 -1
  68. package/document-management/server/services/document-management.service.js +9 -7
  69. package/document-management/tests/ai-config-hierarchy.test.js +0 -5
  70. package/document-management/tests/document-management-ai-overrides.test.js +0 -1
  71. package/document-management/tests/document-management-core.test.js +2 -7
  72. package/document-management/tests/document-management.api.test.js +6 -7
  73. package/document-management/tests/document-statistics.service.test.js +11 -12
  74. package/document-management/tests/document-validation-ai-overrides.test.js +0 -1
  75. package/document-management/tests/document.service.test.js +3 -3
  76. package/document-management/tests/enum-helpers.test.js +2 -3
  77. package/dom/README.md +213 -0
  78. package/enumerable/README.md +259 -0
  79. package/enumeration/README.md +121 -0
  80. package/errors/README.md +267 -0
  81. package/examples/document-management/main.d.ts +1 -0
  82. package/examples/document-management/main.js +14 -11
  83. package/file/README.md +191 -0
  84. package/formats/README.md +210 -0
  85. package/function/README.md +144 -0
  86. package/http/README.md +318 -0
  87. package/http/client/adapters/undici.adapter.js +1 -1
  88. package/http/client/http-client-request.d.ts +6 -5
  89. package/http/client/http-client-request.js +8 -9
  90. package/http/server/node/node-http-server.js +1 -2
  91. package/image-service/README.md +137 -0
  92. package/injector/README.md +491 -0
  93. package/intl/README.md +113 -0
  94. package/json-path/README.md +182 -0
  95. package/jsx/README.md +154 -0
  96. package/key-value-store/README.md +191 -0
  97. package/key-value-store/postgres/module.d.ts +1 -0
  98. package/key-value-store/postgres/module.js +5 -1
  99. package/lock/README.md +249 -0
  100. package/lock/postgres/module.d.ts +1 -0
  101. package/lock/postgres/module.js +5 -1
  102. package/lock/web/web-lock.js +119 -47
  103. package/logger/README.md +287 -0
  104. package/mail/README.md +256 -0
  105. package/mail/module.d.ts +5 -1
  106. package/mail/module.js +11 -6
  107. package/memory/README.md +144 -0
  108. package/message-bus/README.md +244 -0
  109. package/message-bus/message-bus-base.js +1 -1
  110. package/module/README.md +182 -0
  111. package/module/module.d.ts +1 -1
  112. package/module/module.js +77 -17
  113. package/module/modules/web-server.module.js +3 -4
  114. package/notification/server/module.d.ts +1 -0
  115. package/notification/server/module.js +5 -1
  116. package/notification/tests/notification-flow.test.js +2 -2
  117. package/notification/tests/notification-type.service.test.js +24 -15
  118. package/object-storage/README.md +300 -0
  119. package/openid-connect/README.md +274 -0
  120. package/orm/README.md +423 -0
  121. package/orm/decorators.d.ts +5 -1
  122. package/orm/decorators.js +1 -1
  123. package/orm/server/drizzle/schema-converter.js +17 -30
  124. package/orm/server/encryption.d.ts +0 -1
  125. package/orm/server/encryption.js +1 -4
  126. package/orm/server/index.d.ts +1 -6
  127. package/orm/server/index.js +1 -6
  128. package/orm/server/migration.d.ts +19 -0
  129. package/orm/server/migration.js +72 -0
  130. package/orm/server/repository.d.ts +1 -1
  131. package/orm/server/transaction.d.ts +5 -10
  132. package/orm/server/transaction.js +22 -26
  133. package/orm/server/transactional.js +3 -3
  134. package/orm/tests/database-migration.test.d.ts +1 -0
  135. package/orm/tests/database-migration.test.js +82 -0
  136. package/orm/tests/encryption.test.js +3 -4
  137. package/orm/utils.d.ts +17 -2
  138. package/orm/utils.js +49 -1
  139. package/package.json +9 -6
  140. package/password/README.md +164 -0
  141. package/pdf/README.md +246 -0
  142. package/polyfills.js +1 -0
  143. package/pool/README.md +198 -0
  144. package/process/README.md +237 -0
  145. package/promise/README.md +252 -0
  146. package/promise/cancelable-promise.js +1 -1
  147. package/random/README.md +193 -0
  148. package/rate-limit/postgres/module.d.ts +1 -0
  149. package/rate-limit/postgres/module.js +5 -1
  150. package/reflection/README.md +305 -0
  151. package/reflection/decorator-data.js +11 -12
  152. package/rpc/README.md +386 -0
  153. package/rxjs-utils/README.md +262 -0
  154. package/schema/README.md +342 -0
  155. package/serializer/README.md +342 -0
  156. package/signals/implementation/README.md +134 -0
  157. package/sse/README.md +278 -0
  158. package/task-queue/README.md +293 -0
  159. package/task-queue/postgres/drizzle/{0000_simple_invisible_woman.sql → 0000_wakeful_sunspot.sql} +22 -14
  160. package/task-queue/postgres/drizzle/meta/0000_snapshot.json +160 -82
  161. package/task-queue/postgres/drizzle/meta/_journal.json +2 -2
  162. package/task-queue/postgres/module.d.ts +1 -0
  163. package/task-queue/postgres/module.js +5 -1
  164. package/task-queue/postgres/schemas.d.ts +9 -6
  165. package/task-queue/postgres/schemas.js +4 -3
  166. package/task-queue/postgres/task-queue.d.ts +4 -13
  167. package/task-queue/postgres/task-queue.js +462 -355
  168. package/task-queue/postgres/task.model.d.ts +12 -5
  169. package/task-queue/postgres/task.model.js +51 -25
  170. package/task-queue/task-context.d.ts +2 -2
  171. package/task-queue/task-context.js +8 -8
  172. package/task-queue/task-queue.d.ts +53 -19
  173. package/task-queue/task-queue.js +121 -55
  174. package/task-queue/tests/cascading-cancellations.test.d.ts +1 -0
  175. package/task-queue/tests/cascading-cancellations.test.js +38 -0
  176. package/task-queue/tests/complex.test.js +45 -229
  177. package/task-queue/tests/coverage-branch.test.d.ts +1 -0
  178. package/task-queue/tests/coverage-branch.test.js +407 -0
  179. package/task-queue/tests/coverage-enhancement.test.d.ts +1 -0
  180. package/task-queue/tests/coverage-enhancement.test.js +144 -0
  181. package/task-queue/tests/dag-dependencies.test.d.ts +1 -0
  182. package/task-queue/tests/dag-dependencies.test.js +41 -0
  183. package/task-queue/tests/dependencies.test.js +28 -26
  184. package/task-queue/tests/extensive-dependencies.test.js +64 -139
  185. package/task-queue/tests/fan-out-spawning.test.d.ts +1 -0
  186. package/task-queue/tests/fan-out-spawning.test.js +53 -0
  187. package/task-queue/tests/idempotent-replacement.test.d.ts +1 -0
  188. package/task-queue/tests/idempotent-replacement.test.js +61 -0
  189. package/task-queue/tests/missing-idempotent-tasks.test.d.ts +1 -0
  190. package/task-queue/tests/missing-idempotent-tasks.test.js +38 -0
  191. package/task-queue/tests/queue.test.js +128 -8
  192. package/task-queue/tests/worker.test.js +39 -16
  193. package/task-queue/tests/zombie-parent.test.d.ts +1 -0
  194. package/task-queue/tests/zombie-parent.test.js +45 -0
  195. package/task-queue/tests/zombie-recovery.test.d.ts +1 -0
  196. package/task-queue/tests/zombie-recovery.test.js +51 -0
  197. package/templates/README.md +287 -0
  198. package/test5.js +5 -5
  199. package/testing/README.md +157 -0
  200. package/testing/integration-setup.d.ts +4 -4
  201. package/testing/integration-setup.js +54 -29
  202. package/text/README.md +346 -0
  203. package/text/localization.service.js +2 -2
  204. package/threading/README.md +238 -0
  205. package/types/README.md +311 -0
  206. package/utils/README.md +322 -0
  207. package/utils/async-iterable-helpers/observable-iterable.d.ts +1 -1
  208. package/utils/async-iterable-helpers/observable-iterable.js +4 -8
  209. package/utils/async-iterable-helpers/take-until.js +4 -4
  210. package/utils/backoff.js +89 -30
  211. package/utils/file-reader.js +1 -2
  212. package/utils/retry-with-backoff.js +1 -1
  213. package/utils/timer.d.ts +1 -1
  214. package/utils/timer.js +5 -7
  215. package/utils/timing.d.ts +1 -1
  216. package/utils/timing.js +2 -4
  217. package/utils/z-base32.d.ts +1 -0
  218. package/utils/z-base32.js +1 -0
@@ -0,0 +1,134 @@
1
+ # Signals Implementation
2
+
3
+ This module provides the core reactive implementation for the Tstdl library. It is based on Angular's Signals system, adapted for use in any environment (Node.js or Browser) without requiring the Angular runtime.
4
+
5
+ ## Table of Contents
6
+
7
+ - [✨ Features](#-features)
8
+ - [Core Concepts](#core-concepts)
9
+ - [Writable Signals](#writable-signals)
10
+ - [Computed Signals](#computed-signals)
11
+ - [Effects](#effects)
12
+ - [🚀 Basic Usage](#-basic-usage)
13
+ - [🔧 Advanced Topics](#-advanced-topics)
14
+ - [Untracked Reads](#untracked-reads)
15
+ - [RxJS Interop](#rxjs-interop)
16
+ - [Equality Functions](#equality-functions)
17
+ - [📚 API](#-api)
18
+
19
+ ## ✨ Features
20
+
21
+ - **Granular Reactivity**: Only dependents of changed signals are re-evaluated.
22
+ - **Lazy Evaluation**: Computed signals only calculate their value when read.
23
+ - **Glitch-Free**: Eliminates intermediate inconsistent states during updates.
24
+ - **RxJS Integration**: Seamlessly bridge between reactive signals and asynchronous observables.
25
+ - **Environment Agnostic**: Works in Node.js, browsers, and other JavaScript environments.
26
+
27
+ ## Core Concepts
28
+
29
+ ### Writable Signals
30
+
31
+ A `WritableSignal` is the primary source of truth in the reactive graph. It holds a value that can be explicitly set or updated.
32
+
33
+ - `set(value)`: Overwrites the current value.
34
+ - `update(fn)`: Computes a new value based on the previous one.
35
+ - `asReadonly()`: Returns a version of the signal that cannot be modified.
36
+
37
+ ### Computed Signals
38
+
39
+ A `computed` signal derives its value from other signals. It automatically tracks any signals accessed during its execution and re-evaluates only when those dependencies change. Computations are lazy and memoized.
40
+
41
+ ### Effects
42
+
43
+ An `effect` is a reactive block of code that automatically re-runs whenever any signals it reads change. Effects are scheduled to run asynchronously using a microtask to batch updates and avoid redundant executions.
44
+
45
+ ## 🚀 Basic Usage
46
+
47
+ ```typescript
48
+ import { signal, computed, effect } from './index.js';
49
+
50
+ // Create a writable signal
51
+ const count = signal(0);
52
+
53
+ // Create a computed signal
54
+ const isEven = computed(() => count() % 2 === 0);
55
+
56
+ // Create an effect
57
+ effect(() => {
58
+ console.log(`Count: ${count()}, isEven: ${isEven()}`);
59
+ });
60
+
61
+ // Updating the signal triggers the effect
62
+ count.set(1); // Output: Count: 1, isEven: false
63
+ count.update(c => c + 1); // Output: Count: 2, isEven: true
64
+ ```
65
+
66
+ ## 🔧 Advanced Topics
67
+
68
+ ### Untracked Reads
69
+
70
+ Sometimes you want to read a signal's value without creating a dependency. Use `untracked` for this purpose.
71
+
72
+ ```typescript
73
+ import { signal, effect, untracked } from './index.js';
74
+
75
+ const count = signal(0);
76
+ const other = signal('A');
77
+
78
+ effect(() => {
79
+ console.log(count());
80
+ console.log(untracked(other)); // Changes to 'other' won't trigger this effect
81
+ });
82
+ ```
83
+
84
+ ### RxJS Interop
85
+
86
+ The module provides utilities to convert between signals and observables.
87
+
88
+ ```typescript
89
+ import { signal, toObservable, toSignal } from './index.js';
90
+ import { interval } from 'rxjs';
91
+
92
+ // Signal to Observable
93
+ const count = signal(0);
94
+ const count$ = toObservable(count);
95
+
96
+ // Observable to Signal
97
+ const timer$ = interval(1000);
98
+ const timer = toSignal(timer$, { initialValue: 0 });
99
+ ```
100
+
101
+ ### Equality Functions
102
+
103
+ You can customize how signal changes are detected by providing a custom `equal` function.
104
+
105
+ ```typescript
106
+ import { signal } from './index.js';
107
+
108
+ const user = signal({ id: 1, name: 'John' }, {
109
+ equal: (a, b) => a.id === b.id
110
+ });
111
+
112
+ // This update will NOT trigger dependents because the ID is the same
113
+ user.set({ id: 1, name: 'John Doe' });
114
+ ```
115
+
116
+ ## 📚 API
117
+
118
+ ### Functions
119
+
120
+ - `signal(initialValue, options?)`: Creates a `WritableSignal`.
121
+ - `computed(computation, options?)`: Creates a computed `Signal`.
122
+ - `effect(effectFn, options?)`: Creates an `EffectRef`.
123
+ - `untracked(fn)`: Runs `fn` in a non-reactive context.
124
+ - `isSignal(value)`: Returns `true` if the value is a Signal.
125
+ - `isWritableSignal(value)`: Returns `true` if the value is a WritableSignal.
126
+ - `toObservable(signal, options?)`: Converts a signal to an RxJS Observable.
127
+ - `toSignal(observable, options?)`: Converts an RxJS Observable to a signal.
128
+ - `configureDefaultSignalsImplementation()`: Configures the library to use this implementation by default.
129
+
130
+ ### Interfaces
131
+
132
+ - `Signal<T>`: A readonly reactive value.
133
+ - `WritableSignal<T>`: A signal that can be changed.
134
+ - `EffectRef`: A handle to a running effect, allowing it to be destroyed.
package/sse/README.md ADDED
@@ -0,0 +1,278 @@
1
+ # @tstdl/base/sse
2
+
3
+ A comprehensive module for Server-Sent Events (SSE) that provides both a low-level reactive client for discrete events and a high-level, delta-capable data streaming abstraction for synchronizing complex objects efficiently.
4
+
5
+ ## Table of Contents
6
+
7
+ - [✨ Features](#-features)
8
+ - [Core Concepts](#core-concepts)
9
+ - [High-Level: Data Streaming](#high-level-data-streaming)
10
+ - [Low-Level: Event Pushing](#low-level-event-pushing)
11
+ - [🚀 Basic Usage](#-basic-usage)
12
+ - [Server-Side Data Streaming](#server-side-data-streaming)
13
+ - [Client-Side Data Consumption](#client-side-data-consumption)
14
+ - [🔧 Advanced Topics](#-advanced-topics)
15
+ - [Low-Level Event Pushing](#low-level-event-pushing-1)
16
+ - [Handling Errors](#handling-errors)
17
+ - [📚 API](#-api)
18
+
19
+ ## ✨ Features
20
+
21
+ - **Isomorphic Design**: Type-safe utilities for both server (Node.js/Edge) and client (Browser) environments.
22
+ - **Smart Data Synchronization**: `DataStreamSource` automatically calculates JSON diffs (deltas) between updates to minimize bandwidth usage. For optimal array synchronization, ensure your objects have an `id` property.
23
+ - **Automatic State Reconstruction**: The client-side `DataStream` utility automatically patches the local state with incoming deltas, exposing a seamless RxJS Observable of the full object.
24
+ - **Reactive Client**: A robust RxJS wrapper around the native `EventSource` API (`ServerSentEvents`) for handling connection states and events.
25
+ - **Web Streams Support**: Server-side implementation uses standard `ReadableStream`, making it compatible with modern runtimes.
26
+ - **Full SSE Specification**: Supports named events, custom IDs, retry intervals, and comments.
27
+
28
+ ## Core Concepts
29
+
30
+ ### High-Level: Data Streaming
31
+
32
+ The **Data Streaming** abstraction is designed for synchronizing a single, potentially complex state object between the server and client.
33
+
34
+ - **Server (`DataStreamSource`)**: You simply pass the full object to the source whenever it changes. The source uses `jsondiffpatch` to calculate the difference between the current and previous object. It sends the full object initially, and then only the small deltas for subsequent updates.
35
+ - **Client (`DataStream`)**: Consumes the stream, listening for `data` (full snapshot) and `delta` (patch) events. It maintains the local state by applying patches automatically and emits the fully updated object to subscribers.
36
+
37
+ ### Low-Level: Event Pushing
38
+
39
+ The **Event Pushing** layer provides direct control over the SSE protocol, suitable for sending discrete notifications (e.g., "OrderShipped", "NewMessage").
40
+
41
+ - **Server (`ServerSentEventsSource`)**: A wrapper around a `TransformStream` that formats messages according to the SSE spec.
42
+ - **Client (`ServerSentEvents`)**: Wraps the browser's `EventSource` to provide RxJS Observables for messages, connection status, and errors.
43
+
44
+ ## 🚀 Basic Usage
45
+
46
+ ### Server-Side Data Streaming
47
+
48
+ Use `DataStreamSource` to stream state changes. The most convenient way is `DataStreamSource.fromIterable`.
49
+
50
+ ```typescript
51
+ import { apiController, type ApiServerResult } from '@tstdl/base/api/server';
52
+ import { defineApi } from '@tstdl/base/api';
53
+ import { DataStream, DataStreamSource } from '@tstdl/base/sse';
54
+ import { CancellationSignal } from '@tstdl/base/cancellation';
55
+ import { inject } from '@tstdl/base/injector';
56
+ import { timeout } from '@tstdl/base/utils/timing';
57
+ import { object, string, number } from '@tstdl/base/schema';
58
+
59
+ // 1. Define the data shape
60
+ const StockPrice = object({
61
+ symbol: string(),
62
+ price: number(),
63
+ timestamp: number(),
64
+ });
65
+ type StockPrice = typeof StockPrice.T;
66
+
67
+ // 2. Define the API
68
+ const stockApi = defineApi({
69
+ resource: 'stocks',
70
+ endpoints: {
71
+ track: {
72
+ resource: ':symbol/stream',
73
+ method: 'GET',
74
+ parameters: object({ symbol: string() }),
75
+ result: DataStream<StockPrice>, // Type hint for the client
76
+ },
77
+ },
78
+ });
79
+
80
+ // 3. Implement the Controller
81
+ @apiController(stockApi)
82
+ class StockApiController {
83
+ #cancellationSignal = inject(CancellationSignal);
84
+
85
+ track({ parameters }: any): ApiServerResult<typeof stockApi, 'track'> {
86
+ // Create an async generator that yields data updates
87
+ const ticker = this.createTicker(parameters.symbol, this.#cancellationSignal);
88
+
89
+ // Create a source that automatically handles diffing and serialization
90
+ return DataStreamSource.fromIterable(ticker, { delta: true });
91
+ }
92
+
93
+ async *createTicker(symbol: string, signal: CancellationSignal): AsyncIterable<StockPrice> {
94
+ let price = 100;
95
+ while (signal.isUnset) {
96
+ price += (Math.random() - 0.5) * 2;
97
+ yield { symbol, price, timestamp: Date.now() };
98
+ await timeout(1000, signal);
99
+ }
100
+ }
101
+ }
102
+ ```
103
+
104
+ ### Client-Side Data Consumption
105
+
106
+ Use `DataStream.parse` to transform the raw SSE connection into a stream of your data objects.
107
+
108
+ ```typescript
109
+ import { DataStream, ServerSentEvents } from '@tstdl/base/sse';
110
+ import { type Observable } from 'rxjs';
111
+
112
+ type StockPrice = {
113
+ symbol: string;
114
+ price: number;
115
+ timestamp: number;
116
+ };
117
+
118
+ // 1. Establish the connection
119
+ const sse = new ServerSentEvents('/api/stocks/AAPL/stream');
120
+
121
+ // 2. Parse the data stream
122
+ // This handles the initial full load and all subsequent delta patches automatically
123
+ const stock$: Observable<StockPrice> = DataStream.parse<StockPrice>(sse);
124
+
125
+ // 3. Subscribe to updates
126
+ const subscription = stock$.subscribe({
127
+ next: (stock) => {
128
+ console.log(`Update for ${stock.symbol}: $${stock.price.toFixed(2)}`);
129
+ },
130
+ error: (err) => console.error('Stream error:', err),
131
+ complete: () => console.log('Stream closed'),
132
+ });
133
+
134
+ // Cleanup when done
135
+ // subscription.unsubscribe();
136
+ ```
137
+
138
+ ## 🔧 Advanced Topics
139
+
140
+ ### Low-Level Event Pushing
141
+
142
+ If you don't need object synchronization and just want to send named events, use `ServerSentEventsSource` directly.
143
+
144
+ **Server:**
145
+
146
+ ```typescript
147
+ import { ServerSentEventsSource } from '@tstdl/base/sse';
148
+ import { timeout } from '@tstdl/base/utils/timing';
149
+
150
+ async function notificationStream(): Promise<ServerSentEventsSource> {
151
+ const source = new ServerSentEventsSource();
152
+
153
+ // Run in background
154
+ (async () => {
155
+ await timeout(1000);
156
+ if (source.closed()) return;
157
+
158
+ // Send a named JSON event
159
+ await source.sendJson({
160
+ name: 'notification',
161
+ id: '1',
162
+ data: { message: 'Hello World' },
163
+ });
164
+
165
+ await timeout(2000);
166
+ if (source.closed()) return;
167
+
168
+ // Send a text event
169
+ await source.sendText({
170
+ name: 'ping',
171
+ data: 'keep-alive',
172
+ });
173
+
174
+ await source.close();
175
+ })();
176
+
177
+ return source;
178
+ }
179
+ ```
180
+
181
+ **Client:**
182
+
183
+ ```typescript
184
+ import { ServerSentEvents } from '@tstdl/base/sse';
185
+ import { filter, map } from 'rxjs';
186
+
187
+ const sse = new ServerSentEvents('/api/notifications');
188
+
189
+ // Listen specifically for 'notification' events
190
+ const notifications$ = sse.message$('notification').pipe(map((event) => JSON.parse(event.data)));
191
+
192
+ notifications$.subscribe((data) => console.log('New notification:', data));
193
+ ```
194
+
195
+ ### Handling Errors
196
+
197
+ The `DataStreamSource` has a built-in mechanism to send errors to the client before closing the stream.
198
+
199
+ ```typescript
200
+ // Server
201
+ const source = new DataStreamSource();
202
+ try {
203
+ // ... logic
204
+ } catch (err) {
205
+ // Sends an 'error' event with the formatted error and closes the connection
206
+ await source.error(err);
207
+ }
208
+ ```
209
+
210
+ On the client side, `DataStream.parse` will listen for these `error` events and error out the Observable stream accordingly.
211
+
212
+ ## 📚 API
213
+
214
+ ### `DataStreamSource<T>`
215
+
216
+ Server-side class for streaming data objects with optional delta compression.
217
+
218
+ | Member | Signature | Description |
219
+ | :------------- | :----------------------------------------------------------- | :---------------------------------------------------------------------------------- |
220
+ | `constructor` | `(options?: DataStreamSourceOptions)` | Creates a new source. Options include `delta` (boolean) and `errorFormatter`. |
221
+ | `fromIterable` | `static fromIterable<T>(iterable: AnyIterable<T>, options?)` | Creates a source that automatically pulls from an async iterable and sends updates. |
222
+ | `send` | `send(data: T): Promise<void>` | Sends a data update. If `delta` is enabled, calculates diff from previous data. |
223
+ | `error` | `error(error: unknown): Promise<void>` | Sends an error event to the client and closes the stream. |
224
+ | `close` | `close(): Promise<void>` | Closes the underlying stream. |
225
+ | `closed` | `ReadonlySignal<boolean>` | Signal indicating if the stream is closed. |
226
+ | `eventSource` | `ServerSentEventsSource` | Access to the underlying SSE source. |
227
+
228
+ ### `DataStream<T>`
229
+
230
+ Client-side utility for reconstructing data streams.
231
+
232
+ | Member | Signature | Description |
233
+ | :------ | :-------------------------------------------------------------- | :----------------------------------------------------------------------------------- |
234
+ | `parse` | `static parse<T>(eventSource: ServerSentEvents): Observable<T>` | Transforms an SSE connection into an Observable of the synchronized data object `T`. |
235
+
236
+ ### `ServerSentEventsSource`
237
+
238
+ Low-level server-side SSE writer.
239
+
240
+ | Member | Signature | Description |
241
+ | :------------ | :---------------------------------------------------- | :------------------------------------------------------------------------ |
242
+ | `readable` | `ReadableStream<string>` | The Web Stream to return in the HTTP response body. |
243
+ | `sendJson` | `sendJson(event: ServerSentJsonEvent): Promise<void>` | Sends a named event with JSON data. |
244
+ | `sendText` | `sendText(event: ServerSentTextEvent): Promise<void>` | Sends a named event with raw text data. |
245
+ | `sendComment` | `sendComment(comment: string): Promise<void>` | Sends an SSE comment (ignored by browser clients, useful for keep-alive). |
246
+ | `close` | `close(): Promise<void>` | Closes the stream. |
247
+ | `closed` | `ReadonlySignal<boolean>` | Signal indicating if the stream is closed. |
248
+ | `error` | `ReadonlySignal<Error \| undefined>` | Signal containing the error if the stream failed. |
249
+
250
+ ### `ServerSentEvents`
251
+
252
+ Client-side reactive wrapper for `EventSource`.
253
+
254
+ | Member | Signature | Description |
255
+ | :-------------- | :--------------------------------------------------- | :------------------------------------------------------------------------------------- |
256
+ | `constructor` | `(url: string, options?: EventSourceInit)` | Initiates the connection. |
257
+ | `message$` | `message$(event?: string): Observable<MessageEvent>` | Returns an Observable of messages. If `event` is provided, filters by that event name. |
258
+ | `state$` | `Observable<ServerSentEventsState>` | Emits connection state changes (`Connecting`, `Open`, `Closed`). |
259
+ | `open$` | `Observable<void>` | Emits when the connection is open. |
260
+ | `close$` | `Observable<void>` | Emits when the connection is closed. |
261
+ | `error$` | `Observable<Event>` | Emits on connection errors. |
262
+ | `isOpen$` | `Observable<boolean>` | Emits `true` when connected. |
263
+ | `isConnecting$` | `Observable<boolean>` | Emits `true` when connecting. |
264
+ | `isClosed$` | `Observable<boolean>` | Emits `true` when closed. |
265
+ | `state` | `ServerSentEventsState` | Gets the current connection state. |
266
+ | `close` | `close(): void` | Manually closes the connection. |
267
+
268
+ ### Types
269
+
270
+ | Type | Description |
271
+ | :-------------------------- | :-------------------------------------------------------------------------------- |
272
+ | `DataStreamSourceOptions` | Options for `DataStreamSource`: `delta` (boolean) and `errorFormatter` (function). |
273
+ | `DataStreamErrorFormatter` | Function type: `(error: unknown) => UndefinableJson`. |
274
+ | `ServerSentEventBase<Data>` | Base interface for events with `name`, `data`, `id`, and `retry`. |
275
+ | `ServerSentJsonEvent` | Event where `data` is any JSON-serializable value. |
276
+ | `ServerSentTextEvent` | Event where `data` is a string. |
277
+ | `ServerSentEvent` | Union of `ServerSentTextEvent` and `ServerSentJsonEvent`. |
278
+ | `ServerSentEventsState` | Enum: `Connecting` (0), `Open` (1), `Closed` (2). |