@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.
- package/README.md +166 -0
- package/ai/genkit/multi-region.plugin.js +5 -3
- package/ai/genkit/tests/multi-region.test.d.ts +1 -0
- package/ai/genkit/tests/multi-region.test.js +5 -2
- package/ai/parser/parser.js +2 -2
- package/ai/prompts/build.js +1 -0
- package/ai/prompts/instructions-formatter.d.ts +15 -2
- package/ai/prompts/instructions-formatter.js +36 -31
- package/ai/prompts/prompt-builder.js +5 -5
- package/ai/prompts/steering.d.ts +3 -2
- package/ai/prompts/steering.js +3 -1
- package/ai/tests/instructions-formatter.test.js +1 -0
- package/api/README.md +403 -0
- package/api/client/client.js +7 -13
- package/api/client/tests/api-client.test.js +10 -10
- package/api/default-error-handlers.js +1 -1
- package/api/response.d.ts +2 -2
- package/api/response.js +22 -33
- package/api/server/api-controller.d.ts +1 -1
- package/api/server/api-controller.js +3 -3
- package/api/server/api-request-token.provider.d.ts +1 -0
- package/api/server/api-request-token.provider.js +1 -0
- package/api/server/middlewares/allowed-methods.middleware.js +2 -1
- package/api/server/middlewares/content-type.middleware.js +2 -1
- package/api/types.d.ts +3 -2
- package/application/README.md +240 -0
- package/application/application.js +2 -2
- package/audit/README.md +267 -0
- package/authentication/README.md +288 -0
- package/authentication/client/authentication.service.d.ts +12 -11
- package/authentication/client/authentication.service.js +21 -21
- package/authentication/client/http-client.middleware.js +2 -2
- package/authentication/tests/authentication.client-error-handling.test.js +2 -1
- package/authentication/tests/authentication.client-service-refresh.test.js +5 -3
- package/browser/README.md +401 -0
- package/cancellation/README.md +156 -0
- package/cancellation/tests/coverage.test.d.ts +1 -0
- package/cancellation/tests/coverage.test.js +49 -0
- package/cancellation/tests/leak.test.d.ts +1 -0
- package/cancellation/tests/leak.test.js +35 -0
- package/cancellation/tests/token.test.d.ts +1 -0
- package/cancellation/tests/token.test.js +136 -0
- package/cancellation/token.d.ts +53 -177
- package/cancellation/token.js +132 -201
- package/context/README.md +174 -0
- package/cookie/README.md +161 -0
- package/css/README.md +157 -0
- package/data-structures/README.md +320 -0
- package/decorators/README.md +140 -0
- package/distributed-loop/README.md +231 -0
- package/distributed-loop/distributed-loop.js +1 -1
- package/document-management/README.md +403 -0
- package/document-management/server/services/document-management.service.js +9 -7
- package/document-management/tests/document-management-core.test.js +2 -7
- package/document-management/tests/document-management.api.test.js +6 -7
- package/document-management/tests/document-statistics.service.test.js +11 -12
- package/document-management/tests/document.service.test.js +3 -3
- package/document-management/tests/enum-helpers.test.js +2 -3
- package/dom/README.md +213 -0
- package/enumerable/README.md +259 -0
- package/enumeration/README.md +121 -0
- package/errors/README.md +267 -0
- package/file/README.md +191 -0
- package/formats/README.md +210 -0
- package/function/README.md +144 -0
- package/http/README.md +318 -0
- package/http/client/adapters/undici.adapter.js +1 -1
- package/http/client/http-client-request.d.ts +6 -5
- package/http/client/http-client-request.js +8 -9
- package/http/server/node/node-http-server.js +1 -2
- package/image-service/README.md +137 -0
- package/injector/README.md +491 -0
- package/injector/injector.d.ts +1 -0
- package/injector/injector.js +17 -5
- package/injector/tests/leak.test.d.ts +1 -0
- package/injector/tests/leak.test.js +45 -0
- package/intl/README.md +113 -0
- package/json-path/README.md +182 -0
- package/jsx/README.md +154 -0
- package/key-value-store/README.md +191 -0
- package/lock/README.md +249 -0
- package/lock/web/web-lock.js +119 -47
- package/logger/README.md +287 -0
- package/mail/README.md +256 -0
- package/memory/README.md +144 -0
- package/message-bus/README.md +244 -0
- package/message-bus/message-bus-base.js +1 -1
- package/module/README.md +182 -0
- package/module/module.d.ts +1 -1
- package/module/module.js +77 -17
- package/module/modules/web-server.module.js +1 -1
- package/notification/tests/notification-type.service.test.js +24 -15
- package/object-storage/README.md +300 -0
- package/openid-connect/README.md +274 -0
- package/orm/README.md +423 -0
- package/package.json +8 -6
- package/password/README.md +164 -0
- package/pdf/README.md +246 -0
- package/polyfills.js +1 -0
- package/pool/README.md +198 -0
- package/process/README.md +237 -0
- package/promise/README.md +252 -0
- package/promise/cancelable-promise.js +1 -1
- package/random/README.md +193 -0
- package/reflection/README.md +305 -0
- package/rpc/README.md +386 -0
- package/rxjs-utils/README.md +262 -0
- package/schema/README.md +342 -0
- package/serializer/README.md +342 -0
- package/signals/implementation/README.md +134 -0
- package/sse/README.md +278 -0
- package/task-queue/README.md +300 -0
- package/task-queue/postgres/task-queue.d.ts +2 -1
- package/task-queue/postgres/task-queue.js +32 -2
- package/task-queue/task-context.js +1 -1
- package/task-queue/task-queue.d.ts +17 -0
- package/task-queue/task-queue.js +103 -44
- package/task-queue/tests/complex.test.js +4 -4
- package/task-queue/tests/dependencies.test.js +4 -2
- package/task-queue/tests/queue.test.js +111 -0
- package/task-queue/tests/worker.test.js +21 -13
- package/templates/README.md +287 -0
- package/testing/README.md +157 -0
- package/text/README.md +346 -0
- package/threading/README.md +238 -0
- package/types/README.md +311 -0
- package/utils/README.md +322 -0
- package/utils/async-iterable-helpers/observable-iterable.d.ts +1 -1
- package/utils/async-iterable-helpers/observable-iterable.js +4 -8
- package/utils/async-iterable-helpers/take-until.js +4 -4
- package/utils/backoff.js +89 -30
- package/utils/retry-with-backoff.js +1 -1
- package/utils/timer.d.ts +1 -1
- package/utils/timer.js +5 -7
- package/utils/timing.d.ts +1 -1
- package/utils/timing.js +2 -4
- package/utils/z-base32.d.ts +1 -0
- package/utils/z-base32.js +1 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Promise
|
|
2
|
+
|
|
3
|
+
This module provides advanced Promise implementations to handle complex asynchronous patterns such as cancellation, deferred resolution, and lazy execution. It extends standard Promise capabilities to offer more control over asynchronous flows.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [✨ Features](#-features)
|
|
8
|
+
- [Core Concepts](#core-concepts)
|
|
9
|
+
- [CustomPromise](#custompromise)
|
|
10
|
+
- [DeferredPromise](#deferredpromise)
|
|
11
|
+
- [CancelablePromise](#cancelablepromise)
|
|
12
|
+
- [LazyPromise](#lazypromise)
|
|
13
|
+
- [🚀 Basic Usage](#-basic-usage)
|
|
14
|
+
- [Using DeferredPromise](#using-deferredpromise)
|
|
15
|
+
- [Using CancelablePromise](#using-cancelablepromise)
|
|
16
|
+
- [Using LazyPromise](#using-lazypromise)
|
|
17
|
+
- [🔧 Advanced Topics](#-advanced-topics)
|
|
18
|
+
- [Resetting a DeferredPromise](#resetting-a-deferredpromise)
|
|
19
|
+
- [Handling Cancellation Signals](#handling-cancellation-signals)
|
|
20
|
+
- [📚 API](#-api)
|
|
21
|
+
|
|
22
|
+
## ✨ Features
|
|
23
|
+
|
|
24
|
+
- **Deferred Resolution**: Control the resolution or rejection of a promise from outside its executor scope.
|
|
25
|
+
- **Cancellation Support**: Create promises that can be explicitly canceled, returning a specific result state.
|
|
26
|
+
- **Lazy Execution**: Define asynchronous logic that only executes when the promise is actually awaited or subscribed to.
|
|
27
|
+
- **State Inspection**: Synchronously check if a promise is pending, resolved, or rejected (specifically for `DeferredPromise`).
|
|
28
|
+
|
|
29
|
+
## Core Concepts
|
|
30
|
+
|
|
31
|
+
### CustomPromise
|
|
32
|
+
|
|
33
|
+
`CustomPromise` is a base class that extends the native `Promise`. It simplifies creating custom promise implementations by exposing the `resolve` and `reject` functions as protected fields to its subclasses. It also ensures that chained promises (via `then`, `catch`, etc.) return a standard `Promise` by overriding `Symbol.species`.
|
|
34
|
+
|
|
35
|
+
### DeferredPromise
|
|
36
|
+
|
|
37
|
+
A `DeferredPromise` is a Promise where the `resolve` and `reject` functions are exposed as public methods on the instance. This allows you to create a promise in one part of your application and settle it from another, effectively acting as a one-time signal or latch. It also supports being `reset()` to a pending state, allowing the same instance to be reused for sequential events.
|
|
38
|
+
|
|
39
|
+
### CancelablePromise
|
|
40
|
+
|
|
41
|
+
A `CancelablePromise` wraps an asynchronous operation that might need to be aborted. Unlike standard promises, it resolves to a result object that indicates whether the operation finished successfully or was canceled. It provides a `cancellationSignal` to the executor, which can be passed down to other cancelable operations (like `fetch` or timers).
|
|
42
|
+
|
|
43
|
+
### LazyPromise
|
|
44
|
+
|
|
45
|
+
A `LazyPromise` holds an executor function but does not run it immediately upon instantiation. The executor is only invoked when `then`, `catch`, or `finally` is called on the promise (usually when it is `await`ed). This is useful for defining expensive operations or network requests that should only occur if their result is strictly needed.
|
|
46
|
+
|
|
47
|
+
## 🚀 Basic Usage
|
|
48
|
+
|
|
49
|
+
### Using DeferredPromise
|
|
50
|
+
|
|
51
|
+
Use `DeferredPromise` when you need to wait for an event that happens elsewhere.
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { DeferredPromise } from '@tstdl/base/promise';
|
|
55
|
+
import { timeout } from '@tstdl/base/utils';
|
|
56
|
+
|
|
57
|
+
async function main() {
|
|
58
|
+
const signal = new DeferredPromise<string>();
|
|
59
|
+
|
|
60
|
+
// Simulate an async process that will trigger the signal
|
|
61
|
+
void (async () => {
|
|
62
|
+
console.log('Process started...');
|
|
63
|
+
await timeout(1000);
|
|
64
|
+
console.log('Process finished, resolving signal.');
|
|
65
|
+
signal.resolve('Operation Complete');
|
|
66
|
+
})();
|
|
67
|
+
|
|
68
|
+
console.log('Waiting for signal...');
|
|
69
|
+
const result = await signal;
|
|
70
|
+
console.log('Received:', result);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
main();
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Using CancelablePromise
|
|
77
|
+
|
|
78
|
+
Use `CancelablePromise` for operations that users might want to abort, such as a long-running calculation or a network request.
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { CancelablePromise } from '@tstdl/base/promise';
|
|
82
|
+
import { cancelableTimeout } from '@tstdl/base/utils';
|
|
83
|
+
|
|
84
|
+
const longOperation = new CancelablePromise<string, string>((resolve, reject, signal) => {
|
|
85
|
+
// Pass the signal to other cancelable utilities
|
|
86
|
+
cancelableTimeout(2000, signal)
|
|
87
|
+
.then(() => resolve('Finished successfully'))
|
|
88
|
+
.catch((error) => reject(error));
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
async function run() {
|
|
92
|
+
// Cancel the operation before it finishes
|
|
93
|
+
setTimeout(() => {
|
|
94
|
+
longOperation.cancel('User aborted');
|
|
95
|
+
}, 500);
|
|
96
|
+
|
|
97
|
+
const result = await longOperation;
|
|
98
|
+
|
|
99
|
+
if (result.canceled) {
|
|
100
|
+
console.log('Operation canceled:', result.reason);
|
|
101
|
+
} else {
|
|
102
|
+
console.log('Operation success:', result.value);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
run();
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Using LazyPromise
|
|
110
|
+
|
|
111
|
+
Use `LazyPromise` to define a task without starting it immediately. You can provide either a standard executor or an asynchronous promise provider function.
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
import { LazyPromise } from '@tstdl/base/promise';
|
|
115
|
+
|
|
116
|
+
// Using an executor
|
|
117
|
+
const expensiveTask = new LazyPromise<number>((resolve) => {
|
|
118
|
+
console.log('Expensive task starting now...');
|
|
119
|
+
resolve(42);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Using a promise provider
|
|
123
|
+
const lazyProvider = new LazyPromise(async () => {
|
|
124
|
+
console.log('Lazy provider starting now...');
|
|
125
|
+
return 'result';
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
async function main() {
|
|
129
|
+
console.log('Promises created, but tasks have not started.');
|
|
130
|
+
|
|
131
|
+
// The executor runs here, when we await
|
|
132
|
+
const value = await expensiveTask;
|
|
133
|
+
console.log('Result:', value);
|
|
134
|
+
|
|
135
|
+
const providerValue = await lazyProvider;
|
|
136
|
+
console.log('Provider Result:', providerValue);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
main();
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## 🔧 Advanced Topics
|
|
143
|
+
|
|
144
|
+
### Resetting a DeferredPromise
|
|
145
|
+
|
|
146
|
+
A `DeferredPromise` can be reused by calling `reset()`. This puts the promise back into a `Pending` state with a new underlying promise. Note that any previous awaiters will have already resolved with the previous value; `reset()` applies to future awaiters.
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
import { DeferredPromise } from '@tstdl/base/promise';
|
|
150
|
+
|
|
151
|
+
const gate = new DeferredPromise<void>();
|
|
152
|
+
|
|
153
|
+
async function worker(id: number) {
|
|
154
|
+
console.log(`Worker ${id} waiting at gate...`);
|
|
155
|
+
await gate;
|
|
156
|
+
console.log(`Worker ${id} passed.`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function main() {
|
|
160
|
+
// First batch
|
|
161
|
+
const w1 = worker(1);
|
|
162
|
+
const w2 = worker(2);
|
|
163
|
+
|
|
164
|
+
gate.resolve();
|
|
165
|
+
await Promise.all([w1, w2]);
|
|
166
|
+
|
|
167
|
+
// Reset for next batch
|
|
168
|
+
gate.reset();
|
|
169
|
+
|
|
170
|
+
// Second batch
|
|
171
|
+
const w3 = worker(3);
|
|
172
|
+
|
|
173
|
+
setTimeout(() => {
|
|
174
|
+
console.log('Opening gate again...');
|
|
175
|
+
gate.resolve();
|
|
176
|
+
}, 500);
|
|
177
|
+
|
|
178
|
+
await w3;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
main();
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Handling Cancellation Signals
|
|
185
|
+
|
|
186
|
+
When implementing a `CancelablePromise`, it is crucial to respect the `cancellationSignal`. This signal is an instance of `CancellationSignal` from the `@tstdl/base/cancellation` module.
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
import { CancelablePromise } from '@tstdl/base/promise';
|
|
190
|
+
import { CancellationToken } from '@tstdl/base/cancellation';
|
|
191
|
+
|
|
192
|
+
function doWork(token: CancellationToken) {
|
|
193
|
+
return new CancelablePromise<void, string>((resolve, _, signal) => {
|
|
194
|
+
// Link the external token to the internal signal
|
|
195
|
+
const unregister = token.register(() => {
|
|
196
|
+
// If the external token is cancelled, we cancel this promise
|
|
197
|
+
// Note: In a real scenario, you might just pass 'signal' down directly
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const timer = setTimeout(() => {
|
|
201
|
+
resolve();
|
|
202
|
+
}, 5000);
|
|
203
|
+
|
|
204
|
+
// Listen for cancellation on this specific promise
|
|
205
|
+
signal.register(() => {
|
|
206
|
+
clearTimeout(timer);
|
|
207
|
+
unregister();
|
|
208
|
+
console.log('Cleaned up resources due to cancellation');
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## 📚 API
|
|
215
|
+
|
|
216
|
+
### Classes
|
|
217
|
+
|
|
218
|
+
| Class | Description |
|
|
219
|
+
| :------------------------ | :---------------------------------------------------------------------------------------------------------------------------------- |
|
|
220
|
+
| `CustomPromise<T>` | A base class extending `Promise` that exposes `resolve` and `reject` to subclasses. |
|
|
221
|
+
| `DeferredPromise<T>` | A Promise that can be resolved or rejected externally. Supports state inspection (`pending`, `resolved`, `rejected`) and resetting. |
|
|
222
|
+
| `CancelablePromise<T, R>` | A Promise that wraps an operation which can be canceled. Resolves to a `CancelablePromiseResult`. |
|
|
223
|
+
| `LazyPromise<T>` | A Promise that executes its logic only when awaited or when `then`/`catch`/`finally` is called. |
|
|
224
|
+
|
|
225
|
+
### Types & Interfaces
|
|
226
|
+
|
|
227
|
+
| Type | Description |
|
|
228
|
+
| :------------------------------ | :----------------------------------------------------------------------------------------------------- |
|
|
229
|
+
| `PromiseExecutor<T>` | Standard executor function signature for Promises. |
|
|
230
|
+
| `CancelablePromiseExecutor<T>` | Executor signature for `CancelablePromise`, receiving `resolve`, `reject`, and a `CancellationSignal`. |
|
|
231
|
+
| `CancelablePromiseResult<T, R>` | Discriminated union result: `{ canceled: true, reason: R }` or `{ canceled: false, value: T }`. |
|
|
232
|
+
| `PromiseState` | Enum representing the state of a `DeferredPromise`: `Pending`, `Resolved`, `Rejected`. |
|
|
233
|
+
|
|
234
|
+
### DeferredPromise Methods
|
|
235
|
+
|
|
236
|
+
| Method | Description |
|
|
237
|
+
| :--------------------------- | :-------------------------------------------------------------------------------- |
|
|
238
|
+
| `resolve(value: T)` | Resolves the promise. Throws if already settled. |
|
|
239
|
+
| `reject(reason?: any)` | Rejects the promise. Throws if already settled. |
|
|
240
|
+
| `resolveIfPending(value: T)` | Resolves the promise only if it is currently pending. |
|
|
241
|
+
| `resolveAndReset(value: T)` | Resolves the current promise and immediately resets it to pending for future use. |
|
|
242
|
+
| `reset()` | Resets the promise to a pending state. |
|
|
243
|
+
| `pending` | Getter. Returns `true` if the promise is pending. |
|
|
244
|
+
| `resolved` | Getter. Returns `true` if the promise has been resolved. |
|
|
245
|
+
| `rejected` | Getter. Returns `true` if the promise has been rejected. |
|
|
246
|
+
| `settled` | Getter. Returns `true` if the promise is either resolved or rejected. |
|
|
247
|
+
|
|
248
|
+
### CancelablePromise Methods
|
|
249
|
+
|
|
250
|
+
| Method | Description |
|
|
251
|
+
| :------------------ | :--------------------------------------------------------------------------- |
|
|
252
|
+
| `cancel(reason: R)` | Cancels the promise. The promise resolves with `{ canceled: true, reason }`. |
|
|
@@ -20,7 +20,7 @@ export class CancelablePromise extends CustomPromise {
|
|
|
20
20
|
this.#pending = false;
|
|
21
21
|
}
|
|
22
22
|
};
|
|
23
|
-
executor((value) => this.#resolve(Promise.resolve(value).then((result) => ({ canceled: false, value: result }))), this.#reject, this.#cancellationToken
|
|
23
|
+
executor((value) => this.#resolve(Promise.resolve(value).then((result) => ({ canceled: false, value: result }))), this.#reject, this.#cancellationToken);
|
|
24
24
|
}
|
|
25
25
|
cancel(reason) {
|
|
26
26
|
this.#cancellationToken.set();
|
package/random/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Random
|
|
2
|
+
|
|
3
|
+
A comprehensive module for deterministic, seeded random number generation and simulation of random data series. It provides high-performance algorithms like Mulberry32 and SFC32, along with utilities for generating complex, bounded random walks.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [✨ Features](#-features)
|
|
8
|
+
- [Core Concepts](#core-concepts)
|
|
9
|
+
- [Seeded Random Number Generators](#seeded-random-number-generators)
|
|
10
|
+
- [Random Series Simulation](#random-series-simulation)
|
|
11
|
+
- [🚀 Basic Usage](#-basic-usage)
|
|
12
|
+
- [Using Mulberry32](#using-mulberry32)
|
|
13
|
+
- [Using SFC32](#using-sfc32)
|
|
14
|
+
- [Generating a Simple Series](#generating-a-simple-series)
|
|
15
|
+
- [🔧 Advanced Topics](#-advanced-topics)
|
|
16
|
+
- [Forking and Cloning Generators](#forking-and-cloning-generators)
|
|
17
|
+
- [Simulating Stock Charts (Complex Series)](#simulating-stock-charts-complex-series)
|
|
18
|
+
- [Cryptographically Secure Seeds](#cryptographically-secure-seeds)
|
|
19
|
+
- [📚 API](#-api)
|
|
20
|
+
|
|
21
|
+
## ✨ Features
|
|
22
|
+
|
|
23
|
+
- **Seeded RNGs**: Deterministic number generation using seeds, essential for reproducible tests and simulations.
|
|
24
|
+
- **High Performance Algorithms**: Includes implementations of **Mulberry32** (fast, 32-bit state) and **SFC32** (Small Fast Counter, 128-bit state).
|
|
25
|
+
- **State Management**: Capabilities to **fork** (create a new independent stream from current state) and **clone** (duplicate current state) generators.
|
|
26
|
+
- **Random Series Generator**: A powerful iterator for creating random walks, stock market simulations, or sensor data with configurable volatility, bounds, and regression to the mean.
|
|
27
|
+
- **Type Safety**: Fully typed TypeScript implementation.
|
|
28
|
+
|
|
29
|
+
## Core Concepts
|
|
30
|
+
|
|
31
|
+
### Seeded Random Number Generators
|
|
32
|
+
|
|
33
|
+
Standard `Math.random()` is not seedable, making it unsuitable for scenarios where you need reproducible results (e.g., procedural generation, testing, simulations). This module provides classes extending `SeededRandomNumberGenerator` that accept initial seeds. If initialized with the same seed, they produce the exact same sequence of numbers.
|
|
34
|
+
|
|
35
|
+
### Random Series Simulation
|
|
36
|
+
|
|
37
|
+
The `randomSeries` function is a generator that produces a stream of numbers. It models a "random walk" where the next value depends on the previous one, modified by volatility. It supports:
|
|
38
|
+
|
|
39
|
+
- **Bounds**: Keeping values within a specific range.
|
|
40
|
+
- **Regression**: Automatically pulling values back towards the mean when they approach bounds.
|
|
41
|
+
- **Dynamic Volatility**: Changing how erratic the series is over time.
|
|
42
|
+
|
|
43
|
+
## 🚀 Basic Usage
|
|
44
|
+
|
|
45
|
+
### Using Mulberry32
|
|
46
|
+
|
|
47
|
+
Mulberry32 is a very fast generator with a 32-bit state. It is excellent for most non-cryptographic use cases.
|
|
48
|
+
|
|
49
|
+
```ts
|
|
50
|
+
import { mulberry32 } from '@tstdl/base/random';
|
|
51
|
+
|
|
52
|
+
// Initialize with a specific seed for reproducibility
|
|
53
|
+
const rng = mulberry32(12345);
|
|
54
|
+
|
|
55
|
+
console.log(rng.next()); // Returns a float between 0 and 1
|
|
56
|
+
console.log(rng.nextInt()); // Returns a 32-bit integer
|
|
57
|
+
console.log(rng.next()); // Next value in the sequence
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Using SFC32
|
|
61
|
+
|
|
62
|
+
SFC32 (Small Fast Counter) has a 128-bit state, making it suitable when a longer period is required.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { sfc32 } from '@tstdl/base/random';
|
|
66
|
+
|
|
67
|
+
// Initialize with up to 4 seeds
|
|
68
|
+
const rng = sfc32(0x9e3779b9, 0x243f6a88, 0xb7e15162, 1);
|
|
69
|
+
|
|
70
|
+
console.log(rng.next());
|
|
71
|
+
console.log(rng.nextInt());
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Generating a Simple Series
|
|
75
|
+
|
|
76
|
+
Generate a random walk starting at 0.
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { randomSeries } from '@tstdl/base/random';
|
|
80
|
+
|
|
81
|
+
const series = randomSeries({
|
|
82
|
+
initial: 0,
|
|
83
|
+
volatility: 0.1, // 10% change per step
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
for (let i = 0; i < 5; i++) {
|
|
87
|
+
console.log(series.next().value);
|
|
88
|
+
}
|
|
89
|
+
// Output example: 0, 0.05, 0.048, 0.055, ...
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## 🔧 Advanced Topics
|
|
93
|
+
|
|
94
|
+
### Forking and Cloning Generators
|
|
95
|
+
|
|
96
|
+
You can branch RNGs to create independent streams or save state to retry a sequence.
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import { mulberry32 } from '@tstdl/base/random';
|
|
100
|
+
|
|
101
|
+
const rootRng = mulberry32(500);
|
|
102
|
+
|
|
103
|
+
// Fork: Creates a new RNG derived from the current state of rootRng.
|
|
104
|
+
// Useful for creating separate RNGs for different game entities or threads.
|
|
105
|
+
const entityRng = rootRng.fork();
|
|
106
|
+
|
|
107
|
+
// Clone: Creates an exact copy of the current state.
|
|
108
|
+
const savedStateRng = rootRng.clone();
|
|
109
|
+
|
|
110
|
+
console.log(rootRng.next()); // 0.123...
|
|
111
|
+
console.log(savedStateRng.next()); // 0.123... (Same as rootRng)
|
|
112
|
+
console.log(entityRng.next()); // 0.876... (Different sequence)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Simulating Stock Charts (Complex Series)
|
|
116
|
+
|
|
117
|
+
You can simulate complex data like stock prices by combining bounds, regression, and dynamic volatility.
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { randomSeries } from '@tstdl/base/random';
|
|
121
|
+
|
|
122
|
+
// Create a volatility provider that changes over time (e.g., market becomes more volatile)
|
|
123
|
+
const volatilitySeries = randomSeries({
|
|
124
|
+
bounds: [0.01, 0.05], // Volatility between 1% and 5%
|
|
125
|
+
initial: 0.02,
|
|
126
|
+
regressionExponent: 2,
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Create the price series
|
|
130
|
+
const stockPrice = randomSeries({
|
|
131
|
+
initial: 100,
|
|
132
|
+
bounds: [50, 150], // Price stays roughly between 50 and 150
|
|
133
|
+
volatility: volatilitySeries, // Use the dynamic volatility
|
|
134
|
+
relativeTo: 'current', // Changes are relative to the last price
|
|
135
|
+
regressionExponent: 5, // Strong pull back to mean (100) when near bounds
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
// Generate 10 data points
|
|
139
|
+
for (let i = 0; i < 10; i++) {
|
|
140
|
+
console.log(`Price: ${stockPrice.next().value?.toFixed(2)}`);
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Cryptographically Secure Seeds
|
|
145
|
+
|
|
146
|
+
If you need a random seed that is cryptographically secure to initialize your PRNG (Pseudo-Random Number Generator), use the utility provided.
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
import { mulberry32, random32BitSeedCrypto } from '@tstdl/base/random';
|
|
150
|
+
|
|
151
|
+
// Initialize Mulberry32 with a crypto-secure seed
|
|
152
|
+
const secureSeed = random32BitSeedCrypto();
|
|
153
|
+
const rng = mulberry32(secureSeed);
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## 📚 API
|
|
157
|
+
|
|
158
|
+
### Classes & Interfaces
|
|
159
|
+
|
|
160
|
+
| Name | Description |
|
|
161
|
+
| :---------------------------- | :------------------------------------------------------------------------------ |
|
|
162
|
+
| `RandomNumberGenerator` | Abstract base class defining `next()` and `nextInt()`. |
|
|
163
|
+
| `SeededRandomNumberGenerator` | Abstract class extending `RandomNumberGenerator` with `fork()` and `clone()`. |
|
|
164
|
+
| `Mulberry32` | Implementation of `SeededRandomNumberGenerator` using the Mulberry32 algorithm. |
|
|
165
|
+
| `Sfc32` | Implementation of `SeededRandomNumberGenerator` using the SFC32 algorithm. |
|
|
166
|
+
|
|
167
|
+
### Functions
|
|
168
|
+
|
|
169
|
+
| Name | Description |
|
|
170
|
+
| :------------------------------- | :----------------------------------------------------------------------------------- |
|
|
171
|
+
| `mulberry32(seed?)` | Factory function to create a `Mulberry32` instance. |
|
|
172
|
+
| `sfc32(seed1?, seed2?, ...)` | Factory function to create an `Sfc32` instance. |
|
|
173
|
+
| `randomSeries(options?)` | Generator function that yields a sequence of numbers based on simulation parameters. |
|
|
174
|
+
| `random32BitSeed()` | Generates a random 32-bit integer using `Math.random()`. |
|
|
175
|
+
| `random32BitSeedCrypto()` | Generates a random 32-bit integer using the environment's crypto API. |
|
|
176
|
+
| `defaultRandomNumberGeneratorFn` | The default RNG function (uses `Math.random`). |
|
|
177
|
+
|
|
178
|
+
### Types
|
|
179
|
+
|
|
180
|
+
#### `RandomNumberGeneratorFn`
|
|
181
|
+
|
|
182
|
+
A function that returns a random float in the range $[0, 1)$. Equivalent to `() => number`.
|
|
183
|
+
|
|
184
|
+
#### `RandomSeriesOptions`
|
|
185
|
+
|
|
186
|
+
| Property | Type | Default | Description |
|
|
187
|
+
| :------------------- | :------------------------------- | :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
188
|
+
| `initial` | `number \| [number, number]` | `bounds ?? 1` | Initial value or range for the series. If a range is provided, a random value within it is chosen using `generator`. |
|
|
189
|
+
| `bounds` | `[number, number]` | `undefined` | Optional `[min, max]` boundaries. When provided, a regression toward the mean is applied as values approach the edges. |
|
|
190
|
+
| `volatility` | `number \| Iterator<number>` | `0.025` | Change factor per step. Can be a fixed number or an iterator for dynamic volatility (e.g., using another `randomSeries`). |
|
|
191
|
+
| `relativeTo` | `'current' \| 'initial'` | `'initial'` | Determines if `volatility` is applied relative to the current value or the initial value. |
|
|
192
|
+
| `regressionExponent` | `number` | `10` | Controls the strength of the pull back toward the mean of `bounds`. Practical values range from 0.5 to 15. High values have little pull near the mean but exponential pull near the bounds. Values < 1 stay very close to the mean. |
|
|
193
|
+
| `generator` | `RandomNumberGeneratorFn` | `Math.random` | The source of randomness for the series. Use a seeded generator for reproducibility. |
|