@evolu/common 6.0.1-preview.9 → 7.0.0
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 +2 -2
- package/dist/src/Array.d.ts +256 -12
- package/dist/src/Array.d.ts.map +1 -1
- package/dist/src/Array.js +215 -9
- package/dist/src/Assert.d.ts +0 -13
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +0 -15
- package/dist/src/Brand.d.ts +75 -0
- package/dist/src/Brand.d.ts.map +1 -0
- package/dist/src/Brand.js +1 -0
- package/dist/src/Buffer.d.ts +1 -1
- package/dist/src/Buffer.d.ts.map +1 -1
- package/dist/src/Buffer.js +8 -7
- package/dist/src/Cache.d.ts +44 -0
- package/dist/src/Cache.d.ts.map +1 -0
- package/dist/src/Cache.js +52 -0
- package/dist/src/Callbacks.d.ts +45 -12
- package/dist/src/Callbacks.d.ts.map +1 -1
- package/dist/src/Callbacks.js +14 -7
- package/dist/src/Console.d.ts +31 -6
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +72 -9
- package/dist/src/Crypto.d.ts +56 -42
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +40 -53
- package/dist/src/Evolu/Db.d.ts +162 -74
- package/dist/src/Evolu/Db.d.ts.map +1 -1
- package/dist/src/Evolu/Db.js +284 -702
- package/dist/src/Evolu/Diff.d.ts +3 -3
- package/dist/src/Evolu/Diff.d.ts.map +1 -1
- package/dist/src/Evolu/Diff.js +7 -5
- package/dist/src/Evolu/Evolu.d.ts +213 -133
- package/dist/src/Evolu/Evolu.d.ts.map +1 -1
- package/dist/src/Evolu/Evolu.js +189 -180
- package/dist/src/Evolu/Internal.d.ts +0 -2
- package/dist/src/Evolu/Internal.d.ts.map +1 -1
- package/dist/src/Evolu/Internal.js +0 -2
- package/dist/src/Evolu/LocalAuth.d.ts +150 -0
- package/dist/src/Evolu/LocalAuth.d.ts.map +1 -0
- package/dist/src/Evolu/LocalAuth.js +174 -0
- package/dist/src/Evolu/Owner.d.ts +273 -120
- package/dist/src/Evolu/Owner.d.ts.map +1 -1
- package/dist/src/Evolu/Owner.js +130 -104
- package/dist/src/Evolu/Platform.d.ts +9 -7
- package/dist/src/Evolu/Platform.d.ts.map +1 -1
- package/dist/src/Evolu/Protocol.d.ts +268 -240
- package/dist/src/Evolu/Protocol.d.ts.map +1 -1
- package/dist/src/Evolu/Protocol.js +595 -447
- package/dist/src/Evolu/Public.d.ts +6 -8
- package/dist/src/Evolu/Public.d.ts.map +1 -1
- package/dist/src/Evolu/Public.js +2 -3
- package/dist/src/Evolu/PublicKysely.d.ts.map +1 -1
- package/dist/src/Evolu/PublicKysely.js +3 -4
- package/dist/src/Evolu/Query.d.ts +2 -1
- package/dist/src/Evolu/Query.d.ts.map +1 -1
- package/dist/src/Evolu/Query.js +1 -1
- package/dist/src/Evolu/Relay.d.ts +91 -8
- package/dist/src/Evolu/Relay.d.ts.map +1 -1
- package/dist/src/Evolu/Relay.js +214 -88
- package/dist/src/Evolu/Schema.d.ts +125 -47
- package/dist/src/Evolu/Schema.d.ts.map +1 -1
- package/dist/src/Evolu/Schema.js +175 -31
- package/dist/src/Evolu/Storage.d.ts +249 -27
- package/dist/src/Evolu/Storage.d.ts.map +1 -1
- package/dist/src/Evolu/Storage.js +198 -92
- package/dist/src/Evolu/Sync.d.ts +68 -13
- package/dist/src/Evolu/Sync.d.ts.map +1 -1
- package/dist/src/Evolu/Sync.js +469 -20
- package/dist/src/Evolu/Timestamp.d.ts +83 -30
- package/dist/src/Evolu/Timestamp.d.ts.map +1 -1
- package/dist/src/Evolu/Timestamp.js +79 -34
- package/dist/src/Identicon.d.ts +35 -0
- package/dist/src/Identicon.d.ts.map +1 -0
- package/dist/src/Identicon.js +143 -0
- package/dist/src/Instances.d.ts +34 -0
- package/dist/src/Instances.d.ts.map +1 -0
- package/dist/src/Instances.js +44 -0
- package/dist/src/Number.d.ts +4 -3
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +5 -4
- package/dist/src/Object.d.ts +10 -4
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +9 -3
- package/dist/src/Platform.d.ts +20 -0
- package/dist/src/Platform.d.ts.map +1 -0
- package/dist/src/Platform.js +22 -0
- package/dist/src/Random.d.ts +3 -2
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/Relation.d.ts +79 -0
- package/dist/src/Relation.d.ts.map +1 -0
- package/dist/src/Relation.js +127 -0
- package/dist/src/Resources.d.ts +118 -0
- package/dist/src/Resources.d.ts.map +1 -0
- package/dist/src/Resources.js +197 -0
- package/dist/src/Result.d.ts +184 -52
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +30 -241
- package/dist/src/Skiplist.js +2 -1
- package/dist/src/Sqlite.d.ts +89 -5
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +136 -9
- package/dist/src/Task.d.ts +586 -0
- package/dist/src/Task.d.ts.map +1 -0
- package/dist/src/Task.js +469 -0
- package/dist/src/Time.d.ts +66 -1
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +99 -5
- package/dist/src/Type.d.ts +676 -343
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +718 -467
- package/dist/src/Types.d.ts +1 -75
- package/dist/src/Types.d.ts.map +1 -1
- package/dist/src/WebSocket.d.ts +5 -2
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +12 -18
- package/dist/src/Worker.d.ts +39 -11
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +22 -4
- package/dist/src/index.d.ts +8 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -3
- package/package.json +14 -13
- package/src/Array.ts +301 -19
- package/src/Assert.ts +0 -21
- package/src/Brand.ts +75 -0
- package/src/Buffer.ts +7 -7
- package/src/Cache.ts +85 -0
- package/src/Callbacks.ts +62 -22
- package/src/Console.ts +91 -11
- package/src/Crypto.ts +94 -90
- package/src/Evolu/Db.ts +519 -1026
- package/src/Evolu/Diff.ts +7 -5
- package/src/Evolu/Evolu.ts +476 -360
- package/src/Evolu/Internal.ts +0 -2
- package/src/Evolu/LocalAuth.ts +463 -0
- package/src/Evolu/Owner.ts +355 -228
- package/src/Evolu/Platform.ts +9 -9
- package/src/Evolu/Protocol.ts +846 -742
- package/src/Evolu/Public.ts +7 -14
- package/src/Evolu/PublicKysely.ts +4 -5
- package/src/Evolu/Query.ts +3 -2
- package/src/Evolu/Relay.ts +406 -103
- package/src/Evolu/Schema.ts +323 -91
- package/src/Evolu/Storage.ts +559 -137
- package/src/Evolu/Sync.ts +819 -36
- package/src/Evolu/Timestamp.ts +90 -58
- package/src/Identicon.ts +197 -0
- package/src/Instances.ts +90 -0
- package/src/Number.ts +6 -10
- package/src/Object.ts +13 -5
- package/src/Platform.ts +26 -0
- package/src/Random.ts +3 -2
- package/src/Relation.ts +234 -0
- package/src/Resources.ts +367 -0
- package/src/Result.ts +191 -54
- package/src/Skiplist.ts +1 -1
- package/src/Sqlite.ts +152 -17
- package/src/Task.ts +901 -0
- package/src/Time.ts +180 -5
- package/src/Type.ts +1135 -730
- package/src/Types.ts +1 -77
- package/src/WebSocket.ts +27 -25
- package/src/Worker.ts +72 -23
- package/src/index.ts +8 -3
- package/dist/src/Evolu/Config.d.ts +0 -69
- package/dist/src/Evolu/Config.d.ts.map +0 -1
- package/dist/src/Evolu/Config.js +0 -9
- package/dist/src/Evolu/Kysely.d.ts +0 -6
- package/dist/src/Evolu/Kysely.d.ts.map +0 -1
- package/dist/src/Evolu/Kysely.js +0 -21
- package/dist/src/ManyToManyMap.d.ts +0 -26
- package/dist/src/ManyToManyMap.d.ts.map +0 -1
- package/dist/src/ManyToManyMap.js +0 -92
- package/dist/src/NanoId.d.ts +0 -27
- package/dist/src/NanoId.d.ts.map +0 -1
- package/dist/src/NanoId.js +0 -6
- package/dist/src/Promise.d.ts +0 -180
- package/dist/src/Promise.d.ts.map +0 -1
- package/dist/src/Promise.js +0 -176
- package/src/Evolu/Config.ts +0 -83
- package/src/Evolu/Kysely.ts +0 -38
- package/src/ManyToManyMap.ts +0 -140
- package/src/NanoId.ts +0 -39
- package/src/Promise.ts +0 -295
package/dist/src/Promise.d.ts
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import { Result } from "./Result.js";
|
|
2
|
-
import { Predicate } from "./Types.js";
|
|
3
|
-
/**
|
|
4
|
-
* Helper function to delay execution for a specified number of milliseconds.
|
|
5
|
-
*
|
|
6
|
-
* ### Example
|
|
7
|
-
*
|
|
8
|
-
* ```ts
|
|
9
|
-
* await wait(10);
|
|
10
|
-
* ```
|
|
11
|
-
*/
|
|
12
|
-
export declare const wait: (ms: number) => Promise<Result<void, never>>;
|
|
13
|
-
/** Options for configuring retry behavior. */
|
|
14
|
-
export interface RetryOptions<E> {
|
|
15
|
-
/**
|
|
16
|
-
* Maximum number of retry attempts after the initial attempt (default: 3).
|
|
17
|
-
* For example, with maxRetries = 3, the function will be called up to 4 times
|
|
18
|
-
* (1 initial attempt + 3 retries).
|
|
19
|
-
*/
|
|
20
|
-
maxRetries?: number;
|
|
21
|
-
/**
|
|
22
|
-
* Initial delay between retry attempts in milliseconds (default: 100). This
|
|
23
|
-
* is the delay after the first failed attempt. Subsequent delays increase
|
|
24
|
-
* exponentially according to the factor option.
|
|
25
|
-
*/
|
|
26
|
-
initialDelay?: number;
|
|
27
|
-
/**
|
|
28
|
-
* Maximum delay between retry attempts in milliseconds (default: 10000). This
|
|
29
|
-
* caps the exponential backoff to prevent extremely long delays after many
|
|
30
|
-
* retries.
|
|
31
|
-
*/
|
|
32
|
-
maxDelay?: number;
|
|
33
|
-
/**
|
|
34
|
-
* Multiplier that determines how quickly the delay increases (default: 2).
|
|
35
|
-
* With the default value, each successive delay is twice as long as the
|
|
36
|
-
* previous one (e.g., 100ms, 200ms, 400ms, 800ms, etc).
|
|
37
|
-
*/
|
|
38
|
-
factor?: number;
|
|
39
|
-
/**
|
|
40
|
-
* Random jitter factor between 0 and 1 (default: 0.1). Adds randomness to
|
|
41
|
-
* delay times to prevent retry storms in distributed systems.
|
|
42
|
-
*/
|
|
43
|
-
jitter?: number;
|
|
44
|
-
/**
|
|
45
|
-
* Optional AbortSignal to cancel retries. If the signal is aborted, the retry
|
|
46
|
-
* operation stops and returns a RetryAbortError.
|
|
47
|
-
*/
|
|
48
|
-
signal?: AbortSignal;
|
|
49
|
-
/**
|
|
50
|
-
* Optional predicate to determine if an error should be retried. Returns true
|
|
51
|
-
* if the error is retryable, false otherwise. This allows selectively
|
|
52
|
-
* retrying only certain types of errors. By default, all errors are
|
|
53
|
-
* considered retryable.
|
|
54
|
-
*/
|
|
55
|
-
retryable?: Predicate<E>;
|
|
56
|
-
/**
|
|
57
|
-
* Optional callback called before each retry attempt. Receives the error that
|
|
58
|
-
* caused the retry, the current attempt number (starting at 1), and the delay
|
|
59
|
-
* in milliseconds before the next attempt.
|
|
60
|
-
*/
|
|
61
|
-
onRetry?: (error: E, attempt: number, delay: number) => void;
|
|
62
|
-
}
|
|
63
|
-
/** Error representing a retry operation that failed after multiple attempts. */
|
|
64
|
-
export interface RetryError<E> {
|
|
65
|
-
readonly type: "RetryError";
|
|
66
|
-
/** The original error that caused the retry to fail */
|
|
67
|
-
readonly cause: E;
|
|
68
|
-
/** Number of retry attempts made */
|
|
69
|
-
readonly attempts: number;
|
|
70
|
-
}
|
|
71
|
-
/** Error representing a retry operation that was aborted. */
|
|
72
|
-
export interface RetryAbortError {
|
|
73
|
-
readonly type: "RetryAbortError";
|
|
74
|
-
readonly abortedBeforeExecution: boolean;
|
|
75
|
-
}
|
|
76
|
-
/**
|
|
77
|
-
* Executes a function with retry logic using exponential backoff and jitter.
|
|
78
|
-
*
|
|
79
|
-
* ### Example with Result-based API
|
|
80
|
-
*
|
|
81
|
-
* ```ts
|
|
82
|
-
* interface ApiError {
|
|
83
|
-
* type: "ApiError";
|
|
84
|
-
* statusCode: number;
|
|
85
|
-
* }
|
|
86
|
-
*
|
|
87
|
-
* const fetchData = async (
|
|
88
|
-
* url: string,
|
|
89
|
-
* ): Promise<Result<Data, ApiError>> => {
|
|
90
|
-
* // Implementation that returns Result
|
|
91
|
-
* };
|
|
92
|
-
*
|
|
93
|
-
* const result = await retry(
|
|
94
|
-
* async () => fetchData("https://api.example.com/data"),
|
|
95
|
-
* {
|
|
96
|
-
* maxRetries: 5,
|
|
97
|
-
* initialDelay: 200,
|
|
98
|
-
* // Only retry on specific status codes
|
|
99
|
-
* retryable: (error) =>
|
|
100
|
-
* error.type === "ApiError" && [429, 503].includes(error.statusCode),
|
|
101
|
-
* },
|
|
102
|
-
* );
|
|
103
|
-
*
|
|
104
|
-
* if (!result.ok) {
|
|
105
|
-
* if (result.error.type === "RetryAbortError") {
|
|
106
|
-
* console.log("Operation was aborted");
|
|
107
|
-
* } else {
|
|
108
|
-
* console.log(`Failed after ${result.error.attempts} attempts`);
|
|
109
|
-
* }
|
|
110
|
-
* return;
|
|
111
|
-
* }
|
|
112
|
-
*
|
|
113
|
-
* // Use result.value
|
|
114
|
-
* ```
|
|
115
|
-
*
|
|
116
|
-
* ### Example with tryAsync for exception-based API
|
|
117
|
-
*
|
|
118
|
-
* ```ts
|
|
119
|
-
* interface FetchError {
|
|
120
|
-
* type: "FetchError";
|
|
121
|
-
* message: string;
|
|
122
|
-
* }
|
|
123
|
-
*
|
|
124
|
-
* const controller = new AbortController();
|
|
125
|
-
*
|
|
126
|
-
* const result = await retry(
|
|
127
|
-
* async () =>
|
|
128
|
-
* tryAsync(
|
|
129
|
-
* async () => {
|
|
130
|
-
* const response = await fetch("https://api.example.com/data", {
|
|
131
|
-
* signal: controller.signal,
|
|
132
|
-
* });
|
|
133
|
-
*
|
|
134
|
-
* if (!response.ok) {
|
|
135
|
-
* throw new Error(`HTTP error ${response.status}`);
|
|
136
|
-
* }
|
|
137
|
-
*
|
|
138
|
-
* return await response.json();
|
|
139
|
-
* },
|
|
140
|
-
* (error): FetchError => ({
|
|
141
|
-
* type: "FetchError",
|
|
142
|
-
* message: String(error),
|
|
143
|
-
* }),
|
|
144
|
-
* ),
|
|
145
|
-
* {
|
|
146
|
-
* maxRetries: 3,
|
|
147
|
-
* signal: controller.signal,
|
|
148
|
-
* },
|
|
149
|
-
* );
|
|
150
|
-
* ```
|
|
151
|
-
*
|
|
152
|
-
* ## HTTP Request Recommendations
|
|
153
|
-
*
|
|
154
|
-
* For HTTP requests, configure the `retryable` option to only retry on
|
|
155
|
-
* appropriate errors:
|
|
156
|
-
*
|
|
157
|
-
* - **DO retry**: 429 (Too Many Requests), 503 (Service Unavailable), network
|
|
158
|
-
* errors
|
|
159
|
-
* - **DON'T retry**: 4xx client errors (except 429), most 5xx server errors
|
|
160
|
-
*/
|
|
161
|
-
export declare const retry: <T, E>(fn: () => Promise<Result<T, E>>, options?: RetryOptions<E>) => Promise<Result<T, RetryError<E> | RetryAbortError>>;
|
|
162
|
-
export interface TimeoutError {
|
|
163
|
-
readonly type: "TimeoutError";
|
|
164
|
-
readonly timeoutMs: number;
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Wraps an async function with a timeout, returning {@link Result} that fails
|
|
168
|
-
* with {@link TimeoutError} if the timeout is exceeded. The provided function
|
|
169
|
-
* must accept an AbortSignal and return a Result.
|
|
170
|
-
*
|
|
171
|
-
* ### Example
|
|
172
|
-
*
|
|
173
|
-
* ```ts
|
|
174
|
-
* const fetchWithTimeout = () =>
|
|
175
|
-
* withTimeout((signal) => fetch("url", signal), 5000);
|
|
176
|
-
* const result = await retry(fetchWithTimeout, { maxRetries: 3 });
|
|
177
|
-
* ```
|
|
178
|
-
*/
|
|
179
|
-
export declare const withTimeout: <T, E>(fn: (signal: AbortSignal) => Promise<Result<T, E>>, timeoutMs: number) => Promise<Result<T, E | TimeoutError>>;
|
|
180
|
-
//# sourceMappingURL=Promise.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Promise.d.ts","sourceRoot":"","sources":["../../src/Promise.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAW,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC;;;;;;;;GAQG;AACH,eAAO,MAAM,IAAI,GAAI,IAAI,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAK1D,CAAC;AAEJ,8CAA8C;AAC9C,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB;;;OAGG;IACH,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC;IAEzB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9D;AAED,gFAAgF;AAChF,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,uDAAuD;IACvD,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAClB,oCAAoC;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,6DAA6D;AAC7D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,iBAAiB,CAAC;IACjC,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoFG;AACH,eAAO,MAAM,KAAK,GAAU,CAAC,EAAE,CAAC,EAC9B,IAAI,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAC/B,UAAS,YAAY,CAAC,CAAC,CAAM,KAC5B,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CA2EpD,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,WAAW,GAAU,CAAC,EAAE,CAAC,EACpC,IAAI,CAAC,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAClD,WAAW,MAAM,KAChB,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,CAerC,CAAC"}
|
package/dist/src/Promise.js
DELETED
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import { constTrue } from "./Function.js";
|
|
2
|
-
import { err, ok } from "./Result.js";
|
|
3
|
-
/**
|
|
4
|
-
* Helper function to delay execution for a specified number of milliseconds.
|
|
5
|
-
*
|
|
6
|
-
* ### Example
|
|
7
|
-
*
|
|
8
|
-
* ```ts
|
|
9
|
-
* await wait(10);
|
|
10
|
-
* ```
|
|
11
|
-
*/
|
|
12
|
-
export const wait = (ms) => new Promise((resolve) => setTimeout(() => {
|
|
13
|
-
resolve(ok());
|
|
14
|
-
}, ms));
|
|
15
|
-
/**
|
|
16
|
-
* Executes a function with retry logic using exponential backoff and jitter.
|
|
17
|
-
*
|
|
18
|
-
* ### Example with Result-based API
|
|
19
|
-
*
|
|
20
|
-
* ```ts
|
|
21
|
-
* interface ApiError {
|
|
22
|
-
* type: "ApiError";
|
|
23
|
-
* statusCode: number;
|
|
24
|
-
* }
|
|
25
|
-
*
|
|
26
|
-
* const fetchData = async (
|
|
27
|
-
* url: string,
|
|
28
|
-
* ): Promise<Result<Data, ApiError>> => {
|
|
29
|
-
* // Implementation that returns Result
|
|
30
|
-
* };
|
|
31
|
-
*
|
|
32
|
-
* const result = await retry(
|
|
33
|
-
* async () => fetchData("https://api.example.com/data"),
|
|
34
|
-
* {
|
|
35
|
-
* maxRetries: 5,
|
|
36
|
-
* initialDelay: 200,
|
|
37
|
-
* // Only retry on specific status codes
|
|
38
|
-
* retryable: (error) =>
|
|
39
|
-
* error.type === "ApiError" && [429, 503].includes(error.statusCode),
|
|
40
|
-
* },
|
|
41
|
-
* );
|
|
42
|
-
*
|
|
43
|
-
* if (!result.ok) {
|
|
44
|
-
* if (result.error.type === "RetryAbortError") {
|
|
45
|
-
* console.log("Operation was aborted");
|
|
46
|
-
* } else {
|
|
47
|
-
* console.log(`Failed after ${result.error.attempts} attempts`);
|
|
48
|
-
* }
|
|
49
|
-
* return;
|
|
50
|
-
* }
|
|
51
|
-
*
|
|
52
|
-
* // Use result.value
|
|
53
|
-
* ```
|
|
54
|
-
*
|
|
55
|
-
* ### Example with tryAsync for exception-based API
|
|
56
|
-
*
|
|
57
|
-
* ```ts
|
|
58
|
-
* interface FetchError {
|
|
59
|
-
* type: "FetchError";
|
|
60
|
-
* message: string;
|
|
61
|
-
* }
|
|
62
|
-
*
|
|
63
|
-
* const controller = new AbortController();
|
|
64
|
-
*
|
|
65
|
-
* const result = await retry(
|
|
66
|
-
* async () =>
|
|
67
|
-
* tryAsync(
|
|
68
|
-
* async () => {
|
|
69
|
-
* const response = await fetch("https://api.example.com/data", {
|
|
70
|
-
* signal: controller.signal,
|
|
71
|
-
* });
|
|
72
|
-
*
|
|
73
|
-
* if (!response.ok) {
|
|
74
|
-
* throw new Error(`HTTP error ${response.status}`);
|
|
75
|
-
* }
|
|
76
|
-
*
|
|
77
|
-
* return await response.json();
|
|
78
|
-
* },
|
|
79
|
-
* (error): FetchError => ({
|
|
80
|
-
* type: "FetchError",
|
|
81
|
-
* message: String(error),
|
|
82
|
-
* }),
|
|
83
|
-
* ),
|
|
84
|
-
* {
|
|
85
|
-
* maxRetries: 3,
|
|
86
|
-
* signal: controller.signal,
|
|
87
|
-
* },
|
|
88
|
-
* );
|
|
89
|
-
* ```
|
|
90
|
-
*
|
|
91
|
-
* ## HTTP Request Recommendations
|
|
92
|
-
*
|
|
93
|
-
* For HTTP requests, configure the `retryable` option to only retry on
|
|
94
|
-
* appropriate errors:
|
|
95
|
-
*
|
|
96
|
-
* - **DO retry**: 429 (Too Many Requests), 503 (Service Unavailable), network
|
|
97
|
-
* errors
|
|
98
|
-
* - **DON'T retry**: 4xx client errors (except 429), most 5xx server errors
|
|
99
|
-
*/
|
|
100
|
-
export const retry = async (fn, options = {}) => {
|
|
101
|
-
const { maxRetries = 3, initialDelay = 100, maxDelay = 10000, factor = 2, jitter = 0.1, signal, retryable = constTrue, onRetry, } = options;
|
|
102
|
-
let attempt = 0;
|
|
103
|
-
if (signal?.aborted) {
|
|
104
|
-
return err({ type: "RetryAbortError", abortedBeforeExecution: true });
|
|
105
|
-
}
|
|
106
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
107
|
-
while (true) {
|
|
108
|
-
const result = await fn();
|
|
109
|
-
if (result.ok) {
|
|
110
|
-
return result;
|
|
111
|
-
}
|
|
112
|
-
attempt += 1;
|
|
113
|
-
if (attempt > maxRetries || !retryable(result.error)) {
|
|
114
|
-
return err({
|
|
115
|
-
type: "RetryError",
|
|
116
|
-
cause: result.error,
|
|
117
|
-
attempts: attempt,
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
// Calculate delay with exponential backoff
|
|
121
|
-
const exponentialDelay = initialDelay * Math.pow(factor, attempt);
|
|
122
|
-
const cappedDelay = Math.min(exponentialDelay, maxDelay);
|
|
123
|
-
// Apply jitter to prevent thundering herd problem
|
|
124
|
-
const randomFactor = 1 - jitter + Math.random() * jitter * 2;
|
|
125
|
-
const delay = Math.floor(cappedDelay * randomFactor);
|
|
126
|
-
if (onRetry) {
|
|
127
|
-
onRetry(result.error, attempt, delay);
|
|
128
|
-
}
|
|
129
|
-
if (signal?.aborted) {
|
|
130
|
-
return err({ type: "RetryAbortError", abortedBeforeExecution: false });
|
|
131
|
-
}
|
|
132
|
-
// Wait with abort support
|
|
133
|
-
if (signal) {
|
|
134
|
-
const abortPromise = new Promise((resolve) => {
|
|
135
|
-
const onAbort = () => {
|
|
136
|
-
resolve(err({ type: "RetryAbortError", abortedBeforeExecution: false }));
|
|
137
|
-
};
|
|
138
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
139
|
-
});
|
|
140
|
-
const delayPromise = wait(delay);
|
|
141
|
-
const raceResult = await Promise.race([abortPromise, delayPromise]);
|
|
142
|
-
if (!raceResult.ok) {
|
|
143
|
-
return raceResult;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
else {
|
|
147
|
-
await wait(delay);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
/**
|
|
152
|
-
* Wraps an async function with a timeout, returning {@link Result} that fails
|
|
153
|
-
* with {@link TimeoutError} if the timeout is exceeded. The provided function
|
|
154
|
-
* must accept an AbortSignal and return a Result.
|
|
155
|
-
*
|
|
156
|
-
* ### Example
|
|
157
|
-
*
|
|
158
|
-
* ```ts
|
|
159
|
-
* const fetchWithTimeout = () =>
|
|
160
|
-
* withTimeout((signal) => fetch("url", signal), 5000);
|
|
161
|
-
* const result = await retry(fetchWithTimeout, { maxRetries: 3 });
|
|
162
|
-
* ```
|
|
163
|
-
*/
|
|
164
|
-
export const withTimeout = async (fn, timeoutMs) => {
|
|
165
|
-
const controller = new AbortController();
|
|
166
|
-
const signal = controller.signal;
|
|
167
|
-
const timeoutId = setTimeout(() => {
|
|
168
|
-
controller.abort();
|
|
169
|
-
}, timeoutMs);
|
|
170
|
-
const result = await fn(signal);
|
|
171
|
-
clearTimeout(timeoutId);
|
|
172
|
-
if (signal.aborted) {
|
|
173
|
-
return err({ type: "TimeoutError", timeoutMs });
|
|
174
|
-
}
|
|
175
|
-
return result;
|
|
176
|
-
};
|
package/src/Evolu/Config.ts
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { ConsoleConfig } from "../Console.js";
|
|
2
|
-
import { getOrThrow } from "../Result.js";
|
|
3
|
-
import { Mnemonic, SimpleName } from "../Type.js";
|
|
4
|
-
import type { DbIndexesBuilder } from "./Kysely.js";
|
|
5
|
-
|
|
6
|
-
export interface Config extends ConsoleConfig {
|
|
7
|
-
/**
|
|
8
|
-
* The name of Evolu instances. Evolu is multitenant - it can run more
|
|
9
|
-
* instances concurrently. Every Evolu instance has to have its own unique
|
|
10
|
-
* name. Database files are separated and invisible to each other.
|
|
11
|
-
*
|
|
12
|
-
* The default value is: `Evolu`.
|
|
13
|
-
*
|
|
14
|
-
* ### Example
|
|
15
|
-
*
|
|
16
|
-
* ```ts
|
|
17
|
-
* // name: getOrThrow(SimpleName.from("MyApp"))
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
readonly name: SimpleName;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* URL for Evolu sync and backup server.
|
|
24
|
-
*
|
|
25
|
-
* The default value is `https://free.evoluhq.com`.
|
|
26
|
-
*/
|
|
27
|
-
readonly syncUrl: string;
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* URL to reload browser tabs after reset or restore.
|
|
31
|
-
*
|
|
32
|
-
* The default value is `/`.
|
|
33
|
-
*/
|
|
34
|
-
readonly reloadUrl: string;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Maximum physical clock drift allowed in ms.
|
|
38
|
-
*
|
|
39
|
-
* The default value is 5 * 60 * 1000 (5 minutes).
|
|
40
|
-
*/
|
|
41
|
-
readonly maxDrift: number;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Use the `indexes` option to define SQLite indexes.
|
|
45
|
-
*
|
|
46
|
-
* Table and column names are not typed because Kysely doesn't support it.
|
|
47
|
-
*
|
|
48
|
-
* https://medium.com/@JasonWyatt/squeezing-performance-from-sqlite-indexes-indexes-c4e175f3c346
|
|
49
|
-
*
|
|
50
|
-
* ### Example
|
|
51
|
-
*
|
|
52
|
-
* ```ts
|
|
53
|
-
* const evolu = createEvolu(evoluReactDeps)(Schema, {
|
|
54
|
-
* indexes: (create) => [
|
|
55
|
-
* create("todoCreatedAt").on("todo").column("createdAt"),
|
|
56
|
-
* create("todoCategoryCreatedAt")
|
|
57
|
-
* .on("todoCategory")
|
|
58
|
-
* .column("createdAt"),
|
|
59
|
-
* ],
|
|
60
|
-
* });
|
|
61
|
-
* ```
|
|
62
|
-
*/
|
|
63
|
-
readonly indexes?: DbIndexesBuilder;
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Use this option to create Evolu with the specified mnemonic. If omitted,
|
|
67
|
-
* the mnemonic will be autogenerated. That should be the default behavior
|
|
68
|
-
* until special UX requirements are needed (e.g., multitenancy).
|
|
69
|
-
*/
|
|
70
|
-
readonly mnemonic?: Mnemonic;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export interface ConfigDep {
|
|
74
|
-
readonly config: Config;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export const defaultConfig: Config = {
|
|
78
|
-
name: getOrThrow(SimpleName.fromParent("Evolu")),
|
|
79
|
-
syncUrl: "wss://free.evoluhq.com",
|
|
80
|
-
reloadUrl: "/",
|
|
81
|
-
maxDrift: 5 * 60 * 1000,
|
|
82
|
-
enableLogging: false,
|
|
83
|
-
};
|
package/src/Evolu/Kysely.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
CreateIndexBuilder,
|
|
3
|
-
DummyDriver,
|
|
4
|
-
Kysely,
|
|
5
|
-
SqliteAdapter,
|
|
6
|
-
SqliteQueryCompiler,
|
|
7
|
-
} from "kysely";
|
|
8
|
-
import { DbIndex } from "./Db.js";
|
|
9
|
-
|
|
10
|
-
// https://kysely.dev/docs/recipes/splitting-query-building-and-execution
|
|
11
|
-
export const kysely = new Kysely({
|
|
12
|
-
dialect: {
|
|
13
|
-
createAdapter: () => new SqliteAdapter(),
|
|
14
|
-
createDriver: () => new DummyDriver(),
|
|
15
|
-
createIntrospector() {
|
|
16
|
-
throw new Error("Not implemeneted");
|
|
17
|
-
},
|
|
18
|
-
createQueryCompiler: () => new SqliteQueryCompiler(),
|
|
19
|
-
},
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
export type DbIndexesBuilder = (
|
|
23
|
-
create: (indexName: string) => CreateIndexBuilder,
|
|
24
|
-
) => ReadonlyArray<CreateIndexBuilder<any>>;
|
|
25
|
-
|
|
26
|
-
const createIndex = kysely.schema.createIndex.bind(kysely.schema);
|
|
27
|
-
|
|
28
|
-
export const createIndexes = (
|
|
29
|
-
indexes?: DbIndexesBuilder,
|
|
30
|
-
): ReadonlyArray<DbIndex> => {
|
|
31
|
-
if (!indexes) return [];
|
|
32
|
-
return indexes(createIndex).map(
|
|
33
|
-
(index): DbIndex => ({
|
|
34
|
-
name: index.toOperationNode().name.name,
|
|
35
|
-
sql: index.compile().sql,
|
|
36
|
-
}),
|
|
37
|
-
);
|
|
38
|
-
};
|
package/src/ManyToManyMap.ts
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
/** Represents a many-to-many mapping between keys and values. */
|
|
2
|
-
export interface ManyToManyMap<K, V> {
|
|
3
|
-
/** Adds a key-value association to the map. */
|
|
4
|
-
add: (key: K, value: V) => ManyToManyMap<K, V>;
|
|
5
|
-
|
|
6
|
-
/** Removes a specific key-value association. */
|
|
7
|
-
remove: (key: K, value: V) => boolean;
|
|
8
|
-
|
|
9
|
-
/** Gets all values associated with a key. */
|
|
10
|
-
getValues: (key: K) => Set<V> | undefined;
|
|
11
|
-
|
|
12
|
-
/** Gets all keys associated with a value. */
|
|
13
|
-
getKeys: (value: V) => Set<K> | undefined;
|
|
14
|
-
|
|
15
|
-
/** Checks if a specific key-value pair exists. */
|
|
16
|
-
hasPair: (key: K, value: V) => boolean;
|
|
17
|
-
|
|
18
|
-
/** Checks if a key exists in the map. */
|
|
19
|
-
hasKey(key: K): boolean;
|
|
20
|
-
|
|
21
|
-
/** Checks if a value exists in the map. */
|
|
22
|
-
hasValue: (value: V) => boolean;
|
|
23
|
-
|
|
24
|
-
/** Deletes all associations for a key. */
|
|
25
|
-
deleteKey: (key: K) => boolean;
|
|
26
|
-
|
|
27
|
-
/** Deletes all associations for a value. */
|
|
28
|
-
deleteValue: (value: V) => boolean;
|
|
29
|
-
|
|
30
|
-
/** Clears all associations in the map. */
|
|
31
|
-
clear(): void;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** Creates a {@link ManyToManyMap}. */
|
|
35
|
-
export const createManyToManyMap = <K, V>(): ManyToManyMap<K, V> => {
|
|
36
|
-
const forwardMap = new Map<K, Set<V>>();
|
|
37
|
-
const reverseMap = new Map<V, Set<K>>();
|
|
38
|
-
|
|
39
|
-
const map: ManyToManyMap<K, V> = {
|
|
40
|
-
add(key: K, value: V) {
|
|
41
|
-
let values = forwardMap.get(key);
|
|
42
|
-
if (!values) {
|
|
43
|
-
values = new Set<V>();
|
|
44
|
-
forwardMap.set(key, values);
|
|
45
|
-
}
|
|
46
|
-
values.add(value);
|
|
47
|
-
|
|
48
|
-
let keys = reverseMap.get(value);
|
|
49
|
-
if (!keys) {
|
|
50
|
-
keys = new Set<K>();
|
|
51
|
-
reverseMap.set(value, keys);
|
|
52
|
-
}
|
|
53
|
-
keys.add(key);
|
|
54
|
-
|
|
55
|
-
return map;
|
|
56
|
-
},
|
|
57
|
-
|
|
58
|
-
remove(key: K, value: V) {
|
|
59
|
-
const values = forwardMap.get(key);
|
|
60
|
-
if (!values?.has(value)) return false;
|
|
61
|
-
|
|
62
|
-
values.delete(value);
|
|
63
|
-
if (values.size === 0) {
|
|
64
|
-
forwardMap.delete(key);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const keys = reverseMap.get(value);
|
|
68
|
-
if (keys?.size) {
|
|
69
|
-
keys.delete(key);
|
|
70
|
-
if (keys.size === 0) {
|
|
71
|
-
reverseMap.delete(value);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return true;
|
|
76
|
-
},
|
|
77
|
-
|
|
78
|
-
getValues(key: K) {
|
|
79
|
-
return forwardMap.get(key);
|
|
80
|
-
},
|
|
81
|
-
|
|
82
|
-
getKeys(value: V) {
|
|
83
|
-
return reverseMap.get(value);
|
|
84
|
-
},
|
|
85
|
-
|
|
86
|
-
hasPair(key: K, value: V) {
|
|
87
|
-
const values = forwardMap.get(key);
|
|
88
|
-
return values?.has(value) ?? false;
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
hasKey(key: K) {
|
|
92
|
-
return forwardMap.has(key);
|
|
93
|
-
},
|
|
94
|
-
|
|
95
|
-
hasValue(value: V) {
|
|
96
|
-
return reverseMap.has(value);
|
|
97
|
-
},
|
|
98
|
-
|
|
99
|
-
deleteKey(key: K) {
|
|
100
|
-
const values = forwardMap.get(key);
|
|
101
|
-
if (!values) return false;
|
|
102
|
-
|
|
103
|
-
for (const value of values) {
|
|
104
|
-
const keys = reverseMap.get(value);
|
|
105
|
-
if (keys) {
|
|
106
|
-
keys.delete(key);
|
|
107
|
-
if (keys.size === 0) {
|
|
108
|
-
reverseMap.delete(value);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
forwardMap.delete(key);
|
|
113
|
-
return true;
|
|
114
|
-
},
|
|
115
|
-
|
|
116
|
-
deleteValue(value: V) {
|
|
117
|
-
const keys = reverseMap.get(value);
|
|
118
|
-
if (!keys) return false;
|
|
119
|
-
|
|
120
|
-
for (const key of keys) {
|
|
121
|
-
const values = forwardMap.get(key);
|
|
122
|
-
if (values) {
|
|
123
|
-
values.delete(value);
|
|
124
|
-
if (values.size === 0) {
|
|
125
|
-
forwardMap.delete(key);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
reverseMap.delete(value);
|
|
130
|
-
return true;
|
|
131
|
-
},
|
|
132
|
-
|
|
133
|
-
clear() {
|
|
134
|
-
forwardMap.clear();
|
|
135
|
-
reverseMap.clear();
|
|
136
|
-
},
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
return map;
|
|
140
|
-
};
|
package/src/NanoId.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { customAlphabet, nanoid, urlAlphabet } from "nanoid";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Interface representing a NanoId library.
|
|
5
|
-
*
|
|
6
|
-
* It's useful for testing by allowing ID generation to be mocked, ensuring
|
|
7
|
-
* consistent results.
|
|
8
|
-
*
|
|
9
|
-
* @see https://github.com/ai/nanoid
|
|
10
|
-
*
|
|
11
|
-
* ### Example
|
|
12
|
-
*
|
|
13
|
-
* ```ts
|
|
14
|
-
* const foo = createFoo({
|
|
15
|
-
* ...createNanoIdLib(),
|
|
16
|
-
* ...createTime(),
|
|
17
|
-
* });
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
export interface NanoIdLib {
|
|
21
|
-
readonly urlAlphabet: string;
|
|
22
|
-
|
|
23
|
-
readonly customAlphabet: (
|
|
24
|
-
alphabet: string,
|
|
25
|
-
defaultSize?: number,
|
|
26
|
-
) => (size?: number) => string;
|
|
27
|
-
|
|
28
|
-
readonly nanoid: (size?: number) => string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface NanoIdLibDep {
|
|
32
|
-
readonly nanoIdLib: NanoIdLib;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export const createNanoIdLib = (): NanoIdLib => ({
|
|
36
|
-
urlAlphabet,
|
|
37
|
-
customAlphabet,
|
|
38
|
-
nanoid,
|
|
39
|
-
});
|