@tstdl/base 0.93.139 → 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 (133) 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.js +24 -29
  40. package/cancellation/tests/token.test.d.ts +1 -0
  41. package/cancellation/tests/token.test.js +136 -0
  42. package/cancellation/token.d.ts +53 -177
  43. package/cancellation/token.js +132 -208
  44. package/context/README.md +174 -0
  45. package/cookie/README.md +161 -0
  46. package/css/README.md +157 -0
  47. package/data-structures/README.md +320 -0
  48. package/decorators/README.md +140 -0
  49. package/distributed-loop/README.md +231 -0
  50. package/distributed-loop/distributed-loop.js +1 -1
  51. package/document-management/README.md +403 -0
  52. package/document-management/server/services/document-management.service.js +9 -7
  53. package/document-management/tests/document-management-core.test.js +2 -7
  54. package/document-management/tests/document-management.api.test.js +6 -7
  55. package/document-management/tests/document-statistics.service.test.js +11 -12
  56. package/document-management/tests/document.service.test.js +3 -3
  57. package/document-management/tests/enum-helpers.test.js +2 -3
  58. package/dom/README.md +213 -0
  59. package/enumerable/README.md +259 -0
  60. package/enumeration/README.md +121 -0
  61. package/errors/README.md +267 -0
  62. package/file/README.md +191 -0
  63. package/formats/README.md +210 -0
  64. package/function/README.md +144 -0
  65. package/http/README.md +318 -0
  66. package/http/client/adapters/undici.adapter.js +1 -1
  67. package/http/client/http-client-request.d.ts +6 -5
  68. package/http/client/http-client-request.js +8 -9
  69. package/http/server/node/node-http-server.js +1 -2
  70. package/image-service/README.md +137 -0
  71. package/injector/README.md +491 -0
  72. package/intl/README.md +113 -0
  73. package/json-path/README.md +182 -0
  74. package/jsx/README.md +154 -0
  75. package/key-value-store/README.md +191 -0
  76. package/lock/README.md +249 -0
  77. package/lock/web/web-lock.js +119 -47
  78. package/logger/README.md +287 -0
  79. package/mail/README.md +256 -0
  80. package/memory/README.md +144 -0
  81. package/message-bus/README.md +244 -0
  82. package/message-bus/message-bus-base.js +1 -1
  83. package/module/README.md +182 -0
  84. package/module/module.d.ts +1 -1
  85. package/module/module.js +77 -17
  86. package/module/modules/web-server.module.js +1 -1
  87. package/notification/tests/notification-type.service.test.js +24 -15
  88. package/object-storage/README.md +300 -0
  89. package/openid-connect/README.md +274 -0
  90. package/orm/README.md +423 -0
  91. package/package.json +8 -6
  92. package/password/README.md +164 -0
  93. package/pdf/README.md +246 -0
  94. package/polyfills.js +1 -0
  95. package/pool/README.md +198 -0
  96. package/process/README.md +237 -0
  97. package/promise/README.md +252 -0
  98. package/promise/cancelable-promise.js +1 -1
  99. package/random/README.md +193 -0
  100. package/reflection/README.md +305 -0
  101. package/rpc/README.md +386 -0
  102. package/rxjs-utils/README.md +262 -0
  103. package/schema/README.md +342 -0
  104. package/serializer/README.md +342 -0
  105. package/signals/implementation/README.md +134 -0
  106. package/sse/README.md +278 -0
  107. package/task-queue/README.md +300 -0
  108. package/task-queue/postgres/task-queue.d.ts +2 -1
  109. package/task-queue/postgres/task-queue.js +32 -2
  110. package/task-queue/task-context.js +1 -1
  111. package/task-queue/task-queue.d.ts +17 -0
  112. package/task-queue/task-queue.js +103 -45
  113. package/task-queue/tests/complex.test.js +4 -4
  114. package/task-queue/tests/dependencies.test.js +4 -2
  115. package/task-queue/tests/queue.test.js +111 -0
  116. package/task-queue/tests/worker.test.js +21 -13
  117. package/templates/README.md +287 -0
  118. package/testing/README.md +157 -0
  119. package/text/README.md +346 -0
  120. package/threading/README.md +238 -0
  121. package/types/README.md +311 -0
  122. package/utils/README.md +322 -0
  123. package/utils/async-iterable-helpers/observable-iterable.d.ts +1 -1
  124. package/utils/async-iterable-helpers/observable-iterable.js +4 -8
  125. package/utils/async-iterable-helpers/take-until.js +4 -4
  126. package/utils/backoff.js +89 -30
  127. package/utils/retry-with-backoff.js +1 -1
  128. package/utils/timer.d.ts +1 -1
  129. package/utils/timer.js +5 -7
  130. package/utils/timing.d.ts +1 -1
  131. package/utils/timing.js +2 -4
  132. package/utils/z-base32.d.ts +1 -0
  133. package/utils/z-base32.js +1 -0
@@ -0,0 +1,342 @@
1
+ # @tstdl/base/serializer
2
+
3
+ A robust and extensible serialization library for TypeScript that transforms complex object graphs—including circular references, built-in types, and custom classes—into a JSON-compatible format and back.
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [✨ Features](#-features)
8
+ 2. [Core Concepts](#core-concepts)
9
+ 3. [🚀 Basic Usage](#-basic-usage)
10
+ 4. [🔧 Advanced Topics](#-advanced-topics)
11
+ - [Handling Circular References](#handling-circular-references)
12
+ - [Custom Serializable Classes](#custom-serializable-classes)
13
+ - [Registering External Types](#registering-external-types)
14
+ - [Contextual Serialization](#contextual-serialization)
15
+ - [Raw Serialization](#raw-serialization)
16
+ 5. [📚 API](#-api)
17
+
18
+ ## ✨ Features
19
+
20
+ - **Circular Reference Handling**: Automatically detects cycles and serializes them as references to the original path.
21
+ - **Rich Type Support**: Out-of-the-box support for:
22
+ - `Map`, `Set`
23
+ - `Date`, `RegExp`, `Error`
24
+ - `BigInt`, `Symbol` (global via `Symbol.for`)
25
+ - `ArrayBuffer`, `TypedArray` (Int8, Uint8, etc.), `Buffer`
26
+ - `MessagePort` (serialized as raw if available)
27
+ - **JSON Compatible**: The output is a plain JavaScript object structure safe for `JSON.stringify`.
28
+ - **Extensible**: Add support for your own classes using decorators or registration functions.
29
+ - **Context Aware**: Pass shared state (context) during serialization/deserialization to avoid embedding large shared objects.
30
+ - **Type Safe**: Preserves type information for registered classes.
31
+
32
+ ## Core Concepts
33
+
34
+ The serializer converts objects into a "Serialized Data" format. This format is composed entirely of JSON primitives (`string`, `number`, `boolean`, `null`) and plain objects/arrays.
35
+
36
+ - **Primitives**: Kept as-is. `undefined` becomes `{ "<undefined>": null }`.
37
+ - **Wrappers**: Complex types are wrapped in objects with specific keys, e.g., `{ "<Date>": 1672531200000 }` or `{ "<Map>": [...] }`.
38
+ - **References**: If an object is encountered more than once, subsequent occurrences are replaced with a reference path, e.g., `{ "<ref>": "$['users'][0]" }`.
39
+ - **Deserialization**: The `deserialize` function reconstructs the graph. It uses a multi-pass approach to resolve circular references (`ForwardRef`) ensuring the object graph identity is preserved.
40
+
41
+ ## 🚀 Basic Usage
42
+
43
+ The most common use case is serializing an object to a JSON string and restoring it.
44
+
45
+ ```typescript
46
+ import { stringSerialize, stringDeserialize } from '@tstdl/base/serializer';
47
+
48
+ const data = {
49
+ id: 1,
50
+ created: new Date(),
51
+ meta: new Map<string, any>([['role', 'admin']]),
52
+ tags: new Set(['user', 'active']),
53
+ };
54
+
55
+ // Serialize to JSON string
56
+ const json = stringSerialize(data);
57
+ console.log(json);
58
+ // Output: {"id":1,"created":{"<Date>":...},"meta":{"<Map>":[["role","admin"]]},"tags":{"<Set>":["user","active"]}}
59
+
60
+ // Deserialize back to object
61
+ const restored = stringDeserialize<typeof data>(json);
62
+
63
+ console.log(restored.created instanceof Date); // true
64
+ console.log(restored.meta instanceof Map); // true
65
+ console.log(restored.meta.get('role')); // 'admin'
66
+ ```
67
+
68
+ ## 🔧 Advanced Topics
69
+
70
+ ### Handling Circular References
71
+
72
+ You don't need to do anything special; the serializer handles this automatically.
73
+
74
+ ```typescript
75
+ import { serialize, deserialize } from '@tstdl/base/serializer';
76
+
77
+ type Node = { id: number; next?: Node };
78
+
79
+ const nodeA: Node = { id: 1 };
80
+ const nodeB: Node = { id: 2 };
81
+
82
+ nodeA.next = nodeB;
83
+ nodeB.next = nodeA; // Cycle
84
+
85
+ const serialized = serialize(nodeA);
86
+ const restored = deserialize<Node>(serialized);
87
+
88
+ console.log(restored.next?.next === restored); // true
89
+ ```
90
+
91
+ ### Custom Serializable Classes
92
+
93
+ To make your own classes serializable, implement the `Serializable` interface and use the `@serializable` decorator.
94
+
95
+ ```typescript
96
+ import { Serializable, serializable, TryDereference, stringSerialize, stringDeserialize } from '@tstdl/base/serializer';
97
+
98
+ type UserData = { name: string; email: string };
99
+
100
+ @serializable('User') // Unique type name
101
+ class User implements Serializable<User, UserData> {
102
+ constructor(
103
+ public name: string,
104
+ public email: string,
105
+ ) {}
106
+
107
+ // Define how to extract data.
108
+ // 'instance' is this, 'context' is from options.data
109
+ [Serializable.serialize](instance: User, context: any): UserData {
110
+ return { name: instance.name, email: instance.email };
111
+ }
112
+
113
+ // Define how to reconstruct the instance.
114
+ // 'tryDereference' is used to resolve circular references in complex data.
115
+ [Serializable.deserialize](data: UserData, tryDereference: TryDereference, context: any): User {
116
+ return new User(data.name, data.email);
117
+ }
118
+ }
119
+
120
+ const user = new User('Alice', 'alice@example.com');
121
+ const json = stringSerialize(user);
122
+ const restored = stringDeserialize<User>(json);
123
+
124
+ console.log(restored instanceof User); // true
125
+ console.log(restored.name); // 'Alice'
126
+ ```
127
+
128
+ ### Advanced Deserialization (Circular References)
129
+
130
+ If your custom data structure contains other objects that might have circular references back to the object currently being deserialized, use the `tryDereference` callback.
131
+
132
+ ```typescript
133
+ [Serializable.deserialize](data: any, tryDereference: TryDereference): Folder {
134
+ const folder = new Folder();
135
+
136
+ for (const childData of data.children) {
137
+ const child = deserialize(childData);
138
+ folder.add(child);
139
+
140
+ // If 'child' is a forward reference (not yet fully deserialized),
141
+ // this will register a callback to be called once it is.
142
+ tryDereference(child, (dereferenced) => {
143
+ // logic to update the reference if needed
144
+ });
145
+ }
146
+
147
+ return folder;
148
+ }
149
+ ```
150
+
151
+ ### Registering External Types
152
+
153
+ If you cannot modify the class (e.g., it comes from a third-party library), use `registerSerializer`.
154
+
155
+ ```typescript
156
+ import { registerSerializer, serialize, deserialize } from '@tstdl/base/serializer';
157
+
158
+ class Point {
159
+ constructor(
160
+ public x: number,
161
+ public y: number,
162
+ ) {}
163
+ }
164
+
165
+ // Register the serializer
166
+ registerSerializer(
167
+ Point,
168
+ 'Point',
169
+ (instance) => ({ x: instance.x, y: instance.y }), // Serializer
170
+ (data) => new Point(data.x, data.y), // Deserializer
171
+ );
172
+
173
+ const point = new Point(10, 20);
174
+ const serialized = serialize(point);
175
+ const restored = deserialize<Point>(serialized);
176
+
177
+ console.log(restored instanceof Point); // true
178
+ ```
179
+
180
+ ### Contextual Serialization
181
+
182
+ Use `context` to reference shared objects that exist in both the serialization and deserialization environments, reducing payload size.
183
+
184
+ ```typescript
185
+ import { serialize, deserialize } from '@tstdl/base/serializer';
186
+
187
+ const appConfig = { theme: 'dark', version: 2 };
188
+
189
+ const userSettings = {
190
+ notifications: true,
191
+ config: appConfig, // Reference to shared object
192
+ };
193
+
194
+ // Pass context during serialization
195
+ const serialized = serialize(userSettings, {
196
+ context: { appConfig },
197
+ });
198
+
199
+ // The serialized output will reference appConfig via path, not copy it.
200
+ // { "notifications": true, "config": { "<ref>": "$['__context__']['appConfig']" } }
201
+
202
+ // Pass the SAME context during deserialization
203
+ const restored = deserialize<typeof userSettings>(serialized, {
204
+ context: { appConfig },
205
+ });
206
+
207
+ console.log(restored.config === appConfig); // true
208
+ ```
209
+
210
+ ### Raw Serialization
211
+
212
+ Sometimes you want an object to be passed through as-is (treated as a primitive), or you know it is already JSON-safe and don't want the serializer to traverse it.
213
+
214
+ ```typescript
215
+ import { registerRawSerializable, serialize } from '@tstdl/base/serializer';
216
+
217
+ class Vector3 {
218
+ constructor(
219
+ public x: number,
220
+ public y: number,
221
+ public z: number,
222
+ ) {}
223
+ }
224
+
225
+ // Treat Vector3 as a raw object (properties are serialized directly, no type wrapper)
226
+ registerRawSerializable(Vector3);
227
+
228
+ const vec = new Vector3(1, 2, 3);
229
+ const serialized = serialize(vec);
230
+
231
+ console.log(serialized);
232
+ // Output: { x: 1, y: 2, z: 3 }
233
+ // Note: When deserialized, this will be a plain object, NOT an instance of Vector3.
234
+ ```
235
+
236
+ ### Replacers
237
+
238
+ Replacers allow you to transform values before they are processed by the serializer. This is useful for sanitizing data or handling types not known by the serializer.
239
+
240
+ ```typescript
241
+ import { serialize } from '@tstdl/base/serializer';
242
+
243
+ const data = { password: 'secret', name: 'Bob' };
244
+
245
+ const serialized = serialize(data, {
246
+ replacers: [
247
+ (value, context) => {
248
+ if (typeof value === 'object' && value !== null && 'password' in value) {
249
+ return { ...value, password: '***' };
250
+ }
251
+ return value;
252
+ }
253
+ ]
254
+ });
255
+
256
+ console.log(serialized.password); // '***'
257
+ ```
258
+
259
+ ### ⚠️ Security (Unsafe Serialization)
260
+
261
+ By default, the serializer throws an error if it encounters a `function`. You can enable function serialization using `allowUnsafe`.
262
+
263
+ > [!WARNING]
264
+ > Enabling `allowUnsafe` is dangerous. It uses `eval()` during deserialization, which can lead to **Remote Code Execution (RCE)** if the source data is not trusted. Use this only with data from verified, secure sources.
265
+
266
+ ```typescript
267
+ import { stringSerialize, stringDeserialize } from '@tstdl/base/serializer';
268
+
269
+ const data = {
270
+ greet: (name: string) => `Hello, ${name}!`,
271
+ };
272
+
273
+ const json = stringSerialize(data, { allowUnsafe: true });
274
+ const restored = stringDeserialize<typeof data>(json, { allowUnsafe: true });
275
+
276
+ console.log(restored.greet('World')); // 'Hello, World!'
277
+ ```
278
+
279
+ ## 📚 API
280
+
281
+ ### Functions
282
+
283
+ | Function | Description |
284
+ | :------------------------------------- | :---------------------------------------------------------------------------- |
285
+ | `serialize<T>(value, options?)` | Serializes a value into a JSON-compatible object structure (`Serialized<T>`). |
286
+ | `deserialize<T>(data, options?)` | Reconstructs a value from its serialized structure. |
287
+ | `stringSerialize<T>(value, options?)` | Helper that calls `serialize` and then `JSON.stringify`. |
288
+ | `stringDeserialize<T>(json, options?)` | Helper that calls `JSON.parse` and then `deserialize`. |
289
+ | `registerSerializer(...)` | Manually registers a serializer/deserializer pair for a class constructor. |
290
+ | `registerSerializable(type, name?)` | Registers a class that implements the `Serializable` interface. |
291
+ | `registerRawSerializable(ctor)` | Registers a constructor to be treated as a raw object (passed through). |
292
+
293
+ ### Decorators
294
+
295
+ | Decorator | Description |
296
+ | :------------------------- | :--------------------------------------------------------------- |
297
+ | `@serializable(typeName?)` | Class decorator to register a class implementing `Serializable`. |
298
+
299
+ ### Interfaces & Types
300
+
301
+ | Type | Description |
302
+ | :---------------------- | :--------------------------------------------------------------------------------------- |
303
+ | `Serializable<T, Data>` | Interface requiring `[Serializable.serialize]` and `[Serializable.deserialize]` methods. |
304
+ | `SerializationOptions` | Options object for serialization/deserialization. |
305
+
306
+ ### SerializationOptions
307
+
308
+ ```typescript
309
+ type SerializationOptions = {
310
+ /**
311
+ * Enable de/serialization of functions (unsafe!).
312
+ * @default false
313
+ */
314
+ allowUnsafe?: boolean;
315
+
316
+ /**
317
+ * Custom replacer functions to transform values before serialization.
318
+ */
319
+ replacers?: SerializationReplacer[];
320
+
321
+ /**
322
+ * Constructors to treat as raw (not serialized with type info).
323
+ */
324
+ raws?: AbstractConstructor[];
325
+
326
+ /**
327
+ * Context object for referencing shared data.
328
+ */
329
+ context?: Record<string, any>;
330
+
331
+ /**
332
+ * Data object passed to custom serializers/deserializers and replacers.
333
+ */
334
+ data?: Record<string, any>;
335
+
336
+ /**
337
+ * Disables dereferencing of ForwardRefs. Mostly useful for debugging custom serializers.
338
+ * @default false
339
+ */
340
+ doNotDereferenceForwardRefs?: boolean;
341
+ };
342
+ ```
@@ -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.